From 7fc3cfa06a25d92f54f53c9be4ef92dd66d3e959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Zl=C3=A1mal?= Date: Wed, 2 Jul 2025 21:55:25 +0200 Subject: [PATCH 1/3] Implemented new pen "Insert Pen". When stroke is created using this pen, items on page below first point of stroke are moved up/down by the vertical length of stroke. Can be used to create free vertical space on page (or remove it). When moved items do not fit to page, its height is enlarged to hold all items --- lib/components/canvas/_stroke.dart | 3 +++ lib/components/toolbar/pen_modal.dart | 20 ++++++++++++++++++++ lib/data/editor/page.dart | 2 +- lib/data/tools/_tool.dart | 1 + lib/data/tools/pen.dart | 13 +++++++++++++ 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/components/canvas/_stroke.dart b/lib/components/canvas/_stroke.dart index 10e1ffd71a..707e2e90a0 100644 --- a/lib/components/canvas/_stroke.dart +++ b/lib/components/canvas/_stroke.dart @@ -277,6 +277,9 @@ class Stroke { double get maxY { return points.isEmpty ? 0 : points.map((point) => point.y).reduce(max); } + double get minY { + return points.isEmpty ? 0 : points.map((point) => point.y).reduce(min); + } RecognizedUnistroke? detectShape() { if (points.length < 3) return null; diff --git a/lib/components/toolbar/pen_modal.dart b/lib/components/toolbar/pen_modal.dart index 8cfa1737e7..09d1661cdb 100644 --- a/lib/components/toolbar/pen_modal.dart +++ b/lib/components/toolbar/pen_modal.dart @@ -125,6 +125,26 @@ class _PenModalState extends State { tooltip: t.editor.pens.shapePen, icon: const FaIcon(ShapePen.shapePenIcon), ), + const SizedBox.square(dimension: 8), + IconButton( + onPressed: () => setState(() { + widget.setTool(Pen.insertPen()); + }), + style: TextButton.styleFrom( + foregroundColor: Pen.currentPen.icon == Pen.insertPenIcon + ? Theme.of(context).colorScheme.secondary + : Theme.of(context).colorScheme.onSurface, + backgroundColor: Pen.currentPen.icon == Pen.insertPenIcon + ? Theme.of(context) + .colorScheme + .secondary + .withValues(alpha: 0.1) + : Colors.transparent, + shape: const CircleBorder(), + ), + tooltip: t.editor.pens.insertPen, + icon: const FaIcon(Pen.insertPenIcon), + ), ], ], ); diff --git a/lib/data/editor/page.dart b/lib/data/editor/page.dart index a8c1da5db2..846f5aed2f 100644 --- a/lib/data/editor/page.dart +++ b/lib/data/editor/page.dart @@ -25,7 +25,7 @@ class EditorPage extends Listenable implements HasSize { static const Size defaultSize = Size(defaultWidth, defaultHeight); @override - final Size size; + Size size; late final CanvasKey innerCanvasKey = CanvasKey(); RenderBox? _renderBox; diff --git a/lib/data/tools/_tool.dart b/lib/data/tools/_tool.dart index 1fb397e5b7..0d841ca8ad 100644 --- a/lib/data/tools/_tool.dart +++ b/lib/data/tools/_tool.dart @@ -23,6 +23,7 @@ class _TextEditingTool extends Tool { enum ToolId { fountainPen('fountainPen'), ballpointPen('ballpointPen'), + insertPen('insertPen'), highlighter('Highlighter'), pencil('Pencil'), shapePen('ShapePen'), diff --git a/lib/data/tools/pen.dart b/lib/data/tools/pen.dart index 308a10f3b4..1a8f4fe3c1 100644 --- a/lib/data/tools/pen.dart +++ b/lib/data/tools/pen.dart @@ -46,6 +46,18 @@ class Pen extends Tool { color = Color(Prefs.lastBallpointPenColor.value), toolId = ToolId.ballpointPen; + Pen.insertPen() + : name = t.editor.pens.insertPen, + sizeMin = 1, + sizeMax = 25, + sizeStep = 1, + icon = insertPenIcon, + options = Prefs.lastBallpointPenOptions.value, + pressureEnabled = false, + color = Color(Prefs.lastBallpointPenColor.value), + toolId = ToolId.insertPen; + + final String name; final double sizeMin, sizeMax, sizeStep; late final int sizeStepsBetweenMinAndMax = @@ -57,6 +69,7 @@ class Pen extends Tool { static const IconData fountainPenIcon = FontAwesomeIcons.penFancy; static const IconData ballpointPenIcon = FontAwesomeIcons.pen; + static const IconData insertPenIcon = FontAwesomeIcons.arrowsUpDown; static Stroke? currentStroke; Color color; From 39e64597c3c68c36c5f017b7109f07e9faef3768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Zl=C3=A1mal?= Date: Wed, 2 Jul 2025 21:59:05 +0200 Subject: [PATCH 2/3] forgot to push this file --- lib/pages/editor/editor.dart | 101 ++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/lib/pages/editor/editor.dart b/lib/pages/editor/editor.dart index d0db84219f..b782b09de5 100644 --- a/lib/pages/editor/editor.dart +++ b/lib/pages/editor/editor.dart @@ -136,6 +136,11 @@ class EditorState extends State { Pen.currentPen = Pen.ballpointPen(); } return Pen.currentPen; + case ToolId.insertPen: + if (Pen.currentPen.toolId != Prefs.lastTool.value) { + Pen.currentPen = Pen.insertPen(); + } + return Pen.currentPen; case ToolId.shapePen: if (Pen.currentPen.toolId != Prefs.lastTool.value) { Pen.currentPen = ShapePen(); @@ -628,6 +633,7 @@ class EditorState extends State { moveOffset += offset; } + void onDrawEnd(ScaleEndDetails details) { final page = coreInfo.pages[dragPageIndex!]; bool shouldSave = true; @@ -643,14 +649,23 @@ class EditorState extends State { newStroke.convertToLine(); } - createPage(newStroke.pageIndex); - page.insertStroke(newStroke); - history.recordChange(EditorHistoryItem( - type: EditorHistoryItemType.draw, - pageIndex: dragPageIndex!, - strokes: [newStroke], - images: [], - )); + if (currentTool.toolId != ToolId.insertPen) { + // normal pen + createPage(newStroke.pageIndex); + page.insertStroke(newStroke); + history.recordChange(EditorHistoryItem( + type: EditorHistoryItemType.draw, + pageIndex: dragPageIndex!, + strokes: [newStroke], + images: [], + )); + } + else { + // is insert pen, I must insert free space of the vertical length of stroke + double yFirst=newStroke.points[0].y; + double yLast=newStroke.points[newStroke.points.length-1].y; + moveItemsOnPageUpDown(page,dragPageIndex!,yFirst,yLast); // move all items below up/down + } } else if (currentTool is Eraser) { final erased = (currentTool as Eraser).onDragEnd(); if (tmpTool != null && @@ -706,6 +721,76 @@ class EditorState extends State { if (shouldSave) autosaveAfterDelay(); } + // move all items below maxY down by maxY-minY + void moveItemsOnPageUpDown(EditorPage page,int pageIndex, double yFirst,double yLast){ + if ((yFirst-yLast).abs()<1.0){ + return; // too small move + } + + final bool moveDown=yLast>yFirst; + final double maxY; + maxY=yFirst; // all items below first point + List strokesBelow=[]; + double maxStrokesY; + maxStrokesY=0.0; + for (int i = 0; i < page.strokes.length; i++) { + final stroke = page.strokes[i]; + if (stroke.minY>=maxY) { + // stroke is below inserted place + strokesBelow.add(stroke); // add stroke to list of interest + if (stroke.maxY>maxStrokesY) { + maxStrokesY=stroke.maxY; // the lowest possible point of strokes + } + } + } + + List imagesBelow=[]; + + for (int i = 0; i < page.images.length; i++) { + final EditorImage image = page.images[i]; + if (image.dstRect.top>=maxY){ + //image is below inserted place + imagesBelow.add(image); // add stroke to list of interest + if (image.dstRect.bottom>maxStrokesY) { + maxStrokesY=image.dstRect.bottom; // the lowest possible point of images + } + } + } + if (strokesBelow.length==0 && imagesBelow.length==0) { + return; // nothing to move + } + final double shiftY=yLast-yFirst; + if (maxStrokesY+shiftY>page.size.height){ + // must enlarge page + page.size=Size(page.size.width,maxStrokesY+shiftY); + } + if (maxStrokesY+shiftY Date: Wed, 2 Jul 2025 22:49:06 +0200 Subject: [PATCH 3/3] fixed some errors and added one file --- lib/components/canvas/_stroke.dart | 8 ++++++++ lib/i18n/strings_en.g.dart | 1 + lib/pages/editor/editor.dart | 26 ++++++++++++++++---------- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/components/canvas/_stroke.dart b/lib/components/canvas/_stroke.dart index 707e2e90a0..d8e29386f7 100644 --- a/lib/components/canvas/_stroke.dart +++ b/lib/components/canvas/_stroke.dart @@ -363,6 +363,14 @@ class Stroke { } } + Offset get firstPoint { + return(Offset(points[0].x,points[0].y)); + } + + Offset get lastPoint { + return(Offset(points.last.x,points.last.y)); + } + Stroke copy() => Stroke( color: color, pressureEnabled: pressureEnabled, diff --git a/lib/i18n/strings_en.g.dart b/lib/i18n/strings_en.g.dart index fae5ccef55..01e99f7f07 100644 --- a/lib/i18n/strings_en.g.dart +++ b/lib/i18n/strings_en.g.dart @@ -624,6 +624,7 @@ class TranslationsEditorPensEn { // Translations String get fountainPen => 'Fountain pen'; String get ballpointPen => 'Ballpoint pen'; + String get insertPen => 'Insert space pen'; String get highlighter => 'Highlighter'; String get pencil => 'Pencil'; String get shapePen => 'Shape pen'; diff --git a/lib/pages/editor/editor.dart b/lib/pages/editor/editor.dart index b782b09de5..52a3591b1f 100644 --- a/lib/pages/editor/editor.dart +++ b/lib/pages/editor/editor.dart @@ -662,8 +662,8 @@ class EditorState extends State { } else { // is insert pen, I must insert free space of the vertical length of stroke - double yFirst=newStroke.points[0].y; - double yLast=newStroke.points[newStroke.points.length-1].y; + double yFirst=newStroke.firstPoint.dy; + double yLast=newStroke.lastPoint.dy; moveItemsOnPageUpDown(page,dragPageIndex!,yFirst,yLast); // move all items below up/down } } else if (currentTool is Eraser) { @@ -727,7 +727,6 @@ class EditorState extends State { return; // too small move } - final bool moveDown=yLast>yFirst; final double maxY; maxY=yFirst; // all items below first point List strokesBelow=[]; @@ -769,13 +768,20 @@ class EditorState extends State { page.size=Size(page.size.width,EditorPage.defaultHeight); } // and now move items - Offset moveOffset=Offset(0.0,shiftY); - for(Stroke stroke in strokesBelow){ - stroke.shift(moveOffset); - } - for(EditorImage image in imagesBelow){ - image.dstRect.shift(moveOffset); - } + setState(() { + Offset moveOffset = Offset(0.0, shiftY); + for (Stroke stroke in strokesBelow) { + stroke.shift(moveOffset); + } + for (EditorImage image in imagesBelow) { + image.dstRect = Rect.fromLTRB( + image.dstRect.left, + image.dstRect.top+moveOffset.dy, + image.dstRect.right, + image.dstRect.bottom+moveOffset.dy, + ); + } + }); history.recordChange(EditorHistoryItem( type: EditorHistoryItemType.move,