diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 5795bb8405..41df7ae4a4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -157,6 +157,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public Drawable ProxiedLayer => HeadCircle.ApproachCircle; + public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Body.ReceiveMouseInputAt(screenSpacePos); + public override Vector2 SelectionPoint => ToScreenSpace(Body.Position); public override Quad SelectionQuad => Body.PathDrawQuad; } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs index 901d1c568d..89af67ba2a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs @@ -78,6 +78,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces container.Attach(RenderbufferInternalFormat.DepthComponent16); } + public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => path.ReceiveMouseInputAt(screenSpacePos); + public void SetRange(double p0, double p1) { if (p0 > p1) diff --git a/osu.Game.Tests/Visual/TestCaseEditorSelectionLayer.cs b/osu.Game.Tests/Visual/TestCaseEditorSelectionLayer.cs index 755800c4e1..50a39e6c33 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorSelectionLayer.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorSelectionLayer.cs @@ -19,7 +19,12 @@ namespace osu.Game.Tests.Visual { public class TestCaseEditorSelectionLayer : OsuTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(SelectionLayer) }; + public override IReadOnlyList RequiredTypes => new[] + { + typeof(SelectionBox), + typeof(SelectionLayer), + typeof(CaptureBox) + }; [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Rulesets/Edit/Layers/Selection/CaptureBox.cs b/osu.Game/Rulesets/Edit/Layers/Selection/CaptureBox.cs new file mode 100644 index 0000000000..48f6393ccc --- /dev/null +++ b/osu.Game/Rulesets/Edit/Layers/Selection/CaptureBox.cs @@ -0,0 +1,68 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using OpenTK; + +namespace osu.Game.Rulesets.Edit.Layers.Selection +{ + /// + /// A box which encloses s. + /// + public class CaptureBox : VisibilityContainer + { + private readonly IDrawable captureArea; + private readonly IReadOnlyList capturedObjects; + + public CaptureBox(IDrawable captureArea, IReadOnlyList capturedObjects) + { + this.captureArea = captureArea; + this.capturedObjects = capturedObjects; + + Masking = true; + BorderThickness = 3; + + InternalChild = new Box + { + RelativeSizeAxes = Axes.Both, + AlwaysPresent = true, + Alpha = 0 + }; + + State = Visibility.Visible; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BorderColour = colours.Yellow; + + // Move the rectangle to cover the hitobjects + var topLeft = new Vector2(float.MaxValue, float.MaxValue); + var bottomRight = new Vector2(float.MinValue, float.MinValue); + + foreach (var obj in capturedObjects) + { + topLeft = Vector2.ComponentMin(topLeft, captureArea.ToLocalSpace(obj.SelectionQuad.TopLeft)); + bottomRight = Vector2.ComponentMax(bottomRight, captureArea.ToLocalSpace(obj.SelectionQuad.BottomRight)); + } + + topLeft -= new Vector2(5); + bottomRight += new Vector2(5); + + Size = bottomRight - topLeft; + Position = topLeft; + } + + public override bool DisposeOnDeathRemoval => true; + + protected override void PopIn() => this.FadeIn(); + protected override void PopOut() => this.FadeOut(); + } +} diff --git a/osu.Game/Rulesets/Edit/Layers/Selection/Handle.cs b/osu.Game/Rulesets/Edit/Layers/Selection/Handle.cs deleted file mode 100644 index d275022a15..0000000000 --- a/osu.Game/Rulesets/Edit/Layers/Selection/Handle.cs +++ /dev/null @@ -1,105 +0,0 @@ -// 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.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; -using osu.Game.Graphics; -using OpenTK; -using OpenTK.Graphics; - -namespace osu.Game.Rulesets.Edit.Layers.Selection -{ - /// - /// Represents a marker visible on the border of a which exposes - /// properties that are used to resize a . - /// - public class Handle : CompositeDrawable - { - private const float marker_size = 10; - - /// - /// Invoked when this requires the current drag rectangle. - /// - public Func GetDragRectangle; - - /// - /// Invoked when this wants to update the drag rectangle. - /// - public Action UpdateDragRectangle; - - /// - /// Invoked when this has finished updates to the drag rectangle. - /// - public Action FinishDrag; - - private Color4 normalColour; - private Color4 hoverColour; - - public Handle() - { - Size = new Vector2(marker_size); - - InternalChild = new CircularContainer - { - RelativeSizeAxes = Axes.Both, - Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Colour = normalColour = colours.Yellow; - hoverColour = colours.YellowDarker; - } - - protected override bool OnDragStart(InputState state) => true; - - protected override bool OnDrag(InputState state) - { - var currentRectangle = GetDragRectangle(); - - float left = currentRectangle.Left; - float right = currentRectangle.Right; - float top = currentRectangle.Top; - float bottom = currentRectangle.Bottom; - - // Apply modifications to the capture rectangle - if ((Anchor & Anchor.y0) > 0) - top += state.Mouse.Delta.Y; - else if ((Anchor & Anchor.y2) > 0) - bottom += state.Mouse.Delta.Y; - - if ((Anchor & Anchor.x0) > 0) - left += state.Mouse.Delta.X; - else if ((Anchor & Anchor.x2) > 0) - right += state.Mouse.Delta.X; - - UpdateDragRectangle(RectangleF.FromLTRB(left, top, right, bottom)); - return true; - } - - protected override bool OnDragEnd(InputState state) - { - FinishDrag(); - return true; - } - - protected override bool OnHover(InputState state) - { - this.FadeColour(hoverColour, 100); - return true; - } - - protected override void OnHoverLost(InputState state) - { - this.FadeColour(normalColour, 100); - } - } -} diff --git a/osu.Game/Rulesets/Edit/Layers/Selection/HandleContainer.cs b/osu.Game/Rulesets/Edit/Layers/Selection/HandleContainer.cs deleted file mode 100644 index 359cdd009a..0000000000 --- a/osu.Game/Rulesets/Edit/Layers/Selection/HandleContainer.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Linq; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Primitives; - -namespace osu.Game.Rulesets.Edit.Layers.Selection -{ - /// - /// A that has s around its border. - /// - public class HandleContainer : CompositeDrawable - { - /// - /// Invoked when a requires the current drag rectangle. - /// - public Func GetDragRectangle; - - /// - /// Invoked when a wants to update the drag rectangle. - /// - public Action UpdateDragRectangle; - - /// - /// Invoked when a has finished updates to the drag rectangle. - /// - public Action FinishDrag; - - public HandleContainer() - { - InternalChildren = new Drawable[] - { - new Handle - { - Anchor = Anchor.TopLeft, - Origin = Anchor.Centre - }, - new Handle - { - Anchor = Anchor.TopCentre, - Origin = Anchor.Centre - }, - new Handle - { - Anchor = Anchor.TopRight, - Origin = Anchor.Centre - }, - new Handle - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.Centre - }, - new Handle - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.Centre - }, - new Handle - { - Anchor = Anchor.CentreRight, - Origin = Anchor.Centre - }, - new Handle - { - Anchor = Anchor.BottomRight, - Origin = Anchor.Centre - }, - new Handle - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre - }, - new OriginHandle - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre - } - }; - - InternalChildren.OfType().ForEach(m => - { - m.GetDragRectangle = () => GetDragRectangle(); - m.UpdateDragRectangle = r => UpdateDragRectangle(r); - m.FinishDrag = () => FinishDrag(); - }); - } - } -} diff --git a/osu.Game/Rulesets/Edit/Layers/Selection/HitObjectSelectionBox.cs b/osu.Game/Rulesets/Edit/Layers/Selection/HitObjectSelectionBox.cs deleted file mode 100644 index fcb2f8f57f..0000000000 --- a/osu.Game/Rulesets/Edit/Layers/Selection/HitObjectSelectionBox.cs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using osu.Game.Rulesets.Objects.Drawables; -using OpenTK; -using OpenTK.Graphics; -using osu.Framework.Configuration; - -namespace osu.Game.Rulesets.Edit.Layers.Selection -{ - /// - /// A box that represents a drag selection. - /// - public class HitObjectSelectionBox : CompositeDrawable - { - public readonly Bindable Selection = new Bindable(); - - /// - /// The s that can be selected through a drag-selection. - /// - public IEnumerable CapturableObjects; - - private readonly Container borderMask; - private readonly Drawable background; - private readonly HandleContainer handles; - - private Color4 captureFinishedColour; - - private readonly Vector2 startPos; - - /// - /// Creates a new . - /// - /// The point at which the drag was initiated, in the parent's coordinates. - public HitObjectSelectionBox(Vector2 startPos) - { - this.startPos = startPos; - - InternalChildren = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(-1), - Child = borderMask = new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - BorderColour = Color4.White, - BorderThickness = 2, - MaskingSmoothness = 1, - Child = background = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.1f, - AlwaysPresent = true - }, - } - }, - handles = new HandleContainer - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - GetDragRectangle = () => dragRectangle, - UpdateDragRectangle = updateDragRectangle, - FinishDrag = FinishCapture - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - captureFinishedColour = colours.Yellow; - } - - /// - /// The secondary corner of the drag selection box. A rectangle will be fit between the starting position and this value. - /// - public Vector2 DragEndPosition { set => updateDragRectangle(RectangleF.FromLTRB(startPos.X, startPos.Y, value.X, value.Y)); } - - private RectangleF dragRectangle; - private void updateDragRectangle(RectangleF rectangle) - { - dragRectangle = rectangle; - - Position = new Vector2( - Math.Min(rectangle.Left, rectangle.Right), - Math.Min(rectangle.Top, rectangle.Bottom)); - - Size = new Vector2( - Math.Max(rectangle.Left, rectangle.Right) - Position.X, - Math.Max(rectangle.Top, rectangle.Bottom) - Position.Y); - } - - private readonly List capturedHitObjects = new List(); - - /// - /// Processes hitobjects to determine which ones are captured by the drag selection. - /// Captured hitobjects will be enclosed by the drag selection upon . - /// - public void BeginCapture() - { - capturedHitObjects.Clear(); - - foreach (var obj in CapturableObjects) - { - if (!obj.IsAlive || !obj.IsPresent) - continue; - - if (ScreenSpaceDrawQuad.Contains(obj.SelectionPoint)) - capturedHitObjects.Add(obj); - } - } - - /// - /// Encloses hitobjects captured through in the drag selection box. - /// - public void FinishCapture() - { - if (capturedHitObjects.Count == 0) - { - Hide(); - return; - } - - // Move the rectangle to cover the hitobjects - var topLeft = new Vector2(float.MaxValue, float.MaxValue); - var bottomRight = new Vector2(float.MinValue, float.MinValue); - - foreach (var obj in capturedHitObjects) - { - topLeft = Vector2.ComponentMin(topLeft, Parent.ToLocalSpace(obj.SelectionQuad.TopLeft)); - bottomRight = Vector2.ComponentMax(bottomRight, Parent.ToLocalSpace(obj.SelectionQuad.BottomRight)); - } - - topLeft -= new Vector2(5); - bottomRight += new Vector2(5); - - this.MoveTo(topLeft, 200, Easing.OutQuint) - .ResizeTo(bottomRight - topLeft, 200, Easing.OutQuint); - - dragRectangle = RectangleF.FromLTRB(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); - - borderMask.BorderThickness = 3; - borderMask.FadeColour(captureFinishedColour, 200); - - // Transform into markers to let the user modify the drag selection further. - background.Delay(50).FadeOut(200); - handles.FadeIn(200); - - Selection.Value = new SelectionInfo - { - Objects = capturedHitObjects, - SelectionQuad = Parent.ToScreenSpace(dragRectangle) - }; - } - - private bool isActive = true; - public override bool HandleKeyboardInput => isActive; - public override bool HandleMouseInput => isActive; - - public override void Hide() - { - isActive = false; - this.FadeOut(400, Easing.OutQuint).Expire(); - - Selection.Value = null; - } - } -} diff --git a/osu.Game/Rulesets/Edit/Layers/Selection/OriginHandle.cs b/osu.Game/Rulesets/Edit/Layers/Selection/OriginHandle.cs deleted file mode 100644 index 6f8c946165..0000000000 --- a/osu.Game/Rulesets/Edit/Layers/Selection/OriginHandle.cs +++ /dev/null @@ -1,50 +0,0 @@ -// 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.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using OpenTK; - -namespace osu.Game.Rulesets.Edit.Layers.Selection -{ - /// - /// Represents the origin of a . - /// - public class OriginHandle : CompositeDrawable - { - private const float marker_size = 10; - private const float line_width = 2; - - public OriginHandle() - { - Size = new Vector2(marker_size); - - InternalChildren = new[] - { - new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - Height = line_width - }, - new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Y, - Width = line_width - }, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Colour = colours.Yellow; - } - } -} diff --git a/osu.Game/Rulesets/Edit/Layers/Selection/SelectionBox.cs b/osu.Game/Rulesets/Edit/Layers/Selection/SelectionBox.cs new file mode 100644 index 0000000000..8eee15d0b2 --- /dev/null +++ b/osu.Game/Rulesets/Edit/Layers/Selection/SelectionBox.cs @@ -0,0 +1,60 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Shapes; +using OpenTK.Graphics; + +namespace osu.Game.Rulesets.Edit.Layers.Selection +{ + /// + /// A box that represents a drag selection. + /// + public class SelectionBox : VisibilityContainer + { + /// + /// Creates a new . + /// + public SelectionBox() + { + InternalChildren = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(-1), + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + BorderColour = Color4.White, + BorderThickness = 2, + MaskingSmoothness = 1, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.1f, + AlwaysPresent = true + }, + } + } + }; + } + + public void SetDragRectangle(RectangleF rectangle) + { + var topLeft = Parent.ToLocalSpace(rectangle.TopLeft); + var bottomRight = Parent.ToLocalSpace(rectangle.BottomRight); + + Position = topLeft; + Size = bottomRight - topLeft; + } + + public override bool DisposeOnDeathRemoval => true; + + protected override void PopIn() => this.FadeIn(250, Easing.OutQuint); + protected override void PopOut() => this.FadeOut(250, Easing.OutQuint); + } +} diff --git a/osu.Game/Rulesets/Edit/Layers/Selection/SelectionInfo.cs b/osu.Game/Rulesets/Edit/Layers/Selection/SelectionInfo.cs deleted file mode 100644 index beedb415c2..0000000000 --- a/osu.Game/Rulesets/Edit/Layers/Selection/SelectionInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; -using osu.Framework.Graphics.Primitives; -using osu.Game.Rulesets.Objects.Drawables; - -namespace osu.Game.Rulesets.Edit.Layers.Selection -{ - public class SelectionInfo - { - /// - /// The objects that are captured by the selection. - /// - public IEnumerable Objects; - - /// - /// The screen space quad of the selection box surrounding . - /// - public Quad SelectionQuad; - } -} diff --git a/osu.Game/Rulesets/Edit/Layers/Selection/SelectionLayer.cs b/osu.Game/Rulesets/Edit/Layers/Selection/SelectionLayer.cs index 93755d400a..bda613f617 100644 --- a/osu.Game/Rulesets/Edit/Layers/Selection/SelectionLayer.cs +++ b/osu.Game/Rulesets/Edit/Layers/Selection/SelectionLayer.cs @@ -1,18 +1,20 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Configuration; +using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; using osu.Framework.Input; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; +using OpenTK; namespace osu.Game.Rulesets.Edit.Layers.Selection { public class SelectionLayer : CompositeDrawable { - public readonly Bindable Selection = new Bindable(); - private readonly Playfield playfield; public SelectionLayer(Playfield playfield) @@ -22,40 +24,95 @@ namespace osu.Game.Rulesets.Edit.Layers.Selection RelativeSizeAxes = Axes.Both; } - private HitObjectSelectionBox selectionBoxBox; + private SelectionBox selectionBox; + private CaptureBox captureBox; + + private readonly List selectedHitObjects = new List(); + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + clearSelection(); + return true; + } protected override bool OnDragStart(InputState state) { - // Hide the previous drag box - we won't be working with it any longer - selectionBoxBox?.Hide(); - - AddInternal(selectionBoxBox = new HitObjectSelectionBox(ToLocalSpace(state.Mouse.NativeState.Position)) - { - CapturableObjects = playfield.HitObjects.Objects, - }); - - Selection.BindTo(selectionBoxBox.Selection); - + AddInternal(selectionBox = new SelectionBox()); return true; } protected override bool OnDrag(InputState state) { - selectionBoxBox.DragEndPosition = ToLocalSpace(state.Mouse.NativeState.Position); - selectionBoxBox.BeginCapture(); + selectionBox.Show(); + + var dragPosition = state.Mouse.NativeState.Position; + var dragStartPosition = state.Mouse.NativeState.PositionMouseDown ?? dragPosition; + + var screenSpaceDragQuad = new Quad(dragStartPosition.X, dragStartPosition.Y, dragPosition.X - dragStartPosition.X, dragPosition.Y - dragStartPosition.Y); + + selectionBox.SetDragRectangle(screenSpaceDragQuad.AABBFloat); + selectQuad(screenSpaceDragQuad); + return true; } protected override bool OnDragEnd(InputState state) { - selectionBoxBox.FinishCapture(); + selectionBox.Hide(); + selectionBox.Expire(); + + finishSelection(); + return true; } protected override bool OnClick(InputState state) { - selectionBoxBox?.Hide(); + selectPoint(state.Mouse.NativeState.Position); + finishSelection(); + return true; } + + /// + /// Deselects all selected s. + /// + private void clearSelection() + { + selectedHitObjects.Clear(); + captureBox?.Hide(); + captureBox?.Expire(); + } + + /// + /// Selects all hitobjects that are present within the area of a . + /// + /// The selection . + private void selectQuad(Quad screenSpaceQuad) + { + foreach (var obj in playfield.HitObjects.Objects.Where(h => h.IsAlive && h.IsPresent && screenSpaceQuad.Contains(h.SelectionPoint))) + selectedHitObjects.Add(obj); + } + + /// + /// Selects the top-most hitobject that is present under a specific point. + /// + /// The to select at. + private void selectPoint(Vector2 screenSpacePoint) + { + var selected = playfield.HitObjects.Objects.Reverse().Where(h => h.IsAlive && h.IsPresent).FirstOrDefault(h => h.ReceiveMouseInputAt(screenSpacePoint)); + if (selected == null) + return; + + selectedHitObjects.Add(selected); + } + + private void finishSelection() + { + if (selectedHitObjects.Count == 0) + return; + + AddInternal(captureBox = new CaptureBox(this, selectedHitObjects.ToList())); + } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7e440dacf8..70c904e8b9 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -346,6 +346,7 @@ + @@ -366,11 +367,7 @@ - - - - - +