Files
Terminal.Gui/Examples/UICatalog/Scenarios/ContextMenus.cs
Tig 3e2eebfd2c Fixes #4057 - MASSIVE! Fully implements ColorScheme->Scheme + VisualRole + Colors.->SchemeManager. (#4062)
* touching publish.yml

* ColorScheme->Scheme

* ColorScheme->Scheme 2

* Prototype of GetAttributeForRole

* Badly broke CM

* Further Badly broke CM

* Refactored CM big-time. View still broken

* All unit test pass again. Tons added. CM is still WIP, but Schemes is not mostly refactored and working.

* Actually:
All unit test pass again.
Tons added.
CM is still WIP, but Schemes is not mostly refactored and working.

* Bug fixes.
DeepMemberWiseClone cleanup

* Further cleanup of Scope<T>, ConfigProperty, etc.

* Made ConfigManager thread safe.

* WIP: Broken

* WIP: new deep clone impl

* WIP: new deep clone impl is done. Now fixing CM

* WIP:
- config.md
- Working on AOT clean up
- Core CM is broken; but known.

* WIP

* Merged.
Removed CM from Application.Init

* WIP

* More WIP; Less broke

* All CM unit tests pass... Not sure if it actually works though

* All unit tests pass... Themes are broken though in UI Cat

* CM Ready for review?

* Fixed failures due to TextStyles PR

* Working on Scheme/Attribute

* Working on Scheme/Attribute 2

* Working on Scheme/Attribute 3

* Working on Scheme/Attribute 4

* Working on Scheme/Attribute 5

* Working on Scheme/Attribute 6

* Added test to show how awful memory usage is

* Improved schema. Updated config.json

* Nade Scope<T> concurrentdictionary and added test to prove

* Made Themes ConcrurrentDictionary. Added bunches of tests

* Code cleanup

* Code cleanup 2

* Code cleanup 3

* Tweaking Scheme

* ClearJsonErrors

* ClearJsonErrors2

* Updated Attribute API

* It all (mostly) works!

* Skip odd unit test

* Messed with Themes

* Theme tweaks

* Code reorg. New .md stuff

* Fixed Enabled. Added mock driver

* Fixed a bunch of View.Enabled related issues

* Scheme -> Get/SetScheme()

* Cleanup

* Cleanup2

* Broke something

* Fixed everything

* Made CM.Enable better

* Text Style Scenario

* Added comments

* Fixed UI Catalog Theme Changing

* Fixed more dynamic CM update stuff

* Warning cleanup

* New Default Theme

* fixed unit test

* Refactoring Scheme and Attribute to fix inheritance

* more unit tests

* ConfigProperty is not updating schemes correctly

* All unit tests pass.
Code cleanup

* All unit tests pass.
Code cleanup2

* Fixed unit tests

* Upgraded TextField and TextView

* Fixed TextView !Enabled bug

* More updates to TextView. More unit tests for SchemeManager

* Upgraded CharMap

* API docs

* Fixe HexView API

* upgrade HexView

* Fixed shortcut KeyView

* Fixed more bugs. Added new themes

* updated themes

* upgraded Border

* Fixed themes memory usage...mostly

* Fixed themes memory usage...mostly2

* Fixed themes memory usage...2

* Fixed themes memory usage...3

* Added new colors

* Fixed GetHardCodedConfig bug

* Added Themes Scenario - WIP

* Added Themes Scenario

* Tweaked Themes Scenario

* Code cleanup

* Fixed json schmea

* updated deepdives

* updated deepdives

* Tweaked Themes Scenario

* Made Schemes a concurrent dict

* Test cleanup

* Thread safe ConfigProperty tests

* trying to make things more thread safe

* more trying to make things more thread safe

* Fixing bugs in shadowview

* Fixing bugs in shadowview 2

* Refactored GetViewsUnderMouse to GetViewsUnderLocation etc...

* Fixed dupe unit tests?

* Added better description of layout and coordiantes to deep dive

* Added better description of layout and coordiantes to deep dive

* Modified tests that call v2.AddTimeout; they were returning true which means restart the timer!
This was causing mac/linux unit test failures.
I think

* Fixed auto scheme.
Broke TextView/TextField selection

* Realized Attribute.IsExplicitlySet is stupid; just use nullable

* Fixed Attribute. Simplified. MOre theme testing

* Updated themes again

* GetViewsUnderMouse to GetViewsUnderLocation broke TransparentMouse.

* Fixing mouseunder bugs

* rewriting...

* All working again.
Shadows are now slick as snot.
GetViewsUnderLocation is rewritten to actually work and be readable.
Tons more low-level unit tests.
Margin is now actually ViewportSettings.Transparent.

* Code cleanup

* Code cleanup

* Code cleanup of color apis

* Fixed Hover/Highlight

* Update Examples/UICatalog/Scenarios/AllViewsTester.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update Examples/UICatalog/Scenarios/Clipping.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fixed race condition?

* reverted

* Simplified Attribute API by removing events from SetAttributeForRole

* Removed recursion from GetViewsAtLocation

* Removed unneeded code

* Code clean up.
Fixed Scheme bug.

* reverted temporary disable

* Adjusted scheme algo

* Upgraded TextValidateField

* Fixed TextValidate bugs

* Tweaks

* Frameview rounded border by default

* API doc cleanup

* Readme fix

* Addressed tznind feeback

* Fixed more unit test issues by protecting Application statics from being set if Application.Initialized is not true

* Fixed more unit test issues by protecting Application statics from being set if Application.Initialized is not true 2

* cleanup

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-29 14:08:48 -06:00

272 lines
11 KiB
C#

using System.Globalization;
using JetBrains.Annotations;
using Terminal.Gui;
namespace UICatalog.Scenarios;
[ScenarioMetadata ("ContextMenus", "Context Menu Sample.")]
[ScenarioCategory ("Menus")]
public class ContextMenus : Scenario
{
[CanBeNull]
private PopoverMenu _winContextMenu;
private TextField _tfTopLeft, _tfTopRight, _tfMiddle, _tfBottomLeft, _tfBottomRight;
private readonly List<CultureInfo> _cultureInfos = Application.SupportedCultures;
private readonly Key _winContextMenuKey = Key.Space.WithCtrl;
public override void Main ()
{
// Init
Application.Init ();
// Setup - Create a top-level application window and configure it.
Window appWindow = new ()
{
Title = GetQuitKeyAndName (),
Arrangement = ViewArrangement.Fixed,
SchemeName = "Toplevel"
};
var text = "Context Menu";
var width = 20;
CreateWinContextMenu ();
var label = new Label
{
X = Pos.Center (), Y = 1, Text = $"Press '{_winContextMenuKey}' to open the Window context menu."
};
appWindow.Add (label);
label = new ()
{
X = Pos.Center (),
Y = Pos.Bottom (label),
Text = $"Press '{PopoverMenu.DefaultKey}' to open the TextField context menu."
};
appWindow.Add (label);
_tfTopLeft = new () { Id = "_tfTopLeft", Width = width, Text = text };
appWindow.Add (_tfTopLeft);
_tfTopRight = new () { Id = "_tfTopRight", X = Pos.AnchorEnd (width), Width = width, Text = text };
appWindow.Add (_tfTopRight);
_tfMiddle = new () { Id = "_tfMiddle", X = Pos.Center (), Y = Pos.Center (), Width = width, Text = text };
appWindow.Add (_tfMiddle);
_tfBottomLeft = new () { Id = "_tfBottomLeft", Y = Pos.AnchorEnd (1), Width = width, Text = text };
appWindow.Add (_tfBottomLeft);
_tfBottomRight = new () { Id = "_tfBottomRight", X = Pos.AnchorEnd (width), Y = Pos.AnchorEnd (1), Width = width, Text = text };
appWindow.Add (_tfBottomRight);
appWindow.KeyDown += OnAppWindowOnKeyDown;
appWindow.MouseClick += OnAppWindowOnMouseClick;
CultureInfo originalCulture = Thread.CurrentThread.CurrentUICulture;
appWindow.Closed += (s, e) => { Thread.CurrentThread.CurrentUICulture = originalCulture; };
// Run - Start the application.
Application.Run (appWindow);
appWindow.Dispose ();
appWindow.KeyDown -= OnAppWindowOnKeyDown;
appWindow.MouseClick -= OnAppWindowOnMouseClick;
_winContextMenu?.Dispose ();
// Shutdown - Calling Application.Shutdown is required.
Application.Shutdown ();
return;
void OnAppWindowOnMouseClick (object s, MouseEventArgs e)
{
if (e.Flags == MouseFlags.Button3Clicked)
{
// ReSharper disable once AccessToDisposedClosure
_winContextMenu?.MakeVisible (e.ScreenPosition);
e.Handled = true;
}
}
void OnAppWindowOnKeyDown (object s, Key e)
{
if (e == _winContextMenuKey)
{
// ReSharper disable once AccessToDisposedClosure
_winContextMenu?.MakeVisible ();
e.Handled = true;
}
}
}
private void CreateWinContextMenu ()
{
if (_winContextMenu is { })
{
_winContextMenu.Dispose ();
_winContextMenu = null;
}
_winContextMenu = new (
[
new MenuItemv2
{
Title = "C_ultures",
SubMenu = GetSupportedCultureMenu (),
},
new Line (),
new MenuItemv2
{
Title = "_Configuration...",
HelpText = "Show configuration",
Action = () => MessageBox.Query (
50,
10,
"Configuration",
"This would be a configuration dialog",
"Ok"
)
},
new MenuItemv2
{
Title = "M_ore options",
SubMenu = new (
[
new MenuItemv2
{
Title = "_Setup...",
HelpText = "Perform setup",
Action = () => MessageBox
.Query (
50,
10,
"Setup",
"This would be a setup dialog",
"Ok"
),
Key = Key.T.WithCtrl
},
new MenuItemv2
{
Title = "_Maintenance...",
HelpText = "Maintenance mode",
Action = () => MessageBox
.Query (
50,
10,
"Maintenance",
"This would be a maintenance dialog",
"Ok"
)
}
])
},
new Line (),
new MenuItemv2
{
Title = "_Quit",
Action = () => Application.RequestStop ()
}
])
{
Key = _winContextMenuKey
};
}
private Menuv2 GetSupportedCultureMenu ()
{
List<MenuItemv2> supportedCultures = [];
int index = -1;
foreach (CultureInfo c in _cultureInfos)
{
MenuItemv2 culture = new ();
culture.CommandView = new CheckBox { CanFocus = false };
if (index == -1)
{
// Create English because GetSupportedCutures doesn't include it
culture.Id = "_English";
culture.Title = "_English";
culture.HelpText = "en-US";
((CheckBox)culture.CommandView).CheckedState =
Thread.CurrentThread.CurrentUICulture.Name == "en-US" ? CheckState.Checked : CheckState.UnChecked;
CreateAction (supportedCultures, culture);
supportedCultures.Add (culture);
index++;
culture = new ();
culture.CommandView = new CheckBox { CanFocus = false };
}
culture.Id = $"_{c.Parent.EnglishName}";
culture.Title = $"_{c.Parent.EnglishName}";
culture.HelpText = c.Name;
((CheckBox)culture.CommandView).CheckedState =
Thread.CurrentThread.CurrentUICulture.Name == culture.HelpText ? CheckState.Checked : CheckState.UnChecked;
CreateAction (supportedCultures, culture);
supportedCultures.Add (culture);
}
Menuv2 menu = new (supportedCultures.ToArray ());
return menu;
void CreateAction (List<MenuItemv2> cultures, MenuItemv2 culture)
{
culture.Action += () =>
{
Thread.CurrentThread.CurrentUICulture = new (culture.HelpText);
foreach (MenuItemv2 item in cultures)
{
((CheckBox)item.CommandView).CheckedState =
Thread.CurrentThread.CurrentUICulture.Name == item.HelpText ? CheckState.Checked : CheckState.UnChecked;
}
};
}
}
public override List<Key> GetDemoKeyStrokes ()
{
List<Key> keys = new ();
keys.Add (Key.F10.WithShift);
keys.Add (Key.Esc);
keys.Add (Key.Space.WithCtrl);
keys.Add (Key.CursorDown);
keys.Add (Key.Enter);
keys.Add (Key.F10.WithShift);
keys.Add (Key.Esc);
keys.Add (Key.Tab);
keys.Add (Key.Space.WithCtrl);
keys.Add (Key.CursorDown);
keys.Add (Key.CursorDown);
keys.Add (Key.Enter);
keys.Add (Key.F10.WithShift);
keys.Add (Key.Esc);
keys.Add (Key.Tab);
keys.Add (Key.Space.WithCtrl);
keys.Add (Key.CursorDown);
keys.Add (Key.CursorDown);
keys.Add (Key.CursorDown);
keys.Add (Key.Enter);
keys.Add (Key.F10.WithShift);
keys.Add (Key.Esc);
return keys;
}
}