/*
* This file is part of LaTeXDraw.
* Copyright (c) 2005-2017 Arnaud BLOUIN
* LaTeXDraw is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
* LaTeXDraw is distributed without any warranty; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package net.sf.latexdraw.instruments;
import com.google.inject.Inject;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.util.StringConverter;
import net.sf.latexdraw.actions.ModifyPencilParameter;
import net.sf.latexdraw.actions.shape.ModifyShapeProperty;
import net.sf.latexdraw.actions.shape.ShapeProperties;
import net.sf.latexdraw.models.ShapeFactory;
import net.sf.latexdraw.models.interfaces.shape.IDrawing;
import net.sf.latexdraw.models.interfaces.shape.IGroup;
import net.sf.latexdraw.view.jfx.Canvas;
import org.malai.action.Action;
import org.malai.javafx.binding.CheckboxBinding;
import org.malai.javafx.binding.ColorPickerBinding;
import org.malai.javafx.binding.ComboBoxBinding;
import org.malai.javafx.binding.SpinnerBinding;
import org.malai.javafx.instrument.JfxInstrument;
import org.malai.undo.Undoable;
/**
* This abstract instrument defines the base definition of instruments that customise shape properties.
* @author Arnaud BLOUIN
*/
public abstract class ShapePropertyCustomiser extends JfxInstrument {
/** The Hand instrument. */
@Inject protected Hand hand;
/** The Pencil instrument. */
@Inject protected Pencil pencil;
@Inject protected Canvas canvas;
@Inject protected IDrawing drawing;
/**
* Creates the instrument.
*/
ShapePropertyCustomiser() {
super();
}
static <T extends Number> void scrollOnSpinner(final Spinner<T> spinner) {
spinner.setOnScroll(event -> {
if(event.getDeltaY() < 0d) {
spinner.decrement();
}else if(event.getDeltaY() > 0d) {
spinner.increment();
}
});
// Workaround to avoid NPE when setting no value in a spinner.
// Fixed in Java 9
spinner.getEditor().setOnAction(action -> {
final SpinnerValueFactory<T> factory = spinner.getValueFactory();
if(factory != null) {
final StringConverter<T> converter = factory.getConverter();
if(converter != null) {
final T value = converter.fromString(spinner.getEditor().getText());
if(value == null) {
spinner.getEditor().setText(converter.toString(factory.getValue()));
}else {
factory.setValue(value);
}
}
}
action.consume();
});
}
@Override
public void onActionDone(final Action action) {
update();
}
@Override
public void onUndoableUndo(final Undoable undoable) {
update();
}
@Override
public void onUndoableRedo(final Undoable undoable) {
update();
}
/**
* Updates the instrument and its widgets
* @since 3.0
*/
public void update() {
if(pencil.isActivated()) {
update(ShapeFactory.INST.createGroup(pencil.createShapeInstance()));
}
else {
update(drawing.getSelection());
}
}
/**
* Updates the widgets using the given shape.
* @param shape The shape used to update the widgets. If null, nothing is performed.
* @since 3.0
*/
protected abstract void update(final IGroup shape);
/**
* Sets the widgets of the instrument visible or not.
* @param visible True: they are visible.
* @since 3.0
*/
protected abstract void setWidgetsVisible(final boolean visible);
@Override
public void setActivated(final boolean act) {
super.setActivated(act);
setWidgetsVisible(act);
}
static class List4Pencil extends ComboBoxBinding<ModifyPencilParameter, ShapePropertyCustomiser> {
ShapeProperties prop;
List4Pencil(final ShapePropertyCustomiser ins, final ComboBox<?> combo, ShapeProperties property) throws InstantiationException, IllegalAccessException {
super(ins, ModifyPencilParameter.class, combo);
prop = property;
}
@Override
public void initAction() {
action.setPencil(instrument.pencil);
action.setProperty(prop);
action.setValue(interaction.getWidget().getSelectionModel().getSelectedItem());
}
@Override
public boolean isConditionRespected() {
return instrument.pencil.isActivated();
}
}
static class List4Selection extends ComboBoxBinding<ModifyShapeProperty, ShapePropertyCustomiser> {
ShapeProperties prop;
List4Selection(final ShapePropertyCustomiser ins, final ComboBox<?> combo, ShapeProperties property) throws InstantiationException, IllegalAccessException {
super(ins, ModifyShapeProperty.class, combo);
prop = property;
}
@Override
public void initAction() {
action.setGroup(instrument.canvas.getDrawing().getSelection().duplicateDeep(false));
action.setProperty(prop);
action.setValue(interaction.getWidget().getSelectionModel().getSelectedItem());
}
@Override
public boolean isConditionRespected() {
return instrument.hand.isActivated();
}
}
static class Spinner4Pencil extends SpinnerBinding<ModifyPencilParameter, ShapePropertyCustomiser> {
ShapeProperties prop;
boolean angle;
Spinner4Pencil(final ShapePropertyCustomiser ins, final Spinner<?> widget, ShapeProperties property, boolean isAngle) throws InstantiationException, IllegalAccessException {
super(ins, true, ModifyPencilParameter.class, widget);
prop = property;
angle = isAngle;
}
@Override
public void initAction() {
action.setProperty(prop);
action.setPencil(instrument.pencil);
if(angle) {
action.setValue(Math.toRadians((Double) interaction.getWidget().getValue()));
}
else {
action.setValue(interaction.getWidget().getValue());
}
}
@Override
public void updateAction() {
action.setValue(Math.toRadians((Double) interaction.getWidget().getValue()));
}
@Override
public boolean isConditionRespected() {
return instrument.pencil.isActivated();
}
}
static class Spinner4Selection extends SpinnerBinding<ModifyShapeProperty, ShapePropertyCustomiser> {
ShapeProperties prop;
boolean angle;
Spinner4Selection(final ShapePropertyCustomiser ins, final Spinner<?> widget, ShapeProperties property, boolean isAngle) throws InstantiationException, IllegalAccessException {
super(ins, true, ModifyShapeProperty.class, widget);
prop = property;
angle = isAngle;
}
@Override
public void initAction() {
action.setProperty(prop);
action.setGroup(instrument.canvas.getDrawing().getSelection().duplicateDeep(false));
updateActionValue();
}
private void updateActionValue() {
if(angle) {
action.setValue(Math.toRadians((Double) interaction.getWidget().getValue()));
}
else {
action.setValue(interaction.getWidget().getValue());
}
}
@Override
public void updateAction() {
updateActionValue();
}
@Override
public boolean isConditionRespected() {
return instrument.hand.isActivated();
}
}
static class ColourPicker4Pencil extends ColorPickerBinding<ModifyPencilParameter, ShapePropertyCustomiser> {
ShapeProperties prop;
ColourPicker4Pencil(final ShapePropertyCustomiser ins, ColorPicker picker, ShapeProperties property) throws InstantiationException, IllegalAccessException {
super(ins, ModifyPencilParameter.class, picker);
prop = property;
}
@Override
public void initAction() {
action.setValue(ShapeFactory.INST.createColorFX(interaction.getWidget().getValue()));
action.setPencil(instrument.pencil);
action.setProperty(prop);
}
@Override
public boolean isConditionRespected() {
return instrument.pencil.isActivated();
}
}
static class ColourPicker4Selection extends ColorPickerBinding<ModifyShapeProperty, ShapePropertyCustomiser> {
ShapeProperties prop;
ColourPicker4Selection(final ShapePropertyCustomiser ins, ColorPicker picker, ShapeProperties property) throws InstantiationException, IllegalAccessException {
super(ins, ModifyShapeProperty.class, picker);
prop = property;
}
@Override
public void initAction() {
action.setGroup(instrument.canvas.getDrawing().getSelection().duplicateDeep(false));
action.setValue(ShapeFactory.INST.createColorFX(interaction.getWidget().getValue()));
action.setProperty(prop);
}
@Override
public boolean isConditionRespected() {
return instrument.hand.isActivated();
}
}
static class Checkbox4Pencil extends CheckboxBinding<ModifyPencilParameter, ShapePropertyCustomiser> {
ShapeProperties prop;
Checkbox4Pencil(final ShapePropertyCustomiser ins, ButtonBase widget, ShapeProperties property) throws InstantiationException, IllegalAccessException {
super(ins, ModifyPencilParameter.class, widget);
prop = property;
}
@Override
public void initAction() {
action.setProperty(prop);
action.setPencil(instrument.pencil);
action.setValue(interaction.getWidget().isSelected());
}
@Override
public boolean isConditionRespected() {
return instrument.pencil.isActivated();
}
}
static class Checkbox4Selection extends CheckboxBinding<ModifyShapeProperty, ShapePropertyCustomiser> {
ShapeProperties prop;
Checkbox4Selection(final ShapePropertyCustomiser ins, ButtonBase widget, ShapeProperties property) throws InstantiationException, IllegalAccessException {
super(ins, ModifyShapeProperty.class, widget);
prop = property;
}
@Override
public boolean isConditionRespected() {
return instrument.hand.isActivated();
}
@Override
public void initAction() {
action.setProperty(prop);
action.setGroup(instrument.canvas.getDrawing().getSelection().duplicateDeep(false));
action.setValue(interaction.getWidget().isSelected());
}
}
}