diff options
author | Alvin Wong <[email protected]> | 2021-05-02 21:36:06 +0800 |
---|---|---|
committer | Alvin Wong <[email protected]> | 2021-05-02 21:57:45 +0800 |
commit | 82c985d78502cb78766eb941ddf6674d5bd167c0 (patch) | |
tree | 75b52eef82b87f9df7ad0b8c50f76a24d22002c2 | |
parent | 969cadc3eb483e28cd3bd41ee5e53b0f4fcf0b13 (diff) | |
download | IronOS-82c985d78502cb78766eb941ddf6674d5bd167c0.tar.gz IronOS-82c985d78502cb78766eb941ddf6674d5bd167c0.zip |
Impl. menu item scroll down animation
-rw-r--r-- | source/Core/Drivers/OLED.cpp | 72 | ||||
-rw-r--r-- | source/Core/Drivers/OLED.hpp | 1 | ||||
-rw-r--r-- | source/Core/Src/gui.cpp | 28 |
3 files changed, 94 insertions, 7 deletions
diff --git a/source/Core/Drivers/OLED.cpp b/source/Core/Drivers/OLED.cpp index 0555f838..65dce02b 100644 --- a/source/Core/Drivers/OLED.cpp +++ b/source/Core/Drivers/OLED.cpp @@ -59,7 +59,38 @@ FRToSI2C::I2C_REG OLED_Setup_Array[] = { }; // Setup based on the SSD1307 and modified for the SSD1306 -const uint8_t REFRESH_COMMANDS[17] = {0x80, 0xAF, 0x80, 0x21, 0x80, 0x20, 0x80, 0x7F, 0x80, 0xC0, 0x80, 0x22, 0x80, 0x00, 0x80, 0x01, 0x40}; +const uint8_t REFRESH_COMMANDS[17] = { + // Set display ON: + 0x80, + 0xAF, // cmd + + // Set column address: + // A[6:0] - Column start address = 0x20 + // B[6:0] - Column end address = 0x7F + 0x80, + 0x21, // cmd + 0x80, + 0x20, // A + 0x80, + 0x7F, // B + + // Set COM output scan direction (normal mode, COM0 to COM[N-1]) + 0x80, + 0xC0, + + // Set page address: + // A[2:0] - Page start address = 0 + // B[2:0] - Page end address = 1 + 0x80, + 0x22, // cmd + 0x80, + 0x00, // A + 0x80, + 0x01, // B + + // Start of data + 0x40, +}; /* * Animation timing function that follows a bezier curve. @@ -235,6 +266,45 @@ void OLED::useSecondaryFramebuffer(bool useSecondary) { setFramebuffer(NULL); } } +/** + * Plays a transition animation of scrolling downward. Note this does *not* + * use the secondary framebuffer. + * + * This transition relies on the previous screen data already in the OLED + * RAM. The caller shall not call `OLED::refresh()` before calling this + * method, as doing so will overwrite the previous screen data. The caller + * does not need to call `OLED::refresh()` after this function returns. + * + * **This function blocks until the transition has completed.** + */ +void OLED::transitionScrollDown() { + // We want to draw the updated framebuffer to the next page downward. + uint8_t const pageStart = screenBuffer[13]; + uint8_t const nextPage = (pageStart + 2) % 8; + // Change page start address: + screenBuffer[13] = nextPage; + // Change page end address: + screenBuffer[15] = nextPage + 1; + + refresh(); + osDelay(TICKS_100MS / 5); + + uint8_t const startLine = pageStart * 8 + 1; + uint8_t const scrollTo = (pageStart + 2) * 8; + + // Scroll the screen by changing display start line. + for (uint8_t current = startLine; current <= scrollTo; current++) { + // Set display start line (0x40~0x7F): + // X[5:0] - display start line value + uint8_t scrollCommandByte = 0b01000000 | (current & 0b00111111); + + // Also update setup command for "set display start line": + OLED_Setup_Array[8].val = scrollCommandByte; + + FRToSI2C::I2C_RegisterWrite(DEVICEADDR_OLED, 0x80, scrollCommandByte); + osDelay(TICKS_100MS / 5); + } +} void OLED::setRotation(bool leftHanded) { #ifdef OLED_FLIP diff --git a/source/Core/Drivers/OLED.hpp b/source/Core/Drivers/OLED.hpp index 9332c4ee..7d88ac96 100644 --- a/source/Core/Drivers/OLED.hpp +++ b/source/Core/Drivers/OLED.hpp @@ -81,6 +81,7 @@ public: static void drawScrollIndicator(uint8_t p, uint8_t h); // Draws a scrolling position indicator
static void transitionSecondaryFramebuffer(bool forwardNavigation);
static void useSecondaryFramebuffer(bool useSecondary);
+ static void transitionScrollDown();
private:
static void drawChar(uint16_t charCode, FontStyle fontStyle); // Draw a character to the current cursor location
diff --git a/source/Core/Src/gui.cpp b/source/Core/Src/gui.cpp index 2ee0bc8b..15a6a82e 100644 --- a/source/Core/Src/gui.cpp +++ b/source/Core/Src/gui.cpp @@ -1043,6 +1043,7 @@ void gui_Menu(const menuitem *menu) { uint8_t scrollContentSize = 0; bool scrollBlink = false; bool lastValue = false; + bool scrollingDown = false; ScrollMessage scrollMessage; @@ -1068,6 +1069,10 @@ void gui_Menu(const menuitem *menu) { while ((menu[currentScreen].draw != nullptr) && earlyExit == false) { OLED::setCursor(0, 0); + if (scrollingDown) { + animOpenState = true; + } + // If the user has hesitated for >=3 seconds, show the long text // Otherwise "draw" the option if ((xTaskGetTickCount() - lastButtonTime < (TICKS_SECOND * 3)) || menu[currentScreen].description == 0) { @@ -1089,6 +1094,18 @@ void gui_Menu(const menuitem *menu) { lcdRefresh |= scrollMessage.drawUpdate(description, xTaskGetTickCount()); } + if (lcdRefresh) { + if (scrollingDown) { + OLED::transitionScrollDown(); + scrollingDown = false; + animOpenState = false; + } else { + OLED::refresh(); // update the LCD + osDelay(40); + } + lcdRefresh = false; + } + ButtonState buttons = getButtonState(); if (buttons != lastButtonState) { @@ -1115,7 +1132,8 @@ void gui_Menu(const menuitem *menu) { case BUTTON_B_SHORT: if (scrollMessage.isReset()) { currentScreen++; - lastValue = false; + scrollingDown = true; + lastValue = false; } else scrollMessage.reset(); break; @@ -1136,6 +1154,7 @@ void gui_Menu(const menuitem *menu) { case BUTTON_B_LONG: if (xTaskGetTickCount() - autoRepeatTimer + autoRepeatAcceleration > PRESS_ACCEL_INTERVAL_MAX) { currentScreen++; + scrollingDown = true; autoRepeatTimer = xTaskGetTickCount(); scrollMessage.reset(); @@ -1151,11 +1170,6 @@ void gui_Menu(const menuitem *menu) { autoRepeatAcceleration = PRESS_ACCEL_INTERVAL_MAX - PRESS_ACCEL_INTERVAL_MIN; } - if (lcdRefresh) { - OLED::refresh(); // update the LCD - osDelay(40); - lcdRefresh = false; - } if ((xTaskGetTickCount() - lastButtonTime) > (TICKS_SECOND * 30)) { // If user has not pressed any buttons in 30 seconds, exit back a menu layer // This will trickle the user back to the main screen eventually @@ -1163,6 +1177,8 @@ void gui_Menu(const menuitem *menu) { scrollMessage.reset(); } } + + animOpenState = false; } void enterSettingsMenu() { |