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 com.sun.javafx.scene.control.skin;
27
28 import javafx.beans.InvalidationListener;
29 import javafx.beans.Observable;
30 import javafx.beans.property.*;
31 import javafx.event.EventHandler;
32 import javafx.scene.Scene;
33 import javafx.scene.control.*;
34 import javafx.scene.input.MouseEvent;
35 import javafx.scene.layout.*;
36 import javafx.scene.paint.*;
37 import javafx.stage.Modality;
38 import javafx.stage.Stage;
39 import javafx.stage.StageStyle;
40 import javafx.stage.Window;
41 import javafx.beans.binding.Bindings;
42 import javafx.beans.binding.ObjectBinding;
43 import javafx.geometry.Insets;
44 import javafx.geometry.Orientation;
45 import javafx.geometry.Pos;
46 import javafx.geometry.Rectangle2D;
47 import javafx.scene.input.KeyEvent;
48 import javafx.stage.Screen;
49 import javafx.stage.WindowEvent;
50
51 import static com.sun.javafx.scene.control.skin.ColorPickerSkin.getString;
52
53 /**
54 *
55 * @author paru
56 */
57 public class CustomColorDialog extends HBox {
58
59 private final Stage dialog = new Stage();
60 private ColorRectPane colorRectPane;
61 private ControlsPane controlsPane;
62
63 private ObjectProperty<Color> currentColorProperty = new SimpleObjectProperty<>(Color.WHITE);
64 private ObjectProperty<Color> customColorProperty = new SimpleObjectProperty<>(Color.TRANSPARENT);
65 private Runnable onSave;
66 private Runnable onUse;
67 private Runnable onCancel;
68
69 private WebColorField webField = null;
70 private Scene customScene;
71
72 public CustomColorDialog(Window owner) {
73 getStyleClass().add("custom-color-dialog");
74 if (owner != null) dialog.initOwner(owner);
75 dialog.setTitle(getString("customColorDialogTitle"));
76 dialog.initModality(Modality.APPLICATION_MODAL);
77 dialog.initStyle(StageStyle.UTILITY);
78 dialog.setResizable(false);
79 colorRectPane = new ColorRectPane();
80 controlsPane = new ControlsPane();
81 setHgrow(controlsPane, Priority.ALWAYS);
82
83 customScene = new Scene(this);
84 final Scene ownerScene = owner.getScene();
85 if (ownerScene != null) {
86 if (ownerScene.getUserAgentStylesheet() != null) {
87 customScene.setUserAgentStylesheet(ownerScene.getUserAgentStylesheet());
88 }
89 customScene.getStylesheets().addAll(ownerScene.getStylesheets());
90 }
91 getChildren().addAll(colorRectPane, controlsPane);
92
93 dialog.setScene(customScene);
94 dialog.addEventHandler(KeyEvent.ANY, keyEventListener);
95 }
96
97 private final EventHandler<KeyEvent> keyEventListener = e -> {
98 switch (e.getCode()) {
99 case ESCAPE :
100 dialog.setScene(null);
101 dialog.close();
102 default:
103 break;
104 }
105 };
106
107 public void setCurrentColor(Color currentColor) {
108 this.currentColorProperty.set(currentColor);
109 }
110
111 Color getCurrentColor() {
112 return currentColorProperty.get();
113 }
114
115 ObjectProperty<Color> customColorProperty() {
116 return customColorProperty;
117 }
118
119 void setCustomColor(Color color) {
120 customColorProperty.set(color);
121 }
122
123 Color getCustomColor() {
124 return customColorProperty.get();
125 }
126
127 public Runnable getOnSave() {
128 return onSave;
129 }
130
131 public void setOnSave(Runnable onSave) {
132 this.onSave = onSave;
133 }
134
135 public Runnable getOnUse() {
136 return onUse;
137 }
138
139 public void setOnUse(Runnable onUse) {
140 this.onUse = onUse;
141 }
142
143 public Runnable getOnCancel() {
144 return onCancel;
145 }
146
147 public void setOnCancel(Runnable onCancel) {
148 this.onCancel = onCancel;
149 }
150
151 public void setOnHidden(EventHandler<WindowEvent> onHidden) {
152 dialog.setOnHidden(onHidden);
153 }
154
155 Stage getDialog() {
156 return dialog;
157 }
158
159 public void show() {
160 if (dialog.getOwner() != null) {
161 // Workaround of RT-29871: Instead of just invoking fixPosition()
162 // here need to use listener that fixes dialog position once both
163 // width and height are determined
164 dialog.widthProperty().addListener(positionAdjuster);
165 dialog.heightProperty().addListener(positionAdjuster);
166 positionAdjuster.invalidated(null);
167 }
168 if (dialog.getScene() == null) dialog.setScene(customScene);
169 colorRectPane.updateValues();
170 dialog.show();
171 }
172
173 private InvalidationListener positionAdjuster = new InvalidationListener() {
174
175 @Override
507 {
508 bind(currentColorProperty);
509 }
510 @Override protected Background computeValue() {
511 return new Background(new BackgroundFill(currentColorProperty.get(), CornerRadii.EMPTY, Insets.EMPTY));
512 }
513 });
514
515 newColorRect = new Region();
516 newColorRect.getStyleClass().add("color-rect");
517 newColorRect.setId("new-color");
518 newColorRect.backgroundProperty().bind(new ObjectBinding<Background>() {
519 {
520 bind(customColorProperty);
521 }
522 @Override protected Background computeValue() {
523 return new Background(new BackgroundFill(customColorProperty.get(), CornerRadii.EMPTY, Insets.EMPTY));
524 }
525 });
526
527 currentColorLabel = new Label(getString("currentColor"));
528 newColorLabel = new Label(getString("newColor"));
529
530 whiteBox = new Region();
531 whiteBox.getStyleClass().add("customcolor-controls-background");
532
533 hsbButton = new ToggleButton(getString("colorType.hsb"));
534 hsbButton.getStyleClass().add("left-pill");
535 rgbButton = new ToggleButton(getString("colorType.rgb"));
536 rgbButton.getStyleClass().add("center-pill");
537 webButton = new ToggleButton(getString("colorType.web"));
538 webButton.getStyleClass().add("right-pill");
539 final ToggleGroup group = new ToggleGroup();
540
541 hBox = new HBox();
542 hBox.setAlignment(Pos.CENTER);
543 hBox.getChildren().addAll(hsbButton, rgbButton, webButton);
544
545 Region spacer1 = new Region();
546 spacer1.setId("spacer1");
547 Region spacer2 = new Region();
548 spacer2.setId("spacer2");
549 Region leftSpacer = new Region();
550 leftSpacer.setId("spacer-side");
551 Region rightSpacer = new Region();
552 rightSpacer.setId("spacer-side");
553 Region bottomSpacer = new Region();
554 bottomSpacer.setId("spacer-bottom");
555
556 currentAndNewColor = new GridPane();
557 currentAndNewColor.getColumnConstraints().addAll(new ColumnConstraints(), new ColumnConstraints());
615 labels[i].visibleProperty().bind(group.selectedToggleProperty().isNotEqualTo(webButton));
616 }
617 if (i < 3) {
618 // sliders and fields shouldn't be visible in Web page
619 sliders[i].visibleProperty().bind(group.selectedToggleProperty().isNotEqualTo(webButton));
620 fields[i].visibleProperty().bind(group.selectedToggleProperty().isNotEqualTo(webButton));
621 units[i].visibleProperty().bind(group.selectedToggleProperty().isEqualTo(hsbButton));
622 }
623 int row = 1 + i;
624 if (i == 3) {
625 // opacity row is shifted one gridPane row down
626 row++;
627 }
628
629 settingsPane.add(labels[i], 1, row);
630 settingsPane.add(sliders[i], 2, row);
631 settingsPane.add(fields[i], 3, row);
632 settingsPane.add(units[i], 4, row);
633 }
634
635 set(3, getString("opacity_colon"), 100, colorRectPane.alpha);
636
637 hsbButton.setToggleGroup(group);
638 rgbButton.setToggleGroup(group);
639 webButton.setToggleGroup(group);
640 group.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
641 if (newValue == null) {
642 group.selectToggle(oldValue);
643 } else {
644 if (newValue == hsbButton) {
645 showHSBSettings();
646 } else if (newValue == rgbButton) {
647 showRGBSettings();
648 } else {
649 showWebSettings();
650 }
651 }
652 });
653 group.selectToggle(hsbButton);
654
655 buttonBox = new HBox();
656 buttonBox.setId("buttons-hbox");
657
658 Button saveButton = new Button(getString("Save"));
659 saveButton.setDefaultButton(true);
660 saveButton.setOnAction(t -> {
661 if (onSave != null) {
662 onSave.run();
663 }
664 dialog.hide();
665 });
666
667 Button useButton = new Button(getString("Use"));
668 useButton.setOnAction(t -> {
669 if (onUse != null) {
670 onUse.run();
671 }
672 dialog.hide();
673 });
674
675 Button cancelButton = new Button(getString("Cancel"));
676 cancelButton.setCancelButton(true);
677 cancelButton.setOnAction(e -> {
678 customColorProperty.set(getCurrentColor());
679 if (onCancel != null) {
680 onCancel.run();
681 }
682 dialog.hide();
683 });
684 buttonBox.getChildren().addAll(saveButton, useButton, cancelButton);
685
686 getChildren().addAll(currentAndNewColor, settingsPane, buttonBox);
687 }
688
689 private void showHSBSettings() {
690 set(0, getString("hue_colon"), 360, colorRectPane.hue);
691 set(1, getString("saturation_colon"), 100, colorRectPane.sat);
692 set(2, getString("brightness_colon"), 100, colorRectPane.bright);
693 }
694
695 private void showRGBSettings() {
696 set(0, getString("red_colon"), 255, colorRectPane.red);
697 set(1, getString("green_colon"), 255, colorRectPane.green);
698 set(2, getString("blue_colon"), 255, colorRectPane.blue);
699 }
700
701 private void showWebSettings() {
702 labels[0].setText(getString("web_colon"));
703 }
704
705 private Property<Number>[] bindedProperties = new Property[4];
706
707 private void set(int row, String caption, int maxValue, Property<Number> prop) {
708 labels[row].setText(caption);
709 if (bindedProperties[row] != null) {
710 sliders[row].valueProperty().unbindBidirectional(bindedProperties[row]);
711 fields[row].valueProperty().unbindBidirectional(bindedProperties[row]);
712 }
713 sliders[row].setMax(maxValue);
714 sliders[row].valueProperty().bindBidirectional(prop);
715 labels[row].setLabelFor(sliders[row]);
716 fields[row].setMaxValue(maxValue);
717 fields[row].valueProperty().bindBidirectional(prop);
718 bindedProperties[row] = prop;
719 }
720 }
721
722 static double clamp(double value) {
|
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 com.sun.javafx.scene.control;
27
28 import com.sun.javafx.scene.control.IntegerField;
29 import com.sun.javafx.scene.control.WebColorField;
30 import com.sun.javafx.scene.control.skin.IntegerFieldSkin;
31 import com.sun.javafx.scene.control.skin.WebColorFieldSkin;
32 import javafx.beans.InvalidationListener;
33 import javafx.beans.Observable;
34 import javafx.beans.property.*;
35 import javafx.event.EventHandler;
36 import javafx.scene.Scene;
37 import javafx.scene.control.*;
38 import javafx.scene.input.MouseEvent;
39 import javafx.scene.layout.*;
40 import javafx.scene.paint.*;
41 import javafx.stage.Modality;
42 import javafx.stage.Stage;
43 import javafx.stage.StageStyle;
44 import javafx.stage.Window;
45 import javafx.beans.binding.Bindings;
46 import javafx.beans.binding.ObjectBinding;
47 import javafx.geometry.Insets;
48 import javafx.geometry.Orientation;
49 import javafx.geometry.Pos;
50 import javafx.geometry.Rectangle2D;
51 import javafx.scene.input.KeyEvent;
52 import javafx.stage.Screen;
53 import javafx.stage.WindowEvent;
54
55 /**
56 *
57 */
58 public class CustomColorDialog extends HBox {
59
60 private final Stage dialog = new Stage();
61 private ColorRectPane colorRectPane;
62 private ControlsPane controlsPane;
63
64 private ObjectProperty<Color> currentColorProperty = new SimpleObjectProperty<>(Color.WHITE);
65 private ObjectProperty<Color> customColorProperty = new SimpleObjectProperty<>(Color.TRANSPARENT);
66 private Runnable onSave;
67 private Runnable onUse;
68 private Runnable onCancel;
69
70 private WebColorField webField = null;
71 private Scene customScene;
72
73 public CustomColorDialog(Window owner) {
74 getStyleClass().add("custom-color-dialog");
75 if (owner != null) dialog.initOwner(owner);
76 dialog.setTitle(Properties.getColorPickerString("customColorDialogTitle"));
77 dialog.initModality(Modality.APPLICATION_MODAL);
78 dialog.initStyle(StageStyle.UTILITY);
79 dialog.setResizable(false);
80 colorRectPane = new ColorRectPane();
81 controlsPane = new ControlsPane();
82 setHgrow(controlsPane, Priority.ALWAYS);
83
84 customScene = new Scene(this);
85 final Scene ownerScene = owner.getScene();
86 if (ownerScene != null) {
87 if (ownerScene.getUserAgentStylesheet() != null) {
88 customScene.setUserAgentStylesheet(ownerScene.getUserAgentStylesheet());
89 }
90 customScene.getStylesheets().addAll(ownerScene.getStylesheets());
91 }
92 getChildren().addAll(colorRectPane, controlsPane);
93
94 dialog.setScene(customScene);
95 dialog.addEventHandler(KeyEvent.ANY, keyEventListener);
96 }
97
98 private final EventHandler<KeyEvent> keyEventListener = e -> {
99 switch (e.getCode()) {
100 case ESCAPE :
101 dialog.setScene(null);
102 dialog.close();
103 default:
104 break;
105 }
106 };
107
108 public void setCurrentColor(Color currentColor) {
109 this.currentColorProperty.set(currentColor);
110 }
111
112 public final Color getCurrentColor() {
113 return currentColorProperty.get();
114 }
115
116 public final ObjectProperty<Color> customColorProperty() {
117 return customColorProperty;
118 }
119
120 public final void setCustomColor(Color color) {
121 customColorProperty.set(color);
122 }
123
124 public final Color getCustomColor() {
125 return customColorProperty.get();
126 }
127
128 public Runnable getOnSave() {
129 return onSave;
130 }
131
132 public void setOnSave(Runnable onSave) {
133 this.onSave = onSave;
134 }
135
136 public Runnable getOnUse() {
137 return onUse;
138 }
139
140 public void setOnUse(Runnable onUse) {
141 this.onUse = onUse;
142 }
143
144 public Runnable getOnCancel() {
145 return onCancel;
146 }
147
148 public void setOnCancel(Runnable onCancel) {
149 this.onCancel = onCancel;
150 }
151
152 public void setOnHidden(EventHandler<WindowEvent> onHidden) {
153 dialog.setOnHidden(onHidden);
154 }
155
156 public Stage getDialog() {
157 return dialog;
158 }
159
160 public void show() {
161 if (dialog.getOwner() != null) {
162 // Workaround of RT-29871: Instead of just invoking fixPosition()
163 // here need to use listener that fixes dialog position once both
164 // width and height are determined
165 dialog.widthProperty().addListener(positionAdjuster);
166 dialog.heightProperty().addListener(positionAdjuster);
167 positionAdjuster.invalidated(null);
168 }
169 if (dialog.getScene() == null) dialog.setScene(customScene);
170 colorRectPane.updateValues();
171 dialog.show();
172 }
173
174 private InvalidationListener positionAdjuster = new InvalidationListener() {
175
176 @Override
508 {
509 bind(currentColorProperty);
510 }
511 @Override protected Background computeValue() {
512 return new Background(new BackgroundFill(currentColorProperty.get(), CornerRadii.EMPTY, Insets.EMPTY));
513 }
514 });
515
516 newColorRect = new Region();
517 newColorRect.getStyleClass().add("color-rect");
518 newColorRect.setId("new-color");
519 newColorRect.backgroundProperty().bind(new ObjectBinding<Background>() {
520 {
521 bind(customColorProperty);
522 }
523 @Override protected Background computeValue() {
524 return new Background(new BackgroundFill(customColorProperty.get(), CornerRadii.EMPTY, Insets.EMPTY));
525 }
526 });
527
528 currentColorLabel = new Label(Properties.getColorPickerString("currentColor"));
529 newColorLabel = new Label(Properties.getColorPickerString("newColor"));
530
531 whiteBox = new Region();
532 whiteBox.getStyleClass().add("customcolor-controls-background");
533
534 hsbButton = new ToggleButton(Properties.getColorPickerString("colorType.hsb"));
535 hsbButton.getStyleClass().add("left-pill");
536 rgbButton = new ToggleButton(Properties.getColorPickerString("colorType.rgb"));
537 rgbButton.getStyleClass().add("center-pill");
538 webButton = new ToggleButton(Properties.getColorPickerString("colorType.web"));
539 webButton.getStyleClass().add("right-pill");
540 final ToggleGroup group = new ToggleGroup();
541
542 hBox = new HBox();
543 hBox.setAlignment(Pos.CENTER);
544 hBox.getChildren().addAll(hsbButton, rgbButton, webButton);
545
546 Region spacer1 = new Region();
547 spacer1.setId("spacer1");
548 Region spacer2 = new Region();
549 spacer2.setId("spacer2");
550 Region leftSpacer = new Region();
551 leftSpacer.setId("spacer-side");
552 Region rightSpacer = new Region();
553 rightSpacer.setId("spacer-side");
554 Region bottomSpacer = new Region();
555 bottomSpacer.setId("spacer-bottom");
556
557 currentAndNewColor = new GridPane();
558 currentAndNewColor.getColumnConstraints().addAll(new ColumnConstraints(), new ColumnConstraints());
616 labels[i].visibleProperty().bind(group.selectedToggleProperty().isNotEqualTo(webButton));
617 }
618 if (i < 3) {
619 // sliders and fields shouldn't be visible in Web page
620 sliders[i].visibleProperty().bind(group.selectedToggleProperty().isNotEqualTo(webButton));
621 fields[i].visibleProperty().bind(group.selectedToggleProperty().isNotEqualTo(webButton));
622 units[i].visibleProperty().bind(group.selectedToggleProperty().isEqualTo(hsbButton));
623 }
624 int row = 1 + i;
625 if (i == 3) {
626 // opacity row is shifted one gridPane row down
627 row++;
628 }
629
630 settingsPane.add(labels[i], 1, row);
631 settingsPane.add(sliders[i], 2, row);
632 settingsPane.add(fields[i], 3, row);
633 settingsPane.add(units[i], 4, row);
634 }
635
636 set(3, Properties.getColorPickerString("opacity_colon"), 100, colorRectPane.alpha);
637
638 hsbButton.setToggleGroup(group);
639 rgbButton.setToggleGroup(group);
640 webButton.setToggleGroup(group);
641 group.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
642 if (newValue == null) {
643 group.selectToggle(oldValue);
644 } else {
645 if (newValue == hsbButton) {
646 showHSBSettings();
647 } else if (newValue == rgbButton) {
648 showRGBSettings();
649 } else {
650 showWebSettings();
651 }
652 }
653 });
654 group.selectToggle(hsbButton);
655
656 buttonBox = new HBox();
657 buttonBox.setId("buttons-hbox");
658
659 Button saveButton = new Button(Properties.getColorPickerString("Save"));
660 saveButton.setDefaultButton(true);
661 saveButton.setOnAction(t -> {
662 if (onSave != null) {
663 onSave.run();
664 }
665 dialog.hide();
666 });
667
668 Button useButton = new Button(Properties.getColorPickerString("Use"));
669 useButton.setOnAction(t -> {
670 if (onUse != null) {
671 onUse.run();
672 }
673 dialog.hide();
674 });
675
676 Button cancelButton = new Button(Properties.getColorPickerString("Cancel"));
677 cancelButton.setCancelButton(true);
678 cancelButton.setOnAction(e -> {
679 customColorProperty.set(getCurrentColor());
680 if (onCancel != null) {
681 onCancel.run();
682 }
683 dialog.hide();
684 });
685 buttonBox.getChildren().addAll(saveButton, useButton, cancelButton);
686
687 getChildren().addAll(currentAndNewColor, settingsPane, buttonBox);
688 }
689
690 private void showHSBSettings() {
691 set(0, Properties.getColorPickerString("hue_colon"), 360, colorRectPane.hue);
692 set(1, Properties.getColorPickerString("saturation_colon"), 100, colorRectPane.sat);
693 set(2, Properties.getColorPickerString("brightness_colon"), 100, colorRectPane.bright);
694 }
695
696 private void showRGBSettings() {
697 set(0, Properties.getColorPickerString("red_colon"), 255, colorRectPane.red);
698 set(1, Properties.getColorPickerString("green_colon"), 255, colorRectPane.green);
699 set(2, Properties.getColorPickerString("blue_colon"), 255, colorRectPane.blue);
700 }
701
702 private void showWebSettings() {
703 labels[0].setText(Properties.getColorPickerString("web_colon"));
704 }
705
706 private Property<Number>[] bindedProperties = new Property[4];
707
708 private void set(int row, String caption, int maxValue, Property<Number> prop) {
709 labels[row].setText(caption);
710 if (bindedProperties[row] != null) {
711 sliders[row].valueProperty().unbindBidirectional(bindedProperties[row]);
712 fields[row].valueProperty().unbindBidirectional(bindedProperties[row]);
713 }
714 sliders[row].setMax(maxValue);
715 sliders[row].valueProperty().bindBidirectional(prop);
716 labels[row].setLabelFor(sliders[row]);
717 fields[row].setMaxValue(maxValue);
718 fields[row].valueProperty().bindBidirectional(prop);
719 bindedProperties[row] = prop;
720 }
721 }
722
723 static double clamp(double value) {
|