implements PR-07b asset navigator and row subscriptions
This commit is contained in:
parent
c351814b6f
commit
3e0592e75c
@ -1,16 +1,13 @@
|
|||||||
package p.studio.workspaces.assets;
|
package p.studio.workspaces.assets;
|
||||||
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.control.ToggleButton;
|
import javafx.scene.control.ToggleButton;
|
||||||
import javafx.scene.layout.FlowPane;
|
import javafx.scene.layout.FlowPane;
|
||||||
import javafx.scene.layout.HBox;
|
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.Region;
|
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import p.studio.Container;
|
import p.studio.Container;
|
||||||
import p.studio.controls.lifecycle.StudioControlLifecycle;
|
import p.studio.controls.lifecycle.StudioControlLifecycle;
|
||||||
@ -41,6 +38,7 @@ final class AssetWorkspaceNavigatorControl extends VBox implements StudioControl
|
|||||||
|
|
||||||
private AssetWorkspaceNavigatorViewState viewState;
|
private AssetWorkspaceNavigatorViewState viewState;
|
||||||
private EnumSet<AssetNavigatorFilter> activeFilters = EnumSet.noneOf(AssetNavigatorFilter.class);
|
private EnumSet<AssetNavigatorFilter> activeFilters = EnumSet.noneOf(AssetNavigatorFilter.class);
|
||||||
|
private String projectionSignature = "";
|
||||||
|
|
||||||
AssetWorkspaceNavigatorControl(
|
AssetWorkspaceNavigatorControl(
|
||||||
ProjectReference projectReference,
|
ProjectReference projectReference,
|
||||||
@ -136,10 +134,16 @@ final class AssetWorkspaceNavigatorControl extends VBox implements StudioControl
|
|||||||
|
|
||||||
navigatorStateLabel.setText(viewState.message());
|
navigatorStateLabel.setText(viewState.message());
|
||||||
if (!viewState.hasProjection()) {
|
if (!viewState.hasProjection()) {
|
||||||
|
projectionSignature = "";
|
||||||
navigatorContent.getChildren().setAll(createMessage(viewState.message()));
|
navigatorContent.getChildren().setAll(createMessage(viewState.message()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String nextSignature = projectionSignature(viewState.projection());
|
||||||
|
if (Objects.equals(projectionSignature, nextSignature)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
projectionSignature = nextSignature;
|
||||||
navigatorContent.getChildren().clear();
|
navigatorContent.getChildren().clear();
|
||||||
for (AssetNavigatorGroup group : viewState.projection().groups()) {
|
for (AssetNavigatorGroup group : viewState.projection().groups()) {
|
||||||
final VBox groupBox = new VBox(6);
|
final VBox groupBox = new VBox(6);
|
||||||
@ -150,61 +154,18 @@ final class AssetWorkspaceNavigatorControl extends VBox implements StudioControl
|
|||||||
groupBox.getChildren().add(groupLabel);
|
groupBox.getChildren().add(groupLabel);
|
||||||
|
|
||||||
for (AssetWorkspaceAssetSummary asset : group.assets()) {
|
for (AssetWorkspaceAssetSummary asset : group.assets()) {
|
||||||
groupBox.getChildren().add(createAssetRow(asset, asset.selectionKey().equals(viewState.workspaceState().selectedKey())));
|
groupBox.getChildren().add(new AssetWorkspaceNavigatorRowControl(
|
||||||
|
projectReference,
|
||||||
|
workspaceBus,
|
||||||
|
interactions,
|
||||||
|
asset,
|
||||||
|
asset.selectionKey().equals(viewState.workspaceState().selectedKey())));
|
||||||
}
|
}
|
||||||
|
|
||||||
navigatorContent.getChildren().add(groupBox);
|
navigatorContent.getChildren().add(groupBox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node createAssetRow(AssetWorkspaceAssetSummary asset, boolean selected) {
|
|
||||||
final VBox row = new VBox(4);
|
|
||||||
row.getStyleClass().add("assets-workspace-asset-row");
|
|
||||||
row.getStyleClass().add(assetRowToneClass(asset.assetFamily()));
|
|
||||||
updateAssetRowSelection(row, selected);
|
|
||||||
|
|
||||||
final HBox topLine = new HBox(8);
|
|
||||||
topLine.setAlignment(Pos.CENTER_LEFT);
|
|
||||||
final Label name = new Label(asset.assetName());
|
|
||||||
name.getStyleClass().add("assets-workspace-asset-name");
|
|
||||||
name.getStyleClass().add(assetNameToneClass(asset.assetFamily()));
|
|
||||||
final Region spacer = new Region();
|
|
||||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
|
||||||
final HBox badges = new HBox(6);
|
|
||||||
badges.setAlignment(Pos.CENTER_RIGHT);
|
|
||||||
badges.getStyleClass().add("assets-workspace-asset-badges");
|
|
||||||
if (asset.state() == AssetWorkspaceAssetState.UNREGISTERED) {
|
|
||||||
badges.getChildren().add(createBadge(Container.i18n().text(I18n.ASSETS_BADGE_UNREGISTERED), "assets-workspace-badge-orphan"));
|
|
||||||
} else if (asset.buildParticipation() == AssetWorkspaceBuildParticipation.INCLUDED) {
|
|
||||||
badges.getChildren().add(createBadge(buildParticipationLabel(asset.buildParticipation()), "assets-workspace-badge-preload"));
|
|
||||||
if (asset.preload()) {
|
|
||||||
badges.getChildren().add(createBadge(Container.i18n().text(I18n.ASSETS_BADGE_PRELOAD), "assets-workspace-badge-preload"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
badges.getChildren().add(createBadge(buildParticipationLabel(asset.buildParticipation()), "assets-workspace-badge-diagnostics"));
|
|
||||||
}
|
|
||||||
if (asset.hasDiagnostics()) {
|
|
||||||
badges.getChildren().add(createBadge(Container.i18n().text(I18n.ASSETS_BADGE_DIAGNOSTICS), "assets-workspace-badge-diagnostics"));
|
|
||||||
}
|
|
||||||
topLine.getChildren().addAll(name, spacer, badges);
|
|
||||||
|
|
||||||
final Label path = new Label(AssetNavigatorProjectionBuilder.relativeRoot(asset, projectRoot));
|
|
||||||
path.getStyleClass().add("assets-workspace-asset-path");
|
|
||||||
row.getChildren().addAll(topLine, path);
|
|
||||||
row.setOnMouseClicked(event -> interactions.selectAsset(asset.selectionKey()));
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateAssetRowSelection(VBox row, boolean selected) {
|
|
||||||
if (selected) {
|
|
||||||
if (!row.getStyleClass().contains("assets-workspace-asset-row-selected")) {
|
|
||||||
row.getStyleClass().add("assets-workspace-asset-row-selected");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
row.getStyleClass().remove("assets-workspace-asset-row-selected");
|
|
||||||
}
|
|
||||||
|
|
||||||
private Node createMessage(String text) {
|
private Node createMessage(String text) {
|
||||||
final Label label = new Label(text);
|
final Label label = new Label(text);
|
||||||
label.getStyleClass().add("assets-workspace-empty-state");
|
label.getStyleClass().add("assets-workspace-empty-state");
|
||||||
@ -212,35 +173,15 @@ final class AssetWorkspaceNavigatorControl extends VBox implements StudioControl
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node createBadge(String text, String styleClass) {
|
private String projectionSignature(AssetNavigatorProjection projection) {
|
||||||
final Label badge = new Label(text);
|
final StringBuilder signature = new StringBuilder();
|
||||||
badge.getStyleClass().add("assets-workspace-badge");
|
for (AssetNavigatorGroup group : projection.groups()) {
|
||||||
badge.getStyleClass().add(styleClass);
|
signature.append(group.label()).append('|');
|
||||||
return badge;
|
for (AssetWorkspaceAssetSummary asset : group.assets()) {
|
||||||
}
|
signature.append(asset.selectionKey().stableKey()).append(',');
|
||||||
|
}
|
||||||
private String buildParticipationLabel(AssetWorkspaceBuildParticipation buildParticipation) {
|
signature.append(';');
|
||||||
return switch (buildParticipation) {
|
}
|
||||||
case INCLUDED -> Container.i18n().text(I18n.ASSETS_VALUE_INCLUDED);
|
return signature.toString();
|
||||||
case EXCLUDED -> Container.i18n().text(I18n.ASSETS_VALUE_EXCLUDED);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private String assetRowToneClass(String assetFamily) {
|
|
||||||
return switch (assetFamily == null ? "" : assetFamily.toLowerCase()) {
|
|
||||||
case "image_bank" -> "assets-workspace-asset-row-image";
|
|
||||||
case "palette_bank" -> "assets-workspace-asset-row-palette";
|
|
||||||
case "sound_bank" -> "assets-workspace-asset-row-sound";
|
|
||||||
default -> "assets-workspace-asset-row-generic";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private String assetNameToneClass(String assetFamily) {
|
|
||||||
return switch (assetFamily == null ? "" : assetFamily.toLowerCase()) {
|
|
||||||
case "image_bank" -> "assets-workspace-asset-name-image";
|
|
||||||
case "palette_bank" -> "assets-workspace-asset-name-palette";
|
|
||||||
case "sound_bank" -> "assets-workspace-asset-name-sound";
|
|
||||||
default -> "assets-workspace-asset-name-generic";
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,153 @@
|
|||||||
|
package p.studio.workspaces.assets;
|
||||||
|
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Priority;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import p.studio.Container;
|
||||||
|
import p.studio.controls.lifecycle.StudioControlLifecycle;
|
||||||
|
import p.studio.controls.lifecycle.StudioControlLifecycleSupport;
|
||||||
|
import p.studio.events.StudioAssetsAssetSummaryPatchedEvent;
|
||||||
|
import p.studio.events.StudioAssetsWorkspaceSelectionChangedEvent;
|
||||||
|
import p.studio.events.StudioWorkspaceEventBus;
|
||||||
|
import p.studio.projects.ProjectReference;
|
||||||
|
import p.studio.utilities.i18n.I18n;
|
||||||
|
import p.studio.workspaces.framework.StudioSubscriptionBag;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
final class AssetWorkspaceNavigatorRowControl extends VBox implements StudioControlLifecycle {
|
||||||
|
private final ProjectReference projectReference;
|
||||||
|
private final Path projectRoot;
|
||||||
|
private final StudioWorkspaceEventBus workspaceBus;
|
||||||
|
private final AssetWorkspaceInteractionPort interactions;
|
||||||
|
private final StudioSubscriptionBag subscriptions = new StudioSubscriptionBag();
|
||||||
|
|
||||||
|
private AssetWorkspaceAssetSummary summary;
|
||||||
|
private boolean selected;
|
||||||
|
|
||||||
|
AssetWorkspaceNavigatorRowControl(
|
||||||
|
ProjectReference projectReference,
|
||||||
|
StudioWorkspaceEventBus workspaceBus,
|
||||||
|
AssetWorkspaceInteractionPort interactions,
|
||||||
|
AssetWorkspaceAssetSummary summary,
|
||||||
|
boolean selected) {
|
||||||
|
StudioControlLifecycleSupport.install(this, this);
|
||||||
|
this.projectReference = Objects.requireNonNull(projectReference, "projectReference");
|
||||||
|
this.projectRoot = this.projectReference.rootPath();
|
||||||
|
this.workspaceBus = Objects.requireNonNull(workspaceBus, "workspaceBus");
|
||||||
|
this.interactions = Objects.requireNonNull(interactions, "interactions");
|
||||||
|
this.summary = Objects.requireNonNull(summary, "summary");
|
||||||
|
this.selected = selected;
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void subscribe() {
|
||||||
|
subscriptions.add(workspaceBus.subscribe(StudioAssetsWorkspaceSelectionChangedEvent.class, event -> {
|
||||||
|
if (projectReference.equals(event.project())) {
|
||||||
|
updateSelection(event.selectionKey().equals(summary.selectionKey()));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
subscriptions.add(workspaceBus.subscribe(StudioAssetsAssetSummaryPatchedEvent.class, event -> {
|
||||||
|
if (projectReference.equals(event.project())
|
||||||
|
&& summary.selectionKey().equals(event.summary().selectionKey())) {
|
||||||
|
summary = event.summary();
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unsubscribe() {
|
||||||
|
subscriptions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSelection(boolean selected) {
|
||||||
|
if (this.selected == selected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selected = selected;
|
||||||
|
renderSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void render() {
|
||||||
|
getChildren().clear();
|
||||||
|
getStyleClass().setAll("assets-workspace-asset-row", assetRowToneClass(summary.assetFamily()));
|
||||||
|
renderSelection();
|
||||||
|
|
||||||
|
final HBox topLine = new HBox(8);
|
||||||
|
topLine.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
final Label name = new Label(summary.assetName());
|
||||||
|
name.getStyleClass().addAll("assets-workspace-asset-name", assetNameToneClass(summary.assetFamily()));
|
||||||
|
final Region spacer = new Region();
|
||||||
|
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||||
|
final HBox badges = new HBox(6);
|
||||||
|
badges.setAlignment(Pos.CENTER_RIGHT);
|
||||||
|
badges.getStyleClass().add("assets-workspace-asset-badges");
|
||||||
|
populateBadges(badges);
|
||||||
|
topLine.getChildren().addAll(name, spacer, badges);
|
||||||
|
|
||||||
|
final Label path = new Label(AssetNavigatorProjectionBuilder.relativeRoot(summary, projectRoot));
|
||||||
|
path.getStyleClass().add("assets-workspace-asset-path");
|
||||||
|
getChildren().setAll(topLine, path);
|
||||||
|
setOnMouseClicked(event -> interactions.selectAsset(summary.selectionKey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderSelection() {
|
||||||
|
getStyleClass().remove("assets-workspace-asset-row-selected");
|
||||||
|
if (selected) {
|
||||||
|
getStyleClass().add("assets-workspace-asset-row-selected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateBadges(HBox badges) {
|
||||||
|
if (summary.state() == AssetWorkspaceAssetState.UNREGISTERED) {
|
||||||
|
badges.getChildren().add(createBadge(Container.i18n().text(I18n.ASSETS_BADGE_UNREGISTERED), "assets-workspace-badge-orphan"));
|
||||||
|
} else if (summary.buildParticipation() == AssetWorkspaceBuildParticipation.INCLUDED) {
|
||||||
|
badges.getChildren().add(createBadge(buildParticipationLabel(summary.buildParticipation()), "assets-workspace-badge-preload"));
|
||||||
|
if (summary.preload()) {
|
||||||
|
badges.getChildren().add(createBadge(Container.i18n().text(I18n.ASSETS_BADGE_PRELOAD), "assets-workspace-badge-preload"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
badges.getChildren().add(createBadge(buildParticipationLabel(summary.buildParticipation()), "assets-workspace-badge-diagnostics"));
|
||||||
|
}
|
||||||
|
if (summary.hasDiagnostics()) {
|
||||||
|
badges.getChildren().add(createBadge(Container.i18n().text(I18n.ASSETS_BADGE_DIAGNOSTICS), "assets-workspace-badge-diagnostics"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label createBadge(String text, String styleClass) {
|
||||||
|
final Label badge = new Label(text);
|
||||||
|
badge.getStyleClass().addAll("assets-workspace-badge", styleClass);
|
||||||
|
return badge;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildParticipationLabel(AssetWorkspaceBuildParticipation buildParticipation) {
|
||||||
|
return switch (buildParticipation) {
|
||||||
|
case INCLUDED -> Container.i18n().text(I18n.ASSETS_VALUE_INCLUDED);
|
||||||
|
case EXCLUDED -> Container.i18n().text(I18n.ASSETS_VALUE_EXCLUDED);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String assetRowToneClass(String assetFamily) {
|
||||||
|
return switch (assetFamily == null ? "" : assetFamily.toLowerCase()) {
|
||||||
|
case "image_bank" -> "assets-workspace-asset-row-image";
|
||||||
|
case "palette_bank" -> "assets-workspace-asset-row-palette";
|
||||||
|
case "sound_bank" -> "assets-workspace-asset-row-sound";
|
||||||
|
default -> "assets-workspace-asset-row-generic";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String assetNameToneClass(String assetFamily) {
|
||||||
|
return switch (assetFamily == null ? "" : assetFamily.toLowerCase()) {
|
||||||
|
case "image_bank" -> "assets-workspace-asset-name-image";
|
||||||
|
case "palette_bank" -> "assets-workspace-asset-name-palette";
|
||||||
|
case "sound_bank" -> "assets-workspace-asset-name-sound";
|
||||||
|
default -> "assets-workspace-asset-name-generic";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user