From 31c62bb89a26f19b29c6a766d0b3c348e0d469db Mon Sep 17 00:00:00 2001 From: Ray Berezowski <6616212+rberezowski@users.noreply.github.com> Date: Wed, 26 Aug 2026 21:06:25 -0400 Subject: [PATCH] Add disabled launcher items --- MainWindow.xaml.cs | 44 +++++++++++++++++++++++++++++++++- Models/LauncherConfig.cs | 2 ++ README.md | 1 + Services/ConfigService.cs | 3 ++- Services/LauncherController.cs | 7 +++--- TaskbarLauncher.csproj | 4 ++-- Views/LauncherPopup.xaml.cs | 32 +++++++++++++++++++++---- config.example.json | 5 ++++ docs/INSTALL.md | 2 ++ 9 files changed, 88 insertions(+), 12 deletions(-) diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 23ed20b..58a794b 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -90,16 +90,23 @@ public partial class MainWindow : Window }; pinMenuItem.Click += ToggleFavorite_Click; + var disableMenuItem = new System.Windows.Controls.MenuItem + { + Header = item.IsDisabled ? "Enable Item" : "Disable Item" + }; + disableMenuItem.Click += ToggleDisabled_Click; + var duplicateMenuItem = new System.Windows.Controls.MenuItem { Header = "Duplicate Item" }; duplicateMenuItem.Click += DuplicateItem_Click; var treeItem = new TreeViewItem { - Header = $"{(item.IsFavorite ? "[Pinned] " : "")}{item.Title} ({item.Type})", + Header = $"{GetTreeStatusPrefix(item)}{item.Title} ({item.Type})", Tag = item, ContextMenu = new System.Windows.Controls.ContextMenu() }; treeItem.ContextMenu.Items.Add(pinMenuItem); + treeItem.ContextMenu.Items.Add(disableMenuItem); treeItem.ContextMenu.Items.Add(duplicateMenuItem); treeItem.PreviewMouseRightButtonDown += (_, e) => { @@ -115,6 +122,22 @@ public partial class MainWindow : Window return treeItem; } + private static string GetTreeStatusPrefix(LauncherItem item) + { + List parts = []; + if (item.IsFavorite) + { + parts.Add("Pinned"); + } + + if (item.IsDisabled) + { + parts.Add("Disabled"); + } + + return parts.Count == 0 ? "" : $"[{string.Join(", ", parts)}] "; + } + private bool SelectTreeItem(LauncherItem item) { foreach (object root in ItemsTree.Items) @@ -827,6 +850,23 @@ public partial class MainWindow : Window : $"Unpinned {itemToSelect.Title}. Click Save to keep it."; } + private void ToggleDisabled_Click(object sender, RoutedEventArgs e) + { + if (controller is null || selectedItem is null) + { + return; + } + + ApplyCurrentItem(); + selectedItem.IsDisabled = !selectedItem.IsDisabled; + LauncherItem itemToSelect = selectedItem; + selectedPath = FindItemPath(itemToSelect); + RefreshView(itemToSelect); + StatusText.Text = itemToSelect.IsDisabled + ? $"Disabled {itemToSelect.Title}. Click Save to keep it." + : $"Enabled {itemToSelect.Title}. Click Save to keep it."; + } + private void DuplicateItem_Click(object sender, RoutedEventArgs e) { if (controller is null || selectedItem is null) @@ -890,6 +930,7 @@ public partial class MainWindow : Window Arguments = item.Arguments, IconPath = item.IconPath, IsFavorite = item.IsFavorite, + IsDisabled = item.IsDisabled, DisplayMode = item.DisplayMode, Children = item.Children.Select(child => DuplicateItem(child, renameRoot: false)).ToList() }; @@ -1482,6 +1523,7 @@ public partial class MainWindow : Window Arguments = string.IsNullOrWhiteSpace(ArgumentsBox.Text) ? null : ArgumentsBox.Text.Trim(), IconPath = string.IsNullOrWhiteSpace(IconPathBox.Text) ? null : IconPathBox.Text.Trim(), IsFavorite = selectedItem.IsFavorite, + IsDisabled = selectedItem.IsDisabled, DisplayMode = ItemDisplayModeBox.SelectedItem is LauncherDisplayMode mode ? mode : selectedItem.DisplayMode diff --git a/Models/LauncherConfig.cs b/Models/LauncherConfig.cs index 0ade9b6..5aea27c 100644 --- a/Models/LauncherConfig.cs +++ b/Models/LauncherConfig.cs @@ -27,6 +27,8 @@ public sealed class LauncherItem public bool IsFavorite { get; set; } + public bool IsDisabled { get; set; } + public LauncherDisplayMode DisplayMode { get; set; } = LauncherDisplayMode.CompactList; public List Children { get; set; } = []; diff --git a/README.md b/README.md index 960e4ec..9c0507d 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Download the compiled Windows release from: - Nested menus, drag/drop ordering, and drag/drop item creation in Settings - Right-click launcher entries to edit them in Settings - Right-click launcher entries to pin or unpin them from the top +- Right-click launcher entries or Settings items to temporarily disable them - Right-click item duplication in Settings - Right-click items in Settings to pin them to the top of their menu - Per-item icon and display mode diff --git a/Services/ConfigService.cs b/Services/ConfigService.cs index 39eeb18..af23666 100644 --- a/Services/ConfigService.cs +++ b/Services/ConfigService.cs @@ -237,10 +237,11 @@ public static class ConfigService } config.RecentItems ??= []; - config.RecentItems.RemoveAll(item => item.Type == LauncherItemType.Menu || string.IsNullOrWhiteSpace(item.Target)); + config.RecentItems.RemoveAll(item => item.Type == LauncherItemType.Menu || item.IsDisabled || string.IsNullOrWhiteSpace(item.Target)); foreach (LauncherItem item in config.RecentItems) { item.IsFavorite = false; + item.IsDisabled = false; item.Children = []; NormalizeDisplayModes(item); } diff --git a/Services/LauncherController.cs b/Services/LauncherController.cs index bc70aa6..7810161 100644 --- a/Services/LauncherController.cs +++ b/Services/LauncherController.cs @@ -151,7 +151,7 @@ public sealed class LauncherController : IDisposable private void RecordRecentItem(LauncherItem item) { - if (item.Type == LauncherItemType.Menu || string.IsNullOrWhiteSpace(item.Target)) + if (item.Type == LauncherItemType.Menu || item.IsDisabled || string.IsNullOrWhiteSpace(item.Target)) { return; } @@ -182,6 +182,7 @@ public sealed class LauncherController : IDisposable Arguments = item.Arguments, IconPath = item.IconPath, IsFavorite = false, + IsDisabled = false, DisplayMode = item.DisplayMode, Children = [] }; @@ -194,7 +195,7 @@ public sealed class LauncherController : IDisposable foreach (LauncherItem child in menuItem.Children) { - if (child.Type == LauncherItemType.Menu || string.IsNullOrWhiteSpace(child.Target)) + if (child.Type == LauncherItemType.Menu || child.IsDisabled || string.IsNullOrWhiteSpace(child.Target)) { continue; } @@ -224,7 +225,7 @@ public sealed class LauncherController : IDisposable { error = null; - if (item.Type == LauncherItemType.Menu || string.IsNullOrWhiteSpace(item.Target)) + if (item.Type == LauncherItemType.Menu || item.IsDisabled || string.IsNullOrWhiteSpace(item.Target)) { return false; } diff --git a/TaskbarLauncher.csproj b/TaskbarLauncher.csproj index 4141908..5f59469 100644 --- a/TaskbarLauncher.csproj +++ b/TaskbarLauncher.csproj @@ -12,8 +12,8 @@ Ray Berezowski Assets\AppIcon.ico 1.0.1 - 1.0.1.7 - 1.0.1.7 + 1.0.1.8 + 1.0.1.8 1.0.1 diff --git a/Views/LauncherPopup.xaml.cs b/Views/LauncherPopup.xaml.cs index 6f39856..0e4056d 100644 --- a/Views/LauncherPopup.xaml.cs +++ b/Views/LauncherPopup.xaml.cs @@ -94,7 +94,7 @@ public partial class LauncherPopup : Window ItemsPanel.Children.Clear(); visibleLaunchButtons.Clear(); - if (config.RecentItems.Count > 0) + if (config.RecentItems.Any(item => !item.IsDisabled)) { ItemsPanel.Children.Add(CreateRecentItemsControl()); } @@ -116,7 +116,7 @@ public partial class LauncherPopup : Window }; StackPanel recentItems = new(); - foreach (LauncherItem item in config.RecentItems) + foreach (LauncherItem item in config.RecentItems.Where(item => !item.IsDisabled)) { recentItems.Children.Add(CreateItemControl(item, 1, expandMenusByDefault: false, allowEdit: false)); } @@ -195,6 +195,7 @@ public partial class LauncherPopup : Window contextMenu.Items.Add(openAllMenuItem); contextMenu.Items.Add(new Separator()); contextMenu.Items.Add(CreatePinMenuItem(item)); + contextMenu.Items.Add(CreateDisableMenuItem(item)); contextMenu.Items.Add(CreateEditMenuItem(item)); return new TextBlock @@ -208,6 +209,7 @@ public partial class LauncherPopup : Window { System.Windows.Controls.ContextMenu contextMenu = new(); contextMenu.Items.Add(CreatePinMenuItem(item)); + contextMenu.Items.Add(CreateDisableMenuItem(item)); contextMenu.Items.Add(CreateEditMenuItem(item)); return contextMenu; } @@ -230,6 +232,24 @@ public partial class LauncherPopup : Window return pinMenuItem; } + private System.Windows.Controls.MenuItem CreateDisableMenuItem(LauncherItem item) + { + System.Windows.Controls.MenuItem disableMenuItem = new() + { + Header = item.IsDisabled ? "Enable Item" : "Disable Item" + }; + disableMenuItem.Click += (_, e) => + { + item.IsDisabled = !item.IsDisabled; + ConfigService.Save(config); + BuildItems(); + QueueReposition(); + e.Handled = true; + }; + + return disableMenuItem; + } + private System.Windows.Controls.MenuItem CreateEditMenuItem(LauncherItem item) { System.Windows.Controls.MenuItem editMenuItem = new() @@ -248,12 +268,14 @@ public partial class LauncherPopup : Window private static bool IsLaunchable(LauncherItem item) { - return item.Type != LauncherItemType.Menu && !string.IsNullOrWhiteSpace(item.Target); + return item.Type != LauncherItemType.Menu && !item.IsDisabled && !string.IsNullOrWhiteSpace(item.Target); } private static IEnumerable GetDisplayItems(IEnumerable items) { - return items.OrderByDescending(item => item.IsFavorite); + return items + .Where(item => !item.IsDisabled) + .OrderByDescending(item => item.IsFavorite); } private void SearchBox_TextChanged(object sender, TextChangedEventArgs e) @@ -300,7 +322,7 @@ public partial class LauncherPopup : Window { foreach (LauncherItem item in GetDisplayItems(items)) { - bool isLaunchable = item.Type != LauncherItemType.Menu; + bool isLaunchable = item.Type != LauncherItemType.Menu && !item.IsDisabled; if (isLaunchable && Matches(item, query)) { matches.Add(item); diff --git a/config.example.json b/config.example.json index 473ac12..ad805ea 100644 --- a/config.example.json +++ b/config.example.json @@ -11,6 +11,7 @@ "Arguments": null, "IconPath": null, "IsFavorite": false, + "IsDisabled": false, "DisplayMode": "CompactList", "Children": [ { @@ -20,6 +21,7 @@ "Arguments": null, "IconPath": "%USERPROFILE%\\Documents", "IsFavorite": false, + "IsDisabled": false, "DisplayMode": "CompactList", "Children": [] }, @@ -30,6 +32,7 @@ "Arguments": null, "IconPath": "%USERPROFILE%\\Downloads", "IsFavorite": false, + "IsDisabled": false, "DisplayMode": "CompactList", "Children": [] } @@ -42,6 +45,7 @@ "Arguments": null, "IconPath": null, "IsFavorite": false, + "IsDisabled": false, "DisplayMode": "CompactList", "Children": [ { @@ -51,6 +55,7 @@ "Arguments": null, "IconPath": "notepad.exe", "IsFavorite": false, + "IsDisabled": false, "DisplayMode": "CompactList", "Children": [] } diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 34d8925..f663cf3 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -21,6 +21,7 @@ Install the **.NET Desktop Runtime** for **Windows x64**. 4. Press `Ctrl+Alt+Space` to open the launcher. 5. Right-click a launcher entry and choose **Edit in Settings** to jump to that item. 6. Right-click a launcher entry and choose **Pin to Top** or **Unpin from Top**. +7. Right-click a launcher entry and choose **Disable Item** to hide it until it is enabled again from Settings. Recently launched entries appear in the launcher popup under **Recent**. @@ -37,6 +38,7 @@ From Settings you can: - Drag/drop files, folders, shortcuts, or web links into the launcher item list - Right-click an item and choose **Duplicate Item** to copy it - Right-click an item and choose **Pin to Top** to show it first in its menu +- Right-click an item and choose **Disable Item** or **Enable Item** to hide or restore it - Set per-item icon sizes - Back up and restore `config.json` - Enable Start with Windows