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