// 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.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; using FancyZonesEditor.Models; namespace FancyZonesEditor { /// /// Interaction logic for LayoutPreview.xaml /// public partial class LayoutPreview : UserControl { // Non-localizable strings private const string PropertyZoneCountID = "ZoneCount"; private const string PropertyShowSpacingID = "ShowSpacing"; private const string PropertySpacingID = "Spacing"; private const string ObjectDependencyID = "IsActualSize"; public static readonly DependencyProperty IsActualSizeProperty = DependencyProperty.Register(ObjectDependencyID, typeof(bool), typeof(LayoutPreview), new PropertyMetadata(false)); private LayoutModel _model; private List _zones = new List(); public LayoutPreview() { InitializeComponent(); DataContextChanged += LayoutPreview_DataContextChanged; ((App)Application.Current).ZoneSettings.PropertyChanged += ZoneSettings_PropertyChanged; } private void LayoutPreview_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { _model = (LayoutModel)DataContext; RenderPreview(); } public bool IsActualSize { get { return (bool)GetValue(IsActualSizeProperty); } set { SetValue(IsActualSizeProperty, value); } } private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == PropertyZoneCountID) { RenderPreview(); } else if ((e.PropertyName == PropertyShowSpacingID) || (e.PropertyName == PropertySpacingID)) { if (_model is GridLayoutModel) { RenderPreview(); } } } public Int32Rect[] GetZoneRects() { return _zones.ToArray(); } private void OnLoaded(object sender, RoutedEventArgs e) { _model = (LayoutModel)DataContext; RenderPreview(); } private void RenderPreview() { if (_model == null) { return; } Body.Children.Clear(); Body.RowDefinitions.Clear(); Body.ColumnDefinitions.Clear(); _zones.Clear(); if (_model is GridLayoutModel gridModel) { RenderGridPreview(gridModel); } else if (_model is CanvasLayoutModel canvasModel) { RenderCanvasPreview(canvasModel); } } private void RenderActualScalePreview(GridLayoutModel grid) { int rows = grid.Rows; int cols = grid.Columns; RowColInfo[] rowInfo = (from percent in grid.RowPercents select new RowColInfo(percent)).ToArray(); RowColInfo[] colInfo = (from percent in grid.ColumnPercents select new RowColInfo(percent)).ToArray(); Settings settings = ((App)Application.Current).ZoneSettings; int spacing = settings.ShowSpacing ? settings.Spacing : 0; int width = (int)Settings.WorkArea.Width; int height = (int)Settings.WorkArea.Height; double totalWidth = width - (spacing * (cols + 1)); double totalHeight = height - (spacing * (rows + 1)); double top = spacing; for (int row = 0; row < rows; row++) { double cellHeight = rowInfo[row].Recalculate(top, totalHeight); top += cellHeight + spacing; } double left = spacing; for (int col = 0; col < cols; col++) { double cellWidth = colInfo[col].Recalculate(left, totalWidth); left += cellWidth + spacing; } Viewbox viewbox = new Viewbox { Stretch = Stretch.Uniform, }; Body.Children.Add(viewbox); Canvas frame = new Canvas { Width = width, Height = height, }; viewbox.Child = frame; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { int childIndex = grid.CellChildMap[row, col]; if (((row == 0) || (grid.CellChildMap[row - 1, col] != childIndex)) && ((col == 0) || (grid.CellChildMap[row, col - 1] != childIndex))) { // this is not a continuation of a span Rectangle rect = new Rectangle(); left = colInfo[col].Start; top = rowInfo[row].Start; Canvas.SetTop(rect, top); Canvas.SetLeft(rect, left); int maxRow = row; while (((maxRow + 1) < rows) && (grid.CellChildMap[maxRow + 1, col] == childIndex)) { maxRow++; } int maxCol = col; while (((maxCol + 1) < cols) && (grid.CellChildMap[row, maxCol + 1] == childIndex)) { maxCol++; } rect.Width = Math.Max(0, colInfo[maxCol].End - left); rect.Height = Math.Max(0, rowInfo[maxRow].End - top); rect.StrokeThickness = 1; rect.Stroke = Brushes.DarkGray; rect.Fill = Brushes.LightGray; frame.Children.Add(rect); _zones.Add(new Int32Rect( (int)left, (int)top, (int)rect.Width, (int)rect.Height)); } } } } private void RenderSmallScalePreview(GridLayoutModel grid) { foreach (int percent in grid.RowPercents) { RowDefinition def = new RowDefinition { Height = new GridLength(percent, GridUnitType.Star), }; Body.RowDefinitions.Add(def); } foreach (int percent in grid.ColumnPercents) { ColumnDefinition def = new ColumnDefinition { Width = new GridLength(percent, GridUnitType.Star), }; Body.ColumnDefinitions.Add(def); } Settings settings = ((App)Application.Current).ZoneSettings; Thickness margin = new Thickness(settings.ShowSpacing ? settings.Spacing / 20 : 0); List visited = new List(); for (int row = 0; row < grid.Rows; row++) { for (int col = 0; col < grid.Columns; col++) { int childIndex = grid.CellChildMap[row, col]; if (!visited.Contains(childIndex)) { visited.Add(childIndex); Rectangle rect = new Rectangle(); Grid.SetRow(rect, row); Grid.SetColumn(rect, col); int span = 1; int walk = row + 1; while ((walk < grid.Rows) && grid.CellChildMap[walk, col] == childIndex) { span++; walk++; } Grid.SetRowSpan(rect, span); span = 1; walk = col + 1; while ((walk < grid.Columns) && grid.CellChildMap[row, walk] == childIndex) { span++; walk++; } Grid.SetColumnSpan(rect, span); rect.Margin = margin; rect.StrokeThickness = 1; rect.Stroke = Brushes.DarkGray; rect.Fill = Brushes.LightGray; Body.Children.Add(rect); } } } } private void RenderGridPreview(GridLayoutModel grid) { if (IsActualSize) { RenderActualScalePreview(grid); } else { RenderSmallScalePreview(grid); } } private void RenderCanvasPreview(CanvasLayoutModel canvas) { Viewbox viewbox = new Viewbox { Stretch = Stretch.Uniform, }; Body.Children.Add(viewbox); Canvas frame = new Canvas { Width = Settings.WorkArea.Width, Height = Settings.WorkArea.Height, }; viewbox.Child = frame; foreach (Int32Rect zone in canvas.Zones) { Rectangle rect = new Rectangle(); Canvas.SetTop(rect, zone.Y); Canvas.SetLeft(rect, zone.X); rect.MinWidth = zone.Width; rect.MinHeight = zone.Height; rect.StrokeThickness = 5; rect.Stroke = Brushes.DarkGray; rect.Fill = Brushes.LightGray; frame.Children.Add(rect); } } } }