Merged with mega from 2023-08-25

This commit is contained in:
uwekaditz
2023-08-27 16:13:14 +02:00
parent 68e2f467b1
commit dccd13f0f1
9 changed files with 554 additions and 174 deletions
+12 -2
View File
@@ -65,7 +65,17 @@ Device Settings
.. image:: P036_ScrollOptions.png
* **Scroll**: Switching between pages can be "instant" or "scrolling". Please note that scrolling will need more resources of the ESP, which can have an effect on other active tasks of the node.
* **Scroll**: Switching between pages can be "instant", "scrolling" or a "ticker" band. Please note that scrolling will need more resources of the ESP, which can have an effect on other active tasks of the node.
For the ``Ticker`` there are some restrictions:
* Depending on the build used (NORMAL and CUSTOM) this option is available
* only one line is displaying the ticker string
* all line contents are parsed and combined to this ticker string, the parsing happens only at each ticker start (using the setting ``Interval``)
* the optional split token ``<|>`` is replaced by three spaces
* the gaps between the ticker items must be set by the ``line content`` (tailing spaces)
* the starting alignment (left, center, right) depends on the setting ``Align content (global)``
* the font is taken from the setting ``Modify font`` of the first line, the ``Alignment`` settings of the lines are ignored (always right aligned)
* the ticker speed depends on the length of the ticker string and the setting ``Interval`` setting
* the footer is automatically hidden
* **GPIO <- Display button**: Setting up a ``Display Button``, allows to configure a Display Timeout and wake the display on demand, either by a button, or by using some presence detection.
@@ -125,7 +135,7 @@ The user defined texts may also contain a split token ``<|>`` to display the lin
* **Alignment**: For each line, the alignment to be used can be selected, or the global setting can be used.
* **Interval** By default, Interval will be set to 0. If set to a non-zero value, the pre-configured content will be updated automatically using that interval (seconds).
* **Interval** By default, Interval will be set to 0. It needs to be set to a non-zero value, to switch between the frames using that interval (seconds).
General
Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 29 KiB

+16
View File
@@ -39,6 +39,7 @@
The updated line text is not stored in the settings itself, but kept in memory.
After a reboot the stored plugin settings will be used.
The line text can also be restored from the settings by the command ``restore``.
All template notations can be used, like system variables, or reference to a task value.
@@ -50,6 +51,7 @@
This command is to display a specific frame (aka page), or the next frame. When reaching the last frame, a 'next' (0) will display the first frame.
The <framenr> parameter corresponds to the desired frame (1..<number of frames>) to display. The number of frames is determined by dividing the lines in use (at least one line in that frame with some data), by the number of Lines per Frame. So practically, the range is 1..3 when all lines are used and 4 Lines per Frame is set, or 1..12 if Line per frames is set to 1. The number of frames is updated if a frame would initially be empty, and an external source places text on a line of that frame (see above).
If scroll is set to ``ticker`` only <framenr> = 1 is supported, it starts the ticker from the beginning.
When omitting <framenr>, or providing 0, the next frame is displayed.
@@ -59,6 +61,7 @@
``oledframedcmd,linecount,<1..4>``
","
This command changes the number of lines in each frame. When the next frame is to be displayed, the frames are recalculated and the sequence is restarted at the first frame.
If scroll is set to ``ticker`` this command is not supported.
If Generate events for 'Linecount' is selected, a ``<taskname#linecount=<lines>`` event is generated on initialization of the plugin and when changing the setting.
"
@@ -73,6 +76,19 @@
Set the global align option for content to centre (0), left (1) or right (2).
"
"
``oledframedcmd,restore,<line>``
","
If the <line> parameter is set to 0 all line contents will be restored from the settings.
Otherwise the <line> parameter corresponds with the same lines as the plugin configuration has,
and only the content of this line will be restored from the settings.
"
"
``oledframedcmd,scroll,<speed>``
","
The <speed> parameter corresponds with the line number of the scroll parameter of the settings (1=Very slow ... 6=Ticker).
After applying the new scroll speed the display restarts with the first page.
"
"
``oledframedcmd,userDef1,"<user Defined Header1>"``
","
Set the user defined header nr. 1 with any desired text value.
+9
View File
@@ -532,6 +532,15 @@ uint16_t OLEDDisplay::getStringWidth(const String& strUser) {
return width;
}
uint8_t OLEDDisplay::getCharWidth(const char c) {
uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
if (utf8ascii(c) == 0)
return 0;
if (c < firstChar)
return 0;
return pgm_read_byte(fontData + JUMPTABLE_START + (c- firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH);
}
void OLEDDisplay::setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) {
this->textAlignment = textAlignment;
}
+5
View File
@@ -190,6 +190,11 @@ class OLEDDisplay : public Print {
// Convencience method for the const char version
uint16_t getStringWidth(const String& text);
// Returns the width of c with the already set fontData
// returns a 0 if c is non-ascii
// in this case the next char must be converted
uint8_t getCharWidth(const char c);
// Specifies relative to which anchor point
// the text is rendered. Available constants:
// TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER_BOTH
+1
View File
@@ -378,6 +378,7 @@ static const char DATA_ESPEASY_DEFAULT_MIN_CSS[] PROGMEM = {
// #define USES_P036 // FrameOLED
// #define P036_FEATURE_DISPLAY_PREVIEW 1 // Enable Preview feature, shows on-display content on Devices overview page
// #define P036_FEATURE_ALIGN_PREVIEW 1 // Enable center/right-align feature when preview is enabled (auto-disabled for 1M builds)
// #define P036_ENABLE_TICKER 1 // Enable ticker function
// #define USES_P037 // MQTTImport
// #define P037_MAPPING_SUPPORT 1 // Enable Value mapping support
// #define P037_FILTER_SUPPORT 1 // Enable filtering support
+141 -62
View File
@@ -14,8 +14,20 @@
// Added to the main repository with some optimizations and some limitations.
// As long as the device is not enabled, no RAM is wasted.
//
// @uwekaditz: 2023-08-10
// BUG: Individual font setting can only enlarge or maximize the font, if more than 1 line should be displayed (it was buggy not only for ticker!)
// BUG: CalculateIndividualFontSettings() must be called until the font fits (it was buggy not only for ticker!)
// BUG: Compiler error for '#ifdef P036_FONT_CALC_LOG'
// @tonhuisman: 2023-08-08
// CHG: Enable Userdefined headers feature, even on LIMIT_BUILD_SIZE builds
// @uwekaditz: 2023-07-25
// BUG: Calculation for ticker IdxStart and IdxEnd was wrong for 64x48 display
// CHG: Start page updates after network has connected in PLUGIN_ONCE_A_SECOND, faster than waiting for the next PLUGIN_READ
// @uwekaditz: 2023-07-23
// NEW: Add ticker for scrolling speed, solves issue #4188
// ADD: Setting and support for oledframedcmd,restore,<0|<nn>> subcommand par2: (0=all|Line Content<nn>)
// ADD: Setting and support for oledframedcmd,scroll,<1..6> subcommand, par2: (casted to ePageScrollSpeeds)
// CHG: Minor change in debug messages (addLogMove() for dynamic messages)
// @tonhuisman: 2023-07-01
// CHG: Make compile-time defines for P036_SEND_EVENTS boolean
// CHG: Make compile-time defines for P036_ENABLE_LINECOUNT boolean
@@ -207,12 +219,14 @@
# define PLUGIN_NAME_036 "Display - OLED SSD1306/SH1106 Framed"
# define PLUGIN_VALUENAME1_036 "OLED"
# if P036_SEND_EVENTS
# define P036_EVENT_DISPLAY 0 // event: <taskname>#display=0/1
# define P036_EVENT_CONTRAST 1 // event: <taskname>#contrast=0/1/2
# define P036_EVENT_FRAME 2 // event: <taskname>#frame=1..n
# define P036_EVENT_LINE 3 // event: <taskname>#line=1..n
# define P036_EVENT_LINECNT 4 // event: <taskname>#linecount=1..4
# define P036_EVENT_RESTORE 5 // event: <taskname>#restore=1..n
# define P036_EVENT_SCROLL 6 // event: <taskname>#scroll=ePSS_VerySlow..ePSS_Ticker
# if P036_SEND_EVENTS
void P036_SendEvent(struct EventStruct *event,
uint8_t eventId,
int16_t eventValue);
@@ -321,20 +335,32 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
}
# endif // if P036_ENABLE_LEFT_ALIGN
{
const __FlashStringHelper *options[5] = {
# if P036_ENABLE_TICKER
const int optionCnt = 6;
# else // if P036_ENABLE_TICKER
const int optionCnt = 5;
# endif // if P036_ENABLE_TICKER
const __FlashStringHelper *options[optionCnt] = {
F("Very Slow"),
F("Slow"),
F("Fast"),
F("Very Fast"),
F("Instant")
F("Instant"),
# if P036_ENABLE_TICKER
F("Ticker"),
# endif // if P036_ENABLE_TICKER
};
const int optionValues[5] =
const int optionValues[optionCnt] =
{ static_cast<int>(ePageScrollSpeed::ePSS_VerySlow),
static_cast<int>(ePageScrollSpeed::ePSS_Slow),
static_cast<int>(ePageScrollSpeed::ePSS_Fast),
static_cast<int>(ePageScrollSpeed::ePSS_VeryFast),
static_cast<int>(ePageScrollSpeed::ePSS_Instant) };
addFormSelector(F("Scroll"), F("scroll"), 5, options, optionValues, P036_SCROLL);
static_cast<int>(ePageScrollSpeed::ePSS_Instant),
# if P036_ENABLE_TICKER
static_cast<int>(ePageScrollSpeed::ePSS_Ticker),
# endif // if P036_ENABLE_TICKER
};
addFormSelector(F("Scroll"), F("scroll"), optionCnt, options, optionValues, P036_SCROLL);
}
// FIXME TD-er: Why is this using pin3 and not pin1? And why isn't this using the normal pin selection functions?
@@ -698,6 +724,7 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
(P036_ROTATE == 2), // 1 = Normal, 2 = Rotated
P036_CONTRAST,
P036_TIMER,
static_cast<ePageScrollSpeed>(P036_SCROLL), // Scroll speed
P036_NLINES
))) {
clearPluginTaskData(event->TaskIndex);
@@ -896,6 +923,12 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
if (P036_DisplayIsOn) {
// Display is on.
if (!P036_data->bRunning && NetworkConnected() && (P036_data->ScrollingPages.Scrolling == 0)) {
// start page updates after network has connected
P036_data->P036_DisplayPage(event);
}
else {
P036_data->HeaderContent = static_cast<eHeaderContent>(get8BitFromUL(P036_FLAGS_0, P036_FLAG_HEADER)); // HeaderContent
P036_data->HeaderContentAlternative = static_cast<eHeaderContent>(get8BitFromUL(P036_FLAGS_0, P036_FLAG_HEADER_ALTERNATIVE));
@@ -907,6 +940,7 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
P036_data->update_display();
}
}
}
success = true;
break;
@@ -1023,15 +1057,17 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
addLog(LOG_LEVEL_INFO, F("P036_PLUGIN_WRITE ..."));
# endif // PLUGIN_036_DEBUG
bool bUpdateDisplay = false;
bool bDisplayON = false;
uint8_t eventId = 0;
const String command = parseString(string, 1);
const int LineNo = event->Par1;
const String subcommand = parseString(string, 2);
int LineNo = event->Par1;
# if P036_SEND_EVENTS
const bool sendEvents = bitRead(P036_FLAGS_0, P036_FLAG_SEND_EVENTS); // Bit 28 Send Events
# endif // if P036_SEND_EVENTS
if ((equals(command, F("oledframedcmd"))) && P036_data->isInitialized()) {
const String subcommand = parseString(string, 2);
if (equals(subcommand, F("display"))) {
// display functions
const String para1 = parseString(string, 3);
@@ -1067,49 +1103,25 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
else if (equals(para1, F("low"))) {
success = true;
P036_data->setContrast(OLED_CONTRAST_LOW);
# if P036_SEND_EVENTS
if (sendEvents) {
P036_SendEvent(event, P036_EVENT_CONTRAST, 0);
if (!P036_DisplayIsOn) {
P036_SendEvent(event, P036_EVENT_DISPLAY, 1);
}
}
# endif // if P036_SEND_EVENTS
P036_SetDisplayOn(1); // Save the fact that the display is now ON
LineNo = 0; // is event parameter
eventId = P036_EVENT_CONTRAST;
bDisplayON = true;
}
else if (equals(para1, F("med"))) {
success = true;
P036_data->setContrast(OLED_CONTRAST_MED);
# if P036_SEND_EVENTS
if (sendEvents) {
P036_SendEvent(event, P036_EVENT_CONTRAST, 1);
if (!P036_DisplayIsOn) {
P036_SendEvent(event, P036_EVENT_DISPLAY, 1);
}
}
# endif // if P036_SEND_EVENTS
P036_SetDisplayOn(1); // Save the fact that the display is now ON
LineNo = 1; // is event parameter
eventId = P036_EVENT_CONTRAST;
bDisplayON = true;
}
else if (equals(para1, F("high"))) {
success = true;
P036_data->setContrast(OLED_CONTRAST_HIGH);
# if P036_SEND_EVENTS
if (sendEvents) {
P036_SendEvent(event, P036_EVENT_CONTRAST, 2);
if (!P036_DisplayIsOn) {
P036_SendEvent(event, P036_EVENT_DISPLAY, 1);
}
}
# endif // if P036_SEND_EVENTS
P036_SetDisplayOn(1); // Save the fact that the display is now ON
LineNo = 2; // is event parameter
eventId = P036_EVENT_CONTRAST;
bDisplayON = true;
}
else if (equals(para1, F("user")) &&
@@ -1120,17 +1132,9 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
success = true;
P036_data->display->setContrast(static_cast<uint8_t>(event->Par3), static_cast<uint8_t>(event->Par4),
static_cast<uint8_t>(event->Par5));
# if P036_SEND_EVENTS
if (sendEvents) {
P036_SendEvent(event, P036_EVENT_CONTRAST, 3);
if (!P036_DisplayIsOn) {
P036_SendEvent(event, P036_EVENT_DISPLAY, 1);
}
}
# endif // if P036_SEND_EVENTS
P036_SetDisplayOn(1); // Save the fact that the display is now ON
LineNo = 3; // is event parameter
eventId = P036_EVENT_CONTRAST;
bDisplayON = true;
}
} else if ((equals(subcommand, F("frame"))) &&
(event->Par2 >= 0) &&
@@ -1162,11 +1166,19 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
else if ((equals(subcommand, F("linecount"))) &&
(event->Par2 >= 1) &&
(event->Par2 <= 4)) {
# if P036_ENABLE_TICKER
if (static_cast<ePageScrollSpeed>(P036_SCROLL) == ePageScrollSpeed::ePSS_Ticker) {
// Ticker supports only 1 line, can not be changed
success = (event->Par2 == 1);
return success;
}
# endif // if P036_ENABLE_TICKER
success = true;
if (P036_NLINES != event->Par2) {
P036_NLINES = event->Par2;
P036_data->setNrLines(P036_NLINES);
P036_data->setNrLines(event, P036_NLINES);
# if P036_SEND_EVENTS
if (sendEvents && bitRead(P036_FLAGS_0, P036_FLAG_EVENTS_FRAME_LINE)) { // Bit 29 Send Events Frame & Line
@@ -1176,6 +1188,47 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
}
}
# endif // if P036_ENABLE_LINECOUNT
else if ((equals(subcommand, F("restore"))) &&
(event->Par2 >= 0) && // 0: restore all line contents
(event->Par2 <= P36_Nlines)) {
// restore content functions
success = true;
LineNo = event->Par2;
P036_data->RestoreLineContent(event->TaskIndex,
get4BitFromUL(P036_FLAGS_0, P036_FLAG_SETTINGS_VERSION), // Bit23-20 Version CustomTaskSettings
LineNo);
if (LineNo == 0)
LineNo = 1; // after restoring all contents start with first Line
eventId = P036_EVENT_RESTORE;
bUpdateDisplay = true;
}
else if ((equals(subcommand, F("scroll"))) &&
(event->Par2 >= 1)) {
// set scroll
success = true;
switch (event->Par2) {
case 1: P036_SCROLL = static_cast<int16_t>(ePageScrollSpeed::ePSS_VerySlow); break;
case 2: P036_SCROLL = static_cast<int16_t>(ePageScrollSpeed::ePSS_Slow); break;
case 3: P036_SCROLL = static_cast<int16_t>(ePageScrollSpeed::ePSS_Fast); break;
case 4: P036_SCROLL = static_cast<int16_t>(ePageScrollSpeed::ePSS_VeryFast); break;
case 5: P036_SCROLL = static_cast<int16_t>(ePageScrollSpeed::ePSS_Instant); break;
# if P036_ENABLE_TICKER
case 6: P036_SCROLL = static_cast<int16_t>(ePageScrollSpeed::ePSS_Ticker); break;
# endif // if P036_ENABLE_TICKER
default:
success = false;
break;
}
if (success) {
P036_data->prepare_pagescrolling(static_cast<ePageScrollSpeed>(P036_SCROLL), P036_NLINES);
eventId = P036_EVENT_SCROLL;
LineNo = 1; // after change scroll start with first Line
bUpdateDisplay = true;
}
}
# if P036_ENABLE_LEFT_ALIGN
else if ((equals(subcommand, F("leftalign"))) &&
((event->Par2 == 0) ||
@@ -1238,6 +1291,27 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
*currentLine = currentLine->substring(0, strlen - iCharToRemove);
}
}
eventId = P036_FLAG_EVENTS_FRAME_LINE;
bUpdateDisplay = true;
}
}
if (success && (eventId > 0)) {
if (bDisplayON) {
# ifdef P036_SEND_EVENTS
if (sendEvents) {
P036_SendEvent(event, eventId, LineNo);
if (!P036_DisplayIsOn) {
P036_SendEvent(event, P036_EVENT_DISPLAY, 1);
}
}
# endif // ifdef P036_SEND_EVENTS
P036_SetDisplayOn(1); // Save the fact that the display is now ON
}
if (bUpdateDisplay) {
P036_data->MaxFramesToDisplay = 0xff; // update frame count
# if P036_SEND_EVENTS
@@ -1245,7 +1319,8 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
# endif // if P036_SEND_EVENTS
if (!P036_DisplayIsOn &&
!bitRead(P036_FLAGS_0, P036_FLAG_NODISPLAY_ONRECEIVE)) { // Bit 18 NoDisplayOnReceivedText
(!bitRead(P036_FLAGS_0, P036_FLAG_NODISPLAY_ONRECEIVE) || // Bit 18 NoDisplayOnReceivedText
(eventId == P036_EVENT_SCROLL))) {
// display was OFF, turn it ON
P036_data->display->displayOn();
P036_SetDisplayOn(1); // Save the fact that the display is now ON
@@ -1273,23 +1348,25 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
}
# ifdef PLUGIN_036_DEBUG
if (eventId == P036_FLAG_EVENTS_FRAME_LINE) {
String log;
if (loglevelActiveFor(LOG_LEVEL_INFO) &&
log.reserve(200)) { // estimated
log += F("[P36] Line: ");
log = F("[P36] Line: ");
log += LineNo;
log += F(" NewContent:");
log += NewContent;
log += F(" Content:");
log += P036_data->DisplayLinesV1[LineNo - 1].Content;
log += P036_data->LineContent->DisplayLinesV1[LineNo - 1].Content;
log += F(" Length:");
log += P036_data->DisplayLinesV1[LineNo - 1].Content.length();
log += P036_data->LineContent->DisplayLinesV1[LineNo - 1].Content.length();
log += F(" Pix: ");
log += P036_data->display->getStringWidth(P036_data->DisplayLinesV1[LineNo - 1].Content);
log += P036_data->display->getStringWidth(P036_data->LineContent->DisplayLinesV1[LineNo - 1].Content);
log += F(" Reserved:");
log += P036_data->DisplayLinesV1[LineNo - 1].reserved;
log += P036_data->LineContent->DisplayLinesV1[LineNo - 1].reserved;
addLogMove(LOG_LEVEL_INFO, log);
delay(5); // otherwise it is may be to fast for the serial monitor
}
}
# endif // PLUGIN_036_DEBUG
}
@@ -1323,6 +1400,8 @@ const __FlashStringHelper* P36_eventId_toString(uint8_t eventId)
# if P036_ENABLE_LINECOUNT
case P036_EVENT_LINECNT: return F("linecount");
# endif // if P036_ENABLE_LINECOUNT
case P036_EVENT_RESTORE: return F("restore");
case P036_EVENT_SCROLL: return F("scroll");
}
return F("");
}
+332 -102
View File
@@ -114,33 +114,18 @@ void P036_data_struct::reset() {
# ifdef P036_FONT_CALC_LOG
const __FlashStringHelper * tFontSettings::FontName() const {
if (fontData == ArialMT_Plain_24) {
return F("Arial_24");
}
# ifndef P036_LIMIT_BUILD_SIZE
if (fontData == Dialog_plain_18) {
return F("Dialog_18");
}
# endif // ifndef P036_LIMIT_BUILD_SIZE
if (fontData == ArialMT_Plain_16) {
return F("Arial_16");
}
# ifndef P036_LIMIT_BUILD_SIZE
if (fontData == Dialog_plain_12) {
return F("Dialog_12");
}
# endif // ifndef P036_LIMIT_BUILD_SIZE
if (fontData == ArialMT_Plain_10) {
return F("Arial_10");
}
else {
return F("Unknown font");
switch (fontIdx) {
case 0: return F("Arial_24"); break;
# ifndef P036_LIMIT_BUILD_SIZE
case 1: return F("Dialog_18"); break;
case 2: return F("Arial_16"); break;
case 3: return F("Dialog_12"); break;
case 4: return F("Arial_10"); break;
# else // ifndef P036_LIMIT_BUILD_SIZE
case 1: return F("Arial_16"); break;
case 2: return F("Arial_10"); break;
# endif // ifndef P036_LIMIT_BUILD_SIZE
default: return F("Unknown font");
}
}
@@ -195,6 +180,7 @@ bool P036_data_struct::init(taskIndex_t taskIndex,
bool Rotated,
uint8_t Contrast,
uint16_t DisplayTimer,
ePageScrollSpeed ScrollSpeed,
uint8_t NrLines) {
reset();
@@ -272,9 +258,11 @@ bool P036_data_struct::init(taskIndex_t taskIndex,
}
// prepare font and positions for page and line scrolling
prepare_pagescrolling();
prepare_pagescrolling(ScrollSpeed, NrLines);
}
bRunning = NetworkConnected();
return isInitialized();
}
@@ -295,11 +283,30 @@ void P036_data_struct::setOrientationRotated(bool rotated) {
}
}
void P036_data_struct::RestoreLineContent(taskIndex_t taskIndex,
uint8_t LoadVersion,
uint8_t LineNo) {
P036_LineContent *TempContent = new (std::nothrow) P036_LineContent();
if (TempContent != nullptr) {
TempContent->loadDisplayLines(taskIndex, LoadVersion);
if (LineNo == 0) {
for (int i = 0; i < P36_Nlines; ++i) {
*(&LineContent->DisplayLinesV1[i].Content) = TempContent->DisplayLinesV1[i].Content;
}
}
else {
*(&LineContent->DisplayLinesV1[LineNo - 1].Content) = TempContent->DisplayLinesV1[LineNo - 1].Content;
}
delete TempContent;
}
}
# if P036_ENABLE_LINECOUNT
void P036_data_struct::setNrLines(uint8_t NrLines) {
void P036_data_struct::setNrLines(struct EventStruct *event, uint8_t NrLines) {
if ((NrLines >= 1) && (NrLines <= P36_MAX_LinesPerPage)) {
ScrollingPages.linesPerFrameDef = NrLines;
prepare_pagescrolling(); // Recalculate font
prepare_pagescrolling(static_cast<ePageScrollSpeed>(P036_SCROLL), NrLines); // Recalculate font
MaxFramesToDisplay = 0xFF; // Recalculate page indicator
CalcMaxPageCount(); // Update max page count
nextFrameToDisplay = 0; // Reset to first page
@@ -543,7 +550,7 @@ int16_t P036_data_struct::GetHeaderHeight() const {
}
int16_t P036_data_struct::GetIndicatorTop() const {
if (bHideFooter) {
if (bHideFooter || bUseTicker) {
// no footer (indicator) -> returm max. display height
return getDisplaySizeSettings(disp_resolution).Height;
}
@@ -580,14 +587,20 @@ tIndividualFontSettings P036_data_struct::CalculateIndividualFontSettings(uint8_
switch (iModifyFont) {
case eModifyFont::eEnlarge:
if (ScrollingPages.linesPerFrameDef > 1) {
// Font can only be enlarged if more than 1 line is displayed
lFontIndex--;
if (lFontIndex < IdxForBiggestFont) { lFontIndex = IdxForBiggestFont; }
result.IdxForBiggestFontUsed = lFontIndex;
if (lFontIndex < IdxForBiggestFont) { lFontIndex = IdxForBiggestFont; }
result.IdxForBiggestFontUsed = lFontIndex;
}
break;
case eModifyFont::eMaximize:
lFontIndex = IdxForBiggestFont;
result.IdxForBiggestFontUsed = lFontIndex;
if (ScrollingPages.linesPerFrameDef > 1) {
// Font can only be maximized if more than 1 line is displayed
lFontIndex = IdxForBiggestFont;
result.IdxForBiggestFontUsed = lFontIndex;
}
break;
case eModifyFont::eReduce:
lFontIndex++;
@@ -621,6 +634,9 @@ tIndividualFontSettings P036_data_struct::CalculateIndividualFontSettings(uint8_
// just one lines per frame -> no space inbetween
lSpace = 0;
lTop = (MaxHeight - lHeight) / 2;
if (lHeight > MaxHeight) {
result.NextLineNo = 0xFF; // settings do not fit
}
} else {
if (deltaHeight >= (lLinesPerFrame - 1)) {
// individual line setting fits
@@ -661,6 +677,27 @@ tIndividualFontSettings P036_data_struct::CalculateIndividualFontSettings(uint8_
LineSettings[k].ypos = LineSettings[k - 1].ypos + FontSizes[LineSettings[k - 1].fontIdx].Height + lSpace;
}
}
# ifdef P036_CHECK_INDIVIDUAL_FONT
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log1;
if (log1.reserve(140)) { // estimated
delay(10); // otherwise it is may be to fast for the serial monitor
log1 = F("IndividualFontSettings:");
log1 += F(" result.NextLineNo:"); log1 += result.NextLineNo;
log1 += F(" result.IdxForBiggestFontUsed:"); log1 += result.IdxForBiggestFontUsed;
log1 += F(" LineNo:"); log1 += LineNo;
log1 += F(" LinesPerFrame:"); log1 += LinesPerFrame;
if (result.NextLineNo != 0xFF) {
log1 += F(" FrameNo:"); log1 += FrameNo;
log1 += F(" lTop:"); log1 += lTop;
log1 += F(" lSpace:"); log1 += lSpace;
}
addLogMove(LOG_LEVEL_INFO, log1);
}
}
#endif // # ifdef P036_CHECK_INDIVIDUAL_FONT
return result;
}
@@ -690,10 +727,9 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) {
strformat(F("P036 CalculateFontSettings lines: %d, height: %d, header: %s, footer: %s"),
iLinesPerFrame,
iHeight,
boolToString(!bHideHeader).c_str(),
boolToString(!bHideFooter).c_str()));
boolToString(!bHideHeader),
boolToString(!bHideFooter)));
}
String log;
# endif // ifdef P036_FONT_CALC_LOG
iMaxHeightForFont = lround(iHeight / (iLinesPerFrame * 1.0f)); // no extra space between lines
@@ -712,13 +748,13 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) {
# ifdef P036_FONT_CALC_LOG
String log1;
log1.reserve(80);
log1.clear();
# endif // ifdef P036_FONT_CALC_LOG
for (i = 0; i < P36_MaxFontCount - 1; i++) {
// check available fonts for the line setting
# ifdef P036_FONT_CALC_LOG
log1 += F(" -> i: ");
delay(5); // otherwise it is may be to fast for the serial monitor
log1 = F(" -> i: ");
log1 += i;
log1 += F(", h: ");
log1 += FontSizes[i].Height;
@@ -740,7 +776,7 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) {
# ifdef P036_FONT_CALC_LOG
log1 += F(", no font fits, fontIdx: ");
log1 += iFontIndex;
addLog(LOG_LEVEL_INFO, log1);
addLogMove(LOG_LEVEL_INFO, log1);
# endif // ifdef P036_FONT_CALC_LOG
break;
@@ -793,6 +829,13 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) {
uint8_t iIdxForBiggestFont = 0;
while (currentLine < P36_Nlines) {
# if P036_ENABLE_TICKER
if (bUseTicker && (currentLine > 0)) {
// for ticker only the first line defines the font
break;
}
# endif // if P036_ENABLE_TICKER
// calculate individual font settings
IndividualFontSettings = CalculateIndividualFontSettings(currentLine,
iFontIndex,
@@ -803,8 +846,8 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) {
if (IndividualFontSettings.NextLineNo == 0xFF) {
// individual settings do not fit
if (bReduceLinesPerFrame) {
currentLinesPerFrame--; // reduce numer of lines per frame
if ((bReduceLinesPerFrame) && (currentLinesPerFrame > 1)) {
currentLinesPerFrame--; // reduce number of lines per frame
} else {
iIdxForBiggestFont = IndividualFontSettings.IdxForBiggestFontUsed + 1; // use smaller font size as maximum
}
@@ -823,24 +866,15 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) {
String log1;
if (log1.reserve(140)) { // estimated
log1.clear();
log1 = F("IndividualFontSettings:");
log1 += F(" iFontIndex:"); log1 += iFontIndex;
log1 += F(" iLinesPerFrame:"); log1 += iLinesPerFrame;
log1 += F(" TopLineOffset:"); log1 += TopLineOffset;
log1 += F(" iHeight:"); log1 += iHeight;
log1 += F(" iUsedHeightForFonts:"); log1 += iUsedHeightForFonts;
log1 += F(" iMaxHeightForFont:"); log1 += iMaxHeightForFont;
addLog(LOG_LEVEL_INFO, log1);
for (uint8_t i = 0; i < P36_Nlines; i++) {
delay(5); // otherwise it is may be to fast for the serial monitor
log1.clear();
log1 += F("Line["); log1 += i;
log1 = F("Line["); log1 += i;
log1 += F("]: Frame:"); log1 += LineSettings[i].frame;
log1 += F(" FontIdx:"); log1 += LineSettings[i].fontIdx;
log1 += F(" ypos:"); log1 += LineSettings[i].ypos - TopLineOffset;
log1 += F(" FontHeight:"); log1 += LineSettings[i].FontHeight;
addLog(LOG_LEVEL_INFO, log1);
addLogMove(LOG_LEVEL_INFO, log1);
}
}
}
@@ -855,7 +889,7 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) {
String log1;
if (log1.reserve(140)) { // estimated
log1.clear();
delay(5); // otherwise it is may be to fast for the serial monitor
log1 = F("CalculateFontSettings: Font:");
log1 += result.FontName();
log1 += F(" Idx:");
@@ -887,10 +921,23 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) {
return result;
}
void P036_data_struct::prepare_pagescrolling() {
void P036_data_struct::prepare_pagescrolling(ePageScrollSpeed lscrollspeed,
uint8_t NrLines) {
if (!isInitialized()) {
return;
}
# if P036_ENABLE_TICKER
bUseTicker = (lscrollspeed == ePageScrollSpeed::ePSS_Ticker);
# else // if P036_ENABLE_TICKER
bUseTicker = false;
# endif //if P036_ENABLE_TICKER
if (bUseTicker) {
ScrollingPages.linesPerFrameDef = 1;
}
else {
ScrollingPages.linesPerFrameDef = NrLines;
}
CalculateFontSettings(0);
}
@@ -908,7 +955,7 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
if (loglevelActiveFor(LOG_LEVEL_INFO) &&
log.reserve(32)) {
log += F("Start Scrolling: Speed: ");
log = F("Start Scrolling: Speed: ");
log += static_cast<int>(lscrollspeed);
addLogMove(LOG_LEVEL_INFO, log);
}
@@ -920,6 +967,9 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
if (lscrollspeed == ePageScrollSpeed::ePSS_Instant) {
// no scrolling, just the handling time to build the new page
iPageScrollTime = P36_PageScrollTick - P36_PageScrollTimer;
} else if (lscrollspeed == ePageScrollSpeed::ePSS_Ticker) {
// for ticker, no scrolling, just the handling time to build the new page
iPageScrollTime = P36_PageScrollTick - P36_PageScrollTimer;
} else {
iPageScrollTime = (P36_MaxDisplayWidth / (P36_PageScrollPix * static_cast<int>(lscrollspeed))) * P36_PageScrollTick;
}
@@ -930,7 +980,7 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log;
log.reserve(32);
log += F("PageScrollTime: ");
log = F("PageScrollTime: ");
log += iPageScrollTime;
addLogMove(LOG_LEVEL_INFO, log);
}
@@ -943,6 +993,22 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
MaxPixWidthForPageScrolling -= getDisplaySizeSettings(disp_resolution).PixLeft;
}
# if P036_ENABLE_TICKER
if (bUseTicker) {
ScrollingLines.Ticker.Tcontent = EMPTY_STRING;
ScrollingLines.Ticker.IdxEnd = 0;
ScrollingLines.Ticker.IdxStart = 0;
for (uint8_t i = 0; i < P36_Nlines; i++) {
String tmpString(LineContent->DisplayLinesV1[i].Content);
tmpString.replace(F("<|>"), " "); // replace the split token with three space char
ScrollingLines.Ticker.Tcontent += P36_parseTemplate(tmpString, i);
}
ScrollingLines.Ticker.len = ScrollingLines.Ticker.Tcontent.length();
}
# endif // if P036_ENABLE_TICKER
for (uint8_t j = 0; j < ScrollingPages.linesPerFrameDef; j++) {
// default no line scrolling and strings are centered
uint16_t PixLengthLineOut = 0; // pix length of line out
@@ -965,9 +1031,56 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
ScrollingLines.SLine[j].LastWidth = PixLengthLineOut; // while page scrolling this line is right aligned
}
if ((PixLengthLineIn > getDisplaySizeSettings(disp_resolution).Width) &&
if ((bUseTicker || (PixLengthLineIn > getDisplaySizeSettings(disp_resolution).Width)) &&
(iScrollTime > 0)) {
// width of the line > display width -> scroll line
if (bUseTicker) {
# if P036_ENABLE_TICKER
ScrollingLines.SLine[j].Width = 0;
uint16_t AddPixTicker;
switch (textAlignment) {
case TEXT_ALIGN_CENTER: ScrollingLines.SLine[j].CurrentLeft = getDisplaySizeSettings(disp_resolution).PixLeft +
getDisplaySizeSettings(disp_resolution).Width / 2;
AddPixTicker = getDisplaySizeSettings(disp_resolution).Width / 2; // half width at begin
break;
case TEXT_ALIGN_RIGHT: ScrollingLines.SLine[j].CurrentLeft = getDisplaySizeSettings(disp_resolution).PixLeft +
getDisplaySizeSettings(disp_resolution).Width;
AddPixTicker = getDisplaySizeSettings(disp_resolution).Width; // full width at begin
break;
default: ScrollingLines.SLine[j].CurrentLeft = getDisplaySizeSettings(disp_resolution).PixLeft;
AddPixTicker = 0;
}
ScrollingLines.SLine[j].fPixSum = ScrollingLines.SLine[j].CurrentLeft;
display->setFont(FontSizes[LineSettings[j].fontIdx].fontData);
ScrollingLines.SLine[j].dPix = (static_cast<float>(display->getStringWidth(ScrollingLines.Ticker.Tcontent) + AddPixTicker)) /
static_cast<float>(iScrollTime);
ScrollingLines.SLine[j].SLcontent = EMPTY_STRING;
ScrollingLines.Ticker.TickerAvgPixPerChar = lround(static_cast<float>(display->getStringWidth(
ScrollingLines.Ticker.Tcontent)) /
static_cast<float>(ScrollingLines.Ticker.len));
if (ScrollingLines.Ticker.TickerAvgPixPerChar < ScrollingLines.SLine[j].dPix) {
ScrollingLines.Ticker.TickerAvgPixPerChar = round(2 * ScrollingLines.SLine[j].dPix);
}
ScrollingLines.Ticker.MaxPixLen = getDisplaySizeSettings(disp_resolution).Width + 2 * ScrollingLines.Ticker.TickerAvgPixPerChar;
// add more characters to display
while (true) {
char c = ScrollingLines.Ticker.Tcontent.charAt(ScrollingLines.Ticker.IdxEnd);
uint8_t PixForChar = display->getCharWidth(c);
if ((ScrollingLines.SLine[0].Width + PixForChar) >= ScrollingLines.Ticker.MaxPixLen) {
break; // no more characters necessary to add
}
ScrollingLines.Ticker.IdxEnd++;
ScrollingLines.SLine[j].Width += PixForChar;
}
# endif // if P036_ENABLE_TICKER
}
else {
ScrollingLines.SLine[j].SLcontent = ScrollingPages.In[j].SPLcontent;
ScrollingLines.SLine[j].SLidx = ScrollingPages.In[j].SPLidx; // index to LineSettings[]
ScrollingLines.SLine[j].Width = PixLengthLineIn; // while page scrolling this line is left aligned
@@ -977,19 +1090,38 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
// pix change per scrolling line tick
ScrollingLines.SLine[j].dPix =
(static_cast<float>(PixLengthLineIn - getDisplaySizeSettings(disp_resolution).Width)) / iScrollTime;
}
# ifdef P036_SCROLL_CALC_LOG
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
delay(5); // otherwise it is may be to fast for the serial monitor
String log;
log.reserve(32);
log += F("Line: ");
log = F("Line: ");
log += (j + 1);
log += F(" width: ");
log += ScrollingLines.SLine[j].Width;
log += F(" dPix: ");
log += ScrollingLines.SLine[j].dPix;
addLogMove(LOG_LEVEL_INFO, log);
# if P036_ENABLE_TICKER
if (bUseTicker) {
delay(5); // otherwise it is may be to fast for the serial monitor
String log1;
log1.reserve(200);
log1 = F("+++ iScrollTime: ");
log1 += iScrollTime;
log1 += F(" StrLength: ");
log1 += ScrollingLines.Ticker.len;
log1 += F(" StrInPix: ");
log1 += display->getStringWidth(ScrollingLines.Ticker.Tcontent);
log1 += F(" PixPerChar: ");
log1 += ScrollingLines.Ticker.TickerAvgPixPerChar;
addLogMove(LOG_LEVEL_INFO, log1);
}
# endif // if P036_ENABLE_TICKER
}
# endif // P036_SCROLL_CALC_LOG
}
@@ -1040,13 +1172,14 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
if (loglevelActiveFor(LOG_LEVEL_INFO) &&
log.reserve(128)) {
log += F("Line: "); log += (j + 1);
delay(5); // otherwise it is may be to fast for the serial monitor
log = F("Line: "); log += (j + 1);
log += F(" LineIn: "); log += LineInStr;
log += F(" Length: "); log += strlen;
log += F(" PixLength: "); log += PixLengthLineIn;
log += F(" AvgPixPerChar: "); log += fAvgPixPerChar;
log += F(" CharsRemoved: "); log += iCharToRemove;
addLog(LOG_LEVEL_INFO, log);
addLogMove(LOG_LEVEL_INFO, log);
log.clear();
log += F(" -> Changed to: "); log += ScrollingPages.In[j].SPLcontent;
log += F(" Length: "); log += ScrollingPages.In[j].SPLcontent.length();
@@ -1145,13 +1278,15 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
if (loglevelActiveFor(LOG_LEVEL_INFO) &&
log.reserve(128)) {
log += F("Line: "); log += (j + 1);
delay(5); // otherwise it is may be to fast for the serial monitor
log = F("Line: "); log += (j + 1);
log += F(" LineOut: "); log += LineOutStr;
log += F(" Length: "); log += strlen;
log += F(" PixLength: "); log += PixLengthLineOut;
log += F(" AvgPixPerChar: "); log += fAvgPixPerChar;
log += F(" CharsRemoved: "); log += iCharToRemove;
addLog(LOG_LEVEL_INFO, log);
addLogMove(LOG_LEVEL_INFO, log);
delay(5); // otherwise it is may be to fast for the serial monitor
log.clear();
log += F(" -> Changed to: "); log += ScrollingPages.Out[j].SPLcontent;
log += F(" Length: "); log += ScrollingPages.Out[j].SPLcontent.length();
@@ -1198,18 +1333,30 @@ uint8_t P036_data_struct::display_scroll_timer(bool initialScroll,
}
}
if (!bUseTicker) {
for (uint8_t j = 0; j < ScrollingPages.linesPerFrameOut; j++) {
if ((initialScroll && (lscrollspeed < ePageScrollSpeed::ePSS_Instant)) ||
!initialScroll) {
// scrolling, prepare scrolling out to right
// scrolling, prepare scrolling page out to right
DrawScrollingPageLine(&ScrollingPages.Out[j], ScrollingLines.SLine[j].LastWidth, TEXT_ALIGN_RIGHT);
}
}
for (uint8_t j = 0; j < ScrollingPages.linesPerFrameIn; j++) {
// non-scrolling or scrolling prepare scrolling in from left
// non-scrolling or scrolling prepare scrolling page in from left
DrawScrollingPageLine(&ScrollingPages.In[j], ScrollingLines.SLine[j].Width, TEXT_ALIGN_LEFT);
}
}
# if P036_ENABLE_TICKER
else {
// for Ticker start with the set alignment
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FontSizes[LineSettings[ScrollingLines.SLine[0].SLidx].fontIdx].fontData);
display->drawString(ScrollingLines.SLine[0].CurrentLeft,
LineSettings[ScrollingLines.SLine[0].SLidx].ypos,
ScrollingLines.Ticker.Tcontent.substring(ScrollingLines.Ticker.IdxStart, ScrollingLines.Ticker.IdxEnd));
}
# endif // if P036_ENABLE_TICKER
update_display();
@@ -1245,9 +1392,8 @@ void P036_data_struct::display_scrolling_lines() {
}
if (bscroll) {
ScrollingLines.wait++;
if (ScrollingLines.wait < P36_WaitScrollLines) {
ScrollingLines.wait++;
return; // wait before scrolling line not finished
}
@@ -1268,18 +1414,74 @@ void P036_data_struct::display_scrolling_lines() {
display->setFont(FontSizes[LineSettings[ScrollingLines.SLine[i].SLidx].fontIdx].fontData);
if (((ScrollingLines.SLine[i].CurrentLeft - getDisplaySizeSettings(disp_resolution).PixLeft) +
ScrollingLines.SLine[i].Width) >= getDisplaySizeSettings(disp_resolution).Width) {
if (bUseTicker || (((iCurrentLeft - getDisplaySizeSettings(disp_resolution).PixLeft) +
ScrollingLines.SLine[i].Width) >= getDisplaySizeSettings(disp_resolution).Width)) {
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(ScrollingLines.SLine[i].CurrentLeft,
if (bUseTicker) {
#if P036_ENABLE_TICKER
display->drawString(iCurrentLeft,
LineSettings[ScrollingLines.SLine[0].SLidx].ypos,
ScrollingLines.Ticker.Tcontent.substring(ScrollingLines.Ticker.IdxStart, ScrollingLines.Ticker.IdxEnd));
// add more characters to display
iCurrentLeft -= getDisplaySizeSettings(disp_resolution).PixLeft;
while (true) {
if (ScrollingLines.Ticker.IdxEnd >= ScrollingLines.Ticker.len) {// end of string
break;
}
uint8_t c = ScrollingLines.Ticker.Tcontent.charAt(ScrollingLines.Ticker.IdxEnd);
uint8_t PixForChar = display->getCharWidth(c);// PixForChar can be 0 if c is non ascii
if ((static_cast<int>(ScrollingLines.SLine[0].Width + PixForChar) + iCurrentLeft) >= ScrollingLines.Ticker.MaxPixLen) {
break; // no more characters necessary to add
}
ScrollingLines.Ticker.IdxEnd++;
ScrollingLines.SLine[0].Width += PixForChar;
}
// remove already displayed characters
float fCurrentPixLeft = static_cast<float>(getDisplaySizeSettings(disp_resolution).PixLeft) - 2.0f *
ScrollingLines.Ticker.TickerAvgPixPerChar;
while (ScrollingLines.SLine[0].fPixSum < fCurrentPixLeft) {
uint8_t c = ScrollingLines.Ticker.Tcontent.charAt(ScrollingLines.Ticker.IdxStart);
uint8_t PixForChar = display->getCharWidth(c);// PixForChar can be 0 if c is non ascii
ScrollingLines.SLine[0].fPixSum += static_cast<float>(PixForChar);
ScrollingLines.Ticker.IdxStart++;
if (ScrollingLines.Ticker.IdxStart >= ScrollingLines.Ticker.IdxEnd) {
ScrollingLines.SLine[0].Width = 0;// Stop scrolling
# ifdef PLUGIN_036_DEBUG
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(LOG_LEVEL_INFO, F("Ticker finished"));
}
# endif // PLUGIN_036_DEBUG
break;
}
if (ScrollingLines.SLine[0].Width > PixForChar) {
ScrollingLines.SLine[0].Width -= PixForChar;
}
}
break;
#endif // if P036_ENABLE_TICKER
} else {
display->drawString(iCurrentLeft,
LineSettings[ScrollingLines.SLine[i].SLidx].ypos,
ScrollingLines.SLine[i].SLcontent);
}
} else {
if (!bUseTicker) {
// line scrolling finished -> line is shown as aligned right
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(P36_MaxDisplayWidth - getDisplaySizeSettings(disp_resolution).PixLeft,
LineSettings[ScrollingLines.SLine[i].SLidx].ypos,
ScrollingLines.SLine[i].SLcontent);
}
ScrollingLines.SLine[i].Width = 0; // Stop scrolling
}
}
@@ -1369,7 +1571,7 @@ void P036_data_struct::P036_JumpToPage(struct EventStruct *event, uint8_t nextFr
bPageScrollDisabled = true; // show next page without scrolling
disableFrameChangeCnt = 2; // disable next page change in PLUGIN_READ if PLUGIN_READ was already scheduled
P036_DisplayPage(event); // Display the selected page, function needs 65ms!
displayTimer = PCONFIG(4); // Restart timer
displayTimer = P036_TIMER; // Restart timer
}
void P036_data_struct::P036_JumpToPageOfLine(struct EventStruct *event, uint8_t LineNo)
@@ -1378,6 +1580,9 @@ void P036_data_struct::P036_JumpToPageOfLine(struct EventStruct *event, uint8_t
P036_JumpToPage(event, LineSettings[LineNo].DisplayedPageNo);
}
// Defines the Scroll area layout
// Displays the selected page, function needs 65ms!
// Called by PLUGIN_READ and P036_JumpToPage()
void P036_data_struct::P036_DisplayPage(struct EventStruct *event)
{
# ifdef PLUGIN_036_DEBUG
@@ -1478,26 +1683,28 @@ void P036_data_struct::P036_DisplayPage(struct EventStruct *event)
# if P036_FEATURE_DISPLAY_PREVIEW && P036_FEATURE_ALIGN_PREVIEW
// Preview: Center or Right-Align add spaces on the left
const bool isAlignCenter = ScrollingPages.In[i].Alignment == OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER;
const bool isAlignRight = ScrollingPages.In[i].Alignment == OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_RIGHT;
if (!bUseTicker) {
// Preview: Center or Right-Align add spaces on the left
const bool isAlignCenter = ScrollingPages.In[i].Alignment == OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER;
const bool isAlignRight = ScrollingPages.In[i].Alignment == OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_RIGHT;
if (isAlignRight || isAlignCenter) {
const uint16_t maxlength = getDisplaySizeSettings(disp_resolution).Width;
const uint16_t pixlength = display->getStringWidth(currentLines[i]); // pix length for entire string
const uint16_t charlength = display->getStringWidth(F(" ")); // pix length for a space char
int16_t addSpaces = (maxlength - pixlength) / charlength;
if (isAlignRight || isAlignCenter) {
const uint16_t maxlength = getDisplaySizeSettings(disp_resolution).Width;
const uint16_t pixlength = display->getStringWidth(currentLines[i]); // pix length for entire string
const uint16_t charlength = display->getStringWidth(F(" ")); // pix length for a space char
int16_t addSpaces = (maxlength - pixlength) / charlength;
if (isAlignCenter) {
addSpaces /= 2;
}
if (isAlignCenter) {
addSpaces /= 2;
}
if (addSpaces > 0) {
currentLines[i].reserve(currentLines[i].length() + addSpaces);
if (addSpaces > 0) {
currentLines[i].reserve(currentLines[i].length() + addSpaces);
while (addSpaces > 0) {
currentLines[i] = ' ' + currentLines[i];
addSpaces--;
while (addSpaces > 0) {
currentLines[i] = ' ' + currentLines[i];
addSpaces--;
}
}
}
}
@@ -1537,10 +1744,12 @@ void P036_data_struct::P036_DisplayPage(struct EventStruct *event)
const bool bScrollWithoutWifi = bitRead(PCONFIG_LONG(0), 24); // Bit 24
const bool bScrollLines = bitRead(PCONFIG_LONG(0), 17); // Bit 17
bLineScrollEnabled = (bScrollLines && (NetworkConnected() || bScrollWithoutWifi)); // scroll lines only if WifiIsConnected,
bRunning = NetworkConnected() || bScrollWithoutWifi;
bLineScrollEnabled = ((bScrollLines || bUseTicker) && bRunning);// scroll lines only if WifiIsConnected,
// WifiIsConnected,
// otherwise too slow
ePageScrollSpeed lscrollspeed = static_cast<ePageScrollSpeed>(PCONFIG(3));
ePageScrollSpeed lscrollspeed = static_cast<ePageScrollSpeed>(P036_SCROLL);
if (bPageScrollDisabled) { lscrollspeed = ePageScrollSpeed::ePSS_Instant; } // first page after INIT without scrolling
@@ -1550,7 +1759,7 @@ void P036_data_struct::P036_DisplayPage(struct EventStruct *event)
Scheduler.setPluginTaskTimer(P36_PageScrollTimer, event->TaskIndex, event->Par1); // calls next page scrollng tick
}
if (NetworkConnected() || bScrollWithoutWifi) {
if (bRunning) {
// scroll lines only if WifiIsConnected, otherwise too slow
bPageScrollDisabled = false; // next PLUGIN_READ will do page scrolling
}
@@ -1582,7 +1791,16 @@ String P036_data_struct::P36_parseTemplate(String& tmpString, uint8_t lineIdx) {
const eAlignment iAlignment =
static_cast<eAlignment>(get3BitFromUL(LineContent->DisplayLinesV1[lineIdx].ModifyLayout, P036_FLAG_ModifyLayout_Alignment));
switch (getTextAlignment(iAlignment)) {
OLEDDISPLAY_TEXT_ALIGNMENT iTextAlignment = getTextAlignment(static_cast<eAlignment>(iAlignment));
# if P036_ENABLE_TICKER
if (bUseTicker) {
iTextAlignment = TEXT_ALIGN_RIGHT; // ticker is always right aligned
}
# endif // if P036_ENABLE_TICKER
switch (iTextAlignment) {
case TEXT_ALIGN_LEFT:
// add leading spaces from tmpString to the result
@@ -1727,19 +1945,19 @@ void P036_data_struct::CalcMaxPageCount(void) {
String log1;
if (log1.reserve(140)) { // estimated
log1.clear();
log1 = F("CalcMaxPageCount: MaxFramesToDisplay:"); log1 += MaxFramesToDisplay;
addLog(LOG_LEVEL_INFO, log1);
addLogMove(LOG_LEVEL_INFO, log1);
for (uint8_t i = 0; i < P36_Nlines; i++) {
log1.clear();
log1 += F("Line["); log1 += i;
delay(5); // otherwise it is may be to fast for the serial monitor
log1 = F("Line["); log1 += i;
log1 += F("]: Frame:"); log1 += LineSettings[i].frame;
log1 += F(" DisplayedPageNo:"); log1 += LineSettings[i].DisplayedPageNo;
log1 += F(" FontIdx:"); log1 += LineSettings[i].fontIdx;
log1 += F(" ypos:"); log1 += LineSettings[i].ypos - TopLineOffset;
log1 += F(" FontHeight:"); log1 += LineSettings[i].FontHeight;
addLog(LOG_LEVEL_INFO, log1);
addLogMove(LOG_LEVEL_INFO, log1);
}
}
}
@@ -1771,6 +1989,15 @@ void P036_data_struct::DrawScrollingPageLine(tScrollingPageLines *Scrollin
OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) {
int16_t LeftOffset = 0;
switch (textAlignment) {
case TEXT_ALIGN_LEFT: LeftOffset = -P36_MaxDisplayWidth;
break;
case TEXT_ALIGN_RIGHT: LeftOffset = 0;
break;
default:
LeftOffset = 0;
break;
}
display->setFont(FontSizes[LineSettings[ScrollingPageLine->SPLidx].fontIdx].fontData);
if (Width > 0) {
@@ -1784,10 +2011,6 @@ void P036_data_struct::DrawScrollingPageLine(tScrollingPageLines *Scrollin
// line is kept aligned while scrolling page
display->setTextAlignment(ScrollingPageLine->Alignment);
if (textAlignment == TEXT_ALIGN_LEFT) {
LeftOffset = -P36_MaxDisplayWidth;
}
// textAlignment=TEXT_ALIGN_LEFT: for non-scrolling pages ScrollingPages.dPixSum=P36_MaxDisplayWidth -> therefore the calculation must
// use P36_MaxDisplayWidth, too
display->drawString(LeftOffset + GetTextLeftMargin(ScrollingPageLine->Alignment) + ScrollingPages.dPixSum,
@@ -1797,6 +2020,12 @@ void P036_data_struct::DrawScrollingPageLine(tScrollingPageLines *Scrollin
}
void P036_data_struct::CreateScrollingPageLine(tScrollingPageLines *ScrollingPageLine, uint8_t Counter) {
if (bUseTicker) {
# if P036_ENABLE_TICKER
ScrollingPageLine->SPLcontent = EMPTY_STRING;
# endif // if P036_ENABLE_TICKER
}
else {
String tmpString(LineContent->DisplayLinesV1[Counter].Content);
ScrollingPageLine->SPLcontent = P36_parseTemplate(tmpString, Counter);
@@ -1828,6 +2057,7 @@ void P036_data_struct::CreateScrollingPageLine(tScrollingPageLines *ScrollingPag
ScrollingPageLine->Alignment = getTextAlignment(iAlignment);
ScrollingPageLine->SPLidx = Counter; // index to LineSettings[]
}
}
# if P036_FEATURE_DISPLAY_PREVIEW
bool P036_data_struct::web_show_values() {
+38 -8
View File
@@ -26,7 +26,7 @@
# ifndef P036_FEATURE_DISPLAY_PREVIEW
# define P036_FEATURE_DISPLAY_PREVIEW 1
# endif // ifndef P036_FEATURE_DISPLAY_PREVIEW
# ifdef P036_FEATURE_ALIGN_PREVIEW
# ifndef P036_FEATURE_ALIGN_PREVIEW
# define P036_FEATURE_ALIGN_PREVIEW 1
# endif // ifdef P036_FEATURE_ALIGN_PREVIEW
@@ -45,6 +45,9 @@
# ifndef P036_USERDEF_HEADERS
# define P036_USERDEF_HEADERS 1 // Enable User defined headers
# endif // ifndef P036_USERDEF_HEADERS
# ifndef P036_ENABLE_TICKER
# define P036_ENABLE_TICKER 1 // Enable ticker function
# endif // ifndef
# else // ifndef P036_LIMIT_BUILD_SIZE
# if defined(P036_SEND_EVENTS) && P036_SEND_EVENTS
# undef P036_SEND_EVENTS
@@ -65,6 +68,9 @@
// # ifndef P036_USERDEF_HEADERS
// # define P036_USERDEF_HEADERS 0 // Disable User defined headers
// # endif // ifndef P036_USERDEF_HEADERS
# ifndef P036_ENABLE_TICKER
# define P036_ENABLE_TICKER 0 // Disable ticker function
# endif // ifndef
# endif // ifndef P036_LIMIT_BUILD_SIZE
# ifndef P036_USERDEF_HEADERS
# define P036_USERDEF_HEADERS 1 // Enable User defined headers if not handled yet
@@ -128,7 +134,7 @@
# define P036_FLAG_SCROLL_WITHOUTWIFI 24 // Bit 24 ScrollWithoutWifi
# define P036_FLAG_HIDE_HEADER 25 // Bit 25 Hide header
# define P036_FLAG_INPUT_PULLUP 26 // Bit 26 Input PullUp
// # define P036_FLAG_INPUT_PULLDOWN 27 // Bit 27 Input PullDown, 2022-09-04 no longer used
// # define P036_FLAG_INPUT_PULLDOWN 27 // Bit 27 Input PullDown, 2022-09-04 not longer used
# define P036_FLAG_SEND_EVENTS 28 // Bit 28 SendEvents
# define P036_FLAG_EVENTS_FRAME_LINE 29 // Bit 29 SendEvents also on Frame & Line
# define P036_FLAG_HIDE_FOOTER 30 // Bit 30 Hide footer
@@ -169,7 +175,8 @@ enum class ePageScrollSpeed : uint8_t {
ePSS_Slow = 2u, // 400ms
ePSS_Fast = 4u, // 200ms
ePSS_VeryFast = 8u, // 100ms
ePSS_Instant = 32u // 20ms
ePSS_Instant = 32u, // 20ms
ePSS_Ticker = 255u // tickerspeed depends on line length
};
enum class eP036pinmode : uint8_t {
@@ -187,8 +194,20 @@ typedef struct {
uint8_t SLidx = 0; // index to DisplayLinesV1
} tScrollLine;
typedef struct {
String Tcontent; // content (all parsed lines)
uint16_t len = 0; // length of content
uint16_t IdxStart = 0; // Start index of TickerContent for displaying (left side)
uint16_t IdxEnd = 0; // End index of TickerContent for displaying (right side)
uint16_t TickerAvgPixPerChar = 0; // max of average pixel per character or pix change per scroll time (100ms)
int16_t MaxPixLen = 0; // Max pix length to display (display width + 2*TickerAvgPixPerChar)
} tTicker;
typedef struct {
tScrollLine SLine[P36_MAX_LinesPerPage]{};
# if P036_ENABLE_TICKER
tTicker Ticker;
# endif // if P036_ENABLE_TICKER
uint16_t wait = 0; // waiting time before scrolling
} tScrollingLines;
@@ -203,7 +222,7 @@ typedef struct {
tScrollingPageLines Out[P36_MAX_LinesPerPage]{};
int dPixSum = 0; // act pix change
uint8_t Scrolling = 0; // 0=Ready, 1=Scrolling
uint8_t dPix = 0; // pix change per scroll time (25ms)
uint8_t dPix = 0; // pix change per scroll time (25ms per page, 100ms per line)
uint8_t linesPerFrameDef = 0; // the default number of lines in frame in/out
uint8_t linesPerFrameIn = 0; // the number of lines in frame in
uint8_t linesPerFrameOut = 0; // the number of lines in frame out
@@ -343,6 +362,7 @@ struct P036_data_struct : public PluginTaskData_base {
bool Rotated,
uint8_t Contrast,
uint16_t DisplayTimer,
ePageScrollSpeed ScrollSpeed,
uint8_t NrLines);
bool isInitialized() const;
@@ -355,9 +375,16 @@ struct P036_data_struct : public PluginTaskData_base {
void setOrientationRotated(bool rotated);
# if P036_ENABLE_LINECOUNT
void setNrLines(uint8_t NrLines);
void setNrLines(struct EventStruct *event,
uint8_t NrLines);
# endif // if P036_ENABLE_LINECOUNT
// Restores line content from flash memory
// LineNo == 0: all line contents
// otherwise just the line content of the given LineNo
void RestoreLineContent(taskIndex_t taskIndex,
uint8_t LoadVersion,
uint8_t LineNo);
// The screen is set up as:
// - 10 rows at the top for the header
@@ -368,7 +395,8 @@ struct P036_data_struct : public PluginTaskData_base {
void display_title(const String& title);
void display_logo();
void display_indicator();
void prepare_pagescrolling();
void prepare_pagescrolling(ePageScrollSpeed lscrollspeed,
uint8_t NrLines);
uint8_t display_scroll(ePageScrollSpeed lscrollspeed,
int lTaskTimer);
uint8_t display_scroll_timer(bool initialScroll = false,
@@ -417,8 +445,8 @@ struct P036_data_struct : public PluginTaskData_base {
// Instantiate display here - does not work to do this within the INIT call
OLEDDisplay *display = nullptr;
tScrollingLines ScrollingLines{};
tScrollingPages ScrollingPages{};
tScrollingLines ScrollingLines{}; // scrolling lines in from right, out to left
tScrollingPages ScrollingPages{}; // scrolling pages in from left, out to right
// CustomTaskSettings
P036_LineContent *LineContent = nullptr;
@@ -453,6 +481,8 @@ struct P036_data_struct : public PluginTaskData_base {
uint8_t frameCounter = 0; // need to keep track of framecounter from call to call
uint8_t disableFrameChangeCnt = 0; // counter to disable frame change after JumpToPage in case PLUGIN_READ already scheduled
bool bPageScrollDisabled = true; // first page after INIT or after JumpToPage without scrolling
bool bRunning = false; // page updates are rumming = (NetworkConnected() || bScrollWithoutWifi)
bool bUseTicker = false; // scroll line like a ticker
OLEDDISPLAY_TEXT_ALIGNMENT textAlignment = TEXT_ALIGN_CENTER;