Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8c03cdb
added buttons to UI with preliminary icons
podzolelements Aug 3, 2025
d543167
horizontal mirroring is functional for BrushStrokes
podzolelements Aug 3, 2025
039277e
center horizontal mirrors on selection area, not individual strokes
podzolelements Aug 3, 2025
761ede0
horizontal mirroring of ShapeStrokes is fully functional
podzolelements Aug 4, 2025
8555e6d
apply code formatting rules, no functional changes
podzolelements Aug 4, 2025
a5c3d41
horizontal mirroring functional on both bitmapped and vector images
podzolelements Aug 5, 2025
1eaaff6
vertical mirroring fully implemented
podzolelements Aug 6, 2025
a40d12a
update icons
podzolelements Aug 7, 2025
bd036d3
condense mirror_stroke_* functions with orientation parameter
podzolelements Aug 21, 2025
7fe6cc3
move point mirroring functions into rnote-compose
podzolelements Aug 21, 2025
0f64659
move affine matrix transformations into Transform
podzolelements Aug 22, 2025
d95cbb4
add mirroring to Segments and Elements; internalize PenPath mirroring
podzolelements Aug 22, 2025
ee8fd4d
move mirroring logic out of Stroke for point-based shapes
podzolelements Aug 22, 2025
9036e09
add mirroring for transform-based shapes
podzolelements Aug 22, 2025
01d37ce
add direct mirroring to BrushStrokes
podzolelements Aug 22, 2025
fa56d6f
add mirroring as an operation to the Transformable trait
podzolelements Aug 22, 2025
5061f26
condense Transformable mirror functions with orientation paremeter
podzolelements Aug 23, 2025
27bb53a
add orientation based mirror_point
podzolelements Aug 23, 2025
bff1482
fix code style, no functional changes
podzolelements Aug 24, 2025
a1b167f
prevent mirror operations with TextStrokes selected
podzolelements Aug 25, 2025
019285a
add keyboard shortcuts
podzolelements Aug 26, 2025
af9d5d0
change keyboard shortcuts and bind them to gtk accels
podzolelements Aug 26, 2025
9a63a48
modify WidgetFlags to send a popup message to the user
podzolelements Aug 26, 2025
e7322e0
relocate gettext call
podzolelements Aug 27, 2025
4159527
properly update stroke geometry
podzolelements Aug 27, 2025
53da69d
move WidgetFlags text popup proccessing into rnote-ui
podzolelements Aug 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/rnote-compose/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pub mod ext;
pub mod penevent;
/// module for pen paths
pub mod penpath;
/// module for misc operations on points
pub mod point_utils;
/// utilities for serializing / deserializing
pub mod serialize;
/// module for shapes
Expand Down
9 changes: 8 additions & 1 deletion crates/rnote-compose/src/penpath/element.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// Imports
use crate::transform::Transformable;
use crate::{
point_utils,
transform::{MirrorOrientation, Transformable},
};
use p2d::bounding_volume::Aabb;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -35,6 +38,10 @@ impl Transformable for Element {
fn scale(&mut self, scale: na::Vector2<f64>) {
self.pos = self.pos.component_mul(&scale);
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
point_utils::mirror_point(&mut self.pos, centerline, orientation);
}
}

impl Element {
Expand Down
10 changes: 9 additions & 1 deletion crates/rnote-compose/src/penpath/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub use segment::Segment;
// Imports
use crate::ext::{KurboShapeExt, Vector2Ext};
use crate::shapes::{CubicBezier, Line, QuadraticBezier, Shapeable};
use crate::transform::Transformable;
use crate::transform::{MirrorOrientation, Transformable};
use kurbo::Shape;
use p2d::bounding_volume::{Aabb, BoundingVolume};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -98,6 +98,14 @@ impl Transformable for PenPath {
segment.scale(scale);
});
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
self.start.mirror(centerline, orientation);

self.segments.iter_mut().for_each(|element| {
element.mirror(centerline, orientation);
});
}
}

impl PenPath {
Expand Down
22 changes: 21 additions & 1 deletion crates/rnote-compose/src/penpath/segment.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Imports
use super::Element;
use crate::transform::Transformable;
use crate::{
point_utils,
transform::{MirrorOrientation, Transformable},
};
use serde::{Deserialize, Serialize};

/// A single segment, usually of a pen path.
Expand Down Expand Up @@ -93,6 +96,23 @@ impl Transformable for Segment {
}
}
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
match self {
Segment::LineTo { end } => {
end.mirror(centerline, orientation);
}
Segment::QuadBezTo { cp, end } => {
point_utils::mirror_point(cp, centerline, orientation);
end.mirror(centerline, orientation);
}
Segment::CubBezTo { cp1, cp2, end } => {
point_utils::mirror_point(cp1, centerline, orientation);
point_utils::mirror_point(cp2, centerline, orientation);
end.mirror(centerline, orientation);
}
}
}
}

impl Segment {
Expand Down
27 changes: 27 additions & 0 deletions crates/rnote-compose/src/point_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::transform::MirrorOrientation;

/// horizontally mirrors point around line 'x = centerline_x'
pub fn mirror_point_x(point: &mut na::Vector2<f64>, centerline_x: f64) {
point.x -= centerline_x;
point.x *= -1.0;
point.x += centerline_x;
}

/// vertically mirrors point around line 'y = centerline_y'
pub fn mirror_point_y(point: &mut na::Vector2<f64>, centerline_y: f64) {
point.y -= centerline_y;
point.y *= -1.0;
point.y += centerline_y;
}

/// mirror point around either Horizontal: 'x = centerline' or Vertical: 'y = centerline' line
pub fn mirror_point(point: &mut na::Vector2<f64>, centerline: f64, orientation: MirrorOrientation) {
match orientation {
MirrorOrientation::Horizontal => {
mirror_point_x(point, centerline);
}
MirrorOrientation::Vertical => {
mirror_point_y(point, centerline);
}
}
}
9 changes: 7 additions & 2 deletions crates/rnote-compose/src/shapes/arrow.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Imports
use super::Line;
use crate::ext::Vector2Ext;
use crate::shapes::Shapeable;
use crate::transform::Transformable;
use crate::transform::{MirrorOrientation, Transformable};
use crate::{ext::Vector2Ext, point_utils};
use kurbo::{PathEl, Shape};
use na::Rotation2;
use p2d::bounding_volume::Aabb;
Expand Down Expand Up @@ -56,6 +56,11 @@ impl Transformable for Arrow {
self.start = self.start.component_mul(&scale);
self.tip = self.tip.component_mul(&scale);
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
point_utils::mirror_point(&mut self.start, centerline, orientation);
point_utils::mirror_point(&mut self.tip, centerline, orientation);
}
}

impl Shapeable for Arrow {
Expand Down
9 changes: 8 additions & 1 deletion crates/rnote-compose/src/shapes/cubbez.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
use super::line::Line;
use super::quadbez::QuadraticBezier;
use crate::ext::{KurboShapeExt, Vector2Ext};
use crate::point_utils;
use crate::shapes::Shapeable;
use crate::transform::Transformable;
use crate::transform::{MirrorOrientation, Transformable};
use kurbo::Shape;
use p2d::bounding_volume::Aabb;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -50,6 +51,12 @@ impl Transformable for CubicBezier {
self.cp2 = self.cp2.component_mul(&scale);
self.end = self.end.component_mul(&scale);
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
for point in [&mut self.start, &mut self.cp1, &mut self.cp2, &mut self.end] {
point_utils::mirror_point(point, centerline, orientation);
}
}
}

impl Shapeable for CubicBezier {
Expand Down
6 changes: 5 additions & 1 deletion crates/rnote-compose/src/shapes/ellipse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::Line;
use crate::Transform;
use crate::ext::{Affine2Ext, Vector2Ext};
use crate::shapes::Shapeable;
use crate::transform::Transformable;
use crate::transform::{MirrorOrientation, Transformable};
use kurbo::Shape;
use p2d::bounding_volume::Aabb;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -41,6 +41,10 @@ impl Transformable for Ellipse {
fn scale(&mut self, scale: na::Vector2<f64>) {
self.transform.append_scale_mut(scale);
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
self.transform.append_mirror_mut(centerline, orientation);
}
}

impl Shapeable for Ellipse {
Expand Down
9 changes: 7 additions & 2 deletions crates/rnote-compose/src/shapes/line.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Imports
use crate::Transform;
use crate::ext::{AabbExt, Vector2Ext};
use crate::shapes::Rectangle;
use crate::shapes::Shapeable;
use crate::transform::Transformable;
use crate::transform::{MirrorOrientation, Transformable};
use crate::{Transform, point_utils};
use kurbo::Shape;
use p2d::bounding_volume::Aabb;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -38,6 +38,11 @@ impl Transformable for Line {
self.start = self.start.component_mul(&scale);
self.end = self.end.component_mul(&scale);
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
point_utils::mirror_point(&mut self.start, centerline, orientation);
point_utils::mirror_point(&mut self.end, centerline, orientation);
}
}

impl Shapeable for Line {
Expand Down
11 changes: 10 additions & 1 deletion crates/rnote-compose/src/shapes/polygon.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Imports
use super::{Line, Shapeable};
use crate::ext::{AabbExt, Vector2Ext};
use crate::transform::Transformable;
use crate::point_utils;
use crate::transform::{MirrorOrientation, Transformable};
use p2d::bounding_volume::Aabb;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -41,6 +42,14 @@ impl Transformable for Polygon {
*p = p.component_mul(&scale);
}
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
point_utils::mirror_point(&mut self.start, centerline, orientation);

self.path.iter_mut().for_each(|point| {
point_utils::mirror_point(point, centerline, orientation);
});
}
}

impl Shapeable for Polygon {
Expand Down
12 changes: 10 additions & 2 deletions crates/rnote-compose/src/shapes/polyline.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Imports
use super::{Line, Shapeable};
use crate::ext::Vector2Ext;
use crate::transform::Transformable;
use crate::transform::{MirrorOrientation, Transformable};
use crate::{ext::Vector2Ext, point_utils};
use p2d::bounding_volume::Aabb;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -41,6 +41,14 @@ impl Transformable for Polyline {
*p = p.component_mul(&scale);
}
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
point_utils::mirror_point(&mut self.start, centerline, orientation);

self.path.iter_mut().for_each(|point| {
point_utils::mirror_point(point, centerline, orientation);
});
}
}

impl Shapeable for Polyline {
Expand Down
9 changes: 8 additions & 1 deletion crates/rnote-compose/src/shapes/quadbez.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
use super::CubicBezier;
use super::line::Line;
use crate::ext::{KurboShapeExt, Vector2Ext};
use crate::point_utils;
use crate::shapes::Shapeable;
use crate::transform::Transformable;
use crate::transform::{MirrorOrientation, Transformable};
use kurbo::Shape;
use p2d::bounding_volume::Aabb;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -44,6 +45,12 @@ impl Transformable for QuadraticBezier {
self.cp = self.cp.component_mul(&scale);
self.end = self.end.component_mul(&scale);
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
for point in [&mut self.start, &mut self.cp, &mut self.end] {
point_utils::mirror_point(point, centerline, orientation);
}
}
}

impl Shapeable for QuadraticBezier {
Expand Down
6 changes: 5 additions & 1 deletion crates/rnote-compose/src/shapes/rectangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::Line;
use crate::Transform;
use crate::ext::{AabbExt, Vector2Ext};
use crate::shapes::Shapeable;
use crate::transform::Transformable;
use crate::transform::{MirrorOrientation, Transformable};
use p2d::bounding_volume::Aabb;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -81,6 +81,10 @@ impl Transformable for Rectangle {
fn scale(&mut self, scale: na::Vector2<f64>) {
self.transform.append_scale_mut(scale);
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
self.transform.mirror(centerline, orientation);
}
}

impl Rectangle {
Expand Down
31 changes: 30 additions & 1 deletion crates/rnote-compose/src/shapes/shape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use super::{
Arrow, CubicBezier, Ellipse, Line, Polygon, Polyline, QuadraticBezier, Rectangle, Shapeable,
};
use crate::transform::Transformable;
use crate::transform::{MirrorOrientation, Transformable};
use p2d::bounding_volume::Aabb;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -129,6 +129,35 @@ impl Transformable for Shape {
}
}
}

fn mirror(&mut self, centerline: f64, orientation: MirrorOrientation) {
match self {
Self::Line(line) => {
line.mirror(centerline, orientation);
}
Self::Arrow(arrow) => {
arrow.mirror(centerline, orientation);
}
Self::Rectangle(rectangle) => {
rectangle.mirror(centerline, orientation);
}
Self::Ellipse(ellipse) => {
ellipse.mirror(centerline, orientation);
}
Self::QuadraticBezier(quadratic_bezier) => {
quadratic_bezier.mirror(centerline, orientation);
}
Self::CubicBezier(cubic_bezier) => {
cubic_bezier.mirror(centerline, orientation);
}
Self::Polyline(polyline) => {
polyline.mirror(centerline, orientation);
}
Self::Polygon(polygon) => {
polygon.mirror(centerline, orientation);
}
}
}
}

impl Shapeable for Shape {
Expand Down
Loading