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:
|
case CANNED_MESSAGE_RUN_STATE_ACTIVE:
|
||||||
if (event->inputEvent == INPUT_BROKER_LEFT || event->inputEvent == INPUT_BROKER_RIGHT) {
|
if (event->inputEvent == INPUT_BROKER_LEFT || event->inputEvent == INPUT_BROKER_RIGHT) {
|
||||||
runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||||
|
textScrollOffset = 0; // 重置滚动偏移
|
||||||
|
cursor = 0;
|
||||||
requestFocus();
|
requestFocus();
|
||||||
UIFrameEvent e;
|
UIFrameEvent e;
|
||||||
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
||||||
@@ -420,6 +422,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
|||||||
if (event->kbchar >= 32 && event->kbchar <= 126) {
|
if (event->kbchar >= 32 && event->kbchar <= 126) {
|
||||||
LOG_DEBUG("CannedMessage: Entering FREETEXT, kbchar=%d", event->kbchar);
|
LOG_DEBUG("CannedMessage: Entering FREETEXT, kbchar=%d", event->kbchar);
|
||||||
runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||||
|
textScrollOffset = 0; // 重置滚动偏移
|
||||||
|
cursor = 0;
|
||||||
requestFocus();
|
requestFocus();
|
||||||
UIFrameEvent e;
|
UIFrameEvent e;
|
||||||
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
||||||
@@ -935,6 +939,28 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
|
|||||||
return true;
|
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 ...
|
// '#' key: cycle input mode DIGIT -> LOWER -> UPPER -> DIGIT ...
|
||||||
if (event->kbchar == '#') {
|
if (event->kbchar == '#') {
|
||||||
// First, commit any pending multi-tap character
|
// First, commit any pending multi-tap character
|
||||||
@@ -1334,6 +1360,14 @@ int32_t CannedMessageModule::runOnce()
|
|||||||
this->freetext.substring(this->cursor);
|
this->freetext.substring(this->cursor);
|
||||||
}
|
}
|
||||||
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);
|
uint16_t maxChars = meshtastic_Constants_DATA_PAYLOAD_LEN - (moduleConfig.canned_message.send_bell ? 1 : 0);
|
||||||
if (this->freetext.length() > maxChars) {
|
if (this->freetext.length() > maxChars) {
|
||||||
this->cursor = maxChars;
|
this->cursor = maxChars;
|
||||||
@@ -1465,8 +1499,42 @@ void CannedMessageModule::drawKeyboard(OLEDDisplay *display, OLEDDisplayUiState
|
|||||||
|
|
||||||
display->setColor(OLEDDISPLAY_COLOR::WHITE);
|
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);
|
display->setFont(FONT_MEDIUM);
|
||||||
|
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
|||||||
char highlight = 0x00;
|
char highlight = 0x00;
|
||||||
char payload = 0x00;
|
char payload = 0x00;
|
||||||
unsigned int cursor = 0;
|
unsigned int cursor = 0;
|
||||||
|
unsigned int textScrollOffset = 0; // 文本滚动偏移(用于 FREETEXT 模式)
|
||||||
unsigned long lastTouchMillis = 0;
|
unsigned long lastTouchMillis = 0;
|
||||||
uint32_t lastFilterUpdate = 0;
|
uint32_t lastFilterUpdate = 0;
|
||||||
static constexpr uint32_t filterDebounceMs = 30;
|
static constexpr uint32_t filterDebounceMs = 30;
|
||||||
|
|||||||
Reference in New Issue
Block a user