aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-09-21 09:58:41 +0100
committerdam <dam@gudinoff>2023-09-21 09:58:41 +0100
commit1b6fbda3a7f9fa95e2dbbafea56388900167639c (patch)
tree8f107ea66d62362ab55087f30551269fb8840a9a
parent12181226862c73ab04992850b54c91e503f59bce (diff)
downloadtask-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.jai175
-rw-r--r--TUI/unix.jai2
-rw-r--r--ttt.jai14
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);
}
diff --git a/ttt.jai b/ttt.jai
index 0cd8ead..3910cd0 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -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;