161 lines
4.0 KiB
Java
161 lines
4.0 KiB
Java
package envoy.client.ui;
|
|
|
|
import java.io.IOException;
|
|
import java.util.Stack;
|
|
import java.util.logging.Level;
|
|
|
|
import javafx.fxml.FXMLLoader;
|
|
import javafx.scene.*;
|
|
import javafx.stage.Stage;
|
|
|
|
import dev.kske.eventbus.core.*;
|
|
|
|
import envoy.util.EnvoyLog;
|
|
|
|
import envoy.client.data.Settings;
|
|
import envoy.client.data.shortcuts.*;
|
|
import envoy.client.event.*;
|
|
|
|
/**
|
|
* Manages a stack of scenes. The most recently added scene is displayed inside a stage. When a
|
|
* scene is removed from the stack, its predecessor is displayed.
|
|
* <p>
|
|
* When a scene is loaded, the style sheet for the current theme is applied to it.
|
|
*
|
|
* @author Kai S. K. Engelbart
|
|
* @since Envoy Client v0.1-beta
|
|
*/
|
|
public final class SceneContext {
|
|
|
|
private final Stage stage;
|
|
private final Stack<Parent> roots = new Stack<>();
|
|
private final Stack<Object> controllers = new Stack<>();
|
|
|
|
private Scene scene;
|
|
|
|
/**
|
|
* Initializes the scene context.
|
|
*
|
|
* @param stage the stage in which scenes will be displayed
|
|
* @since Envoy Client v0.1-beta
|
|
*/
|
|
public SceneContext(Stage stage) {
|
|
this.stage = stage;
|
|
EventBus.getInstance().registerListener(this);
|
|
}
|
|
|
|
/**
|
|
* Loads a new scene specified by a scene info.
|
|
*
|
|
* @param info specifies the scene to load
|
|
* @throws RuntimeException if the loading process fails
|
|
* @since Envoy Client v0.1-beta
|
|
*/
|
|
public void load(SceneInfo info) {
|
|
EnvoyLog.getLogger(SceneContext.class).log(Level.FINER, "Loading scene " + info);
|
|
|
|
try {
|
|
|
|
// Load root node and controller
|
|
var loader = new FXMLLoader();
|
|
Parent root = loader.load(getClass().getResourceAsStream(info.path));
|
|
Object controller = loader.getController();
|
|
roots.push(root);
|
|
controllers.push(controller);
|
|
|
|
if (scene == null) {
|
|
|
|
// One-time scene initialization
|
|
scene = new Scene(root, stage.getWidth(), stage.getHeight());
|
|
applyCSS();
|
|
stage.setScene(scene);
|
|
} else {
|
|
scene.setRoot(root);
|
|
}
|
|
|
|
// Remove previous keyboard shortcuts
|
|
scene.getAccelerators().clear();
|
|
|
|
// Supply the global custom keyboard shortcuts for that scene
|
|
scene.getAccelerators()
|
|
.putAll(GlobalKeyShortcuts.getInstance().getKeyboardShortcuts(info));
|
|
|
|
// Supply the scene specific keyboard shortcuts
|
|
if (controller instanceof KeyboardMapping)
|
|
scene.getAccelerators()
|
|
.putAll(((KeyboardMapping) controller).getKeyboardShortcuts());
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes the current scene and displays the previous one.
|
|
*
|
|
* @since Envoy Client v0.1-beta
|
|
*/
|
|
public void pop() {
|
|
|
|
// Pop current root node and controller
|
|
roots.pop();
|
|
controllers.pop();
|
|
|
|
// Apply new scene if present
|
|
if (!roots.isEmpty()) {
|
|
scene.setRoot(roots.peek());
|
|
|
|
// Invoke restore if controller is restorable
|
|
var controller = controllers.peek();
|
|
if (controller instanceof Restorable)
|
|
((Restorable) controller).onRestore();
|
|
} else {
|
|
|
|
// Remove the current scene entirely
|
|
scene = null;
|
|
stage.setScene(null);
|
|
}
|
|
}
|
|
|
|
private void applyCSS() {
|
|
if (scene != null) {
|
|
var styleSheets = scene.getStylesheets();
|
|
var themeCSS = "/css/" + Settings.getInstance().getCurrentTheme() + ".css";
|
|
styleSheets.clear();
|
|
styleSheets.addAll(getClass().getResource("/css/base.css").toExternalForm(),
|
|
getClass().getResource(themeCSS).toExternalForm());
|
|
}
|
|
}
|
|
|
|
@Event(Logout.class)
|
|
@Priority(150)
|
|
private void onLogout() {
|
|
roots.clear();
|
|
controllers.clear();
|
|
}
|
|
|
|
@Event(ThemeChangeEvent.class)
|
|
@Priority(150)
|
|
private void onThemeChange() {
|
|
applyCSS();
|
|
}
|
|
|
|
/**
|
|
* @param <T> the type of the controller
|
|
* @return the controller used by the current scene
|
|
* @since Envoy Client v0.1-beta
|
|
*/
|
|
public <T> T getController() { return (T) controllers.peek(); }
|
|
|
|
/**
|
|
* @return the stage in which the scenes are displayed
|
|
* @since Envoy Client v0.1-beta
|
|
*/
|
|
public Stage getStage() { return stage; }
|
|
|
|
/**
|
|
* @return whether the scene stack is empty
|
|
* @since Envoy Client v0.2-beta
|
|
*/
|
|
public boolean isEmpty() { return roots.isEmpty(); }
|
|
}
|