You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2010/01/22 16:54:19 UTC

svn commit: r902133 - in /pivot/trunk: tests/src/org/apache/pivot/tests/form_test.wtkx wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraFormSkin.java

Author: gbrown
Date: Fri Jan 22 15:54:18 2010
New Revision: 902133

URL: http://svn.apache.org/viewvc?rev=902133&view=rev
Log:
Further updates to TerraFormSkin.

Modified:
    pivot/trunk/tests/src/org/apache/pivot/tests/form_test.wtkx
    pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraFormSkin.java

Modified: pivot/trunk/tests/src/org/apache/pivot/tests/form_test.wtkx
URL: http://svn.apache.org/viewvc/pivot/trunk/tests/src/org/apache/pivot/tests/form_test.wtkx?rev=902133&r1=902132&r2=902133&view=diff
==============================================================================
--- pivot/trunk/tests/src/org/apache/pivot/tests/form_test.wtkx (original)
+++ pivot/trunk/tests/src/org/apache/pivot/tests/form_test.wtkx Fri Jan 22 15:54:18 2010
@@ -16,7 +16,7 @@
 limitations under the License.
 -->
 
-<Form styles="{fill:true}"
+<Form styles="{fill:true, padding:0, leftAlignLabels:true}"
     xmlns:wtkx="http://pivot.apache.org/wtkx"
     xmlns:effects="org.apache.pivot.wtk.effects"
     xmlns="org.apache.pivot.wtk">

Modified: pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraFormSkin.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraFormSkin.java?rev=902133&r1=902132&r2=902133&view=diff
==============================================================================
--- pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraFormSkin.java (original)
+++ pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraFormSkin.java Fri Jan 22 15:54:18 2010
@@ -28,7 +28,6 @@
 import org.apache.pivot.collections.Sequence;
 import org.apache.pivot.wtk.ApplicationContext;
 import org.apache.pivot.wtk.Bounds;
-import org.apache.pivot.wtk.BoxPane;
 import org.apache.pivot.wtk.Component;
 import org.apache.pivot.wtk.ComponentMouseListener;
 import org.apache.pivot.wtk.Dimensions;
@@ -37,14 +36,12 @@
 import org.apache.pivot.wtk.FormAttributeListener;
 import org.apache.pivot.wtk.FormListener;
 import org.apache.pivot.wtk.HorizontalAlignment;
-import org.apache.pivot.wtk.ImageView;
 import org.apache.pivot.wtk.Insets;
 import org.apache.pivot.wtk.Label;
 import org.apache.pivot.wtk.MessageType;
 import org.apache.pivot.wtk.Point;
 import org.apache.pivot.wtk.Separator;
 import org.apache.pivot.wtk.Theme;
-import org.apache.pivot.wtk.VerticalAlignment;
 import org.apache.pivot.wtk.Window;
 import org.apache.pivot.wtk.WindowStateListener;
 import org.apache.pivot.wtk.effects.Decorator;
@@ -55,20 +52,16 @@
 /**
  * Terra form skin.
  * <p>
- * TODO Create a section info structure
+ * TODO Dynamically calculate field indicator size based on popup height
  * <p>
- * TODO Drop use of BoxPane for headers and move image views out into the section info structure
- * <p>
- * TODO Dynamically calculate field identifier decorator size based on component size (both types)
+ * TODO Paint inline flag messages
  * <p>
  * TODO Animate preferred size calculations when flags change (make this configurable via
  * a style flag)
- * <p>
- * TODO Create message objects as needed depending on showFlagMessagesInline flag?
  */
 public class TerraFormSkin extends ContainerSkin
     implements FormListener, FormAttributeListener {
-    private static class PopupFieldIdentifierDecorator implements Decorator {
+    private static class FieldIndicatorDecorator implements Decorator {
         private Component component = null;
         private Graphics2D graphics = null;
 
@@ -112,63 +105,16 @@
         }
     }
 
-    private static class InlineFieldIdentifierDecorator implements Decorator {
-        private Component component = null;
-        private Graphics2D graphics = null;
-
-        @Override
-        public Graphics2D prepare(Component component, Graphics2D graphics) {
-            this.component = component;
-            this.graphics = graphics;
-            return graphics;
-        }
-
-        @Override
-        public void update() {
-            Label label = (Label)component;
-            if (label.getText() != null) {
-                int height = component.getHeight();
-
-                GeneralPath arrow = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
-                arrow.moveTo(0, 0);
-                arrow.lineTo(-height / 2, height / 2);
-                arrow.lineTo(0, height);
-                arrow.closePath();
-
-                graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                    RenderingHints.VALUE_ANTIALIAS_ON);
-
-                graphics.setColor((Color)component.getStyles().get("backgroundColor"));
-                graphics.fill(arrow);
-            }
-
-            component = null;
-            graphics = null;
-        }
-
-        @Override
-        public Bounds getBounds(Component component) {
-            int height = component.getHeight();
-            return new Bounds(-height / 2, 0, height / 2, height);
-        }
-
-        @Override
-        public AffineTransform getTransform(Component component) {
-            return new AffineTransform();
-        }
-    }
-
     private ArrayList<Separator> separators = new ArrayList<Separator>();
-    private ArrayList<ArrayList<BoxPane>> rowHeaders = new ArrayList<ArrayList<BoxPane>>();
+    private ArrayList<ArrayList<Label>> labels = new ArrayList<ArrayList<Label>>();
 
     private Label flagMessageLabel = new Label();
     private Window flagMessageWindow = new Window(flagMessageLabel);
-    private ArrayList<ArrayList<Label>> flagMessageLabels = new ArrayList<ArrayList<Label>>();
 
     private Insets padding;
     private int horizontalSpacing;
     private int verticalSpacing;
-    private int flagImageOffset;
+    private int flagIconOffset;
     private boolean fill;
     private boolean showFirstSectionHeading;
     private boolean showFlagIcons;
@@ -176,14 +122,24 @@
     private boolean showFlagMessagesInline;
     private boolean leftAlignLabels;
     private String delimiter;
-    private Image errorMessageIcon = null;
-    private Image warningMessageIcon = null;
-    private Image questionMessageIcon = null;
-    private Image infoMessageIcon = null;
-
-    // TODO Add values for flag message colors; expose both icons and colors as styles
+    private Image errorIcon = null;
+    private Color errorMessageColor = null;
+    private Color errorMessageBackgroundColor = null;
+    private Color errorHighlightColor = null;
+    private Image warningIcon = null;
+    private Color warningMessageColor = null;
+    private Color warningMessageBackgroundColor = null;
+    private Color warningHighlightColor = null;
+    private Image questionIcon = null;
+    private Color questionMessageColor = null;
+    private Color questionMessageBackgroundColor = null;
+    private Color questionHighlightColor = null;
+    private Image infoIcon = null;
+    private Color infoMessageColor = null;
+    private Color infoMessageBackgroundColor = null;
+    private Color infoHighlightColor = null;
 
-    private int flagImageWidth = 0;
+    private int maximumFlagImageWidth = 0;
 
     private ComponentMouseListener fieldMouseListener = new ComponentMouseListener.Adapter() {
         @Override
@@ -198,33 +154,31 @@
                         flagMessageLabel.setText(message);
 
                         MessageType messageType = flag.getMessageType();
-                        TerraTheme theme = (TerraTheme)Theme.getTheme();
 
                         Color color = null;
                         Color backgroundColor = null;
-
                         switch (messageType) {
                             case ERROR: {
-                                color = theme.getColor(4);
-                                backgroundColor = theme.getColor(22);
+                                color = errorMessageColor;
+                                backgroundColor = errorMessageBackgroundColor;
                                 break;
                             }
 
                             case WARNING: {
-                                color = theme.getColor(1);
-                                backgroundColor = theme.getColor(19);
+                                color = warningMessageColor;
+                                backgroundColor = warningMessageBackgroundColor;
                                 break;
                             }
 
                             case QUESTION: {
-                                color = theme.getColor(4);
-                                backgroundColor = theme.getColor(16);
+                                color = questionMessageColor;
+                                backgroundColor = questionMessageBackgroundColor;
                                 break;
                             }
 
                             case INFO: {
-                                color = theme.getColor(1);
-                                backgroundColor = theme.getColor(10);
+                                color = infoMessageColor;
+                                backgroundColor = infoMessageBackgroundColor;
                                 break;
                             }
                         }
@@ -267,7 +221,7 @@
         padding = new Insets(4);
         horizontalSpacing = 6;
         verticalSpacing = 6;
-        flagImageOffset = 4;
+        flagIconOffset = 4;
         fill = false;
         showFirstSectionHeading = false;
         showFlagIcons = true;
@@ -276,23 +230,40 @@
         leftAlignLabels = false;
         delimiter = DEFAULT_DELIMITER;
 
-        TerraTheme terraTheme = (TerraTheme)Theme.getTheme();
-        errorMessageIcon = terraTheme.getSmallMessageIcon(MessageType.ERROR);
-        warningMessageIcon = terraTheme.getSmallMessageIcon(MessageType.WARNING);
-        questionMessageIcon = terraTheme.getSmallMessageIcon(MessageType.QUESTION);
-        infoMessageIcon = terraTheme.getSmallMessageIcon(MessageType.INFO);
+        // Get theme icons/colors
+        TerraTheme theme = (TerraTheme)Theme.getTheme();
+
+        errorIcon = theme.getSmallMessageIcon(MessageType.ERROR);
+        errorMessageColor = theme.getColor(4);
+        errorMessageBackgroundColor = theme.getColor(22);
+        errorHighlightColor = theme.getColor(21);
+
+        warningIcon = theme.getSmallMessageIcon(MessageType.WARNING);
+        warningMessageColor = theme.getColor(1);
+        warningMessageBackgroundColor = theme.getColor(19);
+        warningHighlightColor = theme.getColor(18);
+
+        questionIcon = theme.getSmallMessageIcon(MessageType.QUESTION);
+        questionMessageColor = theme.getColor(4);
+        questionMessageBackgroundColor = theme.getColor(16);
+        questionHighlightColor = theme.getColor(15);
+
+        infoIcon = theme.getSmallMessageIcon(MessageType.INFO);
+        infoMessageColor = theme.getColor(1);
+        infoMessageBackgroundColor = theme.getColor(10);
+        infoHighlightColor = theme.getColor(9);
 
         // Determine maximum icon size
-        flagImageWidth = Math.max(flagImageWidth, errorMessageIcon.getWidth());
-        flagImageWidth = Math.max(flagImageWidth, warningMessageIcon.getWidth());
-        flagImageWidth = Math.max(flagImageWidth, questionMessageIcon.getWidth());
-        flagImageWidth = Math.max(flagImageWidth, infoMessageIcon.getWidth());
+        maximumFlagImageWidth = Math.max(maximumFlagImageWidth, errorIcon.getWidth());
+        maximumFlagImageWidth = Math.max(maximumFlagImageWidth, warningIcon.getWidth());
+        maximumFlagImageWidth = Math.max(maximumFlagImageWidth, questionIcon.getWidth());
+        maximumFlagImageWidth = Math.max(maximumFlagImageWidth, infoIcon.getWidth());
 
         // Create the flag message popup
         flagMessageLabel.getStyles().put("padding", new Insets(3, 4, 3, 4));
 
         flagMessageWindow.getDecorators().add(new DropShadowDecorator(3, 3, 3));
-        flagMessageWindow.getDecorators().add(new PopupFieldIdentifierDecorator());
+        flagMessageWindow.getDecorators().add(new FieldIndicatorDecorator());
 
         flagMessageWindow.getWindowStateListeners().add(new WindowStateListener.Adapter() {
             private ApplicationContext.ScheduledCallback scheduledHideFlagMessageCallback = null;
@@ -336,7 +307,7 @@
     public int getPreferredWidth(int height) {
         int preferredWidth = 0;
 
-        int maximumRowHeaderWidth = 0;
+        int maximumLabelWidth = 0;
         int maximumFieldWidth = 0;
         int maximumFlagMessageWidth = 0;
         int maximumSeparatorWidth = 0;
@@ -360,22 +331,19 @@
                 Component field = section.get(fieldIndex);
 
                 if (field.isVisible()) {
-                    BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-                    maximumRowHeaderWidth = Math.max(maximumRowHeaderWidth,
-                        rowHeader.getPreferredWidth(-1));
-                    maximumFieldWidth = Math.max(maximumFieldWidth,
-                        field.getPreferredWidth(-1));
+                    Label label = labels.get(sectionIndex).get(fieldIndex);
+                    maximumLabelWidth = Math.max(maximumLabelWidth, label.getPreferredWidth(-1));
+                    maximumFieldWidth = Math.max(maximumFieldWidth, field.getPreferredWidth(-1));
 
                     if (showFlagMessagesInline) {
-                        Label flagMessageLabel = flagMessageLabels.get(sectionIndex).get(fieldIndex);
-                        maximumFlagMessageWidth = Math.max(maximumFlagMessageWidth,
-                            flagMessageLabel.getPreferredWidth(-1));
+                        // TODO Calculate maximumFlagMessageWidth
                     }
                 }
             }
         }
 
-        preferredWidth = maximumRowHeaderWidth + horizontalSpacing + maximumFieldWidth;
+        preferredWidth = maximumFlagImageWidth + flagIconOffset + maximumLabelWidth
+            + horizontalSpacing + maximumFieldWidth;
 
         if (showFlagMessagesInline) {
             preferredWidth += horizontalSpacing + maximumFlagMessageWidth;
@@ -413,12 +381,11 @@
                 Component field = section.get(fieldIndex);
 
                 if (field.isVisible()) {
-                    // Determine the row header size and baseline
-                    BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-
-                    Dimensions rowHeaderSize = rowHeader.getPreferredSize();
-                    int rowHeaderAscent = rowHeader.getBaseline(rowHeaderSize.width, rowHeaderSize.height);
-                    int rowHeaderDescent = rowHeaderSize.height - rowHeaderAscent;
+                    // Determine the label size and baseline
+                    Label label = labels.get(sectionIndex).get(fieldIndex);
+                    Dimensions labelSize = label.getPreferredSize();
+                    int labelAscent = label.getBaseline(labelSize.width, labelSize.height);
+                    int labelDescent = labelSize.height - labelAscent;
 
                     // Determine the field size and baseline
                     Dimensions fieldSize;
@@ -435,23 +402,9 @@
 
                     int fieldDescent = fieldSize.height - fieldAscent;
 
-                    // Determine the message label size and baseline
-                    int flagMessageLabelAscent = 0;
-                    int flagMessageLabelDescent = 0;
-
-                    if (showFlagMessagesInline) {
-                        Label flagMessageLabel = flagMessageLabels.get(sectionIndex).get(fieldIndex);
-
-                        Dimensions flagMessageLabelSize = flagMessageLabel.getPreferredSize();
-                        flagMessageLabelAscent = flagMessageLabel.getBaseline(flagMessageLabelSize.width,
-                            flagMessageLabelSize.height);
-                        flagMessageLabelDescent = flagMessageLabelSize.height - flagMessageLabelAscent;
-                    }
-
                     // Determine the row height
-                    int maximumAscent = Math.max(rowHeaderAscent, Math.max(fieldAscent, flagMessageLabelAscent));
-                    int maximumDescent = Math.max(rowHeaderDescent, Math.max(fieldDescent, flagMessageLabelDescent));
-
+                    int maximumAscent = Math.max(labelAscent, fieldAscent);
+                    int maximumDescent = Math.max(labelDescent, fieldDescent);
                     int rowHeight = maximumAscent + maximumDescent;
 
                     preferredHeight += rowHeight;
@@ -507,11 +460,10 @@
                 Component field = section.get(fieldIndex);
 
                 if (field.isVisible()) {
-                    BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-
-                    // Determine the row header size and baseline
-                    Dimensions rowHeaderSize = rowHeader.getPreferredSize();
-                    int rowHeaderAscent = rowHeader.getBaseline(rowHeaderSize.width, rowHeaderSize.height);
+                    // Determine the label size and baseline
+                    Label label = labels.get(sectionIndex).get(fieldIndex);
+                    Dimensions labelSize = label.getPreferredSize();
+                    int labelAscent = label.getBaseline(labelSize.width, labelSize.height);
 
                     // Determine the field size and baseline
                     Dimensions fieldSize;
@@ -523,22 +475,11 @@
 
                     int fieldAscent = field.getBaseline(fieldSize.width, fieldSize.height);
                     if (fieldAscent == -1) {
-                        fieldAscent = rowHeaderAscent;
-                    }
-
-                    // Determine the message label size and baseline
-                    int flagMessageLabelAscent = 0;
-
-                    if (showFlagMessagesInline) {
-                        Label flagMessageLabel = flagMessageLabels.get(sectionIndex).get(fieldIndex);
-
-                        Dimensions flagMessageLabelSize = flagMessageLabel.getPreferredSize();
-                        flagMessageLabelAscent = flagMessageLabel.getBaseline(flagMessageLabelSize.width,
-                            flagMessageLabelSize.height);
+                        fieldAscent = labelAscent;
                     }
 
                     // Determine the baseline
-                    int maximumAscent = Math.max(rowHeaderAscent, Math.max(fieldAscent, flagMessageLabelAscent));
+                    int maximumAscent = Math.max(labelAscent, fieldAscent);
                     baseline = rowY + maximumAscent;
                 }
 
@@ -554,7 +495,7 @@
     }
 
     private int getFieldWidth(int width) {
-        int maximumRowHeaderWidth = 0;
+        int maximumLabelWidth = 0;
         int maximumFlagMessageWidth = 0;
 
         Form form = (Form)getComponent();
@@ -569,21 +510,17 @@
                 Component field = section.get(fieldIndex);
 
                 if (field.isVisible()) {
-                    BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-                    maximumRowHeaderWidth = Math.max(maximumRowHeaderWidth,
-                        rowHeader.getPreferredWidth(-1));
+                    Label label = labels.get(sectionIndex).get(fieldIndex);
+                    maximumLabelWidth = Math.max(maximumLabelWidth, label.getPreferredWidth(-1));
 
                     if (showFlagMessagesInline) {
-                        Label flagMessageLabel = flagMessageLabels.get(sectionIndex).get(fieldIndex);
-
-                        maximumFlagMessageWidth = Math.max(maximumFlagMessageWidth,
-                            flagMessageLabel.getPreferredWidth(-1));
+                        // TODO Calculate maximumFlagMessageWidth
                     }
                 }
             }
         }
 
-        int fieldWidth = Math.max(0, width - (maximumRowHeaderWidth + horizontalSpacing));
+        int fieldWidth = Math.max(0, width - (maximumLabelWidth + horizontalSpacing));
 
         if (showFlagMessagesInline) {
             fieldWidth = Math.max(0, fieldWidth - (horizontalSpacing + maximumFlagMessageWidth));
@@ -599,8 +536,8 @@
         Form form = (Form)getComponent();
         Form.SectionSequence sections = form.getSections();
 
-        // Determine the maximum row header and message flag widths
-        int maximumRowHeaderWidth = 0;
+        // Determine the maximum label and flag message width
+        int maximumLabelWidth = 0;
         int maximumFlagMessageWidth = 0;
 
         for (int sectionIndex = 0, sectionCount = sections.getLength();
@@ -612,15 +549,11 @@
                 Component field = section.get(fieldIndex);
 
                 if (field.isVisible()) {
-                    BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-                    maximumRowHeaderWidth = Math.max(maximumRowHeaderWidth,
-                        rowHeader.getPreferredWidth(-1));
+                    Label label = labels.get(sectionIndex).get(fieldIndex);
+                    maximumLabelWidth = Math.max(maximumLabelWidth, label.getPreferredWidth(-1));
 
                     if (showFlagMessagesInline) {
-                        Label flagMessageLabel = flagMessageLabels.get(sectionIndex).get(fieldIndex);
-
-                        maximumFlagMessageWidth = Math.max(maximumFlagMessageWidth,
-                            flagMessageLabel.getPreferredWidth(-1));
+                        // TODO Calculate maximumFlagMessageWidth
                     }
                 }
             }
@@ -628,7 +561,7 @@
 
         // Determine the field width
         int width = getWidth();
-        int fieldWidth = Math.max(0, width - (maximumRowHeaderWidth + horizontalSpacing));
+        int fieldWidth = Math.max(0, width - (maximumLabelWidth + horizontalSpacing));
 
         if (showFlagMessagesInline) {
             fieldWidth = Math.max(0, fieldWidth - (horizontalSpacing + maximumFlagMessageWidth));
@@ -637,7 +570,6 @@
         fieldWidth = Math.max(0, fieldWidth - (padding.left + padding.right));
 
         // Lay out the components
-        int rowX = padding.left;
         int rowY = padding.top;
 
         for (int sectionIndex = 0, sectionCount = sections.getLength();
@@ -651,26 +583,24 @@
             } else {
                 separator.setVisible(true);
                 separator.setSize(width, separator.getPreferredHeight(width));
-                separator.setLocation(rowX, rowY);
+                separator.setLocation(padding.left, rowY);
                 rowY += separator.getHeight();
             }
 
             for (int fieldIndex = 0, fieldCount = section.getLength();
                 fieldIndex < fieldCount; fieldIndex++) {
+                Label label = labels.get(sectionIndex).get(fieldIndex);
                 Component field = section.get(fieldIndex);
 
-                BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-
                 if (field.isVisible()) {
-                    // Show the row header
-                    rowHeader.setVisible(true);
+                    // Show the label
+                    label.setVisible(true);
 
-                    // Determine the row header size and baseline
-                    Dimensions rowHeaderSize = new Dimensions(maximumRowHeaderWidth,
-                        rowHeader.getPreferredHeight());
-                    rowHeader.setSize(rowHeaderSize);
-                    int rowHeaderAscent = rowHeader.getBaseline(rowHeaderSize.width, rowHeaderSize.height);
-                    int rowHeaderDescent = rowHeaderSize.height - rowHeaderAscent;
+                    // Determine the label size and baseline
+                    Dimensions labelSize = new Dimensions(maximumLabelWidth, label.getPreferredHeight());
+                    label.setSize(labelSize);
+                    int labelAscent = label.getBaseline(labelSize.width, labelSize.height);
+                    int labelDescent = labelSize.height - labelAscent;
 
                     // Determine the field size and baseline
                     Dimensions fieldSize;
@@ -684,65 +614,33 @@
 
                     int fieldAscent = field.getBaseline(fieldSize.width, fieldSize.height);
                     if (fieldAscent == -1) {
-                        fieldAscent = rowHeaderAscent;
+                        fieldAscent = labelAscent;
                     }
 
                     int fieldDescent = fieldSize.height - fieldAscent;
 
-                    // Determine the message label size and baseline
-                    int flagMessageLabelAscent = 0;
-                    int flagMessageLabelDescent = 0;
-
-                    if (showFlagMessagesInline) {
-                        Label flagMessageLabel = flagMessageLabels.get(sectionIndex).get(fieldIndex);
-
-                        Dimensions flagMessageLabelSize = flagMessageLabel.getPreferredSize();
-                        flagMessageLabel.setSize(flagMessageLabelSize);
-
-                        flagMessageLabelAscent = flagMessageLabel.getBaseline(flagMessageLabelSize.width,
-                            flagMessageLabelSize.height);
-                        flagMessageLabelDescent = flagMessageLabelSize.height - flagMessageLabelAscent;
-                    }
-
                     // Determine the baseline and row height
-                    int maximumAscent = Math.max(rowHeaderAscent, Math.max(fieldAscent, flagMessageLabelAscent));
-                    int maximumDescent = Math.max(rowHeaderDescent, Math.max(fieldDescent, flagMessageLabelDescent));
+                    int maximumAscent = Math.max(labelAscent, fieldAscent);
+                    int maximumDescent = Math.max(labelDescent, fieldDescent);
 
                     int baseline = maximumAscent;
                     int rowHeight = maximumAscent + maximumDescent;
 
-                    // Position the row header
-                    int rowHeaderX = padding.left;
-                    int rowHeaderY = rowY + (baseline - rowHeaderAscent);
-                    rowHeader.setLocation(rowHeaderX, rowHeaderY);
+                    // Position the label
+                    int labelX = padding.left + maximumFlagImageWidth + flagIconOffset;
+                    int labelY = rowY + (baseline - labelAscent);
+                    label.setLocation(labelX, labelY);
 
                     // Position the field
-                    int fieldX = maximumRowHeaderWidth + horizontalSpacing + padding.left;
+                    int fieldX = labelX + maximumLabelWidth + horizontalSpacing;
                     int fieldY = rowY + (baseline - fieldAscent);
                     field.setLocation(fieldX, fieldY);
 
-                    // Position the message label
-                    if (showFlagMessagesInline) {
-                        Label flagMessageLabel = flagMessageLabels.get(sectionIndex).get(fieldIndex);
-
-                        int flagMessageLabelX = maximumRowHeaderWidth + horizontalSpacing
-                            + field.getWidth() + horizontalSpacing;
-                        int flagMessageLabelY = rowY + (baseline - flagMessageLabelAscent);
-
-                        flagMessageLabel.setLocation(flagMessageLabelX, flagMessageLabelY);
-                    }
-
                     // Update the row y-coordinate
                     rowY += rowHeight + verticalSpacing;
                 } else {
-                    // Hide the row header
-                    rowHeader.setVisible(false);
-
-                    // Hide the flag message label
-                    if (showFlagMessagesInline) {
-                        Label flagMessageLabel = flagMessageLabels.get(sectionIndex).get(fieldIndex);
-                        flagMessageLabel.setVisible(false);
-                    }
+                    // Hide the label
+                    label.setVisible(false);
                 }
             }
         }
@@ -764,35 +662,60 @@
                 Component field = section.get(fieldIndex);
 
                 Form.Flag flag = Form.getFlag(field);
-                if (flag != null && showFlagHighlight) {
-                    TerraTheme theme = (TerraTheme)Theme.getTheme();
+
+                if (flag != null) {
+                    String message = flag.getMessage();
                     MessageType messageType = flag.getMessageType();
 
+                    Image flagIcon = null;
                     Color highlightColor = null;
-
+                    Color messageColor = null;
+                    Color messageBackgroundColor = null;
                     switch (messageType) {
                         case ERROR: {
-                            highlightColor = theme.getColor(21);
+                            flagIcon = errorIcon;
+                            highlightColor = errorHighlightColor;
+                            messageColor = errorMessageColor;
+                            messageBackgroundColor = errorMessageBackgroundColor;
                             break;
                         }
 
                         case WARNING: {
-                            highlightColor = theme.getColor(18);
+                            flagIcon = warningIcon;
+                            highlightColor = warningHighlightColor;
+                            messageColor = warningMessageColor;
+                            messageBackgroundColor = warningMessageBackgroundColor;
                             break;
                         }
 
                         case QUESTION: {
-                            highlightColor = theme.getColor(15);
+                            flagIcon = questionIcon;
+                            highlightColor = questionHighlightColor;
+                            messageColor = questionMessageColor;
+                            messageBackgroundColor = questionMessageBackgroundColor;
                             break;
                         }
 
                         case INFO: {
-                            highlightColor = theme.getColor(9);
+                            flagIcon = infoIcon;
+                            highlightColor = infoHighlightColor;
+                            messageColor = infoMessageColor;
+                            messageBackgroundColor = infoMessageBackgroundColor;
                             break;
                         }
                     }
 
-                    if (highlightColor != null) {
+                    if (showFlagIcons && flagIcon != null) {
+                        Label label = labels.get(sectionIndex).get(fieldIndex);
+                        int flagIconX = label.getX() - (flagIcon.getWidth() + flagIconOffset);
+                        int flagIconY = label.getY() + (label.getHeight() - flagIcon.getHeight()) / 2;
+
+                        graphics.translate(flagIconX, flagIconY);
+                        flagIcon.paint(graphics);
+                        graphics.translate(-flagIconX, -flagIconY);
+                    }
+
+                    if (showFlagHighlight && highlightColor != null) {
                         Bounds fieldBounds = field.getBounds();
 
                         graphics.setColor(highlightColor);
@@ -802,6 +725,10 @@
                             fieldBounds.width + FLAG_HIGHLIGHT_PADDING * 2 - 1,
                             fieldBounds.height + FLAG_HIGHLIGHT_PADDING * 2 - 1);
                     }
+
+                    if (showFlagMessagesInline && message != null) {
+                        // TODO
+                    }
                 }
             }
         }
@@ -890,41 +817,25 @@
         setVerticalSpacing(verticalSpacing.intValue());
     }
 
-    public int getFlagImageOffset() {
-        return flagImageOffset;
+    public int getFlagIconOffset() {
+        return flagIconOffset;
     }
 
-    public void setFlagImageOffset(int flagImageOffset) {
-        if (flagImageOffset < 0) {
-            throw new IllegalArgumentException("flagImageOffset is negative.");
-        }
-
-        this.flagImageOffset = flagImageOffset;
-
-        // Set spacing style of existing row headers to flagImageOffset
-        Form form = (Form)getComponent();
-        Form.SectionSequence sections = form.getSections();
-
-        for (int sectionIndex = 0, sectionCount = sections.getLength();
-            sectionIndex < sectionCount; sectionIndex++) {
-            Form.Section section = sections.get(sectionIndex);
-
-            for (int fieldIndex = 0, fieldCount = section.getLength();
-                fieldIndex < fieldCount; fieldIndex++) {
-                BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-                rowHeader.getStyles().put("spacing", flagImageOffset);
-            }
+    public void setFlagIconOffset(int flagIconOffset) {
+        if (flagIconOffset < 0) {
+            throw new IllegalArgumentException("flagIconOffset is negative.");
         }
 
+        this.flagIconOffset = flagIconOffset;
         invalidateComponent();
     }
 
-    public final void setFlagImageOffset(Number flagImageOffset) {
-        if (flagImageOffset == null) {
-            throw new IllegalArgumentException("flagImageOffset is null.");
+    public final void setFlagIconOffset(Number flagIconOffset) {
+        if (flagIconOffset == null) {
+            throw new IllegalArgumentException("flagIconOffset is null.");
         }
 
-        setFlagImageOffset(flagImageOffset.intValue());
+        setFlagIconOffset(flagIconOffset.intValue());
     }
 
     public boolean getFill() {
@@ -951,23 +862,6 @@
 
     public void setShowFlagIcons(boolean showFlagIcons) {
         this.showFlagIcons = showFlagIcons;
-
-        // Set visibility of existing flag image views to false
-        Form form = (Form)getComponent();
-        Form.SectionSequence sections = form.getSections();
-
-        for (int sectionIndex = 0, sectionCount = sections.getLength();
-            sectionIndex < sectionCount; sectionIndex++) {
-            Form.Section section = sections.get(sectionIndex);
-
-            for (int fieldIndex = 0, fieldCount = section.getLength();
-                fieldIndex < fieldCount; fieldIndex++) {
-                BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-                ImageView flagImageView = (ImageView)rowHeader.get(0);
-                flagImageView.setVisible(showFlagIcons);
-            }
-        }
-
         invalidateComponent();
     }
 
@@ -996,7 +890,7 @@
     public void setLeftAlignLabels(boolean leftAlignLabels) {
         this.leftAlignLabels = leftAlignLabels;
 
-        // Set horizontal alignment style of existing row headers to left or right
+        // Set horizontal alignment style of existing labels
         Form form = (Form)getComponent();
         Form.SectionSequence sections = form.getSections();
 
@@ -1006,13 +900,13 @@
 
             for (int fieldIndex = 0, fieldCount = section.getLength();
                 fieldIndex < fieldCount; fieldIndex++) {
-                BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-                rowHeader.getStyles().put("horizontalAlignment", leftAlignLabels ?
+                Label label = labels.get(sectionIndex).get(fieldIndex);
+                label.getStyles().put("horizontalAlignment", leftAlignLabels ?
                     HorizontalAlignment.LEFT : HorizontalAlignment.RIGHT);
             }
         }
 
-        invalidateComponent();
+        repaintComponent();
     }
 
     public String getDelimiter() {
@@ -1081,8 +975,11 @@
 
     @Override
     public void flagChanged(Form form, Component field, Form.Flag previousFlag) {
-        Form.Section section = Form.getSection(field);
-        updateFieldFlag(section, section.indexOf(field));
+        if (showFlagMessagesInline) {
+            invalidateComponent();
+        } else {
+            repaintComponent();
+        }
     }
 
     private void insertSection(Form.Section section, int index) {
@@ -1093,12 +990,9 @@
         separators.insert(separator, index);
         form.add(separator);
 
-        // Insert row header list
-        ArrayList<BoxPane> sectionRowHeaders = new ArrayList<BoxPane>();
-        rowHeaders.insert(sectionRowHeaders, index);
-
-        // Insert flag message list
-        flagMessageLabels.insert(new ArrayList<Label>(), index);
+        // Insert label list
+        ArrayList<Label> sectionLabels = new ArrayList<Label>();
+        labels.insert(sectionLabels, index);
 
         // Insert fields
         for (int i = 0, n = section.getLength(); i < n; i++) {
@@ -1117,11 +1011,8 @@
             removeFields(index + i, 0, removed.get(i));
         }
 
-        // Remove row header list
-        rowHeaders.remove(index, count);
-
-        // Remove flag message list
-        flagMessageLabels.remove(index, count);
+        // Remove labels
+        labels.remove(index, count);
 
         // Remove separators
         Sequence<Separator> removedSeparators = separators.remove(index, count);
@@ -1136,38 +1027,19 @@
         Form form = (Form)getComponent();
         int sectionIndex = form.getSections().indexOf(section);
 
-        // Create the row header
-        BoxPane rowHeader = new BoxPane();
-        rowHeader.getStyles().put("horizontalAlignment", leftAlignLabels ?
-            HorizontalAlignment.LEFT : HorizontalAlignment.RIGHT);
-        rowHeader.getStyles().put("verticalAlignment", VerticalAlignment.CENTER);
-
-        ImageView flagImageView = new ImageView();
-        flagImageView.setPreferredWidth(flagImageWidth);
-        flagImageView.setVisible(showFlagIcons);
-
-        rowHeader.add(flagImageView);
-
+        // Create the label
         Label label = new Label();
-        rowHeader.add(label);
+        label.getStyles().put("horizontalAlignment", leftAlignLabels ?
+            HorizontalAlignment.LEFT : HorizontalAlignment.RIGHT);
 
-        rowHeaders.get(sectionIndex).insert(rowHeader, index);
-        form.add(rowHeader);
+        labels.get(sectionIndex).insert(label, index);
+        form.add(label);
 
         // Add mouse listener
         field.getComponentMouseListeners().add(fieldMouseListener);
 
-        // Add flag message label
-        Label flagMessageLabel = new Label();
-        flagMessageLabel.getStyles().put("padding", new Insets(3, 4, 3, 4));
-        flagMessageLabel.getDecorators().add(new InlineFieldIdentifierDecorator());
-
-        flagMessageLabels.get(sectionIndex).insert(flagMessageLabel, index);
-        form.add(flagMessageLabel);
-
-        // Update the field label and flag
+        // Update the field label
         updateFieldLabel(section, index);
-        updateFieldFlag(section, index);
 
         invalidateComponent();
     }
@@ -1176,15 +1048,11 @@
         Form form = (Form)getComponent();
         int count = removed.getLength();
 
-        // Remove the row headers
-        Sequence<BoxPane> removedRowHeaders = rowHeaders.get(sectionIndex).remove(index, count);
-
-        // Remove flag message labels
-        Sequence<Label> removedFlagMessageLabels = flagMessageLabels.get(sectionIndex).remove(index, count);
+        // Remove the labels
+        Sequence<Label> removedLabels = labels.get(sectionIndex).remove(index, count);
 
         for (int i = 0; i < count; i++) {
-            form.remove(removedRowHeaders.get(i));
-            form.remove(removedFlagMessageLabels.get(i));
+            form.remove(removedLabels.get(i));
 
             // Remove mouse listener
             Component field = removed.get(i);
@@ -1207,81 +1075,8 @@
         Component field = section.get(fieldIndex);
 
         int sectionIndex = form.getSections().indexOf(section);
-        BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-        Label label = (Label)rowHeader.get(1);
+        Label label = labels.get(sectionIndex).get(fieldIndex);
         String labelText = Form.getLabel(field);
         label.setText((labelText == null) ? "" : labelText + delimiter);
     }
-
-    private void updateFieldFlag(Form.Section section, int fieldIndex) {
-        Form form = (Form)getComponent();
-        Component field = section.get(fieldIndex);
-
-        int sectionIndex = form.getSections().indexOf(section);
-        BoxPane rowHeader = rowHeaders.get(sectionIndex).get(fieldIndex);
-        ImageView flagImageView = (ImageView)rowHeader.get(0);
-
-        Label flagMessageLabel = flagMessageLabels.get(sectionIndex).get(fieldIndex);
-
-        Form.Flag flag = Form.getFlag(field);
-
-        if (flag == null) {
-            flagImageView.setImage((Image)null);
-
-            flagMessageLabel.setText(null);
-            flagMessageLabel.getStyles().put("color", 1);
-            flagMessageLabel.getStyles().put("backgroundColor", null);
-        } else {
-            MessageType messageType = flag.getMessageType();
-            TerraTheme theme = (TerraTheme)Theme.getTheme();
-
-            Image messageIcon = null;
-            Color color = null;
-            Color backgroundColor = null;
-
-            switch (messageType) {
-                case ERROR: {
-                    messageIcon = errorMessageIcon;
-                    color = theme.getColor(4);
-                    backgroundColor = theme.getColor(22);
-                    break;
-                }
-
-                case WARNING: {
-                    messageIcon = warningMessageIcon;
-                    color = theme.getColor(1);
-                    backgroundColor = theme.getColor(19);
-                    break;
-                }
-
-                case QUESTION: {
-                    messageIcon = questionMessageIcon;
-                    color = theme.getColor(4);
-                    backgroundColor = theme.getColor(16);
-                    break;
-                }
-
-                case INFO: {
-                    messageIcon = infoMessageIcon;
-                    color = theme.getColor(1);
-                    backgroundColor = theme.getColor(10);
-                    break;
-                }
-            }
-
-            flagImageView.setImage(messageIcon);
-
-            flagMessageLabel.setText(flag.getMessage());
-            flagMessageLabel.getStyles().put("color", color);
-            flagMessageLabel.getStyles().put("backgroundColor", backgroundColor);
-        }
-
-        if (showFlagHighlight) {
-            Bounds fieldBounds = field.getBounds();
-            repaintComponent(fieldBounds.x - FLAG_HIGHLIGHT_PADDING,
-                fieldBounds.y - FLAG_HIGHLIGHT_PADDING,
-                fieldBounds.width + FLAG_HIGHLIGHT_PADDING * 2 - 1,
-                fieldBounds.height + FLAG_HIGHLIGHT_PADDING * 2 - 1);
-        }
-    }
 }