#include "serialization-static-ui.hpp" #include "compile-time-assert.hpp" #include "ecs.hpp" #include "font.hpp" #include "level.hpp" #include "pk.h" #include "serialization.hpp" #include "static-ui.hpp" pk_handle pke_serialize_ui_box_internal(srlztn_serialize_helper *h, pke_ui_box_type_data::pke_ui_box_type_data_text *data) { char *s; pke_kve kve{}; pke_kve_container kvec{}; kvec.srlztn_handle = h->handle_head; kvec.type_code = cstring_to_pk_cstr(SRLZTN_OBJ_UI_BOX_TYPE_DATA); kvec.bkt = h->bkt; kvec.arr.bkt = h->bkt; kvec.children.bkt = h->bkt; kvec.child_handles.bkt = h->bkt; h->handle_head.itemIndex++; compt_a<8==sizeof(pke_ui_box_type_data::pke_ui_box_type_data_text)>(); { kve.key = SRLZTN_UI_BOX_DATA_TEXT_FONT_RENDER_UUID; s = pk_new_arr(37, h->bkt); FontRender *fr = FontType_GetFontRender(data->font_type_render); sprintf(s, pk_uuid_printf_format, pk_uuid_printf_var(fr->uuid)); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } // 2025-08-19 TODO JCB // pressed callback pk_arr_append_t(&h->kvp_containers, kvec); kvec.arr.data = nullptr; kvec.children.data = nullptr; kvec.child_handles.data = nullptr; return kvec.srlztn_handle; } pk_handle pke_serialize_ui_box_internal(srlztn_serialize_helper *h, pke_ui_box_type_data::pke_ui_box_type_data_button_text *data) { char *s; pke_kve kve{}; pke_kve_container kvec{}; kvec.srlztn_handle = h->handle_head; kvec.type_code = cstring_to_pk_cstr(SRLZTN_OBJ_UI_BOX_TYPE_DATA); kvec.bkt = h->bkt; kvec.arr.bkt = h->bkt; kvec.children.bkt = h->bkt; kvec.child_handles.bkt = h->bkt; h->handle_head.itemIndex++; compt_a<24==sizeof(pke_ui_box_type_data::pke_ui_box_type_data_button_text)>(); { kve.key = SRLZTN_UI_BOX_DATA_BUTTON_TEXT_FONT_RENDER_UUID; s = pk_new_arr(37, h->bkt); FontRender *fr = FontType_GetFontRender(data->font_type_render); sprintf(s, pk_uuid_printf_format, pk_uuid_printf_var(fr->uuid)); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } // 2025-09-24 TODO JCB // data->pke_event_handle; // data->ev_id; pk_arr_append_t(&h->kvp_containers, kvec); kvec.arr.data = nullptr; kvec.children.data = nullptr; kvec.child_handles.data = nullptr; return kvec.srlztn_handle; } pk_handle pke_serialize_ui_box_internal(srlztn_serialize_helper *h, pke_ui_box_type_data::pke_ui_box_type_data_button_image *data) { char *s; pke_kve kve{}; pke_kve_container kvec{}; kvec.srlztn_handle = h->handle_head; kvec.type_code = cstring_to_pk_cstr(SRLZTN_OBJ_UI_BOX_TYPE_DATA); kvec.bkt = h->bkt; kvec.arr.bkt = h->bkt; kvec.children.bkt = h->bkt; kvec.child_handles.bkt = h->bkt; h->handle_head.itemIndex++; compt_a<64==sizeof(pke_ui_box_type_data::pke_ui_box_type_data_button_image)>(); { kve.key = SRLZTN_UI_BOX_DATA_BUTTON_IMAGE_ASSET_KEY_DEFAULT; s = pk_new_arr(AssetKeyLength, h->bkt); memcpy(s, data->img_key_default, AssetKeyLength); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } { kve.key = SRLZTN_UI_BOX_DATA_BUTTON_IMAGE_ASSET_KEY_HOVERED; s = pk_new_arr(AssetKeyLength, h->bkt); memcpy(s, data->img_key_hovered, AssetKeyLength); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } { kve.key = SRLZTN_UI_BOX_DATA_BUTTON_IMAGE_ASSET_KEY_PRESSED; s = pk_new_arr(AssetKeyLength, h->bkt); memcpy(s, data->img_key_pressed, AssetKeyLength); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } // 2025-08-19 TODO JCB // pressed callback pk_arr_append_t(&h->kvp_containers, kvec); kvec.arr.data = nullptr; kvec.children.data = nullptr; kvec.child_handles.data = nullptr; return kvec.srlztn_handle; } void pke_deserialize_ui_box_internal(srlztn_deserialize_helper *h, pke_kve_container *kvec, pke_ui_box_type_data::pke_ui_box_type_data_text *data) { (void)h; assert(kvec != nullptr); assert(data != nullptr); assert(kvec->arr.next == 1); uint32_t u; FontRender *fr = nullptr; pk_uuid font_render_uuid = pk_uuid_zed; compt_a<8==sizeof(pke_ui_box_type_data::pke_ui_box_type_data_text)>(); if (strstr(SRLZTN_UI_BOX_DATA_TEXT_FONT_RENDER_UUID, kvec->arr[0].key)) { kvec->arr[0].val >> font_render_uuid; } assert(font_render_uuid != pk_uuid_zed); for (u = 0; u < h->mapping.next; ++u) { if (h->mapping[u].serialized_uuid == font_render_uuid) { assert(h->mapping[u].created_entity != nullptr); fr = static_cast(h->mapping[u].created_entity); data->font_type_render = {fr->font_type_handle, fr->font_render_handle}; break; } } assert(fr != nullptr); } void pke_deserialize_ui_box_internal(srlztn_deserialize_helper *h, pke_kve_container *kvec, pke_ui_box_type_data::pke_ui_box_type_data_button_text *data) { (void)h; assert(kvec != nullptr); assert(data != nullptr); assert(kvec->arr.next == 1); uint32_t u; FontRender *fr = nullptr; pk_uuid font_render_uuid = pk_uuid_zed; // TODO data->font_type_render = FontTypeRender_MAX; data->pke_event_handle = PkeEventHandle_MAX; data->ev_id = pk_ev_id_T{0}; compt_a<24==sizeof(pke_ui_box_type_data::pke_ui_box_type_data_button_text)>(); if (strstr(SRLZTN_UI_BOX_DATA_BUTTON_TEXT_FONT_RENDER_UUID, kvec->arr[0].key)) { kvec->arr[0].val >> font_render_uuid; } assert(font_render_uuid != pk_uuid_zed); for (u = 0; u < h->mapping.next; ++u) { if (h->mapping[u].serialized_uuid == font_render_uuid) { assert(h->mapping[u].created_entity != nullptr); fr = static_cast(h->mapping[u].created_entity); data->font_type_render = {fr->font_type_handle, fr->font_render_handle}; break; } } assert(fr != nullptr); } void pke_deserialize_ui_box_internal(srlztn_deserialize_helper *h, pke_kve_container *kvec, pke_ui_box_type_data::pke_ui_box_type_data_button_image *data) { (void)h; uint32_t u; pke_kve *kve; assert(kvec != nullptr); assert(data != nullptr); assert(kvec->arr.next == 3); data->gr_binds_bkt_arr_handle = pk_bkt_arr_handle_MAX; data->pke_event_handle = PkeEventHandle_MAX; data->ev_id = {}; compt_a<64==sizeof(pke_ui_box_type_data::pke_ui_box_type_data_button_image)>(); for (u = 0; u < kvec->arr.next; ++u) { kve = &kvec->arr[u]; if (strstr(SRLZTN_UI_BOX_DATA_BUTTON_IMAGE_ASSET_KEY_DEFAULT, kve->key)) { // TODO there's gotta be a more elegant solution to this if (strlen(kve->val) < AssetKeyLength) { sprintf(data->img_key_default, "%s", kve->val); } else { memcpy(data->img_key_default, kve->val, AssetKeyLength); } continue; } if (strstr(SRLZTN_UI_BOX_DATA_BUTTON_IMAGE_ASSET_KEY_HOVERED, kve->key)) { if (strlen(kve->val) < AssetKeyLength) { sprintf(data->img_key_hovered, "%s", kve->val); } else { memcpy(data->img_key_hovered, kve->val, AssetKeyLength); } continue; } if (strstr(SRLZTN_UI_BOX_DATA_BUTTON_IMAGE_ASSET_KEY_PRESSED, kve->key)) { if (strlen(kve->val) < AssetKeyLength) { sprintf(data->img_key_pressed, "%s", kve->val); } else { memcpy(data->img_key_pressed, kve->val, AssetKeyLength); } continue; } } } pk_handle pke_serialize_ui_box(srlztn_serialize_helper *h, pke_ui_box *box) { char *s; int len; pke_kve kve{}; pke_kve_container kvec{}; kvec.child_handles.bkt = h->bkt; switch (box->type) { case PKE_UI_BOX_TYPE_STANDARD: break; case PKE_UI_BOX_TYPE_TEXT: pk_arr_append_t(&kvec.child_handles, pke_serialize_ui_box_internal(h, &box->type_data->text)); break; case PKE_UI_BOX_TYPE_BUTTON_TEXT: pk_arr_append_t(&kvec.child_handles, pke_serialize_ui_box_internal(h, &box->type_data->button_text)); break; case PKE_UI_BOX_TYPE_BUTTON_IMAGE: pk_arr_append_t(&kvec.child_handles, pke_serialize_ui_box_internal(h, &box->type_data->button_image)); break; default: fprintf(stderr, "[pke_serialize_ui_box] unhandled box type: %hhu\n", static_cast(box->type)); return PK_HANDLE_MAX; } kvec.srlztn_handle = h->handle_head; kvec.type_code = cstring_to_pk_cstr(SRLZTN_OBJ_UI_BOX); kvec.bkt = h->bkt; kvec.arr.bkt = h->bkt; kvec.children.bkt = h->bkt; h->handle_head.itemIndex++; compt_a<208==sizeof(pke_ui_box)>(); if (box->uuid != pk_uuid_zed && box->uuid != pk_uuid_max) { kve.key = SRLZTN_UI_BOX_UUID; s = pk_new_arr(37, h->bkt); sprintf(s, pk_uuid_printf_format, pk_uuid_printf_var(box->uuid)); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } if (box->parentHandle != EntityHandle_MAX) { Entity_Base *e = ECS_GetEntity(box->parentHandle); kve.key = SRLZTN_UI_BOX_PARENT_UUID; s = pk_new_arr(37, h->bkt); sprintf(s, pk_uuid_printf_format, pk_uuid_printf_var(e->uuid)); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } if (box->flags != PKE_UI_BOX_FLAG_NONE) { kve.key = SRLZTN_UI_BOX_FLAGS; s = pk_new_arr(19, h->bkt); sprintf(s, "0x%.2lX", static_cast(box->flags)); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } { kve.key = SRLZTN_UI_BOX_POS_TOP_LEFT; len = snprintf(NULL, 0, "%f;%f", box->pos_top_left.x, box->pos_top_left.y); s = pk_new_arr(len+1, h->bkt); sprintf(s, "%f;%f", box->pos_top_left.x, box->pos_top_left.y); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } if (box->min_size != glm::vec2(0,0)) { kve.key = SRLZTN_UI_BOX_MIN_SIZE; len = snprintf(NULL, 0, "%f;%f", box->min_size.x, box->min_size.y); s = pk_new_arr(len+1, h->bkt); sprintf(s, "%f%f", box->min_size.x, box->min_size.y); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } if (box->max_size != glm::vec2(0,0)) { kve.key = SRLZTN_UI_BOX_MAX_SIZE; len = snprintf(NULL, 0, "%f;%f", box->max_size[0], box->max_size[1]); s = pk_new_arr(len+1, h->bkt); sprintf(s, "%f;%f", box->max_size[0], box->max_size[1]); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } if (box->flex_weight != 0.f) { kve.key = SRLZTN_UI_BOX_FLEX_WEIGHT; len = snprintf(NULL, 0, "%f", box->flex_weight); s = pk_new_arr(len+1, h->bkt); sprintf(s, "%f", box->flex_weight); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); // only serialize if we're using flex kve.key = SRLZTN_UI_BOX_FLEX_DIRECTION; s = pk_new_arr(5, h->bkt); sprintf(s, "0x%.2X", box->flex_direction); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); kve.key = SRLZTN_UI_BOX_FLEX_PADDING; len = snprintf(NULL, 0, "%f", box->flex_padding); s = pk_new_arr(len+1, h->bkt); sprintf(s, "%f", box->flex_padding); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } { kve.key = SRLZTN_UI_BOX_TYPE; s = pk_new_arr(5, h->bkt); sprintf(s, "0x%.2X", static_cast(box->type)); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } { kve.key = SRLZTN_UI_BOX_LAYER; s = pk_new_arr(5, h->bkt); sprintf(s, "0x%.2X", box->layer); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } if (PK_HAS_FLAG(box->flags, PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE) == false) { kve.key = SRLZTN_UI_BOX_COLOR_BORDER; len = snprintf(NULL, 0, "%f%s%f%s%f%s%f", box->color_border[0], SRLZTN_NUM_SEPARATOR, box->color_border[1], SRLZTN_NUM_SEPARATOR, box->color_border[2], SRLZTN_NUM_SEPARATOR, box->color_border[3]); s = pk_new_arr(len+1, h->bkt); sprintf(s, "%f%s%f%s%f%s%f", box->color_border[0], SRLZTN_NUM_SEPARATOR, box->color_border[1], SRLZTN_NUM_SEPARATOR, box->color_border[2], SRLZTN_NUM_SEPARATOR, box->color_border[3]); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } if (PK_HAS_FLAG(box->flags, PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE) == false) { kve.key = SRLZTN_UI_BOX_COLOR_BACKGROUND; len = snprintf(NULL, 0, "%f%s%f%s%f%s%f", box->color_background[0], SRLZTN_NUM_SEPARATOR, box->color_background[1], SRLZTN_NUM_SEPARATOR, box->color_background[2], SRLZTN_NUM_SEPARATOR, box->color_background[3]); s = pk_new_arr(len+1, h->bkt); sprintf(s, "%f%s%f%s%f%s%f", box->color_background[0], SRLZTN_NUM_SEPARATOR, box->color_background[1], SRLZTN_NUM_SEPARATOR, box->color_background[2], SRLZTN_NUM_SEPARATOR, box->color_background[3]); kve.val = s; kve.end = SRLZTN_KVE_END; pk_arr_append_t(&kvec.arr, kve); } pk_arr_append_t(&h->kvp_containers, kvec); pke_kve_container *kvec_ptr = &h->kvp_containers[h->kvp_containers.next-1]; for (pke_ui_box_count_T i = 0; i < box->internal.h_children; ++i) { pk_arr_append_t(&kvec_ptr->child_handles, pke_serialize_ui_box(h, box->internal.children[i])); } kvec.arr.data = nullptr; kvec.children.data = nullptr; kvec.child_handles.data = nullptr; return kvec.srlztn_handle; } void pke_deserialize_ui_box(srlztn_deserialize_helper *h, pke_kve_container *kvec) { /* How this works, a concrete example * * wrapper box > type_text box > { type_text data + FRSettings } * * 1. wrapper box parse & create * 2. box_type text starts parse * a. parse type_data (one child only) (by reference) * 1. parse font-render settings (by reference) * */ uint32_t i, index; PK_STN_RES res; const char *starting_char; char *stn_end; pke_kve *kve; pke_ui_box bx{}; pke_ui_box *parent_box = nullptr; bx.type_data = nullptr; compt_a<208==sizeof(pke_ui_box)>(); for (i = 0; i < kvec->arr.next; ++i) { kve = &kvec->arr[i]; if (strstr(SRLZTN_UI_BOX_UUID, kve->key)) { kve->val >> bx.uuid; continue; } if (strstr(SRLZTN_UI_BOX_PARENT_UUID, kve->key)) { uint32_t target_instance_index = -1; pk_uuid id; kve->val >> id; target_instance_index = pk_arr_find_first_index(&h->mapping, &id, srlztn_mapping_find_first_handle_by_uuid); if (target_instance_index != uint32_t(-1)) { parent_box = static_cast(h->mapping[target_instance_index].created_entity); } continue; } if (strstr(SRLZTN_UI_BOX_FLAGS, kve->key)) { PKE_UI_BOX_FLAG_T flags; res = pk_stn(&flags, kve->val, &stn_end, 16); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_FLAGS, res); continue; } bx.flags = PKE_UI_BOX_FLAG(flags); continue; } if (strstr(SRLZTN_UI_BOX_POS_TOP_LEFT, kve->key)) { starting_char = kve->val; index = 0; do { assert(index < 2); res = pk_stn(&bx.pos_top_left[index], starting_char, &stn_end); if (res != PK_STN_RES_SUCCESS) break; starting_char = stn_end + 1; ++index; } while (*stn_end != '\0'); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_POS_TOP_LEFT, res); } continue; } if (strstr(SRLZTN_UI_BOX_MIN_SIZE, kve->key)) { starting_char = kve->val; index = 0; do { assert(index < 2); res = pk_stn(&bx.min_size[index], starting_char, &stn_end); if (res != PK_STN_RES_SUCCESS) break; starting_char = stn_end + 1; ++index; } while (*stn_end != '\0'); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_MIN_SIZE, res); } continue; } if (strstr(SRLZTN_UI_BOX_MAX_SIZE, kve->key)) { starting_char = kve->val; index = 0; do { assert(index < 2); res = pk_stn(&bx.max_size[index], starting_char, &stn_end); if (res != PK_STN_RES_SUCCESS) break; starting_char = stn_end + 1; ++index; } while (*stn_end != '\0'); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_MAX_SIZE, res); } continue; } if (strstr(SRLZTN_UI_BOX_FLEX_WEIGHT, kve->key)) { res = pk_stn(&bx.flex_weight, kve->val, &stn_end); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_FLEX_WEIGHT, res); continue; } continue; } if (strstr(SRLZTN_UI_BOX_FLEX_PADDING, kve->key)) { res = pk_stn(&bx.flex_padding, kve->val, &stn_end); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_FLEX_PADDING, res); continue; } continue; } if (strstr(SRLZTN_UI_BOX_FLEX_DIRECTION, kve->key)) { res = pk_stn(&bx.flex_direction, kve->val, &stn_end); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_FLEX_DIRECTION, res); continue; } continue; } if (strstr(SRLZTN_UI_BOX_LAYER, kve->key)) { res = pk_stn(&bx.layer, kve->val, &stn_end); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_LAYER, res); continue; } continue; } if (strstr(SRLZTN_UI_BOX_TYPE, kve->key)) { uint8_t v; res = pk_stn(&v, kve->val, &stn_end); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse '%s' from '%s', err: %i\n", SRLZTN_UI_BOX_TYPE, kve->val, res); continue; } // log warning for unknown bx.type = PKE_UI_BOX_TYPE{v}; switch (bx.type) { case PKE_UI_BOX_TYPE_STANDARD: case PKE_UI_BOX_TYPE_TEXT: case PKE_UI_BOX_TYPE_INPUT_TEXT: case PKE_UI_BOX_TYPE_BUTTON_TEXT: case PKE_UI_BOX_TYPE_BUTTON_IMAGE: break; default: fprintf(stderr, "[pke_deserialize_ui_box] Parsed unknown ui box data type from: '%s'\n", kve->val); continue; } continue; } if (strstr(SRLZTN_UI_BOX_COLOR_BORDER, kve->key)) { starting_char = kve->val; index = 0; do { assert(index < 4); res = pk_stn(&bx.color_border[index], starting_char, &stn_end); if (res != PK_STN_RES_SUCCESS) break; starting_char = stn_end + 1; ++index; } while (*stn_end != '\0'); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_COLOR_BORDER, res); } continue; } if (strstr(SRLZTN_UI_BOX_COLOR_BACKGROUND, kve->key)) { starting_char = kve->val; index = 0; do { assert(index < 4); res = pk_stn(&bx.color_background[index], starting_char, &stn_end); if (res != PK_STN_RES_SUCCESS) break; starting_char = stn_end + 1; ++index; } while (*stn_end != '\0'); if (res != PK_STN_RES_SUCCESS) { fprintf(stderr, "[pke_deserialize_ui_box] Failed to parse value for: '%s', err: %i\n", SRLZTN_UI_BOX_COLOR_BACKGROUND, res); } continue; } } // deserialize data // TODO specific bucket? if (bx.type != PKE_UI_BOX_TYPE_STANDARD) { bx.type_data = pk_new(); switch (bx.type) { case PKE_UI_BOX_TYPE_TEXT: pke_deserialize_ui_box_internal(h, kvec->children[0], &bx.type_data->text); break; case PKE_UI_BOX_TYPE_BUTTON_TEXT: pke_deserialize_ui_box_internal(h, kvec->children[0], &bx.type_data->button_text); break; case PKE_UI_BOX_TYPE_BUTTON_IMAGE: pke_deserialize_ui_box_internal(h, kvec->children[0], &bx.type_data->button_image); break; default: fprintf(stderr, "[pke_deserialize_ui_box] unhandled box type: %hhu\n", static_cast(bx.type)); return; } } pke_ui_box *box; if (parent_box == nullptr) { box = pke_ui_box_new_root(bx.type, bx.uuid); pke_level_register_root_ui_box(h->level, box); } else { box = pke_ui_box_new_child(parent_box, bx.type, bx.uuid); } box->flags = bx.flags; box->pos_top_left = bx.pos_top_left; box->min_size = bx.min_size; box->max_size = bx.max_size; box->flex_weight = bx.flex_weight; box->flex_padding = bx.flex_padding; box->type = bx.type; box->flex_direction = bx.flex_direction; box->layer = bx.layer; box->color_border = bx.color_border; box->color_background = bx.color_background; // TODO consider type-specific clone functions if (box->type_data != nullptr && bx.type_data != nullptr) { *box->type_data = *bx.type_data; pk_delete(bx.type_data); bx.type_data = nullptr; } if (box->type == PKE_UI_BOX_TYPE_BUTTON_IMAGE) { pke_ui_box_update_textures(box); } srlztn_ecs_mapping map{}; map.serialized_uuid = bx.uuid; map.created_entity = box; pk_arr_append_t(&h->mapping, map); // recursively deserialize children for (i = 0; i < kvec->children.next; ++i) { pke_kve_container *child_kvec = kvec->children[i]; if (strcmp(child_kvec->type_code.val, SRLZTN_OBJ_UI_BOX) == 0) { pke_deserialize_ui_box(h, child_kvec); } } return; }