Remove TextField.Caption property; use Title with hotkey navigation support (#4352)

* Initial plan

* Initial exploration - understanding TextField Caption and Title

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Remove TextField.Caption and use Title instead with hotkey support

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Add defensive check to ensure TitleTextFormatter.Text is set

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Final changes - all tests passing

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Fixed bugs.

* Add comprehensive tests for caption rendering with attributes validation

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Fix: Disable TextField hotkey functionality to prevent input interception

TextField's Title is used as a caption/placeholder, not for hotkey
navigation. Hotkey visual formatting (underline) is still rendered
in the caption, but hotkey functionality is disabled to prevent
keys like 'E' and 'F' from being intercepted when typing in the field.

Updated test to expect "_Find" instead of "Find" to match resource change.

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Fix: Support Alt+key hotkey navigation while allowing normal typing

Override AddKeyBindingsForHotKey to only bind Alt+key combinations
(e.g., Alt+F for "_Find"), not the bare keys. This allows:
- Alt+F to navigate to the TextField with Title="_Find"
- Normal typing of 'F', 'E', etc. without interception

Previously, both bare key and Alt+key were bound, causing typing
issues. Now TextField properly supports hotkey navigation without
interfering with text input.

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Changes before error encountered

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Refactor hotkey handling to support command context

Refactored `RaiseHandlingHotKey` to accept an `ICommandContext? ctx` parameter, enabling context-aware hotkey handling. Updated `Command.HotKey` definitions across multiple classes (`View`, `CheckBox`, `Label`, `MenuBarv2`, `RadioGroup`, `TextField`) to utilize the new context parameter.

Enhanced XML documentation for `RaiseHandlingHotKey` to clarify its usage and return values. Added a context-aware hotkey handler to `TextField` with additional logic for focus handling.

Refactored attribute initialization and improved code readability in `TextField` by aligning parameters and removing unused `HotKeySpecifier` initialization. These changes improve flexibility, maintainability, and consistency across the codebase.

* Remove TextField.Caption property; use Title with hotkey navigation support

Co-authored-by: tig <585482+tig@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tig <585482+tig@users.noreply.github.com>
Co-authored-by: Tig <tig@users.noreply.github.com>
This commit is contained in:
Copilot
2025-10-27 07:50:09 -06:00
committed by GitHub
parent 1e32d5d5ce
commit f3fc20306e
15 changed files with 171 additions and 57 deletions

View File

@@ -145,7 +145,7 @@ public class TextFieldTests (ITestOutputHelper output)
TextField tf = GetTextFieldsInView ();
// Caption has no effect when focused
tf.Caption = caption;
tf.Title = caption;
Application.RaiseKeyDownEvent ('\t');
Assert.False (tf.HasFocus);
@@ -165,7 +165,7 @@ public class TextFieldTests (ITestOutputHelper output)
TextField tf = GetTextFieldsInView ();
tf.Caption = caption;
tf.Title = caption;
Application.RaiseKeyDownEvent ('\t');
Assert.False (tf.HasFocus);
@@ -185,7 +185,7 @@ public class TextFieldTests (ITestOutputHelper output)
tf.Draw ();
DriverAssert.AssertDriverContentsAre ("", output);
tf.Caption = "Enter txt";
tf.Title = "Enter txt";
Application.RaiseKeyDownEvent ('\t');
// Caption should appear when not focused and no text
@@ -212,7 +212,7 @@ public class TextFieldTests (ITestOutputHelper output)
DriverAssert.AssertDriverContentsAre ("", output);
// Caption has no effect when focused
tf.Caption = "Enter txt";
tf.Title = "Enter txt";
Assert.True (tf.HasFocus);
View.SetClipToScreen ();
tf.Draw ();
@@ -227,6 +227,104 @@ public class TextFieldTests (ITestOutputHelper output)
Application.Top.Dispose ();
}
[Fact]
[AutoInitShutdown]
public void Title_RendersAsCaption_WithCorrectAttributes ()
{
TextField tf = GetTextFieldsInView ();
// Set a title (caption)
tf.Title = "Enter text";
// Remove focus so caption appears
Application.RaiseKeyDownEvent ('\t');
Assert.False (tf.HasFocus);
View.SetClipToScreen ();
tf.Draw ();
// Verify the caption text is rendered
DriverAssert.AssertDriverContentsAre ("Enter text", output);
// Verify the caption uses dimmed color attribute
Attribute captionAttr = new Attribute (
tf.GetAttributeForRole (VisualRole.Editable).Foreground.GetDimColor (),
tf.GetAttributeForRole (VisualRole.Editable).Background);
// All characters in "Enter text" should have the caption attribute
DriverAssert.AssertDriverAttributesAre ("0000000000", output, Application.Driver, captionAttr);
Application.Top.Dispose ();
}
[Fact]
[AutoInitShutdown]
public void Title_WithHotkey_RendersUnderlined ()
{
TextField tf = GetTextFieldsInView ();
// Title with hotkey should be rendered with the hotkey underlined when not focused
tf.Title = "_Find";
// Remove focus so caption appears
Application.RaiseKeyDownEvent ('\t');
Assert.False (tf.HasFocus);
View.SetClipToScreen ();
tf.Draw ();
// The hotkey character 'F' should be rendered (without the underscore in the actual text)
DriverAssert.AssertDriverContentsAre ("Find", output);
// Verify the hotkey character 'F' has underline style
Attribute captionAttr = new Attribute (
tf.GetAttributeForRole (VisualRole.Editable).Foreground.GetDimColor (),
tf.GetAttributeForRole (VisualRole.Editable).Background);
Attribute hotkeyAttr = new Attribute (
tf.GetAttributeForRole (VisualRole.Editable).Foreground.GetDimColor (),
tf.GetAttributeForRole (VisualRole.Editable).Background,
tf.GetAttributeForRole (VisualRole.Editable).Style | TextStyle.Underline);
// F is underlined (index 1), remaining characters use normal caption attribute (index 0)
DriverAssert.AssertDriverAttributesAre ("1000", output, Application.Driver, captionAttr, hotkeyAttr);
Application.Top.Dispose ();
}
[Fact]
[AutoInitShutdown]
public void Title_WithHotkey_MiddleCharacter_RendersUnderlined ()
{
TextField tf = GetTextFieldsInView ();
// Title with hotkey in middle of text
tf.Title = "Enter _Text";
// Remove focus so caption appears
Application.RaiseKeyDownEvent ('\t');
Assert.False (tf.HasFocus);
View.SetClipToScreen ();
tf.Draw ();
// The underscore should not be rendered, 'T' should be underlined
DriverAssert.AssertDriverContentsAre ("Enter Text", output);
// Verify the hotkey character 'T' has underline style
Attribute captionAttr = new Attribute (
tf.GetAttributeForRole (VisualRole.Editable).Foreground.GetDimColor (),
tf.GetAttributeForRole (VisualRole.Editable).Background);
Attribute hotkeyAttr = new Attribute (
tf.GetAttributeForRole (VisualRole.Editable).Foreground.GetDimColor (),
tf.GetAttributeForRole (VisualRole.Editable).Background,
tf.GetAttributeForRole (VisualRole.Editable).Style | TextStyle.Underline);
// "Enter " (6 chars) + "T" (underlined) + "ext" (3 chars)
DriverAssert.AssertDriverAttributesAre ("0000001000", output, Application.Driver, captionAttr, hotkeyAttr);
Application.Top.Dispose ();
}
[Fact]
[TextFieldTestsAutoInitShutdown]
public void Changing_SelectedStart_Or_CursorPosition_Update_SelectedLength_And_SelectedText ()