Skip to content

Commit

Permalink
Merge pull request #3854 from tig/v2-BackportPopoverFixes
Browse files Browse the repository at this point in the history
Backport of a bunch of fixes from #3691
  • Loading branch information
tig authored Nov 26, 2024
2 parents b55ed5a + e5c5f61 commit ead4bef
Show file tree
Hide file tree
Showing 25 changed files with 805 additions and 472 deletions.
2 changes: 2 additions & 0 deletions Terminal.Gui/Application/Application.Driver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public static partial class Application // Driver abstractions
/// <summary>Gets the <see cref="ConsoleDriver"/> that has been selected. See also <see cref="ForceDriver"/>.</summary>
public static ConsoleDriver? Driver { get; internal set; }

// BUGBUG: Force16Colors should be nullable.
/// <summary>
/// Gets or sets whether <see cref="Application.Driver"/> will be forced to output only the 16 colors defined in
/// <see cref="ColorName16"/>. The default is <see langword="false"/>, meaning 24-bit (TrueColor) colors will be output
Expand All @@ -16,6 +17,7 @@ public static partial class Application // Driver abstractions
[SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
public static bool Force16Colors { get; set; }

// BUGBUG: ForceDriver should be nullable.
/// <summary>
/// Forces the use of the specified driver (one of "fake", "ansi", "curses", "net", or "windows"). If not
/// specified, the driver is selected based on the platform.
Expand Down
5 changes: 5 additions & 0 deletions Terminal.Gui/Application/Application.Keyboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public static bool RaiseKeyDownEvent (Key key)
{
if (binding.Value.BoundView is { })
{
if (!binding.Value.BoundView.Enabled)
{
return false;
}

bool? handled = binding.Value.BoundView?.InvokeCommands (binding.Value.Commands, binding.Key, binding.Value);

if (handled != null && (bool)handled)
Expand Down
5 changes: 5 additions & 0 deletions Terminal.Gui/Drawing/Glyphs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
/// </remarks>
public class GlyphDefinitions
{
// IMPORTANT: If you change these, make sure to update the ./Resources/config.json file as
// IMPORTANT: it is the source of truth for the default glyphs at runtime.
// IMPORTANT: Configuration Manager test SaveDefaults uses this class to generate the default config file
// IMPORTANT: in ./UnitTests/bin/Debug/netX.0/config.json

/// <summary>File icon. Defaults to ☰ (Trigram For Heaven)</summary>
public Rune File { get; set; } = (Rune)'☰';

Expand Down
54 changes: 43 additions & 11 deletions Terminal.Gui/Input/KeyBindings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#nullable enable

using static System.Formats.Asn1.AsnWriter;

namespace Terminal.Gui;

/// <summary>
Expand All @@ -17,7 +19,7 @@ public class KeyBindings
public KeyBindings () { }

/// <summary>Initializes a new instance bound to <paramref name="boundView"/>.</summary>
public KeyBindings (View boundView) { BoundView = boundView; }
public KeyBindings (View? boundView) { BoundView = boundView; }

/// <summary>Adds a <see cref="KeyBinding"/> to the collection.</summary>
/// <param name="key"></param>
Expand All @@ -27,7 +29,12 @@ public void Add (Key key, KeyBinding binding, View? boundViewForAppScope = null)
{
if (BoundView is { } && binding.Scope.FastHasFlags (KeyBindingScope.Application))
{
throw new ArgumentException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add");
throw new InvalidOperationException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add");
}

if (BoundView is { } && boundViewForAppScope is null)
{
boundViewForAppScope = BoundView;
}

if (TryGet (key, out KeyBinding _))
Expand Down Expand Up @@ -78,6 +85,10 @@ public void Add (Key key, KeyBindingScope scope, View? boundViewForAppScope = nu
{
throw new ArgumentException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add");
}
else
{
// boundViewForAppScope = BoundView;
}

if (key is null || !key.IsValid)
{
Expand All @@ -93,11 +104,9 @@ public void Add (Key key, KeyBindingScope scope, View? boundViewForAppScope = nu
if (TryGet (key, out KeyBinding binding))
{
throw new InvalidOperationException (@$"A key binding for {key} exists ({binding}).");

//Bindings [key] = new (commands, scope, BoundView);
}

Add (key, new KeyBinding (commands, scope, BoundView), boundViewForAppScope);
Add (key, new KeyBinding (commands, scope, boundViewForAppScope), boundViewForAppScope);
}

/// <summary>
Expand All @@ -120,9 +129,14 @@ public void Add (Key key, KeyBindingScope scope, View? boundViewForAppScope = nu
/// </param>
public void Add (Key key, KeyBindingScope scope, params Command [] commands)
{
if (BoundView is null && !scope.FastHasFlags (KeyBindingScope.Application))
{
throw new InvalidOperationException ("BoundView cannot be null.");
}

if (BoundView is { } && scope.FastHasFlags (KeyBindingScope.Application))
{
throw new ArgumentException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add");
throw new InvalidOperationException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add");
}

if (key == Key.Empty || !key.IsValid)
Expand All @@ -140,7 +154,7 @@ public void Add (Key key, KeyBindingScope scope, params Command [] commands)
throw new InvalidOperationException (@$"A key binding for {key} exists ({binding}).");
}

Add (key, new KeyBinding (commands, scope, BoundView));
Add (key, new KeyBinding (commands, scope, BoundView), BoundView);
}

/// <summary>
Expand Down Expand Up @@ -219,14 +233,22 @@ public void Add (Key key, params Command [] commands)
/// <summary>The collection of <see cref="KeyBinding"/> objects.</summary>
public Dictionary<Key, KeyBinding> Bindings { get; } = new (new KeyEqualityComparer ());

/// <summary>
/// Gets the keys that are bound.
/// </summary>
/// <returns></returns>
public IEnumerable<Key> GetBoundKeys ()
{
return Bindings.Keys;
}

/// <summary>
/// The view that the <see cref="KeyBindings"/> are bound to.
/// </summary>
/// <remarks>
/// If <see langword="null"/>, the <see cref="KeyBindings"/> are not bound to a <see cref="View"/>. This is used for
/// Application.KeyBindings.
/// If <see langword="null"/> the KeyBindings object is being used for Application.KeyBindings.
/// </remarks>
public View? BoundView { get; }
internal View? BoundView { get; }

/// <summary>Removes all <see cref="KeyBinding"/> objects from the collection.</summary>
public void Clear () { Bindings.Clear (); }
Expand Down Expand Up @@ -312,7 +334,7 @@ public IEnumerable<Key> GetKeysFromCommands (params Command [] commands)
/// <param name="boundViewForAppScope">Optional View for <see cref="KeyBindingScope.Application"/> bindings.</param>
public void Remove (Key key, View? boundViewForAppScope = null)
{
if (!TryGet (key, out KeyBinding binding))
if (!TryGet (key, out KeyBinding _))
{
return;
}
Expand Down Expand Up @@ -371,6 +393,11 @@ public void ReplaceKey (Key oldKey, Key newKey)
/// <returns><see langword="true"/> if the Key is bound; otherwise <see langword="false"/>.</returns>
public bool TryGet (Key key, out KeyBinding binding)
{
//if (BoundView is null)
//{
// throw new InvalidOperationException ("KeyBindings must be bound to a View to use this method.");
//}

binding = new (Array.Empty<Command> (), KeyBindingScope.Disabled, null);

if (key.IsValid)
Expand All @@ -394,6 +421,11 @@ public bool TryGet (Key key, KeyBindingScope scope, out KeyBinding binding)
{
if (!key.IsValid)
{
//if (BoundView is null)
//{
// throw new InvalidOperationException ("KeyBindings must be bound to a View to use this method.");
//}

binding = new (Array.Empty<Command> (), KeyBindingScope.Disabled, null);
return false;
}
Expand Down
167 changes: 163 additions & 4 deletions Terminal.Gui/Resources/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,173 @@
// to throw exceptions.
"ConfigurationManager.ThrowOnJsonErrors": false,

"Application.NextTabKey": "Tab",
"Application.PrevTabKey": "Shift+Tab",
// --------------- Application Settings ---------------
"Key.Separator": "+",

"Application.ArrangeKey": "Ctrl+F5",
"Application.Force16Colors": false,
//"Application.ForceDriver": "", // TODO: ForceDriver should be nullable
"Application.IsMouseDisabled": false,
"Application.NextTabGroupKey": "F6",
"Application.NextTabKey": "Tab",
"Application.PrevTabGroupKey": "Shift+F6",
"Application.PrevTabKey": "Shift+Tab",
"Application.QuitKey": "Esc",
"Application.ArrangeKey": "Ctrl+F5",
"Key.Separator": "+",

// --------------- Colors ---------------


// --------------- View Specific Settings ---------------
"ContextMenu.DefaultKey": "Shift+F10",
"FileDialog.MaxSearchResults": 10000,
"FileDialogStyle.DefaultUseColors": false,
"FileDialogStyle.DefaultUseUnicodeCharacters": false,

// --------------- Glyphs ---------------
"Glyphs": {
"File": "",
"Folder": "",
"HorizontalEllipsis": "",
"VerticalFourDots": "",
"CheckStateChecked": "",
"CheckStateUnChecked": "",
"CheckStateNone": "",
"Selected": "",
"UnSelected": "",
"RightArrow": "",
"LeftArrow": "",
"DownArrow": "",
"UpArrow": "",
"LeftDefaultIndicator": "",
"RightDefaultIndicator": "",
"LeftBracket": "",
"RightBracket": "",
"BlocksMeterSegment": "",
"ContinuousMeterSegment": "",
"Stipple": "",
"Diamond": "",
"Close": "",
"Minimize": "",
"Maximize": "",
"Dot": "",
"BlackCircle": "",
"Expand": "+",
"Collapse": "-",
"IdenticalTo": "",
"Move": "",
"SizeHorizontal": "",
"SizeVertical": "",
"SizeTopLeft": "",
"SizeTopRight": "",
"SizeBottomRight": "",
"SizeBottomLeft": "",
"Apple": "\uD83C\uDF4E",
"AppleBMP": "",
"HLine": "",
"VLine": "",
"HLineDbl": "",
"VLineDbl": "",
"HLineHvDa2": "",
"VLineHvDa3": "",
"HLineHvDa3": "",
"HLineHvDa4": "",
"VLineHvDa2": "",
"VLineHvDa4": "",
"HLineDa2": "",
"VLineDa3": "",
"HLineDa3": "",
"HLineDa4": "",
"VLineDa2": "",
"VLineDa4": "",
"HLineHv": "",
"VLineHv": "",
"HalfLeftLine": "",
"HalfTopLine": "",
"HalfRightLine": "",
"HalfBottomLine": "",
"HalfLeftLineHv": "",
"HalfTopLineHv": "",
"HalfRightLineHv": "",
"HalfBottomLineLt": "",
"RightSideLineLtHv": "",
"BottomSideLineLtHv": "",
"LeftSideLineHvLt": "",
"TopSideLineHvLt": "",
"ULCorner": "",
"ULCornerDbl": "",
"ULCornerR": "",
"ULCornerHv": "",
"ULCornerHvLt": "",
"ULCornerLtHv": "",
"ULCornerDblSingle": "",
"ULCornerSingleDbl": "",
"LLCorner": "",
"LLCornerHv": "",
"LLCornerHvLt": "",
"LLCornerLtHv": "",
"LLCornerDbl": "",
"LLCornerSingleDbl": "",
"LLCornerDblSingle": "",
"LLCornerR": "",
"URCorner": "",
"URCornerDbl": "",
"URCornerR": "",
"URCornerHv": "",
"URCornerHvLt": "",
"URCornerLtHv": "",
"URCornerDblSingle": "",
"URCornerSingleDbl": "",
"LRCorner": "",
"LRCornerDbl": "",
"LRCornerR": "",
"LRCornerHv": "",
"LRCornerDblSingle": "",
"LRCornerSingleDbl": "",
"LRCornerLtHv": "",
"LRCornerHvLt": "",
"LeftTee": "",
"LeftTeeDblH": "",
"LeftTeeDblV": "",
"LeftTeeDbl": "",
"LeftTeeHvH": "",
"LeftTeeHvV": "",
"LeftTeeHvDblH": "",
"RightTee": "",
"RightTeeDblH": "",
"RightTeeDblV": "",
"RightTeeDbl": "",
"RightTeeHvH": "",
"RightTeeHvV": "",
"RightTeeHvDblH": "",
"TopTee": "",
"TopTeeDblH": "",
"TopTeeDblV": "",
"TopTeeDbl": "",
"TopTeeHvH": "",
"TopTeeHvV": "",
"TopTeeHvDblH": "",
"BottomTee": "",
"BottomTeeDblH": "",
"BottomTeeDblV": "",
"BottomTeeDbl": "",
"BottomTeeHvH": "",
"BottomTeeHvV": "",
"BottomTeeHvDblH": "",
"Cross": "",
"CrossDblH": "",
"CrossDblV": "",
"CrossDbl": "",
"CrossHvH": "",
"CrossHvV": "",
"CrossHv": "",
"ShadowVerticalStart": "",
"ShadowVertical": "",
"ShadowHorizontalStart": "",
"ShadowHorizontal": "",
"ShadowHorizontalEnd": ""
},

// --------------- Themes -----------------
"Theme": "Default",
"Themes": [
{
Expand Down
2 changes: 1 addition & 1 deletion Terminal.Gui/View/Layout/DimAuto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ internal override int Calculate (int location, int superviewContentSize, View us
int screenX4 = dimension == Dimension.Width ? Application.Screen.Width * 4 : Application.Screen.Height * 4;
int autoMax = MaximumContentDim?.GetAnchor (superviewContentSize) ?? screenX4;

Debug.Assert (autoMin <= autoMax, "MinimumContentDim must be less than or equal to MaximumContentDim.");
Debug.WriteLineIf (autoMin > autoMax, "MinimumContentDim must be less than or equal to MaximumContentDim.");

if (Style.FastHasFlags (DimAutoStyle.Text))
{
Expand Down
10 changes: 9 additions & 1 deletion Terminal.Gui/View/View.Drawing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public void Draw ()
// Draw the Border and Padding.
// We clip to the frame to prevent drawing outside the frame.
saved = ClipFrame ();

DoDrawBorderAndPadding ();
SetClip (saved);

Expand All @@ -71,7 +72,7 @@ public void Draw ()
DoSetAttribute ();
DoClearViewport ();

// Draw the subviews
// Draw the subviews only if needed
if (SubViewNeedsDraw)
{
DoSetAttribute ();
Expand Down Expand Up @@ -166,6 +167,13 @@ private void DoDrawBorderAndPaddingSubViews ()

private void DoDrawBorderAndPadding ()
{
if (SubViewNeedsDraw)
{
// A Subview may add to the LineCanvas. This ensures any Adornment LineCanvas updates happen.
Border?.SetNeedsDraw ();
Padding?.SetNeedsDraw ();
}

if (OnDrawingBorderAndPadding ())
{
return;
Expand Down
Loading

0 comments on commit ead4bef

Please sign in to comment.