mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
rebuilt
This commit is contained in:
23
Terminal.Gui/View/IDesignable.cs
Normal file
23
Terminal.Gui/View/IDesignable.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// Interface declaring common functionality useful for designer implementations.
|
||||
/// </summary>
|
||||
public interface IDesignable
|
||||
{
|
||||
/// <summary>
|
||||
/// Causes the View to enable design-time mode. This typically means that the view will load demo data and
|
||||
/// be configured to allow for design-time manipulation.
|
||||
/// </summary>
|
||||
/// <param name="context">Optional arbitrary, View-specific, context.</param>
|
||||
/// <typeparam name="TContext">A non-null type for <paramref name="context"/>.</typeparam>
|
||||
/// <returns><see langword="true"/> if the view successfully loaded demo data.</returns>
|
||||
public bool EnableForDesign<TContext> (in TContext context) where TContext : notnull => EnableForDesign ();
|
||||
|
||||
/// <summary>
|
||||
/// Causes the View to enable design-time mode. This typically means that the view will load demo data and
|
||||
/// be configured to allow for design-time manipulation.
|
||||
/// </summary>
|
||||
/// <returns><see langword="true"/> if the view successfully loaded demo data.</returns>
|
||||
public bool EnableForDesign () => false;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ namespace Terminal.Gui;
|
||||
/// invoked repeatedly while the button is pressed.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class Button : View
|
||||
public class Button : View, IDesignable
|
||||
{
|
||||
private readonly Rune _leftBracket;
|
||||
private readonly Rune _leftDefault;
|
||||
@@ -190,4 +190,12 @@ public class Button : View
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool EnableForDesign ()
|
||||
{
|
||||
Title = "_Button";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ using System.ComponentModel;
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>Provides a drop-down list of items the user can select from.</summary>
|
||||
public class ComboBox : View
|
||||
public class ComboBox : View, IDesignable
|
||||
{
|
||||
private readonly ComboListView _listview;
|
||||
private readonly int _minimumHeight = 2;
|
||||
@@ -243,7 +243,7 @@ public class ComboBox : View
|
||||
public event EventHandler Expanded;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected internal override bool OnMouseEvent (MouseEvent me)
|
||||
protected internal override bool OnMouseEvent (MouseEvent me)
|
||||
{
|
||||
if (me.Position.X == Viewport.Right - 1
|
||||
&& me.Position.Y == Viewport.Top
|
||||
@@ -813,7 +813,7 @@ public class ComboBox : View
|
||||
set => _hideDropdownListOnClick = WantContinuousButtonPressed = value;
|
||||
}
|
||||
|
||||
protected internal override bool OnMouseEvent (MouseEvent me)
|
||||
protected internal override bool OnMouseEvent (MouseEvent me)
|
||||
{
|
||||
var res = false;
|
||||
bool isMousePositionValid = IsMousePositionValid (me);
|
||||
@@ -983,4 +983,14 @@ public class ComboBox : View
|
||||
AddCommand (Command.LineUp, () => _container.MoveUpList ());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool EnableForDesign ()
|
||||
{
|
||||
var source = new ObservableCollection<string> (["Combo Item 1", "Combo Item two", "Combo Item Quattro", "Last Combo Item"]);
|
||||
SetSource (source);
|
||||
Height = Dim.Auto (DimAutoStyle.Content, minimumContentDim: source.Count + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ public interface IListDataSource: IDisposable
|
||||
/// first item that starts with what the user types will be selected.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class ListView : View
|
||||
public class ListView : View, IDesignable
|
||||
{
|
||||
private bool _allowsMarking;
|
||||
private bool _allowsMultipleSelection = true;
|
||||
@@ -921,6 +921,15 @@ public class ListView : View
|
||||
Source.SuspendCollectionChangedEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool EnableForDesign ()
|
||||
{
|
||||
var source = new ListWrapper<string> (["List Item 1", "List Item two", "List Item Quattro", "Last List Item"]);
|
||||
Source = source;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Terminal.Gui;
|
||||
/// duplicates a shortcut (e.g. _File and Alt-F), the hot key wins.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class MenuBar : View
|
||||
public class MenuBar : View, IDesignable
|
||||
{
|
||||
// Spaces before the Title
|
||||
private static readonly int _leftPadding = 1;
|
||||
@@ -1591,4 +1591,177 @@ public class MenuBar : View
|
||||
}
|
||||
|
||||
#endregion Mouse Handling
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool EnableForDesign<TContext> (in TContext context) where TContext : notnull
|
||||
{
|
||||
if (context is not Func<string, bool> actionFn)
|
||||
{
|
||||
actionFn = (s) => true;
|
||||
}
|
||||
|
||||
Menus =
|
||||
[
|
||||
new MenuBarItem (
|
||||
"_File",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_New",
|
||||
"",
|
||||
() => actionFn ("New"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.N
|
||||
),
|
||||
new (
|
||||
"_Open",
|
||||
"",
|
||||
() => actionFn ("Open"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.O
|
||||
),
|
||||
new (
|
||||
"_Save",
|
||||
"",
|
||||
() => actionFn ("Save"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.S
|
||||
),
|
||||
null,
|
||||
|
||||
// Don't use Application.Quit so we can disambiguate between quitting and closing the toplevel
|
||||
new (
|
||||
"_Quit",
|
||||
"",
|
||||
() => actionFn ("Quit"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.Q
|
||||
)
|
||||
}
|
||||
),
|
||||
new MenuBarItem (
|
||||
"_Edit",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_Copy",
|
||||
"",
|
||||
() => actionFn ("Copy"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.C
|
||||
),
|
||||
new (
|
||||
"C_ut",
|
||||
"",
|
||||
() => actionFn ("Cut"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.X
|
||||
),
|
||||
new (
|
||||
"_Paste",
|
||||
"",
|
||||
() => actionFn ("Paste"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.V
|
||||
),
|
||||
new MenuBarItem (
|
||||
"_Find and Replace",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"F_ind",
|
||||
"",
|
||||
() => actionFn ("Find"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.F
|
||||
),
|
||||
new (
|
||||
"_Replace",
|
||||
"",
|
||||
() => actionFn ("Replace"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.H
|
||||
),
|
||||
new MenuBarItem (
|
||||
"_3rd Level",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_1st",
|
||||
"",
|
||||
() => actionFn (
|
||||
"1"
|
||||
),
|
||||
null,
|
||||
null,
|
||||
KeyCode.F1
|
||||
),
|
||||
new (
|
||||
"_2nd",
|
||||
"",
|
||||
() => actionFn (
|
||||
"2"
|
||||
),
|
||||
null,
|
||||
null,
|
||||
KeyCode.F2
|
||||
)
|
||||
}
|
||||
),
|
||||
new MenuBarItem (
|
||||
"_4th Level",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_5th",
|
||||
"",
|
||||
() => actionFn (
|
||||
"5"
|
||||
),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask
|
||||
| KeyCode.D5
|
||||
),
|
||||
new (
|
||||
"_6th",
|
||||
"",
|
||||
() => actionFn (
|
||||
"6"
|
||||
),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask
|
||||
| KeyCode.D6
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
new (
|
||||
"_Select All",
|
||||
"",
|
||||
() => actionFn ("Select All"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask
|
||||
| KeyCode.ShiftMask
|
||||
| KeyCode.S
|
||||
)
|
||||
}
|
||||
),
|
||||
new MenuBarItem ("_About", "Top-Level", () => actionFn ("About"))
|
||||
];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public enum ProgressBarFormat
|
||||
/// <see cref="Pulse"/> method is called. Call <see cref="Pulse"/> repeatedly as progress is made.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class ProgressBar : View
|
||||
public class ProgressBar : View, IDesignable
|
||||
{
|
||||
private int [] _activityPos;
|
||||
private bool _bidirectionalMarquee = true;
|
||||
@@ -277,4 +277,13 @@ public class ProgressBar : View
|
||||
_fraction = 0;
|
||||
Initialized += ProgressBar_Initialized;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool EnableForDesign ()
|
||||
{
|
||||
Width = Dim.Fill ();
|
||||
Height = Dim.Auto (DimAutoStyle.Text, minimumContentDim: 1);
|
||||
Fraction = 0.75f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>Displays a group of labels each with a selected indicator. Only one of those can be selected at a given time.</summary>
|
||||
public class RadioGroup : View
|
||||
public class RadioGroup : View, IDesignable
|
||||
{
|
||||
private int _cursor;
|
||||
private List<(int pos, int length)> _horizontal;
|
||||
@@ -229,32 +229,6 @@ public class RadioGroup : View
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_radioLabels.Count == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// Return labels as a CSV string
|
||||
return string.Join (",", _radioLabels);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty (value))
|
||||
{
|
||||
RadioLabels = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
RadioLabels = value.Split (',').Select (x => x.Trim ()).ToArray ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The currently selected item from the list of radio labels</summary>
|
||||
/// <value>The selected.</value>
|
||||
public int SelectedItem
|
||||
@@ -487,4 +461,11 @@ public class RadioGroup : View
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool EnableForDesign ()
|
||||
{
|
||||
RadioLabels = new [] { "Option _1", "Option _2", "Option _3" };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,49 +348,17 @@ public class AllViewsTester : Scenario
|
||||
view.ColorScheme = Colors.ColorSchemes ["Base"];
|
||||
}
|
||||
|
||||
// If the view supports a Text property, set it so we have something to look at
|
||||
if (view.GetType ().GetProperty ("Text") != null)
|
||||
if (view is IDesignable designable)
|
||||
{
|
||||
try
|
||||
{
|
||||
view.GetType ()
|
||||
.GetProperty ("Text")
|
||||
?.GetSetMethod ()
|
||||
?.Invoke (view, new [] { _demoText });
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
MessageBox.ErrorQuery ("Exception", e.InnerException.Message, "Ok");
|
||||
view = null;
|
||||
}
|
||||
}
|
||||
|
||||
// If the view supports a Title property, set it so we have something to look at
|
||||
if (view != null && view.GetType ().GetProperty ("Title") != null)
|
||||
{
|
||||
if (view.GetType ().GetProperty ("Title")!.PropertyType == typeof (string))
|
||||
{
|
||||
view?.GetType ()
|
||||
.GetProperty ("Title")
|
||||
?.GetSetMethod ()
|
||||
?.Invoke (view, new [] { "Test Title" });
|
||||
}
|
||||
else
|
||||
{
|
||||
view?.GetType ()
|
||||
.GetProperty ("Title")
|
||||
?.GetSetMethod ()
|
||||
?.Invoke (view, new [] { "Test Title" });
|
||||
}
|
||||
}
|
||||
|
||||
// If the view supports a Source property, set it so we have something to look at
|
||||
if (view != null && view.GetType ().GetProperty ("Source") != null && view.GetType ().GetProperty ("Source").PropertyType == typeof (IListDataSource))
|
||||
{
|
||||
var source = new ListWrapper<string> (["Test Text #1", "Test Text #2", "Test Text #3"]);
|
||||
view?.GetType ().GetProperty ("Source")?.GetSetMethod ()?.Invoke (view, [source]);
|
||||
designable.EnableForDesign (_demoText);
|
||||
}
|
||||
else
|
||||
{
|
||||
view.Text = _demoText;
|
||||
view.Title = "_Test Title";
|
||||
}
|
||||
|
||||
// TODO: Add IOrientation so this doesn't require reflection
|
||||
// If the view supports a Title property, set it so we have something to look at
|
||||
if (view?.GetType ().GetProperty ("Orientation") is { } prop)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using Terminal.Gui;
|
||||
|
||||
namespace UICatalog.Scenarios;
|
||||
|
||||
[ScenarioMetadata ("MenuBar", "Demonstrates the MenuBar using the same menu used in unit tests.")]
|
||||
[ScenarioMetadata ("MenuBar", "Demonstrates the MenuBar using the demo menu.")]
|
||||
[ScenarioCategory ("Controls")]
|
||||
[ScenarioCategory ("Menus")]
|
||||
public class MenuBarScenario : Scenario
|
||||
@@ -14,186 +14,6 @@ public class MenuBarScenario : Scenario
|
||||
private Label _lastAction;
|
||||
private Label _lastKey;
|
||||
|
||||
/// <summary>
|
||||
/// This method creates at test menu bar. It is called by the MenuBar unit tests, so it's possible to do both unit
|
||||
/// testing and user-experience testing with the same setup.
|
||||
/// </summary>
|
||||
/// <param name="actionFn"></param>
|
||||
/// <returns></returns>
|
||||
public static MenuBar CreateTestMenu (Func<string, bool> actionFn)
|
||||
{
|
||||
// TODO: add a disabled menu item to this
|
||||
var mb = new MenuBar
|
||||
{
|
||||
Menus =
|
||||
[
|
||||
new MenuBarItem (
|
||||
"_File",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_New",
|
||||
"",
|
||||
() => actionFn ("New"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.N
|
||||
),
|
||||
new (
|
||||
"_Open",
|
||||
"",
|
||||
() => actionFn ("Open"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.O
|
||||
),
|
||||
new (
|
||||
"_Save",
|
||||
"",
|
||||
() => actionFn ("Save"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.S
|
||||
),
|
||||
null,
|
||||
|
||||
// Don't use Application.Quit so we can disambiguate between quitting and closing the toplevel
|
||||
new (
|
||||
"_Quit",
|
||||
"",
|
||||
() => actionFn ("Quit"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.Q
|
||||
)
|
||||
}
|
||||
),
|
||||
new MenuBarItem (
|
||||
"_Edit",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_Copy",
|
||||
"",
|
||||
() => actionFn ("Copy"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.C
|
||||
),
|
||||
new (
|
||||
"C_ut",
|
||||
"",
|
||||
() => actionFn ("Cut"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.X
|
||||
),
|
||||
new (
|
||||
"_Paste",
|
||||
"",
|
||||
() => actionFn ("Paste"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.V
|
||||
),
|
||||
new MenuBarItem (
|
||||
"_Find and Replace",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"F_ind",
|
||||
"",
|
||||
() => actionFn ("Find"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.F
|
||||
),
|
||||
new (
|
||||
"_Replace",
|
||||
"",
|
||||
() => actionFn ("Replace"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask | KeyCode.H
|
||||
),
|
||||
new MenuBarItem (
|
||||
"_3rd Level",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_1st",
|
||||
"",
|
||||
() => actionFn (
|
||||
"1"
|
||||
),
|
||||
null,
|
||||
null,
|
||||
KeyCode.F1
|
||||
),
|
||||
new (
|
||||
"_2nd",
|
||||
"",
|
||||
() => actionFn (
|
||||
"2"
|
||||
),
|
||||
null,
|
||||
null,
|
||||
KeyCode.F2
|
||||
)
|
||||
}
|
||||
),
|
||||
new MenuBarItem (
|
||||
"_4th Level",
|
||||
new MenuItem []
|
||||
{
|
||||
new (
|
||||
"_5th",
|
||||
"",
|
||||
() => actionFn (
|
||||
"5"
|
||||
),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask
|
||||
| KeyCode.D5
|
||||
),
|
||||
new (
|
||||
"_6th",
|
||||
"",
|
||||
() => actionFn (
|
||||
"6"
|
||||
),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask
|
||||
| KeyCode.D6
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
new (
|
||||
"_Select All",
|
||||
"",
|
||||
() => actionFn ("Select All"),
|
||||
null,
|
||||
null,
|
||||
KeyCode.CtrlMask
|
||||
| KeyCode.ShiftMask
|
||||
| KeyCode.S
|
||||
)
|
||||
}
|
||||
),
|
||||
new MenuBarItem ("_About", "Top-Level", () => actionFn ("About"))
|
||||
]
|
||||
};
|
||||
mb.UseKeysUpDownAsKeysLeftRight = true;
|
||||
mb.Key = KeyCode.F9;
|
||||
mb.Title = "TestMenuBar";
|
||||
|
||||
return mb;
|
||||
}
|
||||
|
||||
public override void Main ()
|
||||
{
|
||||
// Init
|
||||
@@ -239,14 +59,19 @@ public class MenuBarScenario : Scenario
|
||||
_focusedView = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
|
||||
appWindow.Add (_focusedView);
|
||||
|
||||
MenuBar menuBar = CreateTestMenu (
|
||||
s =>
|
||||
{
|
||||
_lastAction.Text = s;
|
||||
MenuBar menuBar = new MenuBar ();
|
||||
menuBar.UseKeysUpDownAsKeysLeftRight = true;
|
||||
menuBar.Key = KeyCode.F9;
|
||||
menuBar.Title = "TestMenuBar";
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
bool fnAction (string s)
|
||||
{
|
||||
_lastAction.Text = s;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
menuBar.EnableForDesign ((Func<string, bool>)fnAction);
|
||||
|
||||
menuBar.MenuOpening += (s, e) =>
|
||||
{
|
||||
|
||||
@@ -1253,14 +1253,16 @@ wo
|
||||
MenuItem mbiCurrent = null;
|
||||
MenuItem miCurrent = null;
|
||||
|
||||
MenuBar menu = MenuBarScenario.CreateTestMenu (
|
||||
s =>
|
||||
MenuBar menu = new MenuBar ();
|
||||
menu.EnableForDesign (
|
||||
new Func<object, bool> (s =>
|
||||
{
|
||||
miAction = s;
|
||||
miAction = s as string;
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
menu.Key = KeyCode.F9;
|
||||
menu.MenuOpening += (s, e) => mbiCurrent = e.CurrentMenu;
|
||||
menu.MenuOpened += (s, e) => { miCurrent = e.MenuItem; };
|
||||
@@ -1301,14 +1303,16 @@ wo
|
||||
MenuItem mbiCurrent = null;
|
||||
MenuItem miCurrent = null;
|
||||
|
||||
MenuBar menu = MenuBarScenario.CreateTestMenu (
|
||||
s =>
|
||||
MenuBar menu = new MenuBar ();
|
||||
menu.EnableForDesign (
|
||||
new Func<object, bool> (s =>
|
||||
{
|
||||
miAction = s;
|
||||
miAction = s as string;
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
menu.Key = KeyCode.F9;
|
||||
menu.MenuOpening += (s, e) => mbiCurrent = e.CurrentMenu;
|
||||
menu.MenuOpened += (s, e) => { miCurrent = e.MenuItem; };
|
||||
|
||||
Reference in New Issue
Block a user