Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
fa5d824
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Dec 7, 2025
76d95cd
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Dec 9, 2025
f8ff664
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Dec 9, 2025
56fcb75
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Dec 9, 2025
6b8f369
Improve logging for debugging and error traceability
tig Dec 9, 2025
5e69cb1
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Dec 9, 2025
ec5e2b4
Merge branch 'v2_develop' into v2_4471-Continuous
tig Dec 9, 2025
f9f2b7a
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Dec 9, 2025
7162593
Merge branch 'v2_4471-Continuous' of tig:tig/Terminal.Gui into v2_447…
tig Dec 9, 2025
df04be7
Fixed warnings
tig Dec 9, 2025
13543f6
Refactored `MouseHeldDown` to support accelerating timeouts for
tig Dec 9, 2025
08080d6
WIP: Refactor MouseFlags and improve mouse event handling
tig Dec 10, 2025
080ae6b
WIP: Big code cleanup and reorg of Mouse processing helpers.
tig Dec 10, 2025
757ea98
WIP: Add comprehensive driver/input/output unit tests
tig Dec 10, 2025
2623fbf
New arch
tig Dec 11, 2025
36ecf66
WIP: Implement timestamp-based multi-click detection with pending clicks
tig Dec 11, 2025
1021d21
Add implementation summary for timestamp-based multi-click detection
tig Dec 11, 2025
5ec15e8
WIP:
tig Dec 11, 2025
566e8c0
Almost working - Geting single and double clicks but at least single …
tig Dec 11, 2025
d9b9eb8
Made MouseEventArgs.Position nullable to indicate it might not be set.
tig Dec 11, 2025
6046792
MouseEventArgs -> Mouse
tig Dec 11, 2025
d43f47f
API docs
tig Dec 11, 2025
c53adff
Renames.
tig Dec 11, 2025
57245fa
Code clean up and deep dive
tig Dec 11, 2025
c9415f8
Docs
tig Dec 11, 2025
3d44c14
tests
tig Dec 11, 2025
bb9c155
More analysis
tig Dec 11, 2025
e42275f
fxied some tests
tig Dec 11, 2025
2210e04
Massive mouse nameing cleanup
tig Dec 11, 2025
50d46b5
Merge branch 'v2_4471-Continuous' of tig:tig/Terminal.Gui into v2_447…
tig Dec 12, 2025
56e2f4d
HighlightStates rename and code cleanup
tig Dec 12, 2025
130b908
More renames
tig Dec 12, 2025
1f343b0
Disabled broken tests with Skip = "Broken in #4474"
tig Dec 12, 2025
e36bdba
Commented legacy
tig Dec 12, 2025
202dc05
Phase 2
tig Dec 12, 2025
4d385a6
Merge branch 'v2_4471-Continuous' of tig:tig/Terminal.Gui into v2_447…
tig Dec 12, 2025
abbe9be
Add testable input and debug/test suite for UnixInput
tig Dec 12, 2025
a79eb41
Add AnsiKeyboardEncoder/MouseEncoder and related tests
tig Dec 12, 2025
e2ab7df
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Dec 13, 2025
bf903e4
Merged
tig Dec 13, 2025
071824b
merged
tig Dec 13, 2025
570933d
Merge branch 'v2_4471-Continuous' of tig:tig/Terminal.Gui into v2_447…
tig Dec 13, 2025
259095f
Enabled previously skpped tests. STuff is broke
tig Dec 13, 2025
527b50a
Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop
tig Dec 13, 2025
96168b4
Merge branch 'v2_develop' into v2_4471-Continuous
tig Dec 13, 2025
6910084
updates transparent shadow test
tig Dec 13, 2025
82acab6
Refactor Fake driver to use pure ANSI char stream
tig Dec 13, 2025
2299987
Add platform raw mode support to FakeInput (Unix/Win)
tig Dec 13, 2025
ea847a6
Merge branch 'v2_4471-Continuous' of tig:tig/Terminal.Gui into v2_447…
tig Dec 13, 2025
cd672a6
Refactor FakeDriver: true ANSI/VT, platform helpers, size
tig Dec 13, 2025
03057f9
Unify ANSI key conversion for Unix and test drivers
tig Dec 13, 2025
5d00146
Introduce DriverRegistry: type-safe, AOT-friendly driver system
tig Dec 13, 2025
7f4e3c0
Rename Fake driver to ANSI driver throughout codebase
tig Dec 13, 2025
4b84161
Rename ANSI* classes to Ansi* and update docs/references
tig Dec 13, 2025
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
31 changes: 22 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,15 @@ Welcome! This guide provides everything you need to know to contribute effective

**⚠️ CRITICAL - These rules MUST be followed in ALL new or modified code:**

- **Do NOT add formatting tools** - Use existing `.editorconfig` and `Terminal.sln.DotSettings`
**AI or AI Agent Written or Modified Code MUST Follow these instructions**

- Use existing `.editorconfig` and `Terminal.sln.DotSettings` to determine code style and formatting.
- Format code with:
1. ReSharper/Rider (`Ctrl-E-C`)
2. JetBrains CleanupCode CLI tool (free)
3. Visual Studio (`Ctrl-K-D`) as fallback
- **Only format files you modify**
- Follow `.editorconfig` settings (e.g., braces on new lines, spaces after keywords)
- 4-space indentation
- No trailing whitespace
- File-scoped namespaces
- Only format files you modify
- Follow `.editorconfig` settings
- **ALWAYS use explicit types** - Never use `var` except for built-in simple types (`int`, `string`, `bool`, `double`, `float`, `decimal`, `char`, `byte`)
```csharp
// ✅ CORRECT - Explicit types
Expand All @@ -144,7 +143,6 @@ Welcome! This guide provides everything you need to know to contribute effective
var args = new MouseEventArgs { Position = new Point(5, 5) };
var views = new List<View?>();
```

- **ALWAYS use target-typed `new ()`** - Use `new ()` instead of `new TypeName()` when the type is already declared
```csharp
// ✅ CORRECT - Target-typed new
Expand All @@ -155,8 +153,21 @@ Welcome! This guide provides everything you need to know to contribute effective
View view = new View() { Width = 10 };
MouseEventArgs args = new MouseEventArgs();
```
- **ALWAYS** use collection initializers if possible:
```csharp
// ✅ CORRECT - Collection initializer
List<View> views = [
new Button("OK"),
new Button("Cancel")
];

// ❌ WRONG - Adding items separately
List<View> views = new ();
views.Add(new Button("OK"));
views.Add(new Button("Cancel"));
```

**⚠️ CRITICAL - These conventions apply to ALL code - production code, test code, examples, and samples.**
**⚠️ CRITICAL - These conventions apply to ALL code - production code, test code, examples, documentation, and samples.**

## Testing Requirements

Expand All @@ -173,6 +184,8 @@ Welcome! This guide provides everything you need to know to contribute effective

### Test Patterns

- **AI Created Tests MUST follow these patterns exactly.**
- **Add comment indicating the test was AI generated** - e.g., `// CoPilot - ChatGPT v4`
- **Make tests granular** - Each test should cover smallest area possible
- Follow existing test patterns in respective test projects
- **Avoid adding new tests to the `UnitTests` Project** - Make them parallelizable and add them to `UnitTests.Parallelizable`
Expand Down Expand Up @@ -241,7 +254,7 @@ Welcome! This guide provides everything you need to know to contribute effective
**`/Terminal.Gui/`** - Core library (496 C# files):
- `App/` - Application lifecycle (`Application.cs` static class, `SessionToken`, `MainLoop`)
- `Configuration/` - `ConfigurationManager` for settings
- `Drivers/` - Console driver implementations (`Dotnet`, `Windows`, `Unix`, `Fake`)
- `Drivers/` - Console driver implementations (`dotnet`, `Windows`, `Unix`, `ansi`)
- `Drawing/` - Rendering system (attributes, colors, glyphs)
- `Input/` - Keyboard and mouse input handling
- `ViewBase/` - Core `View` class hierarchy and layout
Expand Down
14 changes: 14 additions & 0 deletions Examples/UICatalog/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
"commandName": "Project",
"commandLineArgs": "--driver dotnet -dl Trace"
},
"UICatalog --driver ansi": {
"commandName": "Project",
"commandLineArgs": "--driver ansi -dl Trace"
},
"WSL: UICatalog": {
"commandName": "Executable",
"executablePath": "wsl",
Expand All @@ -30,6 +34,12 @@
"commandLineArgs": "dotnet UICatalog.dll --driver unix",
"distributionName": ""
},
"WSL: UICatalog --driver ansi": {
"commandName": "Executable",
"executablePath": "wsl",
"commandLineArgs": "dotnet UICatalog.dll --driver ansi",
"distributionName": ""
},
"WSL-Gnome: UICatalog": {
"commandName": "Executable",
"executablePath": "wsl",
Expand Down Expand Up @@ -60,6 +70,10 @@
"commandName": "Project",
"commandLineArgs": "--driver windows --benchmark"
},
"Benchmark All --driver ansi": {
"commandName": "Project",
"commandLineArgs": "--driver ansi --benchmark"
},
"WSL: Benchmark All": {
"commandName": "Executable",
"executablePath": "wsl",
Expand Down
4 changes: 2 additions & 2 deletions Examples/UICatalog/Resources/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
"UI Catalog Theme": {
"Window.DefaultShadow": "Transparent",
"Button.DefaultShadow": "None",
"CheckBox.DefaultHighlightStates": "In, Pressed, PressedOutside",
"CheckBox.DefaultMouseHighlightStates": "In, Pressed, PressedOutside",
"MessageBox.DefaultButtonAlignment": "Start",
"StatusBar.DefaultSeparatorLineStyle": "Single",
"Dialog.DefaultMinimumWidth": 80,
Expand All @@ -148,7 +148,7 @@
"Dialog.DefaultButtonAlignment": "Start",
"FrameView.DefaultBorderStyle": "Double",
"MessageBox.DefaultMinimumHeight": 0,
"Button.DefaultHighlightStates": "In, Pressed",
"Button.DefaultMouseHighlightStates": "In, Pressed",
"Menu.DefaultBorderStyle": "Heavy",
"MenuBar.DefaultBorderStyle": "Heavy",
"Schemes": [
Expand Down
2 changes: 1 addition & 1 deletion Examples/UICatalog/Scenarios/Adornments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public override void Main ()
Y = 1,
Text = "_Button in Padding Y = 1",
CanFocus = true,
HighlightStates = MouseState.None,
MouseHighlightStates = MouseState.None,
};
btnButtonInPadding.Accepting += (s, e) => MessageBox.Query (appWindow.App, 20, 7, "Hi", "Button in Padding Pressed!", "Ok");
btnButtonInPadding.BorderStyle = LineStyle.Dashed;
Expand Down
44 changes: 22 additions & 22 deletions Examples/UICatalog/Scenarios/Bars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,12 @@ void PopOverMenuOnAccept (object o, CommandEventArgs args)

menuLikeExamples.MouseEvent += MenuLikeExamplesMouseEvent;

void MenuLikeExamplesMouseEvent (object _, MouseEventArgs e)
void MenuLikeExamplesMouseEvent (object _, Terminal.Gui.Input.Mouse mouse)
{
if (e.Flags.HasFlag (MouseFlags.Button3Clicked))
if (mouse.Flags.HasFlag (MouseFlags.RightButtonClicked))
{
popOverMenu.X = e.Position.X;
popOverMenu.Y = e.Position.Y;
popOverMenu.X = mouse.Position!.Value.X;
popOverMenu.Y = mouse.Position!.Value.Y;
popOverMenu.Visible = true;
//popOverMenu.Enabled = popOverMenu.Visible;
popOverMenu.SetFocus ();
Expand Down Expand Up @@ -275,7 +275,7 @@ void MenuLikeExamplesMouseEvent (object _, MouseEventArgs e)

//private void ShowContextMenu (object s, MouseEventEventArgs e)
//{
// if (e.Flags != MouseFlags.Button3Clicked)
// if (e.Flags != MouseFlags.RightButtonClicked)
// {
// return;
// }
Expand Down Expand Up @@ -392,7 +392,7 @@ void MenuLikeExamplesMouseEvent (object _, MouseEventArgs e)
// // If user clicks outside of the menuWindow, close it
// if (!contextMenu.Frame.Contains (e.Position.X, e.Position.Y))
// {
// if (e.Flags is (MouseFlags.Button1Clicked or MouseFlags.Button3Clicked))
// if (e.Flags is (MouseFlags.LeftButtonClicked or MouseFlags.RightButtonClicked))
// {
// contextMenu.RequestStop ();
// }
Expand All @@ -415,23 +415,23 @@ private void ConfigMenuBar (Bar bar)
Title = "_File",
HelpText = "File Menu",
Key = Key.D0.WithAlt,
HighlightStates = MouseState.In
MouseHighlightStates = MouseState.In
};

var editMenuBarItem = new Shortcut
{
Title = "_Edit",
HelpText = "Edit Menu",
Key = Key.D1.WithAlt,
HighlightStates = MouseState.In
MouseHighlightStates = MouseState.In
};

var helpMenuBarItem = new Shortcut
{
Title = "_Help",
HelpText = "Halp Menu",
Key = Key.D2.WithAlt,
HighlightStates = MouseState.In
MouseHighlightStates = MouseState.In
};

bar.Add (fileMenuBarItem, editMenuBarItem, helpMenuBarItem);
Expand All @@ -445,23 +445,23 @@ private void ConfigureMenu (Bar bar)
Title = "Z_igzag",
Key = Key.I.WithCtrl,
Text = "Gonna zig zag",
HighlightStates = MouseState.In
MouseHighlightStates = MouseState.In
};

var shortcut2 = new Shortcut
{
Title = "Za_G",
Text = "Gonna zag",
Key = Key.G.WithAlt,
HighlightStates = MouseState.In
MouseHighlightStates = MouseState.In
};

var shortcut3 = new Shortcut
{
Title = "_Three",
Text = "The 3rd item",
Key = Key.D3.WithAlt,
HighlightStates = MouseState.In
MouseHighlightStates = MouseState.In
};

var line = new Line ()
Expand All @@ -475,13 +475,13 @@ private void ConfigureMenu (Bar bar)
Title = "_Four",
Text = "Below the line",
Key = Key.D3.WithAlt,
HighlightStates = MouseState.In
MouseHighlightStates = MouseState.In
};

shortcut4.CommandView = new CheckBox ()
{
Title = shortcut4.Title,
HighlightStates = MouseState.None,
MouseHighlightStates = MouseState.None,
CanFocus = false
};
// This ensures the checkbox state toggles when the hotkey of Title is pressed.
Expand Down Expand Up @@ -523,18 +523,18 @@ public void ConfigStatusBar (Bar bar)

bar.Add (shortcut);

var button1 = new Button
var LeftButton = new Button
{
Text = "I'll Hide",
// Visible = false
};
button1.Accepting += Button_Clicked;
bar.Add (button1);
LeftButton.Accepting += Button_Clicked;
bar.Add (LeftButton);

shortcut.Accepting += (s, e) =>
{
button1.Visible = !button1.Visible;
button1.Enabled = button1.Visible;
LeftButton.Visible = !LeftButton.Visible;
LeftButton.Enabled = LeftButton.Visible;
e.Handled = true;
};

Expand All @@ -545,13 +545,13 @@ public void ConfigStatusBar (Bar bar)
CanFocus = true
});

var button2 = new Button
var MiddleButton = new Button
{
Text = "Or me!",
};
button2.Accepting += (s, e) => Application.RequestStop ();
MiddleButton.Accepting += (s, e) => Application.RequestStop ();

bar.Add (button2);
bar.Add (MiddleButton);

return;

Expand Down
46 changes: 36 additions & 10 deletions Examples/UICatalog/Scenarios/Buttons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ string MoveHotkey (string txt)
{
X = 0,
Y = Pos.Bottom (moveUnicodeHotKeyBtn) + 1,
Title = "_Numeric Up/Down (press-and-hold):",
Title = "Numeric Up/Down (press-and-_hold):",
};

var numericUpDown = new NumericUpDown<int>
Expand All @@ -360,43 +360,69 @@ void NumericUpDown_ValueChanged (object sender, EventArgs<int> e) { }
{
X = 0,
Y = Pos.Bottom (numericUpDown) + 1,
Title = "_No Repeat:"
Title = "No Repea_t:"
};
var noRepeatAcceptCount = 0;

var noRepeatButton = new Button
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Title = $"Accept Cou_nt: {noRepeatAcceptCount}",
WantContinuousButtonPressed = false
Title = $"Accepting Count: {noRepeatAcceptCount}",
MouseHoldRepeat = false
};
noRepeatButton.Accepting += (s, e) =>
{
noRepeatButton.Title = $"Accept Cou_nt: {++noRepeatAcceptCount}";
noRepeatButton.Title = $"Accepting Count: {++noRepeatAcceptCount}";
Logging.Trace ("noRepeatButton Button Pressed");
e.Handled = true;
};
main.Add (label, noRepeatButton);

label = new ()
{
X = Pos.Right (noRepeatButton) + 1,
Y = Pos.Top (label),
Title = "N_o Repeat (no highlight):"
};
var noRepeatNoHighlightAcceptCount = 0;

var noRepeatNoHighlight = new Button
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Title = $"Accepting Count: {noRepeatNoHighlightAcceptCount}",
MouseHoldRepeat = false,
MouseHighlightStates = MouseState.None
};
noRepeatNoHighlight.Accepting += (s, e) =>
{
noRepeatNoHighlight.Title = $"Accepting Count: {++noRepeatNoHighlightAcceptCount}";
Logging.Trace ("noRepeatNoHighlight Button Pressed");
e.Handled = true;
};
main.Add (label, noRepeatNoHighlight);

label = new ()
{
X = 0,
Y = Pos.Bottom (label) + 1,
Title = "_Repeat (press-and-hold):"
Title = "Repeat (_press-and-hold):"
};
var acceptCount = 0;

var repeatButtonAcceptingCount = 0;

var repeatButton = new Button
{
Id = "repeatButton",
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Title = $"Accept Co_unt: {acceptCount}",
WantContinuousButtonPressed = true
Title = $"Accepting Count: {repeatButtonAcceptingCount}",
MouseHoldRepeat = true
};
repeatButton.Accepting += (s, e) =>
{
repeatButton.Title = $"Accept Co_unt: {++acceptCount}";
repeatButton.Title = $"Accepting Count: {++repeatButtonAcceptingCount}";
e.Handled = true;
};

Expand Down
6 changes: 3 additions & 3 deletions Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,14 @@ public override void Main ()
_categoryList.Activating += (_, e) =>
{
// Only handle mouse clicks
if (e.Context is not CommandContext<MouseBinding> { Binding.MouseEventArgs: { } mouseArgs })
if (e.Context is not CommandContext<MouseBinding> { Binding.MouseEventArgs: { } mouse })
{
return;
}

_categoryList.ScreenToCell (mouseArgs.Position, out int? clickedCol);
_categoryList.ScreenToCell (mouse.Position!.Value, out int? clickedCol);

if (clickedCol != null && mouseArgs.Flags.HasFlag (MouseFlags.Button1Clicked))
if (clickedCol != null && mouse.Flags.HasFlag (MouseFlags.LeftButtonClicked))
{
EnumerableTableSource<UnicodeRange> table = (EnumerableTableSource<UnicodeRange>)_categoryList.Table;
string prevSelection = table.Data.ElementAt (_categoryList.SelectedRow).Category;
Expand Down
2 changes: 1 addition & 1 deletion Examples/UICatalog/Scenarios/ContextMenus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void OnAppWindowOnActivating (object? s, CommandEventArgs e)
{
if (e.Context is CommandContext<MouseBinding> { Binding.MouseEventArgs: { } mouseArgs })
{
if (mouseArgs.Flags == MouseFlags.Button3Clicked)
if (mouseArgs.Flags == MouseFlags.RightButtonClicked)
{
// ReSharper disable once AccessToDisposedClosure
_winContextMenu?.MakeVisible (mouseArgs.ScreenPosition);
Expand Down
Loading
Loading