mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-28 08:58:07 +00:00
Small batch of misc enhancements (#64)
This PR cherry-picks some improvements from #63 that are general-purpose and not specifically related to IK. * Some logic has been added to `AppElement` to track the currently selected Scene Element * `disabled` property has been added to `ButtonElement`, with custom styling and accessibility features * Tagging entities with their `SceneElement` type has been made more robust and reliable (previously, it was possible for all entities to appear in the hierarchy as "Generic" elements depending on the order of system execution) Additionally: * Forces the Netlify CI pipeline to always used the latest stable Rust version
This commit is contained in:
@@ -3,10 +3,12 @@
|
||||
set -euxo pipefail
|
||||
|
||||
# Install build dependencies
|
||||
rustup update
|
||||
rustup default stable
|
||||
rustup target add wasm32-unknown-unknown
|
||||
|
||||
# Emit versions
|
||||
rustup show active-toolchain
|
||||
rustup show
|
||||
npm version
|
||||
|
||||
# Install project dependencies
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import { on } from "@storyteller/framework";
|
||||
import * as studio from "@storyteller/studio";
|
||||
import {
|
||||
type EntitySelectEvent,
|
||||
type SceneSavedEvent,
|
||||
type SceneStateEvent,
|
||||
SceneState,
|
||||
StudioMode,
|
||||
} from "@storyteller/studio";
|
||||
import { StudioURLParams } from "@storyteller/studio-web";
|
||||
import {
|
||||
SceneHierarchyElement,
|
||||
type SceneObject,
|
||||
StudioURLParams,
|
||||
} from "@storyteller/studio-web";
|
||||
import { CanvasProvider } from "@storyteller/studio-web/canvas-provider";
|
||||
import { match } from "@storyteller/utility";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
@@ -33,6 +38,9 @@ export class AppElement extends LitElement {
|
||||
@state() showHelp = false;
|
||||
@state() loading = true;
|
||||
|
||||
@state() selection?: SceneObject;
|
||||
|
||||
#hierarchy = createRef<SceneHierarchyElement>();
|
||||
#params = new StudioURLParams();
|
||||
#canvasProvider: Ref<CanvasProvider> = createRef();
|
||||
|
||||
@@ -79,6 +87,15 @@ export class AppElement extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
@on("entity-select")
|
||||
onEntitySelected({ detail: id }: EntitySelectEvent): void {
|
||||
if (!id) {
|
||||
this.selection = undefined;
|
||||
} else {
|
||||
this.selection = this.#hierarchy.value?.entityMap.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
toggleHelp(): void {
|
||||
this.showHelp = !this.showHelp;
|
||||
}
|
||||
@@ -122,9 +139,16 @@ export class AppElement extends LitElement {
|
||||
|
||||
<!-- Studio-mode-only elements -->
|
||||
${this.#params.mode === StudioMode.Editor ? html`
|
||||
<sts-transform-toolbar class="v-start h-center"></sts-transform-toolbar>
|
||||
<sts-scene-hierarchy class="hierarchy v-start h-end"></sts-scene-hierarchy>
|
||||
<sts-anim-editor class="timeline v-end h-start h-before-hierarchy"></sts-anim-editor>
|
||||
<sts-transform-toolbar
|
||||
class="v-start h-center"
|
||||
></sts-transform-toolbar>
|
||||
<sts-scene-hierarchy
|
||||
class="hierarchy v-start h-end"
|
||||
${ref(this.#hierarchy)}
|
||||
></sts-scene-hierarchy>
|
||||
<sts-anim-editor
|
||||
class="timeline v-end h-start h-before-hierarchy"
|
||||
></sts-anim-editor>
|
||||
` : nothing}
|
||||
|
||||
<!-- Dialogs and modals -->
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
color: #FFFF;
|
||||
}
|
||||
|
||||
:host(.disabled),
|
||||
:host(.disabled:hover) {
|
||||
background: #0003;
|
||||
color: #FFF6;
|
||||
}
|
||||
|
||||
.icon {
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { on } from "@storyteller/framework";
|
||||
import { LitElement, html, nothing, unsafeCSS } from "lit";
|
||||
import { LitElement, type PropertyValues, html, nothing, unsafeCSS } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import styles from "./button.element.scss?inline";
|
||||
@@ -11,10 +11,21 @@ export class ButtonElement extends LitElement {
|
||||
static override styles = unsafeCSS(styles);
|
||||
|
||||
@property() icon?: string;
|
||||
@property({ type: Boolean }) disabled = false;
|
||||
|
||||
override role = "button";
|
||||
override tabIndex = 0;
|
||||
|
||||
protected override willUpdate(changes: PropertyValues<this>): void {
|
||||
if (changes.has("disabled")) {
|
||||
this.ariaDisabled = this.disabled ? "true" : null;
|
||||
this.tabIndex = this.disabled ? -1 : 0;
|
||||
this.classList.toggle("disabled", this.disabled);
|
||||
}
|
||||
|
||||
super.willUpdate(changes);
|
||||
}
|
||||
|
||||
@on("keydown")
|
||||
onKeyDown(event: KeyboardEvent) {
|
||||
if (/^( |Enter)$/.test(event.key)) {
|
||||
|
||||
@@ -14,7 +14,7 @@ import styles from "./scene-hierarchy.element.scss?inline";
|
||||
|
||||
import "@storyteller/studio-ui/tree";
|
||||
|
||||
interface SceneObject extends Omit<studio.SceneObject, "icon"|"children"> {
|
||||
export interface SceneObject extends Omit<studio.SceneObject, "children"> {
|
||||
icon?: string;
|
||||
children: SceneObject[];
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ pub(super) fn notify_entity_spawn_changes(
|
||||
mut l_missing_parents: Local<VecDeque<Entity>>,
|
||||
q_window: Query<&Window, With<PrimaryWindow>>,
|
||||
q_inspectables: Query<(Entity, &SceneElement)>,
|
||||
q_element_changes: Query<Entity, Changed<SceneElement>>,
|
||||
q_others: Query<Entity, Without<SceneElement>>,
|
||||
q_names: Query<&Name>,
|
||||
q_parents: Query<&Children>,
|
||||
@@ -146,6 +147,7 @@ pub(super) fn notify_entity_spawn_changes(
|
||||
ent,
|
||||
type_,
|
||||
&q_inspectables,
|
||||
&q_element_changes,
|
||||
&q_names,
|
||||
&q_parents,
|
||||
&q_children,
|
||||
@@ -166,6 +168,7 @@ pub(super) fn notify_entity_spawn_changes(
|
||||
ent,
|
||||
SceneElement::Generic,
|
||||
&q_inspectables,
|
||||
&q_element_changes,
|
||||
&q_names,
|
||||
&q_parents,
|
||||
&q_children,
|
||||
@@ -204,11 +207,12 @@ fn build_scene_object(
|
||||
ent: Entity,
|
||||
type_: SceneElement,
|
||||
q_inspectables: &Query<(Entity, &SceneElement)>,
|
||||
q_element_changes: &Query<Entity, Changed<SceneElement>>,
|
||||
q_names: &Query<&Name>,
|
||||
q_parents: &Query<&Children>,
|
||||
q_children: &Query<&Parent>,
|
||||
) -> Option<SceneObject> {
|
||||
if notified.contains(&ent) {
|
||||
if notified.contains(&ent) && !q_element_changes.contains(ent) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
+2
-11
@@ -233,13 +233,13 @@ pub struct ImportSceneEvent(pub String);
|
||||
derive(Serialize_repr, Deserialize_repr)
|
||||
)]
|
||||
#[derive(Component, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[allow(dead_code)] // Some variants only used in `wasm`, some planned for later use
|
||||
pub enum SceneElement {
|
||||
Generic,
|
||||
Mesh,
|
||||
Skeleton,
|
||||
Bone,
|
||||
Light,
|
||||
#[allow(dead_code)] // TODO: Will be used for camera animation
|
||||
Camera,
|
||||
}
|
||||
|
||||
@@ -395,17 +395,8 @@ fn tag_scene_elements(
|
||||
mesh_entities: Query<Entity, With<Handle<Mesh>>>,
|
||||
) {
|
||||
for (e, children) in q_named_non_primitives.iter() {
|
||||
let mut has_mesh = false;
|
||||
for child in children {
|
||||
if mesh_entities.contains(*child) {
|
||||
has_mesh = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if has_mesh {
|
||||
if children.iter().any(|child| mesh_entities.contains(*child)) {
|
||||
cmd.entity(e).insert(SceneElement::Mesh);
|
||||
} else {
|
||||
cmd.entity(e).insert(SceneElement::Generic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user