fix(statusbar): open the layout context menu at the clicked tab
The right-click menu was pinned to the screen's bottom-left corner. Each layout tab now records its screen bounds through a PosReport wrapper (which learned runtime-built ids for the dynamic tab names), and the menu anchors next to the clicked tab via the shared status-bar popup positioning, falling back to the left edge only when no bounds were recorded (#428). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8821bb7131
commit
d6b1307a0e
4 changed files with 30 additions and 20 deletions
|
|
@ -1505,7 +1505,7 @@ impl OpenCADStudio {
|
|||
.unwrap_or_else(|| iced::widget::Space::new().width(0).height(0).into());
|
||||
|
||||
let layout_ctx_layer: Element<'_, Message> = if let Some(name) = &self.layout_context_menu {
|
||||
layout_context_menu_overlay(name)
|
||||
layout_context_menu_overlay(name, win)
|
||||
} else {
|
||||
iced::widget::Space::new().width(0).height(0).into()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -935,7 +935,7 @@ pub(super) fn viewport_context_menu_overlay(
|
|||
|
||||
/// A small right-click context menu rendered above the status bar.
|
||||
/// The `name` is the layout tab that was right-clicked.
|
||||
pub(super) fn layout_context_menu_overlay(name: &str) -> Element<'_, Message> {
|
||||
pub(super) fn layout_context_menu_overlay(name: &str, win: (f32, f32)) -> Element<'_, Message> {
|
||||
const MENU_BG: Color = Color {
|
||||
r: 0.17,
|
||||
g: 0.17,
|
||||
|
|
@ -1009,16 +1009,12 @@ pub(super) fn layout_context_menu_overlay(name: &str) -> Element<'_, Message> {
|
|||
.on_press(Message::LayoutContextMenuClose)
|
||||
.on_right_press(Message::LayoutContextMenuClose);
|
||||
|
||||
// Position the menu above the status bar at the left.
|
||||
let positioned = container(menu)
|
||||
.align_bottom(Fill)
|
||||
.align_left(Fill)
|
||||
.padding(iced::Padding {
|
||||
top: 0.0,
|
||||
right: 0.0,
|
||||
bottom: 30.0,
|
||||
left: 8.0,
|
||||
});
|
||||
// Anchor the menu above the status bar next to the right-clicked tab —
|
||||
// its bounds were recorded by the tab's PosReport wrapper (#428). A
|
||||
// missing report (shouldn't happen) falls back to the left edge.
|
||||
let pill = crate::ui::wrap_bar::dropdown_bounds(&format!("SB_LAYOUT_TAB:{name}"));
|
||||
let positioned =
|
||||
crate::ui::popup::position_statusbar_popup(menu.into(), pill, win, 160.0, false);
|
||||
|
||||
stack![catcher, positioned].into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -742,10 +742,16 @@ fn space_tab<'a>(
|
|||
let ctx_msg = Message::LayoutContextMenu(label.clone());
|
||||
|
||||
// Use mouse_area so we can capture right-click for the context menu.
|
||||
mouse_area(display)
|
||||
.on_press(switch_msg)
|
||||
.on_right_press(ctx_msg)
|
||||
.into()
|
||||
// PosReport records the tab's screen bounds so the context menu can
|
||||
// anchor next to the clicked tab instead of the screen's left edge
|
||||
// (#428).
|
||||
crate::ui::wrap_bar::PosReport::owned(
|
||||
format!("SB_LAYOUT_TAB:{label}"),
|
||||
mouse_area(display)
|
||||
.on_press(switch_msg)
|
||||
.on_right_press(ctx_msg),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ thread_local! {
|
|||
/// Screen bounds of every ribbon dropdown button, keyed by dropdown id, so
|
||||
/// an open dropdown's overlay can anchor directly below its widget at any
|
||||
/// size. Written by `PosReport` on draw, read by `dropdown_bounds`.
|
||||
static DD_BOUNDS: RefCell<FxHashMap<&'static str, Rectangle>> =
|
||||
static DD_BOUNDS: RefCell<FxHashMap<String, Rectangle>> =
|
||||
RefCell::new(FxHashMap::default());
|
||||
}
|
||||
|
||||
|
|
@ -871,14 +871,22 @@ impl<'a> From<DensitySwap<'a>> for Element<'a, Message> {
|
|||
/// A transparent wrapper that records its child's screen bounds under `id` on
|
||||
/// every draw, so an open dropdown can anchor its overlay just below the widget.
|
||||
pub struct PosReport<'a> {
|
||||
id: &'static str,
|
||||
id: std::borrow::Cow<'static, str>,
|
||||
child: Element<'a, Message>,
|
||||
}
|
||||
|
||||
impl<'a> PosReport<'a> {
|
||||
pub fn new(id: &'static str, child: impl Into<Element<'a, Message>>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
id: std::borrow::Cow::Borrowed(id),
|
||||
child: child.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Report under a runtime-built id (e.g. one per layout tab).
|
||||
pub fn owned(id: String, child: impl Into<Element<'a, Message>>) -> Self {
|
||||
Self {
|
||||
id: std::borrow::Cow::Owned(id),
|
||||
child: child.into(),
|
||||
}
|
||||
}
|
||||
|
|
@ -971,7 +979,7 @@ impl<'a> Widget<Message, Theme, Renderer> for PosReport<'a> {
|
|||
viewport: &Rectangle,
|
||||
) {
|
||||
DD_BOUNDS.with(|m| {
|
||||
m.borrow_mut().insert(self.id, layout.bounds());
|
||||
m.borrow_mut().insert(self.id.to_string(), layout.bounds());
|
||||
});
|
||||
self.child.as_widget().draw(
|
||||
&tree.children[0],
|
||||
|
|
|
|||
Loading…
Reference in a new issue