diff --git a/Core.cs b/Core.cs index 39c1b129d..8c0688369 100644 --- a/Core.cs +++ b/Core.cs @@ -16,7 +16,7 @@ namespace Terminal { public class Responder { public virtual bool CanFocus { get; set; } - public bool HasFocus { get; internal set; } + public virtual bool HasFocus { get; internal set; } // Key handling /// @@ -198,6 +198,14 @@ namespace Terminal { CanFocus = true; } + public void Add (params View [] views) + { + if (views == null) + return; + foreach (var view in views) + Add (view); + } + /// /// Removes all the widgets from this container. /// @@ -332,6 +340,16 @@ namespace Terminal { Move (frame.X, frame.Y); } + public override bool HasFocus { + get { + return base.HasFocus; + } + internal set { + if (base.HasFocus != value) + SetNeedsDisplay (); + base.HasFocus = value; + } + } /// /// Returns the currently focused view inside this view, or null if nothing is focused. /// @@ -403,13 +421,12 @@ namespace Terminal { if (c == null) throw new ArgumentException ("the specified view is not part of the hierarchy of this view"); - if (focused != null) + if (focused != null) focused.HasFocus = false; + focused = view; - view.HasFocus = true; - if (view != null) - view.EnsureFocus (); - focused.PositionCursor (); + focused.HasFocus = true; + focused.EnsureFocus (); } public override bool ProcessKey (KeyEvent kb) @@ -420,6 +437,25 @@ namespace Terminal { return false; } + public override bool ProcessHotKey (KeyEvent kb) + { + if (subviews == null || subviews.Count == 0) + return false; + foreach (var view in subviews) + if (view.ProcessHotKey (kb)) + return true; + return false; + } + + public override bool ProcessColdKey (KeyEvent kb) + { + if (subviews == null || subviews.Count == 0) + return false; + foreach (var view in subviews) + if (view.ProcessHotKey (kb)) + return true; + return false; + } /// /// Finds the first view in the hierarchy that wants to get the focus if nothing is currently focused, otherwise, it does nothing. @@ -677,19 +713,21 @@ namespace Terminal { public override void Redraw (Rect bounds) { - Driver.SetAttribute (Colors.Base.Normal); - DrawFrame (); - if (HasFocus) + if (NeedDisplay) { + Driver.SetAttribute (Colors.Base.Normal); + DrawFrame (); + if (HasFocus) + Driver.SetAttribute (Colors.Dialog.Normal); + var width = Frame.Width; + if (Title != null && width > 4) { + Move (1, 0); + Driver.AddCh (' '); + var str = Title.Length > width ? Title.Substring (0, width - 4) : Title; + Driver.AddStr (str); + Driver.AddCh (' '); + } Driver.SetAttribute (Colors.Dialog.Normal); - var width = Frame.Width; - if (Title != null && width > 4) { - Move (1, 0); - Driver.AddCh (' '); - var str = Title.Length > width ? Title.Substring (0, width - 4) : Title; - Driver.AddStr (str); - Driver.AddCh (' '); } - Driver.SetAttribute (Colors.Dialog.Normal); contentView.Redraw (contentView.Bounds); } } @@ -848,6 +886,7 @@ namespace Terminal { return; if (state.Toplevel.NeedDisplay || state.Toplevel.childNeedsDisplay) { state.Toplevel.Redraw (state.Toplevel.Bounds); + state.Toplevel.PositionCursor (); Driver.Refresh (); } } diff --git a/Event.cs b/Event.cs index b00fad620..266d95c82 100644 --- a/Event.cs +++ b/Event.cs @@ -1,114 +1,114 @@ namespace Terminal { - /// - /// The Key enumeration contains special encoding for some keys, but can also - /// encode all the unicode values that can be passed. - /// - /// - /// - /// If the SpecialMask is set, then the value is that of the special mask, - /// otherwise, the value is the one of the lower bits (as extracted by CharMask) - /// - /// - /// Control keys are the values between 1 and 26 corresponding to Control-A to Control-Z - /// - /// - public enum Key : uint { - CharMask = 0xfffff, - SpecialMask = 0xfff00000, - ControlA = 1, - ControlB, - ControlC, - ControlD, - ControlE, - ControlF, - ControlG, - ControlH, - ControlI, - Tab = ControlI, - ControlJ, - ControlK, - ControlL, - ControlM, - ControlN, - ControlO, - ControlP, - ControlQ, - ControlR, - ControlS, - ControlT, - ControlU, - ControlV, - ControlW, - ControlX, - ControlY, - ControlZ, - Esc = 27, - Space = 32, - Delete = 127, + /// + /// The Key enumeration contains special encoding for some keys, but can also + /// encode all the unicode values that can be passed. + /// + /// + /// + /// If the SpecialMask is set, then the value is that of the special mask, + /// otherwise, the value is the one of the lower bits (as extracted by CharMask) + /// + /// + /// Control keys are the values between 1 and 26 corresponding to Control-A to Control-Z + /// + /// + public enum Key : uint { + CharMask = 0xfffff, + SpecialMask = 0xfff00000, + ControlA = 1, + ControlB, + ControlC, + ControlD, + ControlE, + ControlF, + ControlG, + ControlH, + ControlI, + Tab = ControlI, + ControlJ, + ControlK, + ControlL, + ControlM, + ControlN, + ControlO, + ControlP, + ControlQ, + ControlR, + ControlS, + ControlT, + ControlU, + ControlV, + ControlW, + ControlX, + ControlY, + ControlZ, + Esc = 27, + Space = 32, + Delete = 127, - AltMask = 0x80000000, + AltMask = 0x80000000, - Backspace = 0x100000, - CursorUp, - CursorDown, - CursorLeft, - CursorRight, - PageUp, - PageDown, - Home, - End, - DeleteChar, - InsertChar, - F1, - F2, - F3, - F4, - F5, - F6, - F7, - F8, - F9, - F10, - BackTab, - Unknown - } + Backspace = 0x100000, + CursorUp, + CursorDown, + CursorLeft, + CursorRight, + PageUp, + PageDown, + Home, + End, + DeleteChar, + InsertChar, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + BackTab, + Unknown + } - public struct KeyEvent { - public Key Key; - public int KeyValue => (int)Key; - public bool IsAlt => (Key & Key.AltMask) != 0; - public bool IsCtrl => ((uint)Key >= 1) && ((uint)Key <= 26); + public struct KeyEvent { + public Key Key; + public int KeyValue => (int)Key; + public bool IsAlt => (Key & Key.AltMask) != 0; + public bool IsCtrl => ((uint)Key >= 1) && ((uint)Key <= 26); - public KeyEvent (Key k) - { - Key = k; - } - } + public KeyEvent (Key k) + { + Key = k; + } + } - public class Event { - public class Key : Event { - public int Code { get; private set; } - public bool Alt { get; private set; } - public Key (int code) - { - Code = code; - } - } + public class Event { + public class Key : Event { + public int Code { get; private set; } + public bool Alt { get; private set; } + public Key (int code) + { + Code = code; + } + } - public class Mouse : Event { - } + public class Mouse : Event { + } - public static Event CreateMouseEvent () - { - return new Mouse (); - } + public static Event CreateMouseEvent () + { + return new Mouse (); + } - public static Event CreateKeyEvent (int code) - { - return new Key (code); - } + public static Event CreateKeyEvent (int code) + { + return new Key (code); + } - } + } } \ No newline at end of file diff --git a/Views/Button.cs b/Views/Button.cs index fca6cafb1..d96dfc070 100644 --- a/Views/Button.cs +++ b/Views/Button.cs @@ -3,166 +3,166 @@ using System.Collections.Generic; using System.Linq; namespace Terminal { - /// - /// Button view - /// - /// - /// Provides a button that can be clicked, or pressed with - /// the enter key and processes hotkeys (the first uppercase - /// letter in the button becomes the hotkey). - /// - public class Button : View { - string text; - string shown_text; - char hot_key; - int hot_pos = -1; - bool is_default; + /// + /// Button view + /// + /// + /// Provides a button that can be clicked, or pressed with + /// the enter key and processes hotkeys (the first uppercase + /// letter in the button becomes the hotkey). + /// + public class Button : View { + string text; + string shown_text; + char hot_key; + int hot_pos = -1; + bool is_default; - /// - /// Clicked event, raised when the button is clicked. - /// - /// - /// Client code can hook up to this event, it is - /// raised when the button is activated either with - /// the mouse or the keyboard. - /// - public event EventHandler Clicked; + /// + /// Clicked event, raised when the button is clicked. + /// + /// + /// Client code can hook up to this event, it is + /// raised when the button is activated either with + /// the mouse or the keyboard. + /// + public event EventHandler Clicked; - /// - /// Public constructor, creates a button based on - /// the given text at position 0,0 - /// - /// - /// The size of the button is computed based on the - /// text length. This button is not a default button. - /// - public Button (string s) : this (0, 0, s) { } + /// + /// Public constructor, creates a button based on + /// the given text at position 0,0 + /// + /// + /// The size of the button is computed based on the + /// text length. This button is not a default button. + /// + public Button (string s) : this (0, 0, s) { } - /// - /// Public constructor, creates a button based on - /// the given text. - /// - /// - /// If the value for is_default is true, a special - /// decoration is used, and the enter key on a - /// dialog would implicitly activate this button. - /// - public Button (string s, bool is_default) : this (0, 0, s, is_default) { } + /// + /// Public constructor, creates a button based on + /// the given text. + /// + /// + /// If the value for is_default is true, a special + /// decoration is used, and the enter key on a + /// dialog would implicitly activate this button. + /// + public Button (string s, bool is_default) : this (0, 0, s, is_default) { } - /// - /// Public constructor, creates a button based on - /// the given text at the given position. - /// - /// - /// The size of the button is computed based on the - /// text length. This button is not a default button. - /// - public Button (int x, int y, string s) : this (x, y, s, false) { } + /// + /// Public constructor, creates a button based on + /// the given text at the given position. + /// + /// + /// The size of the button is computed based on the + /// text length. This button is not a default button. + /// + public Button (int x, int y, string s) : this (x, y, s, false) { } - /// - /// The text displayed by this widget. - /// - public string Text { - get { - return text; - } + /// + /// The text displayed by this widget. + /// + public string Text { + get { + return text; + } - set { - text = value; - if (is_default) - shown_text = "[< " + value + " >]"; - else - shown_text = "[ " + value + " ]"; + set { + text = value; + if (is_default) + shown_text = "[< " + value + " >]"; + else + shown_text = "[ " + value + " ]"; - hot_pos = -1; - hot_key = (char)0; - int i = 0; - foreach (char c in shown_text) { - if (Char.IsUpper (c)) { - hot_key = c; - hot_pos = i; - break; - } - i++; - } - } - } + hot_pos = -1; + hot_key = (char)0; + int i = 0; + foreach (char c in shown_text) { + if (Char.IsUpper (c)) { + hot_key = c; + hot_pos = i; + break; + } + i++; + } + } + } - /// - /// Public constructor, creates a button based on - /// the given text at the given position. - /// - /// - /// If the value for is_default is true, a special - /// decoration is used, and the enter key on a - /// dialog would implicitly activate this button. - /// - public Button (int x, int y, string s, bool is_default) - : base (new Rect (x, y, s.Length + 4 + (is_default ? 2 : 0), 1)) - { - CanFocus = true; + /// + /// Public constructor, creates a button based on + /// the given text at the given position. + /// + /// + /// If the value for is_default is true, a special + /// decoration is used, and the enter key on a + /// dialog would implicitly activate this button. + /// + public Button (int x, int y, string s, bool is_default) + : base (new Rect (x, y, s.Length + 4 + (is_default ? 2 : 0), 1)) + { + CanFocus = true; - this.is_default = is_default; - Text = s; - } + this.is_default = is_default; + Text = s; + } - public override void Redraw (Rect region) - { - Driver.SetAttribute (HasFocus ? Colors.Base.Focus : Colors.Base.Normal); - Move (0, 0); - Driver.AddStr (shown_text); + public override void Redraw (Rect region) + { + Driver.SetAttribute (HasFocus ? Colors.Base.Focus : Colors.Base.Normal); + Move (0, 0); + Driver.AddStr (shown_text); - if (hot_pos != -1) { - Move (hot_pos, 0); - Driver.SetAttribute (HasFocus ? Colors.Base.HotFocus: Colors.Base.HotNormal); - Driver.AddCh (hot_key); - } - } + if (hot_pos != -1) { + Move (hot_pos, 0); + Driver.SetAttribute (HasFocus ? Colors.Base.HotFocus : Colors.Base.HotNormal); + Driver.AddCh (hot_key); + } + } - public override void PositionCursor () - { - Move (hot_pos, 0); - } + public override void PositionCursor () + { + Move (hot_pos, 0); + } - bool CheckKey (KeyEvent key) - { - if (Char.ToUpper ((char)key.KeyValue) == hot_key) { - this.SetFocus (this); - if (Clicked != null) - Clicked (this, EventArgs.Empty); - return true; - } - return false; - } + bool CheckKey (KeyEvent key) + { + if (Char.ToUpper ((char)key.KeyValue) == hot_key) { + this.SuperView.SetFocus (this); + if (Clicked != null) + Clicked (this, EventArgs.Empty); + return true; + } + return false; + } - public override bool ProcessHotKey (KeyEvent kb) - { - if (kb.IsAlt) - return CheckKey (kb); + public override bool ProcessHotKey (KeyEvent kb) + { + if (kb.IsAlt) + return CheckKey (kb); - return false; - } + return false; + } - public override bool ProcessColdKey (KeyEvent kb) - { - if (is_default && kb.KeyValue == '\n') { - if (Clicked != null) - Clicked (this, EventArgs.Empty); - return true; - } - return CheckKey (kb); - } + public override bool ProcessColdKey (KeyEvent kb) + { + if (is_default && kb.KeyValue == '\n') { + if (Clicked != null) + Clicked (this, EventArgs.Empty); + return true; + } + return CheckKey (kb); + } - public override bool ProcessKey (KeyEvent kb) - { - var c = kb.KeyValue; - if (c == '\n' || c == ' ' || Char.ToUpper ((char)c) == hot_key) { - if (Clicked != null) - Clicked (this, EventArgs.Empty); - return true; - } - return false; - } + public override bool ProcessKey (KeyEvent kb) + { + var c = kb.KeyValue; + if (c == '\n' || c == ' ' || Char.ToUpper ((char)c) == hot_key) { + if (Clicked != null) + Clicked (this, EventArgs.Empty); + return true; + } + return false; + } #if false public override void ProcessMouse (Curses.MouseEvent ev) @@ -175,5 +175,5 @@ namespace Terminal { } } #endif - } + } } diff --git a/Views/TextField.cs b/Views/TextField.cs index 1159030a0..2b8de221c 100644 --- a/Views/TextField.cs +++ b/Views/TextField.cs @@ -105,7 +105,7 @@ namespace Terminal { if (p < text.Length) { Driver.AddCh (Secret ? '*' : text [p]); } else - Driver.AddCh ('_'); + Driver.AddCh (' '); } PositionCursor (); } diff --git a/demo.cs b/demo.cs index 724fd0ec2..e36b73899 100644 --- a/demo.cs +++ b/demo.cs @@ -1,19 +1,35 @@ using Terminal; class Demo { + static void ShowTextAlignments (View container) + { + container.Add ( + new Label (new Rect (0, 0, 40, 3), "1-Hello world, how are you doing today") { TextAlignment = TextAlignment.Left }, + new Label (new Rect (0, 4, 40, 3), "2-Hello world, how are you doing today") { TextAlignment = TextAlignment.Right }, + new Label (new Rect (0, 8, 40, 3), "3-Hello world, how are you doing today") { TextAlignment = TextAlignment.Centered }, + new Label (new Rect (0, 12, 40, 3), "4-Hello world, how are you doing today") { TextAlignment = TextAlignment.Justified }); + } + + static void ShowEntries (View container) + { + container.Add ( + new Label (3, 2, "Login: "), + new TextField (14, 2, 40, ""), + new Label (3, 4, "Password: "), + new TextField (14, 4, 40, "") { Secret = true }, + new Button (3, 6, "Ok"), + new Button (10, 6, "Cancel") + ); + } + static void Main () { Application.Init (); var top = Application.Top; - var win = new Window (new Rect (0, 0, 80, 24), "Hello") { - new Label (new Rect (0, 0, 40, 3), "1-Hello world, how are you doing today") { TextAlignment = TextAlignment.Left }, - new Label (new Rect (0, 4, 40, 3), "2-Hello world, how are you doing today") { TextAlignment = TextAlignment.Right}, - new Label (new Rect (0, 8, 40, 3), "3-Hello world, how are you doing today") { TextAlignment = TextAlignment.Centered }, - new Label (new Rect (0, 12, 40, 3), "4-Hello world, how are you doing today") { TextAlignment = TextAlignment.Justified}, - //new Button (3, 16, "Ok"), - new Label (3, 14, "Login: "), - new TextField (10, 14, 40, ""), - }; + var win = new Window (new Rect (0, 0, 80, 24), "Hello"); + + ShowEntries (win); + // ShowTextAlignments (win); top.Add (win); Application.Run (); }