MenĂ¼.
authorWintermute <wintermute@hannover.ccc.de>
Sun, 20 Oct 2013 19:02:23 +0000 (21:02 +0200)
committerWintermute <wintermute@hannover.ccc.de>
Sun, 20 Oct 2013 19:02:23 +0000 (21:02 +0200)
badge/ui/menu.c [new file with mode: 0644]
badge/ui/menu.h [new file with mode: 0644]
mock/Makefile
mock/badge_main_loop.c

diff --git a/badge/ui/menu.c b/badge/ui/menu.c
new file mode 100644 (file)
index 0000000..e4eaac7
--- /dev/null
@@ -0,0 +1,99 @@
+#include "menu.h"
+
+#include "event.h"
+#include "font.h"
+#include "sprite.h"
+
+#include <stdbool.h>
+
+enum {
+  MENU_ARROW_UP,
+  MENU_ARROW_DOWN
+};
+
+static badge_sprite const arrows[] = {
+  { 5, 7, (uint8_t const *) "\x04\xc3\xdf\x40" },
+  { 5, 7, (uint8_t const *) "\x10\xd8\x1f\x06\x01" }
+};
+
+enum {
+  MENU_MARGIN_TOP      = 2,
+  MENU_MARGIN_BOTTOM   = 3,
+  MENU_MARGIN_LEFT     = 3,
+  MENU_ENTRIES_HEIGHT  = 1 + BADGE_FONT_HEIGHT,
+  MENU_ENTRIES_VISIBLE = (BADGE_DISPLAY_HEIGHT - MENU_MARGIN_TOP - MENU_MARGIN_BOTTOM) / MENU_ENTRIES_HEIGHT
+};
+
+static void badge_menu_show(char const *const *menu,
+                            size_t n,
+                            size_t first_visible,
+                            size_t selected)
+{
+  badge_framebuffer fb = { { { 0 } } };
+  bool arrow_up   = true;
+  bool arrow_down = true;
+
+  size_t first_used_row = 0;
+  size_t used_rows = MENU_ENTRIES_VISIBLE;
+
+  if(n <= MENU_ENTRIES_VISIBLE) {
+    first_visible  = 0;
+    used_rows      = n;
+    first_used_row = (MENU_ENTRIES_VISIBLE - used_rows) / 2;
+  }
+
+  if(first_visible == 0) {
+    arrow_up = false;
+  }
+
+  if(first_visible + MENU_ENTRIES_VISIBLE >= n) {
+    arrow_down = false;
+  }
+
+  for(size_t i = 0; i < used_rows; ++i) {
+    badge_framebuffer_render_text(&fb,
+                                  (int8_t) (MENU_MARGIN_LEFT + BADGE_FONT_WIDTH),
+                                  (int8_t) (MENU_MARGIN_TOP  + (first_used_row + i) * MENU_ENTRIES_HEIGHT),
+                                  menu[first_visible + i]);
+  }
+
+  badge_framebuffer_render_char(&fb, MENU_MARGIN_LEFT, MENU_MARGIN_TOP + MENU_ENTRIES_HEIGHT * (selected - first_visible + first_used_row), '*');
+  if(arrow_up  ) { badge_framebuffer_blt(&fb, MENU_MARGIN_LEFT, MENU_MARGIN_TOP,                                                    &arrows[MENU_ARROW_UP  ], 0); }
+  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); }
+
+  badge_framebuffer_flush(&fb);
+}
+
+size_t badge_menu(char const *const *menu,
+                   size_t n,
+                   size_t first_visible,
+                   size_t selected)
+{
+  for(;;) {
+    badge_menu_show(menu, n, first_visible, selected);
+
+    badge_event_t ev;
+
+    do {
+      ev = badge_event_wait();
+    } while(badge_event_type(ev) != BADGE_EVENT_USER_INPUT);
+
+    uint8_t old_state = badge_event_old_input_state(ev);
+    uint8_t new_state = badge_event_new_input_state(ev);
+    uint8_t new_buttons = new_state & (old_state ^ new_state);
+
+    if(new_buttons & (BADGE_EVENT_KEY_BTN_A | BADGE_EVENT_KEY_BTN_B)) {
+      return selected;
+    } else if((new_buttons & BADGE_EVENT_KEY_UP  ) && selected != 0) {
+      --selected;
+      if(first_visible != 0 && selected <= first_visible) {
+        first_visible = selected - 1;
+      }
+    } else if(new_buttons & BADGE_EVENT_KEY_DOWN && selected + 1 < n) {
+      ++selected;
+      if(first_visible + (MENU_ENTRIES_VISIBLE - 2 + (selected + 1 == n)) < selected) {
+        first_visible = selected - (MENU_ENTRIES_VISIBLE - 2 + (selected + 1 == n));
+      }
+    }
+  }
+}
diff --git a/badge/ui/menu.h b/badge/ui/menu.h
new file mode 100644 (file)
index 0000000..712618d
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef INCLUDED_BADGE_UI_MENU_H
+#define INCLUDED_BADGE_UI_MENU_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+size_t badge_menu(char const *const * menu,
+                  size_t n,
+                  size_t first_visible,
+                  size_t preselected);
+
+#endif
index 969b2b4..de9d367 100644 (file)
@@ -17,6 +17,7 @@ BADGE_CXXSRCS = mock-main.cc \
 BADGE_CSRCS   = badge_main_loop.c
 
 BADGE_FAROBJS = ui/font.o \
+                ui/menu.o \
                 ui/sprite.o \
                 jumpnrun/collision.o \
                 jumpnrun/enemies.o \
index 0f8b880..3a1c3d2 100644 (file)
@@ -3,6 +3,7 @@
 #include "jumpnrun/jumpnrun.h"
 #include "ui/display.h"
 #include "ui/event.h"
+#include "ui/menu.h"
 #include "ui/sprite.h"
 
 #include <stdint.h>
 #include <unistd.h>
 
 void badge_main_loop(void) {
+  char const *const menu[] = {
+    "smb",
+    "skynet",
+    "wrongturn",
+    "lubiXOXO",
+    "lubilove",
+    "gnobbel",
+    "foo",
+    "mean",
+    "xyzzy",
+    "abc",
+    "nonsense"
+  };
+
+  size_t choice = badge_menu(menu, ARRAY_SIZE(menu), 0, 0);
+
+  printf("%zu\n", choice);
 
   for(;;) {
     FILE *fd = fopen("../badge/jumpnrun/levels.txt", "r");
This page took 0.03865 seconds and 4 git commands to generate.