ready for pr

This commit is contained in:
Charlie Kindel
2020-06-18 01:29:25 -07:00
parent 8272d8aff3
commit 120991ec5b
14 changed files with 323 additions and 231 deletions

View File

@@ -0,0 +1,4 @@
namespace Terminal.Gui {
internal class Range {
}
}

View File

@@ -5,6 +5,28 @@ using System.Linq;
using NStack;
namespace Terminal.Gui {
/// <summary>
/// Text alignment enumeration, controls how text is displayed.
/// </summary>
public enum TextAlignment {
/// <summary>
/// Aligns the text to the left of the frame.
/// </summary>
Left,
/// <summary>
/// Aligns the text to the right side of the frame.
/// </summary>
Right,
/// <summary>
/// Centers the text in the frame.
/// </summary>
Centered,
/// <summary>
/// Shows the text as justified text in the frame.
/// </summary>
Justified
}
/// <summary>
/// Provides text formatting capabilites for console apps. Supports, hotkeys, horizontal alignment, multille lines, and word-based line wrap.
/// </summary>
@@ -177,21 +199,20 @@ namespace Terminal.Gui {
return lines;
}
var runes = StripCRLF (text).ToRunes ();
var runes = StripCRLF (text).ToRuneList();
while ((end = start + width) < runes.Length) {
while ((end = start + width) < runes.Count) {
while (runes [end] != ' ' && end > start)
end -= 1;
if (end == start)
end = start + width;
lines.Add (ustring.Make (runes [start..end]).TrimSpace ());
lines.Add (ustring.Make (runes.GetRange (start, end - start)).TrimSpace());
start = end;
}
if (start < text.RuneCount)
lines.Add (ustring.Make (runes [start..]).TrimSpace ());
if (start < text.RuneCount) {
lines.Add (ustring.Make (runes.GetRange (start, runes.Count - start)).TrimSpace ());
}
return lines;
}
@@ -212,10 +233,10 @@ namespace Terminal.Gui {
return text;
}
var runes = text.ToRunes ();
int slen = runes.Length;
var runes = text.ToRuneList ();
int slen = runes.Count;
if (slen > width) {
return ustring.Make (runes [0..width]); // text [0, width];
return ustring.Make (runes.GetRange(0, width));
} else {
if (talign == TextAlignment.Justified) {
return Justify (text, width);
@@ -302,13 +323,13 @@ namespace Terminal.Gui {
return lineResult;
}
var runes = text.ToRunes ();
int runeCount = runes.Length;
var runes = text.ToRuneList ();
int runeCount = runes.Count;
int lp = 0;
for (int i = 0; i < runeCount; i++) {
Rune c = text [i];
if (c == '\n') {
var wrappedLines = WordWrap (ustring.Make (runes [lp..i]), width);
var wrappedLines = WordWrap (ustring.Make (runes.GetRange(lp, i - lp)), width);
foreach (var line in wrappedLines) {
lineResult.Add (ClipAndJustify (line, width, talign));
}
@@ -318,7 +339,7 @@ namespace Terminal.Gui {
lp = i + 1;
}
}
foreach (var line in WordWrap (ustring.Make (runes [lp..runeCount]), width)) {
foreach (var line in WordWrap (ustring.Make (runes.GetRange(lp, runeCount - lp)), width)) {
lineResult.Add (ClipAndJustify (line, width, talign));
}
@@ -516,7 +537,7 @@ namespace Terminal.Gui {
// Use "Lines" to ensure a Format (don't use "lines"))
for (int line = 0; line < Lines.Count; line++) {
if (line < (bounds.Height - bounds.Top) || line >= bounds.Height)
if (line > bounds.Height)
continue;
var runes = lines [line].ToRunes ();
int x;
@@ -537,7 +558,7 @@ namespace Terminal.Gui {
throw new ArgumentOutOfRangeException ();
}
for (var col = bounds.Left; col < bounds.Left + bounds.Width; col++) {
Application.Driver.Move (col, bounds.Y + line);
Application.Driver.Move (col, bounds.Top + line);
var rune = (Rune)' ';
if (col >= x && col < (x + runes.Length)) {
rune = runes [col - x];
@@ -552,5 +573,6 @@ namespace Terminal.Gui {
}
}
}
}
}

View File

@@ -18,28 +18,6 @@ using System.Linq;
using NStack;
namespace Terminal.Gui {
/// <summary>
/// Text alignment enumeration, controls how text is displayed.
/// </summary>
public enum TextAlignment {
/// <summary>
/// Aligns the text to the left of the frame.
/// </summary>
Left,
/// <summary>
/// Aligns the text to the right side of the frame.
/// </summary>
Right,
/// <summary>
/// Centers the text in the frame.
/// </summary>
Centered,
/// <summary>
/// Shows the text as justified text in the frame.
/// </summary>
Justified
}
/// <summary>
/// Determines the LayoutStyle for a view, if Absolute, during LayoutSubviews, the
/// value from the Frame will be used, if the value is Computed, then the Frame
@@ -172,12 +150,12 @@ namespace Terminal.Gui {
public Action<MouseEventArgs> MouseClick;
/// <summary>
/// The HotKey defined for this view. A user pressing HotKey on the keyboard while this view has focus will cause the Clicked event to fire.
/// Gets or sets the HotKey defined for this view. A user pressing HotKey on the keyboard while this view has focus will cause the Clicked event to fire.
/// </summary>
public Key HotKey { get => viewText.HotKey; set => viewText.HotKey = value; }
/// <summary>
///
/// Gets or sets the specifier character for the hotkey (e.g. '_'). Set to '\xffff' to disable hotkey support for this View instance. The default is '\xffff'.
/// </summary>
public Rune HotKeySpecifier { get => viewText.HotKeySpecifier; set => viewText.HotKeySpecifier = value; }
@@ -860,21 +838,24 @@ namespace Terminal.Gui {
/// <summary>
/// Utility function to draw strings that contain a hotkey.
/// </summary>
/// <param name="text">String to display, the underscoore before a letter flags the next letter as the hotkey.</param>
/// <param name="text">String to display, the hotkey specifier before a letter flags the next letter as the hotkey.</param>
/// <param name="hotColor">Hot color.</param>
/// <param name="normalColor">Normal color.</param>
/// <remarks>
/// The hotkey is any character following an underscore ('_') character.</remarks>
/// <para>The hotkey is any character following the hotkey specifier, which is the underscore ('_') character by default.</para>
/// <para>The hotkey specifier can be changed via <see cref="HotKeySpecifier"/></para>
/// </remarks>
public void DrawHotString (ustring text, Attribute hotColor, Attribute normalColor)
{
Driver.SetAttribute (normalColor);
var hotkeySpec = HotKeySpecifier == (Rune)0xffff ? (Rune)'_' : HotKeySpecifier;
Application.Driver.SetAttribute (normalColor);
foreach (var rune in text) {
if (rune == '_') {
Driver.SetAttribute (hotColor);
if (rune == hotkeySpec) {
Application.Driver.SetAttribute (hotColor);
continue;
}
Driver.AddRune (rune);
Driver.SetAttribute (normalColor);
Application.Driver.AddRune (rune);
Application.Driver.SetAttribute (normalColor);
}
}
@@ -1078,9 +1059,8 @@ namespace Terminal.Gui {
if (!ustring.IsNullOrEmpty (Text)) {
Clear ();
// Draw any Text
// TODO: Figure out if this should go here or after OnDrawContent
viewText?.SetNeedsFormat ();
viewText?.Draw (ViewToScreen (Bounds), ColorScheme.Normal, ColorScheme.HotNormal);
viewText?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : ColorScheme.Normal, HasFocus ? ColorScheme.HotFocus : ColorScheme.HotNormal);
}
// Invoke DrawContentEvent
@@ -1594,7 +1574,19 @@ namespace Terminal.Gui {
/// The text displayed by the <see cref="View"/>.
/// </summary>
/// <remarks>
/// The text will only be displayed if the View has no subviews.
/// <para>
/// If provided, the text will be drawn before any subviews are drawn.
/// </para>
/// <para>
/// The text will be drawn starting at the view origin (0, 0) and will be formatted according
/// to the <see cref="TextAlignment"/> property. If the view's height is greater than 1, the
/// text will word-wrap to additional lines if it does not fit horizontally. If the view's height
/// is 1, the text will be clipped.
/// </para>
/// <para>
/// Set the <see cref="HotKeySpecifier"/> to enable hotkey support. To disable hotkey support set <see cref="HotKeySpecifier"/> to
/// <c>(Rune)0xffff</c>.
/// </para>
/// </remarks>
public virtual ustring Text {
get => viewText.Text;
@@ -1605,7 +1597,7 @@ namespace Terminal.Gui {
}
/// <summary>
/// Controls the text-alignment property of the View. Changing this property will redisplay the <see cref="View"/>.
/// Gets or sets how the View's <see cref="Text"/> is aligned horizontally when drawn. Changing this property will redisplay the <see cref="View"/>.
/// </summary>
/// <value>The text alignment.</value>
public virtual TextAlignment TextAlignment {

View File

@@ -1,12 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.1</TargetFrameworks>
<TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
<RootNamespace>Terminal.Gui</RootNamespace>
<AssemblyName>Terminal.Gui</AssemblyName>
<DocumentationFile>bin\Release\Terminal.Gui.xml</DocumentationFile>
<GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
<AssemblyVersion>0.90.0.0</AssemblyVersion>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup>
<GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' ">true</GeneratePackageOnBuild>
@@ -75,7 +74,7 @@
* Added a OpenSelectedItem event to the ListView #429. (Thanks @bdisp!)
* Fixes the return value of the position cursor in the TextField. (Thanks @bdisp!)
* Updates screen on Unix window resizing. (Thanks @bdisp!)
* Fixes the functions of the Edit-&gt;Copy-Cut-Paste menu for the TextField that was not working well. (Thanks @bdisp!)
* Fixes the functions of the Edit-Copy-Cut-Paste menu for the TextField that was not working well. (Thanks @bdisp!)
* More robust error handing in Pos/Dim. Fixes #355 stack overflow with Pos based on the size of windows at startup. Added a OnResized action to set the Pos after the terminal are resized. (Thanks @bdisp!)
* Fixes #389 Window layouting breaks when resizing. (Thanks @bdisp!)
* Fixes #557 MessageBox needs to take ustrings (BREAKING CHANGE). (Thanks @tig!)
@@ -101,6 +100,15 @@
* ConsoleDriver and Drivers have new standard glyph definitions for things like right arrow. (Thanks @tig!)
* ScrollView updated to use pretty glyphs. (Thanks @tig!)
* Menubar now uses pretty arrow glyph for sub-menus. (Thanks @tig!)
* The project now has a growing set of unit tests (over 100 tests). (Thanks @tig!)
* View now has a Text property, implemented via the new TextFormatting class. (Thanks @tig!)
* TextAlignment is implemented once across all Views that support it.
* Unicode support is now much more robust and complete; dozens of bugs fixed.
* Any view dervied from View now has a Text property with multi-line text formatting, including word-wrap and hotkey support.
* Any view derived from View now gets mouse click (Clicked event) support for free.
* Label is now just an alias for View.
* Button is now a very thin class derived from View (no API changes).
* Dozens of unit tests for TextAlignment are provided reducing the chance of regressions.
0.81:
* Fix ncurses engine for macOS/Linux, it works again

View File

@@ -15,8 +15,14 @@ namespace Terminal.Gui {
/// <remarks>
/// <para>
/// Provides a button showing text invokes an <see cref="Action"/> when clicked on with a mouse
/// or when the user presses SPACE, ENTER, or hotkey. The hotkey is specified by the first uppercase
/// letter in the button.
/// or when the user presses SPACE, ENTER, or hotkey. The hotkey is the first letter or digit following the first underscore ('_')
/// in the button text.
/// </para>
/// <para>
/// Use <see cref="View.HotKeySpecifier"/> to change the hotkey specifier from the default of ('_').
/// </para>
/// <para>
/// If no hotkey specifier is found, the first uppercase letter encountered will be used as the hotkey.
/// </para>
/// <para>
/// When the button is configured as the default (<see cref="IsDefault"/>) and the user presses
@@ -103,19 +109,8 @@ namespace Terminal.Gui {
CanFocus = true;
this.IsDefault = is_default;
Text = text ?? string.Empty;
//int w = SetWidthHeight (text, is_default);
//Frame = new Rect (Frame.Location, new Size (w, 1));
}
//int SetWidthHeight (ustring text, bool is_default)
//{
// int w = text.RuneCount;// + 4 + (is_default ? 2 : 0);
// Width = w;
// Height = 1;
// Frame = new Rect (Frame.Location, new Size (w, 1));
// return w;
//}
/// <summary>
/// The text displayed by this <see cref="Button"/>.
/// </summary>
@@ -153,7 +148,6 @@ namespace Terminal.Gui {
Width = w;
Height = 1;
Frame = new Rect (Frame.Location, new Size (w, 1));
SetNeedsDisplay ();
}
@@ -196,6 +190,5 @@ namespace Terminal.Gui {
}
return base.ProcessKey (kb);
}
}
}

View File

@@ -76,9 +76,9 @@ namespace UICatalog {
_leftPane = new Window ("Classes") {
X = 0,
Y = 0, // for menu
Y = 0,
Width = 15,
Height = Dim.Fill (),
Height = Dim.Fill (1), // for status bar
CanFocus = false,
ColorScheme = Colors.TopLevel,
};
@@ -87,7 +87,7 @@ namespace UICatalog {
X = 0,
Y = 0,
Width = Dim.Fill (0),
Height = Dim.Fill (), // for status bar
Height = Dim.Fill (0),
AllowsMarking = false,
ColorScheme = Colors.TopLevel,
};

View File

@@ -70,9 +70,6 @@ namespace UICatalog {
//prev = colorButton;
x += colorButton.Frame.Width + 2;
}
// BUGBUG: For some reason these buttons don't move to correct locations initially.
// This was the only way I find to resolves this with the View prev variable.
//Top.Ready += () => Top.Redraw (Top.Bounds);
Button button;
Win.Add (button = new Button ("A super long _Button that will probably expose a bug in clipping or wrapping of text. Will it?") {
@@ -187,23 +184,26 @@ namespace UICatalog {
ustring MoveHotkey (ustring txt)
{
// Remove the '_'
var i = txt.IndexOf ('_');
var runes = txt.ToRuneList ();
var i = runes.IndexOf ('_');
ustring start = "";
if (i > -1)
start = txt [0, i];
txt = start + txt [i + 1, txt.RuneCount];
if (i > -1) {
start = ustring.Make (runes.GetRange (0, i));
}
txt = start + ustring.Make (runes.GetRange (i + 1, runes.Count - (i + 1)));
runes = txt.ToRuneList ();
// Move over one or go to start
i++;
if (i >= txt.RuneCount) {
if (i >= runes.Count) {
i = 0;
}
// Slip in the '_'
start = txt [0, i];
txt = start + ustring.Make ('_') + txt [i, txt.RuneCount];
return txt;
start = ustring.Make (runes.GetRange (0, i));
return start + ustring.Make ('_') + ustring.Make (runes.GetRange (i, runes.Count - i));
}
var mhkb = "Click to Change th_is Button's Hotkey";
@@ -218,7 +218,7 @@ namespace UICatalog {
};
Win.Add (moveHotKeyBtn);
var muhkb = ustring.Make(" ~  s  gui.cs   master ↑10 = Сохранить");
var muhkb = ustring.Make (" ~  s  gui.cs   master ↑10 = Сохранить");
var moveUnicodeHotKeyBtn = new Button (muhkb) {
X = Pos.Left (absoluteFrame) + 1,
Y = Pos.Bottom (radioGroup) + 1,

View File

@@ -34,7 +34,7 @@ namespace UICatalog {
//Win.Height = Dim.Fill () - 2;
var label = new Label ("ScrollView (new Rect (5, 5, 100, 60)) with a 200, 100 ContentSize...") {
X = 0, Y = 0,
ColorScheme = Colors.Dialog
//ColorScheme = Colors.Dialog
};
Top.Add (label);

View File

@@ -6,10 +6,10 @@ using System.Reflection;
using Terminal.Gui;
namespace UICatalog {
[ScenarioMetadata (Name: "LabelsAsButtons", Description: "POC to see how making Label more a base class would work")]
[ScenarioMetadata (Name: "Labels As Buttons", Description: "Illustrates that Button is really just a Label++")]
[ScenarioCategory ("Controls")]
[ScenarioCategory ("POC")]
class LabelsAsButtons : Scenario {
class LabelsAsLabels : Scenario {
public override void Setup ()
{
// Add a label & text field so we can demo IsDefault
@@ -22,107 +22,120 @@ namespace UICatalog {
var edit = new TextField (31, 0, 15, "");
Win.Add (edit);
// This is the default button (IsDefault = true); if user presses ENTER in the TextField
// This is the default Label (IsDefault = true); if user presses ENTER in the TextField
// the scenario will quit
var defaultButton = new Label ("_Quit") {
var defaultLabel = new Label ("_Quit") {
X = Pos.Center (),
//TODO: Change to use Pos.AnchorEnd()
Y = Pos.Bottom (Win) - 3,
//IsDefault = true,
Clicked = () => Application.RequestStop (),
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
Win.Add (defaultButton);
Win.Add (defaultLabel);
var swapButton = new Label (50, 0, "Swap Default (Absolute Layout)");
swapButton.Clicked = () => {
//defaultButton.IsDefault = !defaultButton.IsDefault;
//swapButton.IsDefault = !swapButton.IsDefault;
var swapLabel = new Label (50, 0, "S_wap Default (Absolute Layout)") {
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
Win.Add (swapButton);
swapLabel.Clicked = () => {
//defaultLabel.IsDefault = !defaultLabel.IsDefault;
//swapLabel.IsDefault = !swapLabel.IsDefault;
};
Win.Add (swapLabel);
static void DoMessage (Label button, ustring txt)
static void DoMessage (Label Label, ustring txt)
{
button.Clicked = () => {
var btnText = button.Text.ToString ();
Label.Clicked = () => {
var btnText = Label.Text.ToString ();
MessageBox.Query ("Message", $"Did you click {txt}?", "Yes", "No");
};
}
var colorButtonsLabel = new Label ("Color Buttons:") {
var colorLabelsLabel = new Label ("Color Labels:") {
X = 0,
Y = Pos.Bottom (editLabel) + 1,
};
Win.Add (colorButtonsLabel);
//View prev = colorButtonsLabel;
Win.Add (colorLabelsLabel);
//With this method there is no need to call Top.Ready += () => Top.Redraw (Top.Bounds);
var x = Pos.Right (colorButtonsLabel) + 2;
var x = Pos.Right (colorLabelsLabel) + 2;
foreach (var colorScheme in Colors.ColorSchemes) {
var colorButton = new Label ($"{colorScheme.Key}") {
var colorLabel = new Label ($"{colorScheme.Key}") {
ColorScheme = colorScheme.Value,
//X = Pos.Right (prev) + 2,
X = x,
Y = Pos.Y (colorButtonsLabel),
Y = Pos.Y (colorLabelsLabel),
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
DoMessage (colorButton, colorButton.Text);
Win.Add (colorButton);
//prev = colorButton;
x += colorButton.Frame.Width + 2;
DoMessage (colorLabel, colorLabel.Text);
Win.Add (colorLabel);
x += colorLabel.Text.Length + 2;
}
// BUGBUG: For some reason these buttons don't move to correct locations initially.
// This was the only way I find to resolves this with the View prev variable.
//Top.Ready += () => Top.Redraw (Top.Bounds);
Top.Ready += () => Top.Redraw (Top.Bounds);
Label button;
Win.Add (button = new Label ("A super long _Button that will probably expose a bug in clipping or wrapping of text. Will it?") {
Label Label;
Win.Add (Label = new Label ("A super long _Label that will probably expose a bug in clipping or wrapping of text. Will it?") {
X = 2,
Y = Pos.Bottom (colorButtonsLabel) + 1,
Y = Pos.Bottom (colorLabelsLabel) + 1,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
});
DoMessage (button, button.Text);
DoMessage (Label, Label.Text);
// Note the 'N' in 'Newline' will be the hotkey
Win.Add (button = new Label ("a Newline\nin the button") {
Win.Add (Label = new Label ("a Newline\nin the Label") {
X = 2,
Y = Pos.Bottom (button) + 1,
Clicked = () => MessageBox.Query ("Message", "Question?", "Yes", "No")
Y = Pos.Bottom (Label) + 1,
Clicked = () => MessageBox.Query ("Message", "Question?", "Yes", "No"),
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
});
var textChanger = new Label ("Te_xt Changer") {
X = 2,
Y = Pos.Bottom (button) + 1,
Y = Pos.Bottom (Label) + 1,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
Win.Add (textChanger);
textChanger.Clicked = () => textChanger.Text += "!";
Win.Add (button = new Label ("Lets see if this will move as \"Text Changer\" grows") {
Win.Add (Label = new Label ("Lets see if this will move as \"Text Changer\" grows") {
X = Pos.Right (textChanger) + 2,
Y = Pos.Y (textChanger),
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
});
var removeButton = new Label ("Remove this button") {
var removeLabel = new Label ("Remove this Label") {
X = 2,
Y = Pos.Bottom (button) + 1,
ColorScheme = Colors.Error
Y = Pos.Bottom (Label) + 1,
ColorScheme = Colors.Error,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
Win.Add (removeButton);
Win.Add (removeLabel);
// This in intresting test case because `moveBtn` and below are laid out relative to this one!
removeButton.Clicked = () => Win.Remove (removeButton);
removeLabel.Clicked = () => Win.Remove (removeLabel);
var computedFrame = new FrameView ("Computed Layout") {
X = 0,
Y = Pos.Bottom (removeButton) + 1,
Y = Pos.Bottom (removeLabel) + 1,
Width = Dim.Percent (50),
Height = 5
};
Win.Add (computedFrame);
// Demonstrates how changing the View.Frame property can move Views
var moveBtn = new Label ("Move This \u263b Button _via Pos") {
var moveBtn = new Label ("Move This \u263b Label _via Pos") {
X = 0,
Y = Pos.Center () - 1,
Width = 30,
ColorScheme = Colors.Error,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
moveBtn.Clicked = () => {
moveBtn.X = moveBtn.Frame.X + 5;
@@ -132,12 +145,14 @@ namespace UICatalog {
computedFrame.Add (moveBtn);
// Demonstrates how changing the View.Frame property can SIZE Views (#583)
var sizeBtn = new Label ("Size This \u263a Button _via Pos") {
//var sizeBtn = new Label ("Size This x Button _via Pos") {
var sizeBtn = new Label ("Size This \u263a Label _via Pos") {
//var sizeBtn = new Label ("Size This x Label _via Pos") {
X = 0,
Y = Pos.Center () + 1,
Width = 30,
ColorScheme = Colors.Error,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
sizeBtn.Clicked = () => {
sizeBtn.Width = sizeBtn.Frame.Width + 5;
@@ -147,15 +162,17 @@ namespace UICatalog {
var absoluteFrame = new FrameView ("Absolute Layout") {
X = Pos.Right (computedFrame),
Y = Pos.Bottom (removeButton) + 1,
Y = Pos.Bottom (removeLabel) + 1,
Width = Dim.Fill (),
Height = 5
};
Win.Add (absoluteFrame);
// Demonstrates how changing the View.Frame property can move Views
var moveBtnA = new Label (0, 0, "Move This Button via Frame") {
var moveBtnA = new Label (0, 0, "Move This Label via Frame") {
ColorScheme = Colors.Error,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
moveBtnA.Clicked = () => {
moveBtnA.Frame = new Rect (moveBtnA.Frame.X + 5, moveBtnA.Frame.Y, moveBtnA.Frame.Width, moveBtnA.Frame.Height);
@@ -165,15 +182,19 @@ namespace UICatalog {
// Demonstrates how changing the View.Frame property can SIZE Views (#583)
var sizeBtnA = new Label (0, 2, " ~  s  gui.cs   master ↑10 = Со_хранить") {
ColorScheme = Colors.Error,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
sizeBtnA.Clicked = () => {
sizeBtnA.Frame = new Rect (sizeBtnA.Frame.X, sizeBtnA.Frame.Y, sizeBtnA.Frame.Width + 5, sizeBtnA.Frame.Height);
};
absoluteFrame.Add (sizeBtnA);
var label = new Label ("Text Alignment (changes the four buttons above): ") {
var label = new Label ("Text Alignment (changes the four Labels above): ") {
X = 2,
Y = Pos.Bottom (computedFrame) + 1,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
Win.Add (label);
@@ -188,31 +209,36 @@ namespace UICatalog {
ustring MoveHotkey (ustring txt)
{
// Remove the '_'
var i = txt.IndexOf ('_');
var runes = txt.ToRuneList ();
var i = runes.IndexOf ('_');
ustring start = "";
if (i > -1)
start = txt [0, i];
txt = start + txt [i + 1, txt.RuneCount];
if (i > -1) {
start = ustring.Make (runes.GetRange (0, i));
}
txt = start + ustring.Make (runes.GetRange (i + 1, runes.Count - (i + 1)));
runes = txt.ToRuneList ();
// Move over one or go to start
i++;
if (i >= txt.RuneCount) {
if (i >= runes.Count) {
i = 0;
}
// Slip in the '_'
start = txt [0, i];
txt = start + ustring.Make ('_') + txt [i, txt.RuneCount];
return txt;
start = ustring.Make (runes.GetRange (0, i));
return start + ustring.Make ('_') + ustring.Make (runes.GetRange (i, runes.Count - i));
}
var mhkb = "Click to Change th_is Button's Hotkey";
var mhkb = "Click to Change th_is Label's Hotkey";
var moveHotKeyBtn = new Label (mhkb) {
X = 2,
Y = Pos.Bottom (radioGroup) + 1,
Width = mhkb.Length + 10,
ColorScheme = Colors.TopLevel,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
moveHotKeyBtn.Clicked = () => {
moveHotKeyBtn.Text = MoveHotkey (moveHotKeyBtn.Text);
@@ -225,6 +251,8 @@ namespace UICatalog {
Y = Pos.Bottom (radioGroup) + 1,
Width = muhkb.Length + 30,
ColorScheme = Colors.TopLevel,
HotKeySpecifier = (System.Rune)'_',
CanFocus = true,
};
moveUnicodeHotKeyBtn.Clicked = () => {
moveUnicodeHotKeyBtn.Text = MoveHotkey (moveUnicodeHotKeyBtn.Text);

View File

@@ -10,7 +10,7 @@ namespace UICatalog {
public override void Setup ()
{
Win.X = 10;
Win.Width = Dim.Fill (20);
Win.Width = Dim.Fill (10);
string txt = "Hello world, how are you today? Pretty neat!";
string unicodeSampleText = "A Unicode sentence (пÑРвеÑ) has words.";
@@ -22,8 +22,8 @@ namespace UICatalog {
var multiLineHeight = 5;
foreach (var alignment in alignments) {
singleLines[(int)alignment] = new Label (txt) { TextAlignment = alignment, Width = Dim.Fill (), Height = 1, ColorScheme = Colors.Dialog };
multipleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, Width = Dim.Fill (), Height = multiLineHeight, ColorScheme = Colors.Dialog };
singleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = 1, ColorScheme = Colors.Dialog };
multipleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = multiLineHeight, ColorScheme = Colors.Dialog };
}
// Add a label & text field so we can demo IsDefault
@@ -35,7 +35,7 @@ namespace UICatalog {
var edit = new TextView () {
X = Pos.Right (editLabel) + 1,
Y = Pos.Y (editLabel),
Width = Dim.Fill("Text:".Length + " Unicode Sample".Length + 2),
Width = Dim.Fill ("Text:".Length + " Unicode Sample".Length + 2),
Height = 4,
ColorScheme = Colors.TopLevel,
Text = txt,
@@ -57,7 +57,7 @@ namespace UICatalog {
};
Win.Add (unicodeSample);
var update = new Button ("_Update", is_default: true) {
var update = new Button ("_Update") {
X = Pos.Right (edit) + 1,
Y = Pos.Bottom (edit) - 1,
Clicked = () => {
@@ -69,7 +69,14 @@ namespace UICatalog {
};
Win.Add (update);
var label = new Label ($"Demonstrating single-line (should clip):") { Y = Pos.Bottom (edit) + 1 };
var enableHotKeyCheckBox = new CheckBox ("Enable Hotkey (_)", false) {
X = 0,
Y = Pos.Bottom (edit),
};
Win.Add (enableHotKeyCheckBox);
var label = new Label ($"Demonstrating single-line (should clip):") { Y = Pos.Bottom (enableHotKeyCheckBox) + 1 };
Win.Add (label);
foreach (var alignment in alignments) {
label = new Label ($"{alignment}:") { Y = Pos.Bottom (label) };
@@ -80,7 +87,7 @@ namespace UICatalog {
}
txt += "\nSecond line\n\nFourth Line.";
label = new Label ($"Demonstrating multi-line and word wrap:") { Y = Pos.Bottom (label) + 1 };
label = new Label ($"Demonstrating multi-line and word wrap:") { Y = Pos.Bottom (label) };
Win.Add (label);
foreach (var alignment in alignments) {
label = new Label ($"{alignment}:") { Y = Pos.Bottom (label) };
@@ -89,6 +96,15 @@ namespace UICatalog {
Win.Add (multipleLines [(int)alignment]);
label = multipleLines [(int)alignment];
}
enableHotKeyCheckBox.Toggled += (previous) => {
foreach (var alignment in alignments) {
singleLines [(int)alignment].HotKeySpecifier = previous ? (Rune)0xffff : (Rune)'_';
multipleLines [(int)alignment].HotKeySpecifier = previous ? (Rune)0xffff : (Rune)'_';
}
Win.SetNeedsDisplay ();
Win.LayoutSubviews ();
};
}
}
}

View File

@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Terminal.Gui;
namespace UICatalog {
[ScenarioMetadata (Name: "TextFormatter Demo", Description: "Demos and tests the TextFormatter class.")]
[ScenarioCategory ("Text")]
[ScenarioCategory ("POC")]
class TextFormatterDemo : Scenario {
public override void Init (Toplevel top, ColorScheme colorScheme)
{
Application.Init ();
Top = top;
if (Top == null) {
Top = Application.Top;
}
Win = null;
}
public override void Setup ()
{
Top.Text = "Press CTRL-Q to Quit. This is the Text for the TopLevel View. TextAlignment.Centered was specified. It is intentionally very long to illustrate word wrap.\n" +
"<-- There is a new line here to show a hard line break. You should see this text bleed underneath the subviews, which start at Y = 3.";
Top.TextAlignment = TextAlignment.Centered;
Top.ColorScheme = Colors.Base;
string text = "Hello world, how are you today? Pretty neat!\nSecond line\n\nFourth Line.";
string unicode = "Τὴ γλῶσσα μοῦ ἔδωσαν ἑλληνικὴ\nτὸ σπίτι φτωχικὸ στὶς ἀμμουδιὲς τοῦ Ὁμήρου.\nΜονάχη ἔγνοια ἡ γλῶσσα μου στὶς ἀμμουδιὲς τοῦ Ὁμήρου.";
var unicodeCheckBox = new CheckBox ("Unicode", Top.HotKeySpecifier == (Rune)' ') {
X = 0,
Y = 3,
};
Top.Add (unicodeCheckBox);
var alignments = Enum.GetValues (typeof (Terminal.Gui.TextAlignment)).Cast<Terminal.Gui.TextAlignment> ().ToList ();
var singleLines = new Label [alignments.Count];
var multipleLines = new Label [alignments.Count];
var multiLineHeight = 5;
foreach (var alignment in alignments) {
singleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = 1, ColorScheme = Colors.Dialog };
multipleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = multiLineHeight, ColorScheme = Colors.Dialog };
}
var label = new Label ($"Demonstrating single-line (should clip):") { Y = Pos.Bottom (unicodeCheckBox) + 1 };
Top.Add (label);
foreach (var alignment in alignments) {
label = new Label ($"{alignment}:") { Y = Pos.Bottom (label) };
Top.Add (label);
singleLines [(int)alignment].Y = Pos.Bottom (label);
Top.Add (singleLines [(int)alignment]);
label = singleLines [(int)alignment];
}
label = new Label ($"Demonstrating multi-line and word wrap:") { Y = Pos.Bottom (label) };
Top.Add (label);
foreach (var alignment in alignments) {
label = new Label ($"{alignment}:") { Y = Pos.Bottom (label) };
Top.Add (label);
multipleLines [(int)alignment].Y = Pos.Bottom (label);
Top.Add (multipleLines [(int)alignment]);
label = multipleLines [(int)alignment];
}
unicodeCheckBox.Toggled += (previous) => {
foreach (var alignment in alignments) {
singleLines [(int)alignment].Text = previous ? text : unicode;
multipleLines [(int)alignment].Text = previous ? text : unicode;
}
};
}
}
}

View File

@@ -10,6 +10,9 @@ namespace UICatalog {
class UnicodeInMenu : Scenario {
public override void Setup ()
{
//string text = "Hello world, how are you today? Pretty neat!\nSecond line\n\nFourth Line.";
string unicode = "Τὴ γλῶσσα μοῦ ἔδωσαν ἑλληνικὴ\nτὸ σπίτι φτωχικὸ στὶς ἀμμουδιὲς τοῦ Ὁμήρου.\nΜονάχη ἔγνοια ἡ γλῶσσα μου στὶς ἀμμουδιὲς τοῦ Ὁμήρου.";
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_Файл", new MenuItem [] {
new MenuItem ("_Создать", "Creates new file", null),
@@ -25,23 +28,32 @@ namespace UICatalog {
});
Top.Add (menu);
var label = new Label ("Button:") { X = 0, Y = 1 };
var label = new Label ("Label:") { X = 0, Y = 1 };
Win.Add (label);
var button2 = new Button ("Со_хранить") { X = 15, Y = Pos.Y (label), Width = Dim.Percent (50), };
Win.Add (button2);
var testlabel = new Label ("Стоял _он, дум великих полн") { X = 20, Y = Pos.Y (label), Width = Dim.Percent (50), };
Win.Add (testlabel);
label = new Label ("Label (CanFocus):") { X = Pos.X (label), Y = Pos.Bottom (label) + 1 };
Win.Add (label);
testlabel = new Label ("Стоял &он, дум великих полн") { X = 20, Y = Pos.Y (label), Width = Dim.Percent (50), CanFocus = true, HotKeySpecifier = new System.Rune('&') };
Win.Add (testlabel);
label = new Label ("Button:") { X = Pos.X (label), Y = Pos.Bottom (label) + 1 };
Win.Add (label);
var button = new Button ("A123456789♥♦♣♠JQK") { X = 20, Y = Pos.Y (label) };
Win.Add (button);
label = new Label ("CheckBox:") { X = Pos.X (label), Y = Pos.Bottom (label) + 1 };
Win.Add (label);
var checkBox = new CheckBox (" ~  s  gui.cs   master ↑10") { X = 15, Y = Pos.Y (label), Width = Dim.Percent (50) };
var checkBox = new CheckBox (" ~  s  gui.cs   master ↑10") { X = 20, Y = Pos.Y (label), Width = Dim.Percent (50) };
Win.Add (checkBox);
label = new Label ("ComboBox:") { X = Pos.X (label), Y = Pos.Bottom (label) + 1 };
Win.Add (label);
var comboBox = new ComboBox () {
X = 15,
X = 20,
Y = Pos.Y (label),
Width = Dim.Percent (50),
ColorScheme = Colors.Error
};
comboBox.SetSource (new List<string> () { "item #1", " ~  s  gui.cs   master ↑10", "Со_хранить" });
@@ -51,7 +63,7 @@ namespace UICatalog {
label = new Label ("HexView:") { X = Pos.X (label), Y = Pos.Bottom (label) + 2 };
Win.Add (label);
var hexView = new HexView (new System.IO.MemoryStream (Encoding.ASCII.GetBytes (" ~  s  gui.cs   master ↑10 Со_хранить"))) {
X = 15,
X = 20,
Y = Pos.Y (label),
Width = Dim.Percent (60),
Height = 5
@@ -60,56 +72,39 @@ namespace UICatalog {
label = new Label ("ListView:") { X = Pos.X (label), Y = Pos.Bottom (hexView) + 1 };
Win.Add (label);
var listView = new ListView (new List<string> () { "item #1", " ~  s  gui.cs   master ↑10", "Со_хранить" }) {
X = 15,
var listView = new ListView (new List<string> () { "item #1", " ~  s  gui.cs   master ↑10", "Со_хранить", unicode }) {
X = 20,
Y = Pos.Y (label),
Width = Dim.Percent (60),
Height = 3,
ColorScheme = Colors.Menu
};
Win.Add (listView);
label = new Label ("RadioGroup:") { X = Pos.X (label), Y = Pos.Bottom (listView) + 1 };
Win.Add (label);
var radioGroup = new RadioGroup (new ustring [] { "item #1", " ~  s  gui.cs   master ↑10", "Со_хранить" }, selected: 0) {
X = 15,
X = 20,
Y = Pos.Y (label),
Width = Dim.Percent (60),
ColorScheme = Colors.Menu
};
Win.Add (radioGroup);
label = new Label ("TextField:") { X = Pos.X (label), Y = Pos.Bottom (radioGroup) + 1 };
Win.Add (label);
var textField = new TextField (" ~  s  gui.cs   master ↑10 = Со_хранить") { X = 15, Y = Pos.Y (label), Width = Dim.Percent (60) };
var textField = new TextField (" ~  s  gui.cs   master ↑10 = Со_хранить") { X = 20, Y = Pos.Y (label), Width = Dim.Percent (60) };
Win.Add (textField);
label = new Label ("TextView:") { X = Pos.X (label), Y = Pos.Bottom (textField) + 1 };
Win.Add (label);
var textView = new TextView () {
X = 15,
X = 20,
Y = Pos.Y (label),
Width = Dim.Percent (60),
Height = 3,
ColorScheme = Colors.Menu,
Text = " ~  s  gui.cs   master ↑10\nСо_хранить",
Height = 5,
Text = unicode,
};
Win.Add (textView);
//label = new Label ("Charset:") {
// X = Pos.Percent(75) + 1,
// Y = 0,
//};
//Win.Add (label);
//var charset = new Label ("") {
// X = Pos.Percent(75) + 1,
// Y = Pos.Y (label) + 1,
// Width = Dim.Fill (1),
// Height = Dim.Fill (),
// ColorScheme = Colors.Dialog
//};
//Win.Add (charset);
// Move Win down to row 1, below menu
Win.Y = 1;
Top.LayoutSubviews ();

View File

@@ -1,48 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Terminal.Gui;
namespace UICatalog {
[ScenarioMetadata (Name: "View Text", Description: "Demos and tests View's Text capabilities.")]
[ScenarioCategory ("Text")]
[ScenarioCategory ("POC")]
class ViewWithText : Scenario {
public override void Setup ()
{
Win.Text = "This is the Te_xt for the host Win object. TextAlignment.Centered was specified. It is intentionally very long to illustrate word wrap.\n" +
"<-- There is a new line here to show a hard line break. You should see this text bleed underneath the subviews, which start at Y = 3.";
Win.TextAlignment = TextAlignment.Centered;
#if true
string txt = "Hello world, how are you today? Pretty neat!";
#else
string txt = "Hello world, how are you today? Unicode:  ~  gui.cs  . Neat?";
#endif
var alignments = Enum.GetValues (typeof (Terminal.Gui.TextAlignment)).Cast<Terminal.Gui.TextAlignment> ().ToList ();
var label = new View ($"Demonstrating single-line (should clip!):") { Y = 3 };
Win.Add (label);
foreach (var alignment in alignments) {
label = new Label ($"{alignment}:") { Y = Pos.Bottom (label) };
Win.Add (label);
label = new Label (txt) {
TextAlignment = alignment,
Y = Pos.Bottom (label),
Width = Dim.Fill (),
Height = 1,
ColorScheme = Colors.Dialog,
};
Win.Add (label);
}
txt += "\nSecond line\n\nFourth Line.";
label = new View ($"Demonstrating multi-line and word wrap:") { Y = Pos.Bottom (label) + 1 };
Win.Add (label);
foreach (var alignment in alignments) {
label = new View ($"{alignment}:") { Y = Pos.Bottom (label) };
Win.Add (label);
label = new View (txt) { TextAlignment = alignment, Width = Dim.Fill (), Height = 6, ColorScheme = Colors.Dialog, Y = Pos.Bottom (label) };
Win.Add (label);
}
}
}
}

View File

@@ -1613,6 +1613,10 @@ namespace Terminal.Gui {
Assert.Equal ("se", wrappedLines [1].ToString ());
Assert.Equal ("nte", wrappedLines [2].ToString ());
Assert.Equal ("nce", wrappedLines [3].ToString ());
Assert.Equal ("ha", wrappedLines [4].ToString ());
Assert.Equal ("s", wrappedLines [5].ToString ());
Assert.Equal ("wo", wrappedLines [6].ToString ());
Assert.Equal ("rds", wrappedLines [7].ToString ());
Assert.Equal (".", wrappedLines [^1].ToString ());
maxWidth = 2;