mirror of
https://github.com/ppy/osu.git
synced 2024-12-05 09:42:54 +08:00
Updated Implementing a ruleset editor (markdown)
parent
8c7de8ea22
commit
0539d9c002
@ -54,25 +54,79 @@ public class TestSceneEditor : EditorTestScene
|
||||
|
||||
Running your visual tests, you should now see the editor in a relatively good visual state. You should also notice that basic object movement in the timeline should work as expected, as long as you are doing all `DrawableHitObject` visual update logic in `UpdateState`. This is because `HitObject`'s `StartTime` bindable handling is done for you.
|
||||
|
||||
## Making selection and movement work in the compose area
|
||||
|
||||
If you are a scrolling ruleset, you will also benefit from selection logic automatically working in the main compose area too.
|
||||
|
||||
If not, *todo*
|
||||
|
||||
## Keeping DrawableHitObjects compatible with the editor
|
||||
|
||||
*todo*
|
||||
- All transforms and state changes should be done in `UpdateState`. This allows internal logic to update visual state without user intervention.
|
||||
- DrawablesHitObjects must respond to changes to bindables. Current bindables are:
|
||||
- StartTimeBindable (handled for the user)
|
||||
- SamplesBindable
|
||||
- DurationBindable (coming soon?)
|
||||
- Any custom attributes added (for instance the `Position` of an `OsuHitObject`) should be bindables and also allow handling the same flow.
|
||||
|
||||
## Creating a custom selection handler
|
||||
|
||||
*todo*
|
||||
The default `SelectionHandler` implementation goes a long way to make things work out of the box, but there are some scenarios you will need to create a custom implementation:
|
||||
|
||||
### Making selection work for non-scrolling ruleset
|
||||
|
||||
If you are a scrolling ruleset, you will also benefit from selection logic automatically working in the main compose area too. If not, you will need to override [`HandleMovement`](https://github.com/ppy/osu/blob/9b277d52e52c926a30e9816393cd734d014c96c4/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs#L74-L86)
|
||||
|
||||
### Adding context menu options for current selection
|
||||
|
||||
To create context menu items for the current selection, you will need to override [`GetContextMenuItemsForSelection`](https://github.com/ppy/osu/blob/9b277d52e52c926a30e9816393cd734d014c96c4/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs#L291). It is recommended to use `TernaryStateMenuItem`s to correctly represent a selection which has multiple different states, or to hide options which can't feasibly operate on the current selection.
|
||||
|
||||
An example of examining and applying the ternary state to the current selection follows:
|
||||
|
||||
```csharp
|
||||
protected override IEnumerable<MenuItem> GetContextMenuItemsForSelection(IEnumerable<SelectionBlueprint> selection)
|
||||
{
|
||||
// validity check — we can only show this menu item if all of the selection is the correct type.
|
||||
if (selection.All(s => s.HitObject is TaikoHitObject))
|
||||
{
|
||||
// pre-cast for simplicity.
|
||||
var hits = selection.Select(s => s.HitObject).OfType<TaikoHitObject>();
|
||||
|
||||
yield return new TernaryStateMenuItem("Strong", action: state =>
|
||||
{
|
||||
// applied state will always be true or false — this is after a user change.
|
||||
foreach (var h in hits)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case TernaryState.True:
|
||||
h.IsStrong = true;
|
||||
break;
|
||||
|
||||
case TernaryState.False:
|
||||
h.IsStrong = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Only required if you need to run ApplyDefaults on the HitObject.
|
||||
// If you are handling the change via bindables this is usually not required.
|
||||
EditorBeatmap?.UpdateHitObject(h);
|
||||
}
|
||||
})
|
||||
{
|
||||
// set the initial state using a handle helper function below.
|
||||
State = { Value = getTernaryState(hits, h => h.IsStrong) }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private TernaryState getTernaryState<T>(IEnumerable<T> selection, Func<T, bool> func)
|
||||
{
|
||||
if (selection.Any(func))
|
||||
return selection.All(func) ? TernaryState.True : TernaryState.Indeterminate;
|
||||
|
||||
return TernaryState.False;
|
||||
}
|
||||
```
|
||||
|
||||
## Creating composer blueprints
|
||||
|
||||
*todo*
|
||||
|
||||
_todo_
|
||||
|
||||
## Creating placement tools
|
||||
|
||||
*todo*
|
||||
_todo_
|
||||
|
Loading…
Reference in New Issue
Block a user