From f2ccca2ed12e5e529a8b85c42454d2c7af620f54 Mon Sep 17 00:00:00 2001
From: Ray Berezowski <6616212+rberezowski@users.noreply.github.com>
Date: Wed, 26 Aug 2026 21:45:57 -0400
Subject: [PATCH] Improve launcher search results
---
README.md | 2 +-
TaskbarLauncher.csproj | 4 +-
Views/LauncherPopup.xaml.cs | 75 ++++++++++++++++++++++++++++++++-----
docs/INSTALL.md | 2 +
4 files changed, 70 insertions(+), 13 deletions(-)
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**.