Skip to content

Drop Down Menu

Drop down menus are versatile GUI elements that allow users to select from a list of options. The GUIDropDownMenu class, along with the GUIDropDownMenuItem class, provides a robust implementation of this functionality. Below is the detailed documentation for these classes.

A dropdown button that says "test"

GUIDropDownMenu

Constructor

GUIDropDownMenu(
    uint16_t leftX, uint16_t topY, uint16_t rightX, uint16_t bottomY,
    uint16_t eventID
)

Creates a drop down menu with the specified bounding box and event ID.

  • leftX, topY, rightX, bottomY: Coordinates defining the bounding box of the drop down menu.
  • eventID: The event ID for the drop down menu.

Methods

SetScrollBarVisibility

void SetScrollBarVisibility(ScrollBarVisibility visibility)

Sets the visibility of the scroll bar.

  • visibility: One of the ScrollBarVisibility enum values:
    • ScrollBarHidden: Always hide the scroll bar.
    • ScrollBarAlwaysVisible: Always show the scroll bar.
    • ScrollBarVisibleWhenRequired: Show the scroll bar only when required.

AddMenuItem

void AddMenuItem(GUIDropDownMenuItem &dropDownMenuItem)

Adds a menu item to the drop down menu.

  • dropDownMenuItem: The menu item to add.

GUIDropDownMenuItem

Constructor

GUIDropDownMenuItem(const char *s, int idx, int flags)

Creates a drop down menu item with the specified text, index, and flags.

  • s: The text displayed for the menu item.
  • idx: The index of the menu item.
  • flags: A bitfield of flags specified by bitwise-ORing members of the Flag enum (e.g., FlagTextAlignRight, FlagTextAlignLeft, FlagEnabled).

Flags

FlagTextAlignRight

FlagTextAlignRight = 1 << 5

Aligns the text of the item within the drop down to the right.

FlagTextAlignLeft

FlagTextAlignLeft = 1 << 6

Aligns the text of the item within the drop down to the left.

FlagEnabled

FlagEnabled = 1 << 15

Allows the item to be selected.

Usage

Here’s an example that demonstrates the creation and usage of a drop down menu with multiple items:

// parent is the dialog or parent container

const uint16_t APP_NAMES_EVENT_ID = 1;

GUIDropDownMenu m_appNames(
    parent.GetLeftX() + 10,
    parent.GetTopY() + 10,
    parent.GetRightX() - 10,
    parent.GetBottomY() - 10,
    APP_NAMES_EVENT_ID
);

// Adding items to the drop down menu
m_appNames.AddMenuItem(*(
    new GUIDropDownMenuItem(
        "Option 1", 1,
        GUIDropDownMenuItem::FlagEnabled | GUIDropDownMenuItem::FlagTextAlignLeft
    )
));

m_appNames.AddMenuItem(*(
    new GUIDropDownMenuItem(
        "Option 2", 2,
        GUIDropDownMenuItem::FlagEnabled | GUIDropDownMenuItem::FlagTextAlignLeft
    )
));

m_appNames.SetScrollBarVisibility(
    GUIDropDownMenu::ScrollBarVisibleWhenRequired
);

parent.AddElement(m_appNames);

Example Dialog Implementation

A real world usage example dialog class that uses the GUIDropDownMenu and GUIDropDownMenuItem is the actual Hollyhock 2 Launcher

Fruits Picker dialog

It’s important to note a few things there:

  • MenuItem index starts at 1, not 0
  • You can’t size the dropdown button, only the dropdown popup dialog

#include <appdef.hpp>
#include <sdk/os/debug.hpp>
#include <sdk/os/gui.hpp>
#include <sdk/os/lcd.hpp>
#include <sdk/os/mem.hpp>
#include <sdk/os/string.hpp>

/*
 * Fill this section in with some information about your app.
 * All fields are optional - so if you don't need one, take it out.
 */
APP_NAME("DropDown dialog app")
APP_DESCRIPTION("Testing a DropDown with a button")
APP_AUTHOR("Demo")
APP_VERSION("1.0.0")

class FruitSelector : public GUIDialog {
public:
  int m_selectedFruitIndex;

  FruitSelector()
      : GUIDialog(GUIDialog::Height95, GUIDialog::AlignTop,
                  "What's the best fruit?", GUIDialog::KeyboardStateNone),
        m_fruitDropDown(GetLeftX() + 10, GetTopY() + 10, GetRightX() - 10,
                        // You  can't size the dropdown picker element, only the
                        // dropdown menu size
                        GetBottomY() - 10, FRUIT_DROPDOWN_EVENT_ID),
        m_selectedFruitTextBox(GetLeftX() + 10, GetTopY() + 60,
                               GetRightX() - 10, GetTopY() + 100,
                               "The best fruit is: None selected"),
        m_selectButton(GetLeftX() + 10, GetTopY() + 110, GetRightX() - 10,
                       GetTopY() + 145, "Select", SELECT_BUTTON_EVENT_ID) {
    const char *fruits[] = {"Apple", "Banana", "Orange", "Grape", "Mango"};
    const int numFruits = sizeof(fruits) / sizeof(fruits[0]);

    for (int i = 0; i < numFruits; ++i) {
      m_fruitDropDown.AddMenuItem(*(new GUIDropDownMenuItem(
          fruits[i], i + 1, // off-by-one, indexes begin at 1 for the DropDown
          GUIDropDownMenuItem::FlagEnabled |
              GUIDropDownMenuItem::FlagTextAlignLeft)));
    }

    m_fruitDropDown.SetScrollBarVisibility(
        GUIDropDownMenu::ScrollBarVisibleWhenRequired);

    AddElement(m_fruitDropDown);
    AddElement(m_selectedFruitTextBox);
    AddElement(m_selectButton);
  }

  virtual int OnEvent(GUIDialog_Wrapped *dialog,
                      GUIDialog_OnEvent_Data *event) {
    if (event->GetEventID() == SELECT_BUTTON_EVENT_ID) {
      UpdateSelectedFruit();
      return 0;
    }

    if (event->GetEventID() == FRUIT_DROPDOWN_EVENT_ID &&
        (event->type & 0xF) == 0xD) {
      m_selectedFruitIndex = event->data - 1; // -1 to fox the off-by-one
      return 0;
    }

    return GUIDialog::OnEvent(dialog, event);
  }

  void UpdateSelectedFruit() {
    const char *fruits[] = {"Apple", "Banana", "Orange", "Grape", "Mango"};
    const int numFruits = sizeof(fruits) / sizeof(fruits[0]);

    if (m_selectedFruitIndex >= 0 && m_selectedFruitIndex < numFruits) {
      m_selectedFruitTextBox.SetText(fruits[m_selectedFruitIndex]);
      Refresh();
    }
  }

private:
  const uint16_t FRUIT_DROPDOWN_EVENT_ID = 1;
  const uint16_t SELECT_BUTTON_EVENT_ID = 2;

  GUIDropDownMenu m_fruitDropDown;
  GUITextBox m_selectedFruitTextBox;
  GUIButton m_selectButton;
};

int main() {
  FruitSelector fruitSelector;
  fruitSelector.ShowDialog();
  return 0;
}

This example creates a dialog with a drop down menu containing a list of fruits (“Apple”, “Banana”, “Orange”, “Grape”, “Mango”). There is a label initially displaying “The best fruit is: None selected” and a button labeled “Select”. When the button is pressed, the label is updated to show the selected fruit.