diff --git a/docs/api.md b/docs/api.md index ca12a8ec..90ac5a99 100644 --- a/docs/api.md +++ b/docs/api.md @@ -76,6 +76,7 @@ All keys are optional, so you can send just the properties you want to use. | `progressC` | string or array of integers | The color of the progressbar | -1 | | `progressBC` | string or array of integers | The color of the progressbar background | -1 | | `pos` | number | defines the position of your custompage in the loop, starting at 0 for the first position. This will only apply with your first push. This function is experimental | N/A | +| `draw` | array of objects | Array of drawing instructions. Each object represents a drawing command. | See the drawing instructions below | Color values can have a hex string or an array of R,G,B values: `"#FFFFFF" or [255,255,0]` @@ -91,6 +92,57 @@ Here's an example JSON object to display the text "Hello, AWTRIX Light!" with th "duration": 10 } ``` + +### Drawing Instructions +?> Pease note: Depending on the amount of objects, the RAM usage can be very high. This could cause freezes or reboots. + It's important to be mindful of the number of objects and the complexity of the drawing instructions to avoid performance issues. + +Each drawing instruction is an object with a required command key `c` and additional keys depending on the command: + +| Command | Additional Keys | Description | +| ------- | --------------- | ----------- | +| `dp` | `x`, `y`, `cl` | Draw a pixel at position (`x`, `y`) with color `cl` | +| `dl` | `x0`, `y0`, `x1`, `y1`, `cl` | Draw a line from (`x0`, `y0`) to (`x1`, `y1`) with color `cl` | +| `dr` | `x`, `y`, `w`, `h`, `cl` | Draw a rectangle with top-left corner at (`x`, `y`), width `w`, height `h`, and color `cl` | +| `df` | `x`, `y`, `w`, `h`, `cl` | Draw a filled rectangle with top-left corner at (`x`, `y`), width `w`, height `h`, and color `cl` | +| `dc` | `x`, `y`, `r`, `cl` | Draw a circle with center at (`x`, `y`), radius `r`, and color `cl` | +| `dfc` | `x`, `y`, `r`, `cl` | Draw a filled circle with center at (`x`, `y`), radius `r`, and color `cl` | +| `dt` | `x`, `y`, `t`, `cl` | Draw text `t` with top-left corner at (`x`, `y`) and color `cl` | + +Color values can be a hex string or an array of R, G, B values: +`"#FFFFFF" or [255, 255, 0]` + +### Example + +Here's an example JSON object to draw a red circle, a blue rectangle, and the text "Hello" in green: + +```json +{ "draw": [ + { + "c": "dc", + "x": 28, + "y": 4, + "r": 3, + "cl": "#FF0000" + }, + { + "c": "dr", + "x": 20, + "y": 4, + "w": 4, + "h": 4, + "cl": "#0000FF" + }, + { + "c": "dt", + "x": 0, + "y": 0, + "t": "Hello", + "cl": "#00FF00" + } + ] +} +``` ### Display a text in colored fragments You can display a text where you allowed to colorize fragments of the text. diff --git a/src/Apps.h b/src/Apps.h index 455633ae..addadaa8 100644 --- a/src/Apps.h +++ b/src/Apps.h @@ -15,6 +15,7 @@ #include #include #include +#include Ticker downloader; @@ -27,6 +28,7 @@ String WEATHER_HUM; struct CustomApp { + std::vector drawInstructions; int16_t scrollposition = 0; int16_t scrollDelay = 0; String text; @@ -64,6 +66,7 @@ std::map customApps; struct Notification { + std::vector drawInstructions; int16_t scrollposition = 34; int16_t scrollDelay = 0; String text; @@ -266,7 +269,7 @@ void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i } matrix->drawRGBBitmap(x, y + 1, icon_2075, 8, 8); matrix->setCursor(14 + x, 6 + y); - int humidity = CURRENT_HUM; + int humidity = CURRENT_HUM; matrix->print(humidity); matrix->print("%"); } @@ -368,8 +371,9 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState return; } + // reset custom App properties if last frame - if (lastFrame) + if (firstFrame) { ca->iconWasPushed = false; ca->scrollposition = 9 + ca->textOffset; @@ -390,6 +394,7 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState bool hasIcon = ca->icon; matrix->fillRect(x, y, 32, 8, ca->background); + // Calculate text and available width uint16_t textWidth = 0; if (!ca->fragments.empty()) @@ -495,7 +500,6 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState } else { - if (ca->rainbow) { DisplayManager.HSVtext(x + textX, 6 + y, ca->text.c_str(), false, ca->textCase); @@ -545,9 +549,9 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState ++ca->iconPosition; } - if (ca->scrollposition < 8 && !ca->iconWasPushed) + if (ca->scrollposition < 9 && !ca->iconWasPushed) { - ca->iconPosition = ca->scrollposition - 8; + ca->iconPosition = ca->scrollposition - 9; if (ca->iconPosition <= -9) { @@ -559,7 +563,6 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState // Display animated GIF if enabled and App is fixed, since we have only one gifplayer instance, it looks weird when 2 apps want to draw a different gif if (ca->isGif) { - gifPlayer->playGif(x + ca->iconPosition, y, &ca->icon); } else @@ -571,10 +574,15 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState // Draw vertical line if text is scrolling if (!noScrolling) { - // matrix->drawLine(8 + x + ca->iconPosition, 0 + y, 8 + x + ca->iconPosition, 7 + y, 0); + matrix->drawLine(8 + x + ca->iconPosition, 0 + y, 8 + x + ca->iconPosition, 7 + y, 0); } } + if (ca->drawInstructions.size() > 0) + { + DisplayManager.processDrawInstructions(x, y, ca->drawInstructions); + } + if (ca->progress > -1) { DisplayManager.drawProgressBar((hasIcon ? 9 : 0), 7 + y, ca->progress, ca->pColor, ca->pbColor); @@ -617,6 +625,7 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer notify.lineSize = 0; notify.textOffset = 0; notify.progress = -1; + notify.drawInstructions.clear(); return; } @@ -773,7 +782,7 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer ++notify.iconPosition; } - if (notify.scrollposition < 8 && !notify.iconWasPushed) + if (notify.scrollposition < 9 && !notify.iconWasPushed) { notify.iconPosition = notify.scrollposition - 9; @@ -800,7 +809,7 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer // Display icon divider line if text is scrolling if (!noScrolling) { - // matrix->drawLine(8 + notify.iconPosition, 0, 8 + notify.iconPosition, 7, 0); + matrix->drawLine(8 + notify.iconPosition, 0, 8 + notify.iconPosition, 7, 0); } } @@ -809,6 +818,11 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer DisplayManager.drawProgressBar((hasIcon ? 9 : 0), 7, notify.progress, notify.pColor, notify.pbColor); } + if (notify.drawInstructions.size() > 0) + { + DisplayManager.processDrawInstructions(0, 0, notify.drawInstructions); + } + // Reset text color after displaying notification DisplayManager.getInstance().resetTextColor(); } diff --git a/src/DisplayManager.cpp b/src/DisplayManager.cpp index a2a51997..39770f33 100644 --- a/src/DisplayManager.cpp +++ b/src/DisplayManager.cpp @@ -1,10 +1,10 @@ #include #include + #include "MatrixDisplayUi.h" #include #include "icons.h" #include "Globals.h" -#include #include "PeripheryManager.h" #include "MQTTManager.h" #include "GifPlayer.h" @@ -301,7 +301,6 @@ void DisplayManager_::generateCustomPage(const String &name, const char *json) if (strcmp(json, "") == 0 && customApps.count(name)) { removeCustomAppFromApps(name, true); - showGif = false; return; } @@ -309,7 +308,6 @@ void DisplayManager_::generateCustomPage(const String &name, const char *json) DeserializationError error = deserializeJson(doc, json); if (error) { - showGif = false; doc.clear(); return; } @@ -437,6 +435,18 @@ void DisplayManager_::generateCustomPage(const String &name, const char *json) customApp.lineSize = 0; } + customApp.drawInstructions.clear(); + if (doc.containsKey("draw")) + { + JsonArray instructions = doc["draw"]; + for (JsonObject instruction : instructions) + { + String instructionStr; + serializeJson(instruction, instructionStr); + customApp.drawInstructions.push_back(instructionStr); + } + } + customApp.duration = doc.containsKey("duration") ? doc["duration"].as() * 1000 : 0; int pos = doc.containsKey("pos") ? doc["pos"].as() : -1; customApp.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false; @@ -548,6 +558,18 @@ void DisplayManager_::generateNotification(const char *json) auto background = doc["background"]; notify.background = getColorFromJsonVariant(background, 0); } + notify.flag = true; + notify.drawInstructions.clear(); + if (doc.containsKey("draw")) + { + JsonArray instructions = doc["draw"]; + for (JsonObject instruction : instructions) + { + String instructionStr; + serializeJson(instruction, instructionStr); + notify.drawInstructions.push_back(instructionStr); + } + } notify.duration = doc.containsKey("duration") ? doc["duration"].as() * 1000 : TIME_PER_APP; notify.repeat = doc.containsKey("repeat") ? doc["repeat"].as() : -1; @@ -666,8 +688,6 @@ void DisplayManager_::generateNotification(const char *json) notify.text = ""; } - notify.flag = true; - if (doc.containsKey("icon")) { String iconFileName = doc["icon"].as(); @@ -929,6 +949,7 @@ void DisplayManager_::gererateTimer(String Payload) time_t futureTime = mktime(&futureTimeinfo); int interval = difftime(futureTime, now) * 1000; TimerTicker.once_ms(interval, timerCallback); + } void DisplayManager_::switchToApp(const char *json) @@ -1557,4 +1578,72 @@ void DisplayManager_::reorderApps(const String &jsonString) Apps = reorderedApps; ui->setApps(Apps); ui->forceResetState(); -} \ No newline at end of file +} + +void DisplayManager_::processDrawInstructions(int16_t xOffset, int16_t yOffset, const std::vector &drawInstructions) +{ + for (const String &instructionStr : drawInstructions) + { + StaticJsonDocument<128> instructionDoc; + deserializeJson(instructionDoc, instructionStr); + JsonObject instruction = instructionDoc.as(); + + String command = instruction["c"].as(); + Serial.println(command); + auto cl = instruction["cl"]; + uint16_t color = getColorFromJsonVariant(cl, TEXTCOLOR_565); + if (command == "dp") + { + int x = instruction["x"].as(); + int y = instruction["y"].as(); + matrix->drawPixel(x + xOffset, y + yOffset, color); + } + else if (command == "dl") + { + int x0 = instruction["x0"].as(); + int y0 = instruction["y0"].as(); + int x1 = instruction["x1"].as(); + int y1 = instruction["y1"].as(); + matrix->drawLine(x0 + xOffset, y0 + yOffset, x1 + xOffset, y1 + yOffset, color); + } + else if (command == "dr") + { + int x = instruction["x"].as(); + int y = instruction["y"].as(); + int w = instruction["w"].as(); + int h = instruction["h"].as(); + matrix->drawRect(x + xOffset, y + yOffset, w, h, color); + } + else if (command == "df") + { + int x = instruction["x"].as(); + int y = instruction["y"].as(); + int w = instruction["w"].as(); + int h = instruction["h"].as(); + matrix->fillRect(x + xOffset, y + yOffset, w, h, color); + } + else if (command == "dc") + { + int x = instruction["x"].as(); + int y = instruction["y"].as(); + int r = instruction["r"].as(); + matrix->drawCircle(x + xOffset, y + yOffset, r, color); + } + else if (command == "dfc") + { + int x = instruction["x"].as(); + int y = instruction["y"].as(); + int r = instruction["r"].as(); + matrix->fillCircle(x + xOffset, y + yOffset, r, color); + } + else if (command == "dt") + { + int x = instruction["x"].as(); + int y = instruction["y"].as(); + String text = instruction["t"].as(); + matrix->setCursor(x + xOffset, y + yOffset + 5); + matrix->setTextColor(color); + matrix->print(text); + } + } +} diff --git a/src/DisplayManager.h b/src/DisplayManager.h index a754be17..03fb8b25 100644 --- a/src/DisplayManager.h +++ b/src/DisplayManager.h @@ -1,8 +1,12 @@ #ifndef DisplayManager_h #define DisplayManager_h + #include +#include #include +#include + class DisplayManager_ { @@ -78,6 +82,7 @@ class DisplayManager_ void showSleepAnimation(); void showCurtainEffect(); void sendAppLoop(); + void processDrawInstructions(int16_t x, int16_t y, const std::vector &drawInstructions); String ledsAsJson(); String getAppsWithIcon(); }; diff --git a/src/Globals.cpp b/src/Globals.cpp index bc8ae0bb..ac19aa64 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -214,7 +214,7 @@ IPAddress gateway; IPAddress subnet; IPAddress primaryDNS; IPAddress secondaryDNS; -const char *VERSION = "0.58"; +const char *VERSION = "0.59"; String MQTT_HOST = ""; uint16_t MQTT_PORT = 1883; String MQTT_USER; diff --git a/src/Globals.h b/src/Globals.h index 04391d00..e6057eed 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -25,7 +25,6 @@ #define DEBUG_PRINTF(format, ...) #endif -#define configASSERT(x) if((x) == 0) {printf("ASSERTION FAILED at line %d in file %s.\n", __LINE__, __FILE__); taskDISABLE_INTERRUPTS(); for(;;);} extern const char *uniqueID; extern const char *VERSION; diff --git a/lib/MatrixUI/MatrixDisplayUi.cpp b/src/MatrixDisplayUi.cpp similarity index 96% rename from lib/MatrixUI/MatrixDisplayUi.cpp rename to src/MatrixDisplayUi.cpp index e2958b7b..b3d5a91a 100644 --- a/lib/MatrixUI/MatrixDisplayUi.cpp +++ b/src/MatrixDisplayUi.cpp @@ -1,383 +1,383 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2016 by Daniel Eichhorn - * Copyright (c) 2016 by Fabrice Weinberg - * Copyright (c) 2023 by Stephan Muehl (Blueforcer) - * Note: This old lib for SSD1306 displays has been extremly - * modified for AWTRIX Light and has nothing to do with the original purposes. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include "MatrixDisplayUi.h" -#include "Fonts/AwtrixFont.h" - -GifPlayer gif1; -GifPlayer gif2; - -MatrixDisplayUi::MatrixDisplayUi(FastLED_NeoMatrix *matrix) -{ - this->matrix = matrix; -} - -void MatrixDisplayUi::init() -{ - this->matrix->begin(); - this->matrix->setTextWrap(false); - this->matrix->setBrightness(70); - this->matrix->setFont(&AwtrixFont); - gif1.setMatrix(this->matrix); - gif2.setMatrix(this->matrix); -} - -void MatrixDisplayUi::setTargetFPS(uint8_t fps) -{ - float oldInterval = this->updateInterval; - this->updateInterval = ((float)1.0 / (float)fps) * 1000; - - // Calculate new ticksPerApp - float changeRatio = oldInterval / (float)this->updateInterval; - this->ticksPerApp *= changeRatio; - this->ticksPerTransition *= changeRatio; -} - -// -/------ Automatic controll ------\- - -void MatrixDisplayUi::enablesetAutoTransition() -{ - this->setAutoTransition = true; -} -void MatrixDisplayUi::disablesetAutoTransition() -{ - this->setAutoTransition = false; -} -void MatrixDisplayUi::setsetAutoTransitionForwards() -{ - this->state.appTransitionDirection = 1; - this->lastTransitionDirection = 1; -} -void MatrixDisplayUi::setsetAutoTransitionBackwards() -{ - this->state.appTransitionDirection = -1; - this->lastTransitionDirection = -1; -} -void MatrixDisplayUi::setTimePerApp(uint16_t time) -{ - this->ticksPerApp = (int)((float)time / (float)updateInterval); -} -void MatrixDisplayUi::setTimePerTransition(uint16_t time) -{ - this->ticksPerTransition = (int)((float)time / (float)updateInterval); -} - -// -/----- App settings -----\- -void MatrixDisplayUi::setAppAnimation(AnimationDirection dir) -{ - this->appAnimationDirection = dir; -} - -void MatrixDisplayUi::setApps(const std::vector> &appPairs) -{ - - delete[] AppFunctions; - AppCount = appPairs.size(); - AppFunctions = new AppCallback[AppCount]; - for (size_t i = 0; i < AppCount; ++i) - { - AppFunctions[i] = appPairs[i].second; - } - this->resetState(); - DisplayManager.sendAppLoop(); -} - -// -/----- Overlays ------\- -void MatrixDisplayUi::setOverlays(OverlayCallback *overlayFunctions, uint8_t overlayCount) -{ - this->overlayFunctions = overlayFunctions; - this->overlayCount = overlayCount; -} - -// -/----- Manuel control -----\- -void MatrixDisplayUi::nextApp() -{ - if (this->state.appState != IN_TRANSITION) - { - this->state.manuelControll = true; - this->state.appState = IN_TRANSITION; - this->state.ticksSinceLastStateSwitch = 0; - this->lastTransitionDirection = this->state.appTransitionDirection; - this->state.appTransitionDirection = 1; - } -} -void MatrixDisplayUi::previousApp() -{ - if (this->state.appState != IN_TRANSITION) - { - this->state.manuelControll = true; - this->state.appState = IN_TRANSITION; - this->state.ticksSinceLastStateSwitch = 0; - this->lastTransitionDirection = this->state.appTransitionDirection; - this->state.appTransitionDirection = -1; - } -} - -void MatrixDisplayUi::switchToApp(uint8_t app) -{ - if (app >= this->AppCount) - return; - this->state.ticksSinceLastStateSwitch = 0; - if (app == this->state.currentApp) - return; - this->state.appState = FIXED; - this->state.currentApp = app; -} - -void MatrixDisplayUi::transitionToApp(uint8_t app) -{ - if (app >= this->AppCount) - return; - this->state.ticksSinceLastStateSwitch = 0; - if (app == this->state.currentApp) - return; - this->nextAppNumber = app; - this->lastTransitionDirection = this->state.appTransitionDirection; - this->state.manuelControll = true; - this->state.appState = IN_TRANSITION; - - this->state.appTransitionDirection = app < this->state.currentApp ? -1 : 1; -} - -// -/----- State information -----\- -MatrixDisplayUiState *MatrixDisplayUi::getUiState() -{ - return &this->state; -} - -int8_t MatrixDisplayUi::update() -{ - long appStart = millis(); - int8_t timeBudget = this->updateInterval - (appStart - this->state.lastUpdate); - if (timeBudget <= 0) - { - // Implement frame skipping to ensure time budget is keept - if (this->setAutoTransition && this->state.lastUpdate != 0) - this->state.ticksSinceLastStateSwitch += ceil(-timeBudget / this->updateInterval); - - this->state.lastUpdate = appStart; - this->tick(); - } - - return this->updateInterval - (millis() - appStart); -} - -void MatrixDisplayUi::tick() -{ - this->state.ticksSinceLastStateSwitch++; - - if (this->AppCount > 0) - { - switch (this->state.appState) - { - case IN_TRANSITION: - if (this->state.ticksSinceLastStateSwitch >= this->ticksPerTransition) - { - this->state.appState = FIXED; - this->state.currentApp = getnextAppNumber(); - this->state.ticksSinceLastStateSwitch = 0; - this->nextAppNumber = -1; - } - break; - case FIXED: - // Revert manuelControll - if (this->state.manuelControll) - { - this->state.appTransitionDirection = this->lastTransitionDirection; - this->state.manuelControll = false; - } - if (this->state.ticksSinceLastStateSwitch >= this->ticksPerApp) - { - if (this->setAutoTransition) - { - this->state.appState = IN_TRANSITION; - } - this->state.ticksSinceLastStateSwitch = 0; - } - break; - } - } - - this->matrix->clear(); - - if (this->AppCount > 0) - this->drawApp(); - this->drawOverlays(); - this->drawIndicators(); - DisplayManager.gammaCorrection(); - this->matrix->show(); -} - -void MatrixDisplayUi::drawIndicators() -{ - if (indicator1State && !indicator1Blink) - { - matrix->drawPixel(31, 0, indicator1Color); - matrix->drawPixel(30, 0, indicator1Color); - matrix->drawPixel(31, 1, indicator1Color); - } - if (indicator2State && !indicator2Blink) - { - matrix->drawPixel(31, 7, indicator2Color); - matrix->drawPixel(31, 6, indicator2Color); - matrix->drawPixel(30, 7, indicator2Color); - } - - if (indicator1State && indicator1Blink && (millis() % 1000) < 500) - { - matrix->drawPixel(31, 0, indicator1Color); - matrix->drawPixel(30, 0, indicator1Color); - matrix->drawPixel(31, 1, indicator1Color); - } - - if (indicator2State && indicator2Blink && (millis() % 1000) < 500) - { - matrix->drawPixel(31, 7, indicator2Color); - matrix->drawPixel(31, 6, indicator2Color); - matrix->drawPixel(30, 7, indicator2Color); - } -} - -void MatrixDisplayUi::drawApp() -{ - switch (this->state.appState) - { - case IN_TRANSITION: - { - float progress = (float)this->state.ticksSinceLastStateSwitch / (float)this->ticksPerTransition; - int16_t x, y, x1, y1; - switch (this->appAnimationDirection) - { - case SLIDE_UP: - x = 0; - y = -8 * progress; - x1 = 0; - y1 = y + 8; - break; - case SLIDE_DOWN: - x = 0; - y = 8 * progress; - x1 = 0; - y1 = y - 8; - break; - } - // Invert animation if direction is reversed. - int8_t dir = this->state.appTransitionDirection >= 0 ? 1 : -1; - x *= dir; - y *= dir; - x1 *= dir; - y1 *= dir; - bool FirstApp = progress < 0.2; - bool LastApp = progress > 0.8; - this->matrix->drawRect(x, y, x1, y1, matrix->Color(0, 0, 0)); - (this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, x, y, FirstApp, LastApp, &gif1); - (this->AppFunctions[this->getnextAppNumber()])(this->matrix, &this->state, x1, y1, FirstApp, LastApp, &gif2); - break; - } - case FIXED: - (this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, 0, 0, false, false, &gif2); - break; - } -} - -bool MatrixDisplayUi::isCurrentAppValid() -{ - for (size_t i = 0; i < AppCount; ++i) - { - if (AppFunctions[i] == AppFunctions[this->state.currentApp]) - { - return true; - } - } - return false; -} - -void MatrixDisplayUi::resetState() -{ - if (!isCurrentAppValid()) - { - this->state.lastUpdate = 0; - this->state.ticksSinceLastStateSwitch = 0; - this->state.appState = FIXED; - this->state.currentApp = 0; - } -} - -void MatrixDisplayUi::forceResetState() -{ - this->state.lastUpdate = 0; - this->state.ticksSinceLastStateSwitch = 0; - this->state.appState = FIXED; - this->state.currentApp = 0; -} - -void MatrixDisplayUi::drawOverlays() -{ - for (uint8_t i = 0; i < this->overlayCount; i++) - { - (this->overlayFunctions[i])(this->matrix, &this->state, &gif2); - } -} - -uint8_t MatrixDisplayUi::getnextAppNumber() -{ - if (this->nextAppNumber != -1) - return this->nextAppNumber; - return (this->state.currentApp + this->AppCount + this->state.appTransitionDirection) % this->AppCount; -} - -void MatrixDisplayUi::setIndicator1Color(uint16_t color) -{ - this->indicator1Color = color; -} - -void MatrixDisplayUi::setIndicator1State(bool state) -{ - this->indicator1State = state; -} - -void MatrixDisplayUi::setIndicator2Color(uint16_t color) -{ - this->indicator2Color = color; -} - -void MatrixDisplayUi::setIndicator2State(bool state) -{ - this->indicator2State = state; -} - -void MatrixDisplayUi::setIndicator1Blink(bool blink) -{ - this->indicator1Blink = blink; -} - -void MatrixDisplayUi::setIndicator2Blink(bool blink) -{ - this->indicator2Blink = blink; -} +/** + * The MIT License (MIT) + * + * Copyright (c) 2016 by Daniel Eichhorn + * Copyright (c) 2016 by Fabrice Weinberg + * Copyright (c) 2023 by Stephan Muehl (Blueforcer) + * Note: This old lib for SSD1306 displays has been extremly + * modified for AWTRIX Light and has nothing to do with the original purposes. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "MatrixDisplayUi.h" +#include "Fonts/AwtrixFont.h" + +GifPlayer gif1; +GifPlayer gif2; + +MatrixDisplayUi::MatrixDisplayUi(FastLED_NeoMatrix *matrix) +{ + this->matrix = matrix; +} + +void MatrixDisplayUi::init() +{ + this->matrix->begin(); + this->matrix->setTextWrap(false); + this->matrix->setBrightness(70); + this->matrix->setFont(&AwtrixFont); + gif1.setMatrix(this->matrix); + gif2.setMatrix(this->matrix); +} + +void MatrixDisplayUi::setTargetFPS(uint8_t fps) +{ + float oldInterval = this->updateInterval; + this->updateInterval = ((float)1.0 / (float)fps) * 1000; + + // Calculate new ticksPerApp + float changeRatio = oldInterval / (float)this->updateInterval; + this->ticksPerApp *= changeRatio; + this->ticksPerTransition *= changeRatio; +} + +// -/------ Automatic controll ------\- + +void MatrixDisplayUi::enablesetAutoTransition() +{ + this->setAutoTransition = true; +} +void MatrixDisplayUi::disablesetAutoTransition() +{ + this->setAutoTransition = false; +} +void MatrixDisplayUi::setsetAutoTransitionForwards() +{ + this->state.appTransitionDirection = 1; + this->lastTransitionDirection = 1; +} +void MatrixDisplayUi::setsetAutoTransitionBackwards() +{ + this->state.appTransitionDirection = -1; + this->lastTransitionDirection = -1; +} +void MatrixDisplayUi::setTimePerApp(uint16_t time) +{ + this->ticksPerApp = (int)((float)time / (float)updateInterval); +} +void MatrixDisplayUi::setTimePerTransition(uint16_t time) +{ + this->ticksPerTransition = (int)((float)time / (float)updateInterval); +} + +// -/----- App settings -----\- +void MatrixDisplayUi::setAppAnimation(AnimationDirection dir) +{ + this->appAnimationDirection = dir; +} + +void MatrixDisplayUi::setApps(const std::vector> &appPairs) +{ + + delete[] AppFunctions; + AppCount = appPairs.size(); + AppFunctions = new AppCallback[AppCount]; + for (size_t i = 0; i < AppCount; ++i) + { + AppFunctions[i] = appPairs[i].second; + } + this->resetState(); + DisplayManager.sendAppLoop(); +} + +// -/----- Overlays ------\- +void MatrixDisplayUi::setOverlays(OverlayCallback *overlayFunctions, uint8_t overlayCount) +{ + this->overlayFunctions = overlayFunctions; + this->overlayCount = overlayCount; +} + +// -/----- Manuel control -----\- +void MatrixDisplayUi::nextApp() +{ + if (this->state.appState != IN_TRANSITION) + { + this->state.manuelControll = true; + this->state.appState = IN_TRANSITION; + this->state.ticksSinceLastStateSwitch = 0; + this->lastTransitionDirection = this->state.appTransitionDirection; + this->state.appTransitionDirection = 1; + } +} +void MatrixDisplayUi::previousApp() +{ + if (this->state.appState != IN_TRANSITION) + { + this->state.manuelControll = true; + this->state.appState = IN_TRANSITION; + this->state.ticksSinceLastStateSwitch = 0; + this->lastTransitionDirection = this->state.appTransitionDirection; + this->state.appTransitionDirection = -1; + } +} + +void MatrixDisplayUi::switchToApp(uint8_t app) +{ + if (app >= this->AppCount) + return; + this->state.ticksSinceLastStateSwitch = 0; + if (app == this->state.currentApp) + return; + this->state.appState = FIXED; + this->state.currentApp = app; +} + +void MatrixDisplayUi::transitionToApp(uint8_t app) +{ + if (app >= this->AppCount) + return; + this->state.ticksSinceLastStateSwitch = 0; + if (app == this->state.currentApp) + return; + this->nextAppNumber = app; + this->lastTransitionDirection = this->state.appTransitionDirection; + this->state.manuelControll = true; + this->state.appState = IN_TRANSITION; + + this->state.appTransitionDirection = app < this->state.currentApp ? -1 : 1; +} + +// -/----- State information -----\- +MatrixDisplayUiState *MatrixDisplayUi::getUiState() +{ + return &this->state; +} + +int8_t MatrixDisplayUi::update() +{ + long appStart = millis(); + int8_t timeBudget = this->updateInterval - (appStart - this->state.lastUpdate); + if (timeBudget <= 0) + { + // Implement frame skipping to ensure time budget is keept + if (this->setAutoTransition && this->state.lastUpdate != 0) + this->state.ticksSinceLastStateSwitch += ceil(-timeBudget / this->updateInterval); + + this->state.lastUpdate = appStart; + this->tick(); + } + + return this->updateInterval - (millis() - appStart); +} + +void MatrixDisplayUi::tick() +{ + this->state.ticksSinceLastStateSwitch++; + + if (this->AppCount > 0) + { + switch (this->state.appState) + { + case IN_TRANSITION: + if (this->state.ticksSinceLastStateSwitch >= this->ticksPerTransition) + { + this->state.appState = FIXED; + this->state.currentApp = getnextAppNumber(); + this->state.ticksSinceLastStateSwitch = 0; + this->nextAppNumber = -1; + } + break; + case FIXED: + // Revert manuelControll + if (this->state.manuelControll) + { + this->state.appTransitionDirection = this->lastTransitionDirection; + this->state.manuelControll = false; + } + if (this->state.ticksSinceLastStateSwitch >= this->ticksPerApp) + { + if (this->setAutoTransition) + { + this->state.appState = IN_TRANSITION; + } + this->state.ticksSinceLastStateSwitch = 0; + } + break; + } + } + + this->matrix->clear(); + + if (this->AppCount > 0) + this->drawApp(); + this->drawOverlays(); + this->drawIndicators(); + DisplayManager.gammaCorrection(); + this->matrix->show(); +} + +void MatrixDisplayUi::drawIndicators() +{ + if (indicator1State && !indicator1Blink) + { + matrix->drawPixel(31, 0, indicator1Color); + matrix->drawPixel(30, 0, indicator1Color); + matrix->drawPixel(31, 1, indicator1Color); + } + if (indicator2State && !indicator2Blink) + { + matrix->drawPixel(31, 7, indicator2Color); + matrix->drawPixel(31, 6, indicator2Color); + matrix->drawPixel(30, 7, indicator2Color); + } + + if (indicator1State && indicator1Blink && (millis() % 1000) < 500) + { + matrix->drawPixel(31, 0, indicator1Color); + matrix->drawPixel(30, 0, indicator1Color); + matrix->drawPixel(31, 1, indicator1Color); + } + + if (indicator2State && indicator2Blink && (millis() % 1000) < 500) + { + matrix->drawPixel(31, 7, indicator2Color); + matrix->drawPixel(31, 6, indicator2Color); + matrix->drawPixel(30, 7, indicator2Color); + } +} + +void MatrixDisplayUi::drawApp() +{ + switch (this->state.appState) + { + case IN_TRANSITION: + { + float progress = (float)this->state.ticksSinceLastStateSwitch / (float)this->ticksPerTransition; + int16_t x, y, x1, y1; + switch (this->appAnimationDirection) + { + case SLIDE_UP: + x = 0; + y = -8 * progress; + x1 = 0; + y1 = y + 8; + break; + case SLIDE_DOWN: + x = 0; + y = 8 * progress; + x1 = 0; + y1 = y - 8; + break; + } + // Invert animation if direction is reversed. + int8_t dir = this->state.appTransitionDirection >= 0 ? 1 : -1; + x *= dir; + y *= dir; + x1 *= dir; + y1 *= dir; + bool FirstApp = progress < 0.2; + bool LastApp = progress > 0.8; + this->matrix->drawRect(x, y, x1, y1, matrix->Color(0, 0, 0)); + (this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, x, y, FirstApp, LastApp, &gif1); + (this->AppFunctions[this->getnextAppNumber()])(this->matrix, &this->state, x1, y1, FirstApp, LastApp, &gif2); + break; + } + case FIXED: + (this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, 0, 0, false, false, &gif2); + break; + } +} + +bool MatrixDisplayUi::isCurrentAppValid() +{ + for (size_t i = 0; i < AppCount; ++i) + { + if (AppFunctions[i] == AppFunctions[this->state.currentApp]) + { + return true; + } + } + return false; +} + +void MatrixDisplayUi::resetState() +{ + if (!isCurrentAppValid()) + { + this->state.lastUpdate = 0; + this->state.ticksSinceLastStateSwitch = 0; + this->state.appState = FIXED; + this->state.currentApp = 0; + } +} + +void MatrixDisplayUi::forceResetState() +{ + this->state.lastUpdate = 0; + this->state.ticksSinceLastStateSwitch = 0; + this->state.appState = FIXED; + this->state.currentApp = 0; +} + +void MatrixDisplayUi::drawOverlays() +{ + for (uint8_t i = 0; i < this->overlayCount; i++) + { + (this->overlayFunctions[i])(this->matrix, &this->state, &gif2); + } +} + +uint8_t MatrixDisplayUi::getnextAppNumber() +{ + if (this->nextAppNumber != -1) + return this->nextAppNumber; + return (this->state.currentApp + this->AppCount + this->state.appTransitionDirection) % this->AppCount; +} + +void MatrixDisplayUi::setIndicator1Color(uint16_t color) +{ + this->indicator1Color = color; +} + +void MatrixDisplayUi::setIndicator1State(bool state) +{ + this->indicator1State = state; +} + +void MatrixDisplayUi::setIndicator2Color(uint16_t color) +{ + this->indicator2Color = color; +} + +void MatrixDisplayUi::setIndicator2State(bool state) +{ + this->indicator2State = state; +} + +void MatrixDisplayUi::setIndicator1Blink(bool blink) +{ + this->indicator1Blink = blink; +} + +void MatrixDisplayUi::setIndicator2Blink(bool blink) +{ + this->indicator2Blink = blink; +} diff --git a/lib/MatrixUI/MatrixDisplayUi.h b/src/MatrixDisplayUi.h similarity index 94% rename from lib/MatrixUI/MatrixDisplayUi.h rename to src/MatrixDisplayUi.h index a87ae83f..2007dc47 100644 --- a/lib/MatrixUI/MatrixDisplayUi.h +++ b/src/MatrixDisplayUi.h @@ -1,210 +1,209 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2016 by Daniel Eichhorn - * Copyright (c) 2016 by Fabrice Weinberg - * Highly modified 2023 for AWTRIX Light by Stephan Muehl (Blueforcer) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef MatrixDisplayUi_h -#define MatrixDisplayUi_h - -#include -#include "FastLED_NeoMatrix.h" -#include -#include "GifPlayer.h" -#include "../../src/DisplayManager.h" - -// #define DEBUG_MatrixDisplayUi(...) Serial.printf( __VA_ARGS__ ) - -#ifndef DEBUG_MatrixDisplayUi -#define DEBUG_MatrixDisplayUi(...) -#endif - -enum AnimationDirection -{ - SLIDE_UP, - SLIDE_DOWN -}; - -enum AppState -{ - IN_TRANSITION, - FIXED -}; - -// Structure of the UiState -struct MatrixDisplayUiState -{ - - u_int64_t lastUpdate = 0; - uint16_t ticksSinceLastStateSwitch = 0; - - AppState appState = FIXED; - uint8_t currentApp = 0; - - // Normal = 1, Inverse = -1; - int8_t appTransitionDirection = 1; - bool lastFrameShown = false; - bool manuelControll = false; - - // Custom data that can be used by the user - void *userData = NULL; -}; - -typedef void (*AppCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer); -typedef void (*OverlayCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer *gifPlayer); - -class MatrixDisplayUi -{ -private: - FastLED_NeoMatrix *matrix; - - // Values for the Apps - AnimationDirection appAnimationDirection = SLIDE_DOWN; - int8_t lastTransitionDirection = 1; - - uint16_t ticksPerApp = 151; // ~ 5000ms at 30 FPS - uint16_t ticksPerTransition = 15; // ~ 500ms at 30 FPS - - bool setAutoTransition = true; - bool lastFrameShown; - AppCallback *AppFunctions = nullptr; - - // Internally used to transition to a specific app - int8_t nextAppNumber = -1; - - // Values for Overlays - OverlayCallback *overlayFunctions; - uint8_t overlayCount = 0; - - // UI State - MatrixDisplayUiState state; - - // Bookeeping for update - uint8_t updateInterval = 33; - - void drawApp(); - void drawOverlays(); - void tick(); - void resetState(); - bool isCurrentAppValid(); - -public: - MatrixDisplayUi(FastLED_NeoMatrix *matrix); - uint8_t AppCount = 0; - /** - * Initialise the display - */ - void init(); - - uint8_t getnextAppNumber(); - /** - * Configure the internal used target FPS - */ - void setTargetFPS(uint8_t fps); - - // Automatic Controll - /** - * Enable automatic transition to next app after the some time can be configured with `setTimePerApp` and `setTimePerTransition`. - */ - void enablesetAutoTransition(); - - /** - * Disable automatic transition to next app. - */ - void disablesetAutoTransition(); - - /** - * Set the direction if the automatic transitioning - */ - void setsetAutoTransitionForwards(); - void setsetAutoTransitionBackwards(); - - /** - * Set the approx. time a app is displayed - */ - void setTimePerApp(uint16_t time); - - /** - * Set the approx. time a transition will take - */ - void setTimePerTransition(uint16_t time); - - void setIndicator1Color(uint16_t color); - void setIndicator1State(bool state); - void setIndicator2Color(uint16_t color); - void setIndicator2State(bool state); - - void setIndicator1Blink(bool Blink); - void setIndicator2Blink(bool Blink); - - void drawIndicators(); - // Customize indicator position and style - - // App settings - - /** - * Configure what animation is used to transition from one app to another - */ - void setAppAnimation(AnimationDirection dir); - - /** - * Add app drawing functions - */ - void setApps(const std::vector> &appPairs); - - // Overlay - void forceResetState(); - /** - * Add overlays drawing functions that are draw independent of the Apps - */ - void setOverlays(OverlayCallback *overlayFunctions, uint8_t overlayCount); - - // Manual Control - void nextApp(); - void previousApp(); - - /** - * Switch without transition to app `app`. - */ - void switchToApp(uint8_t app); - - /** - * Transition to app `app`, when the `app` number is bigger than the current - * app the forward animation will be used, otherwise the backwards animation is used. - */ - void transitionToApp(uint8_t app); - - // State Info - MatrixDisplayUiState *getUiState(); - - int8_t update(); - - uint16_t indicator1Color = 63488; - uint16_t indicator2Color = 31; - bool indicator1State = false; - bool indicator2State = false; - bool indicator1Blink = false; - bool indicator2Blink = false; -}; -#endif +/** + * The MIT License (MIT) + * + * Copyright (c) 2016 by Daniel Eichhorn + * Copyright (c) 2016 by Fabrice Weinberg + * Highly modified 2023 for AWTRIX Light by Stephan Muehl (Blueforcer) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef MatrixDisplayUi_h +#define MatrixDisplayUi_h + + +#include +#include "FastLED_NeoMatrix.h" +#include "GifPlayer.h" +#include "DisplayManager.h" + + +#ifndef DEBUG_MatrixDisplayUi +#define DEBUG_MatrixDisplayUi(...) +#endif + +enum AnimationDirection +{ + SLIDE_UP, + SLIDE_DOWN +}; + +enum AppState +{ + IN_TRANSITION, + FIXED +}; + +// Structure of the UiState +struct MatrixDisplayUiState +{ + + u_int64_t lastUpdate = 0; + uint16_t ticksSinceLastStateSwitch = 0; + + AppState appState = FIXED; + uint8_t currentApp = 0; + + // Normal = 1, Inverse = -1; + int8_t appTransitionDirection = 1; + bool lastFrameShown = false; + bool manuelControll = false; + + // Custom data that can be used by the user + void *userData = NULL; +}; + +typedef void (*AppCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer); +typedef void (*OverlayCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer *gifPlayer); + +class MatrixDisplayUi +{ +private: + FastLED_NeoMatrix *matrix; + + // Values for the Apps + AnimationDirection appAnimationDirection = SLIDE_DOWN; + int8_t lastTransitionDirection = 1; + + uint16_t ticksPerApp = 151; // ~ 5000ms at 30 FPS + uint16_t ticksPerTransition = 15; // ~ 500ms at 30 FPS + + bool setAutoTransition = true; + bool lastFrameShown; + AppCallback *AppFunctions = nullptr; + + // Internally used to transition to a specific app + int8_t nextAppNumber = -1; + + // Values for Overlays + OverlayCallback *overlayFunctions; + uint8_t overlayCount = 0; + + // UI State + MatrixDisplayUiState state; + + // Bookeeping for update + uint8_t updateInterval = 33; + + void drawApp(); + void drawOverlays(); + void tick(); + void resetState(); + bool isCurrentAppValid(); + +public: + MatrixDisplayUi(FastLED_NeoMatrix *matrix); + uint8_t AppCount = 0; + /** + * Initialise the display + */ + void init(); + + uint8_t getnextAppNumber(); + /** + * Configure the internal used target FPS + */ + void setTargetFPS(uint8_t fps); + + // Automatic Controll + /** + * Enable automatic transition to next app after the some time can be configured with `setTimePerApp` and `setTimePerTransition`. + */ + void enablesetAutoTransition(); + + /** + * Disable automatic transition to next app. + */ + void disablesetAutoTransition(); + + /** + * Set the direction if the automatic transitioning + */ + void setsetAutoTransitionForwards(); + void setsetAutoTransitionBackwards(); + + /** + * Set the approx. time a app is displayed + */ + void setTimePerApp(uint16_t time); + + /** + * Set the approx. time a transition will take + */ + void setTimePerTransition(uint16_t time); + + void setIndicator1Color(uint16_t color); + void setIndicator1State(bool state); + void setIndicator2Color(uint16_t color); + void setIndicator2State(bool state); + + void setIndicator1Blink(bool Blink); + void setIndicator2Blink(bool Blink); + + void drawIndicators(); + // Customize indicator position and style + + // App settings + + /** + * Configure what animation is used to transition from one app to another + */ + void setAppAnimation(AnimationDirection dir); + + /** + * Add app drawing functions + */ + void setApps(const std::vector> &appPairs); + + // Overlay + void forceResetState(); + /** + * Add overlays drawing functions that are draw independent of the Apps + */ + void setOverlays(OverlayCallback *overlayFunctions, uint8_t overlayCount); + + // Manual Control + void nextApp(); + void previousApp(); + + /** + * Switch without transition to app `app`. + */ + void switchToApp(uint8_t app); + + /** + * Transition to app `app`, when the `app` number is bigger than the current + * app the forward animation will be used, otherwise the backwards animation is used. + */ + void transitionToApp(uint8_t app); + + // State Info + MatrixDisplayUiState *getUiState(); + + int8_t update(); + + uint16_t indicator1Color = 63488; + uint16_t indicator2Color = 31; + bool indicator1State = false; + bool indicator2State = false; + bool indicator1Blink = false; + bool indicator2Blink = false; +}; +#endif diff --git a/src/PeripheryManager.cpp b/src/PeripheryManager.cpp index cc38b453..96befa86 100644 --- a/src/PeripheryManager.cpp +++ b/src/PeripheryManager.cpp @@ -293,10 +293,20 @@ void PeripheryManager_::setup() void PeripheryManager_::tick() { - MQTTManager.sendButton(0, button_left.read()); - MQTTManager.sendButton(1, button_select.read()); - MQTTManager.sendButton(2, button_right.read()); + if (ROTATE_SCREEN) + { + MQTTManager.sendButton(2, button_left.read()); + + MQTTManager.sendButton(0, button_right.read()); + } + else + { + MQTTManager.sendButton(0, button_left.read()); + MQTTManager.sendButton(2, button_right.read()); + } + + MQTTManager.sendButton(1, button_select.read()); unsigned long currentMillis_BatTempHum = millis(); if (currentMillis_BatTempHum - previousMillis_BatTempHum >= interval_BatTempHum) { diff --git a/src/ServerManager.cpp b/src/ServerManager.cpp index 8f77ba74..ff10cab0 100644 --- a/src/ServerManager.cpp +++ b/src/ServerManager.cpp @@ -74,7 +74,7 @@ void ServerManager_::setup() mws.addCSS(custom_css); mws.addJavascript(custom_script); mws.addHandler("/save", HTTP_POST, saveHandler); - mws.addHandler("/api/sound", HTTP_POST, []() + mws.addHandler("/api/sound", HTTP_POST, []() { PeripheryManager.playFromFile("/MELODIES/" + mws.webserver->arg("plain") + ".txt"); mws.webserver->send(200,"OK"); }); mws.addHandler("/api/notify", HTTP_POST, []() { DisplayManager.generateNotification(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); }); diff --git a/src/main.cpp b/src/main.cpp index 4c03e528..bb274c34 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,6 +70,7 @@ void setup() delay(500); xTaskCreatePinnedToCore(BootAnimation, "Task", 10000, NULL, 1, &taskHandle, 0); ServerManager.setup(); + //PeripheryManager.playBootSound(); if (ServerManager.isConnected) { MQTTManager.setup();