diff --git a/Terminal.Gui/Core/TextFormatter.cs b/Terminal.Gui/Core/TextFormatter.cs
index d485cf353..920575b83 100644
--- a/Terminal.Gui/Core/TextFormatter.cs
+++ b/Terminal.Gui/Core/TextFormatter.cs
@@ -1145,20 +1145,17 @@ namespace Terminal.Gui {
var start = isVertical ? bounds.Top : bounds.Left;
var size = isVertical ? bounds.Height : bounds.Width;
var current = start;
- var startX = start < 0
- ? start
- : isVertical ? start - y : start - x;
var savedClip = Application.Driver?.Clip;
if (Application.Driver != null && containerBounds != default) {
Application.Driver.Clip = containerBounds == default
? bounds
: new Rect (Math.Max (containerBounds.X, bounds.X),
Math.Max (containerBounds.Y, bounds.Y),
- Math.Min (containerBounds.Width, containerBounds.Right - bounds.Left),
- Math.Min (containerBounds.Height, containerBounds.Bottom - bounds.Top));
+ Math.Max (Math.Min (containerBounds.Width, containerBounds.Right - bounds.Left), 0),
+ Math.Max (Math.Min (containerBounds.Height, containerBounds.Bottom - bounds.Top), 0));
}
- for (var idx = startX; current < start + size; idx++) {
+ for (var idx = (isVertical ? start - y : start - x); current < start + size; idx++) {
if (idx < 0) {
current++;
continue;
diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs
index 4e90ba4db..20971d9ab 100644
--- a/Terminal.Gui/Core/View.cs
+++ b/Terminal.Gui/Core/View.cs
@@ -1417,15 +1417,20 @@ namespace Terminal.Gui {
Border.DrawContent (this);
}
- if (!ustring.IsNullOrEmpty (Text) || (this is Label && !AutoSize)) {
+ if (!ustring.IsNullOrEmpty (TextFormatter.Text) || (this is Label && !AutoSize)) {
Clear ();
// Draw any Text
if (TextFormatter != null) {
TextFormatter.NeedsFormat = true;
}
+ var containerBounds = SuperView == null ? default : SuperView.ViewToScreen (SuperView.Bounds);
+ containerBounds.X = Math.Max (containerBounds.X, Driver.Clip.X);
+ containerBounds.Y = Math.Max (containerBounds.Y, Driver.Clip.Y);
+ containerBounds.Width = Math.Min (containerBounds.Width, Driver.Clip.Width);
+ containerBounds.Height = Math.Min (containerBounds.Height, Driver.Clip.Height);
TextFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : GetNormalColor (),
HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled,
- SuperView == null ? default : SuperView.ViewToScreen (SuperView.Bounds));
+ containerBounds);
}
// Invoke DrawContentEvent
diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs
index 947c3ac08..ca204fa13 100644
--- a/Terminal.Gui/Views/Button.cs
+++ b/Terminal.Gui/Views/Button.cs
@@ -221,26 +221,6 @@ namespace Terminal.Gui {
SetNeedsDisplay ();
}
- ///
- public override void Redraw (Rect bounds)
- {
- if (ColorScheme != null) {
- Driver.SetAttribute (HasFocus ? ColorScheme.Focus : ColorScheme.Normal);
- }
-
- if (Border != null) {
- Border.DrawContent (this);
- }
-
- if (!ustring.IsNullOrEmpty (TextFormatter.Text)) {
- Clear ();
- TextFormatter.NeedsFormat = true;
- TextFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : GetNormalColor (),
- HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled,
- SuperView == null ? default : SuperView.ViewToScreen (SuperView.Bounds));
- }
- }
-
///
public override bool ProcessHotKey (KeyEvent kb)
{
diff --git a/UnitTests/ScenarioTests.cs b/UnitTests/ScenarioTests.cs
index 61fd9a3e8..10757b366 100644
--- a/UnitTests/ScenarioTests.cs
+++ b/UnitTests/ScenarioTests.cs
@@ -26,15 +26,15 @@ namespace Terminal.Gui {
int CreateInput (string input)
{
// Put a control-q in at the end
- Console.MockKeyPresses.Push (new ConsoleKeyInfo ('q', ConsoleKey.Q, shift: false, alt: false, control: true));
+ FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo ('q', ConsoleKey.Q, shift: false, alt: false, control: true));
foreach (var c in input.Reverse ()) {
if (char.IsLetter (c)) {
- Console.MockKeyPresses.Push (new ConsoleKeyInfo (char.ToLower (c), (ConsoleKey)char.ToUpper (c), shift: char.IsUpper (c), alt: false, control: false));
+ FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo (char.ToLower (c), (ConsoleKey)char.ToUpper (c), shift: char.IsUpper (c), alt: false, control: false));
} else {
- Console.MockKeyPresses.Push (new ConsoleKeyInfo (c, (ConsoleKey)c, shift: false, alt: false, control: false));
+ FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo (c, (ConsoleKey)c, shift: false, alt: false, control: false));
}
}
- return Console.MockKeyPresses.Count;
+ return FakeConsole.MockKeyPresses.Count;
}
///
@@ -48,59 +48,61 @@ namespace Terminal.Gui {
List scenarioClasses = Scenario.GetDerivedClasses ();
Assert.NotEmpty (scenarioClasses);
- foreach (var scenarioClass in scenarioClasses) {
+ lock (FakeConsole.MockKeyPresses) {
+ foreach (var scenarioClass in scenarioClasses) {
- // Setup some fake keypresses
- // Passing empty string will cause just a ctrl-q to be fired
- Console.MockKeyPresses.Clear ();
- int stackSize = CreateInput ("");
+ // Setup some fake keypresses
+ // Passing empty string will cause just a ctrl-q to be fired
+ FakeConsole.MockKeyPresses.Clear ();
+ int stackSize = CreateInput ("");
- Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+ Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
- int iterations = 0;
- Application.Iteration = () => {
- iterations++;
- // Stop if we run out of control...
- if (iterations > 10) {
- Application.RequestStop ();
+ int iterations = 0;
+ Application.Iteration = () => {
+ iterations++;
+ // Stop if we run out of control...
+ if (iterations > 10) {
+ Application.RequestStop ();
+ }
+ };
+
+ int ms;
+ if (scenarioClass.Name == "CharacterMap") {
+ ms = 2000;
+ } else {
+ ms = 1000;
}
- };
+ var abortCount = 0;
+ Func abortCallback = (MainLoop loop) => {
+ abortCount++;
+ Application.RequestStop ();
+ return false;
+ };
+ var token = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (ms), abortCallback);
- int ms;
- if (scenarioClass.Name == "CharacterMap") {
- ms = 1500;
- }else {
- ms = 1000;
+ var scenario = (Scenario)Activator.CreateInstance (scenarioClass);
+ scenario.Init (Application.Top, Colors.Base);
+ scenario.Setup ();
+ // There is no need to call Application.Begin because Init already creates the Application.Top
+ // If Application.RunState is used then the Application.RunLoop must also be used instead Application.Run.
+ //var rs = Application.Begin (Application.Top);
+ scenario.Run ();
+
+ //Application.End (rs);
+
+ // Shutdown must be called to safely clean up Application if Init has been called
+ Application.Shutdown ();
+
+ if (abortCount != 0) {
+ output.WriteLine ($"Scenario {scenarioClass} had abort count of {abortCount}");
+ }
+
+ Assert.Equal (0, abortCount);
+ // # of key up events should match # of iterations
+ Assert.Equal (1, iterations);
+ Assert.Equal (stackSize, iterations);
}
- var abortCount = 0;
- Func abortCallback = (MainLoop loop) => {
- abortCount++;
- Application.RequestStop ();
- return false;
- };
- var token = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (ms), abortCallback);
-
- var scenario = (Scenario)Activator.CreateInstance (scenarioClass);
- scenario.Init (Application.Top, Colors.Base);
- scenario.Setup ();
- // There is no need to call Application.Begin because Init already creates the Application.Top
- // If Application.RunState is used then the Application.RunLoop must also be used instead Application.Run.
- //var rs = Application.Begin (Application.Top);
- scenario.Run ();
-
- //Application.End (rs);
-
- // Shutdown must be called to safely clean up Application if Init has been called
- Application.Shutdown ();
-
- if(abortCount != 0) {
- output.WriteLine ($"Scenario {scenarioClass} had abort count of {abortCount}");
- }
-
- Assert.Equal (0, abortCount);
- // # of key up events should match # of iterations
- Assert.Equal (1, iterations);
- Assert.Equal (stackSize, iterations);
}
#if DEBUG_IDISPOSABLE
foreach (var inst in Responder.Instances) {
diff --git a/UnitTests/ViewTests.cs b/UnitTests/ViewTests.cs
index f3b499abf..8a88eaac3 100644
--- a/UnitTests/ViewTests.cs
+++ b/UnitTests/ViewTests.cs
@@ -1985,14 +1985,276 @@ Y
view.Frame = new Rect (0, 0, 8, 4);
((FakeDriver)Application.Driver).SetBufferSize (7, 3);
+ }
+
+ [Fact, AutoInitShutdown]
+ public void DrawTextFormatter_Respects_The_Clip_Bounds ()
+ {
+ var view = new View (new Rect (0, 0, 20, 20));
+ view.Add (new Label ("0123456789abcdefghij"));
+ view.Add (new Label (0, 1, "1\n2\n3\n4\n5\n6\n7\n8\n9\n0"));
+ view.Add (new Button (1, 1, "Press me!"));
+ var scrollView = new ScrollView (new Rect (1, 1, 15, 10)) {
+ ContentSize = new Size (40, 40),
+ ShowHorizontalScrollIndicator = true,
+ ShowVerticalScrollIndicator = true
+ };
+ scrollView.Add (view);
+ var win = new Window (new Rect (1, 1, 20, 14), "Test");
+ win.Add (scrollView);
+ Application.Top.Add (win);
+ Application.Begin (Application.Top);
+
+ var expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 0123456789abcd▲ │
+ │ 1[ Press me! ]┬ │
+ │ 2 │ │
+ │ 3 ┴ │
+ │ 4 ░ │
+ │ 5 ░ │
+ │ 6 ░ │
+ │ 7 ░ │
+ │ 8 ▼ │
+ │ ◄├───┤░░░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
expected = @"
-┌──────
-│
-│
+ ┌ Test ────────────┐
+ │ │
+ │ 123456789abcde▲ │
+ │ [ Press me! ] ┬ │
+ │ │ │
+ │ ┴ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ▼ │
+ │ ◄├───┤░░░░░░░► │
+ │ │
+ └──────────────────┘
";
pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
- Assert.Equal (new Rect (0, 0, 7, 3), pos);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
+ expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 23456789abcdef▲ │
+ │ Press me! ] ┬ │
+ │ │ │
+ │ ┴ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ▼ │
+ │ ◄├────┤░░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
+ expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 3456789abcdefg▲ │
+ │ Press me! ] ┬ │
+ │ │ │
+ │ ┴ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ▼ │
+ │ ◄├────┤░░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
+ expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 456789abcdefgh▲ │
+ │ ress me! ] ┬ │
+ │ │ │
+ │ ┴ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ▼ │
+ │ ◄░├───┤░░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
+ expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 56789abcdefghi▲ │
+ │ ess me! ] ┬ │
+ │ │ │
+ │ ┴ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ▼ │
+ │ ◄░├────┤░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
+ expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 6789abcdefghij▲ │
+ │ ss me! ] ┬ │
+ │ │ │
+ │ ┴ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ▼ │
+ │ ◄░├────┤░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
+ expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 789abcdefghij ▲ │
+ │ s me! ] ┬ │
+ │ │ │
+ │ ┴ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ░ │
+ │ ▼ │
+ │ ◄░░├───┤░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Home, new KeyModifiers ())));
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorDown, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
+ expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 1[ Press me! ]▲ │
+ │ 2 ┬ │
+ │ 3 │ │
+ │ 4 ┴ │
+ │ 5 ░ │
+ │ 6 ░ │
+ │ 7 ░ │
+ │ 8 ░ │
+ │ 9 ▼ │
+ │ ◄├───┤░░░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorDown, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
+ expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 2 ▲ │
+ │ 3 ┬ │
+ │ 4 │ │
+ │ 5 ┴ │
+ │ 6 ░ │
+ │ 7 ░ │
+ │ 8 ░ │
+ │ 9 ░ │
+ │ 0 ▼ │
+ │ ◄├───┤░░░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
+
+ Assert.True (scrollView.ProcessKey (new KeyEvent (Key.CursorDown, new KeyModifiers ())));
+ Application.Top.Redraw (Application.Top.Bounds);
+
+ expected = @"
+ ┌ Test ────────────┐
+ │ │
+ │ 3 ▲ │
+ │ 4 ┬ │
+ │ 5 │ │
+ │ 6 ┴ │
+ │ 7 ░ │
+ │ 8 ░ │
+ │ 9 ░ │
+ │ 0 ░ │
+ │ ▼ │
+ │ ◄├───┤░░░░░░░► │
+ │ │
+ └──────────────────┘
+";
+
+ pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
+ Assert.Equal (new Rect (1, 1, 21, 14), pos);
}
}
}