Skip to content

Commit

Permalink
Merge pull request #3072 from jorolf/abstract-text-box
Browse files Browse the repository at this point in the history
Make TextBox abstract and add custom carets
  • Loading branch information
smoogipoo authored Dec 24, 2019
2 parents c823730 + 27a0cd2 commit d3612b4
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 140 deletions.
82 changes: 80 additions & 2 deletions osu.Framework.Tests/Visual/UserInterface/TestSceneTextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;

namespace osu.Framework.Tests.Visual.UserInterface
Expand All @@ -19,7 +22,7 @@ public class TestSceneTextBox : ManualInputManagerTestScene
{
typeof(BasicTextBox),
typeof(TextBox),
typeof(PasswordTextBox)
typeof(BasicPasswordTextBox)
};

private FillFlowContainer textBoxes;
Expand Down Expand Up @@ -96,6 +99,13 @@ public void VariousTextBoxes()
TabbableContentContainer = textBoxes
});

textBoxes.Add(new CustomTextBox
{
Text = @"Custom textbox",
Size = new Vector2(500, 30),
TabbableContentContainer = textBoxes
});

FillFlowContainer otherTextBoxes = new FillFlowContainer
{
Direction = FillDirection.Vertical,
Expand All @@ -118,7 +128,7 @@ public void VariousTextBoxes()
TabbableContentContainer = otherTextBoxes
});

otherTextBoxes.Add(new PasswordTextBox
otherTextBoxes.Add(new BasicPasswordTextBox
{
PlaceholderText = @"Password textbox",
Text = "Secret ;)",
Expand Down Expand Up @@ -260,5 +270,73 @@ private class NumberTextBox : BasicTextBox
{
protected override bool CanAddCharacter(char character) => char.IsNumber(character);
}

private class CustomTextBox : BasicTextBox
{
protected override Drawable GetDrawableCharacter(char c) => new ScalingText(c, CalculatedTextSize);

private class ScalingText : CompositeDrawable
{
private readonly SpriteText text;

public ScalingText(char c, float textSize)
{
AddInternal(text = new SpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = c.ToString(),
Font = FrameworkFont.Condensed.With(size: textSize),
});
}

protected override void LoadComplete()
{
base.LoadComplete();

Size = text.DrawSize;
}

public override void Show()
{
text.Scale = Vector2.Zero;
text.FadeIn(200).ScaleTo(1, 200);
}

public override void Hide()
{
text.Scale = Vector2.One;
text.ScaleTo(0, 200).FadeOut(200);
}
}

protected override Caret CreateCaret() => new BorderCaret();

private class BorderCaret : Caret
{
private const float caret_width = 2;

public BorderCaret()
{
RelativeSizeAxes = Axes.Y;

Masking = true;
BorderColour = Color4.White;
BorderThickness = 3;

InternalChild = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Transparent
};
}

public override void DisplayAt(Vector2 position, float? selectionWidth)
{
Position = position - Vector2.UnitX;
Width = selectionWidth + 1 ?? caret_width;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace osu.Framework.Graphics.UserInterface
{
public class PasswordTextBox : TextBox, ISuppressKeyEventLogging
public class BasicPasswordTextBox : BasicTextBox, ISuppressKeyEventLogging
{
protected virtual char MaskCharacter => '*';

Expand Down
167 changes: 160 additions & 7 deletions osu.Framework/Graphics/UserInterface/BasicTextBox.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,187 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osuTK;
using osuTK.Graphics;

namespace osu.Framework.Graphics.UserInterface
{
public class BasicTextBox : TextBox
{
protected override float CaretWidth => 2;
protected virtual float CaretWidth => 2;

protected override Color4 SelectionColour => FrameworkColour.YellowGreen;
private const float caret_move_time = 60;

protected virtual Color4 SelectionColour => FrameworkColour.YellowGreen;

protected Color4 BackgroundCommit { get; set; } = FrameworkColour.Green;

private Color4 backgroundFocused = new Color4(100, 100, 100, 255);
private Color4 backgroundUnfocused = new Color4(100, 100, 100, 120);

private readonly Box background;

protected Color4 BackgroundFocused
{
get => backgroundFocused;
set
{
backgroundFocused = value;
if (HasFocus)
background.Colour = value;
}
}

protected Color4 BackgroundUnfocused
{
get => backgroundUnfocused;
set
{
backgroundUnfocused = value;
if (!HasFocus)
background.Colour = value;
}
}

protected virtual Color4 InputErrorColour => Color4.Red;

public BasicTextBox()
{
CornerRadius = 0;
Add(background = new Box
{
RelativeSizeAxes = Axes.Both,
Depth = 1,
Colour = BackgroundUnfocused,
});

BackgroundFocused = FrameworkColour.BlueGreen;
BackgroundUnfocused = FrameworkColour.BlueGreenDark;
BackgroundCommit = FrameworkColour.Green;
TextFlow.Height = 0.75f;
TextContainer.Height = 0.75f;
}

protected override void NotifyInputError() => background.FlashColour(InputErrorColour, 200);

protected override void Commit()
{
base.Commit();

background.Colour = ReleaseFocusOnCommit ? BackgroundUnfocused : BackgroundFocused;
background.ClearTransforms();
background.FlashColour(BackgroundCommit, 400);
}

protected override void OnFocusLost(FocusLostEvent e)
{
base.OnFocusLost(e);

background.ClearTransforms();
background.Colour = BackgroundFocused;
background.FadeColour(BackgroundUnfocused, 200, Easing.OutExpo);
}

protected override void OnFocus(FocusEvent e)
{
base.OnFocus(e);

background.ClearTransforms();
background.Colour = BackgroundUnfocused;
background.FadeColour(BackgroundFocused, 200, Easing.Out);
}

protected override Drawable GetDrawableCharacter(char c) => new SpriteText { Text = c.ToString(), Font = FrameworkFont.Condensed.With(size: CalculatedTextSize) };
protected override Drawable GetDrawableCharacter(char c) => new FallingDownContainer
{
AutoSizeAxes = Axes.Both,
Child = new SpriteText { Text = c.ToString(), Font = FrameworkFont.Condensed.With(size: CalculatedTextSize) }
};

protected override SpriteText CreatePlaceholder() => new SpriteText
protected override SpriteText CreatePlaceholder() => new FadingPlaceholderText
{
Colour = FrameworkColour.YellowGreen,
Font = FrameworkFont.Condensed,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
X = CaretWidth,
};

public class FallingDownContainer : Container
{
public override void Show()
{
var col = (Color4)Colour;
this.FadeColour(col.Opacity(0)).FadeColour(col, caret_move_time * 2, Easing.Out);
}

public override void Hide()
{
this.FadeOut(200);
this.MoveToY(DrawSize.Y, 200, Easing.InExpo);
}
}

public class FadingPlaceholderText : SpriteText
{
public override void Show() => this.FadeIn(200);

public override void Hide() => this.FadeOut(200);
}

protected override Caret CreateCaret() => new BasicCaret
{
CaretWidth = CaretWidth,
SelectionColour = SelectionColour,
};

public class BasicCaret : Caret
{
public BasicCaret()
{
RelativeSizeAxes = Axes.Y;
Size = new Vector2(1, 0.9f);

Colour = Color4.Transparent;
Anchor = Anchor.CentreLeft;
Origin = Anchor.CentreLeft;

Masking = true;
CornerRadius = 1;

InternalChild = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
};
}

public override void Hide() => this.FadeOut(200);

public float CaretWidth { get; set; }

public Color4 SelectionColour { get; set; }

public override void DisplayAt(Vector2 position, float? selectionWidth)
{
if (selectionWidth != null)
{
this.MoveTo(new Vector2(position.X, position.Y), 60, Easing.Out);
this.ResizeWidthTo(selectionWidth.Value + CaretWidth / 2, caret_move_time, Easing.Out);
this
.FadeTo(0.5f, 200, Easing.Out)
.FadeColour(SelectionColour, 200, Easing.Out);
}
else
{
this.MoveTo(new Vector2(position.X - CaretWidth / 2, position.Y), 60, Easing.Out);
this.ResizeWidthTo(CaretWidth, caret_move_time, Easing.Out);
this
.FadeColour(Color4.White, 200, Easing.Out)
.Loop(c => c.FadeTo(0.7f).FadeTo(0.4f, 500, Easing.InOutSine));
}
}
}
}
}
21 changes: 21 additions & 0 deletions osu.Framework/Graphics/UserInterface/Caret.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Graphics.Containers;
using osuTK;

namespace osu.Framework.Graphics.UserInterface
{
/// <summary>
/// A UI component generally used to show the current cursor location in a text edit field.
/// </summary>
public abstract class Caret : CompositeDrawable
{
/// <summary>
/// Request the caret be displayed at a particular location, with an optional selection length.
/// </summary>
/// <param name="position">The position (in parent space) where the caret should be displayed.</param>
/// <param name="selectionWidth">If a selection is active, the length (in parent space) of the selection. The caret should extend to display this selection to the user.</param>
public abstract void DisplayAt(Vector2 position, float? selectionWidth);
}
}
Loading

0 comments on commit d3612b4

Please sign in to comment.