From 511b30ffd31ea150bdbaa5cc09593fc01d9154c5 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 18 Aug 2026 10:56:07 +0200 Subject: [PATCH 1/2] Avoid redundant strlen --- src/backends/sdl2_renderer.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/backends/sdl2_renderer.cpp b/src/backends/sdl2_renderer.cpp index 7de6f7a..977ef51 100644 --- a/src/backends/sdl2_renderer.cpp +++ b/src/backends/sdl2_renderer.cpp @@ -238,26 +238,27 @@ ret_code Renderer::drawText(Context &ctx, const char *string, Font *font, const ctx.mLogger(LogSeverity::Error, msg.c_str()); return ErrorCode; } - + + const size_t stringLen = strlen(string); int32_t margin{ctx.mStyle.mMargin}; SDL_Rect Message_rect{}; switch (alignment) { case Alignment::Left: Message_rect.x = r.top.x + margin; Message_rect.y = r.top.y + margin; - Message_rect.w = font->mSize*static_cast(strlen(string)); + Message_rect.w = font->mSize*static_cast(stringLen); Message_rect.h = font->mSize + margin*2; break; case Alignment::Center: Message_rect.x = r.top.x + 2 * margin + surfaceMessage->clip_rect.w / 2; Message_rect.y = r.top.y + margin; - Message_rect.w = font->mSize * static_cast(strlen(string)); + Message_rect.w = font->mSize * static_cast(stringLen); Message_rect.h = font->mSize + margin * 2; break; case Alignment::Right: - Message_rect.x = r.top.x + surfaceMessage->clip_rect.w - static_cast(font->mSize) * static_cast(strlen(string)); + Message_rect.x = r.top.x + surfaceMessage->clip_rect.w - static_cast(font->mSize) * static_cast(stringLen); Message_rect.y = r.top.y + margin; - Message_rect.w = font->mSize * static_cast(strlen(string)); + Message_rect.w = font->mSize * static_cast(stringLen); Message_rect.h = font->mSize + margin * 2; break; case Alignment::Invalid: From 360e5b386818b8c4109b4f98f56829bd1c6da719 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 18 Aug 2026 11:16:01 +0200 Subject: [PATCH 2/2] Fix review finding --- README.md | 13 +- contrib/vcpkg | 2 +- src/backends/sdl2_renderer.cpp | 4 +- src/backends/sdl2_renderer.h | 2 +- src/tinyui.h | 6 + src/widgets.cpp | 220 +++++++++++++++++---------------- 6 files changed, 129 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index 76632bd..6f4bbc1 100644 --- a/README.md +++ b/README.md @@ -94,13 +94,12 @@ results to ## Planned -- Datagrid -- Groups -- Tabs -- Togglebuttons -- Layouter -- Engine Integration -- Tutorials +1. Layouter +2. Copy & Paste +2. Groups +3. Tabs +4. Engine Integration examples +5. Tutorials --- diff --git a/contrib/vcpkg b/contrib/vcpkg index f1fe3ac..594ad88 160000 --- a/contrib/vcpkg +++ b/contrib/vcpkg @@ -1 +1 @@ -Subproject commit f1fe3acb62b7aba476e48e3395c40d88478ac444 +Subproject commit 594ad8871e1e8e45f8e626c015fd611163430207 diff --git a/src/backends/sdl2_renderer.cpp b/src/backends/sdl2_renderer.cpp index 977ef51..c8c189e 100644 --- a/src/backends/sdl2_renderer.cpp +++ b/src/backends/sdl2_renderer.cpp @@ -201,7 +201,7 @@ ret_code Renderer::releaseRenderer(Context &ctx) { return ResultOk; } -ret_code Renderer::drawText(Context &ctx, const char *string, Font *font, const Rect &r, const Color4 &fgC, +ret_code Renderer::drawText(Context &ctx, const char *string, size_t maxLen, Font *font, const Rect &r, const Color4 &fgC, const Color4 &bgC, Alignment alignment) { if (string == nullptr) { return InvalidHandle; @@ -239,7 +239,7 @@ ret_code Renderer::drawText(Context &ctx, const char *string, Font *font, const return ErrorCode; } - const size_t stringLen = strlen(string); + const size_t stringLen = strnlen(string, maxLen); int32_t margin{ctx.mStyle.mMargin}; SDL_Rect Message_rect{}; switch (alignment) { diff --git a/src/backends/sdl2_renderer.h b/src/backends/sdl2_renderer.h index 29d9f34..2e01c1c 100644 --- a/src/backends/sdl2_renderer.h +++ b/src/backends/sdl2_renderer.h @@ -113,7 +113,7 @@ struct Renderer { static ret_code initScreen(Context &ctx, int32_t x, int32_t y, int32_t w, int32_t h); static ret_code initScreen(Context &ctx, SDL_Window *mWindow, SDL_Renderer *mRenderer); static ret_code releaseScreen(Context &ctx); - static ret_code drawText(Context &ctx, const char *string, Font *font, const Rect &r, const Color4 &fgC, const Color4 &bgC, Alignment alignment); + static ret_code drawText(Context &ctx, const char *string, size_t maxLen, Font *font, const Rect &r, const Color4 &fgC, const Color4 &bgC, Alignment alignment); static ret_code drawRect(Context &ctx, int32_t x, int32_t y, int32_t w, int32_t h, bool filled, Color4 fg); static ret_code drawImage(Context &ctx, int32_t x, int32_t y, int32_t w, int32_t h, Image *image); static ret_code beginRender(Context &ctx, Color4 bg, SDL_Texture *renderTarget = nullptr); diff --git a/src/tinyui.h b/src/tinyui.h index 421fc80..d21ef72 100644 --- a/src/tinyui.h +++ b/src/tinyui.h @@ -569,4 +569,10 @@ inline void clamp(T min, T max, T &value) { } } +#ifdef TINYUI_TRACE_ENABLED +# define TINYUI_TRACE(...) tinyui::TinyUi::getContext().mLogger(tinyui::LogSeverity::Trace, __VA_ARGS__) +#else +# define TINYUI_TRACE(...) +#endif TINYUI_TRACE_ENABLED + } // Namespace TinyUi diff --git a/src/widgets.cpp b/src/widgets.cpp index 41f463a..3f15672 100644 --- a/src/widgets.cpp +++ b/src/widgets.cpp @@ -38,142 +38,148 @@ namespace tinyui { static constexpr Id RootHandle = 1; namespace { -Id createHandle() { - static Id id{ RootHandle }; - return ++id; -} -Image *findImage(Context &ctx, const char *filename) { - if (filename == nullptr) { - return nullptr; + Id createHandle() { + static Id id{ RootHandle }; + return ++id; } - auto it = ctx.mImageCache.find(filename); - if (it == ctx.mImageCache.end()) { - return nullptr; - } + Image *findImage(Context &ctx, const char *filename) { + if (filename == nullptr) { + return nullptr; + } - return it->second; -} + auto it = ctx.mImageCache.find(filename); + if (it == ctx.mImageCache.end()) { + return nullptr; + } -Image *loadIntoImageCache(Context &ctx, const char *filename) { - if (filename == nullptr) { - return nullptr; + return it->second; } - Image *image = findImage(ctx, filename); - if (image != nullptr) { - return image; - } + Image *loadIntoImageCache(Context &ctx, const char *filename) { + if (filename == nullptr) { + return nullptr; + } - int w{ -1 }; - int h{ -1 }; - int bytesPerPixel{ -1 }; - unsigned char *data = stbi_load(filename, &w, &h, &bytesPerPixel, 0); - if (data == nullptr) { - return nullptr; - } + Image *image = findImage(ctx, filename); + if (image != nullptr) { + return image; + } - image = new Image; - if (image == nullptr) { - return nullptr; - } + int w{ -1 }; + int h{ -1 }; + int bytesPerPixel{ -1 }; + unsigned char *data = stbi_load(filename, &w, &h, &bytesPerPixel, 0); + if (data == nullptr) { + return nullptr; + } - int32_t pitch = w * bytesPerPixel; - pitch = (pitch + 3) & ~3; - image->mSurfaceImpl = Renderer::createSurfaceImpl(data, w, h, bytesPerPixel, pitch); - image->mX = w; - image->mY = h; - image->mComp = bytesPerPixel; - ctx.mImageCache[filename] = image; + image = new Image; + if (image == nullptr) { + return nullptr; + } - return image; -} + int32_t pitch = w * bytesPerPixel; + pitch = (pitch + 3) & ~3; + image->mSurfaceImpl = Renderer::createSurfaceImpl(data, w, h, bytesPerPixel, pitch); + image->mX = w; + image->mY = h; + image->mComp = bytesPerPixel; + ctx.mImageCache[filename] = image; -void releaseImageCache(Context &ctx) { - for (auto it = ctx.mImageCache.begin(); it != ctx.mImageCache.end(); ++it) { - if (Image *image = it->second; image != nullptr) { - Renderer::releaseSurfaceImpl(image->mSurfaceImpl); - delete image; - } + return image; } - ctx.mImageCache.clear(); -} -Widget *getValidRoot(Context &ctx) { - if (ctx.mRoot != nullptr) { - return ctx.mRoot; + void releaseImageCache(Context &ctx) { + for (auto it = ctx.mImageCache.begin(); it != ctx.mImageCache.end(); ++it) { + if (Image *image = it->second; image != nullptr) { + Renderer::releaseSurfaceImpl(image->mSurfaceImpl); + delete image; + } + } + ctx.mImageCache.clear(); } - ctx.mRoot = new Widget; - ctx.mRoot->mType = WidgetType::RootContainer; - ctx.mRoot->mHandle = WidgetHandle::getRootHandle(); + Widget *getValidRoot(Context &ctx) { + if (ctx.mRoot != nullptr) { + return ctx.mRoot; + } - return ctx.mRoot; -} + ctx.mRoot = new Widget; + ctx.mRoot->mType = WidgetType::RootContainer; + ctx.mRoot->mHandle = WidgetHandle::getRootHandle(); -Widget *setParent(Context &ctx, Widget *child, WidgetHandle parentId) { - Widget *parent{ nullptr }; - if (parentId.mId == 0) { - parent = getValidRoot(ctx); - } else { - parent = Widgets::findWidget(parentId, ctx.mRoot); + return ctx.mRoot; } - if (parent == nullptr) { - return nullptr; - } + Widget *setParent(Context &ctx, Widget *child, WidgetHandle parentId) { + Widget *parent{ nullptr }; + if (parentId.mId == 0) { + parent = getValidRoot(ctx); + } else { + parent = Widgets::findWidget(parentId, ctx.mRoot); + } - parent->mChildren.emplace_back(child); - parent->mRect.mergeWithRect(child->mRect); + if (parent == nullptr) { + return nullptr; + } - return parent; -} + parent->mChildren.emplace_back(child); + parent->mRect.mergeWithRect(child->mRect); -Widget *createWidget(Context &ctx, WidgetHandle parentId, const Rect &rect, WidgetType type) { - auto *widget = new Widget; - widget->mHandle = WidgetHandle{ createHandle() }; - widget->mType = type; - widget->mRect = rect; - widget->mParent = setParent(ctx, widget, parentId); - if (widget->mParent == nullptr) { - assert(widget->mParent != nullptr); - delete widget; - widget = nullptr; + return parent; } - return widget; -} + Widget *createWidget(Context &ctx, WidgetHandle parentId, const Rect &rect, WidgetType type) { + auto *widget = new Widget; + widget->mHandle = WidgetHandle{ createHandle() }; + widget->mType = type; + widget->mRect = rect; + widget->mParent = setParent(ctx, widget, parentId); + if (widget->mParent == nullptr) { + assert(widget->mParent != nullptr); + delete widget; + widget = nullptr; + } -void deleteKeyFromText(Context &ctx) { - ctx.mFocus->mText.erase(ctx.mFocus->mText.size() - 1); -} + return widget; + } -void appendKeyToText(Context &ctx, char *buffer) { - if (buffer == nullptr) { - return; + void deleteKeyFromText(Context &ctx) { + ctx.mFocus->mText.erase(ctx.mFocus->mText.size() - 1); } - if (ctx.mFocus->mKeyInputType == KeyInputType::Numeric) { - if (buffer[0] < '0' || buffer[0] > '9') { + void appendKeyToText(Context &ctx, char *buffer) { + if (buffer == nullptr) { + TINYUI_TRACE("appendKeyToText: buffer is nullptr"); + return; + } + if (ctx.mFocus == nullptr) { + TINYUI_TRACE("appendKeyToText: ctx.mFocus is nullptr"); return; } + + if (ctx.mFocus->mKeyInputType == KeyInputType::Numeric) { + if (buffer[0] < '0' || buffer[0] > '9') { + return; + } + } + + ctx.mFocus->mText.append(buffer); } - - ctx.mFocus->mText.append(buffer); -} -void handleInputField(Context &ctx, EventPayload *eventPayload) { - char buffer[2] = { - static_cast(eventPayload->payload[0]), - '\0' - }; - if (buffer[0] == SDLK_BACKSPACE) { - deleteKeyFromText(ctx); - } else { - appendKeyToText(ctx, buffer); + void handleInputField(Context &ctx, EventPayload *eventPayload) { + char buffer[2] = { + static_cast(eventPayload->payload[0]), + '\0' + }; + if (buffer[0] == SDLK_BACKSPACE) { + deleteKeyFromText(ctx); + } else { + appendKeyToText(ctx, buffer); + } } -} } // namespace void eventDispatcher(Context &ctx, int32_t eventId, EventPayload *eventPayload) { @@ -545,7 +551,7 @@ static void render(Context &ctx, const Widget *currentWidget) { if (!currentWidget->mText.empty()) { const Color4 fg = ctx.mStyle.mTextColor; const Color4 bg = ctx.mStyle.mBg; - Renderer::drawText(ctx, currentWidget->mText.c_str(), ctx.mDefaultFont, + Renderer::drawText(ctx, currentWidget->mText.c_str(), currentWidget->mText.length(), ctx.mDefaultFont, currentWidget->mRect, fg, bg, currentWidget->mAlignment); } } @@ -557,7 +563,7 @@ static void render(Context &ctx, const Widget *currentWidget) { if (!currentWidget->mText.empty()) { const Color4 fg = ctx.mStyle.mTextColor; const Color4 bg = ctx.mStyle.mBg; - Renderer::drawText(ctx, currentWidget->mText.c_str(), ctx.mDefaultFont, + Renderer::drawText(ctx, currentWidget->mText.c_str(), currentWidget->mText.length(), ctx.mDefaultFont, currentWidget->mRect, fg, bg, currentWidget->mAlignment); } } @@ -568,7 +574,7 @@ static void render(Context &ctx, const Widget *currentWidget) { if (!currentWidget->mText.empty()) { const Color4 fg = ctx.mStyle.mTextColor; const Color4 bg = ctx.mStyle.mBg; - Renderer::drawText(ctx, currentWidget->mText.c_str(), ctx.mDefaultFont, + Renderer::drawText(ctx, currentWidget->mText.c_str(), currentWidget->mText.length(), ctx.mDefaultFont, currentWidget->mRect, fg, bg, currentWidget->mAlignment); } } @@ -614,7 +620,7 @@ static void render(Context &ctx, const Widget *currentWidget) { const Color4 fg = ctx.mStyle.mTextColor; const Color4 bg = ctx.mStyle.mBg; Rect textRect(checkBoxRect.top.x + checkBoxRect.width + 5, r.top.y, r.width - checkBoxRect.width - 5, r.height); - Renderer::drawText(ctx, currentWidget->mText.c_str(), ctx.mDefaultFont, + Renderer::drawText(ctx, currentWidget->mText.c_str(), currentWidget->mText.length(), ctx.mDefaultFont, textRect, fg, bg, currentWidget->mAlignment); } } @@ -628,7 +634,7 @@ static void render(Context &ctx, const Widget *currentWidget) { if (!currentWidget->mText.empty()) { const Color4 fg = ctx.mStyle.mTextColor; const Color4 bg = ctx.mStyle.mBg; - Renderer::drawText(ctx, currentWidget->mText.c_str(), ctx.mDefaultFont, + Renderer::drawText(ctx, currentWidget->mText.c_str(), currentWidget->mText.length(), ctx.mDefaultFont, currentWidget->mRect, fg, bg, currentWidget->mAlignment); } }