Last active
December 15, 2021 22:37
-
-
Save vurtun/193fe21103f01fabac5df8d480daca3e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} |
Author
vurtun
commented
Nov 22, 2020
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment