Skip to content
Merged
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
17 changes: 8 additions & 9 deletions Pinta.Core/Classes/BaseTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ protected BaseTool (IServiceProvider services)

// Update cursor when active document changes
workspace.ActiveDocumentChanged += (_, _) => {
if (tools.CurrentTool == this)
SetCursor (CurrentCursor);
if (IsActiveTool ()) {
SetCursor (DefaultCursor);
}
};

// Give tools a chance to save their settings on application quit
Settings.SaveSettingsBeforeQuit += (_, _)
=> OnSaveSettings (Settings);
Expand Down Expand Up @@ -92,12 +92,6 @@ public virtual Cursor? DefaultCursor
/// </summary>
public Cursor? CurrentCursor { get; private set; }

/// <summary>
/// Specifies whether this application needs to update this tool's
/// cursor after a zoom operation.
/// </summary>
public virtual bool CursorChangesOnZoom
=> false;

/// <summary>
/// Specifies whether the tool manipulates selections.
Expand Down Expand Up @@ -327,6 +321,11 @@ public void SetCursor (Cursor? cursor)
workspace.ActiveWorkspace.Canvas.Cursor = cursor;
}

protected bool IsActiveTool ()
{
return tools.CurrentTool == this;
}

#region Toolbar
private ToolBoxButton? tool_item;
private ToolBarDropDownButton? antialiasing_button;
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Core/Classes/Document.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public Document (
Selection = new DocumentSelection ();

Layers = new DocumentLayers (tools, this);
Workspace = new DocumentWorkspace (actions, tools, this);
Workspace = new DocumentWorkspace (actions, this);
IsDirty = false;
HasBeenSavedInSession = false;
ImageSize = size;
Expand Down
8 changes: 0 additions & 8 deletions Pinta.Core/Classes/DocumentWorkspace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public sealed class DocumentWorkspace
private readonly Document document;

private readonly ActionManager actions;
private readonly ToolManager tools;

private enum ZoomType
{
Expand All @@ -44,11 +43,9 @@ private enum ZoomType

internal DocumentWorkspace (
ActionManager actions,
ToolManager tools,
Document document)
{
this.actions = actions;
this.tools = tools;

this.document = document;

Expand Down Expand Up @@ -116,11 +113,6 @@ public double Scale {
ViewSize = GetNewViewSize (document.ImageSize, value);

Invalidate ();

if (tools.CurrentTool?.CursorChangesOnZoom == true) {
//The current tool's cursor changes when the zoom changes.
tools.CurrentTool.SetCursor (tools.CurrentTool.CurrentCursor);
}
}
}

Expand Down
12 changes: 7 additions & 5 deletions Pinta.Core/Extensions/GdkExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,21 @@ public static bool HasModifierKey (this Gdk.ModifierType current_state)
public static Gdk.Texture CreateIconWithShape (
string imgName,
CursorShape shape,
double scale,
int shapeWidth,
int imgToShapeX,
int imgToShapeY,
out int shapeX,
out int shapeY)
{
Gdk.Texture result = CreateIconWithShape (imgName, shape, shapeWidth, shapeWidth, 0, imgToShapeX, imgToShapeY, out shapeX, out shapeY);
Gdk.Texture result = CreateIconWithShape (imgName, shape, scale, shapeWidth, shapeWidth, 0, imgToShapeX, imgToShapeY, out shapeX, out shapeY);
return result;
}

public static Gdk.Texture CreateIconWithShape (
string imgName,
CursorShape shape,
double scale,
int shapeWidth,
int shapeHeight,
int shapeAngle,
Expand All @@ -114,7 +116,7 @@ public static Gdk.Texture CreateIconWithShape (

double zoom =
(PintaCore.Workspace.HasOpenDocuments)
? Math.Min (30d, PintaCore.Workspace.ActiveDocument.Workspace.Scale)
? Math.Min (30d, scale)
: 1d;

int clampedWidth = (int) Math.Min (800d, shapeWidth * zoom);
Expand All @@ -130,8 +132,8 @@ public static Gdk.Texture CreateIconWithShape (
RectangleI initialShapeBBox = new (
imgToShapeX - Math.Max (halfOfShapeWidth, halfOfShapeHeight),
imgToShapeY - Math.Max (halfOfShapeWidth, halfOfShapeHeight),
clampedWidth,
clampedHeight);
Math.Max (clampedWidth, clampedHeight),
Math.Max (clampedWidth, clampedHeight));

// Inflate shape bounding box to allow for anti-aliasing
RectangleI inflatedBBox = initialShapeBBox.Inflated (2, 2);
Expand Down Expand Up @@ -186,7 +188,7 @@ public static Gdk.Texture CreateIconWithShape (
shapeRect = shapeRect.Inflated (-1, -1);
PointD[] pointsOfInflatedRotatedRectangle = RotateRectangle (shapeRect, shapeAngle);
g.DrawPolygonal (new ReadOnlySpan<PointD> (pointsOfRotatedRectangle), outerColor, LineCap.Butt);
g.DrawPolygonal (new ReadOnlySpan<PointD> (pointsOfInflatedRotatedRectangle), innerColor, LineCap.Butt);
g.DrawPolygonal (new ReadOnlySpan<PointD> ([.. pointsOfInflatedRotatedRectangle, pointsOfInflatedRotatedRectangle[0]]), innerColor, LineCap.Butt);
}
break;
}
Expand Down
17 changes: 17 additions & 0 deletions Pinta.Core/Managers/WorkspaceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public interface IWorkspaceService
public event EventHandler? LayerAdded;
public event EventHandler? LayerRemoved;
public event EventHandler? SelectedLayerChanged;
public event EventHandler? ViewSizeChanged;
public event PropertyChangedEventHandler? LayerPropertyChanged;
}

Expand Down Expand Up @@ -140,6 +141,14 @@ public static Document NewDocument (

return doc;
}

public static double GetScale (this IWorkspaceService workspace)
{
if (workspace is null || !workspace.HasOpenDocuments) {
return 1;
}
return workspace.ActiveDocument.Workspace.Scale;
}
}

public sealed class WorkspaceManager : IWorkspaceService
Expand Down Expand Up @@ -207,6 +216,7 @@ public void ActivateDocument (Document document)
document.Layers.LayerRemoved += Document_LayerRemoved;
document.Layers.SelectedLayerChanged += Document_SelectedLayerChanged;
document.Layers.LayerPropertyChanged += Document_LayerPropertyChanged;
document.Workspace.ViewSizeChanged += Document_ViewSizeChanged;

open_documents.Add (document);

Expand Down Expand Up @@ -236,6 +246,11 @@ private void Document_LayerAdded (object? sender, IndexEventArgs e)
LayerAdded?.Invoke (sender, e);
}

private void Document_ViewSizeChanged (object? sender, EventArgs ev)
{
ViewSizeChanged?.Invoke (sender, ev);
}

public void CloseDocument (Document document)
{
int index = open_documents.IndexOf (document);
Expand Down Expand Up @@ -263,6 +278,7 @@ public void CloseDocument (Document document)
document.Layers.LayerRemoved -= Document_LayerRemoved;
document.Layers.SelectedLayerChanged -= Document_SelectedLayerChanged;
document.Layers.LayerPropertyChanged -= Document_LayerPropertyChanged;
document.Workspace.ViewSizeChanged -= Document_ViewSizeChanged;
document.Close ();

OnDocumentClosed (new DocumentEventArgs (document));
Expand Down Expand Up @@ -453,6 +469,7 @@ private Task ShowFilePermissionErrorDialog (
public event EventHandler? LayerRemoved;
public event EventHandler? SelectedLayerChanged;
public event PropertyChangedEventHandler? LayerPropertyChanged;
public event EventHandler? ViewSizeChanged;

public event EventHandler<DocumentEventArgs>? DocumentActivated;
public event EventHandler<DocumentEventArgs>? DocumentClosed;
Expand Down
10 changes: 7 additions & 3 deletions Pinta.Tools/Brushes/SlashBrush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@ public override string Name
private int line_width;
private int angle;

private readonly IWorkspaceService workspace;

private const string AngleSettingName = "slash-brush-angle";

public SlashBrush (ISettingsService settingsService)
public SlashBrush (ISettingsService settingsService, IWorkspaceService workspace)
{
this.workspace = workspace;
IntegerOption angleOption = new IntegerOption (
AngleSettingName,
0,
Expand Down Expand Up @@ -86,7 +89,7 @@ present logic...
new_bottom.X * old_bottom.Y - new_bottom.Y * old_bottom.X +
old_bottom.X * old_top.Y - old_bottom.Y * old_top.X));

if (area < 2) {
if (area < 2 && (last_pos.X != current_pos.X || last_pos.Y != current_pos.Y)) {
old_top = OffsetPoint (old_top, -1, 1, angle + 90);
new_top = OffsetPoint (new_top, -1, 1, angle + 90);
old_bottom = OffsetPoint (old_bottom, 1, 1, angle + 90);
Expand Down Expand Up @@ -135,14 +138,15 @@ public override void UpdateLineWidth (int lineWidth)

public override Gdk.Cursor GetCursor ()
{
double scale = workspace.GetScale ();
/*
If we do not override a 0 angle with 180, the logic in GdkExtensions will
step into the "rectangle" path which will look inconsistent (unfilled) to all
other angles, so call a 0 angle with 180 for cursor creation so that it looks
consistent.
*/
var icon = GdkExtensions.CreateIconWithShape ("Cursor.Paintbrush.png",
CursorShape.Rectangle, 2, line_width, angle == 0 ? 180 : angle, 8, 24,
CursorShape.Rectangle, scale, 2, line_width, angle == 0 ? 180 : angle, 8, 24,
out var iconOffsetX, out var iconOffsetY);

return Gdk.Cursor.NewFromTexture (icon, iconOffsetX, iconOffsetY, null);
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Tools/CoreToolsExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void Initialize ()
PintaCore.PaintBrushes.AddPaintBrush (new Brushes.GridBrush ());
PintaCore.PaintBrushes.AddPaintBrush (new Brushes.PlainBrush (PintaCore.Workspace));
PintaCore.PaintBrushes.AddPaintBrush (new Brushes.SplatterBrush (services.GetService<ISettingsService> ()));
PintaCore.PaintBrushes.AddPaintBrush (new Brushes.SlashBrush (services.GetService<ISettingsService> ()));
PintaCore.PaintBrushes.AddPaintBrush (new Brushes.SlashBrush (services.GetService<ISettingsService> (), services.GetService<IWorkspaceService> ()));
PintaCore.PaintBrushes.AddPaintBrush (new Brushes.SquaresBrush ());

PintaCore.Tools.AddTool (new MoveSelectedTool (services));
Expand Down
13 changes: 11 additions & 2 deletions Pinta.Tools/Tools/CloneStampTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,33 @@ public sealed class CloneStampTool : BaseBrushTool
private PointI? last_point = null;

private readonly SystemManager system_manager;
private readonly IWorkspaceService workspace;
public CloneStampTool (IServiceProvider services) : base (services)
{
system_manager = services.GetService<SystemManager> ();
workspace = services.GetService<IWorkspaceService> ();

// Update cursor on zoom
workspace.ViewSizeChanged += (_, _) => {
if (IsActiveTool ()) {
SetCursor (DefaultCursor);
}
};
}

public override string Name => Translations.GetString ("Clone Stamp");
public override string Icon => Pinta.Resources.Icons.ToolCloneStamp;
// Translators: {0} is 'Ctrl', or a platform-specific key such as 'Command' on macOS.
public override string StatusBarText => Translations.GetString ("{0} + left click to set origin, left click to paint.", system_manager.CtrlLabel ());
public override bool CursorChangesOnZoom => true;
public override Gdk.Key ShortcutKey => new (Gdk.Constants.KEY_L);
public override int Priority => 47;
protected override bool ShowAntialiasingButton => true;

public override Cursor DefaultCursor {
get {
double scale = workspace.GetScale ();
var icon = GdkExtensions.CreateIconWithShape ("Cursor.CloneStamp.png",
CursorShape.Ellipse, BrushWidth, 16, 26,
CursorShape.Ellipse, scale, BrushWidth, 16, 26,
out var iconOffsetX, out var iconOffsetY);
return Gdk.Cursor.NewFromTexture (icon, iconOffsetX, iconOffsetY, null);
}
Expand Down
12 changes: 11 additions & 1 deletion Pinta.Tools/Tools/ColorPickerTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,39 @@ public sealed class ColorPickerTool : BaseTool
{
private readonly IPaletteService palette;
private readonly IToolService tools;
private readonly IWorkspaceService workspace;

private MouseButton button_down;

public ColorPickerTool (IServiceProvider services) : base (services)
{
workspace = services.GetService<IWorkspaceService> ();
palette = services.GetService<IPaletteService> ();
tools = services.GetService<IToolService> ();

// Update cursor on zoom
workspace.ViewSizeChanged += (_, _) => {
if (IsActiveTool ()) {
SetCursor (DefaultCursor);
}
};
}

public override string Name => Translations.GetString ("Color Picker");
public override string Icon => Pinta.Resources.Icons.ToolColorPicker;
public override string StatusBarText => Translations.GetString ("Left click to set primary color.\nRight click to set secondary color.");
public override bool CursorChangesOnZoom => true;
public override Gdk.Key ShortcutKey => new (Gdk.Constants.KEY_K);
public override int Priority => 33;
private int SampleSize => SampleSizeDropDown.SelectedItem.GetTagOrDefault (1);
private bool SampleLayerOnly => SampleTypeDropDown.SelectedItem.GetTagOrDefault (false);

public override Gdk.Cursor DefaultCursor {
get {
double scale = workspace.GetScale ();
Gdk.Texture icon = GdkExtensions.CreateIconWithShape (
"Cursor.ColorPicker.png",
CursorShape.Rectangle,
scale,
SampleSize,
7,
27,
Expand Down
18 changes: 14 additions & 4 deletions Pinta.Tools/Tools/EraserTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,19 @@ private enum EraserType

private const int LUT_Resolution = 256;
private readonly Lazy<byte[,]> lazy_lut_factor = new (CreateLookupTable);
private readonly IWorkspaceService workspace;

public EraserTool (IServiceProvider services) : base (services) { }
public EraserTool (IServiceProvider services) : base (services)
{
workspace = services.GetService<IWorkspaceService> ();

// Update cursor on zoom
workspace.ViewSizeChanged += (_, _) => {
if (IsActiveTool ()) {
SetCursor (DefaultCursor);
}
};
}

public override string Name
=> Translations.GetString ("Eraser");
Expand All @@ -56,19 +67,18 @@ public override string Icon
public override string StatusBarText
=> Translations.GetString ("Left click to erase to transparent, right click to erase to secondary color. ");

public override bool CursorChangesOnZoom
=> true;

public override Gdk.Key ShortcutKey
=> new (Gdk.Constants.KEY_E);

public override int Priority => 27;

public override Gdk.Cursor DefaultCursor {
get {
double scale = workspace.GetScale ();
var icon = GdkExtensions.CreateIconWithShape (
"Cursor.Eraser.png",
CursorShape.Ellipse,
scale,
BrushWidth,
8,
22,
Expand Down
7 changes: 7 additions & 0 deletions Pinta.Tools/Tools/MagicWandTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ public MagicWandTool (IServiceProvider services) : base (services)
{
workspace = services.GetService<IWorkspaceService> ();
LimitToSelection = false;

// Update cursor on zoom
workspace.ViewSizeChanged += (_, _) => {
if (IsActiveTool ()) {
SetCursor (DefaultCursor);
}
};
}

public override Gdk.Key ShortcutKey => new (Gdk.Constants.KEY_S);
Expand Down
Loading
Loading