LCDGFX LCD display driver  1.0.5
This library is developed to control SSD1306/SSD1325/SSD1327/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays
ssd1306_common.inl
1 /*
2  MIT License
3 
4  Copyright (c) 2016-2020, Alexey Dynda
5 
6  Permission is hereby granted, free of charge, to any person obtaining a copy
7  of this software and associated documentation files (the "Software"), to deal
8  in the Software without restriction, including without limitation the rights
9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  copies of the Software, and to permit persons to whom the Software is
11  furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in all
14  copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  SOFTWARE.
23 */
24 
28 
29 #include "lcd_hal/io.h"
30 #include <stdio.h>
31 
32 #if 0
33 
34 uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
35 {
36  uint8_t i, j=0;
37  uint8_t text_index = 0;
38  uint8_t page_offset = 0;
39  uint8_t x = xpos;
40  y >>= 3;
41  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
42  for(;;)
43  {
44  uint8_t ldata;
45  if ( (x > ssd1306_lcd.width - s_fixedFont.h.width) || (ch[j] == '\0') )
46  {
47  x = xpos;
48  y++;
49  if (y >= (ssd1306_lcd.height >> 3))
50  {
51  break;
52  }
53  page_offset++;
54  if (page_offset == s_fixedFont.pages)
55  {
56  text_index = j;
57  page_offset = 0;
58  if (ch[j] == '\0')
59  {
60  break;
61  }
62  }
63  else
64  {
65  j = text_index;
66  }
67  ssd1306_intf.stop();
68  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
69  }
70  uint16_t unicode;
71  do
72  {
73  unicode = ssd1306_unicode16FromUtf8(ch[j]);
74  j++;
75  } while ( unicode == SSD1306_MORE_CHARS_REQUIRED );
76  SCharInfo char_info;
77  ssd1306_getCharBitmap(unicode, &char_info);
78  ldata = 0;
79  x += char_info.width + char_info.spacing;
80  if (char_info.height > page_offset * 8)
81  {
82  char_info.glyph += page_offset * char_info.width;
83  for( i = char_info.width; i>0; i--)
84  {
85  uint8_t data;
86  if ( style == STYLE_NORMAL )
87  {
88  data = pgm_read_byte(&char_info.glyph[0]);
89  }
90  else if ( style == STYLE_BOLD )
91  {
92  uint8_t temp = pgm_read_byte(&char_info.glyph[0]);
93  data = temp | ldata;
94  ldata = temp;
95  }
96  else
97  {
98  uint8_t temp = pgm_read_byte(&char_info.glyph[1]);
99  data = (temp & 0xF0) | ldata;
100  ldata = (temp & 0x0F);
101  }
102  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
103  char_info.glyph++;
104  }
105  }
106  else
107  {
108  char_info.spacing += char_info.width;
109  }
110  for (i = 0; i < char_info.spacing; i++)
111  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
112  }
113  ssd1306_intf.stop();
114  return j;
115 }
116 
117 uint8_t ssd1306_printFixed_oldStyle(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
118 {
119  uint8_t i, j=0;
120  uint8_t text_index = 0;
121  uint8_t page_offset = 0;
122  uint8_t x = xpos;
123  y >>= 3;
124  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
125  for(;;)
126  {
127  uint8_t c;
128  uint8_t ldata;
129  uint16_t offset;
130  if( (x > ssd1306_lcd.width - s_fixedFont.h.width) || (ch[j] == '\0') )
131  {
132  x = xpos;
133  y++;
134  if (y >= (ssd1306_lcd.height >> 3))
135  {
136  break;
137  }
138  page_offset++;
139  if (page_offset == s_fixedFont.pages)
140  {
141  text_index = j;
142  page_offset = 0;
143  if (ch[j] == '\0')
144  {
145  break;
146  }
147  }
148  else
149  {
150  j = text_index;
151  }
152  ssd1306_intf.stop();
153  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
154  }
155  c = ch[j];
156  if ( c >= s_fixedFont.h.ascii_offset )
157  {
158  c -= s_fixedFont.h.ascii_offset;
159  }
160  ldata = 0;
161  offset = (c * s_fixedFont.pages + page_offset) * s_fixedFont.h.width;
162  for( i=s_fixedFont.h.width; i>0; i--)
163  {
164  uint8_t data;
165  if ( style == STYLE_NORMAL )
166  {
167  data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
168  }
169  else if ( style == STYLE_BOLD )
170  {
171  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset]);
172  data = temp | ldata;
173  ldata = temp;
174  }
175  else
176  {
177  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset + 1]);
178  data = (temp & 0xF0) | ldata;
179  ldata = (temp & 0x0F);
180  }
181  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
182  offset++;
183  }
184  x += s_fixedFont.h.width;
185  j++;
186  }
187  ssd1306_intf.stop();
188  return j;
189 }
190 
191 uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
192 {
193  uint8_t i, j=0;
194  uint8_t text_index = 0;
195  uint8_t page_offset = 0;
196  uint8_t x = xpos;
197  y >>= 3;
198  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
199  for(;;)
200  {
201  uint8_t c;
202  uint8_t ldata;
203  uint16_t offset;
204  if( (x > ssd1306_lcd.width - (s_fixedFont.h.width << 1)) || (ch[j] == '\0') )
205  {
206  x = xpos;
207  y++;
208  if (y >= (ssd1306_lcd.height >> 3))
209  {
210  break;
211  }
212  page_offset++;
213  if (page_offset == (s_fixedFont.pages << 1))
214  {
215  text_index = j;
216  page_offset = 0;
217  if (ch[j] == '\0')
218  {
219  break;
220  }
221  }
222  else
223  {
224  j = text_index;
225  }
226  ssd1306_intf.stop();
227  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
228  }
229  c = ch[j];
230  if ( c >= 32 )
231  {
232  c -= 32;
233  }
234  ldata = 0;
235  offset = (c * s_fixedFont.pages + (page_offset >> 1)) * s_fixedFont.h.width;
236  for( i=s_fixedFont.h.width; i>0; i--)
237  {
238  uint8_t data;
239  if ( style == STYLE_NORMAL )
240  {
241  data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
242  }
243  else if ( style == STYLE_BOLD )
244  {
245  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset]);
246  data = temp | ldata;
247  ldata = temp;
248  }
249  else
250  {
251  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset + 1]);
252  data = (temp & 0xF0) | ldata;
253  ldata = (temp & 0x0F);
254  }
255  if (page_offset & 1) data >>= 4;
256  data = ((data & 0x01) ? 0x03: 0x00) |
257  ((data & 0x02) ? 0x0C: 0x00) |
258  ((data & 0x04) ? 0x30: 0x00) |
259  ((data & 0x08) ? 0xC0: 0x00);
260  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
261  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
262  offset++;
263  }
264  x += (s_fixedFont.h.width << 1);
265  j++;
266  }
267  ssd1306_intf.stop();
268  return j;
269 }
270 
271 
272 uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor)
273 {
274  uint8_t i, j=0;
275  uint8_t text_index = 0;
276  uint8_t page_offset = 0;
277  uint8_t x = xpos;
278  y >>= 3;
279  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
280  for(;;)
281  {
282  uint8_t ldata;
283  if( (x > ssd1306_lcd.width - (s_fixedFont.h.width << factor)) || (ch[j] == '\0') )
284  {
285  x = xpos;
286  y++;
287  if (y >= (ssd1306_lcd.height >> 3))
288  {
289  break;
290  }
291  page_offset++;
292  if (page_offset == (s_fixedFont.pages << factor))
293  {
294  text_index = j;
295  page_offset = 0;
296  if (ch[j] == '\0')
297  {
298  break;
299  }
300  }
301  else
302  {
303  j = text_index;
304  }
305  ssd1306_intf.stop();
306  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
307  }
308  uint16_t unicode;
309  do
310  {
311  unicode = ssd1306_unicode16FromUtf8(ch[j]);
312  j++;
313  } while ( unicode == SSD1306_MORE_CHARS_REQUIRED );
314  SCharInfo char_info;
315  ssd1306_getCharBitmap(unicode, &char_info);
316  ldata = 0;
317  x += ((char_info.width + char_info.spacing) << factor);
318  if (char_info.height > (page_offset >> factor) * 8)
319  {
320  char_info.glyph += (page_offset >> factor) * char_info.width;
321  for( i=char_info.width; i>0; i--)
322  {
323  uint8_t data;
324  if ( style == STYLE_NORMAL )
325  {
326  data = pgm_read_byte(char_info.glyph);
327  }
328  else if ( style == STYLE_BOLD )
329  {
330  uint8_t temp = pgm_read_byte(char_info.glyph);
331  data = temp | ldata;
332  ldata = temp;
333  }
334  else
335  {
336  uint8_t temp = pgm_read_byte(char_info.glyph+1);
337  data = (temp & 0xF0) | ldata;
338  ldata = (temp & 0x0F);
339  }
340  if ( factor > 0 )
341  {
342  uint8_t accum = 0;
343  uint8_t mask = ~((0xFF) << (1<<factor));
344  // N=0 -> right shift is always 0
345  // N=1 -> right shift goes through 0, 4
346  // N=2 -> right shift goes through 0, 2, 4, 6
347  // N=3 -> right shift goes through 0, 1, 2, 3, 4, 5, 6, 7
348  data >>= ((page_offset & ((1<<factor) - 1))<<(3-factor));
349  for (uint8_t idx = 0; idx < 1<<(3-factor); idx++)
350  {
351  accum |= (((data>>idx) & 0x01) ? (mask<<(idx<<factor)) : 0);
352  }
353  data = accum;
354  }
355  for (uint8_t z=(1<<factor); z>0; z--)
356  {
357  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
358  }
359  char_info.glyph++;
360  }
361  }
362  else
363  {
364  char_info.spacing += char_info.width;
365  }
366  for (i = 0; i < (char_info.spacing << factor); i++)
367  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
368  }
369  ssd1306_intf.stop();
370  return j;
371 }
372 
373 void ssd1306_putPixel_delayed(uint8_t x, uint8_t y, uint8_t complete)
374 {
375  static uint8_t lx = 0, ly = 0xFF;
376  static uint8_t pixels = 0;
377  if ((lx != x) || ((ly & 0xF8) != (y & 0xF8)) || (complete))
378  {
379  if (ly != 0xFF)
380  {
381  ssd1306_putPixels( lx, ly, pixels );
382  }
383  pixels = 0;
384  ly = 0xFF;
385  }
386  if ( !complete )
387  {
388  pixels |= (1 << (y & 0x07));
389  lx = x; ly = y;
390  }
391 }
392 
393 void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
394 {
395  lcduint_t dx = x1 > x2 ? (x1 - x2): (x2 - x1);
396  lcduint_t dy = y1 > y2 ? (y1 - y2): (y2 - y1);
397  lcduint_t err = 0;
398  if (dy > dx)
399  {
400  if (y1 > y2)
401  {
402  ssd1306_swap_data(x1, x2, uint8_t);
403  ssd1306_swap_data(y1, y2, uint8_t);
404  }
405  for(; y1<=y2; y1++)
406  {
407  err += dx;
408  if (err >= dy)
409  {
410  err -= dy;
411  x1 < x2 ? x1++: x1--;
412  }
413  ssd1306_putPixel_delayed( x1, y1, 0 );
414  }
415  ssd1306_putPixel_delayed( 0, 0, 1 );
416  }
417  else
418  {
419  if (x1 > x2)
420  {
421  ssd1306_swap_data(x1, x2, uint8_t);
422  ssd1306_swap_data(y1, y2, uint8_t);
423  }
424  for(; x1<=x2; x1++)
425  {
426  err += dy;
427  if (err >= dx)
428  {
429  err -= dx;
430  if (y1 < y2) y1++; else y1--;
431  }
432  ssd1306_putPixel( x1, y1 );
433  }
434  }
435 }
436 
437 void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
438 {
439  uint8_t j;
440  ssd1306_lcd.set_block(x, y >> 3, w);
441  for(j=(h >> 3); j>0; j--)
442  {
443  ssd1306_lcd.send_pixels_buffer1(buf,w);
444  buf+=w;
445  ssd1306_lcd.next_page();
446  }
447  ssd1306_intf.stop();
448 }
449 
450 void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
451 {
452  lcduint_t origin_width = w;
453  uint8_t offset = y & 0x07;
454  uint8_t complexFlag = 0;
455  uint8_t mainFlag = 1;
456  uint8_t max_pages;
457  uint8_t pages;
458  lcduint_t i, j;
459  if (y + (lcdint_t)h <= 0) return;
460  if (y >= (lcdint_t)ssd1306_lcd.height) return;
461  if (x + (lcdint_t)w <= 0) return;
462  if (x >= (lcdint_t)ssd1306_lcd.width) return;
463  if (y < 0)
464  {
465  buf += ((lcduint_t)((-y) + 7) >> 3) * w;
466  h += y;
467  y = 0;
468  complexFlag = 1;
469  }
470  if (x < 0)
471  {
472  buf += -x;
473  w += x;
474  x = 0;
475  }
476  max_pages = (lcduint_t)(h + 15 - offset) >> 3;
477  if ((lcduint_t)((lcduint_t)y + h) > (lcduint_t)ssd1306_lcd.height)
478  {
479  h = (lcduint_t)(ssd1306_lcd.height - (lcduint_t)y);
480  }
481  if ((lcduint_t)((lcduint_t)x + w) > (lcduint_t)ssd1306_lcd.width)
482  {
483  w = (lcduint_t)(ssd1306_lcd.width - (lcduint_t)x);
484  }
485  pages = ((y + h - 1) >> 3) - (y >> 3) + 1;
486 
487  ssd1306_lcd.set_block(x, y >> 3, w);
488  for(j=0; j < pages; j++)
489  {
490  if ( j == (lcduint_t)(max_pages - 1) ) mainFlag = !offset;
491  for( i=w; i > 0; i--)
492  {
493  uint8_t data = 0;
494  if ( mainFlag ) data |= (pgm_read_byte(buf) << offset);
495  if ( complexFlag ) data |= (pgm_read_byte(buf - origin_width) >> (8 - offset));
496  buf++;
497  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^data);
498  }
499  buf += origin_width - w;
500  complexFlag = offset;
501  ssd1306_lcd.next_page();
502  }
503  ssd1306_intf.stop();
504 }
505 
506 
507 void ssd1306_setFont6x8(const uint8_t * progmemFont)
508 {
509  s_font6x8 = progmemFont + 4;
510 }
511 
512 #endif
513 
515 //
516 // COMMON GRAPHICS
517 //
519 
520 template <class O, class I>
522 {
523  this->putPixel(p.x, p.y);
524 }
525 
526 template <class O, class I>
528 {
529  this->drawHLine(x1, y1, x2);
530  this->drawHLine(x1, y2, x2);
531  this->drawVLine(x1, y1, y2);
532  this->drawVLine(x2, y1, y2);
533 }
534 
535 template <class O, class I>
537 {
538  this->drawRect(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
539 }
540 
541 template <class O, class I>
543 {
544  lcduint_t dx = x1 > x2 ? (x1 - x2): (x2 - x1);
545  lcduint_t dy = y1 > y2 ? (y1 - y2): (y2 - y1);
546  lcduint_t err = 0;
547  if (dy > dx)
548  {
549  if (y1 > y2)
550  {
551  ssd1306_swap_data(x1, x2, lcdint_t);
552  ssd1306_swap_data(y1, y2, lcdint_t);
553  }
554  for(; y1<=y2; y1++)
555  {
556  err += dx;
557  if (err >= dy)
558  {
559  err -= dy;
560  x1 < x2 ? x1++: x1--;
561  }
562  this->putPixel( x1, y1 );
563  }
564  }
565  else
566  {
567  if (x1 > x2)
568  {
569  ssd1306_swap_data(x1, x2, lcdint_t);
570  ssd1306_swap_data(y1, y2, lcdint_t);
571  }
572  for(; x1<=x2; x1++)
573  {
574  err += dy;
575  if (err >= dx)
576  {
577  err -= dx;
578  if (y1 < y2) y1++; else y1--;
579  }
580  this->putPixel( x1, y1 );
581  }
582  }
583 }
584 
585 template <class O, class I>
587 {
588  this->drawLine(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
589 }
590 
591 template <class O, class I>
593 {
594  this->fillRect(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
595 }
596 
597 template <class O, class I>
599 {
600  this->m_fontStyle = style;
601  this->m_cursorX = xpos;
602  this->m_cursorY = y;
603  for (;;)
604  {
605  char c = pgm_read_byte(ch);
606  if (!c) break;
607  this->write(c);
608  ch++;
609  }
610 }
611 
612 template <class O, class I>
613 void NanoDisplayOps<O,I>::write( const char *str )
614 {
615  while (*str)
616  {
617  this->write(*str);
618  str++;
619  }
620 }
621 
622 template <class O, class I>
623 void NanoDisplayOps<O,I>::print( int number )
624 {
625  char intStr[12];
626  snprintf(intStr, sizeof(intStr), "%i", number );
627  this->write( intStr );
628 }
629 
630 #ifndef min
631 #define min(x,y) ((x)<(y)?(x):(y))
632 #endif
633 
634 #ifndef max
635 #define max(x,y) ((x)>(y)?(x):(y))
636 #endif
637 
638 template <class O, class I>
639 static uint8_t getMaxScreenItems(NanoDisplayOps<O,I> &display, SAppMenu *menu)
640 {
641  return (menu->height - 16) / display.getFont().getHeader().height;
642 }
643 
644 template <class O, class I>
645 static uint8_t calculateScrollPosition(NanoDisplayOps<O,I> &display, SAppMenu *menu, uint8_t selection)
646 {
647  if ( selection < menu->scrollPosition )
648  {
649  return selection;
650  }
651  else if ( selection - menu->scrollPosition > getMaxScreenItems<O,I>(display, menu) - 1)
652  {
653  return selection - getMaxScreenItems<O,I>(display, menu) + 1;
654  }
655  return menu->scrollPosition;
656 }
657 
658 template <class O, class I>
659 static void drawMenuItem(NanoDisplayOps<O,I> &display, SAppMenu *menu, uint8_t index)
660 {
661  if (index == menu->selection)
662  {
663  display.negativeMode();
664  }
665  else
666  {
667  display.positiveMode();
668  }
669  lcdint_t item_top = 8 + menu->top + (index - menu->scrollPosition)*display.getFont().getHeader().height;
670  display.printFixed(menu->left + 8, item_top,
671  menu->items[index], STYLE_NORMAL );
672  display.positiveMode();
673 }
674 
675 template <class O, class I>
676 static void drawMenuItemSmooth(NanoDisplayOps<O,I> &display, SAppMenu *menu, uint8_t index)
677 {
678  if (index == menu->selection)
679  {
680  display.negativeMode();
681  }
682  else
683  {
684  display.positiveMode();
685  }
686  lcdint_t item_top = 8 + menu->top + (index - menu->scrollPosition)*display.getFont().getHeader().height;
687  display.setColor( 0x0000 );
688  display.fillRect( menu->left + 8 + display.getFont().getTextSize(menu->items[index]), item_top,
689  menu->width + menu->left - 9, item_top + display.getFont().getHeader().height - 1 );
690  display.setColor( 0xFFFF );
691  display.printFixed(menu->left + 8, item_top,
692  menu->items[index], STYLE_NORMAL );
693  display.positiveMode();
694 }
695 
696 template <class O, class I>
697 void NanoDisplayOps<O,I>::createMenu(SAppMenu *menu, const char **items, uint8_t count, const NanoRect &rect)
698 {
699  menu->items = items;
700  menu->count = count;
701  menu->selection = 0;
702  menu->oldSelection = 0;
703  menu->scrollPosition = 0;
704  menu->top = rect.p1.y;
705  menu->left = rect.p1.x;
706  menu->width = rect.p2.x ? rect.width() : ( this->width() - menu->left );
707  menu->height = rect.p2.y ? rect.height() : ( this->height() - menu->top );
708 }
709 
710 template <class O, class I>
712 {
713  drawRect(4 + menu->left, 4 + menu->top, menu->width + menu->left - 5, menu->height + menu->top - 5);
714  menu->scrollPosition = calculateScrollPosition<O,I>(*this, menu, menu->selection );
715  for (uint8_t i = menu->scrollPosition; i < min(menu->count, (menu->scrollPosition + getMaxScreenItems<O,I>( *this, menu ))); i++)
716  {
717  drawMenuItem<O,I>(*this, menu, i);
718  }
719  menu->oldSelection = menu->selection;
720 }
721 
722 template <class O, class I>
724 {
725  drawRect(4 + menu->left, 4 + menu->top, menu->width + menu->left - 5, menu->height + menu->top - 5);
726  menu->scrollPosition = calculateScrollPosition<O,I>(*this, menu, menu->selection );
727  for (uint8_t i = menu->scrollPosition; i < min(menu->count, (menu->scrollPosition + getMaxScreenItems<O,I>( *this, menu ))); i++)
728  {
729  drawMenuItemSmooth<O,I>(*this, menu, i);
730  }
731  menu->oldSelection = menu->selection;
732 }
733 
734 template <class O, class I>
736 {
737  if (menu->selection != menu->oldSelection)
738  {
739  uint8_t scrollPosition = calculateScrollPosition<O,I>( *this, menu, menu->selection );
740  if ( scrollPosition != menu->scrollPosition )
741  {
742  this->clear();
743  showMenu(menu);
744  }
745  else
746  {
747  drawMenuItem<O,I>( *this, menu, menu->oldSelection);
748  drawMenuItem<O,I>( *this, menu, menu->selection);
749  menu->oldSelection = menu->selection;
750  }
751  }
752 }
753 
754 template <class O, class I>
756 {
757  if (menu->selection != menu->oldSelection)
758  {
759  uint8_t scrollPosition = calculateScrollPosition<O,I>( *this, menu, menu->selection );
760  if ( scrollPosition != menu->scrollPosition )
761  {
762  showMenuSmooth(menu);
763  }
764  else
765  {
766  drawMenuItemSmooth<O,I>( *this, menu, menu->oldSelection);
767  drawMenuItemSmooth<O,I>( *this, menu, menu->selection);
768  menu->oldSelection = menu->selection;
769  }
770  }
771 }
772 
773 template <class O, class I>
775 {
776  return menu->selection;
777 }
778 
779 template <class O, class I>
781 {
782  if (menu->selection < menu->count - 1)
783  {
784  menu->selection++;
785  }
786  else
787  {
788  menu->selection = 0;
789  }
790 }
791 
792 template <class O, class I>
794 {
795  if (menu->selection > 0)
796  {
797  menu->selection--;
798  }
799  else
800  {
801  menu->selection = menu->count - 1;
802  }
803 }
804 
805 template <class O, class I>
807 {
808  this->drawBuffer1Fast( x, y, canvas.width(), canvas.height(), canvas.getData() );
809 }
810 
811 template <class O, class I>
813 {
814  this->drawBuffer4( x, y, canvas.width(), canvas.height(), canvas.getData() );
815 }
816 
817 template <class O, class I>
819 {
820  this->drawBuffer8( x, y, canvas.width(), canvas.height(), canvas.getData() );
821 }
822 
823 template <class O, class I>
825 {
826  this->drawBuffer16( x, y, canvas.width(), canvas.height(), canvas.getData() );
827 }
828 
829 template <class O, class I>
831 {
832  lcduint_t height = 8;
833  lcduint_t width = 8;
834  char str[5] = "100%";
835  if ( progress < 100 )
836  {
837  str[0] = ' ';
838  str[1] = progress / 10 + '0';
839  str[2] = progress % 10 + '0';
840  str[3] = '%';
841  }
842  if ( this->m_font != nullptr )
843  {
844  width = this->getFont().getTextSize( str, &height );
845  }
846  lcdint_t middle = this->height() / 2;
847  lcdint_t progress_pos = 8 + (int16_t)(this->width() - 16) * progress / 100;
848  uint16_t color = this->m_color;
849  this->m_color = 0x0000;
850  this->fillRect( progress_pos, middle, this->width() - 8, middle + height );
851  this->m_color = color;
852  this->drawRect( progress_pos, middle, this->width() - 8, middle + height );
853  this->fillRect( 8, middle, progress_pos, middle + height );
854  if ( this->m_font != nullptr )
855  {
856  this->printFixed( this->width() / 2 - width / 2, middle - height, str );
857  }
858 }
859 
860 template <class O, class I>
862  lcduint_t width, lcduint_t height,
863  const char *caption, bool blank)
864 {
865  if ( width == 0 ) { width = this->width() - 8; x = 4; }
866  if ( height == 0 ) { height = this->height() - 4; y = 0; }
867  if ( blank )
868  {
869  uint16_t color = this->m_color;
870  this->m_color = 0x0000;
871  this->fillRect( x, y, x + width - 1, y + height - 1 );
872  this->m_color = color;
873  }
874  if ( caption )
875  {
876  y += this->getFont().getHeader().height / 2;
877  height -= this->getFont().getHeader().height / 2;
878  }
879  this->drawRect( x, y, x + width - 1, y + height - 1 );
880  if ( caption )
881  {
882  lcduint_t theight;
883  lcduint_t twidth = this->getFont().getTextSize( caption, &theight );
884  this->printFixed( x + (width - twidth)/2, y - theight/2, caption );
885  }
886 }
887 
lcdint_t left
left offset
Definition: canvas_types.h:169
uint8_t height
char height in pixels
Definition: canvas_types.h:146
uint8_t lcduint_t
Definition: canvas_types.h:81
void menuUp(SAppMenu *menu)
Definition: rect.h:42
lcdint_t height() const
Definition: rect.h:63
void drawRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
NanoPoint p2
Definition: rect.h:48
int8_t lcdint_t
Definition: canvas_types.h:79
void write(const char *str)
uint8_t menuSelection(SAppMenu *menu)
void createMenu(SAppMenu *menu, const char **items, uint8_t count, const NanoRect &rect={})
lcduint_t width
width of menu
Definition: canvas_types.h:171
uint8_t * getData()
Definition: canvas.h:334
lcdint_t y
Definition: point.h:45
#define SSD1306_MORE_CHARS_REQUIRED
Definition: canvas_types.h:43
lcduint_t width()
Definition: canvas.h:337
lcduint_t height
height of menu
Definition: canvas_types.h:173
void putPixel(const NanoPoint &p)
lcduint_t height()
Definition: canvas.h:340
void drawCanvas(lcdint_t x, lcdint_t y, NanoCanvasOps< 1 > &canvas) __attribute__((noinline))
void print(int number)
void drawLine(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
void updateMenuSmooth(SAppMenu *menu)
void updateMenu(SAppMenu *menu)
uint8_t selection
currently selected item. Internally updated.
Definition: canvas_types.h:161
void showMenuSmooth(SAppMenu *menu)
uint8_t scrollPosition
position of menu scrolling. Internally updated
Definition: canvas_types.h:165
uint8_t count
count of menu items in the menu
Definition: canvas_types.h:159
uint8_t width
char width in pixels
Definition: canvas_types.h:145
void showMenu(SAppMenu *menu)
lcdint_t top
top offset
Definition: canvas_types.h:167
void fillRect(const NanoRect &rect)
const uint8_t * glyph
char data, located in progmem.
Definition: canvas_types.h:148
lcdint_t width() const
Definition: rect.h:51
void drawProgressBar(int8_t progress)
void printFixedPgm(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style=STYLE_NORMAL) __attribute__((noinline))
#define min(a, b)
Definition: canvas_types.h:42
uint8_t spacing
additional spaces after char in pixels
Definition: canvas_types.h:147
void drawWindow(lcdint_t x, lcdint_t y, lcduint_t width, lcduint_t height, const char *caption, bool blank)
EFontStyle
Definition: canvas_types.h:90
NanoPoint p1
Definition: rect.h:45
lcdint_t x
Definition: point.h:43
#define ssd1306_swap_data(a, b, type)
Definition: io.h:108
uint8_t oldSelection
selected item, when last redraw operation was performed. Internally updated.
Definition: canvas_types.h:163
void menuDown(SAppMenu *menu)
const char ** items
list of menu items of the menu
Definition: canvas_types.h:157