Skip to content

Commit 414c827

Browse files
authored
Merge pull request #243 from devmobasa/feat/collapsible-side-sections
feat: add collapsible side sections
2 parents e36a296 + aa420d8 commit 414c827

41 files changed

Lines changed: 1539 additions & 455 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/backend/wayland/state/toolbar/events/tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::config::ToolbarLayoutMode;
88
use crate::draw::{Color, FontDescriptor};
99
use crate::input::state::test_support::make_test_input_state;
1010
use crate::input::{EraserMode, Tool};
11+
use crate::ui::toolbar::ToolbarSideSection;
1112
use anyhow::anyhow;
1213
use std::fs;
1314
use std::path::{Path, PathBuf};
@@ -77,6 +78,7 @@ fn runtime_toolbar_events_do_not_directly_save_config() {
7778
ToolbarEvent::SaveSessionAsCancel,
7879
ToolbarEvent::SessionInfo,
7980
ToolbarEvent::ClearSession,
81+
ToolbarEvent::ToggleSideSectionCollapsed(ToolbarSideSection::Session, true),
8082
];
8183

8284
for event in events {

src/backend/wayland/toolbar/layout/side/actions.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::{HitKind, HitRegion, SideLayoutContext, ToolbarLayoutSpec, format_binding_label};
22
use crate::backend::wayland::toolbar::rows::{centered_grid_layout, grid_layout, row_item_width};
3+
use crate::ui::toolbar::ToolbarSideSection;
34
use crate::ui::toolbar::model::{
45
ToolbarActionsModel, ToolbarCommandGroup, ToolbarCommandGroupKind,
56
};
@@ -14,6 +15,14 @@ pub(super) fn push_actions_hits(
1415
};
1516

1617
let actions_card_h = ctx.spec.side_actions_height(ctx.snapshot);
18+
super::section_header::push_collapsible_header_hit(ctx, y, ToolbarSideSection::Actions, hits);
19+
if ctx
20+
.snapshot
21+
.side_section_collapsed(ToolbarSideSection::Actions)
22+
{
23+
return y + actions_card_h + ctx.section_gap;
24+
}
25+
1726
let mut action_y = y + ToolbarLayoutSpec::SIDE_SECTION_TOGGLE_OFFSET_Y;
1827
let mut has_group = false;
1928
for group in model.groups() {
Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,95 @@
1-
use super::{SideLayoutContext, ToolbarLayoutSpec};
2-
use crate::ui::toolbar::ToolContext;
1+
use super::{HitKind, HitRegion, SideLayoutContext, ToolbarEvent, ToolbarLayoutSpec};
2+
use crate::ui::toolbar::{ToolContext, ToolbarSideSection};
33

4-
// Arrow hit regions are built in render to avoid duplicate registrations.
5-
pub(super) fn advance_arrow_section(ctx: &SideLayoutContext<'_>, y: f64) -> f64 {
4+
pub(super) fn push_arrow_section_hits(
5+
ctx: &SideLayoutContext<'_>,
6+
y: f64,
7+
hits: &mut Vec<HitRegion>,
8+
) -> f64 {
69
if !ToolContext::from_snapshot(ctx.snapshot).show_arrow_labels {
710
return y;
811
}
912

10-
let card_h = if ctx.snapshot.arrow_label_enabled {
11-
ToolbarLayoutSpec::SIDE_TOGGLE_CARD_HEIGHT_WITH_RESET
12-
} else {
13-
ToolbarLayoutSpec::SIDE_TOGGLE_CARD_HEIGHT
14-
};
13+
let card_h = ctx.spec.side_arrow_labels_height(ctx.snapshot);
14+
super::section_header::push_collapsible_header_hit(
15+
ctx,
16+
y,
17+
ToolbarSideSection::ArrowLabels,
18+
hits,
19+
);
20+
if ctx
21+
.snapshot
22+
.side_section_collapsed(ToolbarSideSection::ArrowLabels)
23+
{
24+
return y + card_h + ctx.section_gap;
25+
}
26+
27+
let toggle_y = y + ToolbarLayoutSpec::SIDE_SECTION_TOGGLE_OFFSET_Y;
28+
hits.push(HitRegion {
29+
rect: (
30+
ctx.x,
31+
toggle_y,
32+
ctx.content_width,
33+
ToolbarLayoutSpec::SIDE_TOGGLE_HEIGHT,
34+
),
35+
event: ToolbarEvent::ToggleArrowLabels(!ctx.snapshot.arrow_label_enabled),
36+
kind: HitKind::Click,
37+
tooltip: Some("Auto-number arrows 1, 2, 3.".to_string()),
38+
});
39+
if ctx.snapshot.arrow_label_enabled {
40+
let reset_y =
41+
toggle_y + ToolbarLayoutSpec::SIDE_TOGGLE_HEIGHT + ToolbarLayoutSpec::SIDE_TOGGLE_GAP;
42+
hits.push(HitRegion {
43+
rect: (
44+
ctx.x,
45+
reset_y,
46+
ctx.content_width,
47+
ToolbarLayoutSpec::SIDE_TOGGLE_HEIGHT,
48+
),
49+
event: ToolbarEvent::ResetArrowLabelCounter,
50+
kind: HitKind::Click,
51+
tooltip: Some("Reset numbering to 1.".to_string()),
52+
});
53+
}
54+
55+
y + card_h + ctx.section_gap
56+
}
57+
58+
pub(super) fn push_step_marker_hits(
59+
ctx: &SideLayoutContext<'_>,
60+
y: f64,
61+
hits: &mut Vec<HitRegion>,
62+
) -> f64 {
63+
if !ToolContext::from_snapshot(ctx.snapshot).show_step_counter {
64+
return y;
65+
}
66+
67+
let card_h = ctx.spec.side_step_markers_height(ctx.snapshot);
68+
super::section_header::push_collapsible_header_hit(
69+
ctx,
70+
y,
71+
ToolbarSideSection::StepMarkers,
72+
hits,
73+
);
74+
if ctx
75+
.snapshot
76+
.side_section_collapsed(ToolbarSideSection::StepMarkers)
77+
{
78+
return y + card_h + ctx.section_gap;
79+
}
80+
81+
let reset_y = y + ToolbarLayoutSpec::SIDE_SECTION_TOGGLE_OFFSET_Y;
82+
hits.push(HitRegion {
83+
rect: (
84+
ctx.x,
85+
reset_y,
86+
ctx.content_width,
87+
ToolbarLayoutSpec::SIDE_TOGGLE_HEIGHT,
88+
),
89+
event: ToolbarEvent::ResetStepMarkerCounter,
90+
kind: HitKind::Click,
91+
tooltip: Some("Reset numbering to 1.".to_string()),
92+
});
93+
1594
y + card_h + ctx.section_gap
1695
}

src/backend/wayland/toolbar/layout/side/boards.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::{HitKind, HitRegion, SideLayoutContext, ToolbarLayoutSpec, format_binding_label};
22
use crate::backend::wayland::toolbar::rows::{capped_grid_columns, grid_layout, row_item_width};
3+
use crate::ui::toolbar::ToolbarSideSection;
34
use crate::ui::toolbar::model::toolbar_boards_model;
45

56
pub(super) fn push_boards_hits(
@@ -12,6 +13,14 @@ pub(super) fn push_boards_hits(
1213
};
1314

1415
let boards_card_h = ctx.spec.side_boards_height(ctx.snapshot);
16+
super::section_header::push_collapsible_header_hit(ctx, y, ToolbarSideSection::Boards, hits);
17+
if ctx
18+
.snapshot
19+
.side_section_collapsed(ToolbarSideSection::Boards)
20+
{
21+
return y + boards_card_h + ctx.section_gap;
22+
}
23+
1524
let boards_y = y + ToolbarLayoutSpec::SIDE_SECTION_TOGGLE_OFFSET_Y;
1625
let btn_h = if ctx.use_icons {
1726
ToolbarLayoutSpec::SIDE_ACTION_BUTTON_HEIGHT_ICON

src/backend/wayland/toolbar/layout/side/colors.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
use super::{HitKind, HitRegion, SideLayoutContext, ToolbarEvent, ToolbarLayoutSpec};
2+
use crate::ui::toolbar::ToolbarSideSection;
23

34
pub(super) fn push_color_picker_hits(
45
ctx: &SideLayoutContext<'_>,
56
y: f64,
67
hits: &mut Vec<HitRegion>,
78
) -> f64 {
9+
let card_h = ctx.spec.side_colors_height(ctx.snapshot);
10+
super::section_header::push_collapsible_header_hit(ctx, y, ToolbarSideSection::Colors, hits);
11+
if ctx
12+
.snapshot
13+
.side_section_collapsed(ToolbarSideSection::Colors)
14+
{
15+
return y + card_h + ctx.section_gap;
16+
}
17+
818
let picker_y = y + ToolbarLayoutSpec::SIDE_COLOR_PICKER_OFFSET_Y;
919
let picker_h = ctx.spec.side_color_picker_height(ctx.snapshot);
1020
hits.push(HitRegion {
@@ -19,5 +29,5 @@ pub(super) fn push_color_picker_hits(
1929
tooltip: None,
2030
});
2131

22-
y + ctx.spec.side_colors_height(ctx.snapshot) + ctx.section_gap
32+
y + card_h + ctx.section_gap
2333
}

src/backend/wayland/toolbar/layout/side/delay.rs

Lines changed: 77 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,92 @@ use super::{
22
HitKind, HitRegion, SideLayoutContext, ToolbarEvent, ToolbarLayoutSpec, delay_secs_from_t,
33
delay_t_from_ms,
44
};
5+
use crate::ui::toolbar::ToolbarSideSection;
56

67
pub(super) fn push_delay_hits(
78
ctx: &SideLayoutContext<'_>,
89
y: f64,
910
hits: &mut Vec<HitRegion>,
1011
) -> f64 {
11-
if ctx.snapshot.show_step_section
12-
&& ctx.snapshot.show_delay_sliders
13-
&& ctx.snapshot.drawer_open
14-
&& ctx.snapshot.drawer_tab == crate::input::ToolbarDrawerTab::App
12+
if !ctx.snapshot.show_step_section
13+
|| !ctx.snapshot.drawer_open
14+
|| ctx.snapshot.drawer_tab != crate::input::ToolbarDrawerTab::App
1515
{
16-
let undo_t = delay_t_from_ms(ctx.snapshot.undo_all_delay_ms);
17-
let redo_t = delay_t_from_ms(ctx.snapshot.redo_all_delay_ms);
18-
let toggles_h =
19-
ToolbarLayoutSpec::SIDE_TOGGLE_HEIGHT * 2.0 + ToolbarLayoutSpec::SIDE_TOGGLE_GAP;
20-
let custom_h = if ctx.snapshot.custom_section_enabled {
21-
ToolbarLayoutSpec::SIDE_CUSTOM_SECTION_HEIGHT
22-
} else {
23-
0.0
24-
};
25-
let slider_start_y = y
26-
+ ToolbarLayoutSpec::SIDE_STEP_HEADER_HEIGHT
27-
+ toggles_h
28-
+ custom_h
29-
+ ToolbarLayoutSpec::SIDE_STEP_SLIDER_TOP_PADDING;
30-
let slider_hit_h = ToolbarLayoutSpec::SIDE_DELAY_SLIDER_HEIGHT
31-
+ ToolbarLayoutSpec::SIDE_DELAY_SLIDER_HIT_PADDING * 2.0;
32-
let undo_y = slider_start_y + ToolbarLayoutSpec::SIDE_DELAY_SLIDER_UNDO_OFFSET_Y;
33-
hits.push(HitRegion {
34-
rect: (
35-
ctx.x,
36-
undo_y - ToolbarLayoutSpec::SIDE_DELAY_SLIDER_HIT_PADDING,
37-
ctx.content_width,
38-
slider_hit_h,
39-
),
40-
event: ToolbarEvent::SetUndoDelay(delay_secs_from_t(undo_t)),
41-
kind: HitKind::DragUndoDelay,
42-
tooltip: None,
43-
});
44-
let redo_y = slider_start_y + ToolbarLayoutSpec::SIDE_DELAY_SLIDER_REDO_OFFSET_Y;
45-
hits.push(HitRegion {
46-
rect: (
47-
ctx.x,
48-
redo_y - ToolbarLayoutSpec::SIDE_DELAY_SLIDER_HIT_PADDING,
49-
ctx.content_width,
50-
slider_hit_h,
51-
),
52-
event: ToolbarEvent::SetRedoDelay(delay_secs_from_t(redo_t)),
53-
kind: HitKind::DragRedoDelay,
54-
tooltip: None,
55-
});
16+
return y;
5617
}
5718

58-
if ctx.snapshot.show_step_section
59-
&& ctx.snapshot.drawer_open
60-
&& ctx.snapshot.drawer_tab == crate::input::ToolbarDrawerTab::App
19+
let card_h = ctx.spec.side_step_height(ctx.snapshot);
20+
super::section_header::push_collapsible_header_hit(ctx, y, ToolbarSideSection::StepUndo, hits);
21+
if ctx
22+
.snapshot
23+
.side_section_collapsed(ToolbarSideSection::StepUndo)
6124
{
62-
y + ctx.spec.side_step_height(ctx.snapshot) + ctx.section_gap
63-
} else {
64-
y
25+
return y + card_h + ctx.section_gap;
26+
}
27+
28+
let toggle_h = ToolbarLayoutSpec::SIDE_TOGGLE_HEIGHT;
29+
let toggle_gap = ToolbarLayoutSpec::SIDE_TOGGLE_GAP;
30+
let custom_toggle_y = y + ToolbarLayoutSpec::SIDE_SECTION_TOGGLE_OFFSET_Y;
31+
hits.push(HitRegion {
32+
rect: (ctx.x, custom_toggle_y, ctx.content_width, toggle_h),
33+
event: ToolbarEvent::ToggleCustomSection(!ctx.snapshot.custom_section_enabled),
34+
kind: HitKind::Click,
35+
tooltip: Some("Step controls: multi-step undo/redo.".to_string()),
36+
});
37+
let delay_toggle_y = custom_toggle_y + toggle_h + toggle_gap;
38+
hits.push(HitRegion {
39+
rect: (ctx.x, delay_toggle_y, ctx.content_width, toggle_h),
40+
event: ToolbarEvent::ToggleDelaySliders(!ctx.snapshot.show_delay_sliders),
41+
kind: HitKind::Click,
42+
tooltip: Some("Delay sliders: undo/redo delays.".to_string()),
43+
});
44+
45+
if ctx.snapshot.show_delay_sliders {
46+
push_delay_slider_hits(ctx, y, hits);
6547
}
48+
49+
y + card_h + ctx.section_gap
50+
}
51+
52+
fn push_delay_slider_hits(ctx: &SideLayoutContext<'_>, y: f64, hits: &mut Vec<HitRegion>) {
53+
let undo_t = delay_t_from_ms(ctx.snapshot.undo_all_delay_ms);
54+
let redo_t = delay_t_from_ms(ctx.snapshot.redo_all_delay_ms);
55+
let toggles_h =
56+
ToolbarLayoutSpec::SIDE_TOGGLE_HEIGHT * 2.0 + ToolbarLayoutSpec::SIDE_TOGGLE_GAP;
57+
let custom_h = if ctx.snapshot.custom_section_enabled {
58+
ToolbarLayoutSpec::SIDE_CUSTOM_SECTION_HEIGHT
59+
} else {
60+
0.0
61+
};
62+
let slider_start_y = y
63+
+ ToolbarLayoutSpec::SIDE_STEP_HEADER_HEIGHT
64+
+ toggles_h
65+
+ custom_h
66+
+ ToolbarLayoutSpec::SIDE_STEP_SLIDER_TOP_PADDING;
67+
let slider_hit_h = ToolbarLayoutSpec::SIDE_DELAY_SLIDER_HEIGHT
68+
+ ToolbarLayoutSpec::SIDE_DELAY_SLIDER_HIT_PADDING * 2.0;
69+
let undo_y = slider_start_y + ToolbarLayoutSpec::SIDE_DELAY_SLIDER_UNDO_OFFSET_Y;
70+
hits.push(HitRegion {
71+
rect: (
72+
ctx.x,
73+
undo_y - ToolbarLayoutSpec::SIDE_DELAY_SLIDER_HIT_PADDING,
74+
ctx.content_width,
75+
slider_hit_h,
76+
),
77+
event: ToolbarEvent::SetUndoDelay(delay_secs_from_t(undo_t)),
78+
kind: HitKind::DragUndoDelay,
79+
tooltip: None,
80+
});
81+
let redo_y = slider_start_y + ToolbarLayoutSpec::SIDE_DELAY_SLIDER_REDO_OFFSET_Y;
82+
hits.push(HitRegion {
83+
rect: (
84+
ctx.x,
85+
redo_y - ToolbarLayoutSpec::SIDE_DELAY_SLIDER_HIT_PADDING,
86+
ctx.content_width,
87+
slider_hit_h,
88+
),
89+
event: ToolbarEvent::SetRedoDelay(delay_secs_from_t(redo_t)),
90+
kind: HitKind::DragRedoDelay,
91+
tooltip: None,
92+
});
6693
}

0 commit comments

Comments
 (0)