mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
ScrollView
This commit is contained in:
@@ -1,7 +1,167 @@
|
||||
using System;
|
||||
//
|
||||
// ScrollView.cs: ScrollView and ScrollBarView views.
|
||||
//
|
||||
// Authors:
|
||||
// Miguel de Icaza (miguel@gnome.org)
|
||||
//
|
||||
//
|
||||
// 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
|
||||
using System;
|
||||
namespace Terminal.Gui {
|
||||
/// <summary>
|
||||
///
|
||||
/// ScrollBarViews are views that display a 1-character scrollbar, either horizontal or vertical
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The scrollbar is drawn to be a representation of the Size, assuming that the
|
||||
/// scroll position is set at Position.
|
||||
/// </remarks>
|
||||
public class ScrollBarView : View {
|
||||
bool vertical;
|
||||
int size, position;
|
||||
|
||||
/// <summary>
|
||||
/// The size that this scrollbar represents
|
||||
/// </summary>
|
||||
/// <value>The size.</value>
|
||||
public int Size {
|
||||
get => size;
|
||||
set {
|
||||
size = value;
|
||||
SetNeedsDisplay ();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The position to show the scrollbar at.
|
||||
/// </summary>
|
||||
/// <value>The position.</value>
|
||||
public int Position {
|
||||
get => position;
|
||||
set {
|
||||
position = value;
|
||||
SetNeedsDisplay ();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:Terminal.Gui.ScrollBarView"/> class.
|
||||
/// </summary>
|
||||
/// <param name="rect">Frame for the scrollbar.</param>
|
||||
/// <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, otherwize, the scrollbar is horizontal.</param>
|
||||
public ScrollBarView (Rect rect, int size, int position, bool isVertical) : base (rect)
|
||||
{
|
||||
vertical = isVertical;
|
||||
this.position = position;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redraw the scrollbar
|
||||
/// </summary>
|
||||
/// <param name="region">Region to be redrawn.</param>
|
||||
public override void Redraw(Rect region)
|
||||
{
|
||||
Driver.SetAttribute (ColorScheme.Normal);
|
||||
|
||||
if (vertical) {
|
||||
if (region.Right < Bounds.Width - 1)
|
||||
return;
|
||||
|
||||
var col = Bounds.Width - 1;
|
||||
var bh = Bounds.Height;
|
||||
SpecialChar special;
|
||||
|
||||
if (bh < 3) {
|
||||
var by1 = position * bh / Size;
|
||||
var by2 = (position + bh) * bh / Size;
|
||||
|
||||
for (int y = 0; y < bh; y++) {
|
||||
Move (col, y);
|
||||
if (y < by1 || y > by2)
|
||||
special = SpecialChar.Stipple;
|
||||
else
|
||||
special = SpecialChar.Diamond;
|
||||
Driver.AddSpecial (special);
|
||||
}
|
||||
} else {
|
||||
bh -= 2;
|
||||
var by1 = position * bh / Size;
|
||||
var by2 = (position + bh) * bh / Size;
|
||||
|
||||
|
||||
Move (col, 0);
|
||||
Driver.AddRune ('^');
|
||||
Move (col, Bounds.Height - 1);
|
||||
Driver.AddRune ('v');
|
||||
for (int y = 0; y < bh; y++) {
|
||||
Move (col, y+1);
|
||||
|
||||
if (y < by1 || y > by2)
|
||||
special = SpecialChar.Stipple;
|
||||
else {
|
||||
if (by2 - by1 == 0)
|
||||
special = SpecialChar.Diamond;
|
||||
else {
|
||||
if (y == by1)
|
||||
special = SpecialChar.TopTee;
|
||||
else if (y == by2)
|
||||
special = SpecialChar.BottomTee;
|
||||
else
|
||||
special = SpecialChar.VLine;
|
||||
}
|
||||
}
|
||||
Driver.AddSpecial (special);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (region.Bottom < Bounds.Height - 1)
|
||||
return;
|
||||
|
||||
var row = Bounds.Height - 1;
|
||||
var bw = Bounds.Width;
|
||||
if (bw < 3) {
|
||||
} else {
|
||||
bw -= 2;
|
||||
var bx1 = position * bw / Size;
|
||||
var bx2 = (position + bw) * bw / Size;
|
||||
|
||||
Move (0, row);
|
||||
Driver.AddRune ('<');
|
||||
|
||||
for (int x = 0; x < bw; x++) {
|
||||
SpecialChar special;
|
||||
|
||||
if (x < bx1 || x > bx2) {
|
||||
special = SpecialChar.Stipple;
|
||||
} else {
|
||||
if (bx2 - bx1 == 0)
|
||||
special = SpecialChar.Diamond;
|
||||
else {
|
||||
if (x == bx1)
|
||||
special = SpecialChar.LeftTee;
|
||||
else if (x == bx2)
|
||||
special = SpecialChar.RightTee;
|
||||
else
|
||||
special = SpecialChar.HLine;
|
||||
}
|
||||
}
|
||||
Driver.AddSpecial (special);
|
||||
}
|
||||
Driver.AddRune ('>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrollviews are views that present a window into a virtual space where children views are added. Similar to the iOS UIScrollView.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
@@ -15,11 +175,15 @@ namespace Terminal.Gui {
|
||||
/// </remarks>
|
||||
public class ScrollView : View {
|
||||
View contentView;
|
||||
ScrollBarView vertical, horizontal;
|
||||
|
||||
public ScrollView (Rect frame) : base (frame)
|
||||
{
|
||||
contentView = new View (frame);
|
||||
vertical = new ScrollBarView (new Rect (frame.Width - 1, 0, 1, frame.Height), frame.Height, 0, isVertical: true);
|
||||
horizontal = new ScrollBarView (new Rect (0, frame.Height-1, frame.Width-1, 1), frame.Width-1, 0, isVertical: false);
|
||||
base.Add (contentView);
|
||||
CanFocus = true;
|
||||
}
|
||||
|
||||
Size contentSize;
|
||||
@@ -38,6 +202,8 @@ namespace Terminal.Gui {
|
||||
set {
|
||||
contentSize = value;
|
||||
contentView.Frame = new Rect (contentOffset, value);
|
||||
vertical.Size = contentSize.Height;
|
||||
horizontal.Size = contentSize.Width;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +218,8 @@ namespace Terminal.Gui {
|
||||
set {
|
||||
contentOffset = new Point (-value.X, -value.Y);
|
||||
contentView.Frame = new Rect (contentOffset, contentSize);
|
||||
vertical.Position = Math.Max (0, -contentOffset.Y);
|
||||
horizontal.Position = Math.Max (0, -contentOffset.X);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +239,15 @@ namespace Terminal.Gui {
|
||||
public bool ShowHorizontalScrollIndicator {
|
||||
get => showHorizontalScrollIndicator;
|
||||
set {
|
||||
if (value == showHorizontalScrollIndicator)
|
||||
return;
|
||||
|
||||
showHorizontalScrollIndicator = value;
|
||||
SetNeedsDisplay ();
|
||||
if (value)
|
||||
base.Add (horizontal);
|
||||
else
|
||||
Remove (horizontal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +259,15 @@ namespace Terminal.Gui {
|
||||
public bool ShowVerticalScrollIndicator {
|
||||
get => showVerticalScrollIndicator;
|
||||
set {
|
||||
if (value == showVerticalScrollIndicator)
|
||||
return;
|
||||
|
||||
showVerticalScrollIndicator = value;
|
||||
SetNeedsDisplay ();
|
||||
if (value)
|
||||
base.Add (vertical);
|
||||
else
|
||||
Remove (vertical);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,70 +280,16 @@ namespace Terminal.Gui {
|
||||
{
|
||||
var oldClip = ClipToBounds ();
|
||||
base.Redraw(region);
|
||||
Attribute last = ColorScheme.Normal;
|
||||
Driver.SetAttribute (last);
|
||||
|
||||
void SetColor (Attribute a)
|
||||
{
|
||||
if (a != last)
|
||||
Driver.SetAttribute (a);
|
||||
last = a;
|
||||
}
|
||||
|
||||
Driver.Clip = oldClip;
|
||||
Driver.SetAttribute (ColorScheme.Normal);
|
||||
}
|
||||
|
||||
if (true || ShowVerticalScrollIndicator) {
|
||||
var bh = Bounds.Height;
|
||||
var by1 = -contentOffset.Y * bh/ contentSize.Height;
|
||||
var by2 = (-contentOffset.Y+bh) * bh/ contentSize.Height;
|
||||
|
||||
for (int y = 0; y < bh; y++) {
|
||||
Move (Bounds.Width - 1, y);
|
||||
SpecialChar special;
|
||||
|
||||
if (y < by1 || y > by2)
|
||||
special = SpecialChar.Stipple;
|
||||
else {
|
||||
if (by2 - by1 == 0)
|
||||
special = SpecialChar.Diamond;
|
||||
else {
|
||||
if (y == by1)
|
||||
special = SpecialChar.TopTee;
|
||||
else if (y == by2)
|
||||
special = SpecialChar.BottomTee;
|
||||
else
|
||||
special = SpecialChar.VLine;
|
||||
}
|
||||
}
|
||||
Driver.AddSpecial (special);
|
||||
}
|
||||
}
|
||||
if (true || ShowHorizontalScrollIndicator){
|
||||
var bw = Bounds.Width;
|
||||
var bx1 = -contentOffset.X * bw / contentSize.Width;
|
||||
var bx2 = (-contentOffset.X + bw) * bw / contentSize.Width;
|
||||
|
||||
Move (0, Bounds.Height - 1);
|
||||
for (int x = 0; x < bw; x++) {
|
||||
SpecialChar special;
|
||||
|
||||
if (x < bx1 || x > bx2){
|
||||
special = SpecialChar.Stipple;
|
||||
} else {
|
||||
if (bx2 - bx1 == 0)
|
||||
special = SpecialChar.Diamond;
|
||||
else {
|
||||
if (x == bx1)
|
||||
special = SpecialChar.LeftTee;
|
||||
else if (x == bx2)
|
||||
special = SpecialChar.RightTee;
|
||||
else
|
||||
special = SpecialChar.HLine;
|
||||
}
|
||||
}
|
||||
Driver.AddSpecial (special);
|
||||
}
|
||||
}
|
||||
public override void PositionCursor()
|
||||
{
|
||||
if (Subviews.Count == 0)
|
||||
Driver.Move (0, 0);
|
||||
else
|
||||
base.PositionCursor ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4
demo.cs
4
demo.cs
@@ -67,7 +67,9 @@ class Demo {
|
||||
{
|
||||
var scrollView = new ScrollView (new Rect (50, 10, 20, 8)) {
|
||||
ContentSize = new Size (100, 100),
|
||||
ContentOffset = new Point (5, -2)
|
||||
ContentOffset = new Point (5, -2),
|
||||
ShowVerticalScrollIndicator = true,
|
||||
ShowHorizontalScrollIndicator = true
|
||||
};
|
||||
|
||||
//scrollView.Add (new Box10x (0, 0));
|
||||
|
||||
Reference in New Issue
Block a user