Compare commits

...

2 commits

6 changed files with 58 additions and 21 deletions

View file

@ -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 -DNDEBUG
all: $(BUILD) $(BIN)
release: CFLAGS+=-O2 -flto=auto -DNDEBUG

View file

@ -130,13 +130,15 @@ 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 < 100; i++) {
for (int i = 0; i < 10000; 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;
}
printf("%d\n", buttons->last_component_index);
}
break;

View file

@ -28,14 +28,25 @@ int node_dispatch(UINode *node, enum UIEvent ev, size_t d, void *p)
return 0;
}
int result = 0;
int component_index = UI_NODE_LAST_COMPONENT_INDEX_NONE;
for (int i = 0; i < node->nodes_count; i++) {
if (node->last_component_index == UI_NODE_LAST_COMPONENT_INDEX_NONE || (node->last_component_index >= 0 && i > node->last_component_index)) {
break;
}
if (node->nodes[i]->flags & UI_NODE_COMPONENT) {
int result = node_dispatch(node->nodes[i], ev, d, p);
if (result) return result;
component_index = i;
result = node_dispatch(node->nodes[i], ev, d, p);
if (result) break;
}
}
if (node->last_component_index < 0) {
node->last_component_index = component_index;
}
if (result) return result;
if (node->handle) {
int result = (node->handle)(node, ev, d, p);
result = (node->handle)(node, ev, d, p);
if (result) return result;
}
if (node->handle_proto) {
@ -71,12 +82,20 @@ void node_init(UINode *node)
node->height_policy = UI_SIZE_POLICY_DYNAMIC;
node->handle = NULL;
node->handle_proto = NULL;
node->last_component_index = UI_NODE_LAST_COMPONENT_INDEX_NONE;
}
void node_free(UINode *node)
{
if (!node) return;
// TODO: properly handle removing this node from its parent
// Invalidate component index cache
if ((node->flags & UI_NODE_COMPONENT) && node->parent) {
node->parent->last_component_index = UI_NODE_LAST_COMPONENT_INDEX_INVALIDATED;
}
node_dispatch(node, UI_EVENT_DESTROY, 0, NULL);
for (int i = 0; i < node->nodes_count; i++) {
@ -135,7 +154,14 @@ UINode *node_attach(UINode *parent, UINode *node)
return NULL;
}
}
parent->nodes[parent->nodes_count++] = node;
int index = parent->nodes_count++;
parent->nodes[index] = node;
// Let's save the index of the last component so that we can exit the loop early
// if there's no components left when we're in node_dispatch()
if ((node->flags & UI_NODE_COMPONENT) && index > parent->last_component_index) {
parent->last_component_index = index;
}
}
return node;

View file

@ -41,6 +41,8 @@ enum UIDirection {
#define UI_NODE_RETAINS_PRESS (1 << 1)
#define UI_NODE_DISABLED (1 << 2)
#define UI_NODE_LAST_COMPONENT_INDEX_INVALIDATED (-1)
#define UI_NODE_LAST_COMPONENT_INDEX_NONE (-2)
typedef struct UINode {
const char *text;
UIRect rect;
@ -53,6 +55,7 @@ typedef struct UINode {
uint32_t flags;
enum UISizePolicy width_policy;
enum UISizePolicy height_policy;
int last_component_index;
int (*handle)(struct UINode *node, enum UIEvent ev, size_t d, void *p);
int (*handle_proto)(struct UINode *node, enum UIEvent ev, size_t d, void *p);

View file

@ -17,6 +17,9 @@ UITextNode *text_node_new(UINode *parent, PangoFontDescription *desc, UIRGBA col
n->color = color;
n->caret_index = -1;
n->caret_node = NULL;
n->computed_dimensions_invalid = true;
n->computed_text_width = 0;
n->computed_text_height = 0;
n->node.text = "text";
n->node.handle_proto = text_node_handle;
node_attach(parent, (UINode*)n);
@ -47,6 +50,7 @@ int text_node_handle(UINode *node, enum UIEvent ev, size_t d, void *p)
n->layout = layout;
n->pending_text = NULL;
}
n->computed_dimensions_invalid = true;
}
switch (ev) {
@ -59,23 +63,22 @@ int text_node_handle(UINode *node, enum UIEvent ev, size_t d, void *p)
cairo_fill(n->node.drw);
break;
}
case UI_EVENT_GET_WIDTH: {
if (!n->layout) {
break;
}
int w;
pango_layout_get_size(n->layout, &w, NULL);
*(double*)p = pango_units_to_double(w);
return 1;
}
case UI_EVENT_GET_WIDTH: /* through */
case UI_EVENT_GET_HEIGHT: {
if (!n->layout) {
break;
if (n->computed_dimensions_invalid) {
int w, h = 0;
pango_layout_get_size(n->layout, &w, &h);
n->computed_text_width = pango_units_to_double(w);
n->computed_text_height = pango_units_to_double(h);
n->computed_dimensions_invalid = false;
}
int h;
pango_layout_get_size(n->layout, NULL, &h);
*(double*)p = pango_units_to_double(h);
return 1;
if (ev == UI_EVENT_GET_WIDTH) {
*(double*)p = n->computed_text_width;
}
if (ev == UI_EVENT_GET_HEIGHT) {
*(double*)p = n->computed_text_height;
}
break;
}
case UI_EVENT_RELAYOUT: {
if (!n->layout) {

View file

@ -15,6 +15,9 @@ typedef struct UITextNode {
UIRGBA color;
ssize_t caret_index;
UINode *caret_node;
double computed_text_width;
double computed_text_height;
bool computed_dimensions_invalid;
} UITextNode;
int text_node_handle(UINode *node, enum UIEvent ev, size_t d, void *p);