diff --git a/doc/controls/ZoomContentControl.md b/doc/controls/ZoomContentControl.md index c501da467..b8c95813e 100644 --- a/doc/controls/ZoomContentControl.md +++ b/doc/controls/ZoomContentControl.md @@ -41,27 +41,28 @@ xmlns:utu="using:Uno.Toolkit.UI" ### Constructors -| Constructor| Description| -|----------------|-------------------------------------------------------| -| `ZoomContentControl()`|Initializes a new instance of the `ZoomContentControl` class.| +| Constructor | Description | +| ---------------------- | ------------------------------------------------------------- | +| `ZoomContentControl()` | Initializes a new instance of the `ZoomContentControl` class. | ### Properties -| Property| Type | Description | -|-|-|-| -| `IsZoomAllowed` | `bool` | Gets or sets a value indicating whether zooming is allowed. | -| `ScaleWheelRatio` | `double` | Gets or sets the ratio for scaling zoom level when using a mouse wheel. | -| `PanWheelRatio` | `double` | Gets or sets the ratio for panning when using a mouse wheel. | -| `IsPanAllowed` | `bool` | Gets or sets a value indicating whether panning is allowed. | -| `ViewportWidth` | `bool` | Gets or sets the width of the content's viewport. | -| `ViewportHeight` | `bool` | Gets or sets the height of the content's viewport. | -| `IsActive` | `bool` | Gets or sets a value indicating whether the control is active. | -| `AutoFitToCanvas` | `bool` | Determines if the content should automatically fit into the available canvas when the control resizes. | -| `AdditionalMargin` | `Thickness` | Gets or sets additional margins around the content. | +| Property | Type | Description | +| ------------------ | ----------- | ------------------------------------------------------------------------------------------------------ | +| `ZoomLevel` | `double` | Gets or sets the current zoom level for the content. | +| `MinZoomLevel` | `double` | Gets or sets the minimum zoom level allowed for the content. | +| `MaxZoomLevel` | `double` | Gets or sets the maximum zoom level allowed for the content. | +| `IsZoomAllowed` | `bool` | Gets or sets a value indicating whether zooming is allowed. | +| `ScaleWheelRatio` | `double` | Gets or sets the ratio for scaling zoom level when using a mouse wheel. | +| `PanWheelRatio` | `double` | Gets or sets the ratio for panning when using a mouse wheel. | +| `IsPanAllowed` | `bool` | Gets or sets a value indicating whether panning is allowed. | +| `IsActive` | `bool` | Gets or sets a value indicating whether the control is active. | +| `AutoFitToCanvas` | `bool` | Determines if the content should automatically fit into the available canvas when the control resizes. | +| `AdditionalMargin` | `Thickness` | Gets or sets additional margins around the content. | ### Methods -| Method| Return Type| Description| -|-----------------------|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `FitToCanvas()`| `void`| Adjust the zoom level so that the content fits within the available space.| -| `ResetViewport()`| `void`| Resets the zoom level and panning offset to their default values and centers the content.| +| Method | Return Type | Description | +| ----------------- | ----------- | ----------------------------------------------------------------------------------------- | +| `FitToCanvas()` | `void` | Adjust the zoom level so that the content fits within the available space. | +| `ResetViewport()` | `void` | Resets the zoom level and panning offset to their default values and centers the content. | diff --git a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ZoomContentControlSamplePage.xaml b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ZoomContentControlSamplePage.xaml index ebe4b8310..b0bdca11c 100644 --- a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ZoomContentControlSamplePage.xaml +++ b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ZoomContentControlSamplePage.xaml @@ -20,9 +20,9 @@ Height="300" HorizontalAlignment="Center" VerticalAlignment="Center" - ZoomLevel="1.5" + ZoomLevel="1" MinZoomLevel="0.5" - MaxZoomLevel="3.0" + MaxZoomLevel="10" IsZoomAllowed="True" IsPanAllowed="True"> Identifies the ZoomLevel dependency property. - private static DependencyProperty ZoomLevelProperty { get; } = DependencyProperty.Register( + public static DependencyProperty ZoomLevelProperty { get; } = DependencyProperty.Register( nameof(ZoomLevel), typeof(double), typeof(ZoomContentControl), new PropertyMetadata(1d, OnZoomLevelChanged)); /// Gets or sets the current zoom level. - private double ZoomLevel + public double ZoomLevel { get => (double)GetValue(ZoomLevelProperty); set => SetValue(ZoomLevelProperty, value); } #endregion - #region DependencyProperty: [Private] MinZoomLevel + #region DependencyProperty: MinZoomLevel /// Identifies the MinZoomLevel dependency property. - private static DependencyProperty MinZoomLevelProperty { get; } = DependencyProperty.Register( + public static DependencyProperty MinZoomLevelProperty { get; } = DependencyProperty.Register( nameof(MinZoomLevel), typeof(double), typeof(ZoomContentControl), - new PropertyMetadata(default(double), OnMinZoomLevelChanged)); + new PropertyMetadata(1d, OnMinZoomLevelChanged)); /// Gets or sets the minimum zoom level allowed. - private double MinZoomLevel + public double MinZoomLevel { get => (double)GetValue(MinZoomLevelProperty); set => SetValue(MinZoomLevelProperty, value); } #endregion - #region DependencyProperty: [Private] MaxZoomLevel + #region DependencyProperty: MaxZoomLevel /// Identifies the MaxZoomLevel dependency property. - private static DependencyProperty MaxZoomLevelProperty { get; } = DependencyProperty.Register( + public static DependencyProperty MaxZoomLevelProperty { get; } = DependencyProperty.Register( nameof(MaxZoomLevel), typeof(double), typeof(ZoomContentControl), new PropertyMetadata(10d, OnMaxZoomLevelChanged)); /// Gets or sets the maximum zoom level allowed. - private double MaxZoomLevel + public double MaxZoomLevel { get => (double)GetValue(MaxZoomLevelProperty); set => SetValue(MaxZoomLevelProperty, value); @@ -290,41 +290,6 @@ public bool IsPanAllowed #endregion - #region DependencyProperty: ViewportWidth - - /// Identifies the ViewportWidth dependency property. - public static DependencyProperty ViewportWidthProperty { get; } = DependencyProperty.Register( - nameof(ContentWidth), - typeof(double), - typeof(ZoomContentControl), - new PropertyMetadata(default(double))); - - /// Gets or sets the width of the viewport. - public double ContentWidth - { - get => (double)GetValue(ViewportWidthProperty); - set => SetValue(ViewportWidthProperty, value); - } - - #endregion - #region DependencyProperty: ViewportHeight - - /// Identifies the ViewportHeight dependency property. - public static DependencyProperty ViewportHeightProperty { get; } = DependencyProperty.Register( - nameof(ContentHeight), - typeof(double), - typeof(ZoomContentControl), - new PropertyMetadata(default(double))); - - /// Gets or sets the height of the viewport. - public double ContentHeight - { - get => (double)GetValue(ViewportHeightProperty); - set => SetValue(ViewportHeightProperty, value); - } - - #endregion - #region DependencyProperty: IsActive /// Identifies the IsActive dependency property. diff --git a/src/Uno.Toolkit.UI/Controls/ZoomContentControl/ZoomContentControl.cs b/src/Uno.Toolkit.UI/Controls/ZoomContentControl/ZoomContentControl.cs index 90a76e83d..f2a77770e 100644 --- a/src/Uno.Toolkit.UI/Controls/ZoomContentControl/ZoomContentControl.cs +++ b/src/Uno.Toolkit.UI/Controls/ZoomContentControl/ZoomContentControl.cs @@ -61,6 +61,7 @@ private static class TemplateParts private (uint Id, Point Position, Point ScrollOffset)? _capturedPointerContext; private SerialDisposable _contentSubscriptions = new(); + private Size _contentSize; public ZoomContentControl() { @@ -113,12 +114,12 @@ void OnContentLoaded(object sender, RoutedEventArgs e) } void OnContentSizeChanged(object sender, SizeChangedEventArgs e) { - ContentWidth = fe.ActualWidth; - ContentHeight = fe.ActualHeight; - HorizontalZoomCenter = ContentWidth / 2; - VerticalZoomCenter = ContentHeight / 2; + _contentSize = new Size(fe.ActualWidth, fe.ActualHeight); + HorizontalZoomCenter = _contentSize.Width / 2; + VerticalZoomCenter = _contentSize.Height / 2; UpdateScrollBars(); + UpdateScrollVisibility(); } } @@ -160,7 +161,7 @@ private void UpdateScrollVisibility() if (Viewport is { } vp) { ToggleScrollBarVisibility(_scrollH, vp.ActualWidth < ScrollExtentWidth); - ToggleScrollBarVisibility(_scrollV, vp.ActualWidth < ScrollExtentWidth); + ToggleScrollBarVisibility(_scrollV, vp.ActualHeight < ScrollExtentHeight); } void ToggleScrollBarVisibility(ScrollBar? sb, bool value) @@ -206,10 +207,18 @@ private void UpdateScrollBars() { if (Viewport is { } vp) { - HorizontalMinScroll = VerticalMinScroll = 0; - - HorizontalMaxScroll = Math.Max(0, ScrollExtentWidth - vp.ActualWidth); - VerticalMaxScroll = Math.Max(0, ScrollExtentHeight - vp.ActualHeight); + 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; } @@ -391,6 +400,6 @@ private void SetScrollValue(Point value, bool shouldClamp = true) private Point ScrollValue => new Point(HorizontalScrollValue, VerticalScrollValue); - private double ScrollExtentWidth => (ContentWidth + AdditionalMargin.Left + AdditionalMargin.Right) * ZoomLevel; - private double ScrollExtentHeight => (ContentHeight + AdditionalMargin.Top + AdditionalMargin.Bottom) * ZoomLevel; + private double ScrollExtentWidth => (_contentSize.Width + AdditionalMargin.Left + AdditionalMargin.Right) * ZoomLevel; + private double ScrollExtentHeight => (_contentSize.Height + AdditionalMargin.Top + AdditionalMargin.Bottom) * ZoomLevel; } diff --git a/src/Uno.Toolkit.UI/Controls/ZoomContentControl/ZoomContentControl.xaml b/src/Uno.Toolkit.UI/Controls/ZoomContentControl/ZoomContentControl.xaml index ad874f0f2..ed43d5201 100644 --- a/src/Uno.Toolkit.UI/Controls/ZoomContentControl/ZoomContentControl.xaml +++ b/src/Uno.Toolkit.UI/Controls/ZoomContentControl/ZoomContentControl.xaml @@ -51,7 +51,6 @@ Minimum="{TemplateBinding VerticalMinScroll}" Orientation="Vertical" SmallChange="1" - ViewportSize="{TemplateBinding ViewportHeight}" Value="{Binding VerticalScrollValue, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />