layout optimizations
This commit is contained in:
parent
ec15ed6f9f
commit
e659e6f3e2
5 changed files with 67 additions and 22 deletions
2
Makefile
2
Makefile
|
@ -13,7 +13,7 @@ OBJS=$(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SRCS))
|
||||||
DEPS=$(OBJS:%.o=%.d)
|
DEPS=$(OBJS:%.o=%.d)
|
||||||
|
|
||||||
|
|
||||||
all: CFLAGS+=-fsanitize=address -Og -ggdb
|
all: CFLAGS+=-Og -ggdb
|
||||||
all: $(BUILD) $(BIN)
|
all: $(BUILD) $(BIN)
|
||||||
|
|
||||||
release: CFLAGS+=-O2 -flto=auto -DNDEBUG -ggdb
|
release: CFLAGS+=-O2 -flto=auto -DNDEBUG -ggdb
|
||||||
|
|
|
@ -76,7 +76,7 @@ int box_layout_handle(UINode *component, enum UIEvent ev, size_t d, void *p)
|
||||||
((UIRect*)p)->w = is_horizontal ? size : maximum_secondary_position;
|
((UIRect*)p)->w = is_horizontal ? size : maximum_secondary_position;
|
||||||
((UIRect*)p)->h = is_vertical ? size : maximum_secondary_position;
|
((UIRect*)p)->h = is_vertical ? size : maximum_secondary_position;
|
||||||
|
|
||||||
return UI_NODE_COMPUTED_EXTENTS_OK;
|
return UI_NODE_COMPUTED_EXTENTS_CACHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_fixed_for_primary_direction = (is_horizontal && node->width_policy != UI_SIZE_POLICY_COMPUTED) || (is_vertical && node->height_policy != UI_SIZE_POLICY_COMPUTED);
|
bool is_fixed_for_primary_direction = (is_horizontal && node->width_policy != UI_SIZE_POLICY_COMPUTED) || (is_vertical && node->height_policy != UI_SIZE_POLICY_COMPUTED);
|
||||||
|
@ -112,42 +112,50 @@ int box_layout_handle(UINode *component, enum UIEvent ev, size_t d, void *p)
|
||||||
UINode *current = node->nodes[i];
|
UINode *current = node->nodes[i];
|
||||||
if (current->flags & UI_NODE_COMPONENT) continue;
|
if (current->flags & UI_NODE_COMPONENT) continue;
|
||||||
|
|
||||||
|
UIRect updated_rect = current->rect;
|
||||||
|
|
||||||
if (is_horizontal) {
|
if (is_horizontal) {
|
||||||
if (current->width_policy == UI_SIZE_POLICY_GROW) {
|
if (current->width_policy == UI_SIZE_POLICY_GROW) {
|
||||||
current->rect.w = distributes_growing_widgets ? size_per_growing_widget : 0;
|
updated_rect.w = distributes_growing_widgets ? size_per_growing_widget : 0;
|
||||||
}
|
}
|
||||||
if (current->height_policy == UI_SIZE_POLICY_GROW) {
|
if (current->height_policy == UI_SIZE_POLICY_GROW) {
|
||||||
current->rect.h = maximum_secondary_position;
|
updated_rect.h = maximum_secondary_position;
|
||||||
}
|
}
|
||||||
if (current_index) {
|
if (current_index) {
|
||||||
x += gap;
|
x += gap;
|
||||||
}
|
}
|
||||||
current->rect.x = x;
|
updated_rect.x = x;
|
||||||
if (box_layout_node->justify_secondary == UI_BOX_LAYOUT_JUSTIFY_CENTER) {
|
if (box_layout_node->justify_secondary == UI_BOX_LAYOUT_JUSTIFY_CENTER) {
|
||||||
current->rect.y = margin_top + (maximum_secondary_position - current->rect.h) / 2;
|
updated_rect.y = margin_top + (maximum_secondary_position - updated_rect.h) / 2;
|
||||||
} else {
|
} else {
|
||||||
current->rect.y = y;
|
updated_rect.y = y;
|
||||||
}
|
}
|
||||||
x += current->rect.w;
|
x += updated_rect.w;
|
||||||
} else {
|
} else {
|
||||||
if (current->height_policy == UI_SIZE_POLICY_GROW) {
|
if (current->height_policy == UI_SIZE_POLICY_GROW) {
|
||||||
current->rect.h = distributes_growing_widgets ? size_per_growing_widget : 0;
|
updated_rect.h = distributes_growing_widgets ? size_per_growing_widget : 0;
|
||||||
}
|
}
|
||||||
if (current->width_policy == UI_SIZE_POLICY_GROW) {
|
if (current->width_policy == UI_SIZE_POLICY_GROW) {
|
||||||
current->rect.w = maximum_secondary_position;
|
updated_rect.w = maximum_secondary_position;
|
||||||
}
|
}
|
||||||
if (current_index) {
|
if (current_index) {
|
||||||
y += gap;
|
y += gap;
|
||||||
}
|
}
|
||||||
if (box_layout_node->justify_secondary == UI_BOX_LAYOUT_JUSTIFY_CENTER) {
|
if (box_layout_node->justify_secondary == UI_BOX_LAYOUT_JUSTIFY_CENTER) {
|
||||||
current->rect.x = margin_left + (maximum_secondary_position - current->rect.w) / 2;
|
updated_rect.x = margin_left + (maximum_secondary_position - updated_rect.w) / 2;
|
||||||
} else {
|
} else {
|
||||||
current->rect.x = x;
|
updated_rect.x = x;
|
||||||
}
|
}
|
||||||
current->rect.y = y;
|
updated_rect.y = y;
|
||||||
y += current->rect.h;
|
y += updated_rect.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_set_rect(current, updated_rect);
|
||||||
|
|
||||||
|
if (current->layout_dirty) {
|
||||||
node_dispatch(current, UI_EVENT_RELAYOUT, 0, NULL);
|
node_dispatch(current, UI_EVENT_RELAYOUT, 0, NULL);
|
||||||
|
current->layout_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
current_index++;
|
current_index++;
|
||||||
}
|
}
|
||||||
|
|
25
src/main.c
25
src/main.c
|
@ -142,12 +142,27 @@ int app_handle(struct UINode *node, void *data, int event_type, size_t d, void *
|
||||||
|
|
||||||
box_layout_new(buttons, UI_DIRECTION_VERTICAL);
|
box_layout_new(buttons, UI_DIRECTION_VERTICAL);
|
||||||
|
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 5000; i++) {
|
||||||
UINode *button = node_new(buttons, "button");
|
UINode *button_row = node_new(buttons, "button_row");
|
||||||
state_background_node_new(button, UIPurple600, UIPurple700, UIPurple800, 6.0);
|
button_row->width_policy = UI_SIZE_POLICY_GROW;
|
||||||
text_node_new(button, state->font, UINeutral50, "button");
|
UIBoxLayoutNode *layout = box_layout_new(button_row, UI_DIRECTION_HORIZONTAL);
|
||||||
dispatcher_new(button, UI_EVENT_UNPRESSED, INCREMENT_COUNT, state, app_handle);
|
layout->gap = 6;
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
UINode *button = node_new(button_row, "button");
|
||||||
button->width_policy = UI_SIZE_POLICY_GROW;
|
button->width_policy = UI_SIZE_POLICY_GROW;
|
||||||
|
button->height_policy = UI_SIZE_POLICY_STATIC;
|
||||||
|
button->rect.w = 48;
|
||||||
|
button->rect.h = 48;
|
||||||
|
button->flags |= UI_NODE_CONSUMES_HITS;
|
||||||
|
UIBoxLayoutNode *button_layout = box_layout_new(button, UI_DIRECTION_HORIZONTAL);
|
||||||
|
button_layout->justify_primary = UI_BOX_LAYOUT_JUSTIFY_CENTER;
|
||||||
|
button_layout->justify_secondary = UI_BOX_LAYOUT_JUSTIFY_CENTER;
|
||||||
|
state_background_node_new(button, UIPurple600, UIPurple700, UIPurple800, 6.0);
|
||||||
|
UINode *text_container = node_new(button, "text_container");
|
||||||
|
text_node_new(text_container, state->font, UINeutral50, "+");
|
||||||
|
dispatcher_new(button, UI_EVENT_UNPRESSED, INCREMENT_COUNT, state, app_handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
src/node.c
20
src/node.c
|
@ -41,6 +41,21 @@ UIRect node_get_computed_rect(UINode *node) {
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void node_mark_dirty_layout(UINode *node)
|
||||||
|
{
|
||||||
|
node->cached_computed_extents = false;
|
||||||
|
node->layout_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_set_rect(UINode *node, UIRect rect)
|
||||||
|
{
|
||||||
|
if (node->rect.x == rect.x && node->rect.y == rect.y && node->rect.w == rect.w && node->rect.h == rect.h) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node->rect = rect;
|
||||||
|
node_mark_dirty_layout(node);
|
||||||
|
}
|
||||||
|
|
||||||
int node_send(UINode *node, enum UIEvent ev, size_t d, void *p)
|
int node_send(UINode *node, enum UIEvent ev, size_t d, void *p)
|
||||||
{
|
{
|
||||||
if (unlikely(node->flags & UI_NODE_DISABLED)) {
|
if (unlikely(node->flags & UI_NODE_DISABLED)) {
|
||||||
|
@ -123,6 +138,7 @@ void node_init(UINode *node)
|
||||||
node->handle = NULL;
|
node->handle = NULL;
|
||||||
node->handle_proto = NULL;
|
node->handle_proto = NULL;
|
||||||
node->cached_computed_extents = false;
|
node->cached_computed_extents = false;
|
||||||
|
node->layout_dirty = true;
|
||||||
for (int i = 0; i < UI_NODE_DISPATCH_BUCKETS; i++) {
|
for (int i = 0; i < UI_NODE_DISPATCH_BUCKETS; i++) {
|
||||||
node->dispatch_buckets[i].capacity = 0;
|
node->dispatch_buckets[i].capacity = 0;
|
||||||
node->dispatch_buckets[i].count = 0;
|
node->dispatch_buckets[i].count = 0;
|
||||||
|
@ -247,7 +263,9 @@ void node_dump(UINode *node, int depth)
|
||||||
void node_request_relayout(UINode *node)
|
void node_request_relayout(UINode *node)
|
||||||
{
|
{
|
||||||
UINode *current = NULL;
|
UINode *current = NULL;
|
||||||
for (current = node; current->parent && current->width_policy != UI_SIZE_POLICY_STATIC && current->height_policy != UI_SIZE_POLICY_STATIC; current = current->parent);
|
for (current = node; current->parent && current->width_policy != UI_SIZE_POLICY_STATIC && current->height_policy != UI_SIZE_POLICY_STATIC; current = current->parent) {
|
||||||
|
node_mark_dirty_layout(current);
|
||||||
|
}
|
||||||
if (current) {
|
if (current) {
|
||||||
node_dispatch(current, UI_EVENT_RELAYOUT, 0, NULL);
|
node_dispatch(current, UI_EVENT_RELAYOUT, 0, NULL);
|
||||||
window_invalidate_node(current->window, current);
|
window_invalidate_node(current->window, current);
|
||||||
|
|
|
@ -85,7 +85,9 @@ typedef struct UINode {
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
enum UISizePolicy width_policy;
|
enum UISizePolicy width_policy;
|
||||||
enum UISizePolicy height_policy;
|
enum UISizePolicy height_policy;
|
||||||
|
|
||||||
bool cached_computed_extents;
|
bool cached_computed_extents;
|
||||||
|
bool layout_dirty;
|
||||||
|
|
||||||
UINodeDispatchBucket dispatch_buckets[UI_NODE_DISPATCH_BUCKETS];
|
UINodeDispatchBucket dispatch_buckets[UI_NODE_DISPATCH_BUCKETS];
|
||||||
|
|
||||||
|
@ -94,6 +96,8 @@ typedef struct UINode {
|
||||||
} UINode;
|
} UINode;
|
||||||
|
|
||||||
UIRect node_get_computed_rect(UINode *node);
|
UIRect node_get_computed_rect(UINode *node);
|
||||||
|
void node_mark_dirty_layout(UINode *node);
|
||||||
|
void node_set_rect(UINode *node, UIRect rect);
|
||||||
int node_send(UINode *node, enum UIEvent ev, size_t d, void *p);
|
int node_send(UINode *node, enum UIEvent ev, size_t d, void *p);
|
||||||
int node_dispatch(UINode *node, enum UIEvent ev, size_t d, void *p);
|
int node_dispatch(UINode *node, enum UIEvent ev, size_t d, void *p);
|
||||||
UINode *node_by_point(UINode *root, double x, double y);
|
UINode *node_by_point(UINode *root, double x, double y);
|
||||||
|
|
Loading…
Reference in a new issue