Files
OneCAD-Draft/src/ui/cycle_popup.rs
T
Hakan SevenandClaude Opus 4.8 bb54cd034f fix(statusbar): cycling-list hover highlight on row re-entry
Row exit now clears the preview only when the highlight still points at
that row. Moving between rows can fire on_enter before the previous
row's on_exit, so the unconditional clear wiped a freshly highlighted
row (notably when returning to the first row). Guarding the clear fixes
the highlight not reappearing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-05 00:05:15 +03:00

92 lines
2.8 KiB
Rust

//! Selection-cycling list box — shown at the cursor when a click lands on
//! two or more overlapping objects. Each row names a candidate; clicking it
//! adds that object to the current selection. Clicking outside dismisses it.
use iced::widget::{button, column, container, mouse_area, opaque, row, text, Space};
use iced::{Background, Border, Color, Element, Fill, Length, Theme};
use crate::app::Message;
/// Full-canvas overlay: the list box anchored at `anchor` (canvas
/// coordinates) plus a transparent click-catcher that cancels.
pub fn cycle_popup_overlay(
anchor: iced::Point,
items: Vec<(acadrust::Handle, String)>,
) -> Element<'static, Message> {
let rows: Vec<Element<'static, Message>> = items
.into_iter()
.map(|(handle, label)| item_row(handle, label))
.collect();
let panel = container(column(rows))
.style(|_: &Theme| container::Style {
background: Some(Background::Color(PANEL_BG)),
border: Border {
color: PANEL_BORDER,
width: 1.0,
radius: 3.0.into(),
},
..Default::default()
})
.width(Length::Fixed(150.0));
let positioned = column![
Space::new().height(Length::Fixed(anchor.y.max(0.0))),
row![
Space::new().width(Length::Fixed(anchor.x.max(0.0))),
opaque(panel),
],
]
.width(Fill)
.height(Fill);
mouse_area(positioned).on_press(Message::CycleCancel).into()
}
fn item_row(handle: acadrust::Handle, label: String) -> Element<'static, Message> {
let content = text(label).size(11).color(LABEL).align_y(iced::Center);
let btn = button(content)
.on_press(Message::CycleSelect(handle))
.style(|_: &Theme, status| button::Style {
background: Some(Background::Color(match status {
button::Status::Hovered => ROW_HOVER,
_ => Color::TRANSPARENT,
})),
..Default::default()
})
.width(Fill)
.padding([4, 10]);
// Highlight the underlying object while the cursor is over this row.
mouse_area(btn)
.on_enter(Message::CycleHover(Some(handle)))
.on_exit(Message::CycleHoverExit(handle))
.into()
}
// ── Colours ───────────────────────────────────────────────────────────────
const PANEL_BG: Color = Color {
r: 0.15,
g: 0.15,
b: 0.15,
a: 1.0,
};
const PANEL_BORDER: Color = Color {
r: 0.32,
g: 0.32,
b: 0.32,
a: 1.0,
};
const ROW_HOVER: Color = Color {
r: 0.22,
g: 0.45,
b: 0.62,
a: 1.0,
};
const LABEL: Color = Color {
r: 0.92,
g: 0.92,
b: 0.92,
a: 1.0,
};