From e659e6f3e25ae89d247896c52ee84304b2dba8bc Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Fri, 1 Sep 2023 05:05:35 +0300 Subject: [PATCH] layout optimizations --- Makefile | 2 +- src/box-layout-node.c | 36 ++++++++++++++++++++++-------------- src/main.c | 27 +++++++++++++++++++++------ src/node.c | 20 +++++++++++++++++++- src/node.h | 4 ++++ 5 files changed, 67 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 9ad0e60..069f854 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ OBJS=$(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SRCS)) DEPS=$(OBJS:%.o=%.d) -all: CFLAGS+=-fsanitize=address -Og -ggdb +all: CFLAGS+=-Og -ggdb all: $(BUILD) $(BIN) release: CFLAGS+=-O2 -flto=auto -DNDEBUG -ggdb diff --git a/src/box-layout-node.c b/src/box-layout-node.c index 419e5df..90b455d 100644 --- a/src/box-layout-node.c +++ b/src/box-layout-node.c @@ -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)->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); @@ -112,42 +112,50 @@ int box_layout_handle(UINode *component, enum UIEvent ev, size_t d, void *p) UINode *current = node->nodes[i]; if (current->flags & UI_NODE_COMPONENT) continue; + UIRect updated_rect = current->rect; + if (is_horizontal) { 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) { - current->rect.h = maximum_secondary_position; + updated_rect.h = maximum_secondary_position; } if (current_index) { x += gap; } - current->rect.x = x; + updated_rect.x = x; 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 { - current->rect.y = y; + updated_rect.y = y; } - x += current->rect.w; + x += updated_rect.w; } else { 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) { - current->rect.w = maximum_secondary_position; + updated_rect.w = maximum_secondary_position; } if (current_index) { y += gap; } 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 { - current->rect.x = x; + updated_rect.x = x; } - current->rect.y = y; - y += current->rect.h; + updated_rect.y = y; + y += updated_rect.h; + } + + node_set_rect(current, updated_rect); + + if (current->layout_dirty) { + node_dispatch(current, UI_EVENT_RELAYOUT, 0, NULL); + current->layout_dirty = false; } - node_dispatch(current, UI_EVENT_RELAYOUT, 0, NULL); current_index++; } diff --git a/src/main.c b/src/main.c index 18e3b3b..7270943 100644 --- a/src/main.c +++ b/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); - for (int i = 0; i < 20; i++) { - UINode *button = node_new(buttons, "button"); - state_background_node_new(button, UIPurple600, UIPurple700, UIPurple800, 6.0); - text_node_new(button, state->font, UINeutral50, "button"); - dispatcher_new(button, UI_EVENT_UNPRESSED, INCREMENT_COUNT, state, app_handle); - button->width_policy = UI_SIZE_POLICY_GROW; + for (int i = 0; i < 5000; i++) { + UINode *button_row = node_new(buttons, "button_row"); + button_row->width_policy = UI_SIZE_POLICY_GROW; + UIBoxLayoutNode *layout = box_layout_new(button_row, UI_DIRECTION_HORIZONTAL); + 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->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); + } } } diff --git a/src/node.c b/src/node.c index fb430e2..bba6b46 100644 --- a/src/node.c +++ b/src/node.c @@ -41,6 +41,21 @@ UIRect node_get_computed_rect(UINode *node) { 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) { if (unlikely(node->flags & UI_NODE_DISABLED)) { @@ -123,6 +138,7 @@ void node_init(UINode *node) node->handle = NULL; node->handle_proto = NULL; node->cached_computed_extents = false; + node->layout_dirty = true; for (int i = 0; i < UI_NODE_DISPATCH_BUCKETS; i++) { node->dispatch_buckets[i].capacity = 0; node->dispatch_buckets[i].count = 0; @@ -247,7 +263,9 @@ void node_dump(UINode *node, int depth) void node_request_relayout(UINode *node) { 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) { node_dispatch(current, UI_EVENT_RELAYOUT, 0, NULL); window_invalidate_node(current->window, current); diff --git a/src/node.h b/src/node.h index 83fb42b..a5d5b9b 100644 --- a/src/node.h +++ b/src/node.h @@ -85,7 +85,9 @@ typedef struct UINode { uint32_t flags; enum UISizePolicy width_policy; enum UISizePolicy height_policy; + bool cached_computed_extents; + bool layout_dirty; UINodeDispatchBucket dispatch_buckets[UI_NODE_DISPATCH_BUCKETS]; @@ -94,6 +96,8 @@ typedef struct UINode { } UINode; 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_dispatch(UINode *node, enum UIEvent ev, size_t d, void *p); UINode *node_by_point(UINode *root, double x, double y);