-
-
Notifications
You must be signed in to change notification settings - Fork 849
Expand file tree
/
Copy pathDisplayDriver.h
More file actions
156 lines (144 loc) · 4.85 KB
/
DisplayDriver.h
File metadata and controls
156 lines (144 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#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;
};