Skip to content

Add checkbox + demo - #44

Merged
kimkulling merged 1 commit into
mainfrom
feature/checkboxes
Aug 10, 2026
Merged

kimkulling merged 1 commit into
mainfrom
feature/checkboxes

Conversation

@kimkulling

@kimkulling kimkulling commented Aug 10, 2026 •

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Added checkbox support with labels and checked/unchecked visual states.
    • Checkboxes now toggle when clicked and trigger their configured callbacks.
    • Updated the demo layout to include a checkbox and reposition surrounding controls.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR adds checkbox state storage, rendering, mouse-button toggling, and demo placement. Existing factory signatures and callback wiring remain unchanged.

Changes

Checkbox support

Layer / File(s) Summary
Checkbox state and factory contract
src/widgets.h, src/widgets.cpp
Adds CheckBoxContext, stores it on Widget, and initializes checkbox labels and checked state. Reformats declarations without changing signatures.
Checkbox rendering and interaction
src/widgets.cpp
Renders checked or unchecked checkbox visuals with optional text. Mouse-button-down events toggle the checked state before callback dispatch.
Demo checkbox layout
samples/demo/main.cpp
Adds a checkbox at y=200 and moves subsequent controls down by 50 pixels.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Widgets
  participant Widget
  User->>Widgets: click checkbox
  Widgets->>Widget: toggle checked state
  Widgets-->>User: invoke existing callback
  Widgets->>Widget: read label and checked state
  Widgets-->>User: render checkbox and label
Loading

Suggested reviewers: kullingk

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: adding checkbox support and updating the demo.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/checkboxes

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

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

@kimkulling
kimkulling merged commit fc5e2fd into main Aug 10, 2026
3 of 4 checks passed
@kimkulling
kimkulling deleted the feature/checkboxes branch August 10, 2026 14:48

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
src/widgets.h (1)

81-84: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add /// @brief`` documentation for CheckBoxContext.

CheckBoxContext is a new public type, but the declaration has no type-level brief. The mChecked field uses a trailing ///< comment instead of the requested /// @brief`` form. Add brief comments for both declarations.

Proposed documentation fix
+/// `@brief` Stores the checked state of a checkbox.
 struct CheckBoxContext {
-    bool mChecked{false};   ///< The checked state of the checkbox.
+    /// `@brief` The checked state of the checkbox.
+    bool mChecked{false};
 };

As per coding guidelines, use Doxygen-style /// @brief`` comments for documentation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets.h` around lines 81 - 84, Add Doxygen `/// `@brief`` comments for
the public `CheckBoxContext` struct and its `mChecked` member, replacing the
existing trailing `///<` field comment with the requested form while preserving
the documented checked-state meaning.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/widgets.cpp`:
- Around line 594-598: Update the unchecked branch in the checkbox rendering
logic around mCheckBoxContext->mChecked to preserve a visible boundary: retain
the background fill, then draw an outline around checkBoxRect using the
appropriate foreground or border style. Leave the checked-state rendering
unchanged.
- Around line 508-512: Update the checkbox factory implementation in
Widgets::checkBox to assign its callback parameter to child->mCallback and
increment the callback’s reference count consistently with other widget
factories, so Widgets::onMouseButton can dispatch it.
- Around line 509-510: Update Widget::~Widget() to release the CheckBoxContext
allocated by Widgets::checkBox before destruction, ensuring every
mCheckBoxContext allocation has exactly one owner and is freed safely; preserve
existing checkbox behavior.
- Line 508: Update Widgets::checkBox() to validate the text pointer before
calling child->mText.assign(text). Handle nullptr input safely while preserving
the existing checkbox creation behavior for valid labels.

---

Nitpick comments:
In `@src/widgets.h`:
- Around line 81-84: Add Doxygen `/// `@brief`` comments for the public
`CheckBoxContext` struct and its `mChecked` member, replacing the existing
trailing `///<` field comment with the requested form while preserving the
documented checked-state meaning.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 354de63b-300e-4006-8f91-900626d3c5f7

📥 Commits

Reviewing files that changed from the base of the PR and between 1acfb3a and 8872f3f.

📒 Files selected for processing (3)
  • samples/demo/main.cpp
  • src/widgets.cpp
  • src/widgets.h

Comment thread src/widgets.cpp
if (child == nullptr) {
return WidgetHandle{WidgetHandle::InvalidId};
}
child->mText.assign(text);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 4 'mText\.assign\(text\)|text != nullptr' src/widgets.cpp

Repository: kimkulling/tiny_ui

Length of output: 2099


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant functions and header declarations to determine whether the guard changes semantics or API expectations.
sed -n '350,520p' src/widgets.cpp | cat -n
printf '\n--- declarations/usages ---\n'
rg -n -C 3 'createCheckBox|CheckBox|void\s+draw.*(CheckBox|checkBox|checkbox)|WidgetHandle\s+create' src

Repository: kimkulling/tiny_ui

Length of output: 10062


🌐 Web query:

C++ std::string assign const char* nullptr behavior

💡 Result:

In modern C++ (C++23 and later), attempting to assign a nullptr to a std::string is ill-formed and will result in a compiler error [1]. This is because the C++23 standard added a deleted assignment operator: std::basic_string& operator=(std::nullptr_t) = delete; [2][1]. For older versions of C++ (C++11 through C++20), assigning nullptr to a std::string was syntactically valid but constituted undefined behavior [3][4][1]. Historically, this occurred because std::string provided constructors and assignment operators that accepted a const char* pointer [1]. Since nullptr implicitly converts to any pointer type, it matched these overloads, causing the string to attempt to read from a null memory address, which resulted in undefined behavior [3][1]. If you are working with an older C++ standard, you must ensure that any pointer passed to std::string::assign or used in an assignment is non-null [3]. You should explicitly check for null pointers before performing the assignment or construction [3].

Citations:


Guard text before assigning the checkbox label.

Widgets::checkBox() calls child->mText.assign(text) with a const char* that can be nullptr. Guard invalid text before assignment so other callers cannot crash this factory.

Proposed input guard
-    child->mText.assign(text);
+    if (text != nullptr) {
+        child->mText.assign(text);
+    }
📝 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
child->mText.assign(text);
if (text != nullptr) {
child->mText.assign(text);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets.cpp` at line 508, Update Widgets::checkBox() to validate the text
pointer before calling child->mText.assign(text). Handle nullptr input safely
while preserving the existing checkbox creation behavior for valid labels.

Source: Coding guidelines

Comment thread src/widgets.cpp
Comment on lines +508 to +512
child->mText.assign(text);
child->mCheckBoxContext = new CheckBoxContext;
child->mCheckBoxContext->mChecked = checked;


return child->mHandle;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Wire the callback parameter into the checkbox widget.

The public factory documents CallbackI *callback in src/widgets.h, Lines 271-279, but Widgets::checkBox never assigns it to child->mCallback or increments its reference count. Widgets::onMouseButton dispatches found->mCallback at Lines 678-680. A callback passed to checkBox therefore never runs.

Proposed callback wiring
     child->mCheckBoxContext = new CheckBoxContext;
     child->mCheckBoxContext->mChecked = checked;
+    child->mCallback = callback;
+    if (callback != nullptr) {
+        callback->incRef();
+    }

     return child->mHandle;
📝 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
child->mText.assign(text);
child->mCheckBoxContext = new CheckBoxContext;
child->mCheckBoxContext->mChecked = checked;
return child->mHandle;
child->mText.assign(text);
child->mCheckBoxContext = new CheckBoxContext;
child->mCheckBoxContext->mChecked = checked;
child->mCallback = callback;
if (callback != nullptr) {
callback->incRef();
}
return child->mHandle;
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[failure] 509-509: Replace the use of "new" with an operation that automatically manages the memory.

See more on https://sonarcloud.io/project/issues?id=kimkulling_tiny_ui&issues=AZ_sHP2HSyF5a6J6x1yo&open=AZ_sHP2HSyF5a6J6x1yo&pullRequest=44

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets.cpp` around lines 508 - 512, Update the checkbox factory
implementation in Widgets::checkBox to assign its callback parameter to
child->mCallback and increment the callback’s reference count consistently with
other widget factories, so Widgets::onMouseButton can dispatch it.

Comment thread src/widgets.cpp
Comment on lines +509 to +510
child->mCheckBoxContext = new CheckBoxContext;
child->mCheckBoxContext->mChecked = checked;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Release each allocated CheckBoxContext.

Widgets::checkBox allocates CheckBoxContext at Line 509. Widget::~Widget() in src/widgets.h, Lines 112-120, does not release mCheckBoxContext. Clearing a checkbox therefore leaks memory for every checkbox lifetime. Release the context in Widget::~Widget(), or replace the raw pointer with an owning value or RAII member.

Minimal lifetime fix
         if (mContent != nullptr) {
             delete [] mContent;
         }
+        if (mCheckBoxContext != nullptr) {
+            delete mCheckBoxContext;
+        }
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[failure] 509-509: Replace the use of "new" with an operation that automatically manages the memory.

See more on https://sonarcloud.io/project/issues?id=kimkulling_tiny_ui&issues=AZ_sHP2HSyF5a6J6x1yo&open=AZ_sHP2HSyF5a6J6x1yo&pullRequest=44

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets.cpp` around lines 509 - 510, Update Widget::~Widget() to release
the CheckBoxContext allocated by Widgets::checkBox before destruction, ensuring
every mCheckBoxContext allocation has exactly one owner and is freed safely;
preserve existing checkbox behavior.

Source: Linters/SAST tools

Comment thread src/widgets.cpp
Comment on lines +594 to +598
if (currentWidget->mCheckBoxContext->mChecked) {
Renderer::drawRect(ctx, checkBoxRect.top.x, checkBoxRect.top.y, checkBoxRect.width, checkBoxRect.height, true, ctx.mStyle.mFg);
} else {
Renderer::drawRect(ctx, checkBoxRect.top.x, checkBoxRect.top.y, checkBoxRect.width, checkBoxRect.height, true, ctx.mStyle.mBg);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the unchecked box visible.

The unchecked branch fills the square with ctx.mStyle.mBg and draws no outline. If the surrounding background uses the same color, the checkbox has no visible boundary. Draw an outline for the unchecked state.

Proposed unchecked rendering
-                        Renderer::drawRect(ctx, checkBoxRect.top.x, checkBoxRect.top.y, checkBoxRect.width, checkBoxRect.height, true, ctx.mStyle.mBg);
+                        Renderer::drawRect(ctx, checkBoxRect.top.x, checkBoxRect.top.y, checkBoxRect.width, checkBoxRect.height, false, ctx.mStyle.mFg);
📝 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
if (currentWidget->mCheckBoxContext->mChecked) {
Renderer::drawRect(ctx, checkBoxRect.top.x, checkBoxRect.top.y, checkBoxRect.width, checkBoxRect.height, true, ctx.mStyle.mFg);
} else {
Renderer::drawRect(ctx, checkBoxRect.top.x, checkBoxRect.top.y, checkBoxRect.width, checkBoxRect.height, true, ctx.mStyle.mBg);
}
if (currentWidget->mCheckBoxContext->mChecked) {
Renderer::drawRect(ctx, checkBoxRect.top.x, checkBoxRect.top.y, checkBoxRect.width, checkBoxRect.height, true, ctx.mStyle.mFg);
} else {
Renderer::drawRect(ctx, checkBoxRect.top.x, checkBoxRect.top.y, checkBoxRect.width, checkBoxRect.height, false, ctx.mStyle.mFg);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets.cpp` around lines 594 - 598, Update the unchecked branch in the
checkbox rendering logic around mCheckBoxContext->mChecked to preserve a visible
boundary: retain the background fill, then draw an outline around checkBoxRect
using the appropriate foreground or border style. Leave the checked-state
rendering unchanged.

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.

2 participants