@@ -304,6 +304,7 @@ private void load(OsuConfigManager config)
304
304
cutMenuItem = new EditorMenuItem ( "Cut" , MenuItemType . Standard , Cut ) ,
305
305
copyMenuItem = new EditorMenuItem ( "Copy" , MenuItemType . Standard , Copy ) ,
306
306
pasteMenuItem = new EditorMenuItem ( "Paste" , MenuItemType . Standard , Paste ) ,
307
+ cloneMenuItem = new EditorMenuItem ( "Clone" , MenuItemType . Standard , Clone ) ,
307
308
}
308
309
} ,
309
310
new MenuItem ( "View" )
@@ -575,6 +576,10 @@ public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
575
576
this . Exit ( ) ;
576
577
return true ;
577
578
579
+ case GlobalAction . EditorCloneSelection :
580
+ Clone ( ) ;
581
+ return true ;
582
+
578
583
case GlobalAction . EditorComposeMode :
579
584
Mode . Value = EditorScreenMode . Compose ;
580
585
return true ;
@@ -741,6 +746,7 @@ private void updateInProgress(ValueChangedEvent<bool> obj)
741
746
742
747
private EditorMenuItem cutMenuItem ;
743
748
private EditorMenuItem copyMenuItem ;
749
+ private EditorMenuItem cloneMenuItem ;
744
750
private EditorMenuItem pasteMenuItem ;
745
751
746
752
private readonly BindableWithCurrent < bool > canCut = new BindableWithCurrent < bool > ( ) ;
@@ -750,7 +756,11 @@ private void updateInProgress(ValueChangedEvent<bool> obj)
750
756
private void setUpClipboardActionAvailability ( )
751
757
{
752
758
canCut . Current . BindValueChanged ( cut => cutMenuItem . Action . Disabled = ! cut . NewValue , true ) ;
753
- canCopy . Current . BindValueChanged ( copy => copyMenuItem . Action . Disabled = ! copy . NewValue , true ) ;
759
+ canCopy . Current . BindValueChanged ( copy =>
760
+ {
761
+ copyMenuItem . Action . Disabled = ! copy . NewValue ;
762
+ cloneMenuItem . Action . Disabled = ! copy . NewValue ;
763
+ } , true ) ;
754
764
canPaste . Current . BindValueChanged ( paste => pasteMenuItem . Action . Disabled = ! paste . NewValue , true ) ;
755
765
}
756
766
@@ -765,6 +775,21 @@ private void rebindClipboardBindables()
765
775
766
776
protected void Copy ( ) => currentScreen ? . Copy ( ) ;
767
777
778
+ protected void Clone ( )
779
+ {
780
+ // Avoid attempting to clone if copying is not available (as it may result in pasting something unexpected).
781
+ if ( ! canCopy . Value )
782
+ return ;
783
+
784
+ // This is an initial implementation just to get an idea of how people used this function.
785
+ // There are a couple of differences from osu!stable's implementation which will require more work to match:
786
+ // - The "clipboard" is not populated during the duplication process.
787
+ // - The duplicated hitobjects are inserted after the original pattern (add one beat_length and then quantize using beat snap).
788
+ // - The duplicated hitobjects are selected (but this is also applied for all paste operations so should be changed there).
789
+ Copy ( ) ;
790
+ Paste ( ) ;
791
+ }
792
+
768
793
protected void Paste ( ) => currentScreen ? . Paste ( ) ;
769
794
770
795
#endregion
0 commit comments