Browse Source

Works, and shows the problem with lack of clipping for Window objects

Miguel de Icaza 7 years ago
parent
commit
693c5e3452
4 changed files with 353 additions and 96 deletions
  1. 251 39
      Application.cs
  2. 3 3
      Terminal.csproj
  3. 4 2
      demo.cs
  4. 95 52
      driver.cs

+ 251 - 39
Application.cs

@@ -12,7 +12,7 @@ using System.Collections.Generic;
 namespace Terminal {
 
     public class Responder {
-        public virtual bool CanFocus => true;
+        public virtual bool CanFocus { get; set; }
         public bool HasFocus { get; internal set; }
 
         // Key handling
@@ -49,23 +49,96 @@ namespace Terminal {
         public View (Rect frame)
         {
             this.Frame = frame;
+            CanFocus = false;
         }
 
+        /// <summary>
+        /// Invoke to flag that this view needs to be redisplayed, by any code
+        /// that alters the state of the view.
+        /// </summary>
         public void SetNeedsDisplay ()
         {
             NeedDisplay = true;
         }
 
-        public void AddSubview (View view)
+        /// <summary>
+        ///   Adds a subview to this view.
+        /// </summary>
+        /// <remarks>
+        /// </remarks>
+        public void Add (View view)
         {
             if (view == null)
                 return;
             if (subviews == null)
                 subviews = new List<View> ();
             subviews.Add (view);
+            view.container = this;
+            if (view.CanFocus)
+                CanFocus = true;
         }
 
-        public void GetRealRowCol (int col, int row, out int rcol, out int rrow)
+        /// <summary>
+        ///   Removes all the widgets from this container.
+        /// </summary>
+        /// <remarks>
+        /// </remarks>
+        public virtual void RemoveAll ()
+        {
+            if (subviews == null)
+                return;
+
+            while (subviews.Count > 0) {
+                var view = subviews [0];
+                Remove (view);
+                subviews.RemoveAt (0);
+            }        
+        }
+
+        /// <summary>
+        ///   Removes a widget from this container.
+        /// </summary>
+        /// <remarks>
+        /// </remarks>
+        public virtual void Remove (View view)
+        {
+            if (view == null)
+                return;
+
+            subviews.Remove (view);
+            view.container = null;
+
+            if (subviews.Count < 1)
+                this.CanFocus = false;
+        }
+
+        /// <summary>
+        ///   Clears the view region with the current color.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     This clears the entire region used by this view.
+        ///   </para>
+        /// </remarks>
+        public void Clear ()
+        {
+            var h = Frame.Height;
+            var w = Frame.Width;
+            for (int line = 0; line < h; line++) {
+                Move (0, line);
+                for (int col = 0; col < w; col++) 
+                    Driver.AddCh (' ');
+            }
+        }
+
+        /// <summary>
+        /// Converts the (col,row) position from the view into a screen (col,row).  The values are clamped to (0..ScreenDim-1)
+        /// </summary>
+        /// <param name="col">View-based column.</param>
+        /// <param name="row">View-based row.</param>
+        /// <param name="rcol">Absolute column, display relative.</param>
+        /// <param name="rrow">Absolute row, display relative.</param>
+        internal void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
         {
             // Computes the real row, col relative to the screen.
             rrow = row;
@@ -78,16 +151,40 @@ namespace Terminal {
             }
 
             // 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));
+            if (clipped) {
+                rrow = Math.Max (0, Math.Min (rrow, Driver.Rows - 1));
+                rcol = Math.Max (0, Math.Min (rcol, Driver.Cols - 1));
+            }
+        }
+
+      
+
+        /// <summary>
+        /// Draws a frame in the current view, clipped by the boundary of this view
+        /// </summary>
+        /// <param name="rect">Rectangular region for the frame to be drawn.</param>
+        /// <param name="fill">If set to <c>true</c> it fill will the contents.</param>
+        public void DrawFrame (Rect rect, bool fill = false)
+        {
+            ViewToScreen (rect.X, rect.Y, out var x, out var y, clipped: false);
+            Driver.DrawFrame (new Rect (x, y, rect.Width, rect.Height), fill);
         }
 
+        /// <summary>
+        /// This moves the cursor to the specified column and row in the view.
+        /// </summary>
+        /// <returns>The move.</returns>
+        /// <param name="col">Col.</param>
+        /// <param name="row">Row.</param>
         public void Move (int col, int row)
         {
-            GetRealRowCol (col, row, out var rcol, out var rrow);
+            ViewToScreen (col, row, out var rcol, out var rrow);
             Driver.Move (rcol, rrow);
         }
 
+        /// <summary>
+        ///   Positions the cursor in the right position based on the currently focused view in the chain.
+        /// </summary>
         public virtual void PositionCursor ()
         {
             if (focused != null)
@@ -96,6 +193,12 @@ namespace Terminal {
                 Move (frame.X, frame.Y);
         }
 
+        /// <summary>
+        /// Displays the specified character in the specified column and row.
+        /// </summary>
+        /// <param name="col">Col.</param>
+        /// <param name="row">Row.</param>
+        /// <param name="ch">Ch.</param>
         public void AddCh (int col, int row, int ch)
         {
             if (row < 0 || col < 0)
@@ -106,21 +209,30 @@ namespace Terminal {
             Driver.AddCh (ch);
         }
 
+        /// <summary>
+        /// Performs a redraw of this view and its subviews, only redraws the views that have been flagged for a re-display.
+        /// </summary>
         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 ();
+            if (subviews != null) {
+                foreach (var view in subviews) {
+                    if (view.NeedDisplay) {
+                        if (view.Frame.IntersectsWith (clipRect)) {
+                            view.Redraw ();
+                        }
+                        view.NeedDisplay = false;
                     }
-                    view.NeedDisplay = false;
                 }
             }
             NeedDisplay = false;
         }
-        
+
+        /// <summary>
+        /// Focuses the specified sub-view.
+        /// </summary>
+        /// <param name="view">View.</param>
         public void SetFocus (View view)
         {
             if (view == null)
@@ -129,6 +241,15 @@ namespace Terminal {
                 return;
             if (focused == view)
                 return;
+
+            // Make sure that this view is a subview
+            View c;
+            for (c = view.container; c != null; c = c.container)
+                if (c == this)
+                    break;
+            if (c == null)
+                throw new ArgumentException ("the specified view is not part of the hierarchy of this view");
+            
             if (focused != null)
                 focused.HasFocus = false;
             focused = view;
@@ -138,12 +259,18 @@ namespace Terminal {
             focused.PositionCursor ();
         }
 
+        /// <summary>
+        /// Finds the first view in the hierarchy that wants to get the focus if nothing is currently focused, otherwise, it does nothing.
+        /// </summary>
         public void EnsureFocus ()
         {
             if (focused == null)
                 FocusFirst ();
         }
 
+        /// <summary>
+        /// Focuses the first focusable subview if one exists.
+        /// </summary>
         public void FocusFirst ()
         {
             foreach (var view in subviews){
@@ -154,6 +281,9 @@ namespace Terminal {
             }
         }
 
+        /// <summary>
+        /// Focuses the last focusable subview if one exists.
+        /// </summary>
         public void FocusLast ()
         {
             for (int i = subviews.Count; i > 0; ){
@@ -167,6 +297,10 @@ namespace Terminal {
             }
         }
 
+        /// <summary>
+        /// Focuses the previous view.
+        /// </summary>
+        /// <returns><c>true</c>, if previous was focused, <c>false</c> otherwise.</returns>
         public bool FocusPrev ()
         {
             if (focused == null){
@@ -200,6 +334,11 @@ namespace Terminal {
             }
             return false;
         }
+
+        /// <summary>
+        /// Focuses the next view.
+        /// </summary>
+        /// <returns><c>true</c>, if next was focused, <c>false</c> otherwise.</returns>
         public bool FocusNext ()
         {       
             if (focused == null){
@@ -239,7 +378,11 @@ namespace Terminal {
         }
     }
 
+    /// <summary>
+    /// Toplevel views can be modally executed.
+    /// </summary>
     public class Toplevel : View {
+        public bool Running;
 
         public Toplevel (Rect frame) : base (frame)
         {
@@ -247,10 +390,13 @@ namespace Terminal {
 
         public static Toplevel Create () 
         {
-            return new Window (new Rect (0, 0, Driver.Cols, Driver.Rows));
+            return new Toplevel (new Rect (0, 0, Driver.Cols, Driver.Rows));
         }
     }
 
+    /// <summary>
+    /// A toplevel view that draws a frame around its region
+    /// </summary>
     public class Window : Toplevel {
         View contentView;
         string title;
@@ -265,15 +411,34 @@ namespace Terminal {
 
         public Window (Rect frame, string title = null) : base (frame)
         {
+            this.Title = title;
             frame.Inflate (-1, -1);
             contentView = new View (frame);
-            AddSubview (contentView);
+            Add(contentView);
         }
 
-        public override void Redraw ()
+        void DrawFrame ()
         {
+            DrawFrame (Frame, true);
+        }
 
-            base.Redraw ();
+        public override void Redraw ()
+        {
+            Driver.SetColor (Colors.Base.Normal);
+            Clear ();
+            DrawFrame ();
+            if (HasFocus)
+                Driver.SetColor (Colors.Dialog.Normal);
+            var width = Frame.Width;
+            if (Title != null && width > 4) {
+                Move (0, 1);
+                Driver.AddCh (' ');
+                var str = Title.Length > width ? Title.Substring (0, width - 4) : Title;
+                Driver.AddStr (str);
+                Driver.AddCh (' ');
+            }
+            Driver.SetColor (Colors.Dialog.Normal);
+            contentView.Redraw ();
         }
     }
 
@@ -285,6 +450,15 @@ namespace Terminal {
         static Stack<View> toplevels = new Stack<View> ();
         static Responder focus;
 
+        /// <summary>
+        ///   This event is raised on each iteration of the
+        ///   main loop. 
+        /// </summary>
+        /// <remarks>
+        ///   See also <see cref="Timeout"/>
+        /// </remarks>
+        static public event EventHandler Iteration;
+
         public static void MakeFirstResponder (Responder newResponder)
         {
             if (newResponder == null)
@@ -293,11 +467,15 @@ namespace Terminal {
             throw new NotImplementedException ();
         }
 
+        /// <summary>
+        /// Initializes the Application
+        /// </summary>
         public static void Init ()
         {
             if (Top != null)
                 return;
 
+            Driver.Init ();
             MainLoop = new Mono.Terminal.MainLoop ();
             Top = Toplevel.Create ();  
             focus = Top;
@@ -310,11 +488,11 @@ namespace Terminal {
         }
 
         public class RunState : IDisposable {
-            internal RunState (View view)
+            internal RunState (Toplevel view)
             {
-                View = view;
+                Toplevel = view;
             }
-            internal View View;
+            internal Toplevel Toplevel;
 
             public void Dispose ()
             {
@@ -324,35 +502,29 @@ namespace Terminal {
 
             public virtual void Dispose (bool disposing)
             {
-                if (View != null){
-                    Application.End (View);
-                    View = null;
+                if (Toplevel != null){
+                    Application.End (Toplevel);
+                    Toplevel = null;
                 }
             }
         }
 
-        public void Run ()
-        {
-            Run (Top);
-        }
-
-        static public RunState Begin (View view)
+        static public RunState Begin (Toplevel toplevel)
         {
-            if (view == null)
-                    throw new ArgumentNullException ("view");
-            var rs = new RunState (view);
+            if (toplevel == null)
+                throw new ArgumentNullException (nameof(toplevel));
+            var rs = new RunState (toplevel);
 
             Init ();
             Driver.PrepareToRun ();
 
-            toplevels.Push (view);
+            toplevels.Push (toplevel);
 
-            view.LayoutSubviews ();
-            view.FocusFirst ();
-            Redraw (view);
-            view.PositionCursor ();
+            toplevel.LayoutSubviews ();
+            toplevel.FocusFirst ();
+            Redraw (toplevel);
+            toplevel.PositionCursor ();
             Driver.Refresh ();
-            
 
             return rs;
         }
@@ -405,9 +577,49 @@ namespace Terminal {
                 Refresh ();
         }
 
-        public void Run (View view)
+        /// <summary>
+        ///   Runs the main loop for the created dialog
+        /// </summary>
+        /// <remarks>
+        ///   Use the wait parameter to control whether this is a
+        ///   blocking or non-blocking call.
+        /// </remarks>
+        public static void RunLoop(RunState state, bool wait = true)
         {
-            
+            if (state == null)
+                throw new ArgumentNullException(nameof(state));
+            if (state.Toplevel == null)
+                throw new ObjectDisposedException("state");
+
+            for (state.Toplevel.Running = true; state.Toplevel.Running;) {
+                if (MainLoop.EventsPending(wait)){
+                    MainLoop.MainIteration();
+                    if (Iteration != null)
+                        Iteration(null, EventArgs.Empty);
+                }
+                else if (wait == false)
+                    return;
+            }
+        }
+
+        public static void Run ()
+        {
+            Run (Top);
+        }
+
+        /// <summary>
+        ///   Runs the main loop on the given container.
+        /// </summary>
+        /// <remarks>
+        ///   This method is used to start processing events
+        ///   for the main application, but it is also used to
+        ///   run modal dialog boxes.
+        /// </remarks>
+        public static void Run (Toplevel view)
+        {
+            var runToken = Begin (view);
+            RunLoop (runToken);
+            End (runToken);
         }
     }
 }

+ 3 - 3
Terminal.csproj

@@ -35,9 +35,9 @@
     <Compile Include="Application.cs" />
     <Compile Include="driver.cs" />
     <Compile Include="Event.cs" />
-    <Compile Include="Types\Point.cs"/>
-    <Compile Include="Types\Rect.cs"/>
-    <Compile Include="Types\Size.cs"/>
+    <Compile Include="Types\Point.cs" />
+    <Compile Include="Types\Rect.cs" />
+    <Compile Include="Types\Size.cs" />
     <Compile Include="demo.cs" />
   </ItemGroup>
   <ItemGroup>

+ 4 - 2
demo.cs

@@ -3,7 +3,9 @@ using Terminal;
 class Demo {
     static void Main ()
     {
-        var app = new Application ();
-        
+        Application.Init ();
+        var top = Application.Top;
+        top.Add (new Window (new Rect (10, 10, 20, 20), "Hello"));
+        Application.Run ();
     }
 }

+ 95 - 52
driver.cs

@@ -4,29 +4,45 @@ using Unix.Terminal;
 
 namespace Terminal {
     
+    public struct Color {
+        internal int value;
+        public Color (int v)
+        {
+            value = v;
+        }
+
+        public static implicit operator int (Color c) => c.value;
+        public static implicit operator Color (int v) => new Color (v);
+    }
+
     public class ColorScheme {
-        public int Normal;
-        public int Focus;
-        public int HotNormal;
-        public int HotFocus;
-        public int Marked => HotNormal;
-        public int MarkedSelected => HotFocus;
+        public Color Normal;
+        public Color Focus;
+        public Color HotNormal;
+        public Color HotFocus;
+        public Color Marked => HotNormal;
+        public Color MarkedSelected => HotFocus;
+    }
 
+    public static class Colors {
+        public static ColorScheme Base, Dialog, Menu, Error;
     }
 
     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 Move (int col, int row);
         public abstract void AddCh (int ch);
+        public abstract void AddStr (string str);
         public abstract void PrepareToRun ();
         public abstract void Refresh ();
         public abstract void End ();
         public abstract void RedrawTop ();
-        
+        public abstract void SetColor (Color c);
+        public abstract void DrawFrame (Rect region, bool fill);
+
         // Colors used for widgets
-        public static ColorScheme ColorBase, ColorDialog, ColorMenu, ColorError;
     }
 
     public class CursesDriver : ConsoleDriver {
@@ -35,16 +51,18 @@ namespace Terminal {
 
         public override void Move(int col, int row) => Curses.move (row, col);
         public override void AddCh(int ch) => Curses.addch (ch);
+        public override void AddStr (string str) => Curses.addstr (str);
         public override void Refresh() => Curses.refresh ();
         public override void End() => Curses.endwin ();
         public override void RedrawTop() => window.redrawwin ();
+        public override void SetColor (Color c) => Curses.attrset (c.value);
         public Curses.Window window;
 
         static short last_color_pair;
-        static int MakeColor (short f, short b)
+        static Color MakeColor (short f, short b)
         {
             Curses.InitColorPair (++last_color_pair, f, b);
-            return Curses.ColorPair (last_color_pair);
+            return new Color () { value = Curses.ColorPair (last_color_pair) };
         }
 
         public override void PrepareToRun()
@@ -52,6 +70,35 @@ namespace Terminal {
             Curses.timeout (-1);
         }
 
+        public override void DrawFrame (Rect region, bool fill)
+        {
+            int width = region.Width;
+            int height = region.Height;
+            int b;
+
+            Curses.move (region.Y, region.X);
+            Curses.addch (Curses.ACS_ULCORNER);
+            for (b = 0; b < width - 2; b++)
+                Curses.addch (Curses.ACS_HLINE);
+            Curses.addch (Curses.ACS_URCORNER);
+
+            for (b = 1; b < height - 1; b++) {
+                Curses.move (region.Y + b, region.X);
+                Curses.addch (Curses.ACS_VLINE);
+                if (fill) {
+                    for (int x = 1; x < width - 1; x++)
+                        Curses.addch (' ');
+                } else
+                    Curses.move (region.Y + b, region.X + width - 1);
+                Curses.addch (Curses.ACS_VLINE);
+            }
+            Curses.move (region.Y + height - 1, region.X);
+            Curses.addch (Curses.ACS_LLCORNER);
+            for (b = 0; b < width - 2; b++)
+                Curses.addch (Curses.ACS_HLINE);
+            Curses.addch (Curses.ACS_LRCORNER);
+        }
+
         public override void Init()
         {
             if (window != null)
@@ -66,53 +113,49 @@ namespace Terminal {
             Curses.noecho ();
             Curses.Window.Standard.keypad (true);
         
-            ColorBase = new ColorScheme ();
-            ColorDialog = new ColorScheme ();
-            ColorMenu = new ColorScheme ();
-            ColorError = new ColorScheme ();
+            Colors.Base = new ColorScheme ();
+            Colors.Dialog = new ColorScheme ();
+            Colors.Menu = new ColorScheme ();
+            Colors.Error = 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;
+                Colors.Base.Normal = MakeColor (Curses.COLOR_WHITE, Curses.COLOR_BLUE);
+                Colors.Base.Focus = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_CYAN);
+                Colors.Base.HotNormal = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_BLUE);
+                Colors.Base.HotFocus = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_CYAN);
+                Colors.Menu.Normal = Curses.A_BOLD | MakeColor (Curses.COLOR_WHITE, Curses.COLOR_CYAN);
+                Colors.Menu.Focus = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_CYAN);
+                Colors.Menu.HotNormal = Curses.A_BOLD | MakeColor (Curses.COLOR_WHITE, Curses.COLOR_BLACK);
+                Colors.Menu.HotFocus = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_BLACK);
+                Colors.Dialog.Normal    = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_WHITE);
+                Colors.Dialog.Focus     = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_CYAN);
+                Colors.Dialog.HotNormal = MakeColor (Curses.COLOR_BLUE,  Curses.COLOR_WHITE);
+                Colors.Dialog.HotFocus  = MakeColor (Curses.COLOR_BLUE,  Curses.COLOR_CYAN);
+
+                Colors.Error.Normal = Curses.A_BOLD | MakeColor (Curses.COLOR_WHITE, Curses.COLOR_RED);
+                Colors.Error.Focus = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_WHITE);
+                Colors.Error.HotNormal = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_RED);
+                Colors.Error.HotFocus = Colors.Error.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;
+                Colors.Base.Normal = Curses.A_NORMAL;
+                Colors.Base.Focus = Curses.A_REVERSE;
+                Colors.Base.HotNormal = Curses.A_BOLD;
+                Colors.Base.HotFocus = Curses.A_BOLD | Curses.A_REVERSE;
+                Colors.Menu.Normal = Curses.A_REVERSE;
+                Colors.Menu.Focus = Curses.A_NORMAL;
+                Colors.Menu.HotNormal = Curses.A_BOLD;
+                Colors.Menu.HotFocus = Curses.A_NORMAL;
+                Colors.Dialog.Normal    = Curses.A_REVERSE;
+                Colors.Dialog.Focus     = Curses.A_NORMAL;
+                Colors.Dialog.HotNormal = Curses.A_BOLD;
+                Colors.Dialog.HotFocus  = Curses.A_NORMAL;
+                Colors.Error.Normal = Curses.A_BOLD;
+                Colors.Error.Focus = Curses.A_BOLD | Curses.A_REVERSE;
+                Colors.Error.HotNormal = Curses.A_BOLD | Curses.A_REVERSE;
+                Colors.Error.HotFocus = Curses.A_REVERSE;
             }
         }
     }