diff options
| author | dam <dam@gudinoff> | 2023-09-21 09:58:41 +0100 |
|---|---|---|
| committer | dam <dam@gudinoff> | 2023-09-21 09:58:41 +0100 |
| commit | 1b6fbda3a7f9fa95e2dbbafea56388900167639c (patch) | |
| tree | 8f107ea66d62362ab55087f30551269fb8840a9a | |
| parent | 12181226862c73ab04992850b54c91e503f59bce (diff) | |
| download | task-time-tracker-1b6fbda3a7f9fa95e2dbbafea56388900167639c.tar.zst task-time-tracker-1b6fbda3a7f9fa95e2dbbafea56388900167639c.zip | |
Fixed draw_box procedure. Added buggy prototype for read_input.
| -rw-r--r-- | TUI/module.jai | 175 | ||||
| -rw-r--r-- | TUI/unix.jai | 2 | ||||
| -rw-r--r-- | ttt.jai | 14 |
3 files changed, 152 insertions, 39 deletions
diff --git a/TUI/module.jai b/TUI/module.jai index 6d65342..27a871b 100644 --- a/TUI/module.jai +++ b/TUI/module.jai @@ -6,6 +6,7 @@ #assert(false, "Unsupported OS."); } +#import "Basic"; #import "String"; // https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences @@ -52,6 +53,9 @@ Commands :: struct { SetUTF8 :: "\e%G"; // TODO TEST ME PLEASE + // Cursor Position + SetCursorPosition :: "\e[%;%H"; + // Cursor Visibility ShowCursor :: "\e[?25h"; HideCursor :: "\e[?25l"; @@ -78,16 +82,18 @@ Commands :: struct { // 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. + QueryWindowSizeInChars :: "\e[18t"; // Emits the window size as: "ESC [ 8 <r> ; <c> t" Where <r> = row and <c> = column. TODO Does not work on windows. } +// TODO Maybe rename to "setup()" start :: () { OS_prepare_terminal(); write_strings(Commands.HideCursor, Commands.SaveCursorPosition, Commands.EnterAlternateBuffer, Commands.SetUTF8); isTUIActive = true; } +// TODO Maybe rename to "reset()" stop :: () { isTUIActive = false; write_strings(Commands.EnterMainBuffer, Commands.RestoreCursorPosition, Commands.ShowCursor); @@ -96,14 +102,18 @@ stop :: () { draw_box :: (x: int, y: int, width: int, height: int) { + // TODO Check if using a String_Builder improves performance (measure it)! + // TODO Validate input parameters against the terminal size. + assert(x > 0 && y > 0 && width > 1 && height > 1, "Invalid arguments."); - // TODO Hardcoded box starting at 1,1... fix this! - + auto_release_temp(); + + tmp_string: string; + + tmp_string = tprint(Commands.SetCursorPosition, y, x); write_strings( - // Commands.EnterNormalMode, Commands.EnterDrawingMode, - "\e[1;1H", // Move to position 1,1 - // TODO // Move pointer to top-left corner. + tmp_string, Drawings.CornerTL ); @@ -112,11 +122,9 @@ draw_box :: (x: int, y: int, width: int, height: int) { } write_string(Drawings.CornerTR); - - // TODO Take care of the temporary allocations. - for idx: 2..height-1 { - tmpL := tprint("\e[%;%H", idx, 1); - tmpR := tprint("\e[%;%H", idx, width); + for idx: y+1..y+height-2 { + tmpL := tprint(Commands.SetCursorPosition, idx, x); + tmpR := tprint(Commands.SetCursorPosition, idx, x+width-1); write_strings( tmpL, Drawings.LineV, @@ -124,7 +132,7 @@ draw_box :: (x: int, y: int, width: int, height: int) { Drawings.LineV); } - tmpBL := tprint("\e[%;%H", height, 1); + tmpBL := tprint(Commands.SetCursorPosition, y+height-1, x); write_strings( tmpBL, Drawings.CornerBL); @@ -133,13 +141,15 @@ draw_box :: (x: int, y: int, width: int, height: int) { } write_string(Drawings.CornerBR); - write_strings(Commands.EnterNormalMode); + write_string(Commands.EnterNormalMode); } -clear_screen :: inline () { +// TODO Maybe rename to "clear()" +clear_terminal :: inline () { write_string(Commands.ClearScreen); } +// TODO Maybe rename to "get_size()" get_terminal_size :: () -> rows: int, columns: int { rows, columns := OS_get_terminal_size(); return rows, columns; @@ -149,41 +159,138 @@ get_terminal_size :: () -> rows: int, columns: int { // 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() -// } +set_cursor_position :: (row: int, column: int) { + auto_release_temp(); + tmp_string := tprint(Commands.SetCursorPosition, row, column); + write_string(tmp_string); +} +get_cursor_position :: () -> row: int, column: int { + assert(isTUIActive, "TUI is not active."); // TODO + write_string(Commands.QueryCursorPosition); // Returned + input := read_input(false); + // Result: \e[21;1R + assert( + input.data[0] == #char "\e" && + input.data[1] == #char "[" && + input.data[input.count-1] == #char "R", + "Query cursor position returned invalid response."); + + input.data += 2; + print(">%<\n", input); + parts := split(input, ";"); + row := parse_int(*parts[0]); + column := parse_int(*parts[1]); + return row, column; +} + +read_input :: (blocking: bool = true) -> string { + return OS_read_input(blocking); +} // read_input: () -> string; #if OS == .WINDOWS { - // #run read_input = () -> string { - read_input :: () -> string { + OS_read_input :: (blocking: bool) -> string { + result: 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); + + if ReadConsoleA(stdin, temp.data, xx temp.count, *bytes_read) { + 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 { + OS_read_input :: (blocking: bool) -> string { + + term : My_Termios; + tcgetattr(STDIN_FILENO, *term); + + // Input modes. + Input_Modes :: enum u32 { + IGNBRK; // Ignore break condition. + BRKINT; // Signal interrupt on break. + IGNPAR; // Ignore characters with parity errors. + PARMRK; // Mark parity and framing errors. + INPCK; // Enable input parity check. + ISTRIP; // Strip 8th bit off characters. + INLCR; // Map NL to CR on input. + IGNCR; // Ignore CR. + ICRNL; // Map CR to NL on input. + IXON; // Enable start/stop output control. + IXOFF; // Enable start/stop input control. + IXANY; // Any character will restart after stop. + __NOT_USED__; + IMAXBEL; // Ring bell when input queue is full. + IUCLC; // Translate upper case input to lower case. + } + + // IGNBRK :u32: (1 << 0); // Ignore break condition. + // BRKINT :u32: (1 << 1); // Signal interrupt on break. + // IGNPAR :u32: (1 << 2); // Ignore characters with parity errors. + // PARMRK :u32: (1 << 3); // Mark parity and framing errors. + // INPCK :u32: (1 << 4); // Enable input parity check. + // ISTRIP :u32: (1 << 5); // Strip 8th bit off characters. + // INLCR :u32: (1 << 6); // Map NL to CR on input. + // IGNCR :u32: (1 << 7); // Ignore CR. + // ICRNL :u32: (1 << 8); // Map CR to NL on input. + // IXON :u32: (1 << 9); // Enable start/stop output control. + // IXOFF :u32: (1 << 10); // Enable start/stop input control. + // IXANY :u32: (1 << 11); // Any character will restart after stop. + // IMAXBEL :u32: (1 << 13); // Ring bell when input queue is full. + // IUCLC :u32: (1 << 14); // Translate upper case input to lower case. + + // IGNBRK :u32: 0x0001; + // BRKINT :u32: 0x0002; + // IGNCR :u32: 0x0040; + + ECHO :u32: 0x0004; + ECHONL :u32: 0x0010; + ICANON :u32: 0x0080; + IEXTEN :u32: 0x0400; + + backup: My_Termios; + tcgetattr(STDIN_FILENO, *backup); + + if blocking { + term = __term; + // iflags: Input_Modes = (.IGNBRK | .BRKINT | .PARMRK | .ISTRIP | .INLCR | .IGNCR | .ICRNL | .IXON); + // term.c_iflag |= xx iflags; + // term.c_lflag |= (ECHO | ECHONL | ICANON | IEXTEN); + } + else { + iflags: Input_Modes = (.IGNBRK | .BRKINT | .PARMRK | .ISTRIP | .INLCR | .IGNCR | .ICRNL | .IXON); + term.c_iflag &= xx ~(iflags); + term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); + } + + // term.c_iflag &= 0xFFFFFA14;// ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + // term.c_oflag &= 0xFFFFFFFE;// ~OPOST; + // term.c_lflag &= 0xFFFF7FB4;// ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + // term.c_cflag &= 0xFFFFFECF;// ~(CSIZE | PARENB); + // term.c_cflag |= 0x00000030; + + tcsetattr(STDIN_FILENO, 0, *term); + + result: string = ---; buffer: [8192] u8; + write_string(Commands.ShowCursor); bytes_read := read(STDIN_FILENO, buffer.data, buffer.count-1); - str := to_string(buffer.data, bytes_read); - return str; + write_string(Commands.HideCursor); + + // TODO WIP WIP WIP + result = to_string(buffer.data, bytes_read); // TODO WIP WIP WIP This is still using the stack allocated buffer and WILL FAIL! + + tcsetattr(STDIN_FILENO, 0, *backup); + + return result; }; } diff --git a/TUI/unix.jai b/TUI/unix.jai index 439447d..e5c81c3 100644 --- a/TUI/unix.jai +++ b/TUI/unix.jai @@ -33,7 +33,7 @@ OS_prepare_terminal :: () { term_new.c_oflag &= 0xFFFFFFFE;// ~OPOST; term_new.c_lflag &= 0xFFFF7FB4;// ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); term_new.c_cflag &= 0xFFFFFECF;// ~(CSIZE | PARENB); - term_new.c_cflag |= 0x00000030; + term_new.c_cflag |= 0x00000030; // TODO WHAT IS THIS? tcsetattr(STDIN_FILENO, 0, *term_new); } @@ -1183,12 +1183,18 @@ main :: () { // -- -- -- TODO WIP Testing TUI -- START TUI.start(); - TUI.clear_screen(); + TUI.clear_terminal(); rows, columns := TUI.get_terminal_size(); - TUI.draw_box(1,1,columns, rows); - sleep_milliseconds(1500); + TUI.draw_box(1, 1, columns, rows); + TUI.set_cursor_position(3, 3); + input := TUI.read_input(true); + TUI.set_cursor_position(3, 3); + c_row, c_column := TUI.get_cursor_position(); + // sleep_milliseconds(1500); TUI.stop(); - print("\nr:c = %:%\n", rows, columns); + print("\ninput = %\n", input); + print("cursor r:c = %:%\n", c_row, c_column); + print("window r:c = %:%\n", rows, columns); return; |
