2cdf332f01
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27243 a1c6a512-1295-4272-9138-f99709370657
312 lines
7.6 KiB
C
312 lines
7.6 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* 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;
|
|
}
|