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
15 changes: 13 additions & 2 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,16 @@ config_revision = 3
[keybindings]
# Customize keyboard shortcuts for all actions
# Format: key names with modifiers separated by +
# Examples: "Escape", "Ctrl+Z", "Ctrl+Shift+T", "F10"
# Examples: "Escape", "Ctrl+Z", "Super+X", "Ctrl+Shift+T", "F10",
# "MouseBack", "Ctrl+MouseForward", "StylusPrimary",
# "Ctrl+K > Ctrl+C"
# Super also accepts Meta, Logo, Win, and Windows.
# Auxiliary mouse buttons: MouseBack, MouseForward, MouseExtra1–MouseExtra4.
# Stylus barrel buttons: StylusPrimary, StylusSecondary.
# Keyboard sequences use `>` between two or three chords (Ctrl+K > Ctrl+C).
# Commas still separate independent shortcuts: F5, Ctrl+K > Ctrl+C
# A standalone chord cannot also be a sequence prefix.
# Left, middle, and right cannot be bound as actions.
# Each action can have multiple keybindings (e.g., ["+", "="])

# Exit overlay (or cancel current action)
Expand Down Expand Up @@ -758,7 +767,7 @@ position = "bottom-center"
# Show mouse buttons and scroll wheel
show_mouse = true

# Show taps of bare modifiers (Ctrl, Shift, Alt) as their own chips
# Show taps of bare modifiers (Ctrl, Shift, Alt, Super) as their own chips
show_bare_modifiers = true

# How long a chip stays after its last press, before fading (200 - 30000 ms)
Expand Down Expand Up @@ -1359,6 +1368,8 @@ pressure_thickness_scale_step = 0.1
#
# Each button can trigger a keybinding action on press (e.g. "toggle_radial_menu").
# Omit action to ignore the button.
# Prefer StylusPrimary / StylusSecondary under [keybindings]; these tablet
# nodes keep working until you move them in the configurator.
# Eraser switching is handled automatically via the physical tool type
# (controlled by auto_eraser_switch above), not via barrel buttons.

Expand Down
2 changes: 1 addition & 1 deletion configurator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ if its UI task is no longer observed.

- **Drawing, Arrow, Performance, UI, Board, Capture** – numeric fields with inline validation, toggles, and color editors (RGBA/RGB components).
- **Default color** – toggle between named colors and custom RGB triples.
- **Keybindings** – per-action comma-separated shortcut lists that map to `KeybindingsConfig`.
- **Keybindings** – a bulk shortcut manager over the same per-action chips, recorder, and conflict flow. Filter by All / Changed / Conflicts / Unbound / Device / Sequences, sort by category, name, or changed status, and reset visible or all keybindings with confirmation (draft-only until Save). Review Conflicts walks each collision without picking a winner. `--open keybindings/<section>?search=...` still opens that category and now selects the matching action. Press-to-bind recording covers keys, auxiliary mouse buttons, and stylus barrel buttons, plus **Record Sequence** for two- or three-chord keyboard sequences (`Ctrl+K then Ctrl+C`). Per-row reset and a raw comma-separated text editor remain available (`F5, Ctrl+K > Ctrl+C`). Super/Meta chords record when the desktop delivers them. Legacy `[tablet.stylus_button]` assignments can be moved into the keybinding list with an explicit confirmation. Source badges mark Default, Authored, Legacy Tablet, and Unavailable shortcuts.
- **Session** – persistence settings plus named-session catalog management. Rename display labels, reveal files, and forget metadata without touching files. Clear Tool State preserves boards/history while removing persisted tool defaults. Duplicate, Move, Clear Tool State, and Clear are disabled while an overlay, manually started daemon, or background service is active.
- Live dirty-state indicator plus status banner for success/error details.
- Non-fatal warnings list unrecognized config paths. Those values are preserved for forward compatibility instead of being deleted.
Expand Down
17 changes: 17 additions & 0 deletions configurator/src/app/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ use crate::models::{StartupRequest, TabId};
use super::pages::Binding;
use super::state::ConfiguratorApp;

fn load_app_stylesheet() {
let provider = gtk::CssProvider::new();
// `load_from_string` is 4.12+. The configurator floor is Ubuntu 24.04
// (gtk4 `v4_10`). Workspace `--all-features` unifies gtk4 with the
// overlay crate's `v4_12` and then deprecates this method.
#[allow(deprecated)]
provider.load_from_data(include_str!("style.css"));
if let Some(display) = gtk::gdk::Display::default() {
gtk::style_context_add_provider_for_display(
&display,
&provider,
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
}
}

/// GApplication id. A valid dotted id is required by GLib; the window still
/// advertises this as its Wayland app-id, so compositor rules and the
/// `.desktop` `StartupWMClass` must match it.
Expand Down Expand Up @@ -78,6 +94,7 @@ impl Component for ConfiguratorApp {
type Widgets = AppWidgets;

fn init_root() -> Self::Root {
load_app_stylesheet();
adw::ApplicationWindow::builder()
.default_width(1000)
.default_height(680)
Expand Down
8 changes: 4 additions & 4 deletions configurator/src/app/component/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,10 @@ pub(super) fn build(
return gtk::glib::Propagation::Stop;
}
if key == gtk::gdk::Key::Escape {
// The model owns which destructive question is current.
// Propagate as well so a widget with its own Escape
// behavior does not lose it when no confirmation exists.
sender.input(Message::ActiveConfirmationCanceled);
// The recorder owns Escape while it is open so a recorded
// Escape becomes a binding. Confirmation cancel is the
// fallback when nothing is recording.
sender.input(Message::WindowEscapePressed);
}
// Tab is the user moving focus deliberately; a still-pending
// startup search focus must not steal it back later.
Expand Down
7 changes: 5 additions & 2 deletions configurator/src/app/component/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ pub(super) fn refresh(app: &ConfiguratorApp, widgets: &mut AppWidgets) {
// A color field the parser rejects is an edit that never reached the
// draft, so Save is not offered while one is on screen: pressing it
// would write the last value that parsed and lose the text being typed.
let save_enabled =
app.is_dirty && !app.is_saving && !app.is_loading && app.invalid_color_hex_count() == 0;
let save_enabled = app.is_dirty
&& !app.is_saving
&& !app.is_loading
&& app.invalid_color_hex_count() == 0
&& app.pending_shortcut_conflict.is_none();
if widgets.save_button.is_sensitive() != save_enabled {
widgets.save_button.set_sensitive(save_enabled);
}
Expand Down
206 changes: 0 additions & 206 deletions configurator/src/app/pages/keybindings.rs

This file was deleted.

Loading
Loading