Xenith/xenith/ui/tui.hpp
2026-10-02 19:30:49 +07:00

116 lines
4.8 KiB
C++

#pragma once
#include <cstdint>
#include <memory>
#include <termios.h>
#include <vector>
#include <string>
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();
bool is_running() const;
private:
inline static Mouse mouse = Mouse();
inline static std::string chat_input = "";
inline static bool cursor = false;
inline static uint32_t frame_count = 0;
int background = 49;
int foreground = 39;
inline static bool running = true;
inline static int width = 80;
inline static int height = 24;
struct SplitDesc {
enum Type { VERTICAL, HORIZONTAL };
Type type;
int position;
std::vector<std::unique_ptr<SplitDesc>> children;
SplitDesc(Type t, 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 TuiCell {
std::string ch;
int width;
TuiCell() : ch(" "), width(1) {}
TuiCell(const std::string& c, int w) : ch(c), width(w) {}
};
inline static struct termios orig_termios;
inline static const 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 const border_charset border_ascii {
.top_left="+", .top_right="+", .bottom_left="+", .bottom_right="+",
.bottom="-", .top="-", .vertical="|", .bg=" ", .cross="+",
.tee_up="+", .tee_down="+", .tee_left="+", .tee_right="+"
};
inline static const border_charset border_bold {
.top_left="┏", .top_right="┓", .bottom_left="┗", .bottom_right="┛",
.bottom="━", .top="━", .vertical="┃", .bg=" "
};
inline static const border_charset border_solid {
.top_left="▟", .top_right="▙", .bottom_left="▜", .bottom_right="▛",
.bottom="█", .top="█", .vertical="█", .bg=" "
};
inline static const border_charset border_btn {
.top_left="▟", .top_right="▙", .bottom_left="▜", .bottom_right="▛",
.bottom="█", .top="█", .vertical="█", .bg="█"
};
static void get_console_size();
static bool wait_for_input_or_timeout(int timeout_ms);
void apply_color() const;
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();
void set_background(Color clr);
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();
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<std::vector<TuiCell>>& grid, int offset_x, int offset_y, int w, int h, border_charset charset, const SplitDesc* split);
static void apply_single_split(std::vector<std::vector<TuiCell>>& 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<std::vector<TuiCell>>& grid, int w, int h, border_charset charset);
};
Tui app = Tui();
}