feat(node_graph,effect_stack): programmatic selection and card selection events
NodeGraphView::set_selection selects nodes programmatically (emitting SelectionChanged); EffectStackDataSource::selected_effect highlights the chosen card and EffectStackEvent::CardSelected reports card clicks — the two-way clip/node selection sync between the timeline, node editor and inspector.
This commit is contained in:
@@ -198,6 +198,7 @@ impl StackDemoRoot {
|
||||
| EffectStackEvent::RemoveRequested(_)
|
||||
| EffectStackEvent::AddRequested { .. }
|
||||
| EffectStackEvent::ContextMenuRequested { .. }
|
||||
| EffectStackEvent::CardSelected { .. }
|
||||
| EffectStackEvent::ParameterChanged { .. } => {
|
||||
todo!("apply {event:?} to the mock model (or engine, in a real app)")
|
||||
}
|
||||
|
||||
@@ -162,6 +162,15 @@ pub trait EffectStackDataSource: 'static {
|
||||
/// state instead of cards and suppresses all card interactions.
|
||||
fn target_label(&self) -> Option<SharedString>;
|
||||
|
||||
/// The card the stack should highlight as selected — the effect whose
|
||||
/// node is selected in the node graph, when the two views are linked.
|
||||
/// `None` means no card is highlighted. Defaults to `None`.
|
||||
///
|
||||
/// This is a read-only selection mirror; the view never mutates it.
|
||||
fn selected_effect(&self) -> Option<EffectId> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Whether dropping the given effect at `new_index` (an index into the
|
||||
/// list returned by [`effects`](EffectStackDataSource::effects)) would
|
||||
/// be a valid reorder.
|
||||
|
||||
@@ -67,6 +67,14 @@ pub enum EffectStackEvent {
|
||||
/// The desired new expansion state.
|
||||
expanded: bool,
|
||||
},
|
||||
/// The user clicked a card header to select it (the same gesture that
|
||||
/// toggles expansion). Emitted alongside
|
||||
/// [`ExpansionToggled`](Self::ExpansionToggled) so hosts can sync the
|
||||
/// effect selection with the node graph (highlighting the effect's node).
|
||||
CardSelected {
|
||||
/// The clicked effect.
|
||||
effect: EffectId,
|
||||
},
|
||||
/// The user clicked the remove button on a removable card.
|
||||
RemoveRequested(EffectId),
|
||||
/// The user invoked an "add effect" affordance at a stack position.
|
||||
@@ -274,7 +282,9 @@ impl<D: EffectStackDataSource> EffectStackView<D> {
|
||||
}
|
||||
|
||||
/// Toggles a card's expansion by emitting
|
||||
/// [`EffectStackEvent::ExpansionToggled`].
|
||||
/// [`EffectStackEvent::ExpansionToggled`], and reports the card click as
|
||||
/// [`EffectStackEvent::CardSelected`] so hosts can sync the node-graph
|
||||
/// selection with the stack.
|
||||
fn toggle_expanded(&mut self, id: EffectId, cx: &mut Context<Self>) {
|
||||
self.drag_state = DragState::default();
|
||||
let expanded = self
|
||||
@@ -289,6 +299,7 @@ impl<D: EffectStackDataSource> EffectStackView<D> {
|
||||
effect: id,
|
||||
expanded,
|
||||
});
|
||||
cx.emit(EffectStackEvent::CardSelected { effect: id });
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
@@ -360,9 +371,9 @@ impl<D: EffectStackDataSource> Render for EffectStackView<D> {
|
||||
self.drag_state = DragState::default();
|
||||
}
|
||||
|
||||
let (label, effects) = {
|
||||
let (label, effects, selected_effect) = {
|
||||
let data = self.data.read(cx);
|
||||
(data.target_label(), data.effects())
|
||||
(data.target_label(), data.effects(), data.selected_effect())
|
||||
};
|
||||
let insertion_index = self.drag_state.insertion_index;
|
||||
let dragged_id = self.drag_state.dragged;
|
||||
@@ -532,7 +543,9 @@ impl<D: EffectStackDataSource> Render for EffectStackView<D> {
|
||||
.w_full()
|
||||
.rounded_md()
|
||||
.border_1()
|
||||
.border_color(if fixed {
|
||||
.border_color(if selected_effect == Some(id) {
|
||||
colors.selected
|
||||
} else if fixed {
|
||||
colors.border
|
||||
} else {
|
||||
colors.separator
|
||||
|
||||
@@ -318,6 +318,16 @@ impl<D: NodeGraphDataSource + 'static> NodeGraphView<D> {
|
||||
&mut self.state
|
||||
}
|
||||
|
||||
/// Programmatically replaces the selection (e.g. to sync the graph with
|
||||
/// a timeline selection or an inspector card click). Emits
|
||||
/// [`NodeGraphEvent::SelectionChanged`] when the set changed, so hosts
|
||||
/// keep their engine-side selection mirror consistent. Callers should
|
||||
/// not call `cx.notify()` on the view themselves — this method does.
|
||||
pub fn set_selection(&mut self, nodes: BTreeSet<NodeId>, cx: &mut Context<Self>) {
|
||||
self.set_selection_and_emit(nodes, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Returns the data-source entity this view renders.
|
||||
pub fn data(&self) -> &Entity<D> {
|
||||
&self.data
|
||||
|
||||
Reference in New Issue
Block a user