diff --git a/src/app/mod.rs b/src/app/mod.rs index b8205f059..cf794b80a 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -3625,6 +3625,8 @@ pub enum Message { PropPointerPressed, /// Toggle the inline color picker dropdown open/closed. PropColorPickerToggle, + /// A Properties dropdown toggle and whether Quick Properties sent it. + PropPickerSurface(bool, Box), /// Toggle the MTEXT background-colour picker dropdown open/closed. PropBgColorPickerToggle, /// User picked an MTEXT background fill colour — sets `background_color` diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 7974cecfa..4c21f69b4 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -7856,6 +7856,13 @@ impl OpenCADStudio { Task::none() } + Message::PropPickerSurface(quick, message) => { + let task = self.update(*message); + let i = self.active_tab; + self.tabs[i].properties.picker_in_quick = quick; + task + } + Message::PropColorPickerToggle => { let i = self.active_tab; self.tabs[i].properties.color_picker_open = diff --git a/src/ui/properties.rs b/src/ui/properties.rs index 6774f005d..5f59f7209 100644 --- a/src/ui/properties.rs +++ b/src/ui/properties.rs @@ -621,6 +621,12 @@ pub struct PropertiesPanel { pub collapsed_sections: HashSet, /// Whether the editable-dropdown (block Name) option list is open. pub edit_choice_open: bool, + /// The open dropdown belongs to Quick Properties, not the docked panel: + /// both render these rows, and two open copies swallow each other's + /// clicks (#1766). + pub picker_in_quick: bool, + /// Set while `quick_view` builds its rows. + pub rendering_quick: std::cell::Cell, /// Field key of the value row currently being edited, or `None`. Marked when /// the user focuses an editable value field and cleared on commit / when the /// selection changes, so the active row can be highlighted. Geometry fields @@ -659,6 +665,8 @@ impl Default for PropertiesPanel { expanded_groups: HashSet::default(), collapsed_sections: HashSet::default(), edit_choice_open: false, + picker_in_quick: false, + rendering_quick: std::cell::Cell::new(false), active_field: None, field_key_by_id: HashMap::default(), } @@ -680,6 +688,11 @@ impl PropertiesPanel { self.field_key_by_id.get(id).cloned() } + /// Whether the open dropdown belongs to the surface being built. + fn picker_here(&self) -> bool { + self.picker_in_quick == self.rendering_quick.get() + } + pub fn selected_handles(&self) -> Vec { self.selected_group .as_ref() @@ -744,11 +757,13 @@ impl PropertiesPanel { for section in &self.sections { col = col.push(self.render_section(section)); } - scrollable(col.width(Length::Fill)) - .spacing(8) - .width(Length::Fill) - .height(Length::Fill) - .into() + Element::from( + scrollable(col.width(Length::Fill)) + .spacing(8) + .width(Length::Fill) + .height(Length::Fill), + ) + .map(|message| tag_picker(false, message)) }; container(column![header, title_bar, content]) @@ -797,14 +812,19 @@ impl PropertiesPanel { .padding([4, 10]); let mut sections = column![].spacing(0); + self.rendering_quick.set(true); for section in &self.sections { sections = sections.push(self.render_section(section)); } + self.rendering_quick.set(false); - let content = scrollable(sections.width(Length::Fill)) - .spacing(8) - .width(Length::Fill) - .height(Length::Shrink); + let content = Element::from( + scrollable(sections.width(Length::Fill)) + .spacing(8) + .width(Length::Fill) + .height(Length::Shrink), + ) + .map(|message| tag_picker(true, message)); Some( container(column![title, content].spacing(0)) @@ -1002,7 +1022,7 @@ impl PropertiesPanel { if field == "background_color" { let selector = crate::ui::color_select::color_selector( color, - self.bg_color_picker_open, + self.bg_color_picker_open && self.picker_here(), crate::ui::color_select::ColorExtras { by_layer: true, by_block: true, @@ -1035,7 +1055,7 @@ impl PropertiesPanel { | "background_fill_color" | "indicator_fill_color" ) { - let open = self.open_color_field.as_deref() == Some(field); + let open = self.open_color_field.as_deref() == Some(field) && self.picker_here(); let fsel = field.to_string(); let full_palette_field = field.to_string(); let extras = if field == "dim_text_fill_color" { @@ -1078,7 +1098,7 @@ impl PropertiesPanel { let selector = crate::ui::color_select::color_selector_with_name( color, display_name, - self.color_picker_open, + self.color_picker_open && self.picker_here(), crate::ui::color_select::ColorExtras { by_layer: true, by_block: true, @@ -1093,7 +1113,7 @@ impl PropertiesPanel { fn render_color_varies_row<'a>(&'a self, label: &'a str) -> Element<'a, Message> { let selector = crate::ui::color_select::color_selector_varies( - self.color_picker_open, + self.color_picker_open && self.picker_here(), crate::ui::color_select::ColorExtras { by_layer: true, by_block: true, @@ -1352,7 +1372,7 @@ impl PropertiesPanel { }) .width(Length::Fill); let caret = button( - container(if self.edit_choice_open { + container(if self.edit_choice_open && self.picker_here() { crate::ui::icons::themed_arrow_up(9.0) } else { crate::ui::icons::themed_arrow_down(9.0) @@ -1405,7 +1425,7 @@ impl PropertiesPanel { }) .width(Length::Fill); - if !self.edit_choice_open { + if !(self.edit_choice_open && self.picker_here()) { return prop_row_with_active(label, head.into(), active); } @@ -1609,7 +1629,7 @@ impl PropertiesPanel { text(crate::ui::text_util::elide(current, 16)) .size(FONT_SZ) .width(Length::Fill), - if self.hatch_pattern_picker_open { + if self.hatch_pattern_picker_open && self.picker_here() { crate::ui::icons::themed_arrow_up(FONT_SZ) } else { crate::ui::icons::themed_arrow_down(FONT_SZ) @@ -1629,7 +1649,7 @@ impl PropertiesPanel { })), text_color: palette.background.base.text, border: Border { - color: if self.hatch_pattern_picker_open { + color: if self.hatch_pattern_picker_open && self.picker_here() { palette.primary.base.color } else { palette.background.neutral.color @@ -1643,7 +1663,7 @@ impl PropertiesPanel { .padding([COMBO_PAD_V, 6.0]) .width(Length::Fill); - if !self.hatch_pattern_picker_open { + if !(self.hatch_pattern_picker_open && self.picker_here()) { return prop_row_widget(label, head.into()); } @@ -2370,3 +2390,18 @@ mod tests { assert!((0.01..=100.0).contains(&scale)); } } + +/// Marks a dropdown toggle with the surface it came from (see +/// `PropertiesPanel::picker_in_quick`). +fn tag_picker(quick: bool, message: Message) -> Message { + match message { + Message::PropColorPickerToggle + | Message::PropBgColorPickerToggle + | Message::PropColorFieldToggle(_) + | Message::PropEditChoiceToggle + | Message::PropHatchPatternPickerToggle(_) => { + Message::PropPickerSurface(quick, Box::new(message)) + } + other => other, + } +}