diff --git a/EverythingToolbar/Controls/SearchBox.xaml b/EverythingToolbar/Controls/SearchBox.xaml index 6e79356ca..d7cf1193d 100644 --- a/EverythingToolbar/Controls/SearchBox.xaml +++ b/EverythingToolbar/Controls/SearchBox.xaml @@ -85,8 +85,14 @@ TextBlock.FontWeight="Bold" Content=".*" Margin="1" /> + + - \ No newline at end of file diff --git a/EverythingToolbar/Controls/SearchResultsView.xaml b/EverythingToolbar/Controls/SearchResultsView.xaml index 8ba9bb475..38a9f2778 100644 --- a/EverythingToolbar/Controls/SearchResultsView.xaml +++ b/EverythingToolbar/Controls/SearchResultsView.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:properties="clr-namespace:EverythingToolbar.Properties" + xmlns:local="clr-namespace:EverythingToolbar" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignWidth="300" @@ -128,7 +129,6 @@ + FocusVisualStyle="{x:Null}"> + + + + - + \ No newline at end of file diff --git a/EverythingToolbar/Controls/SearchResultsView.xaml.cs b/EverythingToolbar/Controls/SearchResultsView.xaml.cs index 5ab078cc7..0ec49a705 100644 --- a/EverythingToolbar/Controls/SearchResultsView.xaml.cs +++ b/EverythingToolbar/Controls/SearchResultsView.xaml.cs @@ -47,6 +47,12 @@ public SearchResult? SelectedSearchResult } private SearchResult? SelectedItem => SelectedSearchResult; + + private IEnumerable GetSelectedItems() + { + return SearchResultsListView.SelectedItems.Cast(); + } + private const int PageSize = 256; private Point _dragStart; private bool _isScrollBarDragging; @@ -219,7 +225,6 @@ private void ResetScrollBarDragging() private void OnPreviewLeftMouseButtonDown(object sender, MouseButtonEventArgs e) { - // Prevents deselecting an item when Ctrl is held down and clicking on an already selected item if (Keyboard.Modifiers == ModifierKeys.Control) { if (e.OriginalSource is not DependencyObject source) @@ -244,10 +249,10 @@ private void OnKeyPressed(object? sender, KeyEventArgs e) } else if (Keyboard.Modifiers == ModifierKeys.Shift && e.Key == Key.Enter) { - if (SelectedItem == null) - return; + var first = GetSelectedItems().FirstOrDefault(); + if (first == null) return; - SearchResultProvider.OpenSearchInEverything(SearchState.Instance, SelectedItem.FullPathAndFileName); + SearchResultProvider.OpenSearchInEverything(SearchState.Instance, first.FullPathAndFileName); SearchResultsListView.SelectedIndex = -1; } else if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.Enter) @@ -274,11 +279,14 @@ private void OnKeyPressed(object? sender, KeyEventArgs e) } else if (Keyboard.Modifiers == (ModifierKeys.Control | ModifierKeys.Shift) && e.Key == Key.C) { - SelectedItem?.CopyPathToClipboard(); + var paths = string.Join(Environment.NewLine, GetSelectedItems().Select(i => i.FullPathAndFileName)); + if (!string.IsNullOrEmpty(paths)) Clipboard.SetText(paths); } else if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.C) { - SelectedItem?.CopyToClipboard(); + var paths = new StringCollection(); + foreach (var item in GetSelectedItems()) paths.Add(item.FullPathAndFileName); + if (paths.Count > 0) Clipboard.SetFileDropList(paths); } else if (e.Key == Key.Up) { @@ -354,7 +362,6 @@ private void SelectNthSearchResult(int n) private void JumpToEnd() { - // Capture focus before calling Focus() on the ListView so we can restore it afterwards. var originalFocus = Keyboard.FocusedElement; SearchResultsListView.Focus(); ForwardKeyPressToControl(SearchResultsListView, Key.End, originalFocus, restoreFocus: KeepSearchBoxFocused); @@ -430,7 +437,6 @@ private bool ForwardKeyPressToControl( if (presentationSource == null) return false; - // Capture focus state before raising the event originalFocus ??= Keyboard.FocusedElement; var caretIndex = originalFocus is TextBox textBox ? textBox.CaretIndex : -1; @@ -440,7 +446,6 @@ private bool ForwardKeyPressToControl( }; control.RaiseEvent(args); - // Restore focus to SearchBox if requested and it was previously focused if (restoreFocus && originalFocus is TextBox restoredTextBox && caretIndex >= 0) { Dispatcher.BeginInvoke( @@ -460,51 +465,69 @@ private bool ForwardKeyPressToControl( private void OpenSelectedSearchResult() { - if (SelectedItem == null) - return; - - if (!CustomActions.HandleAction(SelectedItem)) - SelectedItem?.Open(); + var items = GetSelectedItems().ToList(); + if (items.Count == 0) return; + foreach (var item in items) + { + if (!CustomActions.HandleAction(item)) + item.Open(); + } SearchWindow.Instance.Hide(); } private void OpenFilePath(object sender, RoutedEventArgs e) { - SelectedItem?.OpenPath(); + foreach (var item in GetSelectedItems()) + item.OpenPath(); SearchWindow.Instance.Hide(); } private void PreviewSelectedFile() { - SelectedItem?.PreviewInQuickLook(); - SelectedItem?.PreviewInSeer(); + var first = GetSelectedItems().FirstOrDefault(); + first?.PreviewInQuickLook(); + first?.PreviewInSeer(); } private void CopyPathToClipBoard(object sender, RoutedEventArgs e) { - SelectedItem?.CopyPathToClipboard(); + var paths = string.Join(Environment.NewLine, GetSelectedItems().Select(i => i.FullPathAndFileName)); + if (!string.IsNullOrEmpty(paths)) + Clipboard.SetText(paths); } private void OpenWith(object sender, RoutedEventArgs e) { - SelectedItem?.OpenWith(); + foreach (var item in GetSelectedItems()) + item.OpenWith(); SearchWindow.Instance.Hide(); } private void ShowInEverything(object sender, RoutedEventArgs e) { - SelectedItem?.ShowInEverything(); + foreach (var item in GetSelectedItems()) + item.ShowInEverything(); SearchWindow.Instance.Hide(); } private void CopyFile(object sender, RoutedEventArgs e) { - SelectedItem?.CopyToClipboard(); + var paths = new StringCollection(); + foreach (var item in GetSelectedItems()) paths.Add(item.FullPathAndFileName); + + if (paths.Count > 0) + Clipboard.SetFileDropList(paths); } private void SingleClickSearchResult(object sender, MouseEventArgs e) { + if (ToolbarSettings.User.IsSelectionModeEnabled) + return; + + if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control) || Keyboard.Modifiers.HasFlag(ModifierKeys.Shift)) + return; + if (!ToolbarSettings.User.IsDoubleClickToOpen) OpenWithMouseClick(); } @@ -525,15 +548,7 @@ private void OpenWithMouseClick() switch (Keyboard.Modifiers) { case ModifierKeys.Alt: - SelectedItem?.ShowProperties(); - SearchWindow.Instance.Hide(); - break; - case ModifierKeys.Control: - SelectedItem?.OpenPath(); - SearchWindow.Instance.Hide(); - break; - case ModifierKeys.Shift: - SelectedItem?.ShowInEverything(); + foreach (var item in GetSelectedItems()) item.ShowProperties(); SearchWindow.Instance.Hide(); break; default: @@ -545,19 +560,21 @@ private void OpenWithMouseClick() private void RunAsAdmin(object sender, RoutedEventArgs e) { - SelectedItem?.RunAsAdmin(); + foreach (var item in GetSelectedItems()) + item.RunAsAdmin(); SearchWindow.Instance.Hide(); } private void ShowFileProperties(object sender, RoutedEventArgs e) { - SelectedItem?.ShowProperties(); + foreach (var item in GetSelectedItems()) + item.ShowProperties(); SearchWindow.Instance.Hide(); } private void ShowFileWindowsContextMenu(object sender, RoutedEventArgs e) { - SelectedItem?.ShowWindowsContextMenu(); + SearchResult.ShowWindowsContextMenu(GetSelectedItems()); } private void OnOpenWithMenuLoaded(object sender, RoutedEventArgs e) @@ -601,12 +618,16 @@ private void OnOpenWithMenuLoaded(object sender, RoutedEventArgs e) private void OpenWithCustomAction(object sender, RoutedEventArgs e) { - if (SelectedItem == null) - return; + var items = GetSelectedItems().ToList(); + if (items.Count == 0) return; var menuItem = sender as MenuItem; var command = menuItem?.Tag?.ToString() ?? ""; - CustomActions.HandleAction(SelectedItem, command); + + foreach (var item in items) + { + CustomActions.HandleAction(item, command); + } } private void OnListViewItemMouseDown(object sender, MouseButtonEventArgs e) @@ -645,7 +666,8 @@ private void OnListViewItemTouchUp(object sender, TouchEventArgs e) private bool TryStartDragDrop(Point currentPosition) { - if (SelectedItem == null) + var items = GetSelectedItems().ToList(); + if (items.Count == 0) return false; var diff = _dragStart - currentPosition; @@ -656,9 +678,9 @@ private bool TryStartDragDrop(Point currentPosition) ) return false; - string[] files = [SelectedItem.FullPathAndFileName]; + string[] files = items.Select(i => i.FullPathAndFileName).ToArray(); var data = new DataObject(DataFormats.FileDrop, files); - data.SetData(DataFormats.Text, files[0]); + data.SetData(DataFormats.Text, string.Join(Environment.NewLine, files)); DragDrop.DoDragDrop(SearchResultsListView, data, DragDropEffects.All); return true; } @@ -670,7 +692,7 @@ private void OnContextMenuOpening(object sender, ContextMenuEventArgs e) if (Keyboard.Modifiers == ModifierKeys.Shift) { - SelectedItem.ShowWindowsContextMenu(); + SearchResult.ShowWindowsContextMenu(GetSelectedItems()); e.Handled = true; } } @@ -700,4 +722,4 @@ private void FocusSelectedItem() Keyboard.Focus(selectedItem); } } -} +} \ No newline at end of file diff --git a/EverythingToolbar/Data/SearchResult.cs b/EverythingToolbar/Data/SearchResult.cs index 772ab4363..92f794b7c 100644 --- a/EverythingToolbar/Data/SearchResult.cs +++ b/EverythingToolbar/Data/SearchResult.cs @@ -286,9 +286,22 @@ public void ShowProperties() public void ShowWindowsContextMenu() { + ShowWindowsContextMenu(new[] { this }); + } + + public static void ShowWindowsContextMenu(IEnumerable items) + { + var itemsList = items.ToList(); + if (itemsList.Count == 0) return; + + var firstItemDir = itemsList[0].Path; + var validItems = itemsList.Where(i => string.Equals(i.Path, firstItemDir, StringComparison.OrdinalIgnoreCase)).ToList(); + var menu = new ShellContextMenu(); - var arrFi = new FileInfo[1]; - arrFi[0] = new FileInfo(FullPathAndFileName); + var arrFi = validItems.Select(i => + i.IsFile ? new FileInfo(i.FullPathAndFileName) : new DirectoryInfo(i.FullPathAndFileName) + ).ToArray(); + menu.ShowContextMenu(arrFi, Control.MousePosition); } diff --git a/EverythingToolbar/Helpers/ShellContextMenu.cs b/EverythingToolbar/Helpers/ShellContextMenu.cs index 33cb00a1b..c8ca902ea 100644 --- a/EverythingToolbar/Helpers/ShellContextMenu.cs +++ b/EverythingToolbar/Helpers/ShellContextMenu.cs @@ -274,60 +274,24 @@ out var pUnknownParentFolder /// /// Array of FileInfo /// Array of PIDLs - protected IntPtr[] GetPIDLs(FileInfo[] arrFI) + protected IntPtr[] GetPIDLs(FileSystemInfo[] arrFI) { if (null == arrFI || 0 == arrFI.Length) { return null; } - var oParentFolder = GetParentFolder(arrFI[0].DirectoryName); - if (null == oParentFolder) - { - return null; - } - - var arrPIDLs = new IntPtr[arrFI.Length]; - var n = 0; - foreach (var fi in arrFI) + string directoryName; + if (arrFI[0] is FileInfo fi) { - // Get the file relative to folder - uint pchEaten = 0; - SFGAO pdwAttributes = 0; - var pPIDL = IntPtr.Zero; - var nResult = oParentFolder.ParseDisplayName( - IntPtr.Zero, - IntPtr.Zero, - fi.Name, - ref pchEaten, - out pPIDL, - ref pdwAttributes - ); - if (S_OK != nResult) - { - FreePIDLs(arrPIDLs); - return null; - } - arrPIDLs[n] = pPIDL; - n++; + directoryName = fi.DirectoryName; } - - return arrPIDLs; - } - - /// - /// Get the PIDLs - /// - /// Array of DirectoryInfo - /// Array of PIDLs - protected IntPtr[] GetPIDLs(DirectoryInfo[] arrFI) - { - if (null == arrFI || 0 == arrFI.Length) + else { - return null; + directoryName = ((DirectoryInfo)arrFI[0]).Parent?.FullName ?? arrFI[0].FullName; } - var oParentFolder = GetParentFolder(arrFI[0].Parent.FullName); + var oParentFolder = GetParentFolder(directoryName); if (null == oParentFolder) { return null; @@ -335,16 +299,15 @@ protected IntPtr[] GetPIDLs(DirectoryInfo[] arrFI) var arrPIDLs = new IntPtr[arrFI.Length]; var n = 0; - foreach (var fi in arrFI) + foreach (var fsi in arrFI) { - // Get the file relative to folder uint pchEaten = 0; SFGAO pdwAttributes = 0; var pPIDL = IntPtr.Zero; var nResult = oParentFolder.ParseDisplayName( IntPtr.Zero, IntPtr.Zero, - fi.Name, + fsi.Name, ref pchEaten, out pPIDL, ref pdwAttributes @@ -384,30 +347,16 @@ protected void FreePIDLs(IntPtr[] arrPIDLs) #endregion #region ShowContextMenu() - - /// - /// Shows the context menu - /// - /// FileInfos (should all be in same directory) - /// Where to show the menu - public void ShowContextMenu(FileInfo[] files, Point pointScreen) - { - // Release all resources first. - ReleaseAll(); - _arrPIDLs = GetPIDLs(files); - ShowContextMenu(pointScreen); - } - /// /// Shows the context menu /// - /// DirectoryInfos (should all be in same directory) + /// FileSystemInfos (should all be in same directory) /// Where to show the menu - public void ShowContextMenu(DirectoryInfo[] dirs, Point pointScreen) + public void ShowContextMenu(FileSystemInfo[] items, Point pointScreen) { // Release all resources first. ReleaseAll(); - _arrPIDLs = GetPIDLs(dirs); + _arrPIDLs = GetPIDLs(items); ShowContextMenu(pointScreen); } diff --git a/EverythingToolbar/ItemTemplates/Compact.xaml b/EverythingToolbar/ItemTemplates/Compact.xaml index 871e00398..f84a3065d 100644 --- a/EverythingToolbar/ItemTemplates/Compact.xaml +++ b/EverythingToolbar/ItemTemplates/Compact.xaml @@ -1,28 +1,73 @@  - + xmlns:c="clr-namespace:EverythingToolbar.Converters;assembly=EverythingToolbar" + xmlns:local="clr-namespace:EverythingToolbar;assembly=EverythingToolbar"> + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/EverythingToolbar/ItemTemplates/CompactDetailed.xaml b/EverythingToolbar/ItemTemplates/CompactDetailed.xaml index 1bfdf30fd..1e651953d 100644 --- a/EverythingToolbar/ItemTemplates/CompactDetailed.xaml +++ b/EverythingToolbar/ItemTemplates/CompactDetailed.xaml @@ -1,41 +1,86 @@  - + xmlns:c="clr-namespace:EverythingToolbar.Converters;assembly=EverythingToolbar" + xmlns:local="clr-namespace:EverythingToolbar;assembly=EverythingToolbar"> + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/EverythingToolbar/ItemTemplates/Normal.xaml b/EverythingToolbar/ItemTemplates/Normal.xaml index cafba34d5..b395535da 100644 --- a/EverythingToolbar/ItemTemplates/Normal.xaml +++ b/EverythingToolbar/ItemTemplates/Normal.xaml @@ -1,31 +1,72 @@  - + xmlns:c="clr-namespace:EverythingToolbar.Converters;assembly=EverythingToolbar" + xmlns:local="clr-namespace:EverythingToolbar;assembly=EverythingToolbar"> + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/EverythingToolbar/ItemTemplates/NormalDetailed.xaml b/EverythingToolbar/ItemTemplates/NormalDetailed.xaml index c96825d4d..ace85eb7b 100644 --- a/EverythingToolbar/ItemTemplates/NormalDetailed.xaml +++ b/EverythingToolbar/ItemTemplates/NormalDetailed.xaml @@ -1,10 +1,12 @@  + xmlns:c="clr-namespace:EverythingToolbar.Converters;assembly=EverythingToolbar" + xmlns:local="clr-namespace:EverythingToolbar;assembly=EverythingToolbar"> + @@ -13,32 +15,44 @@ + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/EverythingToolbar/ToolbarSettings.cs b/EverythingToolbar/ToolbarSettings.cs index 522b336fe..d59a5e3b2 100644 --- a/EverythingToolbar/ToolbarSettings.cs +++ b/EverythingToolbar/ToolbarSettings.cs @@ -137,6 +137,9 @@ public interface IToolbarSettings [Option(DefaultValue = "")] string UILanguage { get; set; } + + [Option(DefaultValue = false)] + bool IsSelectionModeEnabled { get; set; } } public sealed class ToolbarSettingsWrapper(IToolbarSettings settings) : INotifyPropertyChanged @@ -703,6 +706,19 @@ public string UILanguage } } } + + public bool IsSelectionModeEnabled + { + get => settings.IsSelectionModeEnabled; + set + { + if (settings.IsSelectionModeEnabled != value) + { + settings.IsSelectionModeEnabled = value; + OnPropertyChanged(); + } + } + } } public abstract class ToolbarSettings @@ -713,4 +729,4 @@ public abstract class ToolbarSettings public static readonly ToolbarSettingsWrapper User = new(UserSettings); } -} +} \ No newline at end of file