//
// ConsoleDriver.cs: Definition for the Console Driver API
//
// Authors:
// Miguel de Icaza (miguel@gnome.org)
//
// Define this to enable diagnostics drawing for Window Frames
using NStack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Terminal.Gui {
///
/// Basic colors that can be used to set the foreground and background colors in console applications.
///
public enum Color {
///
/// The black color.
///
Black,
///
/// The blue color.
///
Blue,
///
/// The green color.
///
Green,
///
/// The cyan color.
///
Cyan,
///
/// The red color.
///
Red,
///
/// The magenta color.
///
Magenta,
///
/// The brown color.
///
Brown,
///
/// The gray color.
///
Gray,
///
/// The dark gray color.
///
DarkGray,
///
/// The bright bBlue color.
///
BrightBlue,
///
/// The bright green color.
///
BrightGreen,
///
/// The bright cyan color.
///
BrightCyan,
///
/// The bright red color.
///
BrightRed,
///
/// The bright magenta color.
///
BrightMagenta,
///
/// The bright yellow color.
///
BrightYellow,
///
/// The White color.
///
White
}
///
/// Attributes are used as elements that contain both a foreground and a background or platform specific features
///
///
/// s are needed to map colors to terminal capabilities that might lack colors, on color
/// scenarios, they encode both the foreground and the background color and are used in the
/// class to define color schemes that can be used in your application.
///
public struct Attribute {
///
/// The color attribute value.
///
public int Value { get; }
///
/// The foreground color.
///
public Color Foreground { get; }
///
/// The background color.
///
public Color Background { get; }
///
/// Initializes a new instance of the struct.
///
/// Value.
/// Foreground
/// Background
public Attribute (int value, Color foreground = new Color (), Color background = new Color ())
{
Value = value;
Foreground = foreground;
Background = background;
}
///
/// Initializes a new instance of the struct.
///
/// Foreground
/// Background
public Attribute (Color foreground = new Color (), Color background = new Color ())
{
Value = Make (foreground, background).Value;
Foreground = foreground;
Background = background;
}
///
/// Implicit conversion from an to the underlying Int32 representation
///
/// The integer value stored in the attribute.
/// The attribute to convert
public static implicit operator int (Attribute c) => c.Value;
///
/// Implicitly convert an integer value into an
///
/// An attribute with the specified integer value.
/// value
public static implicit operator Attribute (int v) => new Attribute (v);
///
/// Creates an from the specified foreground and background.
///
/// The make.
/// Foreground color to use.
/// Background color to use.
public static Attribute Make (Color foreground, Color background)
{
if (Application.Driver == null)
throw new InvalidOperationException ("The Application has not been initialized");
return Application.Driver.MakeAttribute (foreground, background);
}
///
/// Gets the current from the driver.
///
/// The current attribute.
public static Attribute Get ()
{
if (Application.Driver == null)
throw new InvalidOperationException ("The Application has not been initialized");
return Application.Driver.GetAttribute ();
}
}
///
/// Color scheme definitions, they cover some common scenarios and are used
/// typically in containers such as and to set the scheme that is used by all the
/// views contained inside.
///
public class ColorScheme : IEquatable {
Attribute _normal;
Attribute _focus;
Attribute _hotNormal;
Attribute _hotFocus;
Attribute _disabled;
internal string caller = "";
///
/// The default color for text, when the view is not focused.
///
public Attribute Normal { get { return _normal; } set { _normal = SetAttribute (value); } }
///
/// The color for text when the view has the focus.
///
public Attribute Focus { get { return _focus; } set { _focus = SetAttribute (value); } }
///
/// The color for the hotkey when a view is not focused
///
public Attribute HotNormal { get { return _hotNormal; } set { _hotNormal = SetAttribute (value); } }
///
/// The color for the hotkey when the view is focused.
///
public Attribute HotFocus { get { return _hotFocus; } set { _hotFocus = SetAttribute (value); } }
///
/// The default color for text, when the view is disabled.
///
public Attribute Disabled { get { return _disabled; } set { _disabled = SetAttribute (value); } }
bool preparingScheme = false;
Attribute SetAttribute (Attribute attribute, [CallerMemberName] string callerMemberName = null)
{
if (!Application._initialized && !preparingScheme)
return attribute;
if (preparingScheme)
return attribute;
preparingScheme = true;
switch (caller) {
case "TopLevel":
switch (callerMemberName) {
case "Normal":
HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
break;
case "Focus":
HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
break;
case "HotNormal":
HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
break;
case "HotFocus":
HotNormal = Application.Driver.MakeAttribute (attribute.Foreground, HotNormal.Background);
if (Focus.Foreground != attribute.Background)
Focus = Application.Driver.MakeAttribute (Focus.Foreground, attribute.Background);
break;
}
break;
case "Base":
switch (callerMemberName) {
case "Normal":
HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
break;
case "Focus":
HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
break;
case "HotNormal":
HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
break;
case "HotFocus":
HotNormal = Application.Driver.MakeAttribute (attribute.Foreground, HotNormal.Background);
if (Focus.Foreground != attribute.Background)
Focus = Application.Driver.MakeAttribute (Focus.Foreground, attribute.Background);
break;
}
break;
case "Menu":
switch (callerMemberName) {
case "Normal":
if (Focus.Background != attribute.Background)
Focus = Application.Driver.MakeAttribute (attribute.Foreground, Focus.Background);
HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
Disabled = Application.Driver.MakeAttribute (Disabled.Foreground, attribute.Background);
break;
case "Focus":
Normal = Application.Driver.MakeAttribute (attribute.Foreground, Normal.Background);
HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
break;
case "HotNormal":
if (Focus.Background != attribute.Background)
HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
Disabled = Application.Driver.MakeAttribute (Disabled.Foreground, attribute.Background);
break;
case "HotFocus":
HotNormal = Application.Driver.MakeAttribute (attribute.Foreground, HotNormal.Background);
if (Focus.Foreground != attribute.Background)
Focus = Application.Driver.MakeAttribute (Focus.Foreground, attribute.Background);
break;
case "Disabled":
if (Focus.Background != attribute.Background)
HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
break;
}
break;
case "Dialog":
switch (callerMemberName) {
case "Normal":
if (Focus.Background != attribute.Background)
Focus = Application.Driver.MakeAttribute (attribute.Foreground, Focus.Background);
HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
break;
case "Focus":
Normal = Application.Driver.MakeAttribute (attribute.Foreground, Normal.Background);
HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
break;
case "HotNormal":
if (Focus.Background != attribute.Background)
HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
if (Normal.Foreground != attribute.Background)
Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
break;
case "HotFocus":
HotNormal = Application.Driver.MakeAttribute (attribute.Foreground, HotNormal.Background);
if (Focus.Foreground != attribute.Background)
Focus = Application.Driver.MakeAttribute (Focus.Foreground, attribute.Background);
break;
}
break;
case "Error":
switch (callerMemberName) {
case "Normal":
HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
break;
case "HotNormal":
case "HotFocus":
HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, attribute.Background);
Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
break;
}
break;
}
preparingScheme = false;
return attribute;
}
///
/// Compares two objects for equality.
///
///
/// true if the two objects are equal
public override bool Equals (object obj)
{
return Equals (obj as ColorScheme);
}
///
/// Compares two objects for equality.
///
///
/// true if the two objects are equal
public bool Equals (ColorScheme other)
{
return other != null &&
EqualityComparer.Default.Equals (_normal, other._normal) &&
EqualityComparer.Default.Equals (_focus, other._focus) &&
EqualityComparer.Default.Equals (_hotNormal, other._hotNormal) &&
EqualityComparer.Default.Equals (_hotFocus, other._hotFocus) &&
EqualityComparer.Default.Equals (_disabled, other._disabled);
}
///
/// Returns a hashcode for this instance.
///
/// hashcode for this instance
public override int GetHashCode ()
{
int hashCode = -1242460230;
hashCode = hashCode * -1521134295 + _normal.GetHashCode ();
hashCode = hashCode * -1521134295 + _focus.GetHashCode ();
hashCode = hashCode * -1521134295 + _hotNormal.GetHashCode ();
hashCode = hashCode * -1521134295 + _hotFocus.GetHashCode ();
hashCode = hashCode * -1521134295 + _disabled.GetHashCode ();
return hashCode;
}
///
/// Compares two objects for equality.
///
///
///
/// true if the two objects are equivalent
public static bool operator == (ColorScheme left, ColorScheme right)
{
return EqualityComparer.Default.Equals (left, right);
}
///
/// Compares two objects for inequality.
///
///
///
/// true if the two objects are not equivalent
public static bool operator != (ColorScheme left, ColorScheme right)
{
return !(left == right);
}
}
///
/// The default s for the application.
///
public static class Colors {
static Colors ()
{
// Use reflection to dynamically create the default set of ColorSchemes from the list defined
// by the class.
ColorSchemes = typeof (Colors).GetProperties ()
.Where (p => p.PropertyType == typeof (ColorScheme))
.Select (p => new KeyValuePair (p.Name, new ColorScheme ())) // (ColorScheme)p.GetValue (p)))
.ToDictionary (t => t.Key, t => t.Value);
}
///
/// The application toplevel color scheme, for the default toplevel views.
///
///
///
/// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["TopLevel"];
///
///
public static ColorScheme TopLevel { get => GetColorScheme (); set => SetColorScheme (value); }
///
/// The base color scheme, for the default toplevel views.
///
///
///
/// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Base"];
///
///
public static ColorScheme Base { get => GetColorScheme (); set => SetColorScheme (value); }
///
/// The dialog color scheme, for standard popup dialog boxes
///
///
///
/// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Dialog"];
///
///
public static ColorScheme Dialog { get => GetColorScheme (); set => SetColorScheme (value); }
///
/// The menu bar color
///
///
///
/// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Menu"];
///
///
public static ColorScheme Menu { get => GetColorScheme (); set => SetColorScheme (value); }
///
/// The color scheme for showing errors.
///
///
///
/// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Error"];
///
///
public static ColorScheme Error { get => GetColorScheme (); set => SetColorScheme (value); }
static ColorScheme GetColorScheme ([CallerMemberName] string callerMemberName = null)
{
return ColorSchemes [callerMemberName];
}
static void SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string callerMemberName = null)
{
ColorSchemes [callerMemberName] = colorScheme;
colorScheme.caller = callerMemberName;
}
///
/// Provides the defined s.
///
public static Dictionary ColorSchemes { get; }
}
///
/// Cursors Visibility that are displayed
///
//
// Hexa value are set as 0xAABBCCDD where :
//
// AA stand for the TERMINFO DECSUSR parameter value to be used under Linux & MacOS
// BB stand for the NCurses curs_set parameter value to be used under Linux & MacOS
// CC stand for the CONSOLE_CURSOR_INFO.bVisible parameter value to be used under Windows
// DD stand for the CONSOLE_CURSOR_INFO.dwSize parameter value to be used under Windows
//
public enum CursorVisibility {
///
/// Cursor caret has default
///
/// Works under Xterm-like terminal otherwise this is equivalent to . This default directly depends of the XTerm user configuration settings so it could be Block, I-Beam, Underline with possible blinking.
Default = 0x00010119,
///
/// Cursor caret is hidden
///
Invisible = 0x03000019,
///
/// Cursor caret is normally shown as a blinking underline bar _
///
Underline = 0x03010119,
///
/// Cursor caret is normally shown as a underline bar _
///
/// Under Windows, this is equivalent to
UnderlineFix = 0x04010119,
///
/// Cursor caret is displayed a blinking vertical bar |
///
/// Works under Xterm-like terminal otherwise this is equivalent to
Vertical = 0x05010119,
///
/// Cursor caret is displayed a blinking vertical bar |
///
/// Works under Xterm-like terminal otherwise this is equivalent to
VerticalFix = 0x06010119,
///
/// Cursor caret is displayed as a blinking block ▉
///
Box = 0x01020164,
///
/// Cursor caret is displayed a block ▉
///
/// Works under Xterm-like terminal otherwise this is equivalent to
BoxFix = 0x02020164,
}
/////
///// Special characters that can be drawn with
/////
//public enum SpecialChar {
// ///
// /// Horizontal line character.
// ///
// HLine,
// ///
// /// Vertical line character.
// ///
// VLine,
// ///
// /// Stipple pattern
// ///
// Stipple,
// ///
// /// Diamond character
// ///
// Diamond,
// ///
// /// Upper left corner
// ///
// ULCorner,
// ///
// /// Lower left corner
// ///
// LLCorner,
// ///
// /// Upper right corner
// ///
// URCorner,
// ///
// /// Lower right corner
// ///
// LRCorner,
// ///
// /// Left tee
// ///
// LeftTee,
// ///
// /// Right tee
// ///
// RightTee,
// ///
// /// Top tee
// ///
// TopTee,
// ///
// /// The bottom tee.
// ///
// BottomTee,
//}
///
/// ConsoleDriver is an abstract class that defines the requirements for a console driver.
/// There are currently three implementations: (for Unix and Mac), , and that uses the .NET Console API.
///
public abstract class ConsoleDriver {
///
/// The handler fired when the terminal is resized.
///
protected Action TerminalResized;
///
/// The current number of columns in the terminal.
///
public abstract int Cols { get; }
///
/// The current number of rows in the terminal.
///
public abstract int Rows { get; }
///
/// The current left in the terminal.
///
public abstract int Left { get; }
///
/// The current top in the terminal.
///
public abstract int Top { get; }
///
/// Get the operation system clipboard.
///
public abstract IClipboard Clipboard { get; }
///
/// If false height is measured by the window height and thus no scrolling.
/// If true then height is measured by the buffer height, enabling scrolling.
///
public abstract bool HeightAsBuffer { get; set; }
///
/// Initializes the driver
///
/// Method to invoke when the terminal is resized.
public abstract void Init (Action terminalResized);
///
/// Moves the cursor to the specified column and row.
///
/// Column to move the cursor to.
/// Row to move the cursor to.
public abstract void Move (int col, int row);
///
/// Adds the specified rune to the display at the current cursor position
///
/// Rune to add.
public abstract void AddRune (Rune rune);
///
/// Ensures a Rune is not a control character and can be displayed by translating characters below 0x20
/// to equivalent, printable, Unicode chars.
///
/// Rune to translate
///
public static Rune MakePrintable (Rune c)
{
if (c <= 0x1F || (c >= 0x80 && c <= 0x9F)) {
// ASCII (C0) control characters.
// C1 control characters (https://www.aivosto.com/articles/control-characters.html#c1)
return new Rune (c + 0x2400);
} else {
return c;
}
}
///
/// Adds the specified
///
/// String.
public abstract void AddStr (ustring str);
///
/// Prepare the driver and set the key and mouse events handlers.
///
/// The main loop.
/// The handler for ProcessKey
/// The handler for key down events
/// The handler for key up events
/// The handler for mouse events
public abstract void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler);
///
/// Updates the screen to reflect all the changes that have been done to the display buffer
///
public abstract void Refresh ();
///
/// Updates the location of the cursor position
///
public abstract void UpdateCursor ();
///
/// Retreive the cursor caret visibility
///
/// The current
/// true upon success
public abstract bool GetCursorVisibility (out CursorVisibility visibility);
///
/// Change the cursor caret visibility
///
/// The wished
/// true upon success
public abstract bool SetCursorVisibility (CursorVisibility visibility);
///
/// Ensure the cursor visibility
///
/// true upon success
public abstract bool EnsureCursorVisibility ();
///
/// Ends the execution of the console driver.
///
public abstract void End ();
///
/// Redraws the physical screen with the contents that have been queued up via any of the printing commands.
///
public abstract void UpdateScreen ();
///
/// Selects the specified attribute as the attribute to use for future calls to AddRune, AddString.
///
/// C.
public abstract void SetAttribute (Attribute c);
///
/// Set Colors from limit sets of colors.
///
/// Foreground.
/// Background.
public abstract void SetColors (ConsoleColor foreground, ConsoleColor background);
// Advanced uses - set colors to any pre-set pairs, you would need to init_color
// that independently with the R, G, B values.
///
/// Advanced uses - set colors to any pre-set pairs, you would need to init_color
/// that independently with the R, G, B values.
///
/// Foreground color identifier.
/// Background color identifier.
public abstract void SetColors (short foregroundColorId, short backgroundColorId);
///
/// Allows sending keys without typing on a keyboard.
///
/// The character key.
/// The key.
/// If shift key is sending.
/// If alt key is sending.
/// If control key is sending.
public abstract void SendKeys (char keyChar, ConsoleKey key, bool shift, bool alt, bool control);
///
/// Set the handler when the terminal is resized.
///
///
public void SetTerminalResized (Action terminalResized)
{
TerminalResized = terminalResized;
}
///
/// 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).
/// Not yet implemented.
///
public virtual void DrawWindowTitle (Rect region, ustring title, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom, TextAlignment textAlignment = TextAlignment.Left)
{
var width = region.Width - (paddingLeft + 2) * 2;
if (!ustring.IsNullOrEmpty (title) && width > 4 && region.Y + paddingTop <= region.Y + paddingBottom) {
Move (region.X + 1 + paddingLeft, region.Y + paddingTop);
AddRune (' ');
var str = title.RuneCount >= width ? title [0, width - 2] : title;
AddStr (str);
AddRune (' ');
}
}
///
/// Enables diagnostic functions
///
[Flags]
public enum DiagnosticFlags : uint {
///
/// All diagnostics off
///
Off = 0b_0000_0000,
///
/// When enabled, will draw a
/// ruler in the frame for any side with a padding value greater than 0.
///
FrameRuler = 0b_0000_0001,
///
/// When Enabled, will use
/// 'L', 'R', 'T', and 'B' for padding instead of ' '.
///
FramePadding = 0b_0000_0010,
}
///
/// Set flags to enable/disable diagnostics.
///
public static DiagnosticFlags Diagnostics { get; set; }
///
/// Draws a frame for a window with padding and an 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 virtual void DrawWindowFrame (Rect region, int paddingLeft = 0, int paddingTop = 0, int paddingRight = 0, int paddingBottom = 0, bool border = true, bool fill = false)
{
char clearChar = ' ';
char leftChar = clearChar;
char rightChar = clearChar;
char topChar = clearChar;
char bottomChar = clearChar;
if ((Diagnostics & DiagnosticFlags.FramePadding) == DiagnosticFlags.FramePadding) {
leftChar = 'L';
rightChar = 'R';
topChar = 'T';
bottomChar = 'B';
clearChar = 'C';
}
void AddRuneAt (int col, int row, Rune ch)
{
Move (col, row);
AddRune (ch);
}
// fwidth is count of hLine chars
int fwidth = (int)(region.Width - (paddingRight + paddingLeft));
// fheight is count of vLine chars
int fheight = (int)(region.Height - (paddingBottom + paddingTop));
// fleft is location of left frame line
int fleft = region.X + paddingLeft - 1;
// fright is location of right frame line
int fright = fleft + fwidth + 1;
// ftop is location of top frame line
int ftop = region.Y + paddingTop - 1;
// fbottom is locaiton of bottom frame line
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 < region.X + region.Width; c++) {
AddRuneAt (c, r, topChar);
}
}
}
// Outside top-left
for (int c = region.X; c < fleft; c++) {
AddRuneAt (c, ftop, leftChar);
}
// Frame top-left corner
AddRuneAt (fleft, ftop, paddingTop >= 0 ? (paddingLeft >= 0 ? uLCorner : hLine) : leftChar);
// Frame top
for (int c = fleft + 1; c < fleft + 1 + fwidth; c++) {
AddRuneAt (c, ftop, paddingTop > 0 ? hLine : topChar);
}
// Frame top-right corner
if (fright > fleft) {
AddRuneAt (fright, ftop, paddingTop >= 0 ? (paddingRight >= 0 ? uRCorner : hLine) : rightChar);
}
// Outside top-right corner
for (int c = fright + 1; c < fright + paddingRight; c++) {
AddRuneAt (c, ftop, rightChar);
}
// 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, leftChar);
}
// Frame left
AddRuneAt (fleft, r, paddingLeft > 0 ? vLine : leftChar);
// Fill
if (fill) {
for (int x = fleft + 1; x < fright; x++) {
AddRuneAt (x, r, clearChar);
}
}
// Frame right
if (fright > fleft) {
var v = vLine;
if ((Diagnostics & DiagnosticFlags.FrameRuler) == DiagnosticFlags.FrameRuler) {
v = (char)(((int)'0') + ((r - ftop) % 10)); // vLine;
}
AddRuneAt (fright, r, paddingRight > 0 ? v : rightChar);
}
// Outside right
for (int c = fright + 1; c < fright + paddingRight; c++) {
AddRuneAt (c, r, rightChar);
}
}
// Outside Bottom
for (int c = region.X; c < region.X + region.Width; c++) {
AddRuneAt (c, fbottom, leftChar);
}
// Frame bottom-left
AddRuneAt (fleft, fbottom, paddingLeft > 0 ? lLCorner : leftChar);
if (fright > fleft) {
// Frame bottom
for (int c = fleft + 1; c < fright; c++) {
var h = hLine;
if ((Diagnostics & DiagnosticFlags.FrameRuler) == DiagnosticFlags.FrameRuler) {
h = (char)(((int)'0') + ((c - fleft) % 10)); // hLine;
}
AddRuneAt (c, fbottom, paddingBottom > 0 ? h : bottomChar);
}
// Frame bottom-right
AddRuneAt (fright, fbottom, paddingRight > 0 ? (paddingBottom > 0 ? lRCorner : hLine) : rightChar);
}
// Outside right
for (int c = fright + 1; c < fright + paddingRight; c++) {
AddRuneAt (c, fbottom, rightChar);
}
}
// 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 < region.X + region.Width; c++) {
AddRuneAt (c, r, bottomChar);
}
}
}
}
///
/// Draws a frame on the specified region with the specified padding around the frame.
///
/// Screen relative 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 API has been superseded by .
/// This API is equivalent to calling DrawWindowFrame(Rect, p - 1, p - 1, p - 1, p - 1). In other words,
/// A padding value of 0 means there is actually a one cell border.
///
public virtual void DrawFrame (Rect region, int padding, bool fill)
{
// DrawFrame assumes the border is always at least one row/col thick
// DrawWindowFrame assumes a padding of 0 means NO padding and no frame
DrawWindowFrame (new Rect (region.X, region.Y, region.Width, region.Height),
padding + 1, padding + 1, padding + 1, padding + 1, border: false, fill: fill);
}
///
/// Suspend the application, typically needs to save the state, suspend the app and upon return, reset the console driver.
///
public abstract void Suspend ();
Rect clip;
///
/// Controls the current clipping region that AddRune/AddStr is subject to.
///
/// The clip.
public Rect Clip {
get => clip;
set => this.clip = value;
}
///
/// Start of mouse moves.
///
public abstract void StartReportingMouseMoves ();
///
/// Stop reporting mouses moves.
///
public abstract void StopReportingMouseMoves ();
///
/// Disables the cooked event processing from the mouse driver. At startup, it is assumed mouse events are cooked.
///
public abstract void UncookMouse ();
///
/// Enables the cooked event processing from the mouse driver
///
public abstract void CookMouse ();
///
/// Horizontal line character.
///
public Rune HLine = '\u2500';
///
/// Vertical line character.
///
public Rune VLine = '\u2502';
///
/// Stipple pattern
///
public Rune Stipple = '\u2591';
///
/// Diamond character
///
public Rune Diamond = '\u25ca';
///
/// Upper left corner
///
public Rune ULCorner = '\u250C';
///
/// Lower left corner
///
public Rune LLCorner = '\u2514';
///
/// Upper right corner
///
public Rune URCorner = '\u2510';
///
/// Lower right corner
///
public Rune LRCorner = '\u2518';
///
/// Left tee
///
public Rune LeftTee = '\u251c';
///
/// Right tee
///
public Rune RightTee = '\u2524';
///
/// Top tee
///
public Rune TopTee = '\u252c';
///
/// The bottom tee.
///
public Rune BottomTee = '\u2534';
///
/// Checkmark.
///
public Rune Checked = '\u221a';
///
/// Un-checked checkmark.
///
public Rune UnChecked = '\u2574';
///
/// Selected mark.
///
public Rune Selected = '\u25cf';
///
/// Un-selected selected mark.
///
public Rune UnSelected = '\u25cc';
///
/// Right Arrow.
///
public Rune RightArrow = '\u25ba';
///
/// Left Arrow.
///
public Rune LeftArrow = '\u25c4';
///
/// Down Arrow.
///
public Rune DownArrow = '\u25bc';
///
/// Up Arrow.
///
public Rune UpArrow = '\u25b2';
///
/// Left indicator for default action (e.g. for ).
///
public Rune LeftDefaultIndicator = '\u25e6';
///
/// Right indicator for default action (e.g. for ).
///
public Rune RightDefaultIndicator = '\u25e6';
///
/// Left frame/bracket (e.g. '[' for ).
///
public Rune LeftBracket = '[';
///
/// Right frame/bracket (e.g. ']' for ).
///
public Rune RightBracket = ']';
///
/// On Segment indicator for meter views (e.g. .
///
public Rune OnMeterSegment = '\u258c';
///
/// Off Segment indicator for meter views (e.g. .
///
public Rune OffMeterSegement = ' ';
///
/// Make the attribute for the foreground and background colors.
///
/// Foreground.
/// Background.
///
public abstract Attribute MakeAttribute (Color fore, Color back);
///
/// Gets the current .
///
/// The current attribute.
public abstract Attribute GetAttribute ();
}
}