Skip to content

Commit 13dc621

Browse files
authored
Merge pull request #85 from devmobasa/editable-selection-props
Editable selection props
2 parents 907ea66 + bffc19b commit 13dc621

File tree

11 files changed

+1571
-76
lines changed

11 files changed

+1571
-76
lines changed

config.example.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,9 @@ toggle_status_bar = ["F12", "F4"]
574574
# Toggle fill for rectangle/ellipse
575575
toggle_fill = []
576576

577+
# Toggle selection properties panel
578+
toggle_selection_properties = ["Ctrl+Alt+P"]
579+
577580
# Toggle context menu (keyboard alternative to right-click)
578581
open_context_menu = ["Shift+F10", "Menu"]
579582

docs/CONFIG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,9 @@ toggle_click_highlight = ["Ctrl+Shift+H"]
562562
# Toggle highlight-only drawing tool
563563
toggle_highlight_tool = ["Ctrl+Alt+H"]
564564

565+
# Toggle selection properties panel
566+
toggle_selection_properties = ["Ctrl+Alt+P"]
567+
565568
# Toggle eraser behavior (brush vs stroke)
566569
toggle_eraser_mode = ["Ctrl+Shift+E"]
567570

src/backend/wayland/state/render.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,12 @@ impl WaylandState {
425425
crate::ui::render_preset_toast(&ctx, &self.input_state, width, height);
426426

427427
if !self.zoom.active {
428+
if self.input_state.is_properties_panel_open() {
429+
self.input_state
430+
.update_properties_panel_layout(&ctx, width, height);
431+
} else {
432+
self.input_state.clear_properties_panel_layout();
433+
}
428434
crate::ui::render_properties_panel(&ctx, &self.input_state, width, height);
429435

430436
if self.input_state.is_context_menu_open() {
@@ -438,6 +444,7 @@ impl WaylandState {
438444
crate::ui::render_context_menu(&ctx, &self.input_state, width, height);
439445
} else {
440446
self.input_state.clear_context_menu_layout();
447+
self.input_state.clear_properties_panel_layout();
441448
}
442449

443450
// Inline toolbars (xdg fallback) render directly into main surface when layer-shell is unavailable.

src/config/keybindings.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub enum Action {
7171
ToggleToolbar,
7272
ToggleHighlightTool,
7373
ToggleFill,
74+
ToggleSelectionProperties,
7475
OpenContextMenu,
7576

7677
// Configurator
@@ -367,6 +368,8 @@ pub struct KeybindingsConfig {
367368

368369
#[serde(default = "default_toggle_highlight_tool")]
369370
pub toggle_highlight_tool: Vec<String>,
371+
#[serde(default = "default_toggle_selection_properties")]
372+
pub toggle_selection_properties: Vec<String>,
370373
#[serde(default = "default_open_context_menu")]
371374
pub open_context_menu: Vec<String>,
372375

@@ -531,6 +534,7 @@ impl Default for KeybindingsConfig {
531534
toggle_toolbar: default_toggle_toolbar(),
532535
toggle_fill: default_toggle_fill(),
533536
toggle_highlight_tool: default_toggle_highlight_tool(),
537+
toggle_selection_properties: default_toggle_selection_properties(),
534538
open_context_menu: default_open_context_menu(),
535539
open_configurator: default_open_configurator(),
536540
set_color_red: default_set_color_red(),
@@ -819,6 +823,10 @@ impl KeybindingsConfig {
819823
insert_binding(binding_str, Action::ToggleHighlightTool)?;
820824
}
821825

826+
for binding_str in &self.toggle_selection_properties {
827+
insert_binding(binding_str, Action::ToggleSelectionProperties)?;
828+
}
829+
822830
for binding_str in &self.open_context_menu {
823831
insert_binding(binding_str, Action::OpenContextMenu)?;
824832
}
@@ -1165,6 +1173,10 @@ fn default_toggle_highlight_tool() -> Vec<String> {
11651173
vec!["Ctrl+Alt+H".to_string()]
11661174
}
11671175

1176+
fn default_toggle_selection_properties() -> Vec<String> {
1177+
vec!["Ctrl+Alt+P".to_string()]
1178+
}
1179+
11681180
fn default_open_context_menu() -> Vec<String> {
11691181
vec!["Shift+F10".to_string(), "Menu".to_string()]
11701182
}

src/input/state/actions.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::util;
55
use log::{info, warn};
66
const KEYBOARD_NUDGE_SMALL: i32 = 8;
77
const KEYBOARD_NUDGE_LARGE: i32 = 32;
8+
const PROPERTIES_PANEL_COARSE_STEP: i32 = 5;
89

910
use super::{
1011
DrawingState, InputState, MAX_STROKE_THICKNESS, MIN_STROKE_THICKNESS, SelectionAxis,
@@ -45,8 +46,31 @@ impl InputState {
4546
_ => {}
4647
}
4748

48-
if matches!(key, Key::Escape) && self.properties_panel().is_some() {
49-
self.close_properties_panel();
49+
if self.is_properties_panel_open() {
50+
let adjust_step = if self.modifiers.shift {
51+
PROPERTIES_PANEL_COARSE_STEP
52+
} else {
53+
1
54+
};
55+
let handled = match key {
56+
Key::Escape => {
57+
self.close_properties_panel();
58+
true
59+
}
60+
Key::Up => self.focus_previous_properties_entry(),
61+
Key::Down => self.focus_next_properties_entry(),
62+
Key::Home => self.focus_first_properties_entry(),
63+
Key::End => self.focus_last_properties_entry(),
64+
Key::Return | Key::Space => self.activate_properties_panel_entry(),
65+
Key::Left => self.adjust_properties_panel_entry(-adjust_step),
66+
Key::Right => self.adjust_properties_panel_entry(adjust_step),
67+
Key::Char('+') | Key::Char('=') => self.adjust_properties_panel_entry(adjust_step),
68+
Key::Char('-') | Key::Char('_') => self.adjust_properties_panel_entry(-adjust_step),
69+
_ => false,
70+
};
71+
if handled {
72+
return;
73+
}
5074
return;
5175
}
5276

@@ -341,7 +365,10 @@ impl InputState {
341365

342366
/// Handle an action triggered by a keybinding.
343367
pub(super) fn handle_action(&mut self, action: Action) {
344-
if !matches!(action, Action::OpenContextMenu) {
368+
if !matches!(
369+
action,
370+
Action::OpenContextMenu | Action::ToggleSelectionProperties
371+
) {
345372
self.close_properties_panel();
346373
}
347374

@@ -755,6 +782,17 @@ impl InputState {
755782
self.toggle_context_menu_via_keyboard();
756783
}
757784
}
785+
Action::ToggleSelectionProperties => {
786+
if matches!(self.state, DrawingState::Idle) {
787+
if self.properties_panel().is_some() {
788+
self.close_properties_panel();
789+
} else if self.show_properties_panel() {
790+
self.close_context_menu();
791+
} else {
792+
self.set_ui_toast(UiToastKind::Warning, "No selection to edit.");
793+
}
794+
}
795+
}
758796
Action::OpenConfigurator => {
759797
self.launch_configurator();
760798
}

src/input/state/core/base.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub const UI_TOAST_DURATION_MS: u64 = 5000;
99
use super::{
1010
index::SpatialGrid,
1111
menus::{ContextMenuLayout, ContextMenuState},
12-
properties::ShapePropertiesPanel,
12+
properties::{PropertiesPanelLayout, ShapePropertiesPanel},
1313
selection::SelectionState,
1414
};
1515
use crate::config::{Action, BoardConfig, KeyBinding, PRESET_SLOTS_MAX, ToolPresetConfig};
@@ -315,6 +315,12 @@ pub struct InputState {
315315
pub(super) pending_menu_hover_recalc: bool,
316316
/// Optional properties panel describing the current selection
317317
pub(super) shape_properties_panel: Option<ShapePropertiesPanel>,
318+
/// Cached layout details for the current properties panel
319+
pub properties_panel_layout: Option<PropertiesPanelLayout>,
320+
/// Recompute properties hover next time layout is available
321+
pub(super) pending_properties_hover_recalc: bool,
322+
/// Refresh properties panel entries on the next layout pass
323+
pub(super) properties_panel_needs_refresh: bool,
318324
/// Whether frozen mode is currently active
319325
pub(super) frozen_active: bool,
320326
/// Pending toggle request for the backend (handled in the Wayland loop)
@@ -489,6 +495,9 @@ impl InputState {
489495
last_pointer_position: (0, 0),
490496
pending_menu_hover_recalc: false,
491497
shape_properties_panel: None,
498+
properties_panel_layout: None,
499+
pending_properties_hover_recalc: false,
500+
properties_panel_needs_refresh: false,
492501
frozen_active: false,
493502
pending_frozen_toggle: false,
494503
zoom_active: false,

src/input/state/core/history.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ impl InputState {
1111
}
1212

1313
fn mark_dirty_from_action(&mut self, action: &UndoAction) {
14+
if self.is_properties_panel_open() {
15+
self.properties_panel_needs_refresh = true;
16+
}
1417
match action {
1518
UndoAction::Create { shapes } | UndoAction::Delete { shapes } => {
1619
for (_, shape) in shapes {

0 commit comments

Comments
 (0)