Skip to content

Conversation

@kimkulling
Copy link
Owner

@kimkulling kimkulling commented Apr 29, 2025

Summary by CodeRabbit

  • New Features

    • Introduced support for text field widgets, allowing users to input and edit text.
    • Added keyboard event handling for text fields, including focus management and key press detection.
  • Improvements

    • Increased the height of the root panel widget for enhanced layout.
    • Added a new text field widget to the main sample interface.
    • Improved error handling by removing direct console error outputs.
  • Removals

    • Removed toolbar widget functionality.
  • Documentation

    • Updated and removed certain internal comments for clarity.
  • Other

    • Updated copyright years in file headers.

@coderabbitai
Copy link

coderabbitai bot commented Apr 29, 2025

Walkthrough

This update introduces several enhancements and refactorings to the UI framework. It adds a new TextField widget type, supporting creation and rendering of text fields and enabling keyboard input handling for focused widgets. The event system is expanded with new key event types and a mechanism to track the currently focused widget. The toolbar widget and its related code are removed. Various code cleanups are performed, including copyright year updates, removal of unused includes, and elimination of some error print statements. Several function signatures are updated to improve event handling and driver querying.

Changes

Files/Group Change Summary
samples/main.cpp Updated copyright year, removed unused include, increased root panel height, added NextPanelId constant, and introduced a new textfield widget.
src/backends/sdl2_iodevice.cpp, src/backends/sdl2_iodevice.h, src/backends/sdl2_renderer.cpp, src/backends/sdl2_renderer.h, src/tinyui.cpp, src/tinyui.h, src/widgets.cpp, src/widgets.h Updated copyright year in file headers.
src/backends/sdl2_iodevice.h, src/backends/sdl2_renderer.h Removed Doxygen-style comments from destructor and method declarations.
src/backends/sdl2_renderer.cpp, src/backends/sdl2_renderer.h Replaced std::string_view with C-string and max length in queryDriver function, updated how driver names are compared and passed.
src/tinyui.cpp Removed error message print statements from certain error conditions.
src/tinyui.h Added KeyDownEvent and KeyUpEvent to Events, shifted UpdateEvent, updated NumEvents, introduced EventData struct, and added mFocus member to Context.
src/widgets.cpp, src/widgets.h Added TextField widget type and creation method, added setFocus method, removed toolbar widget and related code, updated event handling for key events and focus, enabled text input for focused text fields, and enhanced rendering for text fields.
src/widgets.cpp Changed eventDispatcher and onKey method signatures, added null checks and improved error handling in image loading, changed pitch variable to int32_t.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant Context
    participant Widgets
    participant Widget(TextField)

    App->>Widgets: textfield(ctx, id, parentId, rect, alignment)
    Widgets->>Context: Add new TextField widget
    App->>Widgets: setFocus(ctx, id)
    Widgets->>Context: Set mFocus to widget with id
    App->>Widgets: onKey(ctx, key, isDown)
    Widgets->>Widgets: eventDispatcher(ctx, KeyDownEvent, eventData)
    Widgets->>Context: Check mFocus
    Widgets->>Widget(TextField): Append key data to text (if focused widget is TextField)
Loading

Poem

In fields of code where widgets grow,
A textfield sprouts, with focus aglow.
Key events dance in nimble delight,
Old toolbars vanish, gone from sight.
Copyrights trimmed, the years align,
The UI hops forward—how fine!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Apr 29, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
E Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@kimkulling kimkulling merged commit b66b7a7 into main Apr 29, 2025
2 of 3 checks passed
@kimkulling kimkulling deleted the feature/use_sdl2_backend_as_ptr branch April 29, 2025 14:21
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (7)
src/widgets.h (3)

39-40: Missing documentation for TextField widget type.

The TextField widget type has been added, but its documentation comment is empty, unlike other widget types that have descriptive comments.

-    TextField,          ///< 
+    TextField,          ///< A text field widget for user input

197-198: Missing documentation for textfield creation method.

The new textfield method lacks documentation comments, which is inconsistent with the documentation style of other widget creation methods.

-    static ret_code textfield(Context &ctx, Id id, Id parentId, const Rect &rect, Alignment alignment);
+    /// @brief Creates a new widget from the type text field.
+    /// @param ctx          The context to create the widget in.
+    /// @param id           The unique id of the widget.
+    /// @param parentId     The parent id of the widget.
+    /// @param rect         The rect of the widget.
+    /// @param alignment    The alignment of the widget.
+    /// @return ResultOk if the widget was created, ErrorCode if not.
+    static ret_code textfield(Context &ctx, Id id, Id parentId, const Rect &rect, Alignment alignment);

283-284: Missing documentation for setFocus method.

The new setFocus method lacks documentation comments, which is inconsistent with the documentation style of other methods in this class.

-    static ret_code setFocus(Context &ctx, Id id);
+    /// @brief Sets focus on the widget with the specified id.
+    /// @param ctx The context to set the focus in.
+    /// @param id  The id of the widget to focus.
+    /// @return ResultOk if the focus was set, ErrorCode if not.
+    static ret_code setFocus(Context &ctx, Id id);
src/widgets.cpp (4)

71-73: Use a wider type for pitch to avoid overflow
w * bytesPerPixel can overflow an int32_t for large textures (e.g. 16-bit pixels @ 16k width). Consider std::size_t or at least uint64_t.

-int32_t pitch = w * bytesPerPixel;
+std::size_t pitch = static_cast<std::size_t>(w) * bytesPerPixel;

206-219: TextField creation looks good but lacks initial text support
textfield() mirrors label() yet does not allow an initial text string. Consider adding a const char *text parameter so callers can pre-populate the field, keeping the API symmetrical with label() and button().


453-458: Stack-allocated EventData is fine, but ensure null-termination
Only the first byte is filled; downstream code now correctly push_backs one char (after previous fix). If you later decide to keep using append, remember to NULL-terminate here.

eventData.data[0] = *key;
eventData.data[1] = 0;  // optional future-proofing

505-514: Restore previous focus & early-out when already focused
setFocus() overwrites ctx.mFocus without clearing any previous visual focus indication and does extra work when the widget is already focused.

-    ctx.mFocus = widget;
+    if (ctx.mFocus == widget) {
+        return ResultOk;          // nothing to change
+    }
+    ctx.mFocus = widget;
+    // TODO: optionally trigger a redraw / focus-changed callback here
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 796dd39 and 7618d3f.

📒 Files selected for processing (9)
  • samples/main.cpp (4 hunks)
  • src/backends/sdl2_iodevice.cpp (1 hunks)
  • src/backends/sdl2_iodevice.h (1 hunks)
  • src/backends/sdl2_renderer.cpp (4 hunks)
  • src/backends/sdl2_renderer.h (2 hunks)
  • src/tinyui.cpp (1 hunks)
  • src/tinyui.h (4 hunks)
  • src/widgets.cpp (7 hunks)
  • src/widgets.h (5 hunks)
🔇 Additional comments (19)
src/backends/sdl2_iodevice.h (2)

4-4: Copyright year corrected.

The copyright year was updated from "2022-2025" to "2022-2024" to reflect the correct current year range.


34-35: Documentation comments removed.

The Doxygen-style comments for the destructor and update method were removed while maintaining the functionality. This appears to be part of a broader documentation cleanup across the codebase.

src/backends/sdl2_iodevice.cpp (1)

4-4: Copyright year corrected.

The copyright year was updated from "2022-2025" to "2022-2024" to reflect the correct current year range.

src/tinyui.h (4)

4-4: Copyright year corrected.

The copyright year was updated from "2022-2025" to "2022-2024" to reflect the correct current year range.


253-256: New keyboard event types added.

Added key events to support keyboard input handling, which enables interaction with the new TextField widget mentioned in the summary.


259-262: Added EventData struct for event information.

The new EventData struct provides a fixed-size buffer to store event-specific data, which will be necessary for passing keyboard input characters to widgets.


336-336: Added widget focus tracking to Context.

Added a pointer to track the currently focused widget, which is essential for directing keyboard events to the appropriate widget (specifically the TextField mentioned in the summary).

Also applies to: 363-363

src/backends/sdl2_renderer.h (1)

4-4: Copyright year corrected.

The copyright year was updated from "2022-2025" to "2022-2024" to reflect the correct current year range.

src/tinyui.cpp (1)

4-4: Copyright year updated correctly.

The copyright year has been updated from 2022-2025 to 2022-2024, which correctly reflects the current year.

samples/main.cpp (4)

4-4: Copyright year updated correctly.

The copyright year has been updated from 2022-2025 to 2022-2024, which correctly reflects the current year.


28-30: Good use of constants for panel IDs.

Using named constants instead of magic numbers improves code readability and maintainability.


65-65: Panel height increased to accommodate new UI elements.

The panel height has been increased from 400 to 500 pixels, which makes sense to accommodate the new textfield widget that is added below other elements.


78-79: Successfully implemented new TextField widget.

The textfield widget is properly positioned below the progressBar and uses the newly implemented widget functionality with appropriate parameters.

src/backends/sdl2_renderer.cpp (4)

4-4: Copyright year updated correctly.

The copyright year has been updated from 2022-2025 to 2022-2024, which correctly reflects the current year.


65-66: Improved function signature for queryDriver.

The function now accepts a raw C-string pointer and maximum length parameter instead of std::string_view, which can be more efficient for C-style string handling in this context.


76-80: Added proper string length bounds checking.

Good security practice - string length is now calculated and limited to the provided maxLen parameter before the comparison, preventing potential buffer overruns.


270-270: Updated function call to match new signature.

The call to queryDriver has been correctly updated to pass a C-string literal and maximum length value.

src/widgets.h (2)

4-4: Copyright year updated correctly.

The copyright year has been updated from 2022-2025 to 2022-2024, which correctly reflects the current year.


148-148: Modernized root item constant declaration.

Changed RootItem from static const to static constexpr, which is a best practice in modern C++ for compile-time constants.


struct SurfaceImpl {
SDL_Surface *mSurface = nullptr;
SDL_Surface *mSurface;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Removed nullptr initialization for mSurface.

The explicit nullptr initialization for the mSurface member was removed. While the destructor and clear() method check for nullptr before freeing, there's a risk of undefined behavior if the member is accessed before being properly initialized.

-    SDL_Surface *mSurface;
+    SDL_Surface *mSurface = nullptr;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
SDL_Surface *mSurface;
- SDL_Surface *mSurface;
+ SDL_Surface *mSurface = nullptr;

Comment on lines +116 to 128
void eventDispatcher(Context &ctx, int32_t eventId, EventData *eventData) {
if (ctx.mFocus == nullptr) {
return;
}

if (eventId == Events::KeyDownEvent || eventId == Events::KeyUpEvent) {
if (eventData != nullptr) {
if (ctx.mFocus->mType == WidgetType::TextField) {
ctx.mFocus->mText.append((const char*)eventData->data[0]);
}
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Unsafe cast when appending a single key to mText
eventData->data[0] is a single byte, yet it is re-interpreted as a C-string:

ctx.mFocus->mText.append((const char*)eventData->data[0]);

This is undefined behaviour and usually crashes because the pointer is interpreted as an address. Append the character itself:

-                ctx.mFocus->mText.append((const char*)eventData->data[0]);
+                ctx.mFocus->mText.push_back(static_cast<char>(eventData->data[0]));

Additional thought: you probably want to filter non-printable characters and support UTF-8.

Comment on lines +59 to +63
image = new Image;
if (image == nullptr) {
return nullptr;
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Prevent memory-leak when stbi_load fails
image is allocated but never freed if stbi_load returns nullptr. This leaks every time an image cannot be loaded.

-    unsigned char *data = stbi_load(filename, &w, &h, &bytesPerPixel, 0);
-    if (data == nullptr) {
-        return nullptr;
+    unsigned char *data = stbi_load(filename, &w, &h, &bytesPerPixel, 0);
+    if (data == nullptr) {
+        delete image;                 // reclaim the allocation
+        return nullptr;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
image = new Image;
if (image == nullptr) {
return nullptr;
}
image = new Image;
if (image == nullptr) {
return nullptr;
}
unsigned char *data = stbi_load(filename, &w, &h, &bytesPerPixel, 0);
if (data == nullptr) {
delete image; // reclaim the allocation
return nullptr;
}

Comment on lines +380 to +385
case WidgetType::TextField:
{
Renderer::drawRect(ctx, r.x1, r.y1, r.width, r.height, true, ctx.mStyle.mFg);
Renderer::drawRect(ctx, r.x1+2, r.y1+2, r.width-4, r.height-4, true, ctx.mStyle.mBorder);
}
break;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Render the text inside the TextField
The current rendering draws the box but never shows the user-typed text, making the widget appear empty.

         Renderer::drawRect(ctx, r.x1+2, r.y1+2, r.width-4, r.height-4, true, ctx.mStyle.mBorder);
+        if (!currentWidget->mText.empty()) {
+            Color4 fg = ctx.mStyle.mTextColor, bg = ctx.mStyle.mBg;
+            Renderer::drawText(ctx, currentWidget->mText.c_str(),
+                               ctx.mSDLContext.mDefaultFont,
+                               currentWidget->mRect, fg, bg,
+                               currentWidget->mAlignment);
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case WidgetType::TextField:
{
Renderer::drawRect(ctx, r.x1, r.y1, r.width, r.height, true, ctx.mStyle.mFg);
Renderer::drawRect(ctx, r.x1+2, r.y1+2, r.width-4, r.height-4, true, ctx.mStyle.mBorder);
}
break;
case WidgetType::TextField:
{
Renderer::drawRect(ctx, r.x1, r.y1, r.width, r.height, true, ctx.mStyle.mFg);
Renderer::drawRect(ctx, r.x1+2, r.y1+2, r.width-4, r.height-4, true, ctx.mStyle.mBorder);
if (!currentWidget->mText.empty()) {
Color4 fg = ctx.mStyle.mTextColor, bg = ctx.mStyle.mBg;
Renderer::drawText(ctx,
currentWidget->mText.c_str(),
ctx.mSDLContext.mDefaultFont,
currentWidget->mRect,
fg, bg,
currentWidget->mAlignment);
}
}
break;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants