1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-13 05:13:49 +08:00

Implement a V2 password textbox (#38028)

This PR adds a password input form control consistent with the V2 form
controls.

Default state:

<img width="601" height="90" alt="image"
src="https://github.com/user-attachments/assets/f7e49468-8e9f-4a94-9c12-ad445b7cac17"
/>

Caps Lock active:

<img width="598" height="90" alt="image"
src="https://github.com/user-attachments/assets/cda4fb67-4803-4e39-9cbd-73f34318ab6f"
/>

---------

Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com>
This commit is contained in:
Krzysztof Gutkowski
2026-06-11 12:39:25 +02:00
committed by GitHub
Unverified
parent ada19d93a7
commit 3b4dfd5903
4 changed files with 133 additions and 5 deletions
@@ -235,6 +235,11 @@ namespace osu.Game.Tests.Visual.UserInterface
Padding = new MarginPadding(10),
Children = new Drawable[]
{
new FormPasswordTextBox
{
Caption = "Password",
TabbableContentContainer = this,
},
new FormNumberBox(allowDecimals: true)
{
Caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
@@ -0,0 +1,106 @@
// 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 System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Framework.Platform;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osuTK;
using osuTK.Input;
namespace osu.Game.Graphics.UserInterfaceV2
{
public partial class FormPasswordTextBox : FormTextBox
{
private CapsWarning capsWarning = null!;
[BackgroundDependencyLoader]
private void load()
{
CaptionContainer.Add(capsWarning = new CapsWarning
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Alpha = 0,
});
}
internal override InnerTextBox CreateTextBox() => new InnerPasswordBox
{
UpdateCapsWarning = visible => capsWarning.FadeTo(visible ? 1 : 0, 250, Easing.OutQuint),
};
internal partial class InnerPasswordBox : InnerTextBox
{
public Action<bool>? UpdateCapsWarning { get; init; }
[Resolved]
private GameHost host { get; set; } = null!;
protected override Drawable GetDrawableCharacter(char c) => new FallingDownContainer
{
AutoSizeAxes = Axes.Both,
Child = new OsuPasswordTextBox.PasswordMaskChar(FontSize),
};
protected override bool AllowUniqueCharacterSamples => false;
public InnerPasswordBox()
{
InputProperties = new TextInputProperties(TextInputType.Password, false);
}
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Key == Key.CapsLock)
UpdateCapsWarning?.Invoke(host.CapsLockEnabled);
return base.OnKeyDown(e);
}
protected override void OnFocus(FocusEvent e)
{
UpdateCapsWarning?.Invoke(host.CapsLockEnabled);
base.OnFocus(e);
}
protected override void OnFocusLost(FocusLostEvent e)
{
UpdateCapsWarning?.Invoke(false);
base.OnFocusLost(e);
}
}
private partial class CapsWarning : OsuTextFlowContainer
{
public CapsWarning()
: base(t => t.Font = OsuFont.Style.Caption1)
{
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AutoSizeAxes = Axes.Both;
Colour = colours.YellowLight;
AddArbitraryDrawable(new SpriteIcon
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Size = new Vector2(10),
Icon = FontAwesome.Solid.ExclamationTriangle,
Margin = new MarginPadding { Right = 2 },
Y = 1f,
});
AddText(CommonStrings.CapsLock);
}
}
}
}
@@ -84,6 +84,8 @@ namespace osu.Game.Graphics.UserInterfaceV2
private FormFieldCaption caption = null!;
private IFocusManager focusManager = null!;
protected Container CaptionContainer { get; private set; } = null!;
[Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!;
@@ -104,12 +106,22 @@ namespace osu.Game.Graphics.UserInterfaceV2
Spacing = new Vector2(0, 4),
Children = new Drawable[]
{
caption = new FormFieldCaption
CaptionContainer = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
Caption = Caption,
TooltipText = HintText,
Children = new Drawable[]
{
caption = new FormFieldCaption
{
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
Caption = Caption,
TooltipText = HintText,
},
},
},
textBox = CreateTextBox().With(t =>
{
+7 -2
View File
@@ -170,9 +170,14 @@ namespace osu.Game.Localisation
public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit");
/// <summary>
/// "Caps lock is active"
/// "Caps Lock"
/// </summary>
public static LocalisableString CapsLockIsActive => new TranslatableString(getKey(@"caps_lock_is_active"), @"Caps lock is active");
public static LocalisableString CapsLock => new TranslatableString(getKey(@"caps_lock"), @"Caps Lock");
/// <summary>
/// "Caps Lock is active"
/// </summary>
public static LocalisableString CapsLockIsActive => new TranslatableString(getKey(@"caps_lock_is_active"), @"Caps Lock is active");
/// <summary>
/// "Revert to default"