summaryrefslogtreecommitdiff
path: root/src/level-import.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/level-import.cpp')
-rw-r--r--src/level-import.cpp424
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;
+}