Began adding Window class
This commit is contained in:
parent
fa4fd92cdf
commit
04677ab97a
@ -1,6 +1,6 @@
|
|||||||
using Mindmagma.Curses;
|
using Mindmagma.Curses;
|
||||||
|
|
||||||
namespace ANSI_Fahrplan;
|
namespace SCI.CursesWrapper;
|
||||||
|
|
||||||
public class ColorSchemes {
|
public class ColorSchemes {
|
||||||
public static void InitAll () {
|
public static void InitAll () {
|
41
CursesWrapper/CursesWrapper.cs
Normal file
41
CursesWrapper/CursesWrapper.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using Mindmagma.Curses;
|
||||||
|
|
||||||
|
namespace SCI.CursesWrapper;
|
||||||
|
|
||||||
|
public class CursesWrapper {
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes NCurses and creates a screen
|
||||||
|
/// </summary>
|
||||||
|
public static nint InitNCurses () {
|
||||||
|
var screen = NCurses.InitScreen ();
|
||||||
|
NCurses.SetCursor (0);
|
||||||
|
NCurses.NoEcho ();
|
||||||
|
|
||||||
|
if (NCurses.HasColors ()) {
|
||||||
|
NCurses.StartColor ();
|
||||||
|
ColorSchemes.InitAll ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the total width of a window
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">Window to query</param>
|
||||||
|
/// <returns>Width of window in columns</returns>
|
||||||
|
public static int GetWidth (nint window) {
|
||||||
|
NCurses.GetMaxYX (window, out int _, out int width);
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the total height of a window
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">Window to query</param>
|
||||||
|
/// <returns>Height of window in rows</returns>
|
||||||
|
public static int GetHeight (nint window) {
|
||||||
|
NCurses.GetMaxYX (window, out int height, out int _);
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
using System.Security.Principal;
|
|
||||||
using Mindmagma.Curses;
|
using Mindmagma.Curses;
|
||||||
|
|
||||||
namespace ANSI_Fahrplan;
|
namespace SCI.CursesWrapper;
|
||||||
|
|
||||||
public class InputHandler {
|
public class InputHandler {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -11,35 +10,54 @@ public class InputHandler {
|
|||||||
/// <param name="e">Event arguments with details like the pressed key code</param>
|
/// <param name="e">Event arguments with details like the pressed key code</param>
|
||||||
public delegate void KeypressEventHandler (object sender, NCursesKeyPressEventArgs e);
|
public delegate void KeypressEventHandler (object sender, NCursesKeyPressEventArgs e);
|
||||||
|
|
||||||
// Event fired when key is pressed
|
/// <summary>
|
||||||
|
/// Event handlers for NCurses key presses
|
||||||
|
/// </summary>
|
||||||
public event KeypressEventHandler? OnKeyPress;
|
public event KeypressEventHandler? OnKeyPress;
|
||||||
|
|
||||||
// Similar to OnKeyPress, but called before any regular OnKeyPress event handlers are called
|
/// <summary>
|
||||||
|
/// Event Handlers called before the regular OnKeyPress handlers are called
|
||||||
|
/// </summary>
|
||||||
public event KeypressEventHandler? OnKeyPressPrivileged;
|
public event KeypressEventHandler? OnKeyPressPrivileged;
|
||||||
|
|
||||||
// When this variable is set, no event handlers will be called except this one
|
/// <summary>
|
||||||
// Once e.CancelNextEvent is true from this event, it will be set to null again
|
/// Gets or sets the window this InputHandler is listening to
|
||||||
private KeypressEventHandler? _rawKeyPressHandler;
|
/// </summary>
|
||||||
public KeypressEventHandler? RawKeyPressHandler { get { return _rawKeyPressHandler; }}
|
private Window? _activeWindow;
|
||||||
|
public Window? ActiveWindow {
|
||||||
|
get {
|
||||||
|
return _activeWindow;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
_activeWindow = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private nint _targetWindow;
|
/// <summary>
|
||||||
public nint TargetWindow { get { return _targetWindow; }}
|
/// Root screen to fall back to when no window is active
|
||||||
|
/// </summary>
|
||||||
private CancellationTokenSource? listeningRoutineCts;
|
private nint rootScreen;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Task running the endless input handler routine
|
||||||
|
/// </summary>
|
||||||
private Task? listeningTask;
|
private Task? listeningTask;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class constructor
|
/// Cancellation Token Source to stop the listening task
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="targetWindow">Window for which to listen to key presses</param>
|
private CancellationTokenSource? listeningRoutineCts;
|
||||||
public InputHandler (nint targetWindow) {
|
|
||||||
_targetWindow = targetWindow;
|
/// <summary>
|
||||||
|
/// Class constructor
|
||||||
|
/// <paramref name="screen">Parent screen this InputHandler is attached to</paramref>
|
||||||
|
/// </summary>
|
||||||
|
public InputHandler (nint screen) {
|
||||||
|
rootScreen = screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start listening to key presses and call registered callbacks
|
/// Start listening to key presses and call registered callbacks
|
||||||
/// <paramref name="window">Window to listen to key presses in<param/>
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void StartListening () {
|
public void StartListening () {
|
||||||
if (IsListening ()) return;
|
if (IsListening ()) return;
|
||||||
@ -62,7 +80,9 @@ public class InputHandler {
|
|||||||
listeningTask.Wait ();
|
listeningTask.Wait ();
|
||||||
listeningTask = null;
|
listeningTask = null;
|
||||||
|
|
||||||
NCurses.Keypad (TargetWindow, false);
|
if (ActiveWindow is not null) {
|
||||||
|
NCurses.Keypad (ActiveWindow.WindowId, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -76,44 +96,30 @@ public class InputHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enable temporary raw keypress event handler to forward
|
|
||||||
/// all keypressed directly to a specific function
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventHandler">Event handler to pass key presses to</param>
|
|
||||||
/// <param name="screen">Screen to pass key char duty to</param>
|
|
||||||
public void EnableRawEventHandler (KeypressEventHandler eventHandler, nint? window = null) {
|
|
||||||
if (window is not null) {
|
|
||||||
StopListening ();
|
|
||||||
_targetWindow = (nint) window;
|
|
||||||
StartListening ();
|
|
||||||
}
|
|
||||||
|
|
||||||
_rawKeyPressHandler = eventHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disables the temporary raw keypress event handler
|
|
||||||
/// <param name="screen">Screen to pass key char duty back to</param>
|
|
||||||
/// </summary>
|
|
||||||
public void DisableRawEventHandler (nint? screen = null) {
|
|
||||||
if (RawKeyPressHandler is null) return;
|
|
||||||
|
|
||||||
if (screen is not null) {
|
|
||||||
StopListening ();
|
|
||||||
_targetWindow = (nint) screen;
|
|
||||||
StartListening ();
|
|
||||||
}
|
|
||||||
|
|
||||||
_rawKeyPressHandler = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prepares the window for proper key press reading
|
/// Prepares the window for proper key press reading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void WindowSetup () {
|
private void WindowSetup () {
|
||||||
NCurses.Keypad (TargetWindow, true);
|
if (ActiveWindow is not null) {
|
||||||
NCurses.NoDelay (TargetWindow, false);
|
NCurses.Keypad (ActiveWindow.WindowId, true);
|
||||||
|
NCurses.NoDelay (ActiveWindow.WindowId, false);
|
||||||
|
} else {
|
||||||
|
NCurses.Keypad (rootScreen, true);
|
||||||
|
NCurses.NoDelay (rootScreen, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Undoes any changes the setup routine configured for the active window
|
||||||
|
/// </summary>
|
||||||
|
private void WindowTeardown () {
|
||||||
|
if (ActiveWindow is not null) {
|
||||||
|
NCurses.Keypad (ActiveWindow.WindowId, false);
|
||||||
|
NCurses.NoDelay (ActiveWindow.WindowId, true);
|
||||||
|
} else {
|
||||||
|
NCurses.Keypad (rootScreen, false);
|
||||||
|
NCurses.NoDelay (rootScreen, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -124,35 +130,38 @@ public class InputHandler {
|
|||||||
|
|
||||||
WindowSetup ();
|
WindowSetup ();
|
||||||
|
|
||||||
|
int keyCode = -1;
|
||||||
|
|
||||||
while (!listeningRoutineCts.Token.IsCancellationRequested) {
|
while (!listeningRoutineCts.Token.IsCancellationRequested) {
|
||||||
int keyCode = NCurses.WindowGetChar (TargetWindow);
|
if (OnKeyPress is null) {
|
||||||
|
Console.Title = "No handlers";
|
||||||
|
} else {
|
||||||
|
Console.Title = $"Got {OnKeyPress.GetInvocationList ().Length} handlers";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ActiveWindow is not null) {
|
||||||
|
keyCode = NCurses.WindowGetChar (ActiveWindow.WindowId);
|
||||||
|
} else {
|
||||||
|
keyCode = NCurses.GetChar ();
|
||||||
|
}
|
||||||
|
|
||||||
// Do nothing until the key code is larger than -1
|
// Do nothing until the key code is larger than -1
|
||||||
if (keyCode < 0) continue;
|
if (keyCode < 0) continue;
|
||||||
|
|
||||||
var eventArgs = new NCursesKeyPressEventArgs (keyCode, TargetWindow);
|
var eventArgs = new NCursesKeyPressEventArgs (keyCode, ActiveWindow);
|
||||||
|
|
||||||
// If enabled, forward all key pressed directly to raw keypress event handler
|
|
||||||
if (RawKeyPressHandler is not null) {
|
|
||||||
RawKeyPressHandler (this, eventArgs);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var skipRegularEventHandlers = false;
|
|
||||||
|
|
||||||
// Handle any registered privileged key handlers
|
// Handle any registered privileged key handlers
|
||||||
if (OnKeyPressPrivileged is not null) {
|
if (OnKeyPressPrivileged is not null) {
|
||||||
foreach (KeypressEventHandler h in OnKeyPressPrivileged.GetInvocationList ()) {
|
foreach (KeypressEventHandler h in OnKeyPressPrivileged.GetInvocationList ()) {
|
||||||
h (this, eventArgs);
|
h (this, eventArgs);
|
||||||
if (eventArgs.CancelNextEvent == true) {
|
if (eventArgs.CancelNextEvent == true) {
|
||||||
skipRegularEventHandlers = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle any regular registered key handlers
|
// Handle any regular registered key handlers
|
||||||
if (OnKeyPress is not null && !skipRegularEventHandlers) {
|
if (OnKeyPress is not null) {
|
||||||
foreach (KeypressEventHandler h in OnKeyPress.GetInvocationList ()) {
|
foreach (KeypressEventHandler h in OnKeyPress.GetInvocationList ()) {
|
||||||
h (this, eventArgs);
|
h (this, eventArgs);
|
||||||
if (eventArgs.CancelNextEvent == true) continue ;
|
if (eventArgs.CancelNextEvent == true) continue ;
|
||||||
@ -169,13 +178,13 @@ public class NCursesKeyPressEventArgs : EventArgs {
|
|||||||
private int _keyCode;
|
private int _keyCode;
|
||||||
public int KeyCode { get { return _keyCode; }}
|
public int KeyCode { get { return _keyCode; }}
|
||||||
|
|
||||||
private nint _targetWindow;
|
private Window? _sourceWindow;
|
||||||
public nint TargetWindow { get { return _targetWindow; }}
|
public Window? SourceWindow { get { return _sourceWindow; }}
|
||||||
|
|
||||||
public bool CancelNextEvent { get; set; } = false;
|
public bool CancelNextEvent { get; set; } = false;
|
||||||
|
|
||||||
public NCursesKeyPressEventArgs (int keyCode, nint targetWindow) {
|
public NCursesKeyPressEventArgs (int keyCode, Window? sourceWindow) {
|
||||||
_keyCode = keyCode;
|
_keyCode = keyCode;
|
||||||
_targetWindow = targetWindow;
|
_sourceWindow = sourceWindow;
|
||||||
}
|
}
|
||||||
}
|
}
|
265
CursesWrapper/Window.cs
Normal file
265
CursesWrapper/Window.cs
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Drawing;
|
||||||
|
using Mindmagma.Curses;
|
||||||
|
|
||||||
|
namespace SCI.CursesWrapper;
|
||||||
|
|
||||||
|
public class Window {
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the window position on the screen
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the width and height of the window
|
||||||
|
/// </summary>
|
||||||
|
private Size _windowSize;
|
||||||
|
public Size WindowSize {
|
||||||
|
get {
|
||||||
|
return _windowSize;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
_windowSize = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the window background color pair
|
||||||
|
/// </summary>
|
||||||
|
private uint _backgroundColorId;
|
||||||
|
public uint BackgroundColorId {
|
||||||
|
get {
|
||||||
|
return _backgroundColorId;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
NCurses.WindowBackground (WindowId, value);
|
||||||
|
Redraw ();
|
||||||
|
_backgroundColorId = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the parent window
|
||||||
|
/// </summary>
|
||||||
|
private Window? _parentWindow;
|
||||||
|
public Window? ParentWindow { get { return _parentWindow; }}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds a list of children windows this window posesses
|
||||||
|
/// </summary>
|
||||||
|
private List<Window> _childWindows = new List<Window> ();
|
||||||
|
public ReadOnlyCollection<Window> ChildWindows { get { return _childWindows.AsReadOnly (); }}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the pointer for this window
|
||||||
|
/// </summary>
|
||||||
|
private nint _windowId;
|
||||||
|
public nint WindowId { get { return _windowId; }}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Input handler assigned to this window
|
||||||
|
/// </summary>
|
||||||
|
private InputHandler? inputHandler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event handler called when this window is active and a key is pressed
|
||||||
|
/// </summary>
|
||||||
|
public event InputHandler.KeypressEventHandler? OnKeyPress;
|
||||||
|
|
||||||
|
/// <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="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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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 ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a child window to this window
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="child"></param>
|
||||||
|
public void AddChildWindow (Window child) {
|
||||||
|
if (_childWindows.Contains (child)) return;
|
||||||
|
_childWindows.Add (child);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a child window from this window
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="child"></param>
|
||||||
|
public void RemoveChildWindow (Window child) {
|
||||||
|
if (!_childWindows.Contains (child)) return;
|
||||||
|
_childWindows.Remove (child);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Discards all optimization options about drawn parts of this window.
|
||||||
|
/// Call before drawing a sub window
|
||||||
|
/// </summary>
|
||||||
|
public void TouchWin () {
|
||||||
|
NCurses.TouchWindow (WindowId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Redraws this window
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Destroys this window and all children windows
|
||||||
|
/// </summary>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 (
|
||||||
|
"Another input handler is already registered"
|
||||||
|
);
|
||||||
|
|
||||||
|
inputHandler = targetInputHandler;
|
||||||
|
inputHandler.OnKeyPress += KeyPressHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Detach from all OnKeyPress events and unset input handler
|
||||||
|
/// </summary>
|
||||||
|
public void UnregisterInputHandler () {
|
||||||
|
if (inputHandler is null) return;
|
||||||
|
|
||||||
|
inputHandler.OnKeyPress -= KeyPressHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle key press events from the input handler
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
private void KeyPressHandler (object sender, NCursesKeyPressEventArgs e) {
|
||||||
|
if (e.SourceWindow != this) return;
|
||||||
|
|
||||||
|
if (OnKeyPress is not null) {
|
||||||
|
OnKeyPress (sender, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tells the input handler this window is active
|
||||||
|
/// </summary>
|
||||||
|
public void SetWindowActive () {
|
||||||
|
if (inputHandler is null) return;
|
||||||
|
|
||||||
|
inputHandler.ActiveWindow = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables a border around this window
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enabled">Sets the status of the border</param>
|
||||||
|
/// <param name="horizontalChar">If specified, uses this character as the top and bottom border</param>
|
||||||
|
/// <param name="verticalChar">If specified, uses this character as the left and right border</param>
|
||||||
|
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, ' ', ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
121
Program.cs
121
Program.cs
@ -1,5 +1,5 @@
|
|||||||
using ANSI_Fahrplan.Screens;
|
using SCI.CursesWrapper;
|
||||||
using ANSI_Fahrplan.UiElements;
|
using ANSI_Fahrplan.Screens;
|
||||||
using Mindmagma.Curses;
|
using Mindmagma.Curses;
|
||||||
|
|
||||||
namespace ANSI_Fahrplan;
|
namespace ANSI_Fahrplan;
|
||||||
@ -19,31 +19,60 @@ class Program {
|
|||||||
* - User can change the list type with function keys
|
* - User can change the list type with function keys
|
||||||
**/
|
**/
|
||||||
|
|
||||||
var screen = NCurses.InitScreen ();
|
var screen = CursesWrapper.InitNCurses ();
|
||||||
NCurses.SetCursor (0);
|
|
||||||
NCurses.NoEcho ();
|
|
||||||
|
|
||||||
var hasColors = NCurses.HasColors ();
|
|
||||||
if (hasColors) {
|
|
||||||
NCurses.StartColor ();
|
|
||||||
ColorSchemes.InitAll ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Screen-wide input handler -- //
|
// -- Screen-wide input handler -- //
|
||||||
var screenInputHandler = new InputHandler (screen);
|
var inputHandler = new InputHandler (screen);
|
||||||
screenInputHandler.StartListening ();
|
inputHandler.StartListening ();
|
||||||
|
|
||||||
|
// Register quit key on main screen
|
||||||
|
inputHandler.OnKeyPress += (object sender, NCursesKeyPressEventArgs e) => {
|
||||||
|
if (e.SourceWindow is not null) return;
|
||||||
|
if (e.KeyCode != 'q') return;
|
||||||
|
|
||||||
|
NCurses.EndWin ();
|
||||||
|
Console.WriteLine ("Bye-bye!");
|
||||||
|
Environment.Exit (0);
|
||||||
|
};
|
||||||
|
|
||||||
// -- Create menu bar -- //
|
// -- Create menu bar -- //
|
||||||
var topMenu = new TopMenu (screen, CreateMenuItems (screen, screenInputHandler));
|
//var topMenu = new TopMenu (screen, CreateMenuItems (screen, screenInputHandler));
|
||||||
|
|
||||||
// -- Show introduction screen -- //
|
// -- Show introduction screen -- //
|
||||||
NCurses.GetMaxYX (screen, out int height, out int width);
|
// NCurses.GetMaxYX (screen, out int height, out int width);
|
||||||
|
|
||||||
var innerWindow = NCurses.NewWindow (height - 2, width - 4, 1, 2);
|
// var innerWindow = NCurses.NewWindow (height - 2, width - 4, 1, 2);
|
||||||
NCurses.Box (innerWindow, (char) 0, (char) 0);
|
// NCurses.Box (innerWindow, (char) 0, (char) 0);
|
||||||
|
|
||||||
//var introScreen = new IntroScreen (innerWindow);
|
var introScreen = new IntroScreen (screen);
|
||||||
//introScreen.Show ();
|
introScreen.SetBorder (true);
|
||||||
|
introScreen.Redraw ();
|
||||||
|
|
||||||
|
var parentWindow = new Window (3, 3, 10 * 2, 10) {
|
||||||
|
BackgroundColorId = ColorSchemes.TextInputField ()
|
||||||
|
};
|
||||||
|
parentWindow.SetBorder (true);
|
||||||
|
parentWindow.Redraw ();
|
||||||
|
|
||||||
|
var childWindow = new Window (1, 1, 3, 3, parentWindow);
|
||||||
|
childWindow.SetBorder (true);
|
||||||
|
childWindow.Redraw ();
|
||||||
|
|
||||||
|
inputHandler.OnKeyPress += (object sender, NCursesKeyPressEventArgs e) => {
|
||||||
|
if (e.SourceWindow is not null) {
|
||||||
|
NCurses.WindowAddChar (e.SourceWindow.WindowId, e.KeyCode);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
NCurses.AddChar (e.KeyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.KeyCode != 'd') return;
|
||||||
|
|
||||||
|
parentWindow.Destroy ();
|
||||||
|
};
|
||||||
|
|
||||||
|
NCurses.AddString ("Done drawing");
|
||||||
|
NCurses.Refresh ();
|
||||||
|
|
||||||
// Wait until the input handler routine stops
|
// Wait until the input handler routine stops
|
||||||
while (true) Thread.Sleep (500);
|
while (true) Thread.Sleep (500);
|
||||||
@ -53,34 +82,34 @@ class Program {
|
|||||||
Environment.Exit (1);
|
Environment.Exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<MenuItem> CreateMenuItems (nint screen, InputHandler inputHandler) {
|
// private static List<MenuItem> CreateMenuItems (nint screen, InputHandler inputHandler) {
|
||||||
var helpItem = new MenuItem ("Help", "F1", inputHandler);
|
// var helpItem = new MenuItem ("Help", "F1", inputHandler);
|
||||||
var upcomingItem = new MenuItem ("Upcoming", "F2", inputHandler);
|
// var upcomingItem = new MenuItem ("Upcoming", "F2", inputHandler);
|
||||||
var byDayItem = new MenuItem ("By Day", "F3", inputHandler);
|
// var byDayItem = new MenuItem ("By Day", "F3", inputHandler);
|
||||||
var byRoomItem = new MenuItem ("By Room", "F4", inputHandler);
|
// var byRoomItem = new MenuItem ("By Room", "F4", inputHandler);
|
||||||
var bySpeakerItem = new MenuItem ("By Speaker", "F5", inputHandler);
|
// var bySpeakerItem = new MenuItem ("By Speaker", "F5", inputHandler);
|
||||||
var quitItem = new MenuItem ("Quit", "q", inputHandler);
|
// var quitItem = new MenuItem ("Quit", "q", inputHandler);
|
||||||
|
|
||||||
quitItem.OnItemActivated += (object? sender, EventArgs e) => {
|
// quitItem.OnItemActivated += (object? sender, EventArgs e) => {
|
||||||
NCurses.EndWin ();
|
// NCurses.EndWin ();
|
||||||
Console.WriteLine ("Bye-bye!");
|
// Console.WriteLine ("Bye-bye!");
|
||||||
Environment.Exit (0);
|
// Environment.Exit (0);
|
||||||
};
|
// };
|
||||||
|
|
||||||
helpItem.OnItemActivated += (object? sender, EventArgs e) => {
|
// helpItem.OnItemActivated += (object? sender, EventArgs e) => {
|
||||||
InputBox.InputCompleted callback = (string ee) => {
|
// InputBox.InputCompleted callback = (string ee) => {
|
||||||
NCurses.MoveAddString (3, 3, $"<{ee}>");
|
// NCurses.MoveAddString (3, 3, $"<{ee}>");
|
||||||
};
|
// };
|
||||||
new InputBox().RequestInput (screen, inputHandler, callback, "Please enter some text now:");
|
// new InputBox().RequestInput (screen, inputHandler, callback, "Please enter some text now:");
|
||||||
};
|
// };
|
||||||
|
|
||||||
return new List<MenuItem> {
|
// return new List<MenuItem> {
|
||||||
helpItem,
|
// helpItem,
|
||||||
upcomingItem,
|
// upcomingItem,
|
||||||
byDayItem,
|
// byDayItem,
|
||||||
byRoomItem,
|
// byRoomItem,
|
||||||
bySpeakerItem,
|
// bySpeakerItem,
|
||||||
quitItem
|
// quitItem
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,28 @@
|
|||||||
using Mindmagma.Curses;
|
using Mindmagma.Curses;
|
||||||
|
using SCI.CursesWrapper;
|
||||||
|
|
||||||
namespace ANSI_Fahrplan.Screens;
|
namespace ANSI_Fahrplan.Screens;
|
||||||
|
|
||||||
public class IntroScreen : Screen {
|
public class IntroScreen : Window {
|
||||||
private nint infoTextBox;
|
private nint infoTextBox;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pass class constructor through to inherited constructor
|
/// Pass class constructor through to inherited constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rootWindow">Root window to use for this screen</param>
|
/// <param name="parentWindow">Parent window of this window object</param>
|
||||||
public IntroScreen (nint rootWindow) : base (rootWindow) { }
|
public IntroScreen (nint screen) :
|
||||||
|
base (
|
||||||
public override void Show () {
|
1, 1,
|
||||||
|
CursesWrapper.GetWidth (screen) - 2,
|
||||||
|
CursesWrapper.GetHeight (screen) - 2
|
||||||
|
)
|
||||||
|
{
|
||||||
string asciiArtPlusText =
|
string asciiArtPlusText =
|
||||||
"Press F1 for a quick start guide or simply press Enter\n" +
|
"Press F1 for a quick start guide or simply press Enter\n" +
|
||||||
"to see upcoming events\n" +
|
"to see upcoming events\n" +
|
||||||
AsciiArt.logo38c3_80x24 +
|
AsciiArt.logo38c3_80x24 +
|
||||||
"\n38C3 Fahrplan in your terminal!";
|
"\n38C3 Fahrplan in your terminal!";
|
||||||
|
|
||||||
AsciiArt.ShowCentered (RootWindow, asciiArtPlusText);
|
AsciiArt.ShowCentered (WindowId, asciiArtPlusText);
|
||||||
|
|
||||||
//infoTextBox = NCurses.SubWindow (infoTextBox, );
|
|
||||||
|
|
||||||
NCurses.Refresh ();
|
|
||||||
NCurses.WindowRefresh (RootWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Hide () {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
8
Screens/ScrollableScreen.cs
Normal file
8
Screens/ScrollableScreen.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace ANSI_Fahrplan.Screens;
|
||||||
|
|
||||||
|
public abstract class ScrollableScreen : Screen {
|
||||||
|
|
||||||
|
public ScrollableScreen (nint rootWindow) : base (rootWindow) {}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
using System.Runtime.InteropServices.Marshalling;
|
using SCI.CursesWrapper;
|
||||||
using Mindmagma.Curses;
|
using Mindmagma.Curses;
|
||||||
|
|
||||||
namespace ANSI_Fahrplan.UiElements;
|
namespace ANSI_Fahrplan.UiElements;
|
||||||
@ -77,7 +77,7 @@ public class InputBox {
|
|||||||
NCurses.SetCursor (0);
|
NCurses.SetCursor (0);
|
||||||
NCurses.NoEcho ();
|
NCurses.NoEcho ();
|
||||||
|
|
||||||
inputHandler.DisableRawEventHandler (screen);
|
//inputHandler.DisableRawEventHandler (screen);
|
||||||
|
|
||||||
NCurses.MoveWindow (screen, 0, 0);
|
NCurses.MoveWindow (screen, 0, 0);
|
||||||
NCurses.DeleteWindow (inputFieldWin);
|
NCurses.DeleteWindow (inputFieldWin);
|
||||||
@ -93,6 +93,6 @@ public class InputBox {
|
|||||||
NCurses.MoveWindow (inputFieldWin, inputFieldWinY, inputFieldWinX);
|
NCurses.MoveWindow (inputFieldWin, inputFieldWinY, inputFieldWinX);
|
||||||
};
|
};
|
||||||
|
|
||||||
inputHandler.EnableRawEventHandler (handlerFunction, inputFieldWin);
|
//inputHandler.EnableRawEventHandler (handlerFunction, inputFieldWin);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
using SCI.CursesWrapper;
|
||||||
using Mindmagma.Curses;
|
using Mindmagma.Curses;
|
||||||
|
|
||||||
namespace ANSI_Fahrplan.UiElements;
|
namespace ANSI_Fahrplan.UiElements;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using SCI.CursesWrapper;
|
||||||
using Mindmagma.Curses;
|
using Mindmagma.Curses;
|
||||||
|
|
||||||
namespace ANSI_Fahrplan.UiElements;
|
namespace ANSI_Fahrplan.UiElements;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user