2828using System . Collections . Generic ;
2929using Cairo ;
3030using ClipperLib ;
31+ using Gtk ;
3132using Pinta . Core ;
3233
3334namespace 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 \n In Polygon mode, click and drag to add a new point to the selection." +
59+ "\n Press Enter to finish the selection." +
60+ "\n Press 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