Skip to content

Commit cefb7f7

Browse files
Added polygon select to lasso tool (#1096) (#1725)
1 parent 0a781f6 commit cefb7f7

5 files changed

Lines changed: 175 additions & 51 deletions

File tree

Pinta.Resources/Icons.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ public static class Icons
164164
public const string FillStyleOutline = "tool-fillstyle-outline-symbolic";
165165
public const string FillStyleOutlineFill = "tool-fillstyle-outlinefill-symbolic";
166166

167+
public const string LassoPolygon = "tool-select-lasso-polygon-symbolic";
168+
167169
public const string HelpBug = "help-bug";
168170
public const string HelpTranslate = "help-translate";
169171
public const string HelpWebsite = "help-website-symbolic";
Lines changed: 37 additions & 0 deletions
Loading

Pinta.Resources/icons/pinta-icons.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22

33
- hicolor/16x16/actions/effects-color-dithering.png
44
- hicolor/16x16/actions/effects-render-cells.png
5-
- hicolor/16x16/actions/effects-render-voronoidiagram.png
5+
- hicolor/16x16/actions/effects-render-voronoidiagram.png
6+
- hicolor/scalable/actions/tool-select-lasso-polygon-symbolic.svg

Pinta.Tools/SettingNames.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ internal static class SettingNames
2626
internal const string FREEFORM_SHAPE_FILL_TYPE = "freeform-shape-fill-type";
2727
internal const string FREEFORM_SHAPE_DASH_PATTERN = "freeform-shape-dash_pattern";
2828

29+
internal const string LASSO_MODE = "lasso-mode";
30+
2931
internal static string Arrow1 (string prefix)
3032
=> $"{prefix}-arrow1";
3133

Pinta.Tools/Tools/LassoSelectTool.cs

Lines changed: 132 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
using System.Collections.Generic;
2929
using Cairo;
3030
using ClipperLib;
31+
using Gtk;
3132
using Pinta.Core;
3233

3334
namespace Pinta.Tools;
@@ -36,74 +37,73 @@ public sealed class LassoSelectTool : BaseTool
3637
{
3738
private readonly IWorkspaceService workspace;
3839

39-
private bool is_drawing = false;
40+
private bool is_dragging = false;
4041
private CombineMode combine_mode;
4142
private SelectionHistoryItem? hist;
4243

43-
private Path? path;
4444
private readonly List<IntPoint> lasso_polygon = [];
4545

46+
private Separator? mode_sep;
47+
private Label? lasso_mode_label;
48+
private ToolBarDropDownButton? lasso_mode_buttom;
49+
4650
public LassoSelectTool (IServiceProvider services) : base (services)
4751
{
4852
workspace = services.GetService<IWorkspaceService> ();
4953
}
5054

5155
public override string Name => Translations.GetString ("Lasso Select");
5256
public override string Icon => Pinta.Resources.Icons.ToolSelectLasso;
53-
public override string StatusBarText => Translations.GetString ("Click and drag to draw the outline for a selection area.");
57+
public override string StatusBarText => Translations.GetString ("In Freeform mode, click and drag to draw the outline for a selection area." +
58+
"\n\nIn Polygon mode, click and drag to add a new point to the selection." +
59+
"\nPress Enter to finish the selection." +
60+
"\nPress Backspace to delete the last point.");
5461
public override Gdk.Key ShortcutKey => new (Gdk.Constants.KEY_S);
5562
public override Gdk.Cursor DefaultCursor => Gdk.Cursor.NewFromTexture (Resources.GetIcon ("Cursor.LassoSelect.png"), 9, 18, null);
5663
public override int Priority => 17;
5764
public override bool IsSelectionTool => true;
5865

66+
private bool IsPolygonMode => LassoModeButtom.SelectedItem.GetTagOrDefault (false);
67+
private bool IsFreeformMode => !IsPolygonMode;
68+
5969
protected override void OnBuildToolBar (Gtk.Box tb)
6070
{
6171
base.OnBuildToolBar (tb);
6272
workspace.SelectionHandler.BuildToolbar (tb, Settings);
73+
74+
tb.Append (Separator);
75+
tb.Append (LassoModeLabel);
76+
tb.Append (LassoModeButtom);
6377
}
6478

6579
protected override void OnMouseDown (Document document, ToolMouseEventArgs e)
6680
{
67-
if (is_drawing)
81+
if (is_dragging)
6882
return;
6983

70-
hist = new SelectionHistoryItem (workspace, Icon, Name);
71-
hist.TakeSnapshot ();
84+
is_dragging = true;
7285

73-
combine_mode = workspace.SelectionHandler.DetermineCombineMode (e);
74-
path = null;
75-
is_drawing = true;
76-
77-
document.PreviousSelection = document.Selection.Clone ();
78-
}
79-
80-
protected override void OnMouseMove (Document document, ToolMouseEventArgs e)
81-
{
82-
if (!is_drawing)
83-
return;
86+
if (lasso_polygon.Count == 0) {
87+
hist = new SelectionHistoryItem (workspace, Icon, Name);
88+
hist.TakeSnapshot ();
8489

85-
PointD p = document.ClampToImageSize (e.PointDouble);
90+
combine_mode = workspace.SelectionHandler.DetermineCombineMode (e);
8691

87-
document.Selection.Visible = true;
92+
document.PreviousSelection = document.Selection.Clone ();
93+
}
8894

89-
ImageSurface surf = document.Layers.SelectionLayer.Surface;
95+
if (IsPolygonMode) {
96+
PointD p = document.ClampToImageSize (e.PointDouble);
9097

91-
using Context g = new (surf) { Antialias = Antialias.Subpixel };
98+
lasso_polygon.Add (new IntPoint ((long) p.X, (long) p.Y));
9299

93-
if (path != null) {
94-
g.AppendPath (path);
95-
} else {
96-
g.MoveTo (p.X, p.Y);
100+
ApplySelection (document);
97101
}
98102

99-
g.LineTo (p.X, p.Y);
100-
lasso_polygon.Add (new IntPoint ((long) p.X, (long) p.Y));
101-
102-
path = g.CopyPath ();
103-
104-
g.FillRule = FillRule.EvenOdd;
105-
g.ClosePath ();
103+
}
106104

105+
private void ApplySelection (Document document)
106+
{
107107
document.Selection.SelectionPolygons.Clear ();
108108
document.Selection.SelectionPolygons.Add ([.. lasso_polygon]);
109109

@@ -115,35 +115,117 @@ protected override void OnMouseMove (Document document, ToolMouseEventArgs e)
115115
document.Workspace.Invalidate ();
116116
}
117117

118-
protected override void OnMouseUp (Document document, ToolMouseEventArgs e)
118+
protected override void OnMouseMove (Document document, ToolMouseEventArgs e)
119119
{
120-
ImageSurface surf = document.Layers.SelectionLayer.Surface;
120+
if (!is_dragging)
121+
return;
121122

122-
using Context g = new (surf);
123-
if (path != null) {
124-
g.AppendPath (path);
125-
path = null;
123+
PointD p = document.ClampToImageSize (e.PointDouble);
124+
125+
if (IsFreeformMode) {
126+
lasso_polygon.Add (new IntPoint ((long) p.X, (long) p.Y));
127+
128+
ApplySelection (document);
129+
return;
126130
}
127131

128-
g.FillRule = FillRule.EvenOdd;
129-
g.ClosePath ();
132+
if (lasso_polygon.Count == 0)
133+
return;
130134

131-
document.Selection.SelectionPolygons.Clear ();
132-
document.Selection.SelectionPolygons.Add ([.. lasso_polygon]);
135+
lasso_polygon[lasso_polygon.Count - 1] = new IntPoint (p.X, p.Y);
133136

134-
SelectionModeHandler.PerformSelectionMode (
135-
document,
136-
combine_mode,
137-
document.Selection.SelectionPolygons);
137+
ApplySelection (document);
138+
}
138139

139-
document.Workspace.Invalidate ();
140+
protected override void OnMouseUp (Document document, ToolMouseEventArgs e)
141+
{
142+
if (IsFreeformMode) {
143+
ApplySelection (document);
144+
145+
FinalizeShape (document);
146+
}
147+
is_dragging = false;
148+
}
140149

150+
private void FinalizeShape (Document document)
151+
{
141152
if (hist != null) {
142-
document.History.PushNewItem (hist);
153+
if (lasso_polygon.Count > 1)
154+
document.History.PushNewItem (hist);
143155
hist = null;
144156
}
145-
146157
lasso_polygon.Clear ();
147-
is_drawing = false;
158+
}
159+
160+
protected override void OnDeactivated (Document? document, BaseTool? newTool)
161+
{
162+
if (document != null)
163+
FinalizeShape (document);
164+
}
165+
166+
protected override bool OnKeyDown (Document document, ToolKeyEventArgs e)
167+
{
168+
if (IsPolygonMode) {
169+
switch (e.Key.Value) {
170+
case Gdk.Constants.KEY_Return:
171+
FinalizeShape (document);
172+
return true;
173+
case Gdk.Constants.KEY_BackSpace:
174+
Backtrack (document);
175+
return true;
176+
}
177+
}
178+
179+
return base.OnKeyDown (document, e);
180+
}
181+
182+
private void Backtrack (Document document)
183+
{
184+
if (lasso_polygon.Count == 0) {
185+
return;
186+
}
187+
188+
ArgumentNullException.ThrowIfNull (hist);
189+
190+
lasso_polygon.RemoveAt (lasso_polygon.Count - 1);
191+
192+
if (lasso_polygon.Count == 0) {
193+
hist.Undo ();
194+
return;
195+
}
196+
197+
ApplySelection (document);
198+
}
199+
200+
protected override void OnCommit (Document? document)
201+
{
202+
if (document != null)
203+
FinalizeShape (document);
204+
}
205+
206+
protected override void OnSaveSettings (ISettingsService settings)
207+
{
208+
base.OnSaveSettings (settings);
209+
210+
if (lasso_mode_buttom is not null)
211+
settings.PutSetting (SettingNames.LASSO_MODE, lasso_mode_buttom.SelectedIndex);
212+
}
213+
214+
private Separator Separator => mode_sep ??= GtkExtensions.CreateToolBarSeparator ();
215+
private Label LassoModeLabel => lasso_mode_label ??= Label.New (string.Format (" {0}: ", Translations.GetString ("Lasso Mode")));
216+
217+
private ToolBarDropDownButton LassoModeButtom {
218+
get {
219+
if (lasso_mode_buttom is null) {
220+
lasso_mode_buttom = new ToolBarDropDownButton ();
221+
222+
lasso_mode_buttom.AddItem (Translations.GetString ("Freeform"), Pinta.Resources.Icons.ToolFreeformShape, false);
223+
lasso_mode_buttom.AddItem (Translations.GetString ("Polygon"), Pinta.Resources.Icons.LassoPolygon, true);
224+
225+
lasso_mode_buttom.SelectedIndex = Settings.GetSetting (SettingNames.LASSO_MODE, 0);
226+
}
227+
228+
return lasso_mode_buttom;
229+
}
148230
}
149231
}

0 commit comments

Comments
 (0)