| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- #include <furi.h>
- #include <gui/gui.h>
- #include <gui/icon_i.h>
- #include <gui/view_dispatcher.h>
- #include <gui/scene_manager.h>
- #include <gui/modules/submenu.h>
- #include <gui/modules/popup.h>
- #include <gui/modules/widget.h>
- #define TAG "tarot"
- /* generated by fbt from .png files in images folder */
- #include <tarot_icons.h>
- /* ids for all scenes used by the app */
- typedef enum {
- AppScene_MainMenu,
- AppScene_About,
- AppScene_Game,
- AppScene_count
- } AppScene;
- /* ids for the 2 types of view used by the app */
- typedef enum { AppView_Submenu, AppView_Popup, AppView_Widget } AppView;
- /* the app context struct */
- typedef struct {
- SceneManager* scene_manager;
- ViewDispatcher* view_dispatcher;
- Submenu* submenu; // Submenu for the main menu
- Popup* popup; // Popup for about
- Widget* widget; // Widget for game
- } App;
- /* all custom events */
- typedef enum { AppEvent_ShowGame, AppEvent_ShowAbout } AppEvent;
- /* main menu scene */
- /* indices for menu items */
- typedef enum { AppMenuSelection_Run, AppMenuSelection_About } AppMenuSelection;
- /* main menu callback - sends a custom event to the scene manager based on the menu selection */
- void tarot_app_menu_callback_main_menu(void* context, uint32_t index) {
- FURI_LOG_T(TAG, "tarot_app_menu_callback_main_menu");
- App* app = context;
- switch(index) {
- case AppMenuSelection_Run:
- scene_manager_handle_custom_event(app->scene_manager, AppEvent_ShowGame);
- break;
- case AppMenuSelection_About:
- scene_manager_handle_custom_event(app->scene_manager, AppEvent_ShowAbout);
- break;
- }
- }
- /* resets the submenu, gives it content, callbacks and selection enums */
- void tarot_app_scene_on_enter_main_menu(void* context) {
- FURI_LOG_T(TAG, "tarot_app_scene_on_enter_main_menu");
- App* app = context;
- submenu_reset(app->submenu);
- submenu_add_item(
- app->submenu,
- "Run",
- AppMenuSelection_Run,
- tarot_app_menu_callback_main_menu,
- app);
- submenu_add_item(
- app->submenu,
- "About",
- AppMenuSelection_About,
- tarot_app_menu_callback_main_menu,
- app);
- view_dispatcher_switch_to_view(app->view_dispatcher, AppView_Submenu);
- }
- /* main menu event handler - switches scene based on the event */
- bool tarot_app_scene_on_event_main_menu(void* context, SceneManagerEvent event) {
- FURI_LOG_T(TAG, "tarot_app_scene_on_event_main_menu");
- App* app = context;
- bool consumed = false;
- switch(event.type) {
- case SceneManagerEventTypeCustom:
- switch(event.event) {
- case AppEvent_ShowGame:
- scene_manager_next_scene(app->scene_manager, AppScene_Game);
- consumed = true;
- break;
- case AppEvent_ShowAbout:
- scene_manager_next_scene(app->scene_manager, AppScene_About);
- consumed = true;
- break;
- }
- break;
- default: // eg. SceneManagerEventTypeBack, SceneManagerEventTypeTick
- consumed = false;
- break;
- }
- return consumed;
- }
- void tarot_app_scene_on_exit_main_menu(void* context) {
- FURI_LOG_T(TAG, "tarot_app_scene_on_exit_main_menu");
- App* app = context;
- submenu_reset(app->submenu);
- }
- /* About scene */
- void tarot_app_scene_on_enter_about(void* context) {
- FURI_LOG_T(TAG, "tarot_app_scene_on_enter_about");
- App* app = context;
- popup_reset(app->popup);
- popup_set_context(app->popup, app);
- popup_set_header(app->popup, "About", 64, 1, AlignCenter, AlignTop);
- popup_set_icon(app->popup, 16, 64-13, &I_github_icon);
- popup_set_text(app->popup, "\n\nCode: pionaiki\nArt: tihyltew\n\n /pionaiki/fz-tarot", 64, 0, AlignCenter, AlignTop);
- view_dispatcher_switch_to_view(app->view_dispatcher, AppView_Popup);
- }
- bool tarot_app_scene_on_event_about(void* context, SceneManagerEvent event) {
- FURI_LOG_T(TAG, "tarot_app_scene_on_event_about");
- UNUSED(context);
- UNUSED(event);
- return false; // don't handle any events
- }
- void tarot_app_scene_on_exit_about(void* context) {
- FURI_LOG_T(TAG, "tarot_app_scene_on_exit_about");
- App* app = context;
- popup_reset(app->popup);
- }
- /* Game scene */
- /* ###### */
- const int card_x = 23;
- const int card_y = 32;
- const int card_number = 22;
- int card_selected = 0;
- struct Card {
- const char name[20];
- const Icon* icon;
- };
- const struct Card card[] = {
- {"The Fool", &I_major_0},
- {"The Magician", &I_major_1},
- {"The High Priestess", &I_major_2},
- {"The Empress", &I_major_3},
- {"The Emperor", &I_major_4},
- {"The Hierophant", &I_major_5},
- {"The Lovers", &I_major_6},
- {"The Chariot", &I_major_7},
- {"Strength", &I_major_8},
- {"The Hermit", &I_major_9},
- {"Wheel of Fortune", &I_major_10},
- {"Justice", &I_major_11},
- {"The Hanged Man", &I_major_12},
- {"Death", &I_major_13},
- {"Temperance", &I_major_14},
- {"The Devil", &I_major_15},
- {"The Tower", &I_major_16},
- {"The Star", &I_major_17},
- {"The Moon", &I_major_18},
- {"The Sun", &I_major_19},
- {"Judgement", &I_major_20},
- {"The World", &I_major_21},
- {"The Fool", &I_major_0_},
- {"The Magician", &I_major_1_},
- {"The High Priestess", &I_major_2_},
- {"The Empress", &I_major_3_},
- {"The Emperor", &I_major_4_},
- {"The Hierophant", &I_major_5_},
- {"The Lovers", &I_major_6_},
- {"The Chariot", &I_major_7_},
- {"Strength", &I_major_8_},
- {"The Hermit", &I_major_9_},
- {"Wheel of Fortune", &I_major_10_},
- {"Justice", &I_major_11_},
- {"The Hanged Man", &I_major_12_},
- {"Death", &I_major_13_},
- {"Temperance", &I_major_14_},
- {"The Devil", &I_major_15_},
- {"The Tower", &I_major_16_},
- {"The Star", &I_major_17_},
- {"The Moon", &I_major_18_},
- {"The Sun", &I_major_19_},
- {"Judgement", &I_major_20_},
- {"The World", &I_major_21_}
- };
- static uint16_t unbiased_rand (uint16_t max) {
- uint16_t remainder = RAND_MAX % max;
- uint16_t x;
- do {
- x = rand();
- } while (x >= RAND_MAX - remainder);
- return x % max;
- }
- struct Spread {
- int card[3];
- bool selected[3];
- };
- struct Spread spread;
- void draw_tarot(void* context) {
- App* app = context;
- widget_reset(app->widget);
- // Set the cursor to the selected card
- spread.selected[0] = 0;
- spread.selected[1] = 0;
- spread.selected[2] = 0;
- spread.selected[card_selected] = 1;
- // Draw cards
- widget_add_icon_element(app->widget, (128-card_x)/2 - 32, 10 - 2*spread.selected[0], card[spread.card[0]].icon);
- widget_add_icon_element(app->widget, (128-card_x)/2, 10 - 2*spread.selected[1], card[spread.card[1]].icon);
- widget_add_icon_element(app->widget, (128-card_x)/2 + 32, 10 - 2*spread.selected[2], card[spread.card[2]].icon);
- // Draw cursor
- widget_add_icon_element(app->widget, (128-card_x)/2 - 34 + card_x/2 + card_selected*32, 41, &I_cursor);
- // Draw card name
- widget_add_string_element(app->widget, 64, 60, AlignCenter, AlignBottom, FontPrimary, card[spread.card[card_selected]].name);
- }
- static bool widget_input_callback(InputEvent* input_event, void* context) {
- App* app = context;
- bool consumed = false;
- if(input_event->type == InputTypeShort) {
- switch(input_event->key) {
- case InputKeyRight:
- card_selected++;
- if (card_selected > 2) {
- card_selected = 0;
- }
- consumed = true;
- break;
- case InputKeyLeft:
- card_selected--;
- if (card_selected < 0) {
- card_selected = 2;
- }
- consumed = true;
- break;
- case InputKeyUp:
- // UP
- //consumed = true;
- break;
- case InputKeyDown:
- // DOWN
- //consumed = true;
- break;
- default:
- consumed = false;
- break;
- }
- }
- if(consumed) draw_tarot(app);
- return consumed;
- }
- void tarot_app_scene_on_enter_game(void* context) {
- FURI_LOG_T(TAG, "tarot_app_scene_on_enter_game");
- App* app = context;
- // Set random spread
- spread.card[0] = unbiased_rand(card_number);
- spread.card[1] = unbiased_rand(card_number);
- while (spread.card[1] == spread.card[0]) {
- spread.card[1] = unbiased_rand(card_number);
- };
- spread.card[2] = unbiased_rand(card_number);
- while (spread.card[2] == spread.card[0] || spread.card[2] == spread.card[1]) {
- spread.card[2] = unbiased_rand(card_number);
- }
- // Upside down card option
- if (0/*settings.upside_down*/) {
- spread.card[0] += card_number*unbiased_rand(2);
- spread.card[1] += card_number*unbiased_rand(2);
- spread.card[2] += card_number*unbiased_rand(2);
- }
-
- draw_tarot(app);
- view_set_context(widget_get_view(app->widget), app);
- view_set_input_callback(widget_get_view(app->widget), widget_input_callback);
- view_dispatcher_switch_to_view(app->view_dispatcher, AppView_Widget);
- }
- bool tarot_app_scene_on_event_game(void* context, SceneManagerEvent event) {
- FURI_LOG_T(TAG, "tarot_app_scene_on_event_game");
- UNUSED(context);
- UNUSED(event);
- return false; // don't handle any events
- }
- void tarot_app_scene_on_exit_game(void* context) {
- FURI_LOG_T(TAG, "tarot_app_scene_on_exit_game");
- App* app = context;
- widget_reset(app->widget);
- }
- /* ###### */
- /* collection of all scene on_enter handlers - in the same order as their enum */
- void (*const tarot_app_scene_on_enter_handlers[])(void*) = {
- tarot_app_scene_on_enter_main_menu,
- tarot_app_scene_on_enter_about,
- tarot_app_scene_on_enter_game};
- /* collection of all scene on event handlers - in the same order as their enum */
- bool (*const tarot_app_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
- tarot_app_scene_on_event_main_menu,
- tarot_app_scene_on_event_about,
- tarot_app_scene_on_event_game};
- /* collection of all scene on exit handlers - in the same order as their enum */
- void (*const tarot_app_scene_on_exit_handlers[])(void*) = {
- tarot_app_scene_on_exit_main_menu,
- tarot_app_scene_on_exit_about,
- tarot_app_scene_on_exit_game};
- /* collection of all on_enter, on_event, on_exit handlers */
- const SceneManagerHandlers tarot_app_scene_event_handlers = {
- .on_enter_handlers = tarot_app_scene_on_enter_handlers,
- .on_event_handlers = tarot_app_scene_on_event_handlers,
- .on_exit_handlers = tarot_app_scene_on_exit_handlers,
- .scene_num = AppScene_count};
- /* custom event handler - passes the event to the scene manager */
- bool tarot_app_scene_manager_custom_event_callback(void* context, uint32_t custom_event) {
- FURI_LOG_T(TAG, "tarot_app_scene_manager_custom_event_callback");
- furi_assert(context);
- App* app = context;
- return scene_manager_handle_custom_event(app->scene_manager, custom_event);
- }
- /* navigation event handler - passes the event to the scene manager */
- bool tarot_app_scene_manager_navigation_event_callback(void* context) {
- FURI_LOG_T(TAG, "tarot_app_scene_manager_navigation_event_callback");
- furi_assert(context);
- App* app = context;
- return scene_manager_handle_back_event(app->scene_manager);
- }
- /* initialise the scene manager with all handlers */
- void tarot_app_scene_manager_init(App* app) {
- FURI_LOG_T(TAG, "tarot_app_scene_manager_init");
- app->scene_manager = scene_manager_alloc(&tarot_app_scene_event_handlers, app);
- }
- /* initialise the views, and initialise the view dispatcher with all views */
- void tarot_app_view_dispatcher_init(App* app) {
- FURI_LOG_T(TAG, "tarot_app_view_dispatcher_init");
- app->view_dispatcher = view_dispatcher_alloc();
- view_dispatcher_enable_queue(app->view_dispatcher);
- // allocate each view
- FURI_LOG_D(TAG, "tarot_app_view_dispatcher_init allocating views");
- app->submenu = submenu_alloc();
- app->popup = popup_alloc();
- app->widget = widget_alloc();
- // assign callback that pass events from views to the scene manager
- FURI_LOG_D(TAG, "tarot_app_view_dispatcher_init setting callbacks");
- view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
- view_dispatcher_set_custom_event_callback(
- app->view_dispatcher, tarot_app_scene_manager_custom_event_callback);
- view_dispatcher_set_navigation_event_callback(
- app->view_dispatcher, tarot_app_scene_manager_navigation_event_callback);
- // add views to the dispatcher, indexed by their enum value
- FURI_LOG_D(TAG, "tarot_app_view_dispatcher_init adding view menu");
- view_dispatcher_add_view(app->view_dispatcher, AppView_Submenu, submenu_get_view(app->submenu));
- FURI_LOG_D(TAG, "tarot_app_view_dispatcher_init adding view popup");
- view_dispatcher_add_view(app->view_dispatcher, AppView_Popup, popup_get_view(app->popup));
- FURI_LOG_D(TAG, "tarot_app_view_dispatcher_init adding view widget");
- view_dispatcher_add_view(app->view_dispatcher, AppView_Widget, widget_get_view(app->widget));
- }
- /* initialise app data, scene manager, and view dispatcher */
- App* tarot_app_init() {
- FURI_LOG_T(TAG, "tarot_app_init");
- App* app = malloc(sizeof(App));
- tarot_app_scene_manager_init(app);
- tarot_app_view_dispatcher_init(app);
- return app;
- }
- /* free all app data, scene manager, and view dispatcher */
- void tarot_app_free(App* app) {
- FURI_LOG_T(TAG, "tarot_app_free");
- scene_manager_free(app->scene_manager);
- view_dispatcher_remove_view(app->view_dispatcher, AppView_Submenu);
- view_dispatcher_remove_view(app->view_dispatcher, AppView_Popup);
- view_dispatcher_remove_view(app->view_dispatcher, AppView_Widget);
- view_dispatcher_free(app->view_dispatcher);
- submenu_free(app->submenu);
- popup_free(app->popup);
- widget_free(app->widget);
- free(app);
- }
- /* go to trace log level in the dev environment */
- void tarot_app_set_log_level() {
- #ifdef FURI_DEBUG
- furi_log_set_level(FuriLogLevelTrace);
- #else
- furi_log_set_level(FuriLogLevelInfo);
- #endif
- }
- /* entrypoint */
- int32_t tarot_app(void* p) {
- UNUSED(p);
- tarot_app_set_log_level();
- // create the app context struct, scene manager, and view dispatcher
- FURI_LOG_I(TAG, "Tarot app starting...");
- App* app = tarot_app_init();
- // set the scene and launch the main loop
- Gui* gui = furi_record_open(RECORD_GUI);
- view_dispatcher_attach_to_gui(app->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
- scene_manager_next_scene(app->scene_manager, AppScene_MainMenu);
- FURI_LOG_D(TAG, "Starting dispatcher...");
- view_dispatcher_run(app->view_dispatcher);
- // free all memory
- FURI_LOG_I(TAG, "Tarot app finishing...");
- furi_record_close(RECORD_GUI);
- tarot_app_free(app);
- return 0;
- }
|