// PolarisUI C++ 0.2.0 — LicenseRef-PolarisUI-NC-FullSource-1.0 #pragma once #include #include #include #include #include #include #include #include #include namespace polaris::ui { inline constexpr const char* version = "0.2.0"; using Color = std::uint32_t; // 0xAARRGGBB struct Vec2 { float x=0, y=0; }; struct Rect { float x=0, y=0, w=0, h=0; bool contains(Vec2 p) const noexcept; Rect intersect(Rect other) const noexcept; }; Color mix(Color a, Color b, float amount); enum class Antialiasing { none, standard, high }; struct Theme { Color text=0xfff0f0f0, muted=0xffbcbcbc, accent=0xffe6e6e6, accent_text=0xff171717; Color surface=0xff171717, field=0x38777777, hover=0x24ffffff, border=0x247c7c7c; Color selected=0x8ae0e0e0, background=0xff151515, background_accent=0xff434343; Color highlight=0xffffffff, shadow=0xff000000; float radius=9, panel_radius=18, font_size=14; float blur=.98f, sigma=18, refraction=10, shine=.82f, dispersion=.85f; float tint=.20f, surface_opacity=1, text_contrast=1.05f, corner_smoothing=.55f; bool dark=true, bezier_corners=true; Antialiasing antialiasing=Antialiasing::high; std::string font_family="Segoe UI"; static Theme light(); static Theme liquid(); static Theme normal(); void validate() const; }; struct Input { Vec2 pointer{-1,-1}; bool down=false, pressed=false, released=false; bool backspace=false, erase=false, left=false, right=false, home=false, end=false; bool enter=false, escape=false, tab=false, shift=false, ctrl=false, select_all=false; bool up_key=false,down_key=false,page_up=false,page_down=false,space=false,alt=false; bool copy=false,cut=false,undo=false,redo=false,right_pressed=false,right_released=false,lost_focus=false; int key_code=0; float wheel=0; std::string text, paste; }; struct Command { std::array values{}; }; class Renderer; class Canvas { public: void begin(float width, float height, const Theme& theme); void clip(Rect rect); Rect clip() const noexcept { return clip_; } void push_clip(Rect rect, float radius=0); void pop_clip(); void backdrop(); void fill(Rect rect, Color color, float radius=0); void stroke(Rect rect, Color color, float thickness=1, float radius=0); void glass(Rect rect, const Theme& theme, float radius=-1); void line(Vec2 from, Vec2 to, Color color, float thickness=1); void ring(Rect rect, Color color, float thickness, float progress=1, float start=0); void color_plane(Rect rect, float hue); void text(const std::string& utf8, Vec2 position, float size, Color color, int weight=400); float text_width(const std::string& utf8, float size, int weight=400) const; const std::vector& commands() const noexcept { return commands_; } float width() const noexcept { return width_; } float height() const noexcept { return height_; } const Theme& theme() const noexcept { return theme_; } private: friend class Renderer; std::vector commands_; std::vector clips_; Rect clip_; Theme theme_; float width_=0,height_=0; Renderer* renderer_=nullptr; Command& add(int kind, Rect bounds, Color color); void rounding(Command& command, float radius, const Theme& theme); }; // Immediate-mode controls. IDs must be stable and unique within one Ui instance. class Ui { public: void begin(Canvas& canvas, const Input& input); void end(); void disabled(bool value) noexcept { disabled_=value; } bool wants_keyboard() const noexcept { return !focus_.empty(); } const std::string& focus() const noexcept { return focus_; } void label(Rect r, const std::string& text, float size=0); void panel(Rect r, const std::string& title="", bool glass=true); bool button(const std::string& id, Rect r, const std::string& text); bool checkbox(const std::string& id, Rect r, const std::string& text, bool& checked); bool toggle(const std::string& id, Rect r, const std::string& text, bool& enabled); bool radio(const std::string& id, Rect r, const std::string& text, int option, int& selected); bool slider(const std::string& id, Rect r, float& value, float minimum=0, float maximum=1); bool text_field(const std::string& id, Rect r, std::string& value, const std::string& placeholder=""); bool number_field(const std::string& id, Rect r, float& value, float minimum, float maximum, float step=1); bool combo(const std::string& id, Rect r, const std::vector& items, int& selected); bool tabs(const std::string& id, Rect r, const std::vector& items, int& selected); bool list(const std::string& id, Rect r, const std::vector& items, int& selected, float row_height=34); void progress(Rect r, float value); void separator(Rect r); void badge(Rect r, const std::string& text); void tooltip(Rect target, const std::string& text); bool material_settings(const std::string& id, Rect r, Theme& theme); private: struct State { std::size_t caret=0; float scroll=0; bool select_all=false; }; Canvas* canvas_=nullptr; Input input_; std::string active_,focus_,open_combo_; std::unordered_map states_; std::vector previous_order_, order_,seen_; bool disabled_=false, focus_seen_=false,press_claimed_=false; std::function overlay_; bool hit(Rect r) const; bool interaction(const std::string& id, Rect r); void register_id(const std::string& id); void face(Rect r, bool hovered, bool pressed, bool selected=false); void centered(Rect r, const std::string& text, Color color); }; struct Pixels { int width=0,height=0; std::vector rgba; }; // One OpenGL 3.3 renderer per process, on the constructing thread. // Construct after making a single-sample desktop OpenGL context current. class Renderer { public: Renderer(); ~Renderer(); Renderer(const Renderer&)=delete; Renderer& operator=(const Renderer&)=delete; void begin(Canvas& canvas, int pixel_width, int pixel_height, float logical_width, float logical_height, const Theme& theme); void background(int pixel_width,int pixel_height,float time,const Theme& theme,bool grid=false); void render(Canvas& canvas,int pixel_width,int pixel_height,Vec2 pointer={},unsigned framebuffer=0,unsigned color_attachment=0x0405); Pixels read_pixels(int width,int height); // Top-left RGBA; window back buffer, before swapping. std::string device() const; private: friend class Canvas; struct Impl; std::unique_ptr impl_; std::thread::id owner_; void check() const; void draw_text(Canvas&,const std::string&,Vec2,float,Color,int); float measure(const std::string&,float,int) const; }; struct WindowOptions { std::string title="PolarisUI C++"; int width=1280,height=800; bool visible=true; }; // Win32/WGL host. Caller-owned contexts can use Renderer directly without Window. class Window { public: explicit Window(const WindowOptions& options={}); ~Window(); Window(const Window&)=delete; Window& operator=(const Window&)=delete; bool poll(); void swap(); void close(); int width() const; int height() const; float dpi_scale() const; const Input& input() const; void title(const std::string& utf8); void text_input(bool enabled); void clipboard_text(const std::string& utf8); void* native_handle() const; private: struct Impl; std::unique_ptr impl_; }; // PNG encoder supplied by Windows Imaging Component; no third-party codecs. void save_png(const std::string& path,const Pixels& pixels); } // namespace polaris::ui