feat: FREETEXT 模式添加滚动条和光标移动\n\n- 添加 textScrollOffset 变量跟踪滚动位置\n- UP/DOWN 按钮移动光标\n- 文本输入时自动滚动保持光标可见\n- 绘制滚动条显示当前位置\n- 进入 FREETEXT 时重置滚动偏移"
This commit is contained in:
@@ -394,6 +394,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
case CANNED_MESSAGE_RUN_STATE_ACTIVE:
|
||||
if (event->inputEvent == INPUT_BROKER_LEFT || event->inputEvent == INPUT_BROKER_RIGHT) {
|
||||
runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||
textScrollOffset = 0; // 重置滚动偏移
|
||||
cursor = 0;
|
||||
requestFocus();
|
||||
UIFrameEvent e;
|
||||
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
||||
@@ -420,6 +422,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
if (event->kbchar >= 32 && event->kbchar <= 126) {
|
||||
LOG_DEBUG("CannedMessage: Entering FREETEXT, kbchar=%d", event->kbchar);
|
||||
runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||
textScrollOffset = 0; // 重置滚动偏移
|
||||
cursor = 0;
|
||||
requestFocus();
|
||||
UIFrameEvent e;
|
||||
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
||||
@@ -935,6 +939,28 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
|
||||
return true;
|
||||
}
|
||||
|
||||
// UP/DOWN keys: move cursor in FREETEXT mode
|
||||
if (event->inputEvent == INPUT_BROKER_UP) {
|
||||
if (cursor > 0) {
|
||||
cursor--;
|
||||
// 确保光标在可见区域内,自动滚动
|
||||
if (cursor < textScrollOffset) {
|
||||
textScrollOffset = cursor;
|
||||
}
|
||||
}
|
||||
lastTouchMillis = millis();
|
||||
screen->forceDisplay();
|
||||
return true;
|
||||
}
|
||||
if (event->inputEvent == INPUT_BROKER_DOWN) {
|
||||
if (cursor < freetext.length()) {
|
||||
cursor++;
|
||||
}
|
||||
lastTouchMillis = millis();
|
||||
screen->forceDisplay();
|
||||
return true;
|
||||
}
|
||||
|
||||
// '#' key: cycle input mode DIGIT -> LOWER -> UPPER -> DIGIT ...
|
||||
if (event->kbchar == '#') {
|
||||
// First, commit any pending multi-tap character
|
||||
@@ -1334,6 +1360,14 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->freetext.substring(this->cursor);
|
||||
}
|
||||
this->cursor++;
|
||||
|
||||
// 自动滚动:确保光标在可见区域内
|
||||
// 假设屏幕宽度约 21 个字符 (128px / 6px)
|
||||
const int visibleChars = 20;
|
||||
if (this->cursor > this->textScrollOffset + visibleChars) {
|
||||
this->textScrollOffset = this->cursor - visibleChars;
|
||||
}
|
||||
|
||||
uint16_t maxChars = meshtastic_Constants_DATA_PAYLOAD_LEN - (moduleConfig.canned_message.send_bell ? 1 : 0);
|
||||
if (this->freetext.length() > maxChars) {
|
||||
this->cursor = maxChars;
|
||||
@@ -1465,8 +1499,42 @@ void CannedMessageModule::drawKeyboard(OLEDDisplay *display, OLEDDisplayUiState
|
||||
|
||||
display->setColor(OLEDDISPLAY_COLOR::WHITE);
|
||||
|
||||
display->drawStringMaxWidth(0, 0, display->getWidth(),
|
||||
cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor));
|
||||
// 绘制带滚动的文本输入区域
|
||||
{
|
||||
String text = cannedMessageModule->freetext;
|
||||
unsigned int cursorPos = cannedMessageModule->cursor;
|
||||
unsigned int scrollOffset = cannedMessageModule->textScrollOffset;
|
||||
|
||||
// 计算可见区域宽度(减去滚动条宽度)
|
||||
int maxWidth = display->getWidth() - 4; // 留出滚动条空间
|
||||
|
||||
// 获取显示文本(从 scrollOffset 开始)
|
||||
String displayText = text.substring(scrollOffset);
|
||||
|
||||
// 添加光标
|
||||
String textWithCursor = displayText.substring(0, cursorPos - scrollOffset) + "_" + displayText.substring(cursorPos - scrollOffset);
|
||||
|
||||
// 绘制文本
|
||||
display->drawStringMaxWidth(0, 0, maxWidth, textWithCursor);
|
||||
|
||||
// 如果文本超出可见区域,绘制滚动条
|
||||
int totalWidth = display->getStringWidth(text);
|
||||
if (totalWidth > maxWidth) {
|
||||
// 计算滚动条位置
|
||||
int scrollbarHeight = 8;
|
||||
int scrollbarWidth = 3;
|
||||
int scrollbarX = display->getWidth() - scrollbarWidth - 1;
|
||||
|
||||
// 滚动条位置与光标位置关联
|
||||
float scrollRatio = (float)cursorPos / std::max(1u, (unsigned int)text.length());
|
||||
int scrollbarY = (display->getHeight() - 20) * scrollRatio;
|
||||
scrollbarY = std::max(0, std::min(scrollbarY, display->getHeight() - 20 - scrollbarHeight));
|
||||
|
||||
// 绘制滚动条
|
||||
display->setColor(OLEDDISPLAY_COLOR::WHITE);
|
||||
display->fillRect(scrollbarX, 10, scrollbarWidth, scrollbarHeight);
|
||||
}
|
||||
}
|
||||
|
||||
display->setFont(FONT_MEDIUM);
|
||||
|
||||
|
||||
@@ -181,6 +181,7 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
char highlight = 0x00;
|
||||
char payload = 0x00;
|
||||
unsigned int cursor = 0;
|
||||
unsigned int textScrollOffset = 0; // 文本滚动偏移(用于 FREETEXT 模式)
|
||||
unsigned long lastTouchMillis = 0;
|
||||
uint32_t lastFilterUpdate = 0;
|
||||
static constexpr uint32_t filterDebounceMs = 30;
|
||||
|
||||
Reference in New Issue
Block a user