diff --git a/README.md b/README.md index 522c6c3..9aec854 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Download the compiled Windows release from: - System tray launcher - Global hotkey, default `Ctrl+Alt+Space` -- Search/filter in the launcher popup +- Search/filter in the launcher popup with parent menu context - Recent items section for quickly relaunching entries - Nested menus, drag/drop ordering, and drag/drop item creation in Settings - Right-click launcher entries to edit them in Settings diff --git a/TaskbarLauncher.csproj b/TaskbarLauncher.csproj index 4a236ed..1012f94 100644 --- a/TaskbarLauncher.csproj +++ b/TaskbarLauncher.csproj @@ -12,8 +12,8 @@ Ray Berezowski Assets\AppIcon.ico 1.0.1 - 1.0.1.13 - 1.0.1.13 + 1.0.1.14 + 1.0.1.14 1.0.1 diff --git a/Views/LauncherPopup.xaml.cs b/Views/LauncherPopup.xaml.cs index 6505b68..4893c01 100644 --- a/Views/LauncherPopup.xaml.cs +++ b/Views/LauncherPopup.xaml.cs @@ -21,6 +21,7 @@ public partial class LauncherPopup : Window private readonly Action showSettings; private readonly Action editItem; private readonly Action openContainingFolder; + private sealed record SearchMatch(LauncherItem Item, string ParentPath); public LauncherPopup(LauncherConfig config, Action launchItem, Action openAllItems, Action showSettings, Action editItem, Action openContainingFolder) { @@ -322,8 +323,8 @@ public partial class LauncherPopup : Window ItemsPanel.Children.Clear(); visibleLaunchButtons.Clear(); - List matches = []; - CollectMatches(config.Items, query, matches); + List matches = []; + CollectMatches(config.Items, query, [], matches); if (matches.Count == 0) { @@ -336,34 +337,88 @@ public partial class LauncherPopup : Window return; } - foreach (LauncherItem item in matches) + foreach (SearchMatch match in matches) { - ItemsPanel.Children.Add(CreateItemControl(item, 0, expandMenusByDefault: false)); + ItemsPanel.Children.Add(CreateSearchResultControl(match)); } } - private static void CollectMatches(IEnumerable items, string query, List matches) + private FrameworkElement CreateSearchResultControl(SearchMatch match) + { + System.Windows.Controls.Button button = new() + { + Content = CreateSearchResultContent(match), + Margin = new Thickness(0, 2, 0, 2), + MinHeight = Math.Max(DisplayModeMetrics.GetRowHeight(GetEffectiveDisplayMode(match.Item)), 48), + HorizontalContentAlignment = System.Windows.HorizontalAlignment.Left, + Tag = match.Item, + ContextMenu = CreateItemContextMenu(match.Item) + }; + + button.Click += (_, _) => launchItem(match.Item); + button.KeyDown += (_, e) => + { + if (e.Key == Key.Enter) + { + launchItem(match.Item); + e.Handled = true; + } + else if (e.Key == Key.Escape) + { + Close(); + e.Handled = true; + } + }; + + visibleLaunchButtons.Add(button); + return button; + } + + private object CreateSearchResultContent(SearchMatch match) + { + StackPanel panel = new(); + panel.Children.Add((UIElement)CreateButtonContent(match.Item)); + + if (!string.IsNullOrWhiteSpace(match.ParentPath)) + { + panel.Children.Add(new TextBlock + { + Text = match.ParentPath, + FontSize = 11, + Foreground = (System.Windows.Media.Brush)System.Windows.Application.Current.Resources["AppMutedTextBrush"], + Margin = new Thickness(0, 3, 0, 0), + TextTrimming = TextTrimming.CharacterEllipsis + }); + } + + return panel; + } + + private static void CollectMatches(IEnumerable items, string query, List parentNames, List matches) { foreach (LauncherItem item in GetDisplayItems(items)) { bool isLaunchable = item.Type != LauncherItemType.Menu && !item.IsDisabled; - if (isLaunchable && Matches(item, query)) + string parentPath = string.Join(" > ", parentNames); + if (isLaunchable && Matches(item, query, parentPath)) { - matches.Add(item); + matches.Add(new SearchMatch(item, parentPath)); } if (item.Children.Count > 0) { - CollectMatches(item.Children, query, matches); + string menuName = string.IsNullOrWhiteSpace(item.Title) ? "Untitled" : item.Title; + CollectMatches(item.Children, query, [.. parentNames, menuName], matches); } } } - private static bool Matches(LauncherItem item, string query) + private static bool Matches(LauncherItem item, string query, string parentPath) { return item.Title.Contains(query, StringComparison.OrdinalIgnoreCase) || item.Target.Contains(query, StringComparison.OrdinalIgnoreCase) || - (item.Arguments?.Contains(query, StringComparison.OrdinalIgnoreCase) ?? false); + (item.Arguments?.Contains(query, StringComparison.OrdinalIgnoreCase) ?? false) || + parentPath.Contains(query, StringComparison.OrdinalIgnoreCase); } private void SearchBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e) diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 7c20ec7..01350cd 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -26,6 +26,8 @@ Install the **.NET Desktop Runtime** for **Windows x64**. Recently launched entries appear in the launcher popup under **Recent**. +Search results include the parent menu path when an item is inside a menu. + ## Configure Open the tray menu and choose **Settings**.