2 | package goryachev.fx;
3 | import goryachev.common.util.FH;
4 | import javafx.scene.Node;
5 |
6 |
7 | /**
8 | * CSS Style.
9 | *
10 | * Usage example:
11 | *
12 | * public static final CssStyle EXAMPLE = new CssStyle();
13 | * ...
14 | * {
15 | * Pane pane = new Pane();
16 | * EXAMPLE.set(pane);
17 | * }
18 | *
19 | */
20 | public class CssStyle
21 | {
22 | private String name;
23 | private static long seq;
24 |
25 |
26 | public CssStyle(String name)
27 | {
28 | this.name = generateName(name);
29 | }
30 |
31 |
32 | public CssStyle()
33 | {
34 | this.name = generateName(null);
35 | }
36 |
37 |
38 | private static synchronized String generateName(String name)
39 | {
40 | if(CssLoader.DUMP)
41 | {
42 | StackTraceElement s = new Throwable().getStackTrace()[2];
43 | String c = s.getClassName().replace('.', '_');
44 | return c + "-L" + s.getLineNumber() + (name == null ? "" : "-" + name);
45 | }
46 | else
47 | {
48 | return "S" + (seq++);
49 | }
50 | }
51 |
52 |
53 | public boolean equals(Object x)
54 | {
55 | if(x == this)
56 | {
57 | return true;
58 | }
59 | else if(x instanceof CssStyle s)
60 | {
61 | return getName().equals(s.getName());
62 | }
63 | else
64 | {
65 | return false;
66 | }
67 | }
68 |
69 |
70 | public int hashCode()
71 | {
72 | int h = FH.hash(CssStyle.class);
73 | h = FH.hash(h, getName());
74 | return h;
75 | }
76 |
77 |
78 | public String getName()
79 | {
80 | return name;
81 | }
82 |
83 |
84 | public String toString()
85 | {
86 | return name;
87 | }
88 |
89 |
90 | public void set(Node n)
91 | {
92 | n.getStyleClass().add(getName());
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FlatButton.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2016-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import javafx.scene.Node;
4 |
5 |
6 | /**
7 | * Flat Button.
8 | */
9 | public class FlatButton
10 | extends FxButton
11 | {
12 | public static final CssStyle STYLE = new CssStyle("FlatButton_STYLE");
13 |
14 |
15 | public FlatButton(String text, FxAction a)
16 | {
17 | super(text, a);
18 | FX.style(this, STYLE);
19 | }
20 |
21 |
22 | public FlatButton(String text, Runnable action)
23 | {
24 | super(text, action);
25 | FX.style(this, STYLE);
26 | }
27 |
28 |
29 | public FlatButton(String text)
30 | {
31 | super(text);
32 | FX.style(this, STYLE);
33 | }
34 |
35 |
36 | public FlatButton(Node icon)
37 | {
38 | super(icon);
39 | FX.style(this, STYLE);
40 | }
41 |
42 |
43 | public FlatButton(Node icon, FxAction a)
44 | {
45 | super(icon, a);
46 | FX.style(this, STYLE);
47 | }
48 |
49 |
50 | public FlatButton(Node icon, Runnable action)
51 | {
52 | super(icon, action);
53 | FX.style(this, STYLE);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FlatToggleButton.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2019-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import java.util.function.Function;
4 | import javafx.beans.value.ChangeListener;
5 | import javafx.beans.value.ObservableValue;
6 | import javafx.scene.Node;
7 | import javafx.scene.control.ToggleButton;
8 |
9 |
10 | /**
11 | * Flat Toggle Button.
12 | */
13 | public class FlatToggleButton
14 | extends ToggleButton
15 | {
16 | public static final CssStyle STYLE = new CssStyle("FlatToggleButton_STYLE");
17 | private static final Object ICONS = new Object();
18 |
19 |
20 | public FlatToggleButton(String text, Node graphic)
21 | {
22 | super(text, graphic);
23 | init();
24 | }
25 |
26 |
27 | public FlatToggleButton(Node graphic)
28 | {
29 | super(null, graphic);
30 | init();
31 | }
32 |
33 |
34 | public FlatToggleButton(String text)
35 | {
36 | super(text);
37 | init();
38 | }
39 |
40 |
41 | public FlatToggleButton()
42 | {
43 | init();
44 | }
45 |
46 |
47 | private void init()
48 | {
49 | FX.style(this, STYLE);
50 | }
51 |
52 |
53 | public void setIcons(Function generator)
54 | {
55 | Object prev = getProperties().get(ICONS);
56 | if(prev instanceof ChangeListener)
57 | {
58 | selectedProperty().removeListener((ChangeListener)prev);
59 | }
60 |
61 | ChangeListener li = new ChangeListener()
62 | {
63 | public void changed(ObservableValue extends Boolean> src, Boolean prev, Boolean cur)
64 | {
65 | updateIcon(generator, cur);
66 | }
67 | };
68 | selectedProperty().addListener(li);
69 | getProperties().put(ICONS, li);
70 |
71 | updateIcon(generator, isSelected());
72 | }
73 |
74 |
75 | protected void updateIcon(Function generator, Boolean on)
76 | {
77 | Node icon = generator.apply(on);
78 | setGraphic(icon);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/goryachev/fx/Formatters.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2017-2024 Andy Goryachev
2 | package goryachev.fx;
3 |
4 |
5 | /**
6 | * Standard Formatters.
7 | */
8 | public class Formatters
9 | {
10 | // TODO should these be settable somehow?
11 | private static FxDecimalFormatter integerFormatter;
12 |
13 |
14 | public static FxDecimalFormatter integerFormatter()
15 | {
16 | if(integerFormatter == null)
17 | {
18 | integerFormatter = new FxDecimalFormatter("#,##0");
19 | }
20 | return integerFormatter;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxApplication.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2021-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import javafx.application.Application;
4 |
5 |
6 | /**
7 | * Base Class for FX Application.
8 | */
9 | public abstract class FxApplication
10 | extends Application
11 | {
12 | private static FxApplication instance;
13 |
14 |
15 | public FxApplication()
16 | {
17 | if(instance != null)
18 | {
19 | throw new Error("there could be only one FxApplication");
20 | }
21 | instance = this;
22 | }
23 |
24 |
25 | public static FxApplication getInstance()
26 | {
27 | if(instance == null)
28 | {
29 | throw new Error("your application must extend FxApplication");
30 | }
31 | return instance;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxBoolean.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2018-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import javafx.beans.property.ReadOnlyBooleanWrapper;
4 |
5 |
6 | /**
7 | * Alias for SimpleBooleanProperty.
8 | */
9 | public class FxBoolean
10 | extends ReadOnlyBooleanWrapper
11 | {
12 | public FxBoolean(boolean initialValue)
13 | {
14 | super(initialValue);
15 | }
16 |
17 |
18 | public FxBoolean()
19 | {
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxBooleanBinding.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2019-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import javafx.beans.Observable;
4 | import javafx.beans.binding.BooleanBinding;
5 |
6 |
7 | /**
8 | * FxBooleanBinding.
9 | */
10 | public abstract class FxBooleanBinding
11 | extends BooleanBinding
12 | {
13 | protected abstract boolean computeValue();
14 |
15 |
16 | public FxBooleanBinding(Observable ... dependencies)
17 | {
18 | bind(dependencies);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxButtonPane.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2016-2024 Andy Goryachev
2 | package goryachev.fx;
3 |
4 |
5 | /**
6 | * Fx Button Pane.
7 | *
8 | * TODO default button
9 | * TODO fix HPane layout
10 | * TODO set minimum button width
11 | * TODO own layout, sets min width and alignment (to avoid fill())
12 | */
13 | public class FxButtonPane
14 | extends HPane
15 | {
16 | public static final CssStyle PANE = new CssStyle("FxButtonPane_PANE");
17 | private static final int MIN_WIDTH = 70;
18 |
19 |
20 | public FxButtonPane()
21 | {
22 | super(5);
23 | FX.style(this, PANE);
24 | }
25 |
26 |
27 | public FxButton addButton(String text, CssStyle style, FxAction a)
28 | {
29 | FxButton b = new FxButton(text, style, a);
30 | return addButton(b);
31 | }
32 |
33 |
34 | public FxButton addButton(String text, FxAction a)
35 | {
36 | FxButton b = new FxButton(text, a);
37 | return addButton(b);
38 | }
39 |
40 |
41 | public FxButton addButton(String text, CssStyle style, Runnable r)
42 | {
43 | FxButton b = new FxButton(text, style, new FxAction(r));
44 | return addButton(b);
45 | }
46 |
47 |
48 | public FxButton addButton(String text, CssStyle style)
49 | {
50 | FxButton b = new FxButton(text, style, FxAction.DISABLED);
51 | return addButton(b);
52 | }
53 |
54 |
55 | public FxButton addButton(String text, Runnable r)
56 | {
57 | FxButton b = new FxButton(text, new FxAction(r));
58 | return addButton(b);
59 | }
60 |
61 |
62 | public FxButton addButton(String text)
63 | {
64 | FxButton b = new FxButton(text);
65 | b.setDisable(true);
66 | return addButton(b);
67 | }
68 |
69 |
70 | public FxButton addButton(FxButton b)
71 | {
72 | b.setMinWidth(MIN_WIDTH);
73 | add(b);
74 | return b;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxChangeListener.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2020-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import goryachev.common.util.IDisconnectable;
4 | import java.util.concurrent.CopyOnWriteArrayList;
5 | import javafx.beans.value.ChangeListener;
6 | import javafx.beans.value.ObservableValue;
7 |
8 |
9 | /**
10 | * A Change Listener that calls a callback when any of the registered properties change.
11 | * This class allows for disconnecting the listeners from all the registered properties.
12 | */
13 | public class FxChangeListener
14 | implements ChangeListener, IDisconnectable
15 | {
16 | private final Runnable callback;
17 | private final CopyOnWriteArrayList properties = new CopyOnWriteArrayList<>();
18 | private boolean enabled = true;
19 |
20 |
21 | public FxChangeListener(Runnable callback)
22 | {
23 | this.callback = callback;
24 | }
25 |
26 |
27 | public void listen(ObservableValue> p)
28 | {
29 | if(p != null)
30 | {
31 | properties.add(p);
32 | p.addListener(this);
33 | }
34 | }
35 |
36 |
37 | public void listen(ObservableValue> ... props)
38 | {
39 | for(ObservableValue> p: props)
40 | {
41 | listen(p);
42 | }
43 | }
44 |
45 |
46 | public void disconnect()
47 | {
48 | for(ObservableValue p: properties)
49 | {
50 | p.removeListener(this);
51 | }
52 | }
53 |
54 |
55 | public void enable()
56 | {
57 | setEnabled(true);
58 | }
59 |
60 |
61 | public void disable()
62 | {
63 | setEnabled(true);
64 | }
65 |
66 |
67 | public void setEnabled(boolean on)
68 | {
69 | enabled = on;
70 | }
71 |
72 |
73 | public boolean isEnabled()
74 | {
75 | return enabled;
76 | }
77 |
78 |
79 | public void changed(ObservableValue src, Object prev, Object curr)
80 | {
81 | fire();
82 | }
83 |
84 |
85 | public void fire()
86 | {
87 | if(enabled)
88 | {
89 | invokeCallback();
90 | }
91 | }
92 |
93 |
94 | protected void invokeCallback()
95 | {
96 | callback.run();
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxCheckBox.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2016-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import javafx.scene.control.CheckBox;
4 |
5 |
6 | /**
7 | * CCheckBox.
8 | */
9 | public class FxCheckBox
10 | extends CheckBox
11 | {
12 | public FxCheckBox(String text, boolean selected)
13 | {
14 | super(text);
15 | setSelected(selected);
16 | }
17 |
18 |
19 | public FxCheckBox(boolean selected)
20 | {
21 | setSelected(selected);
22 | }
23 |
24 |
25 | public FxCheckBox(String text)
26 | {
27 | super(text);
28 | }
29 |
30 |
31 | public FxCheckBox()
32 | {
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxCheckMenuItem.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2016-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import javafx.beans.property.Property;
4 | import javafx.scene.control.CheckMenuItem;
5 |
6 |
7 | /**
8 | * CheckMenuItem that knows how to deal with FxAction or a Property.
9 | */
10 | public class FxCheckMenuItem
11 | extends CheckMenuItem
12 | {
13 | public FxCheckMenuItem(String text)
14 | {
15 | super(text);
16 | }
17 |
18 |
19 | public FxCheckMenuItem(String text, FxAction a)
20 | {
21 | super(text);
22 | a.attach(this);
23 | }
24 |
25 |
26 | public FxCheckMenuItem(String text, Property p)
27 | {
28 | super(text);
29 | selectedProperty().bindBidirectional(p);
30 | }
31 |
32 |
33 | public FxCheckMenuItem(String text, GlobalBooleanProperty op)
34 | {
35 | super(text);
36 | selectedProperty().bindBidirectional(op);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxCtl.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2016-2024 Andy Goryachev
2 | package goryachev.fx;
3 |
4 |
5 | /**
6 | * Simple tags to simplify creation of nodes, labels, and text controls.
7 | */
8 | public enum FxCtl
9 | {
10 | BOLD,
11 | EDITABLE,
12 | FOCUSABLE,
13 | FORCE_MAX_WIDTH,
14 | FORCE_MIN_HEIGHT,
15 | FORCE_MIN_WIDTH,
16 | NON_EDITABLE,
17 | NON_FOCUSABLE,
18 | WRAP_TEXT
19 | }
20 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxDateFormatter.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2016-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 |
6 |
7 | /**
8 | * Fx DateFormatter.
9 | */
10 | public class FxDateFormatter
11 | extends FxFormatter
12 | {
13 | private final SimpleDateFormat format;
14 |
15 |
16 | public FxDateFormatter(String pattern)
17 | {
18 | format = new SimpleDateFormat(pattern);
19 | }
20 |
21 |
22 | public String format(long t)
23 | {
24 | return format.format(t);
25 | }
26 |
27 |
28 | public String toString(Object x)
29 | {
30 | if(x == null)
31 | {
32 | return null;
33 | }
34 | else if(x instanceof Date)
35 | {
36 | return format.format(x);
37 | }
38 | else if(x instanceof Long)
39 | {
40 | Long v = (Long)x;
41 | if(v.longValue() <= 0)
42 | {
43 | return null;
44 | }
45 | return format.format(x);
46 | }
47 | else
48 | {
49 | return null;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxDecimalFormatter.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2016-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import java.text.DecimalFormat;
4 |
5 |
6 | /**
7 | * Fx Decimal Number Formatter.
8 | */
9 | public class FxDecimalFormatter
10 | extends FxFormatter
11 | {
12 | private final DecimalFormat format;
13 |
14 |
15 | public FxDecimalFormatter(String pattern)
16 | {
17 | format = new DecimalFormat(pattern);
18 | }
19 |
20 |
21 | public String toString(Object x)
22 | {
23 | if(x == null)
24 | {
25 | return null;
26 | }
27 | else if(x instanceof Number)
28 | {
29 | return format.format(x);
30 | }
31 | else
32 | {
33 | return null;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxDialogResponse.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2024 Andy Goryachev
2 | package goryachev.fx;
3 |
4 |
5 | /**
6 | * FxDialog response enum covers most common cases,
7 | * similar to {@link javafx.scene.control.ButtonBar.ButtonData}.
8 | */
9 | public enum FxDialogResponse
10 | {
11 | CANCEL,
12 | CANCEL_ALL,
13 | DISCARD,
14 | DISCARD_ALL,
15 | SAVE,
16 | SAVE_ALL,
17 | }
18 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxDouble.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2019-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import javafx.beans.property.SimpleDoubleProperty;
4 |
5 |
6 | /**
7 | * Alias for SimpleLongProperty.
8 | */
9 | public class FxDouble
10 | extends SimpleDoubleProperty
11 | {
12 | public FxDouble(double initialValue)
13 | {
14 | super(initialValue);
15 | }
16 |
17 |
18 | public FxDouble()
19 | {
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxFlags.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2019-2024 Andy Goryachev
2 | package goryachev.fx;
3 |
4 |
5 | /**
6 | * These application-wide flags control FX subsystem.
7 | */
8 | public class FxFlags
9 | {
10 | /**
11 | * To enable polling of css style sheet for changes:
12 | *
13 | * -Dcss.refresh=true
14 | *
15 | */
16 | public static final String CSS_REFRESH = "css.refresh";
17 |
18 | /**
19 | * Enables dumping of the stylesheet to stdout
20 | *
21 | * -Dcss.dump=true
22 | *
23 | */
24 | public static final String CSS_DUMP = "css.dump";
25 | }
26 |
--------------------------------------------------------------------------------
/src/goryachev/fx/FxFormatter.java:
--------------------------------------------------------------------------------
1 | // Copyright © 2016-2024 Andy Goryachev
2 | package goryachev.fx;
3 | import javafx.util.StringConverter;
4 |
5 |
6 | /**
7 | * A StringConverter extension.
8 | */
9 | public abstract class FxFormatter
10 | extends StringConverter