From 871bc421ac544311c1a43a0b8f504d8c479f0883 Mon Sep 17 00:00:00 2001 From: Doublonmousse <115779707+Doublonmousse@users.noreply.github.com> Date: Fri, 23 Feb 2024 10:23:26 +0100 Subject: [PATCH 1/8] ghost stroke width and a outside nodes for selections --- crates/rnote-compose/src/style/mod.rs | 21 ++++++++ .../src/style/rough/roughoptions.rs | 4 ++ .../src/style/smooth/smoothoptions.rs | 5 ++ .../src/style/textured/texturedoptions.rs | 4 ++ crates/rnote-engine/src/engine/mod.rs | 4 +- crates/rnote-engine/src/pens/selector/mod.rs | 28 ++++++++--- .../src/pens/selector/penevents.rs | 49 +++++++++++++++++-- crates/rnote-engine/src/store/stroke_comp.rs | 20 +++++++- .../rnote-engine/src/strokes/brushstroke.rs | 7 ++- .../rnote-engine/src/strokes/shapestroke.rs | 9 +++- crates/rnote-engine/src/strokes/stroke.rs | 22 +++++++++ crates/rnote-ui/src/appwindow/actions.rs | 2 + 12 files changed, 161 insertions(+), 14 deletions(-) diff --git a/crates/rnote-compose/src/style/mod.rs b/crates/rnote-compose/src/style/mod.rs index 16c490c9f2..568a8c66cd 100644 --- a/crates/rnote-compose/src/style/mod.rs +++ b/crates/rnote-compose/src/style/mod.rs @@ -55,8 +55,18 @@ impl Style { } } + /// The ghost stroke width. Available on all styles. + pub fn stroke_width_ghost(&self) -> f64 { + match self { + Style::Smooth(options) => options.stroke_width_ghost, + Style::Rough(options) => options.stroke_width_ghost, + Style::Textured(options) => options.stroke_width_ghost, + } + } + /// Set the stroke width. Available on all styles. pub fn set_stroke_width(&mut self, stroke_width: f64) { + // problem : options.stroke_width of style elements as these are set on resize, not w.r.t the start position match self { Style::Smooth(options) => options.stroke_width = stroke_width, Style::Rough(options) => options.stroke_width = stroke_width, @@ -64,6 +74,17 @@ impl Style { } } + /// Copy the stroke width onto the ghost stroke width. Available on all styles + pub fn copy_ghost_stroke_width(&mut self) { + tracing::debug!("Copy stroke width back to the ghost value"); + match self { + Style::Smooth(options) => options.stroke_width_ghost = options.stroke_width, + Style::Rough(options) => options.stroke_width_ghost = options.stroke_width, + Style::Textured(options) => options.stroke_width_ghost = options.stroke_width, + } + } + + /// The margins for bounds which contain the shape. pub fn bounds_margin(&self) -> f64 { match self { diff --git a/crates/rnote-compose/src/style/rough/roughoptions.rs b/crates/rnote-compose/src/style/rough/roughoptions.rs index 42c64c9caa..a09712199e 100644 --- a/crates/rnote-compose/src/style/rough/roughoptions.rs +++ b/crates/rnote-compose/src/style/rough/roughoptions.rs @@ -13,6 +13,9 @@ pub struct RoughOptions { /// Stroke width. #[serde(rename = "stroke_width", with = "crate::serialize::f64_dp3")] pub stroke_width: f64, + /// ghost stroke width (to refer to when scaling with a resize) + #[serde(rename = "strokle_width_cache")] + pub stroke_width_ghost: f64, /// Fill color. When set to None the fill is not drawn. #[serde(rename = "fill_color")] pub fill_color: Option, @@ -32,6 +35,7 @@ impl Default for RoughOptions { Self { stroke_color: Some(Color::BLACK), stroke_width: 2.4, + stroke_width_ghost: 2.4, fill_color: None, fill_style: FillStyle::Hachure, // Default hachure angle (in rad). is -41 degrees diff --git a/crates/rnote-compose/src/style/smooth/smoothoptions.rs b/crates/rnote-compose/src/style/smooth/smoothoptions.rs index 8cfd651d4b..8e1179e029 100644 --- a/crates/rnote-compose/src/style/smooth/smoothoptions.rs +++ b/crates/rnote-compose/src/style/smooth/smoothoptions.rs @@ -10,6 +10,9 @@ pub struct SmoothOptions { /// Stroke width. #[serde(rename = "stroke_width", with = "crate::serialize::f64_dp3")] pub stroke_width: f64, + /// ghost stroke width (to refer to when scaling with a resize) + #[serde(rename = "strokle_width_cache")] + pub stroke_width_ghost: f64, /// Stroke color. When set to None, the stroke outline is not drawn. #[serde(rename = "stroke_color")] pub stroke_color: Option, @@ -19,12 +22,14 @@ pub struct SmoothOptions { /// Pressure curve. #[serde(rename = "pressure_curve")] pub pressure_curve: PressureCurve, + } impl Default for SmoothOptions { fn default() -> Self { Self { stroke_width: 2.0, + stroke_width_ghost: 2.0, stroke_color: Some(Color::BLACK), fill_color: None, pressure_curve: PressureCurve::default(), diff --git a/crates/rnote-compose/src/style/textured/texturedoptions.rs b/crates/rnote-compose/src/style/textured/texturedoptions.rs index 1a98930f3b..aa17e7ddb6 100644 --- a/crates/rnote-compose/src/style/textured/texturedoptions.rs +++ b/crates/rnote-compose/src/style/textured/texturedoptions.rs @@ -14,6 +14,9 @@ pub struct TexturedOptions { /// Stroke width. #[serde(rename = "stroke_width", with = "crate::serialize::f64_dp3")] pub stroke_width: f64, + /// ghost stroke width (to refer to when scaling with a resize) + #[serde(rename = "strokle_width_cache")] + pub stroke_width_ghost: f64, /// Stroke color. When set to None, the stroke is not drawn. #[serde(rename = "stroke_color")] pub stroke_color: Option, @@ -33,6 +36,7 @@ impl Default for TexturedOptions { Self { seed: None, stroke_width: 6.0, + stroke_width_ghost: 6.0, density: 5.0, stroke_color: Some(Color::BLACK), distribution: TexturedDotsDistribution::default(), diff --git a/crates/rnote-engine/src/engine/mod.rs b/crates/rnote-engine/src/engine/mod.rs index 9c01e114cd..61b16d377d 100644 --- a/crates/rnote-engine/src/engine/mod.rs +++ b/crates/rnote-engine/src/engine/mod.rs @@ -830,7 +830,9 @@ impl Engine { .store .stroke_keys_as_rendered_intersecting_bounds(bounds), }; - self.store.set_selected_keys(&select, true); + // [10] : where we select keys + tracing::debug!("selection of the strokes within bounds"); + self.store.set_selected_keys(&select, true); self.doc_resize_autoexpand() | self.record(Instant::now()) | self.update_rendering_current_viewport() diff --git a/crates/rnote-engine/src/pens/selector/mod.rs b/crates/rnote-engine/src/pens/selector/mod.rs index 726e1b9ea7..ca5177d474 100644 --- a/crates/rnote-engine/src/pens/selector/mod.rs +++ b/crates/rnote-engine/src/pens/selector/mod.rs @@ -467,7 +467,7 @@ impl Selector { /// The radius of the circle when selecting in single mode. const SELECTING_SINGLE_CIRCLE_RADIUS: f64 = 4.0; /// Resize node size, in surface coordinates. - const RESIZE_NODE_SIZE: na::Vector2 = na::vector![18.0, 18.0]; + const RESIZE_NODE_SIZE: na::Vector2 = na::vector![18.0, 18.0]; //non lie a la taille de ce qui est drawn !! /// Rotate node diameter, in surface coordinates. const ROTATE_NODE_DIAMETER: f64 = 18.0; /// The outline color when drawing a selection @@ -492,22 +492,35 @@ impl Selector { } fn resize_node_bounds(position: ResizeCorner, selection_bounds: Aabb, camera: &Camera) -> Aabb { + // also to see here [XXX] let total_zoom = camera.total_zoom(); match position { ResizeCorner::TopLeft => Aabb::from_half_extents( - na::point![selection_bounds.mins[0], selection_bounds.mins[1]], + na::point![ + selection_bounds.mins[0] - Self::RESIZE_NODE_SIZE[0] * 0.5 / total_zoom, + selection_bounds.mins[1] - Self::RESIZE_NODE_SIZE[1] * 0.5 / total_zoom + ], Self::RESIZE_NODE_SIZE * 0.5 / total_zoom, ), ResizeCorner::TopRight => Aabb::from_half_extents( - na::point![selection_bounds.maxs[0], selection_bounds.mins[1]], + na::point![ + selection_bounds.maxs[0] + Self::RESIZE_NODE_SIZE[0] * 0.5 / total_zoom, + selection_bounds.mins[1] - Self::RESIZE_NODE_SIZE[1] * 0.5 / total_zoom + ], Self::RESIZE_NODE_SIZE * 0.5 / total_zoom, ), ResizeCorner::BottomLeft => Aabb::from_half_extents( - na::point![selection_bounds.mins[0], selection_bounds.maxs[1]], + na::point![ + selection_bounds.mins[0] - Self::RESIZE_NODE_SIZE[0] * 0.5 / total_zoom, + selection_bounds.maxs[1] + Self::RESIZE_NODE_SIZE[1] * 0.5 / total_zoom + ], Self::RESIZE_NODE_SIZE * 0.5 / total_zoom, ), ResizeCorner::BottomRight => Aabb::from_half_extents( - na::point![selection_bounds.maxs[0], selection_bounds.maxs[1]], + na::point![ + selection_bounds.maxs[0] + Self::RESIZE_NODE_SIZE[0] * 0.5 / total_zoom, + selection_bounds.maxs[1] + Self::RESIZE_NODE_SIZE[1] * 0.5 / total_zoom + ], Self::RESIZE_NODE_SIZE * 0.5 / total_zoom, ), } @@ -612,6 +625,8 @@ impl Selector { _ => PenState::Up, }; + // [XXX] : ui that is drawn + // Selection rect let selection_rect = selection_bounds.to_kurbo_rect(); @@ -659,7 +674,7 @@ impl Selector { // so that the inner shapes become the exterior for correct clipping clip_path.extend( kurbo::Rect::new( - selection_bounds.maxs[0] + Self::OUTLINE_STROKE_WIDTH / total_zoom, + selection_bounds.maxs[0] + Self::OUTLINE_STROKE_WIDTH / total_zoom, // just to see selection_bounds.mins[1] - Self::OUTLINE_STROKE_WIDTH / total_zoom, selection_bounds.mins[0] - Self::OUTLINE_STROKE_WIDTH / total_zoom, selection_bounds.maxs[1] + Self::OUTLINE_STROKE_WIDTH / total_zoom, @@ -791,6 +806,7 @@ impl Selector { } fn cancel_selection(selection: &[StrokeKey], engine_view: &mut EngineViewMut) -> WidgetFlags { + tracing::debug!("cancelling selection"); let mut widget_flags = WidgetFlags::default(); engine_view.store.set_selected_keys(selection, false); engine_view.store.update_geometry_for_strokes(selection); diff --git a/crates/rnote-engine/src/pens/selector/penevents.rs b/crates/rnote-engine/src/pens/selector/penevents.rs index 1c5819a1a7..0161261484 100644 --- a/crates/rnote-engine/src/pens/selector/penevents.rs +++ b/crates/rnote-engine/src/pens/selector/penevents.rs @@ -74,6 +74,10 @@ impl Selector { match modify_state { ModifyState::Up | ModifyState::Hover(_) => { + tracing::debug!("up or hover state for modify"); + // ok, will be the time to reset the cached size + // now this cached size should be set when elements (strokes) get selected + // If we click on another, not-already selected stroke while in separate style or // while pressing Shift, we add it to the selection let key_to_add = engine_view @@ -91,7 +95,16 @@ impl Selector { .unwrap_or(false) { let key_to_add = key_to_add.unwrap(); - engine_view.store.set_selected(key_to_add, true); + // special case here ? what about a resize of 2 elements and then we add a third in the mix + // we need the ref to be added like the rest as well for the resize to work + tracing::debug!("adding an element to the selection with shift"); + + // copy the ghost value for the part that is already selected + engine_view + .store + .copy_ghost_stroke_width(selection); + + engine_view.store.set_selected(key_to_add, true); selection.push(key_to_add); if let Some(new_bounds) = engine_view.store.bounds_for_strokes(selection) @@ -173,6 +186,14 @@ impl Selector { }; } else { // when clicking outside the selection bounds, reset + // where we deselect from our resize + tracing::debug!("resizing selection cancelled"); + + // copy ghost sizes + engine_view + .store + .copy_ghost_stroke_width(selection); + engine_view.store.set_selected_keys(selection, false); self.state = SelectorState::Idle; @@ -260,6 +281,7 @@ impl Selector { start_bounds, start_pos, } => { + tracing::debug!("resize state event"); let lock_aspectratio = engine_view .pens_config .selector_config @@ -312,17 +334,36 @@ impl Selector { let offset_mean = offset_to_start.mean(); offset_to_start = start_extents * (offset_mean / start_mean); } - let min_extents = (Self::RESIZE_NODE_SIZE + let min_extents = 1e-14f64*(Self::RESIZE_NODE_SIZE // no need for that if they're outside. Still need to be at least eps + na::Vector2::::from_element(Self::ROTATE_NODE_DIAMETER)) / engine_view.camera.total_zoom(); + // this is what has to change. Store the original thing in a single struct of Engine.store at the same place + // the selection takes place ? + + // check what the calculation is here let scale = (start_bounds.extents() + offset_to_start) .maxs(&min_extents) .component_div(&selection_bounds.extents()); + + tracing::debug!("start coordinates {:?}",start_bounds.extents() + offset_to_start); + tracing::debug!("coordinates maxes {:?}",min_extents); + tracing::debug!("size {:?}",selection_bounds.extents()); + tracing::debug!("scale {:?}", scale); + // check the log to see the change ... + // too small to draw the little resizing things + // do it the xournal way ? // resize strokes + // [5] : we do that on the width directly. Needs to change + // but we have to have a "resize has finished" to be in place engine_view .store - .scale_strokes_with_pivot(selection, scale, pivot); + .scale_strokes_with_pivot(selection, scale, pivot); // [4]. + // this should distinguish between end of resize and resize in progress + // we also need the original size of the elements in addition to their displayed sizes + tracing::debug!("{:?}",scale); // to use for the debug of scale on clipboard paste !! + // scale_strokes_with_pivot is also used in the resize_image part. So we need to copy the ghost values in that case (to do on merge) + engine_view .store .scale_strokes_images_with_pivot(selection, scale, pivot); @@ -428,6 +469,8 @@ impl Selector { } }; if !new_selection.is_empty() { + // we made a new selection + tracing::debug!("new selection made"); engine_view.store.set_selected_keys(&new_selection, true); widget_flags.store_modified = true; widget_flags.deselect_color_setters = true; diff --git a/crates/rnote-engine/src/store/stroke_comp.rs b/crates/rnote-engine/src/store/stroke_comp.rs index 8062b12e4a..614c2914c1 100644 --- a/crates/rnote-engine/src/store/stroke_comp.rs +++ b/crates/rnote-engine/src/store/stroke_comp.rs @@ -396,6 +396,7 @@ impl StrokeStore { /// /// The strokes then need to update their rendering. pub(crate) fn scale_strokes(&mut self, keys: &[StrokeKey], scale: na::Vector2) { + // [3] one level upper keys.iter().for_each(|&key| { if let Some(stroke) = Arc::make_mut(&mut self.stroke_components) .get_mut(key) @@ -403,13 +404,27 @@ impl StrokeStore { { { // rotate the stroke geometry - stroke.scale(scale); + stroke.scale(scale); // our problem down the line self.key_tree.update_with_key(key, stroke.bounds()); } } }); } + /// Copy the ghost width + pub(crate) fn copy_ghost_stroke_width(&mut self, keys: &[StrokeKey]) { + keys.iter().for_each(|&key| { + if let Some(stroke) = Arc::make_mut(&mut self.stroke_components) + .get_mut(key) + .map(Arc::make_mut) + { + stroke.copy_ghost_stroke_width(); + // some un neccessary call onto nothing, pattern match here instead ? + } + }) + } + + /// Scale the stroke rendering images. /// /// The strokes then need to update their rendering. @@ -444,8 +459,9 @@ impl StrokeStore { scale: na::Vector2, pivot: na::Vector2, ) { + // [4] self.translate_strokes(keys, -pivot); - self.scale_strokes(keys, scale); + self.scale_strokes(keys, scale); // our problem is here // [3] self.translate_strokes(keys, pivot); } diff --git a/crates/rnote-engine/src/strokes/brushstroke.rs b/crates/rnote-engine/src/strokes/brushstroke.rs index 0e30c790ac..0a7c7e52d4 100644 --- a/crates/rnote-engine/src/strokes/brushstroke.rs +++ b/crates/rnote-engine/src/strokes/brushstroke.rs @@ -256,10 +256,11 @@ impl Transformable for BrushStroke { self.path.rotate(angle, center); } fn scale(&mut self, scale: na::Vector2) { + // [0] self.path.scale(scale); let scale_uniform = (scale[0] + scale[1]) / 2.; self.style - .set_stroke_width(self.style.stroke_width() * scale_uniform); + .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); } } @@ -379,4 +380,8 @@ impl BrushStroke { Ok(image) } + + pub fn copy_ghost_stroke_width(&mut self) { + self.style.copy_ghost_stroke_width(); + } } diff --git a/crates/rnote-engine/src/strokes/shapestroke.rs b/crates/rnote-engine/src/strokes/shapestroke.rs index b4816a5b34..21643e906f 100644 --- a/crates/rnote-engine/src/strokes/shapestroke.rs +++ b/crates/rnote-engine/src/strokes/shapestroke.rs @@ -92,10 +92,13 @@ impl Transformable for ShapeStroke { self.shape.rotate(angle, center); } fn scale(&mut self, scale: na::Vector2) { + // [2] + // should be called for transformations (selection tool) and the new resize mechanisms + // but in all cases the end thing is selected so everything resynced on deselecting self.shape.scale(scale); let scale_uniform = (scale[0] + scale[1]) / 2.; self.style - .set_stroke_width(self.style.stroke_width() * scale_uniform); + .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); } } @@ -120,4 +123,8 @@ impl ShapeStroke { .map(|hitbox| hitbox.loosened(width * 0.5)) .collect() } + + pub fn copy_ghost_stroke_width(&mut self){ + self.style.copy_ghost_stroke_width(); + } } diff --git a/crates/rnote-engine/src/strokes/stroke.rs b/crates/rnote-engine/src/strokes/stroke.rs index dc9f794c75..4f32872b5e 100644 --- a/crates/rnote-engine/src/strokes/stroke.rs +++ b/crates/rnote-engine/src/strokes/stroke.rs @@ -180,11 +180,14 @@ impl Transformable for Stroke { } fn scale(&mut self, scale: na::Vector2) { + // [2] one level upper, calls to that here match self { Self::BrushStroke(brushstroke) => { + // [1] brushstroke.scale(scale); } Self::ShapeStroke(shapestroke) => { + // [1] shapestroke.scale(scale); } Self::TextStroke(textstroke) => { @@ -671,4 +674,23 @@ impl Stroke { } } } + + /// Copy the ghost value + pub fn copy_ghost_stroke_width(&mut self) { + // [2] one level upper, calls to that here + match self { + Self::BrushStroke(brushstroke) => { + // [1] + brushstroke.copy_ghost_stroke_width(); + } + Self::ShapeStroke(shapestroke) => { + // [1] + shapestroke.copy_ghost_stroke_width(); + } + _ => { + // do nothing + (); + } + } + } } diff --git a/crates/rnote-ui/src/appwindow/actions.rs b/crates/rnote-ui/src/appwindow/actions.rs index e79b15215e..a15b440873 100644 --- a/crates/rnote-ui/src/appwindow/actions.rs +++ b/crates/rnote-ui/src/appwindow/actions.rs @@ -428,6 +428,8 @@ impl RnAppWindow { action_selection_select_all.connect_activate( clone!(@weak self as appwindow => move |_, _| { let canvas = appwindow.active_tab_wrapper().canvas(); + // we select here all strokes + tracing::debug!("selecting all strokes"); let widget_flags = canvas.engine_mut().select_all_strokes(); appwindow.handle_widget_flags(widget_flags, &canvas); }), From faa36a2ec46bca67173e4dbdf6426fc61579284e Mon Sep 17 00:00:00 2001 From: Doublonmousse <115779707+Doublonmousse@users.noreply.github.com> Date: Fri, 23 Feb 2024 10:25:18 +0100 Subject: [PATCH 2/8] disable `ghost_stroke_width` --- crates/rnote-engine/src/strokes/brushstroke.rs | 3 ++- crates/rnote-engine/src/strokes/shapestroke.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/rnote-engine/src/strokes/brushstroke.rs b/crates/rnote-engine/src/strokes/brushstroke.rs index 0a7c7e52d4..c10fbe75e6 100644 --- a/crates/rnote-engine/src/strokes/brushstroke.rs +++ b/crates/rnote-engine/src/strokes/brushstroke.rs @@ -260,7 +260,8 @@ impl Transformable for BrushStroke { self.path.scale(scale); let scale_uniform = (scale[0] + scale[1]) / 2.; self.style - .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); + .set_stroke_width(self.style.stroke_width() * scale_uniform); + // .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); } } diff --git a/crates/rnote-engine/src/strokes/shapestroke.rs b/crates/rnote-engine/src/strokes/shapestroke.rs index 21643e906f..b51cb5dd76 100644 --- a/crates/rnote-engine/src/strokes/shapestroke.rs +++ b/crates/rnote-engine/src/strokes/shapestroke.rs @@ -98,7 +98,8 @@ impl Transformable for ShapeStroke { self.shape.scale(scale); let scale_uniform = (scale[0] + scale[1]) / 2.; self.style - .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); + .set_stroke_width(self.style.stroke_width() * scale_uniform); + // .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); } } From 804ec488b5318cbff7bf7cffc1ff5fe4f4630822 Mon Sep 17 00:00:00 2001 From: Doublonmousse <115779707+Doublonmousse@users.noreply.github.com> Date: Sat, 24 Feb 2024 17:44:50 +0100 Subject: [PATCH 3/8] use consts for placing the elements outside --- crates/rnote-engine/src/pens/selector/mod.rs | 2 +- crates/rnote-engine/src/pens/selector/penevents.rs | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/crates/rnote-engine/src/pens/selector/mod.rs b/crates/rnote-engine/src/pens/selector/mod.rs index ca5177d474..901b5fa262 100644 --- a/crates/rnote-engine/src/pens/selector/mod.rs +++ b/crates/rnote-engine/src/pens/selector/mod.rs @@ -529,7 +529,7 @@ impl Selector { fn rotate_node_sphere(selection_bounds: Aabb, camera: &Camera) -> BoundingSphere { let total_zoom = camera.total_zoom(); let pos = na::point![ - selection_bounds.maxs[0], + selection_bounds.maxs[0] + Self::RESIZE_NODE_SIZE[0]/total_zoom, (selection_bounds.maxs[1] + selection_bounds.mins[1]) * 0.5 ]; BoundingSphere::new(pos, Self::ROTATE_NODE_DIAMETER * 0.5 / total_zoom) diff --git a/crates/rnote-engine/src/pens/selector/penevents.rs b/crates/rnote-engine/src/pens/selector/penevents.rs index 0161261484..58f402efec 100644 --- a/crates/rnote-engine/src/pens/selector/penevents.rs +++ b/crates/rnote-engine/src/pens/selector/penevents.rs @@ -334,24 +334,17 @@ impl Selector { let offset_mean = offset_to_start.mean(); offset_to_start = start_extents * (offset_mean / start_mean); } - let min_extents = 1e-14f64*(Self::RESIZE_NODE_SIZE // no need for that if they're outside. Still need to be at least eps - + na::Vector2::::from_element(Self::ROTATE_NODE_DIAMETER)) - / engine_view.camera.total_zoom(); - // this is what has to change. Store the original thing in a single struct of Engine.store at the same place - // the selection takes place ? - // check what the calculation is here + let min_extents = na::vector![1e-2f64,1e-2f64]/engine_view.camera.total_zoom(); let scale = (start_bounds.extents() + offset_to_start) .maxs(&min_extents) .component_div(&selection_bounds.extents()); + // debug traces here just for info tracing::debug!("start coordinates {:?}",start_bounds.extents() + offset_to_start); tracing::debug!("coordinates maxes {:?}",min_extents); tracing::debug!("size {:?}",selection_bounds.extents()); tracing::debug!("scale {:?}", scale); - // check the log to see the change ... - // too small to draw the little resizing things - // do it the xournal way ? // resize strokes // [5] : we do that on the width directly. Needs to change From 84dc896b9d23bb512b0cc263c95650d354ffe044 Mon Sep 17 00:00:00 2001 From: Doublonmousse <115779707+Doublonmousse@users.noreply.github.com> Date: Sat, 24 Feb 2024 18:42:43 +0100 Subject: [PATCH 4/8] separate stroke for resize and stroke (wip) - issue : need to update ALL transformable imp down to elements that won't have anything to do with stroke width --- crates/rnote-compose/src/penpath/element.rs | 4 ++-- crates/rnote-compose/src/penpath/mod.rs | 6 +++--- crates/rnote-compose/src/penpath/segment.rs | 14 +++++++------- crates/rnote-compose/src/shapes/shape.rs | 18 +++++++++--------- .../src/transform/transformable.rs | 2 +- crates/rnote-engine/src/engine/mod.rs | 10 +++++++++- crates/rnote-engine/src/pens/selector/mod.rs | 2 +- .../src/pens/selector/penevents.rs | 18 +++++++++++------- crates/rnote-engine/src/store/mod.rs | 4 ++++ .../rnote-engine/src/store/selection_comp.rs | 10 +++++++++- crates/rnote-engine/src/store/stroke_comp.rs | 9 +++++---- crates/rnote-engine/src/strokes/brushstroke.rs | 10 +++++----- crates/rnote-engine/src/strokes/shapestroke.rs | 10 +++++----- crates/rnote-engine/src/strokes/stroke.rs | 13 ++++++------- 14 files changed, 77 insertions(+), 53 deletions(-) diff --git a/crates/rnote-compose/src/penpath/element.rs b/crates/rnote-compose/src/penpath/element.rs index a7f8696813..66f8844c09 100644 --- a/crates/rnote-compose/src/penpath/element.rs +++ b/crates/rnote-compose/src/penpath/element.rs @@ -32,8 +32,8 @@ impl Transformable for Element { self.pos = isometry.transform_point(&self.pos.into()).coords; } - fn scale(&mut self, scale: na::Vector2) { - self.pos = self.pos.component_mul(&scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.pos = self.pos.component_mul(&scale_resize); } } diff --git a/crates/rnote-compose/src/penpath/mod.rs b/crates/rnote-compose/src/penpath/mod.rs index 00571254e6..5cf864c32d 100644 --- a/crates/rnote-compose/src/penpath/mod.rs +++ b/crates/rnote-compose/src/penpath/mod.rs @@ -92,10 +92,10 @@ impl Transformable for PenPath { }); } - fn scale(&mut self, scale: na::Vector2) { - self.start.scale(scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.start.scale(scale_stroke,scale_resize); self.segments.iter_mut().for_each(|segment| { - segment.scale(scale); + segment.scale(scale_stroke,scale_resize); }); } } diff --git a/crates/rnote-compose/src/penpath/segment.rs b/crates/rnote-compose/src/penpath/segment.rs index b8e4cae6c1..41ea8c80e9 100644 --- a/crates/rnote-compose/src/penpath/segment.rs +++ b/crates/rnote-compose/src/penpath/segment.rs @@ -77,19 +77,19 @@ impl Transformable for Segment { } } - fn scale(&mut self, scale: na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { match self { Self::LineTo { end } => { - end.pos = end.pos.component_mul(&scale); + end.pos = end.pos.component_mul(&scale_resize); } Self::QuadBezTo { cp, end } => { - *cp = cp.component_mul(&scale); - end.pos = end.pos.component_mul(&scale); + *cp = cp.component_mul(&scale_resize); + end.pos = end.pos.component_mul(&scale_resize); } Self::CubBezTo { cp1, cp2, end } => { - *cp1 = cp1.component_mul(&scale); - *cp2 = cp2.component_mul(&scale); - end.pos = end.pos.component_mul(&scale); + *cp1 = cp1.component_mul(&scale_resize); + *cp2 = cp2.component_mul(&scale_resize); + end.pos = end.pos.component_mul(&scale_resize); } } } diff --git a/crates/rnote-compose/src/shapes/shape.rs b/crates/rnote-compose/src/shapes/shape.rs index ad30f8298c..24e6f5a575 100644 --- a/crates/rnote-compose/src/shapes/shape.rs +++ b/crates/rnote-compose/src/shapes/shape.rs @@ -101,31 +101,31 @@ impl Transformable for Shape { } } - fn scale(&mut self, scale: na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { match self { Self::Line(line) => { - line.scale(scale); + line.scale(scale_stroke,scale_resize); } Self::Arrow(arrow) => { - arrow.scale(scale); + arrow.scale(scale_stroke,scale_resize); } Self::Rectangle(rectangle) => { - rectangle.scale(scale); + rectangle.scale(scale_stroke,scale_resize); } Self::Ellipse(ellipse) => { - ellipse.scale(scale); + ellipse.scale(scale_stroke,scale_resize); } Self::QuadraticBezier(quadbez) => { - quadbez.scale(scale); + quadbez.scale(scale_stroke,scale_resize); } Self::CubicBezier(cubbez) => { - cubbez.scale(scale); + cubbez.scale(scale_stroke,scale_resize); } Self::Polyline(polyline) => { - polyline.scale(scale); + polyline.scale(scale_stroke,scale_resize); } Self::Polygon(polygon) => { - polygon.scale(scale); + polygon.scale(scale_stroke,scale_resize); } } } diff --git a/crates/rnote-compose/src/transform/transformable.rs b/crates/rnote-compose/src/transform/transformable.rs index 27c9d37585..13997c5107 100644 --- a/crates/rnote-compose/src/transform/transformable.rs +++ b/crates/rnote-compose/src/transform/transformable.rs @@ -5,5 +5,5 @@ pub trait Transformable { /// Rotate by the given angle (in radians). fn rotate(&mut self, angle: f64, center: na::Point2); /// Scale by the given scale-factor. - fn scale(&mut self, scale: na::Vector2); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2); } diff --git a/crates/rnote-engine/src/engine/mod.rs b/crates/rnote-engine/src/engine/mod.rs index 61b16d377d..b04e2a1e98 100644 --- a/crates/rnote-engine/src/engine/mod.rs +++ b/crates/rnote-engine/src/engine/mod.rs @@ -812,6 +812,7 @@ impl Engine { let widget_flags = self.change_pen_style(PenStyle::Selector); self.store .set_selected_keys(&self.store.selection_keys_as_rendered(), false); + self.store.initial_size_selection = None; widget_flags | self.current_pen_update_state() | self.doc_resize_autoexpand() @@ -832,7 +833,14 @@ impl Engine { }; // [10] : where we select keys tracing::debug!("selection of the strokes within bounds"); - self.store.set_selected_keys(&select, true); + self.store.set_selected_keys(&select, true); + // get the size of the selection ? + let selection_keys = self.store.selection_keys_as_rendered(); + self.store.initial_size_selection = match self.store.bounds_for_strokes(&selection_keys) { + None => None, + Some(aabb) => Some(aabb.extents()) + }; + // self.store. self.doc_resize_autoexpand() | self.record(Instant::now()) | self.update_rendering_current_viewport() diff --git a/crates/rnote-engine/src/pens/selector/mod.rs b/crates/rnote-engine/src/pens/selector/mod.rs index 901b5fa262..31a131e179 100644 --- a/crates/rnote-engine/src/pens/selector/mod.rs +++ b/crates/rnote-engine/src/pens/selector/mod.rs @@ -529,7 +529,7 @@ impl Selector { fn rotate_node_sphere(selection_bounds: Aabb, camera: &Camera) -> BoundingSphere { let total_zoom = camera.total_zoom(); let pos = na::point![ - selection_bounds.maxs[0] + Self::RESIZE_NODE_SIZE[0]/total_zoom, + selection_bounds.maxs[0] + Self::RESIZE_NODE_SIZE[0]/(2.0*total_zoom), (selection_bounds.maxs[1] + selection_bounds.mins[1]) * 0.5 ]; BoundingSphere::new(pos, Self::ROTATE_NODE_DIAMETER * 0.5 / total_zoom) diff --git a/crates/rnote-engine/src/pens/selector/penevents.rs b/crates/rnote-engine/src/pens/selector/penevents.rs index 58f402efec..5de912cb04 100644 --- a/crates/rnote-engine/src/pens/selector/penevents.rs +++ b/crates/rnote-engine/src/pens/selector/penevents.rs @@ -336,22 +336,26 @@ impl Selector { } let min_extents = na::vector![1e-2f64,1e-2f64]/engine_view.camera.total_zoom(); - let scale = (start_bounds.extents() + offset_to_start) + let scale_stroke = (start_bounds.extents() + offset_to_start) .maxs(&min_extents) - .component_div(&selection_bounds.extents()); - + .component_div(&engine_view.store.initial_size_selection.unwrap()); // some dangerous unwrap here ... + + let scale_resize = (start_bounds.extents() + offset_to_start) + .maxs(&min_extents) + .component_div(&selection_bounds.extents()); // some dangerous unwrap here ... + // debug traces here just for info tracing::debug!("start coordinates {:?}",start_bounds.extents() + offset_to_start); tracing::debug!("coordinates maxes {:?}",min_extents); tracing::debug!("size {:?}",selection_bounds.extents()); - tracing::debug!("scale {:?}", scale); + tracing::debug!("scale {:?} {:?}", scale_stroke,scale_resize); // resize strokes // [5] : we do that on the width directly. Needs to change // but we have to have a "resize has finished" to be in place engine_view .store - .scale_strokes_with_pivot(selection, scale, pivot); // [4]. + .scale_strokes_with_pivot(selection, scale_stroke,scale_resize, pivot); // [4]. // this should distinguish between end of resize and resize in progress // we also need the original size of the elements in addition to their displayed sizes tracing::debug!("{:?}",scale); // to use for the debug of scale on clipboard paste !! @@ -359,10 +363,10 @@ impl Selector { engine_view .store - .scale_strokes_images_with_pivot(selection, scale, pivot); + .scale_strokes_images_with_pivot(selection, scale_resize, pivot); *selection_bounds = selection_bounds .translate(-pivot) - .scale_non_uniform(scale) + .scale_non_uniform(scale_resize) .translate(pivot); // possibly nudge camera diff --git a/crates/rnote-engine/src/store/mod.rs b/crates/rnote-engine/src/store/mod.rs index 8b847cf754..6faac4494d 100644 --- a/crates/rnote-engine/src/store/mod.rs +++ b/crates/rnote-engine/src/store/mod.rs @@ -95,6 +95,9 @@ pub struct StrokeStore { /// Needs to be updated with `update_with_key()` when strokes changed their geometry or position! #[serde(skip)] key_tree: KeyTree, + /// initial size of the selection, used to change stroke width with respect to that initial size + #[serde(skip)] + pub initial_size_selection: Option>, } impl Default for StrokeStore { @@ -113,6 +116,7 @@ impl Default for StrokeStore { key_tree: KeyTree::default(), chrono_counter: 0, + initial_size_selection:None, } } } diff --git a/crates/rnote-engine/src/store/selection_comp.rs b/crates/rnote-engine/src/store/selection_comp.rs index f390dbe57f..f173849742 100644 --- a/crates/rnote-engine/src/store/selection_comp.rs +++ b/crates/rnote-engine/src/store/selection_comp.rs @@ -58,7 +58,15 @@ impl StrokeStore { pub(crate) fn set_selected_keys(&mut self, keys: &[StrokeKey], selected: bool) { keys.iter().for_each(|&key| { self.set_selected(key, selected); - }) + }); + // update selection bounds + // duplicate ? + let selection_keys = self.selection_keys_as_rendered(); + + self.initial_size_selection = match self.bounds_for_strokes(&selection_keys) { + None => None, + Some(aabb) => Some(aabb.extents()) + }; } pub(crate) fn selection_keys_unordered(&self) -> Vec { diff --git a/crates/rnote-engine/src/store/stroke_comp.rs b/crates/rnote-engine/src/store/stroke_comp.rs index 614c2914c1..f481524eb0 100644 --- a/crates/rnote-engine/src/store/stroke_comp.rs +++ b/crates/rnote-engine/src/store/stroke_comp.rs @@ -395,7 +395,7 @@ impl StrokeStore { /// Scale the strokes with the factor. /// /// The strokes then need to update their rendering. - pub(crate) fn scale_strokes(&mut self, keys: &[StrokeKey], scale: na::Vector2) { + pub(crate) fn scale_strokes(&mut self, keys: &[StrokeKey],scale_stroke: na::Vector2, scale_resize:na::Vector2) { // [3] one level upper keys.iter().for_each(|&key| { if let Some(stroke) = Arc::make_mut(&mut self.stroke_components) @@ -404,7 +404,7 @@ impl StrokeStore { { { // rotate the stroke geometry - stroke.scale(scale); // our problem down the line + stroke.scale(scale_stroke,scale_resize); // our problem down the line self.key_tree.update_with_key(key, stroke.bounds()); } } @@ -456,12 +456,13 @@ impl StrokeStore { pub(crate) fn scale_strokes_with_pivot( &mut self, keys: &[StrokeKey], - scale: na::Vector2, + scale_stroke: na::Vector2, + scale_resize: na::Vector2, pivot: na::Vector2, ) { // [4] self.translate_strokes(keys, -pivot); - self.scale_strokes(keys, scale); // our problem is here // [3] + self.scale_strokes(keys, scale_stroke,scale_resize); self.translate_strokes(keys, pivot); } diff --git a/crates/rnote-engine/src/strokes/brushstroke.rs b/crates/rnote-engine/src/strokes/brushstroke.rs index c10fbe75e6..317d1df290 100644 --- a/crates/rnote-engine/src/strokes/brushstroke.rs +++ b/crates/rnote-engine/src/strokes/brushstroke.rs @@ -255,13 +255,13 @@ impl Transformable for BrushStroke { fn rotate(&mut self, angle: f64, center: na::Point2) { self.path.rotate(angle, center); } - fn scale(&mut self, scale: na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { // [0] - self.path.scale(scale); - let scale_uniform = (scale[0] + scale[1]) / 2.; + self.path.scale(scale_stroke,scale_resize); + let scale_uniform = (scale_stroke[0] + scale_stroke[1]) / 2.; self.style - .set_stroke_width(self.style.stroke_width() * scale_uniform); - // .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); + // .set_stroke_width(self.style.stroke_width() * scale_uniform); + .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); } } diff --git a/crates/rnote-engine/src/strokes/shapestroke.rs b/crates/rnote-engine/src/strokes/shapestroke.rs index b51cb5dd76..ad3b3246d1 100644 --- a/crates/rnote-engine/src/strokes/shapestroke.rs +++ b/crates/rnote-engine/src/strokes/shapestroke.rs @@ -91,15 +91,15 @@ impl Transformable for ShapeStroke { fn rotate(&mut self, angle: f64, center: na::Point2) { self.shape.rotate(angle, center); } - fn scale(&mut self, scale: na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { // [2] // should be called for transformations (selection tool) and the new resize mechanisms // but in all cases the end thing is selected so everything resynced on deselecting - self.shape.scale(scale); - let scale_uniform = (scale[0] + scale[1]) / 2.; + self.shape.scale(scale_stroke,scale_resize); + let scale_uniform = (scale_stroke[0] + scale_stroke[1]) / 2.; self.style - .set_stroke_width(self.style.stroke_width() * scale_uniform); - // .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); + // .set_stroke_width(self.style.stroke_width() * scale_uniform); + .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); } } diff --git a/crates/rnote-engine/src/strokes/stroke.rs b/crates/rnote-engine/src/strokes/stroke.rs index 4f32872b5e..02a2dd0049 100644 --- a/crates/rnote-engine/src/strokes/stroke.rs +++ b/crates/rnote-engine/src/strokes/stroke.rs @@ -179,25 +179,25 @@ impl Transformable for Stroke { } } - fn scale(&mut self, scale: na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { // [2] one level upper, calls to that here match self { Self::BrushStroke(brushstroke) => { // [1] - brushstroke.scale(scale); + brushstroke.scale(scale_stroke,scale_resize); } Self::ShapeStroke(shapestroke) => { // [1] - shapestroke.scale(scale); + shapestroke.scale(scale_stroke,scale_resize); } Self::TextStroke(textstroke) => { - textstroke.scale(scale); + textstroke.scale(scale_stroke,scale_resize); } Self::VectorImage(vectorimage) => { - vectorimage.scale(scale); + vectorimage.scale(scale_stroke,scale_resize); } Self::BitmapImage(bitmapimage) => { - bitmapimage.scale(scale); + bitmapimage.scale(scale_stroke,scale_resize); } } } @@ -689,7 +689,6 @@ impl Stroke { } _ => { // do nothing - (); } } } From dda95a237e6df2672ccfaddee02af780337d1916 Mon Sep 17 00:00:00 2001 From: Doublonmousse <115779707+Doublonmousse@users.noreply.github.com> Date: Sat, 24 Feb 2024 19:04:00 +0100 Subject: [PATCH 5/8] first test Does seem to fix the stroke issue Couple of points to test/verify/debug - test all elements or double check all `scale` method so that these are correct (not yet correct it seems) - weird artefact going from the min size to a little larger on some elements, to investigate --- crates/rnote-compose/src/shapes/arrow.rs | 6 +++--- crates/rnote-compose/src/shapes/cubbez.rs | 10 +++++----- crates/rnote-compose/src/shapes/ellipse.rs | 4 ++-- crates/rnote-compose/src/shapes/line.rs | 6 +++--- crates/rnote-compose/src/shapes/polygon.rs | 6 +++--- crates/rnote-compose/src/shapes/polyline.rs | 6 +++--- crates/rnote-compose/src/shapes/quadbez.rs | 8 ++++---- crates/rnote-compose/src/shapes/rectangle.rs | 4 ++-- crates/rnote-compose/src/transform/mod.rs | 4 ++-- crates/rnote-engine/src/pens/selector/penevents.rs | 1 - crates/rnote-engine/src/render.rs | 4 ++-- crates/rnote-engine/src/store/stroke_comp.rs | 2 +- crates/rnote-engine/src/strokes/bitmapimage.rs | 4 ++-- crates/rnote-engine/src/strokes/textstroke.rs | 4 ++-- crates/rnote-engine/src/strokes/vectorimage.rs | 4 ++-- 15 files changed, 36 insertions(+), 37 deletions(-) diff --git a/crates/rnote-compose/src/shapes/arrow.rs b/crates/rnote-compose/src/shapes/arrow.rs index 66a567866d..dd955ec23d 100644 --- a/crates/rnote-compose/src/shapes/arrow.rs +++ b/crates/rnote-compose/src/shapes/arrow.rs @@ -52,9 +52,9 @@ impl Transformable for Arrow { self.tip = isometry.transform_point(&self.tip.into()).coords; } - fn scale(&mut self, scale: na::Vector2) { - self.start = self.start.component_mul(&scale); - self.tip = self.tip.component_mul(&scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.start = self.start.component_mul(&scale_resize); + self.tip = self.tip.component_mul(&scale_resize); } } diff --git a/crates/rnote-compose/src/shapes/cubbez.rs b/crates/rnote-compose/src/shapes/cubbez.rs index 3d8e0fc82a..304de0f479 100644 --- a/crates/rnote-compose/src/shapes/cubbez.rs +++ b/crates/rnote-compose/src/shapes/cubbez.rs @@ -44,11 +44,11 @@ impl Transformable for CubicBezier { self.end = isometry.transform_point(&self.end.into()).coords; } - fn scale(&mut self, scale: na::Vector2) { - self.start = self.start.component_mul(&scale); - self.cp1 = self.cp1.component_mul(&scale); - self.cp2 = self.cp2.component_mul(&scale); - self.end = self.end.component_mul(&scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.start = self.start.component_mul(&scale_resize); + self.cp1 = self.cp1.component_mul(&scale_resize); + self.cp2 = self.cp2.component_mul(&scale_resize); + self.end = self.end.component_mul(&scale_resize); } } diff --git a/crates/rnote-compose/src/shapes/ellipse.rs b/crates/rnote-compose/src/shapes/ellipse.rs index c84ca25495..5143b784d6 100644 --- a/crates/rnote-compose/src/shapes/ellipse.rs +++ b/crates/rnote-compose/src/shapes/ellipse.rs @@ -38,8 +38,8 @@ impl Transformable for Ellipse { self.transform.append_rotation_wrt_point_mut(angle, center) } - fn scale(&mut self, scale: na::Vector2) { - self.transform.append_scale_mut(scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.transform.append_scale_mut(scale_resize); } } diff --git a/crates/rnote-compose/src/shapes/line.rs b/crates/rnote-compose/src/shapes/line.rs index 1d6092d432..f655cdbdc7 100644 --- a/crates/rnote-compose/src/shapes/line.rs +++ b/crates/rnote-compose/src/shapes/line.rs @@ -34,9 +34,9 @@ impl Transformable for Line { self.end = isometry.transform_point(&self.end.into()).coords; } - fn scale(&mut self, scale: na::Vector2) { - self.start = self.start.component_mul(&scale); - self.end = self.end.component_mul(&scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.start = self.start.component_mul(&scale_resize); + self.end = self.end.component_mul(&scale_resize); } } diff --git a/crates/rnote-compose/src/shapes/polygon.rs b/crates/rnote-compose/src/shapes/polygon.rs index 6ba8619512..83922d29a2 100644 --- a/crates/rnote-compose/src/shapes/polygon.rs +++ b/crates/rnote-compose/src/shapes/polygon.rs @@ -35,10 +35,10 @@ impl Transformable for Polygon { } } - fn scale(&mut self, scale: na::Vector2) { - self.start = self.start.component_mul(&scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.start = self.start.component_mul(&scale_resize); for p in &mut self.path { - *p = p.component_mul(&scale); + *p = p.component_mul(&scale_resize); } } } diff --git a/crates/rnote-compose/src/shapes/polyline.rs b/crates/rnote-compose/src/shapes/polyline.rs index 9e4bb4d92e..c60fd0e54b 100644 --- a/crates/rnote-compose/src/shapes/polyline.rs +++ b/crates/rnote-compose/src/shapes/polyline.rs @@ -35,10 +35,10 @@ impl Transformable for Polyline { } } - fn scale(&mut self, scale: na::Vector2) { - self.start = self.start.component_mul(&scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.start = self.start.component_mul(&scale_resize); for p in &mut self.path { - *p = p.component_mul(&scale); + *p = p.component_mul(&scale_resize); } } } diff --git a/crates/rnote-compose/src/shapes/quadbez.rs b/crates/rnote-compose/src/shapes/quadbez.rs index 2dcb72d346..45aa9fe020 100644 --- a/crates/rnote-compose/src/shapes/quadbez.rs +++ b/crates/rnote-compose/src/shapes/quadbez.rs @@ -39,10 +39,10 @@ impl Transformable for QuadraticBezier { self.end = isometry.transform_point(&self.end.into()).coords; } - fn scale(&mut self, scale: na::Vector2) { - self.start = self.start.component_mul(&scale); - self.cp = self.cp.component_mul(&scale); - self.end = self.end.component_mul(&scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.start = self.start.component_mul(&scale_resize); + self.cp = self.cp.component_mul(&scale_resize); + self.end = self.end.component_mul(&scale_resize); } } diff --git a/crates/rnote-compose/src/shapes/rectangle.rs b/crates/rnote-compose/src/shapes/rectangle.rs index 6b3b621423..337c9d01d6 100644 --- a/crates/rnote-compose/src/shapes/rectangle.rs +++ b/crates/rnote-compose/src/shapes/rectangle.rs @@ -78,8 +78,8 @@ impl Transformable for Rectangle { self.transform.append_rotation_wrt_point_mut(angle, center) } - fn scale(&mut self, scale: na::Vector2) { - self.transform.append_scale_mut(scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.transform.append_scale_mut(scale_resize); } } diff --git a/crates/rnote-compose/src/transform/mod.rs b/crates/rnote-compose/src/transform/mod.rs index d6be392f15..97c9514dc4 100644 --- a/crates/rnote-compose/src/transform/mod.rs +++ b/crates/rnote-compose/src/transform/mod.rs @@ -50,8 +50,8 @@ impl Transformable for Transform { self.append_rotation_wrt_point_mut(angle, center); } - fn scale(&mut self, scale: na::Vector2) { - self.append_scale_mut(scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.append_scale_mut(scale_resize); } } diff --git a/crates/rnote-engine/src/pens/selector/penevents.rs b/crates/rnote-engine/src/pens/selector/penevents.rs index 5de912cb04..5508806414 100644 --- a/crates/rnote-engine/src/pens/selector/penevents.rs +++ b/crates/rnote-engine/src/pens/selector/penevents.rs @@ -358,7 +358,6 @@ impl Selector { .scale_strokes_with_pivot(selection, scale_stroke,scale_resize, pivot); // [4]. // this should distinguish between end of resize and resize in progress // we also need the original size of the elements in addition to their displayed sizes - tracing::debug!("{:?}",scale); // to use for the debug of scale on clipboard paste !! // scale_strokes_with_pivot is also used in the resize_image part. So we need to copy the ghost values in that case (to do on merge) engine_view diff --git a/crates/rnote-engine/src/render.rs b/crates/rnote-engine/src/render.rs index a9a51abeea..3cf6a200ff 100644 --- a/crates/rnote-engine/src/render.rs +++ b/crates/rnote-engine/src/render.rs @@ -169,8 +169,8 @@ impl Transformable for Image { self.rect.rotate(angle, center) } - fn scale(&mut self, scale: na::Vector2) { - self.rect.scale(scale) + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.rect.scale(scale_stroke,scale_resize) } } diff --git a/crates/rnote-engine/src/store/stroke_comp.rs b/crates/rnote-engine/src/store/stroke_comp.rs index f481524eb0..f004a6d086 100644 --- a/crates/rnote-engine/src/store/stroke_comp.rs +++ b/crates/rnote-engine/src/store/stroke_comp.rs @@ -434,7 +434,7 @@ impl StrokeStore { render_comp.state = RenderCompState::Dirty; for image in render_comp.images.iter_mut() { - image.scale(scale); + image.scale(scale,scale); } #[cfg(feature = "ui")] diff --git a/crates/rnote-engine/src/strokes/bitmapimage.rs b/crates/rnote-engine/src/strokes/bitmapimage.rs index deb324a5ed..df4b91c3dc 100644 --- a/crates/rnote-engine/src/strokes/bitmapimage.rs +++ b/crates/rnote-engine/src/strokes/bitmapimage.rs @@ -91,8 +91,8 @@ impl Transformable for BitmapImage { self.rectangle.rotate(angle, center); } - fn scale(&mut self, scale: na::Vector2) { - self.rectangle.scale(scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.rectangle.scale(scale_stroke,scale_resize); } } diff --git a/crates/rnote-engine/src/strokes/textstroke.rs b/crates/rnote-engine/src/strokes/textstroke.rs index e524138ff8..0b175d5721 100644 --- a/crates/rnote-engine/src/strokes/textstroke.rs +++ b/crates/rnote-engine/src/strokes/textstroke.rs @@ -448,8 +448,8 @@ impl Transformable for TextStroke { self.transform.append_rotation_wrt_point_mut(angle, center); } - fn scale(&mut self, scale: na::Vector2) { - self.transform.append_scale_mut(scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.transform.append_scale_mut(scale_resize); } } diff --git a/crates/rnote-engine/src/strokes/vectorimage.rs b/crates/rnote-engine/src/strokes/vectorimage.rs index 5d4c2f83ee..0434e689c3 100644 --- a/crates/rnote-engine/src/strokes/vectorimage.rs +++ b/crates/rnote-engine/src/strokes/vectorimage.rs @@ -128,8 +128,8 @@ impl Transformable for VectorImage { self.rectangle.rotate(angle, center); } - fn scale(&mut self, scale: na::Vector2) { - self.rectangle.scale(scale); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + self.rectangle.scale(scale_stroke,scale_resize); } } From 0319ae0663b4e03a8c4efde12fa314658a875603 Mon Sep 17 00:00:00 2001 From: Doublonmousse <115779707+Doublonmousse@users.noreply.github.com> Date: Sun, 25 Feb 2024 11:49:57 +0100 Subject: [PATCH 6/8] update on selection change per element Still need to do : - transient bug for the stroke width ? - offset when resizing ? - change line scale for this resizing behavior ? - check limits on stroke width ? --- crates/rnote-compose/src/penpath/element.rs | 2 +- crates/rnote-compose/src/penpath/mod.rs | 6 +- crates/rnote-compose/src/penpath/segment.rs | 2 +- crates/rnote-compose/src/shapes/arrow.rs | 2 +- crates/rnote-compose/src/shapes/cubbez.rs | 2 +- crates/rnote-compose/src/shapes/ellipse.rs | 2 +- crates/rnote-compose/src/shapes/line.rs | 2 +- crates/rnote-compose/src/shapes/polygon.rs | 2 +- crates/rnote-compose/src/shapes/polyline.rs | 2 +- crates/rnote-compose/src/shapes/quadbez.rs | 2 +- crates/rnote-compose/src/shapes/rectangle.rs | 2 +- crates/rnote-compose/src/shapes/shape.rs | 18 ++--- crates/rnote-compose/src/style/mod.rs | 1 - .../src/style/smooth/smoothoptions.rs | 1 - crates/rnote-compose/src/transform/mod.rs | 2 +- .../src/transform/transformable.rs | 2 +- crates/rnote-engine/src/engine/mod.rs | 6 +- crates/rnote-engine/src/pens/selector/mod.rs | 2 +- .../src/pens/selector/penevents.rs | 65 +++++++++++-------- crates/rnote-engine/src/render.rs | 4 +- crates/rnote-engine/src/store/mod.rs | 2 +- .../rnote-engine/src/store/selection_comp.rs | 18 +++-- crates/rnote-engine/src/store/stroke_comp.rs | 16 +++-- .../rnote-engine/src/strokes/bitmapimage.rs | 4 +- .../rnote-engine/src/strokes/brushstroke.rs | 5 +- .../rnote-engine/src/strokes/shapestroke.rs | 7 +- crates/rnote-engine/src/strokes/stroke.rs | 18 ++--- crates/rnote-engine/src/strokes/textstroke.rs | 2 +- .../rnote-engine/src/strokes/vectorimage.rs | 4 +- 29 files changed, 110 insertions(+), 93 deletions(-) diff --git a/crates/rnote-compose/src/penpath/element.rs b/crates/rnote-compose/src/penpath/element.rs index 66f8844c09..0ae8e48a2c 100644 --- a/crates/rnote-compose/src/penpath/element.rs +++ b/crates/rnote-compose/src/penpath/element.rs @@ -32,7 +32,7 @@ impl Transformable for Element { self.pos = isometry.transform_point(&self.pos.into()).coords; } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.pos = self.pos.component_mul(&scale_resize); } } diff --git a/crates/rnote-compose/src/penpath/mod.rs b/crates/rnote-compose/src/penpath/mod.rs index 5cf864c32d..73977ccdd3 100644 --- a/crates/rnote-compose/src/penpath/mod.rs +++ b/crates/rnote-compose/src/penpath/mod.rs @@ -92,10 +92,10 @@ impl Transformable for PenPath { }); } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { - self.start.scale(scale_stroke,scale_resize); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { + self.start.scale(scale_stroke, scale_resize); self.segments.iter_mut().for_each(|segment| { - segment.scale(scale_stroke,scale_resize); + segment.scale(scale_stroke, scale_resize); }); } } diff --git a/crates/rnote-compose/src/penpath/segment.rs b/crates/rnote-compose/src/penpath/segment.rs index 41ea8c80e9..7e3bb04d0a 100644 --- a/crates/rnote-compose/src/penpath/segment.rs +++ b/crates/rnote-compose/src/penpath/segment.rs @@ -77,7 +77,7 @@ impl Transformable for Segment { } } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { match self { Self::LineTo { end } => { end.pos = end.pos.component_mul(&scale_resize); diff --git a/crates/rnote-compose/src/shapes/arrow.rs b/crates/rnote-compose/src/shapes/arrow.rs index dd955ec23d..5e9b400830 100644 --- a/crates/rnote-compose/src/shapes/arrow.rs +++ b/crates/rnote-compose/src/shapes/arrow.rs @@ -52,7 +52,7 @@ impl Transformable for Arrow { self.tip = isometry.transform_point(&self.tip.into()).coords; } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.start = self.start.component_mul(&scale_resize); self.tip = self.tip.component_mul(&scale_resize); } diff --git a/crates/rnote-compose/src/shapes/cubbez.rs b/crates/rnote-compose/src/shapes/cubbez.rs index 304de0f479..80c69ef69b 100644 --- a/crates/rnote-compose/src/shapes/cubbez.rs +++ b/crates/rnote-compose/src/shapes/cubbez.rs @@ -44,7 +44,7 @@ impl Transformable for CubicBezier { self.end = isometry.transform_point(&self.end.into()).coords; } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.start = self.start.component_mul(&scale_resize); self.cp1 = self.cp1.component_mul(&scale_resize); self.cp2 = self.cp2.component_mul(&scale_resize); diff --git a/crates/rnote-compose/src/shapes/ellipse.rs b/crates/rnote-compose/src/shapes/ellipse.rs index 5143b784d6..904c8e9482 100644 --- a/crates/rnote-compose/src/shapes/ellipse.rs +++ b/crates/rnote-compose/src/shapes/ellipse.rs @@ -38,7 +38,7 @@ impl Transformable for Ellipse { self.transform.append_rotation_wrt_point_mut(angle, center) } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.transform.append_scale_mut(scale_resize); } } diff --git a/crates/rnote-compose/src/shapes/line.rs b/crates/rnote-compose/src/shapes/line.rs index f655cdbdc7..3e1ea8a55a 100644 --- a/crates/rnote-compose/src/shapes/line.rs +++ b/crates/rnote-compose/src/shapes/line.rs @@ -34,7 +34,7 @@ impl Transformable for Line { self.end = isometry.transform_point(&self.end.into()).coords; } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.start = self.start.component_mul(&scale_resize); self.end = self.end.component_mul(&scale_resize); } diff --git a/crates/rnote-compose/src/shapes/polygon.rs b/crates/rnote-compose/src/shapes/polygon.rs index 83922d29a2..d713858060 100644 --- a/crates/rnote-compose/src/shapes/polygon.rs +++ b/crates/rnote-compose/src/shapes/polygon.rs @@ -35,7 +35,7 @@ impl Transformable for Polygon { } } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.start = self.start.component_mul(&scale_resize); for p in &mut self.path { *p = p.component_mul(&scale_resize); diff --git a/crates/rnote-compose/src/shapes/polyline.rs b/crates/rnote-compose/src/shapes/polyline.rs index c60fd0e54b..4f9c1d1395 100644 --- a/crates/rnote-compose/src/shapes/polyline.rs +++ b/crates/rnote-compose/src/shapes/polyline.rs @@ -35,7 +35,7 @@ impl Transformable for Polyline { } } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.start = self.start.component_mul(&scale_resize); for p in &mut self.path { *p = p.component_mul(&scale_resize); diff --git a/crates/rnote-compose/src/shapes/quadbez.rs b/crates/rnote-compose/src/shapes/quadbez.rs index 45aa9fe020..8c1d6487b4 100644 --- a/crates/rnote-compose/src/shapes/quadbez.rs +++ b/crates/rnote-compose/src/shapes/quadbez.rs @@ -39,7 +39,7 @@ impl Transformable for QuadraticBezier { self.end = isometry.transform_point(&self.end.into()).coords; } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.start = self.start.component_mul(&scale_resize); self.cp = self.cp.component_mul(&scale_resize); self.end = self.end.component_mul(&scale_resize); diff --git a/crates/rnote-compose/src/shapes/rectangle.rs b/crates/rnote-compose/src/shapes/rectangle.rs index 337c9d01d6..864e740b25 100644 --- a/crates/rnote-compose/src/shapes/rectangle.rs +++ b/crates/rnote-compose/src/shapes/rectangle.rs @@ -78,7 +78,7 @@ impl Transformable for Rectangle { self.transform.append_rotation_wrt_point_mut(angle, center) } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.transform.append_scale_mut(scale_resize); } } diff --git a/crates/rnote-compose/src/shapes/shape.rs b/crates/rnote-compose/src/shapes/shape.rs index 24e6f5a575..bdaf3ce67a 100644 --- a/crates/rnote-compose/src/shapes/shape.rs +++ b/crates/rnote-compose/src/shapes/shape.rs @@ -101,31 +101,31 @@ impl Transformable for Shape { } } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { match self { Self::Line(line) => { - line.scale(scale_stroke,scale_resize); + line.scale(scale_stroke, scale_resize); } Self::Arrow(arrow) => { - arrow.scale(scale_stroke,scale_resize); + arrow.scale(scale_stroke, scale_resize); } Self::Rectangle(rectangle) => { - rectangle.scale(scale_stroke,scale_resize); + rectangle.scale(scale_stroke, scale_resize); } Self::Ellipse(ellipse) => { - ellipse.scale(scale_stroke,scale_resize); + ellipse.scale(scale_stroke, scale_resize); } Self::QuadraticBezier(quadbez) => { - quadbez.scale(scale_stroke,scale_resize); + quadbez.scale(scale_stroke, scale_resize); } Self::CubicBezier(cubbez) => { - cubbez.scale(scale_stroke,scale_resize); + cubbez.scale(scale_stroke, scale_resize); } Self::Polyline(polyline) => { - polyline.scale(scale_stroke,scale_resize); + polyline.scale(scale_stroke, scale_resize); } Self::Polygon(polygon) => { - polygon.scale(scale_stroke,scale_resize); + polygon.scale(scale_stroke, scale_resize); } } } diff --git a/crates/rnote-compose/src/style/mod.rs b/crates/rnote-compose/src/style/mod.rs index 568a8c66cd..91d88a13f9 100644 --- a/crates/rnote-compose/src/style/mod.rs +++ b/crates/rnote-compose/src/style/mod.rs @@ -84,7 +84,6 @@ impl Style { } } - /// The margins for bounds which contain the shape. pub fn bounds_margin(&self) -> f64 { match self { diff --git a/crates/rnote-compose/src/style/smooth/smoothoptions.rs b/crates/rnote-compose/src/style/smooth/smoothoptions.rs index 8e1179e029..6d9d870ff8 100644 --- a/crates/rnote-compose/src/style/smooth/smoothoptions.rs +++ b/crates/rnote-compose/src/style/smooth/smoothoptions.rs @@ -22,7 +22,6 @@ pub struct SmoothOptions { /// Pressure curve. #[serde(rename = "pressure_curve")] pub pressure_curve: PressureCurve, - } impl Default for SmoothOptions { diff --git a/crates/rnote-compose/src/transform/mod.rs b/crates/rnote-compose/src/transform/mod.rs index 97c9514dc4..0ed76f27b9 100644 --- a/crates/rnote-compose/src/transform/mod.rs +++ b/crates/rnote-compose/src/transform/mod.rs @@ -50,7 +50,7 @@ impl Transformable for Transform { self.append_rotation_wrt_point_mut(angle, center); } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.append_scale_mut(scale_resize); } } diff --git a/crates/rnote-compose/src/transform/transformable.rs b/crates/rnote-compose/src/transform/transformable.rs index 13997c5107..43bf8e1821 100644 --- a/crates/rnote-compose/src/transform/transformable.rs +++ b/crates/rnote-compose/src/transform/transformable.rs @@ -5,5 +5,5 @@ pub trait Transformable { /// Rotate by the given angle (in radians). fn rotate(&mut self, angle: f64, center: na::Point2); /// Scale by the given scale-factor. - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2); } diff --git a/crates/rnote-engine/src/engine/mod.rs b/crates/rnote-engine/src/engine/mod.rs index b04e2a1e98..4f0c6a4ea9 100644 --- a/crates/rnote-engine/src/engine/mod.rs +++ b/crates/rnote-engine/src/engine/mod.rs @@ -838,9 +838,9 @@ impl Engine { let selection_keys = self.store.selection_keys_as_rendered(); self.store.initial_size_selection = match self.store.bounds_for_strokes(&selection_keys) { None => None, - Some(aabb) => Some(aabb.extents()) - }; - // self.store. + Some(aabb) => Some(aabb.extents()), + }; + // self.store. self.doc_resize_autoexpand() | self.record(Instant::now()) | self.update_rendering_current_viewport() diff --git a/crates/rnote-engine/src/pens/selector/mod.rs b/crates/rnote-engine/src/pens/selector/mod.rs index 31a131e179..7c83d4cdb0 100644 --- a/crates/rnote-engine/src/pens/selector/mod.rs +++ b/crates/rnote-engine/src/pens/selector/mod.rs @@ -529,7 +529,7 @@ impl Selector { fn rotate_node_sphere(selection_bounds: Aabb, camera: &Camera) -> BoundingSphere { let total_zoom = camera.total_zoom(); let pos = na::point![ - selection_bounds.maxs[0] + Self::RESIZE_NODE_SIZE[0]/(2.0*total_zoom), + selection_bounds.maxs[0] + Self::RESIZE_NODE_SIZE[0] / (2.0 * total_zoom), (selection_bounds.maxs[1] + selection_bounds.mins[1]) * 0.5 ]; BoundingSphere::new(pos, Self::ROTATE_NODE_DIAMETER * 0.5 / total_zoom) diff --git a/crates/rnote-engine/src/pens/selector/penevents.rs b/crates/rnote-engine/src/pens/selector/penevents.rs index 5508806414..b3c63ca0cf 100644 --- a/crates/rnote-engine/src/pens/selector/penevents.rs +++ b/crates/rnote-engine/src/pens/selector/penevents.rs @@ -99,12 +99,11 @@ impl Selector { // we need the ref to be added like the rest as well for the resize to work tracing::debug!("adding an element to the selection with shift"); - // copy the ghost value for the part that is already selected - engine_view - .store - .copy_ghost_stroke_width(selection); + // we change the size of the selection, we need to update the ghost stroke to the real stroke width + // in order not to have any issue here + engine_view.store.copy_ghost_stroke_width(selection); - engine_view.store.set_selected(key_to_add, true); + engine_view.store.set_selected(key_to_add, true); selection.push(key_to_add); if let Some(new_bounds) = engine_view.store.bounds_for_strokes(selection) @@ -188,11 +187,9 @@ impl Selector { // when clicking outside the selection bounds, reset // where we deselect from our resize tracing::debug!("resizing selection cancelled"); - + // copy ghost sizes - engine_view - .store - .copy_ghost_stroke_width(selection); + engine_view.store.copy_ghost_stroke_width(selection); engine_view.store.set_selected_keys(selection, false); self.state = SelectorState::Idle; @@ -335,34 +332,46 @@ impl Selector { offset_to_start = start_extents * (offset_mean / start_mean); } - let min_extents = na::vector![1e-2f64,1e-2f64]/engine_view.camera.total_zoom(); + let min_extents = + na::vector![1e-2f64, 1e-2f64] / engine_view.camera.total_zoom(); + + let min_multiplier = na::vector![1e-5f64, 1e-5f64]; // or limit stroke width into the general sizes limits + // check if this is the case or not let scale_stroke = (start_bounds.extents() + offset_to_start) - .maxs(&min_extents) - .component_div(&engine_view.store.initial_size_selection.unwrap()); // some dangerous unwrap here ... - + .component_div(&engine_view.store.initial_size_selection.unwrap()) + .maxs(&min_multiplier); // some dangerous unwrap here ... + let scale_resize = (start_bounds.extents() + offset_to_start) .maxs(&min_extents) .component_div(&selection_bounds.extents()); // some dangerous unwrap here ... - + // debug traces here just for info - tracing::debug!("start coordinates {:?}",start_bounds.extents() + offset_to_start); - tracing::debug!("coordinates maxes {:?}",min_extents); - tracing::debug!("size {:?}",selection_bounds.extents()); - tracing::debug!("scale {:?} {:?}", scale_stroke,scale_resize); + tracing::debug!( + "start coordinates {:?}", + start_bounds.extents() + offset_to_start + ); + tracing::debug!("coordinates maxes {:?}", min_extents); + tracing::debug!("size {:?}", selection_bounds.extents()); + tracing::debug!("scale {:?} {:?}", scale_stroke, scale_resize); // resize strokes // [5] : we do that on the width directly. Needs to change // but we have to have a "resize has finished" to be in place - engine_view - .store - .scale_strokes_with_pivot(selection, scale_stroke,scale_resize, pivot); // [4]. - // this should distinguish between end of resize and resize in progress - // we also need the original size of the elements in addition to their displayed sizes - // scale_strokes_with_pivot is also used in the resize_image part. So we need to copy the ghost values in that case (to do on merge) - - engine_view - .store - .scale_strokes_images_with_pivot(selection, scale_resize, pivot); + engine_view.store.scale_strokes_with_pivot( + selection, + scale_stroke, + scale_resize, + pivot, + ); // [4]. + // this should distinguish between end of resize and resize in progress + // we also need the original size of the elements in addition to their displayed sizes + // scale_strokes_with_pivot is also used in the resize_image part. So we need to copy the ghost values in that case (to do on merge) + + engine_view.store.scale_strokes_images_with_pivot( + selection, + scale_resize, + pivot, + ); *selection_bounds = selection_bounds .translate(-pivot) .scale_non_uniform(scale_resize) diff --git a/crates/rnote-engine/src/render.rs b/crates/rnote-engine/src/render.rs index 3cf6a200ff..54b8a9f4fe 100644 --- a/crates/rnote-engine/src/render.rs +++ b/crates/rnote-engine/src/render.rs @@ -169,8 +169,8 @@ impl Transformable for Image { self.rect.rotate(angle, center) } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { - self.rect.scale(scale_stroke,scale_resize) + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { + self.rect.scale(scale_stroke, scale_resize) } } diff --git a/crates/rnote-engine/src/store/mod.rs b/crates/rnote-engine/src/store/mod.rs index 6faac4494d..7516fd0540 100644 --- a/crates/rnote-engine/src/store/mod.rs +++ b/crates/rnote-engine/src/store/mod.rs @@ -116,7 +116,7 @@ impl Default for StrokeStore { key_tree: KeyTree::default(), chrono_counter: 0, - initial_size_selection:None, + initial_size_selection: None, } } } diff --git a/crates/rnote-engine/src/store/selection_comp.rs b/crates/rnote-engine/src/store/selection_comp.rs index f173849742..556ce2d094 100644 --- a/crates/rnote-engine/src/store/selection_comp.rs +++ b/crates/rnote-engine/src/store/selection_comp.rs @@ -51,6 +51,17 @@ impl StrokeStore { { selection_comp.selected = selected; + // update selection bounds for each + let selection_keys = self.selection_keys_as_rendered(); + + self.initial_size_selection = match self.bounds_for_strokes(&selection_keys) { + None => None, + Some(aabb) => Some(aabb.extents()), + }; + // copy if selected or deselected (either way) + self.copy_ghost_stroke_width(&[key]); + // update + self.update_chrono_to_last(key); } } @@ -60,13 +71,6 @@ impl StrokeStore { self.set_selected(key, selected); }); // update selection bounds - // duplicate ? - let selection_keys = self.selection_keys_as_rendered(); - - self.initial_size_selection = match self.bounds_for_strokes(&selection_keys) { - None => None, - Some(aabb) => Some(aabb.extents()) - }; } pub(crate) fn selection_keys_unordered(&self) -> Vec { diff --git a/crates/rnote-engine/src/store/stroke_comp.rs b/crates/rnote-engine/src/store/stroke_comp.rs index f004a6d086..6606e45681 100644 --- a/crates/rnote-engine/src/store/stroke_comp.rs +++ b/crates/rnote-engine/src/store/stroke_comp.rs @@ -395,7 +395,12 @@ impl StrokeStore { /// Scale the strokes with the factor. /// /// The strokes then need to update their rendering. - pub(crate) fn scale_strokes(&mut self, keys: &[StrokeKey],scale_stroke: na::Vector2, scale_resize:na::Vector2) { + pub(crate) fn scale_strokes( + &mut self, + keys: &[StrokeKey], + scale_stroke: na::Vector2, + scale_resize: na::Vector2, + ) { // [3] one level upper keys.iter().for_each(|&key| { if let Some(stroke) = Arc::make_mut(&mut self.stroke_components) @@ -404,7 +409,7 @@ impl StrokeStore { { { // rotate the stroke geometry - stroke.scale(scale_stroke,scale_resize); // our problem down the line + stroke.scale(scale_stroke, scale_resize); // our problem down the line self.key_tree.update_with_key(key, stroke.bounds()); } } @@ -418,12 +423,11 @@ impl StrokeStore { .get_mut(key) .map(Arc::make_mut) { - stroke.copy_ghost_stroke_width(); + stroke.copy_ghost_stroke_width(); // some un neccessary call onto nothing, pattern match here instead ? } }) - } - + } /// Scale the stroke rendering images. /// @@ -462,7 +466,7 @@ impl StrokeStore { ) { // [4] self.translate_strokes(keys, -pivot); - self.scale_strokes(keys, scale_stroke,scale_resize); + self.scale_strokes(keys, scale_stroke, scale_resize); self.translate_strokes(keys, pivot); } diff --git a/crates/rnote-engine/src/strokes/bitmapimage.rs b/crates/rnote-engine/src/strokes/bitmapimage.rs index df4b91c3dc..d6d09f78a8 100644 --- a/crates/rnote-engine/src/strokes/bitmapimage.rs +++ b/crates/rnote-engine/src/strokes/bitmapimage.rs @@ -91,8 +91,8 @@ impl Transformable for BitmapImage { self.rectangle.rotate(angle, center); } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { - self.rectangle.scale(scale_stroke,scale_resize); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { + self.rectangle.scale(scale_stroke, scale_resize); } } diff --git a/crates/rnote-engine/src/strokes/brushstroke.rs b/crates/rnote-engine/src/strokes/brushstroke.rs index 317d1df290..44aff3d498 100644 --- a/crates/rnote-engine/src/strokes/brushstroke.rs +++ b/crates/rnote-engine/src/strokes/brushstroke.rs @@ -255,10 +255,11 @@ impl Transformable for BrushStroke { fn rotate(&mut self, angle: f64, center: na::Point2) { self.path.rotate(angle, center); } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { // [0] - self.path.scale(scale_stroke,scale_resize); + self.path.scale(scale_stroke, scale_resize); let scale_uniform = (scale_stroke[0] + scale_stroke[1]) / 2.; + // let scale_uniform = 1.0f64; self.style // .set_stroke_width(self.style.stroke_width() * scale_uniform); .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); diff --git a/crates/rnote-engine/src/strokes/shapestroke.rs b/crates/rnote-engine/src/strokes/shapestroke.rs index ad3b3246d1..ca0c0529b3 100644 --- a/crates/rnote-engine/src/strokes/shapestroke.rs +++ b/crates/rnote-engine/src/strokes/shapestroke.rs @@ -91,12 +91,13 @@ impl Transformable for ShapeStroke { fn rotate(&mut self, angle: f64, center: na::Point2) { self.shape.rotate(angle, center); } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { // [2] // should be called for transformations (selection tool) and the new resize mechanisms // but in all cases the end thing is selected so everything resynced on deselecting - self.shape.scale(scale_stroke,scale_resize); + self.shape.scale(scale_stroke, scale_resize); let scale_uniform = (scale_stroke[0] + scale_stroke[1]) / 2.; + // let scale_uniform = 1.0f64; self.style // .set_stroke_width(self.style.stroke_width() * scale_uniform); .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); @@ -125,7 +126,7 @@ impl ShapeStroke { .collect() } - pub fn copy_ghost_stroke_width(&mut self){ + pub fn copy_ghost_stroke_width(&mut self) { self.style.copy_ghost_stroke_width(); } } diff --git a/crates/rnote-engine/src/strokes/stroke.rs b/crates/rnote-engine/src/strokes/stroke.rs index 02a2dd0049..b88a40a79d 100644 --- a/crates/rnote-engine/src/strokes/stroke.rs +++ b/crates/rnote-engine/src/strokes/stroke.rs @@ -179,25 +179,25 @@ impl Transformable for Stroke { } } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { // [2] one level upper, calls to that here match self { Self::BrushStroke(brushstroke) => { // [1] - brushstroke.scale(scale_stroke,scale_resize); + brushstroke.scale(scale_stroke, scale_resize); } Self::ShapeStroke(shapestroke) => { // [1] - shapestroke.scale(scale_stroke,scale_resize); + shapestroke.scale(scale_stroke, scale_resize); } Self::TextStroke(textstroke) => { - textstroke.scale(scale_stroke,scale_resize); + textstroke.scale(scale_stroke, scale_resize); } Self::VectorImage(vectorimage) => { - vectorimage.scale(scale_stroke,scale_resize); + vectorimage.scale(scale_stroke, scale_resize); } Self::BitmapImage(bitmapimage) => { - bitmapimage.scale(scale_stroke,scale_resize); + bitmapimage.scale(scale_stroke, scale_resize); } } } @@ -675,7 +675,7 @@ impl Stroke { } } - /// Copy the ghost value + /// Copy the ghost value pub fn copy_ghost_stroke_width(&mut self) { // [2] one level upper, calls to that here match self { @@ -688,8 +688,8 @@ impl Stroke { shapestroke.copy_ghost_stroke_width(); } _ => { - // do nothing - } + // do nothing + } } } } diff --git a/crates/rnote-engine/src/strokes/textstroke.rs b/crates/rnote-engine/src/strokes/textstroke.rs index 0b175d5721..533c1e723f 100644 --- a/crates/rnote-engine/src/strokes/textstroke.rs +++ b/crates/rnote-engine/src/strokes/textstroke.rs @@ -448,7 +448,7 @@ impl Transformable for TextStroke { self.transform.append_rotation_wrt_point_mut(angle, center); } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { self.transform.append_scale_mut(scale_resize); } } diff --git a/crates/rnote-engine/src/strokes/vectorimage.rs b/crates/rnote-engine/src/strokes/vectorimage.rs index 0434e689c3..c1f4dbef24 100644 --- a/crates/rnote-engine/src/strokes/vectorimage.rs +++ b/crates/rnote-engine/src/strokes/vectorimage.rs @@ -128,8 +128,8 @@ impl Transformable for VectorImage { self.rectangle.rotate(angle, center); } - fn scale(&mut self, scale_stroke: na::Vector2, scale_resize:na::Vector2) { - self.rectangle.scale(scale_stroke,scale_resize); + fn scale(&mut self, scale_stroke: na::Vector2, scale_resize: na::Vector2) { + self.rectangle.scale(scale_stroke, scale_resize); } } From 38ab8e27205c97f7a268c609d39448e79f00453a Mon Sep 17 00:00:00 2001 From: Doublonmousse <115779707+Doublonmousse@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:19:12 +0100 Subject: [PATCH 7/8] debugging changes --- crates/rnote-compose/src/style/mod.rs | 5 ++- .../src/pens/selector/penevents.rs | 35 +++++++++++++++---- .../rnote-engine/src/strokes/brushstroke.rs | 4 +++ .../rnote-engine/src/strokes/shapestroke.rs | 4 +++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/crates/rnote-compose/src/style/mod.rs b/crates/rnote-compose/src/style/mod.rs index 91d88a13f9..eda1254a39 100644 --- a/crates/rnote-compose/src/style/mod.rs +++ b/crates/rnote-compose/src/style/mod.rs @@ -66,7 +66,10 @@ impl Style { /// Set the stroke width. Available on all styles. pub fn set_stroke_width(&mut self, stroke_width: f64) { - // problem : options.stroke_width of style elements as these are set on resize, not w.r.t the start position + // seemingly no limit on the stroke width here ... + // maybe we should (can get arbitrarly large or small from the resize alone) + // one idea would be : set a min and max and clip here + // second idea : scale limits based on the ghost stroke width and scale quantities match self { Style::Smooth(options) => options.stroke_width = stroke_width, Style::Rough(options) => options.stroke_width = stroke_width, diff --git a/crates/rnote-engine/src/pens/selector/penevents.rs b/crates/rnote-engine/src/pens/selector/penevents.rs index b3c63ca0cf..8e845e0e47 100644 --- a/crates/rnote-engine/src/pens/selector/penevents.rs +++ b/crates/rnote-engine/src/pens/selector/penevents.rs @@ -332,24 +332,45 @@ impl Selector { offset_to_start = start_extents * (offset_mean / start_mean); } - let min_extents = - na::vector![1e-2f64, 1e-2f64] / engine_view.camera.total_zoom(); + // need to set more reasonable defaults for min size (based on stroke width ? + actual size, NOT just min and max multipliers) + // find why this issue only occurs when we start having negative values for the start coordinates + // a.k.a. the start_bounds.extents() + offset_to_start + + // affect only scale_resize + let min_extents = na::vector![ + 1e-2f64 / selection_bounds.extents().x, + 1e-2f64 / selection_bounds.extents().y + ]; + let hundred_lim = na::vector![5f64, 5f64]; // in a frame, noticeable ? + // 2 : 9 frames to catch up + // 5 : 4 frames to catch up if 100 jump + let set_positive = na::vector![1e-15f64, 1e-15f64]; + + let scale_resize = (start_bounds.extents() + offset_to_start) + .maxs(&set_positive) // force positive before division + .component_div(&selection_bounds.extents()) // some dangerous unwrap here ... + .map(|x| if !x.is_finite() { 0.0f64 } else { x }) + .maxs(&min_extents); //apply the extent and then we should not be smaller than 0.01 in either directions + //.mins(&hundred_lim); // for now commented, would bound the max resize factor + + // only affects stroke width here let min_multiplier = na::vector![1e-5f64, 1e-5f64]; // or limit stroke width into the general sizes limits - // check if this is the case or not + // check if this is the case or not : NOT checked let scale_stroke = (start_bounds.extents() + offset_to_start) .component_div(&engine_view.store.initial_size_selection.unwrap()) .maxs(&min_multiplier); // some dangerous unwrap here ... - let scale_resize = (start_bounds.extents() + offset_to_start) - .maxs(&min_extents) - .component_div(&selection_bounds.extents()); // some dangerous unwrap here ... - // debug traces here just for info tracing::debug!( "start coordinates {:?}", start_bounds.extents() + offset_to_start ); + tracing::debug!( + "initial size {:?}", + engine_view.store.initial_size_selection + ); + tracing::debug!("selection bounds {:?}", selection_bounds.extents()); tracing::debug!("coordinates maxes {:?}", min_extents); tracing::debug!("size {:?}", selection_bounds.extents()); tracing::debug!("scale {:?} {:?}", scale_stroke, scale_resize); diff --git a/crates/rnote-engine/src/strokes/brushstroke.rs b/crates/rnote-engine/src/strokes/brushstroke.rs index 44aff3d498..6859427913 100644 --- a/crates/rnote-engine/src/strokes/brushstroke.rs +++ b/crates/rnote-engine/src/strokes/brushstroke.rs @@ -263,6 +263,10 @@ impl Transformable for BrushStroke { self.style // .set_stroke_width(self.style.stroke_width() * scale_uniform); .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); + tracing::debug!( + "stroke width {:?}", + self.style.stroke_width_ghost() * scale_uniform + ); } } diff --git a/crates/rnote-engine/src/strokes/shapestroke.rs b/crates/rnote-engine/src/strokes/shapestroke.rs index ca0c0529b3..01dee464b7 100644 --- a/crates/rnote-engine/src/strokes/shapestroke.rs +++ b/crates/rnote-engine/src/strokes/shapestroke.rs @@ -101,6 +101,10 @@ impl Transformable for ShapeStroke { self.style // .set_stroke_width(self.style.stroke_width() * scale_uniform); .set_stroke_width(self.style.stroke_width_ghost() * scale_uniform); + tracing::debug!( + "stroke width {:?}", + self.style.stroke_width_ghost() * scale_uniform + ); } } From 5fe38f1f8f16c32bf7a1561f470e0aa9dfe9955a Mon Sep 17 00:00:00 2001 From: Doublonmousse <115779707+Doublonmousse@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:28:57 +0100 Subject: [PATCH 8/8] more debug traces for sizes --- crates/rnote-engine/src/pens/selector/penevents.rs | 6 ++++++ crates/rnote-engine/src/render.rs | 2 ++ crates/rnote-engine/src/strokes/content.rs | 6 +++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/rnote-engine/src/pens/selector/penevents.rs b/crates/rnote-engine/src/pens/selector/penevents.rs index 8e845e0e47..4acfc92445 100644 --- a/crates/rnote-engine/src/pens/selector/penevents.rs +++ b/crates/rnote-engine/src/pens/selector/penevents.rs @@ -353,6 +353,10 @@ impl Selector { .map(|x| if !x.is_finite() { 0.0f64 } else { x }) .maxs(&min_extents); //apply the extent and then we should not be smaller than 0.01 in either directions //.mins(&hundred_lim); // for now commented, would bound the max resize factor + + if scale_resize.x > 2.0f64 || scale_resize.y > 2.0f64 { + tracing::debug!("large resize that could activate that intermittent stretched image"); + } // only affects stroke width here let min_multiplier = na::vector![1e-5f64, 1e-5f64]; // or limit stroke width into the general sizes limits @@ -403,6 +407,8 @@ impl Selector { .camera .nudge_w_pos(element.pos, engine_view.document); widget_flags |= engine_view.document.expand_autoexpand(engine_view.camera); + + tracing::debug!("regenerate rendering viewport"); engine_view.store.regenerate_rendering_in_viewport_threaded( engine_view.tasks_tx.clone(), false, diff --git a/crates/rnote-engine/src/render.rs b/crates/rnote-engine/src/render.rs index 54b8a9f4fe..400df0036a 100644 --- a/crates/rnote-engine/src/render.rs +++ b/crates/rnote-engine/src/render.rs @@ -306,6 +306,8 @@ impl Image { let width_scaled = ((bounds.extents()[0]) * image_scale).round() as u32; let height_scaled = ((bounds.extents()[1]) * image_scale).round() as u32; + tracing::debug!("render width {:?} {:?}", width_scaled, height_scaled); + let mut image_surface = cairo::ImageSurface::create( cairo::Format::ARgb32, width_scaled as i32, diff --git a/crates/rnote-engine/src/strokes/content.rs b/crates/rnote-engine/src/strokes/content.rs index 1594bd991b..62084eb537 100644 --- a/crates/rnote-engine/src/strokes/content.rs +++ b/crates/rnote-engine/src/strokes/content.rs @@ -42,9 +42,11 @@ where viewport: Aabb, image_scale: f64, ) -> Result { - let bounds = self.bounds(); + let bounds = self.bounds(); //check the bounds of the shape here + tracing::debug!("bounds for shapes as seen by gen_images {:?}", bounds); if viewport.contains(&bounds) { + tracing::debug!("element in viewport"); Ok(GeneratedContentImages::Full(vec![ render::Image::gen_with_piet( |piet_cx| self.draw(piet_cx, image_scale), @@ -53,6 +55,7 @@ where )?, ])) } else if let Some(intersection_bounds) = viewport.intersection(&bounds) { + tracing::debug!("intersection"); Ok(GeneratedContentImages::Partial { images: vec![render::Image::gen_with_piet( |piet_cx| self.draw(piet_cx, image_scale), @@ -62,6 +65,7 @@ where viewport, }) } else { + tracing::debug!("out of bounds"); Ok(GeneratedContentImages::Partial { images: vec![], viewport,