Patchwork [6/8] petitboot: Add generic UI menu support

login
register
mail settings
Submitter Geoff Levand
Date Feb. 16, 2009, 6:57 a.m.
Message ID <20090216065713.040962467@am.sony.com>
Download mbox | patch
Permalink /patch/23208/
State Accepted
Delegated to: Jeremy Kerr
Headers show

Comments

Geoff Levand - Feb. 16, 2009, 6:57 a.m.
Add support for a generic UI menu system.

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
---
 rules.mk         |    2 
 ui/common/menu.c |  284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ui/common/menu.h |  164 +++++++++++++++++++++++++++++++
 3 files changed, 449 insertions(+), 1 deletion(-)
Jeremy Kerr - Feb. 21, 2009, 3:22 a.m.
Hi Geoff,

> Add support for a generic UI menu system.

I'm in the middle of messing with the twin UI at the moment, so am not 
sure if this will suit. I'll let you know as I progress.

> +EXTERN_C struct menu *menu_init(void* ctx);
> +EXTERN_C void menu_delete(struct menu *menu);
> +EXTERN_C void menu_draw(const struct menu *menu);
> +EXTERN_C void menu_key_up(struct menu *menu);
> +EXTERN_C void menu_key_down(struct menu *menu);
> +EXTERN_C int menu_key_execute(struct menu *menu);
> +EXTERN_C void menu_set_item_text(struct menu *menu, struct menu_item

Do we actually have and C++ users of this?

Cheers,


Jeremy

Patch

--- a/rules.mk
+++ b/rules.mk
@@ -39,7 +39,7 @@  discover_objs = discover/udev.o discover
 	discover/device-handler.o discover/paths.o
 
 # client objs
-ui_common_objs = ui/common/discover-client.o
+ui_common_objs = ui/common/discover-client.o ui/common/menu.o
 ncurses_objs =
 twin_objs = ui/twin/pb-twin.o
 
--- /dev/null
+++ b/ui/common/menu.c
@@ -0,0 +1,284 @@ 
+/*
+ *  Copyright (C) 2009 Sony Computer Entertainment Inc.
+ *  Copyright 2009 Sony Corp.
+ *
+ *  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
+ */
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+
+#include "log/log.h"
+#include "talloc/talloc.h"
+#include "ui/common/menu.h"
+
+/**
+ * menu_item_init - Allocate and initialize a new menu_item instance.
+ *
+ * Returns a pointer the the initialized struct menu_item instance or NULL
+ * on error. The caller is responsible for calling talloc_free() for the
+ * returned instance.
+ */
+
+struct menu_item *menu_item_init(struct menu *menu, enum menu_item_type type,
+	enum menu_item_state state, const char* text)
+{
+	struct menu_item *i = talloc_zero(menu, struct menu_item);
+
+	if (i) {
+		i->i_sig = menu_item_sig;
+		i->type = type;
+		i->state = state;
+		i->text = text ? text : "";
+		i->status = "";
+	}
+
+	return i;
+}
+
+/**
+ * menu_item_delete - Delete a menu_item instance.
+ *
+ */
+
+void menu_item_delete(struct menu_item *i)
+{
+	assert(i->i_sig == menu_item_sig);
+	i->i_sig = menu_removed_sig;
+	talloc_free(i);
+}
+
+/**
+ * menu_item_set_text - Set menu_item text.
+ * @text: Reference taken, must be persistant.
+ */
+
+void menu_item_set_text(struct menu_item *i, const char *text)
+{
+	i->text = text ? text : "";
+}
+
+/**
+ * menu_init - Allocate and initialize a new menu instance.
+ *
+ * Returns a pointer the the initialized struct menu instance or NULL on error.
+ * The caller is responsible for calling talloc_free() for the returned
+ * instance.
+ */
+
+struct menu *menu_init(void* ctx)
+{
+	struct menu *menu = talloc_zero(ctx, struct menu);
+
+	if (menu) {
+		menu->m_sig = menu_sig;
+		list_init(&menu->items);
+	}
+
+	return menu;
+}
+
+/**
+ * menu_delete - Delete a menu instance.
+ *
+ */
+
+void menu_delete(struct menu *menu)
+{
+	assert(menu->m_sig == menu_sig);
+	menu->m_sig = menu_removed_sig;
+	talloc_free(menu);
+}
+
+/**
+ * menu_draw - Display the menu.
+ * @menu: A menu instance returned from menu_init().
+ */
+
+void menu_draw(const struct menu *menu)
+{
+	struct menu_item *i;
+	int y;
+
+	assert(menu->m_sig == menu_sig);
+	assert(menu->draw_item);
+
+	if (menu->draw_start)
+		menu->draw_start(menu);
+	y = 0;
+
+	list_for_each_entry(&menu->items, i, list)
+		if (i->state == state_visable || i->state == state_selected) {
+			assert(i->text);
+			menu->draw_item(menu, i, y++);
+		}
+
+	if (menu->draw_end)
+		menu->draw_end(menu);
+}
+
+static void menu_set_status(struct menu *menu, const char *text)
+{
+	if (menu->status)
+		menu_item_set_text(menu->status, text);
+}
+
+/**
+ * menu_key_up -
+ * @menu: A menu instance returned from menu_init().
+ *
+ * Calls menu_draw().
+ */
+
+void menu_key_up(struct menu *menu)
+{
+	struct menu_item *i;
+	struct menu_item *current = NULL;
+	struct menu_item *next = NULL;
+
+	assert(menu->m_sig == menu_sig);
+
+	list_for_each_entry(&menu->items, i, list) {
+		if (i->state == state_selected) {
+			current = i;
+			break;
+		}
+		if (i->type != type_text && i->state == state_visable)
+			next = i;
+	}
+
+	assert(current);
+
+	if (next) {
+		current->state = state_visable;
+		next->state = state_selected;
+		menu_set_status(menu, next->status);
+		menu_draw(menu);
+	}
+}
+
+/**
+ * menu_key_down -
+ * @menu: A menu instance returned from menu_init().
+ */
+
+void menu_key_down(struct menu *menu)
+{
+	struct menu_item *i;
+	struct menu_item *current = NULL;
+	struct menu_item *next = NULL;
+
+	assert(menu->m_sig == menu_sig);
+
+	list_for_each_entry(&menu->items, i, list)
+		if (i->state == state_selected) {
+			current = i;
+			break;
+		}
+
+	assert(current);
+
+	list_continue_each_entry(&menu->items, i, list)
+		if (i->type != type_text && i->state == state_visable) {
+			next = i;
+			break;
+		}
+
+	if (next) {
+		current->state = state_visable;
+		next->state = state_selected;
+		menu_set_status(menu, next->status);
+		menu_draw(menu);
+	}
+}
+
+/**
+ * menu_set_item_text - Set menu_item text and redraw menu.
+ */
+
+void menu_set_item_text(struct menu *menu, struct menu_item *i,
+	const char *text)
+{
+	menu_item_set_text(i, text);
+	menu_draw(menu);
+}
+
+/**
+ * menu_item_kexec - Run kexec with the supplied boot options.
+ * @opt: Pointer to a @struct boot_option data structure.
+ */
+
+static int menu_item_kexec(const struct menu_item_kexec *kexec)
+{
+	pb_log("%s: %s\n", __func__, kexec->opt->name);
+	return 0;
+}
+
+/**
+ * menu_item_exec - Run exec with the supplied command.
+ * @cmd: A command string.
+ */
+
+static int menu_item_exec(const char* cmd)
+{
+	pb_log("%s: %s\n", __func__, cmd);
+	return 0;
+}
+
+/**
+ * menu_item_process - Execute the action associated with the item.
+ * @i: The item to execute.
+ */
+
+static int menu_item_process(const struct menu_item *i)
+{
+	assert(i->i_sig == menu_item_sig);
+
+	switch (i->type) {
+	case type_kexec:
+		pb_log("%s: kexec: %s\n", __func__, i->text);
+		return menu_item_kexec(&i->kexec);
+	case type_callback:
+		pb_log("%s: callback: %s\n", __func__, i->text);
+		return i->cb->fn(i->cb->arg);
+	case type_cmd:
+		pb_log("%s: cmd: %s\n", __func__, i->text);
+		return menu_item_exec(i->cmd);
+	case type_text:
+	default:
+		assert(0 && "bad type");
+		break;
+	}
+	return -1;
+}
+
+/**
+ * menu_key_execute -
+ * @menu: A menu instance returned from menu_init().
+ */
+
+int menu_key_execute(struct menu *menu)
+{
+	struct menu_item *i;
+
+	assert(menu->m_sig == menu_sig);
+
+	list_for_each_entry(&menu->items, i, list)
+		if (i->state == state_selected)
+			return menu_item_process(i);
+
+	assert(0 && "no state_selected");
+	return -1;
+}
--- /dev/null
+++ b/ui/common/menu.h
@@ -0,0 +1,164 @@ 
+/*
+ *  Copyright (C) 2009 Sony Computer Entertainment Inc.
+ *  Copyright 2009 Sony Corp.
+ *
+ *  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
+ */
+
+#if !defined(_PB_MENU_H)
+#define _PB_MENU_H
+
+#include "list/list.h"
+#include "pb-protocol/pb-protocol.h"
+
+#if defined(__cplusplus)
+# define EXTERN_C extern "C"
+#else
+# define EXTERN_C
+#endif
+
+enum menu_sig {
+	menu_sig         = 333,
+	menu_item_sig    = 444,
+	menu_removed_sig = -555,
+};
+
+/**
+ * enum menu_item_type - The type or action of the menu item.
+ * @type_text: A simple text item with no action, cannot be selected.
+ * @type_kexec: A selectable item that runs kexec.
+ * @type_callback: A selectable item that has an associated callback routine.
+ * @type_cmd: A selectable item that runs a command via exec().
+ */
+
+enum menu_item_type {
+	type_text = 0,
+	type_callback,
+	type_cmd,
+	type_kexec,
+};
+
+/**
+ * struct menu_item_callback - Data structure for @type_callback items.
+ * @fn: The user supplied callback routine.
+ * @arg: A user supplied argument passed to the callback routine.
+ */
+
+struct menu_item_callback {
+	int (*fn)(void *arg);
+	void* arg;
+};
+
+/**
+ * struct menu_item_kexec - Data structure for @type_kexec items.
+ * @dev: A pointer to the device.
+ * @opt: A pointer to the boot option.
+ */
+
+struct menu_item_kexec {
+	const struct device *dev;
+	const struct boot_option *opt;
+};
+
+/**
+ * enum menu_item_state
+ * @state_visable: The default state, visable.
+ * @state_hidden: Used to hide items to declutter the display.
+ * @state_selected: Only a single item can be selected at a time.
+ */
+
+enum menu_item_state {
+	state_visable = 0,
+	state_hidden,
+	state_selected,
+};
+
+/**
+ * struct menu_item - Data structure defining a single menu item.
+ * @i_sig: Signature for callback type checking, should be menu_item_sig.
+ * @text: The text displayed for the menu item.
+ */
+
+struct menu_item {
+	enum menu_sig i_sig;
+	struct list_item list;
+	enum menu_item_type type;
+	enum menu_item_state state;
+	const char* text;
+	const char* status;
+	union {
+		struct menu_item_kexec kexec;
+		const char* cmd;
+		const struct menu_item_callback* cb;
+	};
+};
+
+/**
+ * struct menu - Data structure defining complete menu.
+ * @m_sig: Signature for callback type checking, should be menu_sig.
+ * @items: The list of menu_items to be displayed as the menu.
+ * @status: Pointer to a menu_item (in @items) to be used as the menu's status
+ * line.  Set with menu_set_status_item().
+ * @insert_start: Optional pointer to a menu_item (in @items) that defines a
+ * starting point for adding dynamic items.
+ * @insert_end: Optional pointer to a menu_item (in @items) that defines a
+ * end point for adding dynamic items.
+ * @ui_info: FIXME need this???
+ * @draw_start: Optional user supplied callback to prepare for drawing.
+ * @draw_item: User callback to draw an item, called once for each item in the
+ * menu.
+ * @draw_end: Optional user supplied callback to finalise drawing.
+ */
+
+struct menu {
+	enum menu_sig m_sig;
+	struct list items;
+	struct menu_item *status;
+	struct menu_item *insert_start;
+	struct menu_item *insert_end;
+	//void *ui_info;
+	void (*draw_start)(const struct menu *menu);
+	void (*draw_item)(const struct menu *menu, const struct menu_item *i,
+		int y);
+	void (*draw_end)(const struct menu *menu);
+};
+
+#define to_menu_item(_arg) \
+	(assert(((struct menu_item *)(_arg))->i_sig == menu_item_sig), \
+	((struct menu_item *)(_arg)))
+
+EXTERN_C struct menu_item *menu_item_init(struct menu *menu,
+	enum menu_item_type type, enum menu_item_state state, const char* text);
+EXTERN_C void menu_item_delete(struct menu_item *i);
+EXTERN_C void menu_item_set_text(struct menu_item *i, const char *text);
+
+#define to_menu(_arg) \
+	(assert(((struct menu *)(_arg))->m_sig == menu_sig), \
+	((struct menu *)(_arg)))
+
+EXTERN_C struct menu *menu_init(void* ctx);
+EXTERN_C void menu_delete(struct menu *menu);
+EXTERN_C void menu_draw(const struct menu *menu);
+EXTERN_C void menu_key_up(struct menu *menu);
+EXTERN_C void menu_key_down(struct menu *menu);
+EXTERN_C int menu_key_execute(struct menu *menu);
+EXTERN_C void menu_set_item_text(struct menu *menu, struct menu_item *i,
+	const char *text); // FIXME need this???
+
+static inline void menu_set_status_item(struct menu *menu, struct menu_item *i)
+{
+	menu->status = i;
+}
+
+#endif