Merge branch 'draw-clip-bounds-fix' into wide-runes-render-issues

This commit is contained in:
BDisp
2022-05-13 18:30:04 +01:00
5 changed files with 329 additions and 83 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -221,26 +221,6 @@ namespace Terminal.Gui {
SetNeedsDisplay ();
}
/// <inheritdoc/>
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));
}
}
///<inheritdoc/>
public override bool ProcessHotKey (KeyEvent kb)
{

View File

@@ -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;
}
/// <summary>
@@ -48,59 +48,61 @@ namespace Terminal.Gui {
List<Type> scenarioClasses = Scenario.GetDerivedClasses<Scenario> ();
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<MainLoop, bool> 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<MainLoop, bool> 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) {

View File

@@ -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);
}
}
}