diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 33965ff..2cb2f17 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -11,6 +11,8 @@ #include "imglib.h" // Character sets +#include "fonts/DSEG7Classic-BoldItalic10pt7b.h" +#include "fonts/DSEG7Classic-BoldItalic12pt7b.h" #include "fonts/DSEG7Classic-BoldItalic16pt7b.h" #include "fonts/DSEG7Classic-BoldItalic20pt7b.h" #include "fonts/DSEG7Classic-BoldItalic26pt7b.h" @@ -539,17 +541,21 @@ std::vector wordwrap(String &line, uint16_t maxwidth) { } // Draw centered text -void drawTextCenter(int16_t cx, int16_t cy, String text) { +// returns left edge of printed string +int16_t drawTextCenter(int16_t cx, int16_t cy, String text) { int16_t x1, y1; uint16_t w, h; + displayGetTextBounds(text, 0, 0, &x1, &y1, &w, &h); int16_t cursorX = cx - (x1 + static_cast(w / 2)); int16_t cursorY = cy - (y1 + static_cast(h / 2)); getdisplay().setCursor(cursorX, cursorY); getdisplay().print(text); + + return cursorX; } -// Draw centered botton with centered text +// Draw centered button with centered text void drawButtonCenter(int16_t cx, int16_t cy, int8_t sx, int8_t sy, String text, uint16_t fg, uint16_t bg, bool inverted) { int16_t x1, y1; uint16_t w, h; @@ -576,57 +582,129 @@ void drawButtonCenter(int16_t cx, int16_t cy, int8_t sx, int8_t sy, String text, // int16_t y - upper right y position for text to start printing // const String& text - text to be printed // bool dsegAdjust = false - optional, for adjustment of DSEG italic font -int16_t drawTextRalign(int16_t x, int16_t y, const String& text, bool dsegAdjust) -{ +// returns left edge of printed string +int16_t drawTextRalign(int16_t x, int16_t y, const String& text, bool dsegAdjust) { int16_t x1 = 0, y1 = 0; uint16_t w = 0, h = 0; String str = text; // make sure that we always have a char with max size at last position for boundary test - // to avoid text wobbling of DSEG italic font + // for monotype italic DSEG7 font to avoid text wobbling if (dsegAdjust && str.length() > 0 && isDigit(str[str.length() - 1])) { str.setCharAt(str.length() - 1, '8'); } -#ifdef TFT_DISPLAY - w = getdisplay().textWidth(str); - h = getdisplay().fontHeight(); -#else - getdisplay().getTextBounds(str, 0, y, &x1, &y1, &w, &h); -#endif - + displayGetTextBounds(str, 0, y, &x1, &y1, &w, &h); int16_t cursorX = x - x1 - w; getdisplay().setCursor(cursorX, y); -// getdisplay().setCursor(x - w - 1, y); // '-1' required since some strings wrap around w/o it getdisplay().print(text); - return cursorX; // actual visible left edge + return cursorX; // currently visible left edge } -// Draw right aligned numbers with smaller decimals -// int16_t x - upper right x position for text to start printing -// int16_t y - upper right y position for text to start printing -// const String& text - number as text to be printed -// const GFXfont* mainFont - font type and size for integer part of number -// const GFXfont* decimalFont - font type and size for decimals part of number -void printDecimalRightAlign(int16_t x, int16_t y, const String& text, const GFXfont* mainFont, const GFXfont* decimalFont) { - String integerPart, decimalPart; - const int16_t dot = text.indexOf('.'); +// Implementation of ; does the actual printing +static void printBoatValueImpl(const String &sBoatValue, const int16_t x, const int16_t y, + const int8_t align, const int8_t fontSize, bool smallDecs) { + const GFXfont *mainFont = NULL; + const GFXfont *decimalFont = NULL; + constexpr bool dsegAdjust = true; - if (dot != -1) { - integerPart = text.substring(0, dot + 1); // includes '.' - decimalPart = text.substring(dot + 1); + String integerPart = sBoatValue; + String decimalPart = ""; + int16_t dot = 0; + int16_t decimalLeftX = x; // printing position of decimals part of boat data value + int16_t x1 = 0, y1 = 0; + uint16_t w = 0, h = 0; + + if (sBoatValue.indexOf('"') != -1) { + // boat value string includes a <"> which indicates LAT/LON value -> requires another font than DSEG7 + if (fontSize <= 12) { + mainFont = &Ubuntu_Bold12pt8b; + } else if (fontSize <= 16) { + mainFont = &Ubuntu_Bold16pt8b; + } else if (fontSize <= 20) { + mainFont = &Ubuntu_Bold20pt8b; + } else { + mainFont = &Ubuntu_Bold32pt8b; + } + smallDecs = false; // disable small decimals for LAT/LON in any case + } + else if (fontSize <= 12) { + mainFont = &DSEG7Classic_BoldItalic12pt7b; + decimalFont = &DSEG7Classic_BoldItalic10pt7b; + } else if (fontSize <= 16) { + mainFont = &DSEG7Classic_BoldItalic16pt7b; + decimalFont = &DSEG7Classic_BoldItalic12pt7b; + } else if (fontSize <= 20) { + mainFont = &DSEG7Classic_BoldItalic20pt7b; + decimalFont = &DSEG7Classic_BoldItalic16pt7b; + } else if (fontSize <= 26) { + mainFont = &DSEG7Classic_BoldItalic26pt7b; + decimalFont = &DSEG7Classic_BoldItalic20pt7b; + } else if (fontSize <= 30) { + mainFont = &DSEG7Classic_BoldItalic30pt7b; + decimalFont = &DSEG7Classic_BoldItalic26pt7b; + } else if (fontSize <= 42) { + mainFont = &DSEG7Classic_BoldItalic42pt7b; + decimalFont = &DSEG7Classic_BoldItalic30pt7b; } else { - integerPart = text; + mainFont = &DSEG7Classic_BoldItalic60pt7b; + decimalFont = &DSEG7Classic_BoldItalic42pt7b; } - // Draw decimal part first. - display.setFont(decimalFont); - int16_t decimalLeft = drawTextRalign(x, y, decimalPart); + if (smallDecs) { + dot = sBoatValue.indexOf('.'); + if (dot != -1) { + integerPart = sBoatValue.substring(0, dot + 1); // includes '.' + decimalPart = sBoatValue.substring(dot + 1); + } + // Draw decimal part of boat data value + display.setFont(decimalFont); + if (align == 2) { + decimalLeftX = drawTextRalign(x, y, decimalPart, dsegAdjust); + } else if (align == 1) { + decimalLeftX = drawTextCenter(x, y, decimalPart); + displayGetTextBounds(decimalPart, 0, 0, &x1, &y1, &w, &h); + decimalLeftX -= w / 2 - 1; + } else { + displayGetTextBounds(decimalPart, 0, 0, &x1, &y1, &w, &h); + getdisplay().setCursor(x + w + 1, y); + getdisplay().print(decimalPart); + decimalLeftX = x; + } + } - // Draw integer part immediately to its left. + // Draw integer or full part of boat data value display.setFont(mainFont); - drawTextRalign(decimalLeft, y, integerPart); + if (align == 2) { + drawTextRalign(decimalLeftX, y, integerPart, dsegAdjust); + } else { + getdisplay().setCursor(decimalLeftX, y); + getdisplay().print(integerPart); + } +} + +// Print boat data value at x,y position with selectable alignment +// Version with ; formats the boat data value and then prints the formatted value +// GwApi::BoatValue *bValue - boat value to print +// CommonData &commondata - required for function +// int16_t x - upper left/right x position for text to start printing +// int16_t y - upper left/right y position for text to start printing +// int8_t align - alignment [0,1,2] of the value: 0 = left, 1 = center, 2 = right +// int8_t fontSize - font size for integer part of number or for full value, if is /not set +// bool smallDecs - flag specifies if decimals will be printed in smaller fontsize [default = false] +void printBoatValue(GwApi::BoatValue *bValue, CommonData &commondata, const int16_t x, const int16_t y, + const int8_t align, const int8_t fontSize, const bool smallDecs) +{ + String sBoatValue = formatValue(bValue, commondata).svalue; + printBoatValueImpl(sBoatValue, x, y, align, fontSize, smallDecs); +} + +// Print boat data value at x,y position with selectable alignment; oerload with ready-to-print ; omits boat data value formatting +void printBoatValue(const String &sBoatValue, const int16_t x, const int16_t y, + const int8_t align, const int8_t fontSize, const bool smallDecs) +{ + printBoatValueImpl(sBoatValue, x, y, align, fontSize, smallDecs); } // Draw text inside box, normal or inverted diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h index cb0741a..ddd3f8a 100644 --- a/lib/obp60task/OBP60Extensions.h +++ b/lib/obp60task/OBP60Extensions.h @@ -734,11 +734,12 @@ void setBuzzerPower(uint power); // Set buzzer power String xdrDelete(String input); // Delete xdr prefix from string -void drawTextCenter(int16_t cx, int16_t cy, String text); +int16_t drawTextCenter(int16_t cx, int16_t cy, String text); void drawButtonCenter(int16_t cx, int16_t cy, int8_t sx, int8_t sy, String text, uint16_t fg, uint16_t bg, bool inverted); int16_t drawTextRalign(int16_t x, int16_t y, const String& text, bool dsegAdjust = false); -void printDecimalRightAlign(int16_t x, int16_t y, const String& text, const GFXfont* mainFont, const GFXfont* decimalFont); void drawTextBoxed(Rect box, String text, uint16_t fg, uint16_t bg, bool inverted, bool border); +void printBoatValue(GwApi::BoatValue *bValue, CommonData &commondata, const int16_t x, const int16_t y, const int8_t align, const int8_t fontSize, const bool smallDecs = false); +void printBoatValue(const String &sBoatValue, const int16_t x, const int16_t y, const int8_t align, const int8_t fontSize, const bool smallDecs = false); void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color); void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color); diff --git a/lib/obp60task/OBP60Formatter.cpp b/lib/obp60task/OBP60Formatter.cpp index 7df3f48..3087859 100644 --- a/lib/obp60task/OBP60Formatter.cpp +++ b/lib/obp60task/OBP60Formatter.cpp @@ -96,20 +96,17 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool double limit_dec_10; double limit_dec_100; if (precision == "1") { - // - //All values are displayed using a DSEG7* font. In this font, ' ' is a very short space, and '.' takes up no space at all. - //For a space that is as long as a number, '!' is used. For details see https://www.keshikan.net/fonts-e.html - // + //All values are displayed using a DSEG7* font. In this font, ' ' is a very short space, and '.' takes up no space at all. + //For a space that is as long as a number, '!' is used. For details see https://www.keshikan.net/fonts-e.html + fmt_dec_1 = "!%1.1f"; // blank digit + 2 digit number, incl. 1 decimal -// fmt_dec_10 = "!%2.0f"; //insert a blank digit and then display a two-digit number fmt_dec_10 = "%3.1f"; // 3 digit number, incl. 1 decimal fmt_dec_100 = "%3.0f"; // 3 digit number, no decimal limit_dec_10=9.95; // use fmt_dec_1 below this number to avoid formatting 9.96 as 10.0 instead of 10 limit_dec_100=99.5; } else { fmt_dec_1 = "%3.2f"; -// fmt_dec_10 = "%3.1f"; - fmt_dec_10 = "%3.2f"; // test for small decimals + fmt_dec_10 = "%3.1f"; fmt_dec_100 = "%3.0f"; limit_dec_10=9.995; limit_dec_100=99.95; diff --git a/lib/obp60task/PageSixValues.cpp b/lib/obp60task/PageSixValues.cpp index 0405f82..99175f5 100644 --- a/lib/obp60task/PageSixValues.cpp +++ b/lib/obp60task/PageSixValues.cpp @@ -3,20 +3,43 @@ #include "Pagedata.h" #include "OBP60Extensions.h" -const int SixValues_x1 = 5; -const int SixValues_DeltaX = 200; - -const int SixValues_y1 = 22; -const int SixValues_DeltaY = 83; - -const int HowManyValues = 6; - class PageSixValues : public Page { +private: + GwLog* logger; + GwConfigHandler* config; + + bool holdValues; + String flashLED; + String backlightMode; + + static constexpr int8_t LEFT = 0; + static constexpr int8_t CENTER = 1; + static constexpr int8_t RIGHT = 2; + bool smallDecimals; + + static constexpr int SixValues_x1 = 5; + static constexpr int SixValues_DeltaX = 200; + static constexpr int SixValues_y1 = 22; + static constexpr int SixValues_DeltaY = 83; + + static constexpr int HowManyValues = 6; + // Old values for hold function + String OldDataText[HowManyValues] = { "", "", "", "", "", "" }; + String OldDataUnit[HowManyValues] = { "", "", "", "", "", "" }; + public: PageSixValues(CommonData& common) { commonData = &common; - common.logger->logDebug(GwLog::LOG, "Instantiate PageSixValues"); + config = commonData->config; + logger = commonData->logger; + LOG_DEBUG(GwLog::LOG, "Instantiate PageSixValues"); + + // Get config data + holdValues = config->getBool(config->holdvalues); + flashLED = config->getString(config->flashLED); + backlightMode = config->getString(config->backlight); + smallDecimals = config->getBool(config->smallDecimals); } virtual int handleKey(int key) @@ -31,26 +54,14 @@ public: int displayPage(PageData& pageData) { - GwConfigHandler* config = commonData->config; - GwLog* logger = commonData->logger; - - // Old values for hold function - static String OldDataText[HowManyValues] = { "", "", "", "", "", "" }; - static String OldDataUnits[HowManyValues] = { "", "", "", "", "", "" }; - - // Get config data - String lengthformat = config->getString(config->lengthFormat); - bool holdvalues = config->getBool(config->holdvalues); - String flashLED = config->getString(config->flashLED); - String backlightMode = config->getString(config->backlight); - GwApi::BoatValue* bvalue; String DataName[HowManyValues]; double DataValue[HowManyValues]; bool DataValid[HowManyValues]; String DataText[HowManyValues]; - String DataUnits[HowManyValues]; + String DataUnit[HowManyValues]; String DataFormat[HowManyValues]; + int8_t DsegFontSize = 0; for (int i = 0; i < HowManyValues; i++) { bvalue = pageData.values[i]; @@ -59,7 +70,7 @@ public: DataValue[i] = bvalue->value; // Value as double in SI unit DataValid[i] = bvalue->valid; DataText[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places - DataUnits[i] = formatValue(bvalue, *commonData).unit; + DataUnit[i] = formatValue(bvalue, *commonData).unit; DataFormat[i] = bvalue->getFormat(); // Unit of value } @@ -80,15 +91,16 @@ public: getdisplay().setTextColor(commonData->fgcolor); for (int i = 0; i < (HowManyValues / 2); i++) { - if (i < (HowManyValues / 2) - 1) { // Don't draw horizontal line after last line of values -> standard design - // Horizontal line 3 pix + if (i < (HowManyValues / 2) - 1) { // Don't draw horizontal line after last line of values + // Horizontal line 3 px getdisplay().fillRect(0, SixValues_y1 + (i + 1) * SixValues_DeltaY, 400, 3, commonData->fgcolor); } + for (int j = 0; j < 2; j++) { int ValueIndex = i * 2 + j; int x0 = SixValues_x1 + j * SixValues_DeltaX; int y0 = SixValues_y1 + i * SixValues_DeltaY; - LOG_DEBUG(GwLog::LOG, "Drawing at PageSixValue: %d %s %f %s", ValueIndex, DataName[ValueIndex], DataValue[ValueIndex], DataFormat[ValueIndex]); + LOG_DEBUG(GwLog::DEBUG, "Drawing at PageSixValue: %d %s %f %s %s", ValueIndex, DataName[ValueIndex], DataValue[ValueIndex], DataUnit[ValueIndex], DataFormat[ValueIndex]); // Show name getdisplay().setFont(&Ubuntu_Bold12pt8b); @@ -97,44 +109,38 @@ public: // Show unit getdisplay().setFont(&Ubuntu_Bold8pt8b); - if (holdvalues == false) { - drawTextRalign(x0 + 187, y0 + 19, DataUnits[ValueIndex]); // Unit + if (holdValues == false) { + drawTextRalign(x0 + 187, y0 + 19, DataUnit[ValueIndex]); // Unit } else { - drawTextRalign(x0 + 187, y0 + 19, OldDataUnits[ValueIndex]); + drawTextRalign(x0 + 187, y0 + 19, OldDataUnit[ValueIndex]); } - // Switch font depending on data type + // Set font size depending on data type if (DataFormat[ValueIndex] == "formatLatitude" || DataFormat[ValueIndex] == "formatLongitude") { - getdisplay().setFont(&Ubuntu_Bold12pt8b); + DsegFontSize = 12; } else if (DataFormat[ValueIndex] == "formatTime" || DataFormat[ValueIndex] == "formatDate") { - getdisplay().setFont(&Ubuntu_Bold16pt8b); + DsegFontSize = 16; } - // pressure in hPa - else if (DataFormat[ValueIndex] == "formatXdr:P:P") { - getdisplay().setFont(&DSEG7Classic_BoldItalic26pt7b); - } - // RPM - else if (DataFormat[ValueIndex] == "formatXdr:T:R") { - getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b); + else if (DataFormat[ValueIndex] == "formatXdr:T:R") { // RPM + DsegFontSize = 20; } else { - getdisplay().setFont(&DSEG7Classic_BoldItalic26pt7b); + DsegFontSize = 26; } - // Show bus data - if (holdvalues == false) { -// drawTextRalign(x0 + 187, y0 + 79, DataText[ValueIndex], true); // Real value as formatted string - printDecimalRightAlign(x0 + 187, y0 + 79, DataText[ValueIndex], &DSEG7Classic_BoldItalic26pt7b, &DSEG7Classic_BoldItalic20pt7b); // Real value as formatted string + // Show bus data value + if (holdValues == false) { + printBoatValue(DataText[ValueIndex], x0 + 187, y0 + 79, RIGHT, DsegFontSize, smallDecimals); } else { -// drawTextRalign(x0 + 187, y0 + 79, OldDataText[ValueIndex], true); // Old value as formatted string - printDecimalRightAlign(x0 + 187, y0 + 79, OldDataText[ValueIndex], &DSEG7Classic_BoldItalic26pt7b, &DSEG7Classic_BoldItalic20pt7b); // Real value as formatted string + printBoatValue(OldDataText[ValueIndex], x0 + 187, y0 + 79, RIGHT, DsegFontSize, smallDecimals); } + if (DataValid[ValueIndex] == true) { OldDataText[ValueIndex] = DataText[ValueIndex]; // Save the old value - OldDataUnits[ValueIndex] = DataUnits[ValueIndex]; // Save the old unit + OldDataUnit[ValueIndex] = DataUnit[ValueIndex]; // Save the old unit } } - // Vertical line 3 pix + // Vertical line 3 px getdisplay().fillRect(SixValues_x1 + SixValues_DeltaX - 8, SixValues_y1 + i * SixValues_DeltaY, 3, SixValues_DeltaY, commonData->fgcolor); } diff --git a/lib/obp60task/config_obp40.json b/lib/obp60task/config_obp40.json index e73f545..af535af 100644 --- a/lib/obp60task/config_obp40.json +++ b/lib/obp60task/config_obp40.json @@ -1355,10 +1355,10 @@ }, { "name": "valueprecision", - "label": "Display value precision", + "label": "Value precision", "type": "list", "default": "2", - "description": "Maximum number of decimal places to display [1|2]", + "description": "Number of decimal precision on display: [1|2] decimals", "list": [ "1", "2" @@ -1368,6 +1368,17 @@ "obp40":"true" } }, + { + "name": "smallDecimals", + "label": "Display small decimals", + "type": "boolean", + "default": "true", + "description": "Show decimals of values in smaller size [on|off]", + "category": "OBP40 Display", + "capabilities": { + "obp40": "true" + } + }, { "name": "backlight", "label": "Backlight Mode", diff --git a/lib/obp60task/config_obp60.json b/lib/obp60task/config_obp60.json index fdf48d9..653cd6d 100644 --- a/lib/obp60task/config_obp60.json +++ b/lib/obp60task/config_obp60.json @@ -1344,10 +1344,10 @@ }, { "name": "valueprecision", - "label": "Display value precision", + "label": "Value precision", "type": "list", "default": "2", - "description": "Maximum number of decimal places to display [1|2]", + "description": "Number of decimal precision on display: [1|2] decimals", "list": [ "1", "2" @@ -1357,6 +1357,17 @@ "obp60":"true" } }, + { + "name": "smallDecimals", + "label": "Display small decimals", + "type": "boolean", + "default": "true", + "description": "Show decimals of values in smaller size [on|off]", + "category": "OBP60 Display", + "capabilities": { + "obp60": "true" + } + }, { "name": "backlight", "label": "Backlight Mode", diff --git a/lib/obp60task/config_obp70.json b/lib/obp60task/config_obp70.json index 3fd704a..ffb3d88 100644 --- a/lib/obp60task/config_obp70.json +++ b/lib/obp60task/config_obp70.json @@ -1298,10 +1298,10 @@ }, { "name": "valueprecision", - "label": "Display value precision", + "label": "Value precision", "type": "list", "default": "2", - "description": "Maximum number of decimal places to display [1|2]", + "description": "Number of decimal precision on display: [1|2] decimals", "list": [ "1", "2" @@ -1311,6 +1311,17 @@ "obp70":"true" } }, + { + "name": "smallDecimals", + "label": "Display small decimals", + "type": "boolean", + "default": "true", + "description": "Show decimals of values in smaller size [on|off]", + "category": "OBP70 Display", + "capabilities": { + "obp70": "true" + } + }, { "name": "backlight", "label": "Backlight Mode",