diff options
| author | dam <dam@gudinoff> | 2023-09-20 00:45:44 +0100 |
|---|---|---|
| committer | dam <dam@gudinoff> | 2023-09-20 00:45:44 +0100 |
| commit | 9e2fc467ad0e779734d836656875cf92bcb5732a (patch) | |
| tree | 9cf327b8e19d2d5f0b501a4fce10d7440803e1e2 | |
| parent | 470702f3ef0645b47c11ff54b9a6b0a5e9e8caab (diff) | |
| download | task-time-tracker-9e2fc467ad0e779734d836656875cf92bcb5732a.tar.zst task-time-tracker-9e2fc467ad0e779734d836656875cf92bcb5732a.zip | |
Prepare TUI for windows.
| -rw-r--r-- | tio.jai | 62 | ||||
| -rw-r--r-- | ttt.jai | 18 | ||||
| -rw-r--r-- | tui.jai | 216 |
3 files changed, 228 insertions, 68 deletions
@@ -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; } } @@ -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. @@ -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; + } } |
