2. Core Menu Mechanics
The main norns interface is based around a simple menu selection idea. These components are implemented here.
2.1. typedef + struct
typedef struct norns_menu norns_menu;
<<norns_menu_item>>
struct norns_menu {
<<norns_menu_contents>>
};
2.2. Initialization
The norns menu is initialized with norns_menu_init
. Since
it doesn't allocate anything internally, no cleanup is
required.
void norns_menu_init(norns_menu *menu,
const char *name,
norns_videobuf *buf,
norns_menu_item *items,
int nitems,
norns_poll_d *poll,
void *ud);
void norns_menu_init(norns_menu *menu,
const char *name,
norns_videobuf *buf,
norns_menu_item *items,
int nitems,
norns_poll_d *poll,
void *ud)
{
<<norns_menu_init>>
norns_menu_callbacks(menu, poll);
}
static void norns_menu_callbacks(norns_menu *menu,
norns_poll_d *poll);
static void norns_menu_callbacks(norns_menu *menu,
norns_poll_d *poll)
{
<<norns_menu_callbacks>>
}
<<norns_menu_init_reinit>>
2.3. Re-Initialization
void norns_menu_reinit(norns_menu *menu,
const char *name,
norns_menu_item *items,
int nitems,
void *ud);
void norns_menu_reinit(norns_menu *menu,
const char *name,
norns_menu_item *items,
int nitems,
void *ud)
{
<<norns_menu_init_reinit>>
}
2.4. Core Menu Data
2.4.1. DONE Video Buffer
CLOSED: [2019-11-22 Fri 15:04]
A norns_videobuf
instance is supplied to at runtime. This
is what the norns will draw to.
norns_videobuf *buf;
menu->buf = buf;
2.4.2. DONE Menu Name
CLOSED: [2019-11-22 Fri 15:04] Every menu has a "name", displayed at the top of the screen
const char *name;
menu->name = name;
2.4.3. DONE Menu Items
CLOSED: [2019-11-22 Fri 15:04] Every menu has an array of zero or more items. This is assigned at initialization, and must be allocated externally. The size must be known as well.
norns_menu_item *items;
int nitems;
menu->items = items;
menu->nitems = nitems;
2.4.4. DONE Selected Item
CLOSED: [2019-11-22 Fri 15:04] Selected item starts at 1, so that 0 means nothing is selected. It is zero by default.
int selected;
menu->selected = 0;
2.4.5. User Data
void *ud;
menu->ud = ud;
2.4.6. Counter + Speed
Used to limit the speed of the knob turn.
The weight
variable changes the speed of this knob.
The larger the value, the slower it gets.
int counter;
int weight;
menu->counter = 0;
menu->weight = 2;
2.4.7. Offset
Display offset, for when values go over.
int offset;
menu->offset = 0;
2.5. A single menu item
A menu item has a "name", and an action of what to do when selected. Presumably, these are stored in a constant, which is why the struct is exposed in the header.
typedef struct {
const char *name;
void (*select)(norns_menu *, int);
} norns_menu_item;
2.6. Drawing the Menu
2.6.1. DONE Top Level Draw
CLOSED: [2019-11-22 Fri 14:59] Call this to (re)draw the menu to the video buffer. This does not copy to the framebuffer.
void norns_menu_draw(norns_menu *menu);
void norns_menu_draw(norns_menu *menu)
{
norns_videobuf *vb;
vb = menu->buf;
norns_videobuf_clear(vb);
<<draw_the_header>>
<<draw_menu_items>>
}
2.6.2. DONE Write the header
CLOSED: [2019-11-22 Fri 21:08] Write the header at the top. Write a line separting the header and the menu items.
static void norns_menu_header(norns_menu *menu);
static void norns_menu_header(norns_menu *menu)
{
int i;
norns_draw_string(menu->buf,
0, 0,
0xff, 0x00,
menu->name);
for (i = 0; i < 128; i++) {
norns_videobuf_write(menu->buf, i, 11, 0xff);
}
}
norns_menu_header(menu);
2.6.3. DONE Write items
CLOSED: [2019-11-22 Fri 21:14] Draw the items based on the current top position. Make sure the currently selected item is inverted. (black text on white instead of white text on black).
{
int i;
int item;
int x, y;
int selected;
unsigned char bg;
unsigned char fg;
int nrows;
selected = menu->selected;
nrows = menu->nitems - menu->offset;
if (nrows > 6) nrows = 6;
if (nrows < 0) nrows = 0;
for (i = 0; i < nrows; i++) {
item = menu->offset + i;
if ((item + 1) == selected) {
fg = 0x00;
bg = 0xff;
for (y = 0; y < 10; y++) {
for (x = 0; x < 128; x++) {
norns_videobuf_write(menu->buf,
x, (14 + 9*i) + y,
0xff);
}
}
} else {
fg = 0xff;
bg = 0x00;
}
norns_draw_string(vb,
0, 15 + 9*i,
fg, bg,
menu->items[item].name);
}
}
2.7. Peripheral callbacks
2.7.1. DONE Setting Peripheral Callbacks
CLOSED: [2019-11-23 Sat 13:01]
{
<<set_key_callback>>
<<set_knob_callback>>
}
2.7.2. DONE Key
CLOSED: [2019-11-23 Sat 13:01] Key 0 is used as a selection button.
static void menu_key(void *ud, int state);
static void menu_key(void *ud, int state)
{
norns_menu *menu;
int selected;
if (state == 0) return;
menu = ud;
selected = menu->selected;
if (selected > 0) {
void (*f)(norns_menu *, int);
selected--;
f = menu->items[selected].select;
if (f != NULL) {
f(menu, selected);
}
}
}
norns_poll_cb_key(poll, 1, menu_key, menu);
2.7.3. DONE Knob
CLOSED: [2019-11-23 Sat 13:01] Knob is used to scroll up + down the menu.
static void menu_knob(void *ud, int pos);
void monolith_norns_draw(monolith_d *m);
static void menu_knob(void *ud, int pos)
{
norns_menu *menu;
menu = ud;
norns_menu_step(menu, pos);
norns_menu_draw(menu);
monolith_norns_draw(monolith_data_get());
}
static void norns_menu_step(norns_menu *menu, int pos);
static void norns_menu_step(norns_menu *menu, int pos)
{
int selected;
int offset;
menu->counter = (menu->counter + 1) % menu->weight;
if (menu->counter != 0) return;
selected = menu->selected;
offset = menu->offset;
selected += pos;
if (selected < 1) {
selected = 1;
offset = 0;
}
if (selected > menu->nitems) {
selected = menu->nitems;
}
if ((selected - offset) > 5) {
offset++;
} else if ((selected - offset) <= 0) {
offset--;
}
menu->selected = selected;
menu->offset = offset;
}
norns_poll_cb_knob(poll, 1, menu_knob, menu);
prev | home | next