A better solution (I think) is to set all of your MenuLayer
callbacks to functions, and call menu_layer_reload_data()
when items change. Setting explicit callbacks for each section isn't the best solution if the number of rows is going to change during runtime, and especially not if you may end up with multiple sections or rows that have the same callback behavior. Plus, your code can become pretty messy if you have a lot of rows and/or sections. Unless the callbacks that you want to apply are different for each row or section, the callbacks should be set one time, in one place for all rows.
The SimpleMenu
example was designed primarily for non-dynamic menus. You should look at the demo from demos/feature_menu_layer
instead for how to pull off dynamic menus as intended. A better solution (IMO) is to setup callbacks for the entire MenuLayer
(and not use SimpleMenuLayer
)
I would do something more like this:
MenuLayer menu_layer;
uint16_t menu_get_num_sections_callback( MenuLayer *me, void *data )
{
return 1; // for now, there is only ever 1 section
}
uint16_t menu_get_num_rows_callback(MenuLayer *me, uint16_t section_index, void *data)
{
return my_var_that_holds_current_row_count;
}
int16_t menu_get_header_height_callback( MenuLayer *me, uint16_t section_index, void *data )
{
return MENU_CELL_BASIC_HEADER_HEIGHT;
}
void menu_draw_header_callback(GContext* ctx, const Layer *cell_layer, uint16_t section_index, void *data)
{
menu_cell_basic_header_draw( ctx, cell_layer, "Things to buy..." );
}
void menu_draw_row_callback( GContext* ctx, const Layer *cell_layer, MenuIndex *cell_index, void *data )
{
switch( cell_index->row )
{
// Fill in row content here
}
}
void window_load( Window *me )
{
// ... other window code here
// Set all the callbacks for the menu layer
menu_layer_set_callbacks( &menu_layer, NULL, (MenuLayerCallbacks )
{
.get_num_sections = menu_get_num_sections_callback,
.get_num_rows = menu_get_num_rows_callback,
.get_header_height = menu_get_header_height_callback,
.get_cell_height = menu_get_cell_height_callback,
.draw_header = menu_draw_header_callback,
.draw_row = menu_draw_row_callback,
});
}
If you take this approach, all you need to do to refresh the menu is:
- Update your variable that holds the number of rows
- Update the variables that hold row/cell content
- Call
menu_layer_reload_data( menu_layer )
This method requires less setup than the SimpleMenuLayer
approach, removes repeated calls to similar/same functions (which become error-prone as an app grows) throughout the menu, makes code easier to read and understand, and is more inline with how other APIs/SDKs approach accomplishing the same goal.
I also think that it's how the folks at Pebble intended for dynamic menus to be implemented, and if you compare this to the feature_simple_menu_layer
example, I think you'll agree that this is a much cleaner and easier to understand implementation of a dynamic menu.