[FancyZones Editor] New UX for the FZ editor. (#9325)

* Removed MetroWindow, added theming support and modernWPF

* Rmoved MahApps refs

* Removed MahApps

* Updated canvas zones

* Updated GridEditor

* Fixes

* UI updates

* New layout type selection dialog

* New editor UI

* Updates

* Fix

* UI enhancements

* Updated UI

* Added styles to layoutpreview

* Accesibility improvements

* Accesibility and styling improvements

* Fix

* Cleaned up brushes

* Updated UX

* Updated UI

* Added no layouts description

* Fix

* UI fixes

* [FZ Editor] Serialize/deserialize settings (#8615)

* conflicts fix

* [FZ Editor] Parse json file instead of command line args (#8649)

* [FZ Editor] Serialize/deserialize settings fix (#8707)

* [FZ Editor] Hide unsupported settings in custom layouts flyouts (#8716)

* [FZ Editor] Duplicate custom layouts (#8718)

* [FZ Editor] Duplicate layout behavior (#8720)

* New UX proposal

* Updated spacing

* Switching to toggleswitches

* Revert toggleswitch

* Updated colorbrush

* Updated string for saving label

* Updated UI

* Dark theme color fixes

* Removed space

* [FZ Editor] Bind dialog properties (#9199)

* Resize editor window to fit the content in single-monitor mode (#9203)

* Editor opening fix (#9207)

* Disable "Create" button if the Name textbox is empty (#9212)

* [FZ Editor] Changed edit dialog for template layouts. (#9233)

* [FZ Editor] Small fixes and refactoring. (#9236)

* new layout creation refactoring
* "Save and apply" applies the layout
* number of zones header hide

* [FZ Editor] Empty layout template. (#9237)

* [FZ Editor] Move "Duplicate" and "Delete" buttons to the Edit dialog. (#9272)

* [FZ Editor] Preview the applied layout after editing another layout. (#9278)

* Fixed "Save and apply" button behavior (#9286)

* [FZ Editor] Save template layouts in the settings. (#9283)

* Added default custom layout name (#9291)

* close dialog before opening zones editor (#9302)

* Pressing Esc closes dialogs (#9301)

* [FZ Editor] Reset applied layout to "No layout" if it was deleted. (#9315)

* [FZ Editor] Dark theme colors (#9317)

* "Number of zones" buttons colors. (#9321)

* rebase fix

* added ModernWpf.dll

* address PR comments: updated colors

* added comments, replaced magic numbers

* refactoring

* merge zones crash fix

* removed redundant using directive

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
This commit is contained in:
Seraphima Zykova
2021-01-27 21:33:52 +03:00
committed by GitHub
parent eb15cdde1b
commit 646d61bd4d
61 changed files with 3664 additions and 2781 deletions

View File

@@ -3,40 +3,32 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using FancyZonesEditor.Models;
using MahApps.Metro.Controls;
using FancyZonesEditor.Utils;
using ModernWpf.Controls;
namespace FancyZonesEditor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : MetroWindow
public partial class MainWindow : Window
{
// TODO: share the constants b/w C# Editor and FancyZoneLib
public const int MaxZones = 40;
private const int DefaultWrapPanelItemSize = 262;
private const int SmallWrapPanelItemSize = 180;
private const int DefaultWrapPanelItemSize = 164;
private const int SmallWrapPanelItemSize = 164;
private const int MinimalForDefaultWrapPanelsHeight = 900;
private readonly MainWindowSettingsModel _settings = ((App)Application.Current).MainWindowSettings;
private LayoutModel _backup = null;
// Localizable string
private static readonly string _defaultNamePrefix = "Custom Layout ";
private ContentDialog _openedDialog = null;
public int WrapPanelItemSize { get; set; } = DefaultWrapPanelItemSize;
public double SettingsTextMaxWidth
{
get
{
return (Width / 2) - 60;
}
}
public MainWindow(bool spanZonesAcrossMonitors, Rect workArea)
{
InitializeComponent();
@@ -51,59 +43,84 @@ namespace FancyZonesEditor
if (workArea.Height < MinimalForDefaultWrapPanelsHeight || App.Overlay.MultiMonitorMode)
{
SizeToContent = SizeToContent.WidthAndHeight;
WrapPanelItemSize = SmallWrapPanelItemSize;
}
SizeToContent = SizeToContent.WidthAndHeight;
}
public void Update()
{
DataContext = _settings;
SetSelectedItem();
}
private void MainWindow_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
OnClosing(sender, null);
if (_openedDialog != null)
{
_openedDialog.Hide();
}
else
{
OnClosing(sender, null);
}
}
}
private void DecrementZones_Click(object sender, RoutedEventArgs e)
{
if (_settings.ZoneCount > 1)
var mainEditor = App.Overlay;
if (!(mainEditor.CurrentDataContext is LayoutModel model))
{
_settings.ZoneCount--;
return;
}
if (model.TemplateZoneCount > 1)
{
model.TemplateZoneCount--;
}
}
private void IncrementZones_Click(object sender, RoutedEventArgs e)
{
if (_settings.ZoneCount < MaxZones)
var mainEditor = App.Overlay;
if (!(mainEditor.CurrentDataContext is LayoutModel model))
{
_settings.ZoneCount++;
return;
}
if (model.TemplateZoneCount < LayoutSettings.MaxZones)
{
model.TemplateZoneCount++;
}
}
private void NewCustomLayoutButton_Click(object sender, RoutedEventArgs e)
private void LayoutItem_MouseEnter(object sender, MouseEventArgs e)
{
WindowLayout window = new WindowLayout();
window.Show();
Hide();
// Select(((Grid)sender).DataContext as LayoutModel);
}
private void LayoutItem_Click(object sender, MouseButtonEventArgs e)
{
Select(((Border)sender).DataContext as LayoutModel);
LayoutModel selectedLayoutModel = ((Grid)sender).DataContext as LayoutModel;
Select(selectedLayoutModel);
Apply();
}
private void LayoutItem_Focused(object sender, RoutedEventArgs e)
{
// Ignore focus on Edit button click
if (e.Source is Button)
{
return;
}
Select(((Border)sender).DataContext as LayoutModel);
}
private void LayoutItem_Apply(object sender, KeyEventArgs e)
private void LayoutItem_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return || e.Key == Key.Space)
{
@@ -115,17 +132,39 @@ namespace FancyZonesEditor
private void Select(LayoutModel newSelection)
{
if (App.Overlay.CurrentDataContext is LayoutModel currentSelection)
{
currentSelection.IsSelected = false;
}
newSelection.IsSelected = true;
_settings.SetSelectedModel(newSelection);
App.Overlay.CurrentDataContext = newSelection;
}
private void EditLayout_Click(object sender, RoutedEventArgs e)
private async void NewLayoutButton_Click(object sender, RoutedEventArgs e)
{
string defaultNamePrefix = FancyZonesEditor.Properties.Resources.Default_Custom_Layout_Name;
int maxCustomIndex = 0;
foreach (LayoutModel customModel in MainWindowSettingsModel.CustomModels)
{
string name = customModel.Name;
if (name.StartsWith(defaultNamePrefix))
{
if (int.TryParse(name.Substring(defaultNamePrefix.Length), out int i))
{
if (maxCustomIndex < i)
{
maxCustomIndex = i;
}
}
}
}
LayoutNameText.Text = defaultNamePrefix + " " + (++maxCustomIndex);
GridLayoutRadioButton.IsChecked = true;
GridLayoutRadioButton.Focus();
await NewLayoutDialog.ShowAsync();
}
private void DuplicateLayout_Click(object sender, RoutedEventArgs e)
{
EditLayoutDialog.Hide();
var mainEditor = App.Overlay;
if (!(mainEditor.CurrentDataContext is LayoutModel model))
{
@@ -133,26 +172,32 @@ namespace FancyZonesEditor
}
model.IsSelected = false;
Hide();
bool isPredefinedLayout = MainWindowSettingsModel.IsPredefinedLayout(model);
// make a copy
model = model.Clone();
mainEditor.CurrentDataContext = model;
if (!MainWindowSettingsModel.CustomModels.Contains(model) || isPredefinedLayout)
string name = model.Name;
var index = name.LastIndexOf('(');
if (index != -1)
{
if (isPredefinedLayout)
{
// make a copy
model = model.Clone();
mainEditor.CurrentDataContext = model;
}
name = name.Remove(index);
name = name.TrimEnd();
}
int maxCustomIndex = 0;
foreach (LayoutModel customModel in MainWindowSettingsModel.CustomModels)
int maxCustomIndex = 0;
foreach (LayoutModel customModel in MainWindowSettingsModel.CustomModels)
{
string customModelName = customModel.Name;
if (customModelName.StartsWith(name))
{
string name = customModel.Name;
if (name.StartsWith(_defaultNamePrefix))
int openBraceIndex = customModelName.LastIndexOf('(');
int closeBraceIndex = customModelName.LastIndexOf(')');
if (openBraceIndex != -1 && closeBraceIndex != -1)
{
if (int.TryParse(name.Substring(_defaultNamePrefix.Length), out int i))
string indexSubstring = customModelName.Substring(openBraceIndex + 1, closeBraceIndex - openBraceIndex - 1);
if (int.TryParse(indexSubstring, out int i))
{
if (maxCustomIndex < i)
{
@@ -161,67 +206,70 @@ namespace FancyZonesEditor
}
}
}
model.Name = _defaultNamePrefix + (++maxCustomIndex);
}
mainEditor.OpenEditor(model);
}
model.Name = name + " (" + (++maxCustomIndex) + ')';
private void Apply_Click(object sender, RoutedEventArgs e)
{
Apply();
model.Persist();
App.Overlay.SetLayoutSettings(App.Overlay.Monitors[App.Overlay.CurrentDesktop], model);
App.FancyZonesEditorIO.SerializeZoneSettings();
}
private void Apply()
{
((App)Application.Current).MainWindowSettings.ResetAppliedModel();
var mainEditor = App.Overlay;
if (mainEditor.CurrentDataContext is LayoutModel model)
{
model.Apply();
}
if (!mainEditor.MultiMonitorMode)
{
Close();
_settings.SetAppliedModel(model);
App.Overlay.SetLayoutSettings(App.Overlay.Monitors[App.Overlay.CurrentDesktop], model);
App.FancyZonesEditorIO.SerializeZoneSettings();
}
}
private void OnClosing(object sender, EventArgs e)
{
LayoutModel.SerializeDeletedCustomZoneSets();
App.FancyZonesEditorIO.SerializeZoneSettings();
App.Overlay.CloseLayoutWindow();
App.Current.Shutdown();
}
private void OnInitialized(object sender, EventArgs e)
private void DeleteLayout_Click(object sender, RoutedEventArgs e)
{
SetSelectedItem();
EditLayoutDialog.Hide();
DeleteLayout((FrameworkElement)sender);
}
private void SetSelectedItem()
private async void EditLayout_Click(object sender, RoutedEventArgs e)
{
foreach (LayoutModel model in MainWindowSettingsModel.CustomModels)
var dataContext = ((FrameworkElement)sender).DataContext;
Select((LayoutModel)dataContext);
if (_settings.SelectedModel is GridLayoutModel grid)
{
if (model.IsSelected)
{
TemplateTab.SelectedItem = model;
return;
}
_backup = new GridLayoutModel(grid);
}
else if (_settings.SelectedModel is CanvasLayoutModel canvas)
{
_backup = new CanvasLayoutModel(canvas);
}
await EditLayoutDialog.ShowAsync();
}
private void OnDelete(object sender, RoutedEventArgs e)
private void EditZones_Click(object sender, RoutedEventArgs e)
{
LayoutModel model = ((FrameworkElement)sender).DataContext as LayoutModel;
if (model.IsSelected)
EditLayoutDialog.Hide();
var mainEditor = App.Overlay;
if (!(mainEditor.CurrentDataContext is LayoutModel model))
{
SetSelectedItem();
return;
}
model.Delete();
_settings.SetSelectedModel(model);
Hide();
mainEditor.OpenEditor(model);
}
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
@@ -239,32 +287,129 @@ namespace FancyZonesEditor
e.Handled = true;
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
private void NewLayoutDialog_PrimaryButtonClick(ModernWpf.Controls.ContentDialog sender, ModernWpf.Controls.ContentDialogButtonClickEventArgs args)
{
this.Close();
LayoutModel selectedLayoutModel;
if (GridLayoutRadioButton.IsChecked == true)
{
GridLayoutModel gridModel = new GridLayoutModel(LayoutNameText.Text, LayoutType.Custom)
{
Rows = 1,
RowPercents = new List<int>(1) { GridLayoutModel.GridMultiplier },
};
selectedLayoutModel = gridModel;
}
else
{
selectedLayoutModel = new CanvasLayoutModel(LayoutNameText.Text, LayoutType.Custom)
{
TemplateZoneCount = 0,
};
}
selectedLayoutModel.InitTemplateZones();
App.Overlay.CurrentDataContext = selectedLayoutModel;
var mainEditor = App.Overlay;
Hide();
mainEditor.OpenEditor(selectedLayoutModel);
}
private void Reset_Click(object sender, RoutedEventArgs e)
// This is required to fix a WPF rendering bug when using custom chrome
private void OnContentRendered(object sender, EventArgs e)
{
var overlay = App.Overlay;
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
InvalidateVisual();
}
if (overlay.CurrentDataContext is LayoutModel model)
private void MonitorItem_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return || e.Key == Key.Space)
{
model.IsSelected = false;
model.IsApplied = false;
monitorViewModel.SelectCommand.Execute((MonitorInfoModel)(sender as Border).DataContext);
}
}
private void MonitorItem_MouseDown(object sender, MouseButtonEventArgs e)
{
monitorViewModel.SelectCommand.Execute((MonitorInfoModel)(sender as Border).DataContext);
}
// EditLayout: Cancel changes
private void EditLayoutDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
// restore model properties from settings
_settings.RestoreSelectedModel(_backup);
_backup = null;
Select(_settings.AppliedModel);
}
// EditLayout: Save changes
private void EditLayoutDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
var mainEditor = App.Overlay;
if (!(mainEditor.CurrentDataContext is LayoutModel model))
{
return;
}
overlay.CurrentLayoutSettings.ZonesetUuid = settings.BlankModel.Uuid;
overlay.CurrentLayoutSettings.Type = LayoutType.Blank;
overlay.CurrentDataContext = settings.BlankModel;
_backup = null;
App.FancyZonesEditorIO.SerializeAppliedLayouts();
if (!overlay.MultiMonitorMode)
// update current settings
if (model == _settings.AppliedModel)
{
Close();
App.Overlay.SetLayoutSettings(App.Overlay.Monitors[App.Overlay.CurrentDesktop], model);
}
App.FancyZonesEditorIO.SerializeZoneSettings();
// reset selected model
Select(_settings.AppliedModel);
}
private async void DeleteLayout(FrameworkElement element)
{
var dialog = new ModernWpf.Controls.ContentDialog()
{
Title = FancyZonesEditor.Properties.Resources.Are_You_Sure,
Content = FancyZonesEditor.Properties.Resources.Are_You_Sure_Description,
PrimaryButtonText = FancyZonesEditor.Properties.Resources.Delete,
SecondaryButtonText = FancyZonesEditor.Properties.Resources.Cancel,
};
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
LayoutModel model = element.DataContext as LayoutModel;
if (model == _settings.AppliedModel)
{
_settings.SetAppliedModel(_settings.BlankModel);
Select(_settings.BlankModel);
}
foreach (var monitor in App.Overlay.Monitors)
{
if (monitor.Settings.ZonesetUuid == model.Uuid)
{
App.Overlay.SetLayoutSettings(monitor, _settings.BlankModel);
}
}
App.FancyZonesEditorIO.SerializeZoneSettings();
model.Delete();
}
}
private void Dialog_Opened(ContentDialog sender, ContentDialogOpenedEventArgs args)
{
_openedDialog = sender;
}
private void Dialog_Closed(ContentDialog sender, ContentDialogClosedEventArgs args)
{
_openedDialog = null;
}
}
}