From 72604542111253a9e2dd20992baf6dba81de9773 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 26 Oct 2025 20:43:26 +0100 Subject: [PATCH] feat: created ceramic element library --- elements.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++ elements.h | 15 +++++++++ resources.cpp | 28 ++++++++++++++++ resources.h | 19 +++++++++++ style.cpp | 62 ++++++++++++++++++++++++++++++++++ style.h | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 301 insertions(+) create mode 100644 elements.cpp create mode 100644 elements.h create mode 100644 resources.cpp create mode 100644 resources.h create mode 100644 style.cpp create mode 100644 style.h diff --git a/elements.cpp b/elements.cpp new file mode 100644 index 0000000..4650361 --- /dev/null +++ b/elements.cpp @@ -0,0 +1,84 @@ +#include "elements.h" +#include "style.h" +#include "resources.h" + +namespace cera { +void TextButton(Clay_String text, Clay_Color color, OnHoveredFn onHovered, intptr_t onHoveredData) { + Clay_Color hovered{ cera::ToHoveredColor(color) }; + CLAY_AUTO_ID({ + .layout = { + .padding = cera::buttonPadding, + .childAlignment = { CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER }, + }, + .backgroundColor = Clay_Hovered() + ? hovered + : color, + .cornerRadius = cera::buttonRadii, + .border = { + cera::ToHoveredColor(Clay_Hovered() ? hovered : color), + CLAY_BORDER_ALL(2) + }, + }) { + Clay_OnHover(onHovered, onHoveredData); + cera::Body(text, { + .textColor = cera::textColor, + .textAlignment = CLAY_TEXT_ALIGN_CENTER, + }); + } +} + +void ToggleHovered(Clay_ElementId element, Clay_PointerData pointer, intptr_t data) { + bool *hovered{ (bool*)data }; + if (pointer.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { + *hovered = !(*hovered); + } +} + + +void Toggle(Clay_String label, Clay_Color selected, bool &state) { + CLAY_AUTO_ID({ + .layout = { + .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, + .childGap = 10, + .childAlignment = { CLAY_ALIGN_X_LEFT, CLAY_ALIGN_Y_CENTER }, + }, + }) { + Clay_Color color{Clay_Hovered() + ? cera::ToHoveredColor(selected) + : selected + }; + Clay_OnHover(&ToggleHovered, (intptr_t)(&state)); + CLAY_AUTO_ID({ + .layout = { + .sizing = { + CLAY_SIZING_FIXED(20), CLAY_SIZING_FIXED(20) + } + }, + .backgroundColor = (state + ? selected + : cera::color::transparent + ), + .cornerRadius = cera::buttonRadii, + .border = { + color, + CLAY_BORDER_OUTSIDE(3) + }, + }) { } + Body(label, { + .textColor = cera::textColor + }); + } +} + +void Body(Clay_String string, Clay_TextElementConfig baseCfg) { + baseCfg.fontId = cera::FONT_DEFAULT; + baseCfg.fontSize = cera::baseFontSize; + CLAY_TEXT(string, CLAY_TEXT_CONFIG(baseCfg)); +} + +void Header(Clay_String string, size_t header, Clay_TextElementConfig baseCfg) { + baseCfg.fontId = cera::FONT_BOLD; + baseCfg.fontSize = cera::headerSizes[(header)-1]; + CLAY_TEXT(string, CLAY_TEXT_CONFIG(baseCfg)); +} +} diff --git a/elements.h b/elements.h new file mode 100644 index 0000000..c9a6881 --- /dev/null +++ b/elements.h @@ -0,0 +1,15 @@ +#ifndef ELEMENTS_H +#define ELEMENTS_H + +#include +#include "style.h" + +namespace cera { +typedef void(*OnHoveredFn)(Clay_ElementId element, Clay_PointerData pointer, intptr_t data); +void TextButton(Clay_String text, Clay_Color color, OnHoveredFn onHovered, intptr_t onHoveredData = 0); +void Toggle(Clay_String label, Clay_Color selected, bool &state); +void Body(Clay_String string, Clay_TextElementConfig baseCfg = {.textColor = cera::textColor}); +void Header(Clay_String string, size_t header, Clay_TextElementConfig baseCfg = {.textColor = cera::textColor}); +} + +#endif // !ELEMENTS_H diff --git a/resources.cpp b/resources.cpp new file mode 100644 index 0000000..2798d80 --- /dev/null +++ b/resources.cpp @@ -0,0 +1,28 @@ +#include "resources.h" +#include "style.h" +#include +#include +#include +#include + +namespace cera { +TTF_Font *defaultFont[FONT_MAX]; +TTF_TextEngine *textEngine = nullptr; + +void SetDefaultFont(char const *path) { + defaultFont[FONT_DEFAULT] = TTF_OpenFont(path, cera::baseFontSize * 5); + if (defaultFont[FONT_DEFAULT] == nullptr) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "TTF_OpenFont failed: Failed to load default font '%s': %s", path, SDL_GetError()); + exit(6); + } + TTF_SetFontHinting(defaultFont[FONT_DEFAULT], TTF_HINTING_LIGHT_SUBPIXEL); + defaultFont[FONT_BOLD] = TTF_OpenFont(path, cera::baseFontSize * 5); + if (defaultFont[FONT_BOLD] == nullptr) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "TTF_OpenFont failed: Failed to load default bold font '%s': %s", path, SDL_GetError()); + exit(6); + } + TTF_SetFontHinting(defaultFont[FONT_BOLD], TTF_HINTING_LIGHT_SUBPIXEL); + TTF_SetFontStyle(defaultFont[FONT_BOLD], TTF_STYLE_BOLD); + SDL_Log("SetDefaultFont: Success"); +} +} diff --git a/resources.h b/resources.h new file mode 100644 index 0000000..3adc3cf --- /dev/null +++ b/resources.h @@ -0,0 +1,19 @@ +#ifndef RESOURCES_H +#define RESOURCES_H + +#include + +namespace cera { +enum Font { + FONT_DEFAULT = 0, + FONT_BOLD = 1, + FONT_MAX +}; + +extern TTF_TextEngine *textEngine; +extern TTF_Font *defaultFont[FONT_MAX]; + +void SetDefaultFont(char const *path); +} + +#endif // !RESOURCES_H diff --git a/style.cpp b/style.cpp new file mode 100644 index 0000000..616b284 --- /dev/null +++ b/style.cpp @@ -0,0 +1,62 @@ +#include "style.h" +#include "SDL3/SDL_stdinc.h" +#include "resources.h" +#include + +namespace cera { +Clay_ElementDeclaration ListContainer(Clay_ElementDeclaration baseCfg) { + baseCfg.border = { + .color = panelBorder, + .width = CLAY_BORDER_ALL(2) + }; + baseCfg.cornerRadius = defaultRadiusAll; + return baseCfg; +} + +Clay_ElementDeclaration PanelContainer(Clay_ElementDeclaration baseCfg) { + baseCfg.backgroundColor = panelBackground; + baseCfg.border = { + .color = panelBorder, + .width = CLAY_BORDER_OUTSIDE(2) + }; + baseCfg.cornerRadius = defaultRadiusAll; + baseCfg.layout.padding = CLAY_PADDING_ALL(8); + return baseCfg; +} + +Clay_ElementDeclaration LeftPanelContainer(Clay_ElementDeclaration baseCfg) { + baseCfg = PanelContainer(baseCfg); + baseCfg.border.width = { 0, 2, 2, 2, 0 }; + baseCfg.cornerRadius = { 0, defaultRadius, 0, defaultRadius }; + baseCfg.layout.sizing.height = CLAY_SIZING_GROW(); + return baseCfg; +} + +Clay_ElementDeclaration RightPanelContainer(Clay_ElementDeclaration baseCfg) { + baseCfg = PanelContainer(baseCfg); + baseCfg.border.width = { 2, 0, 2, 2, 0 }; + baseCfg.cornerRadius = { defaultRadius, 0, defaultRadius, 0 }; + baseCfg.layout.sizing.height = CLAY_SIZING_GROW(); + return baseCfg; +} + +Clay_ElementDeclaration Window() { + return { + .layout = { + .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, + .padding = CLAY_PADDING_ALL(windowPadding), + .childGap = 0, + .layoutDirection = CLAY_LEFT_TO_RIGHT + }, + .backgroundColor = windowColor + }; +} + +Clay_Color ToHoveredColor(Clay_Color color) { + float avg = (color.r + color.g + color.b) / 3.f; + color.r = SDL_clamp((color.r - avg) * 0.8f + avg - 30, 0., 1.); + color.g = SDL_clamp((color.g - avg) * 0.8f + avg - 30, 0., 1.); + color.b = SDL_clamp((color.b - avg) * 0.8f + avg - 30, 0., 1.); + return color; +} +} diff --git a/style.h b/style.h new file mode 100644 index 0000000..409396b --- /dev/null +++ b/style.h @@ -0,0 +1,93 @@ +#ifndef STYLE_H +#define STYLE_H + +#include +#include + +namespace cera { +//////////////////////////////////// +// WINDOW STYLE +//////////////////////////////////// + +constexpr uint16_t windowPadding{1}; +constexpr Clay_Color windowColor{20, 20, 20, 255}; + +//////////////////////////////////// +// CONTAINER STYLE +//////////////////////////////////// + +constexpr uint16_t containerGap{10}; +constexpr double defaultRadius{5.0}; + +constexpr Clay_Color panelBackground{ 0,0,0,0 }; +constexpr Clay_Color panelBorder { 150, 150, 150, 150 }; + +constexpr Clay_Padding panelPadding = { + 24, 24, + 24, 24, +}; + +Clay_ElementDeclaration ListContainer(Clay_ElementDeclaration baseCfg = {}); +Clay_ElementDeclaration PanelContainer(Clay_ElementDeclaration baseCfg = {}); +Clay_ElementDeclaration LeftPanelContainer(Clay_ElementDeclaration baseCfg = {}); +Clay_ElementDeclaration RightPanelContainer(Clay_ElementDeclaration baseCfg = {}); +Clay_ElementDeclaration Window(); + +//////////////////////////////////// +// TEXT STYLE +//////////////////////////////////// + +constexpr float paragraphGap = 10; +constexpr uint16_t baseFontSize = 16; + +constexpr uint16_t headerSizes[] = {64, 32, 28, 16}; + +constexpr Clay_Color textColor{170, 170, 170, 255}; + +//////////////////////////////////// +// BUTTONS +//////////////////////////////////// + +constexpr Clay_Color warningButton = { + 177, 56, 52, 255 +}; +constexpr Clay_Color proceedButton = { + 49, 181, 99, 255 +}; +constexpr Clay_Color actionButton = { + 49, 142, 181, 255 +}; + +constexpr Clay_Padding buttonPadding = { + 24, 24, + 4, 4, +}; +constexpr Clay_CornerRadius buttonRadii = { + 3, 3, 3, 3 +}; + +Clay_Color ToHoveredColor(Clay_Color color); + +//////////////////////////////////// +// COMPILATIONS +// | Functions and expressions that combine styling data from the settings above. +//////////////////////////////////// + +constexpr Clay_Sizing layoutExpand = { + .width = CLAY_SIZING_GROW(0), + .height = CLAY_SIZING_GROW(0) +}; + +constexpr Clay_CornerRadius defaultRadiusAll = { + defaultRadius, defaultRadius, + defaultRadius, defaultRadius +}; + +namespace color { +constexpr Clay_Color transparent{ 255, 255, 255, 0 }; +constexpr Clay_Color black{ 0, 0, 0, 255 }; +constexpr Clay_Color white{ 255, 255, 255, 255 }; +} +} + +#endif // !STYLE_H