#include "menu.h" #include "../utils/vector.h" #include "gfx.h" #include "gfxutils.h" #include "../hid/hid.h" #include #include const char *sizeDefs[] = { "B ", "KB", "MB", "GB" }; void _printEntry(MenuEntry_t entry, u32 maxLen, u8 highlighted){ if (entry.hide) return; (highlighted) ? SETCOLOR(COLOR_DEFAULT, FromRGBtoU32(entry.R, entry.G, entry.B)) : SETCOLOR(FromRGBtoU32(entry.R, entry.G, entry.B), COLOR_DEFAULT); if (entry.icon){ gfx_putc(entry.icon); gfx_putc(' '); maxLen -= 2; } u32 curX = 0, curY = 0; gfx_con_getpos(&curX, &curY); gfx_puts_limit(entry.name, maxLen - 8); if (entry.showSize){ SETCOLOR(COLOR_BLUE, COLOR_DEFAULT); gfx_con_setpos(curX + (maxLen - 6) * 16, curY); gfx_printf("%4d", entry.size); gfx_puts_small(sizeDefs[entry.sizeDef]); } gfx_putc('\n'); } void FunctionMenuHandler(MenuEntry_t *entries, int entryCount, menuPaths *paths, u8 options){ Vector_t ent = vecFromArray(entries, entryCount, sizeof(MenuEntry_t)); gfx_clearscreen(); gfx_putc('\n'); int res = newMenu(&ent, 0, 79, 30, options, entryCount); if (paths[res] != NULL) paths[res](); } int newMenu(Vector_t* vec, int startIndex, int screenLenX, int screenLenY, u8 options, int entryCount) { vecPDefArray(MenuEntry_t*, entries, vec); u32 selected = startIndex; while (entries[selected].skip || entries[selected].hide) selected++; u32 lastIndex = selected; u32 startX = 0, startY = 0; gfx_con_getpos(&startX, &startY); if (options & ENABLEPAGECOUNT){ screenLenY -= 2; startY += 32; } bool redrawScreen = true; Input_t *input = hidRead(); // Maybe add a check here so you don't read OOB by providing a too high startindex? u32 lastPress = 0x666 + get_tmr_ms(); u32 holdTimer = 300; while(1) { u32 lastDraw = get_tmr_ms(); if (redrawScreen || options & ALWAYSREDRAW){ if (options & ENABLEPAGECOUNT){ gfx_con_setpos(startX, startY - 32); RESETCOLOR; gfx_printf("Page %d / %d | Total %d entries\n", (selected / screenLenY) + 1, (vec->count / screenLenY) + 1, entryCount); } gfx_con_setpos(startX, startY); if (redrawScreen) gfx_boxGrey(startX, startY, startX + screenLenX * 16, startY + screenLenY * 16, 0x1B); int start = selected / screenLenY * screenLenY; for (int i = start; i < MIN(vec->count, start + screenLenY); i++) _printEntry(entries[i], screenLenX, (i == selected)); } else if (lastIndex != selected) { u32 minLastCur = MIN(lastIndex, selected); u32 maxLastCur = MAX(lastIndex, selected); gfx_con_setpos(startX, startY + ((minLastCur % screenLenY) * 16)); _printEntry(entries[minLastCur], screenLenX, (minLastCur == selected)); gfx_con_setpos(startX, startY + ((maxLastCur % screenLenY) * 16)); _printEntry(entries[maxLastCur], screenLenX, (minLastCur != selected)); } lastIndex = selected; SETCOLOR(COLOR_DEFAULT, COLOR_WHITE); gfx_con_setpos(0, 704); gfx_printf("Time taken for screen draw: %dms ", get_tmr_ms() - lastDraw); while(hidRead()){ if (!(input->buttons)){ holdTimer = 300; break; } if (input->buttons & (JoyRUp | JoyRDown)) holdTimer = 40; if ((lastPress + holdTimer) < get_tmr_ms()){ if (holdTimer > 50) holdTimer -= 50; break; } } while (1){ if (hidRead()->a) return selected; else if (input->b && options & ENABLEB) return 0; else if (input->down || input->rDown || input->right){ //Rdown should probs not trigger a page change. Same for RUp u32 temp = (input->right) ? screenLenY : 1; if (vec->count > selected + temp){ selected += temp; break; } else if (input->right && (selected / screenLenY != (vec->count - 1) / screenLenY)){ selected = vec->count - 1; break; } } else if (input->up || input->rUp || input->left){ u32 temp = (input->left) ? screenLenY : 1; if (selected >= temp){ selected -= temp; break; } } else holdTimer = 300; } lastPress = get_tmr_ms(); int m = (selected > lastIndex) ? 1 : -1; while (selected > 0 && selected < vec->count - 1 && entries[selected].optionUnion & SKIPHIDEBITS) selected += m; if (entries[selected].optionUnion & SKIPHIDEBITS) selected = lastIndex; redrawScreen = (selected / screenLenY != lastIndex / screenLenY); } }