From b8d5e6aeba79f9224a614c6009cbd604c314ceae Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Tue, 19 Dec 2017 22:43:00 -0500 Subject: [PATCH] Button --- Core.cs | 4 +- Terminal.csproj | 1 + Views/Button.cs | 179 ++++++++++++++++++++++++++++++++++++++++++++++++ demo.cs | 3 +- 4 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 Views/Button.cs diff --git a/Core.cs b/Core.cs index c86350c37..4c57f6f5b 100644 --- a/Core.cs +++ b/Core.cs @@ -396,8 +396,10 @@ namespace Terminal { /// public void FocusFirst () { - if (subviews == null) + if (subviews == null) { + SuperView.SetFocus (this); return; + } foreach (var view in subviews) { if (view.CanFocus) { diff --git a/Terminal.csproj b/Terminal.csproj index 0f79098e1..de02b6d27 100644 --- a/Terminal.csproj +++ b/Terminal.csproj @@ -41,6 +41,7 @@ + diff --git a/Views/Button.cs b/Views/Button.cs new file mode 100644 index 000000000..fca6cafb1 --- /dev/null +++ b/Views/Button.cs @@ -0,0 +1,179 @@ +using System; +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; + + /// + /// 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. + /// + /// + /// 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) { } + + /// + /// 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 + " ]"; + + 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; + + 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); + + 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); + } + + 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; + } + + public override bool ProcessHotKey (KeyEvent kb) + { + if (kb.IsAlt) + return CheckKey (kb); + + 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 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) + { + if ((ev.ButtonState & Curses.Event.Button1Clicked) != 0) { + Container.SetFocus (this); + Container.Redraw (); + if (Clicked != null) + Clicked (this, EventArgs.Empty); + } + } +#endif + } +} diff --git a/demo.cs b/demo.cs index 748744721..d7a922ef9 100644 --- a/demo.cs +++ b/demo.cs @@ -11,7 +11,8 @@ class Demo { 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 Label (3, 14, "Login: "), - new TextField (10, 14, 40, "") + new TextField (10, 14, 40, ""), + new Button (3, 16, "Ok") }; top.Add (win); Application.Run ();