mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-29 01:07:58 +01:00
Added Main to Scenario. Updated a few scenarios to test out.
This commit is contained in:
@@ -93,7 +93,7 @@ public static partial class Application
|
||||
{
|
||||
t.Running = false;
|
||||
#if DEBUG_IDISPOSABLE
|
||||
// Don't dispose the tolevels. It's up to caller dispose them
|
||||
// Don't dispose the toplevels. It's up to caller dispose them
|
||||
Debug.Assert (t.WasDisposed);
|
||||
#endif
|
||||
}
|
||||
@@ -105,7 +105,7 @@ public static partial class Application
|
||||
if (Top is { })
|
||||
{
|
||||
Debug.Assert (Top.WasDisposed);
|
||||
// If End wasn't called _latestClosedRunStateToplevel may be null
|
||||
// If End wasn't called _cachedRunStateToplevel may be null
|
||||
if (_cachedRunStateToplevel is { })
|
||||
{
|
||||
Debug.Assert (_cachedRunStateToplevel.WasDisposed);
|
||||
@@ -246,7 +246,8 @@ public static partial class Application
|
||||
// multiple times. We need to do this because some settings are only
|
||||
// valid after a Driver is loaded. In this cases we need just
|
||||
// `Settings` so we can determine which driver to use.
|
||||
Load (true);
|
||||
// Don't reset, so we can inherit the theme from the previous run.
|
||||
Load (false);
|
||||
Apply ();
|
||||
|
||||
// Ignore Configuration for ForceDriver if driverName is specified
|
||||
@@ -350,6 +351,7 @@ public static partial class Application
|
||||
/// </remarks>
|
||||
public static void Shutdown ()
|
||||
{
|
||||
// TODO: Throw an exception if Init hasn't been called.
|
||||
ResetState ();
|
||||
PrintJsonErrors ();
|
||||
}
|
||||
|
||||
@@ -147,9 +147,8 @@ public static class ConfigurationManager
|
||||
{
|
||||
if (_settings is null)
|
||||
{
|
||||
throw new InvalidOperationException (
|
||||
"ConfigurationManager has not been initialized. Call ConfigurationManager.Reset() before accessing the Settings property."
|
||||
);
|
||||
// If Settings is null, we need to initialize it.
|
||||
Reset ();
|
||||
}
|
||||
|
||||
return _settings;
|
||||
|
||||
@@ -88,18 +88,6 @@ public class Scenario : IDisposable
|
||||
/// </summary>
|
||||
public Window Win { get; set; }
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
// BUGBUG: Top should have already been disposed. We dispose it here until we can fix the scenarios that are doing it wrong.
|
||||
Top?.Dispose ();
|
||||
|
||||
// We created Win, so we Dispose it.
|
||||
Win?.Dispose ();
|
||||
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to get the list of categories a <see cref="Scenario"/> belongs to (defined in
|
||||
@@ -140,6 +128,15 @@ public class Scenario : IDisposable
|
||||
return objects.OrderBy (s => s.GetName ()).ToList ();
|
||||
}
|
||||
|
||||
|
||||
public virtual void Main ()
|
||||
{
|
||||
Init ();
|
||||
Setup ();
|
||||
Run ();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Helper that calls <see cref="Application.Init"/> and creates the default <see cref="Terminal.Gui.Window"/> implementation with a frame and label
|
||||
/// showing the name of the <see cref="Scenario"/> and logic to exit back to the Scenario picker UI. Override
|
||||
@@ -186,7 +183,7 @@ public class Scenario : IDisposable
|
||||
/// </remarks>
|
||||
public virtual void Run ()
|
||||
{
|
||||
// Must explicit call Application.Shutdown method to shutdown.
|
||||
// Must explicitly call Application.Shutdown method to shutdown.
|
||||
Application.Run (Top);
|
||||
}
|
||||
|
||||
@@ -197,6 +194,13 @@ public class Scenario : IDisposable
|
||||
/// <summary>Gets the Scenario Name + Description with the Description padded based on the longest known Scenario name.</summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString () { return $"{GetName ().PadRight (_maxScenarioNameLen)}{GetDescription ()}"; }
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
@@ -204,11 +208,10 @@ public class Scenario : IDisposable
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: dispose managed state (managed objects)
|
||||
Top?.Dispose ();
|
||||
Win?.Dispose ();
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// TODO: set large fields to null
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,6 +354,20 @@ public class BackgroundWorkerCollection : Scenario
|
||||
Source = new ListWrapper (_log)
|
||||
};
|
||||
Add (_listLog);
|
||||
|
||||
Closing += WorkerApp_Closing;
|
||||
}
|
||||
private void WorkerApp_Closing (object sender, ToplevelClosingEventArgs e)
|
||||
{
|
||||
Toplevel top = Application.OverlappedChildren.Find (x => x.Data.ToString () == "WorkerApp");
|
||||
|
||||
if (Visible && top == this)
|
||||
{
|
||||
Visible = false;
|
||||
e.Cancel = true;
|
||||
|
||||
Application.OverlappedMoveNext ();
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelWorker ()
|
||||
|
||||
@@ -6,21 +6,18 @@ namespace UICatalog.Scenarios;
|
||||
[ScenarioCategory ("Unicode")]
|
||||
public class ChineseUI : Scenario
|
||||
{
|
||||
public override void Init ()
|
||||
public override void Main ()
|
||||
{
|
||||
Application.Init ();
|
||||
|
||||
Toplevel top = new ();
|
||||
|
||||
var win = new Window
|
||||
{
|
||||
Title = "Test",
|
||||
Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Width = Dim.Fill (),
|
||||
Height = Dim.Fill ()
|
||||
};
|
||||
top.Add (win);
|
||||
|
||||
var buttonPanel = new FrameView
|
||||
{
|
||||
@@ -35,20 +32,20 @@ public class ChineseUI : Scenario
|
||||
var btn = new Button { X = 1, Y = 1, Text = "你" }; // v1: A
|
||||
|
||||
btn.Accept += (s, e) =>
|
||||
{
|
||||
int result = MessageBox.Query (
|
||||
"Confirm",
|
||||
"Are you sure you want to quit ui?",
|
||||
0,
|
||||
"Yes",
|
||||
"No"
|
||||
);
|
||||
{
|
||||
int result = MessageBox.Query (
|
||||
"Confirm",
|
||||
"Are you sure you want to quit ui?",
|
||||
0,
|
||||
"Yes",
|
||||
"No"
|
||||
);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
Application.RequestStop ();
|
||||
}
|
||||
};
|
||||
if (result == 0)
|
||||
{
|
||||
Application.RequestStop ();
|
||||
}
|
||||
};
|
||||
|
||||
buttonPanel.Add (
|
||||
btn,
|
||||
@@ -56,10 +53,10 @@ public class ChineseUI : Scenario
|
||||
new Button { X = 22, Y = 1, Text = "呀" } // v1: C
|
||||
);
|
||||
|
||||
Application.Run (top);
|
||||
Application.Run (win);
|
||||
|
||||
top.Dispose ();
|
||||
win.Dispose ();
|
||||
|
||||
Application.Shutdown ();
|
||||
}
|
||||
|
||||
public override void Run () { }
|
||||
}
|
||||
|
||||
@@ -4,37 +4,28 @@ namespace UICatalog.Scenarios;
|
||||
|
||||
[ScenarioMetadata ("Generic", "Generic sample - A template for creating new Scenarios")]
|
||||
[ScenarioCategory ("Controls")]
|
||||
public class MyScenario : Scenario
|
||||
public sealed class MyScenario : Scenario
|
||||
{
|
||||
public override void Init ()
|
||||
public override void Main ()
|
||||
{
|
||||
// The base `Scenario.Init` implementation:
|
||||
// - Calls `Application.Init ()`
|
||||
// - Adds a full-screen Window to Application.Top with a title
|
||||
// that reads "Press <hotkey> to Quit". Access this Window with `this.Win`.
|
||||
// - Sets the Theme & the ColorScheme property of `this.Win` to `colorScheme`.
|
||||
// To override this, implement an override of `Init`.
|
||||
|
||||
//base.Init ();
|
||||
|
||||
// A common, alternate, implementation where `this.Win` is not used is below. This code
|
||||
// leverages ConfigurationManager to borrow the color scheme settings from UICatalog:
|
||||
|
||||
// Init
|
||||
Application.Init ();
|
||||
ConfigurationManager.Themes.Theme = Theme;
|
||||
ConfigurationManager.Apply ();
|
||||
Top = new Toplevel ();
|
||||
Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
|
||||
}
|
||||
|
||||
public override void Setup ()
|
||||
{
|
||||
// Put scenario code here (in a real app, this would be the code
|
||||
// that would setup the app before `Application.Run` is called`).
|
||||
// With a Scenario, after UI Catalog calls `Scenario.Setup` it calls
|
||||
// `Scenario.Run` which calls `Application.Run`. Example:
|
||||
// Setup - Create a top-level application window and configure it.
|
||||
Window appWindow = new ()
|
||||
{
|
||||
Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}"
|
||||
};
|
||||
|
||||
var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
|
||||
Top.Add (button);
|
||||
button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed the button!", "Ok");
|
||||
appWindow.Add (button);
|
||||
|
||||
// Run - Start the application.
|
||||
Application.Run (appWindow);
|
||||
appWindow.Dispose ();
|
||||
|
||||
// Shutdown - Calling Application.Shutdown is required.
|
||||
Application.Shutdown ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,15 +12,92 @@ public class Notepad : Scenario
|
||||
{
|
||||
private TabView _focusedTabView;
|
||||
private StatusItem _lenStatusItem;
|
||||
private int _numbeOfNewTabs = 1;
|
||||
private int _numNewTabs = 1;
|
||||
private TabView _tabView;
|
||||
|
||||
// Don't create a Window, just return the top-level view
|
||||
public override void Init ()
|
||||
public override void Main ()
|
||||
{
|
||||
Application.Init ();
|
||||
Top = new ();
|
||||
Top.ColorScheme = Colors.ColorSchemes ["Base"];
|
||||
|
||||
Toplevel top = new ();
|
||||
|
||||
var menu = new MenuBar
|
||||
{
|
||||
Menus =
|
||||
[
|
||||
new (
|
||||
"_File",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_New",
|
||||
"",
|
||||
() => New (),
|
||||
null,
|
||||
null,
|
||||
KeyCode.N
|
||||
| KeyCode.CtrlMask
|
||||
| KeyCode.AltMask
|
||||
),
|
||||
new ("_Open", "", () => Open ()),
|
||||
new ("_Save", "", () => Save ()),
|
||||
new ("Save _As", "", () => SaveAs ()),
|
||||
new ("_Close", "", () => Close ()),
|
||||
new ("_Quit", "", () => Quit ())
|
||||
}
|
||||
),
|
||||
new (
|
||||
"_About",
|
||||
"",
|
||||
() => MessageBox.Query ("Notepad", "About Notepad...", "Ok")
|
||||
)
|
||||
]
|
||||
};
|
||||
top.Add (menu);
|
||||
|
||||
_tabView = CreateNewTabView ();
|
||||
|
||||
_tabView.Style.ShowBorder = true;
|
||||
_tabView.ApplyStyleChanges ();
|
||||
|
||||
// Start with only a single view but support splitting to show side by side
|
||||
var split = new TileView (1) { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill (1) };
|
||||
split.Tiles.ElementAt (0).ContentView.Add (_tabView);
|
||||
split.LineStyle = LineStyle.None;
|
||||
|
||||
top.Add (split);
|
||||
|
||||
_lenStatusItem = new (KeyCode.CharMask, "Len: ", null);
|
||||
|
||||
var statusBar = new StatusBar (
|
||||
new []
|
||||
{
|
||||
new (
|
||||
Application.QuitKey,
|
||||
$"{Application.QuitKey} to Quit",
|
||||
() => Quit ()
|
||||
),
|
||||
|
||||
// These shortcut keys don't seem to work correctly in linux
|
||||
//new StatusItem(Key.CtrlMask | Key.N, "~^O~ Open", () => Open()),
|
||||
//new StatusItem(Key.CtrlMask | Key.N, "~^N~ New", () => New()),
|
||||
|
||||
new (KeyCode.CtrlMask | KeyCode.S, "~^S~ Save", () => Save ()),
|
||||
new (KeyCode.CtrlMask | KeyCode.W, "~^W~ Close", () => Close ()),
|
||||
_lenStatusItem
|
||||
}
|
||||
);
|
||||
_focusedTabView = _tabView;
|
||||
_tabView.SelectedTabChanged += TabView_SelectedTabChanged;
|
||||
_tabView.Enter += (s, e) => _focusedTabView = _tabView;
|
||||
|
||||
top.Add (statusBar);
|
||||
top.Ready += (s, e) => New ();
|
||||
|
||||
Application.Run (top);
|
||||
top.Dispose ();
|
||||
|
||||
Application.Shutdown ();
|
||||
}
|
||||
|
||||
public void Save () { Save (_focusedTabView, _focusedTabView.SelectedTab); }
|
||||
@@ -58,99 +135,26 @@ public class Notepad : Scenario
|
||||
if (string.IsNullOrWhiteSpace (fd.Path))
|
||||
{
|
||||
fd.Dispose ();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fd.Canceled)
|
||||
{
|
||||
fd.Dispose ();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
tab.File = new FileInfo (fd.Path);
|
||||
tab.File = new (fd.Path);
|
||||
tab.Text = fd.FileName;
|
||||
tab.Save ();
|
||||
|
||||
fd.Dispose ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Setup ()
|
||||
{
|
||||
var menu = new MenuBar
|
||||
{
|
||||
Menus =
|
||||
[
|
||||
new MenuBarItem (
|
||||
"_File",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_New",
|
||||
"",
|
||||
() => New (),
|
||||
null,
|
||||
null,
|
||||
KeyCode.N
|
||||
| KeyCode.CtrlMask
|
||||
| KeyCode.AltMask
|
||||
),
|
||||
new ("_Open", "", () => Open ()),
|
||||
new ("_Save", "", () => Save ()),
|
||||
new ("Save _As", "", () => SaveAs ()),
|
||||
new ("_Close", "", () => Close ()),
|
||||
new ("_Quit", "", () => Quit ())
|
||||
}
|
||||
),
|
||||
new MenuBarItem (
|
||||
"_About",
|
||||
"",
|
||||
() => MessageBox.Query ("Notepad", "About Notepad...", "Ok")
|
||||
)
|
||||
]
|
||||
};
|
||||
Top.Add (menu);
|
||||
|
||||
_tabView = CreateNewTabView ();
|
||||
|
||||
_tabView.Style.ShowBorder = true;
|
||||
_tabView.ApplyStyleChanges ();
|
||||
|
||||
// Start with only a single view but support splitting to show side by side
|
||||
var split = new TileView (1) { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill (1) };
|
||||
split.Tiles.ElementAt (0).ContentView.Add (_tabView);
|
||||
split.LineStyle = LineStyle.None;
|
||||
|
||||
Top.Add (split);
|
||||
|
||||
_lenStatusItem = new StatusItem (KeyCode.CharMask, "Len: ", null);
|
||||
|
||||
var statusBar = new StatusBar (
|
||||
new []
|
||||
{
|
||||
new (
|
||||
Application.QuitKey,
|
||||
$"{Application.QuitKey} to Quit",
|
||||
() => Quit ()
|
||||
),
|
||||
|
||||
// These shortcut keys don't seem to work correctly in linux
|
||||
//new StatusItem(Key.CtrlMask | Key.N, "~^O~ Open", () => Open()),
|
||||
//new StatusItem(Key.CtrlMask | Key.N, "~^N~ New", () => New()),
|
||||
|
||||
new (KeyCode.CtrlMask | KeyCode.S, "~^S~ Save", () => Save ()),
|
||||
new (KeyCode.CtrlMask | KeyCode.W, "~^W~ Close", () => Close ()),
|
||||
_lenStatusItem
|
||||
}
|
||||
);
|
||||
_focusedTabView = _tabView;
|
||||
_tabView.SelectedTabChanged += TabView_SelectedTabChanged;
|
||||
_tabView.Enter += (s, e) => _focusedTabView = _tabView;
|
||||
|
||||
Top.Add (statusBar);
|
||||
Top.Ready += (s, e) => New ();
|
||||
}
|
||||
|
||||
private void Close () { Close (_focusedTabView, _focusedTabView.SelectedTab); }
|
||||
|
||||
private void Close (TabView tv, Tab tabToClose)
|
||||
@@ -244,7 +248,7 @@ public class Notepad : Scenario
|
||||
return tv;
|
||||
}
|
||||
|
||||
private void New () { Open (null, $"new {_numbeOfNewTabs++}"); }
|
||||
private void New () { Open (null, $"new {_numNewTabs++}"); }
|
||||
|
||||
private void Open ()
|
||||
{
|
||||
@@ -264,7 +268,7 @@ public class Notepad : Scenario
|
||||
}
|
||||
|
||||
// TODO should open in focused TabView
|
||||
Open (new FileInfo (path), Path.GetFileName (path));
|
||||
Open (new (path), Path.GetFileName (path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,27 +339,27 @@ public class Notepad : Scenario
|
||||
|
||||
if (e.Tab == null)
|
||||
{
|
||||
items = new MenuBarItem (
|
||||
new MenuItem [] { new ("Open", "", () => Open ()) }
|
||||
);
|
||||
items = new (
|
||||
new MenuItem [] { new ("Open", "", () => Open ()) }
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
var tv = (TabView)sender;
|
||||
var t = (OpenedFile)e.Tab;
|
||||
|
||||
items = new MenuBarItem (
|
||||
new MenuItem []
|
||||
{
|
||||
new ("Save", "", () => Save (_focusedTabView, e.Tab)),
|
||||
new ("Close", "", () => Close (tv, e.Tab)),
|
||||
null,
|
||||
new ("Split Up", "", () => SplitUp (tv, t)),
|
||||
new ("Split Down", "", () => SplitDown (tv, t)),
|
||||
new ("Split Right", "", () => SplitRight (tv, t)),
|
||||
new ("Split Left", "", () => SplitLeft (tv, t))
|
||||
}
|
||||
);
|
||||
items = new (
|
||||
new MenuItem []
|
||||
{
|
||||
new ("Save", "", () => Save (_focusedTabView, e.Tab)),
|
||||
new ("Close", "", () => Close (tv, e.Tab)),
|
||||
null,
|
||||
new ("Split Up", "", () => SplitUp (tv, t)),
|
||||
new ("Split Down", "", () => SplitDown (tv, t)),
|
||||
new ("Split Right", "", () => SplitRight (tv, t)),
|
||||
new ("Split Left", "", () => SplitLeft (tv, t))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Rectangle screen = ((View)sender).BoundsToScreen (new (e.MouseEvent.X, e.MouseEvent.Y, 0, 0));
|
||||
@@ -368,14 +372,6 @@ public class Notepad : Scenario
|
||||
|
||||
private class OpenedFile : Tab
|
||||
{
|
||||
public FileInfo File { get; set; }
|
||||
|
||||
/// <summary>The text of the tab the last time it was saved</summary>
|
||||
/// <value></value>
|
||||
public string SavedText { get; set; }
|
||||
|
||||
public bool UnsavedChanges => !string.Equals (SavedText, View.Text);
|
||||
|
||||
public OpenedFile CloneTo (TabView other)
|
||||
{
|
||||
var newTab = new OpenedFile { DisplayText = base.Text, File = File };
|
||||
@@ -407,6 +403,8 @@ public class Notepad : Scenario
|
||||
};
|
||||
}
|
||||
|
||||
public FileInfo File { get; set; }
|
||||
|
||||
public void RegisterTextViewEvents (TabView parent)
|
||||
{
|
||||
var textView = (TextView)View;
|
||||
@@ -436,6 +434,12 @@ public class Notepad : Scenario
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>The text of the tab the last time it was saved</summary>
|
||||
/// <value></value>
|
||||
public string SavedText { get; set; }
|
||||
|
||||
public bool UnsavedChanges => !string.Equals (SavedText, View.Text);
|
||||
|
||||
internal void Save ()
|
||||
{
|
||||
string newText = View.Text;
|
||||
|
||||
@@ -290,11 +290,10 @@ internal class UICatalogApp
|
||||
Application.Init (driverName: _forceDriver);
|
||||
_selectedScenario.Theme = _cachedTheme;
|
||||
_selectedScenario.TopLevelColorScheme = _topLevelColorScheme;
|
||||
_selectedScenario.Init ();
|
||||
_selectedScenario.Setup ();
|
||||
_selectedScenario.Run ();
|
||||
_selectedScenario.Main ();
|
||||
_selectedScenario.Dispose ();
|
||||
_selectedScenario = null;
|
||||
// TODO: Throw if shutdown was not called already
|
||||
Application.Shutdown ();
|
||||
VerifyObjectsWereDisposed ();
|
||||
|
||||
@@ -322,13 +321,12 @@ internal class UICatalogApp
|
||||
Apply ();
|
||||
scenario.Theme = _cachedTheme;
|
||||
scenario.TopLevelColorScheme = _topLevelColorScheme;
|
||||
scenario.Init ();
|
||||
scenario.Setup ();
|
||||
scenario.Run ();
|
||||
scenario.Main ();
|
||||
scenario.Dispose ();
|
||||
|
||||
// This call to Application.Shutdown brackets the Application.Init call
|
||||
// made by Scenario.Init() above
|
||||
// TODO: Throw if shutdown was not called already
|
||||
Application.Shutdown ();
|
||||
|
||||
VerifyObjectsWereDisposed ();
|
||||
|
||||
Reference in New Issue
Block a user