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
163 changes: 147 additions & 16 deletions src/app/usage.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,160 @@
use std::collections::HashMap;

use crate::config::{Action, KeyBinding, KeybindingsConfig, action_display_label, action_label};
use crate::label_format::format_binding_labels;

fn default_action_bindings() -> HashMap<Action, Vec<KeyBinding>> {
match KeybindingsConfig::default().build_action_bindings() {
Ok(bindings) => bindings,
Err(err) => {
log::warn!("Failed to build default keybindings: {}", err);
HashMap::new()
}
}
}

fn action_binding_labels(
bindings: &HashMap<Action, Vec<KeyBinding>>,
action: Action,
) -> Vec<String> {
bindings
.get(&action)
.map(|list| list.iter().map(ToString::to_string).collect())
.unwrap_or_default()
}

fn action_binding_label(bindings: &HashMap<Action, Vec<KeyBinding>>, action: Action) -> String {
format_binding_labels(&action_binding_labels(bindings, action))
}

fn action_primary_binding_label(
bindings: &HashMap<Action, Vec<KeyBinding>>,
action: Action,
) -> Option<String> {
bindings
.get(&action)
.and_then(|list| list.first())
.map(|binding| binding.to_string())
}

fn color_binding_labels(bindings: &HashMap<Action, Vec<KeyBinding>>) -> String {
let colors = [
Action::SetColorRed,
Action::SetColorGreen,
Action::SetColorBlue,
Action::SetColorYellow,
Action::SetColorOrange,
Action::SetColorPink,
Action::SetColorWhite,
Action::SetColorBlack,
];
let mut parts = Vec::new();
for action in colors {
let label = action_label(action);
if let Some(binding) = action_primary_binding_label(bindings, action) {
parts.push(format!("{binding} ({label})"));
} else {
parts.push(label.to_string());
}
}
parts.join(", ")
}

pub(crate) fn log_overlay_controls(freeze: bool) {
log::info!("Starting Wayland overlay...");
log::info!("Starting annotation overlay...");
log::info!("Controls:");
log::info!(" - Freehand: Just drag");
log::info!(" - Line: Hold Shift + drag");
log::info!(" - Rectangle: Hold Ctrl + drag");
log::info!(" - Ellipse: Hold Tab + drag");
log::info!(" - Arrow: Hold Ctrl+Shift + drag");
log::info!(" - Text: Press T, click to position, type, press Enter");
let bindings = default_action_bindings();
log::info!(
" - {}: Just drag",
action_display_label(Action::SelectPenTool)
);
log::info!(
" - {}: Hold Shift + drag",
action_display_label(Action::SelectLineTool)
);
log::info!(
" - {}: Hold Ctrl + drag",
action_display_label(Action::SelectRectTool)
);
log::info!(
" - {}: Hold Tab + drag",
action_display_label(Action::SelectEllipseTool)
);
log::info!(
" - {}: Hold Ctrl+Shift + drag",
action_display_label(Action::SelectArrowTool)
);
log::info!(
" - {}: {}, click to position, type, press Enter",
action_display_label(Action::EnterTextMode),
action_binding_label(&bindings, Action::EnterTextMode)
);
log::info!(" - Colors: {}", color_binding_labels(&bindings));
log::info!(
" - {} / {}: {} / {}",
action_display_label(Action::Undo),
action_display_label(Action::Redo),
action_binding_label(&bindings, Action::Undo),
action_binding_label(&bindings, Action::Redo)
);
log::info!(
" - {}: {}",
action_display_label(Action::ClearCanvas),
action_binding_label(&bindings, Action::ClearCanvas)
);
log::info!(
" - {}: {} or scroll down",
action_display_label(Action::IncreaseThickness),
action_binding_label(&bindings, Action::IncreaseThickness)
);
log::info!(
" - {}: {} or scroll up",
action_display_label(Action::DecreaseThickness),
action_binding_label(&bindings, Action::DecreaseThickness)
);
log::info!(
" - {}: {} (toggle frozen background)",
action_display_label(Action::ToggleFrozenMode),
action_binding_label(&bindings, Action::ToggleFrozenMode)
);
log::info!(
" - {} / {}: {} / {} (Ctrl+Alt + scroll)",
action_display_label(Action::ZoomIn),
action_display_label(Action::ZoomOut),
action_binding_label(&bindings, Action::ZoomIn),
action_binding_label(&bindings, Action::ZoomOut)
);
log::info!(
" - {}: {} • {}: {} • Pan view: middle drag/arrow keys",
action_display_label(Action::ResetZoom),
action_binding_label(&bindings, Action::ResetZoom),
action_display_label(Action::ToggleZoomLock),
action_binding_label(&bindings, Action::ToggleZoomLock)
);
log::info!(
" - Colors: R (red), G (green), B (blue), Y (yellow), O (orange), P (pink), W (white), K (black)"
" - {}: Right Click or {}",
action_display_label(Action::OpenContextMenu),
action_binding_label(&bindings, Action::OpenContextMenu)
);
log::info!(" - Undo / Redo: Ctrl+Z / Ctrl+Shift+Z");
log::info!(" - Clear all: E");
log::info!(" - Increase thickness: + or = or scroll down");
log::info!(" - Decrease thickness: - or _ or scroll up");
log::info!(" - Freeze screen: Ctrl+Shift+F (toggle frozen background)");
log::info!(
" - Zoom: Ctrl+Alt + scroll or +/- (Ctrl+Alt+0 reset, Ctrl+Alt+L lock, middle drag/arrow keys to pan)"
" - {}: {} • {}: {} • {}: {} • {}: {} • {}: {}",
action_display_label(Action::ToggleHelp),
action_binding_label(&bindings, Action::ToggleHelp),
action_display_label(Action::ToggleToolbar),
action_binding_label(&bindings, Action::ToggleToolbar),
action_display_label(Action::TogglePresenterMode),
action_binding_label(&bindings, Action::TogglePresenterMode),
action_display_label(Action::OpenConfigurator),
action_binding_label(&bindings, Action::OpenConfigurator),
action_display_label(Action::ToggleStatusBar),
action_binding_label(&bindings, Action::ToggleStatusBar)
);
log::info!(" - Context menu: Right Click or Shift+F10");
log::info!(
" - Help: F1/F10 • Toolbar: F2/F9 • Presenter: Ctrl+Shift+M • Configurator: F11 • Status bar: F4/F12"
" - {}: {}",
action_display_label(Action::Exit),
action_binding_label(&bindings, Action::Exit)
);
log::info!(" - Exit: Escape");
if freeze {
log::info!("Starting frozen mode (freeze-on-start requested)");
}
Expand Down
23 changes: 23 additions & 0 deletions src/backend/wayland/backend/state_init/input_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub(super) fn build_input_state(config: &Config) -> InputState {
);

let action_map = build_action_map(config);
let action_bindings = build_action_bindings(config);

let mut input_state = InputState::with_defaults(
config.drawing.default_color.to_color(),
Expand Down Expand Up @@ -41,6 +42,7 @@ pub(super) fn build_input_state(config: &Config) -> InputState {
config.history.custom_redo_steps,
config.presenter_mode.clone(),
);
input_state.set_action_bindings(action_bindings);

input_state.set_hit_test_tolerance(config.drawing.hit_test_tolerance);
input_state.set_hit_test_threshold(config.drawing.hit_test_linear_threshold);
Expand Down Expand Up @@ -92,3 +94,24 @@ fn build_action_map(config: &Config) -> HashMap<KeyBinding, Action> {
}
}
}

fn build_action_bindings(config: &Config) -> HashMap<Action, Vec<KeyBinding>> {
match config.keybindings.build_action_bindings() {
Ok(map) => map,
Err(err) => {
warn!(
"Invalid keybindings config: {}. Falling back to defaults.",
err
);
KeybindingsConfig::default()
.build_action_bindings()
.unwrap_or_else(|err| {
warn!(
"Failed to build default keybindings: {}. Continuing with no bindings.",
err
);
HashMap::new()
})
}
}
}
23 changes: 16 additions & 7 deletions src/backend/wayland/backend/tray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::fs;

use super::super::state::WaylandState;
use crate::config::Action;
use crate::tray_action::TrayAction;

pub(super) fn process_tray_action(state: &mut WaylandState) {
let action_path = crate::paths::tray_action_file();
Expand All @@ -27,25 +28,33 @@ pub(super) fn process_tray_action(state: &mut WaylandState) {
return;
}

match action_str.as_str() {
"toggle_freeze" => {
let action = match TrayAction::parse(action_str.as_str()) {
Some(action) => action,
None => {
warn!("Unknown tray action '{}'", action_str);
let _ = fs::remove_file(&action_path);
return;
}
};

match action {
TrayAction::ToggleFreeze => {
state.input_state.request_frozen_toggle();
state.input_state.needs_redraw = true;
}
"capture_full" => state.handle_capture_action(Action::CaptureFullScreen),
"capture_window" => state.handle_capture_action(Action::CaptureActiveWindow),
"capture_region" => {
TrayAction::CaptureFull => state.handle_capture_action(Action::CaptureFullScreen),
TrayAction::CaptureWindow => state.handle_capture_action(Action::CaptureActiveWindow),
TrayAction::CaptureRegion => {
// Honor clipboard preference for region captures
if state.config.capture.copy_to_clipboard {
state.handle_capture_action(Action::CaptureClipboardRegion);
} else {
state.handle_capture_action(Action::CaptureFileRegion);
}
}
"toggle_help" => {
TrayAction::ToggleHelp => {
state.input_state.toggle_help_overlay();
}
other => warn!("Unknown tray action '{}'", other),
}

let _ = fs::remove_file(&action_path);
Expand Down
10 changes: 2 additions & 8 deletions src/backend/wayland/state/render/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,15 @@ impl WaylandState {

// Render help overlay if toggled
if self.input_state.show_help {
let page_prev_label = self
.input_state
.action_binding_label(crate::config::Action::PagePrev);
let page_next_label = self
.input_state
.action_binding_label(crate::config::Action::PageNext);
let bindings = crate::ui::HelpOverlayBindings::from_input_state(&self.input_state);
let scroll_max = crate::ui::render_help_overlay(
ctx,
&self.config.ui.help_overlay_style,
width,
height,
self.frozen_enabled(),
self.input_state.help_overlay_page,
page_prev_label.as_str(),
page_next_label.as_str(),
&bindings,
self.input_state.help_overlay_search.as_str(),
self.config.ui.help_overlay_context_filter,
self.input_state.board_config.enabled,
Expand Down
2 changes: 1 addition & 1 deletion src/backend/wayland/state/toolbar/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::*;
impl WaylandState {
/// Returns a snapshot of the current input state for toolbar UI consumption.
pub(in crate::backend::wayland) fn toolbar_snapshot(&self) -> ToolbarSnapshot {
let hints = ToolbarBindingHints::from_keybindings(&self.config.keybindings);
let hints = ToolbarBindingHints::from_input_state(&self.input_state);
let show_drawer_hint =
!self.onboarding.state().drawer_hint_shown && !self.input_state.toolbar_drawer_open;
ToolbarSnapshot::from_input_with_options(&self.input_state, hints, show_drawer_hint)
Expand Down
Loading