summaryrefslogtreecommitdiffstats
path: root/apps/plugins/shopper.c
diff options
context:
space:
mode:
authorNils Wallménius <nils@rockbox.org>2010-08-18 09:10:37 +0000
committerNils Wallménius <nils@rockbox.org>2010-08-18 09:10:37 +0000
commit4461b0498d2402e14ade33da3d9986de531ab8d6 (patch)
tree4193629f3fe340a6d6e8729a25a1bfad69e9367f /apps/plugins/shopper.c
parentaa0973ded2c9b880f0aea677e072599ed495c357 (diff)
downloadrockbox-4461b0498d2402e14ade33da3d9986de531ab8d6.tar.gz
rockbox-4461b0498d2402e14ade33da3d9986de531ab8d6.tar.bz2
rockbox-4461b0498d2402e14ade33da3d9986de531ab8d6.zip
FS10820 - Shopper, a shopping list plugin by Daniel Rigby.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27842 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/shopper.c')
-rw-r--r--apps/plugins/shopper.c482
1 files changed, 482 insertions, 0 deletions
diff --git a/apps/plugins/shopper.c b/apps/plugins/shopper.c
new file mode 100644
index 0000000000..2ca7e112f6
--- /dev/null
+++ b/apps/plugins/shopper.c
@@ -0,0 +1,482 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id:
+ *
+ * Copyright (C) 2010 Daniel Rigby
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "plugin.h"
+#include "lib/playback_control.h"
+
+PLUGIN_HEADER
+
+#define MAX_LIST_SIZE 400
+#define DESC_SIZE 40
+#define MAX_LINE_LEN (DESC_SIZE + 1)
+
+enum flag_type {
+ FL_CLEARED = 0,
+ FL_SET,
+ FL_CATEGORY
+};
+
+enum view_type {
+ EDIT_SHOPPING_LIST = 0,
+ VIEW_SHOPPING_LIST
+};
+
+#define VIEW_TYPE_SIZE VIEW_SHOPPING_LIST + 1
+
+struct items_list_s {
+ unsigned int id;
+ enum flag_type flag;
+ char desc[DESC_SIZE];
+};
+
+static struct items_list_s items_list[MAX_LIST_SIZE];
+static int total_item_count = 0;
+static int view_id_list[MAX_LIST_SIZE];
+static int view_item_count;
+static enum view_type view = EDIT_SHOPPING_LIST;
+static char filename[MAX_PATH];
+static bool changed = false;
+static bool show_categories = true;
+static char category_string[] = "Hide categories";
+
+static const char *list_get_name_cb(int selected_item, void* data,
+ char* buf, size_t buf_len)
+{
+ (void)data;
+ rb->strlcpy(buf, items_list[view_id_list[selected_item]].desc, buf_len);
+ return buf;
+}
+
+static enum themable_icons list_get_icon_cb(int selected_item, void *data)
+{
+ (void)data;
+ if (items_list[view_id_list[selected_item]].flag == FL_CATEGORY)
+ return Icon_Rockbox;
+ else if (items_list[view_id_list[selected_item]].flag == FL_SET)
+ return Icon_Cursor;
+ else
+ return Icon_NOICON;
+}
+
+bool save_changes(void)
+{
+ int fd;
+ int i;
+
+ fd = rb->open(filename,O_WRONLY|O_CREAT|O_TRUNC);
+ if (fd < 0)
+ {
+ rb->splash(HZ*2, "Changes NOT saved");
+ return false;
+ }
+
+ rb->lcd_clear_display();
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost(1);
+#endif
+ for (i = 0;i < total_item_count; i++)
+ {
+ switch (items_list[i].flag)
+ {
+ case FL_CATEGORY:
+ {
+ rb->fdprintf(fd,"#%s\n",items_list[i].desc);
+ break;
+ }
+ case FL_SET:
+ {
+ rb->fdprintf(fd,"!%s\n",items_list[i].desc);
+ break;
+ }
+ case FL_CLEARED:
+ {
+ rb->fdprintf(fd," %s\n",items_list[i].desc);
+ break;
+ }
+ }
+ }
+ /* save current view */
+ rb->fdprintf(fd,"$%d%d\n",view, show_categories);
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost(0);
+#endif
+ rb->close(fd);
+
+ return true;
+}
+
+void create_view(struct gui_synclist *lists)
+{
+ unsigned int cnt = 0;
+ int i, j;
+
+ switch (view)
+ {
+ case EDIT_SHOPPING_LIST:
+ {
+ for (i = 0; i < total_item_count; i++)
+ {
+ if (show_categories || (items_list[i].flag != FL_CATEGORY))
+ view_id_list[cnt++] = i;
+ }
+ view_item_count = cnt;
+ rb->gui_synclist_set_title(lists,"Select items",Icon_Playlist);
+ break;
+ }
+ case VIEW_SHOPPING_LIST:
+ {
+ for (i = 0; i < total_item_count; i++)
+ {
+ if ((items_list[i].flag == FL_CATEGORY) && show_categories)
+ {
+ for (j = i+1; j < total_item_count; j++)
+ {
+ if (items_list[j].flag == FL_SET)
+ {
+ view_id_list[cnt++] = i;
+ break;
+ }
+ if (items_list[j].flag == FL_CATEGORY)
+ break;
+ }
+ }
+ else if (items_list[i].flag == FL_SET)
+ view_id_list[cnt++] = i;
+ }
+ view_item_count = cnt;
+ rb->gui_synclist_set_title(lists,"Shopping list",Icon_Playlist);
+ break;
+ }
+ }
+}
+
+bool toggle(int selected_item)
+{
+ if (items_list[view_id_list[selected_item]].flag == FL_CATEGORY)
+ return false;
+ else if (items_list[view_id_list[selected_item]].flag == FL_SET)
+ items_list[view_id_list[selected_item]].flag = FL_CLEARED;
+ else
+ items_list[view_id_list[selected_item]].flag = FL_SET;
+ return true;
+}
+
+void update_category_string(void)
+{
+ if (show_categories)
+ rb->strcpy(category_string,"Hide categories");
+ else
+ rb->strcpy(category_string,"Show categories");
+}
+
+enum plugin_status load_file(void)
+{
+ int fd;
+ static char temp_line[DESC_SIZE];
+ static struct items_list_s new_item;
+ static int count = 0;
+ int linelen;
+ total_item_count = 0;
+
+ fd = rb->open(filename,O_RDONLY);
+ if (fd < 0)
+ {
+ rb->splashf(HZ*2,"Couldn't open file: %s",filename);
+ return PLUGIN_ERROR;
+ }
+
+ /* read in the file */
+ while (rb->read_line(fd,temp_line,MAX_LINE_LEN))
+ {
+ if (rb->strncmp(temp_line, "$", 1) == 0)
+ {
+ /* read view preferences */
+ linelen = rb->strlen(temp_line);
+ if (linelen >= 2)
+ {
+ unsigned int val = temp_line[1] - '0';
+ if (val < VIEW_TYPE_SIZE)
+ {
+ view = val;
+ }
+ }
+ if (linelen >= 3)
+ {
+ unsigned int val = temp_line[2] - '0';
+ if (val <= 2)
+ {
+ show_categories = val;
+ update_category_string();
+ }
+ }
+ }
+ else
+ {
+ new_item.id = count;
+ if (rb->strncmp(temp_line, " ", 1) == 0)
+ {
+ /* read description, flag = cleared */
+ new_item.flag = FL_CLEARED;
+ rb->memcpy(new_item.desc, &temp_line[1], DESC_SIZE);
+ }
+ else if (rb->strncmp(temp_line, "!", 1) == 0)
+ {
+ /* read description, flag = set */
+ new_item.flag = FL_SET;
+ rb->memcpy(new_item.desc, &temp_line[1], DESC_SIZE);
+ }
+ else if (rb->strncmp(temp_line, "#", 1) == 0)
+ {
+ /* read description, flag = category */
+ new_item.flag = FL_CATEGORY;
+ rb->memcpy(new_item.desc, &temp_line[1], DESC_SIZE);
+ }
+ else
+ {
+ /* read description, flag = cleared */
+ new_item.flag = FL_CLEARED;
+ rb->memcpy(new_item.desc, temp_line, DESC_SIZE);
+ }
+ items_list[total_item_count] = new_item;
+ total_item_count++;
+ if (total_item_count == MAX_LIST_SIZE)
+ {
+ total_item_count = MAX_LIST_SIZE - 1;
+ rb->splashf(HZ*2, "Truncating shopping list to %d items",
+ MAX_LIST_SIZE - 1);
+ changed = true;
+ rb->close(fd);
+ return PLUGIN_OK;
+ }
+ }
+ }
+ rb->close(fd);
+ changed = false;
+ return PLUGIN_OK;
+}
+
+/* this is the plugin entry point */
+enum plugin_status plugin_start(const void* parameter)
+{
+ struct gui_synclist lists;
+ bool exit = false;
+ int button;
+ int cur_sel = 0;
+
+#if LCD_DEPTH > 1
+ rb->lcd_set_backdrop(NULL);
+#endif
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost(1);
+#endif
+ if (parameter)
+ {
+ rb->strcpy(filename,(char*)parameter);
+
+ if (load_file() == PLUGIN_ERROR)
+ return PLUGIN_ERROR;
+ }
+ else
+ return PLUGIN_ERROR;
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost(0);
+#endif
+ /* now dump it in the list */
+ rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1, NULL);
+ rb->gui_synclist_set_icon_callback(&lists, list_get_icon_cb);
+ rb->gui_synclist_limit_scroll(&lists,true);
+ create_view(&lists);
+ rb->gui_synclist_set_nb_items(&lists,view_item_count);
+ rb->gui_synclist_select_item(&lists, 0);
+ rb->gui_synclist_draw(&lists);
+ rb->lcd_update();
+
+ while (!exit)
+ {
+ rb->gui_synclist_draw(&lists);
+ cur_sel = rb->gui_synclist_get_sel_pos(&lists);
+ button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
+ if (rb->gui_synclist_do_button(&lists,&button,LIST_WRAP_UNLESS_HELD))
+ continue;
+ switch (button)
+ {
+ case ACTION_STD_CONTEXT:
+ case ACTION_STD_OK:
+ {
+ changed |= toggle(cur_sel);
+ break;
+ }
+ case ACTION_STD_MENU:
+ {
+ switch(view)
+ {
+ case EDIT_SHOPPING_LIST:
+ {
+ MENUITEM_STRINGLIST(menu, "Options", NULL,
+ "View shopping list",
+ "Clear all items",
+ "Mark all items",
+ category_string,
+ "Revert to saved",
+ "Show Playback Menu",);
+
+ switch (rb->do_menu(&menu, NULL, NULL, false))
+ {
+ case 0:
+ {
+ /* view shopping list */
+ view = VIEW_SHOPPING_LIST;
+ changed = true;
+ break;
+ }
+ case 1:
+ {
+ /* clear all items */
+ int i;
+ for (i = 0; i < total_item_count; i++)
+ {
+ if (items_list[i].flag == FL_SET)
+ items_list[i].flag = FL_CLEARED;
+ }
+ changed = true;
+ break;
+ }
+ case 2:
+ {
+ /* mark all items */
+ int i;
+ for (i = 0; i < total_item_count; i++)
+ {
+ if (items_list[i].flag == FL_CLEARED)
+ items_list[i].flag = FL_SET;
+ }
+ changed = true;
+ break;
+ }
+ case 3:
+ {
+ /* toggle categories */
+ show_categories ^= true;
+ update_category_string();
+ changed = true;
+ break;
+ }
+ case 4:
+ {
+ /* revert to saved */
+ if (load_file() == PLUGIN_ERROR)
+ return PLUGIN_ERROR;
+ break;
+ }
+ case 5:
+ {
+ /* playback menu */
+ playback_control(NULL);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ break;
+ }
+
+ case VIEW_SHOPPING_LIST:
+ {
+ MENUITEM_STRINGLIST(menu, "Options", NULL,
+ "Edit list",
+ "Reset list",
+ category_string,
+ "Revert to saved",
+ "Show Playback Menu",);
+
+ switch (rb->do_menu(&menu, NULL, NULL, false))
+ {
+ case 0:
+ {
+ /* edit list */
+ view = EDIT_SHOPPING_LIST;
+ changed = true;
+ break;
+ }
+ case 1:
+ {
+ /* reset list */
+ int i;
+ for (i = 0; i < total_item_count; i++)
+ {
+ if (items_list[i].flag == FL_SET)
+ items_list[i].flag = FL_CLEARED;
+ }
+ view = EDIT_SHOPPING_LIST;
+ changed = true;
+ break;
+ }
+ case 2:
+ {
+ /* toggle categories */
+ show_categories ^= true;
+ update_category_string();
+ changed = true;
+ break;
+ }
+ case 3:
+ {
+ /* revert to saved */
+ if (load_file() == PLUGIN_ERROR)
+ return PLUGIN_ERROR;
+ break;
+ }
+ case 4:
+ {
+ /* playback menu */
+ playback_control(NULL);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case ACTION_STD_CANCEL:
+ {
+ if (changed)
+ save_changes();
+ exit = 1;
+ break;
+ }
+ }
+
+ create_view(&lists);
+ rb->gui_synclist_set_nb_items(&lists,view_item_count);
+ if (view_item_count > 0 && view_item_count <= cur_sel)
+ rb->gui_synclist_select_item(&lists,view_item_count-1);
+ }
+ return PLUGIN_OK;
+}