Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,10 @@ context_aware_ui = true
# Show preset action toast notifications on apply/save/clear
show_preset_toasts = true

# Dim the top strip after ~4 seconds without drawing. Set false to keep
# the bar fully visible (accessibility).
idle_fade = true

# Show cursor tool preview bubble near the pointer
show_tool_preview = false

Expand Down
6 changes: 6 additions & 0 deletions configurator/src/app/pages/ui/toolbar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ pub(super) fn build(sender: &ComponentSender<ConfiguratorApp>) -> BuiltPage {
"",
|app| app.draft.ui_toolbar_use_icons,
|value| Message::ToggleChanged(ToggleField::UiToolbarUseIcons, value),
)
.switch_row(
"Dim toolbar when idle",
"Fade the top bar to 55% after a few seconds without drawing. Turn off to keep it fully visible.",
|app| app.draft.ui_toolbar_idle_fade,
|value| Message::ToggleChanged(ToggleField::UiToolbarIdleFade, value),
);

page.group("Sections")
Expand Down
5 changes: 5 additions & 0 deletions configurator/src/app/search/terms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ pub(super) const UI_TOOLBAR_TERMS: &[&str] = &[
"show marker opacity controls",
"show tool preview bubble",
"show preset action toasts",
"dim toolbar when idle",
"idle fade",
"toolbar fade",
"toolbar dim",
"keep toolbar visible",
"force inline toolbars",
"mode overrides",
"edit mode",
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/config/draft/from_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ impl ConfigDraft {
ui_toolbar_use_icons: config.ui.toolbar.use_icons,
ui_toolbar_show_more_colors: config.ui.toolbar.show_more_colors,
ui_toolbar_show_preset_toasts: config.ui.toolbar.show_preset_toasts,
ui_toolbar_idle_fade: config.ui.toolbar.idle_fade,
ui_toolbar_layout_mode: ToolbarLayoutModeOption::from_mode(
config.ui.toolbar.layout_mode,
),
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/config/draft/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub struct ConfigDraft {
pub ui_toolbar_use_icons: bool,
pub ui_toolbar_show_more_colors: bool,
pub ui_toolbar_show_preset_toasts: bool,
pub ui_toolbar_idle_fade: bool,
pub ui_toolbar_layout_mode: ToolbarLayoutModeOption,
pub ui_toolbar_zoom_chip_display: ZoomChipDisplayOption,
pub ui_toolbar_show_zoom_chip: bool,
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/config/setters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ impl ConfigDraft {
ToggleField::UiToolbarUseIcons => self.ui_toolbar_use_icons = value,
ToggleField::UiToolbarShowMoreColors => self.ui_toolbar_show_more_colors = value,
ToggleField::UiToolbarPresetToasts => self.ui_toolbar_show_preset_toasts = value,
ToggleField::UiToolbarIdleFade => self.ui_toolbar_idle_fade = value,
ToggleField::UiToolbarShowPresets => {
self.set_toolbar_section_visible(ToolbarSectionFlag::Presets, value);
}
Expand Down
14 changes: 14 additions & 0 deletions configurator/src/models/config/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,20 @@ fn config_draft_round_trips_ui_reduced_motion() {
assert_eq!(round_trip.ui.reduced_motion, ReducedMotion::On);
}

#[test]
fn config_draft_round_trips_ui_toolbar_idle_fade() {
let mut config = Config::default();
config.ui.toolbar.idle_fade = false;

let draft = ConfigDraft::from_config(&config);
assert!(!draft.ui_toolbar_idle_fade);

let round_trip = draft
.to_config(&config)
.expect("expected config to round trip");
assert!(!round_trip.ui.toolbar.idle_fade);
}

/// The revision is provenance for a review the user went through, so a draft
/// that never applied a migration must not stamp one on an old file.
#[test]
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/config/to_config/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl ConfigDraft {
config.ui.toolbar.use_icons = self.ui_toolbar_use_icons;
config.ui.toolbar.show_more_colors = self.ui_toolbar_show_more_colors;
config.ui.toolbar.show_preset_toasts = self.ui_toolbar_show_preset_toasts;
config.ui.toolbar.idle_fade = self.ui_toolbar_idle_fade;
config.ui.toolbar.layout_mode = self.ui_toolbar_layout_mode.to_mode();
config.ui.toolbar.zoom_chip_display = self.ui_toolbar_zoom_chip_display.to_config();
config.ui.toolbar.show_zoom_chip = self.ui_toolbar_show_zoom_chip;
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/fields/toggles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub enum ToggleField {
UiToolbarUseIcons,
UiToolbarShowMoreColors,
UiToolbarPresetToasts,
UiToolbarIdleFade,
UiToolbarShowPresets,
UiToolbarShowActionsSection,
UiToolbarShowActionsAdvanced,
Expand Down
10 changes: 7 additions & 3 deletions docs/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ saved separately so moving through the UI does not rewrite unrelated configurati
- individual toolbar item visibility and toolbar item order;
- the toolbar layout preset and which named toolbar sections are shown;
- the toolbar's own appearance and behaviour toggles — icons vs text labels, extra colours,
context-aware UI, preset toasts, the tool preview, and the delay sliders;
context-aware UI, preset toasts, idle fade, the tool preview, and the delay sliders;
- the status bar, whether its segments respond to clicks, and which segments are shown;
- the board and page badges, the floating badge, and the zoom chip;
- the click highlight and the ring the highlight tool keeps on screen;
Expand Down Expand Up @@ -167,7 +167,7 @@ Both `config.toml` mechanisms leave a timestamped `.bak` beside the file.
| Toggle the status bar, its interactivity, or one of its items; the board/page badges, floating badge, or zoom chip | `runtime-ui.toml` | Runtime-UI writer |
| Toggle click highlight or the highlight-tool ring | `runtime-ui.toml` — both at once | Runtime-UI writer |
| Toggle the input HUD | `runtime-ui.toml` | Runtime-UI writer |
| Toggle the Step section, delay sliders, tool preview, preset toasts, extra colors, or context-aware UI | `runtime-ui.toml` | Runtime-UI writer |
| Toggle the Step section, delay sliders, tool preview, preset toasts, idle fade, extra colors, or context-aware UI | `runtime-ui.toml` | Runtime-UI writer |
| Save or clear a preset slot in the overlay | `config.toml` — that one `[presets.slot_N]` table | Overlay editor (with a timestamped `.bak`) |
| Recolor a quick color swatch in the overlay | `config.toml` — that one `[[drawing.quick_colors]]` entry | Overlay editor (with a timestamped `.bak`) |
| Rename, recolor, add, or delete a board | The session file, for boards marked `persist` | Configurator → Boards for the templates a new session starts from |
Expand Down Expand Up @@ -1107,6 +1107,10 @@ context_aware_ui = true
# Show preset action toast notifications on apply/save/clear
show_preset_toasts = true

# Dim the top strip after ~4 seconds without drawing. Set false to keep
# the bar fully visible (accessibility).
idle_fade = true

# Show cursor tool preview bubble
show_tool_preview = false

Expand Down Expand Up @@ -1188,7 +1192,7 @@ top_controls = [
- **Pinned**: `top_pinned` is the authored default for whether the top toolbar opens on startup. Pinning or unpinning in the overlay saves to `runtime-ui.toml` and leaves this value alone. The show/hide keybinding (`toggle_toolbar`, default <kbd>F9</kbd>) updates the remembered pin, so the next start matches what was on screen.
- **Minimize**: the toolbar minimize button collapses the top strip to a small edge tab instead of hiding it, so there is always an on-screen way back; `top_minimized` is the authored default, and the state you leave the bar in survives restarts as a runtime preference in `runtime-ui.toml`. F9 still toggles full visibility.
- **Micro mode**: `cycle_toolbar_display` (default <kbd>F2</kbd>) cycles the top strip full → micro → hidden. Micro collapses the strip to one 44px round chip showing the active tool inside a ring stroked in the current color (ring width follows stroke thickness); clicking the chip restores the full strip. The full/micro form persists as a runtime preference in `runtime-ui.toml`, seeded by the authored `top_display_mode`; the hidden step alone is runtime-only — the next start derives the strip's visibility from the remembered pin (which the F9 show/hide toggle updates durably), so a cycle-hidden strip comes back. Entering micro un-minimizes the strip; if a config sets both `top_minimized` and micro, the minimized restore tab wins.
- **Idle fade**: the top-strip islands dim to 55% opacity after ~4 seconds without drawing activity and restore when the pointer approaches the toolbar (or on the next stroke). Open top-strip menus, the minimized tab, and the micro chip never fade. With `[ui] reduced_motion` the fade snaps instantly instead of animating; there is no separate config key.
- **Idle fade**: `idle_fade` dims the top-strip islands to 55% opacity after ~4 seconds without drawing activity and restores when the pointer approaches the toolbar (or on the next stroke). Open top-strip menus, the minimized tab, and the micro chip never fade. With `[ui] reduced_motion` the fade snaps instantly instead of animating. Set `idle_fade = false` (or uncheck **Idle fade** in the overlay Settings popover / **Dim toolbar when idle** in the configurator) to keep the bar fully visible.
- **Top-only toolbar**: the unified top toolbar is the only supported layout. Drawing properties live in the contextual style pill; canvas management lives in the **"Canvas…" overflow popover**, the **bottom-right zoom chip**, and the **status-bar board picker**; presets live in the **top-strip presets island**; Session and Settings live in overflow popovers. Older panel keys (`side_layout`, `side_pinned`, `side_minimized`, `side_active_pane`, `collapsed_sections`, `side_offset`, `side_offset_x`, `show_settings_section`, and the retired `items.order.*` lists `side_sections`, `actions`, `pages`, `boards`, `presets`, `tool_options`, and `sessions`) remain readable, are preserved on unrelated saves, and surface as retired-setting diagnostics so they can be removed manually.
- **Session/Settings popovers**: the top strip's overflow menu always carries "Session..." and "Settings..." entries. Opening one closes the other and the overflow menu; Escape and clicking away dismiss it. Content taller than the popover cap scrolls internally.
- **Hidden items**: `ui.toolbar.items.hidden` removes known toolbar buttons/sections from sizing, drawing, and hit testing while preserving unknown future IDs.
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/backend/state_init/input_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ pub(super) fn build_input_state(config: &Config) -> InputState {
config.ui.toolbar.show_delay_sliders,
config.ui.toolbar.show_marker_opacity_section,
config.ui.toolbar.show_preset_toasts,
config.ui.toolbar.idle_fade,
config.ui.toolbar.show_tool_preview,
);
input_state.init_toolbar_minimized_from_config(config.ui.toolbar.top_minimized);
Expand Down
5 changes: 5 additions & 0 deletions src/backend/wayland/runtime_ui_state/live_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ pub(super) fn apply_live_toolbar_state(
{
input.show_preset_toasts = value;
}
if include(&InteractionSeedTarget::ToolbarIdleFade)
&& let Some(value) = bool_value(InteractionSeedTarget::ToolbarIdleFade)
{
input.idle_fade = value;
}
if include(&InteractionSeedTarget::ToolbarToolPreview)
&& let Some(value) = bool_value(InteractionSeedTarget::ToolbarToolPreview)
{
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/runtime_ui_state/rollback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub(in crate::backend::wayland) fn apply_toolbar_runtime_rollback(
Target::ToolbarMoreColors => set_bool(value, |v| input.show_more_colors = v),
Target::ToolbarContextAwareUi => set_bool(value, |v| input.context_aware_ui = v),
Target::ToolbarPresetToasts => set_bool(value, |v| input.show_preset_toasts = v),
Target::ToolbarIdleFade => set_bool(value, |v| input.idle_fade = v),
Target::ToolbarToolPreview => set_bool(value, |v| input.show_tool_preview = v),
Target::ToolbarDelaySliders => set_bool(value, |v| input.show_delay_sliders = v),
Target::HistoryCustomSection => set_bool(value, |v| input.custom_section_enabled = v),
Expand Down
8 changes: 8 additions & 0 deletions src/backend/wayland/runtime_ui_state/seeds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ pub(super) fn runtime_seeds_from_config(
InteractionSeedTarget::ToolbarPresetToasts,
InteractionSeedValue::Bool(config.ui.toolbar.show_preset_toasts),
)?;
insert(
InteractionSeedTarget::ToolbarIdleFade,
InteractionSeedValue::Bool(config.ui.toolbar.idle_fade),
)?;
insert(
InteractionSeedTarget::ToolbarToolPreview,
InteractionSeedValue::Bool(config.ui.toolbar.show_tool_preview),
Expand Down Expand Up @@ -238,6 +242,10 @@ pub(super) fn toolbar_values(
InteractionSeedTarget::ToolbarPresetToasts,
InteractionSeedValue::Bool(input.show_preset_toasts),
),
Target::ToolbarIdleFade => RuntimeUiMutationValues::one(
InteractionSeedTarget::ToolbarIdleFade,
InteractionSeedValue::Bool(input.idle_fade),
),
Target::ToolbarToolPreview => RuntimeUiMutationValues::one(
InteractionSeedTarget::ToolbarToolPreview,
InteractionSeedValue::Bool(user_tool_preview(input)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ fn a_rollback_restores_every_durable_chrome_preference() {
|i| i.show_preset_toasts,
|i| i.show_preset_toasts = !i.show_preset_toasts,
),
(
InteractionSeedTarget::ToolbarIdleFade,
|i| i.idle_fade,
|i| i.idle_fade = !i.idle_fade,
),
(
InteractionSeedTarget::ToolbarToolPreview,
|i| i.show_tool_preview,
Expand Down
2 changes: 2 additions & 0 deletions src/backend/wayland/state/toolbar/events/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ fn overlay_preference_toggles_leave_both_configs_untouched() {
ToolbarEvent::ToggleMoreColors(true),
ToolbarEvent::ToggleContextAwareUi(false),
ToolbarEvent::TogglePresetToasts(false),
ToolbarEvent::ToggleIdleFade(false),
ToolbarEvent::ToggleDelaySliders(true),
ToolbarEvent::ToggleCustomSection(true),
ToolbarEvent::ToggleInputHud(true),
Expand Down Expand Up @@ -829,6 +830,7 @@ fn settings_popover_survives_its_own_controls_and_dismisses_on_everything_else()
ToolbarEvent::ToggleStatusPageBadge(true),
ToolbarEvent::ToggleFloatingBadgeAlways(true),
ToolbarEvent::TogglePresetToasts(true),
ToolbarEvent::ToggleIdleFade(true),
ToolbarEvent::ToggleInputHud(true),
ToolbarEvent::TogglePresets(true),
ToolbarEvent::ToggleActionsSection(true),
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/state/toolbar/fade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ impl WaylandState {
pointer_near,
menus_open: top_menus_open(input),
reduced_chrome,
idle_fade_enabled: input.idle_fade,
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions src/config/tests/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,23 @@ fn ui_status_bar_interactive_round_trips_disabled_value() {
assert!(!reparsed.ui.status_bar_interactive);
}

#[test]
fn ui_toolbar_idle_fade_defaults_to_true_and_round_trips_disabled() {
assert!(Config::default().ui.toolbar.idle_fade);

let omitted: Config = toml::from_str("[ui.toolbar]\nuse_icons = true\n")
.expect("toolbar table without idle_fade should parse");
assert!(omitted.ui.toolbar.idle_fade);

let parsed: Config = toml::from_str("[ui.toolbar]\nidle_fade = false\n")
.expect("idle_fade = false should parse");
assert!(!parsed.ui.toolbar.idle_fade);

let serialized = toml::to_string(&parsed).expect("config serializes");
let reparsed: Config = toml::from_str(&serialized).expect("serialized config reparses");
assert!(!reparsed.ui.toolbar.idle_fade);
}

#[cfg(feature = "tablet-input")]
#[test]
fn load_defaults_tablet_input_to_enabled_when_section_is_missing() {
Expand Down
9 changes: 9 additions & 0 deletions src/config/types/toolbar/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ pub struct ToolbarConfig {
#[serde(default = "default_show_preset_toasts")]
pub show_preset_toasts: bool,

/// Dim the top strip after a few seconds without drawing
#[serde(default = "default_idle_fade")]
pub idle_fade: bool,

/// Show the cursor tool preview bubble
#[serde(default = "default_show_tool_preview")]
pub show_tool_preview: bool,
Expand Down Expand Up @@ -161,6 +165,7 @@ impl Default for ToolbarConfig {
show_marker_opacity_section: default_show_marker_opacity_section(),
context_aware_ui: default_context_aware_ui(),
show_preset_toasts: default_show_preset_toasts(),
idle_fade: default_idle_fade(),
show_tool_preview: default_show_tool_preview(),
top_offset: 0.0,
top_offset_y: 0.0,
Expand Down Expand Up @@ -242,6 +247,10 @@ fn default_show_preset_toasts() -> bool {
true
}

fn default_idle_fade() -> bool {
true
}

fn default_show_tool_preview() -> bool {
false
}
1 change: 1 addition & 0 deletions src/input/state/core/base/state/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ impl InputState {
show_delay_sliders: false, // Default to hidden
show_marker_opacity_section: false,
show_preset_toasts: true,
idle_fade: true,
show_tool_preview: false,
ui_toast: None,
toast_queue: super::super::toast_queue::ToastQueue::default(),
Expand Down
2 changes: 2 additions & 0 deletions src/input/state/core/base/state/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ pub struct InputState {
pub show_marker_opacity_section: bool,
/// Whether to show preset action toast notifications
pub show_preset_toasts: bool,
/// Whether the top strip dims after a few seconds without drawing
pub idle_fade: bool,
/// Whether to show the cursor tool preview bubble
pub show_tool_preview: bool,
/// Active (visible) UI toast (errors/warnings/info)
Expand Down
3 changes: 3 additions & 0 deletions src/input/state/core/tool_controls/toolbar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ impl InputState {
show_delay_sliders: bool,
show_marker_opacity_section: bool,
show_preset_toasts: bool,
idle_fade: bool,
show_tool_preview: bool,
) {
self.toolbar_top_pinned = top_pinned;
Expand All @@ -221,6 +222,7 @@ impl InputState {
self.show_delay_sliders = show_delay_sliders;
self.show_marker_opacity_section = show_marker_opacity_section;
self.show_preset_toasts = show_preset_toasts;
self.idle_fade = idle_fade;
self.show_tool_preview = show_tool_preview;
// Fold the legacy show_* booleans into explicit item overrides,
// then re-derive them from the one resolver. Effective visibility
Expand Down Expand Up @@ -550,6 +552,7 @@ mod tests {
false,
false,
true,
true,
false,
);

Expand Down
4 changes: 4 additions & 0 deletions src/input/state/tests/toolbar_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,10 @@ fn run_only_toolbar_preference_events_never_mark_the_session_dirty() {
ToolbarEvent::TogglePresetToasts(false),
ToolbarEvent::TogglePresetToasts(true),
],
[
ToolbarEvent::ToggleIdleFade(false),
ToolbarEvent::ToggleIdleFade(true),
],
[
ToolbarEvent::ToggleToolPreview(false),
ToolbarEvent::ToggleToolPreview(true),
Expand Down
2 changes: 2 additions & 0 deletions src/runtime_ui_state/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ pub(crate) enum InteractionSeedTarget {
ToolbarMoreColors,
ToolbarContextAwareUi,
ToolbarPresetToasts,
ToolbarIdleFade,
ToolbarToolPreview,
ToolbarDelaySliders,
/// The history pane's custom-step section.
Expand Down Expand Up @@ -177,6 +178,7 @@ impl InteractionSeedValue {
| Target::ToolbarMoreColors
| Target::ToolbarContextAwareUi
| Target::ToolbarPresetToasts
| Target::ToolbarIdleFade
| Target::ToolbarToolPreview
| Target::ToolbarDelaySliders
| Target::HistoryCustomSection
Expand Down
Loading
Loading