#pragma once #include #include #include "GUIManagerID.hpp" #include #include "Elements/Element.hpp" using namespace Eigen; namespace GUIStuff { class GUIManager { public: struct ElementContainer { std::unique_ptr elem; bool isUsedThisFrame; }; GUIManager(); void draw(SkCanvas* c, bool skiaAA); void draw_force(SkCanvas* canvas, bool skiaAA); void set_to_layout(); void layout_if_necessary(); void update(); void update_window(const Vector2f& windowPos, const Vector2f& windowSize, float guiScaleMultiplier); UpdateInputData io; void new_id(const char* id, const std::function& f); void new_id(int64_t id, const std::function& f); void set_z_index(int16_t z, const std::function& f); void set_z_index_keep_clipping_region(int16_t z, const std::function& f); int16_t get_z_index(); void set_post_callback_func(const std::function& f); void set_post_callback_func_high_priority(const std::function& f); void run_post_callback_func(); void invalidate_draw_element(Element* element, const BorderData& extraPadding = {}); void invalidate_draw_in_area(const SCollision::AABB& bb); template ElementType* element(const char* id, const Args&... a) { push_id(id); ElementType* elem = insert_element(); Element* oldParent = parentElement; elem->parent = parentElement; parentElement = elem; elem->set_parent_clipping_region(clippingRegion); Clay_ElementId clayId = strArena.elem_id_from_id_stack(idStack); elem->layout(clayId, a...); elem->set_bounding_box_from_elem_data(Clay_GetElementData(clayId)); // Setting bounding box after layout ensures that the element will have its bounding box set if it's set to be drawn. parentElement = oldParent; pop_id(); return elem; } template ElementType* clipping_element(const char* id, const Args&... a) { push_id(id); ElementType* elem = insert_element(); Element* oldParent = parentElement; elem->parent = parentElement; parentElement = elem; elem->set_parent_clipping_region(clippingRegion); auto oldClippingRegion = clippingRegion; if(elem->get_bb().has_value()) { if(clippingRegion.has_value()) clippingRegion = clippingRegion.value().get_intersection_between_aabbs(elem->get_bb().value()); else clippingRegion = elem->get_bb(); } Clay_ElementId clayId = strArena.elem_id_from_id_stack(idStack); elem->layout(clayId, a...); elem->set_bounding_box_from_elem_data(Clay_GetElementData(clayId)); clippingRegion = oldClippingRegion; parentElement = oldParent; pop_id(); return elem; } void deselect_all(); DefaultStringArena strArena; void input_paste_callback(const CustomEvents::PasteEvent& paste); void input_text_key_callback(const InputManager::KeyCallbackArgs& key); void input_text_callback(const InputManager::TextCallbackArgs& text); void input_key_callback(const InputManager::KeyCallbackArgs& key); void input_mouse_button_callback(InputManager::MouseButtonCallbackArgs button); void input_mouse_motion_callback(InputManager::MouseMotionCallbackArgs motion); void input_mouse_wheel_callback(InputManager::MouseWheelCallbackArgs wheel); bool cursor_obstructed() const; private: void layout(); void layout_begin(); void layout_end(); void single_layout_run(); void mouse_callback(const Vector2f& mousePos, const std::function& f); GUIManagerIDStack idStack; std::vector orderedElements; std::unordered_map elements; template NewElement* insert_element() { auto [it, inserted] = elements.emplace(idStack, ElementContainer()); auto& container = it->second; if(inserted) container = {std::make_unique(*this)}; container.elem->zIndex = zIndex; orderedElements.emplace_back(&container); container.isUsedThisFrame = true; return static_cast(it->second.elem.get()); } static void clay_error_handler(Clay_ErrorData errorData); static Clay_Dimensions clay_skia_measure_text(Clay_StringSlice str, Clay_TextElementConfig* config, void* userData); void push_id(int64_t id); void push_id(const char* id); void pop_id(); int16_t zIndex = 0; Element* parentElement = nullptr; std::optional> clippingRegion; std::function postCallbackFunc; bool postCallbackFuncIsHighPriority; Clay_Context* clayInstance; Clay_Arena clayArena; Clay_RenderCommandArray renderCommands; std::unordered_map oldRenderCommandMap; std::optional> invalidDrawBB; SCollision::AABB get_invalid_draw_bb(SCollision::AABB bb, const BorderData& extraPadding = {}); SCollision::AABB get_invalid_draw_bb_from_command(const Clay_RenderCommand* command); void update_invalidated_draw_area_from_layout(); void calculate_new_clip_rect(std::vector>& clipRectStack, std::optional>& clipRect, bool& clipNoDraw); void clip_rect_transform(SkCanvas* canvas, std::vector>& clipRectStack, std::optional>& clipRect, bool& clipNoDraw); bool setToLayout; bool setToUpdateInvalidateDrawAreaFromLayout; bool cursorObstructed; }; }