Add exact Process selection and atomic column-slot group reorder
Preserve the full-desktop-1 captured source. Qualified previews inspect their exact subject read-only; group movement preserves source order and other columns. Native acceptance and strict-lint payload-size corrections follow separately.
This commit is contained in:
@@ -18,6 +18,7 @@ pub struct Request {
|
||||
pub route_segment: Option<(usize, Position)>,
|
||||
pub creation_point: Option<Position>,
|
||||
pub canvas: Option<route_edit::Context>,
|
||||
pub process: Option<crate::behavior::topology::Context>,
|
||||
pub source_file: Option<String>,
|
||||
}
|
||||
impl Request {
|
||||
@@ -32,6 +33,7 @@ impl Request {
|
||||
route_segment: None,
|
||||
creation_point: None,
|
||||
canvas: None,
|
||||
process: None,
|
||||
source_file: None,
|
||||
}
|
||||
}
|
||||
@@ -61,6 +63,9 @@ impl Opened {
|
||||
|| request
|
||||
.canvas
|
||||
.is_some_and(|c| Some(c) != current_canvas(app))
|
||||
|| request
|
||||
.process
|
||||
.is_some_and(|c| Some(c) != app.topology_context())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
@@ -88,6 +93,10 @@ impl Opened {
|
||||
.request
|
||||
.canvas
|
||||
.is_none_or(|c| Some(c) == current_canvas(app))
|
||||
&& self
|
||||
.request
|
||||
.process
|
||||
.is_none_or(|c| Some(c) == app.topology_context())
|
||||
&& self
|
||||
.request
|
||||
.source_file
|
||||
@@ -101,10 +110,24 @@ fn target_matches(app: &App, request: &Request) -> bool {
|
||||
let Some(target) = request.selection_target.as_deref() else {
|
||||
return true;
|
||||
};
|
||||
if request.canvas.is_none() || !app.multiselect_target_visible(target) {
|
||||
if (request.canvas.is_none() && request.process.is_none())
|
||||
|| !app.multiselect_target_visible(target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
match target {
|
||||
Target::ProcessOccurrence(endpoint) => {
|
||||
request.process.is_some()
|
||||
&& request.canvas.is_none()
|
||||
&& request.placement.is_none()
|
||||
&& endpoint.occurrence == request.object
|
||||
}
|
||||
Target::ProcessLink(id) | Target::ProcessPreviewLink { relation: id, .. } => {
|
||||
request.process.is_some()
|
||||
&& request.canvas.is_none()
|
||||
&& request.placement.is_none()
|
||||
&& *id == request.object
|
||||
}
|
||||
Target::Placement(id) => {
|
||||
request.placement == Some(*id)
|
||||
&& request
|
||||
@@ -132,7 +155,9 @@ fn current_canvas(app: &App) -> Option<route_edit::Context> {
|
||||
|
||||
fn current_diagram(app: &App) -> Option<Id> {
|
||||
if app.page == Page::Behavior {
|
||||
app.state_context().map(|context| context.diagram)
|
||||
app.topology_context()
|
||||
.map(|context| context.owner)
|
||||
.or_else(|| app.state_context().map(|context| context.diagram))
|
||||
} else {
|
||||
app.active_diagram
|
||||
}
|
||||
@@ -156,6 +181,7 @@ pub fn trigger(app: &App) -> iced::Element<'_, Message> {
|
||||
request.canvas = app.route_context();
|
||||
} else if app.page == Page::Behavior {
|
||||
request.canvas = app.state_context();
|
||||
request.process = app.topology_context();
|
||||
if let Some(target) = app.diagram_selection.as_ref().and_then(|s| s.primary()) {
|
||||
request.selection_target = Some(Box::new(target.clone()));
|
||||
request.placement = match target {
|
||||
@@ -233,7 +259,7 @@ pub fn popup(app: &App) -> Option<Menu<Message>> {
|
||||
});
|
||||
}
|
||||
let mut entries = vec![Entry::title(crate::views::short(p.named(id), 38))];
|
||||
if request.canvas.is_some()
|
||||
if (request.canvas.is_some() || request.process.is_some())
|
||||
&& let Some(context) = app.multiselect_context()
|
||||
{
|
||||
use crate::app::multiselect::{Choice, Event as SelectionEvent};
|
||||
@@ -311,11 +337,20 @@ pub fn popup(app: &App) -> Option<Menu<Message>> {
|
||||
)),
|
||||
true,
|
||||
));
|
||||
entries.push(item(
|
||||
"Hide selected placements",
|
||||
Message::DiagramSelection(SelectionEvent::Hide(snapshot.clone())),
|
||||
crate::app::multiselect::placements(&snapshot).is_some(),
|
||||
));
|
||||
if request.process.is_some() {
|
||||
entries.push(Entry::title(
|
||||
"Drag contributions within one column to reorder",
|
||||
));
|
||||
entries.push(Entry::disabled(
|
||||
"Hide unavailable · cards are model contributions",
|
||||
));
|
||||
} else {
|
||||
entries.push(item(
|
||||
"Hide selected placements",
|
||||
Message::DiagramSelection(SelectionEvent::Hide(snapshot.clone())),
|
||||
crate::app::multiselect::placements(&snapshot).is_some(),
|
||||
));
|
||||
}
|
||||
entries.push(Entry::disabled(
|
||||
"Delete selected from model (not yet available)",
|
||||
));
|
||||
@@ -327,6 +362,35 @@ pub fn popup(app: &App) -> Option<Menu<Message>> {
|
||||
});
|
||||
}
|
||||
entries.push(Entry::separator());
|
||||
if let Some(context) = request.process {
|
||||
let endpoint = match request.selection_target.as_deref() {
|
||||
Some(Target::ProcessOccurrence(endpoint))
|
||||
if !endpoint.references.is_empty() =>
|
||||
{
|
||||
Some(endpoint.clone())
|
||||
}
|
||||
Some(Target::ProcessPreviewLink { source, .. }) => Some(source.clone()),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(endpoint) = endpoint {
|
||||
entries.push(Entry::title("Reused contents · read-only in this process"));
|
||||
entries.push(item(
|
||||
"Open referenced definition",
|
||||
Message::TopologyCanvas(
|
||||
crate::behavior::topology::CanvasEvent::OpenQualified(
|
||||
context, endpoint,
|
||||
),
|
||||
),
|
||||
true,
|
||||
));
|
||||
return Some(Menu {
|
||||
token: opened.token,
|
||||
anchor: request.anchor,
|
||||
entries,
|
||||
on_close: Message::Menu(Event::Close),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if app.page == Page::Behavior
|
||||
|
||||
Reference in New Issue
Block a user