#include #include #include #include void saffron_widget_init(SaffronWidget* widget) { /* This function is a generic primitive for initializing widgets. You wouldn't want to do this manually unless you're a lunatic. It is meant to be wrapped around by other functions that change the default parameters, for example, what sane person makes a widget 0x0x0x0? you LUNATIC! */ widget->x = 0; widget->y = 0; widget->w = 0; widget->h = 0; widget->draw = NULL; widget->on_click = NULL; widget->parent = NULL; widget->children = NULL; widget->child_count = 0; widget->width_mode = SAFFRON_SIZE_FIXED; widget->height_mode = SAFFRON_SIZE_FIXED; widget->pixel_perfect = false; widget->type = SAFFRON_WIDGET_UNKNOWN; } SaffronWidget* saffron_widget_new(void) { /* also generic primitive, refer to above comment in saffron_widget_init */ SaffronWidget* widget = malloc(sizeof(SaffronWidget)); if (widget) { saffron_widget_init(widget); } return widget; } void saffron_widget_free(SaffronWidget *widget) { /* follow-up to my previous comment: * yeah it is the caller's responsibility to check * for undefined behaviour but this one line will save * so much time down the line */ if (!widget) return; for (int i = 0; i < widget->child_count; i++) { saffron_widget_free(widget->children[i]); } free(widget->children); free(widget); } void saffron_widget_draw(SaffronWidget* widget, SDL_Renderer *renderer) { if (!widget) return; if (widget->draw) { widget->draw(widget, renderer); } for (int i = 0; i < widget->child_count; i++) { saffron_widget_draw(widget->children[i], renderer); } } void saffron_widget_add_child(SaffronWidget *parent, SaffronWidget *child) { child->parent = parent; parent->children = realloc(parent->children, sizeof(SaffronWidget*) * (parent->child_count + 1)); parent->children[parent->child_count] = child; parent->child_count++; if (parent->type == SAFFRON_WIDGET_BOX) { saffron_box_layout((SaffronBox*)parent); } } SaffronWidget* saffron_widget_hit_test(SaffronWidget* widget, int x, int y) { if (!widget) { printf("[Saffron] hit test: widget is NULL!\n"); return NULL; } if (x < widget->x || x > widget->x + widget->w) { printf("[Saffron] hit test: widget failed X bounds check!\n"); return NULL; } if (y < widget->y || y > widget->y + widget->h) { printf("[Saffron] hit test: widget failed Y bounds check!\n"); return NULL; } // check children front to back for (int i = widget->child_count - 1; i >= 0; i--) { printf("[Saffron] recursing to child (%i)\n", i); SaffronWidget* hit = saffron_widget_hit_test(widget->children[i], x, y); if (hit) return hit; } return widget; }