using System.Collections.ObjectModel; using System.Drawing; using Mindmagma.Curses; namespace SCI.CursesWrapper; public class Window { /// /// Gets or sets the window position on the screen /// private Point _position; public Point Position { get { return _position; } set { if (ParentWindow is not null) { NCurses.WindowMove ( WindowId, ParentWindow.Position.Y + value.Y, ParentWindow.Position.X + value.X ); } else { NCurses.WindowMove ( WindowId, value.Y, value.X ); } _position = value; } } /// /// Gets or sets the width and height of the window /// private Size _windowSize; public Size WindowSize { get { return _windowSize; } set { _windowSize = value; } } /// /// Gets or sets the window background color pair /// private uint _backgroundColorId; public uint BackgroundColorId { get { return _backgroundColorId; } set { NCurses.WindowBackground (WindowId, value); Redraw (); _backgroundColorId = value; } } /// /// Sets the parent window /// private Window? _parentWindow; public Window? ParentWindow { get { return _parentWindow; }} /// /// Holds a list of children windows this window posesses /// private List _childWindows = new List (); public ReadOnlyCollection ChildWindows { get { return _childWindows.AsReadOnly (); }} /// /// Holds the pointer for this window /// private nint _windowId; public nint WindowId { get { return _windowId; }} /// /// Input handler assigned to this window /// private InputHandler? inputHandler; /// /// Event handler called when this window is active and a key is pressed /// public event InputHandler.KeypressEventHandler? OnKeyPress; /// /// Create new window by specifying X/Y and Width/Height geometry /// /// /// /// /// /// public Window (int x, int y, int width, int height, Window? parentWindow = null) { if (parentWindow is not null) { _windowId = NCurses.DeriveWindow ( parentWindow.WindowId, height, width, y, x ); } else { _windowId = NCurses.NewWindow ( height, width, y, x ); } Redraw (); } /// /// Create new window by specifying geometry through Point and Size objects /// /// /// /// public Window (Point position, Size windowSize, Window? parentWindow = null) { if (parentWindow is not null) { _windowId = NCurses.SubWindow ( parentWindow.WindowId, windowSize.Height, windowSize.Width, position.Y, position.X ); } else { _windowId = NCurses.NewWindow ( windowSize.Height, windowSize.Width, position.Y, position.X ); } Redraw (); } /// /// Adds a child window to this window /// /// public void AddChildWindow (Window child) { if (_childWindows.Contains (child)) return; _childWindows.Add (child); } /// /// Removes a child window from this window /// /// public void RemoveChildWindow (Window child) { if (!_childWindows.Contains (child)) return; _childWindows.Remove (child); } /// /// Discards all optimization options about drawn parts of this window. /// Call before drawing a sub window /// public void TouchWin () { NCurses.TouchWindow (WindowId); } /// /// Redraws this window /// public void Redraw () { NCurses.Refresh (); // TODO: Necessary? if (ChildWindows.Count > 0) { foreach (var window in ChildWindows) { window.Redraw (); } } if (ParentWindow is not null) ParentWindow.TouchWin (); NCurses.WindowRefresh (WindowId); } /// /// Destroys this window and all children windows /// public void Destroy () { if (ChildWindows.Count > 0) { foreach (var window in _childWindows) { window.Destroy (); } } if (inputHandler is not null) inputHandler.ActiveWindow = null; if (ParentWindow is not null) ParentWindow.RemoveChildWindow (this); UnregisterInputHandler (); SetBorder (false); NCurses.ClearWindow (WindowId); Console.Title = "About to destroy"; NCurses.DeleteWindow (WindowId); Console.Title = "Destroyed"; //TODO: Program hangs on DeleteWindow } /// /// Register an input handler for this window to attach to OnKeyPress events /// /// InputHandler to register public void RegisterInputHandler (InputHandler targetInputHandler) { if (inputHandler is not null) throw new Exception ( "Another input handler is already registered" ); inputHandler = targetInputHandler; inputHandler.OnKeyPress += KeyPressHandler; } /// /// Detach from all OnKeyPress events and unset input handler /// public void UnregisterInputHandler () { if (inputHandler is null) return; inputHandler.OnKeyPress -= KeyPressHandler; } /// /// Handle key press events from the input handler /// /// /// private void KeyPressHandler (object sender, NCursesKeyPressEventArgs e) { if (e.SourceWindow != this) return; if (OnKeyPress is not null) { OnKeyPress (sender, e); } } /// /// Tells the input handler this window is active /// public void SetWindowActive () { if (inputHandler is null) return; inputHandler.ActiveWindow = this; } /// /// Enables or disables a border around this window /// /// Sets the status of the border /// If specified, uses this character as the top and bottom border /// If specified, uses this character as the left and right border public void SetBorder (bool enabled, char? horizontalChar = null, char? verticalChar = null) { if (horizontalChar is null) horizontalChar = (char) 0; if (verticalChar is null) verticalChar = (char) 0; if (enabled) { NCurses.Box (WindowId, (char) horizontalChar, (char) verticalChar); } else { NCurses.Box (WindowId, ' ', ' '); } } }