diff --git a/Terminal.Gui/Core.cs b/Terminal.Gui/Core.cs index 0b9582efc..7168eba1e 100644 --- a/Terminal.Gui/Core.cs +++ b/Terminal.Gui/Core.cs @@ -1545,12 +1545,12 @@ namespace Terminal.Gui { /// /// Check id current toplevel has menu bar /// - public bool HasMenuBar { get; set; } + public MenuBar MenuBar { get; set; } /// /// Check id current toplevel has status bar /// - public bool HasStatusBar { get; set; } + public StatusBar StatusBar { get; set; } /// public override bool ProcessKey (KeyEvent keyEvent) @@ -1609,9 +1609,9 @@ namespace Terminal.Gui { { if (this == Application.Top) { if (view is MenuBar) - HasMenuBar = true; + MenuBar = view as MenuBar; if (view is StatusBar) - HasStatusBar = true; + StatusBar = view as StatusBar; } base.Add (view); } @@ -1621,9 +1621,9 @@ namespace Terminal.Gui { { if (this == Application.Top) { if (view is MenuBar) - HasMenuBar = true; + MenuBar = null; if (view is StatusBar) - HasStatusBar = true; + StatusBar = null; } base.Remove (view); } @@ -1632,8 +1632,8 @@ namespace Terminal.Gui { public override void RemoveAll () { if (this == Application.Top) { - HasMenuBar = false; - HasStatusBar = false; + MenuBar = null; + StatusBar = null; } base.RemoveAll (); } @@ -1643,16 +1643,16 @@ namespace Terminal.Gui { nx = Math.Max (x, 0); nx = nx + top.Frame.Width > Driver.Cols ? Math.Max (Driver.Cols - top.Frame.Width, 0) : nx; bool m, s; - if (SuperView == null || SuperView.GetType() != typeof(Toplevel)) - m = Application.Top.HasMenuBar; + if (SuperView == null) + m = Application.Top.MenuBar != null; else - m = ((Toplevel)SuperView).HasMenuBar; + m = ((Toplevel)SuperView).MenuBar != null; int l = m ? 1 : 0; ny = Math.Max (y, l); if (SuperView == null) - s = Application.Top.HasStatusBar; + s = Application.Top.StatusBar != null; else - s = ((Toplevel)SuperView).HasStatusBar; + s = ((Toplevel)SuperView).StatusBar != null; l = s ? Driver.Rows - 1 : Driver.Rows; ny = Math.Min (ny, l); ny = ny + top.Frame.Height > l ? Math.Max (l - top.Frame.Height, m ? 1 : 0) : ny; @@ -1674,9 +1674,15 @@ namespace Terminal.Gui { top.X = nx; top.Y = ny; } - if (HasStatusBar && ny + top.Frame.Height > Driver.Rows - 1) { - if (top.Height is Dim.DimFill) - top.Height = Dim.Fill () - 1; + if (StatusBar != null) { + if (ny + top.Frame.Height > Driver.Rows - 1) { + if (top.Height is Dim.DimFill) + top.Height = Dim.Fill () - 1; + } + if (StatusBar.Frame.Y != Driver.Rows - 1) { + StatusBar.Y = Driver.Rows - 1; + SetNeedsDisplay (); + } } } } @@ -1688,7 +1694,7 @@ namespace Terminal.Gui { { Application.CurrentView = this; - if (this == Application.Top) { + if (this == Application.Top || this == Application.Current) { if (!NeedDisplay.IsEmpty) { Driver.SetAttribute (Colors.TopLevel.Normal); Clear (region); diff --git a/Terminal.Gui/Views/ListView.cs b/Terminal.Gui/Views/ListView.cs index 309c408e0..7262fa478 100644 --- a/Terminal.Gui/Views/ListView.cs +++ b/Terminal.Gui/Views/ListView.cs @@ -63,6 +63,12 @@ namespace Terminal.Gui { /// Item index. /// If set to true value. void SetMark (int item, bool value); + + /// + /// Return the source as IList. + /// + /// + IList ToList (); } /// @@ -257,7 +263,7 @@ namespace Terminal.Gui { /// Redraws the ListView /// /// Region. - public override void Redraw(Rect region) + public override void Redraw (Rect region) { var current = ColorScheme.Focus; Driver.SetAttribute (current); @@ -279,12 +285,12 @@ namespace Terminal.Gui { Move (0, row); if (source == null || item >= source.Count) { for (int c = 0; c < f.Width; c++) - Driver.AddRune(' '); + Driver.AddRune (' '); } else { if (allowsMarking) { Driver.AddStr (source.IsMarked (item) ? (AllowsMultipleSelection ? "[x] " : "(o)") : (AllowsMultipleSelection ? "[ ] " : "( )")); } - Source.Render(this, Driver, isSelected, item, col, row, f.Width-col); + Source.Render (this, Driver, isSelected, item, col, row, f.Width - col); } } } @@ -292,12 +298,12 @@ namespace Terminal.Gui { /// /// This event is raised when the cursor selection has changed. /// - public event Action SelectedChanged; + public event EventHandler SelectedChanged; /// /// This event is raised on Enter key or Double Click to open the selected item. /// - public event EventHandler OpenSelectedItem; + public event EventHandler OpenSelectedItem; /// /// Handles cursor movement for this view, passes all other events. @@ -312,27 +318,27 @@ namespace Terminal.Gui { switch (kb.Key) { case Key.CursorUp: case Key.ControlP: - return MoveUp(); + return MoveUp (); case Key.CursorDown: case Key.ControlN: - return MoveDown(); + return MoveDown (); case Key.ControlV: case Key.PageDown: - return MovePageDown(); + return MovePageDown (); case Key.PageUp: - return MovePageUp(); + return MovePageUp (); case Key.Space: - if (MarkUnmarkRow()) + if (MarkUnmarkRow ()) return true; else break; case Key.Enter: - OpenSelectedItem?.Invoke (this, new EventArgs ()); + OnOpenSelectedItem (); break; } @@ -340,7 +346,7 @@ namespace Terminal.Gui { } /// - /// + /// Prevents marking if it's not allowed mark and if it's not allows multiple selection. /// /// public virtual bool AllowsAll () @@ -359,13 +365,14 @@ namespace Terminal.Gui { } /// - /// + /// Marks an unmarked row. /// /// - public virtual bool MarkUnmarkRow(){ + public virtual bool MarkUnmarkRow () + { if (AllowsAll ()) { - Source.SetMark(SelectedItem, !Source.IsMarked(SelectedItem)); - SetNeedsDisplay(); + Source.SetMark (SelectedItem, !Source.IsMarked (SelectedItem)); + SetNeedsDisplay (); return true; } @@ -373,84 +380,114 @@ namespace Terminal.Gui { } /// - /// + /// Moves to the next page. /// /// - public virtual bool MovePageUp(){ + public virtual bool MovePageUp () + { int n = (selected - Frame.Height); if (n < 0) n = 0; - if (n != selected){ + if (n != selected) { selected = n; top = selected; - if (SelectedChanged != null) - SelectedChanged(); - SetNeedsDisplay(); + OnSelectedChanged (); + SetNeedsDisplay (); } return true; } /// - /// + /// Moves to the previous page. /// /// - public virtual bool MovePageDown(){ + public virtual bool MovePageDown () + { var n = (selected + Frame.Height); if (n > source.Count) n = source.Count - 1; - if (n != selected){ + if (n != selected) { selected = n; if (source.Count >= Frame.Height) top = selected; else top = 0; - if (SelectedChanged != null) - SelectedChanged(); - SetNeedsDisplay(); + OnSelectedChanged (); + SetNeedsDisplay (); } return true; } /// - /// + /// Moves to the next row. /// /// - public virtual bool MoveDown(){ - if (selected + 1 < source.Count){ + public virtual bool MoveDown () + { + if (selected + 1 < source.Count) { selected++; if (selected >= top + Frame.Height) top++; - if (SelectedChanged != null) - SelectedChanged(); - SetNeedsDisplay(); + OnSelectedChanged (); + SetNeedsDisplay (); } return true; } /// - /// + /// Moves to the previous row. /// /// - public virtual bool MoveUp(){ - if (selected > 0){ + public virtual bool MoveUp () + { + if (selected > 0) { selected--; if (selected < top) top = selected; - if (SelectedChanged != null) - SelectedChanged(); - SetNeedsDisplay(); + OnSelectedChanged (); + SetNeedsDisplay (); } return true; } + int lastSelectedItem = -1; + + /// + /// Invokes the SelectedChanged event if it is defined. + /// + /// + public virtual bool OnSelectedChanged () + { + if (selected != lastSelectedItem) { + var value = source.ToList () [selected]; + SelectedChanged?.Invoke (this, new ListViewItemEventArgs (selected, value)); + lastSelectedItem = selected; + return true; + } + + return false; + } + + /// + /// Invokes the OnOpenSelectedItem event if it is defined. + /// + /// + public virtual bool OnOpenSelectedItem () + { + var value = source.ToList () [selected]; + OpenSelectedItem?.Invoke (this, new ListViewItemEventArgs (selected, value)); + + return true; + } + /// /// Positions the cursor in this view /// - public override void PositionCursor() + public override void PositionCursor () { if (allowsMarking) Move (1, selected - top); @@ -461,7 +498,8 @@ namespace Terminal.Gui { /// public override bool MouseEvent(MouseEvent me) { - if (!me.Flags.HasFlag (MouseFlags.Button1Clicked) && !me.Flags.HasFlag (MouseFlags.Button1DoubleClicked)) + if (!me.Flags.HasFlag (MouseFlags.Button1Clicked) && !me.Flags.HasFlag (MouseFlags.Button1DoubleClicked) && + me.Flags != MouseFlags.WheeledDown && me.Flags != MouseFlags.WheeledUp) return false; if (!HasFocus) @@ -470,6 +508,14 @@ namespace Terminal.Gui { if (source == null) return false; + if (me.Flags == MouseFlags.WheeledDown) { + MoveDown (); + return true; + } else if (me.Flags == MouseFlags.WheeledUp) { + MoveUp (); + return true; + } + if (me.Y + top >= source.Count) return true; @@ -479,10 +525,10 @@ namespace Terminal.Gui { SetNeedsDisplay (); return true; } - SelectedChanged?.Invoke (); + OnSelectedChanged (); SetNeedsDisplay (); if (me.Flags == MouseFlags.Button1DoubleClicked) - OpenSelectedItem?.Invoke (this, new EventArgs ()); + OnOpenSelectedItem (); return true; } } @@ -497,7 +543,7 @@ namespace Terminal.Gui { int count; /// - /// constructor + /// Constructor based on a source. /// /// public ListWrapper (IList source) @@ -508,7 +554,7 @@ namespace Terminal.Gui { } /// - /// Count of items. + /// Returns the amount of items in the source. /// public int Count => src.Count; @@ -519,7 +565,7 @@ namespace Terminal.Gui { for (int i = 0; i < byteLen;) { (var rune, var size) = Utf8.DecodeRune (ustr, i, i - byteLen); var count = Rune.ColumnWidth (rune); - if (used+count >= width) + if (used + count >= width) break; driver.AddRune (rune); used += count; @@ -531,15 +577,15 @@ namespace Terminal.Gui { } /// - /// Renders an item in the the list. + /// Method that render to the appropriate type based on the type of the item passed to it. /// - /// - /// - /// - /// - /// - /// - /// + /// The ListView. + /// The driver used by the caller. + /// Informs if it's marked or not. + /// The item. + /// The col where to move. + /// The line where to move. + /// The item width. public void Render (ListView container, ConsoleDriver driver, bool marked, int item, int col, int line, int width) { container.Move (col, line); @@ -553,10 +599,10 @@ namespace Terminal.Gui { } /// - /// Returns true of the item is marked. false if not. + /// Returns true if the item is marked, false otherwise. /// - /// - /// + /// The item. + /// trueIf is marked.falseotherwise. public bool IsMarked (int item) { if (item >= 0 && item < count) @@ -565,14 +611,48 @@ namespace Terminal.Gui { } /// - /// Sets the marked state of an item. + /// Sets the item as marked or unmarked based on the value is true or false, respectively. /// - /// - /// + /// The item + /// Marks the item.Unmarked the item.The value. public void SetMark (int item, bool value) { if (item >= 0 && item < count) marks [item] = value; } + + /// + /// Returns the source as IList. + /// + /// + public IList ToList () + { + return src; + } + } + + /// + /// Gets the item and value to use in an event handler. + /// + public class ListViewItemEventArgs : EventArgs { + /// + /// The item. + /// + public int Item { get; } + /// + /// The item value. + /// + public object Value { get; } + + /// + /// Constructor to sets the item and value passed from. + /// + /// The item. + /// The item value + public ListViewItemEventArgs (int item, object value) + { + Item = item; + Value = value; + } } } diff --git a/Terminal.Gui/Views/StatusBar.cs b/Terminal.Gui/Views/StatusBar.cs index e204f97e5..789781815 100644 --- a/Terminal.Gui/Views/StatusBar.cs +++ b/Terminal.Gui/Views/StatusBar.cs @@ -107,6 +107,10 @@ namespace Terminal.Gui { Items = items; CanFocus = false; ColorScheme = Colors.Menu; + X = 0; + Y = Driver.Rows - 1; + Width = Dim.Fill (); + Height = 1; Application.Loaded += (sender, e) => { X = 0; @@ -141,11 +145,11 @@ namespace Terminal.Gui { /// public override void Redraw (Rect region) { - if (Frame.Y != Driver.Rows - 1) { - Frame = new Rect (Frame.X, Driver.Rows - 1, Frame.Width, Frame.Height); - Y = Driver.Rows - 1; - SetNeedsDisplay (); - } + //if (Frame.Y != Driver.Rows - 1) { + // Frame = new Rect (Frame.X, Driver.Rows - 1, Frame.Width, Frame.Height); + // Y = Driver.Rows - 1; + // SetNeedsDisplay (); + //} Move (0, 0); Driver.SetAttribute (ColorScheme.Normal); diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs index 781866ef5..71a53ccd7 100644 --- a/Terminal.Gui/Views/TextField.cs +++ b/Terminal.Gui/Views/TextField.cs @@ -28,6 +28,11 @@ namespace Terminal.Gui { /// public bool Used { get => used; set { used = value; } } + /// + /// If set to true its not allow any changes in the text. + /// + public bool ReadOnly { get; set; } = false; + /// /// Changed event, raised when the text has clicked. /// @@ -95,7 +100,7 @@ namespace Terminal.Gui { set { base.Frame = value; var w = base.Frame.Width; - //first = point > w ? point - w : 0; + first = point > w ? point - w : 0; Adjust (); } } @@ -115,6 +120,9 @@ namespace Terminal.Gui { } set { + if (ReadOnly) + return; + var oldText = ustring.Make (text); text = TextModel.ToRunes (value); if (!Secret && !isFromHistory) { @@ -184,13 +192,16 @@ namespace Terminal.Gui { int col = 0; int width = Frame.Width; var tcount = text.Count; + var roc = new Attribute (Color.DarkGray, Color.Gray); for (int idx = 0; idx < tcount; idx++){ var rune = text [idx]; if (idx < p) continue; var cols = Rune.ColumnWidth (rune); - if (col == point && HasFocus && !Used && SelectedLength == 0) + if (col == point && HasFocus && !Used && SelectedLength == 0 && !ReadOnly) Driver.SetAttribute (Colors.Menu.HotFocus); + else if (ReadOnly) + Driver.SetAttribute (idx >= start && length > 0 && idx < start + length ? color.Focus : roc); else Driver.SetAttribute (idx >= start && length > 0 && idx < start + length ? color.Focus : ColorScheme.Focus); if (col + cols <= width) @@ -261,6 +272,9 @@ namespace Terminal.Gui { switch (kb.Key) { case Key.DeleteChar: case Key.ControlD: + if (ReadOnly) + return true; + if (SelectedLength == 0) { if (text.Count == 0 || text.Count == point) return true; @@ -275,6 +289,9 @@ namespace Terminal.Gui { case Key.Delete: case Key.Backspace: + if (ReadOnly) + return true; + if (SelectedLength == 0) { if (point == 0) return true; @@ -373,6 +390,9 @@ namespace Terminal.Gui { break; case Key.ControlK: // kill-to-end + if (ReadOnly) + return true; + ClearAllSelection (); if (point >= text.Count) return true; @@ -383,6 +403,9 @@ namespace Terminal.Gui { // Undo case Key.ControlZ: + if (ReadOnly) + return true; + if (historyText != null && historyText.Count > 0) { isFromHistory = true; if (idxhistoryText > 0) @@ -396,6 +419,9 @@ namespace Terminal.Gui { //Redo case Key.ControlY: // Control-y, yank + if (ReadOnly) + return true; + if (historyText != null && historyText.Count > 0) { isFromHistory = true; if (idxhistoryText < historyText.Count - 1) { @@ -455,6 +481,9 @@ namespace Terminal.Gui { break; case Key.ControlX: + if (ReadOnly) + return true; + Cut (); break; @@ -472,6 +501,9 @@ namespace Terminal.Gui { if (kb.Key < Key.Space || kb.Key > Key.CharMask) return false; + if (ReadOnly) + return true; + if (SelectedLength != 0) { DeleteSelectedText (); oldCursorPos = point; @@ -639,7 +671,7 @@ namespace Terminal.Gui { point = text.Count; if (point < first) point = 0; - return x; + return point; } void PrepareSelection (int x, int direction = 0) @@ -682,8 +714,11 @@ namespace Terminal.Gui { /// /// Copy the selected text to the clipboard. /// - public void Copy () + public virtual void Copy () { + if (Secret) + return; + if (SelectedLength != 0) { Clipboard.Contents = SelectedText; } @@ -692,7 +727,7 @@ namespace Terminal.Gui { /// /// Cut the selected text to the clipboard. /// - public void Cut () + public virtual void Cut () { if (SelectedLength != 0) { Clipboard.Contents = SelectedText; @@ -715,8 +750,11 @@ namespace Terminal.Gui { /// /// Paste the selected text from the clipboard. /// - public void Paste () + public virtual void Paste () { + if (ReadOnly) + return; + string actualText = Text.ToString (); int start = SelectedStart == -1 ? CursorPosition : SelectedStart; ustring cbTxt = Clipboard.Contents?.ToString () ?? ""; diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs index 0d6f35a5c..738a6f35f 100644 --- a/Terminal.Gui/Views/TextView.cs +++ b/Terminal.Gui/Views/TextView.cs @@ -39,6 +39,7 @@ namespace Terminal.Gui { if (file == null) throw new ArgumentNullException (nameof (file)); try { + FilePath = file; var stream = File.OpenRead (file); } catch { return false; @@ -47,6 +48,19 @@ namespace Terminal.Gui { return true; } + public bool CloseFile () + { + if (FilePath == null) + throw new ArgumentNullException (nameof (FilePath)); + try { + FilePath = null; + lines = new List> (); + } catch { + return false; + } + return true; + } + // Turns the ustring into runes, this does not split the // contents on a newline if it is present. internal static List ToRunes (ustring str) @@ -120,6 +134,8 @@ namespace Terminal.Gui { return sb.ToString (); } + public string FilePath { get; set; } + /// /// The number of text lines in the model /// @@ -351,6 +367,18 @@ namespace Terminal.Gui { SetNeedsDisplay (); } + /// + /// Closes the contents of the stream into the TextView. + /// + /// true, if stream was closed, false otherwise. + public bool CloseFile() + { + ResetPosition (); + var res = model.CloseFile (); + SetNeedsDisplay (); + return res; + } + /// /// The current cursor row. /// diff --git a/UICatalog/Program.cs b/UICatalog/Program.cs index 3a4c1054d..3cb1c866f 100644 --- a/UICatalog/Program.cs +++ b/UICatalog/Program.cs @@ -1,5 +1,6 @@ using NStack; using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -119,7 +120,7 @@ namespace UICatalog { _rightPane.Add (_scenarioListView); _categoryListView.SelectedItem = 0; - CategoryListView_SelectedChanged (); + _categoryListView.OnSelectedChanged (); _statusBar = new StatusBar (new StatusItem [] { //new StatusItem(Key.F1, "~F1~ Help", () => Help()), @@ -150,6 +151,7 @@ namespace UICatalog { _top = Application.Top; _top.KeyUp += KeyUpHandler; + _top.Add (_menu); _top.Add (_leftPane); _top.Add (_rightPane); @@ -228,6 +230,12 @@ namespace UICatalog { used++; } } + + public IList ToList () + { + return Scenarios; + } + } /// @@ -245,7 +253,7 @@ namespace UICatalog { // break; //case Key.Enter: // break; - //} + //}< } else if (a.KeyEvent.Key == Key.Tab || a.KeyEvent.Key == Key.BackTab) { // BUGBUG: Work around Issue #434 by implementing our own TAB navigation if (_top.MostFocused == _categoryListView) @@ -255,7 +263,7 @@ namespace UICatalog { } } - private static void CategoryListView_SelectedChanged () + private static void CategoryListView_SelectedChanged (object sender, ListViewItemEventArgs e) { var item = _categories [_categoryListView.SelectedItem]; List newlist;