// // StatusBar.cs: a statusbar for an application // // Authors: // Miguel de Icaza (miguel@gnome.org) // // TODO: // Add mouse support using System; using NStack; namespace Terminal.Gui { /// /// objects are contained by s. /// Each has a title, a shortcut (hotkey), and an that will be invoked when the /// is pressed. /// The will be a global hotkey for the application in the current context of the screen. /// The colour of the will be changed after each ~. /// A set to `~F1~ Help` will render as *F1* using and /// *Help* as . /// public class StatusItem { /// /// Initializes a new . /// /// Shortcut to activate the . /// Title for the . /// Action to invoke when the is activated. public StatusItem (Key shortcut, ustring title, Action action) { Title = title ?? ""; Shortcut = shortcut; Action = action; } /// /// Gets the global shortcut to invoke the action on the menu. /// public Key Shortcut { get; } /// /// Gets or sets the title. /// /// The title. /// /// The colour of the will be changed after each ~. /// A set to `~F1~ Help` will render as *F1* using and /// *Help* as . /// public ustring Title { get; set;} /// /// Gets or sets the action to be invoked when the statusbar item is triggered /// /// Action to invoke. public Action Action { get; } }; /// /// A status bar is a that snaps to the bottom of a displaying set of s. /// The should be context sensitive. This means, if the main menu and an open text editor are visible, the items probably shown will /// be ~F1~ Help ~F2~ Save ~F3~ Load. While a dialog to ask a file to load is executed, the remaining commands will probably be ~F1~ Help. /// So for each context must be a new instance of a statusbar. /// public class StatusBar : View { // After attempting to implement this, I noticed that there are hard dependencies // on StatusBar and MenuBars within core. They will need to be refactored for having the // StatusBar work at the top #if SNAP_TO_TOP /// /// The style supported by StatusBar /// public enum StatusBarStyle { Default = 0, /// /// The StatusBar will snap at the the bottom line of the Parent view. /// If the console window is made larger while the app is runing, the StatusBar /// will continue to snap to the bottom line of the Parent, staying visible. /// On consoles that support resizing of console apps (e.g. Windows Terminal and ConEmu), /// if the console window is subsequently made shorter, the status bar will remain visible /// as the Parent view resizes. If Parent is null, the StatusBar will snap to the bottom line /// of the console window. /// This is the default. /// SnapToBottom = Default, /// /// The StatusBar will act identically to MenuBar, snapping to the first line of the /// console window. /// SnapToTop = 1, } public StatusBarStyle Style { get; set; } = StatusBarStyle.Default; #endif /// /// The parent view of the . /// public View Parent { get; set; } /// /// The items that compose the /// public StatusItem [] Items { get; set; } /// /// Initializes a new instance of the class with the specified set of s. /// The will be drawn on the lowest line of the terminal or (if not null). /// /// A list of statusbar items. public StatusBar (StatusItem [] items) : base () { Width = Dim.Fill (); Height = 1; Items = items; CanFocus = false; ColorScheme = Colors.Menu; X = 0; Y = Driver.Rows - 1; Width = Dim.Fill (); Height = 1; Application.Loaded += (sender, e) => { X = 0; Height = 1; #if SNAP_TO_TOP switch (Style) { case StatusBarStyle.SnapToTop: X = 0; Y = 0; break; case StatusBarStyle.SnapToBottom: #endif if (Parent == null) { Y = e.Rows - 1; } else { Y = Pos.Bottom (Parent); } #if SNAP_TO_TOP break; } #endif }; } Attribute ToggleScheme (Attribute scheme) { var result = scheme == ColorScheme.Normal ? ColorScheme.HotNormal : ColorScheme.Normal; Driver.SetAttribute (result); return result; } /// 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 (); //} Move (0, 0); Driver.SetAttribute (ColorScheme.Normal); for (int i = 0; i < Frame.Width; i++) Driver.AddRune (' '); Move (1, 0); var scheme = ColorScheme.Normal; Driver.SetAttribute (scheme); for (int i = 0; i < Items.Length; i++) { var title = Items [i].Title; for (int n = 0; n < title.Length; n++) { if (title [n] == '~') { scheme = ToggleScheme (scheme); continue; } Driver.AddRune (title [n]); } Driver.AddRune (' '); } } /// public override bool ProcessHotKey (KeyEvent kb) { foreach (var item in Items) { if (kb.Key == item.Shortcut) { if (item.Action != null) item.Action (); return true; } } return false; } } }