aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-09-20 00:45:44 +0100
committerdam <dam@gudinoff>2023-09-20 00:45:44 +0100
commit9e2fc467ad0e779734d836656875cf92bcb5732a (patch)
tree9cf327b8e19d2d5f0b501a4fce10d7440803e1e2
parent470702f3ef0645b47c11ff54b9a6b0a5e9e8caab (diff)
downloadtask-time-tracker-9e2fc467ad0e779734d836656875cf92bcb5732a.tar.zst
task-time-tracker-9e2fc467ad0e779734d836656875cf92bcb5732a.zip
Prepare TUI for windows.
-rw-r--r--tio.jai62
-rw-r--r--ttt.jai18
-rw-r--r--tui.jai216
3 files changed, 228 insertions, 68 deletions
diff --git a/tio.jai b/tio.jai
index f6ee0cb..9ccd04b 100644
--- a/tio.jai
+++ b/tio.jai
@@ -39,8 +39,11 @@ terminal_state : struct {
// https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcgetattr.c.html
tcgetattr :: (fd : s32, termios_p : *My_Termios) -> s32 #foreign libc;
}
+else #if OS == .WINDOWS {
+ #run print("TODO tio\n", to_standard_error = true);
+}
else {
- assert(false, "unsupported OS\n");
+ #run assert(false, "unsupported OS\n");
}
Graphics_Mode :: struct {
@@ -138,13 +141,21 @@ Color :: enum u8 {
}
update_terminal_size :: () {
- TIOCGWINSZ :: 0x5413;
- winsize : struct {
- ws_row, ws_col, ws_xpixel, ws_ypixel : u16;
+ #if OS == .LINUX {
+ TIOCGWINSZ :: 0x5413;
+ winsize : struct {
+ ws_row, ws_col, ws_xpixel, ws_ypixel : u16;
+ }
+ ioctl(0, TIOCGWINSZ, *winsize);
+ terminal_state.width = xx winsize.ws_col;
+ terminal_state.height = xx winsize.ws_row;
+ }
+ else #if OS == .WINDOWS {
+ print("TODO tio\n", to_standard_error = true);
+ }
+ else {
+ assert(false, "unsupported OS\n");
}
- ioctl(0, TIOCGWINSZ, *winsize);
- terminal_state.width = xx winsize.ws_col;
- terminal_state.height = xx winsize.ws_row;
}
initialize :: () {
@@ -170,10 +181,14 @@ initialize :: () {
tcsetattr(STDIN_FILENO, 0, *term_new);
}
- update_terminal_size();
- } else {
- assert(false, "procedure call on unsupported OS\n");
- }
+ update_terminal_size();
+ }
+ else #if OS == .WINDOWS {
+ print("TODO tio\n", to_standard_error = true);
+ }
+ else {
+ assert(false, "unsupported OS\n");
+ }
}
terminate :: () {
@@ -185,17 +200,24 @@ terminate :: () {
tui_write("\e[?25h"); // show cursor
tui_write("\e[?30h"); // show scrollbar
terminal_state = .{};
-
- } else {
- assert(false, "procedure call on unsupported OS\n");
+ }
+ else #if OS == .WINDOWS {
+ print("TODO tio\n", to_standard_error = true);
+ }
+ else {
+ assert(false, "unsupported OS\n");
}
}
tui_write :: (str : string) {
#if OS == .LINUX {
write(STDIN_FILENO, str.data, xx str.count);
- } else {
- assert(false, "procedure call on unsupported OS\n");
+ }
+ else #if OS == .WINDOWS {
+ #run print("TODO tio\n", to_standard_error = true);
+ }
+ else {
+ #run assert(false, "unsupported OS\n");
}
}
@@ -216,7 +238,13 @@ tui_getch :: (block := true) -> Key {
}
check_signal(buf);
return ifx l <= 0 then Key.READ_ERROR else buf;
- } else {
+ }
+ else #if OS == .WINDOWS {
+ print("TODO tio\n", to_standard_error = true);
+ return .READ_ERROR;
+ }
+ else {
+ assert(false, "unsupported OS\n");
return .READ_ERROR;
}
}
diff --git a/ttt.jai b/ttt.jai
index bb17489..588be28 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -1181,23 +1181,17 @@ read_enter_confirmation :: inline (row: int, style: int, message: string) -> boo
main :: () {
- // 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
+ // -- -- -- TODO WIP Testing TUI -- START
TUI.start();
TUI.clear_screen();
- rows, columns := TUI.get_cena();
+ rows, columns := TUI.get_buffer_size();
TUI.draw_box(1,1,columns, rows);
- // TODO get size of console... its being displayed... but we want to collect it.
- // write_string(TUI.Commands.QueryCursorPosition);
- // write_string(TUI.Commands.QueryWindowSizeInChars);
- // wow := TUI.read_input();
- sleep_milliseconds(3000);
+ sleep_milliseconds(1500);
TUI.stop();
-
- print("--- --- ---\nRxC = %x%\n", rows, columns);
+ print("\nr:c = %:%\n", rows, columns);
return;
+
str: string;
write_string("\e(0"); // Enter Line drawing mode
@@ -1223,6 +1217,8 @@ main :: () {
// write(STDIN_FILENO, str.data, xx str.count);
write_string(str);
return;
+ // -- -- -- TODO WIP Testing TUI -- STOP
+
// TODO Implement signal handling and see modules/Debug.jai for examples.
diff --git a/tui.jai b/tui.jai
index 564e9ba..e2ecaaf 100644
--- a/tui.jai
+++ b/tui.jai
@@ -1,6 +1,27 @@
+
+// TODO Change this into a module with subfiles windows.jai and unix.jai
+// #if OS == .WINDOWS {
+// #load "windows.jai";
+// } else #if (OS == .LINUX) || (OS == .MACOS) {
+// #load "unix.jai";
+// } else {
+// #assert(false, "Unsupported OS.");
+// }
+
+
+// TODO On OS validations, use .LINUX or .MACOS to allow MACOS users to enj... errmmm test this.
+
#import "Basic";
#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";
@@ -69,29 +90,85 @@ Commands :: struct {
}
start :: () {
- // TODO Required to do unlocking input.
- tcgetattr(STDIN_FILENO, *__term);
- term_new := __term;
-
- term_new.c_iflag &= 0xFFFFFA14;// ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
- 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;
-
- tcsetattr(STDIN_FILENO, 0, *term_new);
-
+ #if OS == .LINUX {
+ // TODO Required to do unlocking input.
+ tcgetattr(STDIN_FILENO, *__term);
+ term_new := __term;
+
+ term_new.c_iflag &= 0xFFFFFA14;// ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+ 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;
+
+ tcsetattr(STDIN_FILENO, 0, *term_new);
+ }
+ else {
+ print("TODO TUI\n", to_standard_error = true);
+
+
+ // stdin
+ stdin = GetStdHandle(STD_INPUT_HANDLE );
+ if stdin == INVALID_HANDLE_VALUE {
+ print("Invalid input handler.", to_standard_error = true);
+ return;
+ }
+ if GetConsoleMode(stdin, *initial_stdin_mode) == false {
+ print("Failed to get input mode.", to_standard_error = true);
+ return;
+ }
+ if SetConsoleMode(stdin, initial_stdin_mode | ENABLE_VIRTUAL_TERMINAL_INPUT) == false {
+ print("Failed to set input mode: %.", GetLastError(), to_standard_error = true);
+ return;
+ }
+
+ // stdout
+ stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ outMode: u32 = 0;
+ if stdout == INVALID_HANDLE_VALUE {
+ print("Invalid output handler.", to_standard_error = true);
+ return;
+ }
+ if GetConsoleMode(stdout, *initial_stdout_mode) == false {
+ print("Failed to get output mode.", to_standard_error = true);
+ return;
+ }
+ if SetConsoleMode(stdout, initial_stdout_mode | ENABLE_PROCESSED_OUTPUT| ENABLE_VIRTUAL_TERMINAL_PROCESSING) == false {
+ print("Failed to set output mode: %.", GetLastError(), to_standard_error = true);
+ return;
+ }
+ }
write_strings(Commands.HideCursor, Commands.SaveCursorPosition, Commands.EnterAlternateBuffer, Commands.SetUTF8);
+ isTUIActive = true;
}
stop :: () {
+ isTUIActive = false;
write_strings(Commands.EnterMainBuffer, Commands.RestoreCursorPosition, Commands.ShowCursor);
- tcsetattr(STDIN_FILENO, 0, *__term); // return echo
+ #if OS == .LINUX {
+ tcsetattr(STDIN_FILENO, 0, *__term); // return echo
+ }
+ else {
+ print("TODO TUI\n", to_standard_error = true);
+
+ if SetConsoleMode(stdin, initial_stdin_mode) == false {
+ print("Failed to reset input mode: %.", GetLastError(), to_standard_error = true);
+ return;
+ }
+
+ if SetConsoleMode(stdout, initial_stdout_mode) == false {
+ print("Failed to reset output mode: %.", GetLastError(), to_standard_error = true);
+ return;
+ }
+ }
}
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,
@@ -138,29 +215,41 @@ clear_screen :: inline () {
write_string(Commands.ClearScreen);
}
+
+// 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 == .LINUX {
#import "Basic";
#import "POSIX";
- __term : My_Termios;
-
- My_Termios :: struct {
- c_iflag : u32; // Input modes.
- c_oflag : u32; // Output modes.
- c_cflag : u32; // Control modes.
- c_lflag : u32; // Local modes.
- unknown_pad : u8;
- c_cc : [32]u8; // Special characters.
- c_ispeed : u32; // Input baud rates.
- c_ospeed : u32; // Output baud rates.
- }
+ __term : My_Termios;
+
+ My_Termios :: struct {
+ c_iflag : u32; // Input mode flags.
+ c_oflag : u32; // Output mode flags.
+ c_cflag : u32; // Control modes flags.
+ c_lflag : u32; // Local modes flags.
+ c_line : u8; // Line discipline.
+ c_cc : [32]u8; // Control characters.
+ c_ispeed : u32; // Input speed (baud rates).
+ c_ospeed : u32; // Output speed (baud rates).
+ }
// Required to do unlocking input.
- libc :: #system_library "libc";
- tcsetattr :: (fd : s32, optional_actions : s32, termios_p : *My_Termios) -> s32 #foreign libc;
- tcgetattr :: (fd : s32, termios_p : *My_Termios) -> s32 #foreign libc;
+ libc :: #system_library "libc";
+
+ // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcsetattr.c.html
+ tcsetattr :: (fd : s32, optional_actions : s32, termios_p : *My_Termios) -> s32 #foreign libc;
+
+ // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcgetattr.c.html
+ tcgetattr :: (fd : s32, termios_p : *My_Termios) -> s32 #foreign libc;
@@ -171,13 +260,13 @@ clear_screen :: inline () {
return str;
};
- get_cena :: () -> rows: int, columns: int {
+ get_buffer_size :: () -> rows: int, columns: int {
buffer: [512] u8;
write_string(Commands.QueryWindowSizeInChars);
bytes_read := read(STDIN_FILENO, buffer.data, buffer.count-1);
str := to_string(buffer.data, bytes_read);
-
+
// Result: [8;79;156t
assert(
buffer.data[0] == #char "\e" &&
@@ -195,19 +284,52 @@ clear_screen :: inline () {
else #if OS == .WINDOWS {
#import "Windows";
+ ENABLE_VIRTUAL_TERMINAL_INPUT :: 0x0200;
+
+ ENABLE_PROCESSED_OUTPUT :: 0x0001;
+ ENABLE_WRAP_AT_EOL_OUTPUT :: 0x0002;
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING :: 0x0004;
+ DISABLE_NEWLINE_AUTO_RETURN :: 0x0008;
+ ENABLE_LVB_GRID_WORLDWIDE :: 0x0010;
+
+ SHORT :: s16;
+ WORD :: u16;
+ DWORD :: s32;
+
+ COORD :: struct {
+ X : SHORT;
+ Y : SHORT;
+ }
+
+ SMALL_RECT :: struct {
+ Left : SHORT;
+ Top : SHORT;
+ Right : SHORT;
+ Bottom : SHORT;
+ }
+
+ CONSOLE_SCREEN_BUFFER_INFO :: struct {
+ dwSize : COORD;
+ dwCursorPosition : COORD;
+
+ wAttributes : WORD;
+ srWindow : SMALL_RECT;
+ dwMaximumWindowSize : COORD;
+ }
+
kernel32 :: #system_library "kernel32";
-
- stdin, stdout : HANDLE;
- stdin = GetStdHandle( STD_INPUT_HANDLE );
+ GetConsoleScreenBufferInfo :: (hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) -> bool #foreign kernel32;
+ ReadConsoleA :: (hConsoleHandle: HANDLE, buff : *u8, chars_to_read : s32, chars_read : *s32, lpInputControl := *void ) -> bool #foreign kernel32;
+ // ReadConsole :: (hConsoleInput: HANDLE, lpBuffer: *u8, nNumberOfCharsToRead: s32, lpNumberOfCharsRead: *s32, pInputControl := *void) -> bool #foreign kernel32;
+ GetConsoleMode :: (hConsoleHandle: HANDLE, lpMode: *u32) -> bool #foreign kernel32;
+ SetConsoleMode :: (hConsoleHandle: HANDLE, dwMode: u32) -> bool #foreign kernel32;
+ GetLastError :: () -> s32 #foreign kernel32;
- ReadConsoleA :: (
- hConsoleHandle: HANDLE,
- buff : *u8,
- chars_to_read : s32,
- chars_read : *s32,
- lpInputControl := *void
- ) -> bool #foreign kernel32;
+ stdin: HANDLE;
+ initial_stdin_mode: u32;
+ stdout: HANDLE;
+ initial_stdout_mode: u32;
// #run read_input = () -> string {
read_input :: () -> string {
@@ -224,4 +346,18 @@ else #if OS == .WINDOWS {
memcpy(result.data, temp.data, bytes_read);
return result;
};
+
+ get_buffer_size :: () -> rows: int, columns: int {
+
+ // GET WINDOW CHAR SIZE
+
+
+ ScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO;
+ GetConsoleScreenBufferInfo(stdout, *ScreenBufferInfo);
+ Size: COORD;
+ Size.X = ScreenBufferInfo.srWindow.Right - ScreenBufferInfo.srWindow.Left + 1;
+ Size.Y = ScreenBufferInfo.srWindow.Bottom - ScreenBufferInfo.srWindow.Top + 1;
+
+ return Size.Y, Size.X;
+ }
}