-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSSVXYMatrixText.cpp
More file actions
414 lines (353 loc) · 13.8 KB
/
SSVXYMatrixText.cpp
File metadata and controls
414 lines (353 loc) · 13.8 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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
#include "SSVXYMatrixText.h"
//
// By Serge Skorodinsky, 03/21/2020
//
boolean UTF8Itterator(String* S, uint8_t &index, uint16_t &UTF8)
{
//Scan for valid english (one byte) or russian (two bytes) letter in UTF8 String S, starting from index.
//If found - return TRUE, found letter returned in UTF8, post-foind index returtned in index.
//Optimized to use in while-loop.
if (!(S)) return false; //S not initialized
if (index >= S->length()) return false; //no more characters
UTF8 = S->charAt(index);
if (UTF8 <= 0x7F)
{//english letters
index++;
return true;
}
if ((UTF8 == 0xD0) || (UTF8 == 0xD1))
{//two bytes, russian letters
index++;
if (index >= S->length()) return false; //no more characters
UTF8 = UTF8<<8;
UTF8 = UTF8 + S->charAt(index);
index++;
return true;
}
return false; //two or more bytes, not russian
}
//XYMatrixText Class
XYMatrixText::XYMatrixText(XYMatrix* MatrixCanvas)
{
_matrixCanvas = MatrixCanvas;
_s = NULL;
_charSpace = 0;
//_left_right_swap = false; //is really needed?
//_top_bottom_swap = false; //is really needed?
_charFlip = Flip_None;
_charRotation = Rotate_None;
_stringDir = Dir_LeftToRight;
_font_char_width = 5; //char width, depends on font
_font_char_height = 8; //char height, depends on font
//background
_UpdateBackground = false;
_BackgroundColor = CRGB(10, 10, 10); //almost black
}
void XYMatrixText::setString(String* S)
{
_s = S;
}
uint16_t XYMatrixText::getStringWidthPx()
{
if (!(_s)) return 0;
if (_s->length() == 0) return 0;
uint8_t realUTF8length=0; //UTF8 letter counter
uint8_t index=0; //passed by ref., not used here but required by itterator
uint16_t UTF8=0; //passed by ref., not used here but required by itterator
while ( UTF8Itterator(_s, index, UTF8) ) { realUTF8length++; }
return (realUTF8length * (_font_char_width +_charSpace) -_charSpace);
}
uint16_t XYMatrixText::getStringHeightPx()
{
return _font_char_height;
}
void XYMatrixText::drawString(String* S, int16_t offsetX, int16_t offsetY, CRGB letterColor) //drawString() with String parameter
{
setString(S);
drawString(offsetX, offsetY, letterColor);
}
//positioning, offsets.
//To use these functions BEFORE draw the string - you MUST to use setString(String* S).
//If it is not important - you can use drawString(String* S, ...) function
boolean XYMatrixText::IsStringWidthFit()
{
return (_matrixCanvas->getMatrixWidth() >= getStringWidthPx());
}
boolean XYMatrixText::IsStringHeightFit()
{
return (_matrixCanvas->getMatrixHeight() >= getStringHeightPx());
}
//positioning "just hide"
int16_t XYMatrixText::OffsetX_RightStr_To_LeftArea() //offsetX when right text edge at the left edge of area, text is NOT visible
{
return -getStringWidthPx(); //always negative. -(length*charwidth)+((length-1)*charspace)
}
int16_t XYMatrixText::OffsetX_LeftStr_To_RightArea() //offsetX when left text edge at the right edge of area, text is NOT visible
{
return _matrixCanvas->getMatrixWidth();
}
int16_t XYMatrixText::OffsetY_TopStr_To_BottomArea() //offsetY when top text edge at the bottom edge of the area, text is NOT visible
{
return -getStringHeightPx(); //always negative
}
int16_t XYMatrixText::OffsetY_BottomStr_To_TopArea() //offsetY when top text edge at the bottom edge of the area, text is NOT visible
{
return _matrixCanvas->getMatrixHeight();
}
//positioning "max visibility"
int16_t XYMatrixText::OffsetX_LeftStr_To_LeftArea() //offsetX when left text edge at the left edge of area, text is max visible
{
return 0;
}
int16_t XYMatrixText::OffsetX_RightStr_To_RightArea() //offsetX when right text edge at the right edge of area, text is max visible
{
int16_t res = _matrixCanvas->getMatrixWidth() - getStringWidthPx(); //positive, if matrix wider than string
return res;
}
int16_t XYMatrixText::OffsetY_BottomStr_To_BottomArea() //offsetY when bottom text edge at the bottom edge of area, text is max visible
{
int16_t res = _matrixCanvas->getMatrixHeight() - getStringHeightPx() + 1; //negative, if string is higher than matrix
if (res>0) res=0; //.. or zero
return res;
}
int16_t XYMatrixText::OffsetY_TopStr_To_TopArea() //offsetY when top text edge at the top edge of area, text is max visible
{
int16_t res = _matrixCanvas->getMatrixHeight() - getStringHeightPx(); //positive, if matrix higher than string
if (res<0) res=0; //.. or zero
return res;
}
//positioning "center", if string is bigger (wider or higher) - beginning and ending of string will be out of matrix
int16_t XYMatrixText::OffsetX_Center() //center offsetX when ...
{
return (_matrixCanvas->getMatrixWidth() - getStringWidthPx()) / 2;
}
int16_t XYMatrixText::OffsetY_Center() //center offsetY when ...
{
return (_matrixCanvas->getMatrixHeight() - getStringHeightPx()) / 2;
}
//RUSSIAN UTF8
uint8_t XYMatrixText::getFontIndex(uint16_t UTF8) //returns index in font
{
switch(UTF8)
{
case 0 ... 31: //control bytes, replaced with <space>
return 0;
break;
case 32 ... 127: //english letters ans signes ' '...'⌂', index 0...95
return UTF8-32;
break;
case 0xD090 ... 0xD0BF: //russian letetrs А...п, index 96(0x60)..143(0x8F)
return UTF8-0xD030;
break;
case 0xD180 ... 0xD18F: //russian letetrs р...я, index 144(0x90)..159(9F)
return UTF8-0xD0F0;
break;
default:
return 0xFF; //to indicate error
break;
}
}
uint8_t XYMatrixText::getLetterColumn(uint16_t UTF8, uint8_t column) //font column 0..4, from left to right
{
//check out-of-limits conditions for both parameters?
if (column >= _font_char_width) return 0xAA; //to indicate error
uint8_t index = getFontIndex(UTF8);
if (index == 0xFF) return 0x55; //to indicate error
return pgm_read_byte(&(fontHEX[index] [column]));
}
/*
//not used yet
uint8_t XYMatrixText::getLetterRow(uint16_t UTF8, uint8_t row) //font row 0..7, from bottom to top, returns 5 significant bits
{
if (row >= _font_char_height) return 0x0A; //to indicate error, 5 bits
uint8_t index = getFontIndex(UTF8);
if (index == 0xFF) return 0x15; //to indicate error, 5 bits
uint8_t rowMask = (1<<row);
uint8_t res=0;
for (uint8_t i=0; i<_font_char_width; i++)
{
uint8_t b = pgm_read_byte(&(fontHEX[index] [i])); //read byte from font
res = (res<<1); //shift left
if ((b & rowMask) != 0) {res |= 0x01;} // lowest bit to "1"
}
return res;
}
*/
//make similar function, but to blend color of font top color of background.
void XYMatrixText::drawChar(uint16_t UTF8, int16_t offsetX, int16_t offsetY, CRGB letterColor)
{
switch(_charRotation)
{
case Rotate_None:
drawChar_Vert(UTF8, offsetX, offsetY, letterColor, (_charFlip == Flip_Hor), (_charFlip == Flip_Vert) );
break;
case Rotate_CW90:
drawChar_Hor(UTF8, offsetX, offsetY, letterColor, (_charFlip == Flip_Hor), (_charFlip == Flip_Vert) );
break;
case Rotate_CCW90:
drawChar_Hor(UTF8, offsetX, offsetY, letterColor, (_charFlip != Flip_Hor), (_charFlip != Flip_Vert) );
break;
case Rotate_180:
drawChar_Vert(UTF8, offsetX, offsetY, letterColor, (_charFlip != Flip_Hor), (_charFlip != Flip_Vert) );
break;
default: return;
}
}
void XYMatrixText::drawChar_Hor(uint16_t UTF8, int16_t offsetX, int16_t offsetY, CRGB letterColor, boolean swapLeftRight, boolean swapTopBottom)
{
// int8_t XMinPos;
// int8_t XMaxPos;
int8_t YMinPos;
int8_t YMaxPos;
// if (offsetX < -_font_char_width || offsetX > _matrixCanvas->getMatrixWidth()) return; //out of area, nothing to draw
if (offsetY < -_font_char_width || offsetY > _matrixCanvas->getMatrixWidth()) return; //out of area, nothing to draw
// if (offsetX < 0) XMinPos = -offsetX; else XMinPos = 0;
if (offsetY < 0) YMinPos = -offsetY; else YMinPos = 0;
// if (offsetX > (_matrixCanvas->getMatrixWidth()-_font_char_width))
// XMaxPos = _matrixCanvas->getMatrixWidth()-offsetX;
// else XMaxPos = _font_char_width;
if (offsetY > (_matrixCanvas->getMatrixWidth()-_font_char_width))
YMaxPos = _matrixCanvas->getMatrixWidth()-offsetX;
else YMaxPos = _font_char_width;
for (byte y = YMinPos; y < YMaxPos; y++)
{
int thisByte;
if (swapLeftRight)
thisByte = getLetterColumn(UTF8, y); //NO flip
else thisByte = getLetterColumn(UTF8, _font_char_width-1-y); //flip
for (byte x = 0; x < _font_char_height; x++)
{
boolean thisBit;
if (swapTopBottom)
thisBit = thisByte & (1<<x); //not flip
else thisBit = thisByte & (1<<(_font_char_height-1-x)); //flip
//draw Column
if (thisBit) _matrixCanvas->setPixelColor(offsetX+x, offsetY+y, letterColor);
else
if (_UpdateBackground) _matrixCanvas->setPixelColor(offsetX+x, offsetY+y, _BackgroundColor); // background
}
}
}
void XYMatrixText::drawChar_Vert(uint16_t UTF8, int16_t offsetX, int16_t offsetY, CRGB letterColor, boolean swapLeftRight, boolean swapTopBottom)
{
int8_t XMinPos;
int8_t XMaxPos;
if (offsetX < -_font_char_width || offsetX > _matrixCanvas->getMatrixWidth()) return; //out of area, nothing to draw
if (offsetX < 0) XMinPos = -offsetX; else XMinPos = 0;
if (offsetX > (_matrixCanvas->getMatrixWidth()-_font_char_width))
XMaxPos = _matrixCanvas->getMatrixWidth()-offsetX;
else XMaxPos = _font_char_width;
for (byte x = XMinPos; x < XMaxPos; x++)
{
int thisByte;
if (swapLeftRight)
thisByte = getLetterColumn(UTF8, _font_char_width-1-x); //not flip
else thisByte = getLetterColumn(UTF8, x); //flip
for (byte y = 0; y < _font_char_height; y++)
{
boolean thisBit;
if (swapTopBottom)
thisBit = thisByte & (1<<y); //not flip
else thisBit = thisByte & (1<<(_font_char_height-1-y)); //flip
//draw Column
if (thisBit) _matrixCanvas->setPixelColor(offsetX+x, offsetY+y, letterColor);
else
if (_UpdateBackground) _matrixCanvas->setPixelColor(offsetX+x, offsetY+y, _BackgroundColor); // background
}
}
}
void XYMatrixText::drawString(int16_t offsetX, int16_t offsetY, CRGB letterColor)
{
uint8_t charCnt=0; //UTF8 letter counter
uint8_t index=0; //passed by ref.
uint16_t UTF8=0; //passed by ref.
//starting position
int16_t xpos=offsetX; //accumulator for X position, start position
int16_t ypos=offsetY; //accumulator for Y position, start position
//"change position" logic...
boolean char_v = ((_charRotation == Rotate_None) || (_charRotation == Rotate_180)); //true if char is vertical, false if horisontal
boolean string_v = ((_stringDir == Dir_LeftToRight) || (_stringDir == Dir_RightToLeft)); //true if string is vertical, false if horisontal
int16_t IncrementPos;
if (char_v == string_v) IncrementPos = (_font_char_width +_charSpace);
else IncrementPos = (_font_char_height +_charSpace);
if ((_stringDir == Dir_RightToLeft) || (_stringDir == Dir_TopToBottom))
{
IncrementPos = - IncrementPos; //negative
//correcting starting position
if (string_v) xpos = xpos + IncrementPos +1 +_charSpace; //decrease, with no space
else ypos = ypos + IncrementPos +1 +_charSpace; //decrease, with no space
}
//end of "change position" logic...
//main loop
while ( UTF8Itterator(_s, index, UTF8) )
{
if (xpos > _matrixCanvas->getMatrixWidth()) break; //gets out of range, already too right, never go back
drawChar(UTF8, xpos, ypos, letterColor);
//fillout Spaces, if needed
if ( (_UpdateBackground) && (_charSpace>0) )
{
if (charCnt>0)
{
int16_t x0;
int16_t y0;
int16_t x1;
int16_t y1;
int16_t delta1;
int16_t delta2;
if (char_v == string_v)
{
delta1 = _font_char_width;
delta2 = _font_char_height-1;
}
else
{
delta1 = _font_char_height;
delta2 = _font_char_width-1;
}
switch (_stringDir)
{
case Dir_LeftToRight: x0=xpos-_charSpace; y0=ypos; x1=x0+_charSpace-1; y1=y0+delta2; break;
case Dir_RightToLeft: x0=xpos+delta1; y0=ypos; x1=x0+_charSpace-1; y1=y0+delta2; break;
case Dir_TopToBottom: x0=xpos; y0=ypos+delta1; x1=x0+delta2; y1=y0+_charSpace-1; break;
case Dir_BottomToTop: x0=xpos; y0=ypos-_charSpace; x1=x0+delta2; y1=y0+_charSpace-1; break;
default: break;
}
_matrixCanvas->draw_fillrect(x0, y0, x1, y1, _BackgroundColor);
}
}
charCnt++;
//change position.
if (string_v) xpos = xpos + IncrementPos;
else ypos = ypos + IncrementPos;
}
}
//char flips
TCharFlip XYMatrixText::getCharFlip()
{return _charFlip;}
void XYMatrixText::setCharFlip(TCharFlip CharFlip)
{_charFlip = CharFlip;}
//char rotation
TCharRotation XYMatrixText::getCharRotation()
{return _charRotation;}
void XYMatrixText::setCharRotation(TCharRotation CharRotation)
{_charRotation = CharRotation;}
//Sting Direction
TStringDirection XYMatrixText::getStringDir()
{return _stringDir;}
void XYMatrixText::setStringDir(TStringDirection StringDir)
{_stringDir = StringDir;}
//background color
boolean XYMatrixText::getUpdateBackground()
{return _UpdateBackground;}
void XYMatrixText::setUpdateBackground(boolean UpdateBackground)
{_UpdateBackground = UpdateBackground;}
CRGB XYMatrixText::getBackgroundColor()
{return _BackgroundColor;}
void XYMatrixText::setBackgroundColor(CRGB Color)
{_BackgroundColor = Color;}
//char space
uint8_t XYMatrixText::getCharSpace()
{return _charSpace;}
void XYMatrixText::setCharSpace(uint8_t charSpace)
{_charSpace = charSpace;}
//End of XYMatrixText Class