|
|
|
@ -5,6 +5,8 @@ using Mindmagma.Curses;
|
|
|
|
|
namespace SCI.CursesWrapper;
|
|
|
|
|
|
|
|
|
|
public class Window {
|
|
|
|
|
public const int InnerPadding = 1;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the window position on the screen
|
|
|
|
|
/// </summary>
|
|
|
|
@ -15,10 +17,13 @@ public class Window {
|
|
|
|
|
}
|
|
|
|
|
set {
|
|
|
|
|
if (ParentWindow is not null) {
|
|
|
|
|
int addedPadding = ParentWindow.BorderEnabled?
|
|
|
|
|
InnerPadding + 1 : 0;
|
|
|
|
|
|
|
|
|
|
NCurses.WindowMove (
|
|
|
|
|
WindowId,
|
|
|
|
|
ParentWindow.Position.Y + value.Y,
|
|
|
|
|
ParentWindow.Position.X + value.X
|
|
|
|
|
ParentWindow.Position.Y + value.Y + addedPadding,
|
|
|
|
|
ParentWindow.Position.X + value.X + addedPadding
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
NCurses.WindowMove (
|
|
|
|
@ -54,11 +59,23 @@ public class Window {
|
|
|
|
|
}
|
|
|
|
|
set {
|
|
|
|
|
NCurses.WindowBackground (WindowId, value);
|
|
|
|
|
Redraw ();
|
|
|
|
|
Draw ();
|
|
|
|
|
_backgroundColorId = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool _borderEnabled;
|
|
|
|
|
public bool BorderEnabled {
|
|
|
|
|
get {
|
|
|
|
|
return _borderEnabled;
|
|
|
|
|
}
|
|
|
|
|
set {
|
|
|
|
|
SetBorder (value);
|
|
|
|
|
Draw ();
|
|
|
|
|
_borderEnabled = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets the parent window
|
|
|
|
|
/// </summary>
|
|
|
|
@ -80,7 +97,8 @@ public class Window {
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Input handler assigned to this window
|
|
|
|
|
/// </summary>
|
|
|
|
|
private InputHandler? inputHandler;
|
|
|
|
|
protected InputHandler? _targetInputHandler;
|
|
|
|
|
public InputHandler? TargetInputHandler { get { return _targetInputHandler; }}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Event handler called when this window is active and a key is pressed
|
|
|
|
@ -96,20 +114,32 @@ public class Window {
|
|
|
|
|
/// <param name="height"></param>
|
|
|
|
|
/// <param name="parentWindow"></param>
|
|
|
|
|
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
|
|
|
|
|
);
|
|
|
|
|
_Initialize (new Point (x, y), new Size (width, height), parentWindow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Redraw ();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create new window by specifying geometry through Point and Size objects
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="position"></param>
|
|
|
|
|
/// <param name="windowSize"></param>
|
|
|
|
|
/// <param name="parentWindow"></param>
|
|
|
|
|
public Window (Point position, Size windowSize, Window? parentWindow = null) {
|
|
|
|
|
_Initialize (position, windowSize, parentWindow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create new window by specifying X/Y and Width/Height geometry
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="x"></param>
|
|
|
|
|
/// <param name="y"></param>
|
|
|
|
|
/// <param name="width"></param>
|
|
|
|
|
/// <param name="height"></param>
|
|
|
|
|
/// <param name="targetInputHandler"></param>
|
|
|
|
|
/// <param name="parentWindow"></param>
|
|
|
|
|
public Window (int x, int y, int width, int height, InputHandler targetInputHandler, Window? parentWindow = null) {
|
|
|
|
|
_Initialize (new Point (x, y), new Size (width, height), parentWindow);
|
|
|
|
|
RegisterInputHandler (targetInputHandler);
|
|
|
|
|
SetWindowActive ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -117,14 +147,32 @@ public class Window {
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="position"></param>
|
|
|
|
|
/// <param name="windowSize"></param>
|
|
|
|
|
/// <param name="targetInputHandler"></param>
|
|
|
|
|
/// <param name="parentWindow"></param>
|
|
|
|
|
public Window (Point position, Size windowSize, Window? parentWindow = null) {
|
|
|
|
|
public Window (Point position, Size windowSize, InputHandler targetInputHandler, Window? parentWindow = null) {
|
|
|
|
|
_Initialize (position, windowSize, parentWindow);
|
|
|
|
|
RegisterInputHandler (targetInputHandler);
|
|
|
|
|
SetWindowActive ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Actual initialization function for this class
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="position"></param>
|
|
|
|
|
/// <param name="windowSize"></param>
|
|
|
|
|
/// <param name="parentWindow"></param>
|
|
|
|
|
private void _Initialize (Point position, Size windowSize, Window? parentWindow = null) {
|
|
|
|
|
if (parentWindow is not null) {
|
|
|
|
|
_windowId = NCurses.SubWindow (
|
|
|
|
|
int addedPadding = parentWindow.BorderEnabled?
|
|
|
|
|
InnerPadding + 1 : 0;
|
|
|
|
|
|
|
|
|
|
_windowId = NCurses.DeriveWindow (
|
|
|
|
|
parentWindow.WindowId,
|
|
|
|
|
windowSize.Height, windowSize.Width,
|
|
|
|
|
position.Y, position.X
|
|
|
|
|
position.Y + addedPadding, position.X + addedPadding
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
parentWindow.AddChildWindow (this);
|
|
|
|
|
} else {
|
|
|
|
|
_windowId = NCurses.NewWindow (
|
|
|
|
|
windowSize.Height, windowSize.Width,
|
|
|
|
@ -132,7 +180,20 @@ public class Window {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Redraw ();
|
|
|
|
|
_position = position;
|
|
|
|
|
_windowSize = windowSize;
|
|
|
|
|
_parentWindow = parentWindow;
|
|
|
|
|
|
|
|
|
|
NCurses.Keypad (WindowId, true);
|
|
|
|
|
|
|
|
|
|
Draw ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Destroys the window and its sub-windows when the Window object is destroyed
|
|
|
|
|
/// </summary>
|
|
|
|
|
~Window () {
|
|
|
|
|
Destroy ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -149,7 +210,6 @@ public class Window {
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="child"></param>
|
|
|
|
|
public void RemoveChildWindow (Window child) {
|
|
|
|
|
if (!_childWindows.Contains (child)) return;
|
|
|
|
|
_childWindows.Remove (child);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -162,15 +222,13 @@ public class Window {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Redraws this window
|
|
|
|
|
/// Draws this window and all sub windows
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Redraw () {
|
|
|
|
|
public void Draw () {
|
|
|
|
|
NCurses.Refresh (); // TODO: Necessary?
|
|
|
|
|
|
|
|
|
|
if (ChildWindows.Count > 0) {
|
|
|
|
|
foreach (var window in ChildWindows) {
|
|
|
|
|
window.Redraw ();
|
|
|
|
|
}
|
|
|
|
|
window.Draw ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ParentWindow is not null) ParentWindow.TouchWin ();
|
|
|
|
@ -181,47 +239,54 @@ public class Window {
|
|
|
|
|
/// Destroys this window and all children windows
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Destroy () {
|
|
|
|
|
if (ChildWindows.Count > 0) {
|
|
|
|
|
foreach (var window in _childWindows) {
|
|
|
|
|
// Catch double destroy calls
|
|
|
|
|
if (WindowId == -1) throw new Exception ("Destroy called twice on object");
|
|
|
|
|
|
|
|
|
|
foreach (var window in _childWindows.ToList ()) {
|
|
|
|
|
window.Destroy ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inputHandler is not null) inputHandler.ActiveWindow = null;
|
|
|
|
|
if (ParentWindow is not null) ParentWindow.RemoveChildWindow (this);
|
|
|
|
|
|
|
|
|
|
UnregisterInputHandler ();
|
|
|
|
|
|
|
|
|
|
// Prepare for screen clear
|
|
|
|
|
NCurses.WindowBackground (WindowId, NCurses.ColorPair (-1));
|
|
|
|
|
SetBorder (false);
|
|
|
|
|
|
|
|
|
|
// Clear window and redraw
|
|
|
|
|
NCurses.ClearWindow (WindowId);
|
|
|
|
|
Console.Title = "About to destroy";
|
|
|
|
|
Draw ();
|
|
|
|
|
|
|
|
|
|
NCurses.DeleteWindow (WindowId);
|
|
|
|
|
Console.Title = "Destroyed";
|
|
|
|
|
_windowId = -1;
|
|
|
|
|
|
|
|
|
|
//TODO: Program hangs on DeleteWindow
|
|
|
|
|
// Ensures sure the parent is updated too
|
|
|
|
|
if (ParentWindow is not null) {
|
|
|
|
|
ParentWindow.RemoveChildWindow (this);
|
|
|
|
|
ParentWindow.Draw ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Register an input handler for this window to attach to OnKeyPress events
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="inputHandler">InputHandler to register</param>
|
|
|
|
|
public void RegisterInputHandler (InputHandler targetInputHandler) {
|
|
|
|
|
if (inputHandler is not null) throw new Exception (
|
|
|
|
|
/// <param name="targetInputHandler">InputHandler to register</param>
|
|
|
|
|
public void RegisterInputHandler (InputHandler inputHandler) {
|
|
|
|
|
if (TargetInputHandler is not null) throw new Exception (
|
|
|
|
|
"Another input handler is already registered"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
inputHandler = targetInputHandler;
|
|
|
|
|
inputHandler.OnKeyPress += KeyPressHandler;
|
|
|
|
|
_targetInputHandler = inputHandler;
|
|
|
|
|
TargetInputHandler!.OnKeyPress += KeyPressHandler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Detach from all OnKeyPress events and unset input handler
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void UnregisterInputHandler () {
|
|
|
|
|
if (inputHandler is null) return;
|
|
|
|
|
if (TargetInputHandler is null) return;
|
|
|
|
|
|
|
|
|
|
inputHandler.OnKeyPress -= KeyPressHandler;
|
|
|
|
|
if (TargetInputHandler.ActiveWindow == this) TargetInputHandler.ActiveWindow = null;
|
|
|
|
|
TargetInputHandler.OnKeyPress -= KeyPressHandler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -233,7 +298,7 @@ public class Window {
|
|
|
|
|
if (e.SourceWindow != this) return;
|
|
|
|
|
|
|
|
|
|
if (OnKeyPress is not null) {
|
|
|
|
|
OnKeyPress (sender, e);
|
|
|
|
|
OnKeyPress (this, e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -241,9 +306,10 @@ public class Window {
|
|
|
|
|
/// Tells the input handler this window is active
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void SetWindowActive () {
|
|
|
|
|
if (inputHandler is null) return;
|
|
|
|
|
if (TargetInputHandler is null) return;
|
|
|
|
|
|
|
|
|
|
inputHandler.ActiveWindow = this;
|
|
|
|
|
TargetInputHandler.ActiveWindow = this;
|
|
|
|
|
Draw ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -262,4 +328,28 @@ public class Window {
|
|
|
|
|
NCurses.Box (WindowId, ' ', ' ');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Calcaulates the usable inner width of this window
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Usable inner width of window in columns</returns>
|
|
|
|
|
public int GetUsableWidth () {
|
|
|
|
|
if (BorderEnabled) {
|
|
|
|
|
return WindowSize.Width - 1 - InnerPadding;
|
|
|
|
|
} else {
|
|
|
|
|
return WindowSize.Width;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Calcaulates the usable inner height of this window
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Usable inner height of window in rows</returns>
|
|
|
|
|
public int GetUsableHeight () {
|
|
|
|
|
if (BorderEnabled) {
|
|
|
|
|
return WindowSize.Height - 1 - InnerPadding;
|
|
|
|
|
} else {
|
|
|
|
|
return WindowSize.Height;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|