mirror of
https://github.com/ppy/osu.git
synced 2024-11-14 15:57:24 +08:00
Add simple scale tool
This commit is contained in:
parent
d55fa423e9
commit
6aa92bcc45
@ -101,7 +101,11 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
|
|
||||||
RightToolbox.AddRange(new EditorToolboxGroup[]
|
RightToolbox.AddRange(new EditorToolboxGroup[]
|
||||||
{
|
{
|
||||||
new TransformToolboxGroup { RotationHandler = BlueprintContainer.SelectionHandler.RotationHandler, },
|
new TransformToolboxGroup
|
||||||
|
{
|
||||||
|
RotationHandler = BlueprintContainer.SelectionHandler.RotationHandler,
|
||||||
|
ScaleHandler = BlueprintContainer.SelectionHandler.ScaleHandler,
|
||||||
|
},
|
||||||
FreehandlSliderToolboxGroup
|
FreehandlSliderToolboxGroup
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
121
osu.Game.Rulesets.Osu/Edit/PreciseScalePopover.cs
Normal file
121
osu.Game.Rulesets.Osu/Edit/PreciseScalePopover.cs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
|
using osu.Game.Screens.Edit.Components.RadioButtons;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Edit
|
||||||
|
{
|
||||||
|
public partial class PreciseScalePopover : OsuPopover
|
||||||
|
{
|
||||||
|
private readonly SelectionScaleHandler scaleHandler;
|
||||||
|
|
||||||
|
private readonly Bindable<PreciseScaleInfo> scaleInfo = new Bindable<PreciseScaleInfo>(new PreciseScaleInfo(1, ScaleOrigin.PlayfieldCentre, true, true));
|
||||||
|
|
||||||
|
private SliderWithTextBoxInput<float> scaleInput = null!;
|
||||||
|
private EditorRadioButtonCollection scaleOrigin = null!;
|
||||||
|
|
||||||
|
private RadioButton selectionCentreButton = null!;
|
||||||
|
|
||||||
|
public PreciseScalePopover(SelectionScaleHandler scaleHandler)
|
||||||
|
{
|
||||||
|
this.scaleHandler = scaleHandler;
|
||||||
|
|
||||||
|
AllowableAnchors = new[] { Anchor.CentreLeft, Anchor.CentreRight };
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Child = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Width = 220,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Spacing = new Vector2(20),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
scaleInput = new SliderWithTextBoxInput<float>("Scale:")
|
||||||
|
{
|
||||||
|
Current = new BindableNumber<float>
|
||||||
|
{
|
||||||
|
MinValue = 0.5f,
|
||||||
|
MaxValue = 2,
|
||||||
|
Precision = 0.001f,
|
||||||
|
Value = 1,
|
||||||
|
Default = 1,
|
||||||
|
},
|
||||||
|
Instantaneous = true
|
||||||
|
},
|
||||||
|
scaleOrigin = new EditorRadioButtonCollection
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Items = new[]
|
||||||
|
{
|
||||||
|
new RadioButton("Playfield centre",
|
||||||
|
() => scaleInfo.Value = scaleInfo.Value with { Origin = ScaleOrigin.PlayfieldCentre },
|
||||||
|
() => new SpriteIcon { Icon = FontAwesome.Regular.Square }),
|
||||||
|
selectionCentreButton = new RadioButton("Selection centre",
|
||||||
|
() => scaleInfo.Value = scaleInfo.Value with { Origin = ScaleOrigin.SelectionCentre },
|
||||||
|
() => new SpriteIcon { Icon = FontAwesome.Solid.VectorSquare })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
selectionCentreButton.Selected.DisabledChanged += isDisabled =>
|
||||||
|
{
|
||||||
|
selectionCentreButton.TooltipText = isDisabled ? "Select more than one object to perform selection-based scaling." : string.Empty;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
ScheduleAfterChildren(() => scaleInput.TakeFocus());
|
||||||
|
scaleInput.Current.BindValueChanged(scale => scaleInfo.Value = scaleInfo.Value with { Scale = scale.NewValue });
|
||||||
|
scaleOrigin.Items.First().Select();
|
||||||
|
|
||||||
|
scaleHandler.CanScaleX.BindValueChanged(e =>
|
||||||
|
{
|
||||||
|
selectionCentreButton.Selected.Disabled = !e.NewValue;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
scaleInfo.BindValueChanged(scale =>
|
||||||
|
{
|
||||||
|
var newScale = new Vector2(scale.NewValue.XAxis ? scale.NewValue.Scale : 1, scale.NewValue.YAxis ? scale.NewValue.Scale : 1);
|
||||||
|
scaleHandler.Update(newScale, scale.NewValue.Origin == ScaleOrigin.PlayfieldCentre ? OsuPlayfield.BASE_SIZE / 2 : null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn()
|
||||||
|
{
|
||||||
|
base.PopIn();
|
||||||
|
scaleHandler.Begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopOut()
|
||||||
|
{
|
||||||
|
base.PopOut();
|
||||||
|
|
||||||
|
if (IsLoaded)
|
||||||
|
scaleHandler.Commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ScaleOrigin
|
||||||
|
{
|
||||||
|
PlayfieldCentre,
|
||||||
|
SelectionCentre
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PreciseScaleInfo(float Scale, ScaleOrigin Origin, bool XAxis, bool YAxis);
|
||||||
|
}
|
@ -19,13 +19,20 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
public partial class TransformToolboxGroup : EditorToolboxGroup, IKeyBindingHandler<GlobalAction>
|
public partial class TransformToolboxGroup : EditorToolboxGroup, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
private readonly Bindable<bool> canRotate = new BindableBool();
|
private readonly Bindable<bool> canRotate = new BindableBool();
|
||||||
|
private readonly Bindable<bool> canScale = new BindableBool();
|
||||||
|
|
||||||
private EditorToolButton rotateButton = null!;
|
private EditorToolButton rotateButton = null!;
|
||||||
|
private EditorToolButton scaleButton = null!;
|
||||||
|
|
||||||
private Bindable<bool> canRotatePlayfieldOrigin = null!;
|
private Bindable<bool> canRotatePlayfieldOrigin = null!;
|
||||||
private Bindable<bool> canRotateSelectionOrigin = null!;
|
private Bindable<bool> canRotateSelectionOrigin = null!;
|
||||||
|
|
||||||
|
private Bindable<bool> canScaleX = null!;
|
||||||
|
private Bindable<bool> canScaleY = null!;
|
||||||
|
private Bindable<bool> canScaleDiagonally = null!;
|
||||||
|
|
||||||
public SelectionRotationHandler RotationHandler { get; init; } = null!;
|
public SelectionRotationHandler RotationHandler { get; init; } = null!;
|
||||||
|
public SelectionScaleHandler ScaleHandler { get; init; } = null!;
|
||||||
|
|
||||||
public TransformToolboxGroup()
|
public TransformToolboxGroup()
|
||||||
: base("transform")
|
: base("transform")
|
||||||
@ -45,7 +52,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
rotateButton = new EditorToolButton("Rotate",
|
rotateButton = new EditorToolButton("Rotate",
|
||||||
() => new SpriteIcon { Icon = FontAwesome.Solid.Undo },
|
() => new SpriteIcon { Icon = FontAwesome.Solid.Undo },
|
||||||
() => new PreciseRotationPopover(RotationHandler)),
|
() => new PreciseRotationPopover(RotationHandler)),
|
||||||
// TODO: scale
|
scaleButton = new EditorToolButton("Scale",
|
||||||
|
() => new SpriteIcon { Icon = FontAwesome.Solid.ArrowsAlt },
|
||||||
|
() => new PreciseScalePopover(ScaleHandler))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -66,9 +75,25 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
canRotate.Value = RotationHandler.CanRotatePlayfieldOrigin.Value || RotationHandler.CanRotateSelectionOrigin.Value;
|
canRotate.Value = RotationHandler.CanRotatePlayfieldOrigin.Value || RotationHandler.CanRotateSelectionOrigin.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// aggregate three values into canScale
|
||||||
|
canScaleX = ScaleHandler.CanScaleX.GetBoundCopy();
|
||||||
|
canScaleX.BindValueChanged(_ => updateCanScaleAggregate());
|
||||||
|
|
||||||
|
canScaleY = ScaleHandler.CanScaleY.GetBoundCopy();
|
||||||
|
canScaleY.BindValueChanged(_ => updateCanScaleAggregate());
|
||||||
|
|
||||||
|
canScaleDiagonally = ScaleHandler.CanScaleDiagonally.GetBoundCopy();
|
||||||
|
canScaleDiagonally.BindValueChanged(_ => updateCanScaleAggregate());
|
||||||
|
|
||||||
|
void updateCanScaleAggregate()
|
||||||
|
{
|
||||||
|
canScale.Value = ScaleHandler.CanScaleX.Value || ScaleHandler.CanScaleY.Value || ScaleHandler.CanScaleDiagonally.Value;
|
||||||
|
}
|
||||||
|
|
||||||
// bindings to `Enabled` on the buttons are decoupled on purpose
|
// bindings to `Enabled` on the buttons are decoupled on purpose
|
||||||
// due to the weird `OsuButton` behaviour of resetting `Enabled` to `false` when `Action` is set.
|
// due to the weird `OsuButton` behaviour of resetting `Enabled` to `false` when `Action` is set.
|
||||||
canRotate.BindValueChanged(_ => rotateButton.Enabled.Value = canRotate.Value, true);
|
canRotate.BindValueChanged(_ => rotateButton.Enabled.Value = canRotate.Value, true);
|
||||||
|
canScale.BindValueChanged(_ => scaleButton.Enabled.Value = canScale.Value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
@ -82,6 +107,12 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
rotateButton.TriggerClick();
|
rotateButton.TriggerClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case GlobalAction.EditorToggleScaleControl:
|
||||||
|
{
|
||||||
|
scaleButton.TriggerClick();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -142,6 +142,7 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.MouseWheelRight }, GlobalAction.EditorCyclePreviousBeatSnapDivisor),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.MouseWheelRight }, GlobalAction.EditorCyclePreviousBeatSnapDivisor),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.MouseWheelLeft }, GlobalAction.EditorCycleNextBeatSnapDivisor),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.MouseWheelLeft }, GlobalAction.EditorCycleNextBeatSnapDivisor),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.R }, GlobalAction.EditorToggleRotateControl),
|
new KeyBinding(new[] { InputKey.Control, InputKey.R }, GlobalAction.EditorToggleRotateControl),
|
||||||
|
new KeyBinding(new[] { InputKey.S }, GlobalAction.EditorToggleScaleControl),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static IEnumerable<KeyBinding> inGameKeyBindings => new[]
|
private static IEnumerable<KeyBinding> inGameKeyBindings => new[]
|
||||||
@ -411,6 +412,9 @@ namespace osu.Game.Input.Bindings
|
|||||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorToggleRotateControl))]
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorToggleRotateControl))]
|
||||||
EditorToggleRotateControl,
|
EditorToggleRotateControl,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorToggleScaleControl))]
|
||||||
|
EditorToggleScaleControl,
|
||||||
|
|
||||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.IncreaseOffset))]
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.IncreaseOffset))]
|
||||||
IncreaseOffset,
|
IncreaseOffset,
|
||||||
|
|
||||||
|
@ -369,6 +369,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString EditorToggleRotateControl => new TranslatableString(getKey(@"editor_toggle_rotate_control"), @"Toggle rotate control");
|
public static LocalisableString EditorToggleRotateControl => new TranslatableString(getKey(@"editor_toggle_rotate_control"), @"Toggle rotate control");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Toggle scale control"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorToggleScaleControl => new TranslatableString(getKey(@"editor_toggle_scale_control"), @"Toggle scale control");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Increase mod speed"
|
/// "Increase mod speed"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
Reference in New Issue
Block a user