diff --git a/docs/api.md b/docs/api.md index 9556a83f..1ecf1494 100644 --- a/docs/api.md +++ b/docs/api.md @@ -278,6 +278,8 @@ Here's an example JSON object to draw a red circle, a blue rectangle, and the te AWTRIX 3 allows you to present text where specific fragments can be colorized. Use an array of fragments with `"t"` representing the text fragment and `"c"` denoting the color's hex value. +Each fragment may also carry an optional `"b"` (Integer, ms): when greater than `0` that fragment blinks at the given interval while the other fragments stay steady. This is the per-fragment counterpart to the app-wide `blinkText`; omitting it (or `0`) falls back to the app-wide `blinkText` value. A typical use is a blinking clock separator, e.g. `[{"t":"12"},{"t":":","b":500},{"t":"34"}]`. + ```json { "text": [ @@ -287,7 +289,8 @@ AWTRIX 3 allows you to present text where specific fragments can be colorized. U }, { "t": "world!", - "c": "00FF00" + "c": "00FF00", + "b": 500 } ], "repeat": 2 diff --git a/src/Apps.cpp b/src/Apps.cpp index 378915e7..33378c33 100644 --- a/src/Apps.cpp +++ b/src/Apps.cpp @@ -675,7 +675,8 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState for (size_t i = 0; i < ca->fragments.size(); ++i) { String text = replacePlaceholders(ca->fragments[i]); - DisplayManager.setTextColor(TextEffect(ca->colors[i], ca->fade, ca->blink)); + int fragBlink = (i < ca->blinks.size() && ca->blinks[i] > 0) ? ca->blinks[i] : ca->blink; + DisplayManager.setTextColor(TextEffect(ca->colors[i], ca->fade, fragBlink)); DisplayManager.printText(x + fragmentX, y + 6, text.c_str(), false, ca->textCase); fragmentX += getTextWidth(text.c_str(), ca->textCase); } @@ -706,7 +707,8 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState for (size_t i = 0; i < ca->fragments.size(); ++i) { String text = replacePlaceholders(ca->fragments[i]); - DisplayManager.setTextColor(TextEffect(ca->colors[i], ca->fade, ca->blink)); + int fragBlink = (i < ca->blinks.size() && ca->blinks[i] > 0) ? ca->blinks[i] : ca->blink; + DisplayManager.setTextColor(TextEffect(ca->colors[i], ca->fade, fragBlink)); DisplayManager.printText(x + fragmentX, y + 6, text.c_str(), false, ca->textCase); fragmentX += getTextWidth(text.c_str(), ca->textCase); } diff --git a/src/Apps.h b/src/Apps.h index 9e44bb9a..43574cec 100644 --- a/src/Apps.h +++ b/src/Apps.h @@ -44,6 +44,7 @@ struct CustomApp uint64_t lifetime; std::vector colors; std::vector fragments; + std::vector blinks; int textOffset; int iconOffset; int progress = -1; diff --git a/src/DisplayManager.cpp b/src/DisplayManager.cpp index b151f207..3c88e841 100644 --- a/src/DisplayManager.cpp +++ b/src/DisplayManager.cpp @@ -398,10 +398,12 @@ void removeCustomAppFromApps(const String &name, bool setApps) DisplayManager.setAppTime(TIME_PER_APP); } -bool parseFragmentsText(const JsonArray &fragmentArray, std::vector &colors, std::vector &fragments, uint32_t standardColor) +bool parseFragmentsText(const JsonArray &fragmentArray, std::vector &colors, std::vector &fragments, uint32_t standardColor, std::vector *blinks = nullptr) { colors.clear(); fragments.clear(); + if (blinks) + blinks->clear(); for (JsonObject fragmentObj : fragmentArray) { @@ -419,6 +421,8 @@ bool parseFragmentsText(const JsonArray &fragmentArray, std::vector &c fragments.push_back(utf8ascii(textFragment)); colors.push_back(color); + if (blinks) + blinks->push_back(fragmentObj.containsKey("b") ? fragmentObj["b"].as() : 0); } return true; } @@ -715,11 +719,12 @@ bool DisplayManager_::generateCustomPage(const String &name, JsonObject doc, boo customApp.colors.clear(); customApp.fragments.clear(); + customApp.blinks.clear(); if (doc.containsKey("text") && doc["text"].is()) { JsonArray textArray = doc["text"].as(); - parseFragmentsText(textArray, customApp.colors, customApp.fragments, customApp.color); + parseFragmentsText(textArray, customApp.colors, customApp.fragments, customApp.color, &customApp.blinks); } else if (doc.containsKey("text")) {