211 lines
6.8 KiB
C++
211 lines
6.8 KiB
C++
#ifndef HOST_GUI_H
|
|
#define HOST_GUI_H
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/keysym.h>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <iostream>
|
|
#include <cstdint>
|
|
|
|
namespace gui
|
|
{
|
|
class window;
|
|
class page;
|
|
class RawPicture;
|
|
struct Widget;
|
|
|
|
using callback_void = std::function<void()>;
|
|
using callback_page = std::function<void(page&)>;
|
|
using callback_window = std::function<void(window&)>;
|
|
|
|
struct EventData {
|
|
std::string source_id;
|
|
std::string text;
|
|
float value = 0;
|
|
int index = -1;
|
|
bool flag = false;
|
|
};
|
|
|
|
class EventBus {
|
|
public:
|
|
using Handler = std::function<void(const EventData&)>;
|
|
static EventBus& get();
|
|
int on(const std::string& event, Handler h);
|
|
void off(int token);
|
|
void emit(const std::string& event, EventData data = {});
|
|
private:
|
|
int next_token = 1;
|
|
std::unordered_map<std::string, std::vector<std::pair<int, Handler>>> handlers;
|
|
};
|
|
|
|
class RawPicture {
|
|
public:
|
|
RawPicture(int w = 0, int h = 0, int bits = 32);
|
|
void create(int w, int h, int bits);
|
|
int width() const { return w; }
|
|
int height() const { return h; }
|
|
int bitness() const { return bits; }
|
|
|
|
void clear(uint32_t color = 0x000000);
|
|
void setPixel(int x, int y, uint32_t color);
|
|
uint32_t getPixel(int x, int y) const;
|
|
|
|
void drawLine(int x0, int y0, int x1, int y1, uint32_t c);
|
|
void drawRect(int x, int y, int w, int h, uint32_t c);
|
|
void fillRect(int x, int y, int w, int h, uint32_t c);
|
|
void drawCircle(int cx, int cy, int r, uint32_t c);
|
|
void fillCircle(int cx, int cy, int r, uint32_t c);
|
|
void drawTriangle(int x1,int y1,int x2,int y2,int x3,int y3,uint32_t c);
|
|
void fillTriangle(int x1,int y1,int x2,int y2,int x3,int y3,uint32_t c);
|
|
void drawPolygon(const std::vector<std::pair<int,int>>& pts, uint32_t c);
|
|
void fillPolygon(const std::vector<std::pair<int,int>>& pts, uint32_t c);
|
|
void drawText(Display* dpy, int x, int y, const std::string& t, uint32_t c, int scale = 1);
|
|
void blit(const RawPicture& src, int dx, int dy);
|
|
bool load(const std::string& path);
|
|
void present(Display* dpy, Window win, GC gc, int dx, int dy) const;
|
|
|
|
private:
|
|
int w = 0, h = 0, bits = 32;
|
|
std::vector<uint8_t> buf;
|
|
int bpp() const { return bits / 8; }
|
|
};
|
|
|
|
// ================= Widgets =================
|
|
enum class WidgetType {
|
|
BUTTON, LABEL, INPUT, CHECKBOX, RADIO, SLIDER, PROGRESS,
|
|
LISTBOX, DROPDOWN, TREE_VIEW, TREE, SCROLL, RAW_PIC, SPRITE_BTN
|
|
};
|
|
|
|
struct WidgetData {
|
|
WidgetType type = WidgetType::BUTTON;
|
|
std::string text;
|
|
std::string id;
|
|
unsigned long bg_color = 0x1A1A1A;
|
|
unsigned long fg_color = 0xFFFFFF;
|
|
unsigned long frame_color = 0x00FF00;
|
|
int x = 0;
|
|
int y = 0;
|
|
int width = 100;
|
|
int height = 30;
|
|
bool checked = false;
|
|
float value = 0.0f;
|
|
float target_value = 0.0f;
|
|
int selected_index = -1;
|
|
int scroll = 0;
|
|
bool expanded = false;
|
|
bool indeterminate = false;
|
|
std::vector<std::string> items;
|
|
std::shared_ptr<RawPicture> picture;
|
|
callback_void on_change;
|
|
callback_page on_page_click;
|
|
callback_window on_window_click;
|
|
};
|
|
|
|
using OverlayList = std::vector<const Widget*>;
|
|
|
|
class combat
|
|
{
|
|
friend struct Widget;
|
|
protected:
|
|
std::vector<std::unique_ptr<Widget>> widgets;
|
|
Widget& add_widget(WidgetData d);
|
|
public:
|
|
virtual ~combat() = default;
|
|
|
|
Widget& Button(WidgetData a);
|
|
Widget& Label(WidgetData a);
|
|
Widget& Input(WidgetData a);
|
|
Widget& Checkbox(WidgetData a);
|
|
Widget& Radiobutton(WidgetData a);
|
|
Widget& Slider(WidgetData a);
|
|
Widget& Progressbar(WidgetData a);
|
|
Widget& Listbox(WidgetData a);
|
|
Widget& Dropdown(WidgetData a);
|
|
Widget& TreeView(WidgetData a);
|
|
Widget& TreeNode(WidgetData a);
|
|
Widget& ScrollView(WidgetData a);
|
|
Widget& RawPictureWidget(WidgetData a);
|
|
Widget& SpriteButton(WidgetData a);
|
|
|
|
void visit(const std::function<void(Widget&)>& fn);
|
|
Widget* find(const std::string& id);
|
|
Widget* find_at(int mx, int my);
|
|
|
|
void tick(float dt);
|
|
void render_all(Display*, Window, GC, int ox, int oy, const XRectangle& clip, OverlayList* ov) const;
|
|
int process_press(int mx, int my, window& w, page& p, int ox, int oy);
|
|
bool process_wheel(int delta, int mx, int my, int ox, int oy);
|
|
};
|
|
|
|
struct Widget : combat
|
|
{
|
|
WidgetData data;
|
|
float anim = 0;
|
|
bool open_target = false;
|
|
float phase = 0;
|
|
int cap_ox = 0, cap_oy = 0;
|
|
bool thumb_drag = false;
|
|
int drag_my = 0, drag_scroll = 0;
|
|
|
|
void setValue(float v) { data.target_value = v; if (data.type != WidgetType::PROGRESS) data.value = v; }
|
|
float getValue() const { return data.value; }
|
|
|
|
void tick(float dt);
|
|
void draw(Display*, Window, GC, int ox, int oy, const XRectangle& clip, OverlayList* ov) const;
|
|
void draw_popup(Display*, Window, GC, const XRectangle& clip) const;
|
|
int handle_press(int mx, int my, window& w, page& p, int ox, int oy);
|
|
void handle_drag(int mx, int my);
|
|
void handle_release();
|
|
bool handle_wheel(int delta, int mx, int my, int ox, int oy);
|
|
bool contains(int mx, int my, int ox, int oy) const;
|
|
int content_height() const;
|
|
};
|
|
|
|
class page : public combat {
|
|
public:
|
|
bool active = false;
|
|
int x = 0, y = 0;
|
|
int width = 1200, height = 600;
|
|
};
|
|
|
|
class window
|
|
{
|
|
private:
|
|
Display* X11display = nullptr;
|
|
Window X11window = 0;
|
|
GC gc = nullptr;
|
|
|
|
std::vector<WidgetData> tab_buttons;
|
|
std::unordered_map<std::string, std::unique_ptr<page>> pages;
|
|
std::string current_page_name;
|
|
|
|
Widget* captured = nullptr;
|
|
Widget* focused_input = nullptr;
|
|
|
|
void draw_tabs() const;
|
|
void draw_active_page() const;
|
|
void handle_event(const XEvent& ev);
|
|
|
|
public:
|
|
explicit window(std::string title);
|
|
~window();
|
|
window(const window&) = delete;
|
|
window& operator=(const window&) = delete;
|
|
|
|
Display* display() const { return X11display; }
|
|
void update();
|
|
|
|
void addTAB_BUTTON(WidgetData args);
|
|
void addPAGE(std::string name);
|
|
void configur_page(std::string name, callback_page fn, bool active = false);
|
|
void openPAGE(std::string name);
|
|
Widget* find(const std::string& id);
|
|
void set_focus(Widget* w) { focused_input = w; }
|
|
};
|
|
}
|
|
#endif |