diff --git a/Terminal.Gui/Views/ScrollView.cs b/Terminal.Gui/Views/ScrollView.cs
index 059c5574f..98ae6c0f8 100644
--- a/Terminal.Gui/Views/ScrollView.cs
+++ b/Terminal.Gui/Views/ScrollView.cs
@@ -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 {
///
- ///
+ /// ScrollBarViews are views that display a 1-character scrollbar, either horizontal or vertical
+ ///
+ ///
+ /// The scrollbar is drawn to be a representation of the Size, assuming that the
+ /// scroll position is set at Position.
+ ///
+ public class ScrollBarView : View {
+ bool vertical;
+ int size, position;
+
+ ///
+ /// The size that this scrollbar represents
+ ///
+ /// The size.
+ public int Size {
+ get => size;
+ set {
+ size = value;
+ SetNeedsDisplay ();
+ }
+ }
+
+ ///
+ /// The position to show the scrollbar at.
+ ///
+ /// The position.
+ public int Position {
+ get => position;
+ set {
+ position = value;
+ SetNeedsDisplay ();
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Frame for the scrollbar.
+ /// The size that this scrollbar represents.
+ /// The position within this scrollbar.
+ /// If set to true this is a vertical scrollbar, otherwize, the scrollbar is horizontal.
+ public ScrollBarView (Rect rect, int size, int position, bool isVertical) : base (rect)
+ {
+ vertical = isVertical;
+ this.position = position;
+ this.size = size;
+ }
+
+ ///
+ /// Redraw the scrollbar
+ ///
+ /// Region to be redrawn.
+ 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 ('>');
+ }
+ }
+ }
+ }
+
+ ///
+ /// Scrollviews are views that present a window into a virtual space where children views are added. Similar to the iOS UIScrollView.
///
///
///
@@ -15,11 +175,15 @@ namespace Terminal.Gui {
///
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 ();
}
}
}
diff --git a/demo.cs b/demo.cs
index 9637a4d0f..ef4f4b331 100644
--- a/demo.cs
+++ b/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));