1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-15 14:23:02 +08:00

Implement mask layering (incomplete)

This commit is contained in:
AlFasGD 2018-05-20 13:22:42 +03:00
parent 9b307f0e12
commit d504a44dfb
20 changed files with 426 additions and 47 deletions

View File

@ -0,0 +1,50 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays
{
public class HoldNoteMask : HitObjectMask
{
private readonly BodyPiece body;
private readonly DrawableHoldNote holdNote;
public HoldNoteMask(DrawableHoldNote hold)
: base(hold)
{
holdNote = hold;
Position = hold.Position;
var holdObject = hold.HitObject;
InternalChildren = new Drawable[]
{
new NoteMask(hold.Head),
new NoteMask(hold.Tail),
body = new BodyPiece()
{
AccentColour = Color4.Transparent
},
};
holdObject.ColumnChanged += _ => Position = hold.Position;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
body.BorderColour = colours.Yellow;
}
}
}

View File

@ -0,0 +1,29 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Screens.Edit.Screens.Compose.Layers;
namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays
{
public class ManiaHitObjectColumnMaskLayer : HitObjectMaskLayer
{
public readonly Column Column;
public ManiaHitObjectColumnMaskLayer(ManiaEditPlayfield playfield, HitObjectComposer composer, Column column)
: base(playfield, composer)
{
Column = column;
}
public void CreateMasks() => AddMasks();
protected override void AddMasks()
{
foreach (var obj in Column.HitObjects.Objects)
AddMask(obj);
}
}
}

View File

@ -0,0 +1,28 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit.Screens.Compose.Layers;
using System.Collections.Generic;
namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays
{
public class ManiaHitObjectMaskLayer : HitObjectMaskLayer
{
public readonly List<ManiaHitObjectStageMaskLayer> Stages;
public ManiaHitObjectMaskLayer(ManiaEditPlayfield playfield, HitObjectComposer composer)
: base(playfield, composer)
{
Stages = new List<ManiaHitObjectStageMaskLayer>();
foreach (var s in ((ManiaEditPlayfield)Playfield).Stages)
Stages.Add(new ManiaHitObjectStageMaskLayer((ManiaEditPlayfield)Playfield, Composer, s));
}
protected override void AddMasks()
{
foreach (var s in Stages)
s.CreateMasks();
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Screens.Edit.Screens.Compose.Layers;
using System.Collections.Generic;
namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays
{
public class ManiaHitObjectStageMaskLayer : HitObjectMaskLayer
{
public readonly List<ManiaHitObjectColumnMaskLayer> Columns;
public ManiaHitObjectStageMaskLayer(ManiaEditPlayfield playfield, HitObjectComposer composer, ManiaStage s)
: base(playfield, composer)
{
Columns = new List<ManiaHitObjectColumnMaskLayer>();
foreach (var c in s.Columns)
Columns.Add(new ManiaHitObjectColumnMaskLayer((ManiaEditPlayfield)Playfield, Composer, c));
}
public void CreateMasks() => AddMasks();
protected override void AddMasks()
{
foreach (var c in Columns)
c.CreateMasks();
}
}
}

View File

@ -0,0 +1,35 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays
{
public class NoteMask : HitObjectMask
{
public NoteMask(DrawableNote note)
: base(note)
{
Origin = Anchor.Centre;
Position = note.Position;
Size = note.Size;
Scale = note.Scale;
AddInternal(new NotePiece());
note.HitObject.ColumnChanged += _ => Position = note.Position;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.Yellow;
}
}
}

View File

@ -0,0 +1,58 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Edit.Screens.Compose;
using osu.Game.Screens.Edit.Screens.Compose.Layers;
using System.Collections.Generic;
namespace osu.Game.Rulesets.Mania.Edit
{
public class ManiaHitObjectComposer : HitObjectComposer
{
public BindableBeatDivisor BeatDivisor;
public ManiaHitObjectComposer(Ruleset ruleset, BindableBeatDivisor beatDivisor)
: base(ruleset)
{
BeatDivisor = beatDivisor;
}
protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new ManiaEditRulesetContainer(ruleset, beatmap, BeatDivisor);
protected override IReadOnlyList<ICompositionTool> CompositionTools => new ICompositionTool[]
{
new HitObjectCompositionTool<Note>("Note"),
new HitObjectCompositionTool<HoldNote>("Hold"),
};
// TODO: According to another proposal, extend this to support multiple layers for mania maps
// The logic could be moving all the layers that the beatmap has simultaneously
// To avoid using too many resources, this could be changed to simply changing the Alpha to something
// between 0.25f to 0.5f for notes that are in other layers (and may be also not selected)
// Will also need a tool to navigate through layers
// Please ignore the comment above, I just wanted to write my thoughts down so that I do not forget in 2 months when I get around to it
public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject)
{
switch (hitObject)
{
case DrawableNote note:
return new NoteMask(note);
case DrawableHoldNote holdNote:
return new HoldNoteMask(holdNote);
}
return base.CreateMaskFor(hitObject);
}
protected override HitObjectMaskLayer CreateHitObjectMaskLayer() => new ManiaHitObjectMaskLayer((ManiaEditPlayfield)RulesetContainer.Playfield, this);
}
}

View File

@ -18,8 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary>
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
{
private readonly DrawableNote head;
private readonly DrawableNote tail;
public readonly DrawableNote Head;
public readonly DrawableNote Tail;
private readonly GlowPiece glowPiece;
private readonly BodyPiece bodyPiece;
@ -64,12 +64,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
HoldStartTime = () => holdStartTime
})
},
head = new DrawableHeadNote(this, action)
Head = new DrawableHeadNote(this, action)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre
},
tail = new DrawableTailNote(this, action)
Tail = new DrawableTailNote(this, action)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre
@ -79,8 +79,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
foreach (var tick in tickContainer)
AddNested(tick);
AddNested(head);
AddNested(tail);
AddNested(Head);
AddNested(Tail);
}
public override Color4 AccentColour
@ -92,8 +92,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
glowPiece.AccentColour = value;
bodyPiece.AccentColour = value;
head.AccentColour = value;
tail.AccentColour = value;
Head.AccentColour = value;
Tail.AccentColour = value;
}
}
@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (tail.AllJudged)
if (Tail.AllJudged)
AddJudgement(new HoldNoteJudgement { Result = HitResult.Perfect });
}
@ -119,12 +119,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
base.Update();
// Make the body piece not lie under the head note
bodyPiece.Y = head.Height;
bodyPiece.Height = DrawHeight - head.Height;
bodyPiece.Y = Head.Height;
bodyPiece.Height = DrawHeight - Head.Height;
// Make the fullHeightContainer "contain" the height of the tail note, keeping in mind
// that the tail note overshoots the height of this hit object
fullHeightContainer.Height = DrawHeight + tail.Height;
fullHeightContainer.Height = DrawHeight + Tail.Height;
}
public bool OnPressed(ManiaAction action)
@ -156,7 +156,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
holdStartTime = null;
// If the key has been released too early, the user should not receive full score for the release
if (!tail.IsHit)
if (!Tail.IsHit)
hasBroken = true;
return true;

View File

@ -1,14 +1,42 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mania.Objects.Types;
using osu.Game.Rulesets.Edit.Types;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using System;
namespace osu.Game.Rulesets.Mania.Objects
{
public abstract class ManiaHitObject : HitObject, IHasColumn
public abstract class ManiaHitObject : HitObject, IHasColumn, IHasLayer, IHasXPosition, IHasEditableColumn, IHasEditableLayer
{
public virtual int Column { get; set; }
public event Action<int> ColumnChanged;
private int column { get; set; }
public virtual int Column
{
get => column;
set
{
if (column == value)
return;
column = value;
ColumnChanged?.Invoke(value);
}
}
public virtual int Layer { get; set; }
public virtual float X
{
get => Column;
}
public virtual void OffsetColumn(int offset) => Column += offset;
public virtual void OffsetLayer(int offset) => Layer += offset;
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
}

View File

@ -1,19 +1,19 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Mania.UI
{
@ -25,7 +25,11 @@ namespace osu.Game.Rulesets.Mania.UI
public readonly Bindable<bool> Inverted = new Bindable<bool>(true);
public List<Column> Columns => stages.SelectMany(x => x.Columns).ToList();
private readonly List<ManiaStage> stages = new List<ManiaStage>();
public IReadOnlyList<ManiaStage> Stages => stages;
protected virtual bool DisplayJudgements => true;
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
: base(ScrollingDirection.Up)
@ -50,7 +54,8 @@ namespace osu.Game.Rulesets.Mania.UI
int firstColumnIndex = 0;
for (int i = 0; i < stageDefinitions.Count; i++)
{
var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
var newStage = CreateStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
newStage.DisplayJudgements = DisplayJudgements;
newStage.VisibleTimeRange.BindTo(VisibleTimeRange);
newStage.Inverted.BindTo(Inverted);
@ -63,7 +68,11 @@ namespace osu.Game.Rulesets.Mania.UI
}
}
public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
public override void Add(DrawableHitObject h)
{
h.OnJudgement += OnJudgement;
getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
}
public void Add(BarLine barline) => stages.ForEach(s => s.Add(barline));
@ -88,7 +97,13 @@ namespace osu.Game.Rulesets.Mania.UI
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
if (!judgedObject.DisplayJudgement || !DisplayJudgements)
return;
getStageByColumn(((ManiaHitObject)judgedObject.HitObject).Column).OnJudgement(judgedObject, judgement);
}
protected virtual ManiaStage CreateStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
=> new ManiaStage(firstColumnIndex, definition, ref normalColumnStartAction, ref specialColumnStartAction);
}
}

View File

@ -10,4 +10,7 @@
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Objects\Types\" />
</ItemGroup>
</Project>

View File

@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Edit
protected ICompositionTool CurrentTool { get; private set; }
private RulesetContainer rulesetContainer;
protected RulesetContainer RulesetContainer;
private readonly List<Container> layerContainers = new List<Container>();
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
@ -44,8 +44,8 @@ namespace osu.Game.Rulesets.Edit
try
{
rulesetContainer = CreateRulesetContainer(ruleset, beatmap.Value);
rulesetContainer.Clock = framedClock;
RulesetContainer = CreateRulesetContainer(ruleset, beatmap.Value);
RulesetContainer.Clock = framedClock;
}
catch (Exception e)
{
@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Edit
};
var layerAboveRuleset = CreateLayerContainer();
layerAboveRuleset.Child = new HitObjectMaskLayer(rulesetContainer.Playfield, this);
layerAboveRuleset.Child = CreateHitObjectMaskLayer();
layerContainers.Add(layerBelowRuleset);
layerContainers.Add(layerAboveRuleset);
@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Edit
Children = new Drawable[]
{
layerBelowRuleset,
rulesetContainer,
RulesetContainer,
layerAboveRuleset
}
}
@ -116,13 +116,14 @@ namespace osu.Game.Rulesets.Edit
layerContainers.ForEach(l =>
{
l.Anchor = rulesetContainer.Playfield.Anchor;
l.Origin = rulesetContainer.Playfield.Origin;
l.Position = rulesetContainer.Playfield.Position;
l.Size = rulesetContainer.Playfield.Size;
l.Anchor = RulesetContainer.Playfield.Anchor;
l.Origin = RulesetContainer.Playfield.Origin;
l.Position = RulesetContainer.Playfield.Position;
l.Size = RulesetContainer.Playfield.Size;
});
}
private void setCompositionTool(ICompositionTool tool) => CurrentTool = tool;
protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap);
@ -141,6 +142,11 @@ namespace osu.Game.Rulesets.Edit
/// </summary>
public virtual MaskSelection CreateMaskSelection() => new MaskSelection();
/// <summary>
/// Creates a <see cref="HitObjectMaskLayer"/> depending on the ruleset.
/// </summary>
protected virtual HitObjectMaskLayer CreateHitObjectMaskLayer() => new HitObjectMaskLayer(RulesetContainer.Playfield, this);
/// <summary>
/// Creates a <see cref="ScalableContainer"/> which provides a layer above or below the <see cref="Playfield"/>.
/// </summary>

View File

@ -33,11 +33,21 @@ namespace osu.Game.Rulesets.Edit
/// </summary>
public event Action<HitObjectMask, InputState> SelectionRequested;
/// <summary>
/// Invoked when this <see cref="HitObjectMask"/> has started drag.
/// </summary>
public event Action<HitObjectMask, InputState> DragStarted;
/// <summary>
/// Invoked when this <see cref="HitObjectMask"/> has requested drag.
/// </summary>
public event Action<HitObjectMask, InputState> DragRequested;
/// <summary>
/// Invoked when this <see cref="HitObjectMask"/> has ended drag.
/// </summary>
public event Action<HitObjectMask, InputState> DragEnded;
/// <summary>
/// The <see cref="DrawableHitObject"/> which this <see cref="HitObjectMask"/> applies to.
/// </summary>
@ -120,7 +130,11 @@ namespace osu.Game.Rulesets.Edit
return base.OnClick(state);
}
protected override bool OnDragStart(InputState state) => true;
protected override bool OnDragStart(InputState state)
{
DragStarted?.Invoke(this, state);
return true;
}
protected override bool OnDrag(InputState state)
{
@ -128,6 +142,12 @@ namespace osu.Game.Rulesets.Edit
return true;
}
protected override bool OnDragEnd(InputState state)
{
DragEnded?.Invoke(this, state);
return true;
}
/// <summary>
/// The screen-space point that causes this <see cref="HitObjectMask"/> to be selected.
/// </summary>

View File

@ -1,6 +1,8 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Input;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Edit.Tools
@ -8,6 +10,18 @@ namespace osu.Game.Rulesets.Edit.Tools
public class HitObjectCompositionTool<T> : ICompositionTool
where T : HitObject
{
public string Name => typeof(T).Name;
public string Name { get; } = typeof(T).Name;
public Action<InputState, MouseDownEventArgs, bool> OnMouseDown { get; }
public Action<InputState, MouseDownEventArgs, bool> OnMouseUp { get; }
public HitObjectCompositionTool()
{
}
public HitObjectCompositionTool(string name)
{
Name = name;
}
}
}

View File

@ -1,10 +1,16 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input;
using System;
namespace osu.Game.Rulesets.Edit.Tools
{
public interface ICompositionTool
{
string Name { get; }
Action<InputState, MouseDownEventArgs, bool> OnMouseDown { get; }
Action<InputState, MouseDownEventArgs, bool> OnMouseUp { get; }
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Edit.Types
{
public interface IHasEditableColumn : IHasColumn
{
void OffsetColumn(int offset);
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Edit.Types
{
public interface IHasEditableLayer : IHasLayer
{
void OffsetLayer(int offset);
}
}

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Mania.Objects.Types
namespace osu.Game.Rulesets.Objects.Types
{
/// <summary>
/// A type of hit object which lies in one of a number of predetermined columns.

View File

@ -14,17 +14,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
{
public class HitObjectMaskLayer : CompositeDrawable
{
private readonly Playfield playfield;
private readonly HitObjectComposer composer;
protected readonly Playfield Playfield;
protected readonly HitObjectComposer Composer;
private MaskContainer maskContainer;
public HitObjectMaskLayer(Playfield playfield, HitObjectComposer composer)
{
// we need the playfield as HitObjects may not be initialised until its BDL.
this.playfield = playfield;
this.Playfield = playfield;
this.composer = composer;
this.Composer = composer;
RelativeSizeAxes = Axes.Both;
}
@ -34,12 +34,14 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
{
maskContainer = new MaskContainer();
var maskSelection = composer.CreateMaskSelection();
var maskSelection = Composer.CreateMaskSelection();
maskContainer.MaskSelected += maskSelection.HandleSelected;
maskContainer.MaskDeselected += maskSelection.HandleDeselected;
maskContainer.MaskSelectionRequested += maskSelection.HandleSelectionRequested;
maskContainer.MaskDragStarted += maskSelection.HandleDragStart;
maskContainer.MaskDragRequested += maskSelection.HandleDrag;
maskContainer.MaskDragEnded += maskSelection.HandleDragEnd;
maskSelection.DeselectAll = maskContainer.DeselectAll;
@ -53,9 +55,13 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
maskContainer,
dragLayer.CreateProxy()
};
AddMasks();
}
foreach (var obj in playfield.HitObjects.Objects)
addMask(obj);
protected virtual void AddMasks()
{
foreach (var obj in Playfield.HitObjects.Objects)
AddMask(obj);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
@ -68,9 +74,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
/// Adds a mask for a <see cref="DrawableHitObject"/> which adds movement support.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to create a mask for.</param>
private void addMask(DrawableHitObject hitObject)
protected void AddMask(DrawableHitObject hitObject)
{
var mask = composer.CreateMaskFor(hitObject);
var mask = Composer.CreateMaskFor(hitObject);
if (mask == null)
return;

View File

@ -29,11 +29,21 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
/// </summary>
public event Action<HitObjectMask, InputState> MaskSelectionRequested;
/// <summary>
/// Invoked when any <see cref="HitObjectMask"/> starts drag.
/// </summary>
public event Action<HitObjectMask, InputState> MaskDragStarted;
/// <summary>
/// Invoked when any <see cref="HitObjectMask"/> requests drag.
/// </summary>
public event Action<HitObjectMask, InputState> MaskDragRequested;
/// <summary>
/// Invoked when any <see cref="HitObjectMask"/> ends drag.
/// </summary>
public event Action<HitObjectMask, InputState> MaskDragEnded;
private IEnumerable<HitObjectMask> aliveMasks => AliveInternalChildren.Cast<HitObjectMask>();
public MaskContainer()
@ -50,7 +60,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
drawable.Selected += onMaskSelected;
drawable.Deselected += onMaskDeselected;
drawable.SelectionRequested += onSelectionRequested;
drawable.DragStarted += onDragStarted;
drawable.DragRequested += onDragRequested;
drawable.DragEnded += onDragEnded;
}
public override bool Remove(HitObjectMask drawable)
@ -64,7 +76,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
drawable.Selected -= onMaskSelected;
drawable.Deselected -= onMaskDeselected;
drawable.SelectionRequested -= onSelectionRequested;
drawable.DragStarted -= onDragStarted;
drawable.DragRequested -= onDragRequested;
drawable.DragEnded -= onDragEnded;
}
return result;
@ -103,7 +117,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
}
private void onSelectionRequested(HitObjectMask mask, InputState state) => MaskSelectionRequested?.Invoke(mask, state);
private void onDragStarted(HitObjectMask mask, InputState state) => MaskDragStarted?.Invoke(mask, state);
private void onDragRequested(HitObjectMask mask, InputState state) => MaskDragRequested?.Invoke(mask, state);
private void onDragEnded(HitObjectMask mask, InputState state) => MaskDragEnded?.Invoke(mask, state);
protected override int Compare(Drawable x, Drawable y)
{

View File

@ -25,6 +25,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
private readonly List<HitObjectMask> selectedMasks;
private Drawable outline;
private Vector2 startingPosition;
public MaskSelection()
{
@ -54,6 +55,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
#region User Input Handling
public void HandleDragStart(HitObjectMask m, InputState state) => startingPosition = state.Mouse.Position;
public void HandleDrag(HitObjectMask m, InputState state)
{
// Todo: Various forms of snapping
@ -65,9 +67,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
case IHasEditablePosition editablePosition:
editablePosition.OffsetPosition(state.Mouse.Delta);
break;
case IHasEditableColumn editableColumn:
if (IsDragged)
editableColumn.OffsetColumn((int)((startingPosition.X - state.Mouse.Position.X) / m.Width)); // Perform snapping, needs fixing
break;
}
}
}
public void HandleDragEnd(HitObjectMask m, InputState state)
{
}
#endregion