aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/TUI/module.jai122
-rw-r--r--ttt.jai61
2 files changed, 116 insertions, 67 deletions
diff --git a/modules/TUI/module.jai b/modules/TUI/module.jai
index a5db3bf..f2a3a23 100644
--- a/modules/TUI/module.jai
+++ b/modules/TUI/module.jai
@@ -32,14 +32,17 @@
#import "UTF8";
#load "key_map.jai";
+#add_context tui_style : Style; // This contains the last style applied by the module.
+#add_context tui_buffer : *String_Builder; // If set, this buffer will be used as output target of module procedures.
+
+KEY_SIZE :: #run type_info(Key).runtime_size;
+#assert(input_buffer.count >= KEY_SIZE); // The input buffer size must be capable to hold an entire Key.
+
active := false;
input_override : Key;
input_string : string;
input_buffer : [1024] u8;
-
-KEY_SIZE :: #run type_info(Key).runtime_size;
-
-#assert(input_buffer.count >= KEY_SIZE); // The input buffer size must be capable to hold an entire Key.
+temp_buffer := String_Builder.{ allocator = temporary_allocator };
#scope_module
@@ -51,7 +54,7 @@ assert_is_active :: inline () {
log_tui_error :: (format_string: string, args: .. Any) {
write_strings(Commands.SaveCursorPosition, Commands.MainScreenBuffer);
- log_error(format_string, args);
+ log_error(format_string, ..args);
write_strings(Commands.AlternateScreenBuffer, Commands.RestoreCursorPosition);
}
@@ -151,8 +154,6 @@ Commands :: struct #type_info_none {
CursorNormalMode :: "\e[?1l";
}
-#add_context terminal_style: Style;
-
Style :: struct {
#if COLOR_MODE_BITS == 4 || COLOR_MODE_BITS == 8 {
background: Palette;
@@ -175,25 +176,26 @@ Style :: struct {
}
set_style :: (style: Style) {
- auto_release_temp();
- builder := String_Builder.{ allocator = temporary_allocator };
+ auto_release_temp();
+
+ builder := ifx context.tui_buffer != null then context.tui_buffer else *temp_buffer;
#if COLOR_MODE_BITS == {
case 4;
- print_to_builder(*builder,
+ print_to_builder(builder,
#run sprint("%0%0", Commands.SetGraphicsRendition, Commands.SetGraphicsRendition),
cast(u8)style.foreground + 30, cast(u8)style.background + 40
);
case 8;
- print_to_builder(*builder,
+ print_to_builder(builder,
#run sprint(Commands.SetGraphicsRendition, "38;5;%;48;5;%"),
cast(u8)style.foreground, cast(u8)style.background
);
case 24;
- print_to_builder(*builder,
+ print_to_builder(builder,
#run sprint(Commands.SetGraphicsRendition, "38;2;%;%;%;48;2;%;%;%"),
style.foreground.r, style.foreground.g, style.foreground.b,
style.background.r, style.background.g, style.background.b
@@ -201,25 +203,27 @@ set_style :: (style: Style) {
}
if style.use_default_foreground_color {
- append(*builder, #run sprint(Commands.SetGraphicsRendition, "39"));
+ append(builder, #run sprint(Commands.SetGraphicsRendition, "39"));
}
if style.use_default_background_color {
- append(*builder, #run sprint(Commands.SetGraphicsRendition, "49"));
+ append(builder, #run sprint(Commands.SetGraphicsRendition, "49"));
}
- write_string(builder_to_string(*builder,, allocator = temporary_allocator));
+ if context.tui_buffer == null {
+ write_builder(builder);
+ }
- context.terminal_style = style;
+ context.tui_style = style;
}
clear_style :: () {
write_string(#run sprint(Commands.SetGraphicsRendition, "0"));
- context.terminal_style = .{ };
+ context.tui_style = .{ };
}
using_style :: (style: Style) #expand {
- __style := context.terminal_style;
+ __style := context.tui_style;
set_style(style);
`defer set_style(__style);
}
@@ -493,7 +497,11 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key {
assert_is_active();
assert(count_limit >= 0, "Invalid arguments passed to read_input_line(): 'count_limit' must be greater-than or equal to 0.");
- builder := String_Builder.{ allocator = temporary_allocator };
+ // builder := String_Builder.{ allocator = temporary_allocator };
+ // builder := String_Builder.{};
+ // init_string_builder(*builder, 10000);
+ // reset(*builder);
+ builder := temp_buffer;
str := alloc_string(count_limit);
str.count = 0;
@@ -509,7 +517,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key {
chars_count := count_characters(str);
- // Draw preview.
+ // Preview input line.
if is_visible {
print_to_builder(*builder, Commands.SetCursorPosition, y, x);
append(*builder, str);
@@ -521,6 +529,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key {
for chars_count..count_limit-1 append(*builder, " ");
}
print_to_builder(*builder, Commands.SetCursorPosition, y, x+idx);
+ // write_builder(*builder); // TODO Not sure why this is not working...
write_string(builder_to_string(*builder,, allocator = temporary_allocator));
// Process input key.
@@ -594,38 +603,40 @@ draw_box :: (x: int, y: int, width: int, height: int) {
assert(x > 0 && y > 0 && width > 1 && height > 1, "Invalid arguments passed to draw_box(): 'x' and 'y' must be greater-than 0; 'width' and 'height' must be greater-than 1.");
auto_release_temp();
-
- builder := String_Builder.{ allocator = temporary_allocator };
-
- append(*builder, Commands.DrawingMode);
+
+ builder := ifx context.tui_buffer != null then context.tui_buffer else *temp_buffer;
+
+ append(builder, Commands.DrawingMode);
// Draw top line
- print_to_builder(*builder, Commands.SetCursorPosition, y, x);
- append(*builder, Drawings.CornerTL);
+ print_to_builder(builder, Commands.SetCursorPosition, y, x);
+ append(builder, Drawings.CornerTL);
for 1..width-2 {
- append(*builder, Drawings.LineH);
+ append(builder, Drawings.LineH);
}
- append(*builder, Drawings.CornerTR);
+ append(builder, Drawings.CornerTR);
// Draw left and right sides.
for idx: y+1..y+height-2 {
- print_to_builder(*builder, Commands.SetCursorPosition, idx, x);
- append(*builder, Drawings.LineV);
- print_to_builder(*builder, Commands.SetCursorPosition, idx, x+width-1);
- append(*builder, Drawings.LineV);
+ print_to_builder(builder, Commands.SetCursorPosition, idx, x);
+ append(builder, Drawings.LineV);
+ print_to_builder(builder, Commands.SetCursorPosition, idx, x+width-1);
+ append(builder, Drawings.LineV);
}
// Draw bottom line.
- print_to_builder(*builder, Commands.SetCursorPosition, y+height-1, x);
- append(*builder, Drawings.CornerBL);
+ print_to_builder(builder, Commands.SetCursorPosition, y+height-1, x);
+ append(builder, Drawings.CornerBL);
for 1..width-2 {
- append(*builder, Drawings.LineH);
+ append(builder, Drawings.LineH);
}
- append(*builder, Drawings.CornerBR);
+ append(builder, Drawings.CornerBR);
- append(*builder, Commands.TextMode);
-
- write_string(builder_to_string(*builder,, allocator = temporary_allocator));
+ append(builder, Commands.TextMode);
+
+ if context.tui_buffer == null {
+ write_builder(builder);
+ }
}
clear_terminal :: inline () {
@@ -682,7 +693,12 @@ get_terminal_size :: () -> width: int, height: int {
set_cursor_position :: inline (x: int, y: int) {
assert_is_active();
- print(Commands.SetCursorPosition, y, x);
+ if context.tui_buffer == null {
+ print(Commands.SetCursorPosition, y, x);
+ }
+ else {
+ print_to_builder(context.tui_buffer, Commands.SetCursorPosition, y, x);
+ }
}
get_cursor_position :: () -> x: int, y: int {
@@ -723,3 +739,29 @@ set_terminal_title :: inline (title: string) {
assert_is_active();
print(Commands.SetWindowTitle, title);
}
+
+using_buffer :: (buffer: *String_Builder) #expand {
+ __buffer := context.tui_buffer;
+ context.tui_buffer = buffer;
+ `defer context.tui_buffer = __buffer;
+}
+
+// TODO Maybe we should have a different name for this...?
+tui_print :: inline (format_string: string, args: .. Any) {
+ if context.tui_buffer == null {
+ print(format_string, ..args, to_standard_error = false);
+ }
+ else {
+ print_to_builder(context.tui_buffer, format_string, ..args);
+ }
+}
+
+// TODO Maybe we should have a different name for this...?
+tui_write :: inline (format_string: string) {
+ if context.tui_buffer == null {
+ write_string(format_string);
+ }
+ else {
+ append(context.tui_buffer, format_string);
+ }
+}
diff --git a/ttt.jai b/ttt.jai
index 7d1559b..ff3c757 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -216,29 +216,29 @@ print_time :: (y: int, x: int, time: s64, space: int) -> int {
print_padding :: (size: int, char: u8 = #char " ") {
assert(size >= 0, "Cannot print negative padding values. The procedure accepts signed values just for convenience.");
- while size > 0 {
- print_character(char);
- size -= 1;
- }
+ auto_release_temp();
+ padding := talloc_string(size);
+ memset(padding.data, char, size);
+ TUI.tui_write(padding);
}
TUI.set_cursor_position(x, y);
if time < 0 {
print_padding(left_padding);
- write_string(" - ");
+ TUI.tui_write(" - ");
print_padding(right_padding);
return 0;
}
else if time == 0 {
print_padding(left_padding);
- write_string(" 0 ");
+ TUI.tui_write(" 0 ");
print_padding(right_padding);
return 0;
}
else if time < SECONDS_IN_MINUTE {
print_padding(left_padding);
- print("%s ", FormatInt.{value = time, minimum_digits=3, padding=#char " "});
+ TUI.tui_print("%s ", FormatInt.{value = time, minimum_digits=3, padding=#char " "});
print_padding(right_padding);
return 0;
}
@@ -246,7 +246,7 @@ print_time :: (y: int, x: int, time: s64, space: int) -> int {
hours := time / SECONDS_IN_HOUR;
minutes := (time - (hours * SECONDS_IN_HOUR) ) / SECONDS_IN_MINUTE;
print_padding(left_padding);
- print("%:%", FormatInt.{value = hours, minimum_digits=2}, FormatInt.{value = minutes, minimum_digits=2});
+ TUI.tui_print("%:%", FormatInt.{value = hours, minimum_digits=2}, FormatInt.{value = minutes, minimum_digits=2});
print_padding(right_padding);
return 0;
}
@@ -257,7 +257,7 @@ print_time :: (y: int, x: int, time: s64, space: int) -> int {
ifx time >= #run mul_f64_s64(9.995, SECONDS_IN_DAY) then 1 else
2;
print_padding(left_padding);
- print("%d", FormatFloat.{value = value, trailing_width=decimals, width=4});
+ TUI.tui_print("%d", FormatFloat.{value = value, trailing_width=decimals, width=4});
print_padding(right_padding);
return 0;
}
@@ -268,13 +268,13 @@ print_time :: (y: int, x: int, time: s64, space: int) -> int {
ifx time >= #run mul_f64_s64(9.995, SECONDS_IN_YEAR) then 1 else
2;
print_padding(left_padding);
- print("%y", FormatFloat.{value = value, trailing_width=decimals, width=4});
+ TUI.tui_print("%y", FormatFloat.{value = value, trailing_width=decimals, width=4});
print_padding(right_padding);
return 0;
}
else {
print_padding(left_padding);
- write_string(" ∞ ");
+ TUI.tui_write(" ∞ ");
print_padding(right_padding);
return 0;
}
@@ -897,6 +897,7 @@ update_layout :: () {
dbg_average := 0; // DEBUG
dbg_count := 0; // DEBUG
+buffer: String_Builder; // TODO
draw_user_interface :: (db: *Database, layout: *Layout) {
start := current_time_monotonic(); // DEBUG
@@ -905,6 +906,11 @@ draw_user_interface :: (db: *Database, layout: *Layout) {
empty_line := talloc_string(size_x);
memset(empty_line.data, #char " ", size_x);
+
+ init_string_builder(*buffer, 100000);
+ // builder := String_Builder.{ allocator = temporary_allocator };
+ builder := buffer;
+ TUI.using_buffer(*builder);
adjust_first_day_of_week := int.[
(0 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS,
@@ -931,25 +937,25 @@ draw_user_interface :: (db: *Database, layout: *Layout) {
// Draw outer border.
TUI.draw_box(1, 1, size_x, size_y);
-
+
// Draw table grids.
// TODO Maybe this could be simplified?
y = 1;
x = 1;
- write_string(TUI.Commands.DrawingMode);
+ TUI.tui_write(TUI.Commands.DrawingMode); // append(*builder, TUI.Commands.DrawingMode); TODO
for 0..layout.columns.count-2 {
column := layout.columns[it];
x += 1 + column.width;
TUI.set_cursor_position(x, y);
- write_string(TUI.Drawings.TeeT);
+ TUI.tui_write(TUI.Drawings.TeeT); // TODO append(*builder, TUI.Drawings.TeeT);
for row: 2..size_y {
TUI.set_cursor_position(x, row);
- write_string(TUI.Drawings.LineV);
+ TUI.tui_write(TUI.Drawings.LineV); // TODO append(*builder, TUI.Drawings.LineV);
}
TUI.set_cursor_position(x, size_y);
- write_string(TUI.Drawings.TeeB);
+ TUI.tui_write(TUI.Drawings.TeeB); // TODO append(*builder, TUI.Drawings.TeeB);
}
- write_string(TUI.Commands.TextMode);
+ TUI.tui_write(TUI.Commands.TextMode); // TODO append(*builder, TUI.Commands.TextMode);
///////////////////////////////////////////////////////////////////////////
@@ -961,7 +967,7 @@ draw_user_interface :: (db: *Database, layout: *Layout) {
x += 1;
col = *layout.columns[L_TITLE_IDX];
TUI.set_cursor_position(x + col.alignment_offset, y);
- write_string(ifx db == *archive then layout.archive_title else col.header);
+ TUI.tui_write(ifx db == *archive then layout.archive_title else col.header); // TODO append(*builder, ifx db == *archive then layout.archive_title else col.header);
x += col.width;
// Headers : days
@@ -981,7 +987,7 @@ draw_user_interface :: (db: *Database, layout: *Layout) {
}
col = *layout.columns[L_DAYS_IDX + idx];
TUI.set_cursor_position(x + col.alignment_offset, y);
- write_string(col.header);
+ TUI.tui_write(col.header); // TODO append(*builder, col.header);
x += col.width;
}
TUI.set_style(style_default);
@@ -990,7 +996,7 @@ draw_user_interface :: (db: *Database, layout: *Layout) {
x += 1;
col = *layout.columns[L_TOTAL_IDX];
TUI.set_cursor_position(x + col.alignment_offset, y);
- write_string(col.header);
+ TUI.tui_write(col.header); // TODO append(*builder, col.header);
///////////////////////////////////////////////////////////////////////////
@@ -1033,11 +1039,11 @@ draw_user_interface :: (db: *Database, layout: *Layout) {
task_name := cast(string)task.name;
task_name = truncate(task_name, column_width);
TUI.set_cursor_position(x, y);
- write_string(task_name);
+ TUI.tui_write(task_name); // TODO append(*builder, task_name);
// Paint the remaining column space.
task_name_char_count := count_characters(task_name, is_null_terminated = true);
paint_remaining := string.{ column_width - task_name_char_count, empty_line.data };
- write_string(paint_remaining);
+ TUI.tui_write(paint_remaining); // TODO append(*builder, paint_remaining);
x += column_width;
@@ -1065,10 +1071,10 @@ draw_user_interface :: (db: *Database, layout: *Layout) {
size := 1 + count_digits(db.selected_idx + 1) + 1 + count_digits(db.tasks.count) + 1; // " XXX/YYY "
TUI.set_cursor_position(2, size_y);
if (size <= layout.columns[L_TITLE_IDX].width) {
- print(" %/% ", db.selected_idx + 1, db.tasks.count);
+ TUI.tui_print(" %/% ", db.selected_idx + 1, db.tasks.count);
}
else {
- print("%", db.selected_idx + 1);
+ TUI.tui_print("%", db.selected_idx + 1);
}
@@ -1107,7 +1113,9 @@ draw_user_interface :: (db: *Database, layout: *Layout) {
dbg_average = (dbg_sample + dbg_count * dbg_average) / (dbg_count + 1); // DEBUG
dbg_count += 1; // DEBUG
TUI.set_cursor_position(3, 1);
- print("Average % us ---------", dbg_average/1000); // DEBUG
+ TUI.tui_print("Average % us (% / % : % bytes) ---------", dbg_average/1000, context.temporary_storage.total_bytes_occupied, context.temporary_storage.high_water_mark, context.temporary_storage.size); // DEBUG
+ // write_string(builder_to_string(*builder,, allocator = temporary_allocator));
+ write_builder(*builder);
}
free_memory :: () {
@@ -1117,7 +1125,6 @@ free_memory :: () {
free(app_directory);
free(db_file_path);
free(ar_file_path);
- // reset_temporary_storage(); // TODO Not needed... I guess.
}
read_input_string :: (x: int, y: int, input_limit: int, padding: int = 0) -> value: string, success: bool {
@@ -1133,7 +1140,7 @@ read_input_string :: (x: int, y: int, input_limit: int, padding: int = 0) -> val
write_string(TUI.Commands.TextMode);
TUI.set_cursor_position(x, y);
- style_input := context.terminal_style;
+ style_input := context.tui_style;
style_input.underline = true;
TUI.using_style(style_input);