0

This is a specific question, but I post it anyway...

I can't change a static variable at runtime. My problem is that I can't change the number of rows in a list view on runtime. It works with the code below but this list is now static. If the user wants to add or remove one item, the list in this example still has 5 rows.

These are the lines of the script concerning the items in a section:

#include "pebble_os.h"
#include "pebble_app.h"
#include "pebble_fonts.h"
#include "settings.h"

static Window window;
static SimpleMenuLayer menu_layer;
static SimpleMenuSection menu_sections[1];
static SimpleMenuItem menu_section0_items[5];

[..]

void init_settings_window()

[..]

    menu_sections[0] = (SimpleMenuSection) {
        .title = "Things to buy...",
        .items = menu_section0_items,
        .num_items = ARRAY_LENGTH(menu_section0_items)
    };

The definition of SimpleMenuSection from the API Reference:

struct SimpleMenuSection
Data structure containing the information of a menu section.

Data Fields
const SimpleMenuItem *   items   Array of items in the section.
uint32_t     num_items   Number of items in the .items array.
const char *     title   Title of the section. Optional, leave NULL if unused.
Charles
  • 50,943
  • 13
  • 104
  • 142
Peter
  • 183
  • 2
  • 12
  • I don't understand, _what_ is the thing you want to change at runtime? – Daniel Fischer May 30 '13 at 15:58
  • Was not easy explained by me, sorry. But I solved it (hopefully). In static SimpleMenuItem menu_section0_items[5]; I am able to set the maximum items in a section. In this line .items = menu_section0_items I exchanged menu_section0_items with an uint32_t variable. Now it works. Perhaps it is better to delete this question :( – Peter May 30 '13 at 16:25

2 Answers2

1

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:

  1. Update your variable that holds the number of rows
  2. Update the variables that hold row/cell content
  3. 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.

Chris Ostmo
  • 1,202
  • 1
  • 10
  • 21
0

You may need to use variable length array to determine the array size at runtime. Varialble length array is the part of c99 std and available with gcc compiler.

akhil
  • 732
  • 3
  • 13