1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-17 14:52:56 +08:00
osu-lazer/osu.Game.Rulesets.Osu/Edit/PreciseScalePopover.cs

256 lines
10 KiB
C#
Raw Normal View History

2024-05-26 00:31:19 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
2024-05-26 00:31:19 +08:00
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
2024-05-26 03:44:08 +08:00
using osu.Game.Graphics.UserInterface;
2024-05-26 00:31:19 +08:00
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Screens.Edit;
2024-05-26 00:31:19 +08:00
using osu.Game.Screens.Edit.Components.RadioButtons;
using osuTK;
namespace osu.Game.Rulesets.Osu.Edit
{
public partial class PreciseScalePopover : OsuPopover
{
private readonly OsuSelectionScaleHandler scaleHandler;
2024-05-26 00:31:19 +08:00
2024-07-03 18:40:22 +08:00
private readonly OsuGridToolboxGroup gridToolbox;
private readonly Bindable<PreciseScaleInfo> scaleInfo = new Bindable<PreciseScaleInfo>(new PreciseScaleInfo(1, ScaleOrigin.GridCentre, true, true));
2024-05-26 00:31:19 +08:00
private SliderWithTextBoxInput<float> scaleInput = null!;
private BindableNumber<float> scaleInputBindable = null!;
2024-05-26 00:31:19 +08:00
private EditorRadioButtonCollection scaleOrigin = null!;
private RadioButton gridCentreButton = null!;
private RadioButton playfieldCentreButton = null!;
2024-05-26 00:31:19 +08:00
private RadioButton selectionCentreButton = null!;
2024-05-26 03:44:08 +08:00
private OsuCheckbox xCheckBox = null!;
private OsuCheckbox yCheckBox = null!;
private BindableList<HitObject> selectedItems { get; } = new BindableList<HitObject>();
2024-07-03 18:40:22 +08:00
public PreciseScalePopover(OsuSelectionScaleHandler scaleHandler, OsuGridToolboxGroup gridToolbox)
2024-05-26 00:31:19 +08:00
{
this.scaleHandler = scaleHandler;
2024-07-03 18:40:22 +08:00
this.gridToolbox = gridToolbox;
2024-05-26 00:31:19 +08:00
AllowableAnchors = new[] { Anchor.CentreLeft, Anchor.CentreRight };
}
[BackgroundDependencyLoader]
private void load(EditorBeatmap editorBeatmap)
2024-05-26 00:31:19 +08:00
{
selectedItems.BindTo(editorBeatmap.SelectedHitObjects);
2024-05-26 00:31:19 +08:00
Child = new FillFlowContainer
{
Width = 220,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(20),
Children = new Drawable[]
{
scaleInput = new SliderWithTextBoxInput<float>("Scale:")
{
Current = scaleInputBindable = new BindableNumber<float>
2024-05-26 00:31:19 +08:00
{
MinValue = 0.5f,
MaxValue = 2,
Precision = 0.001f,
Value = 1,
Default = 1,
},
Instantaneous = true
},
scaleOrigin = new EditorRadioButtonCollection
{
RelativeSizeAxes = Axes.X,
Items = new[]
{
gridCentreButton = new RadioButton("Grid centre",
() => setOrigin(ScaleOrigin.GridCentre),
() => new SpriteIcon { Icon = FontAwesome.Regular.PlusSquare }),
playfieldCentreButton = new RadioButton("Playfield centre",
() => setOrigin(ScaleOrigin.PlayfieldCentre),
() => new SpriteIcon { Icon = FontAwesome.Regular.Square }),
2024-05-26 00:31:19 +08:00
selectionCentreButton = new RadioButton("Selection centre",
() => setOrigin(ScaleOrigin.SelectionCentre),
2024-05-26 00:31:19 +08:00
() => new SpriteIcon { Icon = FontAwesome.Solid.VectorSquare })
}
2024-05-26 03:44:08 +08:00
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(4),
Children = new Drawable[]
{
xCheckBox = new OsuCheckbox(false)
{
RelativeSizeAxes = Axes.X,
LabelText = "X-axis",
Current = { Value = true },
},
yCheckBox = new OsuCheckbox(false)
{
RelativeSizeAxes = Axes.X,
LabelText = "Y-axis",
Current = { Value = true },
},
}
},
2024-05-26 00:31:19 +08:00
}
};
gridCentreButton.Selected.DisabledChanged += isDisabled =>
{
gridCentreButton.TooltipText = isDisabled ? "The current selection cannot be scaled relative to grid centre." : string.Empty;
};
playfieldCentreButton.Selected.DisabledChanged += isDisabled =>
{
2024-05-29 15:59:19 +08:00
playfieldCentreButton.TooltipText = isDisabled ? "The current selection cannot be scaled relative to playfield centre." : string.Empty;
};
2024-05-26 00:31:19 +08:00
selectionCentreButton.Selected.DisabledChanged += isDisabled =>
{
2024-05-29 15:59:19 +08:00
selectionCentreButton.TooltipText = isDisabled ? "The current selection cannot be scaled relative to its centre." : string.Empty;
2024-05-26 00:31:19 +08:00
};
}
protected override void LoadComplete()
{
base.LoadComplete();
ScheduleAfterChildren(() =>
{
scaleInput.TakeFocus();
scaleInput.SelectAll();
});
2024-05-26 00:31:19 +08:00
scaleInput.Current.BindValueChanged(scale => scaleInfo.Value = scaleInfo.Value with { Scale = scale.NewValue });
2024-05-26 03:44:08 +08:00
xCheckBox.Current.BindValueChanged(x => setAxis(x.NewValue, yCheckBox.Current.Value));
yCheckBox.Current.BindValueChanged(y => setAxis(xCheckBox.Current.Value, y.NewValue));
selectionCentreButton.Selected.Disabled = !(scaleHandler.CanScaleX.Value || scaleHandler.CanScaleY.Value);
playfieldCentreButton.Selected.Disabled = scaleHandler.IsScalingSlider.Value && !selectionCentreButton.Selected.Disabled;
gridCentreButton.Selected.Disabled = playfieldCentreButton.Selected.Disabled;
2024-05-29 16:01:04 +08:00
scaleOrigin.Items.First(b => !b.Selected.Disabled).Select();
2024-05-26 00:31:19 +08:00
scaleInfo.BindValueChanged(scale =>
{
2024-07-03 22:23:19 +08:00
var newScale = new Vector2(scale.NewValue.Scale, scale.NewValue.Scale);
scaleHandler.Update(newScale, getOriginPosition(scale.NewValue), getAdjustAxis(scale.NewValue), getRotation(scale.NewValue));
2024-05-26 00:31:19 +08:00
});
}
private void updateAxisCheckBoxesEnabled()
{
if (scaleInfo.Value.Origin != ScaleOrigin.SelectionCentre)
{
2024-05-29 16:04:49 +08:00
toggleAxisAvailable(xCheckBox.Current, true);
toggleAxisAvailable(yCheckBox.Current, true);
}
else
{
2024-05-29 16:04:49 +08:00
toggleAxisAvailable(xCheckBox.Current, scaleHandler.CanScaleX.Value);
toggleAxisAvailable(yCheckBox.Current, scaleHandler.CanScaleY.Value);
}
}
2024-05-29 16:04:49 +08:00
private void toggleAxisAvailable(Bindable<bool> axisBindable, bool available)
{
2024-05-29 16:04:49 +08:00
// enable the bindable to allow setting the value
axisBindable.Disabled = false;
// restore the presumed default value given the axis's new availability state
axisBindable.Value = available;
axisBindable.Disabled = !available;
}
private void updateMaxScale()
{
if (!scaleHandler.OriginalSurroundingQuad.HasValue)
return;
const float max_scale = 10;
var scale = scaleHandler.ClampScaleToPlayfieldBounds(new Vector2(max_scale), getOriginPosition(scaleInfo.Value), getAdjustAxis(scaleInfo.Value), getRotation(scaleInfo.Value));
if (!scaleInfo.Value.XAxis)
scale.X = max_scale;
if (!scaleInfo.Value.YAxis)
scale.Y = max_scale;
scaleInputBindable.MaxValue = MathF.Max(1, MathF.Min(scale.X, scale.Y));
}
private void setOrigin(ScaleOrigin origin)
{
scaleInfo.Value = scaleInfo.Value with { Origin = origin };
updateMaxScale();
updateAxisCheckBoxesEnabled();
}
private Vector2? getOriginPosition(PreciseScaleInfo scale)
{
switch (scale.Origin)
{
case ScaleOrigin.GridCentre:
return gridToolbox.StartPosition.Value;
case ScaleOrigin.PlayfieldCentre:
return OsuPlayfield.BASE_SIZE / 2;
case ScaleOrigin.SelectionCentre:
if (selectedItems.Count == 1 && selectedItems.First() is Slider slider)
return slider.Position;
return null;
default:
throw new ArgumentOutOfRangeException(nameof(scale));
}
}
2024-07-03 22:23:19 +08:00
private Axes getAdjustAxis(PreciseScaleInfo scale) => scale.XAxis ? scale.YAxis ? Axes.Both : Axes.X : Axes.Y;
private float getRotation(PreciseScaleInfo scale) => scale.Origin == ScaleOrigin.GridCentre ? gridToolbox.GridLinesRotation.Value : 0;
2024-05-26 03:44:08 +08:00
private void setAxis(bool x, bool y)
{
scaleInfo.Value = scaleInfo.Value with { XAxis = x, YAxis = y };
updateMaxScale();
}
2024-05-26 00:31:19 +08:00
protected override void PopIn()
{
base.PopIn();
scaleHandler.Begin();
updateMaxScale();
2024-05-26 00:31:19 +08:00
}
protected override void PopOut()
{
base.PopOut();
if (IsLoaded) scaleHandler.Commit();
2024-05-26 00:31:19 +08:00
}
}
public enum ScaleOrigin
{
GridCentre,
PlayfieldCentre,
2024-05-26 00:31:19 +08:00
SelectionCentre
}
public record PreciseScaleInfo(float Scale, ScaleOrigin Origin, bool XAxis, bool YAxis);
}