Separate general GUI managing code and global configuration from toolbar UI code

This commit is contained in:
Yousef Khadadeh 2026-03-31 13:17:58 +03:00
parent 2abe7271a8
commit ea35397326
53 changed files with 859 additions and 788 deletions

View file

@ -8,14 +8,14 @@ void top_to_bottom_window_popup_layout(GUIManager& gui, const char* id, Clay_Siz
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = x, .height = y },
.padding = CLAY_PADDING_ALL(gui.io->theme->padding1),
.childGap = gui.io->theme->childGap1,
.padding = CLAY_PADDING_ALL(gui.io.theme->padding1),
.childGap = gui.io.theme->childGap1,
.layoutDirection = CLAY_TOP_TO_BOTTOM
},
.backgroundColor = convert_vec4<Clay_Color>(gui.io->theme->backColor1),
.backgroundColor = convert_vec4<Clay_Color>(gui.io.theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(10),
.floating = { .attachTo = CLAY_ATTACH_TO_PARENT },
.border = {.color = convert_vec4<Clay_Color>(gui.io->theme->fillColor2), .width = CLAY_BORDER_OUTSIDE(1)}
.border = {.color = convert_vec4<Clay_Color>(gui.io.theme->fillColor2), .width = CLAY_BORDER_OUTSIDE(1)}
}) {
innerContent();
}
@ -25,7 +25,7 @@ void top_to_bottom_window_popup_layout(GUIManager& gui, const char* id, Clay_Siz
void left_to_right_layout(GUIManager& gui, Clay_SizingAxis x, Clay_SizingAxis y, const std::function<void()>& innerContent) {
CLAY_AUTO_ID({.layout = {
.sizing = {.width = x, .height = y },
.childGap = gui.io->theme->childGap1,
.childGap = gui.io.theme->childGap1,
.childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER},
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}
@ -41,7 +41,7 @@ void left_to_right_line_layout(GUIManager& gui, const std::function<void()>& inn
void left_to_right_line_centered_layout(GUIManager& gui, const std::function<void()>& innerContent) {
CLAY_AUTO_ID({.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0) },
.childGap = gui.io->theme->childGap1,
.childGap = gui.io.theme->childGap1,
.childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER},
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}

View file

@ -3,19 +3,19 @@
namespace GUIStuff { namespace ElementHelpers {
void text_label_size(GUIManager& gui, std::string_view val, float modifier) {
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io->theme->frontColor1), .fontSize = static_cast<uint16_t>(gui.io->fontSize * modifier)}));
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io.theme->frontColor1), .fontSize = static_cast<uint16_t>(gui.io.fontSize * modifier)}));
}
void text_label_color(GUIManager& gui, std::string_view val, const SkColor4f& color) {
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(color), .fontSize = gui.io->fontSize }));
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(color), .fontSize = gui.io.fontSize }));
}
void text_label_light(GUIManager& gui, std::string_view val) {
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io->theme->frontColor2), .fontSize = gui.io->fontSize }));
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io.theme->frontColor2), .fontSize = gui.io.fontSize }));
}
void text_label(GUIManager& gui, std::string_view val) {
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io->theme->frontColor1), .fontSize = gui.io->fontSize }));
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io.theme->frontColor1), .fontSize = gui.io.fontSize }));
}
void text_label_centered(GUIManager& gui, std::string_view val) {
@ -25,7 +25,7 @@ void text_label_centered(GUIManager& gui, std::string_view val) {
.childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER},
}
}) {
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io->theme->frontColor1), .fontSize = gui.io->fontSize, .textAlignment = CLAY_TEXT_ALIGN_CENTER}));
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io.theme->frontColor1), .fontSize = gui.io.fontSize, .textAlignment = CLAY_TEXT_ALIGN_CENTER}));
}
}
@ -36,7 +36,7 @@ void text_label_light_centered(GUIManager& gui, std::string_view val) {
.childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER},
}
}) {
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io->theme->frontColor2), .fontSize = gui.io->fontSize, .textAlignment = CLAY_TEXT_ALIGN_CENTER}));
CLAY_TEXT(gui.strArena.std_str_to_clay_str(val), CLAY_TEXT_CONFIG({.textColor = convert_vec4<Clay_Color>(gui.io.theme->frontColor2), .fontSize = gui.io.fontSize, .textAlignment = CLAY_TEXT_ALIGN_CENTER}));
}
}

View file

@ -32,7 +32,7 @@ template <typename T> class DropDown : public Element {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) },
.padding = {.left = 4, .right = 4},
.childGap = gui.io->theme->childGap1,
.childGap = gui.io.theme->childGap1,
.childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER},
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}
@ -55,13 +55,13 @@ template <typename T> class DropDown : public Element {
Clay_ElementData dropdownElemData = Clay_GetElementData(localID);
float calculatedDropdownMaxHeight = 0.0f;
if(dropdownElemData.found)
calculatedDropdownMaxHeight = std::max(gui.io->windowSize.y() - dropdownElemData.boundingBox.y - 2.0f, 0.0f);
calculatedDropdownMaxHeight = std::max(gui.io.windowSize.y() - dropdownElemData.boundingBox.y - 2.0f, 0.0f);
CLAY(localID, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(opts.width), .height = CLAY_SIZING_FIT(0, calculatedDropdownMaxHeight)},
.childGap = 0
},
.backgroundColor = convert_vec4<Clay_Color>(gui.io->theme->backColor1),
.backgroundColor = convert_vec4<Clay_Color>(gui.io.theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(4),
.floating = {
.offset = {
@ -74,7 +74,7 @@ template <typename T> class DropDown : public Element {
.attachTo = CLAY_ATTACH_TO_PARENT
},
.border = {
.color = convert_vec4<Clay_Color>(gui.io->theme->fillColor2),
.color = convert_vec4<Clay_Color>(gui.io.theme->fillColor2),
.width = CLAY_BORDER_OUTSIDE(1)
}
}) {
@ -96,11 +96,11 @@ template <typename T> class DropDown : public Element {
}) {
SkColor4f entryColor;
if(selectedEntry)
entryColor = gui.io->theme->backColor2;
entryColor = gui.io.theme->backColor2;
else if(hoveringOver.has_value() && hoveringOver.value() == i)
entryColor = gui.io->theme->backColor2;
entryColor = gui.io.theme->backColor2;
else
entryColor = gui.io->theme->backColor1;
entryColor = gui.io.theme->backColor1;
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},

View file

@ -68,7 +68,7 @@ struct Theme {
std::shared_ptr<Theme> get_default_dark_mode();
struct UpdateInputData {
InputManager* input;
InputManager* input = nullptr;
std::function<void()> layoutRun;
SkFont get_font(float fSize) const;
@ -84,7 +84,6 @@ struct UpdateInputData {
std::shared_ptr<FontData> fonts;
sk_sp<SkTypeface> textTypeface;
DefaultStringArena* strArena;
std::shared_ptr<Theme> theme;
std::unordered_map<std::string, sk_sp<SkSVGDOM>> svgData;
};

View file

@ -8,9 +8,9 @@ PositionAdjustingPopupMenu::PositionAdjustingPopupMenu(GUIManager& gui): Element
void PositionAdjustingPopupMenu::layout(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())
if((popupPos.y() + bb.height()) > gui.io.windowSize.y())
popupPos.y() -= bb.height();
if((popupPos.x() + bb.width()) > gui.io->windowSize.x())
if((popupPos.x() + bb.width()) > gui.io.windowSize.x())
popupPos.x() -= bb.width();
}
@ -18,13 +18,13 @@ void PositionAdjustingPopupMenu::layout(Vector2f popupPos, const std::function<v
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(100), .height = CLAY_SIZING_FIT(0)},
.padding = CLAY_PADDING_ALL(gui.io->theme->padding1),
.padding = CLAY_PADDING_ALL(gui.io.theme->padding1),
.childGap = 1,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP},
.layoutDirection = CLAY_TOP_TO_BOTTOM
},
.backgroundColor = convert_vec4<Clay_Color>(gui.io->theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(gui.io->theme->windowCorners1),
.backgroundColor = convert_vec4<Clay_Color>(gui.io.theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(gui.io.theme->windowCorners1),
.floating = {
.offset = {popupPos.x(), popupPos.y()},
.zIndex = gui.zIndex,

View file

@ -11,7 +11,7 @@ SVGIcon::SVGIcon(GUIManager& gui):
Element(gui) {}
void SVGIcon::layout(const std::string& newSvgPath, bool newIsHighlighted) {
auto& io = *gui.io;
auto& io = gui.io;
auto findSVGData = io.svgData.find(newSvgPath);
if(findSVGData == io.svgData.end())
throw std::runtime_error("[SVGIcon::update] Could not load icon " + newSvgPath);

View file

@ -46,15 +46,15 @@ void ScrollArea::layout(const Options& options) {
// .childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_TOP},
// .layoutDirection = CLAY_TOP_TO_BOTTOM
// },
// .backgroundColor = convert_vec4<Clay_Color>(io->theme->backColor2)
// .backgroundColor = convert_vec4<Clay_Color>(io.theme->backColor2)
// }) {
// SkColor4f scrollerColor;
// if(sD.isMoving)
// scrollerColor = io->theme->fillColor1;
// scrollerColor = io.theme->fillColor1;
// else if(Clay_Hovered())
// scrollerColor = io->theme->fillColor1;
// scrollerColor = io.theme->fillColor1;
// else
// scrollerColor = io->theme->fillColor2;
// scrollerColor = io.theme->fillColor2;
// bool isHoveringOverScroller = false;
// CLAY_AUTO_ID({
@ -71,19 +71,19 @@ void ScrollArea::layout(const Options& options) {
// isHoveringOverScroller = true;
// }
// CLAY_AUTO_ID({ .layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}}}) {}
// if(Clay_Hovered() && io->mouse.leftClick) {
// if(Clay_Hovered() && io.mouse.leftClick) {
// isMoving = true;
// if(isHoveringOverScroller)
// scrollerStartPos = scrollAreaBB.y + areaAboveScrollerSize + scrollerSize * 0.5f;
// else
// scrollerStartPos = std::clamp(io->mouse.pos.y(), scrollAreaBB.y + scrollerSize * 0.5f, scrollAreaBB.y + scrollAreaBB.height - scrollerSize * 0.5f);
// mouseStartPos = io->mouse.pos.y();
// scrollerStartPos = std::clamp(io.mouse.pos.y(), scrollAreaBB.y + scrollerSize * 0.5f, scrollAreaBB.y + scrollAreaBB.height - scrollerSize * 0.5f);
// mouseStartPos = io.mouse.pos.y();
// }
// if(!io->mouse.leftHeld)
// if(!io.mouse.leftHeld)
// isMoving = false;
// if(isMoving) {
// float newScrollPosFrac;
// newScrollPosFrac = std::clamp((scrollerStartPos - (mouseStartPos - io->mouse.pos.y()) - scrollAreaBB.y - scrollerSize * 0.5f) / (scrollAreaBB.height - scrollerSize), 0.0f, 1.0f);
// newScrollPosFrac = std::clamp((scrollerStartPos - (mouseStartPos - io.mouse.pos.y()) - scrollAreaBB.y - scrollerSize * 0.5f) / (scrollAreaBB.height - scrollerSize), 0.0f, 1.0f);
// currentScrollPos = newScrollPosFrac * (-scrollPosMax);
// }
// currentScrollPos = std::clamp(currentScrollPos, -scrollPosMax, 0.0f);

View file

@ -8,7 +8,7 @@ SelectableButton::SelectableButton(GUIManager& gui):
Element(gui) {}
void SelectableButton::layout(const Data& d) {
auto& io = *gui.io;
auto& io = gui.io;
SkColor4f borderColor;
SkColor4f backgroundColorHighlight;

View file

@ -6,7 +6,7 @@ namespace GUIStuff {
template <typename T> TextBox<T>::TextBox(GUIManager& gui): Element(gui) {}
template <typename T> void TextBox<T>::layout(const TextBoxData<T>& userInfo) {
auto& io = *gui.io;
auto& io = gui.io;
this->userInfo = userInfo;
init_textbox(io);
CLAY_AUTO_ID({
@ -59,26 +59,26 @@ template <typename T> void TextBox<T>::clay_draw(SkCanvas* canvas, UpdateInputDa
}
template <typename T> bool TextBox<T>::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button, bool mouseHovering) {
auto& io = *gui.io;
auto& io = gui.io;
if(button.button == InputManager::MouseButton::LEFT && boundingBox.has_value()) {
if(button.down) {
if(mouseHovering) {
*rect = {(boundingBox.value().min + io.windowPos) * io.guiScaleMultiplier, (boundingBox.value().max + io.windowPos) * io.guiScaleMultiplier};
gui.io->input->set_rich_text_box_input_front(textbox, cur, false, rect, userInfo.textInputProps, nullptr);
textbox->process_mouse_left_button(*cur, button.pos - boundingBox.value().min, button.clicks, true, gui.io->input->key(InputManager::KEY_TEXT_SHIFT).held);
gui.io.input->set_rich_text_box_input_front(textbox, cur, false, rect, userInfo.textInputProps, nullptr);
textbox->process_mouse_left_button(*cur, button.pos - boundingBox.value().min, button.clicks, true, gui.io.input->key(InputManager::KEY_TEXT_SHIFT).held);
isSelected = true;
}
else {
gui.io->input->remove_rich_text_box_input(textbox);
gui.io.input->remove_rich_text_box_input(textbox);
if(update_data())
gui.set_post_callback_func(userInfo.onEdit);
init_textbox(*gui.io);
init_textbox(gui.io);
isSelected = false;
}
}
else {
textbox->process_mouse_left_button(*cur, button.pos - boundingBox.value().min, 0, false, gui.io->input->key(InputManager::KEY_TEXT_SHIFT).held);
textbox->process_mouse_left_button(*cur, button.pos - boundingBox.value().min, 0, false, gui.io.input->key(InputManager::KEY_TEXT_SHIFT).held);
}
}
return Element::input_mouse_button_callback(button, mouseHovering);
@ -86,7 +86,7 @@ template <typename T> bool TextBox<T>::input_mouse_button_callback(const InputMa
template <typename T> bool TextBox<T>::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool mouseHovering) {
if(boundingBox.has_value())
textbox->process_mouse_left_button(*cur, motion.pos - boundingBox.value().min, 0, gui.io->input->mouse.leftDown, gui.io->input->key(InputManager::KEY_TEXT_SHIFT).held);
textbox->process_mouse_left_button(*cur, motion.pos - boundingBox.value().min, 0, gui.io.input->mouse.leftDown, gui.io.input->key(InputManager::KEY_TEXT_SHIFT).held);
return Element::input_mouse_motion_callback(motion, mouseHovering);
}
@ -130,7 +130,7 @@ template <typename T> bool TextBox<T>::update_data() {
}
template <typename T> TextBox<T>::~TextBox() {
gui.io->input->remove_rich_text_box_input(textbox);
gui.io.input->remove_rich_text_box_input(textbox);
}
}

View file

@ -45,10 +45,10 @@ Clay_Dimensions GUIManager::clay_skia_measure_text(Clay_StringSlice str, Clay_Te
pStyle.setTextAlign(skia::textlayout::TextAlign::kLeft);
skia::textlayout::TextStyle tStyle;
tStyle.setFontSize(config->fontSize);
tStyle.setFontFamilies(window->io->fonts->get_default_font_families());
tStyle.setFontFamilies(window->io.fonts->get_default_font_families());
pStyle.setTextStyle(tStyle);
skia::textlayout::ParagraphBuilderImpl a(pStyle, window->io->fonts->collection, SkUnicodes::ICU::Make());
skia::textlayout::ParagraphBuilderImpl a(pStyle, window->io.fonts->collection, SkUnicodes::ICU::Make());
a.addText(str.chars, str.length);
std::unique_ptr<skia::textlayout::Paragraph> p = a.Build();
p->layout(std::numeric_limits<float>::max());
@ -58,7 +58,7 @@ Clay_Dimensions GUIManager::clay_skia_measure_text(Clay_StringSlice str, Clay_Te
void GUIManager::draw(SkCanvas* canvas, bool skiaAA) {
canvas->save();
canvas->translate(io->windowPos.x(), io->windowPos.y());
canvas->translate(io.windowPos.x(), io.windowPos.y());
for(size_t i = 0; i < static_cast<size_t>(renderCommands.length); i++) {
Clay_RenderCommand* command = Clay_RenderCommandArray_Get(&renderCommands, i);
@ -94,11 +94,11 @@ void GUIManager::draw(SkCanvas* canvas, bool skiaAA) {
pStyle.setTextAlign(skia::textlayout::TextAlign::kLeft);
skia::textlayout::TextStyle tStyle;
tStyle.setFontSize(config->fontSize);
tStyle.setFontFamilies(io->fonts->get_default_font_families());
tStyle.setFontFamilies(io.fonts->get_default_font_families());
tStyle.setColor(convert_vec4<SkColor4f>(config->textColor).toSkColor());
pStyle.setTextStyle(tStyle);
skia::textlayout::ParagraphBuilderImpl a(pStyle, io->fonts->collection, SkUnicodes::ICU::Make());
skia::textlayout::ParagraphBuilderImpl a(pStyle, io.fonts->collection, SkUnicodes::ICU::Make());
a.addText(config->stringContents.chars, config->stringContents.length);
std::unique_ptr<skia::textlayout::Paragraph> p = a.Build();
p->layout(std::numeric_limits<float>::max());
@ -211,7 +211,7 @@ void GUIManager::draw(SkCanvas* canvas, bool skiaAA) {
}
case CLAY_RENDER_COMMAND_TYPE_CUSTOM: {
Element* customElement = static_cast<Element*>(command->renderData.custom.customData);
customElement->clay_draw(canvas, *io, command, skiaAA);
customElement->clay_draw(canvas, io, command, skiaAA);
break;
}
default:
@ -223,11 +223,11 @@ void GUIManager::draw(SkCanvas* canvas, bool skiaAA) {
}
void GUIManager::update_window(const Vector2f& windowPos, const Vector2f& windowSize, float guiScaleMultiplier) {
if(io->windowPos != windowPos || io->windowSize != windowSize || io->guiScaleMultiplier != guiScaleMultiplier)
if(io.windowPos != windowPos || io.windowSize != windowSize || io.guiScaleMultiplier != guiScaleMultiplier)
set_to_layout();
io->windowPos = windowPos;
io->windowSize = windowSize;
io->guiScaleMultiplier = guiScaleMultiplier;
io.windowPos = windowPos;
io.windowSize = windowSize;
io.guiScaleMultiplier = guiScaleMultiplier;
}
void GUIManager::set_to_layout() {
@ -251,8 +251,7 @@ void GUIManager::layout_begin() {
for(auto& [id, e] : elements)
e.isUsedThisFrame = false;
io->strArena = &strArena;
Clay_SetLayoutDimensions(Clay_Dimensions(io->windowSize.x(), io->windowSize.y()));
Clay_SetLayoutDimensions(Clay_Dimensions(io.windowSize.x(), io.windowSize.y()));
Clay_SetCurrentContext(clayInstance);
strArena.reset();
@ -284,7 +283,7 @@ void GUIManager::update_element_bounding_boxes() {
void GUIManager::single_layout_run() {
layout_begin();
io->layoutRun();
io.layoutRun();
layout_end();
}

View file

@ -23,7 +23,7 @@ class GUIManager {
void update_window(const Vector2f& windowPos, const Vector2f& windowSize, float guiScaleMultiplier);
std::shared_ptr<UpdateInputData> io;
UpdateInputData io;
GUIManagerIDStack idStack;
std::unordered_map<GUIManagerIDStack, ElementContainer> elements;