changeset 6165:a804fa529ce6

RT-34926: [ColorPicker] Selection draws badly when arrow keys are used to traverse RT-34911: [ColorPicker] When hovering over color picker options, blue highlight border is not drawn on right and bottom of color rect Summary: I've rewritten how the hovered colour is rendered, so that rather than simply scaling the rectangle (as was done in Modena), there is now a separate node that is placed in the correct location atop all other nodes. The general issue was that the scaling of the hovered node did not bring the node to the the front, so other colours in the palette were still drawing on top of the node.
author jgiles
date Wed, 22 Jan 2014 14:35:19 +1300
parents ed47253a8c3b
children aa08f837ac40
files apps/toys/Hello/src/main/java/hello/HelloColorPicker.java modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ColorPalette.java modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ColorPickerSkin.java modules/controls/src/main/resources/com/sun/javafx/scene/control/skin/caspian/caspian.css modules/controls/src/main/resources/com/sun/javafx/scene/control/skin/modena/modena.css modules/controls/src/test/java/com/sun/javafx/scene/control/skin/ColorPickerPaletteRetriever.java
diffstat 6 files changed, 96 insertions(+), 155 deletions(-) [+]
line wrap: on
line diff
--- a/apps/toys/Hello/src/main/java/hello/HelloColorPicker.java	Wed Jan 22 11:29:07 2014 +1300
+++ b/apps/toys/Hello/src/main/java/hello/HelloColorPicker.java	Wed Jan 22 14:35:19 2014 +1300
@@ -44,8 +44,6 @@
         launch(args);
     }
     @Override public void start(Stage stage) {
-//        setUserAgentStylesheet(STYLESHEET_CASPIAN);
-
         stage.setTitle("ColorPicker");
 
         EventHandler<ActionEvent> actionEventHandler = new EventHandler<ActionEvent>() {
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ColorPalette.java	Wed Jan 22 11:29:07 2014 +1300
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ColorPalette.java	Wed Jan 22 14:35:19 2014 +1300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,11 +25,9 @@
 
 package com.sun.javafx.scene.control.skin;
 
-import javafx.css.PseudoClass;
+import javafx.geometry.Bounds;
 import javafx.scene.control.ColorPicker;
 import java.util.List;
-import javafx.beans.property.ReadOnlyBooleanProperty;
-import javafx.beans.property.ReadOnlyBooleanWrapper;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.collections.FXCollections;
@@ -45,6 +43,7 @@
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Region;
 import javafx.scene.layout.StackPane;
 import javafx.scene.layout.VBox;
 import javafx.scene.paint.Color;
@@ -52,21 +51,21 @@
 import javafx.scene.shape.StrokeType;
 import javafx.stage.WindowEvent;
 
-public class ColorPalette extends VBox {
+public class ColorPalette extends Region {
 
     private static final int SQUARE_SIZE = 15;
     private static final int NUM_OF_COLUMNS = 12;
     private static final int NUM_OF_ROWS = 10;
-    private static final int LABEL_GAP = 2;
-    
-    private boolean customColorAdded = false;
+
+    // package protected for testing purposes
     ColorPickerGrid colorPickerGrid;
-    ColorPicker colorPicker;
-    GridPane customColorGrid = new GridPane();
-    Hyperlink customColorLink = new Hyperlink("Custom Color..");
-    Separator separator = new Separator();
-    Label customColorLabel = new Label("Custom Colors");
+    final Hyperlink customColorLink = new Hyperlink("Custom Color..");
     CustomColorDialog customColorDialog = null;
+
+    private ColorPicker colorPicker;
+    private final GridPane customColorGrid = new GridPane();
+    private final Separator separator = new Separator();
+    private final Label customColorLabel = new Label("Custom Colors");
     private final List<ColorSquare> customSquares = FXCollections.observableArrayList();
  
     private PopupControl popupControl;
@@ -75,11 +74,13 @@
     
     private Color mouseDragColor = null;
     private boolean dragDetected = false;
+
+    private final ColorSquare hoverSquare = new ColorSquare(null);
     
-    public ColorPalette(Color initPaint, final ColorPicker colorPicker) {
-        getStyleClass().add("color-palette");
+    public ColorPalette(final ColorPicker colorPicker) {
+        getStyleClass().add("color-palette-region");
         this.colorPicker = colorPicker;
-        colorPickerGrid = new ColorPickerGrid(initPaint);
+        colorPickerGrid = new ColorPickerGrid();
         colorPickerGrid.requestFocus();
         colorPickerGrid.setFocusTraversable(true);
         customColorLabel.setAlignment(Pos.CENTER_LEFT);
@@ -149,7 +150,31 @@
                 buildCustomColors();
             }
         });
-        getChildren().addAll(colorPickerGrid, customColorLabel, customColorGrid, separator, customColorLink);
+
+        VBox paletteBox = new VBox();
+        paletteBox.getStyleClass().add("color-palette");
+        paletteBox.getChildren().addAll(colorPickerGrid, customColorLabel, customColorGrid, separator, customColorLink);
+
+        hoverSquare.setMouseTransparent(true);
+        hoverSquare.getStyleClass().addAll("hover-square");
+        setFocusedSquare(null);
+
+        getChildren().addAll(paletteBox, hoverSquare);
+    }
+
+    private void setFocusedSquare(ColorSquare square) {
+        focusedSquare = square;
+
+        hoverSquare.setVisible(focusedSquare != null);
+        if (focusedSquare == null) {
+            return;
+        }
+
+        hoverSquare.rectangle.setFill(focusedSquare.rectangle.getFill());
+
+        Bounds b = square.localToScene(square.getLayoutBounds());
+        hoverSquare.setLayoutX(snapPosition(b.getMinX()) - focusedSquare.getWidth() / 2.0 - (hoverSquare.getScaleX() == 1.0 ? 0 : hoverSquare.getWidth() / 4.0));
+        hoverSquare.setLayoutY(snapPosition(b.getMinY()) - focusedSquare.getHeight() / 2.0 + (hoverSquare.getScaleY() == 1.0 ? 0 : focusedSquare.getHeight() / 4.0));
     }
     
     private void buildCustomColors() {
@@ -244,7 +269,7 @@
                 ColorSquare prevSquare = colorPickerGrid.getSquares().get((index != 0) ? 
                                     (index-1) : (NUM_OF_ROWS*NUM_OF_COLUMNS)-1);
                 prevSquare.requestFocus();
-                focusedSquare = prevSquare;
+                setFocusedSquare(prevSquare);
                 return;
             } 
         }
@@ -256,14 +281,13 @@
                 ColorSquare prevSquare = (ColorSquare)customColorGrid.getChildren().get((index != 0) ? 
                                     (index-1) : len-1);
                 prevSquare.requestFocus();
-                focusedSquare = prevSquare;
+                setFocusedSquare(prevSquare);
                 return;
             } 
         }
         if (index == -1) {
             ColorSquare cs = colorPickerGrid.getSquares().get((NUM_OF_ROWS*NUM_OF_COLUMNS)-1);
-            focusedSquare = cs;
-            cs.requestFocus();;
+            setFocusedSquare(cs);
         }
     }
     
@@ -275,7 +299,7 @@
                 ColorSquare prevSquare = colorPickerGrid.getSquares().get((index-12 >= 0)? 
                         (index-12) : ((NUM_OF_ROWS-1)*NUM_OF_COLUMNS)+index);
                 prevSquare.requestFocus();
-                focusedSquare = prevSquare;
+                setFocusedSquare(prevSquare);
                 return;
             } 
         }
@@ -292,14 +316,13 @@
                     prevSquare = (ColorSquare)customColorGrid.getChildren().get((rowIndex*NUM_OF_COLUMNS)+index);
                 }
                 prevSquare.requestFocus();
-                focusedSquare = prevSquare;
+                setFocusedSquare(prevSquare);
                 return;
             }
         }
         if (index == -1) {
             ColorSquare cs = colorPickerGrid.getSquares().get((NUM_OF_ROWS*NUM_OF_COLUMNS)-1);
-            focusedSquare = cs;
-            focusedSquare.requestFocus();
+            setFocusedSquare(cs);
         }
     }
      
@@ -311,7 +334,7 @@
                 ColorSquare prevSquare = colorPickerGrid.getSquares().get(
                         (index != (NUM_OF_ROWS*NUM_OF_COLUMNS)-1) ? (index+1) : 0);
                 prevSquare.requestFocus();
-                focusedSquare = prevSquare;
+                setFocusedSquare(prevSquare);
                 return;
             } 
         }
@@ -323,14 +346,13 @@
                 ColorSquare prevSquare = (ColorSquare)customColorGrid.getChildren().get(
                         (index != len-1) ? (index+1) : 0);
                 prevSquare.requestFocus();
-                focusedSquare = prevSquare;
+                setFocusedSquare(prevSquare);
                 return;
             } 
         }
         if (index == len) {
             ColorSquare cs = colorPickerGrid.getSquares().get(0);
-            focusedSquare = cs;
-            focusedSquare.requestFocus();
+            setFocusedSquare(cs);
         }
     }
     
@@ -342,7 +364,7 @@
                 ColorSquare prevSquare = colorPickerGrid.getSquares().get((index+12 < NUM_OF_ROWS*NUM_OF_COLUMNS)? 
                         (index+12) : index-((NUM_OF_ROWS-1)*NUM_OF_COLUMNS));
                 prevSquare.requestFocus();
-                focusedSquare = prevSquare;
+                setFocusedSquare(prevSquare);
                 return;
             } 
         }
@@ -359,14 +381,13 @@
                     prevSquare = (ColorSquare)customColorGrid.getChildren().get(index-(rowIndex)*NUM_OF_COLUMNS);
                 }
                 prevSquare.requestFocus();
-                focusedSquare = prevSquare;
+                setFocusedSquare(prevSquare);
                 return;
             } 
         }
         if (index == len) {
             ColorSquare cs = colorPickerGrid.getSquares().get(0);
-            focusedSquare = cs;
-            focusedSquare.requestFocus();
+            setFocusedSquare(cs);
         }
     }
     
@@ -377,39 +398,7 @@
     public ColorPickerGrid getColorGrid() {
         return colorPickerGrid;
     }
-//
-//    @Override protected void layoutChildren() {
-//        double x = getInsets().getLeft();
-//        double y = getInsets().getTop();
-////        double popupWidth = cpg.prefWidth(-1) + paddingX+getInsets().getRight();
-////        double popupHeight = cpg.prefHeight(-1) + getInsets().getTop() + getInsets().getBottom();
-//        colorPickerGrid.relocate(x, y);
-//        y = y+colorPickerGrid.prefHeight(-1)+GAP;
-//        if (customColorAdded) {
-//            if (customColorLabel.isVisible()) {
-//                customColorLabel.resizeRelocate(x, y, colorPickerGrid.prefWidth(-1), customColorLabel.prefHeight(y));
-//                y = y+customColorLabel.prefHeight(-1)+LABEL_GAP;
-//            }
-//            customColorGrid.relocate(x, y);
-//            y = y+customColorGrid.prefHeight(-1)+GAP;
-//        }
-//        separator.resizeRelocate(x, y, colorPickerGrid.prefWidth(-1), separator.prefHeight(-1));
-//        y = y+separator.prefHeight(-1)+GAP;
-//        customColorLink.resizeRelocate(x, y, colorPickerGrid.prefWidth(-1), customColorLink.prefHeight(-1));
-//    }
-//
-//    @Override protected double computePrefWidth(double height) {
-//        return getInsets().getLeft() + colorPickerGrid.prefWidth(-1) + getInsets().getRight();
-//    }
-//
-//    @Override protected double computePrefHeight(double width) {
-//        double totalHeight = colorPickerGrid.prefHeight(-1) + GAP +
-//                ((customColorAdded) ?
-//                (customColorGrid.prefHeight(-1)+customColorLabel.prefHeight(-1))+LABEL_GAP+GAP : 0) +
-//                separator.prefHeight(-1) + GAP + customColorLink.prefHeight(-1);
-//        return getInsets().getTop() + totalHeight + getInsets().getBottom();
-//    }
-//
+
     public boolean isCustomColorDialogShowing() {
         if (customColorDialog != null) return customColorDialog.isVisible();
         return false;
@@ -417,45 +406,38 @@
 
     class ColorSquare extends StackPane {
         Rectangle rectangle;
-        boolean isCustom = false;
         boolean isEmpty = false;
+
         public ColorSquare(Color color) {
             this(color, false);
         }
-        public ColorSquare(Color color, boolean value) {
+
+        public ColorSquare(Color color, boolean isCustom) {
             // Add style class to handle selected color square
             getStyleClass().add("color-square");
             setFocusTraversable(true);
-            this.isCustom = value;
+
             rectangle = new Rectangle(SQUARE_SIZE, SQUARE_SIZE);
-            setFocusTraversable(true);
             if (color == null) {
-                rectangle.setFill(Color.WHITE );
+                rectangle.setFill(Color.WHITE);
                 isEmpty = true;
-            }
-            else {
+            } else {
                 rectangle.setFill(color);
             }
-//            setFill(color);
+
             rectangle.setSmooth(false);
-//            Utils.setBlocksMouse(this, true);
-            
             rectangle.setStrokeType(StrokeType.INSIDE);
+
             String tooltipStr = ColorPickerSkin.colorValueToWeb(color);
             Tooltip.install(this, new Tooltip((tooltipStr == null) ? "" : tooltipStr));
           
             rectangle.getStyleClass().add("color-rect");
 
-            addEventHandler(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() {
-                @Override public void handle(MouseEvent event) {
-                    toFront();
-                }
-            });
             addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
                 @Override public void handle(MouseEvent event) {
                     if (!dragDetected && event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 1) {
                         if (!isEmpty) {
-                            Color fill = (Color)rectangle.getFill();
+                            Color fill = (Color) rectangle.getFill();
                             colorPicker.setValue(fill);
                             colorPicker.fireEvent(new ActionEvent());
                             updateSelection(fill);
@@ -468,8 +450,7 @@
                             if (!contextMenu.isShowing()) {
                                 contextMenu.show(ColorSquare.this, Side.RIGHT, 0, 0);
                                 Utils.addMnemonics(contextMenu, ColorSquare.this.getScene(), colorPicker.impl_isShowMnemonics());
-                            }
-                            else {
+                            } else {
                                 contextMenu.hide();
                                 Utils.removeMnemonics(contextMenu, ColorSquare.this.getScene());
                             }
@@ -477,15 +458,14 @@
                     }
                 }
             });
-            focusedProperty().addListener(new ChangeListener<Boolean>() {
-                @Override
-                public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
+            addEventHandler(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() {
+                @Override public void handle(MouseEvent event) {
+                    setFocusedSquare(ColorSquare.this);
                 }
             });
-            addEventHandler(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() {
+            addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() {
                 @Override public void handle(MouseEvent event) {
-                    focusedSquare = ColorSquare.this;
-                    focusedSquare.requestFocus();
+                    setFocusedSquare(null);
                 }
             });
             getChildren().add(rectangle);
@@ -501,39 +481,6 @@
             }
             colorPicker.hide();
         }
-        
-        private ReadOnlyBooleanWrapper selected;
-        protected final void setSelected(boolean value) {
-            selectedPropertyImpl().set(value);
-        }
-        public final boolean isSelected() { return selected == null ? false : selected.get(); }
-
-        public ReadOnlyBooleanProperty selectedProperty() {
-            return selectedPropertyImpl().getReadOnlyProperty();
-        }
-        private ReadOnlyBooleanWrapper selectedPropertyImpl() {
-            if (selected == null) {
-                selected = new ReadOnlyBooleanWrapper() {
-                    @Override protected void invalidated() {
-                        pseudoClassStateChanged(SELECTED_PSEUDOCLASS_STATE, get());
-                    }
-
-                    @Override
-                    public Object getBean() {
-                        return ColorSquare.this;
-                    }
-
-                    @Override
-                    public String getName() {
-                        return "selected";
-                    }
-                };
-            }
-            return selected;
-        }
-        private final PseudoClass SELECTED_PSEUDOCLASS_STATE =
-            PseudoClass.getPseudoClass("selected");
-        
     }
     
     public void clearFocus() {
@@ -542,12 +489,20 @@
 
     // The skin can update selection if colorpicker value changes..
     public void updateSelection(Color color) {
+        setFocusedSquare(null);
+
         for (ColorSquare c : colorPickerGrid.getSquares()) {
-             c.setSelected(c.rectangle.getFill().equals(color));
+            if (c.rectangle.getFill().equals(color)) {
+                setFocusedSquare(c);
+                return;
+            }
         }
         // check custom colors
-        for (ColorSquare cs : customSquares) {
-            cs.setSelected(cs.rectangle.getFill().equals(color));
+        for (ColorSquare c : customSquares) {
+            if (c.rectangle.getFill().equals(color)) {
+                setFocusedSquare(c);
+                return;
+            }
         }
     }
     
@@ -555,7 +510,7 @@
 
         private final List<ColorSquare> squares;
 
-        public ColorPickerGrid(Color initPaint) {
+        public ColorPickerGrid() {
             getStyleClass().add("color-picker-grid");
             setId("ColorCustomizerColorGrid");
             int columnIndex = 0, rowIndex = 0;
@@ -748,7 +703,5 @@
         @Override protected double computePrefHeight(double width) {
             return (SQUARE_SIZE + 1)*10;
         }
-        
     }
-    
 }
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ColorPickerSkin.java	Wed Jan 22 11:29:07 2014 +1300
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ColorPickerSkin.java	Wed Jan 22 14:35:19 2014 +1300
@@ -437,7 +437,7 @@
     @Override protected Node getPopupContent() {
         if (popupContent == null) {
 //            popupContent = new ColorPalette(colorPicker.getValue(), colorPicker);
-            popupContent = new ColorPalette(getSkinnable().getValue(), (ColorPicker)getSkinnable());
+            popupContent = new ColorPalette((ColorPicker)getSkinnable());
             popupContent.setPopupControl(getPopup());
         }
        return popupContent;
--- a/modules/controls/src/main/resources/com/sun/javafx/scene/control/skin/caspian/caspian.css	Wed Jan 22 11:29:07 2014 +1300
+++ b/modules/controls/src/main/resources/com/sun/javafx/scene/control/skin/caspian/caspian.css	Wed Jan 22 14:35:19 2014 +1300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 
  *  
  * This code is free software; you can redistribute it and/or modify it 
@@ -3312,17 +3312,13 @@
     -fx-padding: 0.5;
     -fx-border: black;
 }
+
 /* the color over which the user is hovering */
-.color-palette > .color-picker-grid > .color-square:focused, 
-.color-palette > .color-picker-grid > .color-square:selected:focused {
-    -fx-background-color: -fx-focus-color;
-}
-
-/* the currently selected color */
-.color-palette > .color-picker-grid > .color-square:selected {
-/*    -fx-background-color: derive(-fx-base, -27%)  #989898 , white, derive(-fx-base, -59%)  #555555 ;*/
+.color-palette-region > .color-square.hover-square {
     -fx-background-color: black;
-} 
+    -fx-background-insets: -1;
+    -fx-padding: 1;
+}
 
 .color-palette > .separator > .line {
     -fx-border-color: -fx-text-box-border transparent transparent transparent,
--- a/modules/controls/src/main/resources/com/sun/javafx/scene/control/skin/modena/modena.css	Wed Jan 22 11:29:07 2014 +1300
+++ b/modules/controls/src/main/resources/com/sun/javafx/scene/control/skin/modena/modena.css	Wed Jan 22 14:35:19 2014 +1300
@@ -5,7 +5,7 @@
 */
 
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 
  *  
  * This code is free software; you can redistribute it and/or modify it 
@@ -1938,18 +1938,13 @@
     -fx-padding: 0.5px;
 }
 /* the color over which the user is hovering */
-.color-palette > .color-picker-grid > .color-square:focused, 
-.color-palette > .color-picker-grid > .color-square:selected:focused {
+.color-palette-region > .color-square.hover-square {
     -fx-background-color: -fx-faint-focus-color, -fx-focus-color;
-    -fx-background-insets: -2,0;
+    -fx-background-insets: -3,-1;
     -fx-background-radius: 5,0;
     -fx-scale-x: 1.5;
     -fx-scale-y: 1.5;
 }
-/* the currently selected color */
-.color-palette > .color-picker-grid > .color-square:selected {
-    -fx-background-color: black;
-} 
 /* ------- CUSTOM COLOR DIALOG ------- */
 .custom-color-dialog > .color-rect-pane {
     -fx-spacing: 0.75em;
--- a/modules/controls/src/test/java/com/sun/javafx/scene/control/skin/ColorPickerPaletteRetriever.java	Wed Jan 22 11:29:07 2014 +1300
+++ b/modules/controls/src/test/java/com/sun/javafx/scene/control/skin/ColorPickerPaletteRetriever.java	Wed Jan 22 14:35:19 2014 +1300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@
 
 /**
  *
- * @author paru
  */
 public class ColorPickerPaletteRetriever {
     
@@ -42,9 +41,9 @@
         return (ColorPalette)cpSkin.getPopupContent();
     }
     
-    public static ColorPalette.ColorPickerGrid getColorGrid(ColorPalette colorPalette) {
-        return colorPalette.colorPickerGrid;
-    }
+//    public static ColorPalette.ColorPickerGrid getColorGrid(ColorPalette colorPalette) {
+//        return colorPalette.colorPickerGrid;
+//    }
     
     public static PopupControl getPopup(ColorPicker cp) {
         ColorPickerSkin cpSkin = (ColorPickerSkin)cp.getSkin();