Skip to content
Open
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 Pinta.Core/Classes/BaseTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ClipperLib;
using Gdk;
using Gtk;

Expand Down Expand Up @@ -119,6 +120,16 @@ public virtual bool IsEditableShapeTool
public virtual IEnumerable<IToolHandle> Handles
=> [];

/// <summary>
/// For selection tools, returns the shape of the applied selection, i.e. the selection being combined with the previous selection.
/// When this method doesn't return null, a preview of the new selection is shown with the outlines of the previous and applied selection.
/// If this is not a selection tool, this should always return null
/// If this selection tool is not currently drawing a new selection or is in replace mode, this should return null.
/// </summary>
public virtual IReadOnlyList<IReadOnlyList<IntPoint>>? AppliedSelectionPolygons {
get => null;
}

/// <summary>
/// The shortcut key used to activate this tool in the toolbox.
/// Return Gdk.Key.Invalid for no shortcut key.
Expand Down
3 changes: 2 additions & 1 deletion Pinta.Core/Classes/DocumentSelection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public static List<List<IntPoint>> ConvertToPolygons (IReadOnlyList<IReadOnlyLis
/// </summary>
/// <param name="clipperPolygons">A Clipper Polygon collection.</param>
/// <returns>A Pinta Polygon set.</returns>
private static IReadOnlyList<IReadOnlyList<PointI>> ConvertToPolygonSet (IReadOnlyList<IReadOnlyList<IntPoint>> clipperPolygons)
public static IReadOnlyList<IReadOnlyList<PointI>> ConvertToPolygonSet (IReadOnlyList<IReadOnlyList<IntPoint>> clipperPolygons)
{
var resultingPolygonSet = new PointI[clipperPolygons.Count][];

Expand All @@ -152,6 +152,7 @@ private static IReadOnlyList<IReadOnlyList<PointI>> ConvertToPolygonSet (IReadOn
return resultingPolygonSet;
}


/// <summary>
/// Return a transformed copy of the selection.
/// </summary>
Expand Down
29 changes: 23 additions & 6 deletions Pinta.Gui.Widgets/Widgets/Canvas/PintaCanvas.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Cairo;
using ClipperLib;
using Pinta.Core;

namespace Pinta.Gui.Widgets;
Expand Down Expand Up @@ -224,9 +226,24 @@ private void DrawSelection (Gtk.Snapshot snapshot, Graphene.Rect canvasViewBound
bool fillSelection = tools.CurrentTool?.IsSelectionTool ?? false;

// Convert the selection path.
Gsk.PathBuilder pathBuilder = Gsk.PathBuilder.New ();
pathBuilder.AddCairoPath (document.Selection.SelectionPath);
Gsk.Path selectionPath = pathBuilder.ToPath ();
Gsk.PathBuilder fillPathBuilder = Gsk.PathBuilder.New ();
fillPathBuilder.AddCairoPath (document.Selection.SelectionPath);
Gsk.Path fillPath = fillPathBuilder.ToPath ();

Gsk.Path strokePath;
IReadOnlyList<IReadOnlyList<IntPoint>>? appliedPolygons = tools.CurrentTool?.AppliedSelectionPolygons;
//appliedPolygons not null means the tool wants to show a preview.
if (appliedPolygons is not null) {
//The preview is composed of the outlines of the previous selection and the applied selection.
var previewPolygons = appliedPolygons.Concat (document.PreviousSelection.SelectionPolygons).ToList ();
using Context g = CairoExtensions.CreatePathContext ();
Path outlinePath = g.CreatePolygonPath (DocumentSelection.ConvertToPolygonSet (previewPolygons));

Gsk.PathBuilder strokePathBuilder = Gsk.PathBuilder.New ();
strokePathBuilder.AddCairoPath (outlinePath);
strokePath = strokePathBuilder.ToPath ();
} else
strokePath = fillPath;

snapshot.Save ();
snapshot.PushClip (canvasViewBounds);
Expand All @@ -238,18 +255,18 @@ private void DrawSelection (Gtk.Snapshot snapshot, Graphene.Rect canvasViewBound

if (fillSelection) {
Gdk.RGBA fillColor = new () { Red = 0.7f, Green = 0.8f, Blue = 0.9f, Alpha = 0.2f };
snapshot.AppendFill (selectionPath, Gsk.FillRule.EvenOdd, fillColor);
snapshot.AppendFill (fillPath, Gsk.FillRule.EvenOdd, fillColor);
}

// Draw a white line first so it shows up on dark backgrounds
Gsk.Stroke stroke = Gsk.Stroke.New (lineWidth: 1.0f / scale);
Gdk.RGBA white = new () { Red = 1, Green = 1, Blue = 1, Alpha = 1 };
snapshot.AppendStroke (selectionPath, stroke, white);
snapshot.AppendStroke (strokePath, stroke, white);

// Draw a black dashed line over the white line
stroke.SetDash ([2.0f / scale, 4.0f / scale]);
Gdk.RGBA black = new () { Red = 0, Green = 0, Blue = 0, Alpha = 1 };
snapshot.AppendStroke (selectionPath, stroke, black);
snapshot.AppendStroke (strokePath, stroke, black);

snapshot.Pop ();
snapshot.Restore ();
Expand Down
6 changes: 6 additions & 0 deletions Pinta.Tools/Tools/LassoSelectTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ private void FinalizeShape (Document document)
hist = null;
}
lasso_polygon.Clear ();

//To make sure the preview doesn't show anymore
document.Workspace.Invalidate ();
}

protected override void OnDeactivated (Document? document, BaseTool? newTool)
Expand Down Expand Up @@ -203,6 +206,9 @@ protected override void OnCommit (Document? document)
FinalizeShape (document);
}

public override List<List<IntPoint>>? AppliedSelectionPolygons =>
lasso_polygon.Count > 0 && combine_mode != CombineMode.Replace ? [lasso_polygon] : null;

protected override void OnSaveSettings (ISettingsService settings)
{
base.OnSaveSettings (settings);
Expand Down
8 changes: 8 additions & 0 deletions Pinta.Tools/Tools/SelectTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using ClipperLib;
using Pinta.Core;

namespace Pinta.Tools;
Expand Down Expand Up @@ -108,6 +109,7 @@ protected override void OnMouseMove (Document document, ToolMouseEventArgs e)

RectangleI dirty = ReDraw (document);


SelectionModeHandler.PerformSelectionMode (document, combine_mode, document.Selection.SelectionPolygons);
document.Workspace.Invalidate (dirty.Union (last_dirty));

Expand Down Expand Up @@ -180,6 +182,8 @@ private RectangleI ReDraw (Document document)

DrawShape (document, rect, document.Layers.SelectionLayer);

applied_selection_polygons = new List<List<IntPoint>> (document.Selection.SelectionPolygons);

// Figure out a bounding box for everything that was drawn, and add a bit of padding.
RectangleI dirty = rect.ToInt ();
dirty = dirty.Inflated (2, 2);
Expand Down Expand Up @@ -221,6 +225,10 @@ private void AfterSelectionChange (object? sender, EventArgs event_args)
LoadFromDocument (workspace.ActiveDocument);
}

private List<List<IntPoint>>? applied_selection_polygons = null;
public override List<List<IntPoint>>? AppliedSelectionPolygons =>
handle.IsDragging && combine_mode != CombineMode.Replace ? applied_selection_polygons : null;

/// <summary>
/// Initialize from the document's selection.
/// </summary>
Expand Down
Loading