mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 12:57:36 +08:00
Refactor ZoomableScrollContainer
to allow setting up zoom range and initial zoom after load
This commit is contained in:
parent
93175eaf6e
commit
123930306b
@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.Gray(30)
|
||||
},
|
||||
scrollContainer = new ZoomableScrollContainer
|
||||
scrollContainer = new ZoomableScrollContainer(1, 60, 1)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -80,21 +80,6 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddAssert("Inner container width matches scroll container", () => innerBox.DrawWidth == scrollContainer.DrawWidth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestZoomRangeUpdate()
|
||||
{
|
||||
AddStep("set zoom to 2", () => scrollContainer.Zoom = 2);
|
||||
AddStep("set min zoom to 5", () => scrollContainer.MinZoom = 5);
|
||||
AddAssert("zoom = 5", () => scrollContainer.Zoom == 5);
|
||||
|
||||
AddStep("set max zoom to 10", () => scrollContainer.MaxZoom = 10);
|
||||
AddAssert("zoom = 5", () => scrollContainer.Zoom == 5);
|
||||
|
||||
AddStep("set min zoom to 20", () => scrollContainer.MinZoom = 20);
|
||||
AddStep("set max zoom to 40", () => scrollContainer.MaxZoom = 40);
|
||||
AddAssert("zoom = 20", () => scrollContainer.Zoom == 20);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestZoom0()
|
||||
{
|
||||
|
@ -32,19 +32,27 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
|
||||
private readonly Container zoomedContent;
|
||||
protected override Container<Drawable> Content => zoomedContent;
|
||||
private float currentZoom = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The current zoom level of <see cref="ZoomableScrollContainer" />.
|
||||
/// It may differ from <see cref="Zoom" /> during transitions.
|
||||
/// The current zoom level of <see cref="ZoomableScrollContainer"/>.
|
||||
/// It may differ from <see cref="Zoom"/> during transitions.
|
||||
/// </summary>
|
||||
public float CurrentZoom => currentZoom;
|
||||
public float CurrentZoom { get; private set; } = 1;
|
||||
|
||||
private bool isZoomSetUp;
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private IFrameBasedClock editorClock { get; set; }
|
||||
|
||||
private readonly LayoutValue zoomedContentWidthCache = new LayoutValue(Invalidation.DrawSize);
|
||||
|
||||
private float minZoom;
|
||||
private float maxZoom;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="ZoomableScrollContainer"/> with no zoom range.
|
||||
/// Functionality will be disabled until zoom is set up via <see cref="SetupZoom"/>.
|
||||
/// </summary>
|
||||
public ZoomableScrollContainer()
|
||||
: base(Direction.Horizontal)
|
||||
{
|
||||
@ -53,46 +61,36 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
AddLayout(zoomedContentWidthCache);
|
||||
}
|
||||
|
||||
private float minZoom = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum zoom level allowed.
|
||||
/// Creates a <see cref="ZoomableScrollContainer"/> with a defined zoom range.
|
||||
/// </summary>
|
||||
public float MinZoom
|
||||
public ZoomableScrollContainer(float minimum, float maximum, float initial)
|
||||
: this()
|
||||
{
|
||||
get => minZoom;
|
||||
set
|
||||
{
|
||||
if (value < 1)
|
||||
throw new ArgumentException($"{nameof(MinZoom)} must be >= 1.", nameof(value));
|
||||
|
||||
minZoom = value;
|
||||
|
||||
// ensure zoom range is in valid state before updating zoom.
|
||||
if (MinZoom < MaxZoom)
|
||||
updateZoom();
|
||||
}
|
||||
SetupZoom(initial, minimum, maximum);
|
||||
}
|
||||
|
||||
private float maxZoom = 60;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum zoom level allowed.
|
||||
/// Sets up the minimum and maximum range of this zoomable scroll container, along with the initial zoom value.
|
||||
/// </summary>
|
||||
public float MaxZoom
|
||||
/// <param name="initial">The initial zoom value, applied immediately.</param>
|
||||
/// <param name="minimum">The minimum zoom value.</param>
|
||||
/// <param name="maximum">The maximum zoom value.</param>
|
||||
public void SetupZoom(float initial, float minimum, float maximum)
|
||||
{
|
||||
get => maxZoom;
|
||||
set
|
||||
{
|
||||
if (value < 1)
|
||||
throw new ArgumentException($"{nameof(MaxZoom)} must be >= 1.", nameof(value));
|
||||
if (minimum < 1)
|
||||
throw new ArgumentException($"{nameof(minimum)} ({minimum}) must be >= 1.", nameof(maximum));
|
||||
|
||||
maxZoom = value;
|
||||
if (maximum < 1)
|
||||
throw new ArgumentException($"{nameof(maximum)} ({maximum}) must be >= 1.", nameof(maximum));
|
||||
|
||||
// ensure zoom range is in valid state before updating zoom.
|
||||
if (MaxZoom > MinZoom)
|
||||
updateZoom();
|
||||
}
|
||||
if (minimum > maximum)
|
||||
throw new ArgumentException($"{nameof(minimum)} ({minimum}) must be less than {nameof(maximum)} ({maximum})");
|
||||
|
||||
minZoom = minimum;
|
||||
maxZoom = maximum;
|
||||
CurrentZoom = zoomTarget = initial;
|
||||
isZoomSetUp = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -104,14 +102,17 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
set => updateZoom(value);
|
||||
}
|
||||
|
||||
private void updateZoom(float? value = null)
|
||||
private void updateZoom(float value)
|
||||
{
|
||||
float newZoom = Math.Clamp(value ?? Zoom, MinZoom, MaxZoom);
|
||||
if (!isZoomSetUp)
|
||||
return;
|
||||
|
||||
float newZoom = Math.Clamp(value, minZoom, maxZoom);
|
||||
|
||||
if (IsLoaded)
|
||||
setZoomTarget(newZoom, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X);
|
||||
else
|
||||
currentZoom = zoomTarget = newZoom;
|
||||
CurrentZoom = zoomTarget = newZoom;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -141,22 +142,32 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
|
||||
private void updateZoomedContentWidth()
|
||||
{
|
||||
zoomedContent.Width = DrawWidth * currentZoom;
|
||||
zoomedContent.Width = DrawWidth * CurrentZoom;
|
||||
zoomedContentWidthCache.Validate();
|
||||
}
|
||||
|
||||
public void AdjustZoomRelatively(float change, float? focusPoint = null)
|
||||
{
|
||||
if (!isZoomSetUp)
|
||||
return;
|
||||
|
||||
const float zoom_change_sensitivity = 0.02f;
|
||||
|
||||
setZoomTarget(zoomTarget + change * (MaxZoom - minZoom) * zoom_change_sensitivity, focusPoint);
|
||||
setZoomTarget(zoomTarget + change * (maxZoom - minZoom) * zoom_change_sensitivity, focusPoint);
|
||||
}
|
||||
|
||||
protected void SetZoomImmediately(float value, float min, float max)
|
||||
{
|
||||
maxZoom = max;
|
||||
minZoom = min;
|
||||
CurrentZoom = zoomTarget = value;
|
||||
}
|
||||
|
||||
private float zoomTarget = 1;
|
||||
|
||||
private void setZoomTarget(float newZoom, float? focusPoint = null)
|
||||
{
|
||||
zoomTarget = Math.Clamp(newZoom, MinZoom, MaxZoom);
|
||||
zoomTarget = Math.Clamp(newZoom, minZoom, maxZoom);
|
||||
focusPoint ??= zoomedContent.ToLocalSpace(ToScreenSpace(new Vector2(DrawWidth / 2, 0))).X;
|
||||
|
||||
transformZoomTo(zoomTarget, focusPoint.Value, ZoomDuration, ZoomEasing);
|
||||
@ -192,7 +203,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
private readonly float scrollOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Transforms <see cref="ZoomableScrollContainer.currentZoom"/> to a new value.
|
||||
/// Transforms <see cref="ZoomableScrollContainer.CurrentZoom"/> to a new value.
|
||||
/// </summary>
|
||||
/// <param name="focusPoint">The focus point in absolute coordinates local to the content.</param>
|
||||
/// <param name="contentSize">The size of the content.</param>
|
||||
@ -204,7 +215,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
this.scrollOffset = scrollOffset;
|
||||
}
|
||||
|
||||
public override string TargetMember => nameof(currentZoom);
|
||||
public override string TargetMember => nameof(CurrentZoom);
|
||||
|
||||
private float valueAt(double time)
|
||||
{
|
||||
@ -222,7 +233,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
float expectedWidth = d.DrawWidth * newZoom;
|
||||
float targetOffset = expectedWidth * (focusPoint / contentSize) - focusOffset;
|
||||
|
||||
d.currentZoom = newZoom;
|
||||
d.CurrentZoom = newZoom;
|
||||
d.updateZoomedContentWidth();
|
||||
|
||||
// Temporarily here to make sure ScrollTo gets the correct DrawSize for scrollable area.
|
||||
@ -231,7 +242,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
d.ScrollTo(targetOffset, false);
|
||||
}
|
||||
|
||||
protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.currentZoom;
|
||||
protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.CurrentZoom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user