Working on getting GUI functional again

This commit is contained in:
Yousef Khadadeh 2026-03-31 17:33:09 +03:00
parent f3fde56dcf
commit 16c3097534
49 changed files with 178 additions and 104 deletions

View file

@ -332,8 +332,8 @@ void DrawingProgram::toolbar_gui() {
auto& io = gui.io;
gui.new_id("Drawing Program Toolbar GUI", [&] {
gui.element<LayoutElement>("Drawing Program Toolbar GUI", [&] {
CLAY_AUTO_ID({
gui.element<LayoutElement>("Drawing Program Toolbar GUI", [&] (const Clay_ElementId& lId) {
CLAY(lId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0)},
.padding = CLAY_PADDING_ALL(static_cast<uint16_t>(io.theme->padding1 / 2)),
@ -446,8 +446,8 @@ void DrawingProgram::tool_options_gui() {
auto& io = gui.io;
float minGUIWidth = drawTool->get_type() == DrawingProgramToolType::SCREENSHOT ? 300 : 200;
gui.element<LayoutElement>("Drawing program tool options gui", [&] {
CLAY_AUTO_ID({
gui.element<LayoutElement>("Drawing program tool options gui", [&] (const Clay_ElementId& lId) {
CLAY(lId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(minGUIWidth), .height = CLAY_SIZING_FIT(0)},
.padding = CLAY_PADDING_ALL(io.theme->padding1),
@ -470,7 +470,7 @@ void DrawingProgram::modify_grid(const NetworkingObjects::NetObjWeakPtr<WorldGri
}
void DrawingProgram::update() {
controls.cursorHoveringOverCanvas = true; //world.main.toolbar.check_if_position_isnt_obstructed(world.main.input.mouse.pos);
controls.cursorHoveringOverCanvas = !world.main.g.gui.cursor_obstructed();
if(addFileInNextFrame) {
add_file_to_canvas_by_path_execute(addFileInfo.first, addFileInfo.second);

View file

@ -92,9 +92,8 @@ bool GUIHolder::load_theme(const std::filesystem::path& configPath, const std::s
}
void GUIHolder::update() {
gui.io.windowSize = main.window.size.cast<float>();
gui.io.windowPos = {0, 0};
calculate_final_gui_scale();
gui.update_window({0, 0}, main.window.size.cast<float>(), final_gui_scale());
gui.layout_if_necessary();
}
@ -120,15 +119,19 @@ void GUIHolder::draw(SkCanvas* canvas, bool skiaAA) {
}
void GUIHolder::input_key_callback(const InputManager::KeyCallbackArgs& key) {
gui.input_key_callback(key);
}
void GUIHolder::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
gui.input_mouse_button_callback(button);
}
void GUIHolder::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
gui.input_mouse_motion_callback(motion);
}
void GUIHolder::input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) {
gui.input_mouse_wheel_callback(wheel);
}
void GUIHolder::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) {

View file

@ -13,7 +13,7 @@ struct ColorPickerItemsOptions {
template <typename T> void color_picker_items(GUIManager& gui, const char* id, T* val, const ColorPickerItemsOptions& options = {}) {
gui.new_id(id, [&] {
auto fullOnEdit = [&gui, oE = options.onEdit, val]() {
oE();
if(oE) oE();
gui.set_to_layout();
};
gui.element<ColorPicker<T>>("c", val, options.hasAlpha, fullOnEdit);

View file

@ -4,8 +4,8 @@
namespace GUIStuff { namespace ElementHelpers {
void top_to_bottom_window_popup_layout(GUIManager& gui, const char* id, Clay_SizingAxis x, Clay_SizingAxis y, const std::function<void()>& innerContent, const LayoutElement::Callbacks& callbacks) {
gui.element<LayoutElement>(id, [&] {
CLAY_AUTO_ID({
gui.element<LayoutElement>(id, [&] (const Clay_ElementId& lId) {
CLAY(lId, {
.layout = {
.sizing = {.width = x, .height = y },
.padding = CLAY_PADDING_ALL(gui.io.theme->padding1),

View file

@ -7,7 +7,7 @@ namespace GUIStuff { namespace ElementHelpers {
template <typename T> void slider_scalar_field(GUIManager& gui, const char* id, std::string_view name, T* val, T min, T max, TextBoxScalarOptions options = {}) {
gui.new_id(id, [&] {
options.onEdit = [&, oE = options.onEdit] {
oE();
if(oE) oE();
gui.set_to_layout();
};
left_to_right_line_layout(gui, [&]() {

View file

@ -5,8 +5,8 @@ namespace GUIStuff { namespace ElementHelpers {
void paint_circle_popup_menu(GUIManager& gui, const char* id, const Vector2f& centerPos, const PaintCircleMenu::Data& val) {
constexpr float size = 300.0f;
gui.element<LayoutElement>(id, [&] {
CLAY_AUTO_ID({.layout = {
gui.element<LayoutElement>(id, [&] (const Clay_ElementId& lId) {
CLAY(lId, {.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(size), .height = CLAY_SIZING_FIXED(size)}
},
.floating = {

View file

@ -8,11 +8,11 @@ namespace GUIStuff {
CheckBox::CheckBox(GUIManager& gui):
Element(gui) {}
void CheckBox::layout(const std::function<bool()>& isTicked, const std::function<void()>& onClick) {
void CheckBox::layout(const Clay_ElementId& id, const std::function<bool()>& isTicked, const std::function<void()>& onClick) {
this->isTicked = isTicked;
this->onClick = onClick;
CLAY_AUTO_ID({
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(15), .height = CLAY_SIZING_FIXED(15)}
},

View file

@ -11,7 +11,7 @@ class CheckBox : public Element {
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;
virtual bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override;
void layout(const std::function<bool()>& isTicked, const std::function<void()>& onClick);
void layout(const Clay_ElementId& id, const std::function<bool()>& isTicked, const std::function<void()>& onClick);
private:
static constexpr float CHECKBOX_ANIMATION_TIME = 0.3;
bool isHovering = false;

View file

@ -61,7 +61,7 @@ namespace ColorPickerShaders {
template <typename T> class ColorPicker : public Element {
public:
ColorPicker(GUIManager& gui);
void layout(T* data, bool selectAlpha, const std::function<void()>& onChange);
void layout(const Clay_ElementId& id, T* data, bool selectAlpha, const std::function<void()>& onChange);
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA);
bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;
bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override;

View file

@ -6,13 +6,13 @@ namespace GUIStuff {
template <typename T> ColorPicker<T>::ColorPicker(GUIManager& gui): Element(gui) {}
template <typename T> void ColorPicker<T>::layout(T* data, bool selectAlpha, const std::function<void()>& onChange) {
template <typename T> void ColorPicker<T>::layout(const Clay_ElementId& id, T* data, bool selectAlpha, const std::function<void()>& onChange) {
this->data = data;
savedHsv = rgb_to_hsv<Vector3f, T>(*data);
this->selectAlpha = selectAlpha;
this->onChange = onChange;
CLAY_AUTO_ID({
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) }
},

View file

@ -11,7 +11,7 @@ struct ColorPickerButtonData {
template <typename T> class ColorPickerButton : public Element {
public:
ColorPickerButton(GUIManager& gui);
void layout(T* val, const ColorPickerButtonData& d);
void layout(const Clay_ElementId& id, T* val, const ColorPickerButtonData& d);
private:
ColorPickerButtonData data;
bool isOpen = false;

View file

@ -7,7 +7,7 @@ namespace GUIStuff {
template <typename T> ColorPickerButton<T>::ColorPickerButton(GUIManager& gui): Element(gui) {}
template <typename T> void ColorPickerButton<T>::layout(T* val, const ColorPickerButtonData& d) {
template <typename T> void ColorPickerButton<T>::layout(const Clay_ElementId& id, T* val, const ColorPickerButtonData& d) {
this->data = d;
GUIStuff::ElementHelpers::color_button(gui, "Color Picker Button", val, {

View file

@ -6,8 +6,12 @@ sk_sp<SkRuntimeEffect> ColorRectangleDisplay::alphaBackgroundEffect;
ColorRectangleDisplay::ColorRectangleDisplay(GUIManager& gui): Element(gui) {}
void ColorRectangleDisplay::layout(const std::function<SkColor4f()>& colorFunc) {
void ColorRectangleDisplay::layout(const Clay_ElementId& id, const std::function<SkColor4f()>& colorFunc) {
this->colorFunc = colorFunc;
CLAY(id, {
.layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}},
.custom = {this}
}) {}
}
void ColorRectangleDisplay::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {

View file

@ -7,7 +7,7 @@ namespace GUIStuff {
class ColorRectangleDisplay : public Element {
public:
ColorRectangleDisplay(GUIManager& gui);
void layout(const std::function<SkColor4f()>& colorFunc);
void layout(const Clay_ElementId& id, const std::function<SkColor4f()>& colorFunc);
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
private:
static constexpr const char* alphaBackgroundSksl =

View file

@ -17,7 +17,7 @@ struct DropdownOptions {
template <typename T> class DropDown : public Element {
public:
DropDown(GUIManager& gui): Element(gui) {}
void layout(T* data, const std::vector<std::string>& selections, const DropdownOptions& options = {}) {
void layout(const Clay_ElementId& id, T* data, const std::vector<std::string>& selections, const DropdownOptions& options = {}) {
opts = options;
ElementHelpers::left_to_right_layout(gui, CLAY_SIZING_FIXED(opts.width), CLAY_SIZING_FIT(0), [&] {
gui.element<SelectableButton>("dropdown", SelectableButton::Data{
@ -84,8 +84,8 @@ template <typename T> class DropDown : public Element {
.clipHorizontal = true,
.elementContent = [&](size_t i) {
bool selectedEntry = static_cast<size_t>(*data) == i;
gui.element<LayoutElement>("elem", [&] {
CLAY_AUTO_ID({
gui.element<LayoutElement>("elem", [&] (const Clay_ElementId& lId) {
CLAY(lId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(250), .height = CLAY_SIZING_FIXED(18)},
.padding = CLAY_PADDING_ALL(0),

View file

@ -13,12 +13,11 @@ namespace GUIStuff {
void Element::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {}
void Element::update_bounding_box(Clay_RenderCommand* command) {
boundingBox = get_bb_from_command(command);
}
void Element::clear_bounding_box() {
boundingBox = std::nullopt;
void Element::set_bounding_box_from_elem_data(const Clay_ElementData& elemData) {
if(elemData.found)
boundingBox = {{elemData.boundingBox.x, elemData.boundingBox.y}, {elemData.boundingBox.x + elemData.boundingBox.width, elemData.boundingBox.y + elemData.boundingBox.height}};
else
boundingBox = std::nullopt;
}
const std::optional<SCollision::AABB<float>>& Element::get_bb() const {

View file

@ -11,8 +11,7 @@ namespace GUIStuff {
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA);
virtual bool collides_with_point(const Vector2f& p) const;
void update_bounding_box(Clay_RenderCommand* command);
void clear_bounding_box();
void set_bounding_box_from_elem_data(const Clay_ElementData& elemData);
const std::optional<SCollision::AABB<float>>& get_bb() const;
virtual ~Element() = default;

View file

@ -12,7 +12,7 @@ namespace GUIStuff {
FontPicker::FontPicker(GUIManager& gui): Element(gui) {}
void FontPicker::layout(const Data& data) {
void FontPicker::layout(const Clay_ElementId& id, const Data& data) {
d = data;
//auto& io = *gui.io;

View file

@ -10,7 +10,7 @@ class FontPicker : public Element {
std::function<void()> onFontChange;
};
FontPicker(GUIManager& gui);
void layout(const Data& data);
void layout(const Clay_ElementId& id, const Data& data);
private:
Data d;

View file

@ -14,6 +14,7 @@
#include <nlohmann/json.hpp>
#include "../../RichText/TextBox.hpp"
#include "../../InputManager.hpp"
#include "../GUIManagerID.hpp"
using namespace Eigen;
@ -37,6 +38,18 @@ template <size_t S> class StringArena {
Clay_String std_str_to_clay_str(std::string_view str) {
return Clay_String{.length = static_cast<int32_t>(str.size()), .chars = insert_string_into_arena(str)};
}
Clay_ElementId elem_id_from_id_stack(const GUIManagerIDStack& idStack) {
std::string strToAdd;
for(const GUIManagerID& id : idStack) {
if(id.idIsStr)
strToAdd += reinterpret_cast<const char*>(id.idNum);
else
strToAdd += std::to_string(id.idNum);
strToAdd += '~';
}
Clay_String strForId = std_str_to_clay_str(strToAdd);
return CLAY_SID(strForId);
}
private:
std::array<char, S> stringArena;
size_t stringArenaIndex;

View file

@ -1,12 +1,13 @@
#include "LayoutElement.hpp"
#include "Helpers/ConvertVec.hpp"
namespace GUIStuff {
LayoutElement::LayoutElement(GUIManager& gui): Element(gui) {}
void LayoutElement::layout(const std::function<void()>& layout, const Callbacks& c) {
void LayoutElement::layout(const Clay_ElementId& id, const std::function<void(const Clay_ElementId&)>& layout, const Callbacks& c) {
this->c = c;
layout();
layout(id);
}
bool LayoutElement::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) {

View file

@ -12,7 +12,7 @@ class LayoutElement : public Element {
std::function<bool(const InputManager::MouseWheelCallbackArgs& wheel, bool mouseHovering)> mouseWheel;
std::function<void(const InputManager::KeyCallbackArgs& key)> key;
};
void layout(const std::function<void()>& layout, const Callbacks& c = {});
void layout(const Clay_ElementId& id, const std::function<void(const Clay_ElementId&)>& layout, const Callbacks& c = {});
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;
virtual bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override;
virtual bool input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel, bool mouseHovering) override;

View file

@ -7,7 +7,7 @@ namespace GUIStuff {
MovableTabList::MovableTabList(GUIManager& gui): Element(gui) {}
void MovableTabList::layout(const Data& d) {
void MovableTabList::layout(const Clay_ElementId& id, const Data& d) {
//CLAY_AUTO_ID({.layout = {
// .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(GUIStuff::GUIManager::BIG_BUTTON_SIZE)},
// .padding = CLAY_PADDING_ALL(0),

View file

@ -15,7 +15,7 @@ class MovableTabList : public Element {
};
MovableTabList(GUIManager& gui);
void layout(const Data& d);
void layout(const Clay_ElementId& id, const Data& d);
};
}

View file

@ -9,13 +9,13 @@ template <typename T> class NumberSlider : public Element {
NumberSlider(GUIManager& gui):
Element(gui) {}
void layout(T* data, T minData, T maxData, const std::function<void()>& onChange) {
void layout(const Clay_ElementId& id, T* data, T minData, T maxData, const std::function<void()>& onChange) {
this->data = data;
this->minData = minData;
this->maxData = maxData;
this->onChange = onChange;
CLAY_AUTO_ID({
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(100), .height = CLAY_SIZING_FIXED(10)}
},
@ -76,23 +76,21 @@ template <typename T> class NumberSlider : public Element {
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override {
isHovering = mouseHovering;
isHeld = isHovering && button.button == InputManager::MouseButton::LEFT && button.down;
update_slider_pos(button.pos);
if(isHeld && boundingBox.has_value())
update_slider_pos(button.pos);
return Element::input_mouse_button_callback(button, mouseHovering);
}
virtual bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override {
update_slider_pos(motion.pos);
return Element::input_mouse_motion_callback(motion, mouseHovering);
}
private:
void update_slider_pos(const Vector2f& p) {
gui.set_post_callback_func([&, p] {
if(isHeld && boundingBox.has_value()) {
float fracPosOnSlider = (p.x() - boundingBox.value().min.x()) / boundingBox.value().width();
*data = static_cast<T>(std::clamp<double>(std::lerp<double>(minData, maxData, fracPosOnSlider), minData, maxData)); // Clamp as double then cast so that unsigned types dont wrap on clamp
onChange();
}
float fracPosOnSlider = (p.x() - boundingBox.value().min.x()) / boundingBox.value().width();
*data = static_cast<T>(std::clamp<double>(std::lerp<double>(minData, maxData, fracPosOnSlider), minData, maxData)); // Clamp as double then cast so that unsigned types dont wrap on clamp
if(onChange) onChange();
});
}

View file

@ -14,10 +14,10 @@ constexpr double ROTATE_BAR_SNAP_DISTRIBUTION = std::numbers::pi * 0.25;
PaintCircleMenu::PaintCircleMenu(GUIManager& gui):
Element(gui) {}
void PaintCircleMenu::layout(const Data& data) {
void PaintCircleMenu::layout(const Clay_ElementId& id, const Data& data) {
d = data;
CLAY_AUTO_ID({
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}
},

View file

@ -13,7 +13,7 @@ class PaintCircleMenu : public Element {
std::function<void()> onRotate;
std::function<void()> onPaletteClick;
};
void layout(const Data& data);
void layout(const Clay_ElementId& id, const Data& data);
virtual bool collides_with_point(const Vector2f& p) const override;
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;

View file

@ -1,11 +1,12 @@
#include "PositionAdjustingPopupMenu.hpp"
#include "../GUIManager.hpp"
#include "Helpers/ConvertVec.hpp"
namespace GUIStuff {
PositionAdjustingPopupMenu::PositionAdjustingPopupMenu(GUIManager& gui): Element(gui) {}
void PositionAdjustingPopupMenu::layout(Vector2f popupPos, const std::function<void()>& innerContent) {
void PositionAdjustingPopupMenu::layout(const Clay_ElementId& id, Vector2f popupPos, const std::function<void()>& innerContent) {
if(layoutElement && layoutElement->get_bb().has_value()) {
auto& bb = layoutElement->get_bb().value();
if((popupPos.y() + bb.height()) > gui.io.windowSize.y())
@ -14,8 +15,8 @@ void PositionAdjustingPopupMenu::layout(Vector2f popupPos, const std::function<v
popupPos.x() -= bb.width();
}
layoutElement = gui.element<LayoutElement>("popup", [&]{
CLAY_AUTO_ID({
layoutElement = gui.element<LayoutElement>("popup", [&] (const Clay_ElementId& lId) {
CLAY(lId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(100), .height = CLAY_SIZING_FIT(0)},
.padding = CLAY_PADDING_ALL(gui.io.theme->padding1),

View file

@ -7,7 +7,7 @@ namespace GUIStuff {
class PositionAdjustingPopupMenu : public Element {
public:
PositionAdjustingPopupMenu(GUIManager& gui);
void layout(Vector2f popupPos, const std::function<void()>& innerContent);
void layout(const Clay_ElementId& id, Vector2f popupPos, const std::function<void()>& innerContent);
private:
LayoutElement* layoutElement = nullptr;
};

View file

@ -6,11 +6,11 @@ namespace GUIStuff {
RadioButton::RadioButton(GUIManager& gui):
Element(gui) {}
void RadioButton::layout(const std::function<bool()>& isTicked, const std::function<void()>& onClick) {
void RadioButton::layout(const Clay_ElementId& id, const std::function<bool()>& isTicked, const std::function<void()>& onClick) {
this->onClick = onClick;
this->isTicked = isTicked;
CLAY_AUTO_ID({
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(20), .height = CLAY_SIZING_FIXED(20)}
},

View file

@ -10,7 +10,7 @@ class RadioButton : public Element {
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;
virtual bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override;
void layout(const std::function<bool()>& isTicked, const std::function<void()>& onClick);
void layout(const Clay_ElementId& id, const std::function<bool()>& isTicked, const std::function<void()>& onClick);
private:
static constexpr float RADIOBUTTON_ANIMATION_TIME = 0.3;
bool isHovering = false;

View file

@ -12,11 +12,11 @@ constexpr double ROTATE_BAR_SNAP_DISTRIBUTION = std::numbers::pi * 0.25;
RotateWheel::RotateWheel(GUIManager& gui):
Element(gui) {}
void RotateWheel::layout(double* rotateAngle, const std::function<void()>& onChange) {
void RotateWheel::layout(const Clay_ElementId& id, double* rotateAngle, const std::function<void()>& onChange) {
this->rotateAngle = rotateAngle;
this->onChange = onChange;
CLAY_AUTO_ID({
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}
},

View file

@ -6,7 +6,7 @@ namespace GUIStuff {
class RotateWheel : public Element {
public:
RotateWheel(GUIManager& gui);
void layout(double* rotateAngle, const std::function<void()>& onChange);
void layout(const Clay_ElementId& id, double* rotateAngle, const std::function<void()>& onChange);
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;
virtual bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override;

View file

@ -10,7 +10,7 @@ namespace GUIStuff {
SVGIcon::SVGIcon(GUIManager& gui):
Element(gui) {}
void SVGIcon::layout(const std::string& newSvgPath, bool newIsHighlighted) {
void SVGIcon::layout(const Clay_ElementId& id, const std::string& newSvgPath, bool newIsHighlighted) {
auto& io = gui.io;
auto findSVGData = io.svgData.find(newSvgPath);
if(findSVGData == io.svgData.end())
@ -20,7 +20,7 @@ void SVGIcon::layout(const std::string& newSvgPath, bool newIsHighlighted) {
highlighted = newIsHighlighted;
CLAY_AUTO_ID({
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) }
},

View file

@ -6,7 +6,7 @@ namespace GUIStuff {
class SVGIcon : public Element {
public:
SVGIcon(GUIManager& gui);
void layout(const std::string& newSvgPath, bool newIsHighlighted);
void layout(const Clay_ElementId& id, const std::string& newSvgPath, bool newIsHighlighted);
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
private:
bool highlighted;

View file

@ -5,9 +5,9 @@ namespace GUIStuff {
ScrollArea::ScrollArea(GUIManager& gui): Element(gui) {}
void ScrollArea::layout(const Options& options) {
void ScrollArea::layout(const Clay_ElementId& id, const Options& options) {
opts = options;
CLAY_AUTO_ID({
CLAY(id, {
.layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}}
}) {
Clay_ElementId localID = CLAY_ID_LOCAL("SCROLL_AREA");

View file

@ -25,7 +25,7 @@ class ScrollArea : public Element {
std::function<void(const InnerContentParameters&)> innerContent;
};
void layout(const Options& options);
void layout(const Clay_ElementId& id, const Options& options);
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;
virtual bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override;

View file

@ -7,7 +7,7 @@ namespace GUIStuff {
SelectableButton::SelectableButton(GUIManager& gui):
Element(gui) {}
void SelectableButton::layout(const Data& d) {
void SelectableButton::layout(const Clay_ElementId& id, const Data& d) {
auto& io = gui.io;
SkColor4f borderColor;
@ -37,7 +37,7 @@ void SelectableButton::layout(const Data& d) {
else
backgroundColor = io.theme->fillColor2;
CLAY_AUTO_ID({.layout = {
CLAY(id, {.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
.childGap = 0,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }

View file

@ -26,7 +26,7 @@ class SelectableButton : public Element {
};
SelectableButton(GUIManager& gui);
void layout(const Data& d);
void layout(const Clay_ElementId& id, const Data& d);
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;
virtual bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override;

View file

@ -24,7 +24,7 @@ template <typename T> class TextBox : public Element {
public:
TextBox(GUIManager& gui);
void layout(const TextBoxData<T>& userInfo);
void layout(const Clay_ElementId& id, const TextBoxData<T>& userInfo);
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;
virtual bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override;

View file

@ -5,11 +5,11 @@ namespace GUIStuff {
template <typename T> TextBox<T>::TextBox(GUIManager& gui): Element(gui) {}
template <typename T> void TextBox<T>::layout(const TextBoxData<T>& userInfo) {
template <typename T> void TextBox<T>::layout(const Clay_ElementId& id, const TextBoxData<T>& userInfo) {
auto& io = gui.io;
this->userInfo = userInfo;
init_textbox(io);
CLAY_AUTO_ID({
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(static_cast<float>(io.fontSize * 2)), .height = CLAY_SIZING_FIXED(static_cast<float>(io.fontSize * 1.25f))}
},

View file

@ -7,10 +7,10 @@ namespace GUIStuff {
TextParagraph::TextParagraph(GUIManager& gui):
Element(gui) {}
void TextParagraph::layout(std::unique_ptr<skia::textlayout::Paragraph> paragraph, float width) {
void TextParagraph::layout(const Clay_ElementId& id, std::unique_ptr<skia::textlayout::Paragraph> paragraph, float width) {
data = std::move(paragraph);
data->layout(width);
CLAY_AUTO_ID({
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(width), .height = CLAY_SIZING_FIXED(data->getHeight())}
},

View file

@ -7,7 +7,7 @@ namespace GUIStuff {
class TextParagraph : public Element {
public:
TextParagraph(GUIManager& gui);
void layout(std::unique_ptr<skia::textlayout::Paragraph> paragraph, float width);
void layout(const Clay_ElementId& id, std::unique_ptr<skia::textlayout::Paragraph> paragraph, float width);
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
private:
std::unique_ptr<skia::textlayout::Paragraph> data;

View file

@ -12,7 +12,7 @@ namespace GUIStuff {
TreeListing::TreeListing(GUIManager& gui):
Element(gui) {}
void TreeListing::layout(NetworkingObjects::NetObjID rootObjID, const DisplayData& displayData, SelectionData& selectionData) {
void TreeListing::layout(const Clay_ElementId& id, NetworkingObjects::NetObjID rootObjID, const DisplayData& displayData, SelectionData& selectionData) {
//auto& io = *gui.io;
//if(!io.mouse.leftHeld)

View file

@ -41,7 +41,7 @@ class TreeListing : public Element {
};
TreeListing(GUIManager& gui);
void layout(NetworkingObjects::NetObjID rootObjID, const DisplayData& displayData, SelectionData& selectionData);
void layout(const Clay_ElementId& id, NetworkingObjects::NetObjID rootObjID, const DisplayData& displayData, SelectionData& selectionData);
virtual bool input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) override;
virtual bool input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) override;
virtual void input_key_callback(const InputManager::KeyCallbackArgs& key) override;

View file

@ -256,6 +256,8 @@ void GUIManager::layout_begin() {
strArena.reset();
orderedElements.clear();
Clay_BeginLayout();
}
@ -266,19 +268,9 @@ void GUIManager::layout_end() {
std::erase_if(elements, [](auto& p) {
return !p.second.isUsedThisFrame;
});
update_element_bounding_boxes();
}
void GUIManager::update_element_bounding_boxes() {
for(auto& e : elements)
e.second.elem->clear_bounding_box();
for(size_t i = 0; i < static_cast<size_t>(renderCommands.length); i++) {
Clay_RenderCommand* command = Clay_RenderCommandArray_Get(&renderCommands, i);
if(command->commandType == CLAY_RENDER_COMMAND_TYPE_CUSTOM) {
Element* customElement = static_cast<Element*>(command->renderData.custom.customData);
customElement->update_bounding_box(command);
}
}
std::stable_sort(orderedElements.begin(), orderedElements.end(), [](ElementContainer* a, ElementContainer* b) {
return b->elem->zIndex < a->elem->zIndex; // Order from highest to lowest zIndex
});
}
void GUIManager::single_layout_run() {
@ -319,4 +311,51 @@ void GUIManager::set_post_callback_func(const std::function<void()>& f) {
postCallbackFunc = f;
}
void GUIManager::run_post_callback_func() {
if(postCallbackFunc) {
postCallbackFunc();
postCallbackFunc = nullptr;
}
}
bool GUIManager::cursor_obstructed() const {
return cursorObstructed;
}
void GUIManager::input_key_callback(const InputManager::KeyCallbackArgs& key) {
for(ElementContainer* e : orderedElements)
e->elem->input_key_callback(key);
run_post_callback_func();
}
void GUIManager::input_mouse_button_callback(InputManager::MouseButtonCallbackArgs button) {
button.pos *= io.guiScaleMultiplier;
mouse_callback(button.pos, [&button] (ElementContainer* e, bool mouseHovering) { e->elem->input_mouse_button_callback(button, mouseHovering); });
}
void GUIManager::input_mouse_motion_callback(InputManager::MouseMotionCallbackArgs motion) {
motion.pos *= io.guiScaleMultiplier;
mouse_callback(motion.pos, [&motion] (ElementContainer* e, bool mouseHovering) { e->elem->input_mouse_motion_callback(motion, mouseHovering); });
}
void GUIManager::input_mouse_wheel_callback(InputManager::MouseWheelCallbackArgs wheel) {
wheel.mousePos *= io.guiScaleMultiplier;
mouse_callback(wheel.mousePos, [&wheel] (ElementContainer* e, bool mouseHovering) { e->elem->input_mouse_wheel_callback(wheel, mouseHovering); });
}
void GUIManager::mouse_callback(const Vector2f& mousePos, const std::function<void(ElementContainer*, bool)>& f) {
cursorObstructed = false;
int16_t zIndexObstructed = 0;
for(ElementContainer* e : orderedElements) {
if((!cursorObstructed || zIndexObstructed == e->elem->zIndex) && e->elem->get_bb().has_value() && SCollision::collide(e->elem->get_bb().value(), mousePos)) {
zIndexObstructed = e->elem->zIndex;
cursorObstructed = true;
f(e, true);
}
else
f(e, false);
}
run_post_callback_func();
}
}

View file

@ -25,38 +25,50 @@ class GUIManager {
UpdateInputData io;
GUIManagerIDStack idStack;
std::unordered_map<GUIManagerIDStack, ElementContainer> elements;
void new_id(const char* id, const std::function<void()>& f);
void new_id(int64_t id, const std::function<void()>& f);
void set_post_callback_func(const std::function<void()>& f);
void run_post_callback_func();
int16_t zIndex = 0;
template <typename ElementType, typename... Args> ElementType* element(const char* id, const Args&... a) {
push_id(id);
ElementType* elem = insert_element<ElementType>();
elem->layout(a...);
Clay_ElementId clayId = strArena.elem_id_from_id_stack(idStack);
elem->set_bounding_box_from_elem_data(Clay_GetElementData(clayId));
elem->layout(clayId, a...);
pop_id();
return elem;
}
DefaultStringArena strArena;
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 update_element_bounding_boxes();
void layout_begin();
void layout_end();
void single_layout_run();
void mouse_callback(const Vector2f& mousePos, const std::function<void(ElementContainer*, bool)>& f);
GUIManagerIDStack idStack;
std::vector<ElementContainer*> orderedElements;
std::unordered_map<GUIManagerIDStack, ElementContainer> elements;
template <typename NewElement> NewElement* insert_element() {
auto [it, inserted] = elements.emplace(idStack, ElementContainer());
auto& container = it->second;
if(inserted)
container = {std::make_unique<NewElement>(*this)};
container.elem->zIndex = zIndex;
orderedElements.emplace_back(&container);
container.isUsedThisFrame = true;
return static_cast<NewElement*>(it->second.elem.get());
}
@ -73,6 +85,7 @@ class GUIManager {
Clay_Arena clayArena;
Clay_RenderCommandArray renderCommands;
bool setToLayout;
bool cursorObstructed;
};
}

View file

@ -349,21 +349,25 @@ void MainProgram::input_key_callback(const InputManager::KeyCallbackArgs& key) {
drawGui = !drawGui;
}
}
g.input_key_callback(key);
if(world)
world->input_key_callback(key);
}
void MainProgram::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
g.input_mouse_button_callback(button);
if(world)
world->input_mouse_button_callback(button);
}
void MainProgram::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
g.input_mouse_motion_callback(motion);
if(world)
world->input_mouse_motion_callback(motion);
}
void MainProgram::input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) {
g.input_mouse_wheel_callback(wheel);
if(world)
world->input_mouse_wheel_callback(wheel);
}

View file

@ -546,8 +546,8 @@ void Toolbar::top_toolbar() {
layer_menu(layerMenuPopUpJustOpen);
}
if(menuPopUpOpen) {
gui.element<LayoutElement>("main menu popup", [&] {
CLAY_AUTO_ID({
gui.element<LayoutElement>("main menu popup", [&] (const Clay_ElementId& id) {
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(100), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io.theme->padding1),
@ -1518,8 +1518,8 @@ void Toolbar::center_obstructing_window_gui(const char* id, Clay_SizingAxis x, C
auto& gui = main.g.gui;
auto& io = gui.io;
gui.element<LayoutElement>(id, [&] {
CLAY_AUTO_ID({
gui.element<LayoutElement>(id, [&] (const Clay_ElementId& id) {
CLAY(id, {
.layout = {
.sizing = {.width = x, .height = y },
.padding = CLAY_PADDING_ALL(io.theme->padding1),
@ -2109,8 +2109,8 @@ void Toolbar::file_picker_gui() {
.elementContent = [&] (size_t i) {
const std::filesystem::path& entry = filePicker.entries[i];
bool selectedEntry = filePicker.currentSelectedPath == entry;
gui.element<LayoutElement>("elem", [&] {
CLAY_AUTO_ID({
gui.element<LayoutElement>("elem", [&] (const Clay_ElementId& lId) {
CLAY(lId, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(entryHeight)},
.childGap = 1,