From 7ae2688e313866b89abb1f816a61c298b1f35c72 Mon Sep 17 00:00:00 2001 From: anesthetice <118751106+anesthetice@users.noreply.github.com> Date: Sun, 8 Sep 2024 15:50:04 +0200 Subject: [PATCH 01/15] init + most basic proof of concept --- crates/rnote-compose/src/style/smooth/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/rnote-compose/src/style/smooth/mod.rs b/crates/rnote-compose/src/style/smooth/mod.rs index a1c21ebc86..64049635b0 100644 --- a/crates/rnote-compose/src/style/smooth/mod.rs +++ b/crates/rnote-compose/src/style/smooth/mod.rs @@ -1,8 +1,10 @@ // Modules mod smoothoptions; +use piet::StrokeStyle; // Re-exports pub use smoothoptions::SmoothOptions; +use tracing::info; // Imports use super::Composer; @@ -26,7 +28,13 @@ impl Composer for Line { if let Some(stroke_color) = options.stroke_color { let stroke_brush = cx.solid_brush(stroke_color.into()); - cx.stroke(line, &stroke_brush, options.stroke_width); + let stroke_style = StrokeStyle::new() + .dash_pattern(&[2.0, 3.0]) + .line_cap(piet::LineCap::Round) + .dash_offset(0.0); + + info!("{:#?}", stroke_style); + cx.stroke_styled(line, &stroke_brush, options.stroke_width, &stroke_style); } cx.restore().unwrap(); } From a62abad80188e86a2b86e53922ebfeaa8b3e42f3 Mon Sep 17 00:00:00 2001 From: anesthetice <118751106+anesthetice@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:19:01 +0200 Subject: [PATCH 02/15] basics (re-init of sorts) --- Cargo.lock | 7 +++++ Cargo.toml | 1 + crates/rnote-compose/Cargo.toml | 1 + crates/rnote-compose/src/meson.build | 1 + crates/rnote-compose/src/style/smooth/mod.rs | 1 + .../src/style/smooth/shapestyle.rs | 28 +++++++++++++++++++ .../src/style/smooth/smoothoptions.rs | 5 ++++ 7 files changed, 44 insertions(+) create mode 100644 crates/rnote-compose/src/style/smooth/shapestyle.rs diff --git a/Cargo.lock b/Cargo.lock index e621c14dda..fa66337b7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1117,6 +1117,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "fs_extra" version = "1.3.0" @@ -3343,6 +3349,7 @@ dependencies = [ "approx", "base64", "clap", + "fragile", "ink-stroke-modeler-rs", "kurbo 0.10.4", "nalgebra 0.33.0", diff --git a/Cargo.toml b/Cargo.toml index 8b1b67481b..0fbdbecbfa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ chrono = "0.4.38" clap = { version = "4.5", features = ["derive"] } dialoguer = "0.11.0" flate2 = "1.0" +fragile = "2.0" fs_extra = "1.3" futures = "0.3.30" geo = "0.28.0" diff --git a/crates/rnote-compose/Cargo.toml b/crates/rnote-compose/Cargo.toml index 9d45479681..9acd6536b1 100644 --- a/crates/rnote-compose/Cargo.toml +++ b/crates/rnote-compose/Cargo.toml @@ -13,6 +13,7 @@ anyhow = { workspace = true } approx = { workspace = true } base64 = { workspace = true } clap = { workspace = true, optional = true } +fragile = { workspace = true } ink-stroke-modeler-rs = { workspace = true } kurbo = { workspace = true } nalgebra = { workspace = true } diff --git a/crates/rnote-compose/src/meson.build b/crates/rnote-compose/src/meson.build index b5a6c0400e..a8cd4e4900 100644 --- a/crates/rnote-compose/src/meson.build +++ b/crates/rnote-compose/src/meson.build @@ -38,6 +38,7 @@ rnote_compose_sources = files( 'style/rough/mod.rs', 'style/rough/roughoptions.rs', 'style/smooth/mod.rs', + 'style/smooth/shapestyle.rs', 'style/smooth/smoothoptions.rs', 'style/textured/mod.rs', 'style/textured/textureddotsdistribution.rs', diff --git a/crates/rnote-compose/src/style/smooth/mod.rs b/crates/rnote-compose/src/style/smooth/mod.rs index 64049635b0..bbff07303f 100644 --- a/crates/rnote-compose/src/style/smooth/mod.rs +++ b/crates/rnote-compose/src/style/smooth/mod.rs @@ -1,4 +1,5 @@ // Modules +mod shapestyle; mod smoothoptions; use piet::StrokeStyle; diff --git a/crates/rnote-compose/src/style/smooth/shapestyle.rs b/crates/rnote-compose/src/style/smooth/shapestyle.rs new file mode 100644 index 0000000000..05055f424f --- /dev/null +++ b/crates/rnote-compose/src/style/smooth/shapestyle.rs @@ -0,0 +1,28 @@ +// Imports +use fragile::Fragile; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct ShapeStyle { + line_edge: LineEdge, + line_style: LineStyle, + #[serde(skip)] + inner: Fragile, +} + +impl ShapeStyle { + fn update_line_edge(&mut self) {} +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) enum LineEdge { + Straight, + Rounded, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) enum LineStyle { + Solid, + Dotted, + DashedEquidistant, +} diff --git a/crates/rnote-compose/src/style/smooth/smoothoptions.rs b/crates/rnote-compose/src/style/smooth/smoothoptions.rs index 8cfd651d4b..c23cdfb9c4 100644 --- a/crates/rnote-compose/src/style/smooth/smoothoptions.rs +++ b/crates/rnote-compose/src/style/smooth/smoothoptions.rs @@ -1,4 +1,5 @@ // Imports +use super::shapestyle::ShapeStyle; use crate::style::PressureCurve; use crate::Color; use serde::{Deserialize, Serialize}; @@ -19,6 +20,9 @@ pub struct SmoothOptions { /// Pressure curve. #[serde(rename = "pressure_curve")] pub pressure_curve: PressureCurve, + /// Shape style. + #[serde(rename = "shape_style")] + pub shape_style: Option, } impl Default for SmoothOptions { @@ -28,6 +32,7 @@ impl Default for SmoothOptions { stroke_color: Some(Color::BLACK), fill_color: None, pressure_curve: PressureCurve::default(), + shape_style: None, } } } From e6a4eb9e371dcb11be06c0dd72f92c90bec7d4b3 Mon Sep 17 00:00:00 2001 From: anesthetice <118751106+anesthetice@users.noreply.github.com> Date: Tue, 10 Sep 2024 18:33:50 +0200 Subject: [PATCH 03/15] basic logic, re-ordered shaper menu bar --- crates/rnote-compose/src/style/smooth/mod.rs | 9 +-- .../src/style/smooth/shapestyle.rs | 61 +++++++++++++++++-- .../src/style/smooth/smoothoptions.rs | 24 ++++++++ crates/rnote-ui/src/penssidebar/shaperpage.rs | 42 +++++++------ 4 files changed, 106 insertions(+), 30 deletions(-) diff --git a/crates/rnote-compose/src/style/smooth/mod.rs b/crates/rnote-compose/src/style/smooth/mod.rs index bbff07303f..db50dc2ee9 100644 --- a/crates/rnote-compose/src/style/smooth/mod.rs +++ b/crates/rnote-compose/src/style/smooth/mod.rs @@ -29,13 +29,8 @@ impl Composer for Line { if let Some(stroke_color) = options.stroke_color { let stroke_brush = cx.solid_brush(stroke_color.into()); - let stroke_style = StrokeStyle::new() - .dash_pattern(&[2.0, 3.0]) - .line_cap(piet::LineCap::Round) - .dash_offset(0.0); - - info!("{:#?}", stroke_style); - cx.stroke_styled(line, &stroke_brush, options.stroke_width, &stroke_style); + let stroke_style = options.get_stroke_style_from_shape_style().unwrap(); + cx.stroke_styled(line, &stroke_brush, options.stroke_width, stroke_style); } cx.restore().unwrap(); } diff --git a/crates/rnote-compose/src/style/smooth/shapestyle.rs b/crates/rnote-compose/src/style/smooth/shapestyle.rs index 05055f424f..e01fe9b35f 100644 --- a/crates/rnote-compose/src/style/smooth/shapestyle.rs +++ b/crates/rnote-compose/src/style/smooth/shapestyle.rs @@ -1,17 +1,60 @@ // Imports use fragile::Fragile; use serde::{Deserialize, Serialize}; +use std::ops::{AddAssign, MulAssign}; #[derive(Debug, Clone, Serialize, Deserialize)] pub(crate) struct ShapeStyle { - line_edge: LineEdge, - line_style: LineStyle, + pub line_edge: LineEdge, + pub line_style: LineStyle, #[serde(skip)] - inner: Fragile, + pub inner: Fragile, } impl ShapeStyle { - fn update_line_edge(&mut self) {} + pub(crate) fn update_line_edge(&mut self, line_edge: LineEdge, stroke_width: f64) { + self.line_edge = line_edge; + self.update_inner_strokedash(stroke_width); + } + pub(crate) fn update_line_style(&mut self, line_style: LineStyle, stroke_width: f64) { + self.line_style = line_style; + self.update_inner_strokedash(stroke_width); + } + pub(crate) fn update_inner_strokedash(&mut self, stroke_width: f64) { + let mut unscaled = self.line_style.as_unscaled_vector(); + match self.line_edge { + LineEdge::Straight => unscaled + .iter_mut() + .for_each(|e| e.mul_assign(stroke_width * 3.0)), + LineEdge::Rounded => unscaled.iter_mut().enumerate().for_each(|(idx, e)| { + e.mul_assign(stroke_width * 3.0); + if idx % 2 == 1 { + e.add_assign(stroke_width) + } + }), + } + let Ok(inner) = self.inner.try_get_mut() else { + tracing::warn!("Failed to acquire inner strokestyle, invalid thread access"); + return; + }; + inner.set_dash_pattern(unscaled) + } +} + +impl Default for ShapeStyle { + fn default() -> Self { + Self { + line_edge: LineEdge::Straight, + line_style: LineStyle::Solid, + inner: Fragile::new( + piet::StrokeStyle::new() + .line_join(piet::LineJoin::default()) + .line_cap(piet::LineCap::Butt) + .dash_pattern(&[]) + .dash_offset(0.0), + ), + } + } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -26,3 +69,13 @@ pub(crate) enum LineStyle { Dotted, DashedEquidistant, } + +impl LineStyle { + fn as_unscaled_vector(&self) -> Vec { + match self { + Self::Solid => Vec::new(), + Self::Dotted => vec![0.0, 1.0], + Self::DashedEquidistant => vec![1.0, 1.0], + } + } +} diff --git a/crates/rnote-compose/src/style/smooth/smoothoptions.rs b/crates/rnote-compose/src/style/smooth/smoothoptions.rs index c23cdfb9c4..cd267dfdc4 100644 --- a/crates/rnote-compose/src/style/smooth/smoothoptions.rs +++ b/crates/rnote-compose/src/style/smooth/smoothoptions.rs @@ -36,3 +36,27 @@ impl Default for SmoothOptions { } } } + +impl SmoothOptions { + fn default_shaper() -> Self { + Self { + stroke_width: 2.0, + stroke_color: Some(Color::BLACK), + fill_color: None, + pressure_curve: PressureCurve::default(), + shape_style: Some(ShapeStyle::default()), + } + } + pub(crate) fn get_stroke_style_from_shape_style(&self) -> anyhow::Result<&piet::StrokeStyle> { + self.shape_style + .as_ref() + .ok_or_else(|| anyhow::anyhow!("shape_style is None, expected Some(ShapeStyle)"))? + .inner + .try_get() + .map_err(|_| { + anyhow::anyhow!( + "Invalid thread access, cannot access piet::StrokeStyle (ShaperStyle.inner) as it was created on a seperate thread" + ) + }) + } +} diff --git a/crates/rnote-ui/src/penssidebar/shaperpage.rs b/crates/rnote-ui/src/penssidebar/shaperpage.rs index 3a152f1d40..62d91846ff 100644 --- a/crates/rnote-ui/src/penssidebar/shaperpage.rs +++ b/crates/rnote-ui/src/penssidebar/shaperpage.rs @@ -23,25 +23,18 @@ mod imp { #[template(resource = "/com/github/flxzt/rnote/ui/penssidebar/shaperpage.ui")] pub(crate) struct RnShaperPage { #[template_child] - pub(crate) shaperstyle_menubutton: TemplateChild, - #[template_child] - pub(crate) shaperstyle_listbox: TemplateChild, - #[template_child] - pub(crate) shaperstyle_smooth_row: TemplateChild, - #[template_child] - pub(crate) shaperstyle_rough_row: TemplateChild, - #[template_child] - pub(crate) shapeconfig_menubutton: TemplateChild, - #[template_child] - pub(crate) roughstyle_fillstyle_row: TemplateChild, - #[template_child] - pub(crate) roughstyle_hachure_angle_row: TemplateChild, + pub(crate) shapebuildertype_popover: TemplateChild, #[template_child] - pub(crate) stroke_width_picker: TemplateChild, + pub(crate) shapebuildertype_popover_close_button: TemplateChild