1 /*
   2  * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene.control.skin;
  27 
  28 import com.sun.javafx.css.StyleManager;
  29 
  30 import com.sun.javafx.scene.control.Properties;
  31 import com.sun.javafx.scene.control.behavior.ComboBoxBaseBehavior;
  32 import com.sun.javafx.scene.control.skin.Utils;
  33 import javafx.beans.property.StringProperty;
  34 import javafx.css.StyleOrigin;
  35 import javafx.css.StyleableBooleanProperty;
  36 import javafx.css.CssMetaData;
  37 
  38 import javafx.css.converter.BooleanConverter;
  39 
  40 import java.util.ArrayList;
  41 import java.util.Collections;
  42 import java.util.List;
  43 
  44 import javafx.css.StyleableDoubleProperty;
  45 import javafx.css.StyleableStringProperty;
  46 import javafx.geometry.Pos;
  47 import javafx.scene.Node;
  48 import javafx.scene.control.Control;
  49 import javafx.scene.image.ImageView;
  50 import javafx.scene.layout.StackPane;
  51 import javafx.scene.shape.Rectangle;
  52 
  53 import javafx.css.converter.SizeConverter;
  54 import javafx.css.converter.StringConverter;
  55 import com.sun.javafx.scene.control.behavior.ColorPickerBehavior;
  56 
  57 import java.util.HashMap;
  58 import java.util.Map;
  59 
  60 import javafx.scene.control.ColorPicker;
  61 import javafx.scene.control.TextField;
  62 import javafx.beans.property.BooleanProperty;
  63 import javafx.beans.value.WritableValue;
  64 import javafx.css.Styleable;
  65 import javafx.css.StyleableProperty;
  66 import javafx.scene.control.Label;
  67 import javafx.scene.paint.Color;
  68 
  69 import static javafx.scene.paint.Color.*;
  70 
  71 /**
  72  * Default skin implementation for the {@link ColorPicker} control.
  73  *
  74  * @see ColorPicker
  75  * @since 9
  76  */
  77 public class ColorPickerSkin extends ComboBoxPopupControl<Color> {
  78 
  79     /***************************************************************************
  80      *                                                                         *
  81      * Private fields                                                          *
  82      *                                                                         *
  83      **************************************************************************/
  84 
  85     private Label displayNode;
  86     private StackPane pickerColorBox;
  87     private Rectangle colorRect;
  88     private ColorPalette popupContent;
  89 
  90     private final ColorPickerBehavior behavior;
  91 
  92 
  93 
  94     /***************************************************************************
  95      *                                                                         *
  96      * Constructors                                                            *
  97      *                                                                         *
  98      **************************************************************************/
  99 
 100     /**
 101      * Creates a new ColorPickerSkin instance, installing the necessary child
 102      * nodes into the Control {@link Control#getChildren() children} list, as
 103      * well as the necessary input mappings for handling key, mouse, etc events.
 104      *
 105      * @param control The control that this skin should be installed onto.
 106      */
 107     public ColorPickerSkin(final ColorPicker control) {
 108         super(control);
 109 
 110         // install default input map for the control
 111         this.behavior = new ColorPickerBehavior(control);
 112 //        control.setInputMap(behavior.getInputMap());
 113 
 114         updateComboBoxMode();
 115         registerChangeListener(control.valueProperty(), e -> updateColor());
 116 
 117         // create displayNode
 118         displayNode = new Label();
 119         displayNode.getStyleClass().add("color-picker-label");
 120         displayNode.setManaged(false);
 121 
 122         // label graphic
 123         pickerColorBox = new PickerColorBox();
 124         pickerColorBox.getStyleClass().add("picker-color");
 125         colorRect = new Rectangle(12, 12);
 126         colorRect.getStyleClass().add("picker-color-rect");
 127 
 128         updateColor();
 129 
 130         pickerColorBox.getChildren().add(colorRect);
 131         displayNode.setGraphic(pickerColorBox);
 132     }
 133 
 134 
 135 
 136     /***************************************************************************
 137      *                                                                         *
 138      * Properties                                                              *
 139      *                                                                         *
 140      **************************************************************************/
 141 
 142     // --- color label visible
 143     BooleanProperty colorLabelVisible = new StyleableBooleanProperty(true) {
 144         @Override public void invalidated() {
 145             if (displayNode != null) {
 146                 if (colorLabelVisible.get()) {
 147                     displayNode.setText(colorDisplayName(((ColorPicker)getSkinnable()).getValue()));
 148                 } else {
 149                     displayNode.setText("");
 150                 }
 151             }
 152         }
 153         @Override public Object getBean() {
 154             return ColorPickerSkin.this;
 155         }
 156         @Override public String getName() {
 157             return "colorLabelVisible";
 158         }
 159         @Override public CssMetaData<ColorPicker,Boolean> getCssMetaData() {
 160             return StyleableProperties.COLOR_LABEL_VISIBLE;
 161         }
 162     };
 163 
 164     // --- image url
 165     private final StringProperty imageUrlProperty() { return imageUrl; }
 166     private final StyleableStringProperty imageUrl = new StyleableStringProperty() {
 167         @Override public void applyStyle(StyleOrigin origin, String v) {
 168             super.applyStyle(origin, v);
 169             if (v == null) {
 170                 // remove old image view
 171                 if (pickerColorBox.getChildren().size() == 2) pickerColorBox.getChildren().remove(1);
 172             } else {
 173                 if (pickerColorBox.getChildren().size() == 2) {
 174                     ImageView imageView = (ImageView)pickerColorBox.getChildren().get(1);
 175                     imageView.setImage(StyleManager.getInstance().getCachedImage(v));
 176                 } else {
 177                     pickerColorBox.getChildren().add(new ImageView(StyleManager.getInstance().getCachedImage(v)));
 178                 }
 179             }
 180         }
 181         @Override public Object getBean() {
 182             return ColorPickerSkin.this;
 183         }
 184         @Override public String getName() {
 185             return "imageUrl";
 186         }
 187         @Override public CssMetaData<ColorPicker,String> getCssMetaData() {
 188             return StyleableProperties.GRAPHIC;
 189         }
 190     };
 191 
 192     // --- color rect width
 193     private final StyleableDoubleProperty colorRectWidth =  new StyleableDoubleProperty(12) {
 194         @Override protected void invalidated() {
 195             if(pickerColorBox!=null) pickerColorBox.requestLayout();
 196         }
 197         @Override public CssMetaData<ColorPicker,Number> getCssMetaData() {
 198             return StyleableProperties.COLOR_RECT_WIDTH;
 199         }
 200         @Override public Object getBean() {
 201             return ColorPickerSkin.this;
 202         }
 203         @Override public String getName() {
 204             return "colorRectWidth";
 205         }
 206     };
 207 
 208     // --- color rect height
 209     private final StyleableDoubleProperty colorRectHeight =  new StyleableDoubleProperty(12) {
 210         @Override protected void invalidated() {
 211             if(pickerColorBox!=null) pickerColorBox.requestLayout();
 212         }
 213         @Override public CssMetaData<ColorPicker,Number> getCssMetaData() {
 214             return StyleableProperties.COLOR_RECT_HEIGHT;
 215         }
 216         @Override public Object getBean() {
 217             return ColorPickerSkin.this;
 218         }
 219         @Override public String getName() {
 220             return "colorRectHeight";
 221         }
 222     };
 223 
 224     // --- color rect X
 225     private final StyleableDoubleProperty colorRectX =  new StyleableDoubleProperty(0) {
 226         @Override protected void invalidated() {
 227             if(pickerColorBox!=null) pickerColorBox.requestLayout();
 228         }
 229         @Override public CssMetaData<ColorPicker,Number> getCssMetaData() {
 230             return StyleableProperties.COLOR_RECT_X;
 231         }
 232         @Override public Object getBean() {
 233             return ColorPickerSkin.this;
 234         }
 235         @Override public String getName() {
 236             return "colorRectX";
 237         }
 238     };
 239 
 240     // --- color rect Y
 241     private final StyleableDoubleProperty colorRectY =  new StyleableDoubleProperty(0) {
 242         @Override protected void invalidated() {
 243             if(pickerColorBox!=null) pickerColorBox.requestLayout();
 244         }
 245         @Override public CssMetaData<ColorPicker,Number> getCssMetaData() {
 246             return StyleableProperties.COLOR_RECT_Y;
 247         }
 248         @Override public Object getBean() {
 249             return ColorPickerSkin.this;
 250         }
 251         @Override public String getName() {
 252             return "colorRectY";
 253         }
 254     };
 255 
 256 
 257 
 258     /***************************************************************************
 259      *                                                                         *
 260      * Public API                                                              *
 261      *                                                                         *
 262      **************************************************************************/
 263 
 264     /** {@inheritDoc} */
 265     @Override public void dispose() {
 266         super.dispose();
 267 
 268         if (behavior != null) {
 269             behavior.dispose();
 270         }
 271     }
 272 
 273     /** {@inheritDoc} */
 274     @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
 275         if (!colorLabelVisible.get()) {
 276             return super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset);
 277         }
 278         String displayNodeText = displayNode.getText();
 279         double width = 0;
 280         for (String name : colorNameMap.values()) {
 281             displayNode.setText(name);
 282             width = Math.max(width, super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset));
 283         }
 284         displayNode.setText(Utils.formatHexString(Color.BLACK)); // #000000
 285         width = Math.max(width, super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset));
 286         displayNode.setText(displayNodeText);
 287         return width;
 288     }
 289 
 290     /** {@inheritDoc} */
 291     @Override protected Node getPopupContent() {
 292         if (popupContent == null) {
 293 //            popupContent = new ColorPalette(colorPicker.getValue(), colorPicker);
 294             popupContent = new ColorPalette((ColorPicker)getSkinnable());
 295             popupContent.setPopupControl(getPopup());
 296         }
 297         return popupContent;
 298     }
 299 
 300     /** {@inheritDoc} */
 301     @Override public void show() {
 302         super.show();
 303         final ColorPicker colorPicker = (ColorPicker)getSkinnable();
 304         popupContent.updateSelection(colorPicker.getValue());
 305     }
 306 
 307     /** {@inheritDoc} */
 308     @Override public Node getDisplayNode() {
 309         return displayNode;
 310     }
 311 
 312     /** {@inheritDoc} */
 313     @Override protected void layoutChildren(final double x, final double y,
 314                                             final double w, final double h) {
 315         updateComboBoxMode();
 316         super.layoutChildren(x, y, w, h);
 317     }
 318 
 319 
 320 
 321     /***************************************************************************
 322      *                                                                         *
 323      * Private implementation                                                  *
 324      *                                                                         *
 325      **************************************************************************/
 326 
 327     /** {@inheritDoc} */
 328     @Override void focusLost() {
 329         // do nothing
 330     }
 331 
 332     /** {@inheritDoc} */
 333     @Override ComboBoxBaseBehavior getBehavior() {
 334         return behavior;
 335     }
 336 
 337     private void updateComboBoxMode() {
 338         List<String> styleClass = getSkinnable().getStyleClass();
 339         if (styleClass.contains(ColorPicker.STYLE_CLASS_BUTTON)) {
 340             setMode(ComboBoxMode.BUTTON);
 341         } else if (styleClass.contains(ColorPicker.STYLE_CLASS_SPLIT_BUTTON)) {
 342             setMode(ComboBoxMode.SPLITBUTTON);
 343         }
 344     }
 345 
 346     private static final Map<Color, String> colorNameMap = new HashMap<>(24);
 347     private static final Map<Color, String> cssNameMap = new HashMap<>(139);
 348     static {
 349         // Translatable display names for the most common colors
 350         colorNameMap.put(TRANSPARENT, Properties.getColorPickerString("colorName.transparent"));
 351         colorNameMap.put(BLACK,       Properties.getColorPickerString("colorName.black"));
 352         colorNameMap.put(BLUE,        Properties.getColorPickerString("colorName.blue"));
 353         colorNameMap.put(CYAN,        Properties.getColorPickerString("colorName.cyan"));
 354         colorNameMap.put(DARKBLUE,    Properties.getColorPickerString("colorName.darkblue"));
 355         colorNameMap.put(DARKCYAN,    Properties.getColorPickerString("colorName.darkcyan"));
 356         colorNameMap.put(DARKGRAY,    Properties.getColorPickerString("colorName.darkgray"));
 357         colorNameMap.put(DARKGREEN,   Properties.getColorPickerString("colorName.darkgreen"));
 358         colorNameMap.put(DARKMAGENTA, Properties.getColorPickerString("colorName.darkmagenta"));
 359         colorNameMap.put(DARKRED,     Properties.getColorPickerString("colorName.darkred"));
 360         colorNameMap.put(GRAY,        Properties.getColorPickerString("colorName.gray"));
 361         colorNameMap.put(GREEN,       Properties.getColorPickerString("colorName.green"));
 362         colorNameMap.put(LIGHTBLUE,   Properties.getColorPickerString("colorName.lightblue"));
 363         colorNameMap.put(LIGHTCYAN,   Properties.getColorPickerString("colorName.lightcyan"));
 364         colorNameMap.put(LIGHTGRAY,   Properties.getColorPickerString("colorName.lightgray"));
 365         colorNameMap.put(LIGHTGREEN,  Properties.getColorPickerString("colorName.lightgreen"));
 366         colorNameMap.put(LIGHTYELLOW, Properties.getColorPickerString("colorName.lightyellow"));
 367         colorNameMap.put(MAGENTA,     Properties.getColorPickerString("colorName.magenta"));
 368         colorNameMap.put(MEDIUMBLUE,  Properties.getColorPickerString("colorName.mediumblue"));
 369         colorNameMap.put(ORANGE,      Properties.getColorPickerString("colorName.orange"));
 370         colorNameMap.put(PINK,        Properties.getColorPickerString("colorName.pink"));
 371         colorNameMap.put(RED,         Properties.getColorPickerString("colorName.red"));
 372         colorNameMap.put(WHITE,       Properties.getColorPickerString("colorName.white"));
 373         colorNameMap.put(YELLOW,      Properties.getColorPickerString("colorName.yellow"));
 374 
 375         // CSS names.
 376         // Note that synonyms (such as "grey") have been removed here,
 377         // since a color can be presented with only one name in this
 378         // skin. If a reverse map is created for parsing names in the
 379         // future, then the synonyms should be included there. For a
 380         // full list of CSS names, see Color.java.
 381         cssNameMap.put(ALICEBLUE,            "aliceblue");
 382         cssNameMap.put(ANTIQUEWHITE,         "antiquewhite");
 383         cssNameMap.put(AQUAMARINE,           "aquamarine");
 384         cssNameMap.put(AZURE,                "azure");
 385         cssNameMap.put(BEIGE,                "beige");
 386         cssNameMap.put(BISQUE,               "bisque");
 387         cssNameMap.put(BLACK,                "black");
 388         cssNameMap.put(BLANCHEDALMOND,       "blanchedalmond");
 389         cssNameMap.put(BLUE,                 "blue");
 390         cssNameMap.put(BLUEVIOLET,           "blueviolet");
 391         cssNameMap.put(BROWN,                "brown");
 392         cssNameMap.put(BURLYWOOD,            "burlywood");
 393         cssNameMap.put(CADETBLUE,            "cadetblue");
 394         cssNameMap.put(CHARTREUSE,           "chartreuse");
 395         cssNameMap.put(CHOCOLATE,            "chocolate");
 396         cssNameMap.put(CORAL,                "coral");
 397         cssNameMap.put(CORNFLOWERBLUE,       "cornflowerblue");
 398         cssNameMap.put(CORNSILK,             "cornsilk");
 399         cssNameMap.put(CRIMSON,              "crimson");
 400         cssNameMap.put(CYAN,                 "cyan");
 401         cssNameMap.put(DARKBLUE,             "darkblue");
 402         cssNameMap.put(DARKCYAN,             "darkcyan");
 403         cssNameMap.put(DARKGOLDENROD,        "darkgoldenrod");
 404         cssNameMap.put(DARKGRAY,             "darkgray");
 405         cssNameMap.put(DARKGREEN,            "darkgreen");
 406         cssNameMap.put(DARKKHAKI,            "darkkhaki");
 407         cssNameMap.put(DARKMAGENTA,          "darkmagenta");
 408         cssNameMap.put(DARKOLIVEGREEN,       "darkolivegreen");
 409         cssNameMap.put(DARKORANGE,           "darkorange");
 410         cssNameMap.put(DARKORCHID,           "darkorchid");
 411         cssNameMap.put(DARKRED,              "darkred");
 412         cssNameMap.put(DARKSALMON,           "darksalmon");
 413         cssNameMap.put(DARKSEAGREEN,         "darkseagreen");
 414         cssNameMap.put(DARKSLATEBLUE,        "darkslateblue");
 415         cssNameMap.put(DARKSLATEGRAY,        "darkslategray");
 416         cssNameMap.put(DARKTURQUOISE,        "darkturquoise");
 417         cssNameMap.put(DARKVIOLET,           "darkviolet");
 418         cssNameMap.put(DEEPPINK,             "deeppink");
 419         cssNameMap.put(DEEPSKYBLUE,          "deepskyblue");
 420         cssNameMap.put(DIMGRAY,              "dimgray");
 421         cssNameMap.put(DODGERBLUE,           "dodgerblue");
 422         cssNameMap.put(FIREBRICK,            "firebrick");
 423         cssNameMap.put(FLORALWHITE,          "floralwhite");
 424         cssNameMap.put(FORESTGREEN,          "forestgreen");
 425         cssNameMap.put(GAINSBORO,            "gainsboro");
 426         cssNameMap.put(GHOSTWHITE,           "ghostwhite");
 427         cssNameMap.put(GOLD,                 "gold");
 428         cssNameMap.put(GOLDENROD,            "goldenrod");
 429         cssNameMap.put(GRAY,                 "gray");
 430         cssNameMap.put(GREEN,                "green");
 431         cssNameMap.put(GREENYELLOW,          "greenyellow");
 432         cssNameMap.put(HONEYDEW,             "honeydew");
 433         cssNameMap.put(HOTPINK,              "hotpink");
 434         cssNameMap.put(INDIANRED,            "indianred");
 435         cssNameMap.put(INDIGO,               "indigo");
 436         cssNameMap.put(IVORY,                "ivory");
 437         cssNameMap.put(KHAKI,                "khaki");
 438         cssNameMap.put(LAVENDER,             "lavender");
 439         cssNameMap.put(LAVENDERBLUSH,        "lavenderblush");
 440         cssNameMap.put(LAWNGREEN,            "lawngreen");
 441         cssNameMap.put(LEMONCHIFFON,         "lemonchiffon");
 442         cssNameMap.put(LIGHTBLUE,            "lightblue");
 443         cssNameMap.put(LIGHTCORAL,           "lightcoral");
 444         cssNameMap.put(LIGHTCYAN,            "lightcyan");
 445         cssNameMap.put(LIGHTGOLDENRODYELLOW, "lightgoldenrodyellow");
 446         cssNameMap.put(LIGHTGRAY,            "lightgray");
 447         cssNameMap.put(LIGHTGREEN,           "lightgreen");
 448         cssNameMap.put(LIGHTPINK,            "lightpink");
 449         cssNameMap.put(LIGHTSALMON,          "lightsalmon");
 450         cssNameMap.put(LIGHTSEAGREEN,        "lightseagreen");
 451         cssNameMap.put(LIGHTSKYBLUE,         "lightskyblue");
 452         cssNameMap.put(LIGHTSLATEGRAY,       "lightslategray");
 453         cssNameMap.put(LIGHTSTEELBLUE,       "lightsteelblue");
 454         cssNameMap.put(LIGHTYELLOW,          "lightyellow");
 455         cssNameMap.put(LIME,                 "lime");
 456         cssNameMap.put(LIMEGREEN,            "limegreen");
 457         cssNameMap.put(LINEN,                "linen");
 458         cssNameMap.put(MAGENTA,              "magenta");
 459         cssNameMap.put(MAROON,               "maroon");
 460         cssNameMap.put(MEDIUMAQUAMARINE,     "mediumaquamarine");
 461         cssNameMap.put(MEDIUMBLUE,           "mediumblue");
 462         cssNameMap.put(MEDIUMORCHID,         "mediumorchid");
 463         cssNameMap.put(MEDIUMPURPLE,         "mediumpurple");
 464         cssNameMap.put(MEDIUMSEAGREEN,       "mediumseagreen");
 465         cssNameMap.put(MEDIUMSLATEBLUE,      "mediumslateblue");
 466         cssNameMap.put(MEDIUMSPRINGGREEN,    "mediumspringgreen");
 467         cssNameMap.put(MEDIUMTURQUOISE,      "mediumturquoise");
 468         cssNameMap.put(MEDIUMVIOLETRED,      "mediumvioletred");
 469         cssNameMap.put(MIDNIGHTBLUE,         "midnightblue");
 470         cssNameMap.put(MINTCREAM,            "mintcream");
 471         cssNameMap.put(MISTYROSE,            "mistyrose");
 472         cssNameMap.put(MOCCASIN,             "moccasin");
 473         cssNameMap.put(NAVAJOWHITE,          "navajowhite");
 474         cssNameMap.put(NAVY,                 "navy");
 475         cssNameMap.put(OLDLACE,              "oldlace");
 476         cssNameMap.put(OLIVE,                "olive");
 477         cssNameMap.put(OLIVEDRAB,            "olivedrab");
 478         cssNameMap.put(ORANGE,               "orange");
 479         cssNameMap.put(ORANGERED,            "orangered");
 480         cssNameMap.put(ORCHID,               "orchid");
 481         cssNameMap.put(PALEGOLDENROD,        "palegoldenrod");
 482         cssNameMap.put(PALEGREEN,            "palegreen");
 483         cssNameMap.put(PALETURQUOISE,        "paleturquoise");
 484         cssNameMap.put(PALEVIOLETRED,        "palevioletred");
 485         cssNameMap.put(PAPAYAWHIP,           "papayawhip");
 486         cssNameMap.put(PEACHPUFF,            "peachpuff");
 487         cssNameMap.put(PERU,                 "peru");
 488         cssNameMap.put(PINK,                 "pink");
 489         cssNameMap.put(PLUM,                 "plum");
 490         cssNameMap.put(POWDERBLUE,           "powderblue");
 491         cssNameMap.put(PURPLE,               "purple");
 492         cssNameMap.put(RED,                  "red");
 493         cssNameMap.put(ROSYBROWN,            "rosybrown");
 494         cssNameMap.put(ROYALBLUE,            "royalblue");
 495         cssNameMap.put(SADDLEBROWN,          "saddlebrown");
 496         cssNameMap.put(SALMON,               "salmon");
 497         cssNameMap.put(SANDYBROWN,           "sandybrown");
 498         cssNameMap.put(SEAGREEN,             "seagreen");
 499         cssNameMap.put(SEASHELL,             "seashell");
 500         cssNameMap.put(SIENNA,               "sienna");
 501         cssNameMap.put(SILVER,               "silver");
 502         cssNameMap.put(SKYBLUE,              "skyblue");
 503         cssNameMap.put(SLATEBLUE,            "slateblue");
 504         cssNameMap.put(SLATEGRAY,            "slategray");
 505         cssNameMap.put(SNOW,                 "snow");
 506         cssNameMap.put(SPRINGGREEN,          "springgreen");
 507         cssNameMap.put(STEELBLUE,            "steelblue");
 508         cssNameMap.put(TAN,                  "tan");
 509         cssNameMap.put(TEAL,                 "teal");
 510         cssNameMap.put(THISTLE,              "thistle");
 511         cssNameMap.put(TOMATO,               "tomato");
 512         cssNameMap.put(TRANSPARENT,          "transparent");
 513         cssNameMap.put(TURQUOISE,            "turquoise");
 514         cssNameMap.put(VIOLET,               "violet");
 515         cssNameMap.put(WHEAT,                "wheat");
 516         cssNameMap.put(WHITE,                "white");
 517         cssNameMap.put(WHITESMOKE,           "whitesmoke");
 518         cssNameMap.put(YELLOW,               "yellow");
 519         cssNameMap.put(YELLOWGREEN,          "yellowgreen");
 520     }
 521 
 522     static String colorDisplayName(Color c) {
 523         if (c != null) {
 524             String displayName = colorNameMap.get(c);
 525             if (displayName == null) {
 526                 displayName = Utils.formatHexString(c);
 527             }
 528             return displayName;
 529         } else {
 530             return null;
 531         }
 532     }
 533 
 534     static String tooltipString(Color c) {
 535         if (c != null) {
 536             String tooltipStr = "";
 537             String displayName = colorNameMap.get(c);
 538             if (displayName != null) {
 539                 tooltipStr += displayName + " ";
 540             }
 541 
 542             tooltipStr += Utils.formatHexString(c);
 543 
 544             String cssName = cssNameMap.get(c);
 545             if (cssName != null) {
 546                 tooltipStr += " (css: " + cssName + ")";
 547             }
 548             return tooltipStr;
 549         } else {
 550             return null;
 551         }
 552     }
 553 
 554     private void updateColor() {
 555         final ColorPicker colorPicker = (ColorPicker)getSkinnable();
 556         colorRect.setFill(colorPicker.getValue());
 557         if (colorLabelVisible.get()) {
 558             displayNode.setText(colorDisplayName(colorPicker.getValue()));
 559         } else {
 560             displayNode.setText("");
 561         }
 562     }
 563 
 564 
 565 
 566     /***************************************************************************
 567     *                                                                         *
 568     *                         picker-color-cell                               *
 569     *                                                                         *
 570     **************************************************************************/
 571 
 572     private class PickerColorBox extends StackPane {
 573         @Override protected void layoutChildren() {
 574             final double top = snappedTopInset();
 575             final double left = snappedLeftInset();
 576             final double width = getWidth();
 577             final double height = getHeight();
 578             final double right = snappedRightInset();
 579             final double bottom = snappedBottomInset();
 580             colorRect.setX(snapPosition(colorRectX.get()));
 581             colorRect.setY(snapPosition(colorRectY.get()));
 582             colorRect.setWidth(snapSize(colorRectWidth.get()));
 583             colorRect.setHeight(snapSize(colorRectHeight.get()));
 584             if (getChildren().size() == 2) {
 585                 final ImageView icon = (ImageView) getChildren().get(1);
 586                 Pos childAlignment = StackPane.getAlignment(icon);
 587                 layoutInArea(icon, left, top,
 588                              width - left - right, height - top - bottom,
 589                              0, getMargin(icon),
 590                              childAlignment != null? childAlignment.getHpos() : getAlignment().getHpos(),
 591                              childAlignment != null? childAlignment.getVpos() : getAlignment().getVpos());
 592                 colorRect.setLayoutX(icon.getLayoutX());
 593                 colorRect.setLayoutY(icon.getLayoutY());
 594             } else {
 595                 Pos childAlignment = StackPane.getAlignment(colorRect);
 596                 layoutInArea(colorRect, left, top,
 597                              width - left - right, height - top - bottom,
 598                              0, getMargin(colorRect),
 599                              childAlignment != null? childAlignment.getHpos() : getAlignment().getHpos(),
 600                              childAlignment != null? childAlignment.getVpos() : getAlignment().getVpos());
 601             }
 602         }
 603     }
 604 
 605     /***************************************************************************
 606     *                                                                         *
 607     *                         Stylesheet Handling                             *
 608     *                                                                         *
 609     **************************************************************************/
 610 
 611      private static class StyleableProperties {
 612         private static final CssMetaData<ColorPicker,Boolean> COLOR_LABEL_VISIBLE =
 613                 new CssMetaData<ColorPicker,Boolean>("-fx-color-label-visible",
 614                 BooleanConverter.getInstance(), Boolean.TRUE) {
 615 
 616             @Override public boolean isSettable(ColorPicker n) {
 617                 final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 618                 return skin.colorLabelVisible == null || !skin.colorLabelVisible.isBound();
 619             }
 620 
 621             @Override public StyleableProperty<Boolean> getStyleableProperty(ColorPicker n) {
 622                 final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 623                 return (StyleableProperty<Boolean>)(WritableValue<Boolean>)skin.colorLabelVisible;
 624             }
 625         };
 626         private static final CssMetaData<ColorPicker,Number> COLOR_RECT_WIDTH =
 627                 new CssMetaData<ColorPicker,Number>("-fx-color-rect-width", SizeConverter.getInstance(), 12d) {
 628                     @Override public boolean isSettable(ColorPicker n) {
 629                         final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 630                         return !skin.colorRectWidth.isBound();
 631                     }
 632                     @Override public StyleableProperty<Number> getStyleableProperty(ColorPicker n) {
 633                         final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 634                         return skin.colorRectWidth;
 635                     }
 636                 };
 637         private static final CssMetaData<ColorPicker,Number> COLOR_RECT_HEIGHT =
 638                 new CssMetaData<ColorPicker,Number>("-fx-color-rect-height", SizeConverter.getInstance(), 12d) {
 639                     @Override public boolean isSettable(ColorPicker n) {
 640                         final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 641                         return !skin.colorRectHeight.isBound();
 642                     }
 643                     @Override public StyleableProperty<Number> getStyleableProperty(ColorPicker n) {
 644                         final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 645                         return skin.colorRectHeight;
 646                     }
 647                 };
 648         private static final CssMetaData<ColorPicker,Number> COLOR_RECT_X =
 649                 new CssMetaData<ColorPicker,Number>("-fx-color-rect-x", SizeConverter.getInstance(), 0) {
 650                     @Override public boolean isSettable(ColorPicker n) {
 651                         final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 652                         return !skin.colorRectX.isBound();
 653                     }
 654                     @Override public StyleableProperty<Number> getStyleableProperty(ColorPicker n) {
 655                         final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 656                         return skin.colorRectX;
 657                     }
 658                 };
 659         private static final CssMetaData<ColorPicker,Number> COLOR_RECT_Y =
 660                 new CssMetaData<ColorPicker,Number>("-fx-color-rect-y", SizeConverter.getInstance(), 0) {
 661                     @Override public boolean isSettable(ColorPicker n) {
 662                         final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 663                         return !skin.colorRectY.isBound();
 664                     }
 665                     @Override public StyleableProperty<Number> getStyleableProperty(ColorPicker n) {
 666                         final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 667                         return skin.colorRectY;
 668                     }
 669                 };
 670         private static final CssMetaData<ColorPicker,String> GRAPHIC =
 671             new CssMetaData<ColorPicker,String>("-fx-graphic", StringConverter.getInstance()) {
 672                 @Override public boolean isSettable(ColorPicker n) {
 673                     final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 674                     return !skin.imageUrl.isBound();
 675                 }
 676                 @Override public StyleableProperty<String> getStyleableProperty(ColorPicker n) {
 677                     final ColorPickerSkin skin = (ColorPickerSkin) n.getSkin();
 678                     return skin.imageUrl;
 679                 }
 680             };
 681         private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
 682         static {
 683             final List<CssMetaData<? extends Styleable, ?>> styleables =
 684                 new ArrayList<CssMetaData<? extends Styleable, ?>>(ComboBoxBaseSkin.getClassCssMetaData());
 685             styleables.add(COLOR_LABEL_VISIBLE);
 686             styleables.add(COLOR_RECT_WIDTH);
 687             styleables.add(COLOR_RECT_HEIGHT);
 688             styleables.add(COLOR_RECT_X);
 689             styleables.add(COLOR_RECT_Y);
 690             styleables.add(GRAPHIC);
 691             STYLEABLES = Collections.unmodifiableList(styleables);
 692         }
 693     }
 694 
 695     /**
 696      * Returns the CssMetaData associated with this class, which may include the
 697      * CssMetaData of its superclasses.
 698      */
 699     public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
 700         return StyleableProperties.STYLEABLES;
 701     }
 702 
 703     /**
 704      * {@inheritDoc}
 705      */
 706     @Override
 707     public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
 708         return getClassCssMetaData();
 709     }
 710 
 711     /** {@inheritDoc} */
 712     @Override protected javafx.util.StringConverter<Color> getConverter() {
 713         return null;
 714     }
 715 
 716     /**
 717      * ColorPicker does not use a main text field, so this method has been
 718      * overridden to return null.
 719      */
 720     @Override protected TextField getEditor() {
 721         return null;
 722     }
 723 }