Skip to content

Instantly share code, notes, and snippets.

@vurtun
Last active December 15, 2021 22:37
Show Gist options
  • Select an option

  • Save vurtun/193fe21103f01fabac5df8d480daca3e to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown
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