diff options
| author | dam <devnull@localhost> | 2024-04-15 12:38:18 +0100 |
|---|---|---|
| committer | dam <devnull@localhost> | 2024-04-15 12:38:18 +0100 |
| commit | 3112131c24ede1ea343383ffd4f8ca7bc4783f47 (patch) | |
| tree | b1541d366eb42a1ea2ef5c4a889e045e8dc45119 /modules/TUI | |
| parent | 5844ab303d3d7fc396beb7c6d8a0104496608f08 (diff) | |
| download | task-time-tracker-3112131c24ede1ea343383ffd4f8ca7bc4783f47.tar.zst task-time-tracker-3112131c24ede1ea343383ffd4f8ca7bc4783f47.zip | |
Add module logger that switches between main/alternate screen buffers to write logs.
Diffstat (limited to 'modules/TUI')
| -rw-r--r-- | modules/TUI/module.jai | 27 | ||||
| -rw-r--r-- | modules/TUI/windows.jai | 44 |
2 files changed, 35 insertions, 36 deletions
diff --git a/modules/TUI/module.jai b/modules/TUI/module.jai index 3843cd7..070161c 100644 --- a/modules/TUI/module.jai +++ b/modules/TUI/module.jai @@ -17,6 +17,11 @@ #import "UTF8"; #load "key_map.jai"; +#run { + assert(COLOR_MODE == 4 || COLOR_MODE == 8 || COLOR_MODE == 24, "Invalid COLOR_MODE. Valid values are 4, 8, or 24 (default)."); + assert(input_buffer.count >= KEY_SIZE, "The input buffer size must be capable to hold an entire Key, which should be able to hold an UTF8 code (4 bytes) or a terminal escape code (6 bytes)."); +} + // Special Graphics Characters Drawings :: struct { Blank :: "\x5F"; @@ -271,9 +276,15 @@ input_buffer : [1024] u8; input_string : string; input_override : Key; -#run { - assert(COLOR_MODE == 4 || COLOR_MODE == 8 || COLOR_MODE == 24, "Invalid COLOR_MODE. Valid values are 4, 8, or 24 (default)."); - assert(input_buffer.count >= KEY_SIZE, "The input buffer size must be capable to hold an entire Key, which should be able to hold an UTF8 code (4 bytes) or a terminal escape code (6 bytes)."); +previous_logger : (message: string, data: *void, info: Log_Info); + +module_logger :: (message: string, data: *void, info: Log_Info) { + // print("%0%0\n%0", Commands.MainScreenBuffer, message, Commands.AlternateScreenBuffer); + x, y := get_cursor_position(); + write_string(Commands.MainScreenBuffer); + previous_logger(message, data, info); + write_string(Commands.AlternateScreenBuffer); + set_cursor_position(x, y); } assert_is_active :: inline () { @@ -444,7 +455,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key { } else { set_cursor_position(x, y); - for 0..chars_count print_character(#char "*"); + for 1..chars_count print_character(#char "*"); for chars_count..count_limit-1 print_character(#char " "); } set_cursor_position(x+idx, y); @@ -510,7 +521,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key { start :: () { if active == true return; - + // TODO Should start() call flush_input internally? setup_key_map(); // TODO This is being called multiple times... please fix me! @@ -526,6 +537,9 @@ start :: () { Commands.SetUTF8, Commands.CursorNormalMode, Commands.KeypadNumMode); + + previous_logger = context.logger; + context.logger = module_logger; OS_prepare_terminal(); @@ -538,6 +552,9 @@ stop :: () { clear_style(); OS_reset_terminal(); + + context.logger = previous_logger; + write_strings(Commands.MainScreenBuffer, Commands.RestoreCursorPosition, Commands.ShowCursor); } diff --git a/modules/TUI/windows.jai b/modules/TUI/windows.jai index 5155a3f..5755ef4 100644 --- a/modules/TUI/windows.jai +++ b/modules/TUI/windows.jai @@ -72,21 +72,6 @@ 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; - } - INPUT_RECORD_EVENT_TYPE :: enum u16 { KEY_EVENT :: 0x0001; MOUSE_EVENT :: 0x0002; @@ -148,7 +133,7 @@ was_resized: bool; - windows_buffer: [512] u16; + widechar_buffer: [512] u16; peek_input :: inline () -> INPUT_RECORD, success := true { @@ -187,8 +172,6 @@ count_input :: inline () -> u32, success := true { #scope_export -// TODO All the log_error calls will be hidden by the terminal setup... we should store the logs internally, or write it to a file. - OS_prepare_terminal :: () { // stdin @@ -256,7 +239,7 @@ OS_reset_terminal :: () { } OS_flush_input :: inline () { - /* NOTE + /* This API is not recommended and does not have a virtual terminal equivalent. Attempting to empty the input queue all at once can destroy state in the queue in an unexpected manner. */ @@ -295,19 +278,19 @@ OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, success : } else { - chars_view: [] u16; - chars_view.data = windows_buffer.data; + widechar_view: [] u16; + widechar_view.data = widechar_buffer.data; - chars_to_read := ifx available_inputs <= windows_buffer.count then available_inputs else windows_buffer.count; + chars_to_read := ifx available_inputs <= widechar_buffer.count then available_inputs else widechar_buffer.count; - success = ReadConsoleW(stdin, chars_view.data, chars_to_read, *chars_view.count, null); + success = ReadConsoleW(stdin, widechar_view.data, chars_to_read, *widechar_view.count, null); if success == false { error_code, error_string := get_error_value_and_string(); log_error("Failed to read console: code %, %", error_code, error_string); return 0, false; } - result:, success = wide_to_utf8_new(chars_view.data, xx chars_view.count); + result:, success = wide_to_utf8_new(widechar_view.data, xx widechar_view.count); if success == false { error_code, error_string := get_error_value_and_string(); log_error("Failed to convert from wide to utf8: code %, %", error_code, error_string); @@ -335,13 +318,12 @@ OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, success : // 0: do not wait // -1: wait indefinitely OS_wait_for_input :: (timeout_milliseconds: s32 = -1) -> is_input_available: bool, success := true { - - /* TODO - Add a good comment explaining how the windows part of the module was implemented... what's the idea behind it. - Something like, Since windows provides a single input buffer with all events, we need to peek through them and - discard the ones that are of no use for us. - Because it's a single buffer, all functions need to do repeated work (see if it's resize, see if it's a key press) - ... and so on. + /* + The Windows API provides all input events (keyboard, mouse, window resize) on a single input buffer. + To make it match this module's API, we need to do some pre-processing while waiting for input. + This means that OS_wait_for_input will peek at the input events, signal if a window resize is found, + and discard unwanted events (like button release events). + A similar logic is applied in OS_read_input. */ expiration := current_time_monotonic() + to_apollo(timeout_milliseconds / 1000.0); |
