From 05dfbe81c66a099355d555ef54f5563f87d9b9f4 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:29:04 +0000 Subject: [PATCH 01/30] Starts the change of ToolBarDropDownButton to Gtk.Dropdown Very buggy, tons of warnings --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 112 ++++++++++++++++---- 1 file changed, 93 insertions(+), 19 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 7ac6211c05..a3f1fcc555 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -5,13 +5,16 @@ namespace Pinta.Core; -public sealed class ToolBarDropDownButton : Gtk.MenuButton +public sealed class ToolBarDropDownButton : Gtk.DropDown { private const string ACTION_PREFIX = "tool"; - private readonly bool show_label; - private readonly Gio.Menu dropdown; - private readonly Gio.SimpleActionGroup action_group; + + private Gtk.Box selected_box; + private Gtk.Image dropdown_icon; + private Gtk.Label dropdown_label; + + private Gtk.StringList stringList; private ToolBarItem? selected_item; private readonly List items; @@ -19,17 +22,95 @@ public sealed class ToolBarDropDownButton : Gtk.MenuButton public ToolBarDropDownButton (bool showLabel = false) { - show_label = showLabel; + selected_box = new (); + dropdown_icon = new (); + dropdown_label = new (); + selected_box.Append (dropdown_icon); + selected_box.Append (dropdown_label); items = []; Items = new ReadOnlyCollection (items); - AlwaysShowArrow = true; + show_label = showLabel; + + stringList = new Gtk.StringList (); + SetModel (stringList); + + Gtk.SignalListItemFactory selectedFactory = new (); + selectedFactory.OnSetup += OnSetupSelectedItem; + selectedFactory.OnBind += OnBindSelectedItem; + SetFactory (selectedFactory); + + Gtk.SignalListItemFactory listFactory = new (); + listFactory.OnSetup += OnSetupListItem; + listFactory.OnBind += OnBindListItem; + SetListFactory (listFactory); + } + + private void OnSetupSelectedItem (Gtk.SignalListItemFactory factory, Gtk.SignalListItemFactory.SetupSignalArgs args) + { + Gtk.ListItem item = (Gtk.ListItem) args.Object; + if (item is null) { return; } + item.SetChild (selected_box); + } + + private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args) + { + Gtk.ListItem item = (Gtk.ListItem) args.Object; + if (item is null) { return; } - dropdown = Gio.Menu.New (); - MenuModel = dropdown; + var string_object = (Gtk.StringObject) item.GetItem (); + if (string_object is null) { return; } - action_group = Gio.SimpleActionGroup.New (); - InsertActionGroup (ACTION_PREFIX, action_group); + System.String[] strings = string_object.String.Split ("|"); + if (strings[1] is null) { return; } + + dropdown_icon.SetFromIconName (strings[1]); + if (show_label) { dropdown_label.SetText (strings[0]); } + + SelectedIndex = (int) Selected; + } + + private void OnSetupListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.SetupSignalArgs args) + { + Gtk.ListItem item = (Gtk.ListItem) args.Object; + if (item is null) { return; } + Gtk.Box box = new (); + + Gtk.Image image = new (); + Gtk.Label label = new (); + Gtk.Image selected_icon = new (); + selected_icon.SetFromIconName ("object-select-symbolic"); + item.BindProperty (Gtk.ListItem.SelectedPropertyDefinition.UnmanagedName, selected_icon, Gtk.Image.VisiblePropertyDefinition.UnmanagedName, GObject.BindingFlags.SyncCreate); + selected_icon.Hexpand = true; + selected_icon.Halign = Gtk.Align.End; + + box.Append (image); + box.Append (label); + box.Append (selected_icon); + + item.SetChild (box); + } + + private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args) + { + Gtk.ListItem item = (Gtk.ListItem) args.Object; + if (item is null) { return; } + Gtk.Box box = (Gtk.Box) item.GetChild (); + if (box is null) { return; } + + Gtk.StringObject string_object = (Gtk.StringObject) item.GetItem (); + if (string_object is null) { return; } + + System.String[] strings = string_object.String.Split ("|"); + if (strings[1] is null) { return; } + + Gtk.Image image = (Gtk.Image) box.GetFirstChild (); + if (image is null) { return; } + image.SetFromIconName (strings[1]); + + Gtk.Label label = (Gtk.Label) image.GetNextSibling (); + if (label is null) { return; } + label.SetText (strings[0]); } public ToolBarItem AddItem (string text, string imageId) @@ -40,11 +121,9 @@ public ToolBarItem AddItem (string text, string imageId) public ToolBarItem AddItem (string text, string imageId, object? tag) { ToolBarItem item = new ToolBarItem (text, imageId, tag); - action_group.AddAction (item.Action); - dropdown.AppendItem (Gio.MenuItem.New (text, $"{ACTION_PREFIX}.{item.Action.Name}")); + stringList.Append (text + "|" + imageId + "|" + $"{ACTION_PREFIX}.{item.Action.Name}"); items.Add (item); - item.Action.OnActivate += delegate { SetSelectedItem (item); }; if (selected_item == null) SetSelectedItem (item); @@ -78,15 +157,10 @@ public int SelectedIndex { private void SetSelectedItem (ToolBarItem item) { - IconName = item.ImageId; - selected_item = item; TooltipText = item.Text; - if (show_label) - Label = item.Text; - - OnSelectedItemChanged (); + // OnSelectedItemChanged (); } private void OnSelectedItemChanged () From 8458a050f296b45680efa80eece6d6027a09d29b Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:54:29 +0000 Subject: [PATCH 02/30] Fix whitespace --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index a3f1fcc555..8a2b09eead 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -74,7 +74,7 @@ private void OnSetupListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListIt { Gtk.ListItem item = (Gtk.ListItem) args.Object; if (item is null) { return; } - Gtk.Box box = new (); + Gtk.Box box = new (); Gtk.Image image = new (); Gtk.Label label = new (); @@ -88,7 +88,7 @@ private void OnSetupListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListIt box.Append (label); box.Append (selected_icon); - item.SetChild (box); + item.SetChild (box); } private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args) From 8816bef2c8d2617c99363d2289ee8af86c676c59 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Fri, 3 Apr 2026 23:34:50 +0000 Subject: [PATCH 03/30] Fix selected property of ListItem and move widgets to ToolBarItem --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 84 ++++++++++----------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 8a2b09eead..ad086c356b 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -16,6 +16,7 @@ public sealed class ToolBarDropDownButton : Gtk.DropDown private Gtk.StringList stringList; private ToolBarItem? selected_item; + private int previous_index = 0; private readonly List items; public ReadOnlyCollection Items { get; } @@ -41,7 +42,6 @@ public ToolBarDropDownButton (bool showLabel = false) SetFactory (selectedFactory); Gtk.SignalListItemFactory listFactory = new (); - listFactory.OnSetup += OnSetupListItem; listFactory.OnBind += OnBindListItem; SetListFactory (listFactory); } @@ -57,60 +57,28 @@ private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalLis { Gtk.ListItem item = (Gtk.ListItem) args.Object; if (item is null) { return; } + if (item.Position > 10000) { return; } - var string_object = (Gtk.StringObject) item.GetItem (); - if (string_object is null) { return; } + ToolBarItem toolbar_item = items[(int) item.Position]; - System.String[] strings = string_object.String.Split ("|"); - if (strings[1] is null) { return; } - - dropdown_icon.SetFromIconName (strings[1]); - if (show_label) { dropdown_label.SetText (strings[0]); } + dropdown_icon.SetFromIconName (toolbar_item.ImageId); + if (show_label) { dropdown_label.SetText (toolbar_item.Text); } + items[previous_index].SetSelected (false); + previous_index = (int) Selected; + items[previous_index].SetSelected (true); SelectedIndex = (int) Selected; } - private void OnSetupListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.SetupSignalArgs args) - { - Gtk.ListItem item = (Gtk.ListItem) args.Object; - if (item is null) { return; } - Gtk.Box box = new (); - - Gtk.Image image = new (); - Gtk.Label label = new (); - Gtk.Image selected_icon = new (); - selected_icon.SetFromIconName ("object-select-symbolic"); - item.BindProperty (Gtk.ListItem.SelectedPropertyDefinition.UnmanagedName, selected_icon, Gtk.Image.VisiblePropertyDefinition.UnmanagedName, GObject.BindingFlags.SyncCreate); - selected_icon.Hexpand = true; - selected_icon.Halign = Gtk.Align.End; - - box.Append (image); - box.Append (label); - box.Append (selected_icon); - - item.SetChild (box); - } - private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args) { Gtk.ListItem item = (Gtk.ListItem) args.Object; if (item is null) { return; } - Gtk.Box box = (Gtk.Box) item.GetChild (); - if (box is null) { return; } - - Gtk.StringObject string_object = (Gtk.StringObject) item.GetItem (); - if (string_object is null) { return; } - - System.String[] strings = string_object.String.Split ("|"); - if (strings[1] is null) { return; } - - Gtk.Image image = (Gtk.Image) box.GetFirstChild (); - if (image is null) { return; } - image.SetFromIconName (strings[1]); + System.Console.WriteLine (item.Position); + if (item.Position > 10000) { return; } - Gtk.Label label = (Gtk.Label) image.GetNextSibling (); - if (label is null) { return; } - label.SetText (strings[0]); + ToolBarItem toolbar_item = items[(int) item.Position]; + item.SetChild (toolbar_item.Box); } public ToolBarItem AddItem (string text, string imageId) @@ -121,7 +89,7 @@ public ToolBarItem AddItem (string text, string imageId) public ToolBarItem AddItem (string text, string imageId, object? tag) { ToolBarItem item = new ToolBarItem (text, imageId, tag); - stringList.Append (text + "|" + imageId + "|" + $"{ACTION_PREFIX}.{item.Action.Name}"); + stringList.Append (""); items.Add (item); @@ -183,15 +151,41 @@ public ToolBarItem (string text, string imageId, object? tag) ImageId = imageId; Action = Gio.SimpleAction.New (actionName, null); Tag = tag; + + Box = new (); + Image = new (); + Label = new (); + SelectedIcon = new (); + SelectedIcon.SetFromIconName ("object-select-symbolic"); + SelectedIcon.Visible = false; + + SelectedIcon.Hexpand = true; + SelectedIcon.Halign = Gtk.Align.End; + + Box.Append (Image); + Box.Append (Label); + Box.Append (SelectedIcon); + + Image.SetFromIconName (imageId); + Label.SetText (text); } private static string AdjustName (string baseName) => string.Concat (baseName.Where (c => !char.IsWhiteSpace (c))); + public void SetSelected (bool selected) { + SelectedIcon.Visible = selected; + } + public string ImageId { get; } public object? Tag { get; } public string Text { get; } public Gio.SimpleAction Action { get; } + public Gtk.Box Box { get; } + + private Gtk.Image Image; + private Gtk.Label Label; + private Gtk.Image SelectedIcon; public T GetTagOrDefault (T defaultValue) => Tag is T value ? value : defaultValue; From 6cebe2eb87b8670f26b50270758acd20b9acab00 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Fri, 3 Apr 2026 23:41:15 +0000 Subject: [PATCH 04/30] I'll never get used to { on another line --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index ad086c356b..aa897303dc 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -173,7 +173,8 @@ public ToolBarItem (string text, string imageId, object? tag) private static string AdjustName (string baseName) => string.Concat (baseName.Where (c => !char.IsWhiteSpace (c))); - public void SetSelected (bool selected) { + public void SetSelected (bool selected) + { SelectedIcon.Visible = selected; } From d9379b23a33b5c8cb418d64a32fba01501d121bc Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Fri, 3 Apr 2026 23:50:21 +0000 Subject: [PATCH 05/30] whitespace --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index aa897303dc..cb6c29242c 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -151,7 +151,7 @@ public ToolBarItem (string text, string imageId, object? tag) ImageId = imageId; Action = Gio.SimpleAction.New (actionName, null); Tag = tag; - + Box = new (); Image = new (); Label = new (); From 72a32a6ca4ed05ec6cd35a95726c909f755b8b33 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Fri, 3 Apr 2026 23:54:55 +0000 Subject: [PATCH 06/30] Remove console.log --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index cb6c29242c..455c15ad06 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -74,7 +74,6 @@ private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListIte { Gtk.ListItem item = (Gtk.ListItem) args.Object; if (item is null) { return; } - System.Console.WriteLine (item.Position); if (item.Position > 10000) { return; } ToolBarItem toolbar_item = items[(int) item.Position]; From 2d5ace68fb525c79df63e69704ab42a9caa1b6cd Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:35:06 +0000 Subject: [PATCH 07/30] Only change SelectedIndex if current_index is different from previous_index --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 455c15ad06..e294251ecf 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -64,10 +64,13 @@ private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalLis dropdown_icon.SetFromIconName (toolbar_item.ImageId); if (show_label) { dropdown_label.SetText (toolbar_item.Text); } - items[previous_index].SetSelected (false); - previous_index = (int) Selected; - items[previous_index].SetSelected (true); - SelectedIndex = (int) Selected; + int current_index = (int) Selected; + if (previous_index != current_index) { + items[previous_index].SetSelected (false); + items[current_index].SetSelected (true); + previous_index = current_index; + SelectedIndex = current_index; + } } private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args) @@ -127,7 +130,7 @@ private void SetSelectedItem (ToolBarItem item) selected_item = item; TooltipText = item.Text; - // OnSelectedItemChanged (); + OnSelectedItemChanged (); } private void OnSelectedItemChanged () From fa66ab2423f0d6bacf65c1927212c6e7fcb52a17 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:46:44 +0000 Subject: [PATCH 08/30] ToolBarDropDownButton - Explicitly override base property SelectedItem with new keyword --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index e294251ecf..f5f73f0a4a 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -101,7 +101,7 @@ public ToolBarItem AddItem (string text, string imageId, object? tag) return item; } - public ToolBarItem SelectedItem { + public new ToolBarItem SelectedItem { get => selected_item is not null ? selected_item From 8496c3ac0e3f0a7c24d8fe78c216997af2b108d8 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:14:25 +0000 Subject: [PATCH 09/30] Fix check icon not being visible when selection is zero --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index f5f73f0a4a..1509ed3596 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -7,7 +7,6 @@ namespace Pinta.Core; public sealed class ToolBarDropDownButton : Gtk.DropDown { - private const string ACTION_PREFIX = "tool"; private readonly bool show_label; private Gtk.Box selected_box; @@ -57,7 +56,6 @@ private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalLis { Gtk.ListItem item = (Gtk.ListItem) args.Object; if (item is null) { return; } - if (item.Position > 10000) { return; } ToolBarItem toolbar_item = items[(int) item.Position]; @@ -66,8 +64,8 @@ private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalLis int current_index = (int) Selected; if (previous_index != current_index) { - items[previous_index].SetSelected (false); - items[current_index].SetSelected (true); + items[previous_index]..SetSelectedIconVisible (false); + items[current_index]..SetSelectedIconVisible (true); previous_index = current_index; SelectedIndex = current_index; } @@ -77,7 +75,6 @@ private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListIte { Gtk.ListItem item = (Gtk.ListItem) args.Object; if (item is null) { return; } - if (item.Position > 10000) { return; } ToolBarItem toolbar_item = items[(int) item.Position]; item.SetChild (toolbar_item.Box); @@ -93,6 +90,7 @@ public ToolBarItem AddItem (string text, string imageId, object? tag) ToolBarItem item = new ToolBarItem (text, imageId, tag); stringList.Append (""); + if (items.Count == 0 && previous_index == 0) { item.SetSelectedIconVisible (true); } items.Add (item); if (selected_item == null) @@ -129,6 +127,7 @@ private void SetSelectedItem (ToolBarItem item) { selected_item = item; TooltipText = item.Text; + Selected = (uint) items.IndexOf (selected_item); OnSelectedItemChanged (); } @@ -147,11 +146,8 @@ public ToolBarItem (string text, string imageId) : this (text, imageId, null) { public ToolBarItem (string text, string imageId, object? tag) { - var actionName = AdjustName (text); - Text = text; ImageId = imageId; - Action = Gio.SimpleAction.New (actionName, null); Tag = tag; Box = new (); @@ -172,18 +168,14 @@ public ToolBarItem (string text, string imageId, object? tag) Label.SetText (text); } - private static string AdjustName (string baseName) - => string.Concat (baseName.Where (c => !char.IsWhiteSpace (c))); - - public void SetSelected (bool selected) + public void SetSelectedIconVisible (bool visible) { - SelectedIcon.Visible = selected; + SelectedIcon.Visible = visible; } public string ImageId { get; } public object? Tag { get; } public string Text { get; } - public Gio.SimpleAction Action { get; } public Gtk.Box Box { get; } private Gtk.Image Image; From 65f25f7a57d0d9ed19df47972542ec0b24c1c4ae Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:15:08 +0000 Subject: [PATCH 10/30] Fix typo --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 1509ed3596..66994aa8b7 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -64,8 +64,8 @@ private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalLis int current_index = (int) Selected; if (previous_index != current_index) { - items[previous_index]..SetSelectedIconVisible (false); - items[current_index]..SetSelectedIconVisible (true); + items[previous_index].SetSelectedIconVisible (false); + items[current_index].SetSelectedIconVisible (true); previous_index = current_index; SelectedIndex = current_index; } From 6dba0de96d36e591f9b635c09351cc71e426c944 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:37:22 +0000 Subject: [PATCH 11/30] Reduce verbosity with syntactic sugar (omitting type on new) --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 66994aa8b7..841cfc4f6b 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -29,10 +29,10 @@ public ToolBarDropDownButton (bool showLabel = false) selected_box.Append (dropdown_label); items = []; - Items = new ReadOnlyCollection (items); + Items = new (items); show_label = showLabel; - stringList = new Gtk.StringList (); + stringList = new (); SetModel (stringList); Gtk.SignalListItemFactory selectedFactory = new (); @@ -87,7 +87,7 @@ public ToolBarItem AddItem (string text, string imageId) public ToolBarItem AddItem (string text, string imageId, object? tag) { - ToolBarItem item = new ToolBarItem (text, imageId, tag); + ToolBarItem item = new (text, imageId, tag); stringList.Append (""); if (items.Count == 0 && previous_index == 0) { item.SetSelectedIconVisible (true); } From 882e504f7fe1608eb7018cbe11fa7fe6e88d31fd Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Tue, 7 Apr 2026 13:24:36 +0000 Subject: [PATCH 12/30] Turns ToolBarItem into a Gtk.Box --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 841cfc4f6b..b74a2a18bf 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -77,7 +77,7 @@ private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListIte if (item is null) { return; } ToolBarItem toolbar_item = items[(int) item.Position]; - item.SetChild (toolbar_item.Box); + item.SetChild (toolbar_item); } public ToolBarItem AddItem (string text, string imageId) @@ -140,7 +140,7 @@ private void OnSelectedItemChanged () public event EventHandler? SelectedItemChanged; } -public sealed class ToolBarItem +public sealed class ToolBarItem : Gtk.Box { public ToolBarItem (string text, string imageId) : this (text, imageId, null) { } @@ -150,7 +150,6 @@ public ToolBarItem (string text, string imageId, object? tag) ImageId = imageId; Tag = tag; - Box = new (); Image = new (); Label = new (); SelectedIcon = new (); @@ -160,9 +159,9 @@ public ToolBarItem (string text, string imageId, object? tag) SelectedIcon.Hexpand = true; SelectedIcon.Halign = Gtk.Align.End; - Box.Append (Image); - Box.Append (Label); - Box.Append (SelectedIcon); + Append (Image); + Append (Label); + Append (SelectedIcon); Image.SetFromIconName (imageId); Label.SetText (text); @@ -176,7 +175,6 @@ public void SetSelectedIconVisible (bool visible) public string ImageId { get; } public object? Tag { get; } public string Text { get; } - public Gtk.Box Box { get; } private Gtk.Image Image; private Gtk.Label Label; From f8f684e89858655b350a4291177c938920de9608 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Tue, 7 Apr 2026 13:46:05 +0000 Subject: [PATCH 13/30] Remove private Image and Label properties from ToolBarItem They were not updated anywhere, so it's safe to remove them --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index b74a2a18bf..4ef6775f8d 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -150,8 +150,14 @@ public ToolBarItem (string text, string imageId, object? tag) ImageId = imageId; Tag = tag; - Image = new (); - Label = new (); + Gtk.Image image = new (); + image.SetFromIconName (imageId); + Gtk.Label label = new (); + label.SetText (text); + + Append (image); + Append (label); + SelectedIcon = new (); SelectedIcon.SetFromIconName ("object-select-symbolic"); SelectedIcon.Visible = false; @@ -159,12 +165,7 @@ public ToolBarItem (string text, string imageId, object? tag) SelectedIcon.Hexpand = true; SelectedIcon.Halign = Gtk.Align.End; - Append (Image); - Append (Label); Append (SelectedIcon); - - Image.SetFromIconName (imageId); - Label.SetText (text); } public void SetSelectedIconVisible (bool visible) @@ -176,8 +177,6 @@ public void SetSelectedIconVisible (bool visible) public object? Tag { get; } public string Text { get; } - private Gtk.Image Image; - private Gtk.Label Label; private Gtk.Image SelectedIcon; public T GetTagOrDefault (T defaultValue) From 7f475e33bafc6a35b75cfda59f9483f5d5287121 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:40:48 +0000 Subject: [PATCH 14/30] Use Gio.ListStore instead of Gtk.StringList --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 4ef6775f8d..b4d04fe604 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -13,7 +13,7 @@ public sealed class ToolBarDropDownButton : Gtk.DropDown private Gtk.Image dropdown_icon; private Gtk.Label dropdown_label; - private Gtk.StringList stringList; + private Gio.ListStore widgetList; private ToolBarItem? selected_item; private int previous_index = 0; @@ -32,8 +32,8 @@ public ToolBarDropDownButton (bool showLabel = false) Items = new (items); show_label = showLabel; - stringList = new (); - SetModel (stringList); + widgetList = Gio.ListStore.New (ToolBarItem.GetGType ()); + SetModel (widgetList); Gtk.SignalListItemFactory selectedFactory = new (); selectedFactory.OnSetup += OnSetupSelectedItem; @@ -88,7 +88,7 @@ public ToolBarItem AddItem (string text, string imageId) public ToolBarItem AddItem (string text, string imageId, object? tag) { ToolBarItem item = new (text, imageId, tag); - stringList.Append (""); + widgetList.Append (item); if (items.Count == 0 && previous_index == 0) { item.SetSelectedIconVisible (true); } items.Add (item); @@ -161,7 +161,6 @@ public ToolBarItem (string text, string imageId, object? tag) SelectedIcon = new (); SelectedIcon.SetFromIconName ("object-select-symbolic"); SelectedIcon.Visible = false; - SelectedIcon.Hexpand = true; SelectedIcon.Halign = Gtk.Align.End; From dbdaf0c31717e193ccad65961b9b06592b0c37f4 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Wed, 8 Apr 2026 01:44:19 +0000 Subject: [PATCH 15/30] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8deedf34f0..967200cf8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Thanks to the following contributors who worked on this release: - Adjusted the layout of the layers panel to avoid issues with overlay scrollbars preventing the visibility toggle from being clicked (#1828, #2021) - Gradient types and colors can now be changed before finalizing the gradient (#2058, #2059) - Moved the Layers menu out of the main menu. The actions are available from a menu button in the Layers panel, or from right-clicking on layers (#1386, #2056) +- Dropdowns in the toolbar now show the icons of each option and highlight the currently selected item when opened (#1977, #2092) ### Fixed - Fixed a bug where duplicate submenus could be produced by add-ins with effect categories that were not translated (#1933, #1935) From 00dd84a860b1d15ed2567e1c44c94c1a22424d2c Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:12:10 +0000 Subject: [PATCH 16/30] ToolBarDropDownButton: Separate ToolBarItem from ToolBarItemWidget --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 45 ++++++++++++--------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index b4d04fe604..2a9536e5a4 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -18,6 +18,7 @@ public sealed class ToolBarDropDownButton : Gtk.DropDown private int previous_index = 0; private readonly List items; + private readonly List toolbar_item_widgets; public ReadOnlyCollection Items { get; } public ToolBarDropDownButton (bool showLabel = false) @@ -30,9 +31,10 @@ public ToolBarDropDownButton (bool showLabel = false) items = []; Items = new (items); + toolbar_item_widgets = []; show_label = showLabel; - widgetList = Gio.ListStore.New (ToolBarItem.GetGType ()); + widgetList = Gio.ListStore.New (ToolBarItemWidget.GetGType ()); SetModel (widgetList); Gtk.SignalListItemFactory selectedFactory = new (); @@ -54,18 +56,15 @@ private void OnSetupSelectedItem (Gtk.SignalListItemFactory factory, Gtk.SignalL private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args) { - Gtk.ListItem item = (Gtk.ListItem) args.Object; - if (item is null) { return; } - - ToolBarItem toolbar_item = items[(int) item.Position]; + ToolBarItem toolbar_item = items[(int) Selected]; dropdown_icon.SetFromIconName (toolbar_item.ImageId); if (show_label) { dropdown_label.SetText (toolbar_item.Text); } int current_index = (int) Selected; if (previous_index != current_index) { - items[previous_index].SetSelectedIconVisible (false); - items[current_index].SetSelectedIconVisible (true); + toolbar_item_widgets[previous_index].SetSelectedIconVisible (false); + toolbar_item_widgets[current_index].SetSelectedIconVisible (true); previous_index = current_index; SelectedIndex = current_index; } @@ -76,7 +75,7 @@ private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListIte Gtk.ListItem item = (Gtk.ListItem) args.Object; if (item is null) { return; } - ToolBarItem toolbar_item = items[(int) item.Position]; + ToolBarItemWidget toolbar_item = toolbar_item_widgets[(int) item.Position]; item.SetChild (toolbar_item); } @@ -87,10 +86,12 @@ public ToolBarItem AddItem (string text, string imageId) public ToolBarItem AddItem (string text, string imageId, object? tag) { - ToolBarItem item = new (text, imageId, tag); - widgetList.Append (item); + ToolBarItemWidget widget = new (text, imageId); + toolbar_item_widgets.Add (widget); + widgetList.Append (widget); - if (items.Count == 0 && previous_index == 0) { item.SetSelectedIconVisible (true); } + ToolBarItem item = new (text, imageId, tag); + if (items.Count == 0 && previous_index == 0) { widget.SetSelectedIconVisible (true); } items.Add (item); if (selected_item == null) @@ -140,7 +141,7 @@ private void OnSelectedItemChanged () public event EventHandler? SelectedItemChanged; } -public sealed class ToolBarItem : Gtk.Box +public sealed class ToolBarItem { public ToolBarItem (string text, string imageId) : this (text, imageId, null) { } @@ -149,7 +150,20 @@ public ToolBarItem (string text, string imageId, object? tag) Text = text; ImageId = imageId; Tag = tag; + } + public string ImageId { get; } + public object? Tag { get; } + public string Text { get; } + + public T GetTagOrDefault (T defaultValue) + => Tag is T value ? value : defaultValue; +} + +public sealed class ToolBarItemWidget : Gtk.Box +{ + public ToolBarItemWidget (string text, string imageId) + { Gtk.Image image = new (); image.SetFromIconName (imageId); Gtk.Label label = new (); @@ -172,12 +186,5 @@ public void SetSelectedIconVisible (bool visible) SelectedIcon.Visible = visible; } - public string ImageId { get; } - public object? Tag { get; } - public string Text { get; } - private Gtk.Image SelectedIcon; - - public T GetTagOrDefault (T defaultValue) - => Tag is T value ? value : defaultValue; } From d3fccf718120dc2195e98dba7d99edf80b11f139 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:26:48 +0000 Subject: [PATCH 17/30] Use snake_case for private fields --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 2a9536e5a4..389f0b3df7 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -13,7 +13,7 @@ public sealed class ToolBarDropDownButton : Gtk.DropDown private Gtk.Image dropdown_icon; private Gtk.Label dropdown_label; - private Gio.ListStore widgetList; + private Gio.ListStore widget_list; private ToolBarItem? selected_item; private int previous_index = 0; @@ -34,8 +34,8 @@ public ToolBarDropDownButton (bool showLabel = false) toolbar_item_widgets = []; show_label = showLabel; - widgetList = Gio.ListStore.New (ToolBarItemWidget.GetGType ()); - SetModel (widgetList); + widget_list = Gio.ListStore.New (ToolBarItemWidget.GetGType ()); + SetModel (widget_list); Gtk.SignalListItemFactory selectedFactory = new (); selectedFactory.OnSetup += OnSetupSelectedItem; @@ -172,19 +172,19 @@ public ToolBarItemWidget (string text, string imageId) Append (image); Append (label); - SelectedIcon = new (); - SelectedIcon.SetFromIconName ("object-select-symbolic"); - SelectedIcon.Visible = false; - SelectedIcon.Hexpand = true; - SelectedIcon.Halign = Gtk.Align.End; + selected_icon = new (); + selected_icon.SetFromIconName ("object-select-symbolic"); + selected_icon.Visible = false; + selected_icon.Hexpand = true; + selected_icon.Halign = Gtk.Align.End; - Append (SelectedIcon); + Append (selected_icon); } public void SetSelectedIconVisible (bool visible) { - SelectedIcon.Visible = visible; + selected_icon.Visible = visible; } - private Gtk.Image SelectedIcon; + private Gtk.Image selected_icon; } From e5b0760afc9011fc04e3cfa092b0de516701f1a2 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:30:08 +0000 Subject: [PATCH 18/30] Adds ObjectSelect icon --- Pinta.Resources/Icons.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Pinta.Resources/Icons.cs b/Pinta.Resources/Icons.cs index c778f8fc9d..7bbae7916f 100644 --- a/Pinta.Resources/Icons.cs +++ b/Pinta.Resources/Icons.cs @@ -65,6 +65,7 @@ public static class StandardIcons public const string LayerMoveDown = "pan-down-symbolic"; public const string OpenMenu = "open-menu-symbolic"; + public const string ObjectSelect = "object-select-symbolic"; public const string ApplicationAddon = "application-x-addon-symbolic"; public const string SystemSearch = "system-search-symbolic"; From 363a2f6b3c703f0664d4cb53de8c90d997aa9eb9 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:37:28 +0000 Subject: [PATCH 19/30] Fix typo --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 389f0b3df7..6a2571745f 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -88,7 +88,7 @@ public ToolBarItem AddItem (string text, string imageId, object? tag) { ToolBarItemWidget widget = new (text, imageId); toolbar_item_widgets.Add (widget); - widgetList.Append (widget); + widget_list.Append (widget); ToolBarItem item = new (text, imageId, tag); if (items.Count == 0 && previous_index == 0) { widget.SetSelectedIconVisible (true); } From f4de0c337c58f55badb019a5c632ad41a636376e Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:42:13 +0000 Subject: [PATCH 20/30] Move ObjectSelect icon string to Resources.StandardIcons --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 6a2571745f..48d1ad953e 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -173,7 +173,7 @@ public ToolBarItemWidget (string text, string imageId) Append (label); selected_icon = new (); - selected_icon.SetFromIconName ("object-select-symbolic"); + selected_icon.SetFromIconName (Resources.StandardIcons.ObjectSelect); selected_icon.Visible = false; selected_icon.Hexpand = true; selected_icon.Halign = Gtk.Align.End; From 28ab4d9a00a31f31c431cbf46dc0769d5b47e9f7 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Thu, 16 Apr 2026 12:23:17 +0000 Subject: [PATCH 21/30] Add comments for ToolBarDropDown implementation details --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 48d1ad953e..f8ab9573c1 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -23,6 +23,9 @@ public sealed class ToolBarDropDownButton : Gtk.DropDown public ToolBarDropDownButton (bool showLabel = false) { + // We create the widgets inside the dropdown to avoid having to create yet another custom widget + // for the selectedFactory. Also, we can reference them directly when updated, avoiding + // .nextSibling hacks. selected_box = new (); dropdown_icon = new (); dropdown_label = new (); @@ -61,6 +64,9 @@ private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalLis dropdown_icon.SetFromIconName (toolbar_item.ImageId); if (show_label) { dropdown_label.SetText (toolbar_item.Text); } + // We store the index of the previous selection to avoid having to iterate through all items on the list. + // Also we check if the index changed because OnBindSelectedItem gets called both when the selected item changes + // and on the widget initialization/setup. int current_index = (int) Selected; if (previous_index != current_index) { toolbar_item_widgets[previous_index].SetSelectedIconVisible (false); @@ -91,6 +97,7 @@ public ToolBarItem AddItem (string text, string imageId, object? tag) widget_list.Append (widget); ToolBarItem item = new (text, imageId, tag); + // This is done to ensure the first item has a checkmark if it was selected. if (items.Count == 0 && previous_index == 0) { widget.SetSelectedIconVisible (true); } items.Add (item); From e9b4cbcfebf3f5cddb92c22463baa4c10e945ae3 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Thu, 16 Apr 2026 12:49:28 +0000 Subject: [PATCH 22/30] Revert to using Gtk.StringList instead of Gio.ListStore --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index f8ab9573c1..1a610db6cd 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -13,7 +13,7 @@ public sealed class ToolBarDropDownButton : Gtk.DropDown private Gtk.Image dropdown_icon; private Gtk.Label dropdown_label; - private Gio.ListStore widget_list; + private Gtk.StringList string_list; private ToolBarItem? selected_item; private int previous_index = 0; @@ -37,7 +37,7 @@ public ToolBarDropDownButton (bool showLabel = false) toolbar_item_widgets = []; show_label = showLabel; - widget_list = Gio.ListStore.New (ToolBarItemWidget.GetGType ()); + string_list = new (); SetModel (widget_list); Gtk.SignalListItemFactory selectedFactory = new (); @@ -94,7 +94,11 @@ public ToolBarItem AddItem (string text, string imageId, object? tag) { ToolBarItemWidget widget = new (text, imageId); toolbar_item_widgets.Add (widget); - widget_list.Append (widget); + // We append an empty string because we only need the list's index. + // Otherwise, we'd need to make ToolBarItem inherit from GObject, which is undesired. + // Also, we'd need the indexes anyway to update the previous selection, so + // storing anything else is not required. + string_list.Append (""); ToolBarItem item = new (text, imageId, tag); // This is done to ensure the first item has a checkmark if it was selected. From e6494b816196979ff6b9296206e57d03b94531de Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Thu, 16 Apr 2026 12:51:19 +0000 Subject: [PATCH 23/30] Fix typo --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 1a610db6cd..fcb572f228 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -38,7 +38,7 @@ public ToolBarDropDownButton (bool showLabel = false) show_label = showLabel; string_list = new (); - SetModel (widget_list); + SetModel (string_list); Gtk.SignalListItemFactory selectedFactory = new (); selectedFactory.OnSetup += OnSetupSelectedItem; From f703636e00cbfce1617a9932a1c8db69667c4bbd Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:33:57 +0000 Subject: [PATCH 24/30] Remove private selected_item field and organize selection update better --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 60 ++++++++------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index fcb572f228..107cb1e780 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -13,9 +13,9 @@ public sealed class ToolBarDropDownButton : Gtk.DropDown private Gtk.Image dropdown_icon; private Gtk.Label dropdown_label; - private Gtk.StringList string_list; - private ToolBarItem? selected_item; + // We store the index of the previous selection to avoid having to iterate through all items on the list. private int previous_index = 0; + private Gtk.StringList string_list; private readonly List items; private readonly List toolbar_item_widgets; @@ -64,16 +64,11 @@ private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalLis dropdown_icon.SetFromIconName (toolbar_item.ImageId); if (show_label) { dropdown_label.SetText (toolbar_item.Text); } - // We store the index of the previous selection to avoid having to iterate through all items on the list. - // Also we check if the index changed because OnBindSelectedItem gets called both when the selected item changes - // and on the widget initialization/setup. - int current_index = (int) Selected; - if (previous_index != current_index) { - toolbar_item_widgets[previous_index].SetSelectedIconVisible (false); - toolbar_item_widgets[current_index].SetSelectedIconVisible (true); - previous_index = current_index; - SelectedIndex = current_index; - } + + // SetSelectedIndex checks if the index changed, so we don't need to check here again. This check + // is important because OnBindSelectedItem gets called both when the selected item changes and on + // widget initialization/setup. + SetSelectedIndex ((int) Selected); } private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args) @@ -105,42 +100,33 @@ public ToolBarItem AddItem (string text, string imageId, object? tag) if (items.Count == 0 && previous_index == 0) { widget.SetSelectedIconVisible (true); } items.Add (item); - if (selected_item == null) - SetSelectedItem (item); - return item; } public new ToolBarItem SelectedItem { - get => - selected_item is not null - ? selected_item - : throw new InvalidOperationException ("Attempted to get SelectedItem from a drop down with no items."); - set { - if (selected_item != value) - SetSelectedItem (value); - } + get => items.Count == 0 + ? throw new InvalidOperationException ("Attempted to get SelectedItem from a drop down with no items.") + : items[previous_index]; + set { SetSelectedIndex (items.IndexOf (value)); } } public int SelectedIndex { - get => selected_item is null ? -1 : items.IndexOf (selected_item); - set { - if (value < 0 || value >= items.Count) - return; - - var item = items[value]; - - if (item != selected_item) - SetSelectedItem (item); - } + get => items.Count == 0 ? -1 : previous_index; + set { SetSelectedIndex(value); } } - private void SetSelectedItem (ToolBarItem item) + private void SetSelectedIndex (int index) { - selected_item = item; - TooltipText = item.Text; - Selected = (uint) items.IndexOf (selected_item); + if (index < 0 || index > items.Count || index == previous_index) { + return; + } + + toolbar_item_widgets[previous_index].SetSelectedIconVisible (false); + toolbar_item_widgets[index].SetSelectedIconVisible (true); + TooltipText = items[index].Text; + Selected = (uint) index; + previous_index = index; OnSelectedItemChanged (); } From 0c7a8fe92c08ab73cc4d9ba7fd867f3b53506289 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:35:58 +0000 Subject: [PATCH 25/30] FIx Whitespace --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 107cb1e780..04c38e0c3e 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -112,7 +112,7 @@ public ToolBarItem AddItem (string text, string imageId, object? tag) public int SelectedIndex { get => items.Count == 0 ? -1 : previous_index; - set { SetSelectedIndex(value); } + set { SetSelectedIndex (value); } } private void SetSelectedIndex (int index) From 8e7bae9848e4d7068a46339ef29855a067c547be Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:37:56 +0000 Subject: [PATCH 26/30] Fix whitespace 2 --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 04c38e0c3e..419c6907c8 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -64,7 +64,6 @@ private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalLis dropdown_icon.SetFromIconName (toolbar_item.ImageId); if (show_label) { dropdown_label.SetText (toolbar_item.Text); } - // SetSelectedIndex checks if the index changed, so we don't need to check here again. This check // is important because OnBindSelectedItem gets called both when the selected item changes and on // widget initialization/setup. From 34791d3c4fbab4470b6166e0c9bda88da87f823b Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:49:59 +0000 Subject: [PATCH 27/30] Rename SetSelectedIconVisible to SetCheckmarkVisible --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 419c6907c8..7bb05c5ccc 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -96,7 +96,7 @@ public ToolBarItem AddItem (string text, string imageId, object? tag) ToolBarItem item = new (text, imageId, tag); // This is done to ensure the first item has a checkmark if it was selected. - if (items.Count == 0 && previous_index == 0) { widget.SetSelectedIconVisible (true); } + if (items.Count == 0 && previous_index == 0) { widget.SetCheckmarkVisible (true); } items.Add (item); return item; @@ -120,8 +120,8 @@ private void SetSelectedIndex (int index) return; } - toolbar_item_widgets[previous_index].SetSelectedIconVisible (false); - toolbar_item_widgets[index].SetSelectedIconVisible (true); + toolbar_item_widgets[previous_index].SetCheckmarkVisible (false); + toolbar_item_widgets[index].SetCheckmarkVisible (true); TooltipText = items[index].Text; Selected = (uint) index; @@ -177,7 +177,7 @@ public ToolBarItemWidget (string text, string imageId) Append (selected_icon); } - public void SetSelectedIconVisible (bool visible) + public void SetCheckmarkVisible (bool visible) { selected_icon.Visible = visible; } From 81aefff2be7ffdee75efe21d4d0eeb01d99ebf8b Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:48:46 +0000 Subject: [PATCH 28/30] Remove redundante previous_index check This was redundant because 'previous_index' is always initialized at zero. When the selection changes, the SetSelectedIndex function already removes the checkmark on the first item. --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 7bb05c5ccc..c4d90f469e 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -96,7 +96,7 @@ public ToolBarItem AddItem (string text, string imageId, object? tag) ToolBarItem item = new (text, imageId, tag); // This is done to ensure the first item has a checkmark if it was selected. - if (items.Count == 0 && previous_index == 0) { widget.SetCheckmarkVisible (true); } + if (items.Count == 0) { widget.SetCheckmarkVisible (true); } items.Add (item); return item; From d721ec85974b13804d902b1c55da95dcee403879 Mon Sep 17 00:00:00 2001 From: Pedro Paulo <32345702+pedropaulosuzuki@users.noreply.github.com> Date: Wed, 22 Apr 2026 11:28:18 +0000 Subject: [PATCH 29/30] Fix range comparison Zero-indexed list goes from '0' to 'length - 1'. --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index c4d90f469e..804446fceb 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -116,7 +116,7 @@ public int SelectedIndex { private void SetSelectedIndex (int index) { - if (index < 0 || index > items.Count || index == previous_index) { + if (index < 0 || index >= items.Count || index == previous_index) { return; } From 4b24aac4b01de270174c1547c6b545ccd1530eb2 Mon Sep 17 00:00:00 2001 From: Cameron White Date: Thu, 23 Apr 2026 23:14:22 -0400 Subject: [PATCH 30/30] Remove unnecessary null check --- Pinta.Core/Widgets/ToolBarDropDownButton.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Pinta.Core/Widgets/ToolBarDropDownButton.cs b/Pinta.Core/Widgets/ToolBarDropDownButton.cs index 804446fceb..8a729b28f6 100644 --- a/Pinta.Core/Widgets/ToolBarDropDownButton.cs +++ b/Pinta.Core/Widgets/ToolBarDropDownButton.cs @@ -53,7 +53,6 @@ public ToolBarDropDownButton (bool showLabel = false) private void OnSetupSelectedItem (Gtk.SignalListItemFactory factory, Gtk.SignalListItemFactory.SetupSignalArgs args) { Gtk.ListItem item = (Gtk.ListItem) args.Object; - if (item is null) { return; } item.SetChild (selected_box); } @@ -73,7 +72,6 @@ private void OnBindSelectedItem (Gtk.SignalListItemFactory sender, Gtk.SignalLis private void OnBindListItem (Gtk.SignalListItemFactory sender, Gtk.SignalListItemFactory.BindSignalArgs args) { Gtk.ListItem item = (Gtk.ListItem) args.Object; - if (item is null) { return; } ToolBarItemWidget toolbar_item = toolbar_item_widgets[(int) item.Position]; item.SetChild (toolbar_item);