diff --git a/prometeu-studio/src/main/java/p/studio/controls/shell/StudioRightUtilityPanelControl.java b/prometeu-studio/src/main/java/p/studio/controls/shell/StudioRightUtilityPanelControl.java index 50d5bc35..c26f2b0b 100644 --- a/prometeu-studio/src/main/java/p/studio/controls/shell/StudioRightUtilityPanelControl.java +++ b/prometeu-studio/src/main/java/p/studio/controls/shell/StudioRightUtilityPanelControl.java @@ -6,6 +6,7 @@ import javafx.scene.control.Label; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.layout.BorderPane; +import javafx.scene.layout.VBox; import p.studio.controls.lifecycle.StudioControlLifecycle; import p.studio.controls.lifecycle.StudioControlLifecycleSupport; @@ -13,6 +14,7 @@ import java.util.Objects; public final class StudioRightUtilityPanelControl extends BorderPane implements StudioControlLifecycle { public StudioRightUtilityPanelControl( + Node headerContent, ObservableValue activityTitle, Node activityContent) { StudioControlLifecycleSupport.install(this, this); @@ -26,7 +28,13 @@ public final class StudioRightUtilityPanelControl extends BorderPane implements final TabPane tabs = new TabPane(activityTab); tabs.getStyleClass().add("studio-right-utility-tabs"); - setCenter(tabs); + final VBox layout = new VBox(10); + layout.getStyleClass().add("studio-right-utility-layout"); + if (headerContent != null) { + layout.getChildren().add(headerContent); + } + layout.getChildren().add(tabs); + setCenter(layout); } public static Label createPlaceholderContent(ObservableValue text) { diff --git a/prometeu-studio/src/main/java/p/studio/controls/shell/StudioRunSurfaceControl.java b/prometeu-studio/src/main/java/p/studio/controls/shell/StudioRunSurfaceControl.java index 25aac156..7aa073ca 100644 --- a/prometeu-studio/src/main/java/p/studio/controls/shell/StudioRunSurfaceControl.java +++ b/prometeu-studio/src/main/java/p/studio/controls/shell/StudioRunSurfaceControl.java @@ -1,34 +1,62 @@ package p.studio.controls.shell; -import javafx.beans.value.ObservableValue; +import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.geometry.Pos; import javafx.scene.control.Button; +import javafx.scene.control.Label; import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; import p.studio.Container; import p.studio.controls.lifecycle.StudioControlLifecycle; import p.studio.controls.lifecycle.StudioControlLifecycleSupport; import p.studio.utilities.i18n.I18n; -import java.util.Objects; - public final class StudioRunSurfaceControl extends HBox implements StudioControlLifecycle { + private final BooleanProperty running = new SimpleBooleanProperty(false); + public StudioRunSurfaceControl() { StudioControlLifecycleSupport.install(this, this); getStyleClass().add("studio-run-surface"); setSpacing(8); - setAlignment(Pos.CENTER_RIGHT); + setAlignment(Pos.CENTER_LEFT); - getChildren().addAll( - createButton(Container.i18n().bind(I18n.TOOLBAR_PLAY), () -> { }), - createButton(Container.i18n().bind(I18n.TOOLBAR_STOP), () -> { }), - createButton(Container.i18n().bind(I18n.TOOLBAR_EXPORT), () -> { })); + final Label icon = new Label(); + icon.getStyleClass().add("studio-run-toggle-icon"); + icon.textProperty().bind(Bindings.when(running).then("\u25A0").otherwise("\u25B6")); + + final StackPane iconShell = new StackPane(icon); + iconShell.getStyleClass().add("studio-run-toggle-icon-shell"); + + final Label text = new Label(); + text.getStyleClass().add("studio-run-toggle-text"); + text.textProperty().bind(Bindings.createStringBinding( + () -> Container.i18n().text(running.get() ? I18n.TOOLBAR_STOP : I18n.TOOLBAR_PLAY), + running)); + + final HBox content = new HBox(8, iconShell, text); + content.setAlignment(Pos.CENTER_LEFT); + + final Button toggleButton = new Button(); + toggleButton.getStyleClass().add("studio-run-toggle-button"); + toggleButton.graphicProperty().set(content); + toggleButton.setOnAction(ignored -> running.set(!running.get())); + + running.addListener((ignored, oldValue, newValue) -> { + toggleButton.getStyleClass().removeAll("studio-run-toggle-play", "studio-run-toggle-stop"); + toggleButton.getStyleClass().add(newValue ? "studio-run-toggle-stop" : "studio-run-toggle-play"); + }); + toggleButton.getStyleClass().add("studio-run-toggle-play"); + + getChildren().add(toggleButton); } - private Button createButton(ObservableValue text, Runnable action) { - final Button button = new Button(); - button.getStyleClass().add("studio-run-button"); - button.textProperty().bind(Objects.requireNonNull(text, "text")); - button.setOnAction(ignored -> Objects.requireNonNull(action, "action").run()); - return button; + public boolean isRunning() { + return running.get(); + } + + public BooleanProperty runningProperty() { + return running; } } diff --git a/prometeu-studio/src/main/java/p/studio/controls/shell/StudioShellTopBarControl.java b/prometeu-studio/src/main/java/p/studio/controls/shell/StudioShellTopBarControl.java index 5f750bf6..b5cf3cea 100644 --- a/prometeu-studio/src/main/java/p/studio/controls/shell/StudioShellTopBarControl.java +++ b/prometeu-studio/src/main/java/p/studio/controls/shell/StudioShellTopBarControl.java @@ -5,13 +5,10 @@ import javafx.scene.layout.BorderPane; import p.studio.controls.lifecycle.StudioControlLifecycle; import p.studio.controls.lifecycle.StudioControlLifecycleSupport; -import java.util.Objects; - public final class StudioShellTopBarControl extends BorderPane implements StudioControlLifecycle { - public StudioShellTopBarControl(Node menuBar, Node runSurface) { + public StudioShellTopBarControl(Node menuBar) { StudioControlLifecycleSupport.install(this, this); getStyleClass().add("studio-shell-top-bar"); - setLeft(Objects.requireNonNull(menuBar, "menuBar")); - setRight(Objects.requireNonNull(runSurface, "runSurface")); + setLeft(menuBar); } } diff --git a/prometeu-studio/src/main/java/p/studio/window/MainView.java b/prometeu-studio/src/main/java/p/studio/window/MainView.java index ca7aeda4..84307d6b 100644 --- a/prometeu-studio/src/main/java/p/studio/window/MainView.java +++ b/prometeu-studio/src/main/java/p/studio/window/MainView.java @@ -22,7 +22,7 @@ public final class MainView extends BorderPane { this.projectReference = projectReference; final var menuBar = new StudioShellMenuBarControl(); final var runSurface = new StudioRunSurfaceControl(); - setTop(new StudioShellTopBarControl(menuBar, runSurface)); + setTop(new StudioShellTopBarControl(menuBar)); host.register(new EditorWorkspace()); host.register(new PlaceholderWorkspace(WorkspaceId.ASSETS, I18n.WORKSPACE_ASSETS, "Assets")); @@ -31,8 +31,8 @@ public final class MainView extends BorderPane { final var workspaceRail = new StudioWorkspaceRailControl<>( List.of( - new StudioWorkspaceRailItem<>(WorkspaceId.EDITOR, "📝", Container.i18n().bind(I18n.WORKSPACE_CODE)), new StudioWorkspaceRailItem<>(WorkspaceId.ASSETS, "📦", Container.i18n().bind(I18n.WORKSPACE_ASSETS)), + new StudioWorkspaceRailItem<>(WorkspaceId.EDITOR, "📝", Container.i18n().bind(I18n.WORKSPACE_CODE)), new StudioWorkspaceRailItem<>(WorkspaceId.DEBUG, "🎮", Container.i18n().bind(I18n.WORKSPACE_DEBUG)), new StudioWorkspaceRailItem<>(WorkspaceId.SHIPPER, "⚙️", Container.i18n().bind(I18n.WORKSPACE_SHIPPER)) ), @@ -40,12 +40,13 @@ public final class MainView extends BorderPane { setLeft(workspaceRail); setCenter(host); setRight(new StudioRightUtilityPanelControl( + runSurface, Container.i18n().bind(I18n.SHELL_ACTIVITY), StudioRightUtilityPanelControl.createPlaceholderContent(Container.i18n().bind(I18n.SHELL_ACTIVITY)))); // default - workspaceRail.select(WorkspaceId.EDITOR); - showWorkspace(WorkspaceId.EDITOR); + workspaceRail.select(WorkspaceId.ASSETS); + showWorkspace(WorkspaceId.ASSETS); } public ProjectReference projectReference() { diff --git a/prometeu-studio/src/main/resources/themes/default-prometeu.css b/prometeu-studio/src/main/resources/themes/default-prometeu.css index 5d63d367..18deede6 100644 --- a/prometeu-studio/src/main/resources/themes/default-prometeu.css +++ b/prometeu-studio/src/main/resources/themes/default-prometeu.css @@ -11,25 +11,9 @@ -fx-padding: 0 12 0 0; } -.studio-run-button { - -fx-background-color: transparent; - -fx-text-fill: #d4d4d4; - -fx-font-size: 14px; - -fx-padding: 6 10 6 10; - -fx-background-radius: 6; -} - -.studio-run-button:hover { - -fx-background-color: #2a2d2e; -} - -.studio-run-button:pressed { - -fx-background-color: #37373d; -} - .studio-run-surface { - -fx-alignment: center-right; - -fx-padding: 6 0 6 0; + -fx-alignment: center; + -fx-padding: 12 12 0 12; } .studio-shell-menu-bar { @@ -63,10 +47,67 @@ -fx-border-width: 0 0 0 1; } +.studio-right-utility-layout { + -fx-padding: 0 0 10 0; +} + .studio-right-utility-tabs { -fx-background-color: transparent; } +.studio-run-toggle-button { + -fx-background-radius: 10; + -fx-padding: 10 14 10 14; + -fx-cursor: hand; + -fx-border-radius: 10; + -fx-border-width: 1; +} + +.studio-run-toggle-button:hover { + -fx-opacity: 0.95; +} + +.studio-run-toggle-button:pressed { + -fx-opacity: 0.85; +} + +.studio-run-toggle-play { + -fx-background-color: #173322; + -fx-border-color: #2f8f59; +} + +.studio-run-toggle-stop { + -fx-background-color: #3a1719; + -fx-border-color: #c24a54; +} + +.studio-run-toggle-icon-shell { + -fx-min-width: 24; + -fx-min-height: 24; + -fx-pref-width: 24; + -fx-pref-height: 24; + -fx-alignment: center; +} + +.studio-run-toggle-icon { + -fx-font-size: 15px; + -fx-font-weight: bold; +} + +.studio-run-toggle-play .studio-run-toggle-icon { + -fx-text-fill: #48d17c; +} + +.studio-run-toggle-stop .studio-run-toggle-icon { + -fx-text-fill: #ff5d66; +} + +.studio-run-toggle-text { + -fx-text-fill: #f7fbff; + -fx-font-size: 13px; + -fx-font-weight: bold; +} + .studio-utility-placeholder { -fx-text-fill: #d4d4d4; -fx-padding: 16;