#ifndef ui_hpp #define ui_hpp #include "app.hpp" #include "maths.hpp" #include "video.hpp" #include struct Arena; struct UI { struct Vertex { float x, y, u, v, r, g, b, a; }; struct Colour { uint8_t r, g, b, a; Colour(unsigned rgb, uint8_t a = 0xff); float r_f() { return (float)r / 255.0f; }; float g_f() { return (float)g / 255.0f; }; float b_f() { return (float)b / 255.0f; }; float a_f() { return (float)a / 255.0f; }; }; struct Rect { int x, y, w, h; Rect() = default; Rect(int x, int y, int w, int h); void clip(const Rect& other); void shrink(int a); bool contains(int px, int py); }; struct Vertex_Buffer { Rect clip; bool dirty; Staged_Buffer buf; Buffer_Id indices; int start, usage; void init(Device* dev); void init_indices(Device* dev); void destroy(UI* ui); void update_buffer(Context& ctx); void reset(const Rect& clip); void set_clip(const Rect& clip); void add_quad( UI* ui, int x, int y, int w, int h, float u0, float v0, float u1, float v1, Colour col ); void add_rect( UI* ui, int x, int y, int w, int h, Colour col ); void add_char(UI* ui, int x, int y, char ch, Colour col); void add_text( UI* ui, int x, int y, const char* txt, Colour col ); void draw( UI* ui, Context& ctx, Pipeline& pip, Render_Pass& rp ); Vertex_Buffer* next; }; struct Element; Heap* heap; Device* device; Texture_Id atlas; Shader_Id shader; Vertex_Format_Id vertex_format; Sampler_Id sampler; Staged_Buffer cbuffer; Vertex_Buffer mesh; Pipeline* pipeline; Render_Pass* render_pass; Element* root, * hot, * hovered; struct UI_CBuffer { m4f projection; }; struct { int vert_binding; int atlas_binding; int config_binding; } shader_info; static int text_width(const char* t); static int text_height(const char* t); static UI* create(Device* dev, Arena* a, Shader_Id sh); void init( Device* dev, Heap* h, Texture_Id atlas, Shader_Id sh ); void destroy(); void update(Arena* s, const App& app); void render(Arena* s, Texture_Id target); void draw_container(const Rect& r); void draw_containeri(const Rect& r); Element* alloc_element(size_t size); template T* create_element(Element* parent, Args... args) { T* e = (T*)alloc_element(sizeof(T)); new (e) T(this, parent, args...); return e; } struct Message { enum class Type { click } type; }; typedef int (*Message_Handler)(Element* e, const Message& m); struct Element { UI* ui; Element* parent; Element** children; Message_Handler handler; Rect bound, clip; int child_count; Element(UI* ui, Element* parent); virtual ~Element(); virtual Rect layout(const Rect& avail); void update(const App& app); virtual void on_render(); virtual void on_message(const Message& msg); void add_child(Element* ch); void message(const Message& msg); void render(); }; struct Container : Element { int padding; Container(UI* ui, Element* parent); Rect layout(const Rect& avail) override; }; struct Toolbar : Element { int padding; Toolbar(UI* ui, Element* parent); Rect layout(const Rect& avail) override; void on_render() override; }; struct Button : Element { char* text; Button(UI* ui, Element* parent, const char* label); Rect layout(const Rect& avail) override; void on_render() override; }; }; #endif