package demos.gui.uicomponents;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXSlider;
import com.jfoenix.controls.JFXSlider.IndicatorPosition;
import com.jfoenix.svg.SVGGlyph;
import com.jfoenix.svg.SVGGlyphLoader;
import io.datafx.controller.ViewController;
import io.datafx.controller.flow.context.FXMLViewFlowContext;
import io.datafx.controller.flow.context.ViewFlowContext;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@ViewController(value = "/fxml/ui/SVGLoader.fxml", title = "Material Design Example")
public class SVGLoaderController {
private static final String FX_BACKGROUND_INSETS_0 = "-fx-background-insets: 0;";
private static final String DEFAULT_OPACITY = "33";
private static final String THUMB = ".thumb";
@FXMLViewFlowContext
private ViewFlowContext context;
@FXML
private StackPane detailsContainer;
@FXML
private JFXButton browseFont;
@FXML
private StackPane iconsContainer;
private JFXButton lastClicked = null;
private final String fileName = "icomoon.svg";
private GlyphDetailViewer glyphDetailViewer;
/**
* init fxml when loaded.
*/
@PostConstruct
public void init() throws Exception {
final Stage stage = (Stage) context.getRegisteredObject("Stage");
glyphDetailViewer = new GlyphDetailViewer();
detailsContainer.getChildren().add(glyphDetailViewer);
ScrollPane scrollableGlyphs = allGlyphs();
scrollableGlyphs.setStyle(FX_BACKGROUND_INSETS_0);
iconsContainer.getChildren().add(scrollableGlyphs);
browseFont.setOnAction((action) -> {
FileChooser fileChooser = new FileChooser();
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("SVG files (*.svg)", "*.svg");
fileChooser.getExtensionFilters().add(extFilter);
File file = fileChooser.showOpenDialog(stage);
if (file != null) {
SVGGlyphLoader.clear();
try {
SVGGlyphLoader.loadGlyphsFont(new FileInputStream(file), file.getName());
ScrollPane newglyphs = allGlyphs();
newglyphs.setStyle(FX_BACKGROUND_INSETS_0);
iconsContainer.getChildren().clear();
iconsContainer.getChildren().add(newglyphs);
} catch (IOException ioExc) {
ioExc.printStackTrace();
}
}
});
}
private ScrollPane allGlyphs() {
List<SVGGlyph> glyphs = SVGGlyphLoader.getAllGlyphsIDs()
.stream()
.map(SVGGlyphLoader::getIcoMoonGlyph)
.collect(Collectors.toList());
glyphs.sort(Comparator.comparing(SVGGlyph::getName));
glyphs.forEach(glyph -> glyph.setSize(16, 16));
List<Button> iconButtons = glyphs.stream().map(this::createIconButton).collect(Collectors.toList());
// important to improve the performance of animation in scroll pane so buttons are treated as images
iconButtons.forEach(button -> button.setCache(true));
iconButtons.get(0).fire();
FlowPane glyphLayout = new FlowPane();
glyphLayout.setHgap(10);
glyphLayout.setVgap(10);
glyphLayout.setPadding(new Insets(10));
glyphLayout.getChildren().setAll(iconButtons);
glyphLayout.setPrefSize(600, 300);
ScrollPane scrollableGlyphs = new ScrollPane(glyphLayout);
scrollableGlyphs.setFitToWidth(true);
return scrollableGlyphs;
}
private Button createIconButton(SVGGlyph glyph) {
JFXButton button = new JFXButton(null, glyph);
button.ripplerFillProperty().bind(glyphDetailViewer.colorPicker.valueProperty());
glyphDetailViewer.colorPicker.valueProperty().addListener((o, oldVal, newVal) -> {
String webColor = "#" + Integer.toHexString(newVal.hashCode()).substring(0, 6).toUpperCase();
BackgroundFill fill = ((Region) glyphDetailViewer.sizeSlider.lookup(THUMB)).getBackground()
.getFills()
.get(0);
((Region) glyphDetailViewer.sizeSlider.lookup(THUMB)).setBackground(new Background(new BackgroundFill(
Color.valueOf(webColor),
fill.getRadii(),
fill.getInsets())));
if (lastClicked != null) {
final String currentColor = glyphDetailViewer.colorPicker.getValue()
.toString()
.substring(0, 8);
final BackgroundFill backgroundFill = new BackgroundFill(Color.valueOf(currentColor + DEFAULT_OPACITY),
null,
null);
lastClicked.setBackground(new Background(backgroundFill));
}
});
button.setOnAction(event -> {
if (lastClicked != null) {
lastClicked.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, null, null)));
}
final String currentColor = glyphDetailViewer.colorPicker.getValue()
.toString()
.substring(0, 8);
button.setBackground(new Background(new BackgroundFill(Color.valueOf(currentColor + DEFAULT_OPACITY),
null,
null)));
lastClicked = button;
viewGlyphDetail(glyph);
});
Tooltip.install(button, new Tooltip(glyph.getName()));
return button;
}
private void viewGlyphDetail(SVGGlyph glyph) {
glyphDetailViewer.setGlyph(SVGGlyphLoader.getIcoMoonGlyph(fileName + "." + glyph.getName()));
}
private static final class GlyphDetailViewer extends VBox {
private static final int MIN_ICON_SIZE = 8;
private static final int DEFAULT_ICON_SIZE = 128;
private static final int MAX_ICON_SIZE = 256;
private final ObjectProperty<SVGGlyph> glyph = new SimpleObjectProperty<>();
private final Label idLabel = new Label();
private final Label nameLabel = new Label();
private final ColorPicker colorPicker = new ColorPicker(Color.BLACK);
private final JFXSlider sizeSlider = new JFXSlider(MIN_ICON_SIZE, MAX_ICON_SIZE, DEFAULT_ICON_SIZE);
private final Label sizeLabel = new Label();
private final StackPane centeredGlyph = new StackPane();
GlyphDetailViewer() {
GridPane details = new GridPane();
details.setHgap(10);
details.setVgap(10);
details.setPadding(new Insets(24));
details.setMinSize(GridPane.USE_PREF_SIZE, GridPane.USE_PREF_SIZE);
Label sizeCalculator = new Label("999");
Group sizingRoot = new Group(sizeCalculator);
new Scene(sizingRoot);
sizingRoot.applyCss();
sizingRoot.layout();
sizeLabel.setMinWidth(25);
sizeLabel.setPrefWidth(sizeCalculator.getWidth());
sizeLabel.setAlignment(Pos.BASELINE_RIGHT);
sizeSlider.setIndicatorPosition(IndicatorPosition.RIGHT);
sizeSlider.getStyleClass().add("svg-slider");
HBox sizeControl = new HBox(5, sizeLabel, sizeSlider);
sizeControl.prefWidthProperty().bind(colorPicker.widthProperty());
details.addRow(0, new Label("Id"), idLabel);
details.addRow(1, new Label("Name"), nameLabel);
details.addRow(2, new Label("Color"), colorPicker);
details.addRow(3, new Label("Size"), sizeControl);
sizeLabel.textProperty().bind(sizeSlider.valueProperty().asString("%.0f"));
VBox.setVgrow(centeredGlyph, Priority.ALWAYS);
StackPane.setMargin(centeredGlyph, new Insets(10));
centeredGlyph.setPrefSize(MAX_ICON_SIZE + 10 * 2, MAX_ICON_SIZE + 10 * 2);
glyphProperty().addListener((observable, oldValue, newValue) -> {
if (oldValue != null) {
oldValue.fillProperty().unbind();
oldValue.prefWidthProperty().unbind();
oldValue.prefHeightProperty().unbind();
}
refreshView();
});
getChildren().setAll(details, centeredGlyph);
this.setMinWidth(300);
}
private void refreshView() {
if (glyph.getValue() == null) {
idLabel.setText("");
nameLabel.setText("");
return;
}
glyph.get().setMinSize(StackPane.USE_PREF_SIZE, StackPane.USE_PREF_SIZE);
glyph.get().setPrefSize(sizeSlider.getValue(), sizeSlider.getValue());
glyph.get().setMaxSize(StackPane.USE_PREF_SIZE, StackPane.USE_PREF_SIZE);
glyph.get().prefWidthProperty().bind(sizeSlider.valueProperty());
glyph.get().prefHeightProperty().bind(sizeSlider.valueProperty());
idLabel.setText(String.format("%04d", glyph.get().getGlyphId()));
nameLabel.setText(glyph.get().getName());
glyph.get().setFill(colorPicker.getValue());
glyph.get().fillProperty().bind(colorPicker.valueProperty());
centeredGlyph.getChildren().setAll(glyph.get());
}
public final SVGGlyph getGlyph() {
return glyph.get();
}
final ObjectProperty<SVGGlyph> glyphProperty() {
return glyph;
}
final void setGlyph(SVGGlyph glyph) {
this.glyph.set(glyph);
}
}
}