forked from 1b-agent/opencadstudio-upstream
Dock: LAYERS opens its pallet like Insert Block, Layer Manager layout fixes, 150 ms auto-hide hover delay
- LAYERS ribbon button runs a command that opens the Layer Manager pallet; the ribbon no longer keeps it highlighted. - Layer Manager: search box stays right-aligned, the column header fills the row, no stray contour lines when the pallet is taller than its rows. - Auto-hidden edges don't show the shown-group accent bar. - Auto-hide reveal and hide wait 150 ms of rest, so passing over the strip doesn't flash groups open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
This commit is contained in:
9 files changed
+172
-65
No files matched your search
@@ -354,7 +354,9 @@ impl OpenCADStudio {
|
|||||||
"ORTHO" => return Some(Task::done(Message::ToggleOrtho)),
|
"ORTHO" => return Some(Task::done(Message::ToggleOrtho)),
|
||||||
"PARALLEL" => return Some(Task::done(Message::SetProjection(true))),
|
"PARALLEL" => return Some(Task::done(Message::SetProjection(true))),
|
||||||
"PERSP" => return Some(Task::done(Message::SetProjection(false))),
|
"PERSP" => return Some(Task::done(Message::SetProjection(false))),
|
||||||
"LAYERS" => return Some(Task::done(Message::ToggleLayers)),
|
// LAYERS opens the Layer Manager pallet (its close button or
|
||||||
|
// the toggle message close it).
|
||||||
|
"LAYERS" => self.open_layers_pallet(),
|
||||||
|
|
||||||
// SCRIPT <path> — run a command script: each non-comment
|
// SCRIPT <path> — run a command script: each non-comment
|
||||||
// line is fed through the same command path the `--script` startup
|
// line is fed through the same command path the `--script` startup
|
||||||
|
|||||||
@@ -336,9 +336,19 @@ fn dock_hover_reveals_groups_only_on_an_auto_hiding_edge() {
|
|||||||
assert!(!app.dock_edge_expanded(DockSide::Left));
|
assert!(!app.dock_edge_expanded(DockSide::Left));
|
||||||
// Hovering an icon flies its group out.
|
// Hovering an icon flies its group out.
|
||||||
let _ = app.on_dock(DockMsg::Hover(PanelId::Browser));
|
let _ = app.on_dock(DockMsg::Hover(PanelId::Browser));
|
||||||
|
// ...but only once the pointer rests: the reveal waits for the delay.
|
||||||
|
assert!(!app.dock_edge_expanded(DockSide::Left));
|
||||||
|
let _ = app.on_dock(DockMsg::HoverSettled(app.dock_hover_gen));
|
||||||
assert!(app.dock_edge_expanded(DockSide::Left));
|
assert!(app.dock_edge_expanded(DockSide::Left));
|
||||||
assert_eq!(app.dock_shown_group(DockSide::Left), Some(1));
|
assert_eq!(app.dock_shown_group(DockSide::Left), Some(1));
|
||||||
|
// Leaving and coming back within the delay keeps it open.
|
||||||
let _ = app.on_dock(DockMsg::HoverExit);
|
let _ = app.on_dock(DockMsg::HoverExit);
|
||||||
|
let stale = app.dock_hover_gen;
|
||||||
|
let _ = app.on_dock(DockMsg::HoverStay);
|
||||||
|
let _ = app.on_dock(DockMsg::HoverSettled(stale));
|
||||||
|
assert!(app.dock_edge_expanded(DockSide::Left));
|
||||||
|
let _ = app.on_dock(DockMsg::HoverExit);
|
||||||
|
let _ = app.on_dock(DockMsg::HoverSettled(app.dock_hover_gen));
|
||||||
assert!(!app.dock_edge_expanded(DockSide::Left));
|
assert!(!app.dock_edge_expanded(DockSide::Left));
|
||||||
// Without auto-hide, hovering does not switch groups (clicks do).
|
// Without auto-hide, hovering does not switch groups (clicks do).
|
||||||
let _ = app.on_dock(DockMsg::AutoCollapseToggle(PanelId::Properties));
|
let _ = app.on_dock(DockMsg::AutoCollapseToggle(PanelId::Properties));
|
||||||
@@ -539,12 +549,29 @@ fn hovering_a_strip_icon_reveals_an_auto_hiding_edge_in_the_real_view() {
|
|||||||
icon,
|
icon,
|
||||||
&[iced::Event::Mouse(iced::mouse::Event::CursorMoved { position: icon })],
|
&[iced::Event::Mouse(iced::mouse::Event::CursorMoved { position: icon })],
|
||||||
);
|
);
|
||||||
|
let _ = app.on_dock(DockMsg::HoverSettled(app.dock_hover_gen));
|
||||||
assert!(
|
assert!(
|
||||||
app.dock_edge_expanded(DockSide::Right),
|
app.dock_edge_expanded(DockSide::Right),
|
||||||
"hovering the icon reveals the auto-hiding edge"
|
"hovering the icon reveals the auto-hiding edge"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn layers_ribbon_button_opens_the_pallet_without_staying_highlighted() {
|
||||||
|
let mut app = dock_app();
|
||||||
|
// The ribbon's LAYERS button runs the LAYERS command.
|
||||||
|
let click = || Message::RibbonToolClick {
|
||||||
|
tool_id: "LAYERS".to_string(),
|
||||||
|
event: crate::modules::ModuleEvent::Command("LAYERS".to_string()),
|
||||||
|
};
|
||||||
|
let _ = app.update(click());
|
||||||
|
assert!(app.show_layers);
|
||||||
|
assert_eq!(app.ribbon.active_tool(), None);
|
||||||
|
// Pressing it again keeps it open, like the Blocks palette's button.
|
||||||
|
let _ = app.update(click());
|
||||||
|
assert!(app.show_layers);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dock_double_clicks_float_and_dock_panels() {
|
fn dock_double_clicks_float_and_dock_panels() {
|
||||||
use crate::app::config::DockSide;
|
use crate::app::config::DockSide;
|
||||||
|
|||||||
+85
-5
@@ -7,6 +7,24 @@ use crate::app::{Message, OpenCADStudio};
|
|||||||
/// so a plain click never moves anything.
|
/// so a plain click never moves anything.
|
||||||
const DOCK_DRAG_THRESHOLD: f32 = 5.0;
|
const DOCK_DRAG_THRESHOLD: f32 = 5.0;
|
||||||
|
|
||||||
|
/// Resolves once the dock hover delay has passed (a sleeping helper thread;
|
||||||
|
/// the web build has none and resolves at once).
|
||||||
|
fn hover_delay() -> impl std::future::Future<Output = ()> {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let rx = {
|
||||||
|
let (tx, rx) = iced::futures::channel::oneshot::channel::<()>();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
std::thread::sleep(crate::ui::dock::DOCK_HOVER_DELAY);
|
||||||
|
let _ = tx.send(());
|
||||||
|
});
|
||||||
|
rx
|
||||||
|
};
|
||||||
|
async move {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let _ = rx.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl OpenCADStudio {
|
impl OpenCADStudio {
|
||||||
/// Dock chrome interaction (grab / pin / resize / hover / move) applied to
|
/// Dock chrome interaction (grab / pin / resize / hover / move) applied to
|
||||||
/// whichever panel the message names.
|
/// whichever panel the message names.
|
||||||
@@ -126,11 +144,15 @@ impl OpenCADStudio {
|
|||||||
DockMsg::Hover(id) => {
|
DockMsg::Hover(id) => {
|
||||||
self.dock_icon_hover = Some(id);
|
self.dock_icon_hover = Some(id);
|
||||||
// Only an auto-hiding edge (or floating pallet) reacts to
|
// Only an auto-hiding edge (or floating pallet) reacts to
|
||||||
// hover: it reveals the hovered pallet's group. Otherwise
|
// hover: after a short rest it reveals the hovered pallet's
|
||||||
// groups switch on click. Ignored mid-drag, when the pointer
|
// group. Otherwise groups switch on click. Ignored mid-drag,
|
||||||
// is over the preview rather than the strip.
|
// when the pointer is over the preview rather than the strip.
|
||||||
if self.dock_drag.is_none() && self.dock.auto_hides(id) {
|
if self.dock_drag.is_none() && self.dock.auto_hides(id) {
|
||||||
self.dock_reveal(id);
|
if self.dock_peek == Some(id) {
|
||||||
|
self.dock_hover_cancel();
|
||||||
|
} else {
|
||||||
|
return self.dock_hover_arm(Some(id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DockMsg::HoverEnd(id) => {
|
DockMsg::HoverEnd(id) => {
|
||||||
@@ -142,7 +164,25 @@ impl OpenCADStudio {
|
|||||||
if self.dock_drag.is_none()
|
if self.dock_drag.is_none()
|
||||||
&& self.dock_peek.is_some_and(|id| self.dock.auto_hides(id))
|
&& self.dock_peek.is_some_and(|id| self.dock.auto_hides(id))
|
||||||
{
|
{
|
||||||
self.dock_peek = None;
|
return self.dock_hover_arm(None);
|
||||||
|
}
|
||||||
|
// Left before a pending reveal ran out: it never happens.
|
||||||
|
self.dock_hover_cancel();
|
||||||
|
}
|
||||||
|
DockMsg::HoverStay => {
|
||||||
|
if self.dock_hover_pending == Some(None) {
|
||||||
|
self.dock_hover_cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DockMsg::HoverSettled(gen) => {
|
||||||
|
if gen == self.dock_hover_gen && self.dock_drag.is_none() {
|
||||||
|
match self.dock_hover_pending.take() {
|
||||||
|
Some(Some(id)) if self.dock.auto_hides(id) => self.dock_reveal(id),
|
||||||
|
Some(None) if self.dock_peek.is_some_and(|id| self.dock.auto_hides(id)) => {
|
||||||
|
self.dock_peek = None;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DockMsg::DragMove(point) => self.dock_drag_move(point),
|
DockMsg::DragMove(point) => self.dock_drag_move(point),
|
||||||
@@ -329,6 +369,23 @@ impl OpenCADStudio {
|
|||||||
|
|
||||||
/// Bring `id` into view: show its group on its edge and, where it
|
/// Bring `id` into view: show its group on its edge and, where it
|
||||||
/// auto-hides, keep it revealed until the pointer leaves.
|
/// auto-hides, keep it revealed until the pointer leaves.
|
||||||
|
/// Arm a delayed reveal (`Some`) or hide (`None`); it applies when its
|
||||||
|
/// timer reports back unless a newer hover superseded it.
|
||||||
|
fn dock_hover_arm(&mut self, target: Option<crate::ui::dock::PanelId>) -> iced::Task<Message> {
|
||||||
|
self.dock_hover_gen = self.dock_hover_gen.wrapping_add(1);
|
||||||
|
self.dock_hover_pending = Some(target);
|
||||||
|
let gen = self.dock_hover_gen;
|
||||||
|
iced::Task::perform(hover_delay(), move |()| {
|
||||||
|
Message::Dock(crate::ui::dock::DockMsg::HoverSettled(gen))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Drop any pending delayed reveal / hide.
|
||||||
|
fn dock_hover_cancel(&mut self) {
|
||||||
|
self.dock_hover_gen = self.dock_hover_gen.wrapping_add(1);
|
||||||
|
self.dock_hover_pending = None;
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn dock_reveal(&mut self, id: crate::ui::dock::PanelId) {
|
pub(crate) fn dock_reveal(&mut self, id: crate::ui::dock::PanelId) {
|
||||||
self.dock.show_group_of(id);
|
self.dock.show_group_of(id);
|
||||||
self.dock_peek = Some(id);
|
self.dock_peek = Some(id);
|
||||||
@@ -419,6 +476,29 @@ impl OpenCADStudio {
|
|||||||
self.dock_reveal(id);
|
self.dock_reveal(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Open the Layer Manager pallet (LAYERS). The first time it floats over
|
||||||
|
/// the middle of the drawing, where the dialog it replaced used to open;
|
||||||
|
/// after that it opens wherever the user left it.
|
||||||
|
pub(crate) fn open_layers_pallet(&mut self) {
|
||||||
|
use crate::ui::dock::{FloatPanel, PanelId};
|
||||||
|
self.sync_ribbon_layers();
|
||||||
|
self.show_layers = true;
|
||||||
|
if !self.dock.is_placed(PanelId::Layers) {
|
||||||
|
let (ww, wh) = self.dock_workspace_size();
|
||||||
|
let (w, h) = self.dock_float_size(PanelId::Layers);
|
||||||
|
self.dock.float(FloatPanel {
|
||||||
|
id: PanelId::Layers,
|
||||||
|
x: ((ww - w) * 0.5).max(0.0),
|
||||||
|
y: ((wh - h) * 0.5).max(0.0),
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
});
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
|
self.dock.raise_float(PanelId::Layers);
|
||||||
|
self.dock_reveal(PanelId::Layers);
|
||||||
|
}
|
||||||
|
|
||||||
/// Stop revealing `id` (it closed).
|
/// Stop revealing `id` (it closed).
|
||||||
pub(crate) fn dock_unpeek(&mut self, id: crate::ui::dock::PanelId) {
|
pub(crate) fn dock_unpeek(&mut self, id: crate::ui::dock::PanelId) {
|
||||||
if self.dock_peek == Some(id) {
|
if self.dock_peek == Some(id) {
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ impl OpenCADStudio {
|
|||||||
}
|
}
|
||||||
Some(
|
Some(
|
||||||
mouse_area(row(children).height(Fill))
|
mouse_area(row(children).height(Fill))
|
||||||
|
.on_enter(Message::Dock(crate::ui::dock::DockMsg::HoverStay))
|
||||||
.on_exit(Message::Dock(crate::ui::dock::DockMsg::HoverExit))
|
.on_exit(Message::Dock(crate::ui::dock::DockMsg::HoverExit))
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
@@ -165,7 +166,11 @@ impl OpenCADStudio {
|
|||||||
DockMsg, DropTarget, DOCK_STRIP_W, STRIP_CELL_H, STRIP_DIVIDER_H, STRIP_GRIP_W,
|
DockMsg, DropTarget, DOCK_STRIP_W, STRIP_CELL_H, STRIP_DIVIDER_H, STRIP_GRIP_W,
|
||||||
STRIP_PAD, STRIP_PLUS_GAP,
|
STRIP_PAD, STRIP_PLUS_GAP,
|
||||||
};
|
};
|
||||||
let shown = self.dock_shown_group(side);
|
// Only a group actually on screen is marked as shown: on an
|
||||||
|
// auto-hiding edge nothing is, until a group is revealed.
|
||||||
|
let shown = self
|
||||||
|
.dock_shown_group(side)
|
||||||
|
.filter(|_| self.dock_edge_expanded(side));
|
||||||
let movement = self.dock_drag.and_then(|d| d.movement());
|
let movement = self.dock_drag.and_then(|d| d.movement());
|
||||||
let move_target = movement.and_then(|(_, _, target)| target);
|
let move_target = movement.and_then(|(_, _, target)| target);
|
||||||
let dragging = move_target.is_some();
|
let dragging = move_target.is_some();
|
||||||
|
|||||||
@@ -850,6 +850,10 @@ pub(super) struct OpenCADStudio {
|
|||||||
/// floating frame): hovered, being dragged, or just opened. Cleared when
|
/// floating frame): hovered, being dragged, or just opened. Cleared when
|
||||||
/// the pointer leaves.
|
/// the pointer leaves.
|
||||||
pub(crate) dock_peek: Option<crate::ui::dock::PanelId>,
|
pub(crate) dock_peek: Option<crate::ui::dock::PanelId>,
|
||||||
|
/// Reveal (`Some(pallet)`) or hide (`None`) waiting out the hover delay,
|
||||||
|
/// with the generation its timer carries; any newer hover supersedes it.
|
||||||
|
pub(crate) dock_hover_pending: Option<Option<crate::ui::dock::PanelId>>,
|
||||||
|
pub(crate) dock_hover_gen: u64,
|
||||||
/// What the pointer is dragging in the dock (pallet, group, width,
|
/// What the pointer is dragging in the dock (pallet, group, width,
|
||||||
/// splitter, floating size, Layer Manager column).
|
/// splitter, floating size, Layer Manager column).
|
||||||
pub(crate) dock_drag: Option<crate::ui::dock::DockDrag>,
|
pub(crate) dock_drag: Option<crate::ui::dock::DockDrag>,
|
||||||
@@ -4291,6 +4295,8 @@ impl OpenCADStudio {
|
|||||||
xref_manager: Default::default(),
|
xref_manager: Default::default(),
|
||||||
dock: Default::default(),
|
dock: Default::default(),
|
||||||
dock_peek: None,
|
dock_peek: None,
|
||||||
|
dock_hover_pending: None,
|
||||||
|
dock_hover_gen: 0,
|
||||||
dock_drag: None,
|
dock_drag: None,
|
||||||
dock_drag_last: None,
|
dock_drag_last: None,
|
||||||
dock_title_hover: None,
|
dock_title_hover: None,
|
||||||
|
|||||||
+4
-20
@@ -2552,28 +2552,12 @@ impl OpenCADStudio {
|
|||||||
Message::ScriptLine(line) => self.feed_script_line(&line),
|
Message::ScriptLine(line) => self.feed_script_line(&line),
|
||||||
|
|
||||||
Message::ToggleLayers => {
|
Message::ToggleLayers => {
|
||||||
use crate::ui::dock::PanelId;
|
|
||||||
if self.show_layers {
|
if self.show_layers {
|
||||||
return self.on_dock(crate::ui::dock::DockMsg::Close(PanelId::Layers));
|
return self.on_dock(crate::ui::dock::DockMsg::Close(
|
||||||
|
crate::ui::dock::PanelId::Layers,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
self.sync_ribbon_layers();
|
self.open_layers_pallet();
|
||||||
self.show_layers = true;
|
|
||||||
if !self.dock.is_placed(PanelId::Layers) {
|
|
||||||
// First use: float it over the middle of the drawing,
|
|
||||||
// where the dialog used to open.
|
|
||||||
let (ww, wh) = self.dock_workspace_size();
|
|
||||||
let (w, h) = self.dock_float_size(PanelId::Layers);
|
|
||||||
self.dock.float(crate::ui::dock::FloatPanel {
|
|
||||||
id: PanelId::Layers,
|
|
||||||
x: ((ww - w) * 0.5).max(0.0),
|
|
||||||
y: ((wh - h) * 0.5).max(0.0),
|
|
||||||
w,
|
|
||||||
h,
|
|
||||||
});
|
|
||||||
self.save_config();
|
|
||||||
}
|
|
||||||
self.dock.raise_float(PanelId::Layers);
|
|
||||||
self.dock_reveal(PanelId::Layers);
|
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Layers panel toggle — ribbon definition.
|
// Layer Manager pallet — ribbon definition.
|
||||||
|
|
||||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||||
|
|
||||||
@@ -7,6 +7,8 @@ pub fn tool() -> ToolDef {
|
|||||||
id: "LAYERS",
|
id: "LAYERS",
|
||||||
label: "Layers",
|
label: "Layers",
|
||||||
icon: IconKind::Svg(include_bytes!("../../../../assets/icons/layers/panel.svg")),
|
icon: IconKind::Svg(include_bytes!("../../../../assets/icons/layers/panel.svg")),
|
||||||
event: ModuleEvent::ToggleLayers,
|
// A command like the Blocks palette's: it opens the pallet, and the
|
||||||
|
// ribbon drops the button's highlight once it has run.
|
||||||
|
event: ModuleEvent::Command("LAYERS".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,8 +71,16 @@ pub enum DockMsg {
|
|||||||
FloatRaise(PanelId),
|
FloatRaise(PanelId),
|
||||||
/// The pointer left the edge column; collapse any auto-collapsing panel.
|
/// The pointer left the edge column; collapse any auto-collapsing panel.
|
||||||
HoverExit,
|
HoverExit,
|
||||||
|
/// The pointer entered the edge column again: keep its group revealed.
|
||||||
|
HoverStay,
|
||||||
|
/// The hover delay of the reveal / hide armed as generation `n` ran out.
|
||||||
|
HoverSettled(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How long the pointer must rest before an auto-hiding group reveals or
|
||||||
|
/// hides, so passing over the strip doesn't flash groups open.
|
||||||
|
pub const DOCK_HOVER_DELAY: std::time::Duration = std::time::Duration::from_millis(150);
|
||||||
|
|
||||||
/// The dockable panels the application knows about. New palettes add a variant.
|
/// The dockable panels the application knows about. New palettes add a variant.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
|
|||||||
+29
-36
@@ -323,8 +323,9 @@ impl LayerPanel {
|
|||||||
self.linetype_items = items;
|
self.linetype_items = items;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Layer Manager as a dock pallet: its title bar, then the table at
|
/// The Layer Manager as a dock pallet: its title bar, the toolbar across
|
||||||
/// its natural width, scrolling sideways when the pallet is narrower.
|
/// the pallet (search box on the right), then the table, at least as wide
|
||||||
|
/// as the pallet and scrolling sideways when the pallet is narrower.
|
||||||
pub fn view_panel(
|
pub fn view_panel(
|
||||||
&self,
|
&self,
|
||||||
name_col_w: f32,
|
name_col_w: f32,
|
||||||
@@ -337,19 +338,8 @@ impl LayerPanel {
|
|||||||
crate::tr!("modal", "layer-manager"),
|
crate::tr!("modal", "layer-manager"),
|
||||||
chrome,
|
chrome,
|
||||||
);
|
);
|
||||||
let table = self.view_content(
|
// Inside the pallet's 1 px border on either side.
|
||||||
name_col_w,
|
let body = self.view_content(name_col_w, (width - 2.0).max(0.0));
|
||||||
crate::ui::modal::ModalSizing {
|
|
||||||
width: Length::Shrink,
|
|
||||||
height: Length::Fill,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let body = scrollable(table)
|
|
||||||
.direction(iced::widget::scrollable::Direction::Horizontal(
|
|
||||||
iced::widget::scrollable::Scrollbar::new(),
|
|
||||||
))
|
|
||||||
.width(Length::Fill)
|
|
||||||
.height(Length::Fill);
|
|
||||||
container(column![title_bar, body])
|
container(column![title_bar, body])
|
||||||
.width(Length::Fixed(width))
|
.width(Length::Fixed(width))
|
||||||
.height(Length::Fill)
|
.height(Length::Fill)
|
||||||
@@ -365,11 +355,8 @@ impl LayerPanel {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_content(
|
/// Toolbar and table for a pallet `inner_w` wide.
|
||||||
&self,
|
fn view_content(&self, name_col_w: f32, inner_w: f32) -> Element<'_, Message> {
|
||||||
name_col_w: f32,
|
|
||||||
sizing: crate::ui::modal::ModalSizing,
|
|
||||||
) -> Element<'_, Message> {
|
|
||||||
let has_sel = self.selected.is_some();
|
let has_sel = self.selected.is_some();
|
||||||
let sel_is_zero = self
|
let sel_is_zero = self
|
||||||
.selected
|
.selected
|
||||||
@@ -396,7 +383,7 @@ impl LayerPanel {
|
|||||||
Message::LayerSetCurrent,
|
Message::LayerSetCurrent,
|
||||||
can_set_current,
|
can_set_current,
|
||||||
),
|
),
|
||||||
iced::widget::Space::new().width(sizing.width),
|
iced::widget::Space::new().width(Length::Fill),
|
||||||
// Search box: filters rows by name as the user types (#343).
|
// Search box: filters rows by name as the user types (#343).
|
||||||
text_input(t!("Search…").as_ref(), &self.filter)
|
text_input(t!("Search…").as_ref(), &self.filter)
|
||||||
.on_input(Message::LayerManagerFilterChanged)
|
.on_input(Message::LayerManagerFilterChanged)
|
||||||
@@ -414,7 +401,7 @@ impl LayerPanel {
|
|||||||
)),
|
)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.width(sizing.width)
|
.width(Length::Fill)
|
||||||
.padding([4, 8]);
|
.padding([4, 8]);
|
||||||
|
|
||||||
// ── Column header ─────────────────────────────────────────────────
|
// ── Column header ─────────────────────────────────────────────────
|
||||||
@@ -452,7 +439,6 @@ impl LayerPanel {
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
.spacing(4)
|
.spacing(4)
|
||||||
.width(sizing.width)
|
|
||||||
.align_y(iced::Center);
|
.align_y(iced::Center);
|
||||||
|
|
||||||
for vp in &self.vp_cols {
|
for vp in &self.vp_cols {
|
||||||
@@ -478,7 +464,7 @@ impl LayerPanel {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.padding([4, 8])
|
.padding([4, 8])
|
||||||
.width(sizing.width);
|
.width(Length::Fill);
|
||||||
|
|
||||||
// ── Layer rows ────────────────────────────────────────────────────
|
// ── Layer rows ────────────────────────────────────────────────────
|
||||||
let mut rows_col = column![].spacing(0);
|
let mut rows_col = column![].spacing(0);
|
||||||
@@ -519,19 +505,26 @@ impl LayerPanel {
|
|||||||
|
|
||||||
let table = scrollable(rows_col)
|
let table = scrollable(rows_col)
|
||||||
.id(iced::advanced::widget::Id::new(LAYER_TABLE_SCROLL_ID))
|
.id(iced::advanced::widget::Id::new(LAYER_TABLE_SCROLL_ID))
|
||||||
.height(sizing.height.min(240.0));
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill);
|
||||||
|
|
||||||
// ── Full-window frame ─────────────────────────────────────────────
|
// The header and table stretch to the wider of their columns and the
|
||||||
container(column![toolbar, col_header, table].spacing(0))
|
// pallet (the zero-height spacer), so the header's grey band and
|
||||||
.style(|theme: &Theme| container::Style {
|
// borders always run to the pallet's edge; a narrower pallet scrolls
|
||||||
background: Some(Background::Color(
|
// the table sideways while the toolbar stays put.
|
||||||
theme.palette().background.base.color
|
let grid = column![
|
||||||
)),
|
col_header,
|
||||||
..Default::default()
|
table,
|
||||||
})
|
iced::widget::Space::new().width(Length::Fixed(inner_w)).height(0),
|
||||||
.width(sizing.width)
|
]
|
||||||
.height(sizing.height)
|
.height(Length::Fill);
|
||||||
.into()
|
let grid = scrollable(grid)
|
||||||
|
.direction(iced::widget::scrollable::Direction::Horizontal(
|
||||||
|
iced::widget::scrollable::Scrollbar::new(),
|
||||||
|
))
|
||||||
|
.width(Length::Fill)
|
||||||
|
.height(Length::Fill);
|
||||||
|
column![toolbar, grid].height(Length::Fill).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user