mirror of https://github.com/meshcore-dev/MeshCore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
4.9 KiB
156 lines
4.9 KiB
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
class DisplayDriver {
|
|
int _w, _h;
|
|
protected:
|
|
DisplayDriver(int w, int h) { _w = w; _h = h; }
|
|
public:
|
|
enum Color { DARK=0, LIGHT, RED, GREEN, BLUE, YELLOW, ORANGE }; // on b/w screen, colors will be !=0 synonym of light
|
|
|
|
int width() const { return _w; }
|
|
int height() const { return _h; }
|
|
|
|
virtual bool isOn() = 0;
|
|
virtual void turnOn() = 0;
|
|
virtual void turnOff() = 0;
|
|
virtual void clear() = 0;
|
|
virtual void startFrame(Color bkg = DARK) = 0;
|
|
virtual void setTextSize(int sz) = 0;
|
|
virtual void setColor(Color c) = 0;
|
|
virtual void setCursor(int x, int y) = 0;
|
|
virtual void print(const char* str) = 0;
|
|
virtual void printWordWrap(const char* str, int max_width) { print(str); } // fallback to basic print() if no override
|
|
virtual void fillRect(int x, int y, int w, int h) = 0;
|
|
virtual void drawRect(int x, int y, int w, int h) = 0;
|
|
virtual void drawXbm(int x, int y, const uint8_t* bits, int w, int h) = 0;
|
|
virtual uint16_t getTextWidth(const char* str) = 0;
|
|
virtual void drawTextCentered(int mid_x, int y, const char* str) { // helper method (override to optimise)
|
|
int w = getTextWidth(str);
|
|
setCursor(mid_x - w/2, y);
|
|
print(str);
|
|
}
|
|
virtual void drawTextRightAlign(int x_anch, int y, const char* str) {
|
|
int w = getTextWidth(str);
|
|
setCursor(x_anch - w, y);
|
|
print(str);
|
|
}
|
|
virtual void drawTextLeftAlign(int x_anch, int y, const char* str) {
|
|
setCursor(x_anch, y);
|
|
print(str);
|
|
}
|
|
|
|
// convert UTF-8 characters to displayable block characters for compatibility
|
|
virtual void translateUTF8ToBlocks(char* dest, const char* src, size_t dest_size) {
|
|
size_t j = 0;
|
|
#ifdef OLED_RU
|
|
char last_char = 0;
|
|
char cc = 0;
|
|
#endif
|
|
for (size_t i = 0; src[i] != 0 && j < dest_size - 1; i++) {
|
|
unsigned char c = (unsigned char)src[i];
|
|
if (c >= 32 && c <= 126) {
|
|
#ifdef OLED_RU
|
|
last_char = 0;
|
|
dest[j++] = c; // ASCII printable
|
|
} else if (last_char == 0 && (c == 0xD0 || c == 0xD1 || c == 0xD2)) { // Cyrillic UTF-8 start byte for 2 bytes sequence
|
|
last_char = c;
|
|
} else if (last_char > 0) { // Cyrillic UTF-8 next byte
|
|
cc = 0; // Translated charcode
|
|
switch (last_char) {
|
|
// map UTF-8 cyrillic chars to it CP-1251 ASCII codes
|
|
case 0xD0: {
|
|
if (c == 132)
|
|
cc = (170); // Є
|
|
if (c == 134)
|
|
cc = (178); // І
|
|
if (c == 135)
|
|
cc = (175); // Ї
|
|
if (c == 129)
|
|
cc = (168); // Ё
|
|
if (c > 143 && c < 192)
|
|
cc = (c + 48);
|
|
break;
|
|
}
|
|
case 0xD1: {
|
|
if (c == 148)
|
|
cc = (186); // є
|
|
if (c == 150)
|
|
cc = (179); // і
|
|
if (c == 151)
|
|
cc = (191); // ї
|
|
if (c == 145)
|
|
cc = (184); // ё
|
|
if (c > 127 && c < 144)
|
|
cc = (c + 112);
|
|
break;
|
|
}
|
|
case 0xD2: {
|
|
if (c == 144)
|
|
cc = (165); // Ґ
|
|
if (c == 145)
|
|
cc = (180); // ґ
|
|
break;
|
|
}
|
|
}
|
|
if (cc > 0) {
|
|
dest[j++] = cc;
|
|
}
|
|
last_char = 0;
|
|
} else if (c >= 0x80) {
|
|
last_char = 0;
|
|
dest[j++] = '\xAE'; // CP1251 smile emoji replace
|
|
#else
|
|
dest[j++] = c; // ASCII printable
|
|
} else if (c >= 0x80) {
|
|
dest[j++] = '\xDB'; // CP437 full block █
|
|
#endif
|
|
while (src[i+1] && (src[i+1] & 0xC0) == 0x80)
|
|
i++; // skip UTF-8 continuation bytes
|
|
}
|
|
}
|
|
dest[j] = 0;
|
|
}
|
|
|
|
// draw text with ellipsis if it exceeds max_width
|
|
virtual void drawTextEllipsized(int x, int y, int max_width, const char* str) {
|
|
char temp_str[256]; // reasonable buffer size
|
|
size_t len = strlen(str);
|
|
if (len >= sizeof(temp_str)) len = sizeof(temp_str) - 1;
|
|
memcpy(temp_str, str, len);
|
|
temp_str[len] = 0;
|
|
|
|
if (getTextWidth(temp_str) <= max_width) {
|
|
setCursor(x, y);
|
|
print(temp_str);
|
|
return;
|
|
}
|
|
|
|
// for variable-width fonts (GxEPD), add space after ellipsis
|
|
// for fixed-width fonts (OLED), keep tight spacing to save precious characters
|
|
const char* ellipsis;
|
|
// use a simple heuristic: if 'i' and 'l' have different widths, it's variable-width
|
|
int i_width = getTextWidth("i");
|
|
int l_width = getTextWidth("l");
|
|
if (i_width != l_width) {
|
|
ellipsis = "... "; // variable-width fonts: add space
|
|
} else {
|
|
ellipsis = "..."; // fixed-width fonts: no space
|
|
}
|
|
|
|
int ellipsis_width = getTextWidth(ellipsis);
|
|
int str_len = strlen(temp_str);
|
|
|
|
while (str_len > 0 && getTextWidth(temp_str) > max_width - ellipsis_width) {
|
|
temp_str[--str_len] = 0;
|
|
}
|
|
strcat(temp_str, ellipsis);
|
|
|
|
setCursor(x, y);
|
|
print(temp_str);
|
|
}
|
|
|
|
virtual void endFrame() = 0;
|
|
};
|
|
|