LCDGFX LCD display driver  1.2.0
Lightweight graphics library for SSD1306, SSD1325, SSD1327, SSD1331, SSD1351, SH1106, SH1107, IL9163, ST7735, ST7789, ILI9341, PCD8544 displays over I2C/SPI
checkbox_menu.h
Go to the documentation of this file.
1 /*
2  MIT License
3 
4  Copyright (c) 2020,2022,2025 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 */
28 #ifndef _LCDGFX_CHECKBOX_MENU_H_
29 #define _LCDGFX_CHECKBOX_MENU_H_
30 
31 #include "nano_gfx_types.h"
32 #include "canvas/point.h"
33 #include "canvas/rect.h"
34 #include "canvas/font.h"
35 
36 #ifndef lcd_gfx_min
37 #define lcd_gfx_min(x, y) ((x) < (y) ? (x) : (y))
38 #endif
39 
40 #ifndef lcd_gfx_max
41 #define lcd_gfx_max(x, y) ((x) > (y) ? (x) : (y))
42 #endif
43 
70 {
71 public:
79  LcdGfxCheckboxMenu(const char **items, uint8_t count, const NanoRect &rect = {});
80 
87  template <typename D> void show(D &d);
88 
92  void down();
93 
97  void up();
98 
102  void toggle();
103 
109  bool isChecked(uint8_t index);
110 
116  void setChecked(uint8_t index, bool checked);
117 
123  uint16_t checkedMask();
124 
128  uint8_t selection();
129 
134  void setSelection(uint8_t s);
135 
140  void setRect(const NanoRect &rect = {});
141 
145  uint8_t size();
146 
150  template <typename D> void updateSize(D &d)
151  {
152  if ( !menu.width )
153  {
154  menu.width = d.width() - menu.left;
155  }
156  if ( !menu.height )
157  {
158  menu.height = d.height() - menu.top;
159  }
160  }
161 
162 private:
163  SAppMenu menu;
164  uint16_t m_checked;
165 
166  template <typename D> uint8_t getMaxScreenItems(D &d)
167  {
168  return (menu.height - 16) / d.getFont().getHeader().height;
169  }
170 
171  template <typename D> uint8_t calculateScrollPosition(D &d, uint8_t selection)
172  {
173  if ( selection < menu.scrollPosition )
174  {
175  return selection;
176  }
177  else if ( selection - menu.scrollPosition > getMaxScreenItems(d) - 1 )
178  {
179  return selection - getMaxScreenItems(d) + 1;
180  }
181  return menu.scrollPosition;
182  }
183 
184  template <typename D> void drawMenuItem(D &d, uint8_t index)
185  {
186  if ( index == menu.selection )
187  {
188  d.invertColors();
189  }
190  lcdint_t item_top = 8 + menu.top + (index - menu.scrollPosition) * d.getFont().getHeader().height;
191  lcduint_t fh = d.getFont().getHeader().height;
192  uint16_t color = d.getColor();
193 
194  // Checkbox box size scales with font
195  lcduint_t boxSize = (fh >= 12) ? 7 : 5;
196  lcdint_t boxX = menu.left + 6;
197  lcdint_t boxY = item_top + (fh - boxSize) / 2;
198  lcdint_t textX = boxX + boxSize + 3;
199 
200  // Clear background to the right of text
201  d.setColor(0x0000);
202  d.fillRect(textX + d.getFont().getTextSize(menu.items[index]), item_top,
203  menu.width + menu.left - 9, item_top + fh - 1);
204  // Clear checkbox area background
205  d.fillRect(menu.left + 5, item_top, textX - 1, item_top + fh - 1);
206  d.setColor(color);
207 
208  // Draw checkbox
209  if ( m_checked & (1u << index) )
210  {
211  d.fillRect(boxX, boxY, boxX + boxSize - 1, boxY + boxSize - 1);
212  }
213  else
214  {
215  d.drawRect(boxX, boxY, boxX + boxSize - 1, boxY + boxSize - 1);
216  }
217 
218  // Draw item text
219  d.printFixed(textX, item_top, menu.items[index], STYLE_NORMAL);
220 
221  if ( index == menu.selection )
222  {
223  d.invertColors();
224  }
225  }
226 
227  template <typename D> void drawScrollIndicators(D &d, uint8_t maxItems)
228  {
229  uint16_t color = d.getColor();
230  lcdint_t borderTop = 4 + menu.top;
231  lcdint_t borderBot = menu.height + menu.top - 5;
232  lcdint_t itemsTop = 8 + menu.top;
233  lcdint_t itemsBot = itemsTop + maxItems * d.getFont().getHeader().height;
234  lcdint_t cx = menu.left + menu.width / 2;
235 
236  d.setColor(0x0000);
237  d.fillRect(5 + menu.left, borderTop + 1, menu.width + menu.left - 6, itemsTop - 1);
238  if ( menu.scrollPosition > 0 )
239  {
240  d.setColor(color);
241  d.drawHLine(cx, borderTop + 1, cx);
242  d.drawHLine(cx - 1, borderTop + 2, cx + 1);
243  d.drawHLine(cx - 2, borderTop + 3, cx + 2);
244  }
245 
246  d.setColor(0x0000);
247  d.fillRect(5 + menu.left, itemsBot, menu.width + menu.left - 6, borderBot - 1);
248  if ( menu.scrollPosition + maxItems < menu.count )
249  {
250  d.setColor(color);
251  d.drawHLine(cx - 2, borderBot - 3, cx + 2);
252  d.drawHLine(cx - 1, borderBot - 2, cx + 1);
253  d.drawHLine(cx, borderBot - 1, cx);
254  }
255 
256  lcdint_t sbX = menu.width + menu.left - 8;
257  lcdint_t sbH = itemsBot - itemsTop - 1;
258  if ( sbH > 4 )
259  {
260  lcdint_t thumbH = lcd_gfx_max((lcdint_t)2, (lcdint_t)(sbH * maxItems / menu.count));
261  lcdint_t maxScroll = menu.count - maxItems;
262  lcdint_t thumbY = itemsTop;
263  if ( maxScroll > 0 )
264  {
265  thumbY = itemsTop + (lcdint_t)((long)(sbH - thumbH) * menu.scrollPosition / maxScroll);
266  }
267  d.setColor(0x0000);
268  d.fillRect(sbX, itemsTop, sbX + 1, itemsTop + sbH);
269  d.setColor(color);
270  d.fillRect(sbX, thumbY, sbX + 1, thumbY + thumbH);
271  }
272  d.setColor(color);
273  }
274 };
275 
276 template <typename D> void LcdGfxCheckboxMenu::show(D &d)
277 {
278  updateSize(d);
279  d.drawRect(4 + menu.left, 4 + menu.top, menu.width + menu.left - 5, menu.height + menu.top - 5);
280  menu.scrollPosition = this->calculateScrollPosition(d, menu.selection);
281  uint8_t maxItems = getMaxScreenItems(d);
282  for ( uint8_t i = menu.scrollPosition; i < lcd_gfx_min(menu.count, (menu.scrollPosition + maxItems)); i++ )
283  {
284  this->drawMenuItem(d, i);
285  }
286  menu.oldSelection = menu.selection;
287  if ( menu.count > maxItems )
288  {
289  this->drawScrollIndicators(d, maxItems);
290  }
291 }
292 
297 #endif
lcdint_t left
left offset
Definition: canvas_types.h:167
uint8_t lcduint_t
internal int type, used by the library.
Definition: canvas_types.h:79
NanoRect structure describes rectangle area.
Definition: rect.h:42
uint16_t checkedMask()
Returns the full checkbox state as a bitmask.
uint8_t size()
Returns total count of menu items.
Point class.
int8_t lcdint_t
internal int type, used by the library.
Definition: canvas_types.h:77
void show(D &d)
Shows the checkbox menu on the display.
void up()
Moves selection up by one item.
void updateSize(D &d)
Updates size of the object if not set previously.
lcduint_t width
width of menu
Definition: canvas_types.h:169
#define lcd_gfx_max(a, b)
Macros returning maximum of 2 numbers.
Rectangle class.
lcduint_t height
height of menu
Definition: canvas_types.h:171
void setChecked(uint8_t index, bool checked)
Sets the checkbox state of a specific item.
Basic structures of nano gfx library.
uint8_t selection
currently selected item. Internally updated.
Definition: canvas_types.h:159
uint8_t scrollPosition
position of menu scrolling. Internally updated
Definition: canvas_types.h:163
void setSelection(uint8_t s)
Sets the current selection index.
#define lcd_gfx_min(a, b)
Macros returning minimum of 2 numbers.
void toggle()
Toggles the checkbox state of the currently selected item.
uint8_t selection()
Returns currently selected menu item index.
void down()
Moves selection down by one item.
uint8_t count
count of menu items in the menu
Definition: canvas_types.h:157
Checkbox menu widget for lcdgfx.
Definition: checkbox_menu.h:69
Describes menu object.
Definition: canvas_types.h:152
lcdint_t top
top offset
Definition: canvas_types.h:165
void setRect(const NanoRect &rect={})
Sets rect area for the menu.
bool isChecked(uint8_t index)
Returns true if the item at the given index is checked.
LcdGfxCheckboxMenu(const char **items, uint8_t count, const NanoRect &rect={})
Creates checkbox menu object.
Font class.
uint8_t oldSelection
selected item, when last redraw operation was performed. Internally updated.
Definition: canvas_types.h:161
const char ** items
list of menu items of the menu
Definition: canvas_types.h:155