#pragma once #include #include #include #include #include #include #include #include namespace ui { class Mouse { private: struct pos_t { int x; int y; }; inline static bool btn0 = false; inline static bool btn1 = false; inline static bool btn2 = false; inline static int scroll = 0; inline static pos_t pos = {}; public: static bool is_pressed(int index_btn = 0); static int get_scroll(); static void reset_scroll(); static void parse_ansi(char buf[]); static pos_t get_pos(); }; class Tui { public: enum class Color : int { DefaultText = 39, DefaultBg = 49, Black = 30, Red = 31, Green = 32, Yellow = 33, Blue = 34, Magenta = 35, Cyan = 36, White = 37 }; Tui(); ~Tui(); static void update(); [[nodiscard]] bool is_running() const; private: inline static auto need_update_chat = false; inline static auto mouse = Mouse(); inline static std::string chat_input; inline static bool cursor = false; inline static uint32_t frame_count = 0; inline static int background = 49; inline static int foreground = 39; inline static bool running = true; inline static int width = 80; inline static int height = 24; struct msg_block { std::optional left = std::nullopt; std::optional right = std::nullopt; }; inline static std::vector chat_history; struct SplitDesc { enum Type { VERTICAL, HORIZONTAL }; Type type; int position; std::vector> children; SplitDesc(const Type t, const int pos) : type(t), position(pos) {} }; struct border_charset { std::string_view top_left, top_right, bottom_left, bottom_right; std::string_view bottom, top, horizontal, vertical, bg; std::string_view cross, tee_up, tee_down, tee_left, tee_right; }; struct scroll_chars { std::string_view top; std::string_view full; std::string_view bottom; }; struct TuiCell { std::string ch; int width; TuiCell() : ch(" "), width(1) {} TuiCell(std::string c, const int w) : ch(std::move(c)), width(w) {} }; std::string proces_chars = "⠙⠸⠴⠦⠇⠋"; inline static struct termios orig_termios; inline static constexpr scroll_chars main_scroll_charset { .top = "▗", .full = "▐", .bottom = "▝", }; inline static constexpr border_charset border_clip { .top_left="╭", .top_right="╮", .bottom_left="╰", .bottom_right="╯", .bottom="─", .top="─", .horizontal="─", .vertical="│", .bg=" ", .cross="┼", .tee_up="┴", .tee_down="┬", .tee_left="┤", .tee_right="├" }; inline static constexpr border_charset border_ascii { .top_left="+", .top_right="+", .bottom_left="+", .bottom_right="+", .bottom="-", .top="-", .horizontal="-", .vertical="|", .bg=" ", .cross="+", .tee_up="+", .tee_down="+", .tee_left="+", .tee_right="+" }; inline static constexpr border_charset border_bold { .top_left="┏", .top_right="┓", .bottom_left="┗", .bottom_right="┛", .bottom="━", .top="━", .horizontal="━", .vertical="┃", .bg=" ", .cross = "╋", .tee_up = "┻", .tee_down = "┳", .tee_left = "┨", .tee_right = "┣" }; inline static constexpr border_charset border_solid { .top_left="▟", .top_right="▙", .bottom_left="▜", .bottom_right="▛", .bottom="█", .top="█", .horizontal = "█", .vertical="█", .bg=" ", .cross = "█", .tee_up = "█", .tee_down = "█", .tee_left = "█", .tee_right = "█", }; inline static constexpr border_charset border_btn { .top_left="▟", .top_right="▙", .bottom_left="▜", .bottom_right="▛", .bottom="█", .top="█", .horizontal = "█", .vertical="█", .bg="█", .cross = "█", .tee_up = "█", .tee_down = "█", .tee_left = "█", .tee_right = "█" }; static void init_draw(); static winsize get_console_size(); static bool wait_for_input_or_timeout(int timeout_ms); static void apply_color(); static void disable_raw_mode(); static void enable_raw_mode(); static void move_cursor(int x, int y); static void clear(); static void draw_border(int w, int h, border_charset charset = border_clip, int x = 1, int y = 1); static void hide_cursor(); static void show_cursor(); static void set_background(Color clr); static void set_foreground(Color clr); static void move_cursor_right(int n); static void move_cursor_x(int col); static void move_cursor_y(int row); static void invert_color(); static void draw_button(int x, int y, int w, int h, std::string_view label, border_charset charset = border_solid); static void invert_color_off(); static void draw_split_border(int w, int h, border_charset charset, int x, int y, const SplitDesc* root); static void apply_splits_recursive(std::vector>& grid, int offset_x, int offset_y, int w, int h, border_charset charset, const SplitDesc* split); static void apply_single_split(std::vector>& grid, int offset_x, int offset_y, int w, int h, border_charset charset, const SplitDesc* split); static void draw_border_to_buffer(std::vector>& grid, int w, int h, border_charset charset); static void push_msg_left(const std::string& msg); static void push_msg_right(const std::string& msg); static void draw_msg(); }; }