@@ -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+
312324void 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