147 lines
6.2 KiB
C++
147 lines
6.2 KiB
C++
#pragma once
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <termios.h>
|
|
#include <utility>
|
|
#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();
|
|
[[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<std::string> left = std::nullopt;
|
|
std::optional<std::string> right = std::nullopt;
|
|
};
|
|
inline static std::vector<msg_block> chat_history;
|
|
struct SplitDesc {
|
|
enum Type { VERTICAL, HORIZONTAL };
|
|
Type type;
|
|
int position;
|
|
std::vector<std::unique_ptr<SplitDesc>> 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<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);
|
|
static void push_msg_left(const std::string& msg);
|
|
static void push_msg_right(const std::string& msg);
|
|
static void draw_msg();
|
|
};
|
|
} |