| 95 | } |
| 96 | |
| 97 | void ButtonRemapActivity::render(RenderLock&&) { |
| 98 | const auto labelForHardware = [&](uint8_t hardwareIndex) -> const char* { |
| 99 | for (uint8_t i = 0; i < kRoleCount; i++) { |
| 100 | if (tempMapping[i] == hardwareIndex) { |
| 101 | return getRoleName(i); |
| 102 | } |
| 103 | } |
| 104 | return "-"; |
| 105 | }; |
| 106 | |
| 107 | const auto& metrics = UITheme::getInstance().getMetrics(); |
| 108 | const auto pageWidth = renderer.getScreenWidth(); |
| 109 | const auto pageHeight = renderer.getScreenHeight(); |
| 110 | |
| 111 | renderer.clearScreen(); |
| 112 | |
| 113 | GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_REMAP_FRONT_BUTTONS)); |
| 114 | GUI.drawSubHeader(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight}, |
| 115 | tr(STR_REMAP_PROMPT)); |
| 116 | |
| 117 | int topOffset = metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing; |
| 118 | int contentHeight = pageHeight - topOffset - metrics.buttonHintsHeight - metrics.verticalSpacing; |
| 119 | GUI.drawList( |
| 120 | renderer, Rect{0, topOffset, pageWidth, contentHeight}, kRoleCount, currentStep, |
| 121 | [&](int index) { return getRoleName(static_cast<uint8_t>(index)); }, nullptr, nullptr, |
| 122 | [&](int index) { |
| 123 | uint8_t assignedButton = tempMapping[static_cast<uint8_t>(index)]; |
| 124 | return (assignedButton == kUnassigned) ? tr(STR_UNASSIGNED) : getHardwareName(assignedButton); |
| 125 | }, |
| 126 | true); |
| 127 | |
| 128 | // Temporary warning banner for duplicates. |
| 129 | if (!errorMessage.empty()) { |
| 130 | GUI.drawHelpText(renderer, |
| 131 | Rect{0, pageHeight - metrics.buttonHintsHeight - metrics.contentSidePadding - 15, pageWidth, 20}, |
| 132 | errorMessage.c_str()); |
| 133 | } |
| 134 | |
| 135 | // Provide side button actions at the bottom of the screen (split across two lines). |
| 136 | GUI.drawHelpText(renderer, |
| 137 | Rect{0, topOffset + 4 * metrics.listRowHeight + 4 * metrics.verticalSpacing, pageWidth, 20}, |
| 138 | tr(STR_REMAP_RESET_HINT)); |
| 139 | GUI.drawHelpText(renderer, |
| 140 | Rect{0, topOffset + 4 * metrics.listRowHeight + 5 * metrics.verticalSpacing + 20, pageWidth, 20}, |
| 141 | tr(STR_REMAP_CANCEL_HINT)); |
| 142 | |
| 143 | // Live preview of logical labels under front buttons. |
| 144 | // This mirrors the on-device front button order: Back, Confirm, Left, Right. |
| 145 | GUI.drawButtonHints(renderer, labelForHardware(CrossPointSettings::FRONT_HW_BACK), |
| 146 | labelForHardware(CrossPointSettings::FRONT_HW_CONFIRM), |
| 147 | labelForHardware(CrossPointSettings::FRONT_HW_LEFT), |
| 148 | labelForHardware(CrossPointSettings::FRONT_HW_RIGHT)); |
| 149 | renderer.displayBuffer(); |
| 150 | } |
| 151 | |
| 152 | void ButtonRemapActivity::applyTempMapping() { |
| 153 | // Commit temporary mapping into settings (logical role -> hardware). |
nothing calls this directly
no test coverage detected