From 69a554cb7902d703cb70e08ff067ca87fd3df01e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Oct 2025 06:56:07 +0000 Subject: [PATCH] Add template deletion functionality to FancyZones Editor - Created LayoutTypeDeletableToVisibilityConverter to show delete button for templates (except Blank) - Updated MainWindow.xaml to use new converter for delete buttons and menu items - Modified LayoutModel.Delete() to handle both custom and template layout deletion - Changed TemplateModels from IList to ObservableCollection for UI updates - Updated all index-based TemplateModels access to use LINQ queries - Enhanced DefaultLayoutsModel.Reset() to handle missing templates gracefully - Added fallback logic when templates are deleted Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com> --- ...ayoutTypeDeletableToVisibilityConverter.cs | 28 +++++++++ .../editor/FancyZonesEditor/MainWindow.xaml | 7 ++- .../Models/DefaultLayoutsModel.cs | 21 +++++-- .../FancyZonesEditor/Models/LayoutModel.cs | 12 +++- .../Models/MainWindowSettingsModel.cs | 17 ++--- .../Utils/FancyZonesEditorIO.cs | 63 +++++++++++-------- 6 files changed, 106 insertions(+), 42 deletions(-) create mode 100644 src/modules/fancyzones/editor/FancyZonesEditor/Converters/LayoutTypeDeletableToVisibilityConverter.cs diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Converters/LayoutTypeDeletableToVisibilityConverter.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Converters/LayoutTypeDeletableToVisibilityConverter.cs new file mode 100644 index 0000000000..8be0913e83 --- /dev/null +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Converters/LayoutTypeDeletableToVisibilityConverter.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +using FancyZonesEditor.Models; + +namespace FancyZonesEditor.Converters +{ + public class LayoutTypeDeletableToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + // Allow deletion for custom layouts and all template layouts except Blank + LayoutType type = (LayoutType)value; + return (type == LayoutType.Custom || (type != LayoutType.Blank && type != LayoutType.Custom)) ? Visibility.Visible : Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + } +} diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml b/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml index d7d53e2725..aa40f32041 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml +++ b/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml @@ -33,6 +33,7 @@ + @@ -68,11 +69,11 @@ - + + Visibility="{Binding Path=Type, Converter={StaticResource LayoutTypeDeletableToVisibilityConverter}}"> @@ -437,7 +438,7 @@ Click="DeleteLayout_Click" Style="{StaticResource IconOnlyButtonStyle}" ToolTip="{x:Static props:Resources.Delete}" - Visibility="{Binding Path=Type, Converter={StaticResource LayoutTypeCustomToVisibilityConverter}}"> + Visibility="{Binding Path=Type, Converter={StaticResource LayoutTypeDeletableToVisibilityConverter}}"> m.Type == LayoutType.PriorityGrid) + ?? MainWindowSettingsModel.TemplateModels.FirstOrDefault(m => m.Type != LayoutType.Blank) + ?? MainWindowSettingsModel.TemplateModels.FirstOrDefault(m => m.Type == LayoutType.Blank); break; case MonitorConfigurationType.Vertical: - Set(MainWindowSettingsModel.TemplateModels[(int)LayoutType.Rows], type); + // Try to get Rows, fallback to first available template or Blank + defaultLayout = MainWindowSettingsModel.TemplateModels.FirstOrDefault(m => m.Type == LayoutType.Rows) + ?? MainWindowSettingsModel.TemplateModels.FirstOrDefault(m => m.Type != LayoutType.Blank) + ?? MainWindowSettingsModel.TemplateModels.FirstOrDefault(m => m.Type == LayoutType.Blank); break; } + + if (defaultLayout != null) + { + Set(defaultLayout, type); + } } public void Reset(string uuid) { if (Layouts[MonitorConfigurationType.Horizontal].Uuid == uuid) { - Set(MainWindowSettingsModel.TemplateModels[(int)LayoutType.PriorityGrid], MonitorConfigurationType.Horizontal); + Reset(MonitorConfigurationType.Horizontal); } if (Layouts[MonitorConfigurationType.Vertical].Uuid == uuid) { - Set(MainWindowSettingsModel.TemplateModels[(int)LayoutType.Rows], MonitorConfigurationType.Vertical); + Reset(MonitorConfigurationType.Vertical); } } diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs index 97fcdbc400..781c174c2a 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs @@ -335,7 +335,7 @@ namespace FancyZonesEditor.Models PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } - // Removes this Layout from the registry and the loaded CustomModels list + // Removes this Layout from the registry and the loaded CustomModels list or TemplateModels list public void Delete() { var customModels = MainWindowSettingsModel.CustomModels; @@ -353,6 +353,16 @@ namespace FancyZonesEditor.Models { customModels.RemoveAt(i); } + else + { + // Try to remove from template models if it's a template layout + var templateModels = MainWindowSettingsModel.TemplateModels; + i = templateModels.IndexOf(this); + if (i != -1) + { + templateModels.RemoveAt(i); + } + } } public void RestoreTo(LayoutModel layout) diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Models/MainWindowSettingsModel.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Models/MainWindowSettingsModel.cs index d5d4e45ad7..a24dd24e4e 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Models/MainWindowSettingsModel.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Models/MainWindowSettingsModel.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; +using System.Linq; using System.Runtime.CompilerServices; using FancyZonesEditor.Models; @@ -51,11 +52,11 @@ namespace FancyZonesEditor TemplateZoneCount = 0, SensitivityRadius = 0, }; - TemplateModels.Insert((int)LayoutType.Blank, blankModel); + TemplateModels.Add(blankModel); var focusModel = new CanvasLayoutModel(Properties.Resources.Template_Layout_Focus, LayoutType.Focus); focusModel.InitTemplateZones(); - TemplateModels.Insert((int)LayoutType.Focus, focusModel); + TemplateModels.Add(focusModel); var columnsModel = new GridLayoutModel(Properties.Resources.Template_Layout_Columns, LayoutType.Columns) { @@ -63,7 +64,7 @@ namespace FancyZonesEditor RowPercents = new List(1) { GridLayoutModel.GridMultiplier }, }; columnsModel.InitTemplateZones(); - TemplateModels.Insert((int)LayoutType.Columns, columnsModel); + TemplateModels.Add(columnsModel); var rowsModel = new GridLayoutModel(Properties.Resources.Template_Layout_Rows, LayoutType.Rows) { @@ -71,15 +72,15 @@ namespace FancyZonesEditor ColumnPercents = new List(1) { GridLayoutModel.GridMultiplier }, }; rowsModel.InitTemplateZones(); - TemplateModels.Insert((int)LayoutType.Rows, rowsModel); + TemplateModels.Add(rowsModel); var gridModel = new GridLayoutModel(Properties.Resources.Template_Layout_Grid, LayoutType.Grid); gridModel.InitTemplateZones(); - TemplateModels.Insert((int)LayoutType.Grid, gridModel); + TemplateModels.Add(gridModel); var priorityGridModel = new GridLayoutModel(Properties.Resources.Template_Layout_Priority_Grid, LayoutType.PriorityGrid); priorityGridModel.InitTemplateZones(); - TemplateModels.Insert((int)LayoutType.PriorityGrid, priorityGridModel); + TemplateModels.Add(priorityGridModel); // set default layouts DefaultLayouts.Set(rowsModel, MonitorConfigurationType.Vertical); @@ -130,11 +131,11 @@ namespace FancyZonesEditor { get { - return TemplateModels[(int)LayoutType.Blank]; + return TemplateModels.FirstOrDefault(m => m.Type == LayoutType.Blank); } } - public static IList TemplateModels { get; } = new List(6); + public static ObservableCollection TemplateModels { get; } = new ObservableCollection(); public static ObservableCollection CustomModels { diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs index 4168beaf1c..230b016a39 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.IO; +using System.Linq; using System.Text.Json; using System.Windows; @@ -648,15 +649,18 @@ namespace FancyZonesEditor.Utils // replace deleted layout with the Blank layout if (!existingLayout) { - LayoutModel blankLayout = MainWindowSettingsModel.TemplateModels[(int)LayoutType.Blank]; - settings.ZonesetUuid = blankLayout.Uuid; - settings.Type = blankLayout.Type; - settings.ZoneCount = blankLayout.TemplateZoneCount; - settings.SensitivityRadius = blankLayout.SensitivityRadius; + LayoutModel blankLayout = MainWindowSettingsModel.TemplateModels.FirstOrDefault(m => m.Type == LayoutType.Blank); + if (blankLayout != null) + { + settings.ZonesetUuid = blankLayout.Uuid; + settings.Type = blankLayout.Type; + settings.ZoneCount = blankLayout.TemplateZoneCount; + settings.SensitivityRadius = blankLayout.SensitivityRadius; - // grid layout settings, just resetting them - settings.ShowSpacing = false; - settings.Spacing = 0; + // grid layout settings, just resetting them + settings.ShowSpacing = false; + settings.Spacing = 0; + } } bool unused = true; @@ -748,18 +752,21 @@ namespace FancyZonesEditor.Utils foreach (var wrapper in templateLayouts) { LayoutType type = JsonTagToLayoutType(wrapper.Type); - LayoutModel layout = MainWindowSettingsModel.TemplateModels[(int)type]; + LayoutModel layout = MainWindowSettingsModel.TemplateModels.FirstOrDefault(m => m.Type == type); - layout.SensitivityRadius = wrapper.SensitivityRadius; - layout.TemplateZoneCount = wrapper.ZoneCount; - - if (layout is GridLayoutModel grid) + if (layout != null) { - grid.ShowSpacing = wrapper.ShowSpacing; - grid.Spacing = wrapper.Spacing; - } + layout.SensitivityRadius = wrapper.SensitivityRadius; + layout.TemplateZoneCount = wrapper.ZoneCount; - layout.InitTemplateZones(); + if (layout is GridLayoutModel grid) + { + grid.ShowSpacing = wrapper.ShowSpacing; + grid.Spacing = wrapper.Spacing; + } + + layout.InitTemplateZones(); + } } return true; @@ -807,17 +814,21 @@ namespace FancyZonesEditor.Utils else { LayoutType layoutType = JsonTagToLayoutType(layout.Layout.Type); - defaultLayoutModel = MainWindowSettingsModel.TemplateModels[(int)layoutType]; - defaultLayoutModel.TemplateZoneCount = layout.Layout.ZoneCount; - defaultLayoutModel.SensitivityRadius = layout.Layout.SensitivityRadius; - - if (defaultLayoutModel is GridLayoutModel gridDefaultLayoutModel) + defaultLayoutModel = MainWindowSettingsModel.TemplateModels.FirstOrDefault(m => m.Type == layoutType); + + if (defaultLayoutModel != null) { - gridDefaultLayoutModel.ShowSpacing = layout.Layout.ShowSpacing; - gridDefaultLayoutModel.Spacing = layout.Layout.Spacing; - } + defaultLayoutModel.TemplateZoneCount = layout.Layout.ZoneCount; + defaultLayoutModel.SensitivityRadius = layout.Layout.SensitivityRadius; - MainWindowSettingsModel.DefaultLayouts.Set(defaultLayoutModel, type); + if (defaultLayoutModel is GridLayoutModel gridDefaultLayoutModel) + { + gridDefaultLayoutModel.ShowSpacing = layout.Layout.ShowSpacing; + gridDefaultLayoutModel.Spacing = layout.Layout.Spacing; + } + + MainWindowSettingsModel.DefaultLayouts.Set(defaultLayoutModel, type); + } } if (defaultLayoutModel != null)