mirror of
https://github.com/ppy/osu.git
synced 2024-11-13 15:27:30 +08:00
Merge pull request #26702 from honguyenminh/fix-rotate-editor-button-disabled
Fix rotate tool button in editor disabled when selecting 1 circle
This commit is contained in:
commit
51e9348d27
@ -24,14 +24,38 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
[Test]
|
||||
public void TestHotkeyHandling()
|
||||
{
|
||||
AddStep("select single circle", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.OfType<HitCircle>().First()));
|
||||
AddStep("deselect everything", () => EditorBeatmap.SelectedHitObjects.Clear());
|
||||
AddStep("press rotate hotkey", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.Key(Key.R);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
AddUntilStep("no popover present", () => this.ChildrenOfType<PreciseRotationPopover>().Count(), () => Is.Zero);
|
||||
AddUntilStep("no popover present", getPopover, () => Is.Null);
|
||||
|
||||
AddStep("select single circle",
|
||||
() => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.OfType<HitCircle>().First()));
|
||||
AddStep("press rotate hotkey", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.Key(Key.R);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
AddUntilStep("popover present", getPopover, () => Is.Not.Null);
|
||||
AddAssert("only playfield centre origin rotation available", () =>
|
||||
{
|
||||
var popover = getPopover();
|
||||
var buttons = popover.ChildrenOfType<EditorRadioButton>();
|
||||
return buttons.Any(btn => btn.Text == "Selection centre" && !btn.Enabled.Value)
|
||||
&& buttons.Any(btn => btn.Text == "Playfield centre" && btn.Enabled.Value);
|
||||
});
|
||||
AddStep("press rotate hotkey", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.Key(Key.R);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
AddUntilStep("no popover present", getPopover, () => Is.Null);
|
||||
|
||||
AddStep("select first three objects", () =>
|
||||
{
|
||||
@ -44,14 +68,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
InputManager.Key(Key.R);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
AddUntilStep("popover present", () => this.ChildrenOfType<PreciseRotationPopover>().Count(), () => Is.EqualTo(1));
|
||||
AddUntilStep("popover present", getPopover, () => Is.Not.Null);
|
||||
AddAssert("both origin rotation available", () =>
|
||||
{
|
||||
var popover = getPopover();
|
||||
var buttons = popover.ChildrenOfType<EditorRadioButton>();
|
||||
return buttons.Any(btn => btn.Text == "Selection centre" && btn.Enabled.Value)
|
||||
&& buttons.Any(btn => btn.Text == "Playfield centre" && btn.Enabled.Value);
|
||||
});
|
||||
AddStep("press rotate hotkey", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.Key(Key.R);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
AddUntilStep("no popover present", () => this.ChildrenOfType<PreciseRotationPopover>().Count(), () => Is.Zero);
|
||||
AddUntilStep("no popover present", getPopover, () => Is.Null);
|
||||
|
||||
PreciseRotationPopover? getPopover() => this.ChildrenOfType<PreciseRotationPopover>().SingleOrDefault();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -41,7 +41,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
private void updateState()
|
||||
{
|
||||
var quad = GeometryUtils.GetSurroundingQuad(selectedMovableObjects);
|
||||
CanRotate.Value = quad.Width > 0 || quad.Height > 0;
|
||||
CanRotateSelectionOrigin.Value = quad.Width > 0 || quad.Height > 0;
|
||||
CanRotatePlayfieldOrigin.Value = selectedMovableObjects.Any();
|
||||
}
|
||||
|
||||
private OsuHitObject[]? objectsInRotation;
|
||||
|
@ -24,6 +24,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
private SliderWithTextBoxInput<float> angleInput = null!;
|
||||
private EditorRadioButtonCollection rotationOrigin = null!;
|
||||
|
||||
private RadioButton selectionCentreButton = null!;
|
||||
|
||||
public PreciseRotationPopover(SelectionRotationHandler rotationHandler)
|
||||
{
|
||||
this.rotationHandler = rotationHandler;
|
||||
@ -59,13 +61,17 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
new RadioButton("Playfield centre",
|
||||
() => rotationInfo.Value = rotationInfo.Value with { Origin = RotationOrigin.PlayfieldCentre },
|
||||
() => new SpriteIcon { Icon = FontAwesome.Regular.Square }),
|
||||
new RadioButton("Selection centre",
|
||||
selectionCentreButton = new RadioButton("Selection centre",
|
||||
() => rotationInfo.Value = rotationInfo.Value with { Origin = RotationOrigin.SelectionCentre },
|
||||
() => new SpriteIcon { Icon = FontAwesome.Solid.VectorSquare })
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
selectionCentreButton.Selected.DisabledChanged += isDisabled =>
|
||||
{
|
||||
selectionCentreButton.TooltipText = isDisabled ? "Select more than one object to perform selection-based rotation." : string.Empty;
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -76,6 +82,11 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
angleInput.Current.BindValueChanged(angle => rotationInfo.Value = rotationInfo.Value with { Degrees = angle.NewValue });
|
||||
rotationOrigin.Items.First().Select();
|
||||
|
||||
rotationHandler.CanRotateSelectionOrigin.BindValueChanged(e =>
|
||||
{
|
||||
selectionCentreButton.Selected.Disabled = !e.NewValue;
|
||||
}, true);
|
||||
|
||||
rotationInfo.BindValueChanged(rotation =>
|
||||
{
|
||||
rotationHandler.Update(rotation.NewValue.Degrees, rotation.NewValue.Origin == RotationOrigin.PlayfieldCentre ? OsuPlayfield.BASE_SIZE / 2 : null);
|
||||
|
@ -22,6 +22,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
|
||||
private EditorToolButton rotateButton = null!;
|
||||
|
||||
private Bindable<bool> canRotatePlayfieldOrigin = null!;
|
||||
private Bindable<bool> canRotateSelectionOrigin = null!;
|
||||
|
||||
public SelectionRotationHandler RotationHandler { get; init; } = null!;
|
||||
|
||||
public TransformToolboxGroup()
|
||||
@ -51,9 +54,20 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
// aggregate two values into canRotate
|
||||
canRotatePlayfieldOrigin = RotationHandler.CanRotatePlayfieldOrigin.GetBoundCopy();
|
||||
canRotatePlayfieldOrigin.BindValueChanged(_ => updateCanRotateAggregate());
|
||||
|
||||
canRotateSelectionOrigin = RotationHandler.CanRotateSelectionOrigin.GetBoundCopy();
|
||||
canRotateSelectionOrigin.BindValueChanged(_ => updateCanRotateAggregate());
|
||||
|
||||
void updateCanRotateAggregate()
|
||||
{
|
||||
canRotate.Value = RotationHandler.CanRotatePlayfieldOrigin.Value || RotationHandler.CanRotateSelectionOrigin.Value;
|
||||
}
|
||||
|
||||
// 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.
|
||||
canRotate.BindTo(RotationHandler.CanRotate);
|
||||
canRotate.BindValueChanged(_ => rotateButton.Enabled.Value = canRotate.Value, true);
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
{
|
||||
this.getTargetContainer = getTargetContainer;
|
||||
|
||||
CanRotate.Value = true;
|
||||
CanRotateSelectionOrigin.Value = true;
|
||||
}
|
||||
|
||||
[CanBeNull]
|
||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
CanRotate.Value = selectedItems.Count > 0;
|
||||
CanRotateSelectionOrigin.Value = selectedItems.Count > 0;
|
||||
}
|
||||
|
||||
private Drawable[]? objectsInRotation;
|
||||
|
@ -212,6 +212,14 @@ namespace osu.Game.Rulesets.Edit
|
||||
.Select(t => new RadioButton(t.Name, () => toolSelected(t), t.CreateIcon))
|
||||
.ToList();
|
||||
|
||||
foreach (var item in toolboxCollection.Items)
|
||||
{
|
||||
item.Selected.DisabledChanged += isDisabled =>
|
||||
{
|
||||
item.TooltipText = isDisabled ? "Add at least one timing point first!" : string.Empty;
|
||||
};
|
||||
}
|
||||
|
||||
TernaryStates = CreateTernaryButtons().ToArray();
|
||||
togglesCollection.AddRange(TernaryStates.Select(b => new DrawableTernaryButton(b)));
|
||||
|
||||
@ -244,6 +252,14 @@ namespace osu.Game.Rulesets.Edit
|
||||
if (!timing.NewValue)
|
||||
setSelectTool();
|
||||
});
|
||||
|
||||
EditorBeatmap.HasTiming.BindValueChanged(hasTiming =>
|
||||
{
|
||||
foreach (var item in toolboxCollection.Items)
|
||||
{
|
||||
item.Selected.Disabled = !hasTiming.NewValue;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
|
@ -33,9 +33,6 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||
|
||||
private Drawable icon = null!;
|
||||
|
||||
[Resolved]
|
||||
private EditorBeatmap? editorBeatmap { get; set; }
|
||||
|
||||
public EditorRadioButton(RadioButton button)
|
||||
{
|
||||
Button = button;
|
||||
@ -76,8 +73,6 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||
Selected?.Invoke(Button);
|
||||
};
|
||||
|
||||
editorBeatmap?.HasTiming.BindValueChanged(hasTiming => Button.Selected.Disabled = !hasTiming.NewValue, true);
|
||||
|
||||
Button.Selected.BindDisabledChanged(disabled => Enabled.Value = !disabled, true);
|
||||
updateSelectionState();
|
||||
}
|
||||
@ -99,6 +94,6 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||
X = 40f
|
||||
};
|
||||
|
||||
public LocalisableString TooltipText => Enabled.Value ? string.Empty : "Add at least one timing point first!";
|
||||
public LocalisableString TooltipText => Button.TooltipText;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||
{
|
||||
@ -11,6 +12,7 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this <see cref="RadioButton"/> is selected.
|
||||
/// Disable this bindable to disable the button.
|
||||
/// </summary>
|
||||
public readonly BindableBool Selected;
|
||||
|
||||
@ -50,5 +52,8 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||
/// Deselects this <see cref="RadioButton"/>.
|
||||
/// </summary>
|
||||
public void Deselect() => Selected.Value = false;
|
||||
|
||||
// Tooltip text that will be shown when hovered over
|
||||
public LocalisableString TooltipText { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
private void load()
|
||||
{
|
||||
if (rotationHandler != null)
|
||||
canRotate.BindTo(rotationHandler.CanRotate);
|
||||
canRotate.BindTo(rotationHandler.CanRotateSelectionOrigin);
|
||||
|
||||
canRotate.BindValueChanged(_ => recreate(), true);
|
||||
}
|
||||
|
@ -13,9 +13,14 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
public partial class SelectionRotationHandler : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the rotation can currently be performed.
|
||||
/// Whether rotation anchored by the selection origin can currently be performed.
|
||||
/// </summary>
|
||||
public Bindable<bool> CanRotate { get; private set; } = new BindableBool();
|
||||
public Bindable<bool> CanRotateSelectionOrigin { get; private set; } = new BindableBool();
|
||||
|
||||
/// <summary>
|
||||
/// Whether rotation anchored by the center of the playfield can currently be performed.
|
||||
/// </summary>
|
||||
public Bindable<bool> CanRotatePlayfieldOrigin { get; private set; } = new BindableBool();
|
||||
|
||||
/// <summary>
|
||||
/// Performs a single, instant, atomic rotation operation.
|
||||
|
Loading…
Reference in New Issue
Block a user