| 141 | // ── Public API ─────────────────────────────────────────────────────────────── |
| 142 | |
| 143 | void QVButtonPanel::refreshPanel(const QList<MAP_KEYDATA> &dataList) |
| 144 | { |
| 145 | // Clear existing buttons |
| 146 | for (QToolButton *btn : std::as_const(m_buttons)) { |
| 147 | m_gridLayout->removeWidget(btn); |
| 148 | btn->deleteLater(); |
| 149 | } |
| 150 | m_buttons.clear(); |
| 151 | m_keyNames.clear(); |
| 152 | // Note: m_lockedKeyNames is intentionally NOT cleared here. |
| 153 | // Lock state persists across panel rebuilds and highlights are reapplied below. |
| 154 | |
| 155 | static QRegularExpression vbutton_regex(VBUTTON_REGEX_PATTERN); |
| 156 | |
| 157 | // Collect unique enabled VButton entries in order |
| 158 | QStringList seen; |
| 159 | for (const MAP_KEYDATA &entry : dataList) { |
| 160 | if (!entry.Disabled && vbutton_regex.match(entry.Original_Key).hasMatch()) { |
| 161 | if (entry.FloatingButton_Enable) { |
| 162 | continue; |
| 163 | } |
| 164 | if (!seen.contains(entry.Original_Key)) { |
| 165 | seen.append(entry.Original_Key); |
| 166 | } |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | // Build buttons |
| 171 | int row = 0, col = 0; |
| 172 | for (int i = 0; i < seen.size(); ++i) { |
| 173 | const QString &keyName = seen.at(i); |
| 174 | m_keyNames.append(keyName); |
| 175 | |
| 176 | QToolButton *btn = new QToolButton(m_gridContainer); |
| 177 | btn->setToolButtonStyle(Qt::ToolButtonTextOnly); |
| 178 | btn->setAutoRaise(false); |
| 179 | btn->setText(extractButtonLabel(keyName)); |
| 180 | btn->setFixedSize(m_btnWidth, m_btnHeight); |
| 181 | btn->installEventFilter(this); |
| 182 | applyButtonFont(btn); |
| 183 | |
| 184 | // Tooltip: No. + SendTiming + MappingKey + KeyUpMapping |
| 185 | int findindex = QKeyMapper::findOriKeyInKeyMappingDataList(keyName); |
| 186 | if (findindex >= 0 && QKeyMapper::KeyMappingDataList && QKeyMapper::getInstance()) { |
| 187 | const MAP_KEYDATA &entry = QKeyMapper::KeyMappingDataList->at(findindex); |
| 188 | QString tip = QString("%1 : %2\n").arg(QObject::tr("No."), QString::number(findindex + 1)); |
| 189 | tip += QKeyMapper::getInstance()->makeMappingKeyToolTip(entry); |
| 190 | if (!entry.Note.isEmpty()) { |
| 191 | tip += QString("\n%1 : %2").arg(tr("Note"), entry.Note); |
| 192 | } |
| 193 | btn->setToolTip(tip); |
| 194 | } |
| 195 | |
| 196 | // Use pressed/released instead of clicked to separate KEY_DOWN from KEY_UP timing |
| 197 | int capturedIndex = i; |
| 198 | connect(btn, &QToolButton::pressed, this, [this, capturedIndex]() { onVButtonPressed(capturedIndex); }); |
| 199 | connect(btn, &QToolButton::released, this, [this, capturedIndex]() { onVButtonReleased(capturedIndex); }); |
| 200 | |