#include "level-main.hpp" #include "pke-at-data-interface-types.hpp" #include "pke-at-data-interface.hpp" #include "pke-at-setlist-types.hpp" #include "pke-at-settings.hpp" #include "pke-at-storage-interface.hpp" #include "level-import.hpp" #include #include #include typedef int pke_level_import_state; static const pke_level_import_state state_none = 0; static const pke_level_import_state state_get_service_types = 1; static const pke_level_import_state state_display_service_types = 2; static const pke_level_import_state state_wait_service_types = 3; static const pke_level_import_state state_err_service_types = 4; static const pke_level_import_state state_get_upcoming_plans = 5; static const pke_level_import_state state_display_upcoming_plans = 6; static const pke_level_import_state state_wait_upcoming_plans = 7; static const pke_level_import_state state_err_upcoming_plans = 8; static const pke_level_import_state state_get_plan_items = 9; static const pke_level_import_state state_err_plan_items = 10; static const pke_level_import_state state_display_summary = 11; static const pke_level_import_state state_wait_summary = 12; void pke_at_level_import_recalc_ui(void*,void*,void*); void pke_at_level_import_service_type_clicked(void *vbox, void *data, void*); void pke_at_level_import_upcoming_plan_clicked(void *vbox, void *data, void*); void pke_at_level_import_back_clicked(void*,void*,void*); void pke_at_level_import_exit_clicked(void*,void*,void*); void pke_at_level_import_import_clicked(void*,void*,void*); pke_ui_box *pke_at_level_import_build_ui_list_item(pke_ui_box *parent_box, pk_cstr &&str, pk_ev_cb_fn fn, void *item_ptr, PKE_UI_BOX_TYPE box_type); void pke_at_level_import_build_ui_service_types(); void pke_at_level_import_build_ui_upcoming_plans(); void pke_at_level_import_build_ui_setlist_import_details(); static struct pke_level_import_master { pke_level *level = nullptr; pke_level_import_state state = state_none; struct pke_level_import_master_ui { pke_ui_box *root_box; pke_ui_box *root_bottom_bar; pke_ui_box *root_setlist_details; pke_ui_box *root_setlist_items; pke_ui_box *btn_exit; pke_ui_box *btn_back; pke_ui_box *btn_import; } ui; struct pke_level_import_data { FPADIRT(pk_arr_t) future_service_types; pk_arr_t service_types; di_service_type *selected_service_type; FPADIRT(pk_arr_t) future_upcoming_plans; pk_arr_t plans; di_plan *selected_plan; FPADIRT(pk_arr_t) future_plan_items; pk_arr_t plan_items; } data; } lvl_mstr; pke_level *pke_at_level_import_create() { lvl_mstr.level = pke_level_create("import", pk_uuid_zed, pk_uuid_zed); lvl_mstr.level->pke_cb_spinup.func = pke_at_level_import_init; lvl_mstr.level->pke_cb_tick.func = (void(*)())pke_at_level_import_tick; lvl_mstr.level->pke_cb_teardown.func = pke_at_level_import_teardown; return lvl_mstr.level; } void pke_at_level_import_recalc_ui(void*a=nullptr,void*b=nullptr,void*c=nullptr) { (void)a; (void)b; (void)c; pke_ui_box *root = nullptr; root = lvl_mstr.ui.root_box; if (root != nullptr) { root->min_size.x = 0; root->min_size.y = 0; root->max_size.x = Extent.width - 8; root->max_size.y = Extent.height - 104; root->pos_top_left.x = 4; root->pos_top_left.y = 0; } root = lvl_mstr.ui.root_bottom_bar; if (root != nullptr) { root->min_size.x = Extent.width; root->min_size.y = 100; root->max_size.x = Extent.width; root->max_size.y = 100; root->pos_top_left.x = 0; root->pos_top_left.y = Extent.height - 104; } root = lvl_mstr.ui.root_setlist_details; if (root != nullptr) { root->min_size.x = 500; root->min_size.y = Extent.height - 116; root->max_size.x = 500; root->max_size.y = Extent.height - 116; root->pos_top_left.x = 6; root->pos_top_left.y = 6; } root = lvl_mstr.ui.root_setlist_items; if (root != nullptr) { root->min_size.x = Extent.width - 518; root->min_size.y = Extent.height - 116; root->max_size.x = Extent.width - 518; root->max_size.y = Extent.height - 116; root->pos_top_left.x = 512; root->pos_top_left.y = 6; } } void pke_at_level_import_service_type_clicked(void *vbox, void *data, void *) { fprintf(stdout, "[%s] pke_at_level_import_service_type_clicked : %lu\n", __FILE__, time(NULL)); (void)vbox; di_service_type *service_type = reinterpret_cast(data); lvl_mstr.data.future_upcoming_plans = g_at.data->get_plans_upcoming_from_service_type(service_type); lvl_mstr.data.selected_service_type = service_type; lvl_mstr.state = state_get_upcoming_plans; } void pke_at_level_import_upcoming_plan_clicked(void *vbox, void *data, void*) { (void)vbox; di_plan *plan = reinterpret_cast(data); lvl_mstr.data.future_plan_items = g_at.data->get_plan_items(plan); lvl_mstr.data.selected_plan = plan; lvl_mstr.state = state_get_plan_items; } void pke_at_level_import_back_clicked(void*,void*,void*) { pke_ui_box_count_T u; switch (lvl_mstr.state) { case state_wait_service_types: pkeSettings.rt.nextLevel = pke_at_level_main_create(); break; case state_wait_upcoming_plans: lvl_mstr.data.selected_service_type = nullptr; pk_arr_reset(&lvl_mstr.data.plans); lvl_mstr.state = state_display_service_types; break; case state_wait_summary: lvl_mstr.data.selected_plan = nullptr; pk_arr_reset(&lvl_mstr.data.plan_items); for (u = 0; u < lvl_mstr.ui.root_setlist_items->internal.h_children; ++u) { ECS_MarkForRemoval(lvl_mstr.ui.root_setlist_items->internal.children[u]); } lvl_mstr.ui.btn_import->flags |= PKE_UI_BOX_FLAG_VISIBILITY_DISABLED; lvl_mstr.ui.root_setlist_items->flags |= PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE; lvl_mstr.ui.root_setlist_details->flags |= PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE; lvl_mstr.state = state_display_upcoming_plans; break; default: fprintf(stderr, "[%s] pke_at_level_import_back_clicked unhandled state: %i", __FILE__, lvl_mstr.state); break; } } void pke_at_level_import_exit_clicked(void*,void*,void*) { pkeSettings.rt.nextLevel = pke_at_level_main_create(); } void pke_at_level_import_import_clicked(void*,void*,void*) { uint32_t u; pke_at_setlist_details setlist_details; setlist_details.uuid = pk_uuid_new_v7(); setlist_details.title = lvl_mstr.data.selected_plan->details.title; g_at.storage->pke_at_storage_interface_setlist_upsert(setlist_details); for (u = 0; u < lvl_mstr.data.plans.next; ++u) { di_plan_item *plan_item = &lvl_mstr.data.plan_items[u]; pke_at_song_details song_details{}; song_details.uuid = pk_uuid_new_v7(); song_details.key = plan_item->details.key; song_details.ccli = plan_item->song.details.ccli; song_details.title = plan_item->song.details.title; song_details.arrangement = plan_item->arrangement.details.title; song_details.bpm = plan_item->arrangement.details.beats_per_minute; g_at.storage->pke_at_storage_interface_song_upsert(song_details); pke_at_setlist_song_details setlist_song_details{}; setlist_song_details.setlist_uuid = setlist_details.uuid; setlist_song_details.song_uuid = song_details.uuid; g_at.storage->pke_at_storage_interface_setlist_song_upsert(setlist_song_details); } // EXIT LEVEL } pke_ui_box *pke_at_level_import_build_ui_list_item(pke_ui_box *parent_box, pk_cstr &&str, pk_ev_cb_fn fn = nullptr, void *item_ptr = nullptr, PKE_UI_BOX_TYPE box_type = PKE_UI_BOX_TYPE_BUTTON_TEXT) { FontRenderSettings frs{}; pke_component_event *ev; frs.char_scale = 32; frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH; frs.color_background = glm::vec4(0,0,0,1); frs.color_foreground = glm::vec4(1,1,1,1); frs.flags = FONT_RENDER_FLAG_NONE; pke_ui_box *bx = pke_ui_box_new_child(parent_box, box_type); bx->flex_weight = 1; bx->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_FLEX; bx->min_size.x = 0; bx->min_size.y = 0; bx->max_size.x = 8000; bx->max_size.y = 8000; bx->pos_top_left.x = 0; bx->pos_top_left.y = 0; if (box_type == PKE_UI_BOX_TYPE_TEXT) { bx->type_data->text.font_type_render = FontType_AddStringRender(FontTypeHandle{0,0}, std::move(str), &frs); } if (box_type == PKE_UI_BOX_TYPE_BUTTON_TEXT) { ev = ECS_GetEv(bx->type_data->button_text.pke_event_handle); pk_ev_register_cb(ev->ev_mgr_id, ev->ev_id, fn, item_ptr); bx->type_data->button_text.font_type_render = FontType_AddStringRender(FontTypeHandle{0,0}, std::move(str), &frs); } return bx; } void pke_at_level_import_init() { pke_ui_box *bx; FontRenderSettings frs{}; frs.char_scale = 32; frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH; frs.color_background = glm::vec4(0,0,0,1); frs.color_foreground = glm::vec4(1,1,1,1); frs.flags = FONT_RENDER_FLAG_NONE; lvl_mstr.data.future_service_types = g_at.data->get_service_types(); lvl_mstr.state = state_get_service_types; bx = pke_ui_box_new_root(); bx->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC; // root->flags |= PKE_UI_BOX_FLAG_CENTER_BOTH; bx->flags |= PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE; bx->flex_direction = 1; bx->flex_padding = 4; lvl_mstr.ui.root_box = bx; pke_level_register_root_ui_box(lvl_mstr.level, bx); pke_ui_box *bx_bottom_bar = pke_ui_box_new_root(); lvl_mstr.ui.root_bottom_bar = bx_bottom_bar; bx = bx_bottom_bar; bx->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC; bx->flags |= PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE; bx->flex_direction = 0; bx->flex_padding = 4; pke_level_register_root_ui_box(lvl_mstr.level, bx); pke_ui_box *bx_setlist_details = pke_ui_box_new_root(PKE_UI_BOX_TYPE_TEXT); lvl_mstr.ui.root_setlist_details = bx_setlist_details; bx = bx_setlist_details; bx->type_data->text.font_type_render = FontType_AddStringRender(FontTypeHandle{0,0}, cstring_to_pk_cstr(""), &frs, bx); bx->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC; bx->flags |= PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE; pke_level_register_root_ui_box(lvl_mstr.level, bx); pke_ui_box *bx_setlist_items = pke_ui_box_new_root(); lvl_mstr.ui.root_setlist_items = bx_setlist_items; bx = bx_setlist_items; bx->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC; bx->flags |= PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE; bx->flex_direction = 1; bx->flex_padding = 4; pke_level_register_root_ui_box(lvl_mstr.level, bx); lvl_mstr.ui.btn_exit = pke_at_level_import_build_ui_list_item(bx_bottom_bar, cstring_to_pk_cstr("Exit"), pke_at_level_import_exit_clicked, nullptr, PKE_UI_BOX_TYPE_BUTTON_TEXT); lvl_mstr.ui.btn_exit->color_background = glm::vec4(1,0,0,1); lvl_mstr.ui.btn_back = pke_at_level_import_build_ui_list_item(bx_bottom_bar, cstring_to_pk_cstr("Back"), pke_at_level_import_back_clicked, nullptr, PKE_UI_BOX_TYPE_BUTTON_TEXT); lvl_mstr.ui.btn_back->color_background = glm::vec4(0,0,1,1); bx = pke_at_level_import_build_ui_list_item(bx_bottom_bar, {}, nullptr, nullptr, PKE_UI_BOX_TYPE_STANDARD); bx->flags |= PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE; lvl_mstr.ui.btn_import = pke_at_level_import_build_ui_list_item(bx_bottom_bar, cstring_to_pk_cstr("Import"), pke_at_level_import_import_clicked, nullptr, PKE_UI_BOX_TYPE_BUTTON_TEXT); lvl_mstr.ui.btn_import->color_background = glm::vec4(0,1,0,1); lvl_mstr.ui.btn_import->flags |= PKE_UI_BOX_FLAG_VISIBILITY_DISABLED; pke_at_level_import_recalc_ui(); } void pke_at_level_import_build_ui_service_types() { uint32_t u; for (u = 0; u < lvl_mstr.ui.root_box->internal.h_children; ++u) { ECS_MarkForRemoval(lvl_mstr.ui.root_box->internal.children[u]); } for (u = 0; u < lvl_mstr.data.service_types.next; ++u) { di_service_type *service_type = &lvl_mstr.data.service_types[u]; pk_cstr title = pk_cstr_clone(&service_type->details.name, nullptr); pke_at_level_import_build_ui_list_item(lvl_mstr.ui.root_box, std::move(title), pke_at_level_import_service_type_clicked, service_type); } } void pke_at_level_import_build_ui_upcoming_plans() { uint32_t u; for (u = 0; u < lvl_mstr.ui.root_box->internal.h_children; ++u) { ECS_MarkForRemoval(lvl_mstr.ui.root_box->internal.children[u]); } for (u = 0; u < lvl_mstr.data.service_types.next; ++u) { di_plan *plan = &lvl_mstr.data.plans[u]; pk_cstr title = pk_cstr_clone(&plan->details.title, nullptr); pke_at_level_import_build_ui_list_item(lvl_mstr.ui.root_box, std::move(title), pke_at_level_import_upcoming_plan_clicked, plan); } } void pke_at_level_import_build_ui_setlist_import_details() { uint32_t u; struct tm *t; size_t text_head = 0; char *s; char summary_text[1024]; memset(summary_text, '\0', 1024); lvl_mstr.ui.btn_import->flags = static_cast(static_cast(lvl_mstr.ui.btn_import->flags) & ~static_cast(PKE_UI_BOX_FLAG_VISIBILITY_DISABLED)); for (u = 0; u < lvl_mstr.ui.root_box->internal.h_children; ++u) { ECS_MarkForRemoval(lvl_mstr.ui.root_box->internal.children[u]); } for (u = 0; u < lvl_mstr.ui.root_setlist_items->internal.h_children; ++u) { ECS_MarkForRemoval(lvl_mstr.ui.root_setlist_items->internal.children[u]); } lvl_mstr.ui.root_box->flags |= PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE; lvl_mstr.ui.root_setlist_items->flags = static_cast(static_cast(lvl_mstr.ui.root_setlist_items->flags) & ~static_cast(PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE)); lvl_mstr.ui.root_setlist_details->flags = static_cast(static_cast(lvl_mstr.ui.root_setlist_details->flags) & ~static_cast(PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE)); text_head += sprintf(summary_text+text_head, "(%li)\r\n\r\n", lvl_mstr.data.selected_plan->details.id.id_long); text_head -= 1; if (lvl_mstr.data.selected_plan->details.series_title.length > 0) { text_head += sprintf(summary_text+text_head, "%s\r\n\r\n", lvl_mstr.data.selected_plan->details.series_title.val); text_head -= 1; } if (lvl_mstr.data.selected_plan->details.title.length > 0) { text_head += sprintf(summary_text+text_head, "%s\r\n\r\n", lvl_mstr.data.selected_plan->details.title.val); text_head -= 1; } t = std::localtime(&lvl_mstr.data.selected_plan->details.date); strftime(summary_text+text_head, 1024-text_head, "%FT%TZ", t); pk_cstr cstr; cstr.length = strlen(summary_text); cstr.reserved = cstr.length + 1; s = pk_new_arr(cstr.reserved); sprintf(s, "%s", summary_text); cstr.val = s; pke_ui_box_type_data::pke_ui_box_type_data_text *text = &lvl_mstr.ui.root_setlist_details->type_data->text; FontType_UpdateStringRenderText(text->font_type_render, std::move(cstr)); for (u = 0; u < lvl_mstr.data.plan_items.next; ++u) { pk_cstr title; di_plan_item *plan_item = &lvl_mstr.data.plan_items[u]; title.length = snprintf(nullptr, 0, "%li - (%s) %s", plan_item->song.details.ccli, g_keys[plan_item->details.key].name, plan_item->song.details.title.val); title.reserved = title.length + 1; char *str = pk_new_arr(title.reserved); snprintf(str, title.reserved, "%li - (%s) %s", plan_item->song.details.ccli, g_keys[plan_item->details.key].name, plan_item->song.details.title.val); title.val = str; pke_at_level_import_build_ui_list_item(lvl_mstr.ui.root_setlist_items, std::move(title), nullptr, nullptr, PKE_UI_BOX_TYPE_TEXT); } pke_at_level_import_recalc_ui(); } void pke_at_level_import_tick(double delta) { (void)delta; unsigned int u; // state management if (pkeSettings.rt.was_framebuffer_resized) { pke_at_level_import_recalc_ui(); } if (lvl_mstr.state == state_get_service_types) { if (lvl_mstr.data.future_service_types.wait_for(std::chrono::seconds(0)) != std::future_status::ready) { return; } pke_at_data_interface_response_t> resp = lvl_mstr.data.future_service_types.get(); if (resp.result_code == pke_at_data_interface_result_code_error) { lvl_mstr.state = state_err_service_types; return; } lvl_mstr.data.service_types = *resp.value; pk_delete>(resp.value); lvl_mstr.data.future_service_types = {}; lvl_mstr.state = state_display_service_types; } if (lvl_mstr.state == state_display_service_types) { pke_at_level_import_build_ui_service_types(); lvl_mstr.state = state_wait_service_types; return; } if (lvl_mstr.state == state_err_service_types) { // TODO } if (lvl_mstr.state == state_wait_service_types) { // wait for user input return; } if (lvl_mstr.state == state_get_upcoming_plans) { if (lvl_mstr.data.future_upcoming_plans.wait_for(std::chrono::seconds(0)) != std::future_status::ready) { return; } pke_at_data_interface_response_t> resp = lvl_mstr.data.future_upcoming_plans.get(); if (resp.result_code == pke_at_data_interface_result_code_error) { lvl_mstr.state = state_err_upcoming_plans; return; } lvl_mstr.data.plans = *resp.value; pk_delete>(resp.value); lvl_mstr.data.future_upcoming_plans = {}; lvl_mstr.state = state_display_upcoming_plans; } if (lvl_mstr.state == state_display_upcoming_plans) { pke_at_level_import_build_ui_upcoming_plans(); lvl_mstr.state = state_wait_upcoming_plans; return; } if (lvl_mstr.state == state_wait_upcoming_plans) { // wait for user input return; } if (lvl_mstr.state == state_err_upcoming_plans) { // TODO } if (lvl_mstr.state == state_get_plan_items) { pke_at_data_interface_response_t> resp = lvl_mstr.data.future_plan_items.get(); if (resp.result_code == pke_at_data_interface_result_code_error) { lvl_mstr.state = state_err_plan_items; return; } lvl_mstr.data.plan_items = *resp.value; pk_delete>(resp.value); lvl_mstr.data.future_plan_items = {}; lvl_mstr.state = state_display_summary; // pke_at_level_import_import_plan_items(); // TODO // go to saved plan picker? // or maybe display all the info we got? // then allow the user to import ad-hoc? // for example, might be nice to just re-import a single song // - this begs the question of if we should just let the user search for a song to import, in which case can I go to ccli directly instead? } if (lvl_mstr.state == state_err_plan_items) { // TODO } if (lvl_mstr.state == state_display_summary) { pke_at_level_import_build_ui_setlist_import_details(); lvl_mstr.state = state_wait_summary; return; } if (lvl_mstr.state == state_wait_summary) { // wait for user input return; } } void pke_at_level_import_teardown() { pk_arr_reset(&lvl_mstr.data.plan_items); pk_arr_reset(&lvl_mstr.data.plans); pk_arr_reset(&lvl_mstr.data.service_types); lvl_mstr.data.selected_service_type = nullptr; lvl_mstr.data.selected_plan = nullptr; }