Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions lib/components/canvas/_stroke.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -360,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,
Expand Down
20 changes: 20 additions & 0 deletions lib/components/toolbar/pen_modal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,26 @@ class _PenModalState extends State<PenModal> {
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),
),
],
],
);
Expand Down
2 changes: 1 addition & 1 deletion lib/data/editor/page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions lib/data/tools/_tool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class _TextEditingTool extends Tool {
enum ToolId {
fountainPen('fountainPen'),
ballpointPen('ballpointPen'),
insertPen('insertPen'),
highlighter('Highlighter'),
pencil('Pencil'),
shapePen('ShapePen'),
Expand Down
13 changes: 13 additions & 0 deletions lib/data/tools/pen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ class Pen extends Tool {
color = Color(stows.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 =
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions lib/i18n/strings_en.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
107 changes: 99 additions & 8 deletions lib/pages/editor/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ class EditorState extends State<Editor> {
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 != stows.lastTool.value) {
Pen.currentPen = ShapePen();
Expand Down Expand Up @@ -628,6 +633,7 @@ class EditorState extends State<Editor> {
moveOffset += offset;
}


void onDrawEnd(ScaleEndDetails details) {
final page = coreInfo.pages[dragPageIndex!];
bool shouldSave = true;
Expand All @@ -643,14 +649,23 @@ class EditorState extends State<Editor> {
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.firstPoint.dy;
double yLast=newStroke.lastPoint.dy;
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 &&
Expand Down Expand Up @@ -706,6 +721,82 @@ class EditorState extends State<Editor> {
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 double maxY;
maxY=yFirst; // all items below first point
List<Stroke> 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<EditorImage> 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<EditorPage.defaultHeight){
// page will be smaller than default height set it to default height
page.size=Size(page.size.width,EditorPage.defaultHeight);
}
// and now move items
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,
pageIndex: pageIndex,
strokes: strokesBelow,
images: imagesBelow,
offset: Rect.fromLTRB(
moveOffset.dx,
moveOffset.dy,
moveOffset.dx,
moveOffset.dy,
),
));
}

void onInteractionEnd(ScaleEndDetails details) {
// reset after 1ms to keep track of the same gesture only
_lastSeenPointerCountTimer?.cancel();
Expand Down
Loading