org.eclipse.gef4.fx.jface.FXPaintSelectionDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.gef4.fx.jface.FXPaintSelectionDialog.java

Source

/*******************************************************************************
 * Copyright (c) 2015 itemis AG and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Alexander Nyen (itemis AG) - initial API and implementation
 *
 *******************************************************************************/
package org.eclipse.gef4.fx.jface;

import java.util.List;

import org.eclipse.gef4.fx.swt.controls.FXAdvancedLinearGradientPicker;
import org.eclipse.gef4.fx.swt.controls.FXColorPicker;
import org.eclipse.gef4.fx.swt.controls.FXSimpleLinearGradientPicker;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swt.SWTFXUtils;
import javafx.scene.SnapshotParameters;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.scene.paint.ImagePattern;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Paint;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

/**
 * The {@link FXPaintSelectionDialog} is a {@link Dialog} that allows to select
 * a JavaFX {@link Paint}. It provides a simple color picker, a simple gradient
 * picker, and an advanced gradient picker.
 *
 * @author anyssen
 *
 */
public class FXPaintSelectionDialog extends Dialog {

    /**
     * Creates a rectangular {@link Image} to visualize the given {@link Paint}.
     *
     * @param width
     *            The width of the resulting {@link Image}.
     * @param height
     *            The height of the resulting {@link Image}.
     * @param paint
     *            The {@link Paint} to use for filling the {@link Image}.
     * @return The resulting (filled) {@link Image}.
     */
    protected static ImageData createPaintImage(int width, int height, Paint paint) {
        // use JavaFX canvas to render a rectangle with the given paint
        Canvas canvas = new Canvas(width, height);
        GraphicsContext graphicsContext = canvas.getGraphicsContext2D();
        graphicsContext.setFill(paint);
        graphicsContext.fillRect(0, 0, width, height);
        graphicsContext.setStroke(Color.BLACK);
        graphicsContext.strokeRect(0, 0, width, height);
        // handle transparent color separately (we want to differentiate it from
        // transparent fill)
        if (paint instanceof Color && ((Color) paint).getOpacity() == 0) {
            // draw a red line from bottom-left to top-right to indicate a
            // transparent fill color
            graphicsContext.setStroke(Color.RED);
            graphicsContext.strokeLine(0, height - 1, width, 1);
        }
        WritableImage snapshot = canvas.snapshot(new SnapshotParameters(), null);
        return SWTFXUtils.fromFXImage(snapshot, null);
    }

    private Paint paint;

    private String title;
    // store the last selection when switching options
    private Combo optionsCombo;

    private Label imageLabel;
    private Paint lastFillColor = Color.WHITE;

    private FXColorPicker colorPicker;
    private Paint lastSimpleGradient = FXSimpleLinearGradientPicker.createSimpleLinearGradient(Color.WHITE,
            Color.BLACK);

    private FXSimpleLinearGradientPicker simpleGradientPicker;
    private Paint lastAdvancedGradient = FXAdvancedLinearGradientPicker.createAdvancedLinearGradient(Color.WHITE,
            Color.GREY, Color.BLACK);

    // TODO: add support for image pattern

    private FXAdvancedLinearGradientPicker advancedGradientPicker;

    /**
     * Constructs a new {@link FXPaintSelectionDialog}.
     *
     * @param parent
     *            The parent {@link Shell}.
     * @param title
     *            The title for this dialog.
     */
    public FXPaintSelectionDialog(Shell parent, String title) {
        super(parent);
        this.title = title;
    }

    // overriding this methods allows you to set the
    // title of the custom dialog
    @Override
    protected void configureShell(Shell newShell) {
        super.configureShell(newShell);
        newShell.setText(title);
    }

    /**
     * Creates a {@link Composite} that contains the advanced gradient picker.
     *
     * @param parent
     *            The parent {@link Composite}.
     * @return The {@link Composite} that contains the advanced gradient picker.
     */
    protected Control createAdvancedGradientFillControl(Composite parent) {
        advancedGradientPicker = new FXAdvancedLinearGradientPicker(parent, Color.WHITE, Color.GREY, Color.BLACK);
        advancedGradientPicker.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        advancedGradientPicker.advancedLinearGradientProperty().addListener(new ChangeListener<LinearGradient>() {

            @Override
            public void changed(ObservableValue<? extends LinearGradient> observable, LinearGradient oldValue,
                    LinearGradient newValue) {
                setPaint(newValue);
            }
        });
        return advancedGradientPicker;
    }

    /**
     * Creates a {@link Composite} that contains the simple color picker.
     *
     * @param parent
     *            The parent {@link Composite}.
     * @return The {@link Composite} that contains the simple color picker.
     */
    protected Control createColorFillControl(Composite parent) {
        colorPicker = new FXColorPicker(parent, Color.WHITE);
        colorPicker.colorProperty().addListener(new ChangeListener<Color>() {

            @Override
            public void changed(ObservableValue<? extends Color> observable, Color oldValue, Color newValue) {
                setPaint(newValue);
            }
        });
        return colorPicker;
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        Composite container = (Composite) super.createDialogArea(parent);
        container.setBackground(parent.getBackground());
        container.setFont(parent.getFont());
        GridLayout gl = new GridLayout(1, true);
        gl.marginHeight = 0;
        gl.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
        gl.marginTop = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
        container.setLayout(gl);

        Composite labelContainer = new Composite(container, SWT.NONE);
        labelContainer.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
        gl = new GridLayout(2, true);
        gl.marginWidth = 3; // align with combo below
        labelContainer.setLayout(gl);
        Label fillLabel = new Label(labelContainer, SWT.LEFT);
        fillLabel.setBackground(parent.getBackground());
        fillLabel.setFont(parent.getFont());
        fillLabel.setLayoutData(new GridData());
        fillLabel.setText("Fill:");
        imageLabel = new Label(labelContainer, SWT.RIGHT);
        imageLabel.setLayoutData(new GridData(SWT.END, SWT.TOP, true, false));

        Composite optionsContainer = new Composite(container, SWT.NONE);
        optionsContainer.setBackground(parent.getBackground());
        optionsContainer.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
        gl = new GridLayout(1, true);
        gl.marginWidth = 3; // align with combo above
        optionsContainer.setLayout(gl);

        optionsCombo = new Combo(optionsContainer, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER);
        optionsCombo
                .setItems(new String[] { "No Fill", "Color Fill", "Gradient Fill", "Advanced Gradient Fill"/*
                                                                                                           * , "Image Fill"
                                                                                                           */ });
        optionsCombo.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));

        final Composite optionsComposite = new Composite(optionsContainer, SWT.NONE);
        optionsComposite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
        optionsComposite.setBackground(parent.getBackground());
        final StackLayout sl = new StackLayout();

        optionsComposite.setLayout(sl);

        // no fill
        final Control noFillControl = new Composite(optionsComposite, SWT.NONE);
        final Control colorFillControl = createColorFillControl(optionsComposite);
        final Control simpleGradientFillControl = createSimpleGradientFillControl(optionsComposite);
        final Control advancedGradientFillControl = createAdvancedGradientFillControl(optionsComposite);
        // TODO: others

        optionsCombo.addModifyListener(new ModifyListener() {

            @Override
            public void modifyText(ModifyEvent e) {
                // store previous option value
                if (paint != null) {
                    if (paint instanceof Color && !Color.TRANSPARENT.equals(paint)) {
                        lastFillColor = paint;
                    } else if (FXSimpleLinearGradientPicker.isSimpleLinearGradient(paint)) {
                        lastSimpleGradient = paint;
                    } else if (FXAdvancedLinearGradientPicker.isAdvancedLinearGradient(paint)) {
                        lastAdvancedGradient = paint;
                    }
                }
                // set new option value
                switch (optionsCombo.getSelectionIndex()) {
                case 0:
                    sl.topControl = noFillControl;
                    paint = Color.TRANSPARENT;
                    break;
                case 1:
                    sl.topControl = colorFillControl;
                    setPaint(lastFillColor); // restore last fill color
                    colorPicker.setColor((Color) paint);
                    break;
                case 2:
                    sl.topControl = simpleGradientFillControl;
                    setPaint(lastSimpleGradient);
                    simpleGradientPicker.setSimpleLinearGradient((LinearGradient) paint);
                    break;
                case 3:
                    sl.topControl = advancedGradientFillControl;
                    setPaint(lastAdvancedGradient);
                    advancedGradientPicker.setAdvancedGradient((LinearGradient) paint);
                    break;
                default:
                    throw new IllegalArgumentException("Unsupported option");
                }
                updateImageLabel();
                optionsComposite.layout();
            }

        });

        if (Color.TRANSPARENT.equals(paint)) {
            optionsCombo.select(0);
        } else if (paint instanceof Color) {
            optionsCombo.select(1);
        } else if (FXSimpleLinearGradientPicker.isSimpleLinearGradient(paint)) {
            optionsCombo.select(2);
        } else if (FXAdvancedLinearGradientPicker.isAdvancedLinearGradient(paint)) {
            optionsCombo.select(3);
        } else if (paint instanceof ImagePattern) {
            optionsCombo.select(4);
        }
        return container;
    }

    /**
     * Creates a {@link Composite} that contains the simple gradient picker.
     *
     * @param parent
     *            The parent {@link Composite}.
     * @return The {@link Composite} that contains the simple gradient picker.
     */
    protected Control createSimpleGradientFillControl(Composite parent) {
        simpleGradientPicker = new FXSimpleLinearGradientPicker(parent, Color.WHITE, Color.BLACK);
        simpleGradientPicker.simpleLinearGradientProperty().addListener(new ChangeListener<LinearGradient>() {

            @Override
            public void changed(ObservableValue<? extends LinearGradient> observable, LinearGradient oldValue,
                    LinearGradient newValue) {
                setPaint(newValue);
            }
        });
        return simpleGradientPicker;
    }

    /**
     * Returns the currently selected {@link Paint}.
     *
     * @return The currently selected {@link Paint}.
     */
    public Paint getPaint() {
        return paint;
    }

    /**
     * Changes the currently selected {@link Paint} to the given value.
     *
     * @param paint
     *            The new value for the selected {@link Paint}.
     */
    public void setPaint(Paint paint) {
        // initialize history with initial values (if not initialized before)
        if (this.paint == null) {
            if (paint instanceof Color) {
                if (!Color.TRANSPARENT.equals(paint)) {
                    lastFillColor = paint;
                    lastSimpleGradient = FXSimpleLinearGradientPicker.createSimpleLinearGradient(Color.WHITE,
                            (Color) paint);
                    lastAdvancedGradient = FXAdvancedLinearGradientPicker.createAdvancedLinearGradient(Color.WHITE,
                            ((Color) paint).brighter(), ((Color) paint));
                }
            } else if (FXSimpleLinearGradientPicker.isSimpleLinearGradient(paint)) {
                lastSimpleGradient = paint;
                List<Stop> stops = ((LinearGradient) paint).getStops();
                lastFillColor = stops.get(1).getColor();
                lastAdvancedGradient = FXAdvancedLinearGradientPicker.createAdvancedLinearGradient(
                        stops.get(0).getColor(), stops.get(1).getColor().brighter(), stops.get(1).getColor());
            } else if (FXAdvancedLinearGradientPicker.isAdvancedLinearGradient(paint)) {
                lastAdvancedGradient = paint;
                List<Stop> stops = paint instanceof LinearGradient ? ((LinearGradient) paint).getStops()
                        : ((RadialGradient) paint).getStops();
                lastFillColor = stops.get(stops.size() - 1).getColor();
                lastSimpleGradient = FXSimpleLinearGradientPicker.createSimpleLinearGradient(
                        stops.get(0).getColor(), stops.get(stops.size() - 1).getColor());
            }
        }

        // assign new value
        this.paint = paint;

        // update image label to reflect new value
        updateImageLabel();
    }

    /**
     * Re-renders the image that visualizes the currently selected {@link Paint}
     * .
     */
    protected void updateImageLabel() {
        if (optionsCombo != null && imageLabel != null && paint != null) {
            ImageData imageData = createPaintImage(64, optionsCombo.getItemHeight() - 1, paint);
            imageLabel.setImage(new Image(imageLabel.getDisplay(), imageData, imageData.getTransparencyMask()));
        }
    }

}