Skip to content

Commit

Permalink
fix(zcc): add support for negative canvas coord space
Browse files Browse the repository at this point in the history
  • Loading branch information
Xiaoy312 committed Jan 8, 2025
1 parent f20a9d4 commit be5c11e
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 37 deletions.
104 changes: 67 additions & 37 deletions src/Uno.Toolkit.UI/Controls/ZoomContentControl/ZoomContentControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ T FindTemplatePart<T>(string name) where T : class =>
_translation = FindTemplatePart<TranslateTransform>(TemplateParts.TranslateTransform);

ResetViewport();
UpdateScrollDetails();
}

protected override void OnContentChanged(object oldContent, object newContent)
Expand All @@ -98,6 +99,8 @@ protected override void OnContentChanged(object oldContent, object newContent)
{
fe.Loaded += OnContentLoaded;
fe.SizeChanged += OnContentSizeChanged;
UpdateScrollDetails();

_contentSubscriptions.Disposable = Disposable.Create(() =>
{
fe.Loaded -= OnContentLoaded;
Expand All @@ -107,19 +110,18 @@ protected override void OnContentChanged(object oldContent, object newContent)

void OnContentLoaded(object sender, RoutedEventArgs e)
{
if (Content is Canvas)
{
UpdateScrollDetails();
}
if (AutoFitToCanvas)
{
FitToCanvas();
}
}
void OnContentSizeChanged(object sender, SizeChangedEventArgs e)
{
_contentSize = new Size(fe.ActualWidth, fe.ActualHeight);
HorizontalZoomCenter = _contentSize.Width / 2;
VerticalZoomCenter = _contentSize.Height / 2;

UpdateScrollBars();
UpdateScrollVisibility();
UpdateScrollDetails();
}
}

Expand Down Expand Up @@ -152,28 +154,19 @@ private async void OnZoomLevelChanged()
}

UpdateScrollBars();
UpdateScrollVisibility();
await RaiseRenderedContentUpdated();
}

private void UpdateScrollVisibility()
private async void UpdateScrollDetails()
{
if (Viewport is { } vp)
{
ToggleScrollBarVisibility(_scrollH, vp.ActualWidth < ScrollExtentWidth);
ToggleScrollBarVisibility(_scrollV, vp.ActualHeight < ScrollExtentHeight);
}

void ToggleScrollBarVisibility(ScrollBar? sb, bool value)
if (Content is FrameworkElement fe)
{
if (sb is null) return;

// Showing/hiding the ScrollBar(s)could cause the ContentPresenter to move as it re-centers.
// This adds unnecessary complexity for the zooming logics as we need to preserve the focal point
// under the cursor position or the pinch center point after zooming.
// To avoid all that, we just make them permanently there for layout calculation.
sb.IsEnabled = value;
sb.Opacity = value ? 1 : 0;
_contentSize = new Size(fe.ActualWidth, fe.ActualHeight);
HorizontalZoomCenter = _contentSize.Width / 2;
VerticalZoomCenter = _contentSize.Height / 2;

UpdateScrollBars();
await RaiseRenderedContentUpdated();
}
}

Expand Down Expand Up @@ -207,20 +200,57 @@ private void UpdateScrollBars()
{
if (Viewport is { } vp)
{
var scrollableWidth = Math.Max(0, ScrollExtentWidth - vp.ActualWidth);
var scrollableHeight = Math.Max(0, ScrollExtentHeight - vp.ActualHeight);

// since the content is always centered, we need to able to scroll both way equally:
// [Content-Content-Content]
// [=======[Viewport]======]
HorizontalMaxScroll = scrollableWidth / 2;
HorizontalMinScroll = -HorizontalMaxScroll;
VerticalMaxScroll = scrollableHeight / 2;
VerticalMinScroll = -VerticalMaxScroll;

// update size of thumb
if (_scrollH is { }) _scrollH.ViewportSize = vp.ActualWidth;
if (_scrollV is { }) _scrollV.ViewportSize = vp.ActualHeight;
if (Content is Canvas { Children: { Count: > 0 } } canvas)
{
var realm = canvas.Children
.Select(x => new Rect(x.ActualOffset.X, x.ActualOffset.Y, x.ActualSize.X, x.ActualSize.Y))
.Aggregate(RectHelper.Union);
if (realm != default)
{
realm = realm.Multiply(ZoomLevel).Inflate(AdditionalMargin);

HorizontalMinScroll = -realm.Right + (vp.ActualWidth / 2);
HorizontalMaxScroll = -realm.Left - (vp.ActualWidth / 2);

VerticalMinScroll = realm.Top + (vp.ActualHeight / 2);
VerticalMaxScroll = realm.Bottom - (vp.ActualHeight / 2);
}
else
{
HorizontalMaxScroll = HorizontalMinScroll = 0;
VerticalMaxScroll = VerticalMinScroll = 0;
}
}
else
{
var scrollableWidth = Math.Max(0, ScrollExtentWidth - vp.ActualWidth);
var scrollableHeight = Math.Max(0, ScrollExtentHeight - vp.ActualHeight);

// since the content is always centered, we need to able to scroll both way equally:
// [Content-Content-Content]
// [=======[Viewport]======]
HorizontalMaxScroll = scrollableWidth / 2;
HorizontalMinScroll = -HorizontalMaxScroll;
VerticalMaxScroll = scrollableHeight / 2;
VerticalMinScroll = -VerticalMaxScroll;
}

Update(_scrollH, HorizontalMinScroll < HorizontalMaxScroll, vp.ActualWidth);
Update(_scrollV, VerticalMinScroll < VerticalMaxScroll, vp.ActualHeight);
void Update(ScrollBar? sb, bool shown, double thumbSize)
{
if (sb is null) return;

// update size of thumb
sb.ViewportSize = thumbSize;

// Showing/hiding the ScrollBar(s)could cause the ContentPresenter to move as it re-centers.
// This adds unnecessary complexity for the zooming logics as we need to preserve the focal point
// under the cursor position or the pinch center point after zooming.
// To avoid all that, we just make them permanently there for layout calculation.
sb.IsEnabled = shown;
sb.Opacity = shown ? 1 : 0;
}
}
}

Expand Down
15 changes: 15 additions & 0 deletions src/Uno.Toolkit.UI/Extensions/RectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,25 @@
using System.Threading.Tasks;
using Windows.Foundation;

#if IS_WINUI
using Microsoft.UI.Xaml;
#else
using Windows.UI.Xaml;
#endif

namespace Uno.Toolkit.UI
{
internal static class RectExtensions
{
public static bool IsEmptyOrZero(this Rect rect) => rect is { Width: 0, Height: 0 };

public static Rect Multiply(this Rect x, double value) => new Rect(x.X * value, x.Y * value, x.Width * value, x.Height * value);

public static Rect Inflate(this Rect x, Thickness value) => new Rect(
x.X - value.Left,
x.Y - value.Top,
x.Width + (value.Left + value.Right),
x.Height + (value.Top + value.Bottom)
);
}
}

0 comments on commit be5c11e

Please sign in to comment.