From 8872f3fbbad83cfceddbde90150e2e003fe8a522 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 10 Aug 2026 16:37:14 +0200 Subject: [PATCH] Add checkbox + demo --- samples/demo/main.cpp | 13 ++++++++----- src/widgets.cpp | 32 +++++++++++++++++++++++++++++++- src/widgets.h | 33 +++++++++++++++++++++++++-------- 3 files changed, 64 insertions(+), 14 deletions(-) diff --git a/samples/demo/main.cpp b/samples/demo/main.cpp index 7964120..63f3822 100644 --- a/samples/demo/main.cpp +++ b/samples/demo/main.cpp @@ -94,7 +94,10 @@ int main(int argc, char *argv[]) { Widgets::textButton(panel, "Test 1", Rect(100, 50, 100, ButtonHeight), Alignment::Center, nullptr); Widgets::textButton(panel, "Test 2", Rect(100, 100, 100, ButtonHeight), Alignment::Center, nullptr); Widgets::textButton(panel, "Test 3", Rect(100, 150, 100, ButtonHeight), Alignment::Center, nullptr); - Widgets::imageButton(panel, "button_test.png", Rect(100, 200, 100, ButtonHeight), nullptr); + + Widgets::checkBox(panel, "Check me", Rect(100, 200, 100, ButtonHeight), false, nullptr); + + Widgets::imageButton(panel, "button_test.png", Rect(100, 250, 100, ButtonHeight), nullptr); auto &ctx = TinyUi::getContext(); @@ -102,12 +105,12 @@ int main(int argc, char *argv[]) { CallbackI *dynamicQuitCallback = new CallbackI(quit, (void*) &ctx); CallbackI *dynamicUpdateProgressBarCallback = new CallbackI(updateProgressbar, nullptr, Events::UpdateEvent); - Widgets::textButton(panel, "Quit", Rect(100, 250, 100, ButtonHeight), Alignment::Center, dynamicQuitCallback); - Widgets::progressBar(panel, Rect(100, 300, 100, ButtonHeight), 50, dynamicUpdateProgressBarCallback); + Widgets::textButton(panel, "Quit", Rect(100, 300, 100, ButtonHeight), Alignment::Center, dynamicQuitCallback); + Widgets::progressBar(panel, Rect(100, 350, 100, ButtonHeight), 50, dynamicUpdateProgressBarCallback); - Widgets::inputText(panel, Rect(100, 350, 100, ButtonHeight), Alignment::Left, KeyInputType::Character, ""); + Widgets::inputText(panel, Rect(100, 400, 100, ButtonHeight), Alignment::Left, KeyInputType::Character, ""); - WidgetHandle tree = Widgets::treeView(panel, "tree", Rect(100, 400, 100, ButtonHeight)); + WidgetHandle tree = Widgets::treeView(panel, "tree", Rect(100, 450, 100, ButtonHeight)); if (!tree.isValid()) { ctx.mLogger(LogSeverity::Error, "Cannot create tree view"); return ErrorCode; diff --git a/src/widgets.cpp b/src/widgets.cpp index 5fd7310..f6b5639 100644 --- a/src/widgets.cpp +++ b/src/widgets.cpp @@ -505,8 +505,11 @@ WidgetHandle Widgets::checkBox(WidgetHandle parentId, const char *text, const Re if (child == nullptr) { return WidgetHandle{WidgetHandle::InvalidId}; } + child->mText.assign(text); + child->mCheckBoxContext = new CheckBoxContext; + child->mCheckBoxContext->mChecked = checked; - + return child->mHandle; } static void render(Context &ctx, const Widget *currentWidget) { @@ -583,6 +586,27 @@ static void render(Context &ctx, const Widget *currentWidget) { } break; + case WidgetType::CheckBox: + { + if (currentWidget->mCheckBoxContext != nullptr) { + int size = r.height/2; + Rect checkBoxRect(r.top.x, r.top.y + (r.height - size)/2, size, size); + 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->mText.empty()) { + 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, + textRect, fg, bg, currentWidget->mAlignment); + } + } + } + break; + case WidgetType::InputField: { Renderer::drawRect(ctx, r.top.x, r.top.y, r.width, r.height, true, ctx.mStyle.mFg); @@ -638,6 +662,12 @@ void Widgets::onMouseButton(int x, int y, int eventType, MouseState state) { Widget *found{nullptr}; findSelectedWidget(x, y, ctx.mRoot, &found); if (found != nullptr) { + if (found->mType == WidgetType::CheckBox) { + if (eventType == Events::MouseButtonDownEvent) { + found->mCheckBoxContext->mChecked = !found->mCheckBoxContext->mChecked; + } + } + #ifdef _DEBUG if (eventType == Events::MouseButtonDownEvent) { std::cout << "Clicked " << found->mHandle.mId << "\n"; diff --git a/src/widgets.h b/src/widgets.h index a98e5ab..c1f64df 100644 --- a/src/widgets.h +++ b/src/widgets.h @@ -78,6 +78,10 @@ enum class WidgetStyle { /// @brief This enum is used to describe the alignment of a widget. using WidgetArray = std::vector; +struct CheckBoxContext { + bool mChecked{false}; ///< The checked state of the checkbox. +}; + /// @brief This struct contains all the data which is needed to describe a widget. struct Widget { WidgetHandle mHandle{}; ///< The unique id of the widget @@ -88,13 +92,18 @@ struct Widget { bool mFilledRect{true}; ///< The filled rectangle state uint32_t mStyles{0u}; ///< The style of the widget Alignment mAlignment{Alignment::Left}; ///< The alignment of the widget - KeyInputType mKeyInputType{ KeyInputType::Invalid }; ///< The type of the key input + KeyInputType mKeyInputType{KeyInputType::Invalid}; ///< The type of the key input std::string mText{}; ///< The label text Image *mImage{nullptr}; ///< The image of the widget WidgetArray mChildren{}; ///< The children of the widget CallbackI *mCallback{nullptr}; ///< The callback of the widget uint8_t *mContent{nullptr}; ///< The content of the widget uint32_t mIntention{0}; ///< The interaction intention. + CheckBoxContext *mCheckBoxContext{nullptr}; ///< The checkbox context. + + // Disable copy and assignment + Widget(const Widget &) = delete; + Widget &operator=(const Widget &) = delete; /// @brief The default class constructor. Widget() = default; @@ -147,9 +156,6 @@ struct Widget { bool isEnabled() const { return mEnabled; } - - Widget(const Widget &) = delete; - Widget &operator=(const Widget &) = delete; }; /// @brief The widgets access interface. @@ -212,7 +218,8 @@ struct Widgets { /// @param[in] type The type of the key input. /// @param[in] defaultText The default text of the widget. /// @return ResultOk if the widget was created, ErrorCode if not. - static WidgetHandle inputText(WidgetHandle parentId, const Rect &rect, Alignment alignment, KeyInputType type, const char *defaultText); + static WidgetHandle inputText(WidgetHandle parentId, const Rect &rect, Alignment alignment, + KeyInputType type, const char *defaultText); /// @brief Creates a new text button. /// @param[in] parentId The parent id of the widget. @@ -221,7 +228,8 @@ struct Widgets { /// @param[in] alignment The alignment for the widget. /// @param[in] callback The callback for the widget. /// @return ResultOk if the widget was created, ErrorCode if not. - static WidgetHandle textButton(WidgetHandle parentId, const char *text, const Rect &rect, Alignment alignment, CallbackI *callback); + static WidgetHandle textButton(WidgetHandle parentId, const char *text, const Rect &rect, + Alignment alignment, CallbackI *callback); /// @brief Creates a new image button. /// @param[in] parentId The parent id of the widget. @@ -229,7 +237,8 @@ struct Widgets { /// @param[in] rect The rect of the widget. /// @param[in] callback The callback for the widget. /// @return ResultOk if the widget was created, ErrorCode if not. - static WidgetHandle imageButton(WidgetHandle parentId, const char *image, const Rect &rect, CallbackI *callback); + static WidgetHandle imageButton(WidgetHandle parentId, const char *image, const Rect &rect, + CallbackI *callback); /// @brief Creates a new widget from the type panel. /// @param[in] parentId The parent id of the widget. @@ -259,7 +268,15 @@ struct Widgets { /// @return ResultOk if the widget was created, ErrorCode if not. static WidgetHandle progressBar(WidgetHandle parentId, const Rect &rect, int fillRate, CallbackI *callback); - static WidgetHandle checkBox(WidgetHandle parentId, const char *text, const Rect &rect, bool checked, CallbackI *callback); + /// @brief Creates a new widget from the type checkbox. + /// @param[in] parentId The parent id of the widget. + /// @param[in] text The text of the widget. + /// @param[in] rect The rect of the widget. + /// @param[in] checked The checked state of the widget. + /// @param[in] callback The callback of the widget. + /// @return ResultOk if the widget was created, ErrorCode if not. + static WidgetHandle checkBox(WidgetHandle parentId, const char *text, const Rect &rect, bool checked, + CallbackI *callback); /// @brief Will render all widgets. static void renderWidgets();