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.
This commit is contained in:
Benjamin Popp
2019-06-08 21:12:17 -05:00
parent 15b729fabd
commit 216b125ff3
4 changed files with 65 additions and 34 deletions

View File

@@ -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<string>();
metadata.Add("[GeneralSettings]");
metadata.Add($"ShowMatrixGrid = {ShowMatrix}");
metadata.Add($"ZoomLevel = {ZoomLevel}");
metadata.Add(string.Empty);
metadata.AddRange(Theme.Serialize());
fileSystem.SaveMetadata(ApplicationName, metadata.ToArray());

View File

@@ -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);

View File

@@ -174,12 +174,12 @@
</DockPanel>
</Border>
<!-- Column Headers -->
<hsg3hv:HorizontalSlantedTextControl DockPanel.Dock="Top" HeaderRows="{Binding ColumnHeaders}" ColumnWidth="{x:Static hsg3hv:HexContent.CellWidth}" HorizontalOffset="{Binding ElementName=HexContent, Path=HorizontalScrollValue}"/>
<hsg3hv:HorizontalSlantedTextControl DockPanel.Dock="Top" HeaderRows="{Binding ColumnHeaders}" ColumnWidth="{Binding CellWidth, ElementName=HexContent}" HorizontalOffset="{Binding ElementName=HexContent, Path=HorizontalScrollValue}"/>
<!-- Row Headers -->
<ItemsControl DockPanel.Dock="Left" Width="70" ItemsSource="{Binding Headers}" Background="{DynamicResource Backlight}" MouseDown="HeaderMouseDown">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Viewbox Height="{x:Static hsg3hv:HexContent.CellHeight}" HorizontalAlignment="Right" Margin="0,0,2,0">
<Viewbox Height="{Binding CellHeight, ElementName=HexContent}" HorizontalAlignment="Right" Margin="0,0,2,0">
<TextBlock Foreground="{DynamicResource Secondary}" Text="{Binding}" FontFamily="Consolas" Padding="1"/>
</Viewbox>
</DataTemplate>
@@ -189,7 +189,7 @@
<ScrollBar DockPanel.Dock="Right"
Minimum="{Binding MinimumScroll}" Maximum="{Binding MaximumScroll}" Value="{Binding ScrollValue}"
SmallChange="1" LargeChange="{Binding Height}" />
<ScrollBar DockPanel.Dock="Bottom" Orientation="Horizontal" SmallChange="10" LargeChange="{x:Static hsg3hv:HexContent.CellWidth}"
<ScrollBar DockPanel.Dock="Bottom" Orientation="Horizontal" SmallChange="10" LargeChange="{Binding CellWidth, ElementName=HexContent}"
Minimum="0" Maximum="{Binding HorizontalScrollMaximum, ElementName=HexContent}" Value="{Binding HorizontalScrollValue, ElementName=HexContent}"
Visibility="{Binding ShowHorizontalScroll, ElementName=HexContent, Converter={StaticResource BoolToVisibility}}" />
<hsg3hv:HexContent x:Name="HexContent" ViewPort="{Binding}" ShowGrid="{Binding DataContext.ShowMatrix, RelativeSource={RelativeSource AncestorType=hsg3ww:MainWindow}}" Margin=".5,.5,0,0"/>

View File

@@ -17,15 +17,19 @@ namespace HavenSoft.HexManiac.WPF.Implementations {
private static readonly List<FormattedText> noneVisualCache = new List<FormattedText>();
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));
}