Skip to content

Method: static {...}

1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * SteelBlue: DCI User Interfaces
5: * http://tidalwave.it/projects/steelblue
6: *
7: * Copyright (C) 2015 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *************************************************************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12: * You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/steelblue-src
22: * git clone https://github.com/tidalwave-it/steelblue-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.ui.javafx.impl.button;
27:
28: import jakarta.annotation.Nonnull;
29: import java.util.Collection;
30: import java.util.List;
31: import java.util.concurrent.Executor;
32: import java.util.concurrent.atomic.AtomicInteger;
33: import java.util.function.Supplier;
34: import javafx.beans.property.BooleanProperty;
35: import javafx.geometry.HPos;
36: import javafx.geometry.VPos;
37: import javafx.scene.control.Button;
38: import javafx.scene.control.ButtonBase;
39: import javafx.scene.control.MenuItem;
40: import javafx.scene.control.ToggleButton;
41: import javafx.scene.control.ToggleGroup;
42: import javafx.scene.layout.ColumnConstraints;
43: import javafx.scene.layout.GridPane;
44: import javafx.scene.layout.Pane;
45: import javafx.scene.layout.Priority;
46: import javafx.stage.Window;
47: import javafx.application.Platform;
48: import it.tidalwave.ui.core.BoundProperty;
49: import it.tidalwave.ui.core.role.Displayable;
50: import it.tidalwave.ui.core.role.PresentationModel;
51: import it.tidalwave.ui.core.role.Styleable;
52: import it.tidalwave.ui.core.role.UserAction;
53: import it.tidalwave.ui.core.role.UserActionProvider;
54: import it.tidalwave.ui.javafx.impl.common.DelegateSupport;
55: import it.tidalwave.util.As;
56: import it.tidalwave.role.SimpleComposite;
57: import static it.tidalwave.ui.core.role.Displayable._Displayable_;
58: import static it.tidalwave.ui.core.role.Styleable._Styleable_;
59: import static it.tidalwave.ui.core.role.UserActionProvider._UserActionProvider_;
60: import static it.tidalwave.ui.javafx.impl.DefaultJavaFXBinder.enforceFxApplicationThread;
61: import static java.util.Collections.emptyList;
62: import static java.util.stream.Collectors.*;
63:
64: /***************************************************************************************************************************************************************
65: *
66: * @author Fabrizio Giudici
67: *
68: **************************************************************************************************************************************************************/
69: public class ButtonBindings extends DelegateSupport
70: {
71: private static final As.Type<SimpleComposite<PresentationModel>> _SimpleCompositePresentationModel_ = new As.Type<>(SimpleComposite.class);
72:
73: /***********************************************************************************************************************************************************
74: *
75: **********************************************************************************************************************************************************/
76: public ButtonBindings (@Nonnull final Executor executor, @Nonnull final Supplier<Window> mainWindow)
77: {
78: super(executor, mainWindow);
79: }
80:
81: /***********************************************************************************************************************************************************
82: *
83: **********************************************************************************************************************************************************/
84: public void bind (@Nonnull final ButtonBase button, @Nonnull final UserAction action)
85: {
86: enforceFxApplicationThread();
87: action.maybeAs(_Displayable_).ifPresent(d -> button.setText(d.getDisplayName()));
88: button.setOnAction(ignored -> executor.execute(action::actionPerformed));
89: bindEnableProperty(button.disableProperty(), action.enabled());
90: }
91:
92: /***********************************************************************************************************************************************************
93: *
94: **********************************************************************************************************************************************************/
95: public void bind (@Nonnull final MenuItem menuItem, @Nonnull final UserAction action)
96: {
97: enforceFxApplicationThread();
98: menuItem.setText(action.maybeAs(_Displayable_).map(Displayable::getDisplayName).orElse(""));
99: menuItem.setOnAction(ignored -> executor.execute(action::actionPerformed));
100: bindEnableProperty(menuItem.disableProperty(), action.enabled());
101: }
102:
103: /***********************************************************************************************************************************************************
104: * {@inheritDoc}
105: **********************************************************************************************************************************************************/
106: public void bindToggleButtons (@Nonnull final Pane pane, @Nonnull final PresentationModel pm)
107: {
108: enforceFxApplicationThread();
109: final var group = new ToggleGroup();
110: final var children = pane.getChildren();
111: final var prototypeStyleClass = children.get(0).getStyleClass();
112: final var pmc = pm.as(_SimpleCompositePresentationModel_);
113: children.setAll(pmc.findChildren().stream().map(cpm -> createToggleButton(cpm, prototypeStyleClass, group)).collect(toList()));
114: }
115:
116: /***********************************************************************************************************************************************************
117: *
118: **********************************************************************************************************************************************************/
119: public void bindButtonsInPane (@Nonnull final GridPane gridPane, @Nonnull final Collection<UserAction> actions)
120: {
121: enforceFxApplicationThread();
122: final var columnConstraints = gridPane.getColumnConstraints();
123: final var children = gridPane.getChildren();
124:
125: columnConstraints.clear();
126: children.clear();
127: final var columnIndex = new AtomicInteger(0);
128:
129: actions.forEach(menuAction ->
130: {
131: final var column = new ColumnConstraints();
132: column.setPercentWidth(100.0 / actions.size());
133: columnConstraints.add(column);
134: final var button = createButton();
135: GridPane.setConstraints(button, columnIndex.getAndIncrement(), 0);
136: bind(button, menuAction);
137: children.add(button);
138: });
139: }
140:
141: /***********************************************************************************************************************************************************
142: * {@return a new {@code Button}} for the menu bar.
143: **********************************************************************************************************************************************************/
144: @Nonnull
145: private Button createButton()
146: {
147: final var button = new Button();
148: GridPane.setHgrow(button, Priority.ALWAYS);
149: GridPane.setVgrow(button, Priority.ALWAYS);
150: GridPane.setHalignment(button, HPos.CENTER);
151: GridPane.setValignment(button, VPos.CENTER);
152: button.setPrefSize(Integer.MAX_VALUE, Integer.MAX_VALUE); // fill
153: button.getStyleClass().add("mainMenuButton");
154:
155: return button;
156: }
157:
158: /***********************************************************************************************************************************************************
159: *
160: **********************************************************************************************************************************************************/
161: @Nonnull
162: private ToggleButton createToggleButton (@Nonnull final PresentationModel pm, @Nonnull final List<String> baseStyleClass, @Nonnull final ToggleGroup group)
163: {
164: final var button = new ToggleButton();
165: button.setToggleGroup(group);
166: button.setText(pm.maybeAs(_Displayable_).map(Displayable::getDisplayName).orElse(""));
167: button.getStyleClass().addAll(baseStyleClass);
168: button.getStyleClass().addAll(pm.maybeAs(_Styleable_).map(Styleable::getStyles).orElse(emptyList()));
169: pm.maybeAs(_UserActionProvider_).flatMap(UserActionProvider::getOptionalDefaultAction)
170: .ifPresent(action -> bind(button, action));
171:
172: if (group.getSelectedToggle() == null)
173: {
174: group.selectToggle(button);
175: }
176:
177: return button;
178: }
179:
180: /***********************************************************************************************************************************************************
181: *
182: **********************************************************************************************************************************************************/
183: private void bindEnableProperty (@Nonnull final BooleanProperty property1, @Nonnull final BoundProperty<Boolean> property2)
184: {
185: property1.setValue(!property2.get());
186: property1.addListener((_1, _2, newValue) -> executor.execute(() -> property2.set(!newValue)));
187: property2.addPropertyChangeListener(evt -> Platform.runLater(() -> property1.setValue(!(boolean)evt.getNewValue())));
188: }
189: }