Manual checkout from v2_develop

This commit is contained in:
Tig Kindel
2024-02-12 14:35:55 -07:00
parent 2c040fff27
commit 109bf47eca
6 changed files with 920 additions and 787 deletions

View File

@@ -1,57 +1,147 @@
namespace Terminal.Gui;
/// <summary>
/// Toplevel views are used for both an application's main view (filling the entire screen and
/// for modal (pop-up) views such as <see cref="Dialog"/>, <see cref="MessageBox"/>, and
/// <see cref="Wizard"/>).
/// Toplevel views are used for both an application's main view (filling the entire screen and for modal (pop-up)
/// views such as <see cref="Dialog"/>, <see cref="MessageBox"/>, and <see cref="Wizard"/>).
/// </summary>
/// <remarks>
/// <para>
/// Toplevels can run as modal (popup) views, started by calling
/// <see cref="Application.Run(Toplevel, Func{Exception,bool})"/>.
/// They return control to the caller when <see cref="Application.RequestStop(Toplevel)"/> has
/// been called (which sets the <see cref="Toplevel.Running"/> property to <c>false</c>).
/// <see cref="Application.Run(Toplevel, Func{Exception,bool})"/>. They return control to the caller when
/// <see cref="Application.RequestStop(Toplevel)"/> has been called (which sets the <see cref="Toplevel.Running"/>
/// property to <c>false</c>).
/// </para>
/// <para>
/// A Toplevel is created when an application initializes Terminal.Gui by calling
/// <see cref="Application.Init"/>.
/// The application Toplevel can be accessed via <see cref="Application.Top"/>. Additional
/// Toplevels can be created
/// and run (e.g. <see cref="Dialog"/>s. To run a Toplevel, create the <see cref="Toplevel"/> and
/// call <see cref="Application.Run(Toplevel, Func{Exception,bool})"/>.
/// A Toplevel is created when an application initializes Terminal.Gui by calling <see cref="Application.Init"/>.
/// The application Toplevel can be accessed via <see cref="Application.Top"/>. Additional Toplevels can be created
/// and run (e.g. <see cref="Dialog"/>s. To run a Toplevel, create the <see cref="Toplevel"/> and call
/// <see cref="Application.Run(Toplevel, Func{Exception,bool})"/>.
/// </para>
/// </remarks>
public partial class Toplevel : View
{
internal static Point? _dragPosition;
private Point _startGrabPoint;
/// <summary>
/// Initializes a new instance of the <see cref="Toplevel"/> class with the specified
/// <see cref="LayoutStyle.Absolute"/> layout.
/// </summary>
/// <param name="frame">
/// A Superview-relative rectangle specifying the location and size for the new
/// Toplevel
/// </param>
public Toplevel (Rect frame) : base (frame) { SetInitialProperties (); }
/// <summary>
/// Initializes a new instance of the <see cref="Toplevel"/> class with
/// <see cref="LayoutStyle.Computed"/> layout, defaulting to full screen. The <see cref="View.Width"/> and
/// <see cref="View.Height"/> properties
/// will be set to the dimensions of the terminal using <see cref="Dim.Fill"/>.
/// Initializes a new instance of the <see cref="Toplevel"/> class with <see cref="LayoutStyle.Computed"/> layout,
/// defaulting to full screen. The <see cref="View.Width"/> and <see cref="View.Height"/> properties will be set to the
/// dimensions of the terminal using <see cref="Dim.Fill"/>.
/// </summary>
public Toplevel ()
{
SetInitialProperties ();
Width = Dim.Fill ();
Height = Dim.Fill ();
ColorScheme = Colors.ColorSchemes ["TopLevel"];
Application.GrabbingMouse += Application_GrabbingMouse;
Application.UnGrabbingMouse += Application_UnGrabbingMouse;
// TODO: v2 - ALL Views (Responders??!?!) should support the commands related to
// - Focus
// Move the appropriate AddCommand calls to `Responder`
// Things this view knows how to do
AddCommand (
Command.QuitToplevel,
() =>
{
QuitToplevel ();
return true;
}
);
AddCommand (
Command.Suspend,
() =>
{
Driver.Suspend ();
;
return true;
}
);
AddCommand (
Command.NextView,
() =>
{
MoveNextView ();
return true;
}
);
AddCommand (
Command.PreviousView,
() =>
{
MovePreviousView ();
return true;
}
);
AddCommand (
Command.NextViewOrTop,
() =>
{
MoveNextViewOrTop ();
return true;
}
);
AddCommand (
Command.PreviousViewOrTop,
() =>
{
MovePreviousViewOrTop ();
return true;
}
);
AddCommand (
Command.Refresh,
() =>
{
Application.Refresh ();
return true;
}
);
// Default keybindings for this view
KeyBindings.Add (Application.QuitKey, Command.QuitToplevel);
KeyBindings.Add (Key.CursorRight, Command.NextView);
KeyBindings.Add (Key.CursorDown, Command.NextView);
KeyBindings.Add (Key.CursorLeft, Command.PreviousView);
KeyBindings.Add (Key.CursorUp, Command.PreviousView);
KeyBindings.Add (Key.Tab, Command.NextView);
KeyBindings.Add (Key.Tab.WithShift, Command.PreviousView);
KeyBindings.Add (Key.Tab.WithCtrl, Command.NextViewOrTop);
KeyBindings.Add (Key.Tab.WithShift.WithCtrl, Command.PreviousViewOrTop);
KeyBindings.Add (Key.F5, Command.Refresh);
KeyBindings.Add (Application.AlternateForwardKey, Command.NextViewOrTop); // Needed on Unix
KeyBindings.Add (Application.AlternateBackwardKey, Command.PreviousViewOrTop); // Needed on Unix
#if UNIX_KEY_BINDINGS
KeyBindings.Add (Key.Z.WithCtrl, Command.Suspend);
KeyBindings.Add (Key.L.WithCtrl, Command.Refresh); // Unix
KeyBindings.Add (Key.F.WithCtrl, Command.NextView); // Unix
KeyBindings.Add (Key.I.WithCtrl, Command.NextView); // Unix
KeyBindings.Add (Key.B.WithCtrl, Command.PreviousView); // Unix
#endif
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Toplevel"/> can focus.
/// </summary>
/// <summary>Gets or sets a value indicating whether this <see cref="Toplevel"/> can focus.</summary>
/// <value><c>true</c> if can focus; otherwise, <c>false</c>.</value>
public override bool CanFocus => SuperView == null ? true : base.CanFocus;
@@ -61,14 +151,11 @@ public partial class Toplevel : View
/// </summary>
public bool IsLoaded { get; private set; }
/// <summary>
/// Gets or sets the menu for this Toplevel.
/// </summary>
/// <summary>Gets or sets the menu for this Toplevel.</summary>
public virtual MenuBar MenuBar { get; set; }
/// <summary>
/// Determines whether the <see cref="Toplevel"/> is modal or not.
/// If set to <c>false</c> (the default):
/// Determines whether the <see cref="Toplevel"/> is modal or not. If set to <c>false</c> (the default):
/// <list type="bullet">
/// <item>
/// <description><see cref="View.OnKeyDown"/> events will propagate keys upwards.</description>
@@ -83,36 +170,23 @@ public partial class Toplevel : View
/// <description><see cref="View.OnKeyDown"/> events will NOT propagate keys upwards.</description>
/// </item>
/// <item>
/// <description>
/// The Toplevel will and look like a modal (pop-up) (e.g. see
/// <see cref="Dialog"/>.
/// </description>
/// <description>The Toplevel will and look like a modal (pop-up) (e.g. see <see cref="Dialog"/>.</description>
/// </item>
/// </list>
/// </summary>
public bool Modal { get; set; }
/// <summary>
/// Gets or sets whether the main loop for this <see cref="Toplevel"/> is running or not.
/// </summary>
/// <remarks>
/// Setting this property directly is discouraged. Use <see cref="Application.RequestStop"/>
/// instead.
/// </remarks>
/// <summary>Gets or sets whether the main loop for this <see cref="Toplevel"/> is running or not.</summary>
/// <remarks>Setting this property directly is discouraged. Use <see cref="Application.RequestStop"/> instead.</remarks>
public bool Running { get; set; }
/// <summary>
/// Gets or sets the status bar for this Toplevel.
/// </summary>
/// <summary>Gets or sets the status bar for this Toplevel.</summary>
public virtual StatusBar StatusBar { get; set; }
/// <summary>
/// Invoked when the Toplevel <see cref="RunState"/> becomes the <see cref="Application.Current"/>
/// Toplevel.
/// </summary>
/// <summary>Invoked when the Toplevel <see cref="RunState"/> becomes the <see cref="Application.Current"/> Toplevel.</summary>
public event EventHandler<ToplevelEventArgs> Activate;
///<inheritdoc/>
/// <inheritdoc/>
public override void Add (View view)
{
CanFocus = true;
@@ -121,19 +195,15 @@ public partial class Toplevel : View
}
/// <summary>
/// Invoked when the last child of the Toplevel <see cref="RunState"/> is closed from
/// by <see cref="Application.End(RunState)"/>.
/// Invoked when the last child of the Toplevel <see cref="RunState"/> is closed from by
/// <see cref="Application.End(RunState)"/>.
/// </summary>
public event EventHandler AllChildClosed;
/// <summary>
/// Invoked when the <see cref="Application.AlternateBackwardKey"/> is changed.
/// </summary>
/// <summary>Invoked when the <see cref="Application.AlternateBackwardKey"/> is changed.</summary>
public event EventHandler<KeyChangedEventArgs> AlternateBackwardKeyChanged;
/// <summary>
/// Invoked when the <see cref="Application.AlternateForwardKey"/> is changed.
/// </summary>
/// <summary>Invoked when the <see cref="Application.AlternateForwardKey"/> is changed.</summary>
public event EventHandler<KeyChangedEventArgs> AlternateForwardKeyChanged;
/// <summary>
@@ -142,20 +212,13 @@ public partial class Toplevel : View
/// </summary>
public event EventHandler<ToplevelEventArgs> ChildClosed;
/// <summary>
/// Invoked when a child Toplevel's <see cref="RunState"/> has been loaded.
/// </summary>
/// <summary>Invoked when a child Toplevel's <see cref="RunState"/> has been loaded.</summary>
public event EventHandler<ToplevelEventArgs> ChildLoaded;
/// <summary>
/// Invoked when a cjhild Toplevel's <see cref="RunState"/> has been unloaded.
/// </summary>
/// <summary>Invoked when a cjhild Toplevel's <see cref="RunState"/> has been unloaded.</summary>
public event EventHandler<ToplevelEventArgs> ChildUnloaded;
/// <summary>
/// Invoked when the Toplevel's <see cref="RunState"/> is closed by
/// <see cref="Application.End(RunState)"/>.
/// </summary>
/// <summary>Invoked when the Toplevel's <see cref="RunState"/> is closed by <see cref="Application.End(RunState)"/>.</summary>
public event EventHandler<ToplevelEventArgs> Closed;
/// <summary>
@@ -164,20 +227,16 @@ public partial class Toplevel : View
/// </summary>
public event EventHandler<ToplevelClosingEventArgs> Closing;
/// <summary>
/// Invoked when the Toplevel<see cref="RunState"/> ceases to be the <see cref="Application.Current"/>
/// Toplevel.
/// </summary>
/// <summary>Invoked when the Toplevel<see cref="RunState"/> ceases to be the <see cref="Application.Current"/> Toplevel.</summary>
public event EventHandler<ToplevelEventArgs> Deactivate;
/// <summary>
/// Invoked when the <see cref="Toplevel"/> <see cref="RunState"/> has begun to be loaded.
/// A Loaded event handler is a good place to finalize initialization before calling
/// <see cref="Application.RunLoop(RunState)"/>.
/// Invoked when the <see cref="Toplevel"/> <see cref="RunState"/> has begun to be loaded. A Loaded event handler
/// is a good place to finalize initialization before calling <see cref="Application.RunLoop(RunState)"/>.
/// </summary>
public event EventHandler Loaded;
///<inheritdoc/>
/// <inheritdoc/>
public override bool MouseEvent (MouseEvent mouseEvent)
{
if (!CanFocus)
@@ -234,12 +293,19 @@ public partial class Toplevel : View
// BUGBUG: Assumes Frame == Border?
GetLocationThatFits (
this,
mouseEvent.X + (SuperView == null ? mouseEvent.OfX - _startGrabPoint.X : Frame.X - _startGrabPoint.X),
mouseEvent.Y + (SuperView == null ? mouseEvent.OfY - _startGrabPoint.Y : Frame.Y - _startGrabPoint.Y),
mouseEvent.X
+ (SuperView == null
? mouseEvent.OfX - _startGrabPoint.X
: Frame.X - _startGrabPoint.X),
mouseEvent.Y
+ (SuperView == null
? mouseEvent.OfY - _startGrabPoint.Y
: Frame.Y - _startGrabPoint.Y),
out nx,
out ny,
out _,
out _);
out _
);
_dragPosition = new Point (nx, ny);
X = nx;
@@ -264,9 +330,7 @@ public partial class Toplevel : View
return false;
}
/// <summary>
/// Virtual method to invoke the <see cref="AlternateBackwardKeyChanged"/> event.
/// </summary>
/// <summary>Virtual method to invoke the <see cref="AlternateBackwardKeyChanged"/> event.</summary>
/// <param name="e"></param>
public virtual void OnAlternateBackwardKeyChanged (KeyChangedEventArgs e)
{
@@ -274,9 +338,7 @@ public partial class Toplevel : View
AlternateBackwardKeyChanged?.Invoke (this, e);
}
/// <summary>
/// Virtual method to invoke the <see cref="AlternateForwardKeyChanged"/> event.
/// </summary>
/// <summary>Virtual method to invoke the <see cref="AlternateForwardKeyChanged"/> event.</summary>
/// <param name="e"></param>
public virtual void OnAlternateForwardKeyChanged (KeyChangedEventArgs e)
{
@@ -284,7 +346,7 @@ public partial class Toplevel : View
AlternateForwardKeyChanged?.Invoke (this, e);
}
///<inheritdoc/>
/// <inheritdoc/>
public override void OnDrawContent (Rect contentArea)
{
if (!Visible)
@@ -338,15 +400,15 @@ public partial class Toplevel : View
}
}
///<inheritdoc/>
/// <inheritdoc/>
public override bool OnEnter (View view) { return MostFocused?.OnEnter (view) ?? base.OnEnter (view); }
///<inheritdoc/>
/// <inheritdoc/>
public override bool OnLeave (View view) { return MostFocused?.OnLeave (view) ?? base.OnLeave (view); }
/// <summary>
/// Called from <see cref="Application.Begin(Toplevel)"/> before the <see cref="Toplevel"/> redraws for
/// the first time.
/// Called from <see cref="Application.Begin(Toplevel)"/> before the <see cref="Toplevel"/> redraws for the first
/// time.
/// </summary>
public virtual void OnLoaded ()
{
@@ -360,9 +422,7 @@ public partial class Toplevel : View
Loaded?.Invoke (this, EventArgs.Empty);
}
/// <summary>
/// Virtual method to invoke the <see cref="QuitKeyChanged"/> event.
/// </summary>
/// <summary>Virtual method to invoke the <see cref="QuitKeyChanged"/> event.</summary>
/// <param name="e"></param>
public virtual void OnQuitKeyChanged (KeyChangedEventArgs e)
{
@@ -370,7 +430,7 @@ public partial class Toplevel : View
QuitKeyChanged?.Invoke (this, e);
}
///<inheritdoc/>
/// <inheritdoc/>
public override void PositionCursor ()
{
if (!IsOverlappedContainer)
@@ -412,9 +472,8 @@ public partial class Toplevel : View
}
/// <summary>
/// Adjusts the location and size of <paramref name="top"/> within this Toplevel.
/// Virtual method enabling implementation of specific positions for inherited <see cref="Toplevel"/>
/// views.
/// Adjusts the location and size of <paramref name="top"/> within this Toplevel. Virtual method enabling
/// implementation of specific positions for inherited <see cref="Toplevel"/> views.
/// </summary>
/// <param name="top">The Toplevel to adjust.</param>
public virtual void PositionToplevel (Toplevel top)
@@ -426,7 +485,8 @@ public partial class Toplevel : View
out int nx,
out int ny,
out _,
out StatusBar sb);
out StatusBar sb
);
var layoutSubviews = false;
var maxWidth = 0;
@@ -475,16 +535,12 @@ public partial class Toplevel : View
}
}
/// <summary>
/// Invoked when the <see cref="Application.QuitKey"/> is changed.
/// </summary>
/// <summary>Invoked when the <see cref="Application.QuitKey"/> is changed.</summary>
public event EventHandler<KeyChangedEventArgs> QuitKeyChanged;
/// <summary>
/// Invoked when the <see cref="Toplevel"/> main loop has started it's first iteration.
/// Subscribe to this event to perform tasks when the <see cref="Toplevel"/> has been laid out and
/// focus has been set.
/// changes.
/// Invoked when the <see cref="Toplevel"/> main loop has started it's first iteration. Subscribe to this event to
/// perform tasks when the <see cref="Toplevel"/> has been laid out and focus has been set. changes.
/// <para>
/// A Ready event handler is a good place to finalize initialization after calling
/// <see cref="Application.Run(Func{Exception, bool})"/> on this <see cref="Toplevel"/>.
@@ -492,7 +548,7 @@ public partial class Toplevel : View
/// </summary>
public event EventHandler Ready;
///<inheritdoc/>
/// <inheritdoc/>
public override void Remove (View view)
{
if (this is Toplevel Toplevel && Toplevel.MenuBar != null)
@@ -503,7 +559,7 @@ public partial class Toplevel : View
base.Remove (view);
}
///<inheritdoc/>
/// <inheritdoc/>
public override void RemoveAll ()
{
if (this == Application.Top)
@@ -575,26 +631,23 @@ public partial class Toplevel : View
}
/// <summary>
/// Stops and closes the <see cref="Toplevel"/> specified by <paramref name="top"/>. If
/// <paramref name="top"/> is the top-most Toplevel,
/// <see cref="Application.RequestStop(Toplevel)"/> will be called, causing the application to exit.
/// Stops and closes the <see cref="Toplevel"/> specified by <paramref name="top"/>. If <paramref name="top"/> is
/// the top-most Toplevel, <see cref="Application.RequestStop(Toplevel)"/> will be called, causing the application to
/// exit.
/// </summary>
/// <param name="top">The Toplevel to request stop.</param>
public virtual void RequestStop (Toplevel top) { top.RequestStop (); }
/// <summary>
/// Invoked when the terminal has been resized. The new <see cref="Size"/> of the terminal is provided.
/// </summary>
/// <summary>Invoked when the terminal has been resized. The new <see cref="Size"/> of the terminal is provided.</summary>
public event EventHandler<SizeChangedEventArgs> SizeChanging;
/// <summary>
/// Invoked when the Toplevel <see cref="RunState"/> has been unloaded.
/// A Unloaded event handler is a good place to dispose objects after calling
/// <see cref="Application.End(RunState)"/>.
/// Invoked when the Toplevel <see cref="RunState"/> has been unloaded. A Unloaded event handler is a good place
/// to dispose objects after calling <see cref="Application.End(RunState)"/>.
/// </summary>
public event EventHandler Unloaded;
///<inheritdoc/>
/// <inheritdoc/>
protected override void Dispose (bool disposing)
{
Application.GrabbingMouse -= Application_GrabbingMouse;
@@ -618,15 +671,12 @@ public partial class Toplevel : View
}
/// <summary>
/// Gets a new location of the <see cref="Toplevel"/> that is within the Bounds of the
/// <paramref name="top"/>'s
/// <see cref="View.SuperView"/> (e.g. for dragging a Window).
/// The `out` parameters are the new X and Y coordinates.
/// Gets a new location of the <see cref="Toplevel"/> that is within the Bounds of the <paramref name="top"/>'s
/// <see cref="View.SuperView"/> (e.g. for dragging a Window). The `out` parameters are the new X and Y coordinates.
/// </summary>
/// <remarks>
/// If <paramref name="top"/> does not have a <see cref="View.SuperView"/> or it's SuperView is not
/// <see cref="Application.Top"/>
/// the position will be bound by the <see cref="ConsoleDriver.Cols"/> and
/// <see cref="Application.Top"/> the position will be bound by the <see cref="ConsoleDriver.Cols"/> and
/// <see cref="ConsoleDriver.Rows"/>.
/// </remarks>
/// <param name="top">The Toplevel that is to be moved.</param>
@@ -638,8 +688,7 @@ public partial class Toplevel : View
/// <param name="statusBar">The new top most statusBar</param>
/// <returns>
/// Either <see cref="Application.Top"/> (if <paramref name="top"/> does not have a Super View) or
/// <paramref name="top"/>'s SuperView. This can be used to ensure LayoutSubviews is called on the
/// correct View.
/// <paramref name="top"/>'s SuperView. This can be used to ensure LayoutSubviews is called on the correct View.
/// </returns>
internal View GetLocationThatFits (
Toplevel top,
@@ -754,7 +803,9 @@ public partial class Toplevel : View
if (top.Frame.Height <= maxWidth)
{
ny = ny + top.Frame.Height > maxWidth ? Math.Max (maxWidth - top.Frame.Height, menuVisible ? 1 : 0) : ny;
ny = ny + top.Frame.Height > maxWidth
? Math.Max (maxWidth - top.Frame.Height, menuVisible ? 1 : 0)
: ny;
if (ny > top.Frame.Y + top.Frame.Height)
{
@@ -768,7 +819,6 @@ public partial class Toplevel : View
}
internal virtual void OnActivate (Toplevel deactivated) { Activate?.Invoke (this, new ToplevelEventArgs (deactivated)); }
internal virtual void OnAllChildClosed () { AllChildClosed?.Invoke (this, EventArgs.Empty); }
internal virtual void OnChildClosed (Toplevel top)
@@ -782,9 +832,7 @@ public partial class Toplevel : View
}
internal virtual void OnChildLoaded (Toplevel top) { ChildLoaded?.Invoke (this, new ToplevelEventArgs (top)); }
internal virtual void OnChildUnloaded (Toplevel top) { ChildUnloaded?.Invoke (this, new ToplevelEventArgs (top)); }
internal virtual void OnClosed (Toplevel top) { Closed?.Invoke (this, new ToplevelEventArgs (top)); }
internal virtual bool OnClosing (ToplevelClosingEventArgs ev)
@@ -797,8 +845,8 @@ public partial class Toplevel : View
internal virtual void OnDeactivate (Toplevel activated) { Deactivate?.Invoke (this, new ToplevelEventArgs (activated)); }
/// <summary>
/// Called from <see cref="Application.RunLoop"/> after the <see cref="Toplevel"/> has entered the
/// first iteration of the loop.
/// Called from <see cref="Application.RunLoop"/> after the <see cref="Toplevel"/> has entered the first iteration
/// of the loop.
/// </summary>
internal virtual void OnReady ()
{
@@ -813,9 +861,7 @@ public partial class Toplevel : View
// TODO: Make cancelable?
internal virtual void OnSizeChanging (SizeChangedEventArgs size) { SizeChanging?.Invoke (this, size); }
/// <summary>
/// Called from <see cref="Application.End(RunState)"/> before the <see cref="Toplevel"/> is disposed.
/// </summary>
/// <summary>Called from <see cref="Application.End(RunState)"/> before the <see cref="Toplevel"/> is disposed.</summary>
internal virtual void OnUnloaded ()
{
foreach (Toplevel tl in Subviews.Where (v => v is Toplevel))
@@ -871,7 +917,7 @@ public partial class Toplevel : View
}
}
private void FocusNearestView (IEnumerable<View> views, Direction direction)
private void FocusNearestView (IEnumerable<View> views, NavigationDirection direction)
{
if (views == null)
{
@@ -891,7 +937,7 @@ public partial class Toplevel : View
if (found && v != this)
{
if (direction == Direction.Forward)
if (direction == NavigationDirection.Forward)
{
SuperView?.FocusNext ();
}
@@ -950,7 +996,7 @@ public partial class Toplevel : View
}
else
{
FocusNearestView (SuperView?.TabIndexes, Direction.Forward);
FocusNearestView (SuperView?.TabIndexes, NavigationDirection.Forward);
}
}
@@ -991,7 +1037,7 @@ public partial class Toplevel : View
}
else
{
FocusNearestView (SuperView?.TabIndexes?.Reverse (), Direction.Backward);
FocusNearestView (SuperView?.TabIndexes?.Reverse (), NavigationDirection.Backward);
}
}
@@ -1037,122 +1083,18 @@ public partial class Toplevel : View
Application.RequestStop ();
}
}
private void SetInitialProperties ()
{
ColorScheme = Colors.ColorSchemes ["TopLevel"];
Application.GrabbingMouse += Application_GrabbingMouse;
Application.UnGrabbingMouse += Application_UnGrabbingMouse;
// TODO: v2 - ALL Views (Responders??!?!) should support the commands related to
// - Focus
// Move the appropriate AddCommand calls to `Responder`
// Things this view knows how to do
AddCommand (
Command.QuitToplevel,
() =>
{
QuitToplevel ();
return true;
});
AddCommand (
Command.Suspend,
() =>
{
Driver.Suspend ();
;
return true;
});
AddCommand (
Command.NextView,
() =>
{
MoveNextView ();
return true;
});
AddCommand (
Command.PreviousView,
() =>
{
MovePreviousView ();
return true;
});
AddCommand (
Command.NextViewOrTop,
() =>
{
MoveNextViewOrTop ();
return true;
});
AddCommand (
Command.PreviousViewOrTop,
() =>
{
MovePreviousViewOrTop ();
return true;
});
AddCommand (
Command.Refresh,
() =>
{
Application.Refresh ();
return true;
});
// Default keybindings for this view
KeyBindings.Add (Application.QuitKey, Command.QuitToplevel);
KeyBindings.Add (Key.CursorRight, Command.NextView);
KeyBindings.Add (Key.CursorDown, Command.NextView);
KeyBindings.Add (Key.CursorLeft, Command.PreviousView);
KeyBindings.Add (Key.CursorUp, Command.PreviousView);
KeyBindings.Add (Key.Tab, Command.NextView);
KeyBindings.Add (Key.Tab.WithShift, Command.PreviousView);
KeyBindings.Add (Key.Tab.WithCtrl, Command.NextViewOrTop);
KeyBindings.Add (Key.Tab.WithShift.WithCtrl, Command.PreviousViewOrTop);
KeyBindings.Add (Key.F5, Command.Refresh);
KeyBindings.Add (Application.AlternateForwardKey, Command.NextViewOrTop); // Needed on Unix
KeyBindings.Add (Application.AlternateBackwardKey, Command.PreviousViewOrTop); // Needed on Unix
#if UNIX_KEY_BINDINGS
KeyBindings.Add (Key.Z.WithCtrl, Command.Suspend);
KeyBindings.Add (Key.L.WithCtrl, Command.Refresh);// Unix
KeyBindings.Add (Key.F.WithCtrl, Command.NextView);// Unix
KeyBindings.Add (Key.I.WithCtrl, Command.NextView); // Unix
KeyBindings.Add (Key.B.WithCtrl, Command.PreviousView);// Unix
#endif
}
}
/// <summary>
/// Implements the <see cref="IEqualityComparer{T}"/> for comparing two <see cref="Toplevel"/>s
/// used by <see cref="StackExtensions"/>.
/// Implements the <see cref="IEqualityComparer{T}"/> for comparing two <see cref="Toplevel"/>s used by
/// <see cref="StackExtensions"/>.
/// </summary>
public class ToplevelEqualityComparer : IEqualityComparer<Toplevel>
{
/// <summary>Determines whether the specified objects are equal.</summary>
/// <param name="x">The first object of type <see cref="Toplevel"/> to compare.</param>
/// <param name="y">The second object of type <see cref="Toplevel"/> to compare.</param>
/// <returns>
/// <see langword="true"/> if the specified objects are equal; otherwise, <see langword="false"/>.
/// </returns>
/// <returns><see langword="true"/> if the specified objects are equal; otherwise, <see langword="false"/>.</returns>
public bool Equals (Toplevel x, Toplevel y)
{
if (y == null && x == null)
@@ -1177,8 +1119,8 @@ public class ToplevelEqualityComparer : IEqualityComparer<Toplevel>
/// <param name="obj">The <see cref="Toplevel"/> for which a hash code is to be returned.</param>
/// <returns>A hash code for the specified object.</returns>
/// <exception cref="ArgumentNullException">
/// The type of <paramref name="obj"/>
/// is a reference type and <paramref name="obj"/> is <see langword="null"/>.
/// The type of <paramref name="obj"/> is a reference type and
/// <paramref name="obj"/> is <see langword="null"/>.
/// </exception>
public int GetHashCode (Toplevel obj)
{
@@ -1199,23 +1141,22 @@ public class ToplevelEqualityComparer : IEqualityComparer<Toplevel>
}
/// <summary>
/// Implements the <see cref="IComparer{T}"/> to sort the <see cref="Toplevel"/>
/// from the <see cref="Application.OverlappedChildren"/> if needed.
/// Implements the <see cref="IComparer{T}"/> to sort the <see cref="Toplevel"/> from the
/// <see cref="Application.OverlappedChildren"/> if needed.
/// </summary>
public sealed class ToplevelComparer : IComparer<Toplevel>
{
/// <summary>
/// Compares two objects and returns a value indicating whether one is less than, equal to, or
/// greater than the other.
/// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the
/// other.
/// </summary>
/// <param name="x">The first object to compare.</param>
/// <param name="y">The second object to compare.</param>
/// <returns>
/// A signed integer that indicates the relative values of <paramref name="x"/> and
/// <paramref name="y"/>, as shown in the following table.Value Meaning Less than zero
/// <paramref name="x"/> is less than <paramref name="y"/>.Zero
/// <paramref name="x"/> equals <paramref name="y"/>.Greater than zero
/// <paramref name="x"/> is greater than <paramref name="y"/>.
/// A signed integer that indicates the relative values of <paramref name="x"/> and <paramref name="y"/>, as shown
/// in the following table.Value Meaning Less than zero <paramref name="x"/> is less than <paramref name="y"/>.Zero
/// <paramref name="x"/> equals <paramref name="y"/> .Greater than zero <paramref name="x"/> is greater than
/// <paramref name="y"/>.
/// </returns>
public int Compare (Toplevel x, Toplevel y)
{

View File

@@ -12,124 +12,122 @@ public class Dialogs : Scenario
public override void Setup ()
{
var frame = new FrameView ("Dialog Options")
{
X = Pos.Center (),
Y = 1,
Width = Dim.Percent (75),
Height = Dim.Auto ()
};
var frame = new FrameView { X = Pos.Center (), Y = 1, Width = Dim.Percent (75), Title = "Dialog Options" };
var label = new Label ("Width:")
{
X = 0,
Y = 0,
Width = 15,
Height = 1,
TextAlignment = TextAlignment.Right
};
var label = new Label { X = 0, Y = 0, TextAlignment = TextAlignment.Right, Text = "Width:" };
frame.Add (label);
var widthEdit = new TextField ("0")
var widthEdit = new TextField
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = 5,
Height = 1
Height = 1,
Text = "0"
};
frame.Add (widthEdit);
label = new Label ("Height:")
label = new Label
{
AutoSize = false,
X = 0,
Y = Pos.Bottom (label),
Width = Dim.Width (label),
Height = 1,
TextAlignment = TextAlignment.Right
TextAlignment = TextAlignment.Right,
Text = "Height:"
};
frame.Add (label);
var heightEdit = new TextField ("0")
var heightEdit = new TextField
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = 5,
Height = 1
Height = 1,
Text = "0"
};
frame.Add (heightEdit);
frame.Add (
new Label ("If height & width are both 0,")
{
X = Pos.Right (widthEdit) + 2,
Y = Pos.Top (widthEdit)
});
new Label { X = Pos.Right (widthEdit) + 2, Y = Pos.Top (widthEdit), Text = "If height & width are both 0," }
);
frame.Add (
new Label ("the Dialog will size to 80% of container.")
new Label
{
X = Pos.Right (heightEdit) + 2,
Y = Pos.Top (heightEdit)
});
Y = Pos.Top (heightEdit),
Text = "the Dialog will size to 80% of container."
}
);
label = new Label ("Title:")
label = new Label
{
AutoSize = false,
X = 0,
Y = Pos.Bottom (label),
Width = Dim.Width (label),
Height = 1,
TextAlignment = TextAlignment.Right
TextAlignment = TextAlignment.Right,
Text = "Title:"
};
frame.Add (label);
var titleEdit = new TextField ("Title")
var titleEdit = new TextField
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = Dim.Fill (),
Height = 1
Height = 1,
Text = "Title"
};
frame.Add (titleEdit);
label = new Label ("Num Buttons:")
label = new Label
{
AutoSize = false,
X = 0,
Y = Pos.Bottom (label), // BUGBUG: if this is Pos.Bottom (titleEdit) the initial LayoutSubviews does not work correctly?!?!
Y = Pos.Bottom (label),
Width = Dim.Width (label),
Height = 1,
TextAlignment = TextAlignment.Right
TextAlignment = TextAlignment.Right,
Text = "Num Buttons:"
};
frame.Add (label);
var numButtonsEdit = new TextField ("3")
var numButtonsEdit = new TextField
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = 5,
Height = 1
Height = 1,
Text = "3"
};
frame.Add (numButtonsEdit);
var glyphsNotWords = new CheckBox ($"Add {char.ConvertFromUtf32 (CODE_POINT)} to button text to stress wide char support")
var glyphsNotWords = new CheckBox
{
X = Pos.Left (numButtonsEdit),
Y = Pos.Bottom (label),
TextAlignment = TextAlignment.Right
TextAlignment = TextAlignment.Right,
Text =
$"Add {char.ConvertFromUtf32 (CODE_POINT)} to button text to stress wide char support",
Checked = false
};
frame.Add (glyphsNotWords);
label = new Label ("Button Style:")
label = new Label
{
X = 0,
Y = Pos.Bottom (glyphsNotWords),
TextAlignment = TextAlignment.Right
X = 0, Y = Pos.Bottom (glyphsNotWords), TextAlignment = TextAlignment.Right, Text = "Button Style:"
};
frame.Add (label);
var styleRadioGroup = new RadioGroup (new [] { "_Center", "_Justify", "_Left", "_Right" })
var styleRadioGroup = new RadioGroup
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label)
Y = Pos.Top (label),
RadioLabels = new [] { "_Center", "_Justify", "_Left", "_Right" }
};
frame.Add (styleRadioGroup);
@@ -151,22 +149,15 @@ public class Dialogs : Scenario
Win.Add (frame);
label = new Label ("Button Pressed:")
label = new Label
{
X = Pos.Center (),
Y = Pos.Bottom (frame) + 4,
Height = 1,
TextAlignment = TextAlignment.Right
X = Pos.Center (), Y = Pos.Bottom (frame) + 4, TextAlignment = TextAlignment.Right, Text = "Button Pressed:"
};
Win.Add (label);
var buttonPressedLabel = new Label (" ")
var buttonPressedLabel = new Label
{
X = Pos.Center (),
Y = Pos.Bottom (frame) + 5,
Width = 25,
Height = 1,
ColorScheme = Colors.ColorSchemes ["Error"]
X = Pos.Center (), Y = Pos.Bottom (frame) + 5, ColorScheme = Colors.ColorSchemes ["Error"], Text = " "
};
// glyphsNotWords
@@ -174,11 +165,9 @@ public class Dialogs : Scenario
// true: var btnText = new [] { "0", "\u2780", "➁", "\u2783", "\u2784", "\u2785", "\u2786", "\u2787", "\u2788", "\u2789" };
// \u2781 is ➁ dingbats \ufb70 is
var showDialogButton = new Button ("_Show Dialog")
var showDialogButton = new Button
{
X = Pos.Center (),
Y = Pos.Bottom (frame) + 2,
IsDefault = true
X = Pos.Center (), Y = Pos.Bottom (frame) + 2, IsDefault = true, Text = "_Show Dialog"
};
showDialogButton.Clicked += (s, e) =>
@@ -190,7 +179,8 @@ public class Dialogs : Scenario
numButtonsEdit,
glyphsNotWords,
styleRadioGroup,
buttonPressedLabel);
buttonPressedLabel
);
Application.Run (dlg);
};
@@ -220,7 +210,7 @@ public class Dialogs : Scenario
var numButtons = 3;
int.TryParse (numButtonsEdit.Text, out numButtons);
List<Button> buttons = new List<Button> ();
List<Button> buttons = new ();
int clicked = -1;
for (var i = 0; i < numButtons; i++)
@@ -232,15 +222,15 @@ public class Dialogs : Scenario
{
buttonId = i;
button = new Button (
NumberToWords.Convert (buttonId) + " " + char.ConvertFromUtf32 (buttonId + CODE_POINT),
buttonId == 0);
button = new Button
{
Text = NumberToWords.Convert (buttonId) + " " + char.ConvertFromUtf32 (buttonId + CODE_POINT),
IsDefault = buttonId == 0
};
}
else
{
button = new Button (
NumberToWords.Convert (buttonId),
buttonId == 0);
button = new Button { Text = NumberToWords.Convert (buttonId), IsDefault = buttonId == 0 };
}
button.Clicked += (s, e) =>
@@ -261,10 +251,11 @@ public class Dialogs : Scenario
// This tests dynamically adding buttons; ensuring the dialog resizes if needed and
// the buttons are laid out correctly
dialog = new Dialog (buttons.ToArray ())
dialog = new Dialog
{
Title = titleEdit.Text,
ButtonAlignment = (Dialog.ButtonAlignments)styleRadioGroup.SelectedItem
ButtonAlignment = (Dialog.ButtonAlignments)styleRadioGroup.SelectedItem,
Buttons = buttons.ToArray ()
};
if (height != 0 || width != 0)
@@ -273,11 +264,7 @@ public class Dialogs : Scenario
dialog.Width = width;
}
var add = new Button ("Add a button")
{
X = Pos.Center (),
Y = 10 //Pos.Center ()
};
var add = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Add a button" };
add.Clicked += (s, e) =>
{
@@ -286,15 +273,15 @@ public class Dialogs : Scenario
if (glyphsNotWords.Checked == true)
{
button = new Button (
NumberToWords.Convert (buttonId) + " " + char.ConvertFromUtf32 (buttonId + CODE_POINT),
buttonId == 0);
button = new Button
{
Text = NumberToWords.Convert (buttonId) + " " + char.ConvertFromUtf32 (buttonId + CODE_POINT),
IsDefault = buttonId == 0
};
}
else
{
button = new Button (
NumberToWords.Convert (buttonId),
buttonId == 0);
button = new Button { Text = NumberToWords.Convert (buttonId), IsDefault = buttonId == 0 };
}
button.Clicked += (s, e) =>
@@ -312,10 +299,11 @@ public class Dialogs : Scenario
};
dialog.Add (add);
var addChar = new Button ($"Add a {char.ConvertFromUtf32 (CODE_POINT)} to each button")
var addChar = new Button
{
X = Pos.Center (),
Y = 11 //Pos.Center () + 1
Y = Pos.Center () + 1,
Text = $"Add a {char.ConvertFromUtf32 (CODE_POINT)} to each button"
};
addChar.Clicked += (s, e) =>

View File

@@ -21,29 +21,21 @@ using RuntimeEnvironment = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironm
namespace UICatalog;
/// <summary>
/// UI Catalog is a comprehensive sample library for Terminal.Gui. It provides a simple UI for adding to the catalog of
/// scenarios.
/// UI Catalog is a comprehensive sample library for Terminal.Gui. It provides a simple UI for adding to the
/// catalog of scenarios.
/// </summary>
/// <remarks>
/// <para>
/// UI Catalog attempts to satisfy the following goals:
/// </para>
/// <para>UI Catalog attempts to satisfy the following goals:</para>
/// <para>
/// <list type="number">
/// <item>
/// <description>
/// Be an easy to use showcase for Terminal.Gui concepts and features.
/// </description>
/// <description>Be an easy to use showcase for Terminal.Gui concepts and features.</description>
/// </item>
/// <item>
/// <description>
/// Provide sample code that illustrates how to properly implement said concepts & features.
/// </description>
/// <description>Provide sample code that illustrates how to properly implement said concepts & features.</description>
/// </item>
/// <item>
/// <description>
/// Make it easy for contributors to add additional samples in a structured way.
/// </description>
/// <description>Make it easy for contributors to add additional samples in a structured way.</description>
/// </item>
/// </list>
/// </para>
@@ -63,22 +55,17 @@ internal class UICatalogApp
private static int _cachedScenarioIndex;
private static string? _cachedTheme = string.Empty;
private static List<string>? _categories;
private static readonly FileSystemWatcher _currentDirWatcher = new ();
private static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
private static string _forceDriver = string.Empty;
private static readonly FileSystemWatcher _homeDirWatcher = new ();
private static bool _isFirstRunning = true;
private static Options _options;
private static List<Scenario>? _scenarios;
// If set, holds the scenario the user selected
private static Scenario? _selectedScenario;
private static MenuBarItem? _themeMenuBarItem;
private static MenuItem []? _themeMenuItems;
private static string _topLevelColorScheme = string.Empty;
@@ -114,10 +101,12 @@ internal class UICatalogApp
// Process command line args
// "UICatalog [-driver <driver>] [scenario name]"
// If no driver is provided, the default driver is used.
Option<string> driverOption = new Option<string> (
"--driver",
"The ConsoleDriver to use."
).FromAmong (Application.GetDriverTypes ().Select (d => d.Name).ToArray ());
Option<string> driverOption = new Option<string> ("--driver", "The ConsoleDriver to use.").FromAmong (
Application.GetDriverTypes ()
.Select (d => d.Name)
.ToArray ()
);
driverOption.AddAlias ("-d");
driverOption.AddAlias ("--d");
@@ -125,28 +114,29 @@ internal class UICatalogApp
"scenario",
description: "The name of the scenario to run.",
getDefaultValue: () => "none"
).FromAmong (_scenarios.Select (s => s.GetName ()).Append ("none").ToArray ());
).FromAmong (
_scenarios.Select (s => s.GetName ())
.Append ("none")
.ToArray ()
);
var rootCommand = new RootCommand ("A comprehensive sample library for Terminal.Gui")
{
scenarioArgument,
driverOption
};
var rootCommand =
new RootCommand ("A comprehensive sample library for Terminal.Gui") { scenarioArgument, driverOption };
rootCommand.SetHandler (
context =>
{
var options = new Options
{
Driver = context.ParseResult.GetValueForOption (driverOption) ?? string.Empty,
Driver = context.ParseResult.GetValueForOption (driverOption),
Scenario = context.ParseResult.GetValueForArgument (scenarioArgument)
/* etc. */
};
// See https://github.com/dotnet/command-line-api/issues/796 for the rationale behind this hackery
_options = options;
;
});
}
);
rootCommand.Invoke (args);
@@ -185,9 +175,8 @@ internal class UICatalogApp
}
/// <summary>
/// Shows the UI Catalog selection UI. When the user selects a Scenario to run, the
/// UI Catalog main app UI is killed and the Scenario is run as though it were Application.Top.
/// When the Scenario exits, this function exits.
/// Shows the UI Catalog selection UI. When the user selects a Scenario to run, the UI Catalog main app UI is
/// killed and the Scenario is run as though it were Application.Top. When the Scenario exits, this function exits.
/// </summary>
/// <returns></returns>
private static Scenario RunUICatalogTopLevel ()
@@ -291,7 +280,11 @@ internal class UICatalogApp
{
_topLevelColorScheme = "Base";
int item = _scenarios!.FindIndex (s => s.GetName ().Equals (options.Scenario, StringComparison.OrdinalIgnoreCase));
int item = _scenarios!.FindIndex (
s =>
s.GetName ()
.Equals (options.Scenario, StringComparison.OrdinalIgnoreCase)
);
_selectedScenario = (Scenario)Activator.CreateInstance (_scenarios [item].GetType ())!;
Application.Init (driverName: _forceDriver);
@@ -378,7 +371,6 @@ internal class UICatalogApp
public class UICatalogTopLevel : Toplevel
{
public ListView CategoryList;
public StatusItem DriverName;
public MenuItem? miForce16Colors;
public MenuItem? miIsMenuBorderDisabled;
@@ -390,6 +382,7 @@ internal class UICatalogApp
// TableView works. There's no real reason not to use ListView. Because we use TableView, and TableView
// doesn't (currently) have CollectionNavigator support built in, we implement it here, within the app.
public TableView ScenarioList;
private readonly CollectionNavigator _scenarioCollectionNav = new ();
public UICatalogTopLevel ()
@@ -397,46 +390,66 @@ internal class UICatalogApp
_themeMenuItems = CreateThemeMenuItems ();
_themeMenuBarItem = new MenuBarItem ("_Themes", _themeMenuItems);
MenuBar = new MenuBar (
new []
{
new (
"_File",
new MenuItem []
{
new ("_Quit", "Quit UI Catalog", RequestStop)
}),
_themeMenuBarItem,
new ("Diag_nostics", CreateDiagnosticMenuItems ()),
new (
"_Help",
new MenuItem []
{
new (
"_Documentation",
"",
() => OpenUrl ("https://gui-cs.github.io/Terminal.GuiV2Docs"),
null,
null,
(KeyCode)Key.F1),
new ("_README", "", () => OpenUrl ("https://github.com/gui-cs/Terminal.Gui"), null, null, (KeyCode)Key.F2),
new (
"_About...",
"About UI Catalog",
() => MessageBox.Query ("About UI Catalog", _aboutMessage!.ToString (), 0, false, "_Ok"),
null,
null,
(KeyCode)Key.A.WithCtrl)
})
});
MenuBar = new MenuBar
{
Menus =
[
new MenuBarItem (
"_File",
new MenuItem []
{
new (
"_Quit",
"Quit UI Catalog",
RequestStop
)
}
),
_themeMenuBarItem,
new MenuBarItem ("Diag_nostics", CreateDiagnosticMenuItems ()),
new MenuBarItem (
"_Help",
new MenuItem []
{
new (
"_Documentation",
"",
() => OpenUrl ("https://gui-cs.github.io/Terminal.GuiV2Docs"),
null,
null,
(KeyCode)Key.F1
),
new (
"_README",
"",
() => OpenUrl ("https://github.com/gui-cs/Terminal.Gui"),
null,
null,
(KeyCode)Key.F2
),
new (
"_About...",
"About UI Catalog",
() => MessageBox.Query (
"About UI Catalog",
_aboutMessage!.ToString (),
0,
false,
"_Ok"
),
null,
null,
(KeyCode)Key.A.WithCtrl
)
}
)
]
};
DriverName = new StatusItem (Key.Empty, "Driver:", null);
OS = new StatusItem (Key.Empty, "OS:", null);
StatusBar = new StatusBar
{
Visible = ShowStatusBar
};
StatusBar = new StatusBar { Visible = ShowStatusBar };
StatusBar.Items = new []
{
@@ -455,7 +468,8 @@ internal class UICatalogApp
{
_selectedScenario.RequestStop ();
}
}),
}
),
new (
Key.F10,
"~F10~ Status Bar",
@@ -466,13 +480,14 @@ internal class UICatalogApp
//ContentPane!.Height = Dim.Fill(StatusBar.Visible ? 1 : 0);
LayoutSubviews ();
SetSubViewNeedsDisplay ();
}),
}
),
DriverName,
OS
};
// Create the Category list view. This list never changes.
CategoryList = new ListView (_categories)
CategoryList = new ListView
{
X = 0,
Y = 1,
@@ -482,7 +497,8 @@ internal class UICatalogApp
CanFocus = true,
Title = "Categories",
BorderStyle = LineStyle.Single,
SuperViewRendersLineCanvas = true
SuperViewRendersLineCanvas = true,
Source = new ListWrapper (_categories)
};
CategoryList.OpenSelectedItem += (s, a) => { ScenarioList!.SetFocus (); };
CategoryList.SelectedItemChanged += CategoryView_SelectedChanged;
@@ -528,7 +544,11 @@ internal class UICatalogApp
* max widths as ColumnStyles
*/
int longestName = _scenarios!.Max (s => s.GetName ().Length);
ScenarioList.Style.ColumnStyles.Add (0, new ColumnStyle { MaxWidth = longestName, MinWidth = longestName, MinAcceptableWidth = longestName });
ScenarioList.Style.ColumnStyles.Add (
0,
new ColumnStyle { MaxWidth = longestName, MinWidth = longestName, MinAcceptableWidth = longestName }
);
ScenarioList.Style.ColumnStyles.Add (1, new ColumnStyle { MaxWidth = 1 });
// Enable user to find & select a scenario by typing text
@@ -538,7 +558,11 @@ internal class UICatalogApp
{
if (CollectionNavigatorBase.IsCompatibleKey (a))
{
int? newItem = _scenarioCollectionNav?.GetNextMatchingItem (ScenarioList.SelectedRow, (char)a);
int? newItem =
_scenarioCollectionNav?.GetNextMatchingItem (
ScenarioList.SelectedRow,
(char)a
);
if (newItem is int v && newItem != -1)
{
@@ -626,7 +650,8 @@ internal class UICatalogApp
var item = new MenuItem
{
Title = $"_{theme.Key}",
Shortcut = (KeyCode)new Key ((KeyCode)((uint)KeyCode.D1 + schemeCount++)).WithCtrl
Shortcut = (KeyCode)new Key ((KeyCode)((uint)KeyCode.D1 + schemeCount++))
.WithCtrl
};
item.CheckType |= MenuItemCheckStyle.Checked;
item.Checked = theme.Key == _cachedTheme; // CM.Themes.Theme;
@@ -643,11 +668,7 @@ internal class UICatalogApp
foreach (KeyValuePair<string, ColorScheme> sc in Colors.ColorSchemes)
{
var item = new MenuItem
{
Title = $"_{sc.Key}",
Data = sc.Key
};
var item = new MenuItem { Title = $"_{sc.Key}", Data = sc.Key };
item.CheckType |= MenuItemCheckStyle.Radio;
item.Checked = sc.Key == _topLevelColorScheme;
@@ -657,7 +678,8 @@ internal class UICatalogApp
foreach (MenuItem schemeMenuItem in schemeMenuItems)
{
schemeMenuItem.Checked = (string)schemeMenuItem.Data == _topLevelColorScheme;
schemeMenuItem.Checked =
(string)schemeMenuItem.Data == _topLevelColorScheme;
}
ColorScheme = Colors.ColorSchemes [_topLevelColorScheme];
@@ -693,9 +715,9 @@ internal class UICatalogApp
newlist,
new Dictionary<string, Func<Scenario, object>>
{
{ "Name", s => s.GetName () },
{ "Description", s => s.GetDescription () }
});
{ "Name", s => s.GetName () }, { "Description", s => s.GetDescription () }
}
);
// Create a collection of just the scenario names (the 1st column in our TableView)
// for CollectionNavigator.
@@ -724,8 +746,7 @@ internal class UICatalogApp
{
var item = new MenuItem
{
Title = GetDiagnosticsTitle (diag),
Shortcut = (KeyCode)new Key (index.ToString () [0]).WithAlt
Title = GetDiagnosticsTitle (diag), Shortcut = (KeyCode)new Key (index.ToString () [0]).WithAlt
};
index++;
item.CheckType |= MenuItemCheckStyle.Checked;
@@ -734,7 +755,8 @@ internal class UICatalogApp
{
item.Checked = (_diagnosticFlags
& (ConsoleDriver.DiagnosticFlags.FramePadding
| ConsoleDriver.DiagnosticFlags.FrameRuler))
| ConsoleDriver.DiagnosticFlags
.FrameRuler))
== 0;
}
else
@@ -774,12 +796,19 @@ internal class UICatalogApp
{
if (menuItem.Title == t)
{
menuItem.Checked = !_diagnosticFlags.HasFlag (ConsoleDriver.DiagnosticFlags.FrameRuler)
&& !_diagnosticFlags.HasFlag (ConsoleDriver.DiagnosticFlags.FramePadding);
menuItem.Checked =
!_diagnosticFlags.HasFlag (
ConsoleDriver.DiagnosticFlags
.FrameRuler
)
&& !_diagnosticFlags.HasFlag (ConsoleDriver.DiagnosticFlags.FramePadding);
}
else if (menuItem.Title != t)
{
menuItem.Checked = _diagnosticFlags.HasFlag (GetDiagnosticsEnumValue (menuItem.Title));
menuItem.Checked =
_diagnosticFlags.HasFlag (
GetDiagnosticsEnumValue (menuItem.Title)
);
}
}
@@ -848,7 +877,7 @@ internal class UICatalogApp
private List<MenuItem []> CreateDiagnosticMenuItems ()
{
List<MenuItem []> menuItems = new()
List<MenuItem []> menuItems = new ()
{
CreateDiagnosticFlagsMenuItems (),
new MenuItem [] { null! },
@@ -865,18 +894,20 @@ internal class UICatalogApp
private MenuItem [] CreateDisabledEnabledMenuBorder ()
{
List<MenuItem> menuItems = new ();
miIsMenuBorderDisabled = new MenuItem { Title = "Disable Menu _Border" };
miIsMenuBorderDisabled = new MenuItem
{
Title = "Disable Menu _Border"
};
miIsMenuBorderDisabled.Shortcut = (KeyCode)new Key (miIsMenuBorderDisabled!.Title!.Substring (14, 1) [0]).WithAlt.WithCtrl;
miIsMenuBorderDisabled.Shortcut =
(KeyCode)new Key (miIsMenuBorderDisabled!.Title!.Substring (14, 1) [0]).WithAlt
.WithCtrl;
miIsMenuBorderDisabled.CheckType |= MenuItemCheckStyle.Checked;
miIsMenuBorderDisabled.Action += () =>
{
miIsMenuBorderDisabled.Checked = (bool)!miIsMenuBorderDisabled.Checked!;
MenuBar.MenusBorderStyle = !(bool)miIsMenuBorderDisabled.Checked ? LineStyle.Single : LineStyle.None;
MenuBar.MenusBorderStyle = !(bool)miIsMenuBorderDisabled.Checked
? LineStyle.Single
: LineStyle.None;
};
menuItems.Add (miIsMenuBorderDisabled);
@@ -886,14 +917,17 @@ internal class UICatalogApp
private MenuItem [] CreateDisabledEnabledMouseItems ()
{
List<MenuItem> menuItems = new ();
miIsMouseDisabled = new MenuItem { Title = "_Disable Mouse" };
miIsMouseDisabled = new MenuItem
{
Title = "_Disable Mouse"
};
miIsMouseDisabled.Shortcut = (KeyCode)new Key (miIsMouseDisabled!.Title!.Substring (1, 1) [0]).WithAlt.WithCtrl;
miIsMouseDisabled.Shortcut =
(KeyCode)new Key (miIsMouseDisabled!.Title!.Substring (1, 1) [0]).WithAlt.WithCtrl;
miIsMouseDisabled.CheckType |= MenuItemCheckStyle.Checked;
miIsMouseDisabled.Action += () => { miIsMouseDisabled.Checked = Application.IsMouseDisabled = (bool)!miIsMouseDisabled.Checked!; };
miIsMouseDisabled.Action += () =>
{
miIsMouseDisabled.Checked =
Application.IsMouseDisabled = (bool)!miIsMouseDisabled.Checked!;
};
menuItems.Add (miIsMouseDisabled);
return menuItems.ToArray ();
@@ -903,12 +937,12 @@ internal class UICatalogApp
private MenuItem [] CreateDisabledEnableUseSubMenusSingleFrame ()
{
List<MenuItem> menuItems = new ();
miUseSubMenusSingleFrame = new MenuItem { Title = "Enable _Sub-Menus Single Frame" };
miUseSubMenusSingleFrame = new MenuItem
{
Title = "Enable _Sub-Menus Single Frame"
};
miUseSubMenusSingleFrame.Shortcut = KeyCode.CtrlMask | KeyCode.AltMask | (KeyCode)miUseSubMenusSingleFrame!.Title!.Substring (8, 1) [0];
miUseSubMenusSingleFrame.Shortcut = KeyCode.CtrlMask
| KeyCode.AltMask
| (KeyCode)miUseSubMenusSingleFrame!.Title!.Substring (8, 1) [
0];
miUseSubMenusSingleFrame.CheckType |= MenuItemCheckStyle.Checked;
miUseSubMenusSingleFrame.Action += () =>
@@ -947,12 +981,7 @@ internal class UICatalogApp
private MenuItem [] CreateKeyBindingsMenuItems ()
{
List<MenuItem> menuItems = new ();
var item = new MenuItem
{
Title = "_Key Bindings",
Help = "Change which keys do what"
};
var item = new MenuItem { Title = "_Key Bindings", Help = "Change which keys do what" };
item.Action += () =>
{
@@ -972,7 +1001,9 @@ internal class UICatalogApp
miIsMouseDisabled!.Checked = Application.IsMouseDisabled;
DriverName.Title = $"Driver: {Driver.GetVersionInfo ()}";
OS.Title = $"OS: {RuntimeEnvironment.OperatingSystem} {RuntimeEnvironment.OperatingSystemVersion}";
OS.Title =
$"OS: {RuntimeEnvironment.OperatingSystem} {RuntimeEnvironment.OperatingSystemVersion}";
if (_selectedScenario != null)
{
@@ -1003,9 +1034,7 @@ internal class UICatalogApp
ScenarioList.EnsureSelectedCellIsVisible ();
}
/// <summary>
/// Launches the selected scenario, setting the global _selectedScenario
/// </summary>
/// <summary>Launches the selected scenario, setting the global _selectedScenario</summary>
/// <param name="e"></param>
private void ScenarioView_OpenSelectedItem (object? sender, EventArgs? e)
{
@@ -1017,7 +1046,14 @@ internal class UICatalogApp
// Create new instance of scenario (even though Scenarios contains instances)
var selectedScenarioName = (string)ScenarioList.Table [ScenarioList.SelectedRow, 0];
_selectedScenario = (Scenario)Activator.CreateInstance (_scenarios!.FirstOrDefault (s => s.GetName () == selectedScenarioName)!.GetType ())!;
_selectedScenario = (Scenario)Activator.CreateInstance (
_scenarios!.FirstOrDefault (
s => s.GetName ()
== selectedScenarioName
)!
.GetType ()
)!;
// Tell the main app to stop
Application.RequestStop ();

View File

@@ -5,7 +5,6 @@ namespace Terminal.Gui.TextTests;
public class AppendAutocompleteTests
{
private readonly ITestOutputHelper output;
public AppendAutocompleteTests (ITestOutputHelper output) { this.output = output; }
[Fact]
@@ -225,16 +224,8 @@ public class AppendAutocompleteTests
private TextField GetTextFieldsInView ()
{
var tf = new TextField
{
Width = 10
};
var tf2 = new TextField
{
Y = 1,
Width = 10
};
var tf = new TextField { Width = 10 };
var tf2 = new TextField { Y = 1, Width = 10 };
Toplevel top = Application.Top;
top.Add (tf);

File diff suppressed because it is too large Load Diff

View File

@@ -5,23 +5,19 @@ namespace Terminal.Gui.ViewsTests;
public class WindowTests
{
private readonly ITestOutputHelper _output;
public WindowTests (ITestOutputHelper output) { _output = output; }
[Fact]
[AutoInitShutdown]
public void Activating_MenuBar_By_Alt_Key_Does_Not_Throw ()
{
var menu = new MenuBar (
new MenuBarItem []
{
new (
"Child",
new MenuItem []
{
new ("_Create Child", "", null)
})
});
var menu = new MenuBar
{
Menus =
[
new MenuBarItem ("Child", new MenuItem [] { new ("_Create Child", "", null) })
]
};
var win = new Window ();
win.Add (menu);
Application.Top.Add (win);
@@ -35,23 +31,17 @@ public class WindowTests
[AutoInitShutdown]
public void MenuBar_And_StatusBar_Inside_Window ()
{
var menu = new MenuBar (
new MenuBarItem []
{
new (
"File",
new MenuItem []
{
new ("Open", "", null),
new ("Quit", "", null)
}),
new (
"Edit",
new MenuItem []
{
new ("Copy", "", null)
})
});
var menu = new MenuBar
{
Menus =
[
new MenuBarItem ("File", new MenuItem [] { new ("Open", "", null), new ("Quit", "", null) }),
new MenuBarItem (
"Edit",
new MenuItem [] { new ("Copy", "", null) }
)
]
};
var sb = new StatusBar (
new StatusItem []
@@ -59,14 +49,10 @@ public class WindowTests
new (KeyCode.CtrlMask | KeyCode.Q, "~^Q~ Quit", null),
new (KeyCode.CtrlMask | KeyCode.O, "~^O~ Open", null),
new (KeyCode.CtrlMask | KeyCode.C, "~^C~ Copy", null)
});
}
);
var fv = new FrameView ("Frame View")
{
Y = 1,
Width = Dim.Fill (),
Height = Dim.Fill (1)
};
var fv = new FrameView { Y = 1, Width = Dim.Fill (), Height = Dim.Fill (1), Title = "Frame View" };
var win = new Window ();
win.Add (menu, sb, fv);
Toplevel top = Application.Top;
@@ -86,7 +72,8 @@ public class WindowTests
│└────────────────┘│
│ ^Q Quit │ ^O Open│
└──────────────────┘",
_output);
_output
);
((FakeDriver)Application.Driver).SetBufferSize (40, 20);
@@ -112,7 +99,8 @@ public class WindowTests
│└────────────────────────────────────┘│
│ ^Q Quit │ ^O Open │ ^C Copy │
└──────────────────────────────────────┘",
_output);
_output
);
((FakeDriver)Application.Driver).SetBufferSize (20, 10);
@@ -128,7 +116,8 @@ public class WindowTests
│└────────────────┘│
│ ^Q Quit │ ^O Open│
└──────────────────┘",
_output);
_output
);
}
[Fact]
@@ -163,7 +152,7 @@ public class WindowTests
Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
// Empty Rect
r = new Window (Rect.Empty) { Title = "title" };
r = new Window { Frame = Rect.Empty, Title = "title" };
Assert.NotNull (r);
Assert.Equal ("title", r.Title);
Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
@@ -189,7 +178,7 @@ public class WindowTests
Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
// Rect with values
r = new Window (new Rect (1, 2, 3, 4)) { Title = "title" };
r = new Window { Frame = new Rect (1, 2, 3, 4), Title = "title" };
Assert.Equal ("title", r.Title);
Assert.NotNull (r);
Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);