320 lines
11 KiB
Java
320 lines
11 KiB
Java
////////////////////////////////////////
|
|
// Programming project code
|
|
// UniBw M, 2022, 2023, 2024
|
|
// www.unibw.de/inf2
|
|
// (c) Mark Minas (mark.minas@unibw.de)
|
|
////////////////////////////////////////
|
|
|
|
package pp.dialog;
|
|
|
|
import com.jme3.scene.Spatial;
|
|
import com.simsilica.lemur.Button;
|
|
import com.simsilica.lemur.Container;
|
|
import com.simsilica.lemur.Label;
|
|
import com.simsilica.lemur.component.BorderLayout;
|
|
import com.simsilica.lemur.style.ElementId;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Function;
|
|
|
|
import static com.simsilica.lemur.component.BorderLayout.Position.East;
|
|
import static com.simsilica.lemur.component.BorderLayout.Position.West;
|
|
|
|
/**
|
|
* A builder class for creating and customizing dialog boxes of type {@link SimpleDialog} or its subclasses.
|
|
* This builder pattern facilitates the construction of dialog boxes with various configurations,
|
|
* such as titles, text content, buttons, and additional custom behaviors.
|
|
*
|
|
* @param <D> the type of dialog to be built, typically extending {@link SimpleDialog}
|
|
*/
|
|
public class DialogBuilder<D extends SimpleDialog> {
|
|
|
|
/**
|
|
* Creates a {@link DialogBuilder} for a simple dialog with default settings.
|
|
*
|
|
* @param manager the dialog manager responsible for managing the dialog's lifecycle
|
|
* @return a {@link DialogBuilder} instance for creating simple dialogs
|
|
*/
|
|
public static DialogBuilder<SimpleDialog> simple(DialogManager manager) {
|
|
return new DialogBuilder<>(manager, SimpleDialog::new);
|
|
}
|
|
|
|
protected final DialogManager manager;
|
|
private final Function<DialogManager, D> dialogFactory;
|
|
private final List<Consumer<D>> extensionList = new ArrayList<>();
|
|
private String title;
|
|
private String text;
|
|
private String okLabel;
|
|
private String noLabel;
|
|
private Consumer<D> okAction = d -> {};
|
|
private Consumer<D> noAction = d -> {};
|
|
private boolean okClose = true;
|
|
private boolean noClose = true;
|
|
private Function<D, Spatial> focus;
|
|
|
|
/**
|
|
* Constructs a dialog builder with the specified dialog manager and dialog factory.
|
|
*
|
|
* @param manager the dialog manager responsible for managing the dialog's lifecycle
|
|
* @param dialogFactory a factory function to create instances of the dialog
|
|
*/
|
|
public DialogBuilder(DialogManager manager, Function<DialogManager, D> dialogFactory) {
|
|
this.manager = manager;
|
|
this.dialogFactory = dialogFactory;
|
|
}
|
|
|
|
/**
|
|
* Applies all registered extensions to the given dialog.
|
|
* Extensions allow for additional customizations beyond the standard configurations.
|
|
*
|
|
* @param dialog the dialog object to which the extensions will be applied
|
|
* @see #setExtension(java.util.function.Consumer)
|
|
*/
|
|
protected void extendDialog(D dialog) {
|
|
for (Consumer<D> extension : extensionList)
|
|
extension.accept(dialog);
|
|
}
|
|
|
|
/**
|
|
* Builds and returns the dialog with the specified configurations.
|
|
* This method creates a new dialog object and applies all the configured settings.
|
|
*
|
|
* @return the fully configured dialog object
|
|
*/
|
|
public D build() {
|
|
return build(dialogFactory.apply(manager));
|
|
}
|
|
|
|
/**
|
|
* Builds the dialog by configuring an existing dialog object with the specified settings.
|
|
* This method allows for further customization of a pre-existing dialog object.
|
|
*
|
|
* @param dialog the dialog object to configure
|
|
* @return the configured dialog object for chaining
|
|
*/
|
|
public D build(D dialog) {
|
|
configureTitle(dialog);
|
|
configureText(dialog);
|
|
extendDialog(dialog);
|
|
configureButtons(dialog);
|
|
configureFocus(dialog);
|
|
|
|
return dialog;
|
|
}
|
|
|
|
/**
|
|
* Configures the title of the dialog if a title has been set.
|
|
*
|
|
* @param dialog the dialog to which the title will be added
|
|
*/
|
|
private void configureTitle(D dialog) {
|
|
if (title != null)
|
|
dialog.addChild(new Label(title, new ElementId("header"))); // NON-NLS
|
|
}
|
|
|
|
/**
|
|
* Configures the main text content of the dialog if text has been set.
|
|
*
|
|
* @param dialog the dialog to which the text content will be added
|
|
*/
|
|
private void configureText(D dialog) {
|
|
if (text != null)
|
|
dialog.addChild(new Label(text));
|
|
}
|
|
|
|
/**
|
|
* Configures the OK and NO buttons for the dialog if labels for them have been set.
|
|
*
|
|
* @param dialog the dialog to which the buttons will be added
|
|
*/
|
|
private void configureButtons(D dialog) {
|
|
if (okLabel != null || noLabel != null) {
|
|
final Container buttons = dialog.addChild(new Container(new BorderLayout()));
|
|
if (okLabel != null) {
|
|
final Button okButton = buttons.addChild(new Button(okLabel), West);
|
|
dialog.setOkButton(okButton);
|
|
configureButton(okButton, okAction, okClose, dialog);
|
|
}
|
|
if (noLabel != null) {
|
|
final Button noButton = buttons.addChild(new Button(noLabel), East);
|
|
configureButton(noButton, noAction, noClose, dialog);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Configures a button with its action and whether the dialog should close after the action is performed.
|
|
*
|
|
* @param button the button to configure
|
|
* @param action the action to perform when the button is clicked
|
|
* @param close whether the dialog should close after the action is performed
|
|
* @param dialog the dialog that contains the button
|
|
*/
|
|
private void configureButton(Button button, Consumer<D> action, boolean close, D dialog) {
|
|
button.addClickCommands(s -> {
|
|
if (dialog.isTopDialog()) {
|
|
action.accept(dialog);
|
|
if (close) {
|
|
dialog.close();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Configures the initial focus for the dialog when it is displayed.
|
|
* The focus will be set to either a specified component or the OK button if available.
|
|
*
|
|
* @param dialog the dialog to configure focus for
|
|
*/
|
|
private void configureFocus(D dialog) {
|
|
final Spatial focusComponent = focus == null ? null : focus.apply(dialog);
|
|
if (focusComponent != null || dialog.getOkButton() != null)
|
|
manager.setFocus(focusComponent != null ? focusComponent : dialog.getOkButton());
|
|
}
|
|
|
|
/**
|
|
* Sets the title of the dialog.
|
|
*
|
|
* @param title the title text to be displayed at the top of the dialog
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setTitle(String title) {
|
|
this.title = title;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the main text content of the dialog.
|
|
*
|
|
* @param text the main content text to be displayed in the dialog
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setText(String text) {
|
|
this.text = text;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the label for the OK button.
|
|
*
|
|
* @param okLabel the text label to display on the OK button
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setOkButton(String okLabel) {
|
|
this.okLabel = okLabel;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the label and action for the OK button.
|
|
* When the OK button is clicked, the specified action will be executed.
|
|
*
|
|
* @param okLabel the text label to display on the OK button
|
|
* @param okAction the action to perform when the OK button is clicked
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setOkButton(String okLabel, Consumer<D> okAction) {
|
|
this.okAction = okAction;
|
|
return setOkButton(okLabel);
|
|
}
|
|
|
|
/**
|
|
* Sets the label and action for the OK button.
|
|
* When the OK button is clicked, the specified runnable action will be executed.
|
|
*
|
|
* @param okLabel the text label to display on the OK button
|
|
* @param okAction the runnable action to perform when the OK button is clicked
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setOkButton(String okLabel, Runnable okAction) {
|
|
this.okAction = d -> okAction.run();
|
|
return setOkButton(okLabel);
|
|
}
|
|
|
|
/**
|
|
* Sets the label for the NO button.
|
|
*
|
|
* @param noLabel the text label to display on the NO button
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setNoButton(String noLabel) {
|
|
this.noLabel = noLabel;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the label and action for the NO button.
|
|
* When the NO button is clicked, the specified action will be executed.
|
|
*
|
|
* @param noLabel the text label to display on the NO button
|
|
* @param noAction the action to perform when the NO button is clicked
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setNoButton(String noLabel, Consumer<D> noAction) {
|
|
this.noAction = noAction;
|
|
return setNoButton(noLabel);
|
|
}
|
|
|
|
/**
|
|
* Sets the label and action for the NO button.
|
|
* When the NO button is clicked, the specified runnable action will be executed.
|
|
*
|
|
* @param noLabel the text label to display on the NO button
|
|
* @param noAction the runnable action to perform when the NO button is clicked
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setNoButton(String noLabel, Runnable noAction) {
|
|
this.noAction = d -> noAction.run();
|
|
return setNoButton(noLabel);
|
|
}
|
|
|
|
/**
|
|
* Sets whether the dialog should automatically close when the OK button is clicked.
|
|
*
|
|
* @param okClose true to close the dialog when the OK button is clicked, false otherwise
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setOkClose(boolean okClose) {
|
|
this.okClose = okClose;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets whether the dialog should automatically close when the NO button is clicked.
|
|
*
|
|
* @param noClose true to close the dialog when the NO button is clicked, false otherwise
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setNoClose(boolean noClose) {
|
|
this.noClose = noClose;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets the component that should initially receive focus when the dialog is displayed.
|
|
* If a focus function is not provided, the focus defaults to the OK button.
|
|
*
|
|
* @param focus a function specifying which component of the dialog should receive focus
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setFocus(Function<D, Spatial> focus) {
|
|
this.focus = focus;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds an extension to the dialog.
|
|
* Extensions allow for additional customizations and behaviors beyond the basic configuration.
|
|
*
|
|
* @param extender a consumer that applies the extension to the dialog
|
|
* @return this builder instance for chaining
|
|
*/
|
|
public DialogBuilder<D> setExtension(Consumer<D> extender) {
|
|
extensionList.add(extender);
|
|
return this;
|
|
}
|
|
}
|