#include #include #include #include #include #include #include #include #include "scenes.h" #include "../ui_elements/UI.h" #include "../resources/resources.h" #include "../utils/arena.h" #include "../resources/TextruesAtlas.h" static const float MENU_SCROLL_SENC = 75.0f; static const size_t ARENA_SIZE = 1024 * 64; static const int SCENE_PADDING = 30; static const int FOOTER_PADDING = 60; static const float ARROWS_HEIGHT = 0.4f; static const uint8_t ARROWS_ALPHA = 128; /// Height / width static const float ELEMENT_WIDTH_RATIO = 0.45f; typedef struct { CollectionElement *collection; CollectionElement *selected; Button *backButton; size_t count; float blackout_state; PopUpState state; float scroll; } CollectionSceneData; CollectionSceneData *getData(void *self) { return ((Scene *)self)->data; } static void backButton_onClick(Scene *self) { // CollectionSceneData *data = getData(self); DeleteSceneFromStack(); } void collectionElement_onSelect(CollectionElement *caller) { if (caller == NULL) return; TraceLog(LOG_INFO, "Selected element %s", caller->name); switch (caller->type) { case COLLECTION_ELEMENT_PUZZLE: AddScene(CreatePuzzlePreview(ReadPuzzleFromFile(caller->path))); break; case COLLECTION_ELEMENT_COLLECTION: AddScene(CreatePuzzleCollectionScene(caller, false)); break; default: TraceLog(LOG_WARNING, "Invalid CollectionElement type for %s", caller->path); break; } } void DrawCollectionName(char *name) { Vector2 width = MeasureTextEx(*GetMainFont(), name, HEADER_FONT_SIZE, 1); int screen_width = GetScreenWidth(); Vector2 pos = { .y = SCENE_PADDING , .x = (screen_width - width.x) / 2, }; DrawTextEx(*GetMainFont(), name, pos, HEADER_FONT_SIZE, 1, COLORSCHEME_BROWN); } // Does not allocate the memory char *getCollectionName(char *path) { char *outp = path; size_t len = strlen(path); for (size_t i = 0; i < len; ++i) { if ((path[i] == '/' || path[i] == '\\') && path[i+1] != 0x0) { outp = path + i + 1; } } return outp; } bool updateCollectionScene(void *self) { CollectionSceneData *data = getData(self); if (data->state == POPUP_REVEALING) { data->blackout_state -= BLACKOUT_SPEED * GetFrameTime(); if (data->blackout_state <= 0) { data->blackout_state = 0; data->state = POPUP_ACTIVE; TraceLog(LOG_INFO, "Done revealing"); } return true; } if (data->collection != NULL) { for (size_t i = 0; i < data->collection->childCount; ++i) { UpdateCollectionElement(&data->collection->children[i]); } } if (data->backButton != NULL) UpdateButton(data->backButton); return true; } bool drawCollectionScene(void *self) { CollectionSceneData *data = getData(self); DrawBackground(); DrawCollectionName(data->collection->name); DrawPageView(GetScreenHeight() - 60, 5, 2); if (data->backButton != NULL) DrawButton(data->backButton, &(Rectangle) { .x = 10, .y = GetScreenHeight() - 60, .width = 36, .height = 36, // TODO: make it match the page view scale }); float element_height = GetScreenHeight() - SCENE_PADDING * 2 - HEADER_FONT_SIZE - FOOTER_PADDING; float element_width = element_height * ELEMENT_WIDTH_RATIO; for (size_t i = 0; i < data->collection->childCount; ++i) { DrawCollectionElement(&data->collection->children[i], data->collection, (Rectangle) { .x = SCENE_PADDING + (element_width + PADDING) * i - data->scroll, .y = SCENE_PADDING + HEADER_FONT_SIZE, .width = element_width, .height = element_height, }); } data->scroll -= GetMouseWheelMove() * MENU_SCROLL_SENC; if (data->scroll < 0) data->scroll = 0; float max_scroll = (element_width + PADDING) * data->collection->childCount + SCENE_PADDING * 2 - GetScreenWidth(); if (max_scroll < 0) max_scroll = 0; if (data->scroll > max_scroll) data->scroll = max_scroll; float arrows_height_px = GetScreenHeight() * ARROWS_HEIGHT; Color arrows_color = { .r = 255, .g = 255, .b = 255, .a = ARROWS_ALPHA, }; if (data->scroll != 0) DrawTexturePro(*GetButtonsAtlas(), LEFT_ARROW_ICON_LOCATION, (Rectangle) { .x = 0, .y = (GetScreenHeight() - arrows_height_px) / 2, .width = SCENE_PADDING, .height = arrows_height_px }, (Vector2) {0}, 0, arrows_color); if (data->scroll != max_scroll) DrawTexturePro(*GetButtonsAtlas(), RIGHT_ARROW_ICON_LOCATION, (Rectangle) { .x = GetScreenWidth() - SCENE_PADDING, .y = (GetScreenHeight() - arrows_height_px) / 2, .width = SCENE_PADDING, .height = arrows_height_px }, (Vector2) {0}, 0, arrows_color); if (data->state != POPUP_ACTIVE) { DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), (Color) {0, 0, 0, 255 * (data->blackout_state >= 1 ? 1 : data->blackout_state) }); } return true; } void deinitCollectionScene(void *self) { TraceLog(LOG_INFO, "Deleting a collection scene"); CollectionSceneData *data = getData(self); if (data != NULL) { if (data->collection != NULL) DeinitCollectionElement(data->collection); free(data); } free((Scene *)self); } Scene *CreatePuzzleCollectionScene(CollectionElement *el, bool smooothEntry) { TraceLog(LOG_INFO, "Creating a collection scene"); Scene *outp = malloc(sizeof(Scene)); if (outp == NULL) return NULL; outp->Update = updateCollectionScene; outp->Draw = drawCollectionScene; outp->Deint = deinitCollectionScene; outp->IsTransparent = false; CollectionSceneData *data = malloc(sizeof(CollectionSceneData)); if (data == NULL) { free(outp); return NULL; } if (!el->IsInitialized) InitializeCollection(el, collectionElement_onSelect); data->collection = el; data->selected = NULL; data->state = smooothEntry? POPUP_REVEALING : POPUP_ACTIVE; data->blackout_state = 1.0f; data->scroll = 0.0f; Button *backButton = malloc(sizeof(Button)); if (backButton != NULL) { backButton->parent = outp; backButton->OnClick = backButton_onClick; backButton->atlas = GetButtonsAtlas(); backButton->textrueLocation = BACK_BUTTON_SMALL_LOCATION; } data->backButton = backButton; outp->data = data; return outp; }