Merge branch 'master' of tig:migueldeicaza/gui.cs

This commit is contained in:
Charlie Kindel
2020-06-03 13:20:17 -06:00
11 changed files with 415 additions and 113 deletions

View File

@@ -335,12 +335,12 @@ static class Demo {
$"{mi.Title.ToString ()} selected. Is from submenu: {mi.GetMenuBarItem ()}", "Ok");
}
static void MenuKeysStyle_Toggled (object sender, EventArgs e)
static void MenuKeysStyle_Toggled (object sender, bool e)
{
menu.UseKeysUpDownAsKeysLeftRight = menuKeysStyle.Checked;
}
static void MenuAutoMouseNav_Toggled (object sender, EventArgs e)
static void MenuAutoMouseNav_Toggled (object sender, bool e)
{
menu.WantMousePositionReports = menuAutoMouseNav.Checked;
}

View File

@@ -929,6 +929,9 @@ namespace Terminal.Gui {
{
var clipRect = new Rect (Point.Empty, frame.Size);
// Invoke DrawContentEvent
OnDrawContent (bounds);
if (subviews != null) {
foreach (var view in subviews) {
if (view.NeedDisplay != null && (!view.NeedDisplay.IsEmpty || view.childNeedsDisplay)) {
@@ -941,7 +944,11 @@ namespace Terminal.Gui {
// Clip the sub-view
var savedClip = ClipToBounds ();
// Draw the subview
view.Redraw (view.Bounds);
// Undo the clip
Driver.Clip = savedClip;
}
view.NeedDisplay = Rect.Empty;
@@ -952,6 +959,31 @@ namespace Terminal.Gui {
ClearNeedsDisplay ();
}
/// <summary>
/// Event invoked when the content area of the View is to be drawn.
/// </summary>
/// <remarks>
/// <para>
/// Will be invoked before any subviews added with <see cref="Add(View)"/> have been drawn.
/// </para>
/// <para>
/// Rect provides the view-relative rectangle describing the currently visible viewport into the <see cref="View"/>.
/// </para>
/// </remarks>
public event EventHandler<Rect> DrawContent;
/// <summary>
/// Enables overrides to draw infinitely scrolled content and/or a background behind added controls.
/// </summary>
/// <param name="viewport">The view-relative rectangle describing the currently visible viewport into the <see cref="View"/></param>
/// <remarks>
/// This method will be called before any subviews added with <see cref="Add(View)"/> have been drawn.
/// </remarks>
public virtual void OnDrawContent (Rect viewport)
{
DrawContent?.Invoke (this, viewport);
}
/// <summary>
/// Causes the specified subview to have focus.
/// </summary>

View File

@@ -78,6 +78,15 @@
* 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!)
* Fixes ScrollView in several key ways. (Thanks @tig!)
* Now supports Computed layout and has constructors that don't require parameters.
* ScrollBarViews are now positioned using Computed layout versus error prone absoulte
* ScrollBarViews now correctly position themselves when one, either, or both are on/off.
* IsVertical is now a public property that does the expected thing when changed
* Mouse handling is better; there's still a bug where the mouse doesn't get grabbed by the ScrollView initially but I think this is a broader problem. I need @BDisp's help on this.
* Supports "infinite scrolling" via the new OnDrawContent/DrawContent event on the View class.
* The Scrolling Scenario was enhanced to demo dynamically adding/removing horizontal/vertical scrollbars (and to prove it was working right).
* The Checkbox.Toggled event is now an EventHandler event and passes previous state. (Thanks @tig!)
0.81:
* Fix ncurses engine for macOS/Linux, it works again

View File

@@ -23,9 +23,16 @@ namespace Terminal.Gui {
/// <remarks>
/// Client code can hook up to this event, it is
/// raised when the <see cref="CheckBox"/> is activated either with
/// the mouse or the keyboard.
/// the mouse or the keyboard. The passed <c>bool</c> contains the previous state.
/// </remarks>
public event EventHandler Toggled;
public event EventHandler<bool> Toggled;
/// <summary>
/// Called when the <see cref="Checked"/> property changes. Invokes the <see cref="Toggled"/> event.
/// </summary>
public virtual void OnToggled (bool previousChecked) {
Toggled?.Invoke (this, previousChecked);
}
/// <summary>
/// Initializes a new instance of <see cref="CheckBox"/> based on the given text, uses Computed layout and sets the height and width.
@@ -122,11 +129,9 @@ namespace Terminal.Gui {
public override bool ProcessKey (KeyEvent kb)
{
if (kb.KeyValue == ' ') {
var previousChecked = Checked;
Checked = !Checked;
if (Toggled != null)
Toggled (this, EventArgs.Empty);
OnToggled (previousChecked);
SetNeedsDisplay ();
return true;
}
@@ -140,11 +145,11 @@ namespace Terminal.Gui {
return false;
SuperView.SetFocus (this);
var previousChecked = Checked;
Checked = !Checked;
OnToggled (previousChecked);
SetNeedsDisplay ();
if (Toggled != null)
Toggled (this, EventArgs.Empty);
return true;
}
}

View File

@@ -6,9 +6,7 @@
//
//
// TODO:
// - Mouse handling in scrollbarview
// - focus in scrollview
// - keyboard handling in scrollview to scroll
// - focus handling in scrollview to auto scroll to focused view
// - Raise events
// - Perhaps allow an option to not display the scrollbar arrow indicators?
@@ -31,13 +29,26 @@ namespace Terminal.Gui {
/// </para>
/// </remarks>
public class ScrollBarView : View {
bool vertical;
int size, position;
bool vertical = false;
int size = 0, position = 0;
/// <summary>
/// The size that this scrollbar represents
/// If set to <c>true</c> this is a vertical scrollbar, otherwise, the scrollbar is horizontal.
/// </summary>
public bool IsVertical {
get => vertical;
set {
vertical = value;
SetNeedsDisplay ();
}
}
/// <summary>
/// The size of content the scrollbar represents.
/// </summary>
/// <value>The size.</value>
/// <remarks>The <see cref="Size"/> is typically the size of the virtual content. E.g. when a Scrollbar is
/// part of a <see cref="ScrollView"/> the Size is set to the appropriate dimension of <see cref="ScrollView.ContentSize"/>.</remarks>
public int Size {
get => size;
set {
@@ -52,7 +63,7 @@ namespace Terminal.Gui {
public event Action ChangedPosition;
/// <summary>
/// The position to show the scrollbar at.
/// The position, relative to <see cref="Size"/>, to set the scrollbar at.
/// </summary>
/// <value>The position.</value>
public int Position {
@@ -70,13 +81,40 @@ namespace Terminal.Gui {
}
/// <summary>
/// Initializes a new instance of the <see cref="Gui.ScrollBarView"/> class.
/// Initializes a new instance of the <see cref="Gui.ScrollBarView"/> class using <see cref="LayoutStyle.Absolute"/> layout.
/// </summary>
/// <param name="rect">Frame for the scrollbar.</param>
public ScrollBarView (Rect rect) : this (rect, 0, 0, false) { }
/// <summary>
/// Initializes a new instance of the <see cref="Gui.ScrollBarView"/> class using <see cref="LayoutStyle.Absolute"/> layout.
/// </summary>
/// <param name="rect">Frame for the scrollbar.</param>
/// <param name="size">The size that this scrollbar represents. Sets the <see cref="Size"/> property.</param>
/// <param name="position">The position within this scrollbar. Sets the <see cref="Position"/> property.</param>
/// <param name="isVertical">If set to <c>true</c> this is a vertical scrollbar, otherwise, the scrollbar is horizontal. Sets the <see cref="IsVertical"/> property.</param>
public ScrollBarView (Rect rect, int size, int position, bool isVertical) : base (rect)
{
Init (size, position, isVertical);
}
/// <summary>
/// Initializes a new instance of the <see cref="Gui.ScrollBarView"/> class using <see cref="LayoutStyle.Computed"/> layout.
/// </summary>
public ScrollBarView () : this (0, 0, false) { }
/// <summary>
/// Initializes a new instance of the <see cref="Gui.ScrollBarView"/> class using <see cref="LayoutStyle.Computed"/> layout.
/// </summary>
/// <param name="size">The size that this scrollbar represents.</param>
/// <param name="position">The position within this scrollbar.</param>
/// <param name="isVertical">If set to <c>true</c> this is a vertical scrollbar, otherwise, the scrollbar is horizontal.</param>
public ScrollBarView (Rect rect, int size, int position, bool isVertical) : base (rect)
public ScrollBarView (int size, int position, bool isVertical) : base ()
{
Init (size, position, isVertical);
}
void Init (int size, int position, bool isVertical)
{
vertical = isVertical;
this.position = position;
@@ -84,11 +122,8 @@ namespace Terminal.Gui {
WantContinuousButtonPressed = true;
}
/// <summary>
/// Redraw the scrollbar
/// </summary>
/// <param name="region">Region to be redrawn.</param>
public override void Redraw(Rect region)
///<inheritdoc cref="Redraw(Rect)"/>
public override void Redraw (Rect region)
{
if (ColorScheme == null)
return;
@@ -113,7 +148,7 @@ namespace Terminal.Gui {
special = Driver.Stipple;
else
special = Driver.Diamond;
Driver.AddRune(special);
Driver.AddRune (special);
}
} else {
bh -= 2;
@@ -125,7 +160,7 @@ namespace Terminal.Gui {
Move (col, Bounds.Height - 1);
Driver.AddRune ('v');
for (int y = 0; y < bh; y++) {
Move (col, y+1);
Move (col, y + 1);
if (y < by1 - 1 || y > by2)
special = Driver.Stipple;
else {
@@ -195,7 +230,7 @@ namespace Terminal.Gui {
}
///<inheritdoc cref="MouseEvent"/>
public override bool MouseEvent(MouseEvent me)
public override bool MouseEvent (MouseEvent me)
{
if (me.Flags != MouseFlags.Button1Pressed && me.Flags != MouseFlags.Button1Clicked &&
!me.Flags.HasFlag (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition))
@@ -239,39 +274,66 @@ namespace Terminal.Gui {
}
/// <summary>
/// Scrollviews are views that present a window into a virtual space where children views are added. Similar to the iOS UIScrollView.
/// Scrollviews are views that present a window into a virtual space where subviews are added. Similar to the iOS UIScrollView.
/// </summary>
/// <remarks>
/// <para>
/// The subviews that are added to this scrollview are offset by the
/// ContentOffset property. The view itself is a window into the
/// space represented by the ContentSize.
/// The subviews that are added to this <see cref="Gui.ScrollView"/> are offset by the
/// <see cref="ContentOffset"/> property. The view itself is a window into the
/// space represented by the <see cref="ContentSize"/>.
/// </para>
/// <para>
///
/// Use the
/// </para>
/// </remarks>
public class ScrollView : View {
View contentView;
View contentView = null;
ScrollBarView vertical, horizontal;
/// <summary>
/// Constructs a ScrollView
/// Initializes a new instance of the <see cref="Gui.ScrollView"/> class using <see cref="LayoutStyle.Absolute"/> positioning.
/// </summary>
/// <param name="frame"></param>
public ScrollView (Rect frame) : base (frame)
{
Init (frame);
}
/// <summary>
/// Initializes a new instance of the <see cref="Gui.ScrollView"/> class using <see cref="LayoutStyle.Computed"/> positioning.
/// </summary>
public ScrollView () : base ()
{
Init (new Rect (0, 0, 0, 0));
}
void Init (Rect frame)
{
contentView = new View (frame);
vertical = new ScrollBarView (new Rect (frame.Width - 1, 0, 1, frame.Height), frame.Height, 0, isVertical: true);
vertical = new ScrollBarView (1, 0, isVertical: true) {
X = Pos.AnchorEnd (1),
Y = 0,
Width = 1,
Height = Dim.Fill (showHorizontalScrollIndicator ? 1 : 0)
};
vertical.ChangedPosition += delegate {
ContentOffset = new Point (ContentOffset.X, vertical.Position);
};
horizontal = new ScrollBarView (new Rect (0, frame.Height-1, frame.Width-1, 1), frame.Width-1, 0, isVertical: false);
horizontal = new ScrollBarView (1, 0, isVertical: false) {
X = 0,
Y = Pos.AnchorEnd (1),
Width = Dim.Fill (showVerticalScrollIndicator ? 1 : 0),
Height = 1
};
horizontal.ChangedPosition += delegate {
ContentOffset = new Point (horizontal.Position, ContentOffset.Y);
};
base.Add (contentView);
CanFocus = true;
MouseEnter += View_MouseEnter;
MouseLeave += View_MouseLeave;
}
Size contentSize;
@@ -305,7 +367,7 @@ namespace Terminal.Gui {
return contentOffset;
}
set {
contentOffset = new Point (-Math.Abs (value.X), -Math.Abs(value.Y));
contentOffset = new Point (-Math.Abs (value.X), -Math.Abs (value.Y));
contentView.Frame = new Rect (contentOffset, contentSize);
vertical.Position = Math.Max (0, -contentOffset.Y);
horizontal.Position = Math.Max (0, -contentOffset.X);
@@ -322,12 +384,9 @@ namespace Terminal.Gui {
if (!IsOverridden (view)) {
view.MouseEnter += View_MouseEnter;
view.MouseLeave += View_MouseLeave;
vertical.MouseEnter += View_MouseEnter;
vertical.MouseLeave += View_MouseLeave;
horizontal.MouseEnter += View_MouseEnter;
horizontal.MouseLeave += View_MouseLeave;
}
contentView.Add (view);
SetNeedsLayout ();
}
void View_MouseLeave (object sender, MouseEventEventArgs e)
@@ -359,11 +418,17 @@ namespace Terminal.Gui {
return;
showHorizontalScrollIndicator = value;
SetNeedsDisplay ();
if (value)
SetNeedsLayout ();
if (value) {
base.Add (horizontal);
else
horizontal.MouseEnter += View_MouseEnter;
horizontal.MouseLeave += View_MouseLeave;
} else {
Remove (horizontal);
horizontal.MouseEnter -= View_MouseEnter;
horizontal.MouseLeave -= View_MouseLeave;
}
vertical.Height = Dim.Fill (showHorizontalScrollIndicator ? 1 : 0);
}
}
@@ -372,9 +437,9 @@ namespace Terminal.Gui {
/// </summary>
/// <remarks>
/// </remarks>
public override void RemoveAll()
public override void RemoveAll ()
{
contentView.RemoveAll();
contentView.RemoveAll ();
}
/// <summary>
@@ -388,31 +453,46 @@ namespace Terminal.Gui {
return;
showVerticalScrollIndicator = value;
SetNeedsDisplay ();
if (value)
SetNeedsLayout ();
if (value) {
base.Add (vertical);
else
vertical.MouseEnter += View_MouseEnter;
vertical.MouseLeave += View_MouseLeave;
} else {
Remove (vertical);
vertical.MouseEnter -= View_MouseEnter;
vertical.MouseLeave -= View_MouseLeave;
}
horizontal.Width = Dim.Fill (showVerticalScrollIndicator ? 1 : 0);
}
}
/// <summary>
/// This event is raised when the contents have scrolled
/// </summary>
//public event Action<ScrollView> Scrolled;
public override void Redraw(Rect region)
/// <inheritdoc cref="Redraw(Rect)"/>
public override void Redraw (Rect region)
{
SetViewsNeedsDisplay ();
Driver.SetAttribute (ColorScheme.Normal);
SetViewsNeedsDisplay ();
Clear ();
var savedClip = ClipToBounds ();
OnDrawContent (new Rect (ContentOffset,
new Size (Bounds.Width - (ShowVerticalScrollIndicator ? 1 : 0),
Bounds.Height - (ShowHorizontalScrollIndicator ? 1 : 0))));
contentView.Redraw (contentView.Bounds);
Driver.Clip = savedClip;
vertical.Redraw (vertical.Bounds);
horizontal.Redraw (horizontal.Bounds);
Driver.Clip = savedClip;
if (ShowVerticalScrollIndicator) {
vertical.Redraw (vertical.Bounds);
}
if (ShowHorizontalScrollIndicator) {
horizontal.Redraw (horizontal.Bounds);
}
// Fill in the bottom left corner
if (ShowVerticalScrollIndicator && ShowHorizontalScrollIndicator) {
AddRune (Bounds.Width - 1, Bounds.Height - 1, ' ');
}
Driver.SetAttribute (ColorScheme.Normal);
}
@@ -424,7 +504,7 @@ namespace Terminal.Gui {
}
///<inheritdoc cref="PositionCursor"/>
public override void PositionCursor()
public override void PositionCursor ()
{
if (InternalSubviews.Count == 0)
Driver.Move (0, 0);
@@ -490,7 +570,7 @@ namespace Terminal.Gui {
}
///<inheritdoc cref="ProcessKey"/>
public override bool ProcessKey(KeyEvent kb)
public override bool ProcessKey (KeyEvent kb)
{
if (base.ProcessKey (kb))
return true;

View File

@@ -771,32 +771,12 @@ namespace Terminal.Gui {
case Key.ControlN:
case Key.CursorDown:
if (currentRow + 1 < model.Count) {
if (columnTrack == -1)
columnTrack = currentColumn;
currentRow++;
if (currentRow >= topRow + Frame.Height) {
topRow++;
SetNeedsDisplay ();
}
TrackColumn ();
PositionCursor ();
}
MoveDown ();
break;
case Key.ControlP:
case Key.CursorUp:
if (currentRow > 0) {
if (columnTrack == -1)
columnTrack = currentColumn;
currentRow--;
if (currentRow < topRow) {
topRow--;
SetNeedsDisplay ();
}
TrackColumn ();
PositionCursor ();
}
MoveUp ();
break;
case Key.ControlF:
@@ -1024,6 +1004,18 @@ namespace Terminal.Gui {
SetNeedsDisplay (new Rect (0, currentRow - topRow, 2, Frame.Height));
break;
case Key.CtrlMask | Key.End:
currentRow = model.Count;
TrackColumn ();
PositionCursor ();
break;
case Key.CtrlMask | Key.Home:
currentRow = 0;
TrackColumn ();
PositionCursor ();
break;
default:
// Ignore control characters and other special keys
if (kb.Key < Key.Space || kb.Key > Key.CharMask)
@@ -1043,6 +1035,36 @@ namespace Terminal.Gui {
return true;
}
private void MoveUp ()
{
if (currentRow > 0) {
if (columnTrack == -1)
columnTrack = currentColumn;
currentRow--;
if (currentRow < topRow) {
topRow--;
SetNeedsDisplay ();
}
TrackColumn ();
PositionCursor ();
}
}
private void MoveDown ()
{
if (currentRow + 1 < model.Count) {
if (columnTrack == -1)
columnTrack = currentColumn;
currentRow++;
if (currentRow >= topRow + Frame.Height) {
topRow++;
SetNeedsDisplay ();
}
TrackColumn ();
PositionCursor ();
}
}
IEnumerable<(int col, int row, Rune rune)> ForwardIterator (int col, int row)
{
if (col < 0 || row < 0)
@@ -1173,28 +1195,37 @@ namespace Terminal.Gui {
///<inheritdoc cref="MouseEvent"/>
public override bool MouseEvent (MouseEvent ev)
{
if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked)) {
if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked) &&
!ev.Flags.HasFlag (MouseFlags.WheeledDown) && !ev.Flags.HasFlag (MouseFlags.WheeledUp)) {
return false;
}
if (!HasFocus)
SuperView.SetFocus (this);
if (model.Count > 0) {
var maxCursorPositionableLine = (model.Count - 1) - topRow;
if (ev.Y > maxCursorPositionableLine) {
currentRow = maxCursorPositionableLine;
} else {
currentRow = ev.Y + topRow;
if (ev.Flags == MouseFlags.Button1Clicked) {
if (model.Count > 0) {
var maxCursorPositionableLine = (model.Count - 1) - topRow;
if (ev.Y > maxCursorPositionableLine) {
currentRow = maxCursorPositionableLine;
} else {
currentRow = ev.Y + topRow;
}
var r = GetCurrentLine ();
if (ev.X - leftColumn >= r.Count)
currentColumn = r.Count - leftColumn;
else
currentColumn = ev.X - leftColumn;
}
var r = GetCurrentLine ();
if (ev.X - leftColumn >= r.Count)
currentColumn = r.Count - leftColumn;
else
currentColumn = ev.X - leftColumn;
PositionCursor ();
} else if (ev.Flags == MouseFlags.WheeledDown) {
lastWasKill = false;
MoveDown ();
} else if (ev.Flags == MouseFlags.WheeledUp) {
lastWasKill = false;
MoveUp ();
}
PositionCursor ();
return true;
}
}

View File

@@ -118,6 +118,16 @@ namespace UICatalog {
};
Win.Add (moveBtn);
// Demonstrates how changing the View.Frame property can SIZE Views (#583)
y += 2;
var sizeBtn = new Button (10, y, "Size This Button via Frame") {
ColorScheme = Colors.Error,
};
moveBtn.Clicked = () => {
sizeBtn.Frame = new Rect (sizeBtn.Frame.X, sizeBtn.Frame.Y, sizeBtn.Frame.Width + 5, sizeBtn.Frame.Height);
};
Win.Add (sizeBtn);
// Demo changing hotkey
ustring MoveHotkey (ustring txt)
{

View File

@@ -0,0 +1,123 @@
using NStack;
using System.Collections.Generic;
using System.Text;
using Terminal.Gui;
namespace UICatalog {
/// <summary>
/// This Scenario demonstrates building a custom control (a class deriving from View) that:
/// - Provides a simple "Character Map" application (like Windows' charmap.exe).
/// - Helps test unicode character rendering in Terminal.Gui
/// - Illustrates how to use ScrollView to do infinite scrolling
/// </summary>
[ScenarioMetadata (Name: "Character Map", Description: "Illustrates a custom control and Unicode")]
[ScenarioCategory ("Text")]
[ScenarioCategory ("Controls")]
class CharacterMap : Scenario {
public override void Setup ()
{
var charMap = new CharMap () { X = 0, Y = 0, Width = CharMap.RowWidth + 2, Height = Dim.Fill(), Start = 0x2500,
ColorScheme = Colors.Dialog};
Win.Add (charMap);
Button CreateBlock(Window win, ustring title, int start, int end, View align)
{
var button = new Button ($"{title} (U+{start:x5}-{end:x5})") {
X = Pos.X (align),
Y = Pos.Bottom (align),
Clicked = () => {
charMap.Start = start;
},
};
win.Add (button);
return button;
};
var label = new Label ("Unicode Blocks:") { X = Pos.Right (charMap) + 2, Y = Pos.Y (charMap) };
Win.Add (label);
var button = CreateBlock (Win, "Currency Symbols", 0x20A0, 0x20CF, label);
button = CreateBlock (Win, "Letterlike Symbols", 0x2100, 0x214F, button);
button = CreateBlock (Win, "Arrows", 0x2190, 0x21ff, button);
button = CreateBlock (Win, "Mathematical symbols", 0x2200, 0x22ff, button);
button = CreateBlock (Win, "Miscellaneous Technical", 0x2300, 0x23ff, button);
button = CreateBlock (Win, "Box Drawing & Geometric Shapes", 0x2500, 0x25ff, button);
button = CreateBlock (Win, "Miscellaneous Symbols", 0x2600, 0x26ff, button);
button = CreateBlock (Win, "Dingbats", 0x2700, 0x27ff, button);
button = CreateBlock (Win, "Braille", 0x2800, 0x28ff, button);
button = CreateBlock (Win, "Miscellaneous Symbols and Arrows", 0x2b00, 0x2bff, button);
button = CreateBlock (Win, "Alphabetic Presentation Forms", 0xFB00, 0xFb4f, button);
button = CreateBlock (Win, "Cuneiform Numbers and Punctuation[1", 0x12400, 0x1240f, button);
button = CreateBlock (Win, "Chess Symbols", 0x1FA00, 0x1FA0f, button);
button = CreateBlock (Win, "End", CharMap.MaxCodePointVal - 16, CharMap.MaxCodePointVal, button);
}
}
class CharMap : ScrollView {
/// <summary>
/// Specifies the starting offset for the character map. The default is 0x2500
/// which is the Box Drawing characters.
/// </summary>
public int Start {
get => _start;
set {
_start = value;
ContentOffset = new Point (0, _start / 16);
SetNeedsDisplay ();
}
}
int _start = 0x2500;
public static int MaxCodePointVal => 0xE0FFF;
// Row Header + space + (space + char + space)
public static int RowHeaderWidth => $"U+{MaxCodePointVal:x5}".Length;
public static int RowWidth => RowHeaderWidth + 1 + (" c ".Length * 16);
public CharMap ()
{
ContentSize = new Size (CharMap.RowWidth, MaxCodePointVal / 16);
ShowVerticalScrollIndicator = true;
ShowHorizontalScrollIndicator = false;
LayoutComplete += (sender, args) => {
if (Bounds.Width <= RowWidth) {
ShowHorizontalScrollIndicator = true;
} else {
ShowHorizontalScrollIndicator = false;
}
};
DrawContent += CharMap_DrawContent;
}
#if true
private void CharMap_DrawContent (object sender, Rect viewport)
{
for (int header = 0; header < 16; header++) {
Move (viewport.X + RowHeaderWidth + 1 + (header * 3), 0);
Driver.AddStr ($" {header:x} ");
}
for (int row = 0; row < viewport.Height - 1; row++) {
int val = (-viewport.Y + row) * 16;
if (val < MaxCodePointVal) {
var rowLabel = $"U+{val / 16:x4}x";
Move (0, row + 1);
Driver.AddStr (rowLabel);
for (int col = 0; col < 16; col++) {
Move (viewport.X + RowHeaderWidth + 1 + (col * 3), 0 + row + 1);
Driver.AddStr ($" {(char)((-viewport.Y + row) * 16 + col)} ");
}
}
}
}
#else
public override void OnDrawContent (Rect viewport)
{
CharMap_DrawContent(this, viewport);
base.OnDrawContent (viewport);
}
#endif
}
}

View File

@@ -95,12 +95,13 @@ namespace UICatalog {
Win.Add (label);
// BUGBUG: ScrollView only supports Absolute Positioning (#72)
var scrollView = new ScrollView (new Rect (2, 2, 50, 20));
scrollView.ColorScheme = Colors.TopLevel;
scrollView.ContentSize = new Size (200, 100);
//ContentOffset = new Point (0, 0),
scrollView.ShowVerticalScrollIndicator = true;
scrollView.ShowHorizontalScrollIndicator = true;
var scrollView = new ScrollView (new Rect (2, 2, 50, 20)) {
ColorScheme = Colors.TopLevel,
ContentSize = new Size (200, 100),
//ContentOffset = new Point (0, 0),
ShowVerticalScrollIndicator = true,
ShowHorizontalScrollIndicator = true,
};
const string rule = "|123456789";
var horizontalRuler = new Label ("") {
@@ -177,13 +178,31 @@ namespace UICatalog {
};
scrollView.Add (anchorButton);
var hCheckBox = new CheckBox ("Horizontal Scrollbar", scrollView.ShowHorizontalScrollIndicator) {
X = Pos.X(scrollView),
Y = Pos.Bottom(scrollView) + 1,
};
hCheckBox.Toggled += (sender, previousChecked) => {
scrollView.ShowHorizontalScrollIndicator = ((CheckBox)sender).Checked;
};
Win.Add (hCheckBox);
var vCheckBox = new CheckBox ("Vertical Scrollbar", scrollView.ShowVerticalScrollIndicator) {
X = Pos.Right (hCheckBox) + 3,
Y = Pos.Bottom (scrollView) + 1,
};
vCheckBox.Toggled += (sender, previousChecked) => {
scrollView.ShowVerticalScrollIndicator = ((CheckBox)sender).Checked;
};
Win.Add (vCheckBox);
var scrollView2 = new ScrollView (new Rect (55, 2, 20, 8)) {
ContentSize = new Size (20, 50),
//ContentOffset = new Point (0, 0),
ShowVerticalScrollIndicator = true,
ShowHorizontalScrollIndicator = true
};
scrollView2.Add (new Filler(new Rect (0, 0, 60, 40)));
scrollView2.Add (new Filler (new Rect (0, 0, 60, 40)));
// This is just to debug the visuals of the scrollview when small
var scrollView3 = new ScrollView (new Rect (55, 15, 3, 3)) {
@@ -205,7 +224,7 @@ namespace UICatalog {
var progress = new ProgressBar ();
progress.X = 5;
progress.Y = Pos.AnchorEnd (3);
progress.Y = Pos.AnchorEnd (2);
progress.Width = 50;
bool timer (MainLoop caller)
{

View File

@@ -6,7 +6,7 @@ using Terminal.Gui;
namespace UICatalog {
[ScenarioMetadata (Name: "Text Alignment", Description: "Demonstrates text alignment")]
[ScenarioCategory ("Text")]
class TextAlignment : Scenario {
class TextAlignments : Scenario {
public override void Setup ()
{
int i = 1;

View File

@@ -10,8 +10,6 @@ namespace UICatalog {
class UnicodeInMenu : Scenario {
public override void Setup ()
{
const int margin = 1;
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_Файл", new MenuItem [] {
new MenuItem ("_Создать", "Creates new file", null),
@@ -27,14 +25,9 @@ namespace UICatalog {
});
Top.Add (menu);
var label = new Label ("Button:") { X = margin, Y = margin };
var label = new Label ("Button:") { X = 0, Y = 1 };
Win.Add (label);
var button = new Button (" ~  s  gui.cs   master ↑10") { X = 15, Y = Pos.Y (label) };
Win.Add (button);
label = new Label ("Button:") { X = Pos.X (label), Y = Pos.Bottom (label) + 1 };
Win.Add (label);
var button2 = new Button ("Со_хранить") { X = 15, Y = Pos.Y (label), Width = Dim.Percent (50) };
var button2 = new Button ("Со_хранить") { X = 15, Y = Pos.Y (label), Width = Dim.Percent (50), };
Win.Add (button2);
label = new Label ("CheckBox:") { X = Pos.X (label), Y = Pos.Bottom (label) + 1 };