Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions RichCanvas/Gestures/RichCanvasGestures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public class RichCanvasGestures
/// </summary>
public static InputGesture Pan { get; set; } = new MouseKeyGesture(new MouseGesture(MouseAction.LeftClick), new KeyGesture(Key.Space));

/// <summary>
/// Gets or sets the <see cref="InputGesture"/> used to match the <see cref="RichCanvasCommands.FitToScreen"/>.
/// </summary>
public static InputGesture FitToScreen { get; set; } = new KeyGesture(Key.Home);

/// <summary>
/// Gets or sets the <see cref="ModifierKeys"/> used together with MouseWheel for zooming.
/// <br/>
Expand Down
67 changes: 67 additions & 0 deletions RichCanvas/RichCanvas.Fitting.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Windows;

namespace RichCanvas
{
public partial class RichCanvas
{
private void FitViewToChildren(double marginX, double marginY)
{
if (ItemsHost.Children.Count == 0)
{
return;
}

Rect overallBounds = new(0, 0, 0, 0);

for (int i = 0; i < ItemsHost.Children.Count; i++)
{
var child = ContainerFromElement(ItemsHost.Children[i]);
if (child is RichCanvasContainer container)
{
overallBounds.Union(container.BoundingBox);
}
}
overallBounds.Inflate(marginX, marginY);

FitViewToRect(overallBounds);
}

private void FitViewToRect(Rect newView)
{
// Size / Size
Vector zoomAmounts = new Vector(ActualWidth / newView.Size.Width, ActualHeight / newView.Size.Height);
double zoomAmount = Math.Min(zoomAmounts.X, zoomAmounts.Y);

// Set viewport zoom
ViewportZoom = zoomAmount;

// If the canvas has a ScrollViewer and the scrollbars are visible,
// the offset will be off by a tad. Calling this command immediately again will fix it.
// We can check if there are scrollbars present by doing:
// if (ExtentHeight != ViewportSize.Height) => VerticalScrollBar present
// if (ExtentWidth != ViewportSize.Width) => HorizontalScrollBar present
// You can then try to use SystemParameters.ScrollWidth to try and account for it,
// but I could not get the offset perfect. Additionally, if the ScrollBar is ever styled,
// then we would have to go find the ScrollBar and get its width. But that opens up another whole
// can: we would want to cache it so we don't traverse the tree everytime, but then we need to
// add handling for if/when the styling changes.

// Thus I have decided that being 10 pixels off is not the end of the world, and if anyone is
// bothered they can hit the FitToScreen button again.

// Set viewport location
double offsetLeft = (ViewportSize.Width - newView.Size.Width) / 2;
double offsetTop = (ViewportSize.Height - newView.Size.Height) / 2;
Point topLeft = new Point(newView.TopLeft.X - offsetLeft, newView.TopLeft.Y - offsetTop);
ViewportLocation = topLeft;
}

/// <summary>
/// Change the viewport location and zoom to fit as many items as possible on screen,
/// using a default margin of 0.
/// </summary>
public void FitToScreen() => FitViewToChildren(0, 0);
}
}

17 changes: 17 additions & 0 deletions RichCanvas/RichCanvasCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,19 @@ public class RichCanvasCommands
RichCanvasGestures.ZoomOut
});

/// <summary>
/// Change the viewport location and zoom to fit as many items as possible on screen.
/// </summary>
public static RoutedUICommand FitToScreen { get; } = new RoutedUICommand("Fit to screen", nameof(FitToScreen), typeof(RichCanvasCommands), new InputGestureCollection
{
RichCanvasGestures.FitToScreen
});

internal static void Register(Type type)
{
CommandManager.RegisterClassCommandBinding(type, new CommandBinding(ZoomIn, OnZoomIn));
CommandManager.RegisterClassCommandBinding(type, new CommandBinding(ZoomOut, OnZoomOut));
CommandManager.RegisterClassCommandBinding(type, new CommandBinding(FitToScreen, OnFitToScreen));
}

private static void OnZoomOut(object sender, ExecutedRoutedEventArgs e)
Expand All @@ -47,5 +56,13 @@ private static void OnZoomIn(object sender, ExecutedRoutedEventArgs e)
richItemsControl.ZoomIn();
}
}

private static void OnFitToScreen(object sender, ExecutedRoutedEventArgs e)
{
if (sender is RichCanvas richItemsControl)
{
richItemsControl.FitToScreen();
}
}
}
}