layout optimizations

This commit is contained in:
hippoz 2023-09-01 05:05:35 +03:00
parent ec15ed6f9f
commit e659e6f3e2
Signed by: hippoz
GPG key ID: 56C4E02A85F2FBED
5 changed files with 67 additions and 22 deletions

View file

@ -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

View file

@ -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++;
} }

View file

@ -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);
}
} }
} }

View file

@ -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);

View file

@ -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);