Java color gradient generator
--------------- Gradient.java ------------------ import java.util.*; import javafx.application.*; import javafx.stage.*; import javafx.scene.*; import javafx.scene.layout.*; import javafx.scene.paint.*; import javafx.scene.canvas.*; import javafx.scene.shape.*; import javafx.scene.control.*; import javafx.scene.input.*; import javafx.geometry.*; import javafx.scene.image.*; public class Gradient extends Application { double lastX; List<Stop> stopsList = new ArrayList<>(); List<Pane> slidersList = new ArrayList<>(); double barWidth = 200, sliderWidth = 20, patternSize = 10; Pane bar; LinearGradient linearGradient; ImagePattern patternTransparent; Button addButton, delButton; ColorPicker colorPicker; int select; @Override public void start(Stage stage) { stopsList.add(new Stop(0.2, Color.BLUE)); stopsList.add(new Stop(0.4, Color.RED)); stopsList.add(new Stop(0.6, Color.BLACK)); stopsList.add(new Stop(0.8, Color.TRANSPARENT)); stage.setScene(new Scene(gradientEdPane(), 350, 250)); stage.setOnCloseRequest(event -> { System.out.println(stopsList.toString()); }); stage.show(); } Pane gradientEdPane() { Pane gradientPane = new Pane(); gradientPane.setPrefSize(barWidth + sliderWidth, sliderWidth * 3.25 + 2); gradientPane.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); gradientPane.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); patternTransparent = patternTransparent(); bar = new Pane(new Rectangle(barWidth, sliderWidth * 2, patternTransparent), new Rectangle(barWidth, sliderWidth * 2)); bar.relocate(sliderWidth / 2, 0); ((Rectangle)bar.getChildren().get(1)).setStrokeType(StrokeType.OUTSIDE); ((Rectangle)bar.getChildren().get(1)).setStrokeWidth(1); ((Rectangle)bar.getChildren().get(1)).setStroke(Color.BLACK); colorPicker = new ColorPicker(); colorPicker.setOnAction((ae) -> { stopsList.set(select, new Stop(stopsList.get(select).getOffset(), colorPicker.getValue())); ((Polygon)slidersList.get(select).getChildren().get(1)).setFill(colorPicker.getValue()); repaintGradient(); }); gradientPane.getChildren().add(bar); stopsList.forEach((stop) -> { gradientPane.getChildren().add(createSlider(stop)); }); addButton = new Button("+"); addButton.setPrefWidth(30); addButton.setOnAction((event) -> { for (int i = 0; i < stopsList.size(); i++) { double offset = stopsList.get(i).getOffset() * (1 - (sliderWidth + 4) / barWidth); slidersList.get(i).setLayoutX(barWidth * offset); stopsList.set(i, new Stop(offset , stopsList.get(i).getColor())); } Stop stop = new Stop(1, select >= 0 ? stopsList.get(select).getColor() : Color.TRANSPARENT); stopsList.add(stop); gradientPane.getChildren().add(createSlider(stop)); setDisableButtons(); selectSlider(slidersList.size() - 1); repaintGradient(); }); delButton = new Button("-"); delButton.setPrefWidth(30); delButton.setOnAction((event) -> { assert select >= 0; double offset = stopsList.get(select).getOffset(); gradientPane.getChildren().remove(slidersList.get(select)); stopsList.remove(select); slidersList.remove(select); setDisableButtons(); select = -1; int il = -1, ir = -1; for (int i = 0; i < stopsList.size(); i++) { double off = stopsList.get(i).getOffset(); if (off < offset) { if(il < 0 || off > stopsList.get(il).getOffset()) il = i; } else { if(ir < 0 || off < stopsList.get(ir).getOffset()) ir = i; } } if (il >= 0) selectSlider(il); else if (ir >= 0) selectSlider(ir); repaintGradient(); }); setDisableButtons(); select = -1; if (stopsList.size() > 0) { int m = -1; for (int i = 0; i < stopsList.size(); i++) if(m < 0 || stopsList.get(i).getOffset() < stopsList.get(m).getOffset()) m = i; selectSlider(m); } repaintGradient(); HBox buttonPane = new HBox(6); buttonPane.setPadding(new Insets(16, sliderWidth / 2, 0, sliderWidth / 2)); buttonPane.getChildren().addAll(colorPicker, addButton, delButton); GridPane gradientEdPane = new GridPane(); gradientEdPane.add(gradientPane, 0, 0); gradientEdPane.add(buttonPane, 0, 1); gradientEdPane.setAlignment(Pos.CENTER); return gradientEdPane; } double[] points = { sliderWidth / 2.0, 0.0, sliderWidth, sliderWidth / 2.0, sliderWidth, sliderWidth * 1.25, 0.0, sliderWidth * 1.25, 0.0, sliderWidth / 2.0, }; Pane createSlider(Stop stop) { Pane slider = new Pane(new Polygon(points), new Polygon(points)); slidersList.add(slider); slider.setLayoutX(barWidth * stop.getOffset()); slider.setLayoutY(sliderWidth * 2 + 2); ((Polygon)slider.getChildren().get(0)).setFill(patternTransparent); ((Polygon)slider.getChildren().get(1)).setFill(stop.getColor()); ((Polygon)slider.getChildren().get(1)).setStrokeType(StrokeType.OUTSIDE); ((Polygon)slider.getChildren().get(1)).setStrokeWidth(1); ((Polygon)slider.getChildren().get(1)).setStroke(Color.BLACK); slider.setOnMousePressed(me -> { lastX = me.getX(); selectSlider(slidersList.indexOf(me.getSource())); }); slider.setOnMouseDragged(me -> { double layoutX = slider.getLayoutX() + me.getX() - lastX; double offset = layoutX / barWidth; offset = offset < 0 ? 0 : offset > 1 ? 1 : offset; int ind = slidersList.indexOf(me.getSource()); if (Double.compare(offset, stopsList.get(ind).getOffset()) != 0) { slider.setLayoutX(barWidth * offset); stopsList.set(ind, new Stop(offset, stopsList.get(ind).getColor())); repaintGradient(); } }); return slider; } void setDisableButtons() { if (stopsList.size() == 0) { if(!delButton.isDisable()) { delButton.setDisable(true); colorPicker.setValue(Color.TRANSPARENT); colorPicker.setDisable(true); } } else if (delButton.isDisable()) { delButton.setDisable(false); colorPicker.setDisable(false); } } void repaintGradient() { linearGradient = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stopsList); ((Rectangle)bar.getChildren().get(1)).setFill(linearGradient); } void selectSlider(int newSelect) { if (newSelect != select) { if (select >= 0) { ((Polygon)slidersList.get(select).getChildren().get(1)).setStrokeWidth(1); ((Polygon)slidersList.get(select).getChildren().get(1)).setStroke(Color.BLACK); } assert newSelect >= 0; ((Polygon)slidersList.get(newSelect).getChildren().get(1)).setStrokeWidth(2); ((Polygon)slidersList.get(newSelect).getChildren().get(1)).setStroke(Color.DODGERBLUE); colorPicker.setValue(stopsList.get(newSelect).getColor()); slidersList.get(newSelect).toFront(); select = newSelect; } } ImagePattern patternTransparent() { Canvas canvas = new Canvas(patternSize, patternSize); GraphicsContext gc = canvas.getGraphicsContext2D(); gc.setFill(Color.WHITE); gc.fillRect(0, 0, patternSize, patternSize); gc.setFill(Color.rgb(205, 205, 205)); gc.fillRect(0, 0, patternSize / 2, patternSize / 2); gc.fillRect(patternSize / 2, patternSize / 2, patternSize, patternSize); WritableImage image = canvas.snapshot(new SnapshotParameters(), null); return new ImagePattern(image, 0, 0, patternSize, patternSize, false); } }