diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs new file mode 100644 index 0000000000..3106fedb30 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/HoldNoteMask.cs @@ -0,0 +1,50 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// 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; + } + } +} diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/ManiaHitObjectColumnMaskLayer.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/ManiaHitObjectColumnMaskLayer.cs new file mode 100644 index 0000000000..1f8d391c99 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/ManiaHitObjectColumnMaskLayer.cs @@ -0,0 +1,29 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// 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); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/ManiaHitObjectMaskLayer.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/ManiaHitObjectMaskLayer.cs new file mode 100644 index 0000000000..012fc495b5 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/ManiaHitObjectMaskLayer.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// 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 Stages; + + public ManiaHitObjectMaskLayer(ManiaEditPlayfield playfield, HitObjectComposer composer) + : base(playfield, composer) + { + Stages = new List(); + 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(); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/ManiaHitObjectStageMaskLayer.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/ManiaHitObjectStageMaskLayer.cs new file mode 100644 index 0000000000..ae800019c5 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/ManiaHitObjectStageMaskLayer.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// 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 Columns; + + public ManiaHitObjectStageMaskLayer(ManiaEditPlayfield playfield, HitObjectComposer composer, ManiaStage s) + : base(playfield, composer) + { + Columns = new List(); + 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(); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteMask.cs b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteMask.cs new file mode 100644 index 0000000000..8228adf35f --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Layers/Selection/Overlays/NoteMask.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// 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; + } + } +} diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs new file mode 100644 index 0000000000..3a2c398e84 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -0,0 +1,58 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// 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 CompositionTools => new ICompositionTool[] + { + new HitObjectCompositionTool("Note"), + new HitObjectCompositionTool("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); + } +} diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 8791e8ed86..2f2d1abe6b 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -18,8 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// public class DrawableHoldNote : DrawableManiaHitObject, IKeyBindingHandler { - 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; diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs index e183098a51..8b7191c4c4 100644 --- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs @@ -1,14 +1,42 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // 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 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(); } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 4b936fc7f9..ae931e2f66 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -1,19 +1,19 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // 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 Inverted = new Bindable(true); public List Columns => stages.SelectMany(x => x.Columns).ToList(); + private readonly List stages = new List(); + public IReadOnlyList Stages => stages; + + protected virtual bool DisplayJudgements => true; public ManiaPlayfield(List 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); } } diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index a086da0565..1d95dbf004 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -10,4 +10,7 @@ + + + \ No newline at end of file diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 5f1b9a6bad..545c152bbd 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Edit protected ICompositionTool CurrentTool { get; private set; } - private RulesetContainer rulesetContainer; + protected RulesetContainer RulesetContainer; private readonly List layerContainers = new List(); private readonly Bindable beatmap = new Bindable(); @@ -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 /// public virtual MaskSelection CreateMaskSelection() => new MaskSelection(); + /// + /// Creates a depending on the ruleset. + /// + protected virtual HitObjectMaskLayer CreateHitObjectMaskLayer() => new HitObjectMaskLayer(RulesetContainer.Playfield, this); + /// /// Creates a which provides a layer above or below the . /// diff --git a/osu.Game/Rulesets/Edit/HitObjectMask.cs b/osu.Game/Rulesets/Edit/HitObjectMask.cs index 61fb700dd3..3caa4d9fbf 100644 --- a/osu.Game/Rulesets/Edit/HitObjectMask.cs +++ b/osu.Game/Rulesets/Edit/HitObjectMask.cs @@ -33,11 +33,21 @@ namespace osu.Game.Rulesets.Edit /// public event Action SelectionRequested; + /// + /// Invoked when this has started drag. + /// + public event Action DragStarted; + /// /// Invoked when this has requested drag. /// public event Action DragRequested; + /// + /// Invoked when this has ended drag. + /// + public event Action DragEnded; + /// /// The which this applies to. /// @@ -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; + } + /// /// The screen-space point that causes this to be selected. /// diff --git a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs index 2c3720fc8f..9c3f99127d 100644 --- a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs +++ b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // 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 : ICompositionTool where T : HitObject { - public string Name => typeof(T).Name; + public string Name { get; } = typeof(T).Name; + + public Action OnMouseDown { get; } + public Action OnMouseUp { get; } + + public HitObjectCompositionTool() + { + } + + public HitObjectCompositionTool(string name) + { + Name = name; + } } } diff --git a/osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs index ce8b139b43..456c7e6fb3 100644 --- a/osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs +++ b/osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs @@ -1,10 +1,16 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // 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 OnMouseDown { get; } + Action OnMouseUp { get; } } } diff --git a/osu.Game/Rulesets/Edit/Types/IHasEditableColumn.cs b/osu.Game/Rulesets/Edit/Types/IHasEditableColumn.cs new file mode 100644 index 0000000000..2691223476 --- /dev/null +++ b/osu.Game/Rulesets/Edit/Types/IHasEditableColumn.cs @@ -0,0 +1,12 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// 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); + } +} diff --git a/osu.Game/Rulesets/Edit/Types/IHasEditableLayer.cs b/osu.Game/Rulesets/Edit/Types/IHasEditableLayer.cs new file mode 100644 index 0000000000..3c886caba8 --- /dev/null +++ b/osu.Game/Rulesets/Edit/Types/IHasEditableLayer.cs @@ -0,0 +1,12 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// 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); + } +} diff --git a/osu.Game.Rulesets.Mania/Objects/Types/IHasColumn.cs b/osu.Game/Rulesets/Objects/Types/IHasColumn.cs similarity index 90% rename from osu.Game.Rulesets.Mania/Objects/Types/IHasColumn.cs rename to osu.Game/Rulesets/Objects/Types/IHasColumn.cs index 44a79de7db..ba9c7ac933 100644 --- a/osu.Game.Rulesets.Mania/Objects/Types/IHasColumn.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasColumn.cs @@ -1,7 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // 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 { /// /// A type of hit object which lies in one of a number of predetermined columns. diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs index b9a8e9914a..5339be7d57 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs @@ -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 which adds movement support. /// /// The to create a mask for. - private void addMask(DrawableHitObject hitObject) + protected void AddMask(DrawableHitObject hitObject) { - var mask = composer.CreateMaskFor(hitObject); + var mask = Composer.CreateMaskFor(hitObject); if (mask == null) return; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs index df2691c28e..bce6d876be 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs @@ -29,11 +29,21 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// public event Action MaskSelectionRequested; + /// + /// Invoked when any starts drag. + /// + public event Action MaskDragStarted; + /// /// Invoked when any requests drag. /// public event Action MaskDragRequested; + /// + /// Invoked when any ends drag. + /// + public event Action MaskDragEnded; + private IEnumerable aliveMasks => AliveInternalChildren.Cast(); 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) { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs index 54697bad77..7cd77eeb1c 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers private readonly List 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