Revert "Revert "Use glyphs for checkmarks & selection""

This reverts commit db8f591b56.
This commit is contained in:
Charlie Kindel
2020-10-01 15:31:11 -07:00
parent 5d92481f40
commit 4bde71a147
9 changed files with 207 additions and 129 deletions

View File

@@ -531,20 +531,10 @@ namespace Terminal.Gui {
RightTee = Curses.ACS_RTEE;
TopTee = Curses.ACS_TTEE;
BottomTee = Curses.ACS_BTEE;
Checked = '\u221a';
UnChecked = ' ';
Selected = '\u25cf';
UnSelected = '\u25cc';
RightArrow = Curses.ACS_RARROW;
LeftArrow = Curses.ACS_LARROW;
UpArrow = Curses.ACS_UARROW;
DownArrow = Curses.ACS_DARROW;
LeftDefaultIndicator = '\u25e6';
RightDefaultIndicator = '\u25e6';
LeftBracket = '[';
RightBracket = ']';
OnMeterSegment = '\u258c';
OffMeterSegement = ' ';
Colors.TopLevel = new ColorScheme ();
Colors.Base = new ColorScheme ();

View File

@@ -182,33 +182,6 @@ namespace Terminal.Gui {
Colors.Error.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Red);
Colors.Error.HotFocus = Colors.Error.HotNormal;
HLine = '\u2500';
VLine = '\u2502';
Stipple = '\u2592';
Diamond = '\u25c6';
ULCorner = '\u250C';
LLCorner = '\u2514';
URCorner = '\u2510';
LRCorner = '\u2518';
LeftTee = '\u251c';
RightTee = '\u2524';
TopTee = '\u22a4';
BottomTee = '\u22a5';
Checked = '\u221a';
UnChecked = ' ';
Selected = '\u25cf';
UnSelected = '\u25cc';
RightArrow = '\u25ba';
LeftArrow = '\u25c4';
UpArrow = '\u25b2';
DownArrow = '\u25bc';
LeftDefaultIndicator = '\u25e6';
RightDefaultIndicator = '\u25e6';
LeftBracket = '[';
RightBracket = ']';
OnMeterSegment = '\u258c';
OffMeterSegement = ' ';
//MockConsole.Clear ();
}

View File

@@ -152,33 +152,6 @@ namespace Terminal.Gui {
Colors.Error.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Red);
Colors.Error.HotFocus = Colors.Error.HotNormal;
Console.Clear ();
HLine = '\u2500';
VLine = '\u2502';
Stipple = '\u2592';
Diamond = '\u25c6';
ULCorner = '\u250C';
LLCorner = '\u2514';
URCorner = '\u2510';
LRCorner = '\u2518';
LeftTee = '\u251c';
RightTee = '\u2524';
TopTee = '\u22a4';
BottomTee = '\u22a5';
Checked = '\u221a';
UnChecked = ' ';
Selected = '\u25cf';
UnSelected = '\u25cc';
RightArrow = '\u25ba';
LeftArrow = '\u25c4';
UpArrow = '\u25b2';
DownArrow = '\u25bc';
LeftDefaultIndicator = '\u25e6';
RightDefaultIndicator = '\u25e6';
LeftBracket = '[';
RightBracket = ']';
OnMeterSegment = '\u258c';
OffMeterSegement = ' ';
}
public override Attribute MakeAttribute (Color fore, Color back)

View File

@@ -563,33 +563,6 @@ namespace Terminal.Gui {
Colors.Error.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkRed);
Colors.Error.HotNormal = MakeColor (ConsoleColor.Black, ConsoleColor.White);
Colors.Error.HotFocus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkRed);
HLine = '\u2500';
VLine = '\u2502';
Stipple = '\u2591';
Diamond = '\u25ca';
ULCorner = '\u250C';
LLCorner = '\u2514';
URCorner = '\u2510';
LRCorner = '\u2518';
LeftTee = '\u251c';
RightTee = '\u2524';
TopTee = '\u252c';
BottomTee = '\u2534';
Checked = '\u221a';
UnChecked = ' ';
Selected = '\u25cf';
UnSelected = '\u25cc';
RightArrow = '\u25ba';
LeftArrow = '\u25c4';
UpArrow = '\u25b2';
DownArrow = '\u25bc';
LeftDefaultIndicator = '\u25e6';
RightDefaultIndicator = '\u25e6';
LeftBracket = '[';
RightBracket = ']';
OnMeterSegment = '\u258c';
OffMeterSegement = ' ';
}
[StructLayout (LayoutKind.Sequential)]

View File

@@ -913,132 +913,132 @@ namespace Terminal.Gui {
/// <summary>
/// Horizontal line character.
/// </summary>
public Rune HLine;
public Rune HLine = '\u2500';
/// <summary>
/// Vertical line character.
/// </summary>
public Rune VLine;
public Rune VLine = '\u2502';
/// <summary>
/// Stipple pattern
/// </summary>
public Rune Stipple;
public Rune Stipple = '\u2591';
/// <summary>
/// Diamond character
/// </summary>
public Rune Diamond;
public Rune Diamond = '\u25ca';
/// <summary>
/// Upper left corner
/// </summary>
public Rune ULCorner;
public Rune ULCorner = '\u250C';
/// <summary>
/// Lower left corner
/// </summary>
public Rune LLCorner;
public Rune LLCorner = '\u2514';
/// <summary>
/// Upper right corner
/// </summary>
public Rune URCorner;
public Rune URCorner = '\u2510';
/// <summary>
/// Lower right corner
/// </summary>
public Rune LRCorner;
public Rune LRCorner = '\u2518';
/// <summary>
/// Left tee
/// </summary>
public Rune LeftTee;
public Rune LeftTee = '\u251c';
/// <summary>
/// Right tee
/// </summary>
public Rune RightTee;
public Rune RightTee = '\u2524';
/// <summary>
/// Top tee
/// </summary>
public Rune TopTee;
public Rune TopTee = '\u252c';
/// <summary>
/// The bottom tee.
/// </summary>
public Rune BottomTee;
public Rune BottomTee = '\u2534';
/// <summary>
/// Checkmark.
/// </summary>
public Rune Checked;
public Rune Checked = '\u221a';
/// <summary>
/// Un-checked checkmark.
/// </summary>
public Rune UnChecked;
public Rune UnChecked = '\u2574';
/// <summary>
/// Selected mark.
/// </summary>
public Rune Selected;
public Rune Selected = '\u25cf';
/// <summary>
/// Un-selected selected mark.
/// </summary>
public Rune UnSelected;
public Rune UnSelected = '\u25cc';
/// <summary>
/// Right Arrow.
/// </summary>
public Rune RightArrow;
public Rune RightArrow = '\u25ba';
/// <summary>
/// Left Arrow.
/// </summary>
public Rune LeftArrow;
public Rune LeftArrow = '\u25c4';
/// <summary>
/// Down Arrow.
/// </summary>
public Rune DownArrow;
public Rune DownArrow = '\u25bc';
/// <summary>
/// Up Arrow.
/// </summary>
public Rune UpArrow;
public Rune UpArrow = '\u25b2';
/// <summary>
/// Left indicator for default action (e.g. for <see cref="Button"/>).
/// </summary>
public Rune LeftDefaultIndicator;
public Rune LeftDefaultIndicator = '\u25e6';
/// <summary>
/// Right indicator for default action (e.g. for <see cref="Button"/>).
/// </summary>
public Rune RightDefaultIndicator;
public Rune RightDefaultIndicator = '\u25e6';
/// <summary>
/// Left frame/bracket (e.g. '[' for <see cref="Button"/>).
/// </summary>
public Rune LeftBracket;
public Rune LeftBracket = '[';
/// <summary>
/// Right frame/bracket (e.g. ']' for <see cref="Button"/>).
/// </summary>
public Rune RightBracket;
public Rune RightBracket = ']';
/// <summary>
/// On Segment indicator for meter views (e.g. <see cref="ProgressBar"/>.
/// </summary>
public Rune OnMeterSegment;
public Rune OnMeterSegment = '\u258c';
/// <summary>
/// Off Segment indicator for meter views (e.g. <see cref="ProgressBar"/>.
/// </summary>
public Rune OffMeterSegement;
public Rune OffMeterSegement = ' ';
/// <summary>
/// Make the attribute for the foreground and background colors.

View File

@@ -115,11 +115,12 @@ namespace Terminal.Gui {
{
Driver.SetAttribute (HasFocus ? ColorScheme.Focus : ColorScheme.Normal);
Move (0, 0);
Driver.AddStr (Checked ? "[x] " : "[ ] ");
Move (4, 0);
Driver.AddRune (Checked ? Driver.Checked : Driver.UnChecked);
Driver.AddRune (' ');
Move (2, 0);
Driver.AddStr (Text);
if (hot_pos != -1) {
Move (4 + hot_pos, 0);
Move (2 + hot_pos, 0);
Driver.SetAttribute (HasFocus ? ColorScheme.HotFocus : ColorScheme.HotNormal);
Driver.AddRune (hot_key);
}
@@ -128,7 +129,7 @@ namespace Terminal.Gui {
///<inheritdoc/>
public override void PositionCursor ()
{
Move (1, 0);
Move (0, 0);
}
///<inheritdoc/>

View File

@@ -180,7 +180,19 @@ namespace Terminal.Gui {
/// <summary>
/// If set to true allows more than one item to be selected. If false only allow one item selected.
/// </summary>
public bool AllowsMultipleSelection { get; set; } = true;
public bool AllowsMultipleSelection { get => allowsMultipleSelection;
set {
allowsMultipleSelection = value;
if (Source != null && !allowsMultipleSelection) {
// Clear all selections except selected
for (int i = 0; i < Source.Count; i++) {
if (Source.IsMarked (i) && i != selected) {
Source.SetMark (i, false);
}
}
}
}
}
/// <summary>
/// Gets or sets the item that is displayed at the top of the <see cref="ListView"/>.
@@ -293,7 +305,7 @@ namespace Terminal.Gui {
}
var item = top;
bool focused = HasFocus;
int col = allowsMarking ? 4 : 0;
int col = allowsMarking ? 2 : 0;
for (int row = 0; row < f.Height; row++, item++) {
bool isSelected = item == selected;
@@ -310,7 +322,8 @@ namespace Terminal.Gui {
Driver.AddRune (' ');
} else {
if (allowsMarking) {
Driver.AddStr (source.IsMarked (item) ? (AllowsMultipleSelection ? "[x] " : "(o)") : (AllowsMultipleSelection ? "[ ] " : "( )"));
Driver.AddRune (source.IsMarked (item) ? (AllowsMultipleSelection ? Driver.Selected : Driver.Checked) : (AllowsMultipleSelection ? Driver.UnSelected : Driver.UnChecked));
Driver.AddRune (' ');
}
Source.Render (this, Driver, isSelected, item, col, row, f.Width - col);
}
@@ -539,6 +552,7 @@ namespace Terminal.Gui {
}
int lastSelectedItem = -1;
private bool allowsMultipleSelection = true;
/// <summary>
/// Invokes the SelectedChanged event if it is defined.
@@ -595,9 +609,9 @@ namespace Terminal.Gui {
public override void PositionCursor ()
{
if (allowsMarking)
Move (1, selected - top);
else
Move (0, selected - top);
else
Move (Bounds.Width - 1, selected - top);
}
///<inheritdoc/>

View File

@@ -398,11 +398,10 @@ namespace Terminal.Gui {
uncheckedChar = Driver.UnChecked;
}
// Support Checked even though CHeckType wasn't set
// Support Checked even though CheckType wasn't set
if (item.Checked) {
textToDraw = ustring.Make (new Rune [] { checkChar, ' ' }) + item.Title;
} else if (item.CheckType.HasFlag (MenuItemCheckStyle.Checked) ||
item.CheckType.HasFlag (MenuItemCheckStyle.Radio)) {
} else if (item.CheckType.HasFlag (MenuItemCheckStyle.Checked) || item.CheckType.HasFlag (MenuItemCheckStyle.Radio)) {
textToDraw = ustring.Make (new Rune [] { uncheckedChar, ' ' }) + item.Title;
} else {
textToDraw = item.Title;

View File

@@ -0,0 +1,155 @@
using NStack;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Terminal.Gui;
namespace UICatalog {
[ScenarioMetadata (Name: "List View With Selection", Description: "ListView with colunns and selection")]
[ScenarioCategory ("Controls")]
class ListViewWithSelection : Scenario {
public CheckBox _customRenderCB;
public CheckBox _allowMarkingCB;
public CheckBox _allowMultipleCB;
public ListView _listView;
public List<Type> _scenarios = Scenario.GetDerivedClasses<Scenario>().OrderBy (t => Scenario.ScenarioMetadata.GetName (t)).ToList ();
public override void Setup ()
{
_customRenderCB = new CheckBox ("Render with columns") {
X = 0,
Y = 0,
Height = 1,
};
Win.Add (_customRenderCB);
_customRenderCB.Toggled += _customRenderCB_Toggled; ;
_allowMarkingCB = new CheckBox ("Allow Marking") {
X = Pos.Right (_customRenderCB) + 1,
Y = 0,
Height = 1,
};
Win.Add (_allowMarkingCB);
_allowMarkingCB.Toggled += AllowMarkingCB_Toggled;
_allowMultipleCB = new CheckBox ("Allow Multi-Select") {
X = Pos.Right (_allowMarkingCB) + 1,
Y = 0,
Height = 1,
Visible = _allowMarkingCB.Checked
};
Win.Add (_allowMultipleCB);
_allowMultipleCB.Toggled += AllowMultipleCB_Toggled;
_listView = new ListView () {
X = 1,
Y = 2,
Height = Dim.Fill (),
Width = Dim.Fill (1),
//ColorScheme = Colors.TopLevel,
AllowsMarking = false,
AllowsMultipleSelection = false
};
Win.Add (_listView);
_listView.SetSource (_scenarios);
}
private void _customRenderCB_Toggled (bool prev)
{
if (prev) {
_listView.SetSource (_scenarios);
} else {
_listView.Source = new ScenarioListDataSource (_scenarios);
}
Win.SetNeedsDisplay ();
}
private void AllowMarkingCB_Toggled (bool prev)
{
_listView.AllowsMarking = !prev;
_allowMultipleCB.Visible = _listView.AllowsMarking;
Win.SetNeedsDisplay ();
}
private void AllowMultipleCB_Toggled (bool prev)
{
_listView.AllowsMultipleSelection = !prev;
Win.SetNeedsDisplay ();
}
// This is basicaly the same implementation used by the UICatalog main window
internal class ScenarioListDataSource : IListDataSource {
int _nameColumnWidth = 30;
private List<Type> scenarios;
BitArray marks;
int count;
public List<Type> Scenarios {
get => scenarios;
set {
if (value != null) {
count = value.Count;
marks = new BitArray (count);
scenarios = value;
}
}
}
public bool IsMarked (int item)
{
if (item >= 0 && item < count)
return marks [item];
return false;
}
public int Count => Scenarios != null ? Scenarios.Count : 0;
public ScenarioListDataSource (List<Type> itemList) => Scenarios = itemList;
public void Render (ListView container, ConsoleDriver driver, bool selected, int item, int col, int line, int width)
{
container.Move (col, line);
// Equivalent to an interpolated string like $"{Scenarios[item].Name, -widtestname}"; if such a thing were possible
var s = String.Format (String.Format ("{{0,{0}}}", -_nameColumnWidth), Scenario.ScenarioMetadata.GetName (Scenarios [item]));
RenderUstr (driver, $"{s} {Scenario.ScenarioMetadata.GetDescription (Scenarios [item])}", col, line, width);
}
public void SetMark (int item, bool value)
{
if (item >= 0 && item < count)
marks [item] = value;
}
// A slightly adapted method from: https://github.com/migueldeicaza/gui.cs/blob/fc1faba7452ccbdf49028ac49f0c9f0f42bbae91/Terminal.Gui/Views/ListView.cs#L433-L461
private void RenderUstr (ConsoleDriver driver, ustring ustr, int col, int line, int width)
{
int used = 0;
int index = 0;
while (index < ustr.Length) {
(var rune, var size) = Utf8.DecodeRune (ustr, index, index - ustr.Length);
var count = Rune.ColumnWidth (rune);
if (used + count >= width) break;
driver.AddRune (rune);
used += count;
index += size;
}
while (used < width) {
driver.AddRune (' ');
used++;
}
}
public IList ToList ()
{
return Scenarios;
}
}
}
}