#ifndef HOST_GUI_H #define HOST_GUI_H #include #include #include #include #include #include #include #include #include #include namespace gui { class window; class page; class RawPicture; struct Widget; using callback_void = std::function; using callback_page = std::function; using callback_window = std::function; 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; 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>> 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>& pts, uint32_t c); void fillPolygon(const std::vector>& 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 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 items; std::shared_ptr picture; callback_void on_change; callback_page on_page_click; callback_window on_window_click; }; using OverlayList = std::vector; class combat { friend struct Widget; protected: std::vector> 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& 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 tab_buttons; std::unordered_map> 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