feat(statusbar): quick properties floating panel (QP pill)
When the QP pill is on, a compact floating panel appears at the canvas top-left on selection, reusing the docked panel's editable section rows. Toggleable from the status-bar customization menu. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
66f7d24bc9
commit
834780ec5d
6 changed files with 72 additions and 0 deletions
|
|
@ -179,6 +179,8 @@ pub(super) struct OpenCADStudio {
|
||||||
isolate_popup_open: bool,
|
isolate_popup_open: bool,
|
||||||
/// Clean-screen mode: hide ribbon and side panels for a full canvas.
|
/// Clean-screen mode: hide ribbon and side panels for a full canvas.
|
||||||
clean_screen: bool,
|
clean_screen: bool,
|
||||||
|
/// Quick Properties: show a compact floating property panel on selection.
|
||||||
|
quick_properties: bool,
|
||||||
/// Which status-bar pills the user has chosen to show (persisted).
|
/// Which status-bar pills the user has chosen to show (persisted).
|
||||||
statusbar_config: crate::ui::statusbar_config::StatusBarConfig,
|
statusbar_config: crate::ui::statusbar_config::StatusBarConfig,
|
||||||
/// Whether Tangent snap was enabled before a tangent-pick command started.
|
/// Whether Tangent snap was enabled before a tangent-pick command started.
|
||||||
|
|
@ -752,6 +754,8 @@ pub enum Message {
|
||||||
ToggleCleanScreen,
|
ToggleCleanScreen,
|
||||||
/// Toggle whether entity transparency is shown on screen.
|
/// Toggle whether entity transparency is shown on screen.
|
||||||
ToggleTransparencyDisplay,
|
ToggleTransparencyDisplay,
|
||||||
|
/// Toggle the Quick Properties floating panel.
|
||||||
|
ToggleQuickProperties,
|
||||||
/// Toggle the drawing-units picker open/closed.
|
/// Toggle the drawing-units picker open/closed.
|
||||||
ToggleUnitsPopup,
|
ToggleUnitsPopup,
|
||||||
/// Close the drawing-units picker.
|
/// Close the drawing-units picker.
|
||||||
|
|
@ -1223,6 +1227,7 @@ impl OpenCADStudio {
|
||||||
isolate_popup_open: false,
|
isolate_popup_open: false,
|
||||||
statusbar_config: crate::ui::statusbar_config::StatusBarConfig::load(),
|
statusbar_config: crate::ui::statusbar_config::StatusBarConfig::load(),
|
||||||
clean_screen: false,
|
clean_screen: false,
|
||||||
|
quick_properties: false,
|
||||||
pre_cmd_tangent: None,
|
pre_cmd_tangent: None,
|
||||||
ortho_mode: false,
|
ortho_mode: false,
|
||||||
polar_mode: false,
|
polar_mode: false,
|
||||||
|
|
|
||||||
|
|
@ -3590,6 +3590,10 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
Message::ToggleQuickProperties => {
|
||||||
|
self.quick_properties ^= true;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
Message::ToggleUnitsPopup => {
|
Message::ToggleUnitsPopup => {
|
||||||
self.units_popup_open ^= true;
|
self.units_popup_open ^= true;
|
||||||
Task::none()
|
Task::none()
|
||||||
|
|
|
||||||
|
|
@ -1005,6 +1005,15 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quick Properties: compact floating property panel on selection,
|
||||||
|
// anchored at the canvas top-left so it doesn't track the cursor.
|
||||||
|
if self.quick_properties && !tab.is_start {
|
||||||
|
if let Some(panel) = tab.properties.quick_view() {
|
||||||
|
viewport_stack = viewport_stack
|
||||||
|
.push(position_canvas_overlay(iced::Point::new(12.0, 12.0), panel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Right-click context menu. Lives inside the viewport stack so
|
// Right-click context menu. Lives inside the viewport stack so
|
||||||
// the cursor position (canvas-relative) anchors the menu under
|
// the cursor position (canvas-relative) anchors the menu under
|
||||||
// the cursor instead of drifting into window-relative space.
|
// the cursor instead of drifting into window-relative space.
|
||||||
|
|
@ -1163,6 +1172,7 @@ impl OpenCADStudio {
|
||||||
self.units_popup_open,
|
self.units_popup_open,
|
||||||
tab.scene.is_isolation_active(),
|
tab.scene.is_isolation_active(),
|
||||||
tab.scene.transparency_display,
|
tab.scene.transparency_display,
|
||||||
|
self.quick_properties,
|
||||||
&self.statusbar_config,
|
&self.statusbar_config,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,47 @@ impl PropertiesPanel {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compact floating panel for Quick Properties: the title plus the same
|
||||||
|
/// editable section rows as the docked panel, sized to its content.
|
||||||
|
/// Returns `None` when nothing is selected.
|
||||||
|
pub fn quick_view(&self) -> Option<Element<'_, Message>> {
|
||||||
|
if self.sections.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let title = container(text(&self.title).size(FONT_SZ).color(SECTION_LABEL))
|
||||||
|
.style(|_: &Theme| container::Style {
|
||||||
|
background: Some(Background::Color(SECTION_BG)),
|
||||||
|
border: Border {
|
||||||
|
color: BORDER,
|
||||||
|
width: 1.0,
|
||||||
|
radius: 0.0.into(),
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.width(Length::Fill)
|
||||||
|
.padding([4, 10]);
|
||||||
|
|
||||||
|
let mut col = column![title].spacing(0);
|
||||||
|
for section in &self.sections {
|
||||||
|
col = col.push(self.render_section(section));
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(
|
||||||
|
container(col)
|
||||||
|
.style(|_: &Theme| container::Style {
|
||||||
|
background: Some(Background::Color(PANEL_BG)),
|
||||||
|
border: Border {
|
||||||
|
color: BORDER,
|
||||||
|
width: 1.0,
|
||||||
|
radius: 3.0.into(),
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.width(230)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// ── Section renderer ──────────────────────────────────────────────────
|
// ── Section renderer ──────────────────────────────────────────────────
|
||||||
|
|
||||||
fn render_section<'a>(&'a self, section: &'a PropSection) -> Element<'a, Message> {
|
fn render_section<'a>(&'a self, section: &'a PropSection) -> Element<'a, Message> {
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,8 @@ impl StatusBar {
|
||||||
isolation_active: bool,
|
isolation_active: bool,
|
||||||
// Whether entity transparency is shown (Transparency pill state).
|
// Whether entity transparency is shown (Transparency pill state).
|
||||||
transparency_display: bool,
|
transparency_display: bool,
|
||||||
|
// Whether the Quick Properties floating panel is enabled.
|
||||||
|
quick_properties: bool,
|
||||||
// Which pills the user has chosen to show on the bar.
|
// Which pills the user has chosen to show on the bar.
|
||||||
config: &'a StatusBarConfig,
|
config: &'a StatusBarConfig,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
|
|
@ -193,6 +195,12 @@ impl StatusBar {
|
||||||
"Isolate Objects\nClick for Isolate / Hide / End",
|
"Isolate Objects\nClick for Isolate / Hide / End",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if vis(StatusPill::QuickProps) {
|
||||||
|
right_status = right_status.push(tip(
|
||||||
|
toggle_pill("QP", quick_properties, Message::ToggleQuickProperties),
|
||||||
|
"Quick Properties\nFloating panel on selection",
|
||||||
|
));
|
||||||
|
}
|
||||||
if vis(StatusPill::Vp) && !vp_label.is_empty() {
|
if vis(StatusPill::Vp) && !vp_label.is_empty() {
|
||||||
right_status = right_status.push(tip(
|
right_status = right_status.push(tip(
|
||||||
status_pill(vp_label).into(),
|
status_pill(vp_label).into(),
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ pub enum StatusPill {
|
||||||
Units,
|
Units,
|
||||||
Transparency,
|
Transparency,
|
||||||
Isolate,
|
Isolate,
|
||||||
|
QuickProps,
|
||||||
Vp,
|
Vp,
|
||||||
CleanScreen,
|
CleanScreen,
|
||||||
}
|
}
|
||||||
|
|
@ -47,6 +48,7 @@ impl StatusPill {
|
||||||
StatusPill::Units,
|
StatusPill::Units,
|
||||||
StatusPill::Transparency,
|
StatusPill::Transparency,
|
||||||
StatusPill::Isolate,
|
StatusPill::Isolate,
|
||||||
|
StatusPill::QuickProps,
|
||||||
StatusPill::Vp,
|
StatusPill::Vp,
|
||||||
StatusPill::CleanScreen,
|
StatusPill::CleanScreen,
|
||||||
];
|
];
|
||||||
|
|
@ -68,6 +70,7 @@ impl StatusPill {
|
||||||
StatusPill::Units => "units",
|
StatusPill::Units => "units",
|
||||||
StatusPill::Transparency => "transparency",
|
StatusPill::Transparency => "transparency",
|
||||||
StatusPill::Isolate => "isolate",
|
StatusPill::Isolate => "isolate",
|
||||||
|
StatusPill::QuickProps => "quickprops",
|
||||||
StatusPill::Vp => "vp",
|
StatusPill::Vp => "vp",
|
||||||
StatusPill::CleanScreen => "cleanscreen",
|
StatusPill::CleanScreen => "cleanscreen",
|
||||||
}
|
}
|
||||||
|
|
@ -90,6 +93,7 @@ impl StatusPill {
|
||||||
StatusPill::Units => "Drawing Units",
|
StatusPill::Units => "Drawing Units",
|
||||||
StatusPill::Transparency => "Show Transparency",
|
StatusPill::Transparency => "Show Transparency",
|
||||||
StatusPill::Isolate => "Isolate Objects",
|
StatusPill::Isolate => "Isolate Objects",
|
||||||
|
StatusPill::QuickProps => "Quick Properties",
|
||||||
StatusPill::Vp => "Viewport Count",
|
StatusPill::Vp => "Viewport Count",
|
||||||
StatusPill::CleanScreen => "Clean Screen",
|
StatusPill::CleanScreen => "Clean Screen",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue