diff options
Diffstat (limited to 'src/level-import.cpp')
| -rw-r--r-- | src/level-import.cpp | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/src/level-import.cpp b/src/level-import.cpp new file mode 100644 index 0000000..63fe66b --- /dev/null +++ b/src/level-import.cpp @@ -0,0 +1,424 @@ + +#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 <chrono> +#include <future> +#include <pke/pke.hpp> + +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<di_service_type>) future_service_types; + pk_arr_t<di_service_type> service_types; + di_service_type *selected_service_type; + FPADIRT(pk_arr_t<di_plan>) future_upcoming_plans; + pk_arr_t<di_plan> plans; + di_plan *selected_plan; + FPADIRT(pk_arr_t<di_plan_item>) future_plan_items; + pk_arr_t<di_plan_item> 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<di_service_type**>(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<di_plan**>(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*) { + 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); + 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(FontTypeIndex{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); + fprintf(stdout, "[%s] pke_at_level_import_build_ui_list_item box: %p, ev_id: %lu, ev_handle %u:%u\n", __FILE__, (void *)bx, ev->ev_id, ev->pke_event_handle.b, ev->pke_event_handle.i); + bx->type_data->button_text.font_type_render = FontType_AddStringRender(FontTypeIndex{0}, std::move(str), &frs); + } + return bx; +} + +void pke_at_level_import_init() { + pke_ui_box *bx; + + 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(); + lvl_mstr.ui.root_setlist_details = bx_setlist_details; + bx = bx_setlist_details; + 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; + lvl_mstr.ui.btn_import->flags = static_cast<PKE_UI_BOX_FLAG>(static_cast<PKE_UI_BOX_FLAG_T>(lvl_mstr.ui.btn_import->flags) & ~static_cast<PKE_UI_BOX_FLAG_T>(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<PKE_UI_BOX_FLAG>(static_cast<PKE_UI_BOX_FLAG_T>(lvl_mstr.ui.root_setlist_items->flags) & ~static_cast<PKE_UI_BOX_FLAG_T>(PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE)); + lvl_mstr.ui.root_setlist_details->flags = static_cast<PKE_UI_BOX_FLAG>(static_cast<PKE_UI_BOX_FLAG_T>(lvl_mstr.ui.root_setlist_details->flags) & ~static_cast<PKE_UI_BOX_FLAG_T>(PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE)); + + 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<char>(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<pk_arr_t<di_service_type>> 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<pk_arr_t<di_service_type>>(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<pk_arr_t<di_plan>> 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<pk_arr_t<di_plan>>(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<pk_arr_t<di_plan_item>> 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<pk_arr_t<di_plan_item>>(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; +} |
