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 {
|
namespace Terminal.Gui {
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>
|
/// <para>
|
||||||
@@ -15,11 +175,15 @@ namespace Terminal.Gui {
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class ScrollView : View {
|
public class ScrollView : View {
|
||||||
View contentView;
|
View contentView;
|
||||||
|
ScrollBarView vertical, horizontal;
|
||||||
|
|
||||||
public ScrollView (Rect frame) : base (frame)
|
public ScrollView (Rect frame) : base (frame)
|
||||||
{
|
{
|
||||||
contentView = new View (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);
|
base.Add (contentView);
|
||||||
|
CanFocus = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Size contentSize;
|
Size contentSize;
|
||||||
@@ -38,6 +202,8 @@ namespace Terminal.Gui {
|
|||||||
set {
|
set {
|
||||||
contentSize = value;
|
contentSize = value;
|
||||||
contentView.Frame = new Rect (contentOffset, value);
|
contentView.Frame = new Rect (contentOffset, value);
|
||||||
|
vertical.Size = contentSize.Height;
|
||||||
|
horizontal.Size = contentSize.Width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +218,8 @@ namespace Terminal.Gui {
|
|||||||
set {
|
set {
|
||||||
contentOffset = new Point (-value.X, -value.Y);
|
contentOffset = new Point (-value.X, -value.Y);
|
||||||
contentView.Frame = new Rect (contentOffset, contentSize);
|
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 {
|
public bool ShowHorizontalScrollIndicator {
|
||||||
get => showHorizontalScrollIndicator;
|
get => showHorizontalScrollIndicator;
|
||||||
set {
|
set {
|
||||||
|
if (value == showHorizontalScrollIndicator)
|
||||||
|
return;
|
||||||
|
|
||||||
showHorizontalScrollIndicator = value;
|
showHorizontalScrollIndicator = value;
|
||||||
SetNeedsDisplay ();
|
SetNeedsDisplay ();
|
||||||
|
if (value)
|
||||||
|
base.Add (horizontal);
|
||||||
|
else
|
||||||
|
Remove (horizontal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,8 +259,15 @@ namespace Terminal.Gui {
|
|||||||
public bool ShowVerticalScrollIndicator {
|
public bool ShowVerticalScrollIndicator {
|
||||||
get => showVerticalScrollIndicator;
|
get => showVerticalScrollIndicator;
|
||||||
set {
|
set {
|
||||||
|
if (value == showVerticalScrollIndicator)
|
||||||
|
return;
|
||||||
|
|
||||||
showVerticalScrollIndicator = value;
|
showVerticalScrollIndicator = value;
|
||||||
SetNeedsDisplay ();
|
SetNeedsDisplay ();
|
||||||
|
if (value)
|
||||||
|
base.Add (vertical);
|
||||||
|
else
|
||||||
|
Remove (vertical);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,70 +280,16 @@ namespace Terminal.Gui {
|
|||||||
{
|
{
|
||||||
var oldClip = ClipToBounds ();
|
var oldClip = ClipToBounds ();
|
||||||
base.Redraw(region);
|
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.Clip = oldClip;
|
||||||
|
Driver.SetAttribute (ColorScheme.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
if (true || ShowVerticalScrollIndicator) {
|
public override void PositionCursor()
|
||||||
var bh = Bounds.Height;
|
{
|
||||||
var by1 = -contentOffset.Y * bh/ contentSize.Height;
|
if (Subviews.Count == 0)
|
||||||
var by2 = (-contentOffset.Y+bh) * bh/ contentSize.Height;
|
Driver.Move (0, 0);
|
||||||
|
else
|
||||||
for (int y = 0; y < bh; y++) {
|
base.PositionCursor ();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
demo.cs
4
demo.cs
@@ -67,7 +67,9 @@ class Demo {
|
|||||||
{
|
{
|
||||||
var scrollView = new ScrollView (new Rect (50, 10, 20, 8)) {
|
var scrollView = new ScrollView (new Rect (50, 10, 20, 8)) {
|
||||||
ContentSize = new Size (100, 100),
|
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));
|
//scrollView.Add (new Box10x (0, 0));
|
||||||
|
|||||||
Reference in New Issue
Block a user