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: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,12 @@ The v0.9.23+ prebuilt `wayscriber` packages require glibc 2.39 and GTK 4.12. See
- Freehand pen, highlighter, eraser (circle/rect)
- Shape Pen: draw naturally and confident strokes preview and become editable lines, circles, ovals, rectangles, or triangles; other strokes remain freehand, and one undo turns a recognized shape back into its ink; a brief chip such as "Circle · Ctrl+Z keeps ink" names each recognized shape (`[drawing] shape_recognition_feedback`). Press `S`, click it next to Pen on the toolbar (in the Shapes picker in simple mode), or choose **Shape Pen Tool** in the command palette. Adjust recognition in the style pill's **Pen feel** panel (or its **Shapes** meter or **Detect** stepper, per `[ui.toolbar] stroke_controls`), `[drawing] shape_recognition_sensitivity` (0-4), or the configurator's Drawing page; the level is remembered with the session.
- Pen smoothing: finished pen and marker strokes are cleaned up on release, so the live line never lags the cursor (`[drawing] pen_smoothing`, 0-6, or the style pill's **Pen feel** chip, which opens a panel with a smoothing meter and a live preview of the result; `[ui.toolbar] stroke_controls` swaps it for inline **Smooth** meters or steppers); tablet pressure values are preserved, and the level is remembered with the session
- Shapes: lines, rectangles, ellipses, polygons (with fill toggle)
- Shapes: lines, rectangles, ellipses, polygons (with fill toggle; the properties panel gives a fill its own color)
- Arrows in four styles - standard, pointy, curved (drag its handle to route around what is in the way), and double-ended - with optional auto-numbered labels; step markers for walkthroughs
- Blur tool with four styles: soften, pixelate, secure (flattens the region to one color), and black out
- Spotlight tool: dims everything except the regions you draw, with optional 1×–4× magnification
- Multiline text and sticky notes with smoothing; optional text halos take their contrast from the background the label sits on, so a label stays readable over a board, a filled shape, or a frozen screen (disable with `[drawing] text_halo_enabled = false`; a live transparent board has no pixels to sample and falls back to the text color)
- Selection: <kbd>Alt</kbd>-drag, <kbd>V</kbd> tool, properties panel (<kbd>Ctrl+Alt+P</kbd> or right-click → **Properties**): swatches from your quick-color palette plus **+** for the full color picker, −/+ steppers, on/off switches, the arrow head's Start/End, drawn arrow styles, and a lock toggle; scroll over a row to step it, and hover the title for the shape's ID and creation time
- Selection: <kbd>Alt</kbd>-drag, <kbd>V</kbd> tool, properties panel (<kbd>Ctrl+Alt+P</kbd> or right-click → **Properties**): swatches from your quick-color palette plus **+** for the full color picker (an opaque swatch changes the hue and keeps each shape's opacity), thickness and opacity sliders (one drag is one undo step), a fill row for rectangles, ellipses, and polygons whose first swatch is "no fill" and whose others fill with their own color, independent of the border, −/+ steppers, on/off switches, the arrow head's Start/End, drawn arrow styles, a lock toggle, and buttons to send the selection to the back, back one step, forward one step, or to the front, and to duplicate or delete it; a preset row applies a tool preset's style to the selection (keeping the current tool), and **Save** then a slot stores the selection's style as that preset; scroll over a row to step it, and hover the title for the shape's ID and creation time
- Duplicate (<kbd>Ctrl+D</kbd>), delete (<kbd>Delete</kbd>), undo/redo
- Color picker, screen eyedropper with a magnified pixel loupe, palettes, size via hotkeys or scroll
- Text font cycling with <kbd>Shift+T</kbd> over a configurable list (`[drawing] font_cycle`); with text selected it restyles that text
Expand Down
3 changes: 3 additions & 0 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,9 @@ size = 3.0
# Optional overrides
marker_opacity = 0.32
fill_enabled = false
# Optional fill color, when a fill differs from `color` (written when a
# preset is saved from a shape filled with its own color)
# fill_color = "blue"
font_size = 32.0
text_background_enabled = false
arrow_length = 20.0
Expand Down
8 changes: 7 additions & 1 deletion configurator/src/models/config/presets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::super::fields::{
use super::super::util::format_float;
use super::parse::{parse_optional_f64, parse_required_f64};
use wayscriber::config::{
Config, MouseDragToolsConfig, PRESET_SLOTS_MAX, PRESET_SLOTS_MIN, PresetSlotsConfig,
ColorSpec, Config, MouseDragToolsConfig, PRESET_SLOTS_MAX, PRESET_SLOTS_MIN, PresetSlotsConfig,
PresetToolStatesConfig, ToolPresetConfig,
};
use wayscriber::domain::Tool;
Expand All @@ -22,6 +22,9 @@ pub struct PresetSlotDraft {
pub eraser_mode: PresetEraserModeOption,
pub marker_opacity: String,
pub fill_enabled: OverrideOption,
/// Carried through unedited: set when a preset is saved from a shape
/// filled with its own color, so editing the slot here keeps it.
pub fill_color: Option<ColorSpec>,
pub font_size: String,
pub text_background_enabled: OverrideOption,
pub arrow_length: String,
Expand All @@ -46,6 +49,7 @@ impl PresetSlotDraft {
eraser_mode: PresetEraserModeOption::from_option(preset.eraser_mode),
marker_opacity: preset.marker_opacity.map(format_float).unwrap_or_default(),
fill_enabled: OverrideOption::from_option(preset.fill_enabled),
fill_color: preset.fill_color.clone(),
font_size: preset.font_size.map(format_float).unwrap_or_default(),
text_background_enabled: OverrideOption::from_option(
preset.text_background_enabled,
Expand Down Expand Up @@ -77,6 +81,7 @@ impl PresetSlotDraft {
eraser_mode: PresetEraserModeOption::Default,
marker_opacity: String::new(),
fill_enabled: OverrideOption::Default,
fill_color: None,
font_size: String::new(),
text_background_enabled: OverrideOption::Default,
arrow_length: String::new(),
Expand Down Expand Up @@ -174,6 +179,7 @@ impl PresetSlotDraft {
eraser_mode: self.eraser_mode.to_option(),
marker_opacity,
fill_enabled: self.fill_enabled.to_option(),
fill_color: self.fill_color.clone(),
font_size,
text_background_enabled: self.text_background_enabled.to_option(),
arrow_length,
Expand Down
3 changes: 3 additions & 0 deletions configurator/src/models/config/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,7 @@ fn config_draft_round_trips_presets_and_history() {
eraser_mode: None,
marker_opacity: Some(0.5),
fill_enabled: Some(true),
fill_color: Some(ColorSpec::Name("green".to_string())),
font_size: Some(14.0),
text_background_enabled: Some(false),
arrow_length: Some(20.0),
Expand Down Expand Up @@ -1467,6 +1468,7 @@ fn preset_tool_change_loads_selected_tool_profile_values() {
eraser_mode: None,
marker_opacity: None,
fill_enabled: None,
fill_color: None,
font_size: None,
text_background_enabled: None,
arrow_length: None,
Expand Down Expand Up @@ -1525,6 +1527,7 @@ fn preset_visible_edits_update_selected_tool_profile_only() {
eraser_mode: None,
marker_opacity: None,
fill_enabled: None,
fill_color: None,
font_size: None,
text_background_enabled: None,
arrow_length: None,
Expand Down
5 changes: 4 additions & 1 deletion docs/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -762,12 +762,15 @@ size = 28.0
```

**Required fields:** `tool`, `color`, `size`
**Optional fields:** `tool_settings`, `eraser_kind`, `eraser_mode`, `marker_opacity`, `fill_enabled`, `font_size`, `text_background_enabled`, `arrow_length`, `arrow_angle`, `arrow_head_at_end`, `polygon_sides`, `show_status_bar`, `drag_tools`
**Optional fields:** `tool_settings`, `eraser_kind`, `eraser_mode`, `marker_opacity`, `fill_enabled`, `fill_color`, `font_size`, `text_background_enabled`, `arrow_length`, `arrow_angle`, `arrow_head_at_end`, `polygon_sides`, `show_status_bar`, `drag_tools`

When `tool_settings` is present, applying the preset restores the full drawing profile for all
tools, including StepMarker size and Eraser size, then activates `tool`. Legacy presets without
`tool_settings` keep the old behavior and apply only `color`/`size` to the selected `tool`.
The top-level `color` and `size` are retained for compatibility, readability, and toolbar previews.
`fill_color` is written when a preset is saved from the properties panel off a rectangle, ellipse,
or polygon filled with its own color; applying the preset to selected closed shapes restores that
fill. Without it, a preset's fill takes its border color.

### `[history]` - Undo/Redo Playback

Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/clipboard/transfer/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ fn rect() -> Shape {
w: 10,
h: 10,
fill: false,
fill_color: None,
color: crate::draw::BLACK,
thick: 1.0,
}
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/config_edits/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ fn preset(name: &str) -> Box<crate::config::ToolPresetConfig> {
eraser_mode: None,
marker_opacity: None,
fill_enabled: None,
fill_color: None,
font_size: None,
text_background_enabled: None,
arrow_length: None,
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/session/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,7 @@ fn runtime_open_current_save_failure_preserves_spatial_index_for_active_selectio
w: 10,
h: 10,
fill: false,
fill_color: None,
color: input.style.current_color,
thick: input.style.current_thickness,
});
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/state/clipboard/session_paste/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ fn paste_preflight_skips_stale_target_page_generation() {
w: 3,
h: 4,
fill: false,
fill_color: None,
color: Color {
r: 1.0,
g: 0.0,
Expand Down
5 changes: 4 additions & 1 deletion src/backend/wayland/state/onboarding/first_run_card.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ impl WaylandState {
FirstRunStep::QuickAccess => OnboardingCard {
eyebrow,
title: "Quick access at cursor".to_string(),
body: "Open quick actions near the pointer.".to_string(),
// Alt+click is a fixed mouse gesture, not a binding.
body: "Open quick actions near the pointer. Alt+click a shape to select it \
without switching tools."
.to_string(),
items: self.quick_access_checklist_items(state),
buttons: vec![skip_tour_button()],
footer: String::new(),
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/state/pdf_export/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ fn fit_content_snapshot_uses_content_bounds() {
w: 100,
h: 50,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,7 @@ fn render_source_jobs_paint_annotations_before_applying_key_cuts_on_the_worker()
w: 8,
h: 8,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/state/region_capture/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ mod tests {
w: 3,
h: 2,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/state/region_capture/tests/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ fn the_render_job_composes_drawings_when_asked_and_stays_raw_otherwise() {
w: 3,
h: 2,
fill: true,
fill_color: None,
color: crate::draw::RED,
thick: 1.0,
});
Expand Down
2 changes: 2 additions & 0 deletions src/backend/wayland/state/render/canvas/resource_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ fn baked_and_direct_passes_match_fresh_owners_across_reuse_and_invalidation() {
},
thick: 2.0,
fill: true,
fill_color: None,
});
}
assert!(layer.ensure(&measurer, &mut caches, &shapes, request));
Expand Down Expand Up @@ -327,6 +328,7 @@ fn each_scene_key_rebakes_without_shape_identity_changes() {
},
thick: 2.0,
fill: true,
fill_color: None,
});
}
assert!(layer.ensure(&measurer, &mut caches, &scene, changed));
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/state/render/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ impl WaylandState {
self.input_state.ui_visibility.show_tool_preview
&& self.has_cursor_focus()
&& !self.cursor_blocked_by_toolbar()
&& !self.input_state.canvas_press_dismisses_popup()
&& matches!(
self.input_state.state,
DrawingState::Idle | DrawingState::PendingTextClick { .. }
Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/state/toolbar/events/presets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ mod tests {
eraser_mode: None,
marker_opacity: None,
fill_enabled: None,
fill_color: None,
font_size: None,
text_background_enabled: None,
arrow_length: None,
Expand Down
7 changes: 7 additions & 0 deletions src/canvas_export/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ mod tests {
w: 8,
h: 8,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -115,6 +116,7 @@ mod tests {
w: 4,
h: 4,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -189,6 +191,7 @@ mod tests {
w: 2,
h: 2,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -351,6 +354,7 @@ mod tests {
w: 2,
h: 4,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -468,6 +472,7 @@ mod tests {
w: 6,
h: 6,
fill: true,
fill_color: None,
color: BLACK,
thick: 1.0,
});
Expand Down Expand Up @@ -506,6 +511,7 @@ mod tests {
w: 12,
h: 12,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -541,6 +547,7 @@ mod tests {
w: 12,
h: 12,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down
6 changes: 6 additions & 0 deletions src/canvas_export/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ mod tests {
w: 1,
h: 1,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand All @@ -364,6 +365,7 @@ mod tests {
w: 10,
h: 10,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -392,6 +394,7 @@ mod tests {
w: 1,
h: 1,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -550,6 +553,7 @@ mod tests {
w: 4,
h: 4,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -654,6 +658,7 @@ mod tests {
w: 1,
h: 1,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -690,6 +695,7 @@ mod tests {
w: 8,
h: 1,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down
2 changes: 2 additions & 0 deletions src/canvas_export/tests/board_grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ fn board_grid_png_erasers_restore_pattern_and_snapshot_is_independent() {
w: 20,
h: 20,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down Expand Up @@ -142,6 +143,7 @@ fn board_grid_pdf_stays_vector_without_erasers_and_leaves_margins_plain() {
w: 8,
h: 8,
fill: true,
fill_color: None,
color: RED,
thick: 1.0,
});
Expand Down
1 change: 1 addition & 0 deletions src/config/tests/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ fn validate_clamps_preset_fields() {
eraser_mode: None,
marker_opacity: Some(1.2),
fill_enabled: None,
fill_color: None,
font_size: Some(2.0),
text_background_enabled: None,
arrow_length: Some(100.0),
Expand Down
1 change: 1 addition & 0 deletions src/config/tests/write_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ fn preset(name: &str) -> ToolPresetConfig {
eraser_mode: None,
marker_opacity: None,
fill_enabled: None,
fill_color: None,
font_size: None,
text_background_enabled: None,
arrow_length: None,
Expand Down
28 changes: 28 additions & 0 deletions src/config/tests/write_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ fn preset(name: &str) -> ToolPresetConfig {
eraser_mode: None,
marker_opacity: None,
fill_enabled: None,
fill_color: None,
font_size: None,
text_background_enabled: None,
arrow_length: None,
Expand Down Expand Up @@ -834,3 +835,30 @@ fn an_edit_that_waits_for_the_lock_reapplies_onto_the_retargeted_file() {
"and the file the path used to name keeps every byte"
);
}

/// A preset saved from a shape filled with its own color keeps that fill
/// through the file, and one without leaves no trace of the field.
#[test]
fn a_preset_keeps_its_fill_color_through_the_config_file() {
let temp = crate::test_temp::tempdir().expect("tempdir");
let path = temp.path().join("config.toml");
fs::write(&path, ORIGINAL).expect("seed config");
let mut filled = preset("Filled");
filled.tool = crate::input::Tool::Rect;
filled.fill_enabled = Some(true);
filled.fill_color = Some(ColorSpec::from(Color {
r: 0.0,
g: 0.8,
b: 0.4,
a: 1.0,
}));

persist_preset_slot_at(&path, 1, Some(&filled)).expect("write filled preset");
persist_preset_slot_at(&path, 2, Some(&preset("Plain"))).expect("write plain preset");

let written = fs::read_to_string(&path).expect("readable");
assert_eq!(written.matches("fill_color").count(), 1, "{written}");
let loaded: super::super::Config = toml::from_str(&written).expect("parse");
assert_eq!(loaded.presets.get_slot(1), Some(&filled));
assert_eq!(loaded.presets.get_slot(2), Some(&preset("Plain")));
}
Loading
Loading