diff --git a/Terminal.Gui/Core.cs b/Terminal.Gui/Core.cs
index 58767b0b4..e31fe0b5c 100644
--- a/Terminal.Gui/Core.cs
+++ b/Terminal.Gui/Core.cs
@@ -798,14 +798,14 @@ namespace Terminal.Gui {
}
// Converts a rectangle in view coordinates to screen coordinates.
- Rect RectToScreen (Rect rect)
+ internal Rect RectToScreen (Rect rect)
{
ViewToScreen (rect.X, rect.Y, out var x, out var y, clipped: false);
return new Rect (x, y, rect.Width, rect.Height);
}
// Clips a rectangle in screen coordinates to the dimensions currently available on the screen
- Rect ScreenClip (Rect rect)
+ internal Rect ScreenClip (Rect rect)
{
var x = rect.X < 0 ? 0 : rect.X;
var y = rect.Y < 0 ? 0 : rect.Y;
@@ -1082,7 +1082,7 @@ namespace Terminal.Gui {
/// Constructs.
///
///
- public KeyEventEventArgs(KeyEvent ke) => KeyEvent = ke;
+ public KeyEventEventArgs (KeyEvent ke) => KeyEvent = ke;
///
/// The for the event.
///
@@ -1683,13 +1683,13 @@ namespace Terminal.Gui {
nx = Math.Max (x, 0);
nx = nx + top.Frame.Width > Driver.Cols ? Math.Max (Driver.Cols - top.Frame.Width, 0) : nx;
bool m, s;
- if (SuperView == null || SuperView.GetType() != typeof(Toplevel))
+ if (SuperView == null || SuperView.GetType () != typeof (Toplevel))
m = Application.Top.MenuBar != null;
else
m = ((Toplevel)SuperView).MenuBar != null;
int l = m ? 1 : 0;
ny = Math.Max (y, l);
- if (SuperView == null || SuperView.GetType() != typeof(Toplevel))
+ if (SuperView == null || SuperView.GetType () != typeof (Toplevel))
s = Application.Top.StatusBar != null;
else
s = ((Toplevel)SuperView).StatusBar != null;
@@ -1867,11 +1867,6 @@ namespace Terminal.Gui {
return contentView.GetEnumerator ();
}
- void DrawFrame (bool fill = true)
- {
- DrawFrame (new Rect (0, 0, Frame.Width, Frame.Height), padding, fill: fill);
- }
-
///
/// Add the specified view to the .
///
@@ -1916,30 +1911,24 @@ namespace Terminal.Gui {
public override void Redraw (Rect bounds)
{
Application.CurrentView = this;
+ var scrRect = RectToScreen (new Rect (0, 0, Frame.Width, Frame.Height));
+ var savedClip = Driver.Clip;
+ Driver.Clip = ScreenClip (RectToScreen (Bounds));
if (NeedDisplay != null && !NeedDisplay.IsEmpty) {
- DrawFrameWindow ();
+ Driver.SetAttribute (ColorScheme.Normal);
+ Driver.DrawFrame (scrRect, padding, true);
}
contentView.Redraw (contentView.Bounds);
ClearNeedsDisplay ();
- DrawFrameWindow (false);
+ Driver.SetAttribute (ColorScheme.Normal);
+ Driver.DrawFrame (scrRect, padding, false);
- void DrawFrameWindow (bool fill = true)
- {
- Driver.SetAttribute (ColorScheme.Normal);
- DrawFrame (fill);
- if (HasFocus)
- Driver.SetAttribute (ColorScheme.HotNormal);
- var width = Frame.Width - (padding + 2) * 2;
- if (Title != null && width > 4) {
- Move (1 + padding, padding);
- Driver.AddRune (' ');
- var str = Title.Length >= width ? Title [0, width - 2] : Title;
- Driver.AddStr (str);
- Driver.AddRune (' ');
- }
- Driver.SetAttribute (ColorScheme.Normal);
- }
+ if (HasFocus)
+ Driver.SetAttribute (ColorScheme.HotNormal);
+ Driver.DrawWindowTitle (scrRect, Title, padding, padding, padding, padding);
+ Driver.Clip = savedClip;
+ Driver.SetAttribute (ColorScheme.Normal);
}
//
@@ -2415,7 +2404,7 @@ namespace Terminal.Gui {
if (toplevel.LayoutStyle == LayoutStyle.Computed)
toplevel.RelativeLayout (new Rect (0, 0, Driver.Cols, Driver.Rows));
toplevel.LayoutSubviews ();
- Loaded?.Invoke (null, new ResizedEventArgs () { Rows = Driver.Rows, Cols = Driver.Cols } );
+ Loaded?.Invoke (null, new ResizedEventArgs () { Rows = Driver.Rows, Cols = Driver.Cols });
toplevel.WillPresent ();
Redraw (toplevel);
toplevel.PositionCursor ();
diff --git a/Terminal.Gui/Drivers/ConsoleDriver.cs b/Terminal.Gui/Drivers/ConsoleDriver.cs
index 232be1c28..d68b5ed4b 100644
--- a/Terminal.Gui/Drivers/ConsoleDriver.cs
+++ b/Terminal.Gui/Drivers/ConsoleDriver.cs
@@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Security.Cryptography;
using Mono.Terminal;
using NStack;
using Unix.Terminal;
@@ -525,91 +526,173 @@ namespace Terminal.Gui {
TerminalResized = terminalResized;
}
+ // Useful for debugging (e.g. change to `*`
+ const char clearChar = ' ';
+
+ ///
+ /// Draws the title for a Window-style view incorporating padding.
+ ///
+ /// Screen relative region where the frame will be drawn.
+ /// The title for the window. The title will only be drawn if title is not null or empty and paddingTop is greater than 0.
+ /// Number of columns to pad on the left (if 0 the border will not appear on the left).
+ /// Number of rows to pad on the top (if 0 the border and title will not appear on the top).
+ /// Number of columns to pad on the right (if 0 the border will not appear on the right).
+ /// Number of rows to pad on the bottom (if 0 the border will not appear on the bottom).
+ ///
+ public void DrawWindowTitle (Rect region, ustring title, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom)
+ {
+ var width = region.Width - (paddingLeft + 2) * 2;
+ if (!ustring.IsNullOrEmpty(title) && width > 4) {
+
+ Move (region.X + 1 + paddingLeft, region.Y + paddingTop);
+ AddRune (' ');
+ var str = title.Length >= width ? title [0, width - 2] : title;
+ AddStr (str);
+ AddRune (' ');
+ }
+ }
+
+ ///
+ /// Draws a frame for a window with padding aand n optional visible border inside the padding.
+ ///
+ /// Screen relative region where the frame will be drawn.
+ /// Number of columns to pad on the left (if 0 the border will not appear on the left).
+ /// Number of rows to pad on the top (if 0 the border and title will not appear on the top).
+ /// Number of columns to pad on the right (if 0 the border will not appear on the right).
+ /// Number of rows to pad on the bottom (if 0 the border will not appear on the bottom).
+ /// If set to true and any padding dimension is > 0 the border will be drawn.
+ /// If set to true it will clear the content area (the area inside the padding) with the current color, otherwise the content area will be left untouched.
+ public void DrawWindowFrame (Rect region, int paddingLeft = 0, int paddingTop = 0, int paddingRight = 0, int paddingBottom = 0, bool border = true, bool fill = false)
+ {
+ void AddRuneAt (int col, int row, Rune ch)
+ {
+ Move (col, row);
+ AddRune (ch);
+ }
+
+ int fwidth = (int)(region.Width - (paddingRight + paddingLeft));
+ int fheight = (int)(region.Height - (paddingBottom + paddingTop));
+ int fleft = region.X + paddingLeft;
+ int fright = fleft + fwidth + 1;
+ int ftop = region.Y + paddingTop;
+ int fbottom = ftop + fheight + 1;
+
+ Rune hLine = border ? HLine : clearChar;
+ Rune vLine = border ? VLine : clearChar;
+ Rune uRCorner = border ? URCorner : clearChar;
+ Rune uLCorner = border ? ULCorner : clearChar;
+ Rune lLCorner = border ? LLCorner : clearChar;
+ Rune lRCorner = border ? LRCorner : clearChar;
+
+ // Outside top
+ if (paddingTop > 1) {
+ for (int r = region.Y; r < ftop; r++) {
+ for (int c = region.X; c <= fright + paddingRight; c++) {
+ AddRuneAt (c, r, 'T');
+ }
+ }
+ }
+
+ // Outside top-left
+ for (int c = region.X; c <= fleft; c++) {
+ AddRuneAt (c, ftop, 'L');
+ }
+
+ // Frame top-left corner
+ AddRuneAt (fleft, ftop, paddingTop >= 0 ? (paddingLeft >= 0 ? uLCorner : hLine) : clearChar);
+
+ // Frame top
+ for (int c = fleft + 1; c <= fright; c++) {
+ AddRuneAt (c, ftop, paddingTop > 0 ? hLine : clearChar);
+ }
+
+ // Frame top-right corner
+ if (fright > fleft) {
+ AddRuneAt (fright, ftop, paddingTop >= 0 ? (paddingRight >= 0 ? uRCorner : hLine) : clearChar);
+ }
+
+ // Outside top-right corner
+ for (int c = fright + 1; c < fright + paddingRight; c++) {
+ AddRuneAt (c, ftop, 'R');
+ }
+
+ // Left, Fill, Right
+ if (fbottom > ftop) {
+ for (int r = ftop + 1; r < fbottom; r++) {
+ // Outside left
+ for (int c = region.X; c < fleft; c++) {
+ AddRuneAt (c, r, 'L');
+ }
+
+ // Frame left
+ AddRuneAt (fleft, r, paddingLeft > 0 ? vLine : clearChar);
+
+ // Fill
+ if (fill) {
+ for (int x = fleft + 1; x < fright; x++) {
+ AddRuneAt (x, r, clearChar);
+ }
+ }
+
+ // Frame right
+ if (fright > fleft) {
+ AddRuneAt (fright, r, paddingRight > 0 ? vLine : clearChar);
+ }
+
+ // Outside right
+ for (int c = fright + 1; c < fright + paddingRight; c++) {
+ AddRuneAt (c, r, 'R');
+ }
+ }
+
+ // Outside Bottom
+ for (int c = region.X; c < fleft; c++) {
+ AddRuneAt (c, fbottom, 'L');
+ }
+
+ // Frame bottom-left
+ AddRuneAt (fleft, fbottom, paddingLeft > 0 ? lLCorner : clearChar);
+
+ if (fright > fleft) {
+ // Frame bottom
+ for (int c = fleft + 1; c < fright; c++) {
+ AddRuneAt (c, fbottom, paddingBottom > 0 ? hLine : clearChar);
+ }
+
+ // Frame bottom-right
+ AddRuneAt (fright, fbottom, paddingRight > 0 ? (paddingBottom > 0 ? lRCorner : hLine) : clearChar);
+ }
+
+ // Outside right
+ for (int c = fright + 1; c < fright + paddingRight; c++) {
+ AddRuneAt (c, fbottom, 'R');
+ }
+ }
+
+ // Out bottom - ensure top is always drawn if we overlap
+ if (paddingBottom > 0) {
+ for (int r = fbottom + 1; r < fbottom + paddingBottom; r++) {
+ for (int c = region.X; c <= fright + paddingRight; c++) {
+ AddRuneAt (c, r, 'B');
+ }
+ }
+ }
+ }
+
///
/// Draws a frame on the specified region with the specified padding around the frame.
///
/// Region where the frame will be drawn..
/// Padding to add on the sides.
/// If set to true it will clear the contents with the current color, otherwise the contents will be left untouched.
+ /// This is a legacy/depcrecated API. Use .
+ /// A padding value of 0 means there is actually a 1 cell border.
public virtual void DrawFrame (Rect region, int padding, bool fill)
{
- int width = region.Width;
- int height = region.Height;
- int b;
- int fwidth = width - padding * 2;
- int fheight = height - 1 - padding;
-
- Move (region.X, region.Y);
- if (padding > 0) {
- for (int l = 0; l < padding; l++)
- for (b = region.X; b < region.X + width; b++) {
- AddRune (' ');
- Move (b + 1, region.Y);
- }
- }
- Move (region.X, region.Y + padding);
- for (int c = 0; c < padding; c++) {
- AddRune (' ');
- Move (region.X + 1, region.Y + padding);
- }
- AddRune (ULCorner);
- for (b = region.X; b < region.X + fwidth - 2; b++) {
- AddRune (HLine);
- Move (b + (padding > 0 ? padding + 2 : 2), region.Y + padding);
- }
- AddRune (URCorner);
- for (int c = 0; c < padding; c++) {
- AddRune (' ');
- Move (region.X + 1, region.Y + padding);
- }
- for (b = 1 + padding; b < fheight; b++) {
- Move (region.X, region.Y + b);
- for (int c = 0; c < padding; c++) {
- AddRune (' ');
- Move (region.X + 1, region.Y + b);
- }
- AddRune (VLine);
- if (fill) {
- for (int x = region.X + 1; x < region.X + fwidth - 1; x++) {
- AddRune (' ');
- Move (x + (padding > 0 ? padding + 1 : 1), region.Y + b);
- }
- } else {
- if (padding > 0)
- Move (region.X + fwidth, region.Y + b);
- else
- Move (region.X + fwidth - 1, region.Y + b);
- }
- AddRune (VLine);
- for (int c = 0; c < padding; c++) {
- AddRune (' ');
- Move (region.X + 1, region.Y + b);
- }
- }
- Move (region.X, region.Y + fheight);
- for (int c = 0; c < padding; c++) {
- AddRune (' ');
- Move (region.X + 1, region.Y + b);
- }
- AddRune (LLCorner);
- for (b = region.X; b < region.X + fwidth - 2; b++) {
- AddRune (HLine);
- Move (b + (padding > 0 ? padding + 2 : 2), region.Y + fheight);
- }
- AddRune (LRCorner);
- for (int c = 0; c < padding; c++) {
- AddRune (' ');
- Move (region.X + 1, region.Y);
- }
- if (padding > 0) {
- Move (region.X, region.Y + height - padding);
- for (int l = 0; l < padding; l++) {
- for (b = region.X; b < region.X + width; b++) {
- AddRune (' ');
- Move (b + 1, region.Y + height - padding);
- }
- }
- }
+ // DrawFrame assumes the frame is always at least one row/col thick
+ // DrawWindowFrame assumes a padding of 0 means NO padding
+ padding++;
+ DrawWindowFrame (new Rect (region.X - 1, region.Y - 1, region.Width, region.Height), padding, padding, padding, padding, fill: fill);
}
diff --git a/Terminal.Gui/Views/FrameView.cs b/Terminal.Gui/Views/FrameView.cs
index f5ea13bcf..6768a01ae 100644
--- a/Terminal.Gui/Views/FrameView.cs
+++ b/Terminal.Gui/Views/FrameView.cs
@@ -134,23 +134,26 @@ namespace Terminal.Gui {
///
public override void Redraw (Rect bounds)
{
- if (!NeedDisplay.IsEmpty) {
- Driver.SetAttribute (ColorScheme.Normal);
- DrawFrame ();
- if (HasFocus)
- Driver.SetAttribute (ColorScheme.Normal);
- var width = Frame.Width;
- if (Title != null && width > 4) {
- Move (1, 0);
- Driver.AddRune (' ');
- var str = Title.Length > width ? Title [0, width - 4] : Title;
- Driver.AddStr (str);
- Driver.AddRune (' ');
- }
+ var padding = 0;
+ Application.CurrentView = this;
+ var scrRect = RectToScreen (new Rect (0, 0, Frame.Width, Frame.Height));
+ var savedClip = Driver.Clip;
+ Driver.Clip = ScreenClip (RectToScreen (Bounds));
+
+ if (NeedDisplay != null && !NeedDisplay.IsEmpty) {
Driver.SetAttribute (ColorScheme.Normal);
+ Driver.DrawFrame (scrRect, padding, true);
}
contentView.Redraw (contentView.Bounds);
ClearNeedsDisplay ();
+ Driver.SetAttribute (ColorScheme.Normal);
+ Driver.DrawFrame (scrRect, padding, false);
+
+ if (HasFocus)
+ Driver.SetAttribute (ColorScheme.HotNormal);
+ Driver.DrawWindowTitle (scrRect, Title, padding, padding, padding, padding);
+ Driver.Clip = savedClip;
+ Driver.SetAttribute (ColorScheme.Normal);
}
}
}
diff --git a/UICatalog/Scenarios/ComputedLayout.cs b/UICatalog/Scenarios/ComputedLayout.cs
index d5aecf6e3..17ee66f7d 100644
--- a/UICatalog/Scenarios/ComputedLayout.cs
+++ b/UICatalog/Scenarios/ComputedLayout.cs
@@ -71,10 +71,10 @@ namespace UICatalog {
string txt = "Resize the terminal to see computed layout in action.";
var labelList = new List