infinipaint/src/GUIStuff/GUIManager.hpp

159 lines
6.2 KiB
C++
Raw Normal View History

2025-07-06 20:43:53 +03:00
#pragma once
#include <include/core/SkCanvas.h>
#include <Eigen/Dense>
#include "GUIManagerID.hpp"
#include <clay.h>
#include "Elements/Element.hpp"
2025-07-06 20:43:53 +03:00
using namespace Eigen;
namespace GUIStuff {
class GUIManager {
public:
struct ElementContainer {
std::unique_ptr<Element> elem;
bool isUsedThisFrame;
2025-07-06 20:43:53 +03:00
};
GUIManager();
2026-04-08 17:34:50 +03:00
void draw(SkCanvas* c, bool skiaAA);
2026-04-19 10:03:57 +03:00
void draw_force(SkCanvas* canvas, bool skiaAA);
void set_to_layout();
void layout_if_necessary();
2026-04-08 17:34:50 +03:00
void update();
void update_window(const Vector2f& windowPos, const Vector2f& windowSize, float guiScaleMultiplier);
2025-07-06 20:43:53 +03:00
UpdateInputData io;
2025-07-06 20:43:53 +03:00
2026-03-30 18:51:14 +03:00
void new_id(const char* id, const std::function<void()>& f);
void new_id(int64_t id, const std::function<void()>& f);
2025-07-06 20:43:53 +03:00
2026-04-01 18:00:22 +03:00
void set_z_index(int16_t z, const std::function<void()>& f);
void set_z_index_keep_clipping_region(int16_t z, const std::function<void()>& f);
2026-04-01 18:00:22 +03:00
int16_t get_z_index();
void set_post_callback_func(const std::function<void()>& f);
2026-04-01 18:00:22 +03:00
void set_post_callback_func_high_priority(const std::function<void()>& f);
void run_post_callback_func();
2025-07-06 20:43:53 +03:00
2026-04-08 17:34:50 +03:00
void invalidate_draw_element(Element* element, const BorderData& extraPadding = {});
void invalidate_draw_in_area(const SCollision::AABB<float>& bb);
template <typename ElementType, typename... Args> ElementType* element(const char* id, const Args&... a) {
push_id(id);
2026-04-02 22:05:37 +03:00
ElementType* elem = insert_element<ElementType>();
2026-04-09 16:30:28 +03:00
Element* oldParent = parentElement;
elem->parent = parentElement;
2026-04-02 22:05:37 +03:00
parentElement = elem;
elem->set_parent_clipping_region(clippingRegion);
2026-04-02 22:05:37 +03:00
Clay_ElementId clayId = strArena.elem_id_from_id_stack(idStack);
elem->layout(clayId, a...);
2026-04-01 22:28:48 +03:00
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.
2026-04-02 22:05:37 +03:00
parentElement = oldParent;
2026-04-02 22:05:37 +03:00
pop_id();
return elem;
}
2025-07-06 20:43:53 +03:00
template <typename ElementType, typename... Args> ElementType* clipping_element(const char* id, const Args&... a) {
push_id(id);
ElementType* elem = insert_element<ElementType>();
2026-04-09 16:30:28 +03:00
Element* oldParent = parentElement;
elem->parent = parentElement;
2026-04-02 22:05:37 +03:00
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();
}
2026-04-02 22:05:37 +03:00
Clay_ElementId clayId = strArena.elem_id_from_id_stack(idStack);
elem->layout(clayId, a...);
2026-04-01 22:28:48 +03:00
elem->set_bounding_box_from_elem_data(Clay_GetElementData(clayId));
2026-04-02 22:05:37 +03:00
clippingRegion = oldClippingRegion;
2026-04-02 22:05:37 +03:00
parentElement = oldParent;
pop_id();
return elem;
}
2026-04-09 16:30:28 +03:00
void deselect_all();
DefaultStringArena strArena;
2025-12-20 16:38:51 +03:00
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();
2025-07-06 20:43:53 +03:00
void mouse_callback(const Vector2f& mousePos, const std::function<void(ElementContainer*)>& f);
GUIManagerIDStack idStack;
std::vector<ElementContainer*> orderedElements;
std::unordered_map<GUIManagerIDStack, ElementContainer> elements;
2025-07-06 20:43:53 +03:00
template <typename NewElement> NewElement* insert_element() {
auto [it, inserted] = elements.emplace(idStack, ElementContainer());
auto& container = it->second;
2025-07-06 20:43:53 +03:00
if(inserted)
container = {std::make_unique<NewElement>(*this)};
container.elem->zIndex = zIndex;
orderedElements.emplace_back(&container);
container.isUsedThisFrame = true;
2025-07-06 20:43:53 +03:00
return static_cast<NewElement*>(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);
2026-03-30 18:51:14 +03:00
void push_id(int64_t id);
void push_id(const char* id);
void pop_id();
2026-04-01 18:00:22 +03:00
int16_t zIndex = 0;
Element* parentElement = nullptr;
std::optional<SCollision::AABB<float>> clippingRegion;
std::function<void()> postCallbackFunc;
2026-04-01 18:00:22 +03:00
bool postCallbackFuncIsHighPriority;
2025-07-06 20:43:53 +03:00
Clay_Context* clayInstance;
Clay_Arena clayArena;
2026-04-08 17:34:50 +03:00
2025-07-06 20:43:53 +03:00
Clay_RenderCommandArray renderCommands;
2026-04-08 17:34:50 +03:00
std::unordered_map<uint32_t, Clay_RenderCommand> oldRenderCommandMap;
std::optional<SCollision::AABB<float>> invalidDrawBB;
SCollision::AABB<float> get_invalid_draw_bb(SCollision::AABB<float> bb, const BorderData& extraPadding = {});
SCollision::AABB<float> get_invalid_draw_bb_from_command(const Clay_RenderCommand* command);
void update_invalidated_draw_area_from_layout();
void calculate_new_clip_rect(std::vector<SCollision::AABB<float>>& clipRectStack, std::optional<SCollision::AABB<float>>& clipRect, bool& clipNoDraw);
void clip_rect_transform(SkCanvas* canvas, std::vector<SCollision::AABB<float>>& clipRectStack, std::optional<SCollision::AABB<float>>& clipRect, bool& clipNoDraw);
bool setToLayout;
2026-04-08 17:34:50 +03:00
bool setToUpdateInvalidateDrawAreaFromLayout;
bool cursorObstructed;
2025-07-06 20:43:53 +03:00
};
}