From 9d7bc381a1922e3fcad2fbd68917372c99980a59 Mon Sep 17 00:00:00 2001 From: whywilson Date: Tue, 9 Dec 2025 11:01:16 +0800 Subject: [PATCH] Add nudge scroll on UpDownEncoder devices. --- src/graphics/Screen.cpp | 20 +++++++++++++ src/graphics/draw/MessageRenderer.cpp | 42 +++++++++++++++++++++++++++ src/graphics/draw/MessageRenderer.h | 4 +++ 3 files changed, 66 insertions(+) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 996d9b967..9a6b97c01 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1656,6 +1656,26 @@ int Screen::handleInputEvent(const InputEvent *event) // If no modules are using the input, move between frames if (!inputIntercepted) { +#if defined(INPUTDRIVER_ENCODER_TYPE) && INPUTDRIVER_ENCODER_TYPE == 2 + bool handledEncoderScroll = false; + const bool isTextMessageFrame = (framesetInfo.positions.textMessage != 255 && + this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage && + !messageStore.getMessages().empty()); + if (isTextMessageFrame) { + if (event->inputEvent == INPUT_BROKER_UP_LONG) { + graphics::MessageRenderer::nudgeScroll(-1); + handledEncoderScroll = true; + } else if (event->inputEvent == INPUT_BROKER_DOWN_LONG) { + graphics::MessageRenderer::nudgeScroll(1); + handledEncoderScroll = true; + } + } + + if (handledEncoderScroll) { + setFastFramerate(); + return 0; + } +#endif if (event->inputEvent == INPUT_BROKER_LEFT || event->inputEvent == INPUT_BROKER_ALT_PRESS) { showFrame(FrameDirection::PREVIOUS); } else if (event->inputEvent == INPUT_BROKER_RIGHT || event->inputEvent == INPUT_BROKER_USER_PRESS) { diff --git a/src/graphics/draw/MessageRenderer.cpp b/src/graphics/draw/MessageRenderer.cpp index 6046d42f3..ad0dfa144 100644 --- a/src/graphics/draw/MessageRenderer.cpp +++ b/src/graphics/draw/MessageRenderer.cpp @@ -238,6 +238,48 @@ void resetScrollState() didReset = false; } +void nudgeScroll(int8_t direction) +{ + if (direction == 0) + return; + + if (cachedHeights.empty()) { + scrollY = 0.0f; + return; + } + + OLEDDisplay *display = (screen != nullptr) ? screen->getDisplayDevice() : nullptr; + const int displayHeight = display ? display->getHeight() : 64; + const int navHeight = FONT_HEIGHT_SMALL; + const int usableHeight = std::max(0, displayHeight - navHeight); + + int totalHeight = 0; + for (int h : cachedHeights) + totalHeight += h; + + if (totalHeight <= usableHeight) { + scrollY = 0.0f; + return; + } + + const int scrollStop = std::max(0, totalHeight - usableHeight + cachedHeights.back()); + const int step = std::max(FONT_HEIGHT_SMALL, usableHeight / 3); + + float newScroll = scrollY + static_cast(direction) * static_cast(step); + if (newScroll < 0.0f) + newScroll = 0.0f; + if (newScroll > scrollStop) + newScroll = static_cast(scrollStop); + + if (newScroll != scrollY) { + scrollY = newScroll; + waitingToReset = false; + scrollStarted = false; + scrollStartDelay = millis(); + lastTime = millis(); + } +} + // Fully free cached message data from heap void clearMessageCache() { diff --git a/src/graphics/draw/MessageRenderer.h b/src/graphics/draw/MessageRenderer.h index 7f2e8b1e7..7dec6adec 100644 --- a/src/graphics/draw/MessageRenderer.h +++ b/src/graphics/draw/MessageRenderer.h @@ -5,6 +5,7 @@ #include "OLEDDisplayUi.h" #include "graphics/emotes.h" #include "mesh/generated/meshtastic/mesh.pb.h" // for meshtastic_MeshPacket +#include #include #include @@ -50,6 +51,9 @@ std::vector calculateLineHeights(const std::vector &lines, con // Reset scroll state when new messages arrive void resetScrollState(); +// Manual scroll control for encoder-style inputs +void nudgeScroll(int8_t direction); + // Helper to auto-select the correct thread mode from a message void setThreadFor(const StoredMessage &sm, const meshtastic_MeshPacket &packet);