Skip to content

Commit

Permalink
Merge pull request #2643 from LeeARichardson/gtk-fix-various-treeview…
Browse files Browse the repository at this point in the history
…-bugs

Gtk fix various treeview bugs
  • Loading branch information
cwensley committed Apr 15, 2024
2 parents 3d289b7 + 8ddba71 commit 4721256
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 25 deletions.
69 changes: 44 additions & 25 deletions src/Eto.Gtk/Forms/Controls/GridHandler.cs
@@ -1,5 +1,6 @@
using Eto.GtkSharp.Forms.Cells;
using Eto.GtkSharp.Forms.Menu;

namespace Eto.GtkSharp.Forms.Controls
{
class GridHandler
Expand Down Expand Up @@ -138,12 +139,21 @@ protected override void Initialize()
columns.Register(Widget.Columns);
base.Initialize();

Widget.MouseDown += Widget_MouseDown;
Control.Selection.Changed += (sender, args) =>
{
// Prevent unselecting last selected item.
if (!AllowEmptySelection && AllowMultipleSelection && Control.Selection.CountSelectedRows() == 0)
{
Control.GetCursor(out var cursorRow, out _);
if (cursorRow != null)
{
Control.Selection.SelectPath(cursorRow);
}
}
};

Control.QueryTooltip += Control_QueryTooltip;
Control.HasTooltip = true;


}

private void Control_QueryTooltip(object o, Gtk.QueryTooltipArgs args)
Expand Down Expand Up @@ -534,7 +544,7 @@ public void ColumnClicked(GridColumnHandler column)
public bool AllowMultipleSelection
{
get { return Control.Selection.Mode == Gtk.SelectionMode.Multiple; }
set { Control.Selection.Mode = value ? Gtk.SelectionMode.Multiple : Gtk.SelectionMode.Browse; }
set => SetSelectionMode(AllowEmptySelection, value);
}

public virtual IEnumerable<int> SelectedRows
Expand Down Expand Up @@ -703,37 +713,46 @@ public bool IsEditing
public bool AllowEmptySelection
{
get => Widget.Properties.Get<bool>(GridHandler.AllowEmptySelection_Key, true);
set => Widget.Properties.TrySet(GridHandler.AllowEmptySelection_Key, value, true);
set
{
Widget.Properties.TrySet(GridHandler.AllowEmptySelection_Key, value, true);
SetSelectionMode(value, AllowMultipleSelection);
}
}

private void Widget_MouseDown(object sender, MouseEventArgs e)
private void SetSelectionMode(bool allowEmptySelection, bool allowMultipleSelection)
{
if (!e.Handled && e.Buttons == MouseButtons.Primary)
var currentMode = Control.Selection.Mode;
var newMode =
(allowEmptySelection, allowMultipleSelection) switch
{
(true, true) => Gtk.SelectionMode.Multiple,
(true, false) => Gtk.SelectionMode.Single,
(false, true) => Gtk.SelectionMode.Multiple, // Handled by Selection Changed event in Initialize().
(false, false) => Gtk.SelectionMode.Browse
};

if (newMode != currentMode)
{
var location = e.Location;
if (AllowEmptySelection)
// Workaround to not lose the ability to select after switching to Multi, unselecting everything,
// then switching back to Single or Browse. Cause unknown but reproduced in GtkSharp.
if (currentMode == Gtk.SelectionMode.Multiple
&& newMode is Gtk.SelectionMode.Single or Gtk.SelectionMode.Browse)
{
// clicked on an empty area
if (!Control.GetPathAtPos((int)location.X, (int)location.Y, out _, out _))
Control.GetCursor(out var cursorRowPath, out _);
var mustReselectCursor = cursorRowPath != null && Control.Selection.PathIsSelected(cursorRowPath);

Control.Selection.Mode = Gtk.SelectionMode.None;
Control.Selection.Mode = newMode;

if (mustReselectCursor)
{
UnselectAll();
e.Handled = true;
Control.Selection.SelectPath(cursorRowPath);
}
}
else
{
// cancel ctrl+clicking to remove last selected item
if (Control.GetPathAtPos((int)location.X, (int)location.Y, out var path, out _))
{
if (Control.Model.GetIter(out var iter, path))
{
var isSelected = Control.Selection.IterIsSelected(iter);
if (e.Modifiers == Keys.Control && isSelected && Control.Selection.CountSelectedRows() == 1)
{
e.Handled = true;
}
}
}
Control.Selection.Mode = newMode;
}
}
}
Expand Down
31 changes: 31 additions & 0 deletions test/Eto.Test/UnitTests/Forms/Controls/GridViewSelectTests.cs
Expand Up @@ -124,5 +124,36 @@ public void DeleteSelectedItemsShouldRemoveSelectedItems()
Assert.AreEqual(initialCount / 4, selectionChangedCount, "SelectionChanged event should fire for each selected item removed");
});
}

[Test]
public void UnselectingInMultipleModeThenSwitchingToSingleModeShouldNotBreakSelection()
{
TestBase.Shown(form =>
{
form.Content = grid;
}, () =>
{
grid.AllowEmptySelection = true;
grid.AllowMultipleSelection = true;
grid.UnselectAll();
grid.AllowMultipleSelection = false;
grid.SelectRow(1);
Assert.AreEqual(1, grid.SelectedRow);
});
}

[Test]
public void SwitchingToSingleModeDoesNotBreakUnselecting()
{
TestBase.Invoke(() =>
{
grid.AllowEmptySelection = true;
grid.AllowMultipleSelection = true;
grid.SelectRow(1);
grid.AllowMultipleSelection = false;
grid.UnselectAll();
Assert.AreEqual(-1, grid.SelectedRow);
});
}
}
}

0 comments on commit 4721256

Please sign in to comment.