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

#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;
};