feat(properties): collapse the panel to a vertical bar on a narrow window
When the window is too narrow for the full properties panel it now collapses to a slim vertical "Properties" bar (its label drawn rotated 90° on a canvas), freeing width for the viewport. Clicking the bar expands the panel back out alongside the bar; clicking it again re-collapses (props_expanded state + TogglePropertiesBar). Reuses the rotated-label bar helper originally built for the Start page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e2a56033d4
commit
19a7343c80
3 changed files with 108 additions and 3 deletions
|
|
@ -232,6 +232,9 @@ pub(super) struct OpenCADStudio {
|
||||||
/// Which Start-page section is shown when the page is too narrow for all
|
/// Which Start-page section is shown when the page is too narrow for all
|
||||||
/// three side by side and falls back to a tab bar.
|
/// three side by side and falls back to a tab bar.
|
||||||
start_section: StartSection,
|
start_section: StartSection,
|
||||||
|
/// When the window is too narrow the properties panel collapses to a
|
||||||
|
/// vertical bar; this is the user's toggle to expand it back out.
|
||||||
|
props_expanded: bool,
|
||||||
/// Read-only editor buffer backing the command-line history dropdown, so
|
/// Read-only editor buffer backing the command-line history dropdown, so
|
||||||
/// the log can be drag-selected across lines and copied (issue #232).
|
/// the log can be drag-selected across lines and copied (issue #232).
|
||||||
/// Rebuilt from the history each time the dropdown is opened.
|
/// Rebuilt from the history each time the dropdown is opened.
|
||||||
|
|
@ -1129,6 +1132,8 @@ pub enum Message {
|
||||||
OpenUrl(String),
|
OpenUrl(String),
|
||||||
/// Select which section a narrow (tabbed) Start page shows.
|
/// Select which section a narrow (tabbed) Start page shows.
|
||||||
StartSectionSelect(StartSection),
|
StartSectionSelect(StartSection),
|
||||||
|
/// Expand/collapse the properties panel when it has shrunk to a bar.
|
||||||
|
TogglePropertiesBar,
|
||||||
/// Scroll the status-bar layout-tab strip horizontally by `delta` px
|
/// Scroll the status-bar layout-tab strip horizontally by `delta` px
|
||||||
/// (negative = left). Driven by the ‹ › arrows next to the tabs.
|
/// (negative = left). Driven by the ‹ › arrows next to the tabs.
|
||||||
ScrollLayoutTabs(f32),
|
ScrollLayoutTabs(f32),
|
||||||
|
|
@ -1975,6 +1980,7 @@ impl OpenCADStudio {
|
||||||
command_line: CommandLine::new(),
|
command_line: CommandLine::new(),
|
||||||
patrons: Vec::new(),
|
patrons: Vec::new(),
|
||||||
start_section: StartSection::default(),
|
start_section: StartSection::default(),
|
||||||
|
props_expanded: false,
|
||||||
history_content: iced::widget::text_editor::Content::new(),
|
history_content: iced::widget::text_editor::Content::new(),
|
||||||
status_bar: StatusBar::new(),
|
status_bar: StatusBar::new(),
|
||||||
cursor_pos: Point::ORIGIN,
|
cursor_pos: Point::ORIGIN,
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,11 @@ impl OpenCADStudio {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::TogglePropertiesBar => {
|
||||||
|
self.props_expanded = !self.props_expanded;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
Message::ScrollLayoutTabs(dx) => iced::widget::operation::scroll_by(
|
Message::ScrollLayoutTabs(dx) => iced::widget::operation::scroll_by(
|
||||||
iced::advanced::widget::Id::new(crate::ui::statusbar::LAYOUT_TABS_SCROLL_ID),
|
iced::advanced::widget::Id::new(crate::ui::statusbar::LAYOUT_TABS_SCROLL_ID),
|
||||||
iced::widget::scrollable::AbsoluteOffset { x: dx, y: 0.0 },
|
iced::widget::scrollable::AbsoluteOffset { x: dx, y: 0.0 },
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ use crate::scene::view::viewport_pane::ViewportPane;
|
||||||
use crate::scene::{VIEWCUBE_PAD, VIEWCUBE_REGION_PX};
|
use crate::scene::{VIEWCUBE_PAD, VIEWCUBE_REGION_PX};
|
||||||
use crate::ui::wrap_bar::WrapFlow;
|
use crate::ui::wrap_bar::WrapFlow;
|
||||||
use iced::widget::{
|
use iced::widget::{
|
||||||
button, column, container, mouse_area, pane_grid, responsive, row, shader, stack, text, Row,
|
button, canvas, column, container, mouse_area, pane_grid, responsive, row, shader, stack, text,
|
||||||
Space,
|
Row, Space,
|
||||||
};
|
};
|
||||||
use iced::window;
|
use iced::window;
|
||||||
use iced::{keyboard, Background, Border, Color, Element, Fill, Subscription, Task, Theme};
|
use iced::{keyboard, Background, Border, Color, Element, Fill, Subscription, Task, Theme};
|
||||||
|
|
@ -1143,7 +1143,17 @@ impl OpenCADStudio {
|
||||||
let properties_el: Element<'_, Message> = if tab.is_start {
|
let properties_el: Element<'_, Message> = if tab.is_start {
|
||||||
Space::new().into()
|
Space::new().into()
|
||||||
} else if self.show_properties && !self.clean_screen {
|
} else if self.show_properties && !self.clean_screen {
|
||||||
tab.properties.view()
|
// On a narrow window the panel collapses to a vertical "Properties"
|
||||||
|
// bar to free width for the viewport; clicking the bar expands it.
|
||||||
|
let narrow = self.win_size.0 < 1000.0;
|
||||||
|
let bar = || collapse_bar("Properties", Message::TogglePropertiesBar);
|
||||||
|
if narrow && !self.props_expanded {
|
||||||
|
bar()
|
||||||
|
} else if narrow {
|
||||||
|
row![bar(), tab.properties.view()].into()
|
||||||
|
} else {
|
||||||
|
tab.properties.view()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Space::new().into()
|
Space::new().into()
|
||||||
};
|
};
|
||||||
|
|
@ -1987,6 +1997,90 @@ fn pane_mouse_area<'a>(idx: usize) -> Element<'a, Message> {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Canvas that draws a label rotated 90° (for a collapsed panel's bar).
|
||||||
|
struct VBarLabel {
|
||||||
|
text: String,
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl canvas::Program<Message> for VBarLabel {
|
||||||
|
type State = ();
|
||||||
|
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
_state: &(),
|
||||||
|
renderer: &iced::Renderer,
|
||||||
|
_theme: &Theme,
|
||||||
|
bounds: iced::Rectangle,
|
||||||
|
_cursor: iced::advanced::mouse::Cursor,
|
||||||
|
) -> Vec<canvas::Geometry> {
|
||||||
|
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
||||||
|
frame.with_save(|frame| {
|
||||||
|
frame.translate(iced::Vector::new(bounds.width / 2.0, bounds.height / 2.0));
|
||||||
|
frame.rotate(iced::Radians(std::f32::consts::FRAC_PI_2));
|
||||||
|
frame.fill_text(canvas::Text {
|
||||||
|
content: self.text.clone(),
|
||||||
|
position: iced::Point::ORIGIN,
|
||||||
|
color: self.color,
|
||||||
|
size: iced::Pixels(13.0),
|
||||||
|
align_x: iced::advanced::text::Alignment::Center,
|
||||||
|
align_y: iced::alignment::Vertical::Center,
|
||||||
|
shaping: iced::advanced::text::Shaping::Advanced,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
vec![frame.into_geometry()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A collapsed panel rendered as a tall narrow bar with its name written along
|
||||||
|
/// it, rotated 90°. Pressing it emits `on_press`.
|
||||||
|
pub(super) fn collapse_bar<'a>(name: &str, on_press: Message) -> Element<'a, Message> {
|
||||||
|
const LABEL: Color = Color {
|
||||||
|
r: 0.72,
|
||||||
|
g: 0.72,
|
||||||
|
b: 0.74,
|
||||||
|
a: 1.0,
|
||||||
|
};
|
||||||
|
const BAR_BG: Color = Color {
|
||||||
|
r: 0.13,
|
||||||
|
g: 0.13,
|
||||||
|
b: 0.14,
|
||||||
|
a: 1.0,
|
||||||
|
};
|
||||||
|
const BAR_BORDER: Color = Color {
|
||||||
|
r: 0.22,
|
||||||
|
g: 0.22,
|
||||||
|
b: 0.24,
|
||||||
|
a: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let label = canvas(VBarLabel {
|
||||||
|
text: name.to_string(),
|
||||||
|
color: LABEL,
|
||||||
|
})
|
||||||
|
.width(Fill)
|
||||||
|
.height(Fill);
|
||||||
|
|
||||||
|
mouse_area(
|
||||||
|
container(label)
|
||||||
|
.width(iced::Length::Fixed(26.0))
|
||||||
|
.height(Fill)
|
||||||
|
.style(|_: &Theme| container::Style {
|
||||||
|
background: Some(Background::Color(BAR_BG)),
|
||||||
|
border: Border {
|
||||||
|
color: BAR_BORDER,
|
||||||
|
width: 1.0,
|
||||||
|
radius: 0.0.into(),
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.interaction(iced::mouse::Interaction::Pointer)
|
||||||
|
.on_press(on_press)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn start_page_view<'a>(
|
pub(super) fn start_page_view<'a>(
|
||||||
patrons: &'a [(String, i64)],
|
patrons: &'a [(String, i64)],
|
||||||
recents: &'a [std::path::PathBuf],
|
recents: &'a [std::path::PathBuf],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue