aboutsummaryrefslogtreecommitdiff
path: root/TUI/module.jai
diff options
context:
space:
mode:
Diffstat (limited to 'TUI/module.jai')
-rw-r--r--TUI/module.jai194
1 files changed, 194 insertions, 0 deletions
diff --git a/TUI/module.jai b/TUI/module.jai
new file mode 100644
index 0000000..67a9edd
--- /dev/null
+++ b/TUI/module.jai
@@ -0,0 +1,194 @@
+#if OS == .WINDOWS {
+ #load "windows.jai";
+} else #if (OS == .LINUX) || (OS == .MACOS) {
+ #load "unix.jai";
+} else {
+ #assert(false, "Unsupported OS.");
+}
+
+#import "String";
+
+// https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
+// https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#designate-character-set
+// https://github.com/MicrosoftDocs/Console-Docs/blob/main/docs/console-virtual-terminal-sequences.md
+
+isTUIActive := false; // TODO Rename this variable.
+
+
+Drawings :: struct {
+ CornerBR :: "\x6A";
+ CornerTR :: "\x6B";
+ CornerTL :: "\x6C";
+ CornerBL :: "\x6D";
+ Cross :: "\x6E";
+ LineH :: "\x71";
+ TeeL :: "\x74";
+ TeeR :: "\x75";
+ TeeB :: "\x76";
+ TeeT :: "\x77";
+ LineV :: "\x78";
+
+ Blank :: "\x5F";
+ Diamond :: "\x60";
+ Checkerboard :: "\x61";
+ PlusMinus :: "\x67";
+ LessThanOrEqual :: "\x79";
+ GreaterThanOrEqual :: "\x7A";
+ Pi :: "\x7B";
+ NotEqual :: "\x7C";
+ CenteredDot :: "\x7E";
+}
+
+Commands :: struct {
+ EnterAlternateBuffer :: "\e[?1049h";
+ EnterMainBuffer :: "\e[?1049l";
+
+ EnterDrawingMode :: "\e(0";
+ EnterNormalMode :: "\e(B";
+ ClearScreen :: "\e[2J";
+ ClearLine :: "\e[2K";
+
+ RefreshWindow :: "\e[7t"; // TODO Not yet tested.
+
+ SetUTF8 :: "\e%G"; // TODO TEST ME PLEASE
+
+ // Cursor Visibility
+ ShowCursor :: "\e[?25h";
+ HideCursor :: "\e[?25l";
+ StartBlinking :: "\e[?25h]";
+ StopBlinking :: "\e[?25l]";
+ SaveCursorPosition :: "\e7";
+ RestoreCursorPosition :: "\e8";
+
+ // Cursor Shape
+ DefaultShape :: "\e[0 q";
+ BlinkingBlockShape :: "\e[1 q";
+ SteadyBlockShape :: "\e[2 q";
+ BlinkingUnderlineShape :: "\e[3 q";
+ SteadyUnderlineShape :: "\e[4 q";
+ BlinkingBarShape :: "\e[5 q";
+ SteadyBarShape :: "\e[6 q";
+
+ // Input Mode
+ KeypadAppMode :: "\e=";
+ KeypadNumMode :: "\e>";
+ CursorAppMode :: "\e[?1h";
+ CursorNormalMode :: "\e[?1l";
+
+ // Query State
+ QueryCursorPosition :: "\e[6n"; // Emits the cursor position as: "ESC [ <r> ; <c> R" Where <r> = row and <c> = column.
+ QueryDeviceAttributes :: "\e[0c";
+ QueryWindowSizeInChars :: "\e[18t"; // Emits the window size as: "ESC [ 8 <r> ; <c> t" Where <r> = row and <c> = column.
+
+}
+
+start :: () {
+ OS_prepare_terminal();
+ write_strings(Commands.HideCursor, Commands.SaveCursorPosition, Commands.EnterAlternateBuffer, Commands.SetUTF8);
+ isTUIActive = true;
+}
+
+stop :: () {
+ isTUIActive = false;
+ write_strings(Commands.EnterMainBuffer, Commands.RestoreCursorPosition, Commands.ShowCursor);
+ OS_reset_terminal();
+}
+
+draw_box :: (x: int, y: int, width: int, height: int, to_standard_error := false) {
+
+
+ // TODO Hardcoded box starting at 1,1... fix this!
+
+ write_strings(
+ // Commands.EnterNormalMode,
+ Commands.EnterDrawingMode,
+ "\e[1;1H", // Move to position 1,1
+ // TODO // Move pointer to top-left corner.
+ Drawings.CornerTL,
+ to_standard_error = to_standard_error);
+
+ for 1..width-2 {
+ write_string(Drawings.LineH, to_standard_error = to_standard_error);
+ }
+ write_string(Drawings.CornerTR, to_standard_error = to_standard_error);
+
+
+ // TODO Take care of the temporary allocations.
+ for idx: 2..height-1 {
+ tmpL := tprint("\e[%;%H", idx, 1);
+ tmpR := tprint("\e[%;%H", idx, width);
+ write_strings(
+ tmpL,
+ Drawings.LineV,
+ tmpR,
+ Drawings.LineV,
+ to_standard_error = to_standard_error);
+ }
+
+ tmpBL := tprint("\e[%;%H", height, 1);
+ write_strings(
+ tmpBL,
+ Drawings.CornerBL,
+ to_standard_error = to_standard_error);
+ for 1..width-2 {
+ write_string(Drawings.LineH, to_standard_error = to_standard_error);
+ }
+ write_string(Drawings.CornerBR, to_standard_error = to_standard_error);
+
+ write_strings(
+ // TODO // print
+ Commands.EnterNormalMode,
+ to_standard_error = to_standard_error);
+}
+
+clear_screen :: inline () {
+ write_string(Commands.ClearScreen);
+}
+
+get_terminal_size :: () -> rows: int, columns: int {
+ rows, columns := OS_get_terminal_size();
+ return rows, columns;
+}
+
+// read_input: () -> string {
+ // return OS_read_input();
+// }
+
+// get_cursor_position :: () -> row: int, column: int {
+// assert(isTUIActive, "TUI is not active."); // TODO
+// write_string(TUI.Commands.QueryCursorPosition); // Returned "\e[21;1R"
+// read_input()
+// }
+
+
+// read_input: () -> string;
+
+#if OS == .WINDOWS {
+
+ // #run read_input = () -> string {
+ read_input :: () -> string {
+ MAX_BYTES_TO_READ :: 1024;
+ temp : [MAX_BYTES_TO_READ] u8;
+ result: string = ---;
+ bytes_read : s32;
+
+ if !ReadConsoleA( stdin, temp.data, xx temp.count, *bytes_read )
+ return "";
+
+ result.data = alloc(bytes_read);
+ result.count = bytes_read;
+ memcpy(result.data, temp.data, bytes_read);
+ return result;
+ };
+}
+else #if OS == .LINUX || OS == .MACOS {
+ #import "Basic";
+ #import "POSIX";
+
+ read_input :: () -> string {
+ buffer: [8192] u8;
+ bytes_read := read(STDIN_FILENO, buffer.data, buffer.count-1);
+ str := to_string(buffer.data, bytes_read);
+ return str;
+ };
+}