@@ -22,7 +22,10 @@ namespace osu.Game.Overlays.SkinEditor
2222{
2323 public partial class SkinSelectionHandler : SelectionHandler < ISerialisableDrawable >
2424 {
25- private OsuMenuItem originMenu = null ! ;
25+ private OsuMenuItem ? originMenu ;
26+
27+ private TernaryStateRadioMenuItem ? closestAnchor ;
28+ private AnchorMenuItem [ ] ? fixedAnchors ;
2629
2730 [ Resolved ]
2831 private SkinEditor skinEditor { get ; set ; } = null ! ;
@@ -44,6 +47,38 @@ public override SelectionScaleHandler CreateScaleHandler()
4447 return scaleHandler ;
4548 }
4649
50+ protected override void LoadComplete ( )
51+ {
52+ base . LoadComplete ( ) ;
53+
54+ if ( ChangeHandler != null )
55+ ChangeHandler . OnStateChange += updateTernaryStates ;
56+ SelectedItems . BindCollectionChanged ( ( _ , _ ) => updateTernaryStates ( ) ) ;
57+ }
58+
59+ private void updateTernaryStates ( )
60+ {
61+ var usingClosestAnchor = GetStateFromSelection ( SelectedBlueprints , c => ! c . Item . UsesFixedAnchor ) ;
62+
63+ if ( closestAnchor != null )
64+ closestAnchor . State . Value = usingClosestAnchor ;
65+
66+ if ( fixedAnchors != null )
67+ {
68+ foreach ( var fixedAnchor in fixedAnchors )
69+ fixedAnchor . State . Value = GetStateFromSelection ( SelectedBlueprints , c => c . Item . UsesFixedAnchor && ( ( Drawable ) c . Item ) . Anchor == fixedAnchor . Anchor ) ;
70+ }
71+
72+ if ( originMenu != null )
73+ {
74+ foreach ( var origin in originMenu . Items . OfType < AnchorMenuItem > ( ) )
75+ {
76+ origin . State . Value = GetStateFromSelection ( SelectedBlueprints , c => ( ( Drawable ) c . Item ) . Origin == origin . Anchor ) ;
77+ origin . Action . Disabled = usingClosestAnchor == TernaryState . True ;
78+ }
79+ }
80+ }
81+
4782 public override bool HandleFlip ( Direction direction , bool flipOverOrigin )
4883 {
4984 var selectionQuad = getSelectionQuad ( ) ;
@@ -102,27 +137,17 @@ protected override void DeleteItems(IEnumerable<ISerialisableDrawable> items) =>
102137
103138 protected override IEnumerable < MenuItem > GetContextMenuItemsForSelection ( IEnumerable < SelectionBlueprint < ISerialisableDrawable > > selection )
104139 {
105- var closestItem = new TernaryStateRadioMenuItem ( SkinEditorStrings . Closest , MenuItemType . Standard , _ => applyClosestAnchors ( ) )
106- {
107- State = { Value = GetStateFromSelection ( selection , c => ! c . Item . UsesFixedAnchor ) }
108- } ;
140+ closestAnchor = new TernaryStateRadioMenuItem ( SkinEditorStrings . Closest , MenuItemType . Standard , _ => applyClosestAnchors ( ) ) ;
141+ fixedAnchors = createAnchorItems ( applyFixedAnchors ) . ToArray ( ) ;
109142
110143 yield return new OsuMenuItem ( SkinEditorStrings . Anchor )
111144 {
112- Items = createAnchorItems ( ( d , a ) => d . UsesFixedAnchor && ( ( Drawable ) d ) . Anchor == a , applyFixedAnchors )
113- . Prepend ( closestItem )
114- . ToArray ( )
145+ Items = fixedAnchors . Prepend ( closestAnchor ) . ToArray ( )
115146 } ;
116147
117148 yield return originMenu = new OsuMenuItem ( SkinEditorStrings . Origin ) ;
118149
119- closestItem . State . BindValueChanged ( s =>
120- {
121- // For UX simplicity, origin should only be user-editable when "closest" anchor mode is disabled.
122- originMenu . Items = s . NewValue == TernaryState . True
123- ? Array . Empty < MenuItem > ( )
124- : createAnchorItems ( ( d , o ) => ( ( Drawable ) d ) . Origin == o , applyOrigins ) . ToArray ( ) ;
125- } , true ) ;
150+ originMenu . Items = createAnchorItems ( applyOrigins ) . ToArray ( ) ;
126151
127152 yield return new OsuMenuItemSpacer ( ) ;
128153
@@ -163,27 +188,37 @@ protected override IEnumerable<MenuItem> GetContextMenuItemsForSelection(IEnumer
163188 foreach ( var item in base . GetContextMenuItemsForSelection ( selection ) )
164189 yield return item ;
165190
166- IEnumerable < TernaryStateMenuItem > createAnchorItems ( Func < ISerialisableDrawable , Anchor , bool > checkFunction , Action < Anchor > applyFunction )
191+ updateTernaryStates ( ) ;
192+ }
193+
194+ private IEnumerable < AnchorMenuItem > createAnchorItems ( Action < Anchor > applyFunction )
195+ {
196+ var displayableAnchors = new [ ]
167197 {
168- var displayableAnchors = new [ ]
169- {
170- Anchor . TopLeft ,
171- Anchor . TopCentre ,
172- Anchor . TopRight ,
173- Anchor . CentreLeft ,
174- Anchor . Centre ,
175- Anchor . CentreRight ,
176- Anchor . BottomLeft ,
177- Anchor . BottomCentre ,
178- Anchor . BottomRight ,
179- } ;
180- return displayableAnchors . Select ( a =>
181- {
182- return new TernaryStateRadioMenuItem ( a . ToString ( ) , MenuItemType . Standard , _ => applyFunction ( a ) )
183- {
184- State = { Value = GetStateFromSelection ( selection , c => checkFunction ( c . Item , a ) ) }
185- } ;
186- } ) ;
198+ Anchor . TopLeft ,
199+ Anchor . TopCentre ,
200+ Anchor . TopRight ,
201+ Anchor . CentreLeft ,
202+ Anchor . Centre ,
203+ Anchor . CentreRight ,
204+ Anchor . BottomLeft ,
205+ Anchor . BottomCentre ,
206+ Anchor . BottomRight ,
207+ } ;
208+ return displayableAnchors . Select ( a =>
209+ {
210+ return new AnchorMenuItem ( a , _ => applyFunction ( a ) ) ;
211+ } ) ;
212+ }
213+
214+ private partial class AnchorMenuItem : TernaryStateRadioMenuItem
215+ {
216+ public readonly Anchor Anchor ;
217+
218+ public AnchorMenuItem ( Anchor anchor , Action < Anchor > applyFunction )
219+ : base ( anchor . ToString ( ) , MenuItemType . Standard , _ => applyFunction ( anchor ) )
220+ {
221+ Anchor = anchor ;
187222 }
188223 }
189224
0 commit comments