diff --git a/Application.cs b/Application.cs index 3883d3429..31eb369fb 100644 --- a/Application.cs +++ b/Application.cs @@ -1,20 +1,15 @@ +// +// +// Pending: +// - Check for NeedDisplay on the hierarchy and repaint +// - Layout support +// +// Optimziations +// - Add rendering limitation to the exposed area using System; using System.Collections.Generic; namespace Terminal { - public struct Rect { - public int X, Y, Width, Height; - - public Rect (int x, int y, int width, int height) - { - X = x; - Y = y; - Width = width; - Height = height; - } - - public override string ToString() => $"[{X},{Y}:{Width},{Height}]"; - } public class Responder { public virtual Responder Next { get; set; } @@ -32,16 +27,36 @@ namespace Terminal { } public class View : Responder { + View container = null; public static ConsoleDriver Driver = Application.Driver; public static IList empty = new List(0).AsReadOnly (); List subviews; public IList Subviews => subviews == null ? empty : subviews.AsReadOnly (); + internal bool NeedDisplay { get; private set; } = true; + // The frame for the object Rect frame; + // The offset of the first child view inside the view + Point offset; + + // The frame for this view + public Rect Frame { + get => frame; + set { + frame = value; + SetNeedsDisplay (); + } + } + public View (Rect frame) { - this.frame = frame; + this.Frame = frame; + } + + public void SetNeedsDisplay () + { + NeedDisplay = true; } public void AddSubview (View view) @@ -53,7 +68,53 @@ namespace Terminal { subviews.Add (view); } - + public void GetRealRowCol (int col, int row, out int rcol, out int rrow) + { + // Computes the real row, col relative to the screen. + rrow = row; + rcol = col; + var ccontainer = container; + while (ccontainer != null){ + rrow += container.frame.Y; + rcol += container.frame.X; + ccontainer = ccontainer.container; + } + + // The following ensures that the cursor is always in the screen boundaries. + rrow = Math.Max (0, Math.Min (rrow, Driver.Rows-1)); + rcol = Math.Max (0, Math.Min (rcol, Driver.Cols-1)); + } + + public void Move (int col, int row) + { + GetRealRowCol (col, row, out var rcol, out var rrow); + Driver.Move (rcol, rrow); + } + + public void AddCh (int col, int row, int ch) + { + if (row < 0 || col < 0) + return; + if (row > frame.Height-1 || col > frame.Width-1) + return; + Move (col, row); + Driver.AddCh (ch); + } + + public virtual void Redraw () + { + var clipRect = new Rect (offset, frame.Size); + + foreach (var view in subviews){ + if (view.NeedDisplay){ + if (view.Frame.IntersectsWith (clipRect)){ + view.Redraw (); + } + view.NeedDisplay = false; + } + } + NeedDisplay = false; + } } public class ViewController : Responder { @@ -66,10 +127,12 @@ namespace Terminal { } } - public class Window : View { + public class Toplevel : View { public ViewController RootViewController; + public bool ShowFrame; + - public Window (Rect frame) : base (frame) + public Toplevel (Rect frame) : base (frame) { } @@ -78,15 +141,41 @@ namespace Terminal { Application.MakeFirstResponder (this); } - public static Window Toplevel () + public static Toplevel Create () { return new Window (new Rect (0, 0, Driver.Cols, Driver.Rows)); } } + public class Window : Toplevel { + View contentView; + string title; + + public string Title { + get => title; + set { + title = value; + SetNeedsDisplay (); + } + } + + public Window (Rect frame, string title = null) : base (frame) + { + frame.Inflate (-1, -1); + contentView = new View (frame); + AddSubview (contentView); + } + + public override void Redraw () + { + + base.Redraw (); + } + } + public class Application { public static ConsoleDriver Driver = new CursesDriver (); - public Window MainWindow { get; private set; } + public Toplevel Top { get; private set; } public Mono.Terminal.MainLoop MainLoop { get; private set; } static Stack responders = new Stack (); @@ -103,12 +192,12 @@ namespace Terminal { public void Init () { - if (MainWindow != null) + if (Top != null) return; MainLoop = new Mono.Terminal.MainLoop (); - MainWindow = Window.Toplevel (); - responder = MainWindow; + Top = Toplevel.Create (); + responder = Top; MainLoop.AddWatch (0, Mono.Terminal.MainLoop.Condition.PollIn, x => { //ProcessChar (); diff --git a/Event.cs b/Event.cs new file mode 100644 index 000000000..b59801f5b --- /dev/null +++ b/Event.cs @@ -0,0 +1,28 @@ +namespace Terminal { + + public class Event { + public class Key : Event { + public int Code { get; private set; } + + public Key (int code) + { + Code = code; + } + } + + public class Mouse : Event { + } + + public static Event CreateMouseEvent () + { + return new Mouse (); + } + + public static Event CreateKeyEvent (int code) + { + return new Key (code); + } + + } + +} \ No newline at end of file diff --git a/Terminal.csproj b/Terminal.csproj index 3b5e2f66b..97d44d2bd 100644 --- a/Terminal.csproj +++ b/Terminal.csproj @@ -35,6 +35,9 @@ + + + diff --git a/Types/Point.cs b/Types/Point.cs new file mode 100644 index 000000000..4b6b4c9d9 --- /dev/null +++ b/Types/Point.cs @@ -0,0 +1,227 @@ +// +// System.Drawing.Point.cs +// +// Author: +// Mike Kestner (mkestner@speakeasy.net) +// +// Copyright (C) 2001 Mike Kestner +// Copyright (C) 2004 Novell, Inc. http://www.novell.com +// + +using System; +using System.Globalization; + +namespace Terminal +{ + public struct Point + { + // Private x and y coordinate fields. + public int X, Y; + + // ----------------------- + // Public Shared Members + // ----------------------- + + /// + /// Empty Shared Field + /// + /// + /// + /// An uninitialized Point Structure. + /// + + public static readonly Point Empty; + + /// + /// Addition Operator + /// + /// + /// + /// Translates a Point using the Width and Height + /// properties of the given Size. + /// + + public static Point operator + (Point pt, Size sz) + { + return new Point (pt.X + sz.Width, pt.Y + sz.Height); + } + + /// + /// Equality Operator + /// + /// + /// + /// Compares two Point objects. The return value is + /// based on the equivalence of the X and Y properties + /// of the two points. + /// + + public static bool operator == (Point left, Point right) + { + return ((left.X == right.X) && (left.Y == right.Y)); + } + + /// + /// Inequality Operator + /// + /// + /// + /// Compares two Point objects. The return value is + /// based on the equivalence of the X and Y properties + /// of the two points. + /// + + public static bool operator != (Point left, Point right) + { + return ((left.X != right.X) || (left.Y != right.Y)); + } + + /// + /// Subtraction Operator + /// + /// + /// + /// Translates a Point using the negation of the Width + /// and Height properties of the given Size. + /// + + public static Point operator - (Point pt, Size sz) + { + return new Point (pt.X - sz.Width, pt.Y - sz.Height); + } + + /// + /// Point to Size Conversion + /// + /// + /// + /// Returns a Size based on the Coordinates of a given + /// Point. Requires explicit cast. + /// + + public static explicit operator Size (Point p) + { + return new Size (p.X, p.Y); + } + + // ----------------------- + // Public Constructors + // ----------------------- + /// + /// Point Constructor + /// + /// + /// + /// Creates a Point from a Size value. + /// + + public Point (Size sz) + { + X = sz.Width; + Y = sz.Height; + } + + /// + /// Point Constructor + /// + /// + /// + /// Creates a Point from a specified x,y coordinate pair. + /// + + public Point (int x, int y) + { + this.X = x; + this.Y = y; + } + + // ----------------------- + // Public Instance Members + // ----------------------- + + /// + /// IsEmpty Property + /// + /// + /// + /// Indicates if both X and Y are zero. + /// + public bool IsEmpty { + get { + return ((X == 0) && (Y == 0)); + } + } + + /// + /// Equals Method + /// + /// + /// + /// Checks equivalence of this Point and another object. + /// + + public override bool Equals (object obj) + { + if (!(obj is Point)) + return false; + + return (this == (Point) obj); + } + + /// + /// GetHashCode Method + /// + /// + /// + /// Calculates a hashing value. + /// + + public override int GetHashCode () + { + return X^Y; + } + + /// + /// Offset Method + /// + /// + /// + /// Moves the Point a specified distance. + /// + + public void Offset (int dx, int dy) + { + X += dx; + Y += dy; + } + + /// + /// ToString Method + /// + /// + /// + /// Formats the Point as a string in coordinate notation. + /// + + public override string ToString () + { + return string.Format ("{{X={0},Y={1}}}", X.ToString (CultureInfo.InvariantCulture), + Y.ToString (CultureInfo.InvariantCulture)); + } + public static Point Add (Point pt, Size sz) + { + return new Point (pt.X + sz.Width, pt.Y + sz.Height); + } + + public void Offset (Point p) + { + Offset (p.X, p.Y); + } + + public static Point Subtract (Point pt, Size sz) + { + return new Point (pt.X - sz.Width, pt.Y - sz.Height); + } + + } +} diff --git a/Types/Rect.cs b/Types/Rect.cs new file mode 100644 index 000000000..9ac19383e --- /dev/null +++ b/Types/Rect.cs @@ -0,0 +1,457 @@ +// +// System.Drawing.Rectangle.cs +// +// Author: +// Mike Kestner (mkestner@speakeasy.net) +// +// Copyright (C) 2001 Mike Kestner +// Copyright (C) 2004 Novell, Inc. http://www.novell.com +// + +using System; + +namespace Terminal +{ + public struct Rect + { + public int X, Y, Width, Height; + + /// + /// Empty Shared Field + /// + /// + /// + /// An uninitialized Rectangle Structure. + /// + + public static readonly Rect Empty; + + /// + /// FromLTRB Shared Method + /// + /// + /// + /// Produces a Rectangle structure from left, top, right + /// and bottom coordinates. + /// + + public static Rect FromLTRB (int left, int top, + int right, int bottom) + { + return new Rect (left, top, right - left, + bottom - top); + } + + /// + /// Inflate Shared Method + /// + /// + /// + /// Produces a new Rectangle by inflating an existing + /// Rectangle by the specified coordinate values. + /// + + public static Rect Inflate (Rect rect, int x, int y) + { + Rect r = new Rect (rect.Location, rect.Size); + r.Inflate (x, y); + return r; + } + + /// + /// Inflate Method + /// + /// + /// + /// Inflates the Rectangle by a specified width and height. + /// + + public void Inflate (int width, int height) + { + Inflate (new Size (width, height)); + } + + /// + /// Inflate Method + /// + /// + /// + /// Inflates the Rectangle by a specified Size. + /// + + public void Inflate (Size size) + { + X -= size.Width; + Y -= size.Height; + Width += size.Width * 2; + Height += size.Height * 2; + } + + /// + /// Intersect Shared Method + /// + /// + /// + /// Produces a new Rectangle by intersecting 2 existing + /// Rectangles. Returns null if there is no intersection. + /// + + public static Rect Intersect (Rect a, Rect b) + { + // MS.NET returns a non-empty rectangle if the two rectangles + // touch each other + if (!a.IntersectsWithInclusive (b)) + return Empty; + + return Rect.FromLTRB ( + Math.Max (a.Left, b.Left), + Math.Max (a.Top, b.Top), + Math.Min (a.Right, b.Right), + Math.Min (a.Bottom, b.Bottom)); + } + + /// + /// Intersect Method + /// + /// + /// + /// Replaces the Rectangle with the intersection of itself + /// and another Rectangle. + /// + + public void Intersect (Rect rect) + { + this = Rect.Intersect (this, rect); + } + + /// + /// Union Shared Method + /// + /// + /// + /// Produces a new Rectangle from the union of 2 existing + /// Rectangles. + /// + + public static Rect Union (Rect a, Rect b) + { + return FromLTRB (Math.Min (a.Left, b.Left), + Math.Min (a.Top, b.Top), + Math.Max (a.Right, b.Right), + Math.Max (a.Bottom, b.Bottom)); + } + + /// + /// Equality Operator + /// + /// + /// + /// Compares two Rectangle objects. The return value is + /// based on the equivalence of the Location and Size + /// properties of the two Rectangles. + /// + + public static bool operator == (Rect left, Rect right) + { + return ((left.Location == right.Location) && + (left.Size == right.Size)); + } + + /// + /// Inequality Operator + /// + /// + /// + /// Compares two Rectangle objects. The return value is + /// based on the equivalence of the Location and Size + /// properties of the two Rectangles. + /// + + public static bool operator != (Rect left, Rect right) + { + return ((left.Location != right.Location) || + (left.Size != right.Size)); + } + + + // ----------------------- + // Public Constructors + // ----------------------- + + /// + /// Rectangle Constructor + /// + /// + /// + /// Creates a Rectangle from Point and Size values. + /// + + public Rect (Point location, Size size) + { + X = location.X; + Y = location.Y; + Width = size.Width; + Height = size.Height; + } + + /// + /// Rectangle Constructor + /// + /// + /// + /// Creates a Rectangle from a specified x,y location and + /// width and height values. + /// + + public Rect (int x, int y, int width, int height) + { + this.X = x; + this.Y = y; + this.Width = width; + this.Height = height; + } + + + + /// + /// Bottom Property + /// + /// + /// + /// The Y coordinate of the bottom edge of the Rectangle. + /// Read only. + /// + public int Bottom { + get { + return Y + Height; + } + } + + /// + /// IsEmpty Property + /// + /// + /// + /// Indicates if the width or height are zero. Read only. + /// + public bool IsEmpty { + get { + return ((X == 0) && (Y == 0) && (Width == 0) && (Height == 0)); + } + } + + /// + /// Left Property + /// + /// + /// + /// The X coordinate of the left edge of the Rectangle. + /// Read only. + /// + + public int Left { + get { + return X; + } + } + + /// + /// Location Property + /// + /// + /// + /// The Location of the top-left corner of the Rectangle. + /// + + public Point Location { + get { + return new Point (X, Y); + } + set { + X = value.X; + Y = value.Y; + } + } + + /// + /// Right Property + /// + /// + /// + /// The X coordinate of the right edge of the Rectangle. + /// Read only. + /// + + public int Right { + get { + return X + Width; + } + } + + /// + /// Size Property + /// + /// + /// + /// The Size of the Rectangle. + /// + + public Size Size { + get { + return new Size (Width, Height); + } + set { + Width = value.Width; + Height = value.Height; + } + } + + /// + /// Top Property + /// + /// + /// + /// The Y coordinate of the top edge of the Rectangle. + /// Read only. + /// + + public int Top { + get { + return Y; + } + } + + /// + /// Contains Method + /// + /// + /// + /// Checks if an x,y coordinate lies within this Rectangle. + /// + + public bool Contains (int x, int y) + { + return ((x >= Left) && (x < Right) && + (y >= Top) && (y < Bottom)); + } + + /// + /// Contains Method + /// + /// + /// + /// Checks if a Point lies within this Rectangle. + /// + + public bool Contains (Point pt) + { + return Contains (pt.X, pt.Y); + } + + /// + /// Contains Method + /// + /// + /// + /// Checks if a Rectangle lies entirely within this + /// Rectangle. + /// + + public bool Contains (Rect rect) + { + return (rect == Intersect (this, rect)); + } + + /// + /// Equals Method + /// + /// + /// + /// Checks equivalence of this Rectangle and another object. + /// + + public override bool Equals (object obj) + { + if (!(obj is Rect)) + return false; + + return (this == (Rect) obj); + } + + /// + /// GetHashCode Method + /// + /// + /// + /// Calculates a hashing value. + /// + + public override int GetHashCode () + { + return (Height + Width) ^ X + Y; + } + + /// + /// IntersectsWith Method + /// + /// + /// + /// Checks if a Rectangle intersects with this one. + /// + + public bool IntersectsWith (Rect rect) + { + return !((Left >= rect.Right) || (Right <= rect.Left) || + (Top >= rect.Bottom) || (Bottom <= rect.Top)); + } + + private bool IntersectsWithInclusive (Rect r) + { + return !((Left > r.Right) || (Right < r.Left) || + (Top > r.Bottom) || (Bottom < r.Top)); + } + + /// + /// Offset Method + /// + /// + /// + /// Moves the Rectangle a specified distance. + /// + + public void Offset (int x, int y) + { + this.X += x; + this.Y += y; + } + + /// + /// Offset Method + /// + /// + /// + /// Moves the Rectangle a specified distance. + /// + + public void Offset (Point pos) + { + X += pos.X; + Y += pos.Y; + } + + /// + /// ToString Method + /// + /// + /// + /// Formats the Rectangle as a string in (x,y,w,h) notation. + /// + + public override string ToString () + { + return String.Format ("{{X={0},Y={1},Width={2},Height={3}}}", + X, Y, Width, Height); + } + + } +} diff --git a/Types/Size.cs b/Types/Size.cs new file mode 100644 index 000000000..2e1891aab --- /dev/null +++ b/Types/Size.cs @@ -0,0 +1,225 @@ +// +// System.Drawing.Size.cs +// +// Author: +// Mike Kestner (mkestner@speakeasy.net) +// +// Copyright (C) 2001 Mike Kestner +// Copyright (C) 2004 Novell, Inc. http://www.novell.com +// + +using System; + +namespace Terminal { + public struct Size + { + private int width, height; + public static readonly Size Empty; + + /// + /// Addition Operator + /// + /// + /// + /// Addition of two Size structures. + /// + + public static Size operator + (Size sz1, Size sz2) + { + return new Size (sz1.Width + sz2.Width, + sz1.Height + sz2.Height); + } + + /// + /// Equality Operator + /// + /// + /// + /// Compares two Size objects. The return value is + /// based on the equivalence of the Width and Height + /// properties of the two Sizes. + /// + + public static bool operator == (Size sz1, Size sz2) + { + return ((sz1.Width == sz2.Width) && + (sz1.Height == sz2.Height)); + } + + /// + /// Inequality Operator + /// + /// + /// + /// Compares two Size objects. The return value is + /// based on the equivalence of the Width and Height + /// properties of the two Sizes. + /// + + public static bool operator != (Size sz1, Size sz2) + { + return ((sz1.Width != sz2.Width) || + (sz1.Height != sz2.Height)); + } + + /// + /// Subtraction Operator + /// + /// + /// + /// Subtracts two Size structures. + /// + + public static Size operator - (Size sz1, Size sz2) + { + return new Size (sz1.Width - sz2.Width, + sz1.Height - sz2.Height); + } + + /// + /// Size to Point Conversion + /// + /// + /// + /// Returns a Point based on the dimensions of a given + /// Size. Requires explicit cast. + /// + + public static explicit operator Point (Size size) + { + return new Point (size.Width, size.Height); + } + + /// + /// Size Constructor + /// + /// + /// + /// Creates a Size from a Point value. + /// + + public Size (Point pt) + { + width = pt.X; + height = pt.Y; + } + + /// + /// Size Constructor + /// + /// + /// + /// Creates a Size from specified dimensions. + /// + + public Size (int width, int height) + { + this.width = width; + this.height = height; + } + + /// + /// IsEmpty Property + /// + /// + /// + /// Indicates if both Width and Height are zero. + /// + + public bool IsEmpty { + get { + return ((width == 0) && (height == 0)); + } + } + + /// + /// Width Property + /// + /// + /// + /// The Width coordinate of the Size. + /// + + public int Width { + get { + return width; + } + set { + width = value; + } + } + + /// + /// Height Property + /// + /// + /// + /// The Height coordinate of the Size. + /// + + public int Height { + get { + return height; + } + set { + height = value; + } + } + + /// + /// Equals Method + /// + /// + /// + /// Checks equivalence of this Size and another object. + /// + + public override bool Equals (object obj) + { + if (!(obj is Size)) + return false; + + return (this == (Size) obj); + } + + /// + /// GetHashCode Method + /// + /// + /// + /// Calculates a hashing value. + /// + + public override int GetHashCode () + { + return width^height; + } + + /// + /// ToString Method + /// + /// + /// + /// Formats the Size as a string in coordinate notation. + /// + + public override string ToString () + { + return String.Format ("{{Width={0}, Height={1}}}", width, height); + } + + public static Size Add (Size sz1, Size sz2) + { + return new Size (sz1.Width + sz2.Width, + sz1.Height + sz2.Height); + + } + + public static Size Subtract (Size sz1, Size sz2) + { + return new Size (sz1.Width - sz2.Width, + sz1.Height - sz2.Height); + } + + } +} diff --git a/demo.cs b/demo.cs new file mode 100644 index 000000000..17ce5b4ce --- /dev/null +++ b/demo.cs @@ -0,0 +1,9 @@ +using Terminal; + +class Demo { + static void Main () + { + var app = new Application (); + + } +} \ No newline at end of file diff --git a/driver.cs b/driver.cs index 552979091..27358bf47 100644 --- a/driver.cs +++ b/driver.cs @@ -1,20 +1,45 @@ using System; using System.Collections.Generic; -using C=Unix.Terminal; +using Unix.Terminal; namespace Terminal { + + public class ColorScheme { + public int Normal; + public int Focus; + public int HotNormal; + public int HotFocus; + public int Marked => HotNormal; + public int MarkedSelected => HotFocus; + + } public abstract class ConsoleDriver { public abstract int Cols {get;} public abstract int Rows {get;} public abstract void Init (); + public abstract void Move (int line, int col); + public abstract void AddCh (int ch); + + // Colors used for widgets + public static ColorScheme ColorBase, ColorDialog, ColorMenu, ColorError; } public class CursesDriver : ConsoleDriver { - public override int Cols => C.Curses.Cols; - public override int Rows => C.Curses.Lines; + public override int Cols => Curses.Cols; + public override int Rows => Curses.Lines; - public C.Curses.Window window; + public override void Move(int col, int row) => Curses.move (row, col); + public override void AddCh(int ch) => Curses.addch (ch); + + public Curses.Window window; + + static short last_color_pair; + static int MakeColor (short f, short b) + { + Curses.InitColorPair (++last_color_pair, f, b); + return Curses.ColorPair (last_color_pair); + } public override void Init() { @@ -22,17 +47,61 @@ namespace Terminal { return; try { - window = C.Curses.initscr (); + window = Curses.initscr (); } catch (Exception e){ Console.WriteLine ("Curses failed to initialize, the exception is: " + e); } - C.Curses.raw (); - C.Curses.noecho (); - C.Curses.Window.Standard.keypad (true); + Curses.raw (); + Curses.noecho (); + Curses.Window.Standard.keypad (true); - if (C.Curses.HasColors){ - C.Curses.StartColor (); - C.Curses.UseDefaultColors (); + ColorBase = new ColorScheme (); + ColorDialog = new ColorScheme (); + ColorMenu = new ColorScheme (); + ColorError = new ColorScheme (); + + if (Curses.HasColors){ + Curses.StartColor (); + Curses.UseDefaultColors (); + + ColorBase.Normal = MakeColor (Curses.COLOR_WHITE, Curses.COLOR_BLUE); + ColorBase.Focus = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_CYAN); + ColorBase.HotNormal = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_BLUE); + ColorBase.HotFocus = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_CYAN); + + ColorMenu.Normal = Curses.A_BOLD | MakeColor (Curses.COLOR_WHITE, Curses.COLOR_CYAN); + ColorMenu.Focus = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_CYAN); + ColorMenu.HotNormal = Curses.A_BOLD | MakeColor (Curses.COLOR_WHITE, Curses.COLOR_BLACK); + ColorMenu.HotFocus = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_BLACK); + ColorDialog.Normal = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_WHITE); + ColorDialog.Focus = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_CYAN); + ColorDialog.HotNormal = MakeColor (Curses.COLOR_BLUE, Curses.COLOR_WHITE); + ColorDialog.HotFocus = MakeColor (Curses.COLOR_BLUE, Curses.COLOR_CYAN); + + ColorError.Normal = Curses.A_BOLD | MakeColor (Curses.COLOR_WHITE, Curses.COLOR_RED); + ColorError.Focus = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_WHITE); + ColorError.HotNormal = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_RED); + ColorError.HotFocus = ColorError.HotNormal; + } else { + ColorBase.Normal = Curses.A_NORMAL; + ColorBase.Focus = Curses.A_REVERSE; + ColorBase.HotNormal = Curses.A_BOLD; + ColorBase.HotFocus = Curses.A_BOLD | Curses.A_REVERSE; + + ColorMenu.Normal = Curses.A_REVERSE; + ColorMenu.Focus = Curses.A_NORMAL; + ColorMenu.HotNormal = Curses.A_BOLD; + ColorMenu.HotFocus = Curses.A_NORMAL; + + ColorDialog.Normal = Curses.A_REVERSE; + ColorDialog.Focus = Curses.A_NORMAL; + ColorDialog.HotNormal = Curses.A_BOLD; + ColorDialog.HotFocus = Curses.A_NORMAL; + + ColorError.Normal = Curses.A_BOLD; + ColorError.Focus = Curses.A_BOLD | Curses.A_REVERSE; + ColorError.HotNormal = Curses.A_BOLD | Curses.A_REVERSE; + ColorError.HotFocus = Curses.A_REVERSE; } } }