/******************************************************************************* * Copyright (c) 2015, 2016 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 Nyßen (itemis AG) - initial API and implementation * *******************************************************************************/ package org.eclipse.gef.fx.jface; import java.util.List; import org.eclipse.gef.fx.swt.controls.FXAdvancedLinearGradientPicker; import org.eclipse.gef.fx.swt.controls.FXColorPicker; import org.eclipse.gef.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.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 { 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 = FXPaintUtils.getPaintImageData(64, optionsCombo.getItemHeight() - 1, paint); imageLabel.setImage(new Image(imageLabel.getDisplay(), imageData, imageData.getTransparencyMask())); } } }