| 756 | } |
| 757 | |
| 758 | void SettingsScreen::draw(void) const |
| 759 | { |
| 760 | Gfx::ClearScreen(COLOR_BG); |
| 761 | |
| 762 | // ---- Top bar ---- |
| 763 | UiKit::drawHintCircle(24, (TOPBAR_H - 20) / 2, "-"); |
| 764 | { |
| 765 | const std::string title = i18n::t("settings.title"); |
| 766 | u32 tw, th; |
| 767 | Gfx::GetTextDimensions(20, title.c_str(), &tw, &th); |
| 768 | Gfx::DrawText(20, 24 + 20 + 14, (TOPBAR_H - (int)th) / 2, COLOR_TEXT, title.c_str()); |
| 769 | } |
| 770 | { |
| 771 | // Live config-path label, flashing to `success` briefly on a write. |
| 772 | std::string path = i18n::t("settings.saved_to") + " sdmc:" + Configuration::getInstance().BASEPATH; |
| 773 | Color c = mFlashTimer > 0 ? COLOR_SUCCESS : COLOR_TEXT3; |
| 774 | u32 tw, th; |
| 775 | Gfx::GetTextDimensions(12, path.c_str(), &tw, &th); |
| 776 | Gfx::DrawText(12, 1256 - (int)tw, (TOPBAR_H - (int)th) / 2, c, path.c_str()); |
| 777 | } |
| 778 | |
| 779 | // ---- Frame hairlines ---- |
| 780 | Gfx::DrawRect(0, TOPBAR_H, 1280, 1, COLOR_STROKE1); |
| 781 | Gfx::DrawRect(RAIL_W, TOPBAR_H + 1, 1, 720 - TOPBAR_H - 1 - UiKit::HINTBAR_H, COLOR_STROKE1); |
| 782 | |
| 783 | // ---- Category rail ---- |
| 784 | for (int i = 0; i < (int)Category::COUNT; i++) { |
| 785 | const int y = CAT_Y0 + CAT_PITCH * i; |
| 786 | const bool active = i == (int)mCategory; |
| 787 | if (active) { |
| 788 | Shapes::fillRound(CAT_X, y, CAT_W, CAT_ITEM_H, 0, COLOR_ACCENT); |
| 789 | } |
| 790 | Color fg = active ? COLOR_WHITE : COLOR_TEXT2; |
| 791 | const std::string label = i18n::t(kCategoryKeys[i]); |
| 792 | u32 lw, lh; |
| 793 | Gfx::GetTextDimensions(15, label.c_str(), &lw, &lh); |
| 794 | Gfx::DrawText(15, CAT_X + 16, y + (CAT_ITEM_H - (int)lh) / 2, fg, label.c_str()); |
| 795 | } |
| 796 | // Breathing selector on the rail while it owns the cursor. |
| 797 | if (mCatFocused) { |
| 798 | Shapes::focusRing(CAT_X, CAT_Y0 + CAT_PITCH * (int)mCategory, CAT_W, CAT_ITEM_H, 0, COLOR_ACCENT); |
| 799 | } |
| 800 | |
| 801 | // ---- Rows pane ---- |
| 802 | // Long lists (Library / Save folders) are paged: draw from mScroll and stop |
| 803 | // before a row would spill past the hint bar, so every row stays reachable. |
| 804 | const int viewBottom = UiKit::HINTBAR_Y; |
| 805 | int y = ROWS_Y0; |
| 806 | for (int i = mScroll; i < (int)mRows.size(); i++) { |
| 807 | const Row& row = mRows[i]; |
| 808 | // The first drawn row always reserves a sticky header slot, showing the |
| 809 | // section it belongs to (inherited when the group's header row itself has |
| 810 | // scrolled above the fold). Later rows only reserve when they start a new |
| 811 | // group. The row rect starts below whatever slot was reserved; bail before |
| 812 | // drawing it (or its label) if it no longer fits the viewport. |
| 813 | const bool atTop = (i == mScroll); |
| 814 | const int extra = atTop ? labelSlotH() : inlineSectionExtra(row.section, mRows[i - 1].section); |
| 815 | const int rectTop = y + extra; |
nothing calls this directly
no test coverage detected