diff --git a/src/immdraw.h b/src/immdraw.h index 881a559..b9eb845 100644 --- a/src/immdraw.h +++ b/src/immdraw.h @@ -14,18 +14,7 @@ static inline void immdraw_fill_rect(int16_t x, int16_t y, int16_t w, int16_t h, } static inline void immdraw_font_draw(struct k3Font *font, int16_t x, int16_t y, int16_t w, float sz, size_t len, const char *txt, int alignment, float r, float g, float b, float a) { - struct k3RectF txtsz; - k3FontSz(font, sz, txt, w, &txtsz); - - if(alignment != k3M_ALIGN_LEFT) { - if(alignment == k3M_ALIGN_CENTER) { - x += w / 2.0f - txtsz.w / 2.0f; - } else { - x += w - txtsz.w; - } - } - - k3FontDraw(font, x, GameWndH - y - sz, sz, txt, w, (vec4) {r, g, b, a}); + k3FontDraw(font, x, GameWndH - y - sz, sz, txt, w, alignment, (vec4) {r, g, b, a}); } static inline void immdraw_font_size(struct k3Font *font, float sz, const char *txt, int16_t wall, int16_t aabb[2]) { struct k3RectF txtsz; diff --git a/src/k3font.c b/src/k3font.c index dc75d27..854e0d3 100644 --- a/src/k3font.c +++ b/src/k3font.c @@ -108,7 +108,9 @@ void k3FontSz(struct k3Font *this, float sz, const char *txt, float wall, struct while(1) { uint32_t cp = read_utf8(&txt); - if(!cp) break; + if(cp == 0) { + break; + } if(cp == 10) { x = 0; @@ -119,7 +121,7 @@ void k3FontSz(struct k3Font *this, float sz, const char *txt, float wall, struct if(!g) continue; - if(x + g->width > wall) { + if(x + g->width * this->lineScale * sz > wall) { x = 0; y += sz; } @@ -131,45 +133,79 @@ void k3FontSz(struct k3Font *this, float sz, const char *txt, float wall, struct ret->w = maxX; ret->h = y; } -void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const char *txt, float wall, vec4 color) { +void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const char *txt, float wall, int alignment, vec4 color) { if(wall < 0) { wall = HUGE_VALF; } - float x = xStart, y = yStart; + float y = yStart; + while(1) { - uint32_t cp = read_utf8(&txt); + size_t lineLength = 0; - if(!cp) break; + float lineWidth = 0; - if(cp == 10) { - x = xStart; - y -= sz; + uint32_t cp2; + const char *txt2 = txt; + while(1) { + cp2 = read_utf8(&txt2); + if(cp2 == 0 || cp2 == 10) { + break; + } + + lineLength++; + + struct k3FontGlyph *g = k3FontGetGlyph(this, cp2); + if(g) { + if(lineWidth + g->width * this->lineScale * sz > wall) { + break; + } + lineWidth += g->xadvance * this->lineScale * sz; + } } - struct k3FontGlyph *g = k3FontGetGlyph(this, cp); - - if(!g) continue; - - if(x + g->width - xStart > wall) { - x = xStart; - y -= sz; + if(lineLength == 0 && cp2 == 0) { + break; } - struct k3Tex *tex = this->pages[g->page]; - size_t texW = this->texW; - size_t texH = this->texH; + float x = 0; + if(alignment == 0) { + x = xStart; + } else if(alignment == 1) { + x = xStart + (wall - lineWidth) / 2; + } else if(alignment == 2) { + x = xStart + wall - lineWidth; + } - k3BatchAdd(tex, - (struct k3RectF) {(float) g->x / texW, (float) g->y / texH, (float) g->width / texW, (float) g->height / texH}, - (struct k3RectF) { - x + g->xoffset * this->lineScale * sz, - y + ((-g->height - g->yoffset) * this->lineScale + 1) * sz, - g->width * this->lineScale * sz, - g->height * this->lineScale * sz - }, 0, color, 0); + for(size_t i = 0; i < lineLength; i++) { + uint32_t cp = read_utf8(&txt); + + struct k3FontGlyph *g = k3FontGetGlyph(this, cp); + + if(!g) continue; + + struct k3Tex *tex = this->pages[g->page]; + size_t texW = this->texW; + size_t texH = this->texH; + + k3BatchAdd(tex, + (struct k3RectF) {(float) g->x / texW, (float) g->y / texH, (float) g->width / texW, (float) g->height / texH}, + (struct k3RectF) { + x + g->xoffset * this->lineScale * sz, + y + ((-g->height - g->yoffset) * this->lineScale + 1) * sz, + g->width * this->lineScale * sz, + g->height * this->lineScale * sz + }, 0, color, 0); + + x += g->xadvance * this->lineScale * sz; + } - x += g->xadvance * this->lineScale * sz; + // If the line break was caused directly by a LF, skip over it for next line + if(cp2 == 10) { + read_utf8(&txt); + } + + y -= sz; } k3BatchFlush(); } diff --git a/src/k3font.h b/src/k3font.h index b1246eb..3e196d9 100644 --- a/src/k3font.h +++ b/src/k3font.h @@ -4,6 +4,10 @@ #include"k3batch.h" #include +#define k3_FONT_ALIGN_LEFT 0 +#define k3_FONT_ALIGN_CENTER 1 +#define k3_FONT_ALIGN_RIGHT 2 + struct k3FontGlyph { uint32_t cp; uint16_t x; @@ -39,7 +43,7 @@ struct k3Font *k3FontCreate(); int k3FontLoad(struct k3Font*, const uint8_t *buf, size_t len, k3FontTexLoader); void k3FontSz(struct k3Font*, float sz, const char *txt, float wall, struct k3RectF *ret); -void k3FontDraw(struct k3Font*, float x, float y, float sz, const char *txt, float wall, vec4 color); +void k3FontDraw(struct k3Font*, float x, float y, float sz, const char *txt, float wall, int alignment, vec4 color); struct k3FontGlyph *k3FontGetGlyph(struct k3Font*, uint32_t cp); diff --git a/src/k3menu.c b/src/k3menu.c index db5ac15..dd9c997 100644 --- a/src/k3menu.c +++ b/src/k3menu.c @@ -54,6 +54,7 @@ static bool linear_measure(struct k3MEvent *ev, uint8_t *ud) { o->wDesired = 0; o->hDesired = 0; + intmax_t prevChildMargin[4] = {}; for(size_t i = 0; i < o->childCount; i++) { struct k3MObj *c = o->children[i]; @@ -61,7 +62,19 @@ static bool linear_measure(struct k3MEvent *ev, uint8_t *ud) { o->wDesired = c->wDesired; } - o->hDesired += c->hDesired; + intmax_t margin[4] = {}; + struct k3MProperty *prop = k3MFindProperty(o, k3M_PROP_MARGIN, true); + if(prop) { + for(int s = 0; s < 4; s++) { + if(prop->units[s] == k3M_UNIT_ABSOLUTE) { + margin[s] = prop->f[s]; + } else if(prop->units[s] == k3M_UNIT_PROPORTION && o->parent) { + margin[s] = prop->f[s] * (s % 2 == 0 ? o->h : o->w); + } + } + } + + o->hDesired += margin[0] + c->hDesired + margin[2]; } } static bool linear_arrange(struct k3MEvent *ev, uint8_t *ud) { @@ -87,7 +100,9 @@ static bool linear_arrange(struct k3MEvent *ev, uint8_t *ud) { c->x = o->x + padding[3]; c->y = y; - c->w = o->w - padding[1] - padding[3]; + if(c->w > o->w - padding[1] - padding[3]) { + c->w = o->w - padding[1] - padding[3]; + } if(!k3MEventSend(&(struct k3MEvent) {.original = o, .target = c, .code = k3M_EVENT_SET_HEIGHT_FROM_WIDTH})) { c->h = c->hDesired; @@ -213,21 +228,48 @@ static bool label_draw(struct k3MEvent *ev, uint8_t *ud) { obj_draw_direct((void*) this); if(this->txt) { - int alignment = k3M_ALIGN_CENTER; - - struct k3MProperty *propHA = k3MFindProperty(this, k3M_PROP_HORIZONTAL_ALIGNMENT, false); - if(propHA) alignment = propHA->si[0]; - float sz = this->sz; - struct k3MProperty *fontSize = k3MFindProperty(this, k3M_PROP_FONT_SIZE, false); - if(fontSize) sz = fontSize->f[0]; + struct k3MProperty *prop = k3MFindProperty(this, k3M_PROP_FONT_SIZE, false); + if(prop) sz = prop->f[0]; - immdraw_font_draw(this->font, this->x, this->y, this->w, sz, strlen(this->txt), this->txt, alignment, + int ha = k3M_ALIGN_LEFT; + prop = k3MFindProperty(this, k3M_PROP_HORIZONTAL_ALIGNMENT, false); + if(prop) ha = prop->si[0]; + + int va = k3M_ALIGN_CENTER; + prop = k3MFindProperty(this, k3M_PROP_VERTICAL_ALIGNMENT, false); + if(prop) va = prop->si[0]; + + int16_t x = this->x; + int16_t y = this->y; + + if(va != k3M_ALIGN_TOP) { + struct k3RectF txtsz; + k3FontSz(this->font, this->sz, this->txt, this->w, &txtsz); + if(va == k3M_ALIGN_CENTER) { + y += (this->h - txtsz.h) / 2; + } else if(va == k3M_ALIGN_BOTTOM) { + y += this->h - txtsz.h; + } + } + + immdraw_font_draw(this->font, x, y, this->w, sz, strlen(this->txt), this->txt, ha, 1, 1, 1, 1); } return false; } +static bool label_measure(struct k3MEvent *ev, uint8_t *ud) { + struct k3MLabel *this = (void*) ev->target; + + struct k3RectF txtsz; + k3FontSz(this->font, this->sz, this->txt, -1, &txtsz); + + this->w = ceilf(txtsz.w); + this->h = ceilf(txtsz.h); + + return false; +} static bool label_set_height_from_width(struct k3MEvent *ev, uint8_t *ud) { struct k3MLabel *this = (void*) ev->target; @@ -245,12 +287,9 @@ struct k3MLabel *k3MLabel(struct k3Font *font, float sz, const char *txt) { ret->txt = strdup(txt); k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, label_draw, NULL, 0); + k3MRegisterEventHandler(ret, k3M_EVENT_MEASURE, label_measure, NULL, 0); k3MRegisterEventHandler(ret, k3M_EVENT_SET_HEIGHT_FROM_WIDTH, label_set_height_from_width, NULL, 0); - //int16_t lblsz[2]; - //immdraw_font_size(font, sz, txt, lblsz); - //ret->w = lblsz[0]; - //ret->h = lblsz[1]; return ret; } @@ -379,16 +418,22 @@ static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) { this->keyboardFocus = innermost; } - ev->kind = k3M_EVENTKIND_BUBBLE; - ev->target = innermost; - k3MEventSend(ev); + k3MEventSend(&(struct k3MEvent) { + .code = ev->code, + .kind = k3M_EVENTKIND_BUBBLE, + .original = ev->original, + .target = innermost, + .mouse = ev->mouse, + }); if(ev->code == k3M_EVENT_MOUSE_RELEASE) { - ev->code = k3M_EVENT_MOUSE_CLICK; - - ev->kind = k3M_EVENTKIND_DIRECT; - ev->target = innermost; - k3MEventSend(ev); + k3MEventSend(&(struct k3MEvent) { + .code = k3M_EVENT_MOUSE_CLICK, + .kind = k3M_EVENTKIND_DIRECT, + .original = ev->original, + .target = innermost, + .mouse = ev->mouse, + }); } } @@ -397,20 +442,25 @@ static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) { } else if(ev->code == k3M_EVENT_KEY_PRESS || ev->code == k3M_EVENT_KEY_RELEASE || ev->code == k3M_EVENT_INPUT) { if(this->keyboardFocus) { - ev->kind = k3M_EVENTKIND_BUBBLE; - ev->target = (void*) this->keyboardFocus; - k3MEventSend(ev); + k3MEventSend(&(struct k3MEvent) { + .code = ev->code, + .kind = k3M_EVENTKIND_BUBBLE, + .original = ev->original, + .target = this->keyboardFocus, + .key = ev->key, + }); } return true; } - ev->kind = k3M_EVENTKIND_CAPTURE; for(intmax_t i = this->childCount - 1; i >= 0; i--) { if(!this->children[i]->invisible) { - ev->target = this->children[i]; - if(k3MEventSend(ev)) { + struct k3MEvent newev = *ev; + newev.kind = k3M_EVENTKIND_CAPTURE; + newev.target = this->children[i]; + if(k3MEventSend(&newev)) { return true; } } @@ -492,23 +542,44 @@ static bool textbutton_draw(struct k3MEvent *ev, uint8_t *ud) { obj_draw_direct((void*) this); if(this->txt) { - /*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});*/ - - int alignment = k3M_ALIGN_CENTER; - + int ha = k3M_ALIGN_CENTER; struct k3MProperty *prop = k3MFindProperty(this, k3M_PROP_HORIZONTAL_ALIGNMENT, false); - if(prop) alignment = prop->si[0]; + if(prop) ha = prop->si[0]; - immdraw_font_draw(this->font, this->x, this->y, this->w, this->sz, strlen(this->txt), this->txt, alignment, + int va = k3M_ALIGN_CENTER; + prop = k3MFindProperty(this, k3M_PROP_VERTICAL_ALIGNMENT, false); + if(prop) va = prop->si[0]; + + int16_t x = this->x; + int16_t y = this->y; + + if(va != k3M_ALIGN_TOP) { + struct k3RectF txtsz; + k3FontSz(this->font, this->sz, this->txt, this->w, &txtsz); + if(va == k3M_ALIGN_CENTER) { + y += (this->h - txtsz.h) / 2; + } else if(va == k3M_ALIGN_BOTTOM) { + y += this->h - txtsz.h; + } + } + + immdraw_font_draw(this->font, x, y, this->w, this->sz, strlen(this->txt), this->txt, ha, 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1); } return false; } +static bool textbutton_measure(struct k3MEvent *ev, uint8_t *ud) { + struct k3MTextButton *this = (void*) ev->target; + + struct k3RectF sz = {}; + k3FontSz(this->font, this->sz, this->txt, -1, &sz); + + this->w = ceilf(sz.w); + this->h = ceilf(sz.h); + + return false; +} struct k3MTextButton *k3MTextButton(struct k3Font *font, float sz, const char *txt) { struct k3MTextButton *ret = calloc(1, sizeof(*ret)); @@ -516,6 +587,7 @@ struct k3MTextButton *k3MTextButton(struct k3Font *font, float sz, const char *t ret->sz = sz; ret->txt = strdup(txt); + k3MRegisterEventHandler(ret, k3M_EVENT_MEASURE, textbutton_measure, NULL, 0); k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, textbutton_draw, NULL, 0); return ret;