/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 Gilles Roux * 2003 Garrett Derner * 2010 Yoshihisa Uchida * * 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 "tv_bookmark.h" #include "tv_pager.h" #include "tv_preferences.h" /* text viewer bookmark functions */ enum { TV_BOOKMARK_SYSTEM = 1, TV_BOOKMARK_USER = 2, }; #define SERIALIZE_BOOKMARK_SIZE 8 struct tv_bookmark_info { struct tv_screen_pos pos; unsigned char flag; }; /* bookmark stored array */ struct tv_bookmark_info bookmarks[TV_MAX_BOOKMARKS + 1]; static unsigned char bookmark_count; static int tv_compare_screen_pos(const struct tv_screen_pos *p1, const struct tv_screen_pos *p2) { if (p1->page != p2->page) return p1->page - p2->page; return p1->line - p2->line; } static int bm_comp(const void *a, const void *b) { struct tv_bookmark_info *pa; struct tv_bookmark_info *pb; pa = (struct tv_bookmark_info*)a; pb = (struct tv_bookmark_info*)b; return tv_compare_screen_pos(&pa->pos, &pb->pos); } static int tv_add_bookmark(const struct tv_screen_pos *pos) { if (bookmark_count >= TV_MAX_BOOKMARKS) return -1; bookmarks[bookmark_count].pos = *pos; bookmarks[bookmark_count].flag = TV_BOOKMARK_USER; return bookmark_count++; } static void tv_remove_bookmark(int idx) { int k; if (idx >= 0 && idx < bookmark_count) { for (k = idx + 1; k < bookmark_count; k++) bookmarks[k-1] = bookmarks[k]; bookmark_count--; } } static int tv_find_bookmark(const struct tv_screen_pos *pos) { int i; for (i = 0; i < bookmark_count; i++) { if (tv_compare_screen_pos(&bookmarks[i].pos, pos) == 0) return i; } return -1; } static int tv_change_preferences(const struct tv_preferences *oldp) { int i; if (oldp) { for (i = 0; i < bookmark_count; i++) tv_convert_fpos(bookmarks[i].pos.file_pos, &bookmarks[i].pos); } return TV_CALLBACK_OK; } bool tv_init_bookmark(unsigned char **buf, size_t *size) { (void)buf; (void)size; tv_add_preferences_change_listner(tv_change_preferences); return true; } void tv_finalize_bookmark(void) { /* no-operation function */ } int tv_get_bookmark_positions(struct tv_screen_pos *pos_array) { int i; for(i = 0; i < bookmark_count; i++) *pos_array++ = bookmarks[i].pos; return bookmark_count; } void tv_toggle_bookmark(void) { const struct tv_screen_pos *pos = tv_get_screen_pos(); int idx = tv_find_bookmark(pos); if (idx < 0) { if (tv_add_bookmark(pos) >= 0) rb->splash(HZ/2, "Bookmark add"); else rb->splash(HZ/2, "No more add bookmark"); return; } tv_remove_bookmark(idx); rb->splash(HZ/2, "Bookmark remove"); } void tv_create_system_bookmark(void) { const struct tv_screen_pos *pos = tv_get_screen_pos(); int idx = tv_find_bookmark(pos); if (idx >= 0) bookmarks[idx].flag |= TV_BOOKMARK_SYSTEM; else { bookmarks[bookmark_count].pos = *pos; bookmarks[bookmark_count].flag = TV_BOOKMARK_SYSTEM; bookmark_count++; } } void tv_select_bookmark(void) { int i; struct tv_screen_pos select_pos; for (i = 0; i < bookmark_count; i++) { if (bookmarks[i].flag & TV_BOOKMARK_SYSTEM) break; } /* if does not find the system bookmark, add the system bookmark. */ if (i >= bookmark_count) tv_create_system_bookmark(); if (bookmark_count == 1) select_pos = bookmarks[0].pos; else { int selected = -1; struct opt_items items[bookmark_count]; unsigned char names[bookmark_count][24]; rb->qsort(bookmarks, bookmark_count, sizeof(struct tv_bookmark_info), bm_comp); for (i = 0; i < bookmark_count; i++) { rb->snprintf(names[i], sizeof(names[0]), #if CONFIG_KEYPAD != PLAYER_PAD "%cPage: %d Line: %d", #else "%cP:%d L:%d", #endif (bookmarks[i].flag & TV_BOOKMARK_SYSTEM)? '*' : ' ', bookmarks[i].pos.page + 1, bookmarks[i].pos.line + 1); items[i].string = names[i]; items[i].voice_id = -1; } rb->set_option("Select bookmark", &selected, INT, items, bookmark_count, NULL); if (selected >= 0 && selected < bookmark_count) select_pos = bookmarks[selected].pos; else { /* when does not select any bookmarks, move to the current page */ tv_copy_screen_pos(&select_pos); if (select_pos.file_pos == 0) rb->splash(HZ, "Start the first page"); else rb->splash(HZ, "Return to the current page"); } } /* deletes the system bookmark */ for (i = 0; i < bookmark_count; i++) { if ((bookmarks[i].flag &= TV_BOOKMARK_USER) == 0) { tv_remove_bookmark(i); break; } } /* move to the select position */ if (preferences->vertical_scroll_mode == VS_PAGE) select_pos.line = 0; tv_move_screen(select_pos.page, select_pos.line, SEEK_SET); } /* serialize or deserialize of the bookmark array */ static bool tv_read_bookmark_info(int fd, struct tv_bookmark_info *b) { unsigned char buf[SERIALIZE_BOOKMARK_SIZE]; if (rb->read(fd, buf, sizeof(buf)) < 0) return false; b->pos.file_pos = (buf[0] << 24)|(buf[1] << 16)|(buf[2] << 8)|buf[3]; b->pos.page = (buf[4] << 8)|buf[5]; b->pos.line = buf[6]; b->flag = buf[7]; return true; } bool tv_deserialize_bookmarks(int fd) { int i; bool res = true; if (rb->read(fd, &bookmark_count, 1) < 0) return false; for (i = 0; i < bookmark_count; i++) { if (!tv_read_bookmark_info(fd, &bookmarks[i])) { res = false; break; } } bookmark_count = i; return res; } static bool tv_write_bookmark_info(int fd, const struct tv_bookmark_info *b) { unsigned char buf[SERIALIZE_BOOKMARK_SIZE]; unsigned char *p = buf; *p++ = b->pos.file_pos >> 24; *p++ = b->pos.file_pos >> 16; *p++ = b->pos.file_pos >> 8; *p++ = b->pos.file_pos; *p++ = b->pos.page >> 8; *p++ = b->pos.page; *p++ = b->pos.line; *p = b->flag; return (rb->write(fd, buf, SERIALIZE_BOOKMARK_SIZE) >= 0); } int tv_serialize_bookmarks(int fd) { int i; if (rb->write(fd, &bookmark_count, 1) < 0) return 0; for (i = 0; i < bookmark_count; i++) { if (!tv_write_bookmark_info(fd, &bookmarks[i])) break; } return i * SERIALIZE_BOOKMARK_SIZE + 1; }