mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 07:22:55 +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]
|
[Test]
|
||||||
public void TestHotkeyHandling()
|
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", () =>
|
AddStep("press rotate hotkey", () =>
|
||||||
{
|
{
|
||||||
InputManager.PressKey(Key.ControlLeft);
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
InputManager.Key(Key.R);
|
InputManager.Key(Key.R);
|
||||||
InputManager.ReleaseKey(Key.ControlLeft);
|
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", () =>
|
AddStep("select first three objects", () =>
|
||||||
{
|
{
|
||||||
@ -44,14 +68,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
InputManager.Key(Key.R);
|
InputManager.Key(Key.R);
|
||||||
InputManager.ReleaseKey(Key.ControlLeft);
|
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", () =>
|
AddStep("press rotate hotkey", () =>
|
||||||
{
|
{
|
||||||
InputManager.PressKey(Key.ControlLeft);
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
InputManager.Key(Key.R);
|
InputManager.Key(Key.R);
|
||||||
InputManager.ReleaseKey(Key.ControlLeft);
|
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]
|
[Test]
|
||||||
|
@ -41,7 +41,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
private void updateState()
|
private void updateState()
|
||||||
{
|
{
|
||||||
var quad = GeometryUtils.GetSurroundingQuad(selectedMovableObjects);
|
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;
|
private OsuHitObject[]? objectsInRotation;
|
||||||
|
@ -24,6 +24,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
private SliderWithTextBoxInput<float> angleInput = null!;
|
private SliderWithTextBoxInput<float> angleInput = null!;
|
||||||
private EditorRadioButtonCollection rotationOrigin = null!;
|
private EditorRadioButtonCollection rotationOrigin = null!;
|
||||||
|
|
||||||
|
private RadioButton selectionCentreButton = null!;
|
||||||
|
|
||||||
public PreciseRotationPopover(SelectionRotationHandler rotationHandler)
|
public PreciseRotationPopover(SelectionRotationHandler rotationHandler)
|
||||||
{
|
{
|
||||||
this.rotationHandler = rotationHandler;
|
this.rotationHandler = rotationHandler;
|
||||||
@ -59,13 +61,17 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
new RadioButton("Playfield centre",
|
new RadioButton("Playfield centre",
|
||||||
() => rotationInfo.Value = rotationInfo.Value with { Origin = RotationOrigin.PlayfieldCentre },
|
() => rotationInfo.Value = rotationInfo.Value with { Origin = RotationOrigin.PlayfieldCentre },
|
||||||
() => new SpriteIcon { Icon = FontAwesome.Regular.Square }),
|
() => new SpriteIcon { Icon = FontAwesome.Regular.Square }),
|
||||||
new RadioButton("Selection centre",
|
selectionCentreButton = new RadioButton("Selection centre",
|
||||||
() => rotationInfo.Value = rotationInfo.Value with { Origin = RotationOrigin.SelectionCentre },
|
() => rotationInfo.Value = rotationInfo.Value with { Origin = RotationOrigin.SelectionCentre },
|
||||||
() => new SpriteIcon { Icon = FontAwesome.Solid.VectorSquare })
|
() => 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()
|
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 });
|
angleInput.Current.BindValueChanged(angle => rotationInfo.Value = rotationInfo.Value with { Degrees = angle.NewValue });
|
||||||
rotationOrigin.Items.First().Select();
|
rotationOrigin.Items.First().Select();
|
||||||
|
|
||||||
|
rotationHandler.CanRotateSelectionOrigin.BindValueChanged(e =>
|
||||||
|
{
|
||||||
|
selectionCentreButton.Selected.Disabled = !e.NewValue;
|
||||||
|
}, true);
|
||||||
|
|
||||||
rotationInfo.BindValueChanged(rotation =>
|
rotationInfo.BindValueChanged(rotation =>
|
||||||
{
|
{
|
||||||
rotationHandler.Update(rotation.NewValue.Degrees, rotation.NewValue.Origin == RotationOrigin.PlayfieldCentre ? OsuPlayfield.BASE_SIZE / 2 : null);
|
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 EditorToolButton rotateButton = null!;
|
||||||
|
|
||||||
|
private Bindable<bool> canRotatePlayfieldOrigin = null!;
|
||||||
|
private Bindable<bool> canRotateSelectionOrigin = null!;
|
||||||
|
|
||||||
public SelectionRotationHandler RotationHandler { get; init; } = null!;
|
public SelectionRotationHandler RotationHandler { get; init; } = null!;
|
||||||
|
|
||||||
public TransformToolboxGroup()
|
public TransformToolboxGroup()
|
||||||
@ -51,9 +54,20 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
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
|
// 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.BindTo(RotationHandler.CanRotate);
|
|
||||||
canRotate.BindValueChanged(_ => rotateButton.Enabled.Value = canRotate.Value, true);
|
canRotate.BindValueChanged(_ => rotateButton.Enabled.Value = canRotate.Value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
{
|
{
|
||||||
this.getTargetContainer = getTargetContainer;
|
this.getTargetContainer = getTargetContainer;
|
||||||
|
|
||||||
CanRotate.Value = true;
|
CanRotateSelectionOrigin.Value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
|
|
||||||
private void updateState()
|
private void updateState()
|
||||||
{
|
{
|
||||||
CanRotate.Value = selectedItems.Count > 0;
|
CanRotateSelectionOrigin.Value = selectedItems.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable[]? objectsInRotation;
|
private Drawable[]? objectsInRotation;
|
||||||
|
@ -212,6 +212,14 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
.Select(t => new RadioButton(t.Name, () => toolSelected(t), t.CreateIcon))
|
.Select(t => new RadioButton(t.Name, () => toolSelected(t), t.CreateIcon))
|
||||||
.ToList();
|
.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();
|
TernaryStates = CreateTernaryButtons().ToArray();
|
||||||
togglesCollection.AddRange(TernaryStates.Select(b => new DrawableTernaryButton(b)));
|
togglesCollection.AddRange(TernaryStates.Select(b => new DrawableTernaryButton(b)));
|
||||||
|
|
||||||
@ -244,6 +252,14 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
if (!timing.NewValue)
|
if (!timing.NewValue)
|
||||||
setSelectTool();
|
setSelectTool();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EditorBeatmap.HasTiming.BindValueChanged(hasTiming =>
|
||||||
|
{
|
||||||
|
foreach (var item in toolboxCollection.Items)
|
||||||
|
{
|
||||||
|
item.Selected.Disabled = !hasTiming.NewValue;
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
|
@ -33,9 +33,6 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
|||||||
|
|
||||||
private Drawable icon = null!;
|
private Drawable icon = null!;
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private EditorBeatmap? editorBeatmap { get; set; }
|
|
||||||
|
|
||||||
public EditorRadioButton(RadioButton button)
|
public EditorRadioButton(RadioButton button)
|
||||||
{
|
{
|
||||||
Button = button;
|
Button = button;
|
||||||
@ -76,8 +73,6 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
|||||||
Selected?.Invoke(Button);
|
Selected?.Invoke(Button);
|
||||||
};
|
};
|
||||||
|
|
||||||
editorBeatmap?.HasTiming.BindValueChanged(hasTiming => Button.Selected.Disabled = !hasTiming.NewValue, true);
|
|
||||||
|
|
||||||
Button.Selected.BindDisabledChanged(disabled => Enabled.Value = !disabled, true);
|
Button.Selected.BindDisabledChanged(disabled => Enabled.Value = !disabled, true);
|
||||||
updateSelectionState();
|
updateSelectionState();
|
||||||
}
|
}
|
||||||
@ -99,6 +94,6 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
|||||||
X = 40f
|
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 System;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Components.RadioButtons
|
namespace osu.Game.Screens.Edit.Components.RadioButtons
|
||||||
{
|
{
|
||||||
@ -11,6 +12,7 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="RadioButton"/> is selected.
|
/// Whether this <see cref="RadioButton"/> is selected.
|
||||||
|
/// Disable this bindable to disable the button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableBool Selected;
|
public readonly BindableBool Selected;
|
||||||
|
|
||||||
@ -50,5 +52,8 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons
|
|||||||
/// Deselects this <see cref="RadioButton"/>.
|
/// Deselects this <see cref="RadioButton"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Deselect() => Selected.Value = false;
|
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()
|
private void load()
|
||||||
{
|
{
|
||||||
if (rotationHandler != null)
|
if (rotationHandler != null)
|
||||||
canRotate.BindTo(rotationHandler.CanRotate);
|
canRotate.BindTo(rotationHandler.CanRotateSelectionOrigin);
|
||||||
|
|
||||||
canRotate.BindValueChanged(_ => recreate(), true);
|
canRotate.BindValueChanged(_ => recreate(), true);
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,14 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
public partial class SelectionRotationHandler : Component
|
public partial class SelectionRotationHandler : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the rotation can currently be performed.
|
/// Whether rotation anchored by the selection origin can currently be performed.
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Performs a single, instant, atomic rotation operation.
|
/// Performs a single, instant, atomic rotation operation.
|
||||||
|
Loading…
Reference in New Issue
Block a user