Skip to content

Instantly share code, notes, and snippets.

@vurtun
Last active December 15, 2021 22:37
Show Gist options
  • Save vurtun/193fe21103f01fabac5df8d480daca3e to your computer and use it in GitHub Desktop.
Save vurtun/193fe21103f01fabac5df8d480daca3e to your computer and use it in GitHub Desktop.
// gui_lay_row(ctx, 3, (int[]) { 30, -90, -1 }, 0);
/* Layout */
enum gui_lay_dir {
GUI_ROW,
GUI_COL,
};
struct gui_lay_sol {
int fix_siz;
int fix_cnt;
int dyn_siz;
int dyn_cnt;
float weight;
};
struct gui_lay_con {
const int min;
const int max;
};
enum gui_flow {
GUI_FLOW_STRAIGHT,
GUI_FLOW_WRAP
};
struct gui_lay {
struct gui_box box; /* in */
/* flex */
int fixed;
int *ref;
int x,y;
int max;
int space;
/* fixed */
int gap[2], pad[2];
enum gui_lay_dir orient;
enum gui_flow flow;
int siz, cnt;
const int *slots;
int begin[2];
int at[2];
int idx;
};
static void
gui_lay_setup(struct gui_lay *lay, enum gui_lay_dir dir, int siz)
{
assert(lay);
lay->idx = 0;
lay->siz = siz;
lay->orient = dir;
lay->at[0] = lay->box.x.min + lay->pad[0];
lay->at[1] = lay->box.y.min + lay->pad[1];
lay->begin[0] = lay->at[0];
lay->begin[1] = lay->at[1];
switch(dir) {
case GUI_ROW: {
lay->space = lay->box.x.ext;
lay->ref = &lay->box.x;
lay->fixed = siz;
} break;
case GUI_COL: {
lay->space = lay->box.y.ext;
lay->ref = &lay->box.y;
lay->fixed = siz;
} break;}
}
static void
gui_lay_init(struct gui_ctx *ctx, struct gui_flx_box *lay,
enum gui_lay_dir dir, int cnt, const int *vals, int siz)
{
assert(lay);
assert(vals);
assert(cnt);
lay->cnt = cnt;
lay->slots = vals;
lay->gap[0] = ctx->cfg.gap[0];
lay->gap[1] = ctx->cfg.gap[1];
lay->pad[0] = ctx->cfg.pad[0];
lay->pad[1] = ctx->cfg.pad[1];
gui_lay_setup(lay, dir, siz);
}
static void
gui_lay_gen(struct gui_lay *lay, struct gui_box *box, int siz)
{
assert(ctx);
assert(lay);
assert(box);
if (lay->slots) {
/* allocate space from fixed layout */
lay->idx = lay->idx % lay->cnt;
switch (lay->orient) {
default: assert(0); break;
case GUI_ROW: {
*b = gui_box(lay->at[0], lay->at[1], lay->slots[lay->idx], lay->siz);
lay->at[0] += b->x.ext + lay->gap[0];
} break;
case GUI_COL: {
*b = gui_box(lay->at[0], lay->at[1], lay->siz, lay->slots[lay->idx]);
lay->at[1] += b->y.ext + lay->gap[1];
} break;}
lay->idx++;
} else {
/* allocate space from fixed layout */
switch (lay->dir) {
default: assert(0); break;
case GUI_HORIZONTAL: {
lay->max = min(*lay->at + lay->gap[0] + siz, lay->x + lay->siz);
box->x = gui_min_max(*lay->at + lay->gap[0], lay->max);
box->y = gui_min_ext(lay->y, lay->fixed);
lay->at = !siz ? &lay->max: &box->x.max;
} break;
case GUI_VERTICAL: {
lay->max = min(*lay->at + lay->gap[1] + siz, lay->y + lay->siz);
box->y = gui_min_max(*lay->at + lay->gap[1], lay->max);
box->x = gui_min_ext(lay->x, lay->fixed);
lay->at = !siz ? &lay->max: &box->y.max;
} break;}
/* calculate next layout slot */
if (lay->flow == GUI_FLOW_WRAP) {
switch (lay->orient) {
default: assert(0); break;
case GUI_ROW: {
if (lay->at[0] + lay->slots[lay->idx] + lay->gap[0] > lay->box.x.max) {
lay->at[0] = lay->begin[0];
lay->at[1] += lay->siz + lay->gap[1];
}
} break;
case GUI_COL: {
if (lay->at[1] + lay->slots[lay->idx] + lay->gap[1] > lay->box.y.max) {
lay->at[1] = lay->begin[1];
lay->at[0] += lay->siz + lay->gap[0];
}
} break;}
}
}
}
static void
gui_lay_push(struct gui_lay *lay, struct gui_box *box)
{
assert(ctx);
assert(lay);
assert(box);
assert(lay->slots == 0);
int siz = lay->siz - *lay->ref;
switch (lay->orient) {
default: assert(0); break;
case GUI_ROW:
siz += lay->x;
break;
case GUI_COL:
siz += lay->y;
break;
}
gui_lay_gen(lay,box,max(0,siz));
}
static void
gui_lay_break(struct gui_ctx *ctx, struct gui_lay *lay)
{
assert(ctx);
assert(lay);
assert(lay->slots == 0);
switch (lay->orient) {
default: assert(0); break;
case GUI_ROW: {
lay->at[1] += lay->fixed + lay->gap[1];
lay->at = &lay->x;
} break;
case GUI_COL: {
lay->at[0] += lay->fixed + lay->gap[0];
lay->at = &lay->y;
} break;}
}
static void
gui_lay_solve(int *res, struct gui_flx_box *lay,
const float *slots, int cnt, const struct gui_lay_con *con,
struct gui_lay_sol *sol)
{
assert(res);
assert(lay);
assert(slots);
struct gui_lay_sol dummy;
sol = !sol ? &dummy: sol;
memset(sol, 0, sizeof(*sol));
for (int i = 0; i < cnt; ++i) {
if (slots[i] >= 0.0f) {
sol->dyn_cnt++;
continue;
}
const int siz = cast(int, -slots[i]);
res[i] = con ? clamp(con[i].min, siz, con[i].max): siz;
sol->fix_siz += res[i];
sol->fix_cnt++;
}
const int min = (lay->orient == GUI_ROW) ? lay->at[0]: lay->at[1];
const int max = (lay->orient == GUI_ROW) ? lay->box.x.max : lay->box.y.max;
const int total = max(0, max - min);
if (sol->fix_siz >= total || !sol->dyn_cnt) {
for (int i = 0; i < cnt; ++i) {
if (slots[i] >= 0.0f)
res[i] = con ? con[i].min: 0;
}
}
sol->weight = 0.0f;
sol->dyn_siz = max(0, total - sol->fix_siz);
for (int i = 0; i < cnt; ++i) {
if (slots[i] < 0.0f) continue;
sol->weight += slots[i];
}
int def_dyn_siz = 0;
for (int i = 0; i < cnt; ++i) {
if (slots[i] < 0.0f) continue;
res[i] = cast(int, ((slots[i]/sol->weight) * cast(float, sol->dyn_siz)));
def_dyn_siz += con ? clamp(con[i].min, res[i], con[i].max): res[i];
}
if (def_dyn_siz < sol->dyn_siz) {
int grow_cnt = 0;
float weight = 0.0f;
int grow_siz = def_dyn_siz - sol->dyn_siz;
for (int i = 0; i < cnt; ++i) {
if (slots[i] < 0.0f) continue;
if (res[i] < con[i].max) {
weight += slots[i];
grow_cnt++;
}
}
while (grow_cnt > 0 && grow_siz > 0) {
int nxt_siz = 0;
int nxt_cnt = 0;
float nxt_weight = 0.0f;
for (int i = 0; i < cnt; ++i) {
if (slots[i] < 0.0f) continue;
if (res[i] < con[i].max) {
int siz = cast(int, ((slots[i]/weight) * cast(float, grow_siz)));
if (res[i] + siz > con[i].max) {
nxt_siz += res[i] + siz - con[i].max;
res[i] = con[i].max;
} else {
nxt_weight += slots[i];
res[i] += siz;
nxt_cnt++;
}
}
}
grow_siz = nxt_siz;
grow_cnt = nxt_cnt;
weight = nxt_weight;
}
}
}
static void
gui_lay_row(struct gui_ctx *ctx, struct gui_lay *lay,
const struct gui_box *box, int cnt, const int *vals, int siz)
{
assert(ctx);
assert(lay);
assert(vals);
siz = !siz ? ctx->cfg.item_size : 0;
gui_lay_init(ctx, lay, box, GUI_ROW, cnt, vals, siz);
}
static void
gui_lay_solve_row(struct gui_ctx *ctx, struct gui_lay *lay,
const struct gui_box *box, int cnt, int *res,
const float *slots, int siz, const struct gui_lay_con *con,
struct gui_lay_sol *sol)
{
assert(ctx);
assert(lay);
assert(res);
assert(slots);
siz = !siz ? ctx->cfg.item_size : siz;
gui_lay_row(ctx, lay, box, cnt, res, siz);
gui_lay_solve(res, lay, slots, cnt, con, sol);
}
int main(void)
{
int slots[3];
struct gui_lay lay = {.box = pan->box};
gui_lay_solve_row(ctx, &lay, 3, slots, (float[]){-30.0f, 1.0f, -90.0f}, 0,0,0);
struct gui_btn btn = {0};
gui_lay_gen(&lay, &btn.box, 0);
if (gui_btn_txt(ctx, &btn, "Button", 0))
printf("Button pressed!\n");
struct gui_btn btn = {0};
if (gui_lay_btn_txt(ctx, &lay, &btn, "Button", 0))
printf("Button pressed!\n");
if (gui_lay_btn_txt(ctx, &lay, 0, "Button", 0))
printf("Button pressed!\n");
return 0;
}
@vurtun
Copy link
Author

vurtun commented Nov 22, 2020

dark
steam
win

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment