[ui] added ui_checkbox() helper

This commit is contained in:
Martin Fouilleul 2023-03-11 19:05:25 +01:00
parent b907578eb4
commit 09951afa53
3 changed files with 150 additions and 74 deletions

View File

@ -372,7 +372,13 @@ int main()
UI_STYLE_SIZE); UI_STYLE_SIZE);
widget_view("checkboxes") widget_view("checkboxes")
{ {
static bool check1 = true;
static bool check2 = false;
static bool check3 = false;
ui_checkbox("check1", &check1);
ui_checkbox("check2", &check2);
ui_checkbox("check3", &check3);
} }
} }

157
src/ui.c
View File

@ -487,10 +487,10 @@ ui_box* ui_box_end(void)
return(box); return(box);
} }
void ui_box_set_render_proc(ui_box* box, ui_box_render_proc proc, void* data) void ui_box_set_draw_proc(ui_box* box, ui_box_draw_proc proc, void* data)
{ {
box->renderProc = proc; box->drawProc = proc;
box->renderData = data; box->drawData = data;
} }
void ui_box_set_closed(ui_box* box, bool closed) void ui_box_set_closed(ui_box* box, bool closed)
@ -634,7 +634,7 @@ void ui_box_animate_style(ui_context* ui, ui_box* box)
f32 animationTime = targetStyle->animationTime; f32 animationTime = targetStyle->animationTime;
//NOTE: interpolate based on transition values //NOTE: interpolate based on transition values
u32 flags = box->targetStyle->animationFlags; ui_style_mask mask = box->targetStyle->animationMask;
if(box->fresh) if(box->fresh)
{ {
@ -642,7 +642,7 @@ void ui_box_animate_style(ui_context* ui, ui_box* box)
} }
else else
{ {
if(flags & UI_STYLE_ANIMATE_SIZE_WIDTH) if(mask & UI_STYLE_SIZE_WIDTH)
{ {
ui_animate_ui_size(ui, &box->style.size.c[UI_AXIS_X], targetStyle->size.c[UI_AXIS_X], animationTime); ui_animate_ui_size(ui, &box->style.size.c[UI_AXIS_X], targetStyle->size.c[UI_AXIS_X], animationTime);
} }
@ -651,7 +651,7 @@ void ui_box_animate_style(ui_context* ui, ui_box* box)
box->style.size.c[UI_AXIS_X] = targetStyle->size.c[UI_AXIS_X]; box->style.size.c[UI_AXIS_X] = targetStyle->size.c[UI_AXIS_X];
} }
if(flags & UI_STYLE_ANIMATE_SIZE_HEIGHT) if(mask & UI_STYLE_SIZE_HEIGHT)
{ {
ui_animate_ui_size(ui, &box->style.size.c[UI_AXIS_Y], targetStyle->size.c[UI_AXIS_Y], animationTime); ui_animate_ui_size(ui, &box->style.size.c[UI_AXIS_Y], targetStyle->size.c[UI_AXIS_Y], animationTime);
} }
@ -660,7 +660,7 @@ void ui_box_animate_style(ui_context* ui, ui_box* box)
box->style.size.c[UI_AXIS_Y] = targetStyle->size.c[UI_AXIS_Y]; box->style.size.c[UI_AXIS_Y] = targetStyle->size.c[UI_AXIS_Y];
} }
if(flags & UI_STYLE_ANIMATE_COLOR) if(mask & UI_STYLE_COLOR)
{ {
ui_animate_color(ui, &box->style.color, targetStyle->color, animationTime); ui_animate_color(ui, &box->style.color, targetStyle->color, animationTime);
} }
@ -670,7 +670,7 @@ void ui_box_animate_style(ui_context* ui, ui_box* box)
} }
if(flags & UI_STYLE_ANIMATE_BG_COLOR) if(mask & UI_STYLE_BG_COLOR)
{ {
ui_animate_color(ui, &box->style.bgColor, targetStyle->bgColor, animationTime); ui_animate_color(ui, &box->style.bgColor, targetStyle->bgColor, animationTime);
} }
@ -679,7 +679,7 @@ void ui_box_animate_style(ui_context* ui, ui_box* box)
box->style.bgColor = targetStyle->bgColor; box->style.bgColor = targetStyle->bgColor;
} }
if(flags & UI_STYLE_ANIMATE_BORDER_COLOR) if(mask & UI_STYLE_BORDER_COLOR)
{ {
ui_animate_color(ui, &box->style.borderColor, targetStyle->borderColor, animationTime); ui_animate_color(ui, &box->style.borderColor, targetStyle->borderColor, animationTime);
} }
@ -688,7 +688,7 @@ void ui_box_animate_style(ui_context* ui, ui_box* box)
box->style.borderColor = targetStyle->borderColor; box->style.borderColor = targetStyle->borderColor;
} }
if(flags & UI_STYLE_ANIMATE_FONT_SIZE) if(mask & UI_STYLE_FONT_SIZE)
{ {
ui_animate_f32(ui, &box->style.fontSize, targetStyle->fontSize, animationTime); ui_animate_f32(ui, &box->style.fontSize, targetStyle->fontSize, animationTime);
} }
@ -697,7 +697,7 @@ void ui_box_animate_style(ui_context* ui, ui_box* box)
box->style.fontSize = targetStyle->fontSize; box->style.fontSize = targetStyle->fontSize;
} }
if(flags & UI_STYLE_ANIMATE_BORDER_SIZE) if(mask & UI_STYLE_BORDER_SIZE)
{ {
ui_animate_f32(ui, &box->style.borderSize, targetStyle->borderSize, animationTime); ui_animate_f32(ui, &box->style.borderSize, targetStyle->borderSize, animationTime);
} }
@ -706,7 +706,7 @@ void ui_box_animate_style(ui_context* ui, ui_box* box)
box->style.borderSize = targetStyle->borderSize; box->style.borderSize = targetStyle->borderSize;
} }
if(flags & UI_STYLE_ANIMATE_ROUNDNESS) if(mask & UI_STYLE_ROUNDNESS)
{ {
ui_animate_f32(ui, &box->style.roundness, targetStyle->roundness, animationTime); ui_animate_f32(ui, &box->style.roundness, targetStyle->roundness, animationTime);
} }
@ -800,9 +800,9 @@ void ui_apply_style_with_mask(ui_style* dst, ui_style* src, ui_style_mask mask)
{ {
dst->animationTime = src->animationTime; dst->animationTime = src->animationTime;
} }
if(mask & UI_STYLE_ANIMATION_FLAGS) if(mask & UI_STYLE_ANIMATION_MASK)
{ {
dst->animationFlags = src->animationFlags; dst->animationMask = src->animationMask;
} }
} }
@ -1183,7 +1183,7 @@ void ui_layout_compute_rect(ui_context* ui, ui_box* box, vec2 pos)
if(child->style.floating.c[i]) if(child->style.floating.c[i])
{ {
ui_style* style = child->targetStyle; ui_style* style = child->targetStyle;
if((child->targetStyle->animationFlags & UI_STYLE_ANIMATE_POS) if((child->targetStyle->animationMask & (UI_STYLE_FLOAT_X << i))
&& !child->fresh) && !child->fresh)
{ {
ui_animate_f32(ui, &child->floatPos.c[i], child->style.floatTarget.c[i], style->animationTime); ui_animate_f32(ui, &child->floatPos.c[i], child->style.floatTarget.c[i], style->animationTime);
@ -1298,9 +1298,9 @@ void ui_draw_box(ui_box* box)
ui_rectangle_fill(box->rect, style->roundness); ui_rectangle_fill(box->rect, style->roundness);
} }
if((box->flags & UI_FLAG_DRAW_RENDER_PROC) && box->renderProc) if((box->flags & UI_FLAG_DRAW_PROC) && box->drawProc)
{ {
box->renderProc(box, box->renderData); box->drawProc(box, box->drawData);
} }
for_list(&box->children, child, ui_box, listElt) for_list(&box->children, child, ui_box, listElt)
@ -1489,6 +1489,30 @@ ui_sig ui_label(const char* label)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// button // button
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
ui_sig ui_button_behavior(ui_box* box)
{
ui_sig sig = ui_box_sig(box);
if(sig.hovering)
{
ui_box_set_hot(box, true);
if(sig.dragging)
{
ui_box_activate(box);
}
}
else
{
ui_box_set_hot(box, false);
}
if(!sig.dragging)
{
ui_box_deactivate(box);
}
return(sig);
}
ui_sig ui_button_str8(str8 label) ui_sig ui_button_str8(str8 label)
{ {
ui_context* ui = ui_get_context(); ui_context* ui = ui_get_context();
@ -1537,25 +1561,7 @@ ui_sig ui_button_str8(str8 label)
ui_box* box = ui_box_make_str8(label, flags); ui_box* box = ui_box_make_str8(label, flags);
ui_tag_box(box, "button"); ui_tag_box(box, "button");
ui_sig sig = ui_box_sig(box); ui_sig sig = ui_button_behavior(box);
if(sig.hovering)
{
ui_box_set_hot(box, true);
if(sig.dragging)
{
ui_box_activate(box);
}
}
else
{
ui_box_set_hot(box, false);
}
if(!sig.dragging)
{
ui_box_deactivate(box);
}
return(sig); return(sig);
} }
@ -1564,6 +1570,79 @@ ui_sig ui_button(const char* label)
return(ui_button_str8(STR8((char*)label))); return(ui_button_str8(STR8((char*)label)));
} }
void ui_checkbox_draw(ui_box* box, void* data)
{
bool checked = *(bool*)data;
if(checked)
{
mg_move_to(box->rect.x + 0.2*box->rect.w, box->rect.y + 0.5*box->rect.h);
mg_line_to(box->rect.x + 0.4*box->rect.w, box->rect.y + 0.75*box->rect.h);
mg_line_to(box->rect.x + 0.8*box->rect.w, box->rect.y + 0.2*box->rect.h);
mg_set_color(box->style.color);
mg_set_width(0.2*box->rect.w);
mg_set_joint(MG_JOINT_MITER);
mg_set_max_joint_excursion(0.2 * box->rect.h);
mg_stroke();
}
}
ui_sig ui_checkbox(const char* name, bool* checked)
{
ui_context* ui = ui_get_context();
ui_style defaultStyle = {.size.width = {UI_SIZE_PIXELS, 20},
.size.height = {UI_SIZE_PIXELS, 20},
.bgColor = {1, 1, 1, 1},
.color = {0, 0, 0, 1},
.borderColor = {0.2, 0.2, 0.2, 1},
.borderSize = 1,
.roundness = 5};
ui_style_mask defaultMask = UI_STYLE_SIZE_WIDTH
| UI_STYLE_SIZE_HEIGHT
| UI_STYLE_BG_COLOR
| UI_STYLE_COLOR
| UI_STYLE_BORDER_COLOR
| UI_STYLE_BORDER_SIZE
| UI_STYLE_ROUNDNESS;
ui_style_next(&defaultStyle, defaultMask);
ui_style activeStyle = {.bgColor = {0.5, 0.5, 0.5, 1},
.borderColor = {0.2, 0.2, 0.2, 1},
.borderSize = 2};
ui_style_mask activeMask = UI_STYLE_BG_COLOR
| UI_STYLE_BORDER_COLOR
| UI_STYLE_BORDER_SIZE;
ui_pattern activePattern = {0};
ui_pattern_push(&ui->frameArena,
&activePattern,
(ui_selector){.kind = UI_SEL_STATUS,
.status = UI_ACTIVE|UI_HOVER});
ui_style_match_before(activePattern, &activeStyle, activeMask);
ui_flags flags = UI_FLAG_CLICKABLE
| UI_FLAG_CLIP
| UI_FLAG_DRAW_BACKGROUND
| UI_FLAG_DRAW_PROC
| UI_FLAG_DRAW_BORDER
| UI_FLAG_HOT_ANIMATION
| UI_FLAG_ACTIVE_ANIMATION;
ui_box* box = ui_box_make(name, flags);
ui_tag_box(box, "checkbox");
ui_sig sig = ui_button_behavior(box);
if(sig.clicked)
{
*checked = !*checked;
}
ui_box_set_draw_proc(box, ui_checkbox_draw, checked);
return(sig);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// slider / scrollbar // slider / scrollbar
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -2369,7 +2448,7 @@ ui_text_box_result ui_text_box(const char* name, mem_arena* arena, str8 text)
| UI_FLAG_DRAW_BACKGROUND | UI_FLAG_DRAW_BACKGROUND
| UI_FLAG_DRAW_BORDER | UI_FLAG_DRAW_BORDER
| UI_FLAG_CLIP | UI_FLAG_CLIP
| UI_FLAG_DRAW_RENDER_PROC | UI_FLAG_DRAW_PROC
| UI_FLAG_SCROLLABLE; | UI_FLAG_SCROLLABLE;
ui_box* frame = ui_box_make(name, frameFlags); ui_box* frame = ui_box_make(name, frameFlags);
@ -2521,14 +2600,14 @@ ui_text_box_result ui_text_box(const char* name, mem_arena* arena, str8 text)
//NOTE: set renderer //NOTE: set renderer
str32* renderCodepoints = mem_arena_alloc_type(&ui->frameArena, str32); str32* renderCodepoints = mem_arena_alloc_type(&ui->frameArena, str32);
*renderCodepoints = str32_push_copy(&ui->frameArena, codepoints); *renderCodepoints = str32_push_copy(&ui->frameArena, codepoints);
ui_box_set_render_proc(frame, ui_text_box_render, renderCodepoints); ui_box_set_draw_proc(frame, ui_text_box_render, renderCodepoints);
} }
else else
{ {
//NOTE: set renderer //NOTE: set renderer
str32* renderCodepoints = mem_arena_alloc_type(&ui->frameArena, str32); str32* renderCodepoints = mem_arena_alloc_type(&ui->frameArena, str32);
*renderCodepoints = utf8_push_to_codepoints(&ui->frameArena, text); *renderCodepoints = utf8_push_to_codepoints(&ui->frameArena, text);
ui_box_set_render_proc(frame, ui_text_box_render, renderCodepoints); ui_box_set_draw_proc(frame, ui_text_box_render, renderCodepoints);
} }
return(result); return(result);

View File

@ -100,34 +100,8 @@ typedef union ui_box_floating
bool c[UI_AXIS_COUNT]; bool c[UI_AXIS_COUNT];
} ui_box_floating; } ui_box_floating;
typedef enum { UI_STYLE_ANIMATE_SIZE_WIDTH = 1<<1, //NOTE: flags for axis-dependent properties (e.g. UI_STYLE_FLOAT_X/Y) need to be consecutive bits
UI_STYLE_ANIMATE_SIZE_HEIGHT = 1<<2, // in order to play well with axis agnostic functions
UI_STYLE_ANIMATE_COLOR = 1<<3,
UI_STYLE_ANIMATE_BG_COLOR = 1<<4,
UI_STYLE_ANIMATE_BORDER_COLOR = 1<<5,
UI_STYLE_ANIMATE_BORDER_SIZE = 1<<6,
UI_STYLE_ANIMATE_FONT_SIZE = 1<<7,
UI_STYLE_ANIMATE_ROUNDNESS = 1<<8,
UI_STYLE_ANIMATE_POS = 1<<9,
} ui_style_animation_flags;
typedef struct ui_style
{
ui_box_size size;
ui_layout layout;
ui_box_floating floating;
vec2 floatTarget;
mg_color color;
mg_color bgColor;
mg_color borderColor;
mg_font font;
f32 fontSize;
f32 borderSize;
f32 roundness;
f32 animationTime;
ui_style_animation_flags animationFlags;
} ui_style;
typedef u64 ui_style_mask; typedef u64 ui_style_mask;
enum enum
{ {
@ -150,7 +124,7 @@ enum
UI_STYLE_FONT = 1<<16, UI_STYLE_FONT = 1<<16,
UI_STYLE_FONT_SIZE = 1<<17, UI_STYLE_FONT_SIZE = 1<<17,
UI_STYLE_ANIMATION_TIME = 1<<18, UI_STYLE_ANIMATION_TIME = 1<<18,
UI_STYLE_ANIMATION_FLAGS = 1<<19, UI_STYLE_ANIMATION_MASK = 1<<19,
//masks //masks
UI_STYLE_SIZE = UI_STYLE_SIZE_WIDTH UI_STYLE_SIZE = UI_STYLE_SIZE_WIDTH
@ -170,9 +144,25 @@ enum
| UI_STYLE_FONT | UI_STYLE_FONT
| UI_STYLE_FONT_SIZE | UI_STYLE_FONT_SIZE
| UI_STYLE_ANIMATION_TIME | UI_STYLE_ANIMATION_TIME
| UI_STYLE_ANIMATION_FLAGS, | UI_STYLE_ANIMATION_MASK,
}; };
typedef struct ui_style
{
ui_box_size size;
ui_layout layout;
ui_box_floating floating;
vec2 floatTarget;
mg_color color;
mg_color bgColor;
mg_color borderColor;
mg_font font;
f32 fontSize;
f32 borderSize;
f32 roundness;
f32 animationTime;
ui_style_mask animationMask;
} ui_style;
typedef struct ui_tag { u64 hash; } ui_tag; typedef struct ui_tag { u64 hash; } ui_tag;
@ -253,7 +243,7 @@ typedef struct ui_sig
} ui_sig; } ui_sig;
typedef void(*ui_box_render_proc)(ui_box* box, void* data); typedef void(*ui_box_draw_proc)(ui_box* box, void* data);
typedef enum typedef enum
{ {
@ -271,7 +261,7 @@ typedef enum
UI_FLAG_DRAW_FOREGROUND = (1<<9), UI_FLAG_DRAW_FOREGROUND = (1<<9),
UI_FLAG_DRAW_BORDER = (1<<10), UI_FLAG_DRAW_BORDER = (1<<10),
UI_FLAG_DRAW_TEXT = (1<<11), UI_FLAG_DRAW_TEXT = (1<<11),
UI_FLAG_DRAW_RENDER_PROC = (1<<12), UI_FLAG_DRAW_PROC = (1<<12),
} ui_flags; } ui_flags;
@ -292,8 +282,8 @@ struct ui_box
str8 string; str8 string;
list_info tags; list_info tags;
ui_box_render_proc renderProc; ui_box_draw_proc drawProc;
void* renderData; void* drawData;
// styling // styling
list_info beforeRules; list_info beforeRules;
@ -367,7 +357,7 @@ MP_API void ui_box_push(ui_box* box);
MP_API void ui_box_pop(void); MP_API void ui_box_pop(void);
MP_API ui_box* ui_box_top(void); MP_API ui_box* ui_box_top(void);
MP_API void ui_box_set_render_proc(ui_box* box, ui_box_render_proc proc, void* data); MP_API void ui_box_set_draw_proc(ui_box* box, ui_box_draw_proc proc, void* data);
// C-string helpers // C-string helpers
#define ui_box_lookup(s) ui_box_lookup_str8(STR8(s)) #define ui_box_lookup(s) ui_box_lookup_str8(STR8(s))
@ -432,6 +422,7 @@ enum {
MP_API ui_sig ui_label(const char* label); MP_API ui_sig ui_label(const char* label);
MP_API ui_sig ui_button(const char* label); MP_API ui_sig ui_button(const char* label);
MP_API ui_sig ui_checkbox(const char* name, bool* checked);
MP_API ui_box* ui_slider(const char* label, f32 thumbRatio, f32* scrollValue); MP_API ui_box* ui_slider(const char* label, f32 thumbRatio, f32* scrollValue);
MP_API void ui_panel_begin(const char* name, ui_flags flags); MP_API void ui_panel_begin(const char* name, ui_flags flags);