yup layouting...stil need to clean up a few things

main
Patrick Cleavelin 2024-03-18 17:04:48 -05:00
parent 74e3821233
commit 46dd862512
2 changed files with 132 additions and 64 deletions

View File

@ -307,33 +307,36 @@ void ed_init() {
}, },
}); });
queue_text(_String("But what even is text! []!@#$%^&*()_=+"), (float[]){ 0, 0 }); // queue_text(_String("But what even is text! []!@#$%^&*()_=+"), (float[]){ 0, 0 });
queue_text(_String("v0.1.0"), (float[]){ 32, 128 }); // queue_text(_String("v0.1.0"), (float[]){ 32, 128 });
queue_text(_String("an_editor - what even"), (float[]){ 32, 256 }); // queue_text(_String("an_editor - what even"), (float[]){ 32, 256 });
state.ui_cx = init_ui_context(); state.ui_cx = ui_init_context();
}
void ed_frame() {
string label = _String("Number 1"); string label = _String("Number 1");
ht_set(&state.ui_cx.cached_elements, label, &(ui_element_cache_data) { ui_element(&state.ui_cx, label);
.label = label, ui_element(&state.ui_cx, _String("ui element 2"));
.size = { ui_element(&state.ui_cx, _String("ui element 3"));
.axis = UI_AXIS_HORIZONTAL,
.computed_size = { 200, 256 },
}
});
ui_compute_layout(&state.ui_cx, 0);
state.ui_cx.frame_elements.data[0].size.computed_size[0] = sapp_width();
state.ui_cx.frame_elements.data[0].size.computed_size[1] = sapp_height();
ui_update_cache(&state.ui_cx, 0);
state.gpu_glyphs.size = 0;
for (size_t i = 0; i < state.ui_cx.cached_elements.capacity; ++i) { for (size_t i = 0; i < state.ui_cx.cached_elements.capacity; ++i) {
if (state.ui_cx.cached_elements.key_slots[i].key.data != NULL) { if (state.ui_cx.cached_elements.key_slots[i].key.data != NULL) {
string text = state.ui_cx.cached_elements.key_slots[i].key; string text = state.ui_cx.cached_elements.key_slots[i].key;
ui_element_cache_data *value = ht_get(&state.ui_cx.cached_elements, text); ui_element_cache_data *value = ht_get(&state.ui_cx.cached_elements, text);
if (value) { if (value) {
queue_text(text, (float[]){ (float)value->size.computed_size[0], (float)value->size.computed_size[1] }); queue_text(text, (float[]){ (float)value->size.computed_pos[0], (float)value->size.computed_pos[1] });
} }
} }
} }
}
void ed_frame() {
if (state.gpu_glyphs.size > 0) { if (state.gpu_glyphs.size > 0) {
sg_update_buffer(state.bind.vertex_buffers[1], &(sg_range) { sg_update_buffer(state.bind.vertex_buffers[1], &(sg_range) {
.ptr = state.gpu_glyphs.data, .ptr = state.gpu_glyphs.data,

165
src/ui.h
View File

@ -9,7 +9,7 @@
#define _FONT_WIDTH 16 #define _FONT_WIDTH 16
#define _FONT_HEIGHT 32 #define _FONT_HEIGHT 32
#define _elm(index) (&cx->frame_elements.data[index]) #define _elm(index) (cx->frame_elements.data+index)
#define _flags(index, flgs) ((_elm(index)->flags & (flgs)) == (flgs)) #define _flags(index, flgs) ((_elm(index)->flags & (flgs)) == (flgs))
#define _first(index) (_elm(index)->first) #define _first(index) (_elm(index)->first)
@ -110,11 +110,29 @@ void ui_compute_layout(ui_context *cx, size_t element_index);
#ifdef ED_UI_IMPLEMENTATION #ifdef ED_UI_IMPLEMENTATION
ui_context init_ui_context() { ui_context ui_init_context() {
ed_ht cached_elements = ht_create(MAX_UI_ELEMENTS, sizeof(ui_element_cache_data)); ed_ht cached_elements = ht_create(MAX_UI_ELEMENTS, sizeof(ui_element_cache_data));
array(ui_element_frame_data) frame_elements = newArray(ui_element_frame_data, MAX_UI_ELEMENTS); array(ui_element_frame_data) frame_elements = newArray(ui_element_frame_data, MAX_UI_ELEMENTS);
array(ui_element_frame_data) frame_floating_elements = newArray(ui_element_frame_data, MAX_UI_ELEMENTS); array(ui_element_frame_data) frame_floating_elements = newArray(ui_element_frame_data, MAX_UI_ELEMENTS);
ui_element_frame_data frame_data = (ui_element_frame_data) {
.index = 0,
// TODO: don't just set this to label, because then elements
// with the same label can't be created together
.key = _String("root"),
.label = _String("root"),
.first = -1,
.last = -1,
.next = -1,
.prev = -1,
.parent = -1,
.size = {
.axis = UI_AXIS_HORIZONTAL,
.computed_size = { 640, 480 },
}
};
pushArray(ui_element_frame_data, &frame_elements, frame_data);
return (ui_context) { return (ui_context) {
.cached_elements = cached_elements, .cached_elements = cached_elements,
.frame_elements = frame_elements, .frame_elements = frame_elements,
@ -135,6 +153,8 @@ size_t ui_element(ui_context *cx, string label) {
.next = -1, .next = -1,
.prev = cx->frame_elements.data[cx->current_parent].last, .prev = cx->frame_elements.data[cx->current_parent].last,
.parent = cx->current_parent, .parent = cx->current_parent,
.size.semantic_size[0].type = UI_SEMANTIC_SIZE_FILL,
.size.semantic_size[1].type = UI_SEMANTIC_SIZE_FILL,
}; };
// Get cached element data // Get cached element data
@ -153,10 +173,10 @@ size_t ui_element(ui_context *cx, string label) {
pushArray(ui_element_frame_data, &cx->frame_elements, frame_data); pushArray(ui_element_frame_data, &cx->frame_elements, frame_data);
if (frame_data.prev >= 0) { if (frame_data.prev < SIZE_MAX) {
_prev_ref(frame_data.index)->next = frame_data.index; _prev_ref(frame_data.index)->next = frame_data.index;
} }
if (_elm(cx->current_parent)->first < 0) { if (_elm(cx->current_parent)->first == SIZE_MAX) {
_elm(cx->current_parent)->first = frame_data.index; _elm(cx->current_parent)->first = frame_data.index;
} }
_elm(cx->current_parent)->last = frame_data.index; _elm(cx->current_parent)->last = frame_data.index;
@ -165,7 +185,9 @@ size_t ui_element(ui_context *cx, string label) {
} }
static uint32_t _ui_ancestor_size(ui_context *cx, size_t element_index, ui_axis axis) { static uint32_t _ui_ancestor_size(ui_context *cx, size_t element_index, ui_axis axis) {
if (element_index < 0 || _parent(element_index) < 0) return 0; if (element_index == SIZE_MAX || _parent(element_index) == SIZE_MAX) {
return cx->frame_elements.data[0].size.computed_size[axis];
}
switch (_parent_ref(element_index)->size.semantic_size[axis].type) { switch (_parent_ref(element_index)->size.semantic_size[axis].type) {
case UI_SEMANTIC_SIZE_FIT_TEXT: case UI_SEMANTIC_SIZE_FIT_TEXT:
@ -214,7 +236,7 @@ static void _ui_compute_simple_layout(ui_context *cx, ui_element_frame_data *elm
static void _ui_compute_children_layout(ui_context *cx, ui_element_frame_data *elm) { static void _ui_compute_children_layout(ui_context *cx, ui_element_frame_data *elm) {
uint32_t child_size[2] = { 0 }; uint32_t child_size[2] = { 0 };
// NOTE: the number of fills for the opposite axis of this box needs to be 1 // NOTE: the number of fills for the opposite axis of this box needs to be 1
// because it will never get incremented in the loop below and cause a divide by zero // because it will never get incremented in the loop below and cause a divide by zero
// and the number of fills for the axis of the box needs to start at zero or else it will // and the number of fills for the axis of the box needs to start at zero or else it will
@ -226,35 +248,39 @@ static void _ui_compute_children_layout(ui_context *cx, ui_element_frame_data *e
uint32_t elm_size[2] = { elm->size.computed_size[0], elm->size.computed_size[1] }; uint32_t elm_size[2] = { elm->size.computed_size[0], elm->size.computed_size[1] };
size_t child_index = elm->first; size_t child_index = elm->first;
do { if (child_index < SIZE_MAX) {
ui_compute_layout(cx, child_index); do {
ui_compute_layout(cx, child_index);
if (_elm(child_index)->size.semantic_size[elm->size.axis].type == UI_SEMANTIC_SIZE_FILL) { if (_elm(child_index)->size.semantic_size[elm->size.axis].type == UI_SEMANTIC_SIZE_FILL) {
num_fills[elm->size.axis] += 1; num_fills[elm->size.axis] += 1;
} else { } else {
child_size[elm->size.axis] += _elm(child_index)->size.computed_size[elm->size.axis]; child_size[elm->size.axis] += _elm(child_index)->size.computed_size[elm->size.axis];
} }
} while ((child_index = _next(child_index)) >= 0); } while ((child_index = _next(child_index)) < SIZE_MAX);
}
child_index = elm->first; child_index = elm->first;
do { if (child_index < SIZE_MAX) {
for (size_t axis = UI_AXIS_HORIZONTAL; axis < UI_AXIS_VERTICAL; ++axis) { do {
if (_elm(child_index)->size.semantic_size[axis].type == UI_SEMANTIC_SIZE_FILL) { for (size_t axis = 0; axis < 2; ++axis) {
_elm(child_index)->size.computed_pos[axis] = (elm_size[axis] - child_size[axis]) / num_fills[axis]; if (_elm(child_index)->size.semantic_size[axis].type == UI_SEMANTIC_SIZE_FILL) {
_elm(child_index)->size.computed_size[axis] = (elm_size[axis] - child_size[axis]) / num_fills[axis];
}
} }
}
ui_compute_layout(cx, child_index); ui_compute_layout(cx, child_index);
} while ((child_index = _next(child_index)) >= 0); } while ((child_index = _next(child_index)) < SIZE_MAX);
}
} }
void ui_compute_layout(ui_context *cx, size_t element_index) { void ui_compute_layout(ui_context *cx, size_t element_index) {
if (element_index <= 0) return; if (element_index == SIZE_MAX) return;
ui_axis axis = UI_AXIS_HORIZONTAL; ui_axis axis = UI_AXIS_HORIZONTAL;
__auto_type elm = _elm(element_index); __auto_type elm = _elm(element_index);
if (_parent(element_index) >= 0 && (_elm(element_index)->flags & UI_FLAG_FLOATING) > 0) { if (_parent(element_index) < SIZE_MAX && !_flags(element_index, UI_FLAG_FLOATING)) {
__auto_type parent = _parent_ref(element_index); __auto_type parent = _parent_ref(element_index);
axis = parent->size.axis; axis = parent->size.axis;
elm->size.computed_pos[0] = parent->size.computed_pos[0]; elm->size.computed_pos[0] = parent->size.computed_pos[0];
@ -264,16 +290,19 @@ void ui_compute_layout(ui_context *cx, size_t element_index) {
// elm->size.computed_pos[axis] += parent.scroll_offset; // elm->size.computed_pos[axis] += parent.scroll_offset;
} }
if (!_flags(element_index, UI_FLAG_FLOATING) && _prev(element_index) >= 0) { if (!_flags(element_index, UI_FLAG_FLOATING) && _prev(element_index) < SIZE_MAX) {
__auto_type prev = _prev_ref(element_index); __auto_type prev = _prev_ref(element_index);
if (prev>= 0) { if (prev >= 0) {
elm->size.computed_pos[axis] = prev->size.computed_pos[axis] + prev->size.computed_size[axis]; elm->size.computed_pos[axis] = prev->size.computed_pos[axis] + prev->size.computed_size[axis];
} }
} }
bool post_compute[2] = { false, false }; bool post_compute[2] = { false, false };
_ui_compute_simple_layout(cx, elm, UI_AXIS_HORIZONTAL, post_compute); // only compute layout for children of root
if (elm->index > 0) {
_ui_compute_simple_layout(cx, elm, axis, post_compute);
}
_ui_compute_children_layout(cx, elm); _ui_compute_children_layout(cx, elm);
// NOTE(pcleavelin): the only difference between these two blocks is the ordering of the switch block // NOTE(pcleavelin): the only difference between these two blocks is the ordering of the switch block
@ -282,41 +311,77 @@ void ui_compute_layout(ui_context *cx, size_t element_index) {
elm->size.computed_size[UI_AXIS_HORIZONTAL] = 0; elm->size.computed_size[UI_AXIS_HORIZONTAL] = 0;
size_t child_index = elm->first; size_t child_index = elm->first;
do { if (child_index < SIZE_MAX) {
__auto_type child = _elm(child_index); do {
__auto_type child = _elm(child_index);
switch (elm->size.axis) { switch (elm->size.axis) {
case UI_AXIS_HORIZONTAL: case UI_AXIS_HORIZONTAL:
elm->size.computed_size[UI_AXIS_HORIZONTAL] += child->size.computed_size[UI_AXIS_HORIZONTAL]; elm->size.computed_size[UI_AXIS_HORIZONTAL] += child->size.computed_size[UI_AXIS_HORIZONTAL];
break; break;
case UI_AXIS_VERTICAL: case UI_AXIS_VERTICAL:
if (child->size.computed_size[UI_AXIS_HORIZONTAL] > elm->size.computed_size[UI_AXIS_HORIZONTAL]) { if (child->size.computed_size[UI_AXIS_HORIZONTAL] > elm->size.computed_size[UI_AXIS_HORIZONTAL]) {
elm->size.computed_size[UI_AXIS_HORIZONTAL] = child->size.computed_size[UI_AXIS_HORIZONTAL]; elm->size.computed_size[UI_AXIS_HORIZONTAL] = child->size.computed_size[UI_AXIS_HORIZONTAL];
} }
break; break;
} }
} while ((child_index = _next(child_index)) >= 0); } while ((child_index = _next(child_index)) < SIZE_MAX);
}
} }
if (post_compute[UI_AXIS_VERTICAL]) { if (post_compute[UI_AXIS_VERTICAL]) {
elm->size.computed_size[UI_AXIS_VERTICAL] = 0; elm->size.computed_size[UI_AXIS_VERTICAL] = 0;
size_t child_index = elm->first; size_t child_index = elm->first;
if (child_index < SIZE_MAX) {
do {
__auto_type child = _elm(child_index);
switch (elm->size.axis) {
case UI_AXIS_HORIZONTAL:
if (child->size.computed_size[UI_AXIS_VERTICAL] > elm->size.computed_size[UI_AXIS_VERTICAL]) {
elm->size.computed_size[UI_AXIS_VERTICAL] = child->size.computed_size[UI_AXIS_VERTICAL];
}
break;
case UI_AXIS_VERTICAL:
elm->size.computed_size[UI_AXIS_VERTICAL] += child->size.computed_size[UI_AXIS_VERTICAL];
break;
}
} while ((child_index = _next(child_index)) < SIZE_MAX);
}
}
}
void ui_update_cache(ui_context *cx, size_t element_index) {
if (element_index == SIZE_MAX) return;
size_t child_index = _elm(element_index)->first;
if (child_index < SIZE_MAX) {
do { do {
__auto_type child = _elm(child_index); __auto_type child = _elm(child_index);
switch (elm->size.axis) { ht_set(&cx->cached_elements, child->key, &(ui_element_cache_data) {
case UI_AXIS_HORIZONTAL: .label = child->label,
if (child->size.computed_size[UI_AXIS_VERTICAL] > elm->size.computed_size[UI_AXIS_VERTICAL]) { .size = {
elm->size.computed_size[UI_AXIS_VERTICAL] = child->size.computed_size[UI_AXIS_VERTICAL]; .axis = child->size.axis,
} .semantic_size = { child->size.semantic_size[0], child->size.semantic_size[1] },
break; .computed_size = { child->size.computed_size[0], child->size.computed_size[1] },
case UI_AXIS_VERTICAL: .computed_pos = { child->size.computed_pos[0], child->size.computed_pos[1] },
elm->size.computed_size[UI_AXIS_VERTICAL] += child->size.computed_size[UI_AXIS_VERTICAL]; }
break; // FIXME: don't mangle last_instantiated_index
} });
} while ((child_index = _next(child_index)) >= 0);
ui_update_cache(cx, child_index);
} while ((child_index = _next(child_index)) < SIZE_MAX);
} }
cx->frame_elements.size = 1;
cx->frame_elements.data[0].first = SIZE_MAX;
cx->frame_elements.data[0].prev = SIZE_MAX;
cx->frame_elements.data[0].next = SIZE_MAX;
cx->frame_elements.data[0].last = SIZE_MAX;
cx->frame_elements.data[0].parent = SIZE_MAX;
cx->current_parent = 0;
} }
#endif #endif