From 216b125ff342e09bdbd3397aa5dfc67b923d61a7 Mon Sep 17 00:00:00 2001 From: Benjamin Popp Date: Sat, 8 Jun 2019 21:12:17 -0500 Subject: [PATCH] Zoom setup Change CellWidth and CellHeight to be instance members of `HexContent` instead of static. This forces other components to look up the size (or get handed the size) instead of using a global. This will let us vary the width/height in the future. Add 'ZoomLevel' concept to EditorViewModel, so we can save/load the zoom level. It doesn't currently connect to anything in the UI, but it will eventually map to font size, which will be used to calculate cell size. --- .../ViewModels/EditorViewModel.cs | 9 ++++ src/HexManiac.WPF/Controls/HexContent.cs | 50 +++++++++++++------ src/HexManiac.WPF/Controls/TabView.xaml | 6 +-- .../Implementations/FormatDrawer.cs | 34 +++++++------ 4 files changed, 65 insertions(+), 34 deletions(-) diff --git a/src/HexManiac.Core/ViewModels/EditorViewModel.cs b/src/HexManiac.Core/ViewModels/EditorViewModel.cs index 33c25dc5..c032b702 100644 --- a/src/HexManiac.Core/ViewModels/EditorViewModel.cs +++ b/src/HexManiac.Core/ViewModels/EditorViewModel.cs @@ -101,6 +101,12 @@ namespace HavenSoft.HexManiac.Core.ViewModels { } } + private int zoomLevel = 16; + public int ZoomLevel { + get => zoomLevel; + set => TryUpdate(ref zoomLevel, value); + } + private bool showError; public bool ShowError { get => showError; @@ -234,12 +240,15 @@ namespace HavenSoft.HexManiac.Core.ViewModels { var metadata = fileSystem.MetadataFor(ApplicationName) ?? new string[0]; Theme = new Theme(metadata); ShowMatrix = !metadata.Contains("ShowMatrixGrid = False"); + var zoomLine = metadata.FirstOrDefault(line => line.StartsWith("ZoomLevel =")); + if (zoomLine != null && int.TryParse(zoomLine.Split('=').Last().Trim(), out var zoomLevel)) ZoomLevel = zoomLevel; } public void WriteAppLevelMetadata() { var metadata = new List(); metadata.Add("[GeneralSettings]"); metadata.Add($"ShowMatrixGrid = {ShowMatrix}"); + metadata.Add($"ZoomLevel = {ZoomLevel}"); metadata.Add(string.Empty); metadata.AddRange(Theme.Serialize()); fileSystem.SaveMetadata(ApplicationName, metadata.ToArray()); diff --git a/src/HexManiac.WPF/Controls/HexContent.cs b/src/HexManiac.WPF/Controls/HexContent.cs index 751c9790..179084b3 100644 --- a/src/HexManiac.WPF/Controls/HexContent.cs +++ b/src/HexManiac.WPF/Controls/HexContent.cs @@ -21,16 +21,6 @@ using ScreenPoint = System.Windows.Point; namespace HavenSoft.HexManiac.WPF.Controls { public class HexContent : FrameworkElement { - public const double CellWidth = 30, CellHeight = 20; - - public static readonly Rect CellRect = new Rect(0, 0, CellWidth, CellHeight); - - public static readonly ScreenPoint - TopLeft = new ScreenPoint(0, 0), - TopRight = new ScreenPoint(CellWidth, 0), - BottomLeft = new ScreenPoint(0, CellHeight), - BottomRight = new ScreenPoint(CellWidth, CellHeight); - public static readonly Pen BorderPen = new Pen(Brush(nameof(Theme.Stream2)), 1); private Popup recentMenu; @@ -90,6 +80,24 @@ namespace HavenSoft.HexManiac.WPF.Controls { #endregion + #region CellWidth / Cell Height + + public static readonly DependencyProperty CellWidthProperty = DependencyProperty.Register(nameof(CellWidth), typeof(double), typeof(HexContent), new PropertyMetadata(0.0)); + + public double CellWidth { + get { return (double)GetValue(CellWidthProperty); } + set { SetValue(CellWidthProperty, value); } + } + + public static readonly DependencyProperty CellHeightProperty = DependencyProperty.Register(nameof(CellHeight), typeof(double), typeof(HexContent), new PropertyMetadata(0.0)); + + public double CellHeight { + get { return (double)GetValue(CellHeightProperty); } + set { SetValue(CellHeightProperty, value); } + } + + #endregion + #region ShowGrid public bool ShowGrid { @@ -321,7 +329,7 @@ namespace HavenSoft.HexManiac.WPF.Controls { protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); if (ViewPort == null) return; - var visitor = new FormatDrawer(drawingContext, ViewPort.Width, ViewPort.Height); + var visitor = new FormatDrawer(drawingContext, ViewPort.Width, ViewPort.Height, CellWidth, CellHeight); if (ShowHorizontalScroll) drawingContext.PushTransform(new TranslateTransform(-HorizontalScrollValue, 0)); RenderGrid(drawingContext); @@ -350,17 +358,24 @@ namespace HavenSoft.HexManiac.WPF.Controls { } private void RenderSelection(DrawingContext drawingContext) { + var cellRect = new Rect(0, 0, CellWidth, CellHeight); + ScreenPoint + topLeft = new ScreenPoint(0, 0), + topRight = new ScreenPoint(CellWidth, 0), + bottomLeft = new ScreenPoint(0, CellHeight), + bottomRight = new ScreenPoint(CellWidth, CellHeight); + for (int x = 0; x < ViewPort.Width; x++) { for (int y = 0; y < ViewPort.Height; y++) { if (!ViewPort.IsSelected(new ModelPoint(x, y))) continue; var element = ViewPort[x, y]; drawingContext.PushTransform(new TranslateTransform(x * CellWidth, y * CellHeight)); - drawingContext.DrawRectangle(Brush(nameof(Theme.Backlight)), null, CellRect); - if (!ViewPort.IsSelected(new ModelPoint(x, y - 1))) drawingContext.DrawLine(BorderPen, TopLeft, TopRight); - if (!ViewPort.IsSelected(new ModelPoint(x, y + 1))) drawingContext.DrawLine(BorderPen, BottomLeft, BottomRight); - if (!ViewPort.IsSelected(new ModelPoint(x - 1, y))) drawingContext.DrawLine(BorderPen, TopLeft, BottomLeft); - if (!ViewPort.IsSelected(new ModelPoint(x + 1, y))) drawingContext.DrawLine(BorderPen, TopRight, BottomRight); + drawingContext.DrawRectangle(Brush(nameof(Theme.Backlight)), null, cellRect); + if (!ViewPort.IsSelected(new ModelPoint(x, y - 1))) drawingContext.DrawLine(BorderPen, topLeft, topRight); + if (!ViewPort.IsSelected(new ModelPoint(x, y + 1))) drawingContext.DrawLine(BorderPen, bottomLeft, bottomRight); + if (!ViewPort.IsSelected(new ModelPoint(x - 1, y))) drawingContext.DrawLine(BorderPen, topLeft, bottomLeft); + if (!ViewPort.IsSelected(new ModelPoint(x + 1, y))) drawingContext.DrawLine(BorderPen, topRight, bottomRight); drawingContext.Pop(); } @@ -452,6 +467,9 @@ namespace HavenSoft.HexManiac.WPF.Controls { } private void UpdateViewPortSize() { + CellWidth = 30; + CellHeight = 20; + ViewPort.Width = (int)(ActualWidth / CellWidth); ViewPort.Height = (int)(ActualHeight / CellHeight); diff --git a/src/HexManiac.WPF/Controls/TabView.xaml b/src/HexManiac.WPF/Controls/TabView.xaml index 844d42af..9273f2ef 100644 --- a/src/HexManiac.WPF/Controls/TabView.xaml +++ b/src/HexManiac.WPF/Controls/TabView.xaml @@ -174,12 +174,12 @@ - + - + @@ -189,7 +189,7 @@ - diff --git a/src/HexManiac.WPF/Implementations/FormatDrawer.cs b/src/HexManiac.WPF/Implementations/FormatDrawer.cs index 5a4b7a52..aa46fd2e 100644 --- a/src/HexManiac.WPF/Implementations/FormatDrawer.cs +++ b/src/HexManiac.WPF/Implementations/FormatDrawer.cs @@ -17,15 +17,19 @@ namespace HavenSoft.HexManiac.WPF.Implementations { private static readonly List noneVisualCache = new List(); private readonly int modelWidth, modelHeight; + private readonly Size cellSize; private readonly DrawingContext context; - private readonly Geometry rectangleGeometry = new RectangleGeometry(new Rect(new Point(0, 0), new Point(HexContent.CellWidth, HexContent.CellHeight))); + private readonly Geometry rectangleGeometry; public bool MouseIsOverCurrentFormat { get; set; } public HavenSoft.HexManiac.Core.Models.Point Position { get; set; } - public FormatDrawer(DrawingContext drawingContext, int width, int height) => (context, modelWidth, modelHeight) = (drawingContext, width, height); + public FormatDrawer(DrawingContext drawingContext, int width, int height, double cellWidth, double cellHeight) { + (context, modelWidth, modelHeight, cellSize) = (drawingContext, width, height, new Size(cellWidth, cellHeight)); + rectangleGeometry = new RectangleGeometry(new Rect(new Point(0, 0), cellSize)); + } public static void ClearVisualCaches() { noneVisualCache.Clear(); @@ -49,11 +53,11 @@ namespace HavenSoft.HexManiac.WPF.Implementations { var text = CreateText(content, FontSize, brush); var offset = CellTextOffset; - var widthOverflow = text.Width - HexContent.CellWidth * dataFormat.EditWidth; + var widthOverflow = text.Width - cellSize.Width * dataFormat.EditWidth; if (widthOverflow > 0) { // make it right aligned offset.X -= widthOverflow; - context.PushClip(new RectangleGeometry(new Rect(new Size(HexContent.CellWidth * dataFormat.EditWidth, HexContent.CellHeight)))); + context.PushClip(new RectangleGeometry(new Rect(new Size(cellSize.Width * dataFormat.EditWidth, cellSize.Height)))); context.DrawText(text, new Point(-widthOverflow, CellTextOffset.Y)); context.Pop(); } else { @@ -68,7 +72,7 @@ namespace HavenSoft.HexManiac.WPF.Implementations { var destination = dataFormat.DestinationAsText; if (destination.Length > 13) destination = destination.Substring(0, 11) + "…>"; - var xOffset = 51 - (dataFormat.Position * HexContent.CellWidth) - destination.Length * 4.2; // centering + var xOffset = 51 - (dataFormat.Position * cellSize.Width) - destination.Length * 4.2; // centering var text = CreateText(destination, FontSize, brush); if (dataFormat.Position > Position.X || Position.X - dataFormat.Position > modelWidth - 4) { @@ -122,7 +126,7 @@ namespace HavenSoft.HexManiac.WPF.Implementations { var text = CreateText(stringValue, FontSize, Brush(nameof(Theme.Data1))); var xOffset = CellTextOffset.X; - xOffset += HexContent.CellWidth / 2 * (integer.Length - 1); // adjust based on number of cells to use + xOffset += cellSize.Width / 2 * (integer.Length - 1); // adjust based on number of cells to use xOffset -= (stringValue.Length - 2) * 5; // adjust based on width of text context.DrawText(text, new Point(xOffset, CellTextOffset.Y)); } @@ -134,7 +138,7 @@ namespace HavenSoft.HexManiac.WPF.Implementations { var text = CreateText(stringValue, FontSize * 3 / 4, Brush(nameof(Theme.Data2))); var xOffset = CellTextOffset.X / 2; - context.PushClip(new RectangleGeometry(new Rect(0, 0, HexContent.CellWidth * integerEnum.Length, HexContent.CellHeight))); + context.PushClip(new RectangleGeometry(new Rect(0, 0, cellSize.Width * integerEnum.Length, cellSize.Height))); context.DrawText(text, new Point(xOffset, CellTextOffset.Y)); context.Pop(); } @@ -145,9 +149,9 @@ namespace HavenSoft.HexManiac.WPF.Implementations { var text = CreateText(name, FontSize * 3 / 4, Brush(nameof(Theme.Stream1))); var characterWidth = text.Width / name.Length; - var xOffset = HexContent.CellWidth - name.Length * characterWidth / 2; + var xOffset = cellSize.Width - name.Length * characterWidth / 2; if (xOffset < 0) xOffset = 0; - context.PushClip(new RectangleGeometry(new Rect(0, 0, HexContent.CellWidth * 2, HexContent.CellHeight))); + context.PushClip(new RectangleGeometry(new Rect(0, 0, cellSize.Width * 2, cellSize.Height))); context.DrawText(text, new Point(xOffset, CellTextOffset.Y + 2)); context.Pop(); } @@ -158,9 +162,9 @@ namespace HavenSoft.HexManiac.WPF.Implementations { var text = CreateText(name, FontSize * 3 / 4, Brush(nameof(Theme.Stream2))); var characterWidth = text.Width / name.Length; - var xOffset = HexContent.CellWidth - name.Length * characterWidth / 2; + var xOffset = cellSize.Width - name.Length * characterWidth / 2; if (xOffset < 0) xOffset = 0; - context.PushClip(new RectangleGeometry(new Rect(0, 0, HexContent.CellWidth * 2, HexContent.CellHeight))); + context.PushClip(new RectangleGeometry(new Rect(0, 0, cellSize.Width * 2, cellSize.Height))); context.DrawText(text, new Point(xOffset, CellTextOffset.Y + 2)); context.Pop(); } @@ -173,18 +177,18 @@ namespace HavenSoft.HexManiac.WPF.Implementations { // center the text var characterWidth = text.Width / content.Length; - var xOffset = HexContent.CellWidth - content.Length * characterWidth / 2; + var xOffset = cellSize.Width - content.Length * characterWidth / 2; if (xOffset < 0) xOffset = 0; - context.PushClip(new RectangleGeometry(new Rect(0, 0, HexContent.CellWidth * 2, HexContent.CellHeight))); + context.PushClip(new RectangleGeometry(new Rect(0, 0, cellSize.Width * 2, cellSize.Height))); context.DrawText(text, new Point(xOffset, CellTextOffset.Y + 2)); context.Pop(); } private void Underline(Brush brush, bool isStart, bool isEnd) { int startPoint = isStart ? 5 : 0; - int endPoint = (int)HexContent.CellWidth - (isEnd ? 5 : 0); - double y = (int)HexContent.CellHeight - 1.5; + int endPoint = (int)cellSize.Width - (isEnd ? 5 : 0); + double y = (int)cellSize.Height - 1.5; context.DrawLine(new Pen(brush, 1), new Point(startPoint, y), new Point(endPoint, y)); }