Package com.fxexperience.javafx.scene.control.colorpicker

Source Code of com.fxexperience.javafx.scene.control.colorpicker.ColorPickerPopover

package com.fxexperience.javafx.scene.control.colorpicker;

import com.fxexperience.javafx.scene.control.IntegerField;
import com.fxexperience.javafx.scene.control.WebColorField;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.SliderBuilder;
import javafx.scene.effect.DropShadow;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.stage.Popup;

/**
* @author Jasper Potts
*/
class ColorPickerPopover extends Group {
    private static final int PICKER_PADDING = 20;
    private static final int RECT_SIZE = 170;
    private static final int ARROW_SIZE = 10;
    private static final int ARROW_X = 150;
    private static final int PICKER_WIDTH = 220;
    private static final int PICKER_HEIGHT = 262;
    private static final int RADIUS = 8;
   
    private Popup popup = new Popup();
    private boolean changeIsLocal = false;
    private DoubleProperty hue = new SimpleDoubleProperty() {
        @Override protected void invalidated() {
            if (!changeIsLocal) {
                changeIsLocal = true;
                color.set(Color.hsb(hue.get(), clamp(sat.get() / 100), clamp(bright.get() / 100)));
                changeIsLocal = false;
            }
        }
    };
    private DoubleProperty sat = new SimpleDoubleProperty() {
        @Override protected void invalidated() {
            if (!changeIsLocal) {
                changeIsLocal = true;
                color.set(Color.hsb(hue.get(), clamp(sat.get() / 100), clamp(bright.get() / 100)));
                changeIsLocal = false;
            }
        }
    };
    private DoubleProperty bright = new SimpleDoubleProperty() {
        @Override protected void invalidated() {
            if (!changeIsLocal) {
                changeIsLocal = true;
                color.set(Color.hsb(hue.get(), clamp(sat.get() / 100), clamp(bright.get() / 100)));
                changeIsLocal = false;
            }
        }
    };
    private ObjectProperty<Color> color = new SimpleObjectProperty<Color>(Color.RED) {
        @Override protected void invalidated() {
            if (!changeIsLocal) {
                changeIsLocal = true;
                final Color c = get();
                hue.set(c.getHue());
                sat.set(c.getSaturation() * 100);
                bright.set(c.getBrightness() * 100);
                changeIsLocal = false;
            }
        }
    };
    public ObjectProperty<Color> colorProperty() { return color; }
    public Color getColor() { return color.get(); }
    public void setColor(Color newColor) { color.set(newColor); }

   
    public ColorPickerPopover() {
        getStyleClass().add("color-picker-popover");
        popup.setAutoHide(true);
       
        // add this to popup
        popup.getContent().add(this);
           
        // load stylesheet
        getStylesheets().add(ColorPicker.class.getResource("ColorPicker.css").toString());
       
        // create popover path for main shape
        final Path p = new Path();
        p.getElements().addAll(
                new MoveTo(PICKER_PADDING, PICKER_PADDING + ARROW_SIZE + RADIUS),
                new ArcTo(RADIUS, RADIUS, 90, PICKER_PADDING + RADIUS, PICKER_PADDING + ARROW_SIZE, false, true),
                new LineTo(PICKER_PADDING + ARROW_X - (ARROW_SIZE * 0.8), PICKER_PADDING + ARROW_SIZE),
                new LineTo(PICKER_PADDING + ARROW_X, PICKER_PADDING),
                new LineTo(PICKER_PADDING + ARROW_X + (ARROW_SIZE * 0.8), PICKER_PADDING + ARROW_SIZE),
                new LineTo(PICKER_PADDING + PICKER_WIDTH - RADIUS, PICKER_PADDING + ARROW_SIZE),
                new ArcTo(RADIUS, RADIUS, 90, PICKER_PADDING + PICKER_WIDTH, PICKER_PADDING + ARROW_SIZE + RADIUS, false, true),
                new LineTo(PICKER_PADDING + PICKER_WIDTH, PICKER_PADDING + ARROW_SIZE + PICKER_HEIGHT - RADIUS),
                new ArcTo(RADIUS, RADIUS, 90, PICKER_PADDING + PICKER_WIDTH - RADIUS, PICKER_PADDING + ARROW_SIZE + PICKER_HEIGHT, false, true),
                new LineTo(PICKER_PADDING + RADIUS, PICKER_PADDING + ARROW_SIZE + PICKER_HEIGHT),
                new ArcTo(RADIUS, RADIUS, 90, PICKER_PADDING, PICKER_PADDING + ARROW_SIZE + PICKER_HEIGHT - RADIUS, false, true),
                new ClosePath());
        p.setFill(new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, new Stop(0, Color.web("#313131")), new Stop(0.5, Color.web("#5f5f5f")), new Stop(1, Color.web("#313131"))));
        p.setStroke(null);
        p.setEffect(new DropShadow(15, 0, 1, Color.gray(0, 0.6)));
        p.setCache(true);
               
        // create rectangle to capture mouse events to hide
        Rectangle windowClickRect = RectangleBuilder.create()
            .width(PICKER_PADDING + PICKER_WIDTH + PICKER_PADDING)
            .height(PICKER_PADDING + PICKER_HEIGHT+ PICKER_PADDING)
            .fill(Color.TRANSPARENT)
            .onMouseClicked(new EventHandler<MouseEvent>() {
                @Override public void handle(MouseEvent event) {
                    System.out.println("x= "+event.getX());
                    System.out.println("p.contains(event.getX(), event.getY()) = " + p.contains(event.getX(), event.getY()));
                    if (!p.contains(event.getX(), event.getY())) {
                        hide();
                    }
                }
            })
            .build();
       
        final Circle colorRectIndicator = CircleBuilder.create().centerX(60).centerY(60).radius(5).stroke(Color.WHITE).fill(null).effect(new DropShadow(2, 0, 1, Color.BLACK)).build();
       
        colorRectIndicator.centerXProperty().bind(new DoubleBinding() {
            { bind(sat); }
            @Override protected double computeValue() {
                return (PICKER_PADDING + 10) + (RECT_SIZE * (sat.get() / 100));
            }
        });
       
        colorRectIndicator.centerYProperty().bind(new DoubleBinding() {
            { bind(bright); }
            @Override protected double computeValue() {
                return (PICKER_PADDING + ARROW_SIZE + 10) + (RECT_SIZE * (1 - (bright.get() / 100)));
            }
        });
       
        final Rectangle colorRect = RectangleBuilder.create()
                .x(PICKER_PADDING + 10)
                .y(PICKER_PADDING + ARROW_SIZE + 10)
                .width(RECT_SIZE)
                .height(RECT_SIZE)
                .build();
        colorRect.fillProperty().bind(new ObjectBinding<Paint>() {
            { bind(color); }
            @Override protected Paint computeValue() {
                return Color.hsb(hue.getValue(), 1, 1);
            }
        });
       
        Rectangle colorRectOverlayOne = RectangleBuilder.create()
                .x(PICKER_PADDING + 10)
                .y(PICKER_PADDING + ARROW_SIZE + 10)
                .width(RECT_SIZE)
                .height(RECT_SIZE)
                .fill(new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, new Stop(0, Color.rgb(255, 255, 255, 1)), new Stop(1, Color.rgb(255, 255, 255, 0)))).build();
       
        EventHandler<MouseEvent> rectMouseHandler = new EventHandler<MouseEvent>() {
            @Override public void handle(MouseEvent event) {
                final double x = event.getX() - colorRect.getX();
                final double y = event.getY() - colorRect.getY();
                sat.set(clamp(x / RECT_SIZE) * 100);
                bright.set(100 - (clamp(y / RECT_SIZE) * 100));
            }
        };
       
        Rectangle colorRectOverlayTwo = RectangleBuilder.create()
                .x(PICKER_PADDING + 10)
                .y(PICKER_PADDING + ARROW_SIZE + 10)
                .width(RECT_SIZE)
                .height(RECT_SIZE)
                .fill(new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, new Stop(0, Color.rgb(0, 0, 0, 0)), new Stop(1, Color.rgb(0, 0, 0, 1))))
                .onMouseDragged(rectMouseHandler)
                .onMouseClicked(rectMouseHandler)
                .build();
        final Rectangle colorBar = RectangleBuilder.create()
                .x(PICKER_PADDING + PICKER_WIDTH - 30)
                .y(PICKER_PADDING + ARROW_SIZE + 10)
                .width(20)
                .height(RECT_SIZE)
                .fill(createHueGradient())
                .build();
        final Rectangle colorBarIndicator = RectangleBuilder.create()
                .x(PICKER_PADDING + PICKER_WIDTH - 32)
                .y(PICKER_PADDING + ARROW_SIZE + 15)
                .width(24)
                .height(10)
                .arcWidth(4)
                .arcHeight(4)
                .stroke(Color.WHITE)
                .fill(null)
                .effect(new DropShadow(2, 0, 1, Color.BLACK))
                .build();
       
        colorBarIndicator.yProperty().bind(new DoubleBinding() {
            { bind(hue); }
            @Override protected double computeValue() {
                return (PICKER_PADDING + ARROW_SIZE + 5) + (RECT_SIZE * (hue.get() / 360));
            }
        });
        EventHandler<MouseEvent> barMouseHandler = new EventHandler<MouseEvent>() {
            @Override public void handle(MouseEvent event) {
                final double y = event.getY() - colorBar.getY();
                hue.set(clamp(y / RECT_SIZE) * 360);
            }
        };
        colorBar.setOnMouseDragged(barMouseHandler);
        colorBar.setOnMouseClicked(barMouseHandler);
       
        Label brightnessLabel = new Label("Brightness:");
        brightnessLabel.setMinWidth(Control.USE_PREF_SIZE);
        GridPane.setConstraints(brightnessLabel, 0, 0);
       
        Slider brightnessSlider = SliderBuilder.create().min(0).max(100).id("BrightnessSlider").build();
        brightnessSlider.valueProperty().bindBidirectional(bright);
        GridPane.setConstraints(brightnessSlider, 1, 0);
       
        IntegerField brightnessField = new IntegerField();
        brightnessField.valueProperty().bindBidirectional(bright);
        brightnessField.setPrefColumnCount(7);
        GridPane.setConstraints(brightnessField, 2, 0);
       
        Label saturationLabel = new Label("Saturation:");
        saturationLabel.setMinWidth(Control.USE_PREF_SIZE);
        GridPane.setConstraints(saturationLabel, 0, 1);
       
        Slider saturationSlider = SliderBuilder.create().min(0).max(100).id("SaturationSlider").build();
        saturationSlider.valueProperty().bindBidirectional(sat);
        GridPane.setConstraints(saturationSlider, 1, 1);
       
        saturationSlider.styleProperty().bind(new StringBinding() {
            { bind(color); }
            @Override protected String computeValue() {
                return "picker-color: hsb("+hue.get()+",100%,100%);";
            }
        });
       
        IntegerField saturationField = new IntegerField();
        saturationField.valueProperty().bindBidirectional(sat);
        saturationField.setPrefColumnCount(7);
        GridPane.setConstraints(saturationField, 2, 1);
       
        Label webLabel = new Label("Web:");
        webLabel.setMinWidth(Control.USE_PREF_SIZE);
        GridPane.setConstraints(webLabel, 0, 2);
       
        WebColorField webField = new WebColorField();
        webField.valueProperty().bindBidirectional(color);
        GridPane.setConstraints(webField, 1, 2, 2, 1);
       
        GridPane controls = new GridPane();
        controls.setVgap(5);
        controls.setHgap(5);
        controls.getChildren().addAll(brightnessLabel, brightnessSlider, brightnessField, saturationLabel, saturationSlider, saturationField, webLabel, webField);
        controls.setManaged(false);
        controls.resizeRelocate(
                PICKER_PADDING + 10,
                PICKER_PADDING + ARROW_SIZE + 10 + 170 + 10,
                PICKER_WIDTH - 20,
                controls.getPrefHeight());
       
        getChildren().addAll(windowClickRect, p, colorRect, colorRectOverlayOne, colorRectOverlayTwo, colorBar, colorRectIndicator, colorBarIndicator, controls);
    }
   
    public void show(Control ownerControl) {
        Point2D point = ownerControl.localToScene(ownerControl.getWidth()/2,ownerControl.getHeight());
        double x = point.getX() + ownerControl.getScene().getX() + ownerControl.getScene().getWindow().getX();
        double y = point.getY() + ownerControl.getScene().getY() + ownerControl.getScene().getWindow().getY();
        ColorPickerPopover colorPickerPopover = new ColorPickerPopover();
        popup.show(ownerControl, x-getPopoverPointX(), y-getPopoverPointY());
    }
   
    public void hide() {
        popup.hide();
    }
   
    public boolean isShowing() {
        return popup.isShowing();
    }
   
    private static double getPopoverPointX() {
        return PICKER_PADDING+ARROW_X;
    }
   
    private static double getPopoverPointY() {
        return PICKER_PADDING;
    }
   
    private static double clamp(double value) {
        return value < 0 ? 0 : value > 1 ? 1 : value;
    }
   
    private static LinearGradient createHueGradient() {
        double offset;
        Stop[] stops = new Stop[255];
        for (int y = 0; y < 255; y++) {
            offset = (double)(1 - (1.0 / 255) * y);
            int h = (int)((y / 255.0) * 360);
            stops[y] = new Stop(offset, Color.hsb(h, 1.0, 1.0));
        }
        return new LinearGradient(0f, 1f, 1f, 0f, true, CycleMethod.NO_CYCLE, stops);
    }
}
TOP

Related Classes of com.fxexperience.javafx.scene.control.colorpicker.ColorPickerPopover

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.