mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-28 08:47:59 +01:00
Merge branch 'master' of tig:migueldeicaza/gui.cs
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
123
UICatalog/Scenarios/CharacterMap.cs
Normal file
123
UICatalog/Scenarios/CharacterMap.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user