Skip to content

Commit e4c8bef

Browse files
author
Tobias Frost
committed
Refactor OptionMenu() to be table-driven and to allow more options.
This commit has the refactoring, the new options will follow.
1 parent 6597bf0 commit e4c8bef

File tree

1 file changed

+150
-39
lines changed

1 file changed

+150
-39
lines changed

Maiskolben_TFT/Maiskolben_TFT.ino

Lines changed: 150 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -309,76 +309,187 @@ void setDisplayMode(boolean bgr) {
309309
tft.setRotation(3);
310310
}
311311

312+
#ifdef SHUTOFF_ACTIVE
313+
#define OPT_BIT_SHUTOFF OPT_BIT
314+
#else
315+
#define OPT_BIT_SHUTOFF OPT_BIT_DISABLED
316+
#endif
317+
318+
#ifdef BOOTHEAT_ACTIVE
319+
#define OPT_BIT_BHEAT OPT_BIT
320+
#else
321+
#define OPT_BIT_BHEAT OPT_BIT_DISABLED
322+
#endif
323+
312324
void optionMenu(void) {
325+
uint8_t first_option = 0; // The current option displayed on the top-line.
326+
uint8_t opt = 0; // The current line on the display that is selected.
327+
328+
// for the declaration table.
329+
enum optiontype {
330+
OPT_BIT,
331+
OPT_BIT_DISABLED,
332+
OPT_8BIT_VALUE,
333+
};
334+
335+
// defined options.
336+
struct optionslist {
337+
char *title;
338+
enum optiontype type;
339+
340+
uint8_t min_or_bit; // bitmask to be orded / deleted on option toggle or min value for 8-bit value
341+
uint8_t max; // max value for 8-bit-value
342+
uint8_t stepsize; // step size for +/- for 8-bit-value
343+
uint8_t *target; // target variable.
344+
} optionslist[] = {
345+
// title type min max step target
346+
// mask
347+
{ "Autoshutdown", OPT_BIT_SHUTOFF, 1, 0, 0, (uint8_t *)&autopower },
348+
{ "Heat on boot", OPT_BIT_BHEAT, 1, 0, 0, (uint8_t *)&bootheat },
349+
{ "Fahrenheit", OPT_BIT, 1, 0, 0, (uint8_t *)&fahrenheit },
350+
};
351+
352+
// how many chars do fit into a line?
353+
constexpr uint8_t chars_per_line = 13; // number of chars per line.
354+
constexpr uint8_t displayed_options = 3; // number of option-lines on display
355+
constexpr uint8_t num_options = 4; // total number of options in optionlist[]
356+
357+
// sanitize 8-bit values
358+
for (int i = 0; i < num_options; i++) {
359+
if (optionslist[i].type != OPT_8BIT_VALUE) continue;
360+
uint8_t value = *(optionslist[i].target);
361+
if (value < optionslist[i].min_or_bit) value = optionslist[i].min_or_bit;
362+
if (value > optionslist[i].max) value = optionslist[i].max;
363+
*(optionslist[i].target) = value;
364+
}
365+
366+
const char *onoffexit = "ON OFF EXIT";
367+
const char *plusminusexit = " + - EXIT";
368+
369+
// Prepare Screen
313370
tft.fillScreen(BLACK);
314371
digitalWrite(HEAT_LED, LOW);
315372
tft.setTextSize(2);
316373
tft.setCursor(0,0);
317374
tft.setTextColor(WHITE);
318375
tft.println("Options\n");
319-
tft.setTextColor(WHITE);
320-
tft.setCursor(10,112);
321-
tft.print("ON OFF EXIT");
322-
uint8_t options = 3;
323-
uint8_t opt = 0;
376+
324377
boolean redraw = true;
325378
while (true) {
326379
if (redraw) {
327-
tft.setCursor(0,36);
328-
#ifdef SHUTOFF_ACTIVE
329-
tft.setTextColor(autopower?GREEN:RED);
330-
#else
331-
tft.setTextColor(GRAY);
332-
#endif
333-
tft.println(" Autoshutdown");
334-
#ifdef BOOTHEAT_ACTIVE
335-
tft.setTextColor(bootheat?GREEN:RED);
336-
#else
337-
tft.setTextColor(GRAY);
338-
#endif
339-
tft.println(" Heat on boot");
340-
tft.setTextColor(fahrenheit?GREEN:RED);
341-
tft.println(" Fahrenheit");
380+
tft.setCursor(0, 2 * 18);
381+
// Render options from first_option on.
382+
for (uint8_t i = 0; i < displayed_options; i++) {
383+
uint8_t printed = 0;
384+
uint8_t entry = i + first_option;
385+
uint16_t color = GRAY;
386+
bool is_enabled = 0;
387+
if (optionslist[entry].type == OPT_BIT) {
388+
uint8_t value = optionslist[entry].min_or_bit & *(optionslist[entry].target);
389+
if (value) color = GREEN;
390+
else color = RED;
391+
} else if (optionslist[entry].type == OPT_8BIT_VALUE) {
392+
color = GREEN;
393+
}
394+
if (opt == i) tft.setTextColor(WHITE);
395+
else tft.setTextColor(BLACK);
396+
tft.print(">");
397+
tft.setTextColor(color, BLACK);
398+
tft.print(optionslist[entry].title);
399+
printed = 1 + strlen(optionslist[entry].title);
342400

343-
tft.setCursor(0, (opt+2)*18);
344-
tft.setTextColor(WHITE);
345-
tft.print(">");
401+
if (optionslist[entry].type == OPT_8BIT_VALUE) {
402+
uint8_t val = *(optionslist[entry].target);
403+
tft.print(" ");
404+
if (val < 100) tft.print(" ");
405+
if (val < 10) tft.print(" ");
406+
tft.print(val);
407+
printed += 3;
408+
}
409+
for (uint8_t j = printed; j < chars_per_line; j++) tft.print(" ");
410+
tft.println("");
411+
}
412+
413+
// Render operationstext
414+
tft.setTextColor(WHITE, BLACK);
415+
tft.setCursor(10, 112);
416+
if (optionslist[opt + first_option].type == OPT_8BIT_VALUE) {
417+
tft.print(plusminusexit);
418+
} else {
419+
tft.print(onoffexit);
420+
}
421+
422+
// Render hints that there are more options
423+
if (first_option) tft.setTextColor(YELLOW, BLACK);
424+
else tft.setTextColor(BLACK, BLACK);
425+
tft.setCursor(142, 1 * 18);
426+
tft.print((char)0x18); // "arrow up"
427+
428+
if (num_options - first_option > displayed_options) tft.setTextColor(YELLOW, BLACK);
429+
else tft.setTextColor(BLACK, BLACK);
430+
tft.setCursor(142, (displayed_options + 2) * 18);
431+
tft.print((char)0x19); // "arrow down"
432+
346433
redraw = false;
347434
}
435+
436+
// Button handling.
437+
// opt is current line on screen.
348438
if (!digitalRead(SW_UP)) {
349-
tft.setCursor(0, (opt+2)*18);
350-
tft.setTextColor(BLACK);
351-
tft.print(">");
352-
opt = (opt+options-1)%options;
439+
if (opt == 0 && first_option) {
440+
first_option--;
441+
} else if (opt) {
442+
opt--;
443+
}
353444
while (!digitalRead(SW_UP)) delay(100);
354445
redraw = true;
355446
}
356447
if (!digitalRead(SW_DOWN)) {
357-
tft.setCursor(0, (opt+2)*18);
358-
tft.setTextColor(BLACK);
359-
tft.print(">");
360-
opt = (opt+1)%options;
448+
if (displayed_options - 1 > opt) {
449+
opt++;
450+
} else if (num_options - 1 > opt + first_option) {
451+
first_option++;
452+
}
361453
while (!digitalRead(SW_DOWN)) delay(100);
362454
redraw = true;
363455
}
456+
364457
if (!digitalRead(SW_T1)) {
365-
switch (opt) {
366-
case 0: autopower = 1; break;
367-
case 1: bootheat = 1; break;
368-
case 2: fahrenheit = 1; break;
458+
uint8_t entry = opt + first_option;
459+
enum optiontype type = optionslist[entry].type;
460+
switch (type) {
461+
case OPT_BIT:
462+
*(optionslist[entry].target) |= optionslist[entry].min_or_bit;
463+
break;
464+
case OPT_8BIT_VALUE:
465+
uint8_t value = *(optionslist[entry].target) + optionslist[entry].stepsize;
466+
if (value > optionslist[entry].max) value = optionslist[entry].max;
467+
*(optionslist[entry].target) = value;
468+
break;
369469
}
370470
redraw = true;
371471
}
472+
372473
if (!digitalRead(SW_T2)) {
373-
switch (opt) {
374-
case 0: autopower = 0; break;
375-
case 1: bootheat = 0; break;
376-
case 2: fahrenheit = 0; break;
474+
uint8_t entry = opt + first_option;
475+
enum optiontype type = optionslist[entry].type;
476+
switch (type) {
477+
case OPT_BIT:
478+
*(optionslist[entry].target) &= ~(optionslist[entry].min_or_bit);
479+
break;
480+
case OPT_8BIT_VALUE:
481+
uint8_t value = *(optionslist[entry].target);
482+
if (value >= optionslist[entry].stepsize) value -= optionslist[entry].stepsize;
483+
else value = 0;
484+
if (value < optionslist[entry].min_or_bit) value = optionslist[entry].min_or_bit;
485+
*(optionslist[entry].target) = value;
377486
}
378487
redraw = true;
379488
}
489+
380490
if (!digitalRead(SW_T3)) break;
381491
}
492+
382493
EEPROM.update(EEPROM_OPTIONS, (fahrenheit << 2) | (bootheat << 1) | autopower);
383494
updateRevision();
384495
EEPROM.update(EEPROM_VERSION, EE_VERSION);

0 commit comments

Comments
 (0)