feat(properties): navigate polyline vertices from the panel

The Current Vertex row is now a ◀ / ▶ stepper (new PropValue::Stepper)
showing "i / N". Stepping it moves the panel's focus through the
polyline's vertices — Vertex X/Y and the per-vertex start/end widths show
and edit the focused vertex instead of always the first — and the focused
vertex's grip is drawn hot (filled) in the drawing so it's visible while
navigating. Focus wraps around and resets to the first vertex when the
selection changes. Adds Area and Length to the LwPolyline Geometry group
(Polyline2D already had them). Applies to LwPolyline and Polyline2D.

The focused vertex is threaded to the per-entity property builder/editor
through a dispatch thread-local (like the curve-tolerance override), so
the PropertyEditable trait signatures are unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-08 17:53:05 +03:00
1 parent a4f7ee376f
commit b3c8c0a2f1
12 files changed
+208 -22

No files matched your search

+43
View File
@@ -149,6 +149,9 @@ pub struct PropertiesPanel {
/// from `color_picker_open` so the entity colour and the background colour
/// pickers are independent.
pub bg_color_picker_open: bool,
/// Which vertex a multi-vertex entity (polyline) is focused on — driven by
/// the Current Vertex ◀ / ▶ stepper. Reset to 0 when the selection changes.
pub prop_vertex: usize,
}
impl Default for PropertiesPanel {
@@ -170,6 +173,7 @@ impl Default for PropertiesPanel {
color_picker_open: false,
color_palette_open: false,
bg_color_picker_open: false,
prop_vertex: 0,
}
}
}
@@ -353,6 +357,9 @@ impl PropertiesPanel {
PropValue::BoolToggle { field, value } => {
col = col.push(render_bool_row(&prop.label, *field, *value));
}
PropValue::Stepper { display, .. } => {
col = col.push(render_stepper_row(&prop.label, display));
}
PropValue::EditText(val) => {
col = col.push(self.render_edit_row(&prop.label, prop.field, val));
}
@@ -859,6 +866,42 @@ pub fn color_picker_dropdown<'a>(
// ── Standalone helpers ────────────────────────────────────────────────────
/// A boolean toggle button row (for "Invisible" etc.).
fn render_stepper_row<'a>(label: &'a str, display: &'a str) -> Element<'a, Message> {
let arrow = |glyph: &'static str, delta: i8| {
button(text(glyph).size(FONT_SZ).color(VALUE_COLOR))
.on_press(Message::PropVertexStep(delta))
.padding([0, 6])
.style(|_: &Theme, status| {
let bg = match status {
button::Status::Hovered | button::Status::Pressed => HOVER_BG,
_ => VALUE_BG,
};
button::Style {
background: Some(Background::Color(bg)),
border: Border {
color: BORDER,
width: 1.0,
radius: 2.0.into(),
},
text_color: VALUE_COLOR,
..Default::default()
}
})
};
let widget = iced::widget::row![
arrow("◀", -1),
text(display)
.size(FONT_SZ)
.color(VALUE_COLOR)
.width(Length::Fill)
.align_x(iced::Center),
arrow("▶", 1),
]
.spacing(4)
.align_y(iced::Center);
prop_row_widget(label, widget.into())
}
fn render_bool_row<'a>(label: &'a str, field: &'static str, value: bool) -> Element<'a, Message> {
let btn_label = if value { "Yes" } else { "No" };
let btn =