Skip to content

Commit

Permalink
Merge pull request #7 from kimkulling/feature/add_brogress_bar
Browse files Browse the repository at this point in the history
Feature: Add progress bar
  • Loading branch information
kimkulling authored Jan 3, 2025
2 parents d5113f5 + 2cec28f commit a75dff6
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 93 deletions.
33 changes: 25 additions & 8 deletions samples/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ static constexpr Id RootPanelId = 1;
static constexpr Id NextPanelId = 100;

static void renderDialog(const char *title, Context &ctx) {
Widgets::panel(ctx, NextPanelId, 0, title, 240, 90, 120, 250, nullptr);
Rect r(240, 90, 120, 250);
Widgets::panel(ctx, NextPanelId, 0, title, r, nullptr);
}

int quit(uint32_t id, void *instance) {
Expand All @@ -49,6 +50,19 @@ int quit(uint32_t id, void *instance) {
return ResultOk;
}

int updateProgressbar(uint32_t id, void *instance) {
if (instance == nullptr) {
return ErrorCode;
}

auto *widget = (Widget*) instance;
auto *state = (FilledState*) widget->mContent;
state->filledState++;
if (state->filledState > 100) state->filledState = 0;

return ResultOk;
}

int main(int argc, char *argv[]) {
Style style = TinyUi::getDefaultStyle();
Context &ctx = Context::create("Sample-Screen", style);
Expand All @@ -58,15 +72,18 @@ int main(int argc, char *argv[]) {
return ErrorCode;
}

Widgets::panel(ctx, RootPanelId, 0, "Sample-Dialog", 90, 5, 120, 300, nullptr);
Widgets::label(ctx, 2, RootPanelId, "Title", 100, 10, 100, 20, Alignment::Center);
Widgets::button(ctx, 3, RootPanelId, "Test 1", nullptr, 100, 50, 100, 40, nullptr);
Widgets::button(ctx, 4, RootPanelId, "Test 2", nullptr, 100, 100, 100, 40, nullptr);
Widgets::button(ctx, 5, RootPanelId, "Test 3", nullptr, 100, 150, 100, 40, nullptr);
Widgets::button(ctx, 6, RootPanelId, nullptr, "button_test.png", 100, 200, 100, 40, nullptr);
Widgets::panel(ctx, RootPanelId, 0, "Sample-Dialog", Rect(90, 5, 120, 400), nullptr);
Widgets::label(ctx, 2, RootPanelId, "Title", Rect(100, 10, 100, 20), Alignment::Center);
Widgets::button(ctx, 3, RootPanelId, "Test 1", nullptr, Rect(100, 50, 100, 40), nullptr);
Widgets::button(ctx, 4, RootPanelId, "Test 2", nullptr, Rect(100, 100, 100, 40), nullptr);
Widgets::button(ctx, 5, RootPanelId, "Test 3", nullptr, Rect(100, 150, 100, 40), nullptr);
Widgets::button(ctx, 6, RootPanelId, nullptr, "button_test.png", Rect(100, 200, 100, 40), nullptr);

CallbackI quitCallback(quit, (void*) &ctx);
Widgets::button(ctx, 7, RootPanelId, "Quit", nullptr, 100, 250, 100, 40, &quitCallback);
Widgets::button(ctx, 7, RootPanelId, "Quit", nullptr, Rect(100, 250, 100, 40), &quitCallback);

CallbackI updateProgressBarCallback(updateProgressbar, nullptr, Events::UpdateEvent);
Widgets::progressBar(ctx, 8, RootPanelId, Rect(100, 300, 100, 40), 50, &updateProgressBarCallback);

while (TinyUi::run(ctx)) {
TinyUi::beginRender(ctx, style.mClearColor);
Expand Down
1 change: 0 additions & 1 deletion src/backends/sdl2_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ struct FontImpl {
}
};


/// @brief The renderer implementation using the SDL2 library.
struct Renderer {
static ret_code initRenderer(Context &ctx);
Expand Down
5 changes: 5 additions & 0 deletions src/tinyui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ ret_code TinyUi::getSurfaceInfo(Context &ctx, int32_t &w, int32_t &h) {
}

bool TinyUi::run(Context &ctx) {
if (!ctx.mUpdateCallbackList.empty()) {
for (auto it = ctx.mUpdateCallbackList.begin(); it != ctx.mUpdateCallbackList.end(); ++it) {
(*it)->mfuncCallback[Events::UpdateEvent](1, (*it)->mInstance);
}
}
return Renderer::update(ctx);
}

Expand Down
46 changes: 30 additions & 16 deletions src/tinyui.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ SOFTWARE.

#include <cstdint>
#include <vector>
#include <list>
#include <string>
#include <map>

Expand Down Expand Up @@ -250,7 +251,8 @@ struct Events {
static constexpr int32_t MouseButtonUpEvent = 2;
static constexpr int32_t MouseMoveEvent = 3;
static constexpr int32_t MouseHoverEvent = 4;
static constexpr int32_t NumEvents = MouseHoverEvent + 1;
static constexpr int32_t UpdateEvent = 5;
static constexpr int32_t NumEvents = UpdateEvent + 1;
};

/// @brief This interface is used to store all neede message handlers.
Expand All @@ -268,24 +270,34 @@ struct CallbackI {
clear();
}

CallbackI(funcCallback mbDownFunc, void *instance) :
/// @brief The class constructor
/// @param callbackFunc The callback function.
/// @param instance The instance to use.
/// @param eventType The event type to use.
CallbackI(funcCallback callbackFunc, void *instance, size_t eventType = Events::MouseButtonDownEvent) :
mfuncCallback{ nullptr }, mInstance(instance) {
clear();
mfuncCallback[Events::MouseButtonDownEvent] = mbDownFunc;
mfuncCallback[eventType] = callbackFunc;
}

/// @brief The class destructor.
~CallbackI() = default;

/// @brief Will clear all callback functions.
void clear() {
for (size_t i = 0; i < Events::NumEvents; ++i) {
mfuncCallback[i] = nullptr;
}
}
};

/// @brief The event callback array.
using EventCallbackArray = std::vector<CallbackI*>;

/// @brief The event dispatch map.
using EventDispatchMap = std::map<int32_t, EventCallbackArray>;

/// @brief Function pointer declaration for callbacks.
typedef void (*tui_log_func) (LogSeverity severity, const char *message);

struct SDLContext {
Expand All @@ -301,18 +313,21 @@ struct SDLContext {
mDefaultFont(nullptr), mSelectedFont(nullptr), mOwner(true) {}
};

using UpdateCallbackList = std::list<CallbackI*>;

struct Context {
bool mCreated;
bool mRequestShutdown;
const char *mAppTitle;
const char *mWindowsTitle;
SDLContext mSDLContext;
Style mStyle;
Widget *mRoot;
tui_log_func mLogger;
EventDispatchMap mEventDispatchMap;
FontCache mFontCache;
ImageCache mImageCache;
bool mCreated;
bool mRequestShutdown;
const char *mAppTitle;
const char *mWindowsTitle;
SDLContext mSDLContext;
Style mStyle;
Widget *mRoot;
tui_log_func mLogger = nullptr;
EventDispatchMap mEventDispatchMap;
FontCache mFontCache;
ImageCache mImageCache;
UpdateCallbackList mUpdateCallbackList;

static Context &create(const char *title, Style &style);
static void destroy(Context &ctx);
Expand All @@ -326,8 +341,7 @@ struct Context {
mWindowsTitle(nullptr),
mSDLContext(),
mStyle(),
mRoot(nullptr),
mLogger(nullptr) {
mRoot(nullptr) {
// empty
}
};
Expand Down
74 changes: 48 additions & 26 deletions src/widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,12 @@ void eventDispatcher() {

}

ret_code Widgets::container(Context &ctx, Id id, Id parentId, const char *text, int x, int y, int w, int h) {
ret_code Widgets::container(Context &ctx, Id id, Id parentId, const char *text, const Rect &rect) {
if (ctx.mRoot != nullptr) {
return ErrorCode;
}
Rect r(x, y, w, h);
Widget *widget = createWidget(ctx, id, parentId, r, WidgetType::Container);

Widget *widget = createWidget(ctx, id, parentId, rect, WidgetType::Container);
ctx.mRoot = widget;
if (text != nullptr) {
widget->mText.assign(text);
Expand Down Expand Up @@ -176,14 +176,12 @@ void Widgets::findSelectedWidget(int x, int y, Widget *currentChild, Widget **fo
}
}

ret_code Widgets::label(Context &ctx, Id id, Id parentId, const char *text,
int x, int y, int w, int h, Alignment alignment) {
ret_code Widgets::label(Context &ctx, Id id, Id parentId, const char *text, const Rect &rect, Alignment alignment) {
if (ctx.mRoot == nullptr) {
return ErrorCode;
}

Rect r(x, y, w, h);
Widget *widget = createWidget(ctx, id, parentId, r, WidgetType::Label);
Widget *widget = createWidget(ctx, id, parentId, rect, WidgetType::Label);
if (widget == nullptr) {
return ErrorCode;
}
Expand All @@ -195,14 +193,12 @@ ret_code Widgets::label(Context &ctx, Id id, Id parentId, const char *text,
return ResultOk;
}

ret_code Widgets::button(Context &ctx, Id id, Id parentId, const char *text,
const char *image, int x, int y, int w, int h, CallbackI *callback) {
ret_code Widgets::button(Context &ctx, Id id, Id parentId, const char *text, const char *image, const Rect &rect, CallbackI *callback) {
if (ctx.mSDLContext.mRenderer == nullptr) {
return ErrorCode;
}

Rect r(x, y, w, h);
Widget *child = createWidget(ctx, id, parentId, r, WidgetType::Button);
Widget *child = createWidget(ctx, id, parentId, rect, WidgetType::Button);
if (child == nullptr) {
return ErrorCode;
}
Expand All @@ -219,14 +215,12 @@ ret_code Widgets::button(Context &ctx, Id id, Id parentId, const char *text,
return ResultOk;
}

ret_code Widgets::box(Context &ctx, Id id, Id parentId, int x, int y,
int w, int h, const Color4 &color, bool filled) {
ret_code Widgets::box(Context &ctx, Id id, Id parentId, const Rect &rect, bool filled) {
if (ctx.mSDLContext.mRenderer == nullptr) {
return ErrorCode;
}

Rect r(x, y, w, h);
Widget *child = createWidget(ctx, id, parentId, r, WidgetType::Box);
Widget *child = createWidget(ctx, id, parentId, rect, WidgetType::Box);
if (child == nullptr) {
return ErrorCode;
}
Expand All @@ -236,48 +230,67 @@ ret_code Widgets::box(Context &ctx, Id id, Id parentId, int x, int y,
return ResultOk;
}

ret_code Widgets::panel(Context &ctx, Id id, Id parentId, const char *title, int x, int y, int w, int h,
CallbackI *callback) {
ret_code Widgets::panel(Context &ctx, Id id, Id parentId, const char *title, const Rect &rect, CallbackI *callback) {
if (ctx.mSDLContext.mRenderer == nullptr) {
ctx.mLogger(LogSeverity::Error, "TUI-Renderer is nullptr.");
return ErrorCode;
}

Rect r(x, y, w, h);
Widget *child = createWidget(ctx, id, parentId, r, WidgetType::Panel);
Widget *child = createWidget(ctx, id, parentId, rect, WidgetType::Panel);
if (child == nullptr) {
return ErrorCode;
}

return ResultOk;
}

ret_code Widgets::treeView(Context& ctx, Id id, Id parentId, const char* title, int x, int y, int w, int h) {
ret_code Widgets::treeView(Context &ctx, Id id, Id parentId, const char *title, const Rect &rect, CallbackI *callback) {
if (ctx.mSDLContext.mRenderer == nullptr) {
ctx.mLogger(LogSeverity::Error, "TUI-Renderer is nullptr.");
return ErrorCode;
}

Rect r(x, y, w, h);
Widget *child = createWidget(ctx, id, parentId, r, WidgetType::TreeView);
Widget *child = createWidget(ctx, id, parentId, rect, WidgetType::TreeView);
if (child == nullptr) {
return ErrorCode;
}

return ResultOk;
}

ret_code Widgets::statusBar(Context& ctx, Id id, Id parentId, int x, int y, int w, int h) {

template<class T>
inline void clamp(T min, T max, T &value) {
if (value < min) {
value = min;
}
if (value > max) {
value = max;
}
}

ret_code Widgets::progressBar(Context &ctx, Id id, Id parentId, const Rect &rect, int fillRate, CallbackI *callback) {
if (ctx.mSDLContext.mRenderer == nullptr) {
ctx.mLogger(LogSeverity::Error, "TUI-Renderer is nullptr.");
return ErrorCode;
}

Rect r(x, y, w, h);
Widget *child = createWidget(ctx, id, parentId, r, WidgetType::StatusBar);
Widget *child = createWidget(ctx, id, parentId, rect, WidgetType::ProgressBar);
if (child == nullptr) {
return ErrorCode;
}

FilledState *state = new FilledState;
clamp(0, 100, fillRate);
state->filledState = fillRate;
child->mContent = new uint8_t[sizeof(FilledState)];
child->mCallback = callback;
memcpy(child->mContent, state, sizeof(FilledState));
if (callback != nullptr) {
callback->mInstance = child;
ctx.mUpdateCallbackList.push_back(callback);
}


return ResultOk;
}
Expand Down Expand Up @@ -328,7 +341,16 @@ static void render(Context &ctx, Widget *currentWidget) {
Renderer::drawRect(ctx, r.x1, r.y1, r.width, r.height, false, ctx.mStyle.mBorder);
}
break;


case WidgetType::ProgressBar:
{
Renderer::drawRect(ctx, r.x1, r.y1, r.width, r.height, true, ctx.mStyle.mFg);
FilledState *state = reinterpret_cast<FilledState *>(currentWidget->mContent);
const uint32_t fillRate = state->filledState;
const uint32_t width = r.width * fillRate / 100;
Renderer::drawRect(ctx, r.x1, r.y1, width, r.height, true, ctx.mStyle.mTextColor);
} break;

case WidgetType::Container:
case WidgetType::Box:
{
Expand Down
Loading

0 comments on commit a75dff6

Please sign in to comment.