diff options
Diffstat (limited to 'kscurses')
29 files changed, 0 insertions, 2875 deletions
diff --git a/kscurses/canvas.jai b/kscurses/canvas.jai deleted file mode 100644 index df0b021..0000000 --- a/kscurses/canvas.jai +++ /dev/null @@ -1,172 +0,0 @@ -Canvas :: struct { - zone : Ibox2; - - count : int; - pixels_last_draw : []Char; - pixels_buf : []Char; - links : []Link; - - diff_count := 0; - force_full_refresh := true; - - Link :: struct { prev, next : s32; } -} - -deinit :: (using canvas : *Canvas) { - array_free(pixels_last_draw); - array_free(pixels_buf); pixels_buf = .[]; - array_free(links); -} -resize_clear :: (using canvas : *Canvas, new_zone : Ibox2, filler := Char.{}) { - if new_zone != zone { - array_free(pixels_last_draw); - array_free(pixels_buf); - array_free(links); - - zone = new_zone; - count = zone.width * zone.height; - - pixels_last_draw = NewArray(count, Char); - pixels_buf = NewArray(count, Char); - links = NewArray(count + 1, Link); - links[count] = .{xx count, xx count}; - - if filler != .{} then { - for * pixels_buf { - <<it = filler; - } - } - links[count] = .{-1, -1}; - - force_full_refresh = true; - } else { - for y : 0..zone.height-1 { - for x : 0..zone.width-1 { - c_putchar(canvas, filler, .{xx x, xx y}); - } - } - } -} -// add *void to fill_function -resize_fill :: (using canvas : *Canvas, new_zone : Ibox2, fill_function : (coord : ivec2, zone : Ibox2) -> Char) { - if zone != new_zone { - array_free(pixels_last_draw); - array_free(pixels_buf); - array_free(links); - - zone = new_zone; - count = zone.width * zone.height; - - pixels_last_draw = NewArray(count, Char); - pixels_buf = NewArray(count, Char); - links = NewArray(count + 1, Link); - links[count] = .{xx count, xx count}; - force_full_refresh = true; - } - - c_fill(canvas, fill_function); - // i := 0; - // for y : 0..zone.height-1 { - // for x : 0..zone.width-1 { - // pixels_buf[i] = fill_function(.{x, y}, zone); - // i += 1; - // diff_count += 1; - // } - // } - - // for * links { - // <<it = .{-1, -1}; - // } -} -b_draw_canvas :: (builder : *String_Builder, using canvas : *Canvas) { - if force_full_refresh || diff_count * 4 > zone.width * zone.height { - i := 0; - for y : 0..zone.height-1 { - b_move_cursor(builder, zone.corner + ivec2.{0, y}); - for x : 0..zone.width-1 { - b_putchar(builder, pixels_buf[i]); - pixels_last_draw[i] = pixels_buf[i]; - links[i] = .{-1, -1}; - i += 1; - } - } - } else { - last_pos := ivec2.{-1, -1}; - current := links[count].next; - I := 0; - - while current != count { - assert(I < count); - assert(current >= 0); - - pos := ivec2.{xx(current % zone.width), xx(current / zone.width)} + zone.corner; - if pos.x != last_pos.x + 1 || pos.y != last_pos.y { - b_move_cursor(builder, pos); - } - b_putchar(builder, pixels_buf[current]); - pixels_last_draw[current] = pixels_buf[current]; - - next := links[current].next; - links[current] = .{-1, -1}; - current = next; - last_pos = pos; - I += 1; - } - } - - diff_count = 0; - force_full_refresh = false; - links[count] = .{xx count, xx count}; -} -c_putchar :: (using canvas : *Canvas, pixel : Char, pos_local : ivec2) { - // pos_local := pos - zone.corner; - if !point_inside(pos_local, .{size = zone.size}) return; - current := pos_local.x + pos_local.y * zone.width; - - c_last_draw := pixels_last_draw[current]; - pixels_buf[current] = pixel; - - if links[current].prev == -1 { - assert(links[current].next == -1); - if c_last_draw != pixel { - links[current] = .{links[count].prev, xx count}; - links[links[count].prev].next = current; - links[count].prev = current; - diff_count += 1; - } - } else { - if c_last_draw == pixel { - nbs := links[current]; - assert(links[nbs.prev].next == current && links[nbs.next].prev == current); - links[nbs.prev].next = nbs.next; - links[nbs.next].prev = nbs.prev; - links[current] = .{-1, -1}; - diff_count -= 1; - } - } -} - -c_fill :: (using canvas : *Canvas, fill_function : (coord : ivec2, zone : Ibox2) -> Char) { - for y : 0..zone.height-1 { - for x : 0..zone.width-1 { - char := fill_function(.{x, y}, zone); - c_putchar(canvas, char, .{x, y}); - } - } - // i := 0; - // for y : 0..zone.height-1 { - // for x : 0..zone.width-1 { - // pixels_buf[i] = fill_function(.{x, y}, zone); - // i += 1; - // diff_count += 1; - // } - // } - // refresh_all = true; -} -ks_draw_canvas :: (canvas : *Canvas) { - builder := String_Builder.{allocator = temp}; - b_draw_canvas(*builder, canvas); - ks_write(builder_to_string(*builder, allocator = temp)); -} - - diff --git a/kscurses/events.jai b/kscurses/events.jai deleted file mode 100644 index 603958e..0000000 --- a/kscurses/events.jai +++ /dev/null @@ -1,256 +0,0 @@ -Event :: struct { - type : enum u8 { - NONE :: 0; - KEY :: 1; - WINCH :: 2; - TICK :: 3; - INIT :: 4; - USER :: 5; - }; - union { - key : Key; - data : *void; - } -} - -__event_handler : struct { - proc := (e : Event, __data : *void) { - assert(__data != null); - if e.type == { - case .NONE; - ks_write("empty_event!\n\r"); - case .KEY; - ks_write(tprint("key = %\n\r", e.key)); - case .WINCH; - ks_write(tprint("winch, size = %\n\r", terminal_state.size)); - case .TICK; - ks_write(tprint("tick\n\r")); - } - if e.type == .KEY && e.key == .ESCAPE { - <<cast(*bool)__data = true; // stop_main = true - } - }; - data : *void; -} - -use_events :: (tick_duration_ms :s32= 1000, $use_clock := true, init_event := true) #expand { - init_mutexes(); - #if use_clock clock_thread := start_clock_cycle(tick_duration_ms); - input_thread := start_input_cycle(); - winlooker_thread := start_winlooker_cycle(); - set_handler(); - if init_event push_event(.{type = .INIT}); - `defer { - restore_handler(); - stop_winlooker_cycle(winlooker_thread); - stop_input_cycle(input_thread); - #if use_clock stop_clock_cycle(clock_thread); - deinit_mutexes(); - reset_globals(); - } -} -wait_and_process_events :: () -> bool { - wait_for(*event_wait_sem); - lock(*event_queue_mtx); defer unlock(*event_queue_mtx); - processed := false; - while 1 { - e, ok := pop(*event_queue); - if !ok break; - processed = true; - assert(e.type != .NONE); - __event_handler.proc(e, __event_handler.data); - } - return processed; -} -pop_events :: () -> bool { -} -push_event :: (e : Event) { - lock(*event_queue_mtx); - push(*event_queue, e); - unlock(*event_queue_mtx); - signal(*event_wait_sem); -} - -restart_clock_cycle :: () { - if clock_state != .DISABLED { - lock(*mtx_clock_state); - if clock_state != .STOP { - clock_state = .RESTART; - } - signal(*sem_clock_breaker); - unlock(*mtx_clock_state); - } -} - -#scope_file -// SIGWINCH --sigaction--> handler ---sem--> winlooker --push_event--|--> event_queue --pop_events--> master thread -// stdin --read--> input --push_event--| -// clock --push_event--| - -// event_queue -event_queue_mtx : Mutex; -event_queue : Queue(Event); -event_wait_sem : Semaphore; - -// handler -handler :: (sig : s32) #c_call { - new_context : Context; - push_context new_context { - if sig == SIGWINCH { - signal(*winch_wait_sem); - } else { - log("signal = %\n\r", sig); - } - } -} -set_handler :: () { - sa : sigaction_t; - sa.sa_handler = handler; - sigemptyset(*(sa.sa_mask)); - sa.sa_flags = SA_RESTART; - sigaction(SIGWINCH, *sa, null); -} -restore_handler :: () { - sa : sigaction_t; - sa.sa_handler = SIG_DFL; - sigaction(SIGWINCH, null, *sa); -} - -// winlooker -winch_wait_sem : Semaphore; -stop_winlooker := false; -winlooker_cycle :: (thread : *Thread) -> s64 { - while !stop_winlooker { - wait_for(*winch_wait_sem); - if stop_winlooker break; - update_terminal_size(); - push_event(.{type = .WINCH}); - } - return 0; -} -start_winlooker_cycle :: () -> *Thread #expand { - init(*winch_wait_sem); - winlooker_thread : Thread; - thread_init(*winlooker_thread, winlooker_cycle); - thread_start(*winlooker_thread); - return *winlooker_thread; -} -stop_winlooker_cycle :: (winlooker_thread : *Thread) { - stop_winlooker = true; - signal(*winch_wait_sem); - thread_deinit(winlooker_thread); - destroy(*winch_wait_sem); -} - -// input -stop_input := false; -input_cycle :: (thread : *Thread) -> s64 { - tcflush(STDIN_FILENO, TCIFLUSH); - while !stop_input { - key := ks_getch(); - if stop_input break; - push_event(.{type = .KEY, key = key}); - } - return 0; -} -start_input_cycle :: () -> *Thread #expand { - input_thread : Thread; - thread_init(*input_thread, input_cycle); - log("input = %\n\r", formatInt(input_thread.thread_handle, base = 16)); - thread_start(*input_thread); - return *input_thread; -} -stop_input_cycle :: (input_thread : *Thread) { - stop_input = true; - pthread_cancel(input_thread.thread_handle); - thread_deinit(input_thread); -} - -// clock -clock_state : enum u8 { - NORMAL :: 0; - STOP :: 1; - RESTART :: 2; - DISABLED:: 3; -} = .DISABLED; -sem_clock_breaker : Semaphore; -mtx_clock_state : Mutex; - -clock_cycle :: (thread : *Thread) -> s64 { - tick_duration_ms := <<cast(*s32)thread.data; - - while clock_state != .STOP { - lock(*mtx_clock_state); - destroy(*sem_clock_breaker); - init(*sem_clock_breaker); - clock_state = .NORMAL; - unlock(*mtx_clock_state); - - while 1 { - r := wait_for(*sem_clock_breaker, tick_duration_ms); - - lock(*mtx_clock_state); defer unlock(*mtx_clock_state); - if clock_state != .NORMAL { - assert(r == .SUCCESS); - break; - } else { - push_event(.{type = .TICK}); - } - } - } - return 0; -} -start_clock_cycle :: (tick_duration_ms : s32) -> *Thread #expand { - clock_thread : Thread; - init(*sem_clock_breaker); - init(*mtx_clock_state); - clock_state = .NORMAL; - - thread_init(*clock_thread, clock_cycle); - - tick_duration_ms_ptr := New(s32); - <<tick_duration_ms_ptr = tick_duration_ms; - - clock_thread.data = tick_duration_ms_ptr; - log("clock = %\n\r", formatInt(clock_thread.thread_handle, base = 16)); - thread_start(*clock_thread); - return *clock_thread; -} -stop_clock_cycle :: (clock_thread : *Thread) { - lock(*mtx_clock_state); - clock_state = .STOP; - signal(*sem_clock_breaker); - unlock(*mtx_clock_state); - - thread_deinit(clock_thread); - free(clock_thread.data); - clock_state = .DISABLED; - destroy(*sem_clock_breaker); - destroy(*mtx_clock_state); -} - -// utils -reset_globals :: () { - stop_input = false; - clock_state = .NORMAL; - // stop_clock = false; - stop_winlooker = false; - // fd_winch = .[0, 0]; - deinit(*event_queue); -} -init_mutexes :: () { - init(*event_wait_sem); - init(*event_queue_mtx); -} -deinit_mutexes :: () { - destroy(*event_queue_mtx); - destroy(*event_wait_sem); -} - - -TCIFLUSH :: 0; - -libc :: #system_library "libc"; -tcflush :: (fd : s32, queue_selector : s32) -> s32 #foreign libc; - -#import "Thread";
\ No newline at end of file diff --git a/kscurses/history_stack.jai b/kscurses/history_stack.jai deleted file mode 100644 index 3f73df4..0000000 --- a/kscurses/history_stack.jai +++ /dev/null @@ -1,69 +0,0 @@ -History_Stack :: struct( - Action_Type : Type, - destructor : (obj : Action_Type) = default_destructor -){ - BUF_SIZE :: 100; - buffer : [BUF_SIZE]Action_Type; - offset, current, saved : int; -} - -deinit :: (using history_stack : *History_Stack) { - guard(history); - - for i : 0..saved-1 { - j := (i + offset) % BUF_SIZE; - destructor(buffer[offset]); - } - offset, current, saved = 0; -} - -write :: (using history : *History_Stack, action : Edit_Action) { - guard(history); - - for i : current..saved-1 { - j := (i + offset) % BUF_SIZE; - destructor(buffer[j]); - } - - i0 := (offset + current) % BUF_SIZE; - if current == BUF_SIZE { - destructor(buffer[offset]); - saved = current; - offset = (offset + 1) % BUF_SIZE; - } else { - current += 1; - saved = current; - } - i1 := (offset + current) % BUF_SIZE; - assert(i0 == i1); - buffer[i0] = action; -} - - -undo :: (using history : *History) -> bool, Action_Type { - guard(history); - action : Action_Type = ---; - if current == 0 return false, action; - current -= 1; - action = buffer[(current + offset) % BUF_SIZE]; - return true, action; -} -redo :: (using history : *History) -> bool, Action_Type { - guard(history); - action : Action_Type = ---; - if current == saved return false, action; - action = buffer[(current + offset) % BUF_SIZE]; - current += 1; - return true, action; -} - -#scope_file -default_destructor :: (obj : $T) { } - -guard :: (using history : *History) #expand { - check :: (using history : *History) { - assert(0 <= current && current <= saved && saved <= BUF_SIZE); - assert(0 <= offset && offset <= BUF_SIZE); - } - check(history); defer check(history); -}
\ No newline at end of file diff --git a/kscurses/init.jai b/kscurses/init.jai deleted file mode 100644 index b67c52f..0000000 --- a/kscurses/init.jai +++ /dev/null @@ -1,125 +0,0 @@ -terminal_state : struct { - size : ivec2; - cursor := ivec2.{-1, -1}; // {-1, -1} if cursor hidden - last_mode : Graphics_Mode; -} -update_terminal_size :: () { - TIOCGWINSZ :: 0x5413; - winsize : struct { - ws_row, ws_col, ws_xpixel, ws_ypixel : u16; - } - ioctl(0, TIOCGWINSZ, *winsize); - terminal_state.size = .{xx winsize.ws_col, xx winsize.ws_row}; -} - -ks_init :: () { - #if OS == .LINUX { - __old_logger = context.logger; - context.logger = file_logger; - - ks_write("\e[?25l"); // hide cursor - ks_write("\e7"); // save cursor position - ks_write("\e[?1047h"); // switch screen - ks_write("\e[?30l"); // hide scrollbar - - ks_write("\e[H"); // move to top left corner - ks_write("\e[0m"); // set default mode - ks_write("\e[2J"); // clear screen - { - 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); - } - update_terminal_size(); - } else { - assert(false, "procedure call on unsupported OS\n"); - } -} -ks_terminate :: () { - #if OS == .LINUX { - tcsetattr(STDIN_FILENO, 0, *__term); // return echo - - ks_write("\e[?47l"); // restore screen - ks_write("\e8"); // restore cursor - ks_write("\e[?25h"); // show cursor - ks_write("\e[?30h"); // show scrollbar - terminal_state = .{}; - - context.logger = __old_logger; - } else { - assert(false, "procedure call on unsupported OS\n"); - } -} -use_ks_curses :: () #expand { - ks_init(); - `defer { - ks_terminate(); - } -} -use_default_winch_handler :: () #expand { - init_default_winch_handler(); - `defer deinit_default_winch_handler(); -} -init_default_winch_handler :: () { - #if OS == .LINUX { - act := sigaction_t.{ - sa_handler = (sig : s32) #c_call { - new_context: Context; - push_context new_context { - update_terminal_size(); - } - }, - sa_mask = sigset_t.{__val[0] = SIGWINCH} - }; - sigaction(SIGWINCH, *act, null); - } else { - assert(false, "procedure call on unsupported OS\n"); - } -} -deinit_default_winch_handler :: () { - #if OS == .LINUX { - sa : sigaction_t; - sa.sa_handler = SIG_DFL; - sigaction(SIGWINCH, null, *sa); - } else { - - } -} - -#scope_file -__old_logger : type_of(context.logger); - -#if OS == .LINUX { - __term : My_Termios; - - My_Termios :: struct { - c_iflag : u32; - c_oflag : u32; - c_cflag : u32; - c_lflag : u32; - unknown_pad : u8; - c_cc : [32]u8; - c_ispeed : u32; - c_ospeed : u32; - } - - 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; -} - -#import "File"; -file_logger :: (message: string, data: *void, info: Log_Info) { - file, ok := file_open("log.txt",for_writing=true, keep_existing_content=true); - if !ok return; - - file_write(*file, tprint("[%] %", calendar_to_string(to_calendar(current_time_consensus())), message)); - file_close(*file); -} diff --git a/kscurses/io.jai b/kscurses/io.jai deleted file mode 100644 index b2c2df9..0000000 --- a/kscurses/io.jai +++ /dev/null @@ -1,81 +0,0 @@ -Key :: enum u64 { - READ_ERROR :: 0xffffffff_ffffffff; - - UP :: 0x41_5b1b; - DOWN :: 0x42_5b1b; - RIGHT :: 0x43_5b1b; - LEFT :: 0x44_5b1b; - - CTRL_UP :: 0x4135_3b315b1b; - CTRL_DOWN :: 0x4235_3b315b1b; - CTRL_RIGHT :: 0x4335_3b315b1b; - CTRL_LEFT :: 0x4435_3b315b1b; - - SHIFT_UP :: 0x4132_3b315b1b; - SHIFT_DOWN :: 0x4232_3b315b1b; - SHIFT_RIGHT :: 0x4332_3b315b1b; - SHIFT_LEFT :: 0x4432_3b315b1b; - - CTRL_SHIFT_UP :: 0x4136_3b315b1b; - CTRL_SHIFT_DOWN :: 0x4236_3b315b1b; - CTRL_SHIFT_RIGHT:: 0x4336_3b315b1b; - CTRL_SHIFT_LEFT :: 0x4436_3b315b1b; - - ALT_UP :: 0x4133_3b315b1b; - ALT_DOWN :: 0x4233_3b315b1b; - ALT_RIGHT :: 0x4333_3b315b1b; - ALT_LEFT :: 0x4433_3b315b1b; - - CTRL_C :: 0x03; - CTRL_V :: 0x16; - CTRL_X :: 0x18; - CTRL_Y :: 0x19; - CTRL_Z :: 0x1A; - CTRL_BACKSLASH :: 0x1C; - - // ALT_SHIFT_UP :: 0x4133_3b315b1b; - // ALT_SHIFT_DOWN :: 0x4233_3b315b1b; - // ALT_SHIFT_RIGHT :: 0x4333_3b315b1b; - // ALT_SHIFT_LEFT :: 0x4433_3b315b1b; - - ENTER :: 0x0D; - ESCAPE :: 0x1B; - BACKSPACE :: 0x7F; - DELETE :: 0x7E335B1B; -} -ks_getch :: (block := true) -> Key { - #if OS == .LINUX { - buf : Key = xx 0; - l := read(STDIN_FILENO, (cast(*u8)*buf), 8); //!!! - check_signal :: inline (key : Key) { - #if ENABLE_SIGINT if key == .CTRL_C raise(SIGINT); //!!! - #if ENABLE_SIGQUIT if key == .CTRL_BACKSLASH raise(SIGQUIT); - } - check_signal(buf); - return ifx l <= 0 then Key.READ_ERROR else buf; - } else { - return .READ_ERROR; - } -} -ks_write :: (str : string) { - #if OS == .LINUX { - printed := 0; - // while 1 { - r := write(STDIN_FILENO, str.data + printed, xx (str.count - printed)); - // if printed + r == str.count { - // break; - // } else if r >= 0 { - // printed += r; - // } - // } - } else { - - } - __write_counter += str.count; -} -__write_counter := 0; -write_counter_delta :: () -> int { - result := __write_counter; - __write_counter = 0; - return result; -}
\ No newline at end of file diff --git a/kscurses/lambdas.jai b/kscurses/lambdas.jai deleted file mode 100644 index fd5ffa4..0000000 --- a/kscurses/lambdas.jai +++ /dev/null @@ -1,255 +0,0 @@ -decl_lambda :: ($code_src : Code) -> Code #expand { - node_src := compiler_get_nodes(code_src); - proc_node, data_node, names, names_field, node_header, node_block := split_src(false, node_src); - pair_names, pair_srcs := get_lambda_pairs(proc_node, data_node, names, names_field, node_header, node_block); - return compiler_get_code(*Code_Compound_Declaration.{ - kind = .COMPOUND_DECLARATION, - comma_separated_assignment = xx pair_names, - declaration_properties = *Code_Declaration.{ - kind = .DECLARATION, - expression = pair_srcs - } - }); -} -assign_lambda :: ($code_src : Code, parent_scope := #caller_code) #expand { - #insert,scope(parent_scope) #run _assign_lambda(code_src); -} -struct_lambda :: ($code_src : Code, parent_scope := #caller_code) #expand { - #insert,scope(parent_scope) #run _struct_lambda(code_src); -} -#scope_file -#import "Compiler"; -#import "Basic"; -#import "Program_Print"; -debug_print_code :: (root : *Code_Node) { - builder := String_Builder.{allocator = temp}; - print_expression(*builder, root); - print("%\n", builder_to_string(*builder, allocator = temp)); -} -_assign_lambda :: ($code_src : Code) -> Code { - node_src := compiler_get_nodes(code_src); - proc_node, data_node, names, names_field, node_header, node_block := split_src(false, node_src); - pair_names, pair_srcs := get_lambda_pairs(proc_node, data_node, names, names_field, node_header, node_block); - node_assign := Code_Binary_Operator.{ - kind = .BINARY_OPERATOR, - operator_type = #char"=", - left = pair_names, - right = pair_srcs - }; - return compiler_get_code(*node_assign); -} -_struct_lambda :: ($code_src : Code) -> Code { - node_src := compiler_get_nodes(code_src); - proc_node, data_node, names, names_field, node_header, node_block := split_src(true, node_src); - pair_names, pair_srcs := get_lambda_pairs(proc_node, data_node, names, names_field, node_header, node_block); - node_assign := Code_Binary_Operator.{ - kind = .BINARY_OPERATOR, - operator_type = #char"=", - left = pair_names, - right = pair_srcs - }; - debug_print_code(*node_assign); - return compiler_get_code(*node_assign); -} -//TODO add support for non-"proc/data" names -split_src :: (gen_pair : bool, node_src : *Code_Node) -> proc_node:*Code_Node, data_node:*Code_Node, names:[]string, names_field:[]string, node_header:*Code_Procedure_Header, node_block:*Code_Block #expand { - offset := ifx gen_pair then 1 else 2; - assert(node_src.kind == .BLOCK); - node_src_block := cast(*Code_Block) node_src; - node_src_statements := node_src_block.statements; - captured_count := node_src_statements.count - 2 - offset; - assert(captured_count >= 0); - names := NewArray(captured_count, string); - names_field := NewArray(captured_count, string); - for i : offset..captured_count-1+offset { - assert(node_src_statements[i].kind == .IDENT); - } - for i : 0..captured_count-1 { - name := (cast(*Code_Ident)node_src_statements[i + offset]).name; - names[i], names_field[i] = name, sprint("_%", name); - } - assert(node_src_statements[captured_count + offset].kind == .PROCEDURE_HEADER); - node_header := cast(*Code_Procedure_Header) node_src_statements[captured_count + offset]; - assert(node_src_statements[captured_count + offset + 1].kind == .BLOCK); - node_block := cast(*Code_Block) node_src_statements[captured_count + offset + 1]; - assert(node_block.block_type == .IMPERATIVE); - proc_node, data_node : *Code_Node; - if gen_pair { - proc_node = *Code_Binary_Operator.{ - kind = .BINARY_OPERATOR, - operator_type = #char".", - left = node_src_statements[0], - right = *Code_Ident.{ - kind = .IDENT, - name = "proc" - } - }; - data_node = *Code_Binary_Operator.{ - kind = .BINARY_OPERATOR, - operator_type = #char".", - left = node_src_statements[0], - right = *Code_Ident.{ - kind = .IDENT, - name = "data" - } - }; - } else { - proc_node, data_node = node_src_statements[0], node_src_statements[1]; - } - return proc_node, data_node, names, names_field, node_header, node_block; -} -gen_struct_type_node :: (names : []string, names_field : []string) -> *Code_Node #expand { - captured_count := names.count; - nodes_ident := NewArray(captured_count, Code_Ident); - nodes_ptr := NewArray(captured_count, Code_Unary_Operator); - nodes_typeof := NewArray(captured_count, Code_Size_Or_Type_Info); - nodes_type := NewArray(captured_count, Code_Type_Instantiation); - nodes_declaration := NewArray(captured_count, Code_Declaration); - nodes_declaration_ptr := NewArray(captured_count, *Code_Node); - for i : 0..captured_count-1 { - nodes_ident[i] = .{ - kind = .IDENT, - name = names[i] - }; - nodes_ptr[i] = .{ - kind = .UNARY_OPERATOR, - operator_type = #char"*", - subexpression = *(nodes_ident[i]) - }; - nodes_typeof[i] = .{ - kind = .SIZE_OR_TYPE_INFO, - query_kind = .TYPE_OF, - type_of_expression = *(nodes_ptr[i]) - }; - nodes_type[i] = .{ - kind = .TYPE_INSTANTIATION, - type_valued_expression = *(nodes_typeof[i]) - }; - nodes_declaration[i] = .{ - kind = .DECLARATION, - name = names_field[i], - type_inst = *(nodes_type[i]) - }; - nodes_declaration_ptr[i] = *(nodes_declaration[i]); - } - node_struct := Code_Struct.{ - kind = .STRUCT, - block = *Code_Block.{ - kind = .BLOCK, - block_type = .DATA_DECLARATIONS, - statements = nodes_declaration_ptr - } - }; - return *node_struct; -} -//TODO better assertions -get_lambda_pairs :: (proc_node:*Code_Node, data_node:*Code_Node, names:[]string, names_field:[]string, node_header:*Code_Procedure_Header, node_block:*Code_Block) -> pair_names:*Code_Node, pair_srcs:*Code_Node #expand { - node_0 := gen_struct_type_node(names, names_field); - stat_count := node_block.statements.count; - nodes_new_statements := NewArray(stat_count + 1, *Code_Node); - for i : 0..stat_count-1 { - nodes_new_statements[i + 1] = node_block.statements[i]; - } - nodes_new_statements[0] = *Code_Using.{ - kind = .USING, - expression = *Code_Cast.{ - kind = .CAST, - target_type = *Code_Type_Instantiation.{ - kind = .TYPE_INSTANTIATION, - type_valued_expression = *Code_Unary_Operator.{ - kind = .UNARY_OPERATOR, - subexpression = node_0, - operator_type = #char"*" - } - }, - expression = *Code_Ident.{ - kind = .IDENT, - name = "__data" - } - } - }; - arg_count := node_header.arguments.count; - node_new_args := NewArray(arg_count + 1, *Code_Declaration); - for i : 0..arg_count-1 { - node_new_args[i] = node_header.arguments[i]; - } - node_new_args[arg_count] = *Code_Declaration.{ - kind = .DECLARATION, - name = "__data", - type_inst = *Code_Type_Instantiation.{ - kind = .TYPE_INSTANTIATION, - type_valued_expression = *Code_Unary_Operator.{ - kind = .UNARY_OPERATOR, - operator_type = #char"*", - subexpression = *Code_Ident.{ - kind = .IDENT, - name = "void" - } - } - } - }; - nodes_13 := NewArray(names.count, Code_Ident); - nodes_14 := NewArray(names.count, Code_Unary_Operator); - nodes_14_ptr := NewArray(names.count, *Code_Node); - for i : 0..names.count-1 { - nodes_13[i] = Code_Ident.{ - kind = .IDENT, - name = names[i] - }; - nodes_14[i] = Code_Unary_Operator.{ - kind = .UNARY_OPERATOR, - subexpression = *(nodes_13[i]), - operator_type = #char"*" - }; - nodes_14_ptr[i] = *(nodes_14[i]); - } - exprs : [2]*Code_Node; - exprs[0] = *Code_Procedure_Header.{ - kind = .PROCEDURE_HEADER, - arguments = node_new_args, - returns = node_header.returns, - body_or_null = *Code_Procedure_Body.{ - kind = .PROCEDURE_BODY, - block = *Code_Block.{ - kind = .BLOCK, - statements = nodes_new_statements - } - } - }; - exprs[1] = *Code_Unary_Operator.{ - kind = .UNARY_OPERATOR, - operator_type = #char"*", - subexpression = *Code_Literal.{ - kind = .LITERAL, - value_type = .STRUCT, - struct_literal_info = *Code_Struct_Literal_Info.{ - type_expression = *Code_Type_Instantiation.{ - kind = .TYPE_INSTANTIATION, - type_valued_expression = node_0 - }, - arguments = nodes_14_ptr - } - } - }; - _exprs : [2]Code_Comma_Separated_Argument = .[ - .{exprs[0], .NONE}, - .{exprs[1], .NONE}, - ]; - node_19 := Code_Comma_Separated_Arguments.{ - kind = .COMMA_SEPARATED_ARGUMENTS, - arguments = _exprs - }; - exprs2 : [2]*Code_Node; - exprs2[0] = proc_node; - exprs2[1] = data_node; - _exprs2 : [2]Code_Comma_Separated_Argument = .[ - .{exprs2[0], .NONE}, - .{exprs2[1], .NONE}, - ]; - - node_22 := Code_Comma_Separated_Arguments.{ - kind = .COMMA_SEPARATED_ARGUMENTS, - arg = _exprs2 - }; - return *node_22, *node_19; -} diff --git a/kscurses/modes.jai b/kscurses/modes.jai deleted file mode 100644 index 8c167e0..0000000 --- a/kscurses/modes.jai +++ /dev/null @@ -1,179 +0,0 @@ -MAX_ATTRS :: 7; -Graphics_Mode :: struct { - foreground : Color; - background : Color; - attr_flags : enum_flags u8 { - F_BOLD :: 0x1; - F_DIM :: 0x2; - F_ITALIC :: 0x4; - F_UNDERLINE :: 0x8; - F_BLINKING :: 0x10; - F_INVERSE :: 0x20; - F_STRIKETHROUGH :: 0x40; - } - // attrs : [MAX_ATTRS]bool; - // 0 - bold (on/off/keep) - // 1 - dim/faint - // 2 - italic - // 3 - underline - // 4 - blinking - // 5 - inverse - // 6 - strikethrough - fcol256 : u8; - bcol256 : u8; -} -Color :: enum u8 { - RESET :: 0; - DEFAULT :: 39; - COLOR256 :: 38; - - BLACK :: 30; - RED :: 31; - GREEN :: 32; - YELLOW :: 33; - BLUE :: 34; - MAGENTA :: 35; - CYAN :: 36; - WHITE :: 37; - - BRIGHT_BLACK :: 90; - BRIGHT_RED :: 91; - BRIGHT_GREEN :: 92; - BRIGHT_YELLOW :: 93; - BRIGHT_BLUE :: 94; - BRIGHT_MAGENTA :: 95; - BRIGHT_CYAN :: 96; - BRIGHT_WHITE :: 97; -} -Attr :: enum u8 { - BOLD :: 1; - DIM :: 2; - ITALIC :: 3; - UNDERLINE :: 4; - BLINKING :: 5; - INVERSE :: 7; - STRIKETHROUGH :: 9; - - BOLD_AND_DIM_OFF :: 22; - ITALIC_OFF :: 23; - UNDERLINE_OFF :: 24; - BLINKING_OFF :: 25; - INVERSE_OFF :: 27; - STRIKETHROUGH_OFF :: 29; -} - -make_graphics_mode :: (foreground := Color.DEFAULT, background := Color.DEFAULT, bold := false, dim := false, italic := false, underline := false, blinking := false, inverse := false, strikethrough := false, fcol256 :u8= 0, bcol256 :u8= 0) -> Graphics_Mode { - result : Graphics_Mode; - - result.foreground = foreground; - result.background = xx (background + 10); - - if bold result.attr_flags |= .F_BOLD; - if dim result.attr_flags |= .F_DIM; - if italic result.attr_flags |= .F_ITALIC; - if underline result.attr_flags |= .F_UNDERLINE; - if blinking result.attr_flags |= .F_BLINKING; - if inverse result.attr_flags |= .F_INVERSE; - if strikethrough result.attr_flags |= .F_STRIKETHROUGH; - //======== - - // result.attrs[0] = bold; - // result.attrs[1] = dim; - // result.attrs[2] = italic; - // result.attrs[3] = underline; - // result.attrs[4] = blinking; - // result.attrs[5] = inverse; - // result.attrs[6] = strikethrough; - result.fcol256 = fcol256; - result.bcol256 = bcol256; - - return result; -} - -Char :: struct { - code : u32; - #place code; - codes : [4]u8 = ---; - mode : Graphics_Mode; -} -make_char :: (code : u32, foreground := Color.DEFAULT, background := Color.DEFAULT, bold := false, dim := false, italic := false, underline := false, blinking := false, inverse := false, strikethrough := false, fcol256 :u8= 0, bcol256 :u8= 0) -> Char { - return .{code = code, mode = make_graphics_mode(foreground, background, bold, dim, italic, underline, blinking, inverse, strikethrough, fcol256, bcol256)}; -} -length :: inline (c : Char) -> u8 { - return length_code(c.code); -} -operator== :: (c1 : Char, c2 : Char) -> bool { - return c1.code == c2.code && c1.mode == c2.mode; -} -operator== :: (m1 : Graphics_Mode, m2 : Graphics_Mode) -> bool { - if m1.foreground != m2.foreground return false; - if m1.background != m2.background return false; - if m1.fcol256 != m2.fcol256 return false; - if m1.bcol256 != m2.bcol256 return false; - if m1.attr_flags != m2.attr_flags return false; - return true; -} - -find_best_char :: (p : Vector3, use_mix : bool) -> Char { - cast_255 :: (x : float) -> s32 { - return clamp(cast(s32)(x * 255 + .5), 0, 255); - } - return find_best_char(ivec3.{cast_255(p.x), cast_255(p.y), cast_255(p.z)}, use_mix); -} -find_best_char :: (p : u8vec3, use_mix : bool) -> Char { - return find_best_char(cast_vec(s32, p), use_mix); -} -find_best_char :: (_p : ivec3, use_mix : bool) -> Char { - p := _p; - to_6level :: (x : s32) -> u8, s32 { - a := u8.[ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 5, 5, 5, 5, 5, - ][clamp(x, 0, 255) >> 2]; - return a, s32.[0, 87, 135, 175, 215, 255][a]; - } - - to_6level :: (v : ivec3) -> u8vec3, ivec3, dist:int { - i : u8vec3; - h : ivec3; - i.x, h.x = to_6level(v.x); - i.y, h.y = to_6level(v.y); - i.z, h.z = to_6level(v.z); - w := v - h; - return i, h, w.x * w.x + w.y * w.y + w.z * w.z; - } - col_code :: (v : u8vec3) -> u8 { return 16 + 36 * v.x + 6 * v.y + v.z; } - - b_6, b_256 := to_6level(p); - code_00, code_25, code_50, code_75 := #run utf8(" "), #run utf8("░"), #run utf8("▒"), #run utf8("▓"); - - result := make_char( - code_00, - foreground = .COLOR256, - background = .COLOR256, - bcol256 = col_code(b_6) - ); - - if use_mix { - f_6_25, f_256_25, dist_25 := to_6level(p * 4 - b_256 * 3); - f_6_50, f_256_50, dist_50 := to_6level(p * 2 - b_256); - f_6_75, f_256_75, dist_75 := to_6level((p * 4 - b_256) / 3); - - - if dist_25 > dist_50 then f_6_25, code_25, dist_25 = f_6_50, code_50, dist_50; - if dist_25 > dist_75 then f_6_25, code_25, dist_25 = f_6_75, code_75, dist_75; - - result.code = code_25; - result.mode.fcol256 = col_code(f_6_25); - } - return result; -} - -#scope_file -#import "Math";
\ No newline at end of file diff --git a/kscurses/module.jai b/kscurses/module.jai deleted file mode 100644 index 23c0105..0000000 --- a/kscurses/module.jai +++ /dev/null @@ -1,91 +0,0 @@ -#module_parameters( - ENABLE_SIGINT := true, - ENABLE_SIGQUIT := true, - TICK_DURATION_MS := 1000, - ENABLE_UI_BELL := true, - ENABLE_UI_BLINKING := true -); - -#if OS == .LINUX { - #import "POSIX"; -} - -// ivec2 :: Generic_Vector(s32, 2); -// ivec3 :: Generic_Vector(s32, 3); -// u8vec3 :: Generic_Vector(u8, 3); -// Ibox2 :: Generic_Box(s32, 2); - -// #load "../Extra_Containers/module.jai"; -// #import "Extra_Containers"; - - -#import "Basic"(); -#import "Process"; -#import "String"; - -#load "io.jai"; -#load "init.jai"; -#load "events.jai"; - -#load "vectors.jai"; -#load "modes.jai"; -#load "print.jai"; -#load "utils.jai"; -#load "canvas.jai"; - -#load "ui/style.jai"; -#load "ui/element.jai"; -#load "ui/master.jai"; -#load "ui/links.jai"; - -#load "ui/button.jai"; -#load "ui/group.jai"; -#load "ui/text_buf.jai"; -#load "ui/select_list.jai"; -#load "ui/parent.jai"; -#load "ui/scene_manager.jai"; -#load "ui/popup_manager.jai"; -#load "ui/line_input.jai"; -#load "ui/table.jai"; -#load "ui/scalable_group.jai"; -#load "ui/progress_bar.jai"; - -#load "lambdas.jai"; -#load "queue.jai"; - -// TODO: -// remake canvas: -// -force full refresh only after resize / init -// maybe_resize() -// fill_by_proc() -// clear() - - -// in resize & fill: check if size same -// add c_print_ascii_line, c_print_ascii_line_bounded - -// restart_clock && multiple clocks - -// in set_main_scene check if root is predecessor of active element -// stop_clock -> clock_state - -// module overlap check / set minimum size of terminal - -// make generic_vec2/3 -// make better how_to -// add meaningfull assertion text -// UI_Scene <- UI_Popup -// autogrow in line_input -// detection of the element on which rendering breaks -// extra debug lines on top -// group view -// + grid / group (maybe) -// make text u8/u32 modes in text_buf, line_input & other -// add block_input -// (maybe) unset_active_recursive without arguments -// plotter -// tree/directory view -// push graphics mode - -// add windows(os) support xd -// (August 13, 2023). Fuck it, I don't want to deal with this shit anymore. diff --git a/kscurses/print.jai b/kscurses/print.jai deleted file mode 100644 index a023fea..0000000 --- a/kscurses/print.jai +++ /dev/null @@ -1,148 +0,0 @@ -ks_bell :: () { - bell_str : string; - bell := 7; - bell_str.data, bell_str.count = xx *bell, 1; - ks_write(bell_str); -} - -ui_bell :: inline () { - #if ENABLE_UI_BELL ks_bell(); -} - - -b_move_cursor :: inline (builder : *String_Builder, coord : ivec2) { - print_to_builder(builder, "\e[%;%H", coord.y + 1, coord.x + 1); -} -t_move_cursor :: inline (coord : ivec2) -> string { - return tprint("\e[%;%H", coord.y, coord.x); -} -ks_move_cursor :: inline (coord : ivec2) { - ks_write(tprint("\e[%;%H", coord.y + 1, coord.x + 1)); -} -b_cursor_set_visibility :: inline (builder : *String_Builder, $$visible : bool) { - append(builder, ifx visible "\e[?25h" else "\e[?25l"); -} - -b_print :: (builder : *String_Builder, coord : ivec2, mode : Graphics_Mode, fmt : string, args : ..Any) { - if coord != .{-1, -1} b_move_cursor(builder, coord); - b_mode_set(builder, mode); - print_to_builder(builder, fmt, ..args); -} -t_print :: (coord : ivec2, mode : Graphics_Mode, fmt : string, args : ..Any) -> string { - builder := String_Builder.{allocator = temp}; - b_print(*builder, coord, mode, fmt, ..args); - return builder_to_string(*builder, temp); -} -ks_print :: inline (coord : ivec2, mode : Graphics_Mode, fmt : string, args : ..Any) { - ks_write(t_print(coord, mode, fmt, ..args)); -} - - -b_clear_screen :: (builder : *String_Builder) { - append(builder, "\e[2J"); -} -t_clear_screen :: inline () -> string { - return "\e[2J"; -} -ks_clear_screen :: inline () { - ks_write("\e[2J"); -} - - -b_esc_m :: inline (builder : *String_Builder, $$code : int) { - print_to_builder(builder, "\e[%m", code); -} -t_esc_m :: inline ($$code : int) -> string { - return tprint("\e[%m", code); -} -ks_esc_m :: inline ($$code : int) { - ks_write(t_esc_m(code)); -} - - -#scope_file -b_mode_difference :: (builder : *String_Builder, prev : Graphics_Mode, using current : Graphics_Mode) { - printed_first := false; - add_code :: (code : u8) #expand { - // assert(code != xx Attr.BOLD); - // assert(code != xx Attr.DIM); - if printed_first { - print_to_builder(builder, ";%", code); - } else { - print_to_builder(builder, "\e[%", code); - printed_first = true; - } - } - add_code_on_off :: (prev : bool, current : bool, on_code : Attr, off_code : Attr) #expand { - if prev != current add_code(xx(ifx current on_code else off_code)); - } - if foreground != prev.foreground || fcol256 != prev.fcol256 { - if foreground != Color.COLOR256 { - add_code(xx foreground); - } else { - add_code(38); add_code(5); add_code(xx fcol256); - } - } - if background != prev.background || bcol256 != prev.bcol256 { - if background != (Color.COLOR256 + 10) { - add_code(xx background); - } else { - add_code(48); add_code(5); add_code(xx bcol256); - } - } - if (prev.attr_flags & 1) != (attr_flags & 1) || (prev.attr_flags & 2) != (attr_flags & 2) { - off0 := (prev.attr_flags & 1) && !(attr_flags & 1); - off1 := (prev.attr_flags & 2) && !(attr_flags & 2); - if off0 || off1 { - add_code(xx Attr.BOLD_AND_DIM_OFF); - if (attr_flags & 1) add_code(xx Attr.BOLD); - if (attr_flags & 2) add_code(xx Attr.DIM); - } else { - if (attr_flags & 1) && !(prev.attr_flags & 1) add_code(xx Attr.BOLD); - if (attr_flags & 2) && !(prev.attr_flags & 2) add_code(xx Attr.DIM); - } - } - add_code_on_off(xx prev.attr_flags & 4, xx attr_flags & 4, .ITALIC, .ITALIC_OFF); - add_code_on_off(xx prev.attr_flags & 8, xx attr_flags & 8, .UNDERLINE, .UNDERLINE_OFF); - add_code_on_off(xx prev.attr_flags & 16, xx attr_flags & 16, .BLINKING, .BLINKING_OFF); - add_code_on_off(xx prev.attr_flags & 32, xx attr_flags & 32, .INVERSE, .INVERSE_OFF); - add_code_on_off(xx prev.attr_flags & 64, xx attr_flags & 64, .STRIKETHROUGH, .STRIKETHROUGH_OFF); - if printed_first append(builder, "m"); -} -#scope_export - -//TODO update_state := true -b_mode_set :: (builder : *String_Builder, using mode : Graphics_Mode, update_state := true) { - b_mode_difference(builder, terminal_state.last_mode, mode); - if update_state terminal_state.last_mode = mode; -} -t_mode_set :: (mode : Graphics_Mode, update_state := true) -> string { - builder := String_Builder.{allocator = temp}; - b_mode_set(*builder, mode, update_state); - return builder_to_string(*builder, temp); -} - -ks_mode_reset :: (update_state := true) { - ks_write("\e[0m"); - if update_state terminal_state.last_mode = .{}; -} -t_mode_reset :: inline (update_state := true) -> string { - if update_state terminal_state.last_mode = .{}; - return "\e[0m"; -} -b_mode_reset :: inline (builder : *String_Builder, update_state := true) { - if update_state terminal_state.last_mode = .{}; - append(builder, "\e[0m"); -} - -b_putchar :: (builder : *String_Builder, c : Char) { - b_mode_set(builder, c.mode); - b_putchar(builder, c.code); -} - -b_putchar :: inline (builder : *String_Builder, code : u64) { - char_str : string; - char_str.data = xx *(code); - char_str.count = length_code(code); - append(builder, char_str); -} diff --git a/kscurses/queue.jai b/kscurses/queue.jai deleted file mode 100644 index 86f5dc8..0000000 --- a/kscurses/queue.jai +++ /dev/null @@ -1,57 +0,0 @@ -Queue :: struct(Element_Type : Type) { - buffer : []Element_Type; - begin, count := 0; -} -pop :: (using queue : *Queue($Element_Type)) -> Element_Type, bool { - elem : Element_Type; - ok := true; - if count { - elem = buffer[begin]; - begin += 1; - count -= 1; - } else { - ok = false; - } - return elem, ok; -} -get_space :: (using queue : *Queue($Element_Type), new_elements_count : int) { - if begin + count + new_elements_count <= buffer.count return; - if count <= begin && count + new_elements_count <= buffer.count { - memcpy(buffer.data, buffer.data + begin, size_of(Element_Type) * count); - begin = 0; - } else { - new_buf := NewArray(count + max(new_elements_count, count), Element_Type); - memcpy(new_buf.data, buffer.data + begin, count * size_of(Element_Type)); - begin = 0; - array_free(buffer); - buffer = new_buf; - } -} -push :: (using queue : *Queue($Element_Type), element : Element_Type) { - get_space(queue, 1); - assert(begin + count + 1 <= buffer.count); - buffer[begin + count] = element; - count += 1; -} -deinit :: (using queue : *Queue($Element_Type)) { - array_free(buffer); - <<queue = .{}; -} -for_expansion :: (queue : Queue, body : Code, flags : For_Flags) #expand { - for i : 0..queue.count-1 { - `it_index := i; - `it := queue.buffer[begin + i]; - - #insert body; - } -} -first :: (queue : Queue($Element_Type)) -> Element_Type, bool { - result : Element_Type; - if queue.count > 0 then result = queue.buffer[queue.begin]; - return result, queue.count > 0; -} -last :: (using queue : Queue($Element_Type)) -> Element_Type, bool { - result : Element_Type; - if queue.count > 0 then result = queue.buffer[queue.begin + queue.count - 1]; - return result, queue.count > 0; -} diff --git a/kscurses/readme.md b/kscurses/readme.md deleted file mode 100644 index 7a2f6fc..0000000 --- a/kscurses/readme.md +++ /dev/null @@ -1,43 +0,0 @@ -# kscurses -## _Curses replacement on jai for my needs. Use at your own risk._ - -`tested on version 0.1.073` - -# setup & build -1. download extra-containers module https://github.com/CyanMARgh/extra-containers -2. move it to your extra modules folder -3. specify this foder on top of demos/first.jai -4. compile first.jai - -Currently works only on linux (tested on gnome terminal). - -# features list -- character input -- window resize handle -- text modifiers (bold, italic, underline, blinking, inverse, strikethrough), color256 support -- text/background color. -- arrows, escape key and some -- saving and restoring the terminal -- exit with and crtl+C (optional). -- ui elements (empty, button, text block, selection list) -- multiple scenes and popups support -- events (ticks, input, window resize and user-defined events) -- ui can work both in single-thread mode and multi-thread mode -- 4 print modes: -- - ks_**method** : method prints directly terminal -- - t_**method** : method returns temporary string or string from constant data section -- - b_**method** : method prints to builder -- - c_**method**: method prints to canvas - -# demos list -- basic print methods, canvas and graphic modes usage -- video (now uses events and color256 approximation with semi-transparent characters) -- shorter canvas usage -- ui : progress bars and extra events handler -- ui : text buffer, buttons, selection list, groups, scenes -- ui : popup -- ui : line input -- events processing without default ui -- snake minigame -- ui : table -- ui : scalable group and anchors diff --git a/kscurses/ui/button.jai b/kscurses/ui/button.jai deleted file mode 100644 index 3866e03..0000000 --- a/kscurses/ui/button.jai +++ /dev/null @@ -1,25 +0,0 @@ -UI_Button :: struct { - #as using base : UI_Elem = .{type = .BUTTON}; - text := ""; - on_click : struct { - proc := (data : *void){}; - data : *void; - }; -} - -handle_key_button :: (ui_elem : *UI_Elem, key : Key) -> handled:bool { - using cast(*UI_Button) ui_elem; - assert(cursor_state == .ON); - assert(!links.inner); - if key == .ENTER { - on_click.proc(on_click.data); - return true; - } - return false; -} -c_draw_button :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - using cast(*UI_Button) ui_elem; - mode := ifx cursor_state == .ON && box_type == .NONE then style.text.cursor else style.text.default; - c_draw_line_ascii(canvas, text, zone, .{(zone.width - xx text.count) / 2, xx ((zone.height - 1) / 2)}, mode); - return true; -} diff --git a/kscurses/ui/element.jai b/kscurses/ui/element.jai deleted file mode 100644 index 3db8fcb..0000000 --- a/kscurses/ui/element.jai +++ /dev/null @@ -1,156 +0,0 @@ -UI_Elem :: struct { - type : enum u8 { - NONE :: 0; - BUTTON :: 1; - TEXT_BUF :: 2; - GROUP :: 3; - SELECT_LIST :: 4; - SCENE_MANAGER :: 5; - POPUP_MANAGER :: 6; - LINE_INPUT :: 7; - SCALABLE_GROUP :: 8; - TABLE :: 9; - PROGRESS_BAR :: 10; - } = .NONE; - - using visual_data : struct { - cursor_state : enum u8 { OUTSIDE :: 0; ON :: 1; IN :: 2; } = .OUTSIDE; - box_type : enum u8 { NONE :: 0; BORDER :: 1; NO_BORDER :: 2; } = .BORDER; - description_pos : enum u8 { TOP_LEFT :: 0; TOP_CENTER :: 1; TOP_RIGHT :: 2; BOTTOM_LEFT :: 4; BOTTOM_CENTER :: 5; BOTTOM_RIGHT :: 6; } = .TOP_LEFT; - description := ""; - } - - using links : struct { - left, right, bottom, top, inner, outer : *UI_Elem; - parent : *UI_Parent; - } - - extra_handler : struct { - proc : (key : Key, data : *void) -> bool = null; - data : *void; - } -} - - -vtable_c_draw : []#type (*Canvas, *UI_Elem, Ibox2, *UI_Style) -> (bool) = .[ - c_draw_default, - c_draw_button, - c_draw_textbuf, - c_draw_group, - c_draw_select_list, - c_draw_scene_manager, - c_draw_popup_manager, - c_draw_line_input, - c_draw_scalable_group, - c_draw_table, - c_draw_progress_bar -]; -c_draw :: (canvas : *Canvas, using ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - ok := box_type == .NONE || c_box(canvas, zone, ifx cursor_state == .ON && __ui_master.blink_stage != 1 then style.box.cursor else style.box.default, box_type == .BORDER); - if !ok return false; - ok = c_draw_description(canvas, ui_elem, zone, style); - if !ok return false; - - content_zone := ifx box_type == .BORDER then cut_border(zone, 1) else zone; - - c_draw_proc := vtable_c_draw[xx ui_elem.type]; - assert(xx c_draw_proc); - return c_draw_proc(canvas, ui_elem, content_zone, style); -} -c_draw_default :: (canvas : *Canvas, using ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { return true; }; - -intersection_line :: (box : Ibox2, _line : string, _start : ivec2) -> line:string, start:ivec2 { - line, start := _line, _start; - if start.x < box.left { - line.count += start.x - box.left; - start.x = box.left; - } - if start.x + line.count > box.left + box.width { - line.count = box.left + box.width - start.x; - } - return line, start; -} - -c_draw_line_ascii_raw :: (canvas : *Canvas, line : string, start : ivec2, mode : Graphics_Mode) { - for x : 0..line.count-1 c_putchar(canvas, .{code = xx line[x], mode = mode}, start + ivec2.{xx x, 0}); -} - -c_draw_line_ascii :: (canvas : *Canvas, _line : string, _start : ivec2, mode : Graphics_Mode) { - line, start := intersection_line(canvas.zone, _line, _start); - c_draw_line_ascii_raw(canvas, line, start, mode); -} -c_draw_line_ascii :: (canvas : *Canvas, _line : string, bounds : Ibox2, offset : ivec2, mode : Graphics_Mode) { - assert(inside(bounds, canvas.zone)); - line, start := intersection_line(bounds, _line, bounds.corner + offset); - c_draw_line_ascii_raw(canvas, line, start, mode); -} -c_draw_description :: (canvas : *Canvas, using ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - if !description return true; - if description.count > zone.width - 2 return false; - - top_or_bottom := !(description_pos & 4); - y := ifx top_or_bottom then zone.top else zone.top + zone.height - 1; - - mode := style.text.default; - if description_pos & 3 == { - case 0; c_draw_line_ascii(canvas, description, .{zone.left + 1, y}, mode); - case 1; c_draw_line_ascii(canvas, description, .{xx (zone.left + (zone.width - description.count) / 2), y}, mode); - case 2; c_draw_line_ascii(canvas, description, .{xx (zone.left + zone.width - description.count - 1), y}, mode); - case; assert(false); - } - return true; -} - -vtable_handle_key : []#type (*UI_Elem, Key) -> (bool) = .[ - handle_key_none, - handle_key_button, - handle_key_none, - handle_key_group, - handle_key_select_list, - handle_key_scene_manager, - handle_key_popup_manager, - handle_key_line_input, - handle_key_scalable_group, - handle_key_table, - handle_key_none -]; -handle_key :: (using ui_elem : *UI_Elem, key : Key) -> handled:bool { - handle_proc := vtable_handle_key[ui_elem.type]; - assert(xx handle_proc); - - handled := handle_proc(ui_elem, key); - // assert(cursor_state == .ON || cursor_state == .IN); - if !handled && cursor_state == .ON { - handled = handle_key_move(ui_elem, key); - } - - if !handled && extra_handler.proc { - handled = extra_handler.proc(key, extra_handler.data); - } - return handled; -} -handle_key_none :: (using ui_elem : *UI_Elem, key : Key) -> handled:bool { return false; } -handle_key_move :: (using ui_elem : *UI_Elem, key : Key) -> handled:bool { - __ui_master.blink_stage = 0; - restart_clock_cycle(); - - active_elem := ui_elem; - assert(active_elem.cursor_state == .ON); - try_move :: (new_elem : *UI_Elem) #expand { - if new_elem { - unset_active_recursive(`active_elem); - set_active_recursive(new_elem); - `active_elem = new_elem; - } - } - if key == { - case .LEFT; try_move(links.left); - case .RIGHT; try_move(links.right); - case .UP; try_move(links.top); - case .DOWN; try_move(links.bottom); - case .ESCAPE; try_move(links.outer); - case .ENTER; try_move(links.inner);; - } - assert(active_elem.cursor_state == .ON); - return ui_elem != active_elem; -}
\ No newline at end of file diff --git a/kscurses/ui/group.jai b/kscurses/ui/group.jai deleted file mode 100644 index 366c513..0000000 --- a/kscurses/ui/group.jai +++ /dev/null @@ -1,44 +0,0 @@ -UI_Group :: struct { - #as using base_parent : UI_Parent = .{type = .GROUP}; - - Element :: struct { - ptr : *UI_Elem; - zone : Ibox2; - } - - elements : []Element; -} -set_sub_elements :: (group : *UI_Group, elements : ..UI_Group.Element) { - group.elements = elements; - for e : elements { - e.ptr.parent = group; - } -} -c_draw_group :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - using cast(*UI_Group) ui_elem; - for e : elements { - e_zone := e.zone; - if !inside(e_zone, zone.size) return false; - e_zone.corner += zone.corner; - if !c_draw(canvas, e.ptr, e_zone, style) return false; - } - return true; -} -handle_key_group :: (ui_elem : *UI_Elem, key : Key) -> handled:bool { - using cast(*UI_Group) ui_elem; - assert(cursor_state == .ON || cursor_state == .OUTSIDE); - - handled := false; - if cursor_state == .OUTSIDE { - assert(xx active_element); - { - ok := false; - for e : elements if e.ptr == active_element ok = true; - assert(ok); - } - handled = handle_key(active_element, key); - } else { - assert(xx !active_element); - } - return handled; -}
\ No newline at end of file diff --git a/kscurses/ui/line_input.jai b/kscurses/ui/line_input.jai deleted file mode 100644 index 17823db..0000000 --- a/kscurses/ui/line_input.jai +++ /dev/null @@ -1,122 +0,0 @@ -Char_Type :: u8; -UI_Line_Input :: struct { - #as using base : UI_Elem = .{type = .LINE_INPUT}; - buffer : []Char_Type; - - // resizeable := false; - ptr_left, ptr_right : int; - offset : int; -} - -handle_key_line_input :: (ui_elem : *UI_Elem, key : Key) -> bool { - using ui_line_input := cast(*UI_Line_Input) ui_elem; - - handle_inner :: (using ui_line_input : *UI_Line_Input, key : Key) -> bool { - if is_printable(key) { - return add_char(ui_line_input, xx key); - } else if key == { - case .LEFT; #through; - case .RIGHT; - return move_ptr(ui_line_input, key); - case .BACKSPACE; - return remove_char_left(ui_line_input); - case .ESCAPE; - cursor_state = .ON; - return true; - } - return false; - } - - if cursor_state == .IN { - return handle_inner(ui_line_input, key); - } else if cursor_state == .ON && key == .ENTER { - cursor_state = .IN; - return true; - } - - return false; -} -c_draw_line_input :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - using cast(*UI_Line_Input) ui_elem; - - fix_offset :: () #expand { - if ptr_left - offset < 0 { - offset = ptr_left; - } else if ptr_left - offset >= zone.width { - offset = ptr_left - zone.width + 1; - } - } - fix_offset(); - - left_part, right_part : string; - left_part.data, left_part.count = buffer.data, ptr_left; - - right_part.data, right_part.count = buffer.data + ptr_right + 1, (buffer.count - ptr_right - 1); - - c_draw_line_ascii(canvas, left_part, zone, .{xx -offset, 0}, style.text.default); - c_draw_line_ascii(canvas, right_part, zone, .{xx (ptr_left - offset), 0}, style.text.default); - - terminal_state.cursor = ifx cursor_state == .IN then zone.corner + ivec2.{xx(ptr_left - offset), 0} else .{-1, -1}; - - return true; -} - -init :: (using ui_line_input : *UI_Line_Input, max_length := 100) { - buffer = NewArray(max_length, Char_Type); - ptr_left, ptr_right = 0, max_length - 1; -} -add_char :: (using ui_line_input : *UI_Line_Input, c : Char_Type) -> bool { - if ptr_left > ptr_right return false; - buffer[ptr_left] = c; - ptr_left += 1; - return true; -} -remove_char_left :: (using ui_line_input : *UI_Line_Input) -> bool { - if ptr_left == 0 return false; - ptr_left -= 1; - return true; -} -move_ptr :: (using ui_line_input : *UI_Line_Input, key : Key) -> bool { - if key == { - case .LEFT; - if ptr_left > 0 { - ptr_left -= 1; - buffer[ptr_right] = buffer[ptr_left]; - ptr_right -= 1; - return true; - } - case .RIGHT; - if ptr_right < buffer.count-1 { - ptr_right += 1; - buffer[ptr_left] = buffer[ptr_right]; - ptr_left += 1; - return true; - } - case; - assert(false); - } - return false; -} -deinit :: (using ui_line_input : *UI_Line_Input) { - array_free(buffer); -} - -is_printable :: (key : Key) -> bool { - code := cast(u64) key; - return (code >= #char" " && code <= #char"~"); -} - -get_string :: (using ui_line_input : *UI_Line_Input, allocator := context.allocator) -> string { - result : string; - size := ptr_left + (buffer.count - ptr_right - 1); - result.count = size; - result.data = alloc(size, allocator); - - memcpy(result.data, buffer.data, ptr_left); - memcpy(result.data + ptr_left, buffer.data + ptr_right + 1, buffer.count - ptr_right - 1); - return result; -} -reset :: (using ui_line_input : *UI_Line_Input) { - ptr_left = 0; - ptr_right = buffer.count - 1; -}
\ No newline at end of file diff --git a/kscurses/ui/links.jai b/kscurses/ui/links.jai deleted file mode 100644 index dc8c667..0000000 --- a/kscurses/ui/links.jai +++ /dev/null @@ -1,94 +0,0 @@ -link_lr :: (el : *UI_Elem, er : *UI_Elem) { - el.right = er; - er.left = el; -} -link_tb :: (et : *UI_Elem, eb : *UI_Elem) { - et.bottom = eb; - eb.top = et; -} -link_oi :: (eo : *UI_Elem, ei : *UI_Elem) { - eo.inner = ei; - ei.outer = eo; -} - -link_grid :: (size : ivec2, elements : ..*UI_Elem) { - assert(size.x * size.y == elements.count); - for y : 0..size.y-1 { - for x : 0..size.x-2 { - i := x + size.x * y; - link_lr(elements[i], elements[i + 1]); - } - } - for y : 0..size.y-2 { - for x : 0..size.x-1 { - i := x + size.x * y; - link_tb(elements[i], elements[i + size.x]); - } - } -} -link_grid :: (size : ivec2, elements : []UI_Elem) { - assert(size.x * size.y == elements.count); - for y : 0..size.y-1 { - for x : 0..size.x-2 { - i := x + size.x * y; - link_lr(*elements[i], *elements[i + 1]); - } - } - for y : 0..size.y-2 { - for x : 0..size.x-1 { - i := x + size.x * y; - link_tb(*elements[i], *elements[i + size.x]); - } - } -} -link_row :: (elements : ..*UI_Elem) { - for i : 0..elements.count-2 { - link_lr(elements[i], elements[i + 1]); - } -} -link_column :: (elements : ..*UI_Elem) { - for i : 0..elements.count-2 { - link_tb(elements[i], elements[i + 1]); - } -} -link_to_outer :: (eo : *UI_Elem, ei : ..*UI_Elem) { - if ei.count > 0 { - for ei { - it.outer = eo; - } - eo.inner = ei[0]; - } - -} -link_to_bottom :: (eb : *UI_Elem, et : ..*UI_Elem) { - if et.count > 0 { - for et { - it.bottom = eb; - } - eb.top = et[0]; - } -} -link_to_top :: (et : *UI_Elem, eb : ..*UI_Elem) { - if eb.count > 0 { - for eb { - it.top = et; - } - et.bottom = eb[0]; - } -} -link_to_right :: (er : *UI_Elem, el : ..*UI_Elem) { - if el.count > 0 { - for el { - it.right = er; - } - er.left = el[0]; - } -} -link_to_left :: (el : *UI_Elem, er : ..*UI_Elem) { - if er.count > 0 { - for er { - it.left = el; - } - el.right = er[0]; - } -}
\ No newline at end of file diff --git a/kscurses/ui/master.jai b/kscurses/ui/master.jai deleted file mode 100644 index 9cb0702..0000000 --- a/kscurses/ui/master.jai +++ /dev/null @@ -1,105 +0,0 @@ -UI_Master :: struct { - style : UI_Style; - canvas : Canvas; - root : *UI_Elem; - should_exit := false; - - blink_stage := 0; - - before_draw : struct { - proc := (data : *void) { }; - data : *void; - }; - extra_handle : struct { - proc := (e : Event, data : *void) { }; - data : *void; - }; -} -__ui_master : UI_Master; - - -set_main_scene :: (scene : UI_Scene) { - __ui_master.root = scene.root; - set_active_recursive(scene.entry); -} -run_singlethread_ui :: () { - use_default_winch_handler(); - using __ui_master; - while 1 { - before_draw.proc(before_draw.data); - if should_exit break; - draw(*__ui_master); - reset_temporary_storage(); - handle_key(*__ui_master, ks_getch(block = false)); - if should_exit break; - } - deinit(*__ui_master); -} -run_multithread_ui :: () { - use_events(tick_duration_ms = 530); - __event_handler = .{ - proc = (e : Event, __data : *void) { - using __ui_master; - if e.type == { - case .KEY; - handle_key(*__ui_master, e.key); - case .TICK; - #if ENABLE_UI_BLINKING __ui_master.blink_stage = xx !__ui_master.blink_stage; - } - extra_handle.proc(e, extra_handle.data); - }, - data = null - }; defer __event_handler = .{}; - - using __ui_master; - - while 1 { - before_draw.proc(before_draw.data); - if should_exit break; - processed := wait_and_process_events(); - if should_exit break; - if processed { - draw(*__ui_master); - reset_temporary_storage(); - } - } - deinit(*__ui_master); -} - -#scope_file -draw :: (using ui_master : *UI_Master) { - new_zone := Ibox2.{size = terminal_state.size}; - builder : String_Builder; - - if new_zone != canvas.zone { - resize_clear(*canvas, new_zone); - } - ok := c_draw(*canvas, root, canvas.zone, *style); - if ok { - ks_draw_canvas(*canvas); - } else { - b_mode_set(*builder, style.text.default); - b_clear_screen(*builder); - b_print(*builder, .{0, 0}, style.text.debug, "screen to small: %x%", terminal_state.size.x, terminal_state.size.y); - } - b_cursor_set_visibility(*builder, terminal_state.cursor != ivec2.{-1, -1}); - if terminal_state.cursor != ivec2.{-1, -1} then b_move_cursor(*builder, terminal_state.cursor); - - ks_write(builder_to_string(*builder, allocator = temp)); -} -handle_key :: (using ui_master : *UI_Master, key : Key) { - handled := handle_key(root, key); - if handled return; - - if key == { - case .ESCAPE; { - should_exit = true; - unset_active_recursive(__last_set); - } - case; if key != .READ_ERROR ui_bell(); - } -} -deinit :: (using ui_master : *UI_Master) { - deinit(*canvas); - __ui_master = .{}; -}
\ No newline at end of file diff --git a/kscurses/ui/parent.jai b/kscurses/ui/parent.jai deleted file mode 100644 index af459de..0000000 --- a/kscurses/ui/parent.jai +++ /dev/null @@ -1,33 +0,0 @@ -UI_Parent :: struct { - #as using base : UI_Elem; - active_element : *UI_Elem; -} - -__last_set : *UI_Elem; - -set_active_recursive :: (ui_elem : *UI_Elem) { - assert(!__last_set); __last_set = ui_elem; - assert(ui_elem.cursor_state == .OUTSIDE); ui_elem.cursor_state = .ON; - - current := ui_elem; - while 1 { - parent := current.parent; - if !parent break; - assert(!parent.active_element); - parent.active_element = current; - current = xx parent; - } -} -unset_active_recursive :: (ui_elem : *UI_Elem) { - assert(__last_set == ui_elem); __last_set = null; - assert(ui_elem.cursor_state == .ON); ui_elem.cursor_state = .OUTSIDE; - - current := ui_elem; - while 1 { - parent := current.parent; - if !parent break; - assert(parent.active_element == current); - parent.active_element = null; - current = xx parent; - } -}
\ No newline at end of file diff --git a/kscurses/ui/popup_manager.jai b/kscurses/ui/popup_manager.jai deleted file mode 100644 index 704ad49..0000000 --- a/kscurses/ui/popup_manager.jai +++ /dev/null @@ -1,65 +0,0 @@ -MAX_POPUP_LEVES :: 10; - -UI_Popup_Manager :: struct { - #as using base_parent : UI_Parent = .{type = .POPUP_MANAGER, box_type = .NONE}; - - layers : [MAX_POPUP_LEVES]UI_Popup; - - layers_count := 0; -} - -set_background :: (using ui_popup_manager : *UI_Popup_Manager, scene : UI_Scene) { - assert(layers_count == 0); - layers[0] = .{root = scene.root, entry = scene.entry}; - scene.root.parent = xx ui_popup_manager; - layers_count = 1; -} - -handle_key_popup_manager :: (ui_elem : *UI_Elem, key : Key) -> handled:bool { - using ui_popup_manager := cast(*UI_Popup_Manager) ui_elem; - assert(layers_count > 0, "0 layers in popup manager"); - if !handle_key(active_element, key) { - if key == .ESCAPE && layers_count > 1 { - pop(ui_popup_manager); - return true; - } else { - return false; - } - } else { - return true; - } -} - -c_draw_popup_manager :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - using ui_popup_manager := cast(*UI_Popup_Manager) ui_elem; - assert(layers_count > 0, "0 layers in popup manager"); - for i : 0..layers_count-1 { - popup_zone := zone; - ok : bool; - if layers[i].size != .{-1, -1} then { - popup_zone, ok = fit_in_center(zone, layers[i].size); - if !ok return false; - } - if !c_draw(canvas, layers[i].root, popup_zone, style) return false; - } - return true; -} - -pop :: (using ui_popup_manager : *UI_Popup_Manager) { - assert(layers_count > 1, "can't pop background"); - layers_count -= 1; - unset_active_recursive(__last_set); - layers[layers_count].root.parent = null; - set_active_recursive(layers[layers_count - 1].entry); - -} -push :: (using ui_popup_manager : *UI_Popup_Manager, scene : UI_Popup) { - assert(layers_count < MAX_POPUP_LEVES, "too much popup layers"); - unset_active_recursive(__last_set); - - layers[layers_count] = scene; - scene.root.parent = xx ui_popup_manager; - set_active_recursive(layers[layers_count].entry); - - layers_count += 1; -}
\ No newline at end of file diff --git a/kscurses/ui/progress_bar.jai b/kscurses/ui/progress_bar.jai deleted file mode 100644 index 23d7dc9..0000000 --- a/kscurses/ui/progress_bar.jai +++ /dev/null @@ -1,37 +0,0 @@ -UI_Progress_Bar :: struct { - #as using base : UI_Elem = .{type = .PROGRESS_BAR}; - - value : float; - value_ptr : *float; - - draw_proc := (percent : float, pix_coord : float) -> Vector3 { return ifx pix_coord < percent then Vector3.{0, 1, 0} else .{0, 0, 0}; } - show_percent := true; -} - -set_value :: (progress_bar : *UI_Progress_Bar, value : float) { - progress_bar.value = value; - progress_bar.value_ptr = null; -} -set_value_ptr :: (progress_bar : *UI_Progress_Bar, value_ptr : *float) { - progress_bar.value_ptr = value_ptr; -} - -c_draw_progress_bar :: (canvas : *Canvas, ui_elem : *UI_Elem, _zone : Ibox2, style : *UI_Style) -> bool { - using progress_bar := cast(*UI_Progress_Bar) ui_elem; - value_current := ifx value_ptr then <<value_ptr else value; - zone := _zone; - if zone.width < 6 return false; - if show_percent { - percent_str := tprint("%1%%", formatFloat(value_current * 100, width = 4, trailing_width = 1, zero_removal = .NO)); - c_draw_line_ascii(canvas, percent_str, zone, .{zone.width - 5, zone.height / 2}, style.text.default); - zone.width -= 5; - } - for x : 0..zone.width-1 { - pix_coord := (x + .5) / zone.width; - char := find_best_char(draw_proc(value_current, pix_coord), true); - for y : 0..zone.height-1 { - c_putchar(canvas, char, zone.corner + ivec2.{x, y}); - } - } - return true; -} diff --git a/kscurses/ui/scalable_group.jai b/kscurses/ui/scalable_group.jai deleted file mode 100644 index 6c12bcc..0000000 --- a/kscurses/ui/scalable_group.jai +++ /dev/null @@ -1,88 +0,0 @@ -UI_Scalable_Group :: struct { - #as using base_parent : UI_Parent = .{type = .SCALABLE_GROUP}; - - Scale_Params :: struct { - // using metrics : struct { - x1, y1, x2, y2 : s32; - #place x1; v1 : ivec2; - #place x2; v2 : ivec2; - // }; - scale_mode : enum u8 { - ANCHOR_TL :: 0; // v1 - size, v2 - offset from corner (both positive) - ANCHOR_TR :: 1; - ANCHOR_BL :: 2; - ANCHOR_BR :: 3; - - STRETCH_T :: 4; // x1/2 - left/right offset, y1 - top offset, y2 - height - STRETCH_B :: 5; // x1/2 - left/right offset, y1 - bottom offset, y2 - height - STRETCH_L :: 6; // y1/2 - top/bottom offset, x1 - left offset, x2 - width - STRETCH_R :: 7; // y1/2 - top/bottom offset, x1 - right offset, x2 - width - - STRETCH_C :: 8; // v1 - top-left offset, v2 - bottom-right offset - CENTERIZE :: 9; // v1 - size, v2 - offset from center(signed) - - FIT_EXACT :: 10; //TODO - FIT_ROUGH :: 11; - } = .ANCHOR_TL; - } - - Element :: struct { - ptr : *UI_Elem; - scale_params : Scale_Params; - } - - elements : []Element; -} - -get_zone :: (using zone : Ibox2, using scale_params : UI_Scalable_Group.Scale_Params) -> Ibox2 { - if scale_mode == { - case .ANCHOR_TL; return .{corner = corner + v2, size = v1}; - case .ANCHOR_TR; return .{corner = .{left + width - x2 - x1, top + y2}, size = v1}; - case .ANCHOR_BL; return .{corner = .{left + x2, top + height - y2 - y1}, size = v1}; - case .ANCHOR_BR; return .{corner = .{left + width - x2 - x1, top + height - y2 - y1}, size = v1}; - - case .STRETCH_T; return .{corner = .{left + x1, top + y1}, size = .{width - x1 - x2, y2}}; - case .STRETCH_B; return .{corner = .{left + x1, top + height - y1 - y2}, size = .{width - x1 - x2, y2}}; - case .STRETCH_L; return .{corner = .{left + x1, top + y1}, size = .{x2, height - y1 - y2}}; - case .STRETCH_R; return .{corner = .{left + width - x1 - x2, top + y1}, size = .{x2, height - y1 - y2}}; - - case .STRETCH_C; return .{corner = corner + v1, size = size - v1 - v2}; - case .CENTERIZE; return .{corner = corner + (size - v1) / 2 + v2 , size = v1}; - } - assert(false); - return .{}; -} - -set_sub_elements :: (group : *UI_Scalable_Group, elements : ..UI_Scalable_Group.Element) { - group.elements = elements; - for e : elements { - e.ptr.parent = group; - } -} -c_draw_scalable_group :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - using cast(*UI_Scalable_Group) ui_elem; - for e : elements { - e_zone := get_zone(zone, e.scale_params); - if !inside(e_zone, zone) return false; - if !c_draw(canvas, e.ptr, e_zone, style) return false; - } - return true; -} -handle_key_scalable_group :: (ui_elem : *UI_Elem, key : Key) -> handled:bool { - using cast(*UI_Scalable_Group) ui_elem; - assert(cursor_state == .ON || cursor_state == .OUTSIDE); - - handled := false; - if cursor_state == .OUTSIDE { - assert(xx active_element); - { - ok := false; - for e : elements if e.ptr == active_element ok = true; - assert(ok); - } - handled = handle_key(active_element, key); - } else { - assert(xx !active_element); - } - return handled; -}
\ No newline at end of file diff --git a/kscurses/ui/scene_manager.jai b/kscurses/ui/scene_manager.jai deleted file mode 100644 index 1caff8b..0000000 --- a/kscurses/ui/scene_manager.jai +++ /dev/null @@ -1,48 +0,0 @@ -UI_Scene :: struct { - root : *UI_Elem; - entry : *UI_Elem; -} -UI_Popup :: struct { - root : *UI_Elem; - entry : *UI_Elem; - size : ivec2 = .{-1, -1}; -} - -UI_Scene_Manager :: struct { - #as using base_parent : UI_Parent = .{type = .SCENE_MANAGER, box_type = .NONE}; - scenes : []UI_Scene; -} - -set_sub_elements :: (ui_scene_manager : *UI_Scene_Manager, scenes : ..UI_Scene) { - ui_scene_manager.scenes = scenes; - for ui_scene_manager.scenes it.root.parent = ui_scene_manager; -} - -handle_key_scene_manager :: (ui_elem : *UI_Elem, key : Key) -> handled:bool { - using cast(*UI_Scene_Manager) ui_elem; - assert(cursor_state == .ON || cursor_state == .OUTSIDE); - - handled := false; - if cursor_state == .OUTSIDE { - assert(xx active_element); - { - ok := false; - for s : scenes if s.root == active_element ok = true; - assert(ok); - } - handled = handle_key(active_element, key); - } else { - assert(xx !active_element); - } - return handled; -} - -c_draw_scene_manager :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - using cast(*UI_Scene_Manager) ui_elem; - return c_draw(canvas, active_element, zone, style); -} - -switch_scene :: (using ui_scene_manager : *UI_Scene_Manager, id : int) { - unset_active_recursive(__last_set); - set_active_recursive(scenes[id].entry); -} diff --git a/kscurses/ui/select_list.jai b/kscurses/ui/select_list.jai deleted file mode 100644 index 8c338c6..0000000 --- a/kscurses/ui/select_list.jai +++ /dev/null @@ -1,79 +0,0 @@ -UI_Select_List :: struct { - #as using base : UI_Elem = .{type = .SELECT_LIST}; - only_one := true; - options : []string; - selected : []bool; - - selected_id := -1; - cursor, offset := 0, 0; - - prefix_default := "[ ]"; - prefix_selected := "[+]"; -} -handle_key_select_list :: (ui_elem : *UI_Elem, key : Key) -> handled:bool { - using cast(*UI_Select_List) ui_elem; - assert(cursor_state != .OUTSIDE); - if cursor_state == .ON { - if key == .ENTER { - cursor_state = .IN; - return true; - } - } else { - if key == { - case .DOWN; - if cursor < options.count - 1 then cursor += 1; - case .UP; - if cursor > 0 then cursor -= 1; - case .ESCAPE; - cursor_state = .ON; - case .ENTER; - if only_one { - if cursor == selected_id { - selected_id = -1; - } else { - selected_id = cursor; - } - } else { - selected[cursor] ^= true; - } - case; - return false; - } - return true; - } - return false; -} -init :: (select_list : *UI_Select_List, only_one := true) { - select_list.only_one = only_one; - if !only_one select_list.selected = NewArray(select_list.options.count, bool); -} -deinit :: (using select_list : *UI_Select_List) { - array_free(selected); -} -c_draw_select_list :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - using cast(*UI_Select_List) ui_elem; - rows := min(cast(int) zone.height, options.count - offset); - - fix_offset :: () #expand { - if cursor - offset < 0 { - offset = cursor; - } else if cursor - offset >= zone.height { - offset = cursor - zone.height + 1; - } - } - fix_offset(); - - for y : 0..rows-1 { - i := y + offset; - is_selected := ifx only_one then i == selected_id else selected[i]; - prefix := ifx is_selected then prefix_selected else prefix_default; - mode := ifx i == cursor && cursor_state == .IN - ifx is_selected style.text.cursor_and_selection else style.text.cursor - else - ifx is_selected style.text.selection else style.text.default; - - c_draw_line_ascii(canvas, prefix, zone, .{0, xx y}, mode); - c_draw_line_ascii(canvas, options[i], zone, .{xx prefix.count, xx y}, mode); - } - return true; -}
\ No newline at end of file diff --git a/kscurses/ui/style.jai b/kscurses/ui/style.jai deleted file mode 100644 index 4715860..0000000 --- a/kscurses/ui/style.jai +++ /dev/null @@ -1,118 +0,0 @@ -mode_black_and_white :: #run make_graphics_mode(foreground = .BRIGHT_WHITE, background = .BLACK); - -Box_Style :: struct { - c, tb, lr, tl, tr, bl, br, tbl, tbr, tlr, blr, tblr : u32; - mode_border, mode_space, mode_no_border := mode_black_and_white; -} - -box_style_active :: Box_Style.{ - c = #run utf8(" "), - tb = #run utf8("║"), - lr = #run utf8("═"), - tl = #run utf8("╝"), - tr = #run utf8("╚"), - bl = #run utf8("╗"), - br = #run utf8("╔"), - tbl = #run utf8("╣"), - tbr = #run utf8("╠"), - tlr = #run utf8("╩"), - blr = #run utf8("╦"), - tblr = #run utf8("╬"), - mode_no_border = #run make_graphics_mode(foreground = .BRIGHT_WHITE, background = .BRIGHT_BLACK) -}; -box_style_passive :: Box_Style.{ - c = #run utf8(" "), - tb = #run utf8("│"), - lr = #run utf8("─"), - tl = #run utf8("┘"), - tr = #run utf8("└"), - bl = #run utf8("┐"), - br = #run utf8("┌"), - tbl = #run utf8("┤"), - tbr = #run utf8("├"), - tlr = #run utf8("┴"), - blr = #run utf8("┬"), - tblr = #run utf8("┼") -}; - -UI_Style :: struct { - box : struct { - default := box_style_passive; - cursor := box_style_active; - } - - mode_main := mode_black_and_white; - - text : struct { - default := mode_black_and_white; - cursor := #run make_graphics_mode(background = .BRIGHT_BLACK); - selection := #run make_graphics_mode(background = .YELLOW); - cursor_and_selection := #run make_graphics_mode(background = .BRIGHT_YELLOW); - - debug := #run make_graphics_mode(foreground = .BLACK, background = .BRIGHT_GREEN); - } -} - -c_box :: (canvas : *Canvas, zone : Ibox2, using box_style : Box_Style, border := true) -> bool { - if !inside(ifx border then ivec2.{2, 2} else ivec2.{0, 0}, zone.size) return false; - assert(inside(zone, canvas.zone)); - charset : [9]u32; - if border { - charset[0], charset[1], charset[2], charset[3], charset[4], charset[5], charset[6], charset[7], charset[8] = br, lr, bl, tb, c, tb, tr, lr, tl; - } else { - charset[0], charset[1], charset[2], charset[3], charset[4], charset[5], charset[6], charset[7], charset[8] = c, c, c, c, c, c, c, c, c; - } - - for y : 0..zone.height-1 { - yi := ifx y == 0 then 0 else ifx y == zone.height - 1 then 2 else 1; - for x : 0..zone.width-1 { - xi := ifx x == 0 then 0 else ifx x == zone.width - 1 then 2 else 1; - i := yi * 3 + xi; - c_putchar(canvas, .{code = charset[i], mode = mode_border}, zone.corner + ivec2.{xx x, xx y}); - } - } - return true; -} - -b_box :: (builder : *String_Builder, zone : Ibox2, using charset := box_style_passive, mode := Graphics_Mode.{}, clear_center := true, border := true) { - //assert(inside(zone, terminal_state.size)); - - charset : [9]u32; - if border { - charset = .[br, lr, bl, tb, c, tb, tr, lr, tl]; - } else { - charset = .[c, c, c, c, c, c, c, c, c]; - } - - b_move_cursor(builder, zone.corner); - b_mode_set(builder, mode); - - for y : 0..zone.height-1 { - yi := ifx y == 0 then 0 else ifx y == zone.height - 1 then 2 else 1; - b_move_cursor(builder, .{zone.corner.x, zone.corner.y + y}); - - if !clear_center && yi == 1 { - b_putchar(builder, charset[3]); - b_move_cursor(builder, .{zone.corner.x + zone.width - 1, zone.corner.y + y}); - b_putchar(builder, charset[5]); - } else { - for x : 0..zone.width-1 { - xi := ifx x == 0 then 0 else ifx x == zone.width - 1 then 2 else 1; - i := yi * 3 + xi; - b_putchar(builder, charset[i]); - } - } - - } -} -t_box :: (zone : Ibox2, charset := box_style_passive, clear_center := false) -> string { - builder := String_Builder.{allocator=temp}; - b_box(*builder, zone, charset, make_graphics_mode(), clear_center); - return builder_to_string(*builder, temp); -} -ks_box :: (zone : Ibox2, charset := box_style_passive, clear_center := false) { - ks_write(t_box(zone, charset, clear_center)); -} - - - diff --git a/kscurses/ui/table.jai b/kscurses/ui/table.jai deleted file mode 100644 index dadc1c3..0000000 --- a/kscurses/ui/table.jai +++ /dev/null @@ -1,87 +0,0 @@ -UI_Table :: struct { - #as using base : UI_Elem = .{type = .TABLE}; - - // auto_scale := false; - // metrics : []int; - columns := 0; - rows := 0; - - // description : []string; - content : [..]string; - - cursor, offset := 0; - show_cursor := false; -} - -handle_key_table :: (ui_elem : *UI_Elem, key : Key) -> handled:bool { - return false; -} - -c_draw_table_content :: (canvas : *Canvas, using ui_table : *UI_Table, zone : Ibox2, style : *UI_Style, rows_visible : int) -> bool { - for y : 0..zone.height-1 { - is_selected := y == cursor && show_cursor; - mode := ifx is_selected then style.text.selection else style.text.default; - separator_char := Char.{code = style.box.default.tb, mode = mode}; - - if zone.width < columns { - for x : 0..zone.width { - c_putchar(canvas, separator_char, zone.corner + ivec2.{xx x, xx y}); - } - } else { - i := y + offset; - for x : 0..columns-1 { - l := (zone.width + 1) * x / columns; - r := (zone.width + 1) * (x + 1) / columns - 1; - if y < rows_visible { - field_content := content[i * columns + x]; - field_content.count = min(field_content.count, r - l); - c_draw_line_ascii(canvas, field_content, zone, .{xx l, xx y}, mode); - } - if x != columns-1 c_putchar(canvas, separator_char, zone.corner + ivec2.{xx r, xx y}); - } - } - } - return true; -} - -c_draw_table :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - using ui_table := cast(*UI_Table) ui_elem; - assert(rows * columns == content.count); - - rows_visible := min(cast(int) zone.height, rows - offset); - - fix_offset :: () #expand { - if cursor - offset < 0 { - offset = cursor; - } else if cursor - offset >= zone.height { - offset = cursor - zone.height + 1; - } - } - fix_offset(); - - ok := c_draw_table_content(canvas, ui_table, zone, style, rows_visible); - return ok; -} -init :: (table : *UI_Table, description : []string) { - table.columns = description.count; - table.description = description; -} -init :: (table : *UI_Table, columns : int) { - table.columns = columns; -} - -add_line :: (using table : *UI_Table, line : ..string) { - assert(line.count == columns); - array_add(*content, ..line); - rows += 1; -} -deinit :: (using table : *UI_Table) { - array_free(content); -} - -// TODO -// variadic columns count, different content types -// empty separator -// automatic scale, as option -// description -// align content left/right/center
\ No newline at end of file diff --git a/kscurses/ui/text_buf.jai b/kscurses/ui/text_buf.jai deleted file mode 100644 index 689bb98..0000000 --- a/kscurses/ui/text_buf.jai +++ /dev/null @@ -1,15 +0,0 @@ -UI_Text_Buf :: struct { - #as using base : UI_Elem = .{type = .TEXT_BUF}; - lines : []string; - lines_dynamic : *[]string; -} -c_draw_textbuf :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool { - using cast(*UI_Text_Buf) ui_elem; - - lines_to_draw := ifx lines_dynamic then <<lines_dynamic else lines; - for l, y : lines_to_draw { - if y >= zone.height break; - c_draw_line_ascii(canvas, l, zone, .{0, xx y}, style.text.default); - } - return true; -} diff --git a/kscurses/ui/tilemap.jai b/kscurses/ui/tilemap.jai deleted file mode 100644 index 73f96e5..0000000 --- a/kscurses/ui/tilemap.jai +++ /dev/null @@ -1,20 +0,0 @@ -UI_Tilemap :: struct { - #as using base : UI_Elem = .{type = .TILEMAP}; - - map_size : ivec2; - map : []u64; - tileset : *Tileset; - - background : Char; // if not set, then box's filler instead -} -Tileset :: struct { - tile_size : ivec2; - tiles_count : int; - data : []Char; - // code = 0 -> skip entire character - // fcol/bcol = .DEFAULT -> skip foreground/background -} -c_draw_tile :: (canvas : *Canvas, tileset : *Tileset, offset : ivec2, id : u64, cutoff : Ibox2) { - -} - diff --git a/kscurses/utils.jai b/kscurses/utils.jai deleted file mode 100644 index 2b88e85..0000000 --- a/kscurses/utils.jai +++ /dev/null @@ -1,53 +0,0 @@ -// array_slice :: (array : []$T, left : int, right : int) -> []T { -// assert(left <= right && left >= 0 && right <= array.count); -// result : []T; -// result.data, result.count = array.data + left, right - left; -// return result; -// } - -length_code :: inline (c : u64) -> u8 { - for 0..7 { - if !c return xx it; - c >>= 8; - } - return 8; -} -utf8 :: (str : string) -> u32 { - code : u32; - assert(str.count <= 4); - memcpy(*code, str.data, str.count); - return code; -} -byteswap_64 :: (c : u64) -> u64 { - c = ((0xFFFFFFFF00000000 & c) >> 32) | ((0x00000000FFFFFFFF & c) << 32); - c = ((0xFFFF0000FFFF0000 & c) >> 16) | ((0x0000FFFF0000FFFF & c) << 16); - c = ((0xFF00FF00FF00FF00 & c) >> 8) | ((0x00FF00FF00FF00FF & c) << 8); - return c; -} -byteswap_32 :: (c : u32) -> u32 { - c = ((0xFFFF0000 & c) >> 16) | ((0x0000FFFF & c) << 16); - c = ((0xFF00FF00 & c) >> 8) | ((0x00FF00FF & c) << 8); - return c; -} -char_bs :: (code : u32) -> u32 { - l := length_code(code); - return byteswap_32(code) >> ((8 - l) * 8); -} -utf8_bs :: (str : string) -> u32 { - return char_bs(utf8(str)); -} -arrow_code_to_ivec2 :: (key : Key, $swap_y := true) -> ivec2 { - #if swap_y { - return ifx key == .UP ivec2.{ 0, -1} - else ifx key == .RIGHT ivec2.{ 1, 0} - else ifx key == .DOWN ivec2.{ 0, 1} - else ifx key == .LEFT ivec2.{-1, 0} - else ivec2.{}; - } else { - return ifx key == .UP ivec2.{ 0, 1} - else ifx key == .RIGHT ivec2.{ 1, 0} - else ifx key == .DOWN ivec2.{ 0, -1} - else ifx key == .LEFT ivec2.{-1, 0} - else ivec2.{}; - } -} diff --git a/kscurses/vectors.jai b/kscurses/vectors.jai deleted file mode 100644 index f27d572..0000000 --- a/kscurses/vectors.jai +++ /dev/null @@ -1,210 +0,0 @@ -Generic_Vector :: struct(type : Type, N : int) { - #assert N > 1; - #if N < 5 { - x, y : type; - #if N > 2 { - z : type; - #place x; xy : Generic_Vector(type, 2); - #place y; yz : Generic_Vector(type, 2); - #place x; r : type; - #place y; g : type; - #place z; b : type; - } - #if N > 3 { - w : type; - #place z; zw : Generic_Vector(type, 2); - #place x; xyz : Generic_Vector(type, 3); - #place y; yzw : Generic_Vector(type, 3); - #place w; a : type; - } - #place x; - } - values : [N]type; -} -generic_vector_binary_proc_vv :: (v1 : Generic_Vector($type, $N), v2 : Generic_Vector(type, N), proc : (s1 : type, s2 : type) -> (type)) -> Generic_Vector(type, N) { - result : Generic_Vector(type, N) = ---; - for i : 0..N-1 result.values[i] = proc(v1.values[i], v2.values[i]); - return result; -} -generic_vector_binary_proc_vs :: (v : Generic_Vector($type, $N), s : type, proc : (s1 : type, s2 : type) -> (type)) -> Generic_Vector(type, N) { - result : Generic_Vector(type, N) = ---; - for i : 0..N-1 result.values[i] = proc(v.values[i], s); - return result; -} -generic_vector_binary_proc_sv :: (s : type, v : Generic_Vector($type, $N), proc : (s1 : type, s2 : type) -> (type)) -> Generic_Vector(type, N) { - result : Generic_Vector(type, N) = ---; - for i : 0..N-1 result.values[i] = proc(s, v.values[i]); - return result; -} -generic_vector_unary_proc :: (v : Generic_Vector($type, $N), proc : (s : type) -> (type)) -> Generic_Vector(type, N) { - result : Generic_Vector(type, N) = ---; - for i : 0..N-1 result.values[i] = proc(v.values[i]); - return result; -} - -operator- :: #bake_arguments generic_vector_unary_proc(proc = (s) => -s); - -operator+ :: #bake_arguments generic_vector_binary_proc_vv(proc = (s1, s2) => s1 + s2); -operator- :: #bake_arguments generic_vector_binary_proc_vv(proc = (s1, s2) => s1 - s2); -operator/ :: #bake_arguments generic_vector_binary_proc_vv(proc = (s1, s2) => s1 / s2); -operator* :: #bake_arguments generic_vector_binary_proc_vv(proc = (s1, s2) => s1 * s2); - -operator+ :: #bake_arguments generic_vector_binary_proc_sv(proc = (s1, s2) => s1 + s2); -operator- :: #bake_arguments generic_vector_binary_proc_sv(proc = (s1, s2) => s1 - s2); -operator/ :: #bake_arguments generic_vector_binary_proc_sv(proc = (s1, s2) => s1 / s2); -operator* :: #bake_arguments generic_vector_binary_proc_sv(proc = (s1, s2) => s1 * s2); - -operator+ :: #bake_arguments generic_vector_binary_proc_vs(proc = (s1, s2) => s1 + s2); -operator- :: #bake_arguments generic_vector_binary_proc_vs(proc = (s1, s2) => s1 - s2); -operator/ :: #bake_arguments generic_vector_binary_proc_vs(proc = (s1, s2) => s1 / s2); -operator* :: #bake_arguments generic_vector_binary_proc_vs(proc = (s1, s2) => s1 * s2); - -operator== :: (v1 : Generic_Vector($type, $N), v2 : Generic_Vector(type, N)) -> bool { - for i : 0..N-1 { - if v1.values[i] != v2.values[i] return false; - } - return true; -} - -// affects only on naming -Generic_Box :: struct(type : Type, N : int, left_handed := false) { - #assert N > 1; - #if N <= 3 { - width, height : type; - #if N == 3 { length : type; } - - #if left_handed { right : type; } else { left : type; } - top : type; - #if N == 3 { front : type; } - #place width; - } - size, corner : Generic_Vector(type, N); -} -operator== :: (a : Generic_Box($type, $N, $left_handed), b : Generic_Box(type, N, left_handed)) -> bool { - return a.size == b.size && a.corner == b.corner; -} -is_empty :: (box : Generic_Box) -> bool { - return box.size == .{0, 0}; -} -is_invalid :: (box : Generic_Box) -> bool { - return box.width < 0 || box.height < 0; -} -point_inside :: (point : Generic_Vector($type, $N), zone : Generic_Box(type, N)) -> bool { - for i : 0..N-1 { - p, l, w := point.values[i], zone.corner.values[i], zone.size.values[i]; - if p < l return false; - if p > l + w return false; - } - return true; -} -inside :: (inner : Generic_Box($type, $N, $left_handed), outer : Generic_Box(type, N, left_handed)) -> bool { - return point_inside(inner.corner, outer) && point_inside(inner.corner + inner.size, outer); -} -inside :: (inner : Generic_Box($type, $N, $left_handed), outer : Generic_Vector(type, N)) -> bool { - return inside(inner, Generic_Box(type, N, left_handed).{size = outer}); -} -inside :: (inner : Generic_Vector($type, $N), outer : Generic_Vector(type, N)) -> bool { - for i : 0..N-1 { - if inner.values[i] > outer.values[i] return false; - } - return true; -} -cut_border :: (box : Generic_Box($type, $N, $left_handed), gap : type) -> Generic_Box(type, N, left_handed) { - result : Generic_Box(type, N, left_handed) = ---; - for i : 0..N-1 { - result.corner.values[i] = box.corner.values[i] + gap; - result.size.values[i] = box.size.values[i] - gap * 2; - } - return result; -} -fit_in_center :: (zone : Generic_Box($type, $N, $left_handed), box_size : Generic_Vector(type, N)) -> Generic_Box(type, N, left_handed), fit:bool { - return .{size = box_size, corner = zone.corner + (zone.size - zone.corner) / 2}, inside(box_size, zone.size); -} -intersection :: (box1 : Generic_Box($type, $N, $left_handed), box2 : Generic_Box(type, N, left_handed)) -> Ibox2 { - result : Generic_Box(type, N, left_handed) = ---; - for i : 0..N-1 { - l1, w1 := box1.corner.values[i], box1.size.values[i]; - l2, w2 := box2.corner.values[i], box2.size.values[i]; - result.corner.values[i] = max(l1, l2); - result.size.values[i] = min(l1 + w1, l2 + w2); - } - return result; -} - -cast_vec :: ($type_out : Type, in : Generic_Vector($type_in, $N)) -> Generic_Vector(type_out, N) { - result : Generic_Vector(type_out, N) = ---; - for i : 0..N-1 { - result.values[i] = xx in.values[i]; - } - return result; -} - -fract :: (x : float) -> float { return x - floor(x); } -fract :: (using v : Vector2) -> Vector2 { return .{fract(x), fract(y)}; } -fract :: (using v : Vector3) -> Vector3 { return .{fract(x), fract(y), fract(z)}; } -fract :: (using v : Vector4) -> Vector4 { return .{fract(x), fract(y), fract(z), fract(w)}; } - -floor :: (v : Vector2) -> Vector2 { return .{floor(v.x), floor(v.y)}; } -floor :: (v : Vector3) -> Vector3 { return .{floor(v.x), floor(v.y), floor(v.z)}; } -floor :: (v : Vector4) -> Vector4 { return .{floor(v.x), floor(v.y), floor(v.z), floor(v.w)}; } - -mix :: (x : float, y : float, m : float) -> float { return x + (y - x) * m; } -mix :: (x : Vector2, y : Vector2, m : float) -> Vector2 { return .{mix(x.x, y.x, m), mix(x.y, y.y, m)}; } -mix :: (x : Vector3, y : Vector3, m : float) -> Vector3 { return .{mix(x.x, y.x, m), mix(x.y, y.y, m), mix(x.z, y.z, m)}; } -mix :: (x : Vector4, y : Vector4, m : float) -> Vector4 { return .{mix(x.x, y.x, m), mix(x.y, y.y, m), mix(x.z, y.z, m), mix(x.w, y.w, m)}; } - -mix :: (x : Vector2, y : Vector2, m : Vector2) -> Vector2 { return .{mix(x.x, y.x, m.x), mix(x.y, y.y, m.y)}; } -mix :: (x : Vector3, y : Vector3, m : Vector3) -> Vector3 { return .{mix(x.x, y.x, m.x), mix(x.y, y.y, m.y), mix(x.z, y.z, m.z)}; } -mix :: (x : Vector4, y : Vector4, m : Vector4) -> Vector4 { return .{mix(x.x, y.x, m.x), mix(x.y, y.y, m.y), mix(x.z, y.z, m.z), mix(x.w, y.w, m.z)}; } - -clamp :: (a : Vector2, mi : float, ma : float) -> Vector2 { return .{clamp(a.x, mi, ma), clamp(a.y, mi, ma)}; } -clamp :: (a : Vector3, mi : float, ma : float) -> Vector3 { return .{clamp(a.x, mi, ma), clamp(a.y, mi, ma), clamp(a.z, mi, ma)}; } -clamp :: (a : Vector4, mi : float, ma : float) -> Vector4 { return .{clamp(a.x, mi, ma), clamp(a.y, mi, ma), clamp(a.z, mi, ma), clamp(a.w, mi, ma)}; } - - -sin :: (v : Vector2) -> Vector2 { return .{sin(v.x), sin(v.y)}; } -sin :: (v : Vector3) -> Vector3 { return .{sin(v.x), sin(v.y), sin(v.z)}; } -sin :: (v : Vector4) -> Vector4 { return .{sin(v.x), sin(v.y), sin(v.z), sin(v.w)}; } - -hash22 :: (_p : Vector2, seed := Vector2.{}) -> Vector2 { - p := multiply(Matrix2.{127.1, 311.7, 269.5, 183.3}, _p); - p = Vector2.{-1., -1.} + 2. * fract(sin(p) * 43758.545); - return sin(p * 6.283 + seed * Vector2.{124.1, 8123.1}); -} - -perlin_level :: (p : Vector2) -> float { - pi := floor(p); - pf := p - pi; - w := pf * pf * (Vector2.{3., 3.} - Vector2.{2., 2.} * pf); - - f00 := dot(hash22(pi + Vector2.{0., 0.}), pf - Vector2.{0., 0.}); - f01 := dot(hash22(pi + Vector2.{0., 1.}), pf - Vector2.{0., 1.}); - f10 := dot(hash22(pi + Vector2.{1., 0.}), pf - Vector2.{1., 0.}); - f11 := dot(hash22(pi + Vector2.{1., 1.}), pf - Vector2.{1., 1.}); - - return mix(mix(f00, f10, w.x), mix(f01, f11, w.x), w.y); -} -perlin :: (_p : Vector2) -> float { - p := _p; - M1 :: 4; - a, r, s := 1., 0., 0.; - for i : 0..M1 - 1 { - r += a * perlin_level(p); - s += a; - p *= 2.; - a *= .5; - } - return r / s; -} - -hsv2rgb :: (c : Vector3) -> Vector3 { - K := Vector4.{1, 2. / 3, 1. / 3, 3}; - p := abs(fract(Vector3.{c.x, c.x, c.x} + K.xyz) * 6.0 - Vector3.{K.w, K.w, K.w}); - return c.z * mix(Vector3.{K.x, K.x, K.x}, clamp(p - Vector3.{K.x, K.x, K.x}, 0, 1), c.y); -} - - -ivec2 :: Generic_Vector(s32, 2); -ivec3 :: Generic_Vector(s32, 3); -u8vec3 :: Generic_Vector(u8, 3); -Ibox2 :: Generic_Box(s32, 2, false); |
