diff --git a/src/Sic/MainWindow.Designer.cs b/src/Sic/MainWindow.Designer.cs
index 0740829..c427573 100644
--- a/src/Sic/MainWindow.Designer.cs
+++ b/src/Sic/MainWindow.Designer.cs
@@ -119,7 +119,7 @@ private void InitializeComponent() {
}
imageListView.Dock = DockStyle.Fill;
- imageListView.MultiSelect = false;
+ imageListView.MultiSelect = true;
imageListView.Name = "imageListView";
imageListView.AccessibleName = "Images list";
imageListView.AllowDrop = true;
diff --git a/src/Sic/MainWindow.cs b/src/Sic/MainWindow.cs
index 4e7ff64..9bf1d9d 100644
--- a/src/Sic/MainWindow.cs
+++ b/src/Sic/MainWindow.cs
@@ -401,13 +401,34 @@ private async void AddByLinkMenuItem_Click(object? sender, EventArgs e) {
await PasteFromUrlAsync(dialog.Url);
}
+ ///
+ /// The row a single-image command should act on: the one carrying the focus rectangle when
+ /// it is selected, and otherwise the first selected row.
+ ///
+ private int FocusedOrFirstSelectedIndex() =>
+ imageListView.FocusedItem is { Selected: true } focused
+ ? focused.Index
+ : imageListView.SelectedItems[0].Index;
+
private void RemoveMenuItem_Click(object? sender, EventArgs e) {
if (_imageItems.Count == 0 || imageListView.SelectedItems.Count == 0)
return;
- var index = imageListView.SelectedItems[0].Index;
- _imageItems.RemoveAt(index);
- imageListView.Items.RemoveAt(index);
+ // Descending, so removing one cannot shift the index of another still to go.
+ var indices = imageListView.SelectedItems
+ .Select(row => row.Index)
+ .OrderByDescending(i => i)
+ .ToList();
+
+ foreach (var removed in indices) {
+ _imageItems.RemoveAt(removed);
+ imageListView.Items.RemoveAt(removed);
+ }
+
+ // Land on the row that took the place of the first one removed, so the selection ends
+ // up somewhere predictable rather than nowhere - a list with nothing selected announces
+ // nothing when focus returns to it.
+ var index = indices[^1];
if (imageListView.Items.Count > 0) {
var newIndex = index < imageListView.Items.Count ? index : imageListView.Items.Count - 1;
@@ -703,6 +724,11 @@ private async void ConvertSelectedMenuItem_Click(object? sender, EventArgs e) {
await ConvertItemsAsync(selectedIndices);
}
+ ///
+ /// One image in, one .ico out, so this works on the focused row even when several are
+ /// selected - taking the topmost of a multiple selection would act on an image the user is
+ /// not looking at.
+ ///
private async void CreateMultiSizeIcoMenuItem_Click(object? sender, EventArgs e) {
if (_imageItems.Count == 0 || imageListView.SelectedItems.Count == 0)
return;
@@ -712,7 +738,7 @@ private async void CreateMultiSizeIcoMenuItem_Click(object? sender, EventArgs e)
return;
var sizes = presetDialog.SelectedSizes;
- var index = imageListView.SelectedItems[0].Index;
+ var index = FocusedOrFirstSelectedIndex();
var item = _imageItems[index];
var outputFolder = ValidateOutputFolder();
var outputPath = ImageConverter.GenerateOutputPath(item, "ICO", outputFolder, Config.General.SaveToSourceFolder);
@@ -789,7 +815,7 @@ private async void FitToFileSizeMenuItem_Click(object? sender, EventArgs e) {
var maxBytes = fitDialog.MaxBytes;
var maxWidth = fitDialog.MaxWidth;
- var index = imageListView.SelectedItems[0].Index;
+ var index = FocusedOrFirstSelectedIndex();
var item = _imageItems[index];
var formats = ImageConverter.GetSizeFitFormats(ImageConverter.GetEnabledFormats(Config.General.GetEnabledFormatKeys()));
@@ -1119,7 +1145,13 @@ private void ImageListView_SelectedIndexChanged(object? sender, EventArgs e) {
return;
}
- var index = imageListView.SelectedItems[0].Index;
+ // The focused row when it is part of the selection, otherwise the first selected one.
+ // Extending a selection moves the focus, and previewing where the user actually is
+ // beats previewing where they started.
+ var index = imageListView.FocusedItem is { Selected: true } focused
+ ? focused.Index
+ : imageListView.SelectedItems[0].Index;
+
var item = _imageItems[index];
_selectedItem = item;