110b5baaea4c8dd319e59b0ed2e47437e9aab435
[hackover2013-badge-firmware.git] / badge / ui / menu.c
1 #include "menu.h"
2
3 #include "event.h"
4 #include "font.h"
5 #include "sprite.h"
6
7 #include <stdbool.h>
8
9 enum {
10 MENU_ARROW_UP,
11 MENU_ARROW_DOWN
12 };
13
14 static badge_sprite const arrows[] = {
15 { 5, 7, (uint8_t const *) "\x04\xc3\xdf\x40" },
16 { 5, 7, (uint8_t const *) "\x10\xd8\x1f\x06\x01" }
17 };
18
19 enum {
20 MENU_MARGIN_TOP = 2,
21 MENU_MARGIN_BOTTOM = 3,
22 MENU_MARGIN_LEFT = 3,
23 MENU_ENTRIES_HEIGHT = 1 + BADGE_FONT_HEIGHT,
24 MENU_ENTRIES_VISIBLE = (BADGE_DISPLAY_HEIGHT - MENU_MARGIN_TOP - MENU_MARGIN_BOTTOM) / MENU_ENTRIES_HEIGHT
25 };
26
27 static void badge_menu_show(char const *const *menu,
28 size_t n,
29 size_t first_visible,
30 size_t selected)
31 {
32 badge_framebuffer fb = { { { 0 } } };
33 bool arrow_up = true;
34 bool arrow_down = true;
35
36 size_t first_used_row = 0;
37 size_t used_rows = MENU_ENTRIES_VISIBLE;
38
39 if(n <= MENU_ENTRIES_VISIBLE) {
40 first_visible = 0;
41 used_rows = n;
42 first_used_row = (MENU_ENTRIES_VISIBLE - used_rows) / 2;
43 }
44
45 if(first_visible == 0) {
46 arrow_up = false;
47 }
48
49 if(first_visible + MENU_ENTRIES_VISIBLE >= n) {
50 arrow_down = false;
51 }
52
53 for(size_t i = 0; i < used_rows; ++i) {
54 badge_framebuffer_render_text(&fb,
55 (int8_t) (MENU_MARGIN_LEFT + BADGE_FONT_WIDTH),
56 (int8_t) (MENU_MARGIN_TOP + (first_used_row + i) * MENU_ENTRIES_HEIGHT),
57 menu[first_visible + i]);
58 }
59
60 badge_framebuffer_render_char(&fb, MENU_MARGIN_LEFT, MENU_MARGIN_TOP + MENU_ENTRIES_HEIGHT * (selected - first_visible + first_used_row), '*');
61 if(arrow_up ) { badge_framebuffer_blt(&fb, MENU_MARGIN_LEFT, MENU_MARGIN_TOP, &arrows[MENU_ARROW_UP ], 0); }
62 if(arrow_down) { badge_framebuffer_blt(&fb, MENU_MARGIN_LEFT, MENU_MARGIN_TOP + (MENU_ENTRIES_VISIBLE - 1) * MENU_ENTRIES_HEIGHT, &arrows[MENU_ARROW_DOWN], 0); }
63
64 badge_framebuffer_flush(&fb);
65 }
66
67 size_t badge_menu(char const *const *menu,
68 size_t n,
69 size_t *first_visible,
70 size_t selected)
71 {
72 unsigned scroll_ticks = 0;
73 int scroll_direction = 0;
74
75 for(;;) {
76 if(scroll_ticks == 0) {
77 if (scroll_direction == 1 && selected + 1 < n) {
78 ++selected;
79 } else if(scroll_direction == -1 && selected != 0) {
80 --selected;
81 }
82
83 if(n <= MENU_ENTRIES_VISIBLE) {
84 *first_visible = 0;
85 } else if(selected + 1 == n) {
86 *first_visible = n - MENU_ENTRIES_VISIBLE;
87 } else if(selected <= *first_visible) {
88 *first_visible = selected == 0 ? 0 : selected - 1;
89 } else if(selected - *first_visible + 2 > MENU_ENTRIES_VISIBLE) {
90 *first_visible = selected - MENU_ENTRIES_VISIBLE + 2;
91 }
92
93 badge_menu_show(menu, n, *first_visible, selected);
94
95 scroll_ticks = 25;
96 }
97
98 badge_event_t ev;
99
100 ev = badge_event_wait();
101 switch(badge_event_type(ev)) {
102 case BADGE_EVENT_USER_INPUT:
103 {
104 uint8_t old_state = badge_event_old_input_state(ev);
105 uint8_t new_state = badge_event_new_input_state(ev);
106 uint8_t new_buttons = new_state & (old_state ^ new_state);
107
108 if(new_buttons & (BADGE_EVENT_KEY_BTN_A | BADGE_EVENT_KEY_BTN_B)) {
109 return selected;
110 } else if((new_buttons & BADGE_EVENT_KEY_UP )) {
111 scroll_direction = -1;
112 } else if((new_buttons & BADGE_EVENT_KEY_DOWN)) {
113 scroll_direction = 1;
114 } else {
115 scroll_direction = 0;
116 }
117
118 scroll_ticks = 0;
119 break;
120 }
121 case BADGE_EVENT_GAME_TICK:
122 {
123 --scroll_ticks;
124 break;
125 }
126 }
127 }
128 }
This page took 0.047947 seconds and 3 git commands to generate.