fix(ui): accept toolbar drops across panel labels and gaps (#454)
This commit is contained in:
1 parent
5c7149e57d
commit
ddd528abaf
4 files changed
+81
-7
No files matched your search
@@ -572,12 +572,6 @@ pub fn toolbar(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
let free_x = bx + drawn as f32 * 40.0;
|
||||
let free = Rect::from_min_size(pos2(free_x, top + 2.0), vec2((px + width - 4.0 - free_x).max(8.0), 38.0));
|
||||
let fresp = ui.interact(free, ui.id().with(("panel_free", panel)), if collapsed { Sense::click() } else { Sense::hover() });
|
||||
if fresp.dnd_hover_payload::<ToolbarDrag>().is_some() {
|
||||
painter.line_segment([pos2(free.left(), free.top() + 2.0), pos2(free.left(), free.bottom() - 2.0)], Stroke::new(2.0, t.accent));
|
||||
}
|
||||
if let Some(d) = fresp.dnd_release_payload::<ToolbarDrag>() {
|
||||
drop = Some((d.id, *panel, None));
|
||||
}
|
||||
let mut opened = false;
|
||||
if collapsed {
|
||||
// One button: the panel's first command's icon over a caret; it opens the
|
||||
@@ -691,6 +685,20 @@ pub fn toolbar(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
if lresp.clicked() {
|
||||
ui.ctx().data_mut(|d| d.insert_temp(egui::Id::new("sc_panel_open"), popup_id));
|
||||
}
|
||||
// Labels, gaps and margins append; actual buttons keep their insert-before target.
|
||||
// Respect the current layer so a dropdown covering the panel is not a drop target.
|
||||
let panel_rect = Rect::from_min_max(pos2(px, top + 2.0), pos2(px + width, r.bottom()));
|
||||
let over_button = ui
|
||||
.input(|input| input.pointer.hover_pos())
|
||||
.is_some_and(|p| (0..drawn).any(|i| Rect::from_min_size(pos2(bx + i as f32 * 40.0, top + 2.0), vec2(38.0, 38.0)).contains(p)));
|
||||
if !over_button && ui.rect_contains_pointer(panel_rect) && egui::DragAndDrop::payload::<ToolbarDrag>(ui.ctx()).is_some() {
|
||||
painter.line_segment([pos2(px + width - 4.0, top + 4.0), pos2(px + width - 4.0, top + 38.0)], Stroke::new(2.0, t.accent));
|
||||
if ui.input(|input| input.pointer.any_released())
|
||||
&& let Some(d) = egui::DragAndDrop::take_payload::<ToolbarDrag>(ui.ctx())
|
||||
{
|
||||
drop = Some((d.id, *panel, None));
|
||||
}
|
||||
}
|
||||
let open = ui.ctx().data(|d| d.get_temp::<egui::Id>(egui::Id::new("sc_panel_open"))) == Some(popup_id);
|
||||
if open {
|
||||
let cmds = if collapsed { menu_commands(&cmds, &shown) } else { cmds.clone() };
|
||||
@@ -1319,3 +1327,44 @@ mod dropdown_tests {
|
||||
assert!(menu.contains(*at), "the focused last row is out of view: {at:?} in {menu:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod panel_drop_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn panel_label_gap_and_margins_append_while_buttons_insert_before() {
|
||||
for target in ["label", "gap", "left margin", "right margin", "button"] {
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
h.step(&json!({"click":{"handle":"panel:SOLID:CREATE"}})).unwrap();
|
||||
let label = crate::scenario::handle_at("panel:SOLID:CREATE").unwrap();
|
||||
let destination = match target {
|
||||
"gap" => label - vec2(0.0, 10.0),
|
||||
"left margin" => pos2(label.x - panel_width(4) / 2.0 + 1.0, label.y - 30.0),
|
||||
"right margin" => pos2(label.x + panel_width(4) / 2.0 - 1.0, label.y - 30.0),
|
||||
"button" => crate::scenario::handle_at("button:solid.extrude").unwrap(),
|
||||
_ => label,
|
||||
};
|
||||
h.step(&json!({"drag":[{"handle":"dropdown:solid.cylinder"}, [destination.x,destination.y]],"steps":12})).unwrap();
|
||||
h.step(&json!({"key":"Escape"})).unwrap();
|
||||
let order = if target == "button" {
|
||||
json!(["button:sketch.create", "button:solid.cylinder", "button:solid.extrude", "button:solid.revolve", "button:solid.sweep"])
|
||||
} else {
|
||||
json!(["button:sketch.create", "button:solid.extrude", "button:solid.revolve", "button:solid.sweep", "button:solid.cylinder"])
|
||||
};
|
||||
h.step(&json!({"expect":{"handle_order":order,"tool":null,"dialog":null,"errors":0}})).unwrap();
|
||||
assert!(h.app.session.doc.features.is_empty(), "{target}: pinning must not run the command");
|
||||
h.step(&json!({"restart":"close"})).unwrap();
|
||||
h.step(&json!({"expect":{"handle_order":order}})).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn panel_label_drop_moves_a_button_between_panels() {
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
h.step(&json!({"drag":[{"handle":"button:solid.extrude"},{"handle":"panel:SOLID:MODIFY"}],"steps":12})).unwrap();
|
||||
h.step(&json!({"expect":{"handle_order":["button:solid.fillet","button:solid.chamfer","button:solid.scale","button:solid.extrude"],"tool":null,"dialog":null,"errors":0}})).unwrap();
|
||||
h.step(&json!({"restart":"close"})).unwrap();
|
||||
h.step(&json!({"expect":{"handle_order":["button:solid.scale","button:solid.extrude"]}})).unwrap();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user