| 719 | } |
| 720 | |
| 721 | void MainScreen::updateSelector(const InputState& input) |
| 722 | { |
| 723 | // Hiding/showing titles from Settings bumps the catalog generation and can |
| 724 | // shrink the filtered list under the cursor. Clamp the index and drop the |
| 725 | // selection before anything reads them, so backup/restore can't fall back to |
| 726 | // targeting the first (wrong) title. |
| 727 | const u32 gen = TitleCatalog::get().generation(); |
| 728 | if (gen != mLastGeneration) { |
| 729 | mLastGeneration = gen; |
| 730 | const size_t count = TitleCatalog::get().getFilteredTitleCount(g_currentUId, mSaveTypeFilter); |
| 731 | if (mCursor >= count) { |
| 732 | mCursor = count > 0 ? count - 1 : 0; |
| 733 | } |
| 734 | scrollToCursor(count); // fewer rows may remain than the window showed |
| 735 | MS::clearSelectedEntries(); |
| 736 | } |
| 737 | |
| 738 | if (!backupScrollEnabled) { |
| 739 | size_t count = TitleCatalog::get().getFilteredTitleCount(g_currentUId, mSaveTypeFilter); |
| 740 | if (sidebarFocused && (input.kDown & (HidNpadButton_Right | HidNpadButton_B))) { |
| 741 | sidebarFocused = false; |
| 742 | sidebarExitFrame = true; |
| 743 | } |
| 744 | else if (sidebarFocused) { |
| 745 | // don't update title grid while sidebar is focused |
| 746 | } |
| 747 | else if (sidebarExitFrame) { |
| 748 | // skip grid-cursor updates until Right/B is released so the held key doesn't move the title cursor |
| 749 | if (!(input.kHeld & (HidNpadButton_AnyRight | HidNpadButton_B))) { |
| 750 | sidebarExitFrame = false; |
| 751 | } |
| 752 | } |
| 753 | else if ((input.kDown & HidNpadButton_Left) && mCursor % GRID_COLS == 0) { |
| 754 | sidebarFocused = true; |
| 755 | sidebarCursor = static_cast<int>(mSaveTypeFilter); |
| 756 | } |
| 757 | else { |
| 758 | updateGridCursor(input, count); |
| 759 | } |
| 760 | |
| 761 | // Touch selection over the visible tiles (including the faded partial |
| 762 | // row — tapping it selects the tile and scrolls it into full view). |
| 763 | if (input.touch.count > 0) { |
| 764 | const size_t visBegin = (size_t)mScrollRow * GRID_COLS; |
| 765 | const size_t visEnd = std::min(count, visBegin + (size_t)(GRID_COLS * GRID_DRAW_ROWS)); |
| 766 | for (size_t k = visBegin; k < visEnd; k++) { |
| 767 | const int x = selectorX(k); |
| 768 | const int y = selectorY(k); |
| 769 | if (input.touch.touches[0].x >= x && input.touch.touches[0].x <= x + TILE && input.touch.touches[0].y >= y && |
| 770 | input.touch.touches[0].y <= y + TILE && input.touch.touches[0].y < GRID_BOTTOM) { |
| 771 | mCursor = k; |
| 772 | scrollToCursor(count); |
| 773 | break; |
| 774 | } |
| 775 | } |
| 776 | } |
| 777 | |
| 778 | backupList->resetIndex(); |
nothing calls this directly
no test coverage detected