Skip to content

Menu appearance

Alexander Spiridonov edited this page Aug 5, 2024 · 20 revisions

Appearance of the menu can be customized by adjusting options, that can be passed to GEM (GEM_u8g2, GEM_adafruit_gfx) constructor individually or as a part of GEMAppearance object.

AltSerialGraphicLCD version:

GEM menu(glcd[, menuPointerType[, menuItemsPerScreen[, menuItemHeight[, menuPageScreenTopOffset[, menuValuesLeftOffset]]]]]);
// or
GEM menu(glcd[, appearance]);

U8g2 version:

GEM_u8g2 menu(u8g2[, menuPointerType[, menuItemsPerScreen[, menuItemHeight[, menuPageScreenTopOffset[, menuValuesLeftOffset]]]]]);
// or
GEM_u8g2 menu(u8g2[, appearance]);

Adafruit GFX version:

GEM_adafruit_gfx menu(tft[, menuPointerType[, menuItemsPerScreen[, menuItemHeight[, menuPageScreenTopOffset[, menuValuesLeftOffset]]]]]);
// or
GEM_adafruit_gfx menu(tft[, appearance]);

Options

  • menuPointerType [optional]
    Type: byte
    Values: GEM_POINTER_ROW, GEM_POINTER_DASH
    Default: GEM_POINTER_ROW
    Type of menu pointer visual appearance: either highlighted row or pointer to the left of the row.

  • menuItemsPerScreen [optional]
    Type: byte
    Values: number, GEM_ITEMS_COUNT_AUTO (alias for 0)
    Default: 5
    Count of the menu items per screen. Suitable for 128x64 screen with other variables at their default values. If set to GEM_ITEMS_COUNT_AUTO (available since GEM ver. 1.3), the number of menu items will be determined automatically based on actual height of the screen.

  • menuItemHeight [optional]
    Type: byte
    Units: dots
    Default: 10
    Height of the menu item. Suitable for 128x64 screen with other variables at their default values.

  • menuPageScreenTopOffset [optional]
    Type: byte
    Units: dots
    Default: 10
    Offset from the top of the screen to accommodate title of the menu page. Suitable for 128x64 screen with other variables at their default values.

  • menuValuesLeftOffset [optional]
    Type: byte
    Units: dots
    Default: 86
    Offset from the left of the screen to the value of the associated with menu item variable (effectively the space left for the title of the menu item to be printed on screen). Suitable for 128x64 screen with other variables at their default values; 86 - recommended value for 128x64 screen.

  • appearance [optional]
    Type: GEMAppearance
    Object of type GEMAppearance that holds values of appearance settings that define how menu is rendered on screen. Essentially allows to pass appearance as a single object instead of specifying each option as a aseparate argument.

Calls to GEM, GEM_u8g2 or GEM_adafruit_gfx constructors GEM(glcd), GEM_u8g2(u8g2), GEM_adafruit_gfx(tft) without specifying additional custom parameters are equivalent to the following calls:

GEM menu(glcd, /* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ 5, /* menuItemHeight= */ 10, /* menuPageScreenTopOffset= */ 10, /* menuValuesLeftOffset= */ 86);
GEM_u8g2 menu(u8g2, /* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ 5, /* menuItemHeight= */ 10, /* menuPageScreenTopOffset= */ 10, /* menuValuesLeftOffset= */ 86);
GEM_adafruit_gfx menu(tft, /* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ 5, /* menuItemHeight= */ 10, /* menuPageScreenTopOffset= */ 10, /* menuValuesLeftOffset= */ 86);

Note: carefully choose values of menuItemsPerScreen, menuItemHeight, menuPageScreenTopOffset, menuValuesLeftOffset in accordance to the actual size of your display. Default values of these options are suitable for 128x64 screens. But that is not the only possible option: the other combination of values you set may also be suitable - just calculate them correctly and see what works best for you.

Note: long title of the menu page GEMPage won't overflow to the new line in U8g2 version and will be truncated at the edge of the screen.

Note: it is possible to customize appearance of each menu page individually (since GEM ver. 1.5) by using GEMAppearance object.

Examples

GEM menu(glcd);

Equivalent to:

GEM menu(glcd, /* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ 5, /* menuItemHeight= */ 10, /* menuPageScreenTopOffset= */ 10, /* menuValuesLeftOffset= */ 86);

GEM menu(glcd, /* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ 5, /* menuItemHeight= */ 10, /* menuPageScreenTopOffset= */ 10, /* menuValuesLeftOffset= */ 80);

GEM menu(glcd, /* menuPointerType= */ GEM_POINTER_DASH, /* menuItemsPerScreen= */ 5, /* menuItemHeight= */ 10, /* menuPageScreenTopOffset= */ 10, /* menuValuesLeftOffset= */ 80);

GEM menu(glcd, /* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ 4, /* menuItemHeight= */ 10, /* menuPageScreenTopOffset= */ 16, /* menuValuesLeftOffset= */ 80);

Note: screenshot of the AltSerialGraphicLCD version is shown, long title of the menu page won't overflow to the new line in U8g2 version and will be truncated at the edge of the screen.


GEM menu(glcd, /* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ 4, /* menuItemHeight= */ 14, /* menuPageScreenTopOffset= */ 8, /* menuValuesLeftOffset= */ 80);

GEM menu(glcd, /* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ 7, /* menuItemHeight= */ 8, /* menuPageScreenTopOffset= */ 8, /* menuValuesLeftOffset= */ 80);

GEM menu(glcd, /* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ 9, /* menuItemHeight= */ 6, /* menuPageScreenTopOffset= */ 10, /* menuValuesLeftOffset= */ 80);

GEM menu(glcd, /* menuPointerType= */ GEM_POINTER_DASH, /* menuItemsPerScreen= */ 9, /* menuItemHeight= */ 6, /* menuPageScreenTopOffset= */ 10, /* menuValuesLeftOffset= */ 80);

GEMAppearance

Data structure that holds values of appearance settings that define how menu is rendered on screen. Can be submitted to GEM (GEM_u8g2, GEM_adafruit_gfx) constructor instead of specifying each option as a separate argument, or passed as an argument to GEM::setAppearance() (GEM_u8g2::setAppearance(), GEM_adafruit_gfx::setAppearance()) method to set general appearance of the menu (that will be used for every menu page if not overridden). Pointer to object of type GEMAppearance can be passed to GEMPage::setAppearance() method to customize appearance of corresponding menu page individually.

Object of type GEMAppearance defines as follows:

GEMAppearance appearanceGeneral = {menuPointerType, menuItemsPerScreen, menuItemHeight, menuPageScreenTopOffset, menuValuesLeftOffset}

Basic example of use:

// Create GEMAppearance object with general values (that will be used for every menu page if not overridden)
GEMAppearance appearanceGeneral = {/* menuPointerType= */ GEM_POINTER_ROW, /* menuItemsPerScreen= */ GEM_ITEMS_COUNT_AUTO, /* menuItemHeight= */ 10, /* menuPageScreenTopOffset= */ 10, /* menuValuesLeftOffset= */ 86}
// Create GEMAppearance object as a copy of appearanceGeneral (its values can be customized later in sketch).
// Note that it should be created in a global scope of the sketch (in order to be passed as a pointer to menu page)
GEMAppearance appearanceSettings = appearanceGeneral;

// Create menu object (and pass appearanceGeneral as an argument to constructor)
GEM menu(glcd, appearanceGeneral);

...

// Later in sketch, e.g. in setupMenu()
void setupMenu() {
  ...
  appearanceSettings.menuValuesLeftOffset = 70;
  menuPageSettings.setAppearance(&appearanceSettings); // Note `&` operator
  ...
}

Alternatively:

// Create empty GEMAppearance object (its values can be populated later in sketch).
// Note that it should be created in a global scope of the sketch (in order to be passed as a pointer to menu page)
GEMAppearance appearanceSettings;

// Create menu object (its appearance settings will be populated with default values)
GEM menu(glcd);

...

// Later in sketch, e.g. in setupMenu()
void setupMenu() {
  ...
  // Create GEMAppearance object with general values (that will be used for every menu page if not overridden)
  GEMAppearance appearanceGeneral;
  appearanceGeneral.menuPointerType = GEM_POINTER_ROW;
  appearanceGeneral.menuItemsPerScreen = GEM_ITEMS_COUNT_AUTO;
  appearanceGeneral.menuItemHeight = 10;
  appearanceGeneral.menuPageScreenTopOffset = 10;
  appearanceGeneral.menuValuesLeftOffset = 86;

  // Set appearanceGeneral as a general appearance of the menu
  menu.setAppearance(appearanceGeneral); // Note there is no `&` operator when setting general (or global) appearance of the menu

  // Copy values from appearanceGeneral object to appearanceSettings for further customization
  appearanceSettings = appearanceGeneral;
  appearanceSettings.menuValuesLeftOffset = 70;
  menuPageSettings.setAppearance(&appearanceSettings); // Note `&` operator
  ...
}

Passing GEMAppearance object to GEMPage::setAppearance() method as a pointer allows to change appearance of the individual menu page dynamically by changing values stored in object (and making sure that menu.drawMenu(); is called afterwards) without need for additional call to GEMPage::setAppearance(). In contrast, to change general appearance of the menu (and not individual page) menu.setAppearance(appearanceGeneral); method should be called with new or updated GEMAppearance object supplied as an argument (and menu.drawMenu(); should be called afterwards as well).

Changing fonts

It is possible to change fonts used to print menu page titles and menu item labels and values in U8g2 and Adafruit GFX versions of GEM. There are two different sizes, fonts for which can be changed independently. "Big" font is used to print menu items if height of menu item (menuItemHeight property of GEMAppearance object) is enough to fit it, "small" font will be used instead otherwise. "Small" font is also used to print menu page title. Use ::setFontBig() and ::setFontSmall() methods of Adafruit GFX and U8g2 versions of GEM accordingly. See description of this methods in Readme for more details.

Note: using mono-spaced font is recommended for correct calculations internally (especially for editable menu items).

Adafruit GFX version

Use GEM_adafruit_gfx::setFontBig(font, width, height, baselineOffset) and GEM_adafruit_gfx::setFontSmall(font, width, height, baselineOffset) methods to change fonts. They accept pointer font to the font that Adafruit GFX supports. See Adafruit GFX documentation for details on font format and possible conversion options. Options width and height describe size of a single character, baselineOffset sets offset from the top of the character to baseline (helps to better adjust vertical alignment). Call this method without arguments to revert to default font supplied with GEM.

// Include custom fonts (e.g. ones that come with Adafruit GFX library)
#include <Fonts/Org_01.h>
#include <Fonts/Picopixel.h>

...

void setup() {
  ...
  // Set custom fonts and specify width, height and baselineOffset of characters
  menu
    .setFontBig(&Org_01, 5, 6, 5)
    .setFontSmall(&Picopixel, 4, 6, 5);
  ...
}

U8g2 version

Use GEM_u8g2::setFontBig(font, width, height) and GEM_u8g2::setFontSmall(font, width, height) methods to change fonts. They accept pointer font to the font that U8g2 supports. See U8g2 documentation for list of available fonts. Options width and height describe size of a single character. Adjusting height may help to achieve better vertical alignment. Call this method without arguments to revert to default font settings.

Additionally, support for UTF8 fonts can be enabled by calling GEM_u8g2::enableUTF8() and then setting UTF8 fonts that U8g2 library supports. UTF8 fonts can be used in menu title, menu item labels (GEMItem, including buttons and menu page links), and select options (SelectOptionInt, SelectOptionByte, SelectOptionChar data structures). Editable strings with UTF8 characters are not supported (edit mode of such strings may lead to unpredictable results due to incompatibility with multi-byte UTF8 characters). By default support for UTF8 is off.

void setup() {
  ...
  // Set custom fonts (that come with U8g2 library) and specify width and height of characters
  menu
    .enableUTF8() // Enable UTF8 to support Chinese
    .setFontBig(u8g2_font_unifont_t_chinese2, 8, 10)
    .setFontSmall(u8g2_font_micro_tr, 4, 6);
  ...
}

Changing text magnification (Adafruit GFX version only)

In Adafruit GFX version of GEM it is possible to change text 'magnification' size (as it is called in Adafruit GFX documentation), i.e. scale factor of the text printed on screen (and sprites of the various menu icons, although they can be scaled up to 2 times maximum):

menu.setTextSize(2);
// or
menu.setTextSize(3);

Default scale factor (magnification size) is 1. Should be called before init().

Note: supplied scale factor (magnification size) has no effect on values supplied to GEM_adafruit_gfx constructor, so choose them carefully to be the most suitable for desired text size.

Changing sprite magnification (Adafruit GFX version only)

In Adafruit GFX version of GEM (since GEM ver. 1.5.4) it is possible to change sprite 'magnification' size (i.e. scale factor of the sprites drawn on the screen) independently of text 'magnification' (see previous section). Sprites can be scaled up to 2 times maximum:

menu.setTextSize(2);
menu.setSpriteSize(1);
// or
menu.setSpriteSize(2);

This allows to use magnified sprites alongside larger fonts, without the need to scale fonts.

Default scale factor (magnification size) equals to the one set with setTextSize() method. Should be called after setTextSize() but before init().

Changing color (Adafruit GFX version only)

In Adafruit GFX version of GEM it is possible to change text (foreground) and background colors of the color-capable display:

menu.setForegroundColor(0x0000);
menu.setBackgroundColor(0xFFFF);

Both methods accept color in a 16-bit RGB representation. Adafruit GFX aliases, e.g. ST77XX_WHITE, ST77XX_BLACK, ST77XX_RED, etc. are supported. See Adafruit GFX documentation for detailed description of a format:

For color-capable displays, colors are represented as unsigned 16-bit values. Some displays may physically be capable of more or fewer bits than this, but the library operates with 16-bit values... these are easy for the Arduino to work with while also providing a consistent data type across all the different displays. The primary color components — red, green and blue — are all “packed” into a single 16-bit variable, with the most significant 5 bits conveying red, middle 6 bits conveying green, and least significant 5 bits conveying blue.

Color change will take effect next time menu is drawn. Default values: foreground color 0xFFFF (white), background color 0x0000 (black).

Note: it is possible that some displays may have "inverted" color representation (when R, G, B components come in different order, e.g. B, G, R). If that is the case, try initializing display with different "tab" argument passed to tft.initR() function, e.g. tft.initR(INITR_BLACKTAB), or tft.initR(INITR_GREENTAB), etc. Or just reformat your 16-bit number accordingly.

Examples

menu.setForegroundColor(ST77XX_WHITE);
menu.setBackgroundColor(ST77XX_BLACK);
// or
menu.setForegroundColor(0xFFFF);
menu.setBackgroundColor(0x0000);

menu.setForegroundColor(ST77XX_BLACK);
menu.setBackgroundColor(ST77XX_WHITE);
// or
menu.setForegroundColor(0x0000);
menu.setBackgroundColor(0xFFFF);

menu.setForegroundColor(ST77XX_GREEN);
menu.setBackgroundColor(ST77XX_BLACK);
// or
menu.setForegroundColor(0x07E0);
menu.setBackgroundColor(0x0000);

menu.setForegroundColor(ST77XX_ORANGE);
menu.setBackgroundColor(ST77XX_BLACK);
// or
menu.setForegroundColor(0xFC00);
menu.setBackgroundColor(0x0000);

menu.setForegroundColor(ST77XX_WHITE);
menu.setBackgroundColor(ST77XX_BLUE);
// or
menu.setForegroundColor(0xFFFF);
menu.setBackgroundColor(0x001F);