milsko/src/widget/table.c
2026-05-22 09:19:19 +09:00

227 lines
4.7 KiB
C

#include <Mw/Milsko.h>
#include "../../external/stb_ds.h"
static int wcreate(MwWidget handle) {
MwTable t = malloc(sizeof(*t));
memset(t, 0, sizeof(*t));
handle->internal = t;
MwSetDefault(handle);
MwSetInteger(handle, MwNcolumns, 1);
MwSetInteger(handle, MwNmargin, 0);
MwSetInteger(handle, MwNpadding, 0);
MwSetInteger(handle, MwNhasBorder, 0);
MwSetInteger(handle, MwNinverted, 1);
MwSetInteger(handle, MwNwaitLayout, 0);
t->layout = 0;
return 0;
}
static void destroy(MwWidget handle) {
MwTable t = handle->internal;
arrfree(t->widgets);
free(t);
}
typedef struct intkv {
int key;
int value;
} intkv_t;
static void put_intkv(intkv_t** kv, int x, int y, int c, int r) {
int k = (x << 16) | y;
int v = (c << 16) | r;
hmput(*kv, k, v);
}
static int get_intkv(intkv_t* kv, int x, int y) {
int k = (x << 16) | y;
return hmget(kv, k);
}
#define LAYOUT_BEGIN \
hmfree(kv); \
hmdefault(kv, 0); \
n = 0; \
x = bw; \
y = bw; \
for(i = 0; i < arrlen(handle->children); i++) { \
MwRect rc; \
MwWidget hc = handle->children[i]; \
int cs = MwGetInteger(hc, MwNcolumnSpan); \
int rs = MwGetInteger(hc, MwNrowSpan); \
int w, h; \
int cy; \
int s = MwGetInteger(handle, MwNmargin); \
int v = n; \
\
if(cs == MwDEFAULT) cs = 1; \
if(rs == MwDEFAULT) rs = 1; \
\
w = cs * cw + (cs - 1) * s; \
h = rs * ch + (rs - 1) * s; \
\
MwGetFrame(hc, &rc); \
\
if(hc == child || rc.x != x || rc.y != y || rc.width != w || rc.height != h) {
#define LAYOUT_END(label) \
} \
\
put_intkv(&kv, n % c, n / c, cs, rs); \
\
n += cs; \
repeat_##label :; \
if((n % c) == 0) { \
x = bw; \
y += ch + s; \
} else { \
for(; v < n; v++) { \
x += cw + s; \
} \
} \
\
for(cy = (n / c); cy >= 0; cy--) { \
int v = get_intkv(kv, n % c, cy) & 0xffff; \
\
if(cy <= (n / c) && (n / c) <= (cy + v - 1)) { \
v = n; \
n += get_intkv(kv, n % c, cy) >> 16; \
goto repeat_##label; \
} \
} \
}
static void layout_widget(MwWidget handle, MwWidget child) {
int i;
int c = MwGetInteger(handle, MwNcolumns);
int bw = (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0) + MwGetInteger(handle, MwNpadding);
int m = MwGetInteger(handle, MwNmargin);
int n, x, y, cw = 0, ch = 0;
int gcs;
intkv_t* kv = NULL;
LAYOUT_BEGIN;
LAYOUT_END(1);
gcs = (n + c - 1) / c;
cw = (MwGetInteger(handle, MwNwidth) - bw * 2 - (m * (c - 1))) / c;
ch = (MwGetInteger(handle, MwNheight) - m * (gcs - 1) - bw * 2) / gcs;
LAYOUT_BEGIN;
MwVaApply(hc,
MwNx, x,
MwNy, y,
MwNwidth, w,
MwNheight, h,
NULL);
LAYOUT_END(2);
hmfree(kv);
}
static void layout(MwWidget handle) {
MwTable t = handle->internal;
int i;
if(arrlen(t->widgets) > 0) {
for(i = 0; i < arrlen(t->widgets); i++) layout_widget(handle, t->widgets[i]);
} else {
for(i = 0; i < arrlen(handle->children[i]); i++) layout_widget(handle, handle->children[i]);
}
}
static void draw(MwWidget handle) {
MwBoxClass->draw(handle);
}
static void tick(MwWidget handle) {
MwTable t = handle->internal;
if(t->layout && !MwGetInteger(handle, MwNwaitLayout)) {
layout(handle);
t->layout = 0;
}
}
static void prop_change(MwWidget handle, const char* key) {
if(strcmp(key, MwNcolumns) == 0 || strcmp(key, MwNhasBorder) == 0 || strcmp(key, MwNinverted) == 0 || strcmp(key, MwNpadding) == 0 || strcmp(key, MwNmargin) == 0) {
MwTable t = handle->internal;
t->layout = 1;
MwForceRender(handle);
}
}
static void resize(MwWidget handle) {
MwTable t = handle->internal;
t->layout = 1;
MwForceRender(handle);
}
static void children_update(MwWidget handle, MwWidget child, int new_child) {
MwTable t = handle->internal;
t->layout = 1;
if(new_child) {
arrput(t->widgets, child);
} else {
int i;
for(i = 0; i < arrlen(t->widgets); i++) {
if(t->widgets[i] == child) {
arrdel(t->widgets, i);
i = -1;
}
}
}
MwForceRender(handle);
}
static void children_prop_change(MwWidget handle, MwWidget child, const char* key) {
(void)child;
if(strcmp(key, MwNcolumnSpan) == 0 || strcmp(key, MwNrowSpan) == 0) {
MwTable t = handle->internal;
t->layout = 1;
arrput(t->widgets, child);
MwForceRender(handle);
}
}
MwClassRec MwTableClassRec = {
wcreate, /* create */
destroy, /* destroy */
draw, /* draw */
NULL, /* click */
NULL, /* parent_resize */
prop_change, /* prop_change */
NULL, /* mouse_move */
NULL, /* mouse_up */
NULL, /* mouse_down */
NULL, /* key */
NULL, /* execute */
tick, /* tick */
resize, /* resize */
children_update, /* children_update */
children_prop_change, /* children_prop_change */
NULL, /* clipboard */
NULL, /* props_change */
NULL,
NULL,
NULL};
MwClass MwTableClass = &MwTableClassRec;