1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-18 15:30:06 +08:00

Fix skin editor origin dropdown options applying origin in wrong coordinate space (#37219)

Closes https://github.com/ppy/osu/issues/37185.

The checkboxes in the context menu's ternary states were supposed to
always show the origin "in local space", even if anchor is set to
"closest". The issue here was reusing a method that only really made
sense with closest anchor active for explicit application of
"local-space" origin.

To recap:
- Below I will use concepts of "local-space origin" and "screen-space
origin". To understand the difference, let's use an example:

Say there's a drawable with 180 degree rotation. Suppose it has the
"local origin" of `TopCentre`. The "local origin" is just the `Drawable`
notion of origin; you'd literally set `d.Origin = Anchor.TopCentre`.

The "screen-space origin" of this drawable is `BottomCentre`, because
due to the rotation, that's how the component will visually behave when
its position is altered.

The same sort of distinction applies forth to things like flips /
negative scale and such.

- When you have closest anchor selected, you can only choose the anchor
to snap to. The drawable will snap to that anchor, and choose an origin
closest to it *in screen space* such that the "closest" in "closest
anchor" works as users would expect it to. In this state, if you open
the context menu for origin, all items will be disabled, but the ternary
menu items will show the origin state *as translated back to local
space*.

- When you have an explicit anchor selected, you can choose both the
anchor and origin. In that case, the origin picked is always picked in
local space.

In the end, this is all consistent with how the `Origin` property on
`Drawable` works, and also with what is serialised to skin jsons.
This commit is contained in:
Bartłomiej Dach
2026-04-06 16:03:07 +02:00
committed by GitHub
Unverified
parent 809298ddeb
commit 0f40d61bb8
@@ -120,7 +120,7 @@ namespace osu.Game.Overlays.SkinEditor
var closest = getClosestAnchor(drawable);
applyAnchor(drawable, closest);
applyOrigin(drawable, closest);
applyScreenSpaceOrigin(drawable, closest);
}
protected override void OnSelectionChanged()
@@ -236,10 +236,7 @@ namespace osu.Game.Overlays.SkinEditor
{
var drawable = (Drawable)item;
applyOrigin(drawable, origin);
if (!item.UsesFixedAnchor)
ApplyClosestAnchorOrigin(drawable);
applyLocalSpaceOrigin(drawable, origin);
}
OnOperationEnded();
@@ -320,7 +317,17 @@ namespace osu.Game.Overlays.SkinEditor
drawable.Position -= drawable.AnchorPosition - previousAnchor;
}
private static void applyOrigin(Drawable drawable, Anchor screenSpaceOrigin)
private static void applyLocalSpaceOrigin(Drawable drawable, Anchor localSpaceOrigin)
{
if (localSpaceOrigin == drawable.Origin)
return;
Vector2 offset = drawable.ToParentSpace(localSpaceOrigin.PositionOnQuad(drawable.DrawRectangle)) - drawable.ToParentSpace(drawable.Origin.PositionOnQuad(drawable.DrawRectangle));
drawable.Origin = localSpaceOrigin;
drawable.Position += offset;
}
private static void applyScreenSpaceOrigin(Drawable drawable, Anchor screenSpaceOrigin)
{
var boundingBox = drawable.ScreenSpaceDrawQuad.AABBFloat;