diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 73d1f5765f..d525dc5b22 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -84,6 +84,7 @@ rockpaint,apps search,viewers searchengine,viewers settings_dumper,apps +shopper,viewers shortcuts_append,viewers shortcuts_view,viewers sliding_puzzle,games diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index a63bb922b6..1ca302823c 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -144,6 +144,7 @@ brickmania.c calendar.c maze.c mazezam.c +shopper.c text_editor.c wavview.c robotfindskitten.c 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; +} diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 1b0bdf3c4e..6fb5942aae 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config @@ -73,3 +73,4 @@ z5,viewers/frotz,- z6,viewers/frotz,- z7,viewers/frotz,- z8,viewers/frotz,- +list,viewers/shopper,1 diff --git a/docs/CREDITS b/docs/CREDITS index 898865854e..95b7ea4535 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -556,6 +556,7 @@ Joshua Hulst Pierre-Yves Roosens Hayden Pearce Rodrigo Barretto +Daniel Rigby The libmad team The wavpack team