Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
265 changes: 142 additions & 123 deletions osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public bool CanReverse
if (canReverse == value) return;

canReverse = value;
recreate();
recreateButtons();
}
}

Expand All @@ -78,7 +78,7 @@ public bool CanFlipX
if (canFlipX == value) return;

canFlipX = value;
recreate();
recreateButtons();
}
}

Expand All @@ -95,7 +95,7 @@ public bool CanFlipY
if (canFlipY == value) return;

canFlipY = value;
recreate();
recreateButtons();
}
}

Expand All @@ -116,7 +116,7 @@ public string Text
}

private SelectionBoxDragHandleContainer dragHandles = null!;
private FillFlowContainer buttons = null!;
private FillFlowContainer<SelectionBoxButton> buttons = null!;

private OsuSpriteText? selectionDetailsText;

Expand All @@ -126,6 +126,60 @@ public string Text
[BackgroundDependencyLoader]
private void load()
{
InternalChildren = new Drawable[]
{
new Container
{
Name = "info text",
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
Colour = colours.YellowDark,
RelativeSizeAxes = Axes.Both,
},
selectionDetailsText = new OsuSpriteText
{
Padding = new MarginPadding(2),
Colour = colours.Gray0,
Font = OsuFont.Default.With(size: 11),
Text = text,
}
}
},
new Container
{
Masking = true,
BorderThickness = BORDER_RADIUS,
BorderColour = colours.YellowDark,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,

AlwaysPresent = true,
Alpha = 0
},
}
},
dragHandles = new SelectionBoxDragHandleContainer
{
RelativeSizeAxes = Axes.Both,
// ensures that the centres of all drag handles line up with the middle of the selection box border.
Padding = new MarginPadding(BORDER_RADIUS / 2)
},
buttons = new FillFlowContainer<SelectionBoxButton>
{
AutoSizeAxes = Axes.X,
Height = 30,
Direction = FillDirection.Horizontal,
Margin = new MarginPadding(button_padding),
}
};

if (rotationHandler != null)
canRotate.BindTo(rotationHandler.CanRotateAroundSelectionOrigin);

Expand All @@ -136,10 +190,14 @@ private void load()
canScaleDiagonally.BindTo(scaleHandler.CanScaleDiagonally);
}

canRotate.BindValueChanged(_ => recreate());
canScaleX.BindValueChanged(_ => recreate());
canScaleY.BindValueChanged(_ => recreate());
canScaleDiagonally.BindValueChanged(_ => recreate(), true);
canScaleX.BindValueChanged(_ => recreateScaleHandles());
canScaleY.BindValueChanged(_ => recreateScaleHandles());
canScaleDiagonally.BindValueChanged(_ => recreateScaleHandles(), true);
canRotate.BindValueChanged(_ =>
{
recreateRotationHandles();
recreateButtons();
}, true);
}

protected override bool OnKeyDown(KeyDownEvent e)
Expand Down Expand Up @@ -181,113 +239,92 @@ protected override void Update()
ensureButtonsOnScreen();
}

private void recreate()
private void recreateScaleHandles()
{
if (LoadState < LoadState.Loading)
return;

InternalChildren = new Drawable[]
dragHandles.ClearScaleHandles();

if (canScaleY.Value)
{
new Container
{
Name = "info text",
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
Colour = colours.YellowDark,
RelativeSizeAxes = Axes.Both,
},
selectionDetailsText = new OsuSpriteText
{
Padding = new MarginPadding(2),
Colour = colours.Gray0,
Font = OsuFont.Default.With(size: 11),
Text = text,
}
}
},
new Container
{
Masking = true,
BorderThickness = BORDER_RADIUS,
BorderColour = colours.YellowDark,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
addScaleHandle(Anchor.TopCentre);
addScaleHandle(Anchor.BottomCentre);
}

AlwaysPresent = true,
Alpha = 0
},
}
},
dragHandles = new SelectionBoxDragHandleContainer
{
RelativeSizeAxes = Axes.Both,
// ensures that the centres of all drag handles line up with the middle of the selection box border.
Padding = new MarginPadding(BORDER_RADIUS / 2)
},
buttons = new FillFlowContainer
{
AutoSizeAxes = Axes.X,
Height = 30,
Direction = FillDirection.Horizontal,
Margin = new MarginPadding(button_padding),
}
if (canScaleDiagonally.Value)
{
addScaleHandle(Anchor.TopLeft);
addScaleHandle(Anchor.TopRight);
addScaleHandle(Anchor.BottomLeft);
addScaleHandle(Anchor.BottomRight);
}

if (canScaleX.Value)
{
addScaleHandle(Anchor.CentreLeft);
addScaleHandle(Anchor.CentreRight);
}
}

private void addScaleHandle(Anchor anchor)
{
var handle = new SelectionBoxScaleHandle
{
Anchor = anchor,
};

if (canScaleX.Value) addXScaleComponents();
if (canScaleDiagonally.Value) addFullScaleComponents();
if (canScaleY.Value) addYScaleComponents();
if (CanFlipX) addXFlipComponents();
if (CanFlipY) addYFlipComponents();
if (canRotate.Value) addRotationComponents();
if (CanReverse) reverseButton = addButton(FontAwesome.Solid.Backward, "Reverse pattern (Ctrl-G)", () => OnReverse?.Invoke());
handle.OperationStarted += operationStarted;
handle.OperationEnded += operationEnded;
dragHandles.AddScaleHandle(handle);
}

private void addRotationComponents()
private void recreateRotationHandles()
{
rotateCounterClockwiseButton = addButton(FontAwesome.Solid.Undo, "Rotate 90 degrees counter-clockwise (Ctrl-<)", () => rotationHandler?.Rotate(-90));
rotateClockwiseButton = addButton(FontAwesome.Solid.Redo, "Rotate 90 degrees clockwise (Ctrl->)", () => rotationHandler?.Rotate(90));
if (LoadState < LoadState.Loading)
return;

dragHandles.ClearRotationHandles();

addRotateHandle(Anchor.TopLeft);
addRotateHandle(Anchor.TopRight);
addRotateHandle(Anchor.BottomLeft);
addRotateHandle(Anchor.BottomRight);
}

private void addYScaleComponents()
private void addRotateHandle(Anchor anchor)
{
addScaleHandle(Anchor.TopCentre);
addScaleHandle(Anchor.BottomCentre);
}
var handle = new SelectionBoxRotationHandle
{
Anchor = anchor,
};

private void addFullScaleComponents()
{
addScaleHandle(Anchor.TopLeft);
addScaleHandle(Anchor.TopRight);
addScaleHandle(Anchor.BottomLeft);
addScaleHandle(Anchor.BottomRight);
handle.OperationStarted += operationStarted;
handle.OperationEnded += operationEnded;
dragHandles.AddRotationHandle(handle);
}

private void addXScaleComponents()
private void recreateButtons()
{
addScaleHandle(Anchor.CentreLeft);
addScaleHandle(Anchor.CentreRight);
}
if (LoadState < LoadState.Loading)
return;

private void addXFlipComponents()
{
addButton(FontAwesome.Solid.ArrowsAltH, "Flip horizontally", () => OnFlip?.Invoke(Direction.Horizontal, false));
}
clearButtons();

private void addYFlipComponents()
{
addButton(FontAwesome.Solid.ArrowsAltV, "Flip vertically", () => OnFlip?.Invoke(Direction.Vertical, false));
if (canRotate.Value)
{
rotateCounterClockwiseButton = addButton(FontAwesome.Solid.Undo, "Rotate 90 degrees counter-clockwise (Ctrl-<)", () => rotationHandler?.Rotate(-90));
rotateClockwiseButton = addButton(FontAwesome.Solid.Redo, "Rotate 90 degrees clockwise (Ctrl->)", () => rotationHandler?.Rotate(90));
}

if (CanFlipX)
addButton(FontAwesome.Solid.ArrowsAltH, "Flip horizontally", () => OnFlip?.Invoke(Direction.Horizontal, false));

if (CanFlipY)
addButton(FontAwesome.Solid.ArrowsAltV, "Flip vertically", () => OnFlip?.Invoke(Direction.Vertical, false));

if (CanReverse)
reverseButton = addButton(FontAwesome.Solid.Backward, "Reverse pattern (Ctrl-G)", () => OnReverse?.Invoke());
}

private SelectionBoxButton addButton(IconUsage icon, string tooltip, Action action)
Expand All @@ -308,6 +345,21 @@ private SelectionBoxButton addButton(IconUsage icon, string tooltip, Action acti
return button;
}

private void clearButtons()
{
foreach (var button in buttons)
{
button.Clicked -= freezeButtonPosition;
button.HoverLost -= unfreezeButtonPosition;

button.OperationStarted -= operationStarted;
button.OperationEnded -= operationEnded;
}

unfreezeButtonPosition();
buttons.Clear();
}

/// <remarks>
/// This method should be called when a selection needs to be flipped
/// because of an ongoing scale handle drag that would otherwise cause width or height to go negative.
Expand All @@ -327,41 +379,8 @@ public void PerformFlipFromScaleHandles(Axes axes)
}
}

private void addScaleHandle(Anchor anchor)
{
var handle = new SelectionBoxScaleHandle
{
Anchor = anchor,
};

handle.OperationStarted += operationStarted;
handle.OperationEnded += operationEnded;
dragHandles.AddScaleHandle(handle);
}

private void addRotateHandle(Anchor anchor)
{
var handle = new SelectionBoxRotationHandle
{
Anchor = anchor,
};

handle.OperationStarted += operationStarted;
handle.OperationEnded += operationEnded;
dragHandles.AddRotationHandle(handle);
}

private int activeOperations;

private float convertDragEventToAngleOfRotation(DragEvent e)
{
// Adjust coordinate system to the center of SelectionBox
float startAngle = MathF.Atan2(e.LastMousePosition.Y - DrawHeight / 2, e.LastMousePosition.X - DrawWidth / 2);
float endAngle = MathF.Atan2(e.MousePosition.Y - DrawHeight / 2, e.MousePosition.X - DrawWidth / 2);

return (endAngle - startAngle) * 180 / MathF.PI;
}

private void operationEnded()
{
if (--activeOperations == 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ public void AddScaleHandle(SelectionBoxScaleHandle handle)
scaleHandles.Add(handle);
}

public void ClearScaleHandles()
{
foreach (var scaleHandle in scaleHandles)
unbindDragHandle(scaleHandle);
scaleHandles.Clear();
}

public void AddRotationHandle(SelectionBoxRotationHandle handle)
{
handle.Alpha = 0;
Expand All @@ -60,6 +67,13 @@ public void AddRotationHandle(SelectionBoxRotationHandle handle)
rotationHandles.Add(handle);
}

public void ClearRotationHandles()
{
foreach (var rotationHandle in rotationHandles)
unbindDragHandle(rotationHandle);
rotationHandles.Clear();
}

private void bindDragHandle(SelectionBoxDragHandle handle)
{
handle.HoverGained += updateRotationHandlesVisibility;
Expand All @@ -69,6 +83,15 @@ private void bindDragHandle(SelectionBoxDragHandle handle)
allDragHandles.Add(handle);
}

private void unbindDragHandle(SelectionBoxDragHandle handle)
{
handle.HoverGained -= updateRotationHandlesVisibility;
handle.HoverLost -= updateRotationHandlesVisibility;
handle.MouseDown -= updateRotationHandlesVisibility;
handle.MouseUp -= updateRotationHandlesVisibility;
allDragHandles.Remove(handle);
}

public void FlipScaleHandles(Direction direction)
{
foreach (var handle in scaleHandles)
Expand Down