From c8e6c320f19b72fd019afdacbc8b3d2518f6e8ce Mon Sep 17 00:00:00 2001 From: Mid <> Date: Sun, 27 Jul 2025 16:17:24 +0300 Subject: [PATCH] Add layouts and decouple immediate drawings --- src/k3menu.c | 118 +++++++++++++++++++++++++++++++++++++++++++++------ src/k3menu.h | 32 +++++++++++++- 2 files changed, 134 insertions(+), 16 deletions(-) diff --git a/src/k3menu.c b/src/k3menu.c index d233336..dfa7c8d 100644 --- a/src/k3menu.c +++ b/src/k3menu.c @@ -3,6 +3,78 @@ #include #include #include +#include"immdraw.h" + +void k3MMeasure(struct k3MObj *this) { + for(size_t c = 0; c < this->childCount; c++) { + k3MMeasure(this->children[c]); + } + + struct k3MEvent newev = { + .code = k3M_EVENT_MEASURE, + .kind = k3M_EVENTKIND_DIRECT, + + .original = (void*) this, + .target = (void*) this, + }; + if(!k3MEventSend(&newev)) { + this->wDesired = this->w; + this->hDesired = this->h; + } +} + +void k3MArrange(struct k3MObj *this) { + struct k3MEvent newev = { + .code = k3M_EVENT_ARRANGE, + .kind = k3M_EVENTKIND_DIRECT, + + .original = (void*) this, + .target = (void*) this, + }; + k3MEventSend(&newev); + + for(size_t c = 0; c < this->childCount; c++) { + k3MArrange(this->children[c]); + } +} + +static bool linear_measure(struct k3MEvent *ev, uint8_t *ud) { + struct k3MObj *o = ev->target; + + o->wDesired = 0; + o->hDesired = 0; + + for(size_t i = 0; i < o->childCount; i++) { + struct k3MObj *c = o->children[i]; + + if(o->wDesired < c->wDesired) { + o->wDesired = c->wDesired; + } + + o->hDesired += c->hDesired; + } +} +static bool linear_arrange(struct k3MEvent *ev, uint8_t *ud) { + struct k3MObj *o = ev->target; + + size_t y = o->y; + + for(size_t i = 0; i < o->childCount; i++) { + struct k3MObj *c = o->children[i]; + + c->x = o->x; + c->y = y; + + c->w = c->wDesired; + c->h = c->hDesired; + + y += c->h; + } +} +void k3MSetLayoutLinear(struct k3MObj *this, bool vertical) { + k3MRegisterEventHandler(this, k3M_EVENT_MEASURE, linear_measure, NULL, 0); + k3MRegisterEventHandler(this, k3M_EVENT_ARRANGE, linear_arrange, NULL, 0); +} void k3MenuSetBounds_(struct k3MObj *this, int16_t x, int16_t y, int16_t w, int16_t h) { this->x = x; @@ -38,6 +110,8 @@ int k3MRegisterEventHandler_(struct k3MObj *obj, uint16_t evcode, k3MEventHandle if(ud) { memcpy(obj->handlers[obj->handlerCount - 1].ud, ud, udSize); } + + return 1; } bool k3MEventSend(struct k3MEvent *ev) { @@ -83,10 +157,9 @@ static void obj_draw(struct k3MObj *this) { bgColor[3] = bgColorProp->si[3] / 255.0; } - k3BatchAdd(NULL, (struct k3RectF) {0, 0, 1, 1}, (struct k3RectF) { - this->x, this->y, - this->w, this->h - }, 0, bgColor, borderRadius); + if(bgColor[3] != 0) { + immdraw_fill_rect(this->x, this->y, this->w, this->h, bgColor[0], bgColor[1], bgColor[2], bgColor[3], borderRadius); + } } static bool label_draw(struct k3MEvent *ev, uint8_t *ud) { @@ -95,7 +168,13 @@ static bool label_draw(struct k3MEvent *ev, uint8_t *ud) { obj_draw((void*) this); if(this->txt) { - k3FontDraw(this->font, this->x, this->y, this->sz, this->txt, (vec4) {1, 1, 1, 1}); + int alignment = k3M_ALIGN_CENTER; + + struct k3MProperty *prop = k3MFindProperty(this, k3M_PROP_HORIZONTAL_ALIGNMENT, false); + if(prop) alignment = prop->si[0]; + + immdraw_font_draw(this->font, this->x, this->y, this->w, this->sz, strlen(this->txt), this->txt, alignment, + 1, 1, 1, 1); } return false; @@ -105,7 +184,7 @@ struct k3MLabel *k3MLabel(struct k3Font *font, float sz, const char *txt) { struct k3MLabel *ret = calloc(1, sizeof(*ret)); ret->font = font; ret->sz = sz; - ret->txt = txt; + ret->txt = strdup(txt); k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, label_draw, NULL, 0); @@ -260,11 +339,19 @@ static bool textbutton_draw(struct k3MEvent *ev, uint8_t *ud) { obj_draw((void*) this); if(this->txt) { - struct k3RectF txtsz; + /*struct k3RectF txtsz; k3FontSz(this->font, this->sz, this->txt, &txtsz); k3FontDraw(this->font, this->x + this->w / 2 - txtsz.w / 2, this->y, this->sz, this->txt, (vec4) { - 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1}); + 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1});*/ + + int alignment = k3M_ALIGN_CENTER; + + struct k3MProperty *prop = k3MFindProperty(this, k3M_PROP_HORIZONTAL_ALIGNMENT, false); + if(prop) alignment = prop->si[0]; + + immdraw_font_draw(this->font, this->x, this->y, this->w, this->sz, strlen(this->txt), this->txt, alignment, + 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1); } return false; @@ -274,7 +361,7 @@ struct k3MTextButton *k3MTextButton(struct k3Font *font, float sz, const char *t ret->font = font; ret->sz = sz; - ret->txt = txt; + ret->txt = strdup(txt); k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, textbutton_draw, NULL, 0); @@ -287,13 +374,16 @@ static bool textinput_draw(struct k3MEvent *ev, uint8_t *ud) { obj_draw((void*) this); if(this->txt) { - int isPlaceholder = strlen(this->txt) == 0; + bool isPlaceholder = strlen(this->txt) == 0; const char *txt = isPlaceholder ? this->placeholder : this->txt; - struct k3RectF txtsz; + /*struct k3RectF txtsz; k3FontSz(this->font, this->sz, txt, &txtsz); - k3FontDraw(this->font, this->x, this->y, this->sz, txt, (vec4) {1 - 0.5 * isPlaceholder, 1 - 0.5 * isPlaceholder, 1 - 0.5 * isPlaceholder, 1}); + k3FontDraw(this->font, this->x, this->y, this->sz, txt, (vec4) {1 - 0.5 * isPlaceholder, 1 - 0.5 * isPlaceholder, 1 - 0.5 * isPlaceholder, 1});*/ + + immdraw_font_draw(this->font, this->x, this->y, this->w, this->sz, strlen(txt), txt, k3M_ALIGN_LEFT, + 1 - 0.5 * isPlaceholder, 1 - 0.5 * isPlaceholder, 1 - 0.5 * isPlaceholder, 1); } return false; @@ -302,7 +392,7 @@ static bool textinput_key(struct k3MEvent *ev, uint8_t *ud) { struct k3MTextInput *this = (void*) ev->target; if(ev->key.num == GLFW_KEY_BACKSPACE && ev->code != k3M_EVENT_KEY_RELEASE) { - char *last = k3UTF8LastCodepointZ(this->txt); + char *last = (char*) k3UTF8LastCodepointZ(this->txt); if(last) { *last = 0; } @@ -336,7 +426,7 @@ struct k3MTextInput *k3MTextInput(struct k3Font *font, float sz, const char *pla ret->font = font; ret->sz = sz; - ret->placeholder = placeholder ? placeholder : ""; + ret->placeholder = strdup(placeholder ? placeholder : ""); ret->txt = strdup(txt ? txt : ""); k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, textinput_draw, NULL, 0); diff --git a/src/k3menu.h b/src/k3menu.h index 684dda0..8c1b947 100644 --- a/src/k3menu.h +++ b/src/k3menu.h @@ -3,8 +3,9 @@ #include #include #include -#include"k3font.h" +#include +struct k3Font; struct k3MObj; #define k3M_EVENT_MOUSE_ENTER 0 @@ -18,7 +19,9 @@ struct k3MObj; #define k3M_EVENT_INPUT 8 #define k3M_EVENT_DRAW 9 #define k3M_EVENT_COMPLETE 10 -#define k3M_EVENT_ALL 11 +#define k3M_EVENT_MEASURE 11 +#define k3M_EVENT_ARRANGE 12 +#define k3M_EVENT_ALL 13 #define k3M_MOUSE_BUTTON_0 0 #define k3M_MOUSE_BUTTON_1 1 @@ -30,6 +33,16 @@ struct k3MObj; #define k3M_USERDATA_SIZE 16 +#define k3M_ALIGN_LEFT 0 +#define k3M_ALIGN_CENTER 1 +#define k3M_ALIGN_RIGHT 2 + +#ifdef k3M_FIXED_POINT +typedef uint8_t k3MCC; +#else +typedef float k3MCC; +#endif + struct k3MEvent { uint16_t code; @@ -64,6 +77,8 @@ typedef struct k3MEventHandler { enum k3MPropertyType { k3M_PROP_BG_COLOR, k3M_PROP_BORDER_RADIUS, + k3M_PROP_MARGIN, + k3M_PROP_HORIZONTAL_ALIGNMENT, }; struct k3MProperty { enum k3MPropertyType type; @@ -85,6 +100,9 @@ struct k3MObj { int16_t w; int16_t h; + int16_t wDesired; + int16_t hDesired; + bool invisible, hovered, disabled; k3MEventHandler *handlers; @@ -93,6 +111,16 @@ struct k3MObj { struct k3MProperty *properties; size_t propertyCount; }; +struct k3MObj *k3MObj(); + +/* Akin to the measure pass of WPF. Recursive, called by parent. Sets wDesired and hDesired. */ +void k3MMeasure(struct k3MObj *this); + +/* Akin to the arrange pass of WPF. Recursive, called by parent after w and h is set. Adjusts all children using it's own definitive size. */ +void k3MArrange(struct k3MObj *this); + +/* Set linear layout management on this object. Must not be called on descendants of k3MObj. */ +void k3MSetLayoutLinear(struct k3MObj *this, bool vertical); #define k3MenuSetBounds(a, x, y, w, h) k3MenuSetBounds_((struct k3MObj*) (a), (x), (y), (w), (h)) void k3MenuSetBounds_(struct k3MObj *this, int16_t x, int16_t y, int16_t w, int16_t h);