Modernized RadioGroup to use Dim.Auto.

Upgrade AllViewsTester
This commit is contained in:
Tig
2024-05-14 14:52:10 -07:00
parent 82e681c45a
commit 070d31d5ab
7 changed files with 231 additions and 161 deletions

View File

@@ -42,7 +42,8 @@ public class ProgressBar : View
private int _delta;
private float _fraction;
private bool _isActivity;
private ProgressBarStyle _progressBarStyle;
private ProgressBarStyle _progressBarStyle = ProgressBarStyle.MarqueeBlocks;
private ProgressBarFormat _progressBarFormat = ProgressBarFormat.SimplePlusPercentage;
private Rune _segmentCharacter = Glyphs.BlocksMeterSegment;
/// <summary>
@@ -61,7 +62,6 @@ public class ProgressBar : View
set
{
_bidirectionalMarquee = value;
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
@@ -74,12 +74,9 @@ public class ProgressBar : View
{
_fraction = Math.Min (value, 1);
_isActivity = false;
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
private ProgressBarFormat _progressBarFormat;
/// <summary>Specifies the format that a <see cref="ProgressBar"/> uses to indicate the visual presentation.</summary>
public ProgressBarFormat ProgressBarFormat
{
@@ -87,7 +84,6 @@ public class ProgressBar : View
set
{
_progressBarFormat = value;
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
@@ -118,8 +114,6 @@ public class ProgressBar : View
break;
}
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
@@ -130,7 +124,6 @@ public class ProgressBar : View
set
{
_segmentCharacter = value;
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
@@ -289,6 +282,7 @@ public class ProgressBar : View
private void SetInitialProperties ()
{
Width = Dim.Auto (Dim.DimAutoStyle.Content);
Height = Dim.Auto (Dim.DimAutoStyle.Content, minimumContentDim: 1);
CanFocus = false;
_fraction = 0;

View File

@@ -18,12 +18,15 @@ public class RadioGroup : View
{
CanFocus = true;
Width = Dim.Auto (Dim.DimAutoStyle.Content);
Height = Dim.Auto (Dim.DimAutoStyle.Content);
// Things this view knows how to do
AddCommand (
Command.LineUp,
() =>
{
MoveUp ();
MoveUpLeft ();
return true;
}
@@ -33,7 +36,7 @@ public class RadioGroup : View
Command.LineDown,
() =>
{
MoveDown ();
MoveDownRight ();
return true;
}
@@ -68,12 +71,7 @@ public class RadioGroup : View
}
);
// Default keybindings for this view
KeyBindings.Add (Key.CursorUp, Command.LineUp);
KeyBindings.Add (Key.CursorDown, Command.LineDown);
KeyBindings.Add (Key.Home, Command.TopHome);
KeyBindings.Add (Key.End, Command.BottomEnd);
KeyBindings.Add (Key.Space, Command.Accept);
SetupKeyBindings ();
LayoutStarted += RadioGroup_LayoutStarted;
@@ -84,14 +82,33 @@ public class RadioGroup : View
// TODO: Fix InvertColorsOnPress - only highlight the selected item
private void SetupKeyBindings ()
{
KeyBindings.Clear ();
// Default keybindings for this view
if (Orientation == Orientation.Vertical)
{
KeyBindings.Add (Key.CursorUp, Command.LineUp);
KeyBindings.Add (Key.CursorDown, Command.LineDown);
}
else
{
KeyBindings.Add (Key.CursorLeft, Command.LineUp);
KeyBindings.Add (Key.CursorRight, Command.LineDown);
}
KeyBindings.Add (Key.Home, Command.TopHome);
KeyBindings.Add (Key.End, Command.BottomEnd);
KeyBindings.Add (Key.Space, Command.Accept);
}
private void RadioGroup_MouseClick (object sender, MouseEventEventArgs e)
{
SetFocus ();
int boundsX = e.MouseEvent.Position.X;
int boundsY = e.MouseEvent.Position.Y;
int viewportX = e.MouseEvent.Position.X;
int viewportY = e.MouseEvent.Position.Y;
int pos = _orientation == Orientation.Horizontal ? boundsX : boundsY;
int pos = _orientation == Orientation.Horizontal ? viewportX : viewportY;
int rCount = _orientation == Orientation.Horizontal
? _horizontal.Last ().pos + _horizontal.Last ().length
@@ -100,8 +117,8 @@ public class RadioGroup : View
if (pos < rCount)
{
int c = _orientation == Orientation.Horizontal
? _horizontal.FindIndex (x => x.pos <= boundsX && x.pos + x.length - 2 >= boundsX)
: boundsY;
? _horizontal.FindIndex (x => x.pos <= viewportX && x.pos + x.length - 2 >= viewportX)
: viewportY;
if (c > -1)
{
@@ -125,9 +142,8 @@ public class RadioGroup : View
if (_horizontalSpace != value && _orientation == Orientation.Horizontal)
{
_horizontalSpace = value;
SetWidthHeight (_radioLabels);
UpdateTextFormatterText ();
SetNeedsDisplay ();
SetContentSize ();
}
}
}
@@ -143,7 +159,7 @@ public class RadioGroup : View
}
/// <summary>
/// The radio labels to display. A key binding will be added for each radio radio enabling the user to select
/// The radio labels to display. A key binding will be added for each radio enabling the user to select
/// and/or focus the radio label using the keyboard. See <see cref="View.HotKey"/> for details on how HotKeys work.
/// </summary>
/// <value>The radio labels.</value>
@@ -172,16 +188,30 @@ public class RadioGroup : View
}
}
if (IsInitialized && prevCount != _radioLabels.Count)
{
SetWidthHeight (_radioLabels);
}
SelectedItem = 0;
SetNeedsDisplay ();
SetContentSize ();
}
}
/// <inheritdoc />
public override string Text
{
get
{
if (_radioLabels.Count == 0)
{
return string.Empty;
}
// Return labels as a CSV string
return string.Join (",", _radioLabels);
}
set =>
// Parse as CSV string with spaces trimmed
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
@@ -320,7 +350,8 @@ public class RadioGroup : View
if (!args.Cancel)
{
_orientation = newOrientation;
SetNeedsLayout ();
SetupKeyBindings ();
SetContentSize ();
}
return args.Cancel;
@@ -373,42 +404,7 @@ public class RadioGroup : View
/// <summary>Invoked when the selected radio label has changed.</summary>
public event EventHandler<SelectedItemChangedArgs> SelectedItemChanged;
private void CalculateHorizontalPositions ()
{
if (_orientation == Orientation.Horizontal)
{
_horizontal = new List<(int pos, int length)> ();
var start = 0;
var length = 0;
for (var i = 0; i < _radioLabels.Count; i++)
{
start += length;
length = _radioLabels [i].GetColumns () + 2 + (i < _radioLabels.Count - 1 ? _horizontalSpace : 0);
_horizontal.Add ((start, length));
}
}
}
private static Rectangle MakeRect (int x, int y, List<string> radioLabels)
{
if (radioLabels is null)
{
return new (x, y, 0, 0);
}
var width = 0;
foreach (string s in radioLabels)
{
width = Math.Max (s.GetColumns () + 2, width);
}
return new (x, y, width, radioLabels.Count);
}
private void MoveDown ()
private void MoveDownRight ()
{
if (_cursor + 1 < _radioLabels.Count)
{
@@ -425,7 +421,7 @@ public class RadioGroup : View
private void MoveEnd () { _cursor = Math.Max (_radioLabels.Count - 1, 0); }
private void MoveHome () { _cursor = 0; }
private void MoveUp ()
private void MoveUpLeft ()
{
if (_cursor > 0)
{
@@ -439,39 +435,37 @@ public class RadioGroup : View
}
}
private void RadioGroup_LayoutStarted (object sender, EventArgs e) { SetWidthHeight (_radioLabels); }
private void RadioGroup_LayoutStarted (object sender, EventArgs e) { SetContentSize (); }
private void SelectItem () { SelectedItem = _cursor; }
private void SetWidthHeight (List<string> radioLabels)
private void SetContentSize ()
{
switch (_orientation)
{
case Orientation.Vertical:
Rectangle r = MakeRect (0, 0, radioLabels);
var width = 0;
if (IsInitialized)
foreach (string s in _radioLabels)
{
Width = r.Width + GetAdornmentsThickness ().Horizontal;
Height = radioLabels.Count + GetAdornmentsThickness ().Vertical;
width = Math.Max (s.GetColumns () + 2, width);
}
SetContentSize (new (width, _radioLabels.Count));
break;
case Orientation.Horizontal:
CalculateHorizontalPositions ();
_horizontal = new List<(int pos, int length)> ();
var start = 0;
var length = 0;
foreach ((int pos, int length) item in _horizontal)
for (var i = 0; i < _radioLabels.Count; i++)
{
length += item.length;
}
start += length;
if (IsInitialized)
{
Width = length + GetAdornmentsThickness ().Vertical;
Height = 1 + GetAdornmentsThickness ().Horizontal;
length = _radioLabels [i].GetColumns () + 2 + (i < _radioLabels.Count - 1 ? _horizontalSpace : 0);
_horizontal.Add ((start, length));
}
SetContentSize (new (_horizontal.Sum (item => item.length), 1));
break;
}
}

View File

@@ -17,7 +17,6 @@ public class AllViewsTester : Scenario
// TODO: This is missing some
private readonly List<string> _posNames = new () { "Factor", "AnchorEnd", "Center", "Absolute" };
private ListView _classListView;
private CheckBox _computedCheckBox;
private View _curView;
private FrameView _hostPane;
private RadioGroup _hRadioGroup;
@@ -39,6 +38,9 @@ public class AllViewsTester : Scenario
private RadioGroup _yRadioGroup;
private TextField _yText;
private int _yVal;
private RadioGroup _orientation;
private string _demoText = "This, that, and the other thing.";
private TextView _demoTextView;
public override void Init ()
{
@@ -90,7 +92,7 @@ public class AllViewsTester : Scenario
{
X = 0,
Y = 0,
Width = 15,
Width = Dim.Auto (Dim.DimAutoStyle.Content),
Height = Dim.Fill (1), // for status bar
CanFocus = false,
ColorScheme = Colors.ColorSchemes ["TopLevel"],
@@ -101,7 +103,7 @@ public class AllViewsTester : Scenario
{
X = 0,
Y = 0,
Width = Dim.Fill (),
Width = Dim.Auto (),
Height = Dim.Fill (),
AllowsMarking = false,
ColorScheme = Colors.ColorSchemes ["TopLevel"],
@@ -131,30 +133,20 @@ public class AllViewsTester : Scenario
X = Pos.Right (_leftPane),
Y = 0, // for menu
Width = Dim.Fill (),
Height = 10,
Height = Dim.Auto (),
CanFocus = false,
ColorScheme = Colors.ColorSchemes ["TopLevel"],
Title = "Settings"
};
_computedCheckBox = new CheckBox { X = 0, Y = 0, Text = "_Computed Layout", Checked = true };
_computedCheckBox.Toggled += (s, e) =>
{
if (_curView != null)
{
_hostPane.LayoutSubviews ();
}
};
_settingsPane.Add (_computedCheckBox);
string [] radioItems = { "_Percent(x)", "_AnchorEnd", "_Center", "A_t(x)" };
_locationFrame = new FrameView
{
X = Pos.Left (_computedCheckBox),
Y = Pos.Bottom (_computedCheckBox),
Height = 3 + radioItems.Length,
Width = 36,
X = 0,
Y = 0,
Height = Dim.Auto (), //3 + radioItems.Length,
Width = Dim.Auto (),
Title = "Location (Pos)"
};
_settingsPane.Add (_locationFrame);
@@ -165,16 +157,16 @@ public class AllViewsTester : Scenario
_xRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
_xText = new TextField { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_xVal}" };
_xText.TextChanged += (s, args) =>
{
try
{
_xVal = int.Parse (_xText.Text);
DimPosChanged (_curView);
}
catch
{ }
};
_xText.Accept += (s, args) =>
{
try
{
_xVal = int.Parse (_xText.Text);
DimPosChanged (_curView);
}
catch
{ }
};
_locationFrame.Add (_xText);
_locationFrame.Add (_xRadioGroup);
@@ -184,16 +176,16 @@ public class AllViewsTester : Scenario
_locationFrame.Add (label);
_yText = new TextField { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_yVal}" };
_yText.TextChanged += (s, args) =>
{
try
{
_yVal = int.Parse (_yText.Text);
DimPosChanged (_curView);
}
catch
{ }
};
_yText.Accept += (s, args) =>
{
try
{
_yVal = int.Parse (_yText.Text);
DimPosChanged (_curView);
}
catch
{ }
};
_locationFrame.Add (_yText);
_yRadioGroup = new RadioGroup { X = Pos.X (label), Y = Pos.Bottom (label), RadioLabels = radioItems };
_yRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
@@ -208,14 +200,14 @@ public class AllViewsTester : Scenario
Title = "Size (Dim)"
};
radioItems = new [] { "Auto (min)", "_Percent(width)", "_Fill(width)", "_Sized(width)" };
radioItems = new [] { "Auto", "_Percent(width)", "_Fill(width)", "_Sized(width)" };
label = new Label { X = 0, Y = 0, Text = "Width:" };
_sizeFrame.Add (label);
_wRadioGroup = new RadioGroup { X = 0, Y = Pos.Bottom (label), RadioLabels = radioItems };
_wRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
_wText = new TextField { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_wVal}" };
_wText.TextChanged += (s, args) =>
_wText.Accept += (s, args) =>
{
try
{
@@ -241,34 +233,34 @@ public class AllViewsTester : Scenario
_sizeFrame.Add (_wText);
_sizeFrame.Add (_wRadioGroup);
radioItems = new [] { "_Auto (min)", "P_ercent(height)", "F_ill(height)", "Si_zed(height)" };
radioItems = new [] { "_Auto", "P_ercent(height)", "F_ill(height)", "Si_zed(height)" };
label = new Label { X = Pos.Right (_wRadioGroup) + 1, Y = 0, Text = "Height:" };
_sizeFrame.Add (label);
_hText = new TextField { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_hVal}" };
_hText.TextChanged += (s, args) =>
{
try
{
switch (_hRadioGroup.SelectedItem)
{
case 1:
_hVal = Math.Min (int.Parse (_hText.Text), 100);
_hText.Accept += (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;
case 0:
case 2:
case 3:
_hVal = int.Parse (_hText.Text);
break;
}
break;
}
DimPosChanged (_curView);
}
catch
{ }
};
DimPosChanged (_curView);
}
catch
{ }
};
_sizeFrame.Add (_hText);
_hRadioGroup = new RadioGroup { X = Pos.X (label), Y = Pos.Bottom (label), RadioLabels = radioItems };
@@ -277,6 +269,40 @@ public class AllViewsTester : Scenario
_settingsPane.Add (_sizeFrame);
label = new Label { X = 0, Y = Pos.Bottom (_sizeFrame), Text = "_Orientation:" };
_orientation = new RadioGroup
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
RadioLabels = new [] { "Horizontal", "Vertical" },
Orientation = Orientation.Horizontal
};
_orientation.SelectedItemChanged += (s, selected) =>
{
if (_curView?.GetType ().GetProperty ("Orientation") is {} prop)
{
prop.GetSetMethod ()?.Invoke (_curView, new object [] { _orientation.SelectedItem });
}
};
_settingsPane.Add (label, _orientation);
label = new Label { X = 0, Y = Pos.Bottom (_orientation), Text = "_Text:" };
_demoTextView = new ()
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = Dim.Fill (),
Height = Dim.Auto (minimumContentDim: 2),
Text = _demoText
};
_demoTextView.ContentsChanged += (s, e) =>
{
_demoText = _demoTextView.Text;
_curView.Text = _demoText;
};
_settingsPane.Add (label, _demoTextView);
_hostPane = new FrameView
{
X = Pos.Right (_leftPane),
@@ -327,7 +353,7 @@ public class AllViewsTester : Scenario
view.GetType ()
.GetProperty ("Text")
?.GetSetMethod ()
?.Invoke (view, new [] { "Test Text" });
?.Invoke (view, new [] { _demoText });
}
catch (TargetInvocationException e)
{
@@ -339,7 +365,7 @@ public class AllViewsTester : Scenario
// 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))
if (view.GetType ().GetProperty ("Title")!.PropertyType == typeof (string))
{
view?.GetType ()
.GetProperty ("Title")
@@ -362,8 +388,16 @@ public class AllViewsTester : Scenario
view?.GetType ().GetProperty ("Source")?.GetSetMethod ()?.Invoke (view, new [] { source });
}
// Set Settings
_computedCheckBox.Checked = view.LayoutStyle == LayoutStyle.Computed;
// If the view supports a Title property, set it so we have something to look at
if (view?.GetType ().GetProperty ("Orientation") is {} prop)
{
_orientation.SelectedItem = (int)prop.GetGetMethod()!.Invoke (view, null)!;
_orientation.Enabled = true;
}
else
{
_orientation.Enabled = false;
}
view.Initialized += View_Initialized;
@@ -407,7 +441,7 @@ public class AllViewsTester : Scenario
view.Width = _wRadioGroup.SelectedItem switch
{
0 => Dim.Auto (minimumContentDim: _wVal),
0 => Dim.Auto (),
1 => Dim.Percent (_wVal),
2 => Dim.Fill (_wVal),
3 => Dim.Sized (_wVal),
@@ -416,7 +450,7 @@ public class AllViewsTester : Scenario
view.Height = _hRadioGroup.SelectedItem switch
{
0 => Dim.Auto (minimumContentDim: _hVal),
0 => Dim.Auto (),
1 => Dim.Percent (_hVal),
2 => Dim.Fill (_hVal),
3 => Dim.Sized (_hVal),
@@ -428,6 +462,30 @@ public class AllViewsTester : Scenario
MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
}
if (view.Width is Dim.DimAuto)
{
_wText.Text = $"Auto";
_wText.Enabled = false;
}
else
{
_wText.Text = $"{_wVal}";
_wText.Enabled = true;
}
if (view.Height is Dim.DimAuto)
{
_hText.Text = $"Auto";
_hText.Enabled = false;
}
else
{
_hText.Text = $"{_hVal}";
_hText.Enabled = true;
}
UpdateTitle (view);
}
@@ -470,8 +528,28 @@ public class AllViewsTester : Scenario
var h = view.Height.ToString ();
_wRadioGroup.SelectedItem = _dimNames.IndexOf (_dimNames.Where (s => w.Contains (s)).First ());
_hRadioGroup.SelectedItem = _dimNames.IndexOf (_dimNames.Where (s => h.Contains (s)).First ());
_wText.Text = $"{view.Frame.Width}";
_hText.Text = $"{view.Frame.Height}";
if (view.Width is Dim.DimAuto)
{
_wText.Text = $"Auto";
_wText.Enabled = false;
}
else
{
_wText.Text = $"100";
_wText.Enabled = true;
}
if (view.Height is Dim.DimAuto)
{
_hText.Text = $"Auto";
_hText.Enabled = false;
}
else
{
_hText.Text = $"100";
_hText.Enabled = true;
}
}
private void UpdateTitle (View view) { _hostPane.Title = $"{view.GetType ().Name} - {view.X}, {view.Y}, {view.Width}, {view.Height}"; }
@@ -488,7 +566,7 @@ public class AllViewsTester : Scenario
view.Width = Dim.Fill ();
}
if (view.Width is not Dim.DimAuto && (view.Height is null || view.Frame.Height == 0))
if (view.Height is not Dim.DimAuto && (view.Height is null || view.Frame.Height == 0))
{
view.Height = Dim.Fill ();
}

View File

@@ -33,7 +33,7 @@ public class DimAutoDemo : Scenario
var textEdit = new TextView
{
Text = "",
X = 1, Y = 0, Width = 20, Height = 4
X = 0, Y = 0, Width = 20, Height = 4
};
view.Add (textEdit);

View File

@@ -168,12 +168,14 @@ public class ProgressBarStyles : Scenario
Title = "Blocks",
X = Pos.Center (),
Y = Pos.Bottom (button) + 1,
Width = Dim.Percent(50),
Width = Dim.Percent (50),
BorderStyle = LineStyle.Single,
CanFocus = true
};
container.Add (blocksPB);
rbPBFormat.SelectedItem = (int)blocksPB.ProgressBarFormat;
var continuousPB = new ProgressBar
{
Title = "Continuous",

View File

@@ -110,7 +110,9 @@ public class DimAutoTests (ITestOutputHelper output)
[Theory]
[InlineData (1, 100, 100)]
[InlineData (1, 50, 50)]
[InlineData (1, 50, 52)] // 50% of 100 is 50, but the border adds 2
[InlineData (1, 30, 32)] // 30% of 100 is 30, but the border adds 2
[InlineData (2, 30, 32)] // 30% of 100 is 30, but the border adds 2
public void Min_Percent_Is_Content_Relative (int contentSize, int minPercent, int expected)
{
var view = new View

View File

@@ -206,8 +206,8 @@ public class RadioGroupTests
Assert.Equal (2, rg.HorizontalSpace);
Assert.Equal (0, rg.X);
Assert.Equal (0, rg.Y);
Assert.Equal (21, rg.Width);
Assert.Equal (1, rg.Height);
Assert.Equal (21, rg.Frame.Width);
Assert.Equal (1, rg.Frame.Height);
expected = @$"
┌────────────────────────────┐
@@ -231,8 +231,8 @@ public class RadioGroupTests
Assert.Equal (4, rg.HorizontalSpace);
Assert.Equal (0, rg.X);
Assert.Equal (0, rg.Y);
Assert.Equal (23, rg.Width);
Assert.Equal (1, rg.Height);
Assert.Equal (23, rg.Frame.Width);
Assert.Equal (1, rg.Frame.Height);
expected = @$"
┌────────────────────────────┐