summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-11-06 22:38:36 -0500
committerJonathan Bradley <jcb@pikum.xyz>2025-11-06 22:38:36 -0500
commitf65db3c166ee1f41a7a33b0c19296f46babb09a5 (patch)
treeb98dcb6c0456f1daead3e6c15b617d18e552a1e5
parent6ca4d7a6b6c896cfcba0b3dfe02bf135b5c8ead7 (diff)
pke-at: chkpt: level-import
-rw-r--r--Makefile2
-rw-r--r--config.mk2
-rw-r--r--src/level-import.cpp424
-rw-r--r--src/level-import.hpp11
-rw-r--r--src/level-main.cpp68
-rw-r--r--src/pke-at-data-interface.hpp4
-rw-r--r--src/pke-at-data-planning-center.hpp6
-rw-r--r--src/pke-at-data-stub.cpp21
-rw-r--r--src/pke-at-data-stub.hpp4
-rw-r--r--src/pke-at-setlist-types.cpp23
-rw-r--r--src/pke-at-setlist-types.hpp9
-rw-r--r--src/pke-at-settings.hpp1
-rw-r--r--src/pke-at.cpp20
13 files changed, 560 insertions, 35 deletions
diff --git a/Makefile b/Makefile
index a6b0c06..9a87729 100644
--- a/Makefile
+++ b/Makefile
@@ -91,6 +91,7 @@ obj/%.o : tests/%.cpp | prepare
$(cxx-command)
bin/pke-at: ## Builds the pke-at executable
+bin/pke-at: obj/level-import.o
bin/pke-at: obj/level-init.o
bin/pke-at: obj/level-main.o
bin/pke-at: obj/main.o
@@ -98,6 +99,7 @@ bin/pke-at: obj/pke-at-common.o
bin/pke-at: obj/pke-at-data-stub.o
bin/pke-at: obj/pke-at-data-parser.o
bin/pke-at: obj/pke-at-settings.o
+bin/pke-at: obj/pke-at-setlist-types.o
bin/pke-at: obj/pke-at-storage-sql.o
bin/pke-at: obj/pke-at.o
$(CXX) -v -std=c++23 $(BUILD_MODE_FLAGS) $(INCS) -Wl,--whole-archive $^ $(LDFLAGS) -Wl,--no-whole-archive $(CXXFLAGS) -o $@
diff --git a/config.mk b/config.mk
index 65a6009..4d4bab5 100644
--- a/config.mk
+++ b/config.mk
@@ -20,7 +20,7 @@ GLSLC = /usr/bin/glslc
# libpipewire-0.3 \
# libspa-0.2 \
-USED_STATIC_LIBS = pke \
+USED_STATIC_LIBS = pke-dbg \
sqlite3 \
nlohmann_json \
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;
+}
diff --git a/src/level-import.hpp b/src/level-import.hpp
new file mode 100644
index 0000000..dd0c8a7
--- /dev/null
+++ b/src/level-import.hpp
@@ -0,0 +1,11 @@
+#ifndef PKE_AT_LEVEL_IMPORT_HPP
+#define PKE_AT_LEVEL_IMPORT_HPP
+
+#include "pke/level-types.hpp"
+
+pke_level *pke_at_level_import_create();
+void pke_at_level_import_init();
+void pke_at_level_import_tick(double delta);
+void pke_at_level_import_teardown();
+
+#endif /* PKE_AT_LEVEL_IMPORT_HPP */
diff --git a/src/level-main.cpp b/src/level-main.cpp
index 71999ce..a852f7d 100644
--- a/src/level-main.cpp
+++ b/src/level-main.cpp
@@ -1,6 +1,7 @@
#include "level-main.hpp"
+#include "level-import.hpp"
#include "pke-at-common.hpp"
#include "pke-at-settings.hpp"
@@ -9,6 +10,7 @@
struct pke_level_main_master {
pke_level *level = nullptr;
struct pke_level_main_master_ui {
+ pke_ui_box *root_btn_import = nullptr;
pke_ui_box *ctrls = nullptr;
pke_ui_box *btn_play_pause = nullptr;
pke_ui_box *btn_stop = nullptr;
@@ -99,6 +101,17 @@ void pke_at_level_main_recalc_ui() {
box->pos_top_left.x = 0;
box->pos_top_left.y = 0;
+ box = main_mstr.ui.root_btn_import;
+ box->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC;
+ box->color_border = glm::vec4(1,1,1,1);
+ box->color_background = glm::vec4(.2,.2,.2,1);
+ box->min_size.x = 300;
+ box->min_size.y = 34;
+ box->max_size.x = 300;
+ box->max_size.y = 34;
+ box->pos_top_left.x = Extent.width - 300;
+ box->pos_top_left.y = 0;
+
pke_ui_force_recalc();
}
@@ -115,15 +128,15 @@ void pke_at_level_main_btn_play_pause_cb(void *ev_data, void *cb_data, void *em_
(void)em_data;
if (!PK_HAS_FLAG(g_at.rt.flags, PKE_AT_RUNTIME_FLAG_PLAYING)) {
g_at.rt.flags |= PKE_AT_RUNTIME_FLAG_PLAYING;
- FontType_UpdateStringRenderText(main_mstr.ui.btn_play_pause->type_data->button_text.font_render_handle, cstring_to_pk_cstr("Pause"));
+ FontType_UpdateStringRenderText(main_mstr.ui.btn_play_pause->type_data->button_text.font_type_render, cstring_to_pk_cstr("Pause"));
return;
}
if (!PK_HAS_FLAG(g_at.rt.flags, PKE_AT_RUNTIME_FLAG_PAUSED)) {
g_at.rt.flags |= PKE_AT_RUNTIME_FLAG_PAUSED;
- FontType_UpdateStringRenderText(main_mstr.ui.btn_play_pause->type_data->button_text.font_render_handle, cstring_to_pk_cstr("Resume"));
+ FontType_UpdateStringRenderText(main_mstr.ui.btn_play_pause->type_data->button_text.font_type_render, cstring_to_pk_cstr("Resume"));
} else {
g_at.rt.flags &= ~PKE_AT_RUNTIME_FLAG_PAUSED;
- FontType_UpdateStringRenderText(main_mstr.ui.btn_play_pause->type_data->button_text.font_render_handle, cstring_to_pk_cstr("Pause"));
+ FontType_UpdateStringRenderText(main_mstr.ui.btn_play_pause->type_data->button_text.font_type_render, cstring_to_pk_cstr("Pause"));
}
}
@@ -133,7 +146,7 @@ void pke_at_level_main_btn_stop_cb(void *ev_data, void *cb_data, void *em_data)
(void)em_data;
g_at.rt.flags &= ~(PKE_AT_RUNTIME_FLAG_PLAYING | PKE_AT_RUNTIME_FLAG_PAUSED);
pke_at_bpm_reset(g_at.bpm.target);
- FontType_UpdateStringRenderText(main_mstr.ui.btn_play_pause->type_data->button_text.font_render_handle, cstring_to_pk_cstr("Play"));
+ FontType_UpdateStringRenderText(main_mstr.ui.btn_play_pause->type_data->button_text.font_type_render, cstring_to_pk_cstr("Play"));
}
void pke_at_level_main_btn_next_cb(void *ev_data, void *cb_data, void *em_data) {
@@ -143,63 +156,82 @@ void pke_at_level_main_btn_next_cb(void *ev_data, void *cb_data, void *em_data)
// TODO
}
+void pke_at_level_main_btn_import_cb(void *ev_data, void *cb_data, void *em_data) {
+ (void)ev_data;
+ (void)cb_data;
+ (void)em_data;
+ pkeSettings.rt.nextLevel = pke_at_level_import_create();
+}
+
void pke_at_level_main_init() {
FontRenderSettings frs{};
pke_ui_box *ctrls = pke_ui_box_new_root();
+ pke_ui_box *root_btn_import = pke_ui_box_new_root(PKE_UI_BOX_TYPE_BUTTON_TEXT);
pke_level_register_root_ui_box(main_mstr.level, ctrls);
+ pke_level_register_root_ui_box(main_mstr.level, root_btn_import);
main_mstr.ui.ctrls = ctrls;
+ main_mstr.ui.root_btn_import = root_btn_import;
pke_ui_box *btn_prev_track = pke_ui_box_new_child(ctrls, PKE_UI_BOX_TYPE_BUTTON_TEXT);
main_mstr.ui.btn_prev_track = btn_prev_track;
- frs.char_scale = 12;
+ frs.char_scale = 16;
frs.color_background = glm::vec4(0,0,0,1);
frs.color_foreground = glm::vec4(1,0,0,1);
frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH;
- FontRenderHandle fr_prev = FontType_AddStringRender(FontTypeIndex{0}, cstring_to_pk_cstr(" < "), &frs);
- btn_prev_track->type_data->button_text.font_render_handle = fr_prev;
+ FontTypeRender fr_prev = FontType_AddStringRender(FontTypeIndex{0}, cstring_to_pk_cstr(" < "), &frs);
+ btn_prev_track->type_data->button_text.font_type_render = fr_prev;
pke_component_event *prev_ev = ECS_CreateEv(btn_prev_track, pk_uuid_max);
pk_ev_register_cb(prev_ev->ev_mgr_id, prev_ev->ev_id, pke_at_level_main_btn_prev_cb, nullptr);
btn_prev_track->type_data->button_text.pke_event_handle = prev_ev->pke_event_handle;
pke_ui_box *btn_play_pause = pke_ui_box_new_child(ctrls, PKE_UI_BOX_TYPE_BUTTON_TEXT);
main_mstr.ui.btn_play_pause = btn_play_pause;
- frs.char_scale = 12;
+ frs.char_scale = 16;
frs.color_background = glm::vec4(0,0,0,1);
frs.color_foreground = glm::vec4(0,1,0,1);
frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH;
- FontRenderHandle fr_play = FontType_AddStringRender(FontTypeIndex{0}, cstring_to_pk_cstr(" Play "), &frs);
- btn_play_pause->type_data->button_text.font_render_handle = fr_play;
+ FontTypeRender fr_play = FontType_AddStringRender(FontTypeIndex{0}, cstring_to_pk_cstr(" Play "), &frs);
+ btn_play_pause->type_data->button_text.font_type_render = fr_play;
pke_component_event *play_pause_ev = ECS_CreateEv(btn_play_pause, pk_uuid_max);
pk_ev_register_cb(play_pause_ev->ev_mgr_id, play_pause_ev->ev_id, pke_at_level_main_btn_play_pause_cb, nullptr);
btn_play_pause->type_data->button_text.pke_event_handle = play_pause_ev->pke_event_handle;
pke_ui_box *btn_stop = pke_ui_box_new_child(ctrls, PKE_UI_BOX_TYPE_BUTTON_TEXT);
main_mstr.ui.btn_stop = btn_stop;
- frs.char_scale = 12;
+ frs.char_scale = 16;
frs.color_background = glm::vec4(0,0,0,1);
frs.color_foreground = glm::vec4(0.5,0.5,0,1);
frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH;
- FontRenderHandle fr_stop = FontType_AddStringRender(FontTypeIndex{0}, cstring_to_pk_cstr(" Stop "), &frs);
- btn_stop->type_data->button_text.font_render_handle = fr_stop;
+ FontTypeRender fr_stop = FontType_AddStringRender(FontTypeIndex{0}, cstring_to_pk_cstr(" Stop "), &frs);
+ btn_stop->type_data->button_text.font_type_render = fr_stop;
pke_component_event *stop_ev = ECS_CreateEv(btn_stop, pk_uuid_max);
pk_ev_register_cb(stop_ev->ev_mgr_id, stop_ev->ev_id, pke_at_level_main_btn_stop_cb, nullptr);
btn_stop->type_data->button_text.pke_event_handle = stop_ev->pke_event_handle;
pke_ui_box *btn_next_track = pke_ui_box_new_child(ctrls, PKE_UI_BOX_TYPE_BUTTON_TEXT);
main_mstr.ui.btn_next_track = btn_next_track;
- frs.char_scale = 12;
+ frs.char_scale = 16;
frs.color_background = glm::vec4(0,0,0,1);
frs.color_foreground = glm::vec4(0,0,1,1);
frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH;
- FontRenderHandle fr_next = FontType_AddStringRender(FontTypeIndex{0}, cstring_to_pk_cstr(" > "), &frs);
- btn_next_track->type_data->button_text.font_render_handle = fr_next;
+ FontTypeRender fr_next = FontType_AddStringRender(FontTypeIndex{0}, cstring_to_pk_cstr(" > "), &frs);
+ btn_next_track->type_data->button_text.font_type_render = fr_next;
pke_component_event *next_ev = ECS_CreateEv(btn_next_track, pk_uuid_max);
pk_ev_register_cb(next_ev->ev_mgr_id, next_ev->ev_id, pke_at_level_main_btn_next_cb, nullptr);
btn_next_track->type_data->button_text.pke_event_handle = next_ev->pke_event_handle;
+ frs.char_scale = 16;
+ frs.color_background = glm::vec4(0,0,0,1);
+ frs.color_foreground = glm::vec4(1,1,1,1);
+ frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH;
+ pke_component_event *import_ev = ECS_CreateEv(main_mstr.ui.root_btn_import, pk_uuid_max);
+ main_mstr.ui.root_btn_import->type_data->button_text.pke_event_handle = import_ev->pke_event_handle;
+ pk_ev_register_cb(import_ev->ev_mgr_id, import_ev->ev_id, pke_at_level_main_btn_import_cb, nullptr);
+ main_mstr.ui.root_btn_import->type_data->button_text.font_type_render = FontType_AddStringRender(FontTypeIndex{0}, cstring_to_pk_cstr("IMPORT"), &frs);
+
pke_at_bpm_reset(120);
- g_at.mtrnm.beep = pke_at_audio_get_or_generate_sawtooth(440.f, 0.30);
- g_at.mtrnm.beep_accent = pke_at_audio_get_or_generate_sawtooth(440.f * (3/2.f), 0.30);
+ g_at.mtrnm.beep = g_keys[PKE_AT_KEY_INDEX_B].mtrnm_beat_asset_handle;
+ g_at.mtrnm.beep_accent = g_keys[PKE_AT_KEY_INDEX_B].mtrnm_down_beat_asset_handle;
pke_audio_set_volume(pke_audio_source_sfx, 0.25);
g_at.rt.flags = PKE_AT_RUNTIME_FLAG_NONE;
diff --git a/src/pke-at-data-interface.hpp b/src/pke-at-data-interface.hpp
index ec10747..b57fe58 100644
--- a/src/pke-at-data-interface.hpp
+++ b/src/pke-at-data-interface.hpp
@@ -30,8 +30,8 @@ struct pke_at_data_interface {
virtual void init() const = 0;
virtual void teardown() const = 0;
virtual FPADIRT(pk_arr_t<di_service_type>) get_service_types() const = 0;
- virtual FPADIRT(pk_arr_t<di_plan>) get_plans_upcoming_from_service_type() const = 0;
- virtual FPADIRT(pk_arr_t<di_plan_item>) get_plan_items() const = 0;
+ virtual FPADIRT(pk_arr_t<di_plan>) get_plans_upcoming_from_service_type(di_service_type *service_type) const = 0;
+ virtual FPADIRT(pk_arr_t<di_plan_item>) get_plan_items(di_plan *plan) const = 0;
// virtual FPADIRT(pk_arr_t<pke_at_plan_details>) get_song_arrangements() const = 0;
};
diff --git a/src/pke-at-data-planning-center.hpp b/src/pke-at-data-planning-center.hpp
new file mode 100644
index 0000000..c3fd680
--- /dev/null
+++ b/src/pke-at-data-planning-center.hpp
@@ -0,0 +1,6 @@
+#ifndef PKE_AT_PKE_AT_DATA_PLANNING_CENTER_HPP
+#define PKE_AT_PKE_AT_DATA_PLANNING_CENTER_HPP
+
+
+
+#endif /* PKE_AT_PKE_AT_DATA_PLANNING_CENTER_HPP */
diff --git a/src/pke-at-data-stub.cpp b/src/pke-at-data-stub.cpp
index c36583f..d539f11 100644
--- a/src/pke-at-data-stub.cpp
+++ b/src/pke-at-data-stub.cpp
@@ -15,8 +15,9 @@ void pke_at_data_stub::teardown() const {
FPADIRT(pk_arr_t<di_service_type>)
pke_at_data_stub::get_service_types() const {
- PPADIRT(pk_arr_t<di_service_type>) ret{};
- std::thread([&ret]() {
+ static PPADIRT(pk_arr_t<di_service_type>) ret{};
+ ret = {};
+ std::thread([]() {
pke_at_data_interface_response_t<pk_arr_t<di_service_type>> val{};
val.result_code = pke_at_data_interface_result_code_success;
val.value = pk_new<pk_arr_t<di_service_type>>();
@@ -27,9 +28,11 @@ pke_at_data_stub::get_service_types() const {
};
FPADIRT(pk_arr_t<di_plan>)
-pke_at_data_stub::get_plans_upcoming_from_service_type() const {
- PPADIRT(pk_arr_t<di_plan>) ret{};
- std::thread([&ret]() {
+pke_at_data_stub::get_plans_upcoming_from_service_type(di_service_type *service_type) const {
+ (void)service_type;
+ static PPADIRT(pk_arr_t<di_plan>) ret{};
+ ret = {};
+ std::thread([]() {
pke_at_data_interface_response_t<pk_arr_t<di_plan>> val{};
val.result_code = pke_at_data_interface_result_code_success;
val.value = pk_new<pk_arr_t<di_plan>>();
@@ -40,9 +43,11 @@ pke_at_data_stub::get_plans_upcoming_from_service_type() const {
}
FPADIRT(pk_arr_t<di_plan_item>)
-pke_at_data_stub::get_plan_items() const {
- PPADIRT(pk_arr_t<di_plan_item>) ret{};
- std::thread([&ret]() {
+pke_at_data_stub::get_plan_items(di_plan *plan) const {
+ (void)plan;
+ static PPADIRT(pk_arr_t<di_plan_item>) ret{};
+ ret = {};
+ std::thread([]() {
pke_at_data_interface_response_t<pk_arr_t<di_plan_item>> val{};
val.result_code = pke_at_data_interface_result_code_success;
val.value = pk_new<pk_arr_t<di_plan_item>>();
diff --git a/src/pke-at-data-stub.hpp b/src/pke-at-data-stub.hpp
index 4f8d929..a875ee3 100644
--- a/src/pke-at-data-stub.hpp
+++ b/src/pke-at-data-stub.hpp
@@ -7,8 +7,8 @@ class pke_at_data_stub : public pke_at_data_interface {
void init() const override;
void teardown() const override;
FPADIRT(pk_arr_t<di_service_type>) get_service_types() const override;
- FPADIRT(pk_arr_t<di_plan>) get_plans_upcoming_from_service_type() const override;
- FPADIRT(pk_arr_t<di_plan_item>) get_plan_items() const override;
+ FPADIRT(pk_arr_t<di_plan>) get_plans_upcoming_from_service_type(di_service_type *service_type) const override;
+ FPADIRT(pk_arr_t<di_plan_item>) get_plan_items(di_plan *plan) const override;
// FPADIRT(pk_arr_t<pke_at_plan_details>) get_song_arrangements() const override;
};
diff --git a/src/pke-at-setlist-types.cpp b/src/pke-at-setlist-types.cpp
new file mode 100644
index 0000000..9aeea2b
--- /dev/null
+++ b/src/pke-at-setlist-types.cpp
@@ -0,0 +1,23 @@
+
+#include "pke-at-setlist-types.hpp"
+
+pke_at_key g_keys[PKE_AT_KEY_INDEX_COUNT] = {
+ { "NIL", 0, 0 },
+ { "C", 523.2511, 523.2511 * (3/2.f) },
+ { "C♯", 554.3653, 554.3653 * (3/2.f) },
+ { "D♭", 554.3653, 554.3653 * (3/2.f) },
+ { "D", 587.3295, 587.3295 * (3/2.f) },
+ { "D♯", 622.2540, 622.2540 * (3/2.f) },
+ { "E♭", 622.2540, 622.2540 * (3/2.f) },
+ { "E", 659.2551, 659.2551 * (3/2.f) },
+ { "F", 698.4565, 698.4565 * (3/2.f) },
+ { "F♯", 739.9888, 739.9888 * (3/2.f) },
+ { "G♭", 739.9888, 739.9888 * (3/2.f) },
+ { "G", 783.9909, 783.9909 * (3/2.f) },
+ { "G♯", 830.6094, 830.6094 * (3/2.f) },
+ { "A♭", 830.6094, 830.6094 * (3/2.f) },
+ { "A", 880.0000, 880.0000 * (3/2.f) },
+ { "A♯", 932.3275, 932.3275 * (3/2.f) },
+ { "B♭", 932.3275, 932.3275 * (3/2.f) },
+ { "B", 987.7666, 987.7666 * (3/2.f) },
+};
diff --git a/src/pke-at-setlist-types.hpp b/src/pke-at-setlist-types.hpp
index 90c86d0..242df69 100644
--- a/src/pke-at-setlist-types.hpp
+++ b/src/pke-at-setlist-types.hpp
@@ -89,4 +89,13 @@ struct pke_at_setlist_song {
struct pke_at_setlist_song_details details{};
};
+struct pke_at_key {
+ const char *name;
+ float mtrnm_hz_beat;
+ float mtrnm_hz_down_beat;
+ AssetHandle mtrnm_beat_asset_handle = AssetHandle_MAX;
+ AssetHandle mtrnm_down_beat_asset_handle = AssetHandle_MAX;
+};
+extern struct pke_at_key g_keys[PKE_AT_KEY_INDEX_COUNT];
+
#endif /* PKE_AT_PKE_AT_SETLIST_TYPES_HPP */
diff --git a/src/pke-at-settings.hpp b/src/pke-at-settings.hpp
index dd50532..81074d4 100644
--- a/src/pke-at-settings.hpp
+++ b/src/pke-at-settings.hpp
@@ -19,6 +19,7 @@ struct pke_at_global_settings {
pk_membucket *bkt_transient;
} mem;
struct pke_at_storage_interface *storage;
+ struct pke_at_data_interface *data;
struct pke_at_global_settings_bpm {
float last;
float target;
diff --git a/src/pke-at.cpp b/src/pke-at.cpp
index 0831c08..f53d2eb 100644
--- a/src/pke-at.cpp
+++ b/src/pke-at.cpp
@@ -1,5 +1,7 @@
#include "level-init.hpp"
+#include "pke-at-common.hpp"
+#include "pke-at-data-stub.hpp"
#include "pke-at-setlist-types.hpp"
#include "pke-at-settings.hpp"
#include "pke-at-storage-sql.hpp"
@@ -17,16 +19,26 @@ void pke_at_tick(double delta) {
}
void pke_at_init() {
- uint64_t i;
+ uint64_t u;
pkeSettings.rt.nextLevel = pke_at_level_init_create();
- for (i = 0; i < PKE_AT_SECTION_TYPE_INDEX_COUNT; ++i) {
- if (g_section_types[i].title_key[0] == '\0') continue;
- g_section_types[i].title_handle = AM_GetHandle(g_section_types[i].title_key);
+ for (u = 0; u < PKE_AT_SECTION_TYPE_INDEX_COUNT; ++u) {
+ if (g_section_types[u].title_key[0] == '\0') continue;
+ g_section_types[u].title_handle = AM_GetHandle(g_section_types[u].title_key);
+ }
+
+ for (u = 1; u < PKE_AT_KEY_INDEX_COUNT; ++u) {
+ g_keys[u].mtrnm_beat_asset_handle =
+ pke_at_audio_get_or_generate_sawtooth(g_keys[u].mtrnm_hz_beat, 0.3);
+ g_keys[u].mtrnm_down_beat_asset_handle =
+ pke_at_audio_get_or_generate_sawtooth(g_keys[u].mtrnm_hz_down_beat, 0.3);
}
g_at.storage = pk_new<pke_at_storage_sql>();
g_at.storage->init();
+
+ g_at.data = pk_new<pke_at_data_stub>();
+ g_at.data->init();
}
void pke_at_teardown() {