diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index bc2e923f53..9e77a775f5 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1500,11 +1500,16 @@ public override void Move (int col, int row) crow = row; } + int GetOutputBufferPosition () + { + return crow * Cols + ccol; + } + public override void AddRune (Rune rune) { rune = MakePrintable (rune); var runeWidth = Rune.ColumnWidth (rune); - var position = crow * Cols + ccol; + var position = GetOutputBufferPosition (); var validClip = IsValidContent (ccol, crow, Clip); if (validClip) { @@ -1518,7 +1523,7 @@ public override void AddRune (Rune rune) } else if (runeWidth < 2 && ccol <= Clip.Right - 1 && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { - var prevPosition = crow * Cols + ccol + 1; + var prevPosition = GetOutputBufferPosition () + 1; OutputBuffer [prevPosition].Char.UnicodeChar = (char)' '; contents [crow, ccol + 1, 0] = (int)(uint)' '; @@ -1539,7 +1544,7 @@ public override void AddRune (Rune rune) ccol++; if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { - position = crow * Cols + ccol; + position = GetOutputBufferPosition (); OutputBuffer [position].Attributes = (ushort)currentAttribute; OutputBuffer [position].Char.UnicodeChar = (char)0x00; contents [crow, ccol, 0] = (int)(uint)0x00; diff --git a/Terminal.Gui/Core/TextFormatter.cs b/Terminal.Gui/Core/TextFormatter.cs index 06b0323d5a..8dbe1d23fc 100644 --- a/Terminal.Gui/Core/TextFormatter.cs +++ b/Terminal.Gui/Core/TextFormatter.cs @@ -1182,10 +1182,22 @@ public void Draw (Rect bounds, Attribute normalColor, Attribute hotColor, Rect c } var isVertical = IsVerticalDirection (textDirection); + var savedClip = Application.Driver?.Clip; + var maxBounds = bounds; + if (Application.Driver != null) { + Application.Driver.Clip = maxBounds = containerBounds == default + ? bounds + : new Rect (Math.Max (containerBounds.X, bounds.X), + Math.Max (containerBounds.Y, bounds.Y), + Math.Max (Math.Min (containerBounds.Width, containerBounds.Right - bounds.Left), 0), + Math.Max (Math.Min (containerBounds.Height, containerBounds.Bottom - bounds.Top), 0)); + } for (int line = 0; line < linesFormated.Count; line++) { if ((isVertical && line > bounds.Width) || (!isVertical && line > bounds.Height)) continue; + if ((isVertical && line > maxBounds.Left + maxBounds.Width - bounds.X) || (!isVertical && line > maxBounds.Top + maxBounds.Height - bounds.Y)) + break; var runes = lines [line].ToRunes (); @@ -1262,15 +1274,6 @@ public void Draw (Rect bounds, Attribute normalColor, Attribute hotColor, Rect c var start = isVertical ? bounds.Top : bounds.Left; var size = isVertical ? bounds.Height : bounds.Width; var current = start; - var savedClip = Application.Driver?.Clip; - if (Application.Driver != null) { - Application.Driver.Clip = containerBounds == default - ? bounds - : new Rect (Math.Max (containerBounds.X, bounds.X), - Math.Max (containerBounds.Y, bounds.Y), - 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 = (isVertical ? start - y : start - x); current < start + size; idx++) { if (!fillRemaining && idx < 0) { @@ -1279,6 +1282,9 @@ public void Draw (Rect bounds, Attribute normalColor, Attribute hotColor, Rect c } else if (!fillRemaining && idx > runes.Length - 1) { break; } + if ((!isVertical && idx > maxBounds.Left + maxBounds.Width - bounds.X) || (isVertical && idx > maxBounds.Top + maxBounds.Height - bounds.Y)) + break; + var rune = (Rune)' '; if (isVertical) { Application.Driver?.Move (x, current); @@ -1313,9 +1319,9 @@ public void Draw (Rect bounds, Attribute normalColor, Attribute hotColor, Rect c break; } } - if (Application.Driver != null) - Application.Driver.Clip = (Rect)savedClip; } + if (Application.Driver != null) + Application.Driver.Clip = (Rect)savedClip; } } } diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 488478991a..417c222a3a 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -1495,14 +1495,17 @@ public virtual void Redraw (Rect bounds) if (Border != null) { Border.DrawContent (this); - } else if ((GetType ().IsPublic || GetType ().IsNestedPublic) && !IsOverridden (this, "Redraw") && + } else if (ustring.IsNullOrEmpty (TextFormatter.Text) && + (GetType ().IsPublic || GetType ().IsNestedPublic) && !IsOverridden (this, "Redraw") && (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded)) { - Clear (ViewToScreen (bounds)); + Clear (); + SetChildNeedsDisplay (); } if (!ustring.IsNullOrEmpty (TextFormatter.Text)) { Clear (); + SetChildNeedsDisplay (); // Draw any Text if (TextFormatter != null) { TextFormatter.NeedsFormat = true; diff --git a/Terminal.Gui/Core/Window.cs b/Terminal.Gui/Core/Window.cs index b79d608df0..d0811eb163 100644 --- a/Terminal.Gui/Core/Window.cs +++ b/Terminal.Gui/Core/Window.cs @@ -303,12 +303,6 @@ public override void Redraw (Rect bounds) if (Border.DrawMarginFrame) Driver.DrawWindowTitle (scrRect, Title, padding.Left, padding.Top, padding.Right, padding.Bottom); Driver.SetAttribute (GetNormalColor ()); - - // Checks if there are any SuperView view which intersect with this window. - if (SuperView != null) { - SuperView.SetNeedsLayout (); - SuperView.SetNeedsDisplay (); - } } /// diff --git a/UICatalog/Scenarios/Scrolling.cs b/UICatalog/Scenarios/Scrolling.cs index aec97e7a70..a1b82282a5 100644 --- a/UICatalog/Scenarios/Scrolling.cs +++ b/UICatalog/Scenarios/Scrolling.cs @@ -105,8 +105,8 @@ public override void Setup () { Win.X = 3; Win.Y = 3; - Win.Width = Dim.Fill () - 3; - Win.Height = Dim.Fill () - 3; + Win.Width = Dim.Fill (3); + Win.Height = Dim.Fill (3); var label = new Label ("ScrollView (new Rect (2, 2, 50, 20)) with a 200, 100 ContentSize...") { X = 0, Y = 0, @@ -114,8 +114,12 @@ public override void Setup () }; Win.Add (label); - // BUGBUG: ScrollView only supports Absolute Positioning (#72) - var scrollView = new ScrollView (new Rect (2, 2, 50, 20)) { + // FIXED: ScrollView only supports Absolute Positioning (#72) + var scrollView = new ScrollView { + X = 2, + Y = 2, + Width = 50, + Height = 20, ColorScheme = Colors.TopLevel, ContentSize = new Size (200, 100), //ContentOffset = new Point (0, 0), @@ -124,6 +128,7 @@ public override void Setup () }; const string rule = "0123456789"; + var horizontalRuler = new Label () { X = 0, Y = 0, @@ -133,6 +138,7 @@ public override void Setup () AutoSize = false }; scrollView.Add (horizontalRuler); + const string vrule = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n"; var verticalRuler = new Label () { @@ -148,7 +154,7 @@ public override void Setup () void Top_Loaded () { horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)] + - "\n" + "| ".Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)]; + "\n" + "| ".Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)]; verticalRuler.Text = vrule.Repeat ((int)Math.Ceiling ((double)(verticalRuler.Bounds.Height * 2) / (double)rule.Length)) [0..(verticalRuler.Bounds.Height * 2)]; Top.Loaded -= Top_Loaded; } @@ -164,7 +170,7 @@ void Top_Loaded () var aLongButton = new Button ("A very long button. Should be wide enough to demo clipping!") { X = 3, Y = 4, - Width = Dim.Fill (6), + Width = Dim.Fill (3), }; aLongButton.Clicked += () => MessageBox.Query (20, 7, "MessageBox", "Neat?", "Yes", "No"); scrollView.Add (aLongButton); @@ -206,6 +212,8 @@ void Top_Loaded () }; scrollView.Add (anchorButton); + Win.Add (scrollView); + var hCheckBox = new CheckBox ("Horizontal Scrollbar", scrollView.ShowHorizontalScrollIndicator) { X = Pos.X (scrollView), Y = Pos.Bottom (scrollView) + 1, @@ -265,6 +273,7 @@ void Top_Loaded () scrollView2.DrawContent += (r) => { scrollView2.ContentSize = filler.GetContentSize (); }; + Win.Add (scrollView2); // This is just to debug the visuals of the scrollview when small var scrollView3 = new ScrollView (new Rect (55, 15, 3, 3)) { @@ -273,20 +282,26 @@ void Top_Loaded () ShowHorizontalScrollIndicator = true }; scrollView3.Add (new Box10x (0, 0)); + Win.Add (scrollView3); int count = 0; - var mousePos = new Label ("Mouse: "); - mousePos.X = Pos.Right (scrollView) + 1; - mousePos.Y = Pos.AnchorEnd (1); - mousePos.Width = 50; + var mousePos = new Label ("Mouse: ") { + X = Pos.Right (scrollView) + 1, + Y = Pos.AnchorEnd (1), + Width = 50, + }; + Win.Add (mousePos); Application.RootMouseEvent += delegate (MouseEvent me) { mousePos.Text = $"Mouse: ({me.X},{me.Y}) - {me.Flags} {count++}"; }; - var progress = new ProgressBar (); - progress.X = Pos.Right (scrollView) + 1; - progress.Y = Pos.AnchorEnd (2); - progress.Width = 50; + var progress = new ProgressBar { + X = Pos.Right (scrollView) + 1, + Y = Pos.AnchorEnd (2), + Width = 50 + }; + Win.Add (progress); + bool pulsing = true; bool timer (MainLoop caller) { @@ -301,8 +316,6 @@ void Top_Unloaded () Top.Unloaded -= Top_Unloaded; } Top.Unloaded += Top_Unloaded; - - Win.Add (scrollView, scrollView2, scrollView3, mousePos, progress); } } } \ No newline at end of file diff --git a/UnitTests/ViewTests.cs b/UnitTests/ViewTests.cs index e2a20e80b8..03969c4a73 100644 --- a/UnitTests/ViewTests.cs +++ b/UnitTests/ViewTests.cs @@ -4062,5 +4062,29 @@ public void KeyDown_And_KeyUp_Events_With_Only_Key_Modifiers (bool shift, bool a Assert.False (view.IsKeyPress); Assert.True (view.IsKeyUp); } + + [Fact, AutoInitShutdown] + public void IsOverridden_False_IfNotOverriden () + { + var view = new DerivedView () { Text = "DerivedView does not override MouseEvent", Width = 10, Height = 10 }; + + Assert.False (View.IsOverridden (view, "MouseEvent")); + + var view2 = new Button () { Text = "Button does not overrides OnKeyDown", Width = 10, Height = 10 }; + + Assert.False (View.IsOverridden (view2, "OnKeyDown")); + } + + [Fact, AutoInitShutdown] + public void IsOverridden_True_IfOverriden () + { + var view = new Button () { Text = "Button overrides MouseEvent", Width = 10, Height = 10 }; + + Assert.True (View.IsOverridden (view, "MouseEvent")); + + var view2 = new DerivedView () { Text = "DerivedView overrides OnKeyDown", Width = 10, Height = 10 }; + + Assert.True (View.IsOverridden (view2, "OnKeyDown")); + } } }