Skip to content

Commit

Permalink
Resize Selection
Browse files Browse the repository at this point in the history
You have little square on each corner and you can resize the previous selection
  • Loading branch information
dufoli committed Sep 13, 2011
1 parent 53ed19b commit 6cf43e6
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 19 deletions.
11 changes: 11 additions & 0 deletions Pinta.Core/Classes/BaseTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

namespace Pinta.Core
{
public delegate void MouseHandler (double x, double y, Gdk.ModifierType state);

[TypeExtensionPoint]
public abstract class BaseTool
{
Expand All @@ -46,6 +48,9 @@ public abstract class BaseTool
protected ToolItem tool_sep;
protected ToolBarDropDownButton antialiasing_button;
protected ToolBarDropDownButton alphablending_button;
public event MouseHandler MouseMoved;
public event MouseHandler MousePressed;
public event MouseHandler MouseReleased;

protected BaseTool ()
{
Expand Down Expand Up @@ -80,6 +85,8 @@ static BaseTool ()
#region Public Methods
public void DoMouseMove (object o, MotionNotifyEventArgs args, Cairo.PointD point)
{
if (MouseMoved != null)
MouseMoved (point.X, point.Y, args.Event.State);
OnMouseMove (o, args, point);
}

Expand All @@ -96,11 +103,15 @@ public void DoClearToolBar (Toolbar tb)

public void DoMouseDown (DrawingArea canvas, ButtonPressEventArgs args, Cairo.PointD point)
{
if (MousePressed != null)
MousePressed (point.X, point.Y, args.Event.State);
OnMouseDown (canvas, args, point);
}

public void DoMouseUp (DrawingArea canvas, ButtonReleaseEventArgs args, Cairo.PointD point)
{
if (MouseReleased != null)
MouseReleased (point.X, point.Y, args.Event.State);
OnMouseUp (canvas, args, point);
}

Expand Down
3 changes: 2 additions & 1 deletion Pinta.Tools/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ SOURCES = \
Brushes/GridBrush.cs \
Brushes/SquaresBrush.cs \
Brushes/PlainBrush.cs \
Brushes/CircleBrush.cs
Brushes/CircleBrush.cs \
ToolControl/ToolControl.cs

4 changes: 4 additions & 0 deletions Pinta.Tools/Pinta.Tools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
<Compile Include="Brushes\SquaresBrush.cs" />
<Compile Include="Brushes\PlainBrush.cs" />
<Compile Include="Brushes\CircleBrush.cs" />
<Compile Include="Tools\ToolControl\ToolControl.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Pinta.Core\Pinta.Core.csproj">
Expand Down Expand Up @@ -142,4 +143,7 @@
<Target Name="AfterBuild">
</Target>
-->
<ItemGroup>
<Folder Include="Tools\ToolControl\" />
</ItemGroup>
</Project>
121 changes: 103 additions & 18 deletions Pinta.Tools/Tools/SelectTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,19 @@ namespace Pinta.Tools
public abstract class SelectTool : ShapeTool
{
private PointD reset_origin;

private PointD shape_end;
private int cornerTolerance = 3;
private ToolControl [] controls = new ToolControl [8];
protected SelectionHistoryItem hist;
public override Gdk.Key ShortcutKey { get { return Gdk.Key.S; } }
protected override bool ShowAntialiasingButton { get { return false; } }

bool handler_active = false;

public SelectTool ()
{
CreateHandler ();
}

#region ToolBar
// We don't want the ShapeTool's toolbar
protected override void BuildToolBar (Toolbar tb)
Expand All @@ -52,37 +60,37 @@ protected override void OnMouseDown (DrawingArea canvas, ButtonPressEventArgs ar
// Ignore extra button clicks while drawing
if (is_drawing)
return;

reset_origin = args.Event.GetPoint ();

Document doc = PintaCore.Workspace.ActiveDocument;

double x = Utility.Clamp (point.X, 0, doc.ImageSize.Width - 1);
double y = Utility.Clamp (point.Y, 0, doc.ImageSize.Height - 1);
if (!handler_active || !HandleResize (point.X, point.Y)) {
double x = Utility.Clamp (point.X, 0, doc.ImageSize.Width - 1);
double y = Utility.Clamp (point.Y, 0, doc.ImageSize.Height - 1);

shape_origin = new PointD (x, y);
is_drawing = true;

shape_origin = new PointD (x, y);
is_drawing = true;
}
hist = new SelectionHistoryItem (Icon, Name);
hist.TakeSnapshot ();
}

protected override void OnMouseUp (DrawingArea canvas, ButtonReleaseEventArgs args, Cairo.PointD point)
{
double x = point.X;
double y = point.Y;


// If the user didn't move the mouse, they want to deselect
int tolerance = 0;

if (Math.Abs (reset_origin.X - args.Event.X) <= tolerance && Math.Abs (reset_origin.Y - args.Event.Y) <= tolerance) {
PintaCore.Actions.Edit.Deselect.Activate ();
hist.Dispose ();
hist = null;
handler_active = false;
doc.ToolLayer.Clear ();
} else {
if (hist != null)
PintaCore.Workspace.ActiveDocument.History.PushNewItem (hist);


handler_active = true;
hist = null;
}

Expand All @@ -93,20 +101,97 @@ protected override void OnMouseMove (object o, MotionNotifyEventArgs args, Cairo
{
if (!is_drawing)
return;

Document doc = PintaCore.Workspace.ActiveDocument;

double x = Utility.Clamp (point.X, 0, doc.ImageSize.Width - 1);
double y = Utility.Clamp (point.Y, 0, doc.ImageSize.Height - 1);

doc.ShowSelection = true;
shape_end = new PointD (x, y);
ReDraw (args.Event.State);
}

Rectangle dirty = DrawShape (Utility.PointsToRectangle (shape_origin, new PointD (x, y), (args.Event.State & Gdk.ModifierType.ShiftMask) == Gdk.ModifierType.ShiftMask), doc.SelectionLayer);
protected void RefreshHandler ()
{
controls[0].Position = new PointD (shape_origin.X, shape_origin.Y);
controls[1].Position = new PointD (shape_origin.X, shape_end.Y);
controls[2].Position = new PointD (shape_end.X, shape_origin.Y);
controls[3].Position = new PointD (shape_end.X, shape_end.Y);
controls[4].Position = new PointD (shape_origin.X, (shape_origin.Y + shape_end.Y) / 2);
controls[5].Position = new PointD ((shape_origin.X + shape_end.X) / 2, shape_origin.Y);
controls[6].Position = new PointD (shape_end.X, (shape_origin.Y + shape_end.Y) / 2);
controls[7].Position = new PointD ((shape_origin.X + shape_end.X) / 2, shape_end.Y);
}

public void ReDraw (Gdk.ModifierType state)
{
RefreshHandler ();

Document doc = PintaCore.Workspace.ActiveDocument;

doc.ShowSelection = true;
doc.ToolLayer.Hidden = false;
Rectangle dirty = DrawShape (Utility.PointsToRectangle (shape_origin, shape_end, (state & Gdk.ModifierType.ShiftMask) == Gdk.ModifierType.ShiftMask), doc.SelectionLayer);
doc.ToolLayer.Clear ();
DrawHandler (doc.ToolLayer);
doc.Workspace.Invalidate ();

last_dirty = dirty;
}

protected void CreateHandler ()
{
controls[0] = new ToolControl ((x, y, a) => {
shape_origin.X = x;
shape_origin.Y = y;
ReDraw (a);
});
controls[1] = new ToolControl ((x, y, a) => {
shape_origin.X = x;
shape_end.Y = y;
ReDraw (a);
});
controls[2] = new ToolControl ((x, y, a) => {
shape_end.X = x;
shape_origin.Y = y;
ReDraw (a);
});
controls[3] = new ToolControl ((x, y, a) => {
shape_end.X = x;
shape_end.Y = y;
ReDraw (a);
});
controls[4] = new ToolControl ((x, y, a) => {
shape_origin.X = x;
ReDraw (a);
});
controls[5] = new ToolControl ((x, y, a) => {
shape_origin.Y = y;
ReDraw (a);
});
controls[6] = new ToolControl ((x, y, a) => {
shape_end.X = x;
ReDraw (a);
});
controls[7] = new ToolControl ((x, y, a) => {
shape_end.Y = y;
ReDraw (a);
});
}

public bool HandleResize (double x, double y)
{
bool res = false;
foreach (ToolControl ct in controls)
res |= ct.Handle (this, new PointD (x, y ));
return res;

}

public void DrawHandler (Layer layer)
{
foreach (ToolControl ct in controls)
ct.Render (layer);
}
#endregion
}
}
69 changes: 69 additions & 0 deletions Pinta.Tools/Tools/ToolControl/ToolControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// ToolControl.cs
//
// Author:
// Olivier Dufour <[email protected]>
//
// Copyright (c) 2011
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using Cairo;
using Gdk;
using Pinta.Core;

namespace Pinta.Tools
{
public class ToolControl
{
public ToolControl (MouseHandler moveAction)
{
this.action = moveAction;
Position = new PointD (-5, -5);
}

int tolerance = 3;
MouseHandler action;

public PointD Position {get; set;}

public bool Handle (BaseTool tool, Cairo.PointD point)
{
if (IsInside (point.X, point.Y)) {
tool.MouseMoved += action;
tool.MouseReleased += (x, y, s) => {tool.MouseMoved -= action;};
//TODO unregister mouse release
return true;
}
return false;
}

protected bool IsInside (double x, double y)
{
return (Math.Abs (x - Position.X) <= tolerance) && (Math.Abs (y - Position.Y) <= tolerance);
}

public void Render (Layer layer)
{
using (Context g = new Context (layer.Surface))
g.FillStrokedRectangle (new Cairo.Rectangle (Position.X - 2, Position.Y - 2, 4, 4), new Cairo.Color (0, 0, 1, 0.5), new Cairo.Color (0, 0, 1, 0.7), 1);
}
}
}

0 comments on commit 6cf43e6

Please sign in to comment.