Keep allocation destinations readable without blocking collapsed header drops

This commit is contained in:
2026-09-12 04:34:02 -07:00
parent 76209cc186
commit 1b3c401a19
7 changed files with 416 additions and 157 deletions
+6 -35
View File
@@ -416,19 +416,11 @@ impl Rect {
&& other.position.x + other.size.width <= self.position.x + self.size.width
&& other.position.y + other.size.height <= self.position.y + self.size.height
}
fn overlaps(self, other: Self) -> bool {
self.position.x < other.position.x + other.size.width
&& other.position.x < self.position.x + self.size.width
&& self.position.y < other.position.y + other.size.height
&& other.position.y < self.position.y + self.size.height
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TargetPresentation {
pub placement: Id,
/// Exact frozen painted label bounds, supplied by the renderer/resolver.
pub label: Rect,
}
#[derive(Debug, Clone, Copy, PartialEq)]
@@ -526,29 +518,18 @@ pub fn place(
let mut unfolded = None;
if let Destination::Performer(performer) = plan.destination {
let target = presentation.target.ok_or_else(|| {
Refusal::LayoutRequired("The frozen performer label must be visible.".into())
Refusal::LayoutRequired("A visible accepted performer target is required.".into())
})?;
let node = diagram
.nodes
.get_mut(&target.placement)
.ok_or(Refusal::StaleScope)?;
let frozen_header = plan
let visible_target = plan
.before_visible
.nodes
.iter()
.find(|n| n.id == target.placement)
.map(|n| Rect {
position: n.position,
size: Size {
width: n.size.width,
height: n.size.height.min(62.),
},
});
if node.element != performer
|| frozen_header.is_none_or(|header| !header.contains(target.label))
|| !target.label.valid()
|| !presentation.viewport.contains(target.label)
{
.any(|n| n.id == target.placement && n.element == performer);
if node.element != performer || !visible_target {
return Err(Refusal::LayoutRequired(
"Make room or adjust the view, then drag again.".into(),
));
@@ -589,18 +570,8 @@ pub fn place(
"Make room or adjust the view, then drag again.".into(),
));
}
// A performer may legitimately enclose the work, but its frozen feedback
// label is painted above the candidate. Check their joint readability after
// projection, including same-performer moves; never shift either rectangle.
if presentation
.target
.is_some_and(|target| header.overlaps(target.label))
{
return Err(Refusal::LayoutRequired(
"The work header overlaps the performer label. Aim below or beside the label, then drag again."
.into(),
));
}
// Destination identity lives in a fixed toolbar slot. Frozen hit geometry
// and its outline never introduce an opaque label over this work header.
Ok(PlacementPlan {
diagram,
view,