From a4b248991c67a8e0486d527c6ed06e61b8464095 Mon Sep 17 00:00:00 2001 From: Mommel Date: Sat, 9 May 2026 00:48:02 +0200 Subject: [PATCH 1/2] feat: implement marquee selection for file list --- MainWindow.xaml | 9 +++- MainWindow.xaml.cs | 118 ++++++++++++++++++++++++++++++++++++++++- UnifiedExplorer.csproj | 6 +-- 3 files changed, 127 insertions(+), 6 deletions(-) diff --git a/MainWindow.xaml b/MainWindow.xaml index 555984a..6c584f9 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -230,8 +230,13 @@ - - + + + + + + + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index b238aaf..a7d22f0 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -39,6 +39,22 @@ public double IconSize private ListSortDirection _lastDirection = ListSortDirection.Ascending; private bool _previewVisible = false; private char _lastSearchChar = '\0'; + + private Point _startPoint; + private bool _isSelecting = false; + private ScrollViewer? _listScrollViewer; + + private static T? FindVisualChild(DependencyObject parent) where T : DependencyObject + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + if (child is T typedChild) return typedChild; + var childOfChild = FindVisualChild(child); + if (childOfChild != null) return childOfChild; + } + return null; + } private GridView _detailsView = null!; private GridViewColumn _colName = null!, _colDateMod = null!, _colType = null!, _colSize = null!, _colCreation = null!, _colDimensions = null!; @@ -579,10 +595,110 @@ private void Sort(string sortBy, ListSortDirection direction) } // Drag Drop & Context Logic + private void FileListView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + if (e.OriginalSource is DependencyObject depObj) + { + // Check if user clicked on a ListViewItem + var item = FindVisualParent(depObj); + if (item == null) + { + // Clicked on empty space + _startPoint = e.GetPosition(SelectionCanvas); + FileListView.SelectedItems.Clear(); + _isSelecting = true; + FileListView.CaptureMouse(); + + Canvas.SetLeft(SelectionRectangle, _startPoint.X); + Canvas.SetTop(SelectionRectangle, _startPoint.Y); + SelectionRectangle.Width = 0; + SelectionRectangle.Height = 0; + SelectionRectangle.Visibility = Visibility.Visible; + + if (_listScrollViewer == null) + _listScrollViewer = FindVisualChild(FileListView); + } + } + } + + private static T? FindVisualParent(DependencyObject child) where T : DependencyObject + { + DependencyObject parentObject = child; + while (parentObject != null) + { + if (parentObject is Visual || parentObject is System.Windows.Media.Media3D.Visual3D) + { + parentObject = VisualTreeHelper.GetParent(parentObject); + } + else + { + parentObject = LogicalTreeHelper.GetParent(parentObject); + } + + if (parentObject is T parent) return parent; + } + return null; + } + private void FileListView_PreviewMouseMove(object sender, MouseEventArgs e) { - if (e.LeftButton == MouseButtonState.Pressed && FileListView.SelectedItem is FileSystemItem item && item.IsDirectory) + if (_isSelecting && e.LeftButton == MouseButtonState.Pressed) + { + Point pos = e.GetPosition(SelectionCanvas); + + double x = Math.Min(pos.X, _startPoint.X); + double y = Math.Min(pos.Y, _startPoint.Y); + double w = Math.Abs(pos.X - _startPoint.X); + double h = Math.Abs(pos.Y - _startPoint.Y); + + Canvas.SetLeft(SelectionRectangle, x); + Canvas.SetTop(SelectionRectangle, y); + SelectionRectangle.Width = w; + SelectionRectangle.Height = h; + + Rect selectionRect = new Rect(x, y, w, h); + + // Select items intersecting with rectangle + foreach (var item in FileListView.Items) + { + if (FileListView.ItemContainerGenerator.ContainerFromItem(item) is ListViewItem lvi) + { + Point itemPos = lvi.TransformToVisual(SelectionCanvas).Transform(new Point(0, 0)); + Rect itemRect = new Rect(itemPos, new Size(lvi.ActualWidth, lvi.ActualHeight)); + + if (selectionRect.IntersectsWith(itemRect)) + lvi.IsSelected = true; + else + lvi.IsSelected = false; + } + } + + // Auto-scroll logic + if (_listScrollViewer != null) + { + Point listViewPos = e.GetPosition(FileListView); + double scrollZoneHeight = 20; + + if (listViewPos.Y < scrollZoneHeight) + _listScrollViewer.LineUp(); + else if (listViewPos.Y > FileListView.ActualHeight - scrollZoneHeight) + _listScrollViewer.LineDown(); + } + } + else if (!_isSelecting && e.LeftButton == MouseButtonState.Pressed && FileListView.SelectedItem is FileSystemItem item && item.IsDirectory) + { DragDrop.DoDragDrop(FileListView, item.Path, DragDropEffects.Link); + } + } + + private void FileListView_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + if (_isSelecting) + { + _isSelecting = false; + FileListView.ReleaseMouseCapture(); + SelectionRectangle.Visibility = Visibility.Collapsed; + } } private void FavoritesList_Drop(object sender, DragEventArgs e) diff --git a/UnifiedExplorer.csproj b/UnifiedExplorer.csproj index a623798..e6109be 100644 --- a/UnifiedExplorer.csproj +++ b/UnifiedExplorer.csproj @@ -6,9 +6,9 @@ enable true assets\app.ico - 1.0.1 - 1.0.0.0 - 1.0.1.0 + 1.0.2 + 1.0.2.0 + 1.0.2.0 From d54cbd8275eb3a5261899b77907b9c35a945c978 Mon Sep 17 00:00:00 2001 From: Mommel Date: Sat, 9 May 2026 01:18:52 +0200 Subject: [PATCH 2/2] feat: add visual separator bars to GridSplitters and update ListView mouse event handlers --- MainWindow.xaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MainWindow.xaml b/MainWindow.xaml index 6c584f9..61a2aa3 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -169,10 +169,12 @@ + - + +