vanity-convert: add Makefile
[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 MENU_SCROLL_TICKS = 25
14 };
15
16 static badge_sprite const arrows[] = {
17 { 5, 7, (uint8_t const *) "\x04\xc3\xdf\x40" },
18 { 5, 7, (uint8_t const *) "\x10\xd8\x1f\x06\x01" }
19 };
20
21 enum {
22 MENU_MARGIN_TOP = 3,
23 MENU_MARGIN_BOTTOM = 2,
24 MENU_MARGIN_LEFT = 3,
25 MENU_ENTRIES_HEIGHT = 1 + BADGE_FONT_HEIGHT,
26 MENU_ENTRIES_VISIBLE = (BADGE_DISPLAY_HEIGHT - MENU_MARGIN_TOP - MENU_MARGIN_BOTTOM) / MENU_ENTRIES_HEIGHT
27 };
28
29 static void badge_menu_show(char const *const *menu,
30 uint8_t n,
31 uint8_t *first_visible,
32 uint8_t selected,
33 char selector)
34 {
35 badge_framebuffer fb = { { { 0 } } };
36 bool arrow_up = true;
37 bool arrow_down = true;
38
39 uint8_t first_used_row = 0;
40 uint8_t used_rows = MENU_ENTRIES_VISIBLE;
41
42 if(selected >= n) {
43 selected = n - 1;
44 }
45
46 if(n <= MENU_ENTRIES_VISIBLE) {
47 *first_visible = 0;
48 used_rows = n;
49 first_used_row = (MENU_ENTRIES_VISIBLE - used_rows) / 2;
50 } else if(*first_visible + MENU_ENTRIES_VISIBLE > n) {
51 *first_visible = n - MENU_ENTRIES_VISIBLE;
52 } else if(selected + 1 == n) {
53 *first_visible = n - MENU_ENTRIES_VISIBLE;
54 } else if(selected <= *first_visible) {
55 *first_visible = selected == 0 ? 0 : selected - 1;
56 } else if(selected - *first_visible + 2 > MENU_ENTRIES_VISIBLE) {
57 *first_visible = selected - MENU_ENTRIES_VISIBLE + 2;
58 }
59
60 if(*first_visible == 0) {
61 arrow_up = false;
62 }
63
64 if(*first_visible + MENU_ENTRIES_VISIBLE >= n) {
65 arrow_down = false;
66 }
67
68 for(uint8_t i = 0; i < used_rows; ++i) {
69 badge_framebuffer_render_text(&fb,
70 (int8_t) (MENU_MARGIN_LEFT + BADGE_FONT_WIDTH),
71 (int8_t) (MENU_MARGIN_TOP + (first_used_row + i) * MENU_ENTRIES_HEIGHT),
72 menu[*first_visible + i]);
73 }
74
75 badge_framebuffer_render_char(&fb, MENU_MARGIN_LEFT, MENU_MARGIN_TOP + MENU_ENTRIES_HEIGHT * (selected - *first_visible + first_used_row), selector);
76 if(arrow_up ) { badge_framebuffer_blt(&fb, MENU_MARGIN_LEFT, MENU_MARGIN_TOP, &arrows[MENU_ARROW_UP ], 0); }
77 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); }
78
79 badge_framebuffer_flush(&fb);
80 }
81
82 uint8_t badge_menu(char const *const *menu,
83 uint8_t n,
84 uint8_t *first_visible,
85 uint8_t selected)
86 {
87 unsigned scroll_ticks = 0;
88 int scroll_direction = 0;
89
90 for(;;) {
91 if(scroll_ticks == 0) {
92 if (scroll_direction == 1 && selected + 1 < n) {
93 ++selected;
94 } else if(scroll_direction == -1 && selected != 0) {
95 --selected;
96 }
97
98 badge_menu_show(menu, n, first_visible, selected, '*');
99
100 scroll_ticks = MENU_SCROLL_TICKS;
101 }
102
103 badge_event_t ev;
104
105 ev = badge_event_wait();
106 switch(badge_event_type(ev)) {
107 case BADGE_EVENT_USER_INPUT:
108 {
109 uint8_t old_state = badge_event_old_input_state(ev);
110 uint8_t new_state = badge_event_new_input_state(ev);
111 uint8_t new_buttons = new_state & (old_state ^ new_state);
112
113 if(new_buttons & (BADGE_EVENT_KEY_BTN_A | BADGE_EVENT_KEY_BTN_B)) {
114 return selected;
115 } else if((new_buttons & BADGE_EVENT_KEY_UP )) {
116 scroll_direction = -1;
117 } else if((new_buttons & BADGE_EVENT_KEY_DOWN)) {
118 scroll_direction = 1;
119 } else {
120 scroll_direction = 0;
121 }
122
123 scroll_ticks = 0;
124 break;
125 }
126 case BADGE_EVENT_GAME_TICK:
127 {
128 --scroll_ticks;
129 break;
130 }
131 }
132 }
133 }
134
135 void badge_scroll_text(char const *const *lines, uint8_t n) {
136 uint8_t first_visible = 0;
137 int scroll_direction = 0;
138 unsigned scroll_ticks = 0;
139
140 for(;;) {
141 if(scroll_ticks == 0) {
142 if (scroll_direction == 1 && first_visible + MENU_ENTRIES_VISIBLE < n) {
143 ++first_visible;
144 } else if(scroll_direction == -1 && first_visible != 0) {
145 --first_visible;
146 }
147
148 badge_menu_show(lines, n, &first_visible, first_visible + (first_visible + 1 == n ? 0 : 1), ' ');
149
150 scroll_ticks = MENU_SCROLL_TICKS;
151 }
152
153 badge_event_t ev;
154
155 ev = badge_event_wait();
156 switch(badge_event_type(ev)) {
157 case BADGE_EVENT_USER_INPUT:
158 {
159 uint8_t old_state = badge_event_old_input_state(ev);
160 uint8_t new_state = badge_event_new_input_state(ev);
161 uint8_t new_buttons = new_state & (old_state ^ new_state);
162
163 if(new_buttons & (BADGE_EVENT_KEY_BTN_A | BADGE_EVENT_KEY_BTN_B)) {
164 return;
165 } else if((new_buttons & BADGE_EVENT_KEY_UP )) {
166 scroll_direction = -1;
167 } else if((new_buttons & BADGE_EVENT_KEY_DOWN)) {
168 scroll_direction = 1;
169 } else {
170 scroll_direction = 0;
171 }
172
173 scroll_ticks = 0;
174 break;
175 }
176 case BADGE_EVENT_GAME_TICK:
177 {
178 --scroll_ticks;
179 break;
180 }
181 }
182 }
183 }
This page took 0.052057 seconds and 5 git commands to generate.