summaryrefslogtreecommitdiffstats
path: root/common/menu.c
diff options
context:
space:
mode:
authorJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>2010-08-20 10:22:47 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2010-08-30 20:57:20 +0200
commitb712b26632d4af1e1c9454a3b330ed7b401e165b (patch)
treedecefbfa56cfc958731d7455cf0aab6605e5d5e4 /common/menu.c
parent0db2f6367712cafd91460af7816f1180fa1b5446 (diff)
downloadbarebox-b712b26632d4af1e1c9454a3b330ed7b401e165b.tar.gz
Add Menu Framework
Introduce a menu framework that allow us to create list menu to simplify barebox and make it more user-frendly This kind of menu is very usefull when you do not have a keyboard or a serial console attached to your board to allow you to interract with barebox For the develloper part, The framework introduce two API 1) C that allow you to create menu, submenu, entry and complex menu action 2) Command that allow you as the C API to create menu, submenu, entry and complex menu action but this time the actions will be store in a function and then be evaluated and excecuted at runtime. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'common/menu.c')
-rw-r--r--common/menu.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/common/menu.c b/common/menu.c
new file mode 100644
index 0000000..e03e4d1
--- /dev/null
+++ b/common/menu.c
@@ -0,0 +1,315 @@
+/*
+ * (C) Copyright 2009-2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <init.h>
+#include <menu.h>
+#include <malloc.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <readkey.h>
+
+static struct menu menus;
+
+struct menu* menu_get_menus(void)
+{
+ return &menus;
+}
+
+void menu_free(struct menu *m)
+{
+ struct list_head *pos;
+ struct menu_entry *me;
+
+ if (!m)
+ return;
+ free(m->name);
+ free(m->display);
+
+ pos = &m->entries.list;
+
+ if (pos->prev != pos->next && pos->prev != 0)
+ list_for_each(pos, &m->entries.list) {
+ me = list_entry(pos, struct menu_entry, list);
+ menu_entry_free(me);
+ }
+
+ free(m);
+}
+
+int menu_add(struct menu *m)
+{
+ if (!m || !m->name)
+ return -EINVAL;
+
+ if (menu_get_by_name(m->name))
+ return -EEXIST;
+
+ list_add_tail(&m->list, &menus.list);
+
+ m->nb_entries = 0;
+
+ INIT_LIST_HEAD(&m->entries.list);
+
+ return 0;
+}
+
+void menu_remove(struct menu *m)
+{
+ if (!m)
+ return;
+
+ list_del(&m->list);
+}
+
+int menu_add_entry(struct menu *m, struct menu_entry *me)
+{
+ int len;
+
+ if (!m || !me || !me->display)
+ return -EINVAL;
+
+ len = strlen(me->display);
+
+ m->width = max(len, m->width);
+
+ m->nb_entries++;
+ me->num = m->nb_entries;
+ list_add_tail(&me->list, &m->entries.list);
+
+ return 0;
+}
+
+void menu_remove_entry(struct menu *m, struct menu_entry *me)
+{
+ struct list_head *pos;
+ int i = 1;
+
+ if (!m || !me)
+ return;
+
+ m->nb_entries--;
+ list_del(&me->list);
+
+ list_for_each(pos, &m->entries.list) {
+ me = list_entry(pos, struct menu_entry, list);
+ me->num = i++;
+ }
+}
+
+struct menu* menu_get_by_name(char *name)
+{
+ struct list_head *pos;
+ struct menu* m;
+
+ if (!name)
+ return NULL;
+
+ list_for_each(pos, &menus.list) {
+ m = list_entry(pos, struct menu, list);
+ if(strcmp(m->name, name) == 0)
+ return m;
+ }
+
+ return NULL;
+}
+
+struct menu_entry* menu_entry_get_by_num(struct menu* m, int num)
+{
+ struct list_head *pos;
+ struct menu_entry* me;
+
+ if (!m || num < 1 || num > m->nb_entries)
+ return NULL;
+
+ list_for_each(pos, &m->entries.list) {
+ me = list_entry(pos, struct menu_entry, list);
+ if(me->num == num)
+ return me;
+ }
+
+ return NULL;
+}
+
+void menu_entry_free(struct menu_entry *me)
+{
+ if (!me)
+ return;
+
+ free(me->display);
+ free(me);
+}
+
+static void print_menu_entry(struct menu *m, struct menu_entry *me, int reverse)
+{
+ gotoXY(me->num + 1, 3);
+ if (reverse)
+ printf_reverse("%d: %-*s", me->num, m->width, me->display);
+ else
+ printf("%d: %-*s", me->num, m->width, me->display);
+}
+
+int menu_set_selected_entry(struct menu *m, struct menu_entry* me)
+{
+ struct list_head *pos;
+ struct menu_entry* tmp;
+
+ if (!m || !me)
+ return -EINVAL;
+
+ list_for_each(pos, &m->entries.list) {
+ tmp = list_entry(pos, struct menu_entry, list);
+ if(me == tmp) {
+ m->selected = me;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int menu_set_selected(struct menu *m, int num)
+{
+ struct menu_entry *me;
+
+ me = menu_entry_get_by_num(m, num);
+
+ if (!me)
+ return -EINVAL;
+
+ m->selected = me;
+
+ return 0;
+}
+
+static void print_menu(struct menu *m)
+{
+ struct list_head *pos;
+ struct menu_entry *me;
+
+ clear();
+ gotoXY(1, 2);
+ if(m->display) {
+ puts(m->display);
+ } else {
+ puts("Menu : ");
+ puts(m->name);
+ }
+
+ list_for_each(pos, &m->entries.list) {
+ me = list_entry(pos, struct menu_entry, list);
+ if(m->selected != me)
+ print_menu_entry(m, me, 0);
+ }
+
+ if (!m->selected) {
+ m->selected = list_first_entry(&m->entries.list,
+ struct menu_entry, list);
+ }
+
+ print_menu_entry(m, m->selected, 1);
+}
+
+int menu_show(struct menu *m)
+{
+ int ch;
+ int escape = 0;
+
+ if(!m || list_empty(&m->entries.list))
+ return -EINVAL;
+
+ print_menu(m);
+
+ do {
+ ch = getc();
+ switch(ch) {
+ case 0x1b:
+ escape = 1;
+ break;
+ case '[':
+ if (escape)
+ break;
+ case 'A': /* up */
+ escape = 0;
+ print_menu_entry(m, m->selected, 0);
+ m->selected = list_entry(m->selected->list.prev, struct menu_entry,
+ list);
+ if (&(m->selected->list) == &(m->entries.list)) {
+ m->selected = list_entry(m->selected->list.prev, struct menu_entry,
+ list);
+ }
+ print_menu_entry(m, m->selected, 1);
+ break;
+ case 'B': /* down */
+ escape = 0;
+ print_menu_entry(m, m->selected, 0);
+ m->selected = list_entry(m->selected->list.next, struct menu_entry,
+ list);
+ if (&(m->selected->list) == &(m->entries.list)) {
+ m->selected = list_entry(m->selected->list.next, struct menu_entry,
+ list);
+ }
+ print_menu_entry(m, m->selected, 1);
+ break;
+ case '\n':
+ case '\r':
+ clear();
+ gotoXY(1,1);
+ m->selected->action(m, m->selected);
+ if (m->selected->non_re_ent)
+ return m->selected->num;
+ else
+ print_menu(m);
+ default:
+ break;
+ }
+ } while(1);
+
+ return 0;
+}
+
+void menu_action_exit(struct menu *m, struct menu_entry *me) {}
+
+void menu_action_run(struct menu *m, struct menu_entry *me)
+{
+ int ret;
+ const char *s = getenv((const char*)me->priv);
+
+ /* can be a command as boot */
+ if (!s)
+ s = me->priv;
+
+ ret = run_command (s, 0);
+
+ if (ret < 0)
+ udelay(1000000);
+}
+
+static int menu_init(void)
+{
+ INIT_LIST_HEAD(&menus.list);
+
+ return 0;
+}
+postcore_initcall(menu_init);