Skip to content

Commit 573dcb7

Browse files
authored
Merge branch 'master' into fix-image-dirty-state-on-close
2 parents 9dd962b + 16aa208 commit 573dcb7

230 files changed

Lines changed: 22467 additions & 17943 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ on:
55
push:
66
paths-ignore:
77
- '**.md'
8+
- '**.po'
9+
- '**.pot'
810
pull_request:
911
schedule:
1012
# Run every week just to make sure the CI environment still works.

CHANGELOG.md

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,87 @@
11
# Change Log
22
All notable changes to this project (beginning with version 1.7) will be documented in this file.
33

4-
## [Unreleased](https://github.com/PintaProject/Pinta/compare/3.0...HEAD)
4+
## [Unreleased](https://github.com/PintaProject/Pinta/compare/3.0.3...HEAD)
55

66
Thanks to the following contributors who worked on this release:
77
- @cameronwhite
88
- @badcel
9+
- @ericksson
910
- @JGCarroll
1011
- @Lehonti
1112
- @UrtsiSantsi
1213
- @pedropaulosuzuki
14+
- @bplaat
1315

1416
### Added
17+
- Implemented a new axonometric grid (View > Canvas Grid... > Show Axonometric Grid) (#1438, #1541)
1518
- Rewrote the canvas widget to improve performance and memory usage issues for zoomed-in images (#1020, #1485)
16-
- Added an option (View -> Show/Hide -> Menu Bar) to switch to a menu bar layout instead of a header bar (#781, #1418)
19+
- Added a new Cells effect (#1589)
1720
- The "About" dialog now includes links to the issue tracker and discussion forum (#1343)
1821
- When compiling Pinta, the GirCoreSource MSBuild property can be set to easily build Pinta against a local build of gir.core for easy debugging (#1403)
19-
- Pinta now configures a compatibility version number for add-ins, to support running add-ins built against older versions such as Pinta 3.0 (#1379, #1389)
2022
- Keyboard shortcuts are now displayed on all toolbar button tooltips (#1408, #1432)
23+
- Added a right click menu for layers, containing actions that can be applied to the selected layer (#1588)
24+
- The Dithering effect can now use Pinta's current palette in addition to the effect's preset color palettes (#1594)
25+
- Random seed values for effects can now be directly controlled, in addition to use the Reseed button (#1592, #1591)
26+
- Support for color picking in `SimpleEffectDialog`. Useful for add-in developers (#1611)
2127

2228
### Changed
2329
- Updated dependencies to require GTK 4.18+ and libadwaita 1.7+
24-
- Improved the sizing of the toolbox icons, particularly for high DPI displays (#1374)
25-
- The text tool now uses the system's default font rather than being hardcoded to Arial, which may not exist on some systems (#1422, #1421)
2630
- Removed use of deprecated Gtk.FontButton (#1421)
2731
- View menu moved from hamburger menu to dedicated button (#1428, #1471)
32+
- Updated the application icon on macOS to better match the platform's icon style guidelines (#1572)
2833

2934
### Fixed
30-
- Fixed an issue where the toolbar's height could change when switching tools (#1370, #1391)
3135
- Fixed a bug where cancelling the color picker dialog could still update the palette colors (#1390, #1411)
32-
- The text tool's "Normal and Outline" mode now draws the outline behind the text to avoid obscuring it (#1423, #1426)
36+
- The text tool's "Normal and Outline" mode now draws the outline behind the text to avoid obscuring it (#1423, #1426)
3337
- Improved the handling of negative angle values in the Rotate / Zoom Layer dialog (#1142, #1440)
34-
- Fixed potential crashes when adjusting the brush width (#1340)
38+
- Fixed incorrect behavior with transparent colors in the Gradient tool (#1552, #1543)
39+
- Fixed issues where the layer widget did not show the correct selected layer when switching documents (#1602, #1573)
40+
- Fixed toolbar layout issues with displaying the cursor position and selection size (#1429, #1540)
41+
42+
## [3.0.3](https://github.com/PintaProject/Pinta/release/tag/3.0.3) - 2025/08/01
43+
44+
Thanks to the following contributors who worked on this release:
45+
- @cameronwhite
46+
- @ericksson
47+
- @Lehonti
48+
49+
### Fixed
50+
- Fixed a packaging issue for the macOS arm64 build which caused many icons to disappear (#1605)
51+
- Fixed an issue where hiding a panel did not cause other panels to expand into the available space (#1472, #1500)
3552
- Fixed incorrect behavior of the Atkinson method in the Dithering effect (#1489)
53+
54+
## [3.0.2](https://github.com/PintaProject/Pinta/releases/tag/3.0.2) - 2025/07/06
55+
56+
Thanks to the following contributors who worked on this release:
57+
- @cameronwhite
58+
59+
### Fixed
60+
- Fixed an error when loading the add-in repositories (#1547, #1542)
61+
- Fixed a bug in the Levels dialog where the Red and Blue toggles were reversed (#1551)
62+
- The Vulkan DLL is now bundled with the Windows installer, which fixes errors on startup for certain systems (#1497, #1530)
63+
- Fixed performance issues when opening a large number of files (#1574, #1578)
64+
65+
## [3.0.1](https://github.com/PintaProject/Pinta/releases/tag/3.0.1) - 2025/06/07
66+
67+
Thanks to the following contributors who worked on this release:
68+
- @cameronwhite
69+
- @JGCarroll
70+
- @Lehonti
71+
- @UrtsiSantsi
72+
73+
### Added
74+
- Added an option (View -> Show/Hide -> Menu Bar) to switch to a menu bar layout instead of a header bar (#781, #1418)
75+
- Pinta now configures a compatibility version number for add-ins, to support running add-ins built against older versions such as Pinta 3.0 (#1379, #1389)
76+
77+
### Changed
78+
- Improved the sizing of the toolbox icons, particularly for high DPI displays (#1374)
79+
- The text tool now uses the system's default font rather than being hardcoded to Arial, which may not exist on some systems (#1422, #1421)
80+
- Updated translations
81+
82+
### Fixed
83+
- Fixed an issue where the toolbar's height could change when switching tools (#1370, #1391)
84+
- Fixed potential crashes when adjusting the brush width (#1340)
3685
- Fixed a bug on Windows where Pinta did not use the system's language for translations (#1473, #1493)
3786

3887
## [3.0](https://github.com/PintaProject/Pinta/releases/tag/3.0) - 2025/04/11

Directory.Packages.props

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@
1414
<PackageVersion Include="Mono.Addins.CecilReflector" Version="1.4.2-alpha.4" />
1515
<PackageVersion Include="NGettext" Version="0.6.7" />
1616
<PackageVersion Include="ParagonClipper" Version="6.4.2" />
17-
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
17+
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta6.25358.103" />
1818
<PackageVersion Include="Tmds.DBus" Version="0.21.2" />
1919

2020
<!-- Dependencies used for unit tests -->
21-
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
21+
<PackageVersion Include="BenchmarkDotNet" Version="0.15.2" />
2222
<PackageVersion Include="NUnit" Version="4.3.2" />
23-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
23+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
2424
<PackageVersion Include="NUnit3TestAdapter" Version="5.0.0" />
2525

2626
<!-- To resolve dependency conflict with GirCore.GObject-2.0.Integration and BenchmarkDotNet -->
27-
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
27+
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
2828
</ItemGroup>
2929
</Project>

Pinta.Core/Actions/FileActions.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
// THE SOFTWARE.
2626

2727
using System;
28+
using System.Linq;
29+
using System.Threading.Tasks;
2830

2931
namespace Pinta.Core;
3032

@@ -39,7 +41,14 @@ public sealed class FileActions
3941
public Command Print { get; }
4042

4143
public event EventHandler<ModifyCompressionEventArgs>? ModifyCompression;
42-
public event EventHandler<DocumentCancelEventArgs>? SaveDocument;
44+
45+
/// <remarks>
46+
/// The returned value is
47+
/// <see langword="true" /> if was save succeeded
48+
/// and
49+
/// <see langword="false" /> otherwise
50+
/// </remarks>
51+
public event AsyncEventHandler<FileActions, DocumentSaveEventArgs>.Returning<bool>? SaveDocument;
4352

4453
private readonly SystemManager system;
4554
private readonly AppActions app;
@@ -136,14 +145,18 @@ public void RegisterActions (Gtk.Application application, Gio.Menu menu)
136145

137146
public void RegisterHandlers () { }
138147

139-
internal bool RaiseSaveDocument (Document document, bool saveAs)
148+
/// <returns>
149+
/// <see langword="true"/> if the save succeeded,
150+
/// <see langword="false"/> otherwise (for example, if it was canceled)
151+
/// </returns>
152+
internal async Task<bool> RaiseSaveDocument (Document document, bool saveAs)
140153
{
141-
if (SaveDocument == null)
154+
if (SaveDocument is null)
142155
throw new InvalidOperationException ("GUI is not handling Workspace.SaveDocument");
143156

144-
DocumentCancelEventArgs e = new (document, saveAs);
145-
SaveDocument (this, e);
146-
return !e.Cancel;
157+
DocumentSaveEventArgs e = new (document, saveAs);
158+
var results = await SaveDocument.InvokeSequential (this, e);
159+
return results.All (succeeded => succeeded);
147160
}
148161

149162
internal int RaiseModifyCompression (int defaultCompression, Gtk.Window parent)

Pinta.Core/Actions/LayerActions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ private Gtk.FileFilter CreateImagesFileFilter ()
224224
{
225225
Gtk.FileFilter imagesFilter = Gtk.FileFilter.New ();
226226
foreach (var format in image_formats.Formats) {
227-
if (format.IsWriteOnly ()) continue;
227+
if (!format.IsImportAvailable ()) continue;
228228
foreach (string ext in format.Extensions)
229229
imagesFilter.AddPattern ($"*.{ext}");
230230
}

Pinta.Core/Actions/ViewActions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ public void RegisterActions (Gtk.Application app, Gio.Menu menu)
283283

284284
public void CreateStatusBar (Gtk.Box statusbar)
285285
{
286-
statusbar.Append (GtkExtensions.CreateToolBarSeparator ());
287286
statusbar.Append (ZoomOut.CreateToolBarItem ());
288287
statusbar.Append (ZoomComboBox);
289288
statusbar.Append (ZoomIn.CreateToolBarItem ());

Pinta.Core/Actions/WindowActions.cs

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,13 @@ public sealed class WindowActions
3131
private Gio.Menu doc_section = null!; // NRT - Set in RegisterActions
3232
private static readonly string doc_action_id = "active_document";
3333
private readonly Gio.SimpleAction active_doc_action;
34+
private uint deferred_update_event;
3435

3536
public Command SaveAll { get; }
3637
public Command CloseAll { get; }
3738

38-
private readonly ChromeManager chrome;
3939
private readonly WorkspaceManager workspace;
40-
public WindowActions (
41-
ChromeManager chrome,
42-
ToolManager tools,
43-
WorkspaceManager workspace)
40+
public WindowActions (WorkspaceManager workspace)
4441
{
4542
SaveAll = new Command (
4643
"SaveAll",
@@ -63,16 +60,8 @@ public WindowActions (
6360
GLib.Variant.NewInt32 (-1));
6461

6562
active_doc_action.OnActivate += (o, e) => {
66-
67-
var idx = e.Parameter!.GetInt32 ();
68-
69-
if (idx >= workspace.OpenDocuments.Count)
70-
return;
71-
72-
workspace.SetActiveDocumentInternal (
73-
tools,
74-
workspace.OpenDocuments[idx]);
75-
63+
int idx = e.Parameter!.GetInt32 ();
64+
workspace.SetActiveDocument (idx);
7665
active_doc_action.ChangeState (e.Parameter);
7766
};
7867

@@ -81,9 +70,10 @@ public WindowActions (
8170
e.Document.IsDirtyChanged += (_, _) => RebuildDocumentMenu ();
8271
AddDocumentMenuItem (workspace.OpenDocuments.IndexOf (e.Document));
8372
};
73+
74+
workspace.ActiveDocumentChanged += OnActiveDocumentChanged;
8475
workspace.DocumentClosed += (_, _) => RebuildDocumentMenu ();
8576

86-
this.chrome = chrome;
8777
this.workspace = workspace;
8878
}
8979

@@ -102,28 +92,24 @@ public void RegisterActions (
10292
CloseAll]);
10393

10494
app.AddAction (active_doc_action);
105-
}
10695

107-
public void SetActiveDocument (Document doc)
108-
{
109-
int idx = workspace.OpenDocuments.IndexOf (doc);
110-
active_doc_action.Activate (GLib.Variant.NewInt32 (idx));
96+
// Assign accelerators up to Alt-9 for the active documents.
97+
for (int i = 0; i < 9; ++i)
98+
app.SetAccelsForAction (BuildActionId (i), [$"<Alt>{i + 1}"]);
11199
}
112100

113101
private void AddDocumentMenuItem (int idx)
114102
{
115103
Document doc = workspace.OpenDocuments[idx];
116-
string action_id = $"app.{doc_action_id}({idx})";
117-
string label = $"{doc.DisplayName}{(doc.IsDirty ? '*' : string.Empty)}";
118-
Gio.MenuItem menu_item = Gio.MenuItem.New (label, action_id);
119-
120-
doc_section.AppendItem (menu_item);
104+
string actionId = BuildActionId (idx);
105+
string label = $"{doc.DisplayName}{(doc.IsDirty ? "*" : string.Empty)}";
121106

122-
// We only assign accelerators up to Alt-9
123-
if (idx < 9)
124-
chrome.Application.SetAccelsForAction (action_id, [$"<Alt>{idx + 1}"]);
107+
Gio.MenuItem menuItem = Gio.MenuItem.New (label, actionId);
108+
doc_section.AppendItem (menuItem);
125109
}
126110

111+
private static string BuildActionId (int idx) => $"app.{doc_action_id}({idx})";
112+
127113
private void RebuildDocumentMenu ()
128114
{
129115
doc_section.RemoveAll ();
@@ -133,4 +119,18 @@ private void RebuildDocumentMenu ()
133119

134120
workspace.ResetTitle ();
135121
}
122+
123+
private void OnActiveDocumentChanged (object? o, System.EventArgs eventArgs)
124+
{
125+
// Updating the action's state can be surprisingly expensive when e.g. opening
126+
// many documents (bug #1574), so an update is deferred until we return to the event loop.
127+
if (deferred_update_event > 0)
128+
return;
129+
130+
deferred_update_event = GLib.Functions.IdleAdd (GLib.Constants.PRIORITY_DEFAULT, () => {
131+
active_doc_action.ChangeState (GLib.Variant.NewInt32 (workspace.ActiveDocumentIndex));
132+
deferred_update_event = 0;
133+
return false;
134+
});
135+
}
136136
}

Pinta.Core/Algorithms/Mathematics.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ public static TNumber Magnitude<TNumber> (TNumber x, TNumber y) where TNumber :
2727
public static TNumber MagnitudeSquared<TNumber> (TNumber x, TNumber y) where TNumber : INumber<TNumber>
2828
=> x * x + y * y;
2929

30+
/// <summary>
31+
/// Linear interpolation for byte values, where the blend factor is from 0-255.
32+
/// </summary>
33+
public static byte LerpByte (byte from, byte to, byte frac)
34+
{
35+
return (byte) (from + ((to - from) * frac) / 255);
36+
}
37+
3038
/// <summary>Linear interpolation</summary>
3139
public static TNumber Lerp<TNumber> (
3240
TNumber from,

Pinta.Core/Algorithms/Sampling.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Collections.Immutable;
3+
4+
namespace Pinta.Core;
5+
6+
public static class Sampling
7+
{
8+
/// <returns>
9+
/// Offsets, from top left corner of points,
10+
/// where samples should be taken.
11+
/// </returns>
12+
public static ImmutableArray<PointD> CreateSamplingOffsets (int quality)
13+
{
14+
if (quality < 1)
15+
throw new ArgumentOutOfRangeException (nameof (quality));
16+
17+
var builder = ImmutableArray.CreateBuilder<PointD> ();
18+
builder.Capacity = quality * quality;
19+
double sectionSize = 1.0 / quality;
20+
double initial = sectionSize / 2;
21+
22+
for (int h = 0; h < quality; h++) {
23+
for (int v = 0; v < quality; v++) {
24+
double hOffset = sectionSize * h;
25+
double vOffset = sectionSize * v;
26+
PointD currentPoint = new (
27+
X: initial + hOffset,
28+
Y: initial + vOffset);
29+
builder.Add (currentPoint);
30+
}
31+
}
32+
33+
return builder.MoveToImmutable ();
34+
}
35+
}

0 commit comments

Comments
 (0)