using NStack;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using Terminal.Gui;
using Rune = System.Rune;
///
/// UI Catalog is a comprehensive sample library for Terminal.Gui. It provides a simple UI for adding to the catalog of scenarios.
///
///
///
/// UI Catalog attempts to satisfy the following goals:
///
///
///
/// -
///
/// Be an easy to use showcase for Terminal.Gui concepts and features.
///
///
/// -
///
/// Provide sample code that illustrates how to properly implement said concepts & features.
///
///
/// -
///
/// Make it easy for contributors to add additional samples in a structured way.
///
///
///
///
///
/// See the project README for more details (https://github.com/migueldeicaza/gui.cs/tree/master/UICatalog/README.md).
///
///
namespace UICatalog {
///
/// UI Catalog is a comprehensive sample app and scenario library for
///
public class UICatalogApp {
private static Toplevel _top;
private static MenuBar _menu;
private static int _nameColumnWidth;
private static FrameView _leftPane;
private static List _categories;
private static ListView _categoryListView;
private static FrameView _rightPane;
private static List _scenarios;
private static ListView _scenarioListView;
private static StatusBar _statusBar;
private static StatusItem _capslock;
private static StatusItem _numlock;
private static StatusItem _scrolllock;
private static int _categoryListViewItem;
private static int _scenarioListViewItem;
private static Scenario _runningScenario = null;
private static bool _useSystemConsole = false;
private static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
private static bool _heightAsBuffer = false;
private static bool _isFirstRunning = true;
static void Main (string [] args)
{
Console.OutputEncoding = Encoding.Default;
if (Debugger.IsAttached)
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
_scenarios = Scenario.GetDerivedClasses ().OrderBy (t => Scenario.ScenarioMetadata.GetName (t)).ToList ();
if (args.Length > 0 && args.Contains ("-usc")) {
_useSystemConsole = true;
args = args.Where (val => val != "-usc").ToArray ();
}
if (args.Length > 0) {
var item = _scenarios.FindIndex (t => Scenario.ScenarioMetadata.GetName (t).Equals (args [0], StringComparison.OrdinalIgnoreCase));
_runningScenario = (Scenario)Activator.CreateInstance (_scenarios [item]);
Application.UseSystemConsole = _useSystemConsole;
Application.Init ();
_runningScenario.Init (Application.Top, _baseColorScheme);
_runningScenario.Setup ();
_runningScenario.Run ();
_runningScenario = null;
Application.Shutdown ();
return;
}
Scenario scenario;
while ((scenario = GetScenarioToRun ()) != null) {
#if DEBUG_IDISPOSABLE
// Validate there are no outstanding Responder-based instances
// after a scenario was selected to run. This proves the main UI Catalog
// 'app' closed cleanly.
foreach (var inst in Responder.Instances) {
Debug.Assert (inst.WasDisposed);
}
Responder.Instances.Clear ();
#endif
scenario.Init (Application.Top, _baseColorScheme);
scenario.Setup ();
scenario.Run ();
//static void LoadedHandler ()
//{
// _rightPane.SetFocus ();
// _top.Loaded -= LoadedHandler;
//}
//_top.Loaded += LoadedHandler;
Application.Shutdown ();
#if DEBUG_IDISPOSABLE
// After the scenario runs, validate all Responder-based instances
// were disposed. This proves the scenario 'app' closed cleanly.
foreach (var inst in Responder.Instances) {
Debug.Assert (inst.WasDisposed);
}
Responder.Instances.Clear ();
#endif
}
Application.Shutdown ();
#if DEBUG_IDISPOSABLE
// This proves that when the user exited the UI Catalog app
// it cleaned up properly.
foreach (var inst in Responder.Instances) {
Debug.Assert (inst.WasDisposed);
}
Responder.Instances.Clear ();
#endif
}
///
/// This shows the selection UI. Each time it is run, it calls Application.Init to reset everything.
///
///
private static Scenario GetScenarioToRun ()
{
Application.UseSystemConsole = _useSystemConsole;
Application.Init ();
Application.HeightAsBuffer = _heightAsBuffer;
// Set this here because not initialized until driver is loaded
_baseColorScheme = Colors.Base;
StringBuilder aboutMessage = new StringBuilder ();
aboutMessage.AppendLine ("UI Catalog is a comprehensive sample library for Terminal.Gui");
aboutMessage.AppendLine (@" _ ");
aboutMessage.AppendLine (@" __ _ _ _(_) ___ ___ ");
aboutMessage.AppendLine (@" / _` | | | | | / __/ __|");
aboutMessage.AppendLine (@"| (_| | |_| | || (__\__ \");
aboutMessage.AppendLine (@" \__, |\__,_|_(_)___|___/");
aboutMessage.AppendLine (@" |___/ ");
aboutMessage.AppendLine ("");
aboutMessage.AppendLine ($"Version: {typeof (UICatalogApp).Assembly.GetName ().Version}");
aboutMessage.AppendLine ($"Using Terminal.Gui Version: {FileVersionInfo.GetVersionInfo (typeof (Terminal.Gui.Application).Assembly.Location).ProductVersion}");
aboutMessage.AppendLine ("");
_menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("_Quit", "", () => Application.RequestStop(), null, null, Key.Q | Key.CtrlMask)
}),
new MenuBarItem ("_Color Scheme", CreateColorSchemeMenuItems()),
new MenuBarItem ("Diag_nostics", CreateDiagnosticMenuItems()),
new MenuBarItem ("_Help", new MenuItem [] {
new MenuItem ("_gui.cs API Overview", "", () => OpenUrl ("https://migueldeicaza.github.io/gui.cs/articles/overview.html"), null, null, Key.F1),
new MenuItem ("gui.cs _README", "", () => OpenUrl ("https://github.com/migueldeicaza/gui.cs"), null, null, Key.F2),
new MenuItem ("_About...", "About this app", () => MessageBox.Query ("About UI Catalog", aboutMessage.ToString(), "_Ok"), null, null, Key.CtrlMask | Key.A),
})
});
_leftPane = new FrameView ("Categories") {
X = 0,
Y = 1, // for menu
Width = 25,
Height = Dim.Fill (1),
CanFocus = false,
Shortcut = Key.CtrlMask | Key.C
};
_leftPane.Title = $"{_leftPane.Title} ({_leftPane.ShortcutTag})";
_leftPane.ShortcutAction = () => _leftPane.SetFocus ();
_categories = Scenario.GetAllCategories ();
_categoryListView = new ListView (_categories) {
X = 0,
Y = 0,
Width = Dim.Fill (0),
Height = Dim.Fill (0),
AllowsMarking = false,
CanFocus = true,
};
_categoryListView.OpenSelectedItem += (a) => {
_rightPane.SetFocus ();
};
_categoryListView.SelectedItemChanged += CategoryListView_SelectedChanged;
_leftPane.Add (_categoryListView);
_rightPane = new FrameView ("Scenarios") {
X = 25,
Y = 1, // for menu
Width = Dim.Fill (),
Height = Dim.Fill (1),
CanFocus = true,
Shortcut = Key.CtrlMask | Key.S
};
_rightPane.Title = $"{_rightPane.Title} ({_rightPane.ShortcutTag})";
_rightPane.ShortcutAction = () => _rightPane.SetFocus ();
_nameColumnWidth = Scenario.ScenarioMetadata.GetName (_scenarios.OrderByDescending (t => Scenario.ScenarioMetadata.GetName (t).Length).FirstOrDefault ()).Length;
_scenarioListView = new ListView () {
X = 0,
Y = 0,
Width = Dim.Fill (0),
Height = Dim.Fill (0),
AllowsMarking = false,
CanFocus = true,
};
_scenarioListView.OpenSelectedItem += _scenarioListView_OpenSelectedItem;
_rightPane.Add (_scenarioListView);
_categoryListView.SelectedItem = _categoryListViewItem;
_categoryListView.OnSelectedChanged ();
_capslock = new StatusItem (Key.CharMask, "Caps", null);
_numlock = new StatusItem (Key.CharMask, "Num", null);
_scrolllock = new StatusItem (Key.CharMask, "Scroll", null);
_statusBar = new StatusBar () {
Visible = true,
};
_statusBar.Items = new StatusItem [] {
_capslock,
_numlock,
_scrolllock,
new StatusItem(Key.Q | Key.CtrlMask, "~CTRL-Q~ Quit", () => {
if (_runningScenario is null){
// This causes GetScenarioToRun to return null
_runningScenario = null;
Application.RequestStop();
} else {
_runningScenario.RequestStop();
}
}),
new StatusItem(Key.F10, "~F10~ Hide/Show Status Bar", () => {
_statusBar.Visible = !_statusBar.Visible;
_leftPane.Height = Dim.Fill(_statusBar.Visible ? 1 : 0);
_rightPane.Height = Dim.Fill(_statusBar.Visible ? 1 : 0);
_top.LayoutSubviews();
_top.SetChildNeedsDisplay();
}),
new StatusItem (Key.CharMask, Application.Driver.GetType ().Name, null),
};
SetColorScheme ();
_top = Application.Top;
_top.KeyDown += KeyDownHandler;
_top.Add (_menu);
_top.Add (_leftPane);
_top.Add (_rightPane);
_top.Add (_statusBar);
void TopHandler () {
if (_runningScenario != null) {
_runningScenario = null;
_isFirstRunning = false;
}
if (!_isFirstRunning) {
_rightPane.SetFocus ();
}
_top.Loaded -= TopHandler;
}
_top.Loaded += TopHandler;
// The following code was moved to the TopHandler event
// because in the MainLoop.EventsPending (wait)
// from the Application.RunLoop with the WindowsDriver
// the OnReady event is triggered due the Focus event.
// On CursesDriver and NetDriver the focus event won't be triggered
// and if it's possible I don't know how to do it.
//void ReadyHandler ()
//{
// if (!_isFirstRunning) {
// _rightPane.SetFocus ();
// }
// _top.Ready -= ReadyHandler;
//}
//_top.Ready += ReadyHandler;
Application.Run (_top);
return _runningScenario;
}
static List