Skip to content

Commit f7de7b5

Browse files
committed
Tighten session tool state restore
1 parent fa69152 commit f7de7b5

File tree

4 files changed

+106
-14
lines changed

4 files changed

+106
-14
lines changed

src/input/tool.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use serde::{Deserialize, Serialize};
77
///
88
/// The active tool determines what shape is created when the user drags the mouse.
99
/// Tools are selected by holding modifier keys (Shift, Ctrl, Tab) while dragging.
10-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11+
#[serde(rename_all = "kebab-case")]
1112
pub enum Tool {
1213
/// Select/cursor tool - interact with UI without drawing
1314
Select,

src/session/snapshot.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use super::options::{CompressionMode, SessionOptions};
22
use crate::draw::frame::{MAX_COMPOUND_DEPTH, ShapeId};
33
use crate::draw::{Color, EraserKind, Frame};
4-
use crate::input::EraserMode;
54
use crate::input::{
6-
InputState,
5+
EraserMode, InputState, Tool,
76
board_mode::BoardMode,
87
state::{MAX_STROKE_THICKNESS, MIN_STROKE_THICKNESS},
98
};
@@ -56,6 +55,12 @@ pub struct ToolStateSnapshot {
5655
pub eraser_kind: EraserKind,
5756
#[serde(default = "default_eraser_mode_for_snapshot")]
5857
pub eraser_mode: EraserMode,
58+
#[serde(default)]
59+
pub marker_opacity: Option<f64>,
60+
#[serde(default)]
61+
pub fill_enabled: Option<bool>,
62+
#[serde(default)]
63+
pub tool_override: Option<Tool>,
5964
pub current_font_size: f64,
6065
pub text_background_enabled: bool,
6166
pub arrow_length: f64,
@@ -74,6 +79,9 @@ impl ToolStateSnapshot {
7479
eraser_size: input.eraser_size,
7580
eraser_kind: input.eraser_kind,
7681
eraser_mode: input.eraser_mode,
82+
marker_opacity: Some(input.marker_opacity),
83+
fill_enabled: Some(input.fill_enabled),
84+
tool_override: input.tool_override(),
7785
current_font_size: input.current_font_size,
7886
text_background_enabled: input.text_background_enabled,
7987
arrow_length: input.arrow_length,
@@ -575,30 +583,46 @@ pub fn apply_snapshot(input: &mut InputState, snapshot: SessionSnapshot, options
575583

576584
if options.restore_tool_state {
577585
if let Some(tool_state) = snapshot.tool_state {
586+
let marker_opacity = tool_state.marker_opacity.unwrap_or(input.marker_opacity);
587+
let fill_enabled = tool_state.fill_enabled.unwrap_or(input.fill_enabled);
578588
log::info!(
579-
"Restoring tool state: color={:?}, thickness={:.2}, eraser[size={:.2}, kind={:?}, mode={:?}], font_size={:.1}, text_bg={}, arrow[length={:.1}, angle={:.1}], status_bar={}, prev_color={:?}",
589+
"Restoring tool state: color={:?}, thickness={:.2}, eraser[size={:.2}, kind={:?}, mode={:?}], marker_opacity={:.2}, fill_enabled={}, tool_override={:?}, font_size={:.1}, text_bg={}, arrow[length={:.1}, angle={:.1}], status_bar={}, prev_color={:?}",
580590
tool_state.current_color,
581591
tool_state.current_thickness,
582592
tool_state.eraser_size,
583593
tool_state.eraser_kind,
584594
tool_state.eraser_mode,
595+
marker_opacity,
596+
fill_enabled,
597+
tool_state.tool_override,
585598
tool_state.current_font_size,
586599
tool_state.text_background_enabled,
587600
tool_state.arrow_length,
588601
tool_state.arrow_angle,
589602
tool_state.show_status_bar,
590603
tool_state.board_previous_color
591604
);
592-
input.current_color = tool_state.current_color;
593-
input.current_thickness = tool_state
594-
.current_thickness
595-
.clamp(MIN_STROKE_THICKNESS, MAX_STROKE_THICKNESS);
596-
input.eraser_size = tool_state
597-
.eraser_size
598-
.clamp(MIN_STROKE_THICKNESS, MAX_STROKE_THICKNESS);
605+
let _ = input.set_color(tool_state.current_color);
606+
let _ = input.set_thickness(
607+
tool_state
608+
.current_thickness
609+
.clamp(MIN_STROKE_THICKNESS, MAX_STROKE_THICKNESS),
610+
);
611+
let _ = input.set_eraser_size(
612+
tool_state
613+
.eraser_size
614+
.clamp(MIN_STROKE_THICKNESS, MAX_STROKE_THICKNESS),
615+
);
599616
input.eraser_kind = tool_state.eraser_kind;
600-
input.eraser_mode = tool_state.eraser_mode;
601-
input.current_font_size = tool_state.current_font_size.clamp(8.0, 72.0);
617+
let _ = input.set_eraser_mode(tool_state.eraser_mode);
618+
if let Some(opacity) = tool_state.marker_opacity {
619+
let _ = input.set_marker_opacity(opacity);
620+
}
621+
if let Some(fill_enabled) = tool_state.fill_enabled {
622+
let _ = input.set_fill_enabled(fill_enabled);
623+
}
624+
let _ = input.set_tool_override(tool_state.tool_override);
625+
let _ = input.set_font_size(tool_state.current_font_size.clamp(8.0, 72.0));
602626
input.text_background_enabled = tool_state.text_background_enabled;
603627
input.arrow_length = tool_state.arrow_length.clamp(5.0, 50.0);
604628
input.arrow_angle = tool_state.arrow_angle.clamp(15.0, 60.0);

src/session/storage.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,9 @@ mod tests {
419419
eraser_size: 12.0,
420420
eraser_kind: crate::draw::EraserKind::Circle,
421421
eraser_mode: crate::input::EraserMode::Brush,
422+
marker_opacity: Some(0.32),
423+
fill_enabled: Some(false),
424+
tool_override: None,
422425
current_font_size: 24.0,
423426
text_background_enabled: false,
424427
arrow_length: 20.0,

src/session/tests.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::config::{Action, BoardConfig, SessionConfig, SessionStorageMode};
33
use crate::draw::FontDescriptor;
44
use crate::draw::frame::{ShapeSnapshot, UndoAction};
55
use crate::draw::{Color, Shape};
6-
use crate::input::{ClickHighlightSettings, EraserMode, InputState, board_mode::BoardMode};
6+
use crate::input::{ClickHighlightSettings, EraserMode, InputState, Tool, board_mode::BoardMode};
77
use std::collections::HashMap;
88
use std::fs;
99
use std::path::PathBuf;
@@ -86,6 +86,67 @@ fn snapshot_includes_frames_and_tool_state() {
8686
assert!(snapshot.tool_state.is_some());
8787
}
8888

89+
#[test]
90+
fn apply_snapshot_restores_tool_state() {
91+
let mut options = SessionOptions::new(PathBuf::from("/tmp"), "display-tools");
92+
options.restore_tool_state = true;
93+
94+
let mut input = dummy_input_state();
95+
let desired_color = Color {
96+
r: 0.2,
97+
g: 0.4,
98+
b: 0.6,
99+
a: 1.0,
100+
};
101+
let _ = input.set_color(desired_color);
102+
let _ = input.set_thickness(18.0);
103+
let _ = input.set_eraser_size(22.0);
104+
let _ = input.set_eraser_mode(EraserMode::Stroke);
105+
let _ = input.set_marker_opacity(0.55);
106+
let _ = input.set_fill_enabled(true);
107+
let _ = input.set_font_size(48.0);
108+
let _ = input.set_tool_override(Some(Tool::Rect));
109+
input.text_background_enabled = true;
110+
input.arrow_length = 40.0;
111+
input.arrow_angle = 45.0;
112+
input.arrow_head_at_end = true;
113+
input.board_previous_color = Some(Color {
114+
r: 0.9,
115+
g: 0.2,
116+
b: 0.1,
117+
a: 1.0,
118+
});
119+
input.show_status_bar = false;
120+
121+
let snapshot = snapshot_from_input(&input, &options).expect("snapshot present");
122+
123+
let mut restored = dummy_input_state();
124+
apply_snapshot(&mut restored, snapshot, &options);
125+
126+
assert_eq!(restored.current_color, desired_color);
127+
assert_eq!(restored.current_thickness, 18.0);
128+
assert_eq!(restored.eraser_size, 22.0);
129+
assert_eq!(restored.eraser_mode, EraserMode::Stroke);
130+
assert_eq!(restored.marker_opacity, 0.55);
131+
assert!(restored.fill_enabled);
132+
assert_eq!(restored.current_font_size, 48.0);
133+
assert_eq!(restored.tool_override(), Some(Tool::Rect));
134+
assert!(restored.text_background_enabled);
135+
assert_eq!(restored.arrow_length, 40.0);
136+
assert_eq!(restored.arrow_angle, 45.0);
137+
assert!(restored.arrow_head_at_end);
138+
assert_eq!(
139+
restored.board_previous_color,
140+
Some(Color {
141+
r: 0.9,
142+
g: 0.2,
143+
b: 0.1,
144+
a: 1.0,
145+
})
146+
);
147+
assert!(!restored.show_status_bar);
148+
}
149+
89150
#[test]
90151
fn options_from_config_custom_storage() {
91152
let temp = tempfile::tempdir().unwrap();
@@ -538,6 +599,9 @@ fn save_snapshot_skips_when_payload_exceeds_max_file_size() {
538599
eraser_size: 12.0,
539600
eraser_kind: crate::draw::EraserKind::Circle,
540601
eraser_mode: EraserMode::Brush,
602+
marker_opacity: Some(0.32),
603+
fill_enabled: Some(false),
604+
tool_override: None,
541605
current_font_size: 24.0,
542606
text_background_enabled: false,
543607
arrow_length: 20.0,

0 commit comments

Comments
 (0)