Tons of stuff

This commit is contained in:
Tig
2024-10-23 15:15:53 -06:00
parent 008d49788e
commit b31339da02
91 changed files with 1654 additions and 1025 deletions

View File

@@ -99,10 +99,12 @@ public class Adornments : Scenario
longLabel.TextFormatter.WordWrap = true;
window.Add (tf1, color, button, label, btnButtonInWindow, labelAnchorEnd, longLabel);
editor.Initialized += (s, e) => { editor.ViewToEdit = window; };
window.Initialized += (s, e) =>
{
editor.ViewToEdit = window;
editor.ShowViewIdentifier = true;
var labelInPadding = new Label { X = 1, Y = 0, Title = "_Text:" };
window.Padding.Add (labelInPadding);

View File

@@ -15,37 +15,20 @@ namespace UICatalog.Scenarios;
[ScenarioCategory ("Adornments")]
public class AllViewsTester : Scenario
{
private readonly List<string> _dimNames = new () { "Auto", "Percent", "Fill", "Absolute" };
// TODO: This is missing some
private readonly List<string> _posNames = new () { "Percent", "AnchorEnd", "Center", "Absolute" };
private ListView _classListView;
private View _curView;
private FrameView _hostPane;
private AdornmentsEditor _adornmentsEditor;
private RadioGroup _hRadioGroup;
private TextField _hText;
private int _hVal;
private FrameView _leftPane;
private FrameView _locationFrame;
// Settings
private FrameView _settingsPane;
private FrameView _sizeFrame;
private Dictionary<string, Type> _viewClasses;
private RadioGroup _wRadioGroup;
private TextField _wText;
private int _wVal;
private RadioGroup _xRadioGroup;
private TextField _xText;
private int _xVal;
private RadioGroup _yRadioGroup;
private TextField _yText;
private int _yVal;
private ListView _classListView;
private AdornmentsEditor _adornmentsEditor;
private LayoutEditor _layoutEditor;
private FrameView _settingsPane;
private RadioGroup _orientation;
private string _demoText = "This, that, and the other thing.";
private TextView _demoTextView;
private FrameView _hostPane;
private View _curView;
public override void Main ()
{
// Don't create a sub-win (Scenario.Win); just use Application.Top
@@ -54,7 +37,8 @@ public class AllViewsTester : Scenario
var app = new Window
{
Title = GetQuitKeyAndName (),
ColorScheme = Colors.ColorSchemes ["TopLevel"]
ColorScheme = Colors.ColorSchemes ["TopLevel"],
BorderStyle = LineStyle.None
};
_viewClasses = GetAllViewClassesCollection ()
@@ -62,19 +46,9 @@ public class AllViewsTester : Scenario
.Select (t => new KeyValuePair<string, Type> (t.Name, t))
.ToDictionary (t => t.Key, t => t.Value);
_leftPane = new ()
{
X = 0,
Y = 0,
Width = Dim.Auto (DimAutoStyle.Content),
Height = Dim.Fill (),
CanFocus = true,
ColorScheme = Colors.ColorSchemes ["TopLevel"],
Title = "Classes"
};
_classListView = new ()
{
Title = "Classes [_1]",
X = 0,
Y = 0,
Width = Dim.Auto (),
@@ -82,7 +56,8 @@ public class AllViewsTester : Scenario
AllowsMarking = false,
ColorScheme = Colors.ColorSchemes ["TopLevel"],
SelectedItem = 0,
Source = new ListWrapper<string> (new (_viewClasses.Keys.ToList ()))
Source = new ListWrapper<string> (new (_viewClasses.Keys.ToList ())),
BorderStyle = LineStyle.Rounded
};
_classListView.SelectedItemChanged += (s, args) =>
@@ -100,11 +75,11 @@ public class AllViewsTester : Scenario
_adornmentsEditor.ViewToEdit = _curView;
}
};
_leftPane.Add (_classListView);
_adornmentsEditor = new ()
{
X = Pos.Right (_leftPane),
Title = "Adornments [_2]",
X = Pos.Right (_classListView),
Y = 0,
Width = Dim.Auto (),
Height = Dim.Fill (),
@@ -121,150 +96,31 @@ public class AllViewsTester : Scenario
};
_adornmentsEditor.Border.Add (expandButton);
_settingsPane = new ()
_layoutEditor = new ()
{
Title = "Layout [_3]",
X = Pos.Right (_adornmentsEditor),
Y = 0, // for menu
Y = 0,
Width = Dim.Fill (),
Height = Dim.Auto (),
CanFocus = true,
ColorScheme = Colors.ColorSchemes ["TopLevel"],
Title = "Settings"
BorderStyle = LineStyle.Rounded
};
string [] radioItems = { "_Percent(x)", "_AnchorEnd", "_Center", "A_bsolute(x)" };
_locationFrame = new ()
_settingsPane = new ()
{
X = 0,
Y = 0,
Title = "Settings [_4]",
X = Pos.Right (_adornmentsEditor),
Y = Pos.Bottom (_layoutEditor),
Width = Dim.Fill (),
Height = Dim.Auto (),
Width = Dim.Auto (),
Title = "Location (Pos)",
TabStop = TabBehavior.TabStop,
};
_settingsPane.Add (_locationFrame);
var label = new Label { X = 0, Y = 0, Text = "X:" };
_locationFrame.Add (label);
_xRadioGroup = new () { X = 0, Y = Pos.Bottom (label), RadioLabels = radioItems };
_xRadioGroup.SelectedItemChanged += OnRadioGroupOnSelectedItemChanged;
_xText = new () { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_xVal}" };
_xText.Accepting += (s, args) =>
{
try
{
_xVal = int.Parse (_xText.Text);
DimPosChanged (_curView);
}
catch
{ }
};
_locationFrame.Add (_xText);
_locationFrame.Add (_xRadioGroup);
radioItems = new [] { "P_ercent(y)", "A_nchorEnd", "C_enter", "Absolute(_y)" };
label = new () { X = Pos.Right (_xRadioGroup) + 1, Y = 0, Text = "Y:" };
_locationFrame.Add (label);
_yText = new () { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_yVal}" };
_yText.Accepting += (s, args) =>
{
try
{
_yVal = int.Parse (_yText.Text);
DimPosChanged (_curView);
}
catch
{ }
};
_locationFrame.Add (_yText);
_yRadioGroup = new () { X = Pos.X (label), Y = Pos.Bottom (label), RadioLabels = radioItems };
_yRadioGroup.SelectedItemChanged += OnRadioGroupOnSelectedItemChanged;
_locationFrame.Add (_yRadioGroup);
_sizeFrame = new ()
{
X = Pos.Right (_locationFrame),
Y = Pos.Y (_locationFrame),
Height = Dim.Auto (),
Width = Dim.Auto (),
Title = "Size (Dim)",
TabStop = TabBehavior.TabStop,
CanFocus = true,
ColorScheme = Colors.ColorSchemes ["TopLevel"],
BorderStyle = LineStyle.Rounded
};
radioItems = new [] { "Auto", "_Percent(width)", "_Fill(width)", "A_bsolute(width)" };
label = new () { X = 0, Y = 0, Text = "Width:" };
_sizeFrame.Add (label);
_wRadioGroup = new () { X = 0, Y = Pos.Bottom (label), RadioLabels = radioItems };
_wRadioGroup.SelectedItemChanged += OnRadioGroupOnSelectedItemChanged;
_wText = new () { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_wVal}" };
_wText.Accepting += (s, args) =>
{
try
{
switch (_wRadioGroup.SelectedItem)
{
case 1:
_wVal = Math.Min (int.Parse (_wText.Text), 100);
break;
case 0:
case 2:
case 3:
_wVal = int.Parse (_wText.Text);
break;
}
DimPosChanged (_curView);
}
catch
{ }
};
_sizeFrame.Add (_wText);
_sizeFrame.Add (_wRadioGroup);
radioItems = new [] { "_Auto", "P_ercent(height)", "F_ill(height)", "Ab_solute(height)" };
label = new () { X = Pos.Right (_wRadioGroup) + 1, Y = 0, Text = "Height:" };
_sizeFrame.Add (label);
_hText = new () { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_hVal}" };
_hText.Accepting += (s, args) =>
{
try
{
switch (_hRadioGroup.SelectedItem)
{
case 1:
_hVal = Math.Min (int.Parse (_hText.Text), 100);
break;
case 0:
case 2:
case 3:
_hVal = int.Parse (_hText.Text);
break;
}
DimPosChanged (_curView);
}
catch
{ }
};
_sizeFrame.Add (_hText);
_hRadioGroup = new () { X = Pos.X (label), Y = Pos.Bottom (label), RadioLabels = radioItems };
_hRadioGroup.SelectedItemChanged += OnRadioGroupOnSelectedItemChanged;
_sizeFrame.Add (_hRadioGroup);
_settingsPane.Add (_sizeFrame);
label = new () { X = 0, Y = Pos.Bottom (_sizeFrame), Text = "_Orientation:" };
Label label = new () { X = 0, Y = 0, Text = "_Orientation:" };
_orientation = new ()
{
@@ -320,27 +176,21 @@ public class AllViewsTester : Scenario
_hostPane.Padding.Diagnostics = ViewDiagnosticFlags.Ruler;
_hostPane.Padding.ColorScheme = Colors.ColorSchemes ["Error"];
_hostPane.LayoutStarted += (sender, args) =>
{
};
app.Add (_leftPane, _adornmentsEditor, _settingsPane, _hostPane);
app.Add (_classListView, _adornmentsEditor, _layoutEditor, _settingsPane, _hostPane);
_classListView.SelectedItem = 0;
_leftPane.SetFocus ();
_classListView.SetFocus ();
Application.Run (app);
app.Dispose ();
Application.Shutdown ();
}
private void OnRadioGroupOnSelectedItemChanged (object s, SelectedItemChangedArgs selected) { DimPosChanged (_curView); }
// TODO: Add Command.HotKey handler (pop a message box?)
private void CreateCurrentView (Type type)
{
Debug.Assert(_curView is null);
Debug.Assert (_curView is null);
// If we are to create a generic Type
if (type.IsGenericType)
@@ -381,11 +231,13 @@ public class AllViewsTester : Scenario
}
view.Initialized += CurrentView_Initialized;
view.LayoutComplete += CurrentView_LayoutComplete;
view.SubviewsLaidOut += CurrentView_LayoutComplete;
view.Id = "_curView";
_curView = view;
_hostPane.Add (_curView);
_layoutEditor.ViewToEdit = _curView;
_curView.SetNeedsLayout ();
}
private void DisposeCurrentView ()
@@ -393,89 +245,16 @@ public class AllViewsTester : Scenario
if (_curView != null)
{
_curView.Initialized -= CurrentView_Initialized;
_curView.LayoutComplete -= CurrentView_LayoutComplete;
_curView.SubviewsLaidOut -= CurrentView_LayoutComplete;
_hostPane.Remove (_curView);
_layoutEditor.ViewToEdit = null;
_curView.Dispose ();
_curView = null;
}
}
private void DimPosChanged (View view)
{
if (view == null || _updatingSettings)
{
return;
}
try
{
view.X = _xRadioGroup.SelectedItem switch
{
0 => Pos.Percent (_xVal),
1 => Pos.AnchorEnd (),
2 => Pos.Center (),
3 => Pos.Absolute (_xVal),
_ => view.X
};
view.Y = _yRadioGroup.SelectedItem switch
{
0 => Pos.Percent (_yVal),
1 => Pos.AnchorEnd (),
2 => Pos.Center (),
3 => Pos.Absolute (_yVal),
_ => view.Y
};
view.Width = _wRadioGroup.SelectedItem switch
{
0 => Dim.Auto (),
1 => Dim.Percent (_wVal),
2 => Dim.Fill (_wVal),
3 => Dim.Absolute (_wVal),
_ => view.Width
};
view.Height = _hRadioGroup.SelectedItem switch
{
0 => Dim.Auto (),
1 => Dim.Percent (_hVal),
2 => Dim.Fill (_hVal),
3 => Dim.Absolute (_hVal),
_ => view.Height
};
}
catch (Exception e)
{
MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
}
if (view.Width is DimAuto)
{
_wText.Text = "Auto";
_wText.Enabled = false;
}
else
{
_wText.Text = $"{_wVal}";
_wText.Enabled = true;
}
if (view.Height is DimAuto)
{
_hText.Text = "Auto";
_hText.Enabled = false;
}
else
{
_hText.Text = $"{_hVal}";
_hText.Enabled = true;
}
UpdateHostTitle (view);
}
private List<Type> GetAllViewClassesCollection ()
private static List<Type> GetAllViewClassesCollection ()
{
List<Type> types = new ();
@@ -495,62 +274,10 @@ public class AllViewsTester : Scenario
private void CurrentView_LayoutComplete (object sender, LayoutEventArgs args)
{
UpdateSettings (_curView);
UpdateHostTitle (_curView);
}
private bool _updatingSettings = false;
private void UpdateSettings (View view)
{
_updatingSettings = true;
var x = view.X.ToString ();
var y = view.Y.ToString ();
try
{
_xRadioGroup.SelectedItem = _posNames.IndexOf (_posNames.First (s => x.Contains (s)));
_yRadioGroup.SelectedItem = _posNames.IndexOf (_posNames.First (s => y.Contains (s)));
}
catch (InvalidOperationException e)
{
// This is a hack to work around the fact that the Pos enum doesn't have an "Align" value yet
Debug.WriteLine ($"{e}");
}
_xText.Text = $"{view.Frame.X}";
_yText.Text = $"{view.Frame.Y}";
var w = view.Width.ToString ();
var h = view.Height.ToString ();
_wRadioGroup.SelectedItem = _dimNames.IndexOf (_dimNames.First (s => w.Contains (s)));
_hRadioGroup.SelectedItem = _dimNames.IndexOf (_dimNames.First (s => h.Contains (s)));
if (view.Width.Has<DimAuto> (out _))
{
_wText.Text = "Auto";
_wText.Enabled = false;
}
else
{
_wText.Text = $"{view.Frame.Width}";
_wText.Enabled = true;
}
if (view.Height.Has<DimAuto> (out _))
{
_hText.Text = "Auto";
_hText.Enabled = false;
}
else
{
_hText.Text = $"{view.Frame.Height}";
_hText.Enabled = true;
}
_updatingSettings = false;
}
private void UpdateHostTitle (View view) { _hostPane.Title = $"_Demo of {view.GetType ().Name}"; }
private void UpdateHostTitle (View view) { _hostPane.Title = $"Demo of {view.GetType ().Name} [_0]"; }
private void CurrentView_Initialized (object sender, EventArgs e)
{
@@ -569,8 +296,6 @@ public class AllViewsTester : Scenario
view.Height = Dim.Fill ();
}
UpdateSettings (view);
UpdateHostTitle (view);
}
}

View File

@@ -57,7 +57,7 @@ public class AnimationScenario : Scenario
}
var f = new FileInfo (
Path.Combine (dir.FullName, "Scenarios", "Spinning_globe_dark_small.gif")
Path.Combine (dir.FullName, "Scenarios\\AnimationScenario", "Spinning_globe_dark_small.gif")
);
if (!f.Exists)

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -29,6 +29,7 @@ public class Arrangement : Scenario
Y = 0,
AutoSelectViewToEdit = true,
TabStop = TabBehavior.NoStop,
ShowViewIdentifier = true
};
app.Add (adornmentsEditor);

View File

@@ -50,7 +50,7 @@ public class ComputedLayout : Scenario
Text = vrule
};
app.LayoutComplete += (s, a) =>
app.SubviewsLaidOut += (s, a) =>
{
if (horizontalRuler.Viewport.Width == 0 || horizontalRuler.Viewport.Height == 0)
{

View File

@@ -108,7 +108,8 @@ public class ContentScrolling : Scenario
var editor = new AdornmentsEditor
{
AutoSelectViewToEdit = true
AutoSelectViewToEdit = true,
ShowViewIdentifier = true
};
app.Add (editor);
@@ -137,10 +138,10 @@ public class ContentScrolling : Scenario
var cbAllowNegativeX = new CheckBox
{
Title = "Allow _X < 0",
Y = Pos.Bottom(frameLabel),
Y = Pos.Bottom (frameLabel),
CanFocus = true
};
cbAllowNegativeX.CheckedState = view.ViewportSettings.HasFlag(ViewportSettings.AllowNegativeX) ? CheckState.Checked : CheckState.UnChecked;
cbAllowNegativeX.CheckedState = view.ViewportSettings.HasFlag (ViewportSettings.AllowNegativeX) ? CheckState.Checked : CheckState.UnChecked;
cbAllowNegativeX.CheckedStateChanging += AllowNegativeX_Toggle;
void AllowNegativeX_Toggle (object sender, CancelEventArgs<CheckState> e)
@@ -164,7 +165,7 @@ public class ContentScrolling : Scenario
Y = Pos.Bottom (frameLabel),
CanFocus = true
};
cbAllowNegativeY.CheckedState = view.ViewportSettings.HasFlag(ViewportSettings.AllowNegativeY) ? CheckState.Checked : CheckState.UnChecked;
cbAllowNegativeY.CheckedState = view.ViewportSettings.HasFlag (ViewportSettings.AllowNegativeY) ? CheckState.Checked : CheckState.UnChecked;
cbAllowNegativeY.CheckedStateChanging += AllowNegativeY_Toggle;
void AllowNegativeY_Toggle (object sender, CancelEventArgs<CheckState> e)
@@ -187,7 +188,7 @@ public class ContentScrolling : Scenario
Y = Pos.Bottom (cbAllowNegativeX),
CanFocus = true
};
cbAllowXGreaterThanContentWidth.CheckedState = view.ViewportSettings.HasFlag(ViewportSettings.AllowXGreaterThanContentWidth) ? CheckState.Checked : CheckState.UnChecked;
cbAllowXGreaterThanContentWidth.CheckedState = view.ViewportSettings.HasFlag (ViewportSettings.AllowXGreaterThanContentWidth) ? CheckState.Checked : CheckState.UnChecked;
cbAllowXGreaterThanContentWidth.CheckedStateChanging += AllowXGreaterThanContentWidth_Toggle;
void AllowXGreaterThanContentWidth_Toggle (object sender, CancelEventArgs<CheckState> e)
@@ -211,7 +212,7 @@ public class ContentScrolling : Scenario
Y = Pos.Bottom (cbAllowNegativeX),
CanFocus = true
};
cbAllowYGreaterThanContentHeight.CheckedState = view.ViewportSettings.HasFlag(ViewportSettings.AllowYGreaterThanContentHeight) ? CheckState.Checked : CheckState.UnChecked;
cbAllowYGreaterThanContentHeight.CheckedState = view.ViewportSettings.HasFlag (ViewportSettings.AllowYGreaterThanContentHeight) ? CheckState.Checked : CheckState.UnChecked;
cbAllowYGreaterThanContentHeight.CheckedStateChanging += AllowYGreaterThanContentHeight_Toggle;
void AllowYGreaterThanContentHeight_Toggle (object sender, CancelEventArgs<CheckState> e)
@@ -290,7 +291,7 @@ public class ContentScrolling : Scenario
Y = Pos.Top (labelContentSize),
CanFocus = true
};
cbClearContentOnly.CheckedState = view.ViewportSettings.HasFlag(ViewportSettings.ClearContentOnly) ? CheckState.Checked : CheckState.UnChecked;
cbClearContentOnly.CheckedState = view.ViewportSettings.HasFlag (ViewportSettings.ClearContentOnly) ? CheckState.Checked : CheckState.UnChecked;
cbClearContentOnly.CheckedStateChanging += ClearContentOnly_Toggle;
void ClearContentOnly_Toggle (object sender, CancelEventArgs<CheckState> e)

View File

@@ -1,4 +1,5 @@
using System;
#nullable enable
using System;
using Terminal.Gui;
namespace UICatalog.Scenarios;
@@ -15,7 +16,6 @@ public class AdornmentEditor : View
BoxHeight = 1,
BorderStyle = LineStyle.Single,
SuperViewRendersLineCanvas = true,
Enabled = false
};
private readonly ColorPicker16 _foregroundColorPicker = new ()
@@ -25,11 +25,15 @@ public class AdornmentEditor : View
BoxHeight = 1,
BorderStyle = LineStyle.Single,
SuperViewRendersLineCanvas = true,
Enabled = false
};
private Adornment _adornment;
public Adornment AdornmentToEdit
private CheckBox? _diagThicknessCheckBox;
private CheckBox? _diagRulerCheckBox;
private Adornment? _adornment;
public Adornment? AdornmentToEdit
{
get => _adornment;
set
@@ -41,10 +45,7 @@ public class AdornmentEditor : View
_adornment = value;
foreach (var subview in Subviews)
{
subview.Enabled = _adornment is { };
}
Enabled = _adornment is { };
if (_adornment is null)
{
@@ -53,10 +54,10 @@ public class AdornmentEditor : View
if (IsInitialized)
{
_topEdit.Value = _adornment.Thickness.Top;
_leftEdit.Value = _adornment.Thickness.Left;
_bottomEdit.Value = _adornment.Thickness.Bottom;
_rightEdit.Value = _adornment.Thickness.Right;
_topEdit!.Value = _adornment.Thickness.Top;
_leftEdit!.Value = _adornment.Thickness.Left;
_bottomEdit!.Value = _adornment.Thickness.Bottom;
_rightEdit!.Value = _adornment.Thickness.Right;
_adornment.Initialized += (sender, args) =>
{
@@ -71,17 +72,17 @@ public class AdornmentEditor : View
}
}
public event EventHandler<EventArgs> AdornmentChanged;
public event EventHandler<EventArgs>? AdornmentChanged;
public void OnAdornmentChanged ()
{
AdornmentChanged?.Invoke (this, EventArgs.Empty);
}
private NumericUpDown<int> _topEdit;
private NumericUpDown<int> _leftEdit;
private NumericUpDown<int> _bottomEdit;
private NumericUpDown<int> _rightEdit;
private NumericUpDown<int>? _topEdit;
private NumericUpDown<int>? _leftEdit;
private NumericUpDown<int>? _bottomEdit;
private NumericUpDown<int>? _rightEdit;
public AdornmentEditor ()
{
@@ -95,16 +96,15 @@ public class AdornmentEditor : View
TabStop = TabBehavior.TabStop;
}
private void AdornmentEditor_Initialized (object sender, EventArgs e)
private void AdornmentEditor_Initialized (object? sender, EventArgs e)
{
ExpanderButton expandButton;
ExpanderButton? expandButton;
Border.Add (expandButton = new ExpanderButton ());
_topEdit = new ()
{
X = Pos.Center (), Y = 0,
Format = "{0, 2}",
Enabled = false
};
_topEdit.ValueChanging += Top_ValueChanging;
@@ -114,7 +114,6 @@ public class AdornmentEditor : View
{
X = Pos.Left (_topEdit) - Pos.Func (() => _topEdit.Text.Length) - 2, Y = Pos.Bottom (_topEdit),
Format = _topEdit.Format,
Enabled = false
};
_leftEdit.ValueChanging += Left_ValueChanging;
@@ -124,7 +123,6 @@ public class AdornmentEditor : View
{
X = Pos.Right (_leftEdit) + 5, Y = Pos.Bottom (_topEdit),
Format = _topEdit.Format,
Enabled = false
};
_rightEdit.ValueChanging += Right_ValueChanging;
@@ -134,7 +132,6 @@ public class AdornmentEditor : View
{
X = Pos.Center (), Y = Pos.Bottom (_leftEdit),
Format = _topEdit.Format,
Enabled = false
};
_bottomEdit.ValueChanging += Bottom_ValueChanging;
@@ -143,12 +140,11 @@ public class AdornmentEditor : View
var copyTop = new Button
{
X = Pos.Center (), Y = Pos.Bottom (_bottomEdit), Text = "Cop_y Top",
Enabled = false
};
copyTop.Accepting += (s, e) =>
{
AdornmentToEdit.Thickness = new (_topEdit.Value);
AdornmentToEdit!.Thickness = new (_topEdit.Value);
_leftEdit.Value = _rightEdit.Value = _bottomEdit.Value = _topEdit.Value;
};
Add (copyTop);
@@ -172,10 +168,55 @@ public class AdornmentEditor : View
_rightEdit.Value = AdornmentToEdit?.Thickness.Right ?? 0;
_bottomEdit.Value = AdornmentToEdit?.Thickness.Bottom ?? 0;
foreach (var subview in Subviews)
_diagThicknessCheckBox = new () { Text = "_Thickness Diag." };
if (AdornmentToEdit is { })
{
subview.Enabled = AdornmentToEdit is { };
_diagThicknessCheckBox.CheckedState = AdornmentToEdit.Diagnostics.FastHasFlags (ViewDiagnosticFlags.Thickness) ? CheckState.Checked : CheckState.UnChecked;
}
else
{
_diagThicknessCheckBox.CheckedState = Diagnostics.FastHasFlags (ViewDiagnosticFlags.Thickness) ? CheckState.Checked : CheckState.UnChecked;
}
_diagThicknessCheckBox.CheckedStateChanging += (s, e) =>
{
if (e.NewValue == CheckState.Checked)
{
AdornmentToEdit!.Diagnostics |= ViewDiagnosticFlags.Thickness;
}
else
{
AdornmentToEdit!.Diagnostics &= ~ViewDiagnosticFlags.Thickness;
}
};
Add (_diagThicknessCheckBox);
_diagThicknessCheckBox.Y = Pos.Bottom (_backgroundColorPicker);
_diagRulerCheckBox = new () { Text = "_Ruler" };
if (AdornmentToEdit is { })
{
_diagRulerCheckBox.CheckedState = AdornmentToEdit.Diagnostics.FastHasFlags (ViewDiagnosticFlags.Ruler) ? CheckState.Checked : CheckState.UnChecked;
}
else
{
_diagRulerCheckBox.CheckedState = Diagnostics.FastHasFlags (ViewDiagnosticFlags.Ruler) ? CheckState.Checked : CheckState.UnChecked;
}
_diagRulerCheckBox.CheckedStateChanging += (s, e) =>
{
if (e.NewValue == CheckState.Checked)
{
AdornmentToEdit!.Diagnostics |= ViewDiagnosticFlags.Ruler;
}
else
{
AdornmentToEdit!.Diagnostics &= ~ViewDiagnosticFlags.Ruler;
}
};
Add (_diagRulerCheckBox);
_diagRulerCheckBox.Y = Pos.Bottom (_diagThicknessCheckBox);
}
private EventHandler<ColorEventArgs> ColorPickerColorChanged ()
@@ -193,7 +234,7 @@ public class AdornmentEditor : View
};
}
private void Top_ValueChanging (object sender, CancelEventArgs<int> e)
private void Top_ValueChanging (object? sender, CancelEventArgs<int> e)
{
if (e.NewValue < 0 || AdornmentToEdit is null)
{
@@ -205,7 +246,7 @@ public class AdornmentEditor : View
AdornmentToEdit.Thickness = new (AdornmentToEdit.Thickness.Left, e.NewValue, AdornmentToEdit.Thickness.Right, AdornmentToEdit.Thickness.Bottom);
}
private void Left_ValueChanging (object sender, CancelEventArgs<int> e)
private void Left_ValueChanging (object? sender, CancelEventArgs<int> e)
{
if (e.NewValue < 0 || AdornmentToEdit is null)
{
@@ -217,7 +258,7 @@ public class AdornmentEditor : View
AdornmentToEdit.Thickness = new (e.NewValue, AdornmentToEdit.Thickness.Top, AdornmentToEdit.Thickness.Right, AdornmentToEdit.Thickness.Bottom);
}
private void Right_ValueChanging (object sender, CancelEventArgs<int> e)
private void Right_ValueChanging (object? sender, CancelEventArgs<int> e)
{
if (e.NewValue < 0 || AdornmentToEdit is null)
{
@@ -229,7 +270,7 @@ public class AdornmentEditor : View
AdornmentToEdit.Thickness = new (AdornmentToEdit.Thickness.Left, AdornmentToEdit.Thickness.Top, e.NewValue, AdornmentToEdit.Thickness.Bottom);
}
private void Bottom_ValueChanging (object sender, CancelEventArgs<int> e)
private void Bottom_ValueChanging (object? sender, CancelEventArgs<int> e)
{
if (e.NewValue < 0 || AdornmentToEdit is null)
{

View File

@@ -1,6 +1,5 @@
#nullable enable
using System;
using System.Text;
using Terminal.Gui;
namespace UICatalog.Scenarios;
@@ -12,19 +11,16 @@ public class AdornmentsEditor : View
{
public AdornmentsEditor ()
{
//ColorScheme = Colors.ColorSchemes ["Dialog"];
Title = "AdornmentsEditor";
Width = Dim.Auto (DimAutoStyle.Content);
Height = Dim.Auto (DimAutoStyle.Content);
//SuperViewRendersLineCanvas = true;
CanFocus = true;
TabStop = TabBehavior.TabGroup;
_expandButton = new ()
ExpandButton = new ()
{
Orientation = Orientation.Horizontal
};
@@ -32,19 +28,12 @@ public class AdornmentsEditor : View
Initialized += AdornmentsEditor_Initialized;
}
private readonly ViewDiagnosticFlags _savedDiagnosticFlags = Diagnostics;
private View? _viewToEdit;
private Label? _lblView; // Text describing the vi
private MarginEditor? _marginEditor;
private BorderEditor? _borderEditor;
private PaddingEditor? _paddingEditor;
// TODO: Move Diagnostics to a separate Editor class (DiagnosticsEditor?).
private CheckBox? _diagPaddingCheckBox;
private CheckBox? _diagRulerCheckBox;
/// <summary>
/// Gets or sets whether the AdornmentsEditor should automatically select the View to edit
/// based on the values of <see cref="AutoSelectSuperView"/> and <see cref="AutoSelectAdornments"/>.
@@ -73,20 +62,58 @@ public class AdornmentsEditor : View
_viewToEdit = value;
if (_viewToEdit is not Adornment)
if (_marginEditor is { })
{
_marginEditor!.AdornmentToEdit = _viewToEdit?.Margin ?? null;
_borderEditor!.AdornmentToEdit = _viewToEdit?.Border ?? null;
_paddingEditor!.AdornmentToEdit = _viewToEdit?.Padding ?? null;
_marginEditor.AdornmentToEdit = _viewToEdit?.Margin ?? null;
}
if (_lblView is { })
if (_borderEditor is { })
{
_lblView.Text = $"{_viewToEdit?.GetType ().Name}: {_viewToEdit?.Id}" ?? string.Empty;
_borderEditor.AdornmentToEdit = _viewToEdit?.Border ?? null;
}
if (_paddingEditor is { })
{
_paddingEditor.AdornmentToEdit = _viewToEdit?.Padding ?? null;
}
if (_viewToEdit is not Adornment)
{
Enabled = true;
}
else
{
Enabled = false;
}
Padding.Text = $"View: {GetIdentifyingString(_viewToEdit)}";
}
}
private string GetIdentifyingString (View? view)
{
if (view is null)
{
return "null";
}
if (!string.IsNullOrEmpty (view.Id))
{
return view.Id;
}
if (!string.IsNullOrEmpty (view.Title))
{
return view.Title;
}
if (!string.IsNullOrEmpty (view.Text))
{
return view.Text;
}
return view.GetType ().Name;
}
private void NavigationOnFocusedChanged (object? sender, EventArgs e)
{
@@ -137,43 +164,40 @@ public class AdornmentsEditor : View
}
/// <inheritdoc/>
protected override void Dispose (bool disposing)
protected override void Dispose (bool disposing) { base.Dispose (disposing); }
public ExpanderButton? ExpandButton { get; }
public bool ShowViewIdentifier
{
Diagnostics = _savedDiagnosticFlags;
base.Dispose (disposing);
get => Padding.Thickness != Thickness.Empty;
set
{
if (value)
{
Padding.Thickness = new (0, 2, 0, 0);
}
else
{
Padding.Thickness =Thickness.Empty;
}
}
}
private readonly ExpanderButton? _expandButton;
public ExpanderButton? ExpandButton => _expandButton;
private void AdornmentsEditor_Initialized (object? sender, EventArgs e)
{
BorderStyle = LineStyle.Dotted;
Border.Add (_expandButton!);
_lblView = new ()
{
X = 0,
Y = 0,
Height = 2
};
_lblView.TextFormatter.WordWrap = true;
_lblView.TextFormatter.MultiLine = true;
_lblView.HotKeySpecifier = (Rune)'\uffff';
Add (_lblView);
Border.Add (ExpandButton!);
_marginEditor = new ()
{
X = 0,
Y = Pos.Bottom (_lblView),
Y = 0,
SuperViewRendersLineCanvas = true
};
Add (_marginEditor);
_lblView.Width = Dim.Width (_marginEditor);
_borderEditor = new ()
{
X = Pos.Left (_marginEditor),
@@ -190,41 +214,10 @@ public class AdornmentsEditor : View
};
Add (_paddingEditor);
_diagPaddingCheckBox = new () { Text = "_Diagnostic Padding" };
_diagPaddingCheckBox.CheckedState = Diagnostics.FastHasFlags (ViewDiagnosticFlags.Padding) ? CheckState.Checked : CheckState.UnChecked;
_diagPaddingCheckBox.CheckedStateChanging += (s, e) =>
{
if (e.NewValue == CheckState.Checked)
{
Diagnostics |= ViewDiagnosticFlags.Padding;
}
else
{
Diagnostics &= ~ViewDiagnosticFlags.Padding;
}
};
Add (_diagPaddingCheckBox);
_diagPaddingCheckBox.Y = Pos.Bottom (_paddingEditor);
_diagRulerCheckBox = new () { Text = "_Diagnostic Ruler" };
_diagRulerCheckBox.CheckedState = Diagnostics.FastHasFlags (ViewDiagnosticFlags.Ruler) ? CheckState.Checked : CheckState.UnChecked;
_diagRulerCheckBox.CheckedStateChanging += (s, e) =>
{
if (e.NewValue == CheckState.Checked)
{
Diagnostics |= ViewDiagnosticFlags.Ruler;
}
else
{
Diagnostics &= ~ViewDiagnosticFlags.Ruler;
}
};
Add (_diagRulerCheckBox);
_diagRulerCheckBox.Y = Pos.Bottom (_diagPaddingCheckBox);
_marginEditor.AdornmentToEdit = _viewToEdit?.Margin ?? null;
_borderEditor.AdornmentToEdit = _viewToEdit?.Border ?? null;
_paddingEditor.AdornmentToEdit = _viewToEdit?.Padding ?? null;
Application.MouseEvent += ApplicationOnMouseEvent;
Application.Navigation!.FocusedChanged += NavigationOnFocusedChanged;

View File

@@ -24,43 +24,45 @@ public sealed class ArrangementEditor : View
Initialized += ArrangementEditor_Initialized;
_arrangementSlider.Options = new List<SliderOption<ViewArrangement>> ();
_arrangementSlider.Options =
[
new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.Movable.ToString (),
Data = ViewArrangement.Movable
},
_arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.Movable.ToString (),
Data = ViewArrangement.Movable
});
new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.LeftResizable.ToString (),
Data = ViewArrangement.LeftResizable
},
_arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.LeftResizable.ToString (),
Data = ViewArrangement.LeftResizable
});
new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.RightResizable.ToString (),
Data = ViewArrangement.RightResizable
},
_arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.RightResizable.ToString (),
Data = ViewArrangement.RightResizable
});
new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.TopResizable.ToString (),
Data = ViewArrangement.TopResizable
},
_arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.TopResizable.ToString (),
Data = ViewArrangement.TopResizable
});
new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.BottomResizable.ToString (),
Data = ViewArrangement.BottomResizable
},
_arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.BottomResizable.ToString (),
Data = ViewArrangement.BottomResizable
});
new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.Overlapped.ToString (),
Data = ViewArrangement.Overlapped
}
_arrangementSlider.Options.Add (new SliderOption<ViewArrangement>
{
Legend = ViewArrangement.Overlapped.ToString (),
Data = ViewArrangement.Overlapped
});
];
Add (_arrangementSlider);
}
@@ -69,7 +71,7 @@ public sealed class ArrangementEditor : View
private Label? _lblView; // Text describing the view being edited
private Slider<ViewArrangement> _arrangementSlider = new Slider<ViewArrangement> ()
private readonly Slider<ViewArrangement> _arrangementSlider = new Slider<ViewArrangement> ()
{
Orientation = Orientation.Vertical,
UseMinimumSize = true,

View File

@@ -1,4 +1,5 @@
using System;
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Terminal.Gui;
@@ -7,9 +8,9 @@ namespace UICatalog.Scenarios;
public class BorderEditor : AdornmentEditor
{
private CheckBox _ckbTitle;
private RadioGroup _rbBorderStyle;
private CheckBox _ckbGradient;
private CheckBox? _ckbTitle;
private RadioGroup? _rbBorderStyle;
private CheckBox? _ckbGradient;
public BorderEditor ()
{
@@ -18,14 +19,14 @@ public class BorderEditor : AdornmentEditor
AdornmentChanged += BorderEditor_AdornmentChanged;
}
private void BorderEditor_AdornmentChanged (object sender, EventArgs e)
private void BorderEditor_AdornmentChanged (object? sender, EventArgs e)
{
_ckbTitle.CheckedState = ((Border)AdornmentToEdit).Settings.FastHasFlags (BorderSettings.Title) ? CheckState.Checked : CheckState.UnChecked;
_rbBorderStyle.SelectedItem = (int)((Border)AdornmentToEdit).LineStyle;
_ckbGradient.CheckedState = ((Border)AdornmentToEdit).Settings.FastHasFlags (BorderSettings.Gradient) ? CheckState.Checked : CheckState.UnChecked;
_ckbTitle!.CheckedState = ((Border)AdornmentToEdit!).Settings.FastHasFlags (BorderSettings.Title) ? CheckState.Checked : CheckState.UnChecked;
_rbBorderStyle!.SelectedItem = (int)((Border)AdornmentToEdit).LineStyle;
_ckbGradient!.CheckedState = ((Border)AdornmentToEdit).Settings.FastHasFlags (BorderSettings.Gradient) ? CheckState.Checked : CheckState.UnChecked;
}
private void BorderEditor_Initialized (object sender, EventArgs e)
private void BorderEditor_Initialized (object? sender, EventArgs e)
{
List<LineStyle> borderStyleEnum = Enum.GetValues (typeof (LineStyle)).Cast<LineStyle> ().ToList ();
@@ -35,12 +36,11 @@ public class BorderEditor : AdornmentEditor
Y = Pos.Bottom (Subviews [^1]),
Width = Dim.Fill (),
SelectedItem = (int)(((Border)AdornmentToEdit)?.LineStyle ?? LineStyle.None),
SelectedItem = (int)(((Border)AdornmentToEdit!)?.LineStyle ?? LineStyle.None),
BorderStyle = LineStyle.Single,
Title = "Border St_yle",
SuperViewRendersLineCanvas = true,
Enabled = AdornmentToEdit is { },
RadioLabels = borderStyleEnum.Select (e => e.ToString ()).ToArray ()
RadioLabels = borderStyleEnum.Select (style => style.ToString ()).ToArray ()
};
Add (_rbBorderStyle);
@@ -54,7 +54,6 @@ public class BorderEditor : AdornmentEditor
CheckedState = CheckState.Checked,
SuperViewRendersLineCanvas = true,
Text = "Title",
Enabled = AdornmentToEdit is { }
};
_ckbTitle.CheckedStateChanging += OnCkbTitleOnToggle;
@@ -68,7 +67,6 @@ public class BorderEditor : AdornmentEditor
CheckedState = CheckState.Checked,
SuperViewRendersLineCanvas = true,
Text = "Gradient",
Enabled = AdornmentToEdit is { }
};
_ckbGradient.CheckedStateChanging += OnCkbGradientOnToggle;
@@ -76,10 +74,10 @@ public class BorderEditor : AdornmentEditor
return;
void OnRbBorderStyleOnSelectedItemChanged (object s, SelectedItemChangedArgs e)
void OnRbBorderStyleOnSelectedItemChanged (object? s, SelectedItemChangedArgs args)
{
LineStyle prevBorderStyle = AdornmentToEdit.BorderStyle;
((Border)AdornmentToEdit).LineStyle = (LineStyle)e.SelectedItem;
LineStyle prevBorderStyle = AdornmentToEdit!.BorderStyle;
((Border)AdornmentToEdit).LineStyle = (LineStyle)args.SelectedItem;
if (((Border)AdornmentToEdit).LineStyle == LineStyle.None)
{
@@ -91,34 +89,34 @@ public class BorderEditor : AdornmentEditor
}
((Border)AdornmentToEdit).SetNeedsDisplay ();
SetLayoutNeeded ();
SetNeedsLayout ();
}
void OnCkbTitleOnToggle (object sender, CancelEventArgs<CheckState> args)
void OnCkbTitleOnToggle (object? _, CancelEventArgs<CheckState> args)
{
if (args.NewValue == CheckState.Checked)
{
((Border)AdornmentToEdit).Settings |= BorderSettings.Title;
((Border)AdornmentToEdit!).Settings |= BorderSettings.Title;
}
else
{
((Border)AdornmentToEdit).Settings &= ~BorderSettings.Title;
((Border)AdornmentToEdit!).Settings &= ~BorderSettings.Title;
}
}
void OnCkbGradientOnToggle (object sender, CancelEventArgs<CheckState> args)
void OnCkbGradientOnToggle (object? _, CancelEventArgs<CheckState> args)
{
if (args.NewValue == CheckState.Checked)
{
((Border)AdornmentToEdit).Settings |= BorderSettings.Gradient;
((Border)AdornmentToEdit!).Settings |= BorderSettings.Gradient;
}
else
{
((Border)AdornmentToEdit).Settings &= ~BorderSettings.Gradient;
((Border)AdornmentToEdit!).Settings &= ~BorderSettings.Gradient;
}
}
}

View File

@@ -0,0 +1,300 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Terminal.Gui;
namespace UICatalog.Scenarios;
/// <summary>
/// Provides an editor UI for the Margin, Border, and Padding of a View.
/// </summary>
public class DimEditor : View
{
public DimEditor ()
{
Title = "Dim";
BorderStyle = LineStyle.Rounded;
Width = Dim.Auto (DimAutoStyle.Content);
Height = Dim.Auto (DimAutoStyle.Content);
CanFocus = true;
_expandButton = new ()
{
Orientation = Orientation.Vertical
};
TabStop = TabBehavior.TabGroup;
Initialized += DimEditor_Initialized;
AddCommand (Command.Accept, () => true);
}
private View? _viewToEdit;
private int _value;
private RadioGroup? _dimRadioGroup;
private TextField? _valueEdit;
/// <summary>
/// Gets or sets whether the DimEditor should automatically select the View to edit
/// based on the values of <see cref="AutoSelectSuperView"/> and <see cref="AutoSelectAdornments"/>.
/// </summary>
public bool AutoSelectViewToEdit { get; set; }
/// <summary>
/// Gets or sets the View that will scope the behavior of <see cref="AutoSelectViewToEdit"/>.
/// </summary>
public View? AutoSelectSuperView { get; set; }
/// <summary>
/// Gets or sets whether auto select with the mouse will select Adornments or just Views.
/// </summary>
public bool AutoSelectAdornments { get; set; }
public View? ViewToEdit
{
get => _viewToEdit;
set
{
if (_viewToEdit == value)
{
return;
}
if (value is null && _viewToEdit is { })
{
_viewToEdit.SubviewsLaidOut -= View_LayoutComplete;
}
_viewToEdit = value;
if (_viewToEdit is { })
{
_viewToEdit.SubviewsLaidOut += View_LayoutComplete;
_viewToEdit.SubviewLayout += (sender, args) =>
{
};
}
}
}
private void View_LayoutComplete (object? sender, LayoutEventArgs args)
{
UpdateSettings ();
}
private bool _updatingSettings = false;
private void UpdateSettings ()
{
if (ViewToEdit is null)
{
return;
}
_updatingSettings = true;
Dim? dim;
if (Dimension == Dimension.Width)
{
dim = ViewToEdit.Width;
}
else
{
dim = ViewToEdit.Height;
}
try
{
_dimRadioGroup!.SelectedItem = _dimNames.IndexOf (_dimNames.First (s => dim!.ToString ().StartsWith(s)));
}
catch (InvalidOperationException e)
{
// This is a hack to work around the fact that the Pos enum doesn't have an "Align" value yet
Debug.WriteLine ($"{e}");
}
_valueEdit!.Enabled = false;
switch (dim)
{
case DimAbsolute absolute:
_valueEdit.Enabled = true;
_value = absolute.Size;
_valueEdit!.Text = _value.ToString ();
break;
case DimFill fill:
var margin = fill.Margin as DimAbsolute;
_valueEdit.Enabled = margin is {};
_value = margin?.Size ?? 0;
_valueEdit!.Text = _value.ToString ();
break;
case DimFunc func:
_valueEdit.Enabled = true;
_value = func.Fn ();
_valueEdit!.Text = _value.ToString ();
break;
case DimPercent percent:
_valueEdit.Enabled = true;
_value = percent.Percentage;
_valueEdit!.Text = _value.ToString ();
break;
default:
_valueEdit!.Text = dim!.ToString ();
break;
}
_updatingSettings = false;
}
private void NavigationOnFocusedChanged (object? sender, EventArgs e)
{
if (AutoSelectSuperView is null)
{
return;
}
if (ApplicationNavigation.IsInHierarchy (this, Application.Navigation!.GetFocused ()))
{
return;
}
if (!ApplicationNavigation.IsInHierarchy (AutoSelectSuperView, Application.Navigation!.GetFocused ()))
{
return;
}
ViewToEdit = Application.Navigation!.GetFocused ();
}
private void ApplicationOnMouseEvent (object? sender, MouseEventArgs e)
{
if (e.Flags != MouseFlags.Button1Clicked || !AutoSelectViewToEdit)
{
return;
}
if ((AutoSelectSuperView is { } && !AutoSelectSuperView.FrameToScreen ().Contains (e.Position))
|| FrameToScreen ().Contains (e.Position))
{
return;
}
View? view = e.View;
if (view is null)
{
return;
}
if (view is Adornment adornment)
{
ViewToEdit = AutoSelectAdornments ? adornment : adornment.Parent;
}
else
{
ViewToEdit = view;
}
}
/// <inheritdoc/>
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
}
private readonly ExpanderButton? _expandButton;
public ExpanderButton? ExpandButton => _expandButton;
public Dimension Dimension { get; set; }
private void DimEditor_Initialized (object? sender, EventArgs e)
{
Border.Add (_expandButton!);
var label = new Label
{
X = 0, Y = 0,
Text = $"{Title}:"
};
Add (label);
_dimRadioGroup = new () { X = 0, Y = Pos.Bottom (label), RadioLabels = _radioItems };
_dimRadioGroup.SelectedItemChanged += OnRadioGroupOnSelectedItemChanged;
_valueEdit = new ()
{
X = Pos.Right (label) + 1,
Y = 0,
Width = Dim.Func (() => _radioItems.Max (i => i.GetColumns ()) - label.Frame.Width + 1),
Text = $"{_value}"
};
_valueEdit.Accepting += (s, args) =>
{
try
{
_value = int.Parse (_valueEdit.Text);
DimChanged ();
}
catch
{
// ignored
}
args.Cancel = true;
};
Add (_valueEdit);
Add (_dimRadioGroup);
Application.MouseEvent += ApplicationOnMouseEvent;
Application.Navigation!.FocusedChanged += NavigationOnFocusedChanged;
}
private void OnRadioGroupOnSelectedItemChanged (object? s, SelectedItemChangedArgs selected) { DimChanged (); }
// These need to have same order
private readonly List<string> _dimNames = ["Absolute", "Auto", "Fill", "Func", "Percent",];
private readonly string [] _radioItems = ["Absolute(n)", "Auto", "Fill(n)", "Func(()=>n)", "Percent(n)",];
private void DimChanged ()
{
if (ViewToEdit == null || _updatingSettings)
{
return;
}
try
{
Dim? dim = _dimRadioGroup!.SelectedItem switch
{
0 => Dim.Absolute (_value),
1 => Dim.Auto (),
2 => Dim.Fill (_value),
3 => Dim.Func (() => _value),
4 => Dim.Percent (_value),
_ => Dimension == Dimension.Width ? ViewToEdit.Width : ViewToEdit.Height
};
if (Dimension == Dimension.Width)
{
ViewToEdit.Width = dim;
}
else
{
ViewToEdit.Height = dim;
}
}
catch (Exception e)
{
MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
#nullable enable
using System;
using System.Text;
using Terminal.Gui;
@@ -36,7 +37,6 @@ public class ExpanderButton : Button
Height = 1;
NoDecorations = true;
NoPadding = true;
ShadowStyle = ShadowStyle.None;
AddCommand (Command.HotKey, Toggle);
AddCommand (Command.Toggle, Toggle);
@@ -47,7 +47,12 @@ public class ExpanderButton : Button
Initialized += ExpanderButton_Initialized;
}
private void ExpanderButton_Initialized (object sender, EventArgs e) { ExpandOrCollapse (Collapsed); }
private void ExpanderButton_Initialized (object? sender, EventArgs e)
{
ShadowStyle = ShadowStyle.None;
ExpandOrCollapse (Collapsed);
}
private Orientation _orientation = Orientation.Horizontal;
@@ -102,7 +107,7 @@ public class ExpanderButton : Button
/// <summary>
/// Fired when the orientation has changed. Can be cancelled.
/// </summary>
public event EventHandler<CancelEventArgs<Orientation>> OrientationChanging;
public event EventHandler<CancelEventArgs<Orientation>>? OrientationChanging;
/// <summary>
/// The glyph to display when the view is collapsed.
@@ -146,7 +151,7 @@ public class ExpanderButton : Button
/// <summary>
/// Fired when the orientation has changed. Can be cancelled.
/// </summary>
public event EventHandler<CancelEventArgs<bool>> CollapsedChanging;
public event EventHandler<CancelEventArgs<bool>>? CollapsedChanging;
/// <summary>
/// Collapses or Expands the view.
@@ -159,13 +164,13 @@ public class ExpanderButton : Button
return true;
}
private Dim _previousDim;
private Dim? _previousDim;
private void ExpandOrCollapse (bool collapse)
{
Text = $"{(Collapsed ? CollapsedGlyph : ExpandedGlyph)}";
View superView = SuperView;
View? superView = SuperView;
if (superView is Adornment adornment)
{
@@ -182,12 +187,12 @@ public class ExpanderButton : Button
// Collapse
if (Orientation == Orientation.Vertical)
{
_previousDim = superView.Height;
_previousDim = superView!.Height!;
superView.Height = 1;
}
else
{
_previousDim = superView.Width;
_previousDim = superView!.Width!;
superView.Width = 1;
}
}

View File

@@ -0,0 +1,228 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Terminal.Gui;
namespace UICatalog.Scenarios;
/// <summary>
/// Provides an editor UI for the Margin, Border, and Padding of a View.
/// </summary>
public class LayoutEditor : View
{
public LayoutEditor ()
{
Title = "_LayoutEditor";
Width = Dim.Auto (DimAutoStyle.Content);
Height = Dim.Auto (DimAutoStyle.Content);
CanFocus = true;
TabStop = TabBehavior.TabGroup;
_expandButton = new ()
{
Orientation = Orientation.Vertical
};
Initialized += LayoutEditor_Initialized;
AddCommand (Command.Accept, () => true);
}
private View? _viewToEdit;
private readonly List<string> _dimNames = ["Auto", "Percent", "Fill", "Absolute"];
private PosEditor? _xEditor;
private PosEditor? _yEditor;
private DimEditor? _widthEditor;
private DimEditor? _heightEditor;
/// <summary>
/// Gets or sets whether the LayoutEditor should automatically select the View to edit
/// based on the values of <see cref="AutoSelectSuperView"/> and <see cref="AutoSelectAdornments"/>.
/// </summary>
public bool AutoSelectViewToEdit { get; set; }
/// <summary>
/// Gets or sets the View that will scope the behavior of <see cref="AutoSelectViewToEdit"/>.
/// </summary>
public View? AutoSelectSuperView { get; set; }
/// <summary>
/// Gets or sets whether auto select with the mouse will select Adornments or just Views.
/// </summary>
public bool AutoSelectAdornments { get; set; }
public View? ViewToEdit
{
get => _viewToEdit;
set
{
if (_viewToEdit == value)
{
return;
}
if (value is null && _viewToEdit is { })
{
_viewToEdit.SubviewsLaidOut -= View_LayoutComplete;
}
_viewToEdit = value;
if (_viewToEdit is { })
{
_viewToEdit.SubviewsLaidOut += View_LayoutComplete;
}
if (_xEditor is { })
{
_xEditor.ViewToEdit = _viewToEdit;
}
if (_yEditor is { })
{
_yEditor.ViewToEdit = _viewToEdit;
}
if (_widthEditor is { })
{
_widthEditor.ViewToEdit = _viewToEdit;
}
if (_heightEditor is { })
{
_heightEditor.ViewToEdit = _viewToEdit;
}
}
}
private void View_LayoutComplete (object? sender, LayoutEventArgs args)
{
UpdateSettings ();
}
private bool _updatingSettings = false;
private void UpdateSettings ()
{
if (ViewToEdit is null)
{
return;
}
_updatingSettings = true;
_updatingSettings = false;
}
private void NavigationOnFocusedChanged (object? sender, EventArgs e)
{
if (AutoSelectSuperView is null)
{
return;
}
if (ApplicationNavigation.IsInHierarchy (this, Application.Navigation!.GetFocused ()))
{
return;
}
if (!ApplicationNavigation.IsInHierarchy (AutoSelectSuperView, Application.Navigation!.GetFocused ()))
{
return;
}
ViewToEdit = Application.Navigation!.GetFocused ();
}
private void ApplicationOnMouseEvent (object? sender, MouseEventArgs e)
{
if (e.Flags != MouseFlags.Button1Clicked || !AutoSelectViewToEdit)
{
return;
}
if ((AutoSelectSuperView is { } && !AutoSelectSuperView.FrameToScreen ().Contains (e.Position))
|| FrameToScreen ().Contains (e.Position))
{
return;
}
View? view = e.View;
if (view is null)
{
return;
}
if (view is Adornment adornment)
{
ViewToEdit = AutoSelectAdornments ? adornment : adornment.Parent;
}
else
{
ViewToEdit = view;
}
}
/// <inheritdoc/>
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
}
private readonly ExpanderButton? _expandButton;
public ExpanderButton? ExpandButton => _expandButton;
private void LayoutEditor_Initialized (object? sender, EventArgs e)
{
BorderStyle = LineStyle.Rounded;
Border.Add (_expandButton!);
_xEditor = new ()
{
Title = "_X",
BorderStyle = LineStyle.None,
Dimension = Dimension.Width
};
_yEditor = new ()
{
Title = "_Y",
BorderStyle = LineStyle.None,
Dimension = Dimension.Height,
X = Pos.Right(_xEditor) + 1
};
_widthEditor = new ()
{
Title = "_Width",
BorderStyle = LineStyle.None,
Dimension = Dimension.Width,
X = Pos.Right(_yEditor) + 1
};
_heightEditor = new ()
{
Title = "_Height",
BorderStyle = LineStyle.None,
Dimension = Dimension.Height,
X = Pos.Right (_widthEditor) + 1
};
Add (_xEditor, _yEditor, _widthEditor, _heightEditor);
Application.MouseEvent += ApplicationOnMouseEvent;
Application.Navigation!.FocusedChanged += NavigationOnFocusedChanged;
}
}

View File

@@ -1,5 +1,5 @@
using System;
using System.Linq;
#nullable enable
using System;
using Terminal.Gui;
namespace UICatalog.Scenarios;
@@ -13,17 +13,17 @@ public class MarginEditor : AdornmentEditor
AdornmentChanged += MarginEditor_AdornmentChanged;
}
RadioGroup _rgShadow;
private RadioGroup? _rgShadow;
private void MarginEditor_AdornmentChanged (object sender, EventArgs e)
private void MarginEditor_AdornmentChanged (object? sender, EventArgs e)
{
if (AdornmentToEdit is { })
{
_rgShadow.SelectedItem = (int)((Margin)AdornmentToEdit).ShadowStyle;
_rgShadow!.SelectedItem = (int)((Margin)AdornmentToEdit).ShadowStyle;
}
}
private void MarginEditor_Initialized (object sender, EventArgs e)
private void MarginEditor_Initialized (object? sender, EventArgs e)
{
_rgShadow = new RadioGroup
{
@@ -33,7 +33,6 @@ public class MarginEditor : AdornmentEditor
SuperViewRendersLineCanvas = true,
Title = "_Shadow",
BorderStyle = LineStyle.Dashed,
Enabled = AdornmentToEdit is { },
RadioLabels = Enum.GetNames (typeof (ShadowStyle)),
};
@@ -44,7 +43,7 @@ public class MarginEditor : AdornmentEditor
_rgShadow.SelectedItemChanged += (sender, args) =>
{
((Margin)AdornmentToEdit).ShadowStyle = (ShadowStyle)args.SelectedItem;
((Margin)AdornmentToEdit!).ShadowStyle = (ShadowStyle)args.SelectedItem;
};
Add (_rgShadow);

View File

@@ -1,4 +1,5 @@
namespace UICatalog.Scenarios;
#nullable enable
namespace UICatalog.Scenarios;
public class PaddingEditor : AdornmentEditor
{

View File

@@ -0,0 +1,292 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Terminal.Gui;
namespace UICatalog.Scenarios;
/// <summary>
/// Provides an editor UI for the Margin, Border, and Padding of a View.
/// </summary>
public class PosEditor : View
{
public PosEditor ()
{
Title = "Pos";
BorderStyle = LineStyle.Rounded;
Width = Dim.Auto (DimAutoStyle.Content);
Height = Dim.Auto (DimAutoStyle.Content);
CanFocus = true;
_expandButton = new ()
{
Orientation = Orientation.Vertical
};
TabStop = TabBehavior.TabGroup;
Initialized += PosEditor_Initialized;
AddCommand (Command.Accept, () => true);
}
private View? _viewToEdit;
private int _value;
private RadioGroup? _posRadioGroup;
private TextField? _valueEdit;
/// <summary>
/// Gets or sets whether the PosEditor should automatically select the View to edit
/// based on the values of <see cref="AutoSelectSuperView"/> and <see cref="AutoSelectAdornments"/>.
/// </summary>
public bool AutoSelectViewToEdit { get; set; }
/// <summary>
/// Gets or sets the View that will scope the behavior of <see cref="AutoSelectViewToEdit"/>.
/// </summary>
public View? AutoSelectSuperView { get; set; }
/// <summary>
/// Gets or sets whether auto select with the mouse will select Adornments or just Views.
/// </summary>
public bool AutoSelectAdornments { get; set; }
public View? ViewToEdit
{
get => _viewToEdit;
set
{
if (_viewToEdit == value)
{
return;
}
if (value is null && _viewToEdit is { })
{
_viewToEdit.SubviewsLaidOut -= View_LayoutComplete;
}
_viewToEdit = value;
if (_viewToEdit is { })
{
_viewToEdit.SubviewsLaidOut += View_LayoutComplete;
}
}
}
private void View_LayoutComplete (object? sender, LayoutEventArgs args)
{
UpdateSettings ();
}
private bool _updatingSettings = false;
private void UpdateSettings ()
{
if (ViewToEdit is null)
{
return;
}
_updatingSettings = true;
Pos? pos;
if (Dimension == Dimension.Width)
{
pos = ViewToEdit.X;
}
else
{
pos = ViewToEdit.Y;
}
try
{
_posRadioGroup!.SelectedItem = _posNames.IndexOf (_posNames.First (s => pos.ToString ().Contains (s)));
}
catch (InvalidOperationException e)
{
// This is a hack to work around the fact that the Pos enum doesn't have an "Align" value yet
Debug.WriteLine ($"{e}");
}
_valueEdit!.Enabled = false;
switch (pos)
{
case PosPercent percent:
_valueEdit.Enabled = true;
_value = percent.Percent;
_valueEdit!.Text = _value.ToString ();
break;
case PosAbsolute absolute:
_valueEdit.Enabled = true;
_value = absolute.Position;
_valueEdit!.Text = _value.ToString ();
break;
case PosFunc func:
_valueEdit.Enabled = true;
_value = func.Fn ();
_valueEdit!.Text = _value.ToString ();
break;
default:
_valueEdit!.Text = pos.ToString ();
break;
}
_updatingSettings = false;
}
private void NavigationOnFocusedChanged (object? sender, EventArgs e)
{
if (AutoSelectSuperView is null)
{
return;
}
if (ApplicationNavigation.IsInHierarchy (this, Application.Navigation!.GetFocused ()))
{
return;
}
if (!ApplicationNavigation.IsInHierarchy (AutoSelectSuperView, Application.Navigation!.GetFocused ()))
{
return;
}
ViewToEdit = Application.Navigation!.GetFocused ();
}
private void ApplicationOnMouseEvent (object? sender, MouseEventArgs e)
{
if (e.Flags != MouseFlags.Button1Clicked || !AutoSelectViewToEdit)
{
return;
}
if ((AutoSelectSuperView is { } && !AutoSelectSuperView.FrameToScreen ().Contains (e.Position))
|| FrameToScreen ().Contains (e.Position))
{
return;
}
View? view = e.View;
if (view is null)
{
return;
}
if (view is Adornment adornment)
{
ViewToEdit = AutoSelectAdornments ? adornment : adornment.Parent;
}
else
{
ViewToEdit = view;
}
}
/// <inheritdoc/>
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
}
private readonly ExpanderButton? _expandButton;
public ExpanderButton? ExpandButton => _expandButton;
public Dimension Dimension { get; set; }
private void PosEditor_Initialized (object? sender, EventArgs e)
{
Border.Add (_expandButton!);
var label = new Label
{
X = 0, Y = 0,
Text = $"{Title}:"
};
Add (label);
_posRadioGroup = new () { X = 0, Y = Pos.Bottom (label), RadioLabels = _radioItems };
_posRadioGroup.SelectedItemChanged += OnRadioGroupOnSelectedItemChanged;
_valueEdit = new ()
{
X = Pos.Right (label) + 1,
Y = 0,
Width = Dim.Func (() => _radioItems.Max (i => i.GetColumns ()) - label.Frame.Width + 1),
Text = $"{_value}"
};
_valueEdit.Accepting += (s, args) =>
{
try
{
_value = int.Parse (_valueEdit.Text);
PosChanged ();
}
catch
{
// ignored
}
args.Cancel = true;
};
Add (_valueEdit);
Add (_posRadioGroup);
Application.MouseEvent += ApplicationOnMouseEvent;
Application.Navigation!.FocusedChanged += NavigationOnFocusedChanged;
}
private void OnRadioGroupOnSelectedItemChanged (object? s, SelectedItemChangedArgs selected) { PosChanged (); }
// These need to have same order
private readonly List<string> _posNames = ["Absolute", "Align", "AnchorEnd", "Center", "Func", "Percent",];
private readonly string [] _radioItems = ["Absolute(n)", "Align", "AnchorEnd", "Center", "Func(()=>n)", "Percent(n)",];
private void PosChanged ()
{
if (ViewToEdit == null || _updatingSettings)
{
return;
}
try
{
Pos? pos = _posRadioGroup!.SelectedItem switch
{
0 => Pos.Absolute (_value),
1 => Pos.Align (Alignment.Start),
2 => new PosAnchorEnd (),
3 => Pos.Center (),
4 => Pos.Func (() => _value),
5 => Pos.Percent (_value),
_ => Dimension == Dimension.Width ? ViewToEdit.X : ViewToEdit.Y
};
if (Dimension == Dimension.Width)
{
ViewToEdit.X = pos;
}
else
{
ViewToEdit.Y = pos;
}
SetNeedsLayout ();
}
catch (Exception e)
{
MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
}
}
}

View File

@@ -126,7 +126,7 @@ public class GraphViewExample : Scenario
{
Checked = View.Diagnostics
== (ViewDiagnosticFlags
.Padding
.Thickness
| ViewDiagnosticFlags
.Ruler),
CheckType = MenuItemCheckStyle.Checked
@@ -211,7 +211,7 @@ public class GraphViewExample : Scenario
_miDiags.Checked = !_miDiags.Checked;
View.Diagnostics = _miDiags.Checked == true
? ViewDiagnosticFlags.Padding
? ViewDiagnosticFlags.Thickness
| ViewDiagnosticFlags.Ruler
: ViewDiagnosticFlags.Off;
Application.Refresh ();

View File

@@ -286,7 +286,7 @@ public class DrawingArea : View
// TODO: This is a hack to work around overlapped views not drawing correctly.
// without this the toolbox disappears
SuperView?.SetLayoutNeeded();
SuperView?.SetNeedsLayout();
return true;
}

View File

@@ -107,7 +107,7 @@ public class MenuBarScenario : Scenario
};
// There's no focus change event, so this is a bit of a hack.
menuBar.LayoutComplete += (s, e) => { _focusedView.Text = appWindow.MostFocused?.ToString () ?? "None"; };
menuBar.SubviewsLaidOut += (s, e) => { _focusedView.Text = appWindow.MostFocused?.ToString () ?? "None"; };
var openBtn = new Button { X = Pos.Center (), Y = 4, Text = "_Open Menu", IsDefault = true };
openBtn.Accepting += (s, e) => { menuBar.OpenMenu (); };

View File

@@ -26,6 +26,7 @@ public class Navigation : Scenario
X = 0,
Y = 0,
AutoSelectViewToEdit = true,
ShowViewIdentifier = true,
TabStop = TabBehavior.NoStop
};
app.Add (adornmentsEditor);

View File

@@ -23,6 +23,7 @@ public class NumericUpDownDemo : Scenario
X = 0,
Y = 0,
AutoSelectViewToEdit = true,
ShowViewIdentifier = true,
};
app.Add (editor);

View File

@@ -35,7 +35,9 @@ public class ProgressBarStyles : Scenario
var editor = new AdornmentsEditor ()
{
AutoSelectViewToEdit = false
AutoSelectViewToEdit = false,
ShowViewIdentifier = true
};
app.Add (editor);

View File

@@ -24,6 +24,8 @@ public class ShadowStyles : Scenario
var editor = new AdornmentsEditor ()
{
AutoSelectViewToEdit = true,
ShowViewIdentifier = true,
};
app.Add (editor);

View File

@@ -86,7 +86,7 @@ public class Sliders : Scenario
AllowEmpty = false
};
single.LayoutStarted += (s, e) =>
single.SubviewLayout += (s, e) =>
{
if (single.Orientation == Orientation.Horizontal)
{

View File

@@ -120,7 +120,7 @@ public class TextViewAutocompletePopup : Scenario
);
appWindow.Add (statusBar);
appWindow.LayoutStarted += Win_LayoutStarted;
appWindow.SubviewLayout += Win_LayoutStarted;
// Run - Start the application.
Application.Run (appWindow);

View File

@@ -24,7 +24,9 @@ public class ViewExperiments : Scenario
{
X = 0,
Y = 0,
TabStop = TabBehavior.NoStop
TabStop = TabBehavior.NoStop,
AutoSelectViewToEdit = true,
ShowViewIdentifier = true
};
app.Add (editor);

View File

@@ -287,7 +287,7 @@ public class VkeyPacketSimulator : Scenario
..outputVerticalRuler.Viewport.Height];
}
win.LayoutComplete += Win_LayoutComplete;
win.SubviewsLaidOut += Win_LayoutComplete;
Application.Run (win);
win.Dispose ();

View File

@@ -564,7 +564,7 @@ public class UICatalogApp
{
if (_statusBar.NeedsLayout)
{
// throw new Exception ("DimFunc.Fn aborted because dependent View needs layout.");
throw new LayoutException ("DimFunc.Fn aborted because dependent View needs layout.");
}
return _statusBar.Frame.Height;
})),
@@ -590,7 +590,7 @@ public class UICatalogApp
{
if (_statusBar.NeedsLayout)
{
// throw new Exception ("DimFunc.Fn aborted because dependent View needs layout.");
throw new LayoutException ("DimFunc.Fn aborted because dependent View needs layout.");
}
return _statusBar.Frame.Height;
})),
@@ -792,7 +792,7 @@ public class UICatalogApp
{
const string OFF = "View Diagnostics: _Off";
const string RULER = "View Diagnostics: _Ruler";
const string PADDING = "View Diagnostics: _Padding";
const string THICKNESS = "View Diagnostics: _Thickness";
const string Hover = "View Diagnostics: _Hover";
var index = 0;
@@ -809,7 +809,7 @@ public class UICatalogApp
if (GetDiagnosticsTitle (ViewDiagnosticFlags.Off) == item.Title)
{
item.Checked = !_diagnosticFlags.HasFlag (ViewDiagnosticFlags.Padding)
item.Checked = !_diagnosticFlags.HasFlag (ViewDiagnosticFlags.Thickness)
&& !_diagnosticFlags.HasFlag (ViewDiagnosticFlags.Ruler)
&& !_diagnosticFlags.HasFlag (ViewDiagnosticFlags.Hover);
}
@@ -824,12 +824,12 @@ public class UICatalogApp
if (item.Title == t && item.Checked == false)
{
_diagnosticFlags &= ~(ViewDiagnosticFlags.Padding | ViewDiagnosticFlags.Ruler | ViewDiagnosticFlags.Hover);
_diagnosticFlags &= ~(ViewDiagnosticFlags.Thickness | ViewDiagnosticFlags.Ruler | ViewDiagnosticFlags.Hover);
item.Checked = true;
}
else if (item.Title == t && item.Checked == true)
{
_diagnosticFlags |= ViewDiagnosticFlags.Padding | ViewDiagnosticFlags.Ruler | ViewDiagnosticFlags.Hover;
_diagnosticFlags |= ViewDiagnosticFlags.Thickness | ViewDiagnosticFlags.Ruler | ViewDiagnosticFlags.Hover;
item.Checked = false;
}
else
@@ -851,7 +851,7 @@ public class UICatalogApp
if (menuItem.Title == t)
{
menuItem.Checked = !_diagnosticFlags.HasFlag (ViewDiagnosticFlags.Ruler)
&& !_diagnosticFlags.HasFlag (ViewDiagnosticFlags.Padding)
&& !_diagnosticFlags.HasFlag (ViewDiagnosticFlags.Thickness)
&& !_diagnosticFlags.HasFlag (ViewDiagnosticFlags.Hover);
}
else if (menuItem.Title != t)
@@ -873,7 +873,7 @@ public class UICatalogApp
{
"Off" => OFF,
"Ruler" => RULER,
"Padding" => PADDING,
"Thickness" => THICKNESS,
"Hover" => Hover,
_ => ""
};
@@ -884,7 +884,7 @@ public class UICatalogApp
return title switch
{
RULER => ViewDiagnosticFlags.Ruler,
PADDING => ViewDiagnosticFlags.Padding,
THICKNESS => ViewDiagnosticFlags.Thickness,
Hover => ViewDiagnosticFlags.Hover,
_ => null!
};
@@ -905,14 +905,14 @@ public class UICatalogApp
}
break;
case ViewDiagnosticFlags.Padding:
case ViewDiagnosticFlags.Thickness:
if (add)
{
_diagnosticFlags |= ViewDiagnosticFlags.Padding;
_diagnosticFlags |= ViewDiagnosticFlags.Thickness;
}
else
{
_diagnosticFlags &= ~ViewDiagnosticFlags.Padding;
_diagnosticFlags &= ~ViewDiagnosticFlags.Thickness;
}
break;

View File

@@ -26,7 +26,7 @@
<EmbeddedResource Include="Resources\config.json" />
</ItemGroup>
<ItemGroup>
<None Update="./Scenarios/Spinning_globe_dark_small.gif" CopyToOutputDirectory="PreserveNewest" />
<None Update="Scenarios\AnimationScenario\Spinning_globe_dark_small.gif" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="[2024.2.0,)" PrivateAssets="all" />