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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ Drag modifier mappings are configurable in `config.toml` via `[drawing]` (`drag_

</details>

Arrow labels can auto-number when enabled in the arrow toolbar; reset with <kbd>Ctrl+Shift+R</kbd>. Step markers auto-increment and reset from the toolbar (or bind `reset_step_markers` in `config.toml`). Preset slots can be saved/cleared from the toolbar; edit names and advanced fields in `config.toml`.
Arrow labels can auto-number when enabled in the arrow toolbar; reset with <kbd>Ctrl+Shift+R</kbd>. Step markers auto-increment and reset from the toolbar (or bind `reset_step_markers` in `config.toml`). Preset slots can be saved/cleared from the toolbar; edit names and advanced fields in `config.toml`. Blur has no default keyboard shortcut; bind `select_blur_tool` in `config.toml` if you want direct keyboard access.

---

Expand Down
8 changes: 8 additions & 0 deletions assets/icons/blur.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ select_line_tool = []
select_rect_tool = []
select_ellipse_tool = []
select_arrow_tool = []
select_blur_tool = []
select_highlight_tool = []
toggle_highlight_tool = ["Ctrl+Alt+H"]

Expand Down
5 changes: 5 additions & 0 deletions configurator/src/models/fields/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub enum ToolOption {
Rect,
Ellipse,
Arrow,
Blur,
Marker,
StepMarker,
Highlight,
Expand All @@ -44,6 +45,7 @@ impl ToolOption {
Self::Rect,
Self::Ellipse,
Self::Arrow,
Self::Blur,
Self::Marker,
Self::StepMarker,
Self::Highlight,
Expand All @@ -59,6 +61,7 @@ impl ToolOption {
Self::Rect => "Rectangle",
Self::Ellipse => "Ellipse",
Self::Arrow => "Arrow",
Self::Blur => "Blur",
Self::Marker => "Marker",
Self::StepMarker => "Step",
Self::Highlight => "Highlight",
Expand All @@ -74,6 +77,7 @@ impl ToolOption {
Self::Rect => Tool::Rect,
Self::Ellipse => Tool::Ellipse,
Self::Arrow => Tool::Arrow,
Self::Blur => Tool::Blur,
Self::Marker => Tool::Marker,
Self::StepMarker => Tool::StepMarker,
Self::Highlight => Tool::Highlight,
Expand All @@ -89,6 +93,7 @@ impl ToolOption {
Tool::Rect => Self::Rect,
Tool::Ellipse => Self::Ellipse,
Tool::Arrow => Self::Arrow,
Tool::Blur => Self::Blur,
Tool::Marker => Self::Marker,
Tool::StepMarker => Self::StepMarker,
Tool::Highlight => Self::Highlight,
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/keybindings/field/config/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ impl KeybindingField {
Self::SelectRectTool => &config.tools.select_rect_tool,
Self::SelectEllipseTool => &config.tools.select_ellipse_tool,
Self::SelectArrowTool => &config.tools.select_arrow_tool,
Self::SelectBlurTool => &config.tools.select_blur_tool,
Self::SelectHighlightTool => &config.tools.select_highlight_tool,
Self::IncreaseFontSize => &config.tools.increase_font_size,
Self::DecreaseFontSize => &config.tools.decrease_font_size,
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/keybindings/field/config/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl KeybindingField {
Self::SelectRectTool => config.tools.select_rect_tool = value,
Self::SelectEllipseTool => config.tools.select_ellipse_tool = value,
Self::SelectArrowTool => config.tools.select_arrow_tool = value,
Self::SelectBlurTool => config.tools.select_blur_tool = value,
Self::SelectHighlightTool => config.tools.select_highlight_tool = value,
Self::IncreaseFontSize => config.tools.increase_font_size = value,
Self::DecreaseFontSize => config.tools.decrease_font_size = value,
Expand Down
2 changes: 2 additions & 0 deletions configurator/src/models/keybindings/field/labels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ impl KeybindingField {
Self::SelectRectTool => "Select rectangle tool",
Self::SelectEllipseTool => "Select ellipse tool",
Self::SelectArrowTool => "Select arrow tool",
Self::SelectBlurTool => "Select blur tool",
Self::SelectHighlightTool => "Select highlight tool",
Self::IncreaseFontSize => "Increase font size",
Self::DecreaseFontSize => "Decrease font size",
Expand Down Expand Up @@ -169,6 +170,7 @@ impl KeybindingField {
Self::SelectRectTool => "select_rect_tool",
Self::SelectEllipseTool => "select_ellipse_tool",
Self::SelectArrowTool => "select_arrow_tool",
Self::SelectBlurTool => "select_blur_tool",
Self::SelectHighlightTool => "select_highlight_tool",
Self::IncreaseFontSize => "increase_font_size",
Self::DecreaseFontSize => "decrease_font_size",
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/keybindings/field/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ impl KeybindingField {
Self::SelectRectTool,
Self::SelectEllipseTool,
Self::SelectArrowTool,
Self::SelectBlurTool,
Self::SelectHighlightTool,
Self::IncreaseFontSize,
Self::DecreaseFontSize,
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/keybindings/field/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub enum KeybindingField {
SelectRectTool,
SelectEllipseTool,
SelectArrowTool,
SelectBlurTool,
SelectHighlightTool,
IncreaseFontSize,
DecreaseFontSize,
Expand Down
1 change: 1 addition & 0 deletions configurator/src/models/keybindings/field/tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl KeybindingField {
| Self::SelectRectTool
| Self::SelectEllipseTool
| Self::SelectArrowTool
| Self::SelectBlurTool
| Self::SelectHighlightTool
| Self::ToggleHighlightTool
| Self::ResetArrowLabels
Expand Down
1 change: 1 addition & 0 deletions docs/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ select_line_tool = []
select_rect_tool = []
select_ellipse_tool = []
select_arrow_tool = []
select_blur_tool = []
select_highlight_tool = []
toggle_highlight_tool = ["Ctrl+Alt+H"]

Expand Down
2 changes: 1 addition & 1 deletion src/backend/wayland/frozen/capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ impl FrozenState {

capture.frame.destroy();

self.image = Some(FrozenImage {
self.set_image(FrozenImage {
width: capture.width,
height: capture.height,
stride: (capture.width * 4) as i32,
Expand Down
2 changes: 1 addition & 1 deletion src/backend/wayland/frozen/portal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ impl FrozenState {
portal_output_matches(target_output, self.active_output_id);

if output_matches {
self.image = Some(image);
self.set_image(image);
input_state.set_frozen_active(true);
input_state.dirty_tracker.mark_full();
input_state.needs_redraw = true;
Expand Down
27 changes: 25 additions & 2 deletions src/backend/wayland/frozen/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct FrozenState {
pub(super) active_geometry: Option<OutputGeometry>,
pub(super) capture: Option<CaptureSession>,
pub(super) image: Option<FrozenImage>,
image_generation: u64,
pub(super) portal_rx: Option<PortalCaptureRx>,
pub(super) portal_in_progress: bool,
pub(super) portal_target_output_id: Option<u32>,
Expand All @@ -35,6 +36,7 @@ impl FrozenState {
active_geometry: None,
capture: None,
image: None,
image_generation: 0,
portal_rx: None,
portal_in_progress: false,
portal_target_output_id: None,
Expand Down Expand Up @@ -66,6 +68,15 @@ impl FrozenState {
self.image.as_ref()
}

pub fn image_generation(&self) -> u64 {
self.image_generation
}

pub fn set_image(&mut self, image: FrozenImage) {
self.image = Some(image);
self.bump_image_generation();
}

pub fn is_in_progress(&self) -> bool {
self.capture.is_some() || self.portal_in_progress || self.preflight_pending
}
Expand Down Expand Up @@ -97,14 +108,14 @@ impl FrozenState {
&& (img.width != phys_width || img.height != phys_height)
{
info!("Surface resized; clearing frozen image");
self.image = None;
self.clear_image();
input_state.set_frozen_active(false);
}
}

/// Toggle unfreeze: drop the image and mark redraw.
pub fn unfreeze(&mut self, input_state: &mut InputState) {
self.image = None;
self.clear_image();
input_state.set_frozen_active(false);
input_state.dirty_tracker.mark_full();
input_state.needs_redraw = true;
Expand All @@ -119,4 +130,16 @@ impl FrozenState {
input_state.set_frozen_active(false);
input_state.needs_redraw = true;
}

fn clear_image(&mut self) -> bool {
let had_image = self.image.take().is_some();
if had_image {
self.bump_image_generation();
}
had_image
}

fn bump_image_generation(&mut self) {
self.image_generation = self.image_generation.wrapping_add(1).max(1);
}
}
35 changes: 32 additions & 3 deletions src/backend/wayland/state/render/canvas/background.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@ use super::super::super::*;
use crate::draw::Color;

pub(super) struct CanvasEraserContext {
surface: Option<cairo::ImageSurface>,
pattern: Option<cairo::SurfacePattern>,
backdrop_cache_key: Option<u64>,
bg_color: Option<Color>,
logical_to_image_scale_x: f64,
logical_to_image_scale_y: f64,
}

impl CanvasEraserContext {
pub(super) fn replay_context(&self) -> crate::draw::EraserReplayContext<'_> {
crate::draw::EraserReplayContext {
pattern: self.pattern.as_ref().map(|p| p as &cairo::Pattern),
surface: self.surface.as_ref(),
backdrop_cache_key: self.backdrop_cache_key,
bg_color: self.bg_color,
logical_to_image_scale_x: self.logical_to_image_scale_x,
logical_to_image_scale_y: self.logical_to_image_scale_y,
}
}
}
Expand All @@ -23,26 +31,39 @@ impl WaylandState {
phys_width: u32,
phys_height: u32,
) -> Result<CanvasEraserContext> {
let mut eraser_surface: Option<cairo::ImageSurface> = None;
let mut eraser_pattern: Option<cairo::SurfacePattern> = None;
let mut backdrop_cache_key: Option<u64> = None;
let mut eraser_bg_color: Option<Color> = None;
let mut logical_to_image_scale_x = 1.0;
let mut logical_to_image_scale_y = 1.0;

let allow_background_image =
!self.zoom.is_engaged() || self.input_state.board_is_transparent();
let zoom_render_image = if self.zoom.active && allow_background_image {
self.zoom.image().or_else(|| self.frozen.image())
self.zoom
.image()
.map(|image| (image, (self.zoom.image_generation() << 1) | 1))
.or_else(|| {
self.frozen
.image()
.map(|image| (image, self.frozen.image_generation() << 1))
})
} else {
None
};
let zoom_render_active = self.zoom.active && zoom_render_image.is_some();
let background_image = if zoom_render_active {
zoom_render_image
} else if allow_background_image {
self.frozen.image()
self.frozen
.image()
.map(|image| (image, self.frozen.image_generation() << 1))
} else {
None
};

if let Some(image) = background_image {
if let Some((image, cache_key)) = background_image {
// SAFETY: we create a Cairo surface borrowing our owned buffer; it is dropped
// before commit, and we hold the buffer alive via `image.data`.
let surface = unsafe {
Expand All @@ -66,6 +87,8 @@ impl WaylandState {
} else {
1.0
};
logical_to_image_scale_x = (scale as f64) / scale_x.max(f64::MIN_POSITIVE);
logical_to_image_scale_y = (scale as f64) / scale_y.max(f64::MIN_POSITIVE);
let _ = ctx.save();
if zoom_render_active {
let scale_x_safe = scale_x.max(f64::MIN_POSITIVE);
Expand All @@ -92,7 +115,9 @@ impl WaylandState {
let scale_y_inv = 1.0 / (scale as f64 * scale_y.max(f64::MIN_POSITIVE));
matrix.scale(scale_x_inv, scale_y_inv);
pattern.set_matrix(matrix);
eraser_surface = Some(surface);
eraser_pattern = Some(pattern);
backdrop_cache_key = Some(cache_key);
} else {
match self.input_state.boards.active_background() {
crate::input::BoardBackground::Solid(color) => {
Expand All @@ -105,8 +130,12 @@ impl WaylandState {
}

Ok(CanvasEraserContext {
surface: eraser_surface,
pattern: eraser_pattern,
backdrop_cache_key,
bg_color: eraser_bg_color,
logical_to_image_scale_x,
logical_to_image_scale_y,
})
}
}
59 changes: 56 additions & 3 deletions src/backend/wayland/state/render/canvas/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ impl WaylandState {
crate::draw::Shape::EraserStroke { points, brush } => {
crate::draw::render_eraser_stroke(ctx, points, brush, &replay_ctx);
}
crate::draw::Shape::BlurRect {
x,
y,
w,
h,
strength,
} => {
crate::draw::render_blur_rect(
ctx,
crate::draw::BlurRectParams {
x: *x,
y: *y,
w: *w,
h: *h,
strength: *strength,
cacheable: true,
},
&replay_ctx,
);
}
other => {
crate::draw::render_shape(ctx, other);
}
Expand Down Expand Up @@ -144,9 +164,42 @@ impl WaylandState {

self.render_eraser_hover_halos(ctx, mx, my);

// Render provisional shape if actively drawing
// Use optimized method that avoids cloning for freehand
if self.input_state.render_provisional_shape(ctx, mx, my) {
// Render provisional shape if actively drawing.
let rendered_provisional = if let crate::input::DrawingState::Drawing {
tool: crate::input::Tool::Blur,
start_x,
start_y,
..
} = &self.input_state.state
{
let (x, w) = if mx >= *start_x {
(*start_x, mx - start_x)
} else {
(mx, start_x - mx)
};
let (y, h) = if my >= *start_y {
(*start_y, my - start_y)
} else {
(my, start_y - my)
};
crate::draw::render_blur_rect(
ctx,
crate::draw::BlurRectParams {
x,
y,
w,
h,
strength: self.input_state.current_thickness,
cacheable: false,
},
&replay_ctx,
);
true
} else {
// Use optimized method that avoids cloning for freehand
self.input_state.render_provisional_shape(ctx, mx, my)
};
if rendered_provisional {
debug!("Rendered provisional shape");
}

Expand Down
1 change: 1 addition & 0 deletions src/backend/wayland/state/render/tool_preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub(super) fn draw_tool_preview(
Tool::Rect => toolbar_icons::draw_icon_rect(ctx, icon_x, icon_y, icon_size),
Tool::Ellipse => toolbar_icons::draw_icon_circle(ctx, icon_x, icon_y, icon_size),
Tool::Arrow => toolbar_icons::draw_icon_arrow(ctx, icon_x, icon_y, icon_size),
Tool::Blur => toolbar_icons::draw_icon_blur(ctx, icon_x, icon_y, icon_size),
Tool::Marker => toolbar_icons::draw_icon_marker(ctx, icon_x, icon_y, icon_size),
Tool::StepMarker => toolbar_icons::draw_icon_step_marker(ctx, icon_x, icon_y, icon_size),
Tool::Highlight => toolbar_icons::draw_icon_highlight(ctx, icon_x, icon_y, icon_size),
Expand Down
Loading
Loading