From 2ca2684ede50f145985ae147ca52aef27f7580b2 Mon Sep 17 00:00:00 2001 From: Yoshihisa Uchida Date: Wed, 14 Apr 2010 10:16:00 +0000 Subject: new text viewer git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25644 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/textviewer/textviewer.c | 232 +++++++++++++ apps/plugins/textviewer/textviewer.h | 30 ++ apps/plugins/textviewer/tv_bookmark.c | 338 +++++++++++++++++++ apps/plugins/textviewer/tv_bookmark.h | 44 +++ apps/plugins/textviewer/tv_button.h | 393 ++++++++++++++++++++++ apps/plugins/textviewer/tv_menu.c | 384 +++++++++++++++++++++ apps/plugins/textviewer/tv_menu.h | 28 ++ apps/plugins/textviewer/tv_readtext.c | 483 ++++++++++++++++++++++++++ apps/plugins/textviewer/tv_readtext.h | 31 ++ apps/plugins/textviewer/tv_screen.c | 468 ++++++++++++++++++++++++++ apps/plugins/textviewer/tv_screen.h | 51 +++ apps/plugins/textviewer/tv_settings.c | 464 +++++++++++++++++++++++++ apps/plugins/textviewer/tv_settings.h | 85 +++++ apps/plugins/textviewer/tv_text_processor.c | 505 ++++++++++++++++++++++++++++ 14 files changed, 3536 insertions(+) create mode 100644 apps/plugins/textviewer/textviewer.c create mode 100644 apps/plugins/textviewer/textviewer.h create mode 100644 apps/plugins/textviewer/tv_bookmark.c create mode 100644 apps/plugins/textviewer/tv_bookmark.h create mode 100644 apps/plugins/textviewer/tv_button.h create mode 100644 apps/plugins/textviewer/tv_menu.c create mode 100644 apps/plugins/textviewer/tv_menu.h create mode 100644 apps/plugins/textviewer/tv_readtext.c create mode 100644 apps/plugins/textviewer/tv_readtext.h create mode 100644 apps/plugins/textviewer/tv_screen.c create mode 100644 apps/plugins/textviewer/tv_screen.h create mode 100644 apps/plugins/textviewer/tv_settings.c create mode 100644 apps/plugins/textviewer/tv_settings.h create mode 100644 apps/plugins/textviewer/tv_text_processor.c diff --git a/apps/plugins/textviewer/textviewer.c b/apps/plugins/textviewer/textviewer.c new file mode 100644 index 0000000000..289c741f96 --- /dev/null +++ b/apps/plugins/textviewer/textviewer.c @@ -0,0 +1,232 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "textviewer.h" +#include "tv_bookmark.h" +#include "tv_button.h" +#include "tv_menu.h" +#include "tv_readtext.h" +#include "tv_screen.h" +#include "tv_settings.h" + +PLUGIN_HEADER + +static bool viewer_init(const unsigned char *file) +{ + viewer_init_screen(); + viewer_init_buffer(); + + if (!viewer_open(file)) + return false; + + /* Init mac_text value used in processing buffer */ + mac_text = false; + + return true; +} + +static void viewer_exit(void *parameter) +{ + (void)parameter; + + /* save preference and bookmarks */ + if (!viewer_save_settings()) + rb->splash(HZ, "Can't save preference and bookmarks."); + + viewer_close(); + viewer_finalize_screen(); +} + +enum plugin_status plugin_start(const void* file) +{ + int button, i, ok; + int lastbutton = BUTTON_NONE; + bool autoscroll = false; + long old_tick; + + old_tick = *rb->current_tick; + + if (!file) + return PLUGIN_ERROR; + + ok = viewer_init(file); + if (!ok) { + rb->splash(HZ, "Error opening file."); + return PLUGIN_ERROR; + } + + viewer_load_settings(); /* load the preferences and bookmark */ + +#if LCD_DEPTH > 1 + rb->lcd_set_backdrop(NULL); +#endif + + viewer_draw(); + + while (!done) { + + if (autoscroll) + { + if(old_tick <= *rb->current_tick - (110-prefs.autoscroll_speed*10)) + { + viewer_scroll_down(VIEWER_SCROLL_LINE); + viewer_draw(); + old_tick = *rb->current_tick; + } + } + + button = rb->button_get_w_tmo(HZ/10); + + switch (button) { + case VIEWER_MENU: +#ifdef VIEWER_MENU2 + case VIEWER_MENU2: +#endif + viewer_menu(); + break; + + case VIEWER_AUTOSCROLL: +#ifdef VIEWER_AUTOSCROLL_PRE + if (lastbutton != VIEWER_AUTOSCROLL_PRE) + break; +#endif + autoscroll = !autoscroll; + break; + + case VIEWER_SCROLL_UP: + case VIEWER_SCROLL_UP | BUTTON_REPEAT: +#ifdef VIEWER_SCROLL_UP2 + case VIEWER_SCROLL_UP2: + case VIEWER_SCROLL_UP2 | BUTTON_REPEAT: +#endif + viewer_scroll_up(VIEWER_SCROLL_PREFS); + viewer_draw(); + old_tick = *rb->current_tick; + break; + + case VIEWER_SCROLL_DOWN: + case VIEWER_SCROLL_DOWN | BUTTON_REPEAT: +#ifdef VIEWER_PAGE_DOWN2 + case VIEWER_SCROLL_DOWN2: + case VIEWER_SCROLL_DOWN2 | BUTTON_REPEAT: +#endif + viewer_scroll_down(VIEWER_SCROLL_PREFS); + viewer_draw(); + old_tick = *rb->current_tick; + break; + + case VIEWER_SCREEN_LEFT: + case VIEWER_SCREEN_LEFT | BUTTON_REPEAT: + if (prefs.view_mode == WIDE) + { + /* Screen left */ + viewer_scroll_left(VIEWER_SCROLL_SCREEN); + } + else { /* prefs.view_mode == NARROW */ + /* Top of file */ + viewer_top(); + } + viewer_draw(); + break; + + case VIEWER_SCREEN_RIGHT: + case VIEWER_SCREEN_RIGHT | BUTTON_REPEAT: + if (prefs.view_mode == WIDE) + { + /* Screen right */ + viewer_scrol_right(VIEWER_SCROLL_SCREEN); + } + else { /* prefs.view_mode == NARROW */ + /* Bottom of file */ + viewer_bottom(); + } + viewer_draw(); + break; + +#ifdef VIEWER_LINE_UP + case VIEWER_LINE_UP: + case VIEWER_LINE_UP | BUTTON_REPEAT: + /* Scroll up one line */ + viewer_scroll_up(VIEWER_SCROLL_LINE); + viewer_draw(); + old_tick = *rb->current_tick; + break; + + case VIEWER_LINE_DOWN: + case VIEWER_LINE_DOWN | BUTTON_REPEAT: + /* Scroll down one line */ + viewer_scroll_down(VIEWER_SCROLL_LINE); + viewer_draw(); + old_tick = *rb->current_tick; + break; +#endif +#ifdef VIEWER_COLUMN_LEFT + case VIEWER_COLUMN_LEFT: + case VIEWER_COLUMN_LEFT | BUTTON_REPEAT: + if (prefs.view_mode == WIDE) + { + viewer_scroll_left(VIEWER_SCROLL_COLUMN); + viewer_draw(); + } + break; + + case VIEWER_COLUMN_RIGHT: + case VIEWER_COLUMN_RIGHT | BUTTON_REPEAT: + if (prefs.view_mode == WIDE) + { + viewer_scroll_right(VIEWER_SCROLL_COLUMN); + viewer_draw(); + } + break; +#endif + +#ifdef VIEWER_RC_QUIT + case VIEWER_RC_QUIT: +#endif + case VIEWER_QUIT: +#ifdef VIEWER_QUIT2 + case VIEWER_QUIT2: +#endif + viewer_exit(NULL); + done = true; + break; + + case VIEWER_BOOKMARK: + viewer_add_remove_bookmark(cpage, cline); + viewer_draw(); + break; + + default: + if (rb->default_event_handler_ex(button, viewer_exit, NULL) + == SYS_USB_CONNECTED) + return PLUGIN_USB_CONNECTED; + break; + } + if (button != BUTTON_NONE) + { + lastbutton = button; + rb->yield(); + } + } + return PLUGIN_OK; +} diff --git a/apps/plugins/textviewer/textviewer.h b/apps/plugins/textviewer/textviewer.h new file mode 100644 index 0000000000..7c080f8cc0 --- /dev/null +++ b/apps/plugins/textviewer/textviewer.h @@ -0,0 +1,30 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#ifndef PLUGIN_TEXT_VIEWER_TEXTVIEWER_H +#define PLUGIN_TEXT_VIEWER_TEXTVIEWER_H + +/* UTF-8 BOM */ +#define BOM "\xef\xbb\xbf" +#define BOM_SIZE 3 + +#endif diff --git a/apps/plugins/textviewer/tv_bookmark.c b/apps/plugins/textviewer/tv_bookmark.c new file mode 100644 index 0000000000..261a319e26 --- /dev/null +++ b/apps/plugins/textviewer/tv_bookmark.c @@ -0,0 +1,338 @@ +/*************************************************************************** + * __________ __ ___. + * 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" + +/* text viewer bookmark functions */ + +enum +{ + BOOKMARK_LAST = 1, + BOOKMARK_USER, +}; + +#ifndef HAVE_LCD_BITMAP +#define BOOKMARK_ICON "\xee\x84\x81\x00" +#endif + +#define BOOKMARK_SIZE 8 +#define MAX_BOOKMARKS 10 /* user setting bookmarks + last read page */ + + +struct bookmark_info bookmarks[MAX_BOOKMARKS]; +static int bookmark_count; + +static int bm_comp(const void *a, const void *b) +{ + struct bookmark_info *pa; + struct bookmark_info *pb; + + pa = (struct bookmark_info*)a; + pb = (struct bookmark_info*)b; + + if (pa->page != pb->page) + return pa->page - pb->page; + + return pa->line - pb->line; +} + +int viewer_find_bookmark(int page, int line) +{ + int i; + + for (i = 0; i < bookmark_count; i++) + { + if (bookmarks[i].page == page && bookmarks[i].line == line) + return i; + } + return -1; +} + +void viewer_add_bookmark(int page, int line) +{ + if (bookmark_count >= MAX_BOOKMARKS-1) + return; + + bookmarks[bookmark_count].file_position + = file_pos + screen_top_ptr - buffer; + bookmarks[bookmark_count].page = page; + bookmarks[bookmark_count].line = line; + bookmarks[bookmark_count].flag = BOOKMARK_USER; + bookmark_count++; +} + +static int viewer_add_last_read_bookmark(void) +{ + int i; + + i = viewer_find_bookmark(cpage, cline); + if (i >= 0) + bookmarks[i].flag |= BOOKMARK_LAST; + else + { + viewer_add_bookmark(); + i = bookmark_count-1; + bookmarks[i].flag = BOOKMARK_LAST; + } + return i; +} + +static void viewer_remove_bookmark(int i) +{ + int j; + + if (i < 0 || i >= bookmark_count) + return; + + for (j = i+1; j < bookmark_count; j++) + rb->memcpy(&bookmarks[j-1], &bookmarks[j], + sizeof(struct bookmark_info)); + + bookmark_count--; +} + +void viewer_remove_last_read_bookmark(void) +{ + int i, j; + + for (i = 0; i < bookmark_count; i++) + { + if (bookmarks[i].flag & BOOKMARK_LAST) + { + if (bookmarks[i].flag == BOOKMARK_LAST) + { + for (j = i+1; j < bookmark_count; j++) + rb->memcpy(&bookmarks[j-1], &bookmarks[j], + sizeof(struct bookmark_info)); + + bookmark_count--; + } + else + bookmarks[i].flag = BOOKMARK_USER; + break; + } + } +} + +/* + * the function that a bookmark add when there is not a bookmark in the given position + * or the bookmark remove when there exist a bookmark in the given position. + * + */ +void viewer_add_remove_bookmark(int page, int line) +{ + int idx = viewer_find_bookmark(cpage, cline); + + if (idx < 0) + { + if (bookmark_count >= MAX_BOOKMARKS-1) + rb->splash(HZ/2, "No more add bookmark."); + else + { + viewer_add_bookmark(page, line); + rb->splash(HZ/2, "Bookmark add."); + } + } + viewer_remove_bookmark(idx); + rb->splash(HZ/2, "Bookmark remove."); +} + +static int viewer_get_last_read_bookmark(void) +{ + int i; + + for (i = 0; i < bookmark_count; i++) + { + if (bookmarks[i].flag & BOOKMARK_LAST) + return i; + } + return -1; +} + +void viewer_select_bookmark(int initval) +{ + int i; + int ipage = 0; + int iline = 0; + int screen_pos; + int screen_top; + int selected = -1; + + struct opt_items items[bookmark_count]; + unsigned char names[bookmark_count][38]; + + if (initval >= 0 && initval < bookmark_count) + { + ipage = bookmarks[initval].page; + iline = bookmarks[initval].line; + } + + rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info), + bm_comp); + + for (i = 0; i < bookmark_count; i++) + { + rb->snprintf(names[i], sizeof(names[0]), +#if CONFIG_KEYPAD != PLAYER_PAD + "%sPage: %d Line: %d", +#else + "%sP:%d L:%d", +#endif + (bookmarks[i].flag&BOOKMARK_LAST)? "*":" ", + bookmarks[i].page, + bookmarks[i].line); + items[i].string = names[i]; + items[i].voice_id = -1; + if (selected < 0 && bookmarks[i].page == ipage && bookmarks[i].line == iline) + selected = i; + } + + rb->set_option("Select bookmark", &selected, INT, items, + sizeof(items) / sizeof(items[0]), NULL); + + if (selected < 0 || selected >= bookmark_count) + { + if (initval < 0 || (selected = viewer_get_last_read_bookmark()) < 0) + { + if (initval < 0) + rb->splash(HZ, "Start the first page."); + file_pos = 0; + screen_top_ptr = buffer; + cpage = 1; + cline = 1; + buffer_end = BUFFER_END(); + return; + } + } + + screen_pos = bookmarks[selected].file_position; + screen_top = screen_pos % buffer_size; + file_pos = screen_pos - screen_top; + screen_top_ptr = buffer + screen_top; + cpage = bookmarks[selected].page; + cline = bookmarks[selected].line; + buffer_end = BUFFER_END(); +} + + +static bool viewer_read_bookmark_info(int bfd, struct bookmark_info *b) +{ + unsigned char buf[BOOKMARK_SIZE]; + + if (rb->read(bfd, buf, sizeof(buf)) != sizeof(buf)) + return false; + + b->file_position = (buf[0] << 24)|(buf[1] << 16)|(buf[2] << 8)|buf[3]; + b->page = (buf[4] << 8)|buf[5]; + b->line = buf[6]; + b->flag = buf[7]; + + return true; +} + +bool viewer_read_bookmark_infos(int fd) +{ + unsigned char c; + int i; + + if (rb->read(fd, &c, 1) != 1) + { + bookmark_count = 0; + return false; + } + + bookmark_count = c; + if (bookmark_count > MAX_BOOKMARKS) + bookmark_count = MAX_BOOKMARKS; + + for (i = 0; i < bookmark_count; i++) + { + if (!viewer_read_bookmark_info(fd, &bookmarks[i])) + { + bookmark_count = i; + return false; + } + } + return true; +} + +static bool viewer_write_bookmark_info(int bfd, struct bookmark_info *b) +{ + unsigned char buf[BOOKMARK_SIZE]; + unsigned char *p = buf; + unsigned long ul; + + ul = b->file_position; + *p++ = ul >> 24; + *p++ = ul >> 16; + *p++ = ul >> 8; + *p++ = ul; + + ul = b->page; + *p++ = ul >> 8; + *p++ = ul; + + *p++ = b->line; + *p = b->flag; + + return (rb->write(bfd, buf, sizeof(buf)) == sizeof(buf)); +} + +bool viewer_write_bookmark_infos(int fd) +{ + unsigned char c = bookmark_count; + int i; + + if (rb->write(fd, &c, 1) != 1) + return false; + + for (i = 0; i < bookmark_count; i++) + { + if (!viewer_write_bookmark_info(fd, &bookmarks[i])) + return false; + } + + return true; +} + +bool copy_bookmark_file(int sfd, int dfd, off_t start, off_t size) +{ + off_t rsize; + + if (rb->lseek(sfd, start, SEEK_SET) < 0) + return false; + + while (size > 0) + { + if (size > buffer_size) + rsize = buffer_size; + else + rsize = size; + size -= rsize; + + if (rb->read(sfd, buffer, rsize) != rsize || + rb->write(dfd, buffer, rsize) != rsize) + return false; + } + return true; +} diff --git a/apps/plugins/textviewer/tv_bookmark.h b/apps/plugins/textviewer/tv_bookmark.h new file mode 100644 index 0000000000..4d8e7fc3e8 --- /dev/null +++ b/apps/plugins/textviewer/tv_bookmark.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#ifndef PLUGIN_TEXT_VIEWER_BOOKMARK_H +#define PLUGIN_TEXT_VIEWER_BOOKMARK_H + +/* stuff for the bookmarking */ +struct bookmark_info { + long file_position; + int page; + int line; + unsigned char flag; +}; + +int viewer_find_bookmark(int page, int line); +void viewer_add_remove_bookmark(int page, int line); +void viewer_add_bookmark(int page, int line); +void viewer_remove_last_read_bookmark(void); +void viewer_select_bookmark(int initval); + +bool viewer_read_bookmark_infos(int fd); +bool viewer_write_bookmark_infos(int fd); +bool copy_bookmark_file(int sfd, int dfd, off_t start, off_t size); + +#endif diff --git a/apps/plugins/textviewer/tv_button.h b/apps/plugins/textviewer/tv_button.h new file mode 100644 index 0000000000..7728b9abc6 --- /dev/null +++ b/apps/plugins/textviewer/tv_button.h @@ -0,0 +1,393 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#ifndef PLUGIN_TEXT_VIEWER_BUTTON_H +#define PLUGIN_TEXT_VIEWER_BUTTON_H + +/* variable button definitions */ + +/* Recorder keys */ +#if CONFIG_KEYPAD == RECORDER_PAD +#define VIEWER_QUIT BUTTON_OFF +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_F1 +#define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP) +#define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN) +#define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT) +#define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT) +#define VIEWER_BOOKMARK BUTTON_F2 + +#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD +#define VIEWER_QUIT BUTTON_OFF +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_F1 +#define VIEWER_AUTOSCROLL BUTTON_SELECT +#define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP) +#define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN) +#define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT) +#define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT) +#define VIEWER_BOOKMARK BUTTON_F2 + +/* Ondio keys */ +#elif CONFIG_KEYPAD == ONDIO_PAD +#define VIEWER_QUIT BUTTON_OFF +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT) +#define VIEWER_AUTOSCROLL_PRE BUTTON_MENU +#define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL) +#define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_OFF) + +/* Player keys */ +#elif CONFIG_KEYPAD == PLAYER_PAD +#define VIEWER_QUIT BUTTON_STOP +#define VIEWER_SCROLL_UP BUTTON_LEFT +#define VIEWER_SCROLL_DOWN BUTTON_RIGHT +#define VIEWER_SCREEN_LEFT (BUTTON_ON|BUTTON_LEFT) +#define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT) +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_ON + +/* iRiver H1x0 && H3x0 keys */ +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ + (CONFIG_KEYPAD == IRIVER_H300_PAD) +#define VIEWER_QUIT BUTTON_OFF +#define VIEWER_RC_QUIT BUTTON_RC_STOP +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_MODE +#define VIEWER_AUTOSCROLL BUTTON_SELECT +#define VIEWER_LINE_UP (BUTTON_ON | BUTTON_UP) +#define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN) +#define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT) +#define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT) +#define VIEWER_BOOKMARK (BUTTON_ON | BUTTON_SELECT) + +/* iPods */ +#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ + (CONFIG_KEYPAD == IPOD_3G_PAD) || \ + (CONFIG_KEYPAD == IPOD_1G2G_PAD) +#define VIEWER_QUIT_PRE BUTTON_SELECT +#define VIEWER_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define VIEWER_SCROLL_UP BUTTON_SCROLL_BACK +#define VIEWER_SCROLL_DOWN BUTTON_SCROLL_FWD +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_SELECT + +/* iFP7xx keys */ +#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD +#define VIEWER_QUIT BUTTON_PLAY +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_MODE +#define VIEWER_AUTOSCROLL BUTTON_SELECT +#define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_SELECT) + +/* iAudio X5 keys */ +#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_SELECT +#define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_REC + +/* GIGABEAT keys */ +#elif CONFIG_KEYPAD == GIGABEAT_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL BUTTON_A +#define VIEWER_BOOKMARK BUTTON_SELECT + +/* Sansa E200 keys */ +#elif CONFIG_KEYPAD == SANSA_E200_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_SELECT +#define VIEWER_AUTOSCROLL BUTTON_REC +#define VIEWER_LINE_UP BUTTON_SCROLL_BACK +#define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD +#define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT) + +/* Sansa Fuze keys */ +#elif CONFIG_KEYPAD == SANSA_FUZE_PAD +#define VIEWER_QUIT (BUTTON_HOME|BUTTON_REPEAT) +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_SELECT|BUTTON_REPEAT +#define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN +#define VIEWER_LINE_UP BUTTON_SCROLL_BACK +#define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD +#define VIEWER_BOOKMARK BUTTON_SELECT + +/* Sansa C200 keys */ +#elif CONFIG_KEYPAD == SANSA_C200_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_VOL_UP +#define VIEWER_SCROLL_DOWN BUTTON_VOL_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_SELECT +#define VIEWER_AUTOSCROLL BUTTON_REC +#define VIEWER_LINE_UP BUTTON_UP +#define VIEWER_LINE_DOWN BUTTON_DOWN +#define VIEWER_BOOKMARK (BUTTON_DOWN | BUTTON_SELECT) + +/* Sansa Clip keys */ +#elif CONFIG_KEYPAD == SANSA_CLIP_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_VOL_UP +#define VIEWER_SCROLL_DOWN BUTTON_VOL_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_SELECT +#define VIEWER_AUTOSCROLL BUTTON_HOME +#define VIEWER_LINE_UP BUTTON_UP +#define VIEWER_LINE_DOWN BUTTON_DOWN +#define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT) + +/* Sansa M200 keys */ +#elif CONFIG_KEYPAD == SANSA_M200_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_VOL_UP +#define VIEWER_SCROLL_DOWN BUTTON_VOL_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU (BUTTON_SELECT | BUTTON_UP) +#define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL) +#define VIEWER_LINE_UP BUTTON_UP +#define VIEWER_LINE_DOWN BUTTON_DOWN +#define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT) + +/* iriver H10 keys */ +#elif CONFIG_KEYPAD == IRIVER_H10_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_SCROLL_UP +#define VIEWER_SCROLL_DOWN BUTTON_SCROLL_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_REW +#define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_FF + +/*M-Robe 500 keys */ +#elif CONFIG_KEYPAD == MROBE500_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_RC_PLAY +#define VIEWER_SCROLL_DOWN BUTTON_RC_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_RC_HEART +#define VIEWER_AUTOSCROLL BUTTON_RC_MODE +#define VIEWER_BOOKMARK BUTTON_CENTER + +/*Gigabeat S keys */ +#elif CONFIG_KEYPAD == GIGABEAT_S_PAD +#define VIEWER_QUIT BUTTON_BACK +#define VIEWER_SCROLL_UP BUTTON_PREV +#define VIEWER_SCROLL_DOWN BUTTON_NEXT +#define VIEWER_SCREEN_LEFT (BUTTON_PLAY | BUTTON_LEFT) +#define VIEWER_SCREEN_RIGHT (BUTTON_PLAY | BUTTON_RIGHT) +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL_PRE BUTTON_PLAY +#define VIEWER_AUTOSCROLL (BUTTON_PLAY|BUTTON_REL) +#define VIEWER_LINE_UP BUTTON_UP +#define VIEWER_LINE_DOWN BUTTON_DOWN +#define VIEWER_COLUMN_LEFT BUTTON_LEFT +#define VIEWER_COLUMN_RIGHT BUTTON_RIGHT +#define VIEWER_BOOKMARK BUTTON_SELECT + +/*M-Robe 100 keys */ +#elif CONFIG_KEYPAD == MROBE100_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL BUTTON_DISPLAY +#define VIEWER_BOOKMARK BUTTON_SELECT + +/* iAUdio M3 keys */ +#elif CONFIG_KEYPAD == IAUDIO_M3_PAD +#define VIEWER_QUIT BUTTON_REC +#define VIEWER_RC_QUIT BUTTON_RC_REC +#define VIEWER_SCROLL_UP BUTTON_RC_VOL_UP +#define VIEWER_SCROLL_DOWN BUTTON_RC_VOL_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_RC_REW +#define VIEWER_SCREEN_RIGHT BUTTON_RC_FF +#define VIEWER_MENU BUTTON_RC_MENU +#define VIEWER_AUTOSCROLL BUTTON_RC_MODE +#define VIEWER_BOOKMARK BUTTON_RC_PLAY + +/* Cowon D2 keys */ +#elif CONFIG_KEYPAD == COWON_D2_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_SCROLL_UP BUTTON_MINUS +#define VIEWER_SCROLL_DOWN BUTTON_PLUS +#define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_PLUS) + +#elif CONFIG_KEYPAD == IAUDIO67_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_VOLUP +#define VIEWER_SCROLL_DOWN BUTTON_VOLDOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_RC_QUIT BUTTON_STOP +#define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_PLAY) + +/* Creative Zen Vision:M keys */ +#elif CONFIG_KEYPAD == CREATIVEZVM_PAD +#define VIEWER_QUIT BUTTON_BACK +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL BUTTON_SELECT +#define VIEWER_BOOKMARK BUTTON_PLAY + +/* Philips HDD1630 keys */ +#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL BUTTON_VIEW +#define VIEWER_BOOKMARK BUTTON_SELECT + +/* Philips SA9200 keys */ +#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_PREV +#define VIEWER_SCREEN_RIGHT BUTTON_NEXT +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_RIGHT + +/* Onda VX747 keys */ +#elif CONFIG_KEYPAD == ONDAVX747_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER) + +/* Onda VX777 keys */ +#elif CONFIG_KEYPAD == ONDAVX777_PAD +#define VIEWER_QUIT BUTTON_POWER +#define VIEWER_BOOKMARK (BUTTON_RIGHT|BUTTON_POWER) + +/* SAMSUNG YH-820 / YH-920 / YH-925 keys */ +#elif CONFIG_KEYPAD == SAMSUNG_YH_PAD +#define VIEWER_QUIT BUTTON_REC +#define VIEWER_SCROLL_UP BUTTON_UP +#define VIEWER_SCROLL_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_LEFT +#define VIEWER_SCREEN_RIGHT BUTTON_RIGHT +#define VIEWER_MENU BUTTON_PLAY +#define VIEWER_AUTOSCROLL BUTTON_REW +#define VIEWER_BOOKMARK BUTTON_FFWD + +/* Packard Bell Vibe 500 keys */ +#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD +#define VIEWER_QUIT BUTTON_REC +#define VIEWER_SCROLL_UP BUTTON_OK +#define VIEWER_SCROLL_DOWN BUTTON_CANCEL +#define VIEWER_LINE_UP BUTTON_UP +#define VIEWER_LINE_DOWN BUTTON_DOWN +#define VIEWER_SCREEN_LEFT BUTTON_PREV +#define VIEWER_SCREEN_RIGHT BUTTON_NEXT +#define VIEWER_MENU BUTTON_MENU +#define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_POWER + +#else +#error No keymap defined! +#endif + +#ifdef HAVE_TOUCHSCREEN +#ifdef VIEWER_QUIT +#define VIEWER_QUIT2 BUTTON_TOPLEFT +#else +#define VIEWER_QUIT BUTTON_TOPLEFT +#endif +#ifdef VIEWER_SCROLL_UP +#define VIEWER_SCROLL_UP2 BUTTON_TOPMIDDLE +#else +#define VIEWER_SCROLL_UP BUTTON_TOPMIDDLE +#endif +#ifdef VIEWER_SCROLL_DOWN +#define VIEWER_SCROLL_DOWN2 BUTTON_BOTTOMMIDDLE +#else +#define VIEWER_SCROLL_DOWN BUTTON_BOTTOMMIDDLE +#endif +#ifndef VIEWER_SCREEN_LEFT +#define VIEWER_SCREEN_LEFT BUTTON_MIDLEFT +#endif +#ifndef VIEWER_SCREEN_RIGHT +#define VIEWER_SCREEN_RIGHT BUTTON_MIDRIGHT +#endif +#ifdef VIEWER_MENU +#define VIEWER_MENU2 BUTTON_TOPRIGHT +#else +#define VIEWER_MENU BUTTON_TOPRIGHT +#endif +#ifndef VIEWER_AUTOSCROLL +#define VIEWER_AUTOSCROLL BUTTON_CENTER +#endif +#endif + +#endif diff --git a/apps/plugins/textviewer/tv_menu.c b/apps/plugins/textviewer/tv_menu.c new file mode 100644 index 0000000000..aa1b8d615e --- /dev/null +++ b/apps/plugins/textviewer/tv_menu.c @@ -0,0 +1,384 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "lib/playback_control.h" + + +/* settings helper functions */ + +static bool encoding_setting(void) +{ + static struct opt_items names[NUM_CODEPAGES]; + int idx; + bool res; + enum codepages oldenc = prefs.encoding; + + for (idx = 0; idx < NUM_CODEPAGES; idx++) + { + names[idx].string = rb->get_codepage_name(idx); + names[idx].voice_id = -1; + } + + res = rb->set_option("Encoding", &prefs.encoding, INT, names, + sizeof(names) / sizeof(names[0]), NULL); + + /* When prefs.encoding changes into UTF-8 or changes from UTF-8, + * filesize (file_size) might change. + * In addition, if prefs.encoding is UTF-8, then BOM does not read. + */ + if (oldenc != prefs.encoding && (oldenc == UTF_8 || prefs.encoding == UTF_8)) + { + check_bom(); + get_filesize(); + fill_buffer(file_pos, buffer, buffer_size); + } + + return res; +} + +static bool word_wrap_setting(void) +{ + static const struct opt_items names[] = { + {"On", -1}, + {"Off (Chop Words)", -1}, + }; + + return rb->set_option("Word Wrap", &prefs.word_mode, INT, + names, 2, NULL); +} + +static bool line_mode_setting(void) +{ + static const struct opt_items names[] = { + {"Normal", -1}, + {"Join Lines", -1}, + {"Expand Lines", -1}, +#ifdef HAVE_LCD_BITMAP + {"Reflow Lines", -1}, +#endif + }; + + return rb->set_option("Line Mode", &prefs.line_mode, INT, names, + sizeof(names) / sizeof(names[0]), NULL); +} + +static bool view_mode_setting(void) +{ + static const struct opt_items names[] = { + {"No (Narrow)", -1}, + {"Yes", -1}, + }; + bool ret; + ret = rb->set_option("Wide View", &prefs.view_mode, INT, + names , 2, NULL); + if (prefs.view_mode == NARROW) + col = 0; + calc_max_width(); + return ret; +} + +static bool scroll_mode_setting(void) +{ + static const struct opt_items names[] = { + {"Scroll by Page", -1}, + {"Scroll by Line", -1}, + }; + + return rb->set_option("Scroll Mode", &prefs.scroll_mode, INT, + names, 2, NULL); +} + +#ifdef HAVE_LCD_BITMAP +static bool page_mode_setting(void) +{ + static const struct opt_items names[] = { + {"No", -1}, + {"Yes", -1}, + }; + + return rb->set_option("Overlap Pages", &prefs.page_mode, INT, + names, 2, NULL); +} + +static bool scrollbar_setting(void) +{ + static const struct opt_items names[] = { + {"Off", -1}, + {"On", -1} + }; + + return rb->set_option("Show Scrollbar", &prefs.scrollbar_mode, INT, + names, 2, NULL); +} + +static bool header_setting(void) +{ + int len = (rb->global_settings->statusbar == STATUSBAR_TOP)? 4 : 2; + struct opt_items names[len]; + + names[0].string = "None"; + names[0].voice_id = -1; + names[1].string = "File path"; + names[1].voice_id = -1; + + if (rb->global_settings->statusbar == STATUSBAR_TOP) + { + names[2].string = "Status bar"; + names[2].voice_id = -1; + names[3].string = "Both"; + names[3].voice_id = -1; + } + + return rb->set_option("Show Header", &prefs.header_mode, INT, + names, len, NULL); +} + +static bool footer_setting(void) +{ + int len = (rb->global_settings->statusbar == STATUSBAR_BOTTOM)? 4 : 2; + struct opt_items names[len]; + + names[0].string = "None"; + names[0].voice_id = -1; + names[1].string = "Page Num"; + names[1].voice_id = -1; + + if (rb->global_settings->statusbar == STATUSBAR_BOTTOM) + { + names[2].string = "Status bar"; + names[2].voice_id = -1; + names[3].string = "Both"; + names[3].voice_id = -1; + } + + return rb->set_option("Show Footer", &prefs.footer_mode, INT, + names, len, NULL); +} + +static int font_comp(const void *a, const void *b) +{ + struct opt_items *pa; + struct opt_items *pb; + + pa = (struct opt_items *)a; + pb = (struct opt_items *)b; + + return rb->strcmp(pa->string, pb->string); +} + +static bool font_setting(void) +{ + int count = 0; + DIR *dir; + struct dirent *entry; + int i = 0; + int len; + int new_font = 0; + int old_font; + bool res; + int size = 0; + + dir = rb->opendir(FONT_DIR); + if (!dir) + { + rb->splash(HZ/2, "font dir does not access."); + return false; + } + + while (1) + { + entry = rb->readdir(dir); + + if (entry == NULL) + break; + + len = rb->strlen(entry->d_name); + if (len < 4 || rb->strcmp(entry->d_name + len-4, ".fnt")) + continue; + size += len-3; + count++; + } + rb->closedir(dir); + + struct opt_items names[count]; + unsigned char font_names[size]; + unsigned char *p = font_names; + + dir = rb->opendir(FONT_DIR); + if (!dir) + { + rb->splash(HZ/2, "font dir does not access."); + return false; + } + + while (1) + { + entry = rb->readdir(dir); + + if (entry == NULL) + break; + + len = rb->strlen(entry->d_name); + if (len < 4 || rb->strcmp(entry->d_name + len-4, ".fnt")) + continue; + + rb->snprintf(p, len-3, "%s", entry->d_name); + names[i].string = p; + names[i].voice_id = -1; + p += len-3; + i++; + if (i >= count) + break; + } + rb->closedir(dir); + + rb->qsort(names, count, sizeof(struct opt_items), font_comp); + + for (i = 0; i < count; i++) + { + if (!rb->strcmp(names[i].string, prefs.font)) + { + new_font = i; + break; + } + } + old_font = new_font; + + res = rb->set_option("Select Font", &new_font, INT, + names, count, NULL); + + if (new_font != old_font) + { + rb->memset(prefs.font, 0, MAX_PATH); + rb->snprintf(prefs.font, MAX_PATH, "%s", names[new_font].string); + change_font(prefs.font); + } + + return res; +} +#endif + +static bool autoscroll_speed_setting(void) +{ + return rb->set_int("Auto-scroll Speed", "", UNIT_INT, + &prefs.autoscroll_speed, NULL, 1, 1, 10, NULL); +} + +MENUITEM_FUNCTION(encoding_item, 0, "Encoding", encoding_setting, + NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(word_wrap_item, 0, "Word Wrap", word_wrap_setting, + NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(line_mode_item, 0, "Line Mode", line_mode_setting, + NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(view_mode_item, 0, "Wide View", view_mode_setting, + NULL, NULL, Icon_NOICON); +#ifdef HAVE_LCD_BITMAP +MENUITEM_FUNCTION(scrollbar_item, 0, "Show Scrollbar", scrollbar_setting, + NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(page_mode_item, 0, "Overlap Pages", page_mode_setting, + NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(header_item, 0, "Show Header", header_setting, + NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(footer_item, 0, "Show Footer", footer_setting, + NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(font_item, 0, "Font", font_setting, + NULL, NULL, Icon_NOICON); +#endif +MENUITEM_FUNCTION(scroll_mode_item, 0, "Scroll Mode", scroll_mode_setting, + NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(autoscroll_speed_item, 0, "Auto-Scroll Speed", + autoscroll_speed_setting, NULL, NULL, Icon_NOICON); +MAKE_MENU(option_menu, "Viewer Options", NULL, Icon_NOICON, + &encoding_item, &word_wrap_item, &line_mode_item, &view_mode_item, +#ifdef HAVE_LCD_BITMAP + &scrollbar_item, &page_mode_item, &header_item, &footer_item, &font_item, +#endif + &scroll_mode_item, &autoscroll_speed_item); + +static bool viewer_options_menu(bool is_global) +{ + bool result; + struct preferences tmp_prefs; + + rb->memcpy(&tmp_prefs, &prefs, sizeof(struct preferences)); + + result = (rb->do_menu(&option_menu, NULL, NULL, false) == MENU_ATTACHED_USB); + + if (!is_global && rb->memcmp(&tmp_prefs, &prefs, sizeof(struct preferences))) + { + /* Show-scrollbar mode for current view-width mode */ +#ifdef HAVE_LCD_BITMAP + init_need_scrollbar(); + init_header_and_footer(); +#endif + calc_page(); + } + return result; +} + +void viewer_menu(void) +{ + int result; + + MENUITEM_STRINGLIST(menu, "Viewer Menu", NULL, + "Return", "Viewer Options", + "Show Playback Menu", "Select Bookmark", + "Global Settings", "Quit"); + + result = rb->do_menu(&menu, NULL, NULL, false); + switch (result) + { + case 0: /* return */ + break; + case 1: /* change settings */ + done = viewer_options_menu(false); + break; + case 2: /* playback control */ + playback_control(NULL); + break; + case 3: /* select bookmark */ + viewer_select_bookmark(viewer_add_last_read_bookmark()); + viewer_remove_last_read_bookmark(); + fill_buffer(file_pos, buffer, buffer_size); + if (prefs.scroll_mode == PAGE && cline > 1) + viewer_scroll_to_top_line(); + break; + case 4: /* change global settings */ + { + struct preferences orig_prefs; + + rb->memcpy(&orig_prefs, &prefs, sizeof(struct preferences)); + if (!viewer_load_global_settings()) + viewer_default_preferences(); + done = viewer_options_menu(true); + viewer_save_global_settings(); + rb->memcpy(&prefs, &orig_prefs, sizeof(struct preferences)); + } + break; + case 5: /* quit */ + viewer_exit(NULL); + done = true; + break; + } + viewer_draw(col); +} diff --git a/apps/plugins/textviewer/tv_menu.h b/apps/plugins/textviewer/tv_menu.h new file mode 100644 index 0000000000..68a635e22b --- /dev/null +++ b/apps/plugins/textviewer/tv_menu.h @@ -0,0 +1,28 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#ifndef PLUGIN_TEXT_VIEWER_MENU_H +#define PLUGIN_TEXT_VIEWER_MENU_H + +void viewer_menu(void): + +#endif diff --git a/apps/plugins/textviewer/tv_readtext.c b/apps/plugins/textviewer/tv_readtext.c new file mode 100644 index 0000000000..988ee637eb --- /dev/null +++ b/apps/plugins/textviewer/tv_readtext.c @@ -0,0 +1,483 @@ +/*************************************************************************** + * __________ __ ___. + * 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_readtext.h" + +#define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */ +#define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */ +#define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */ +#define MAX_WIDTH 910 /* Max line length in WIDE mode */ +#define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */ +#define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */ +#define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */ +#define TOP_SECTOR buffer +#define MID_SECTOR (buffer + SMALL_BLOCK_SIZE) +#define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1)) +#undef SCROLLBAR_WIDTH +#define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width +#define MAX_PAGE 9999 + +/* Out-Of-Bounds test for any pointer to data in the buffer */ +#define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end) + +/* Does the buffer contain the beginning of the file? */ +#define BUFFER_BOF() (file_pos==0) + +/* Does the buffer contain the end of the file? */ +#define BUFFER_EOF() (file_size-file_pos <= buffer_size) + +/* Formula for the endpoint address outside of buffer data */ +#define BUFFER_END() \ + ((BUFFER_EOF()) ? (file_size-file_pos+buffer) : (buffer+buffer_size)) + +/* Is the entire file being shown in one screen? */ +#define ONE_SCREEN_FITS_ALL() \ + (next_screen_ptr==NULL && screen_top_ptr==buffer && BUFFER_BOF()) + +#define ADVANCE_COUNTERS(c) { width += glyph_width(c); k++; } +#define LINE_IS_FULL ((k>=max_columns-1) ||( width >= max_width)) +#define LINE_IS_NOT_FULL ((kplugin_get_buffer((size_t *)&buffer_size); + if (buffer_size == 0) + { + rb->splash(HZ, "buffer does not allocate !!"); + return PLUGIN_ERROR; + } + block_size = buffer_size / 3; + buffer_size = 3 * block_size; +} + +static unsigned char* crop_at_width(const unsigned char* p) +{ + int k,width; + unsigned short ch; + const unsigned char *oldp = p; + + k=width=0; + + while (LINE_IS_NOT_FULL) { + oldp = p; + if (BUFFER_OOB(p)) + break; + p = get_ucs(p, &ch); + ADVANCE_COUNTERS(ch); + } + + return (unsigned char*)oldp; +} + +static unsigned char* find_first_feed(const unsigned char* p, int size) +{ + int i; + + for (i=0; i < size; i++) + if (p[i] == 0) + return (unsigned char*) p+i; + + return NULL; +} + +static unsigned char* find_last_feed(const unsigned char* p, int size) +{ + int i; + + for (i=size-1; i>=0; i--) + if (p[i] == 0) + return (unsigned char*) p+i; + + return NULL; +} + +static unsigned char* find_last_space(const unsigned char* p, int size) +{ + int i, j, k; + + k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1; + + if (!BUFFER_OOB(&p[size])) + for (j=k; j < ((int) sizeof(line_break)) - 1; j++) + if (p[size] == line_break[j]) + return (unsigned char*) p+size; + + for (i=size-1; i>=0; i--) + for (j=k; j < (int) sizeof(line_break); j++) + { + if (!((p[i] == '-') && (prefs.word_mode == WRAP))) + if (p[i] == line_break[j]) + return (unsigned char*) p+i; + } + + return NULL; +} + +static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_short) +{ + const unsigned char *next_line = NULL; + int size, i, j, k, width, search_len, spaces, newlines; + bool first_chars; + unsigned char c; + + if (is_short != NULL) + *is_short = true; + + if BUFFER_OOB(cur_line) + return NULL; + + if (prefs.view_mode == WIDE) { + search_len = MAX_WIDTH; + } + else { /* prefs.view_mode == NARROW */ + search_len = crop_at_width(cur_line) - cur_line; + } + + size = BUFFER_OOB(cur_line+search_len) ? buffer_end-cur_line : search_len; + + if ((prefs.line_mode == JOIN) || (prefs.line_mode == REFLOW)) { + /* Need to scan ahead and possibly increase search_len and size, + or possibly set next_line at second hard return in a row. */ + next_line = NULL; + first_chars=true; + for (j=k=width=spaces=newlines=0; ; j++) { + if (BUFFER_OOB(cur_line+j)) + return NULL; + if (LINE_IS_FULL) { + size = search_len = j; + break; + } + + c = cur_line[j]; + switch (c) { + case ' ': + if (prefs.line_mode == REFLOW) { + if (newlines > 0) { + size = j; + next_line = cur_line + size; + return (unsigned char*) next_line; + } + if (j==0) /* i=1 is intentional */ + for (i=0; i 0) { + size = j; + next_line = cur_line + size - spaces; + if (next_line != cur_line) + return (unsigned char*) next_line; + break; + } + + newlines++; + size += spaces -1; + if (BUFFER_OOB(cur_line+size) || size > 2*search_len) + return NULL; + search_len = size; + spaces = first_chars? 0:1; + break; + + default: + if (prefs.line_mode==JOIN || newlines>0) { + while (spaces) { + spaces--; + ADVANCE_COUNTERS(' '); + if (LINE_IS_FULL) { + size = search_len = j; + break; + } + } + newlines=0; + } else if (spaces) { + /* REFLOW, multiple spaces between words: count only + * one. If more are needed, they will be added + * while drawing. */ + search_len = size; + spaces=0; + ADVANCE_COUNTERS(' '); + if (LINE_IS_FULL) { + size = search_len = j; + break; + } + } + first_chars = false; + ADVANCE_COUNTERS(c); + break; + } + } + } + else { + /* find first hard return */ + next_line = find_first_feed(cur_line, size); + } + + if (next_line == NULL) + if (size == search_len) { + if (prefs.word_mode == WRAP) /* Find last space */ + next_line = find_last_space(cur_line, size); + + if (next_line == NULL) + next_line = crop_at_width(cur_line); + else + if (prefs.word_mode == WRAP) + for (i=0; + i READ_PREV_ZONE) + prev_line = p = buffer; + /* (else return NULL and read previous block) */ + + /* Wrap downwards until too far, then use the one before. */ + while (p != NULL && p < cur_line) { + prev_line = p; + p = find_next_line(prev_line, NULL); + } + + if (BUFFER_OOB(prev_line)) + return NULL; + + return (unsigned char*) prev_line; +} + +static void check_bom(void) +{ + unsigned char bom[BOM_SIZE]; + off_t orig = rb->lseek(fd, 0, SEEK_CUR); + + is_bom = false; + + rb->lseek(fd, 0, SEEK_SET); + + if (rb->read(fd, bom, BOM_SIZE) == BOM_SIZE) + is_bom = !memcmp(bom, BOM, BOM_SIZE); + + rb->lseek(fd, orig, SEEK_SET); +} + +static void fill_buffer(long pos, unsigned char* buf, unsigned size) +{ + /* Read from file and preprocess the data */ + /* To minimize disk access, always read on sector boundaries */ + unsigned numread, i; + bool found_CR = false; + off_t offset = rb->lseek(fd, pos, SEEK_SET); + + if (offset == 0 && prefs.encoding == UTF_8 && is_bom) + rb->lseek(fd, BOM_SIZE, SEEK_SET); + + numread = rb->read(fd, buf, size); + buf[numread] = 0; + rb->button_clear_queue(); /* clear button queue */ + + for(i = 0; i < numread; i++) { + switch(buf[i]) { + case '\r': + if (mac_text) { + buf[i] = 0; + } + else { + buf[i] = ' '; + found_CR = true; + } + break; + + case '\n': + buf[i] = 0; + found_CR = false; + break; + + case 0: /* No break between case 0 and default, intentionally */ + buf[i] = ' '; + default: + if (found_CR) { + buf[i - 1] = 0; + found_CR = false; + mac_text = true; + } + break; + } + } +} + +static int read_and_synch(int direction) +{ +/* Read next (or prev) block, and reposition global pointers. */ +/* direction: 1 for down (i.e., further into file), -1 for up */ + int move_size, move_vector, offset; + unsigned char *fill_buf; + + if (direction == -1) /* up */ { + move_size = SMALL_BLOCK_SIZE; + offset = 0; + fill_buf = TOP_SECTOR; + rb->memcpy(BOTTOM_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE); + rb->memcpy(MID_SECTOR, TOP_SECTOR, SMALL_BLOCK_SIZE); + } + else /* down */ { + if (prefs.view_mode == WIDE) { + /* WIDE mode needs more buffer so we have to read smaller blocks */ + move_size = SMALL_BLOCK_SIZE; + offset = LARGE_BLOCK_SIZE; + fill_buf = BOTTOM_SECTOR; + rb->memcpy(TOP_SECTOR, MID_SECTOR, SMALL_BLOCK_SIZE); + rb->memcpy(MID_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE); + } + else { + move_size = LARGE_BLOCK_SIZE; + offset = SMALL_BLOCK_SIZE; + fill_buf = MID_SECTOR; + rb->memcpy(TOP_SECTOR, BOTTOM_SECTOR, SMALL_BLOCK_SIZE); + } + } + move_vector = direction * move_size; + screen_top_ptr -= move_vector; + file_pos += move_vector; + buffer_end = BUFFER_END(); /* Update whenever file_pos changes */ + fill_buffer(file_pos + offset, fill_buf, move_size); + return move_vector; +} + +static void get_next_line_position(unsigned char **line_begin, + unsigned char **line_end, + bool *is_short) +{ + int resynch_move; + + *line_begin = *line_end; + *line_end = find_next_line(*line_begin, is_short); + + if (*line_end == NULL && !BUFFER_EOF()) + { + resynch_move = read_and_synch(1); /* Read block & move ptrs */ + *line_begin -= resynch_move; + if (next_line_ptr > buffer) + next_line_ptr -= resynch_move; + + *line_end = find_next_line(*line_begin, is_short); + } +} + +/* open, close, get file size functions */ + +bool viewer_open(const unsigned char *fname) +{ + if (fname == 0) + return false; + + rb->strlcpy(file_name, fname, MAX_PATH+1); + fd = rb->open(fname, O_RDONLY); + return (fd >= 0); +} + +void viewer_close(void) +{ + if (fd >= 0) + rb->close(fd); +} + +/* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8, + * then file size decreases only BOM_SIZE. + */ +static void get_filesize(void) +{ + file_size = rb->filesize(fd); + if (file_size == -1) + return; + + if (prefs.encoding == UTF_8 && is_bom) + file_size -= BOM_SIZE; +} diff --git a/apps/plugins/textviewer/tv_readtext.h b/apps/plugins/textviewer/tv_readtext.h new file mode 100644 index 0000000000..774ebabd64 --- /dev/null +++ b/apps/plugins/textviewer/tv_readtext.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#ifndef PLUGIN_TEXT_VIEWER_READTEXT_H +#define PLUGIN_TEXT_VIEWER_READTEXT_H + +void viewer_init_buffer(void); + +bool viewer_open(const unsigned char *fname); +void viewer_close(void); + +#endif diff --git a/apps/plugins/textviewer/tv_screen.c b/apps/plugins/textviewer/tv_screen.c new file mode 100644 index 0000000000..ce2d82d59f --- /dev/null +++ b/apps/plugins/textviewer/tv_screen.c @@ -0,0 +1,468 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner + * + * 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_screen.h" +#include "tv_settings.h" + +static int draw_columns; /* number of (pixel) columns available for text */ +static int par_indent_spaces; /* number of spaces to indent first paragraph */ + +#ifdef HAVE_LCD_BITMAP +static struct font *pf; +static int header_height = 0; +static int footer_height = 0; +#endif + +void viewer_init_screen(void) +{ +#ifdef HAVE_LCD_BITMAP + /* initialize fonts */ + pf = rb->font_get(FONT_UI); + draw_columns = display_columns = LCD_WIDTH; +#else + /* REAL fixed pitch :) all chars use up 1 cell */ + display_lines = 2; + draw_columns = display_columns = 11; + par_indent_spaces = 2; +#endif +} + +void viewer_finalize_screen(void) +{ + change_font(rb->global_settings->font_file); +} + +void viewer_draw(void) +{ +} + +void viewer_top(void) +{ + /* Read top of file into buffer + and point screen pointer to top */ + if (file_pos != 0) + { + rb->splash(0, "Loading..."); + + file_pos = 0; + buffer_end = BUFFER_END(); /* Update whenever file_pos changes */ + fill_buffer(0, buffer, buffer_size); + } + + screen_top_ptr = buffer; + cpage = 1; + cline = 1; +} + +void viewer_bottom(void) +{ + unsigned char *line_begin; + unsigned char *line_end; + + rb->splash(0, "Loading..."); + + if (last_screen_top_ptr) + { + cpage = lpage; + cline = 1; + screen_top_ptr = last_screen_top_ptr; + file_pos = last_file_pos; + fill_buffer(file_pos, buffer, buffer_size); + buffer_end = BUFFER_END(); + return; + } + + line_end = screen_top_ptr; + + while (!BUFFER_EOF() || !BUFFER_OOB(line_end)) + { + get_next_line_position(&line_begin, &line_end, NULL); + if (line_end == NULL) + break; + + increment_current_line(); + if (cline == 1) + screen_top_ptr = line_end; + } + lpage = cpage; + cline = 1; + last_screen_top_ptr = screen_top_ptr; + last_file_pos = file_pos; + buffer_end = BUFFER_END(); +} + +static void increment_current_line(void) +{ + if (cline < display_lines) + cline++; + else if (cpage < MAX_PAGE) + { + cpage++; + cline = 1; + } +} + +static void decrement_current_line(void) +{ + if (cline > 1) + cline--; + else if (cpage > 1) + { + cpage--; + cline = display_lines; + } +} + +static void viewer_line_scroll_up(void) +{ + unsigned char *p; + + p = find_prev_line(screen_top_ptr); + if (p == NULL && !BUFFER_BOF()) { + read_and_synch(-1); + p = find_prev_line(screen_top_ptr); + } + if (p != NULL) + screen_top_ptr = p; + + decrement_current_line(); +} + +static void viewer_line_scroll_down(void) +{ + if (cpage == lpage) + return; + + if (next_line_ptr != NULL) + screen_top_ptr = next_line_ptr; + + increment_current_line(); +} + +static void viewer_scroll_to_top_line(void) +{ + int line; + + for (line = cline; line > 1; line--) + viewer_scroll_up(); +} + +void viewer_scroll_up(int mode) +{ + int i; + int line_count = 1; + struct viewer_preference *prefs = viewer_get_preference(); + + if ((mode == VIEWER_SCROLL_PAGE) || + (mode == VIEWER_SCROLL_PREFS && prefs->scroll_mode == PAGE)) + { +#ifdef HAVE_LCD_BITMAP + line_count = display_lines - ((prefs->page_mode==OVERLAP)? 1:0); +#else + line_count = display_lines; +#endif + } + + for (i = 0; i < line_count; i++) + viewer_line_scroll_up(); +} + +void viewer_scroll_down(int mode) +{ + struct viewer_preference *prefs = viewer_get_preference(); + + if ((mode == VIEWER_SCROLL_PAGE) || + (mode == VIEWER_SCROLL_PREFS && prefs->scroll_mode == PAGE)) + { + /* Page down */ + if (next_screen_ptr != NULL) + { + screen_top_ptr = next_screen_to_draw_ptr; + if (cpage < MAX_PAGE) + cpage++; + } + } + else + viewer_line_scroll_down(); +} + +#ifdef HAVE_LCD_BITMAP +static void viewer_scrollbar(void) { + int items, min_shown, max_shown, sb_begin_y, sb_height; + + items = (int) file_size; /* (SH1 int is same as long) */ + min_shown = (int) file_pos + (screen_top_ptr - buffer); + + if (next_screen_ptr == NULL) + max_shown = items; + else + max_shown = min_shown + (next_screen_ptr - screen_top_ptr); + + sb_begin_y = header_height; + sb_height = LCD_HEIGHT - header_height - footer_height; + + rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, sb_begin_y, + SCROLLBAR_WIDTH-1, sb_height, + items, min_shown, max_shown, VERTICAL); +} + +static void viewer_show_header(void) +{ + struct viewer_preference *prefs = viewer_get_preference(); + + if (prefs->header_mode == HD_SBAR || prefs->header_mode == HD_BOTH) + rb->gui_syncstatusbar_draw(rb->statusbars, true); + + if (prefs->header_mode == HD_PATH || prefs->header_mode == HD_BOTH) + rb->lcd_putsxy(0, header_height - pf->height, file_name); +} + +static void viewer_show_footer(void) +{ + struct viewer_preference *prefs = viewer_get_preference(); + + if (prefs->footer_mode == FT_SBAR || prefs->footer_mode == FT_BOTH) + rb->gui_syncstatusbar_draw(rb->statusbars, true); + + if (prefs->footer_mode == FT_PAGE || prefs->footer_mode == FT_BOTH) + { + unsigned char buf[12]; + + if (cline == 1) + rb->snprintf(buf, sizeof(buf), "%d", cpage); + else + rb->snprintf(buf, sizeof(buf), "%d - %d", cpage, cpage+1); + + rb->lcd_putsxy(0, LCD_HEIGHT - footer_height, buf); + } +} + +static bool need_scrollbar(void) +{ + struct viewer_preference *prefs = viewer_get_preference(); + + return prefs->need_scrollbar; +} + +static void init_need_scrollbar(void) { + draw_columns = need_scrollbar()? display_columns-SCROLLBAR_WIDTH : display_columns; + par_indent_spaces = draw_columns/(5*glyph_width(' ')); + calc_max_width(); +} + +static void init_header_and_footer(void) +{ + struct viewer_preference *prefs = viewer_get_preference(); + + header_height = 0; + footer_height = 0; + if (rb->global_settings->statusbar == STATUSBAR_TOP) + { + if (prefs->header_mode == HD_SBAR || prefs->header_mode == HD_BOTH) + header_height = STATUSBAR_HEIGHT; + + if (prefs->footer_mode == FT_SBAR) + prefs->footer_mode = FT_NONE; + else if (prefs->footer_mode == FT_BOTH) + prefs->footer_mode = FT_PAGE; + } + else if (rb->global_settings->statusbar == STATUSBAR_BOTTOM) + { + if (prefs->footer_mode == FT_SBAR || prefs->footer_mode == FT_BOTH) + footer_height = STATUSBAR_HEIGHT; + + if (prefs->header_mode == HD_SBAR) + prefs->header_mode = HD_NONE; + else if (prefs->header_mode == HD_BOTH) + prefs->header_mode = HD_PATH; + } + else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */ + { + if (prefs->header_mode == HD_SBAR) + prefs->header_mode = HD_NONE; + else if (prefs->header_mode == HD_BOTH) + prefs->header_mode = HD_PATH; + + if (prefs->footer_mode == FT_SBAR) + prefs->footer_mode = FT_NONE; + else if (prefs->footer_mode == FT_BOTH) + prefs->footer_mode = FT_PAGE; + } + + if (prefs->header_mode == HD_NONE || prefs->header_mode == HD_PATH || + prefs->footer_mode == FT_NONE || prefs->footer_mode == FT_PAGE) + rb->gui_syncstatusbar_draw(rb->statusbars, false); + + if (prefs->header_mode == HD_PATH || prefs->header_mode == HD_BOTH) + header_height += pf->height; + if (prefs->footer_mode == FT_PAGE || prefs->footer_mode == FT_BOTH) + footer_height += pf->height; + + display_lines = (LCD_HEIGHT - header_height - footer_height) / pf->height; + + lpage = 0; + last_file_pos = 0; + last_screen_top_ptr = NULL; +} + +void change_font(unsigned char *font) +{ + unsigned char buf[MAX_PATH]; + struct viewer_preference *prefs = viewer_get_preference(); + + if (font == NULL || *font == '\0') + return; + + if (rb->strcmp(prefs->font, rb->global_settings->font_file) == 0) + return; + + rb->snprintf(buf, MAX_PATH, "%s/%s.fnt", FONT_DIR, font); + if (rb->font_load(NULL, buf) < 0) + rb->splash(HZ/2, "font load failed."); +} +#else +#define change_font(f) +#endif + +static void calc_page(void) +{ + int i; + unsigned char *line_begin; + unsigned char *line_end; + off_t sfp; + unsigned char *sstp; + struct viewer_preference *prefs = viewer_get_preference(); + + rb->splash(0, "Calculating page/line number..."); + + /* add reading page to bookmarks */ + viewer_add_last_read_bookmark(); + + rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info), + bm_comp); + + cpage = 1; + cline = 1; + file_pos = 0; + screen_top_ptr = buffer; + buffer_end = BUFFER_END(); + + fill_buffer(file_pos, buffer, buffer_size); + line_end = line_begin = buffer; + + for (i = 0; i < bookmark_count; i++) + { + sfp = bookmarks[i].file_position; + sstp = buffer; + + while ((line_begin > sstp || sstp >= line_end) || + (file_pos > sfp || sfp >= file_pos + BUFFER_END() - buffer)) + { + get_next_line_position(&line_begin, &line_end, NULL); + if (line_end == NULL) + break; + + next_line_ptr = line_end; + + if (sstp == buffer && + file_pos <= sfp && sfp < file_pos + BUFFER_END() - buffer) + sstp = sfp - file_pos + buffer; + + increment_current_line(); + } + + decrement_current_line(); + bookmarks[i].page = cpage; + bookmarks[i].line = cline; + bookmarks[i].file_position = file_pos + (line_begin - buffer); + increment_current_line(); + } + + /* remove reading page's bookmark */ + for (i = 0; i < bookmark_count; i++) + { + if (bookmarks[i].flag & BOOKMARK_LAST) + { + int screen_pos; + int screen_top; + + screen_pos = bookmarks[i].file_position; + screen_top = screen_pos % buffer_size; + file_pos = screen_pos - screen_top; + screen_top_ptr = buffer + screen_top; + + cpage = bookmarks[i].page; + cline = bookmarks[i].line; + bookmarks[i].flag ^= BOOKMARK_LAST; + buffer_end = BUFFER_END(); + + fill_buffer(file_pos, buffer, buffer_size); + + if (bookmarks[i].flag == 0) + viewer_remove_bookmark(i); + + if (prefs->scroll_mode == PAGE && cline > 1) + viewer_scroll_to_top_line(); + break; + } + } +} + +static int col_limit(int col) +{ + if (col < 0) + col = 0; + else + if (col >= max_width) + col = max_width - draw_columns; + + return col; +} + +void viewer_scroll_left(int mode) +{ + if (mode == VIEWER_SCROLL_COLUMN) + { + /* Scroll left one column */ + col -= glyph_width('o'); + } + else + { + /* Screen left */ + col -= draw_columns; + } + col = col_limit(col); +} + +void viewer_scroll_right(int mode) +{ + if (mode == VIEWER_SCROLL_COLUMN) + { + /* Scroll right one column */ + col += glyph_width('o'); + } + else + { + /* Screen right */ + col += draw_columns; + } + col = col_limit(col); +} diff --git a/apps/plugins/textviewer/tv_screen.h b/apps/plugins/textviewer/tv_screen.h new file mode 100644 index 0000000000..db29640e42 --- /dev/null +++ b/apps/plugins/textviewer/tv_screen.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#ifndef PLUGIN_TEXT_VIEWER_SCREEN_H +#define PLUGIN_TEXT_VIEWER_SCREEN_H + +/* scroll mode */ +enum +{ + VIEWER_SCROLL_LINE, /* up/down one line */ + VIEWER_SCROLL_PAGE, /* up/down one page */ + VIEWER_SCROLL_COLUMN, /* left/right one column */ + VIEWER_SCROLL_SCREEN, /* left/right one screen */ + VIEWER_SCROLL_PREFS, /*up/down/left/right follows the settings. */ +}; + +void viewer_init_screen(void); +void viewer_finalize_screen(void); + +void viewer_draw(void); + +void viewer_top(void); +void viewer_bottom(void); + +void viewer_scroll_up(int mode); +void viewer_scroll_down(int mode); +void viewer_scroll_left(int mode); +void viewer_scroll_right(int mode); + +void change_font(unsigned char *font); + +#endif diff --git a/apps/plugins/textviewer/tv_settings.c b/apps/plugins/textviewer/tv_settings.c new file mode 100644 index 0000000000..463e6a42de --- /dev/null +++ b/apps/plugins/textviewer/tv_settings.c @@ -0,0 +1,464 @@ +/*************************************************************************** + * __________ __ ___. + * 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 + +/* global settings file + * binary file, so dont use .cfg + * + * setting file format + * + * part byte count + * -------------------------------- + * 'TVGS' 4 + * version 1 + * word_mode 1 + * line_mode 1 + * view_mode 1 + * encoding 1 + * scrollbar_mode 1 + * need_scrollbar 1 + * page_mode 1 + * page_number_mode 1 + * title_mode 1 + * scroll_mode 1 + * autoscroll_speed 1 + * font name MAX_PATH + */ +#define GLOBAL_SETTINGS_FILE VIEWERS_DIR "/viewer.dat" + +/* temporary file */ +#define GLOBAL_SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp" + +#define GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53\x31" /* header="TVGS" version=1 */ +#define GLOBAL_SETTINGS_H_SIZE 5 + +/* preferences and bookmarks at each file + * binary file, so dont use .cfg + * + * setting file format + * + * part byte count + * -------------------------------- + * 'TVS' 3 + * version 1 + * file count 2 + * [1st file] + * file path MAX_PATH + * next file pos 2 + * [preferences] + * word_mode 1 + * line_mode 1 + * view_mode 1 + * encoding 1 + * scrollbar_mode 1 + * need_scrollbar 1 + * page_mode 1 + * header_mode 1 + * footer_mode 1 + * scroll_mode 1 + * autoscroll_speed 1 + * font name MAX_PATH + * bookmark count 1 + * [1st bookmark] + * file_position 4 + * page 2 + * line 1 + * flag 1 + * [2nd bookmark] + * ... + * [last bookmark] + * [2nd file] + * ... + * [last file] + */ +#define SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat" + +/* temporary file */ +#define SETTINGS_TMP_FILE VIEWERS_DIR "/viewer_file.tmp" + +#define SETTINGS_HEADER "\x54\x56\x53\x32" /* header="TVS" version=2 */ +#define SETTINGS_H_SIZE 4 + +#ifndef HAVE_LCD_BITMAP +#define BOOKMARK_ICON "\xee\x84\x81\x00" +#endif + +#define PREFERENCES_SIZE (11 + MAX_PATH) + + +struct preferences prefs; +struct preferences old_prefs; + +static int fd; +static const char *file_name; +static int cline = 1; +static int cpage = 1; +static int lpage = 0; + +static void viewer_default_preferences(void) +{ + prefs.word_mode = WRAP; + prefs.line_mode = NORMAL; + prefs.view_mode = NARROW; + prefs.scroll_mode = PAGE; + prefs.page_mode = NO_OVERLAP; + prefs.scrollbar_mode = SB_OFF; + rb->memset(prefs.font, 0, MAX_PATH); +#ifdef HAVE_LCD_BITMAP + prefs.header_mode = HD_BOTH; + prefs.footer_mode = FT_BOTH; + rb->snprintf(prefs.font, MAX_PATH, "%s", rb->global_settings->font_file); +#else + prefs.header_mode = HD_NONE; + prefs.footer_mode = FT_NONE; +#endif + prefs.autoscroll_speed = 1; + /* Set codepage to system default */ + prefs.encoding = rb->global_settings->default_codepage; +} + +static bool viewer_read_preferences(int pfd) +{ + unsigned char buf[PREFERENCES_SIZE]; + unsigned char *p = buf; + + if (rb->read(pfd, buf, sizeof(buf)) != sizeof(buf)) + return false; + + prefs.word_mode = *p++; + prefs.line_mode = *p++; + prefs.view_mode = *p++; + prefs.encoding = *p++; + prefs.scrollbar_mode = *p++; + prefs.need_scrollbar = *p++; + prefs.page_mode = *p++; + prefs.header_mode = *p++; + prefs.footer_mode = *p++; + prefs.scroll_mode = *p++; + prefs.autoscroll_speed = *p++; + rb->memcpy(prefs.font, p, MAX_PATH); + + return true; +} + +static bool viewer_write_preferences(int pfd) +{ + unsigned char buf[PREFERENCES_SIZE]; + unsigned char *p = buf; + + *p++ = prefs.word_mode; + *p++ = prefs.line_mode; + *p++ = prefs.view_mode; + *p++ = prefs.encoding; + *p++ = prefs.scrollbar_mode; + *p++ = prefs.need_scrollbar; + *p++ = prefs.page_mode; + *p++ = prefs.header_mode; + *p++ = prefs.footer_mode; + *p++ = prefs.scroll_mode; + *p++ = prefs.autoscroll_speed; + rb->memcpy(p, prefs.font, MAX_PATH); + + return (rb->write(pfd, buf, sizeof(buf)) == sizeof(buf)); +} + +static bool viewer_load_global_settings(void) +{ + unsigned buf[GLOBAL_SETTINGS_H_SIZE]; + int sfd = rb->open(GLOBAL_SETTINGS_FILE, O_RDONLY); + + if (sfd < 0) + return false; + + if ((rb->read(sfd, buf, GLOBAL_SETTINGS_H_SIZE) != GLOBAL_SETTINGS_H_SIZE) || + rb->memcmp(buf, GLOBAL_SETTINGS_HEADER, GLOBAL_SETTINGS_H_SIZE) || + !viewer_read_preferences(sfd)) + { + rb->close(sfd); + return false; + } + rb->close(sfd); + return true; +} + +static bool viewer_save_global_settings(void) +{ + int sfd = rb->open(GLOBAL_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC); + + if (sfd < 0) + return false; + + if (rb->write(sfd, &GLOBAL_SETTINGS_HEADER, GLOBAL_SETTINGS_H_SIZE) + != GLOBAL_SETTINGS_H_SIZE || + !viewer_write_preferences(sfd)) + { + rb->close(sfd); + rb->remove(GLOBAL_SETTINGS_TMP_FILE); + return false; + } + rb->close(sfd); + rb->remove(GLOBAL_SETTINGS_FILE); + rb->rename(GLOBAL_SETTINGS_TMP_FILE, GLOBAL_SETTINGS_FILE); + return true; +} + +void viewer_load_settings(void) +{ + unsigned char buf[MAX_PATH+2]; + unsigned int fcount; + unsigned int i; + bool res = false; + int sfd; + unsigned int size; + + sfd = rb->open(SETTINGS_FILE, O_RDONLY); + if (sfd < 0) + goto read_end; + + if ((rb->read(sfd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2) || + rb->memcmp(buf, SETTINGS_HEADER, SETTINGS_H_SIZE)) + { + /* illegal setting file */ + rb->close(sfd); + + if (rb->file_exists(SETTINGS_FILE)) + rb->remove(SETTINGS_FILE); + + goto read_end; + } + + fcount = (buf[SETTINGS_H_SIZE] << 8) | buf[SETTINGS_H_SIZE+1]; + for (i = 0; i < fcount; i++) + { + if (rb->read(sfd, buf, MAX_PATH+2) != MAX_PATH+2) + break; + + size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1]; + if (rb->strcmp(buf, file_name)) + { + if (rb->lseek(sfd, size, SEEK_CUR) < 0) + break; + continue; + } + if (!viewer_read_preferences(sfd)) + break; + + res = viewer_read_bookmark_infos(sfd); + break; + } + + rb->close(sfd); + +read_end: + if (!res) + { + /* load global settings */ + if (!viewer_load_global_settings()) + viewer_default_preferences(); + + file_pos = 0; + screen_top_ptr = buffer; + cpage = 1; + cline = 1; + bookmark_count = 0; + } + + rb->memcpy(&old_prefs, &prefs, sizeof(struct preferences)); + calc_max_width(); + + if (bookmark_count > 1) + viewer_select_bookmark(-1); + else if (bookmark_count == 1) + { + int screen_pos; + int screen_top; + + screen_pos = bookmarks[0].file_position; + screen_top = screen_pos % buffer_size; + file_pos = screen_pos - screen_top; + screen_top_ptr = buffer + screen_top; + cpage = bookmarks[0].page; + cline = bookmarks[0].line; + } + + viewer_remove_last_read_bookmark(); + + check_bom(); + get_filesize(); + + buffer_end = BUFFER_END(); /* Update whenever file_pos changes */ + + if (BUFFER_OOB(screen_top_ptr)) + screen_top_ptr = buffer; + + fill_buffer(file_pos, buffer, buffer_size); + if (prefs.scroll_mode == PAGE && cline > 1) + viewer_scroll_to_top_line(); + + /* remember the current position */ + start_position = file_pos + screen_top_ptr - buffer; + +#ifdef HAVE_LCD_BITMAP + if (rb->strcmp(prefs.font, rb->global_settings->font_file)) + change_font(prefs.font); + + init_need_scrollbar(); + init_header_and_footer(); +#endif +} + +bool viewer_save_settings(void) +{ + unsigned char buf[MAX_PATH+2]; + unsigned int fcount = 0; + unsigned int i; + int idx; + int ofd; + int tfd; + off_t first_copy_size = 0; + off_t second_copy_start_pos = 0; + off_t size; + + /* add reading page to bookmarks */ + idx = viewer_find_bookmark(cpage, cline); + if (idx >= 0) + bookmarks[idx].flag |= BOOKMARK_LAST; + else + { + viewer_add_bookmark(cpage, cline); + bookmarks[bookmark_count-1].flag = BOOKMARK_LAST; + } + + tfd = rb->open(SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC); + if (tfd < 0) + return false; + + ofd = rb->open(SETTINGS_FILE, O_RDWR); + if (ofd >= 0) + { + if ((rb->read(ofd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2) || + rb->memcmp(buf, SETTINGS_HEADER, SETTINGS_H_SIZE)) + { + rb->close(ofd); + goto save_err; + } + fcount = (buf[SETTINGS_H_SIZE] << 8) | buf[SETTINGS_H_SIZE+1]; + + for (i = 0; i < fcount; i++) + { + if (rb->read(ofd, buf, MAX_PATH+2) != MAX_PATH+2) + { + rb->close(ofd); + goto save_err; + } + size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1]; + if (rb->strcmp(buf, file_name)) + { + if (rb->lseek(ofd, size, SEEK_CUR) < 0) + { + rb->close(ofd); + goto save_err; + } + } + else + { + first_copy_size = rb->lseek(ofd, 0, SEEK_CUR); + if (first_copy_size < 0) + { + rb->close(ofd); + goto save_err; + } + second_copy_start_pos = first_copy_size + size; + first_copy_size -= MAX_PATH+2; + fcount--; + break; + } + } + if (first_copy_size == 0) + first_copy_size = rb->filesize(ofd); + + if (!copy_bookmark_file(ofd, tfd, 0, first_copy_size)) + { + rb->close(ofd); + goto save_err; + } + if (second_copy_start_pos > 0) + { + if (!copy_bookmark_file(ofd, tfd, second_copy_start_pos, + rb->filesize(ofd) - second_copy_start_pos)) + { + rb->close(ofd); + goto save_err; + } + } + rb->close(ofd); + } + else + { + rb->memcpy(buf, SETTINGS_HEADER, SETTINGS_H_SIZE); + buf[SETTINGS_H_SIZE] = 0; + buf[SETTINGS_H_SIZE+1] = 0; + if (rb->write(tfd, buf, SETTINGS_H_SIZE+2) != SETTINGS_H_SIZE+2) + goto save_err; + } + + /* copy to current read file's bookmarks */ + rb->memset(buf, 0, MAX_PATH); + rb->snprintf(buf, MAX_PATH, "%s", file_name); + + size = PREFERENCES_SIZE + bookmark_count * BOOKMARK_SIZE + 1; + buf[MAX_PATH] = size >> 8; + buf[MAX_PATH+1] = size; + + if (rb->write(tfd, buf, MAX_PATH+2) != MAX_PATH+2) + goto save_err; + + if (!viewer_write_preferences(tfd)) + goto save_err; + + if (!viewer_write_bookmark_infos(tfd)) + goto save_err; + + if (rb->lseek(tfd, SETTINGS_H_SIZE, SEEK_SET) < 0) + goto save_err; + + fcount++; + buf[0] = fcount >> 8; + buf[1] = fcount; + + if (rb->write(tfd, buf, 2) != 2) + goto save_err; + + rb->close(tfd); + + rb->remove(SETTINGS_FILE); + rb->rename(SETTINGS_TMP_FILE, SETTINGS_FILE); + + return true; + +save_err: + rb->close(tfd); + rb->remove(SETTINGS_TMP_FILE); + return false; +} diff --git a/apps/plugins/textviewer/tv_settings.h b/apps/plugins/textviewer/tv_settings.h new file mode 100644 index 0000000000..317d6aa211 --- /dev/null +++ b/apps/plugins/textviewer/tv_settings.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#ifndef PLUGIN_TEXT_VIEWER_PREFERENCE_H +#define PLUGIN_TEXT_VIEWER_PREFERENCE_H + +struct viewer_preferences { + enum { + WRAP=0, + CHOP, + } word_mode; + + enum { + NORMAL=0, + JOIN, + EXPAND, + REFLOW, /* won't be set on charcell LCD, must be last */ + } line_mode; + + enum { + NARROW=0, + WIDE, + } view_mode; + + enum codepages encoding; + + enum { + SB_OFF=0, + SB_ON, + } scrollbar_mode; + bool need_scrollbar; + + enum { + NO_OVERLAP=0, + OVERLAP, + } page_mode; + + enum { + HD_NONE = 0, + HD_PATH, + HD_SBAR, + HD_BOTH, + } header_mode; + + enum { + FT_NONE = 0, + FT_PAGE, + FT_SBAR, + FT_BOTH, + } footer_mode; + + enum { + PAGE=0, + LINE, + } scroll_mode; + + int autoscroll_speed; + + unsigned char font[MAX_PATH]; +}; + +struct viewer_preferences *viewer_get_preference(void); +void viewer_load_settings(void); +bool viewer_save_settings(void); + +#endif diff --git a/apps/plugins/textviewer/tv_text_processor.c b/apps/plugins/textviewer/tv_text_processor.c new file mode 100644 index 0000000000..3ad80db585 --- /dev/null +++ b/apps/plugins/textviewer/tv_text_processor.c @@ -0,0 +1,505 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner + * + * 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_drawtext.h" + +#define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */ +#define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */ +#define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */ +#define MAX_WIDTH 910 /* Max line length in WIDE mode */ +#define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */ +#define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */ +#define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */ +#define TOP_SECTOR buffer +#define MID_SECTOR (buffer + SMALL_BLOCK_SIZE) +#define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1)) +#undef SCROLLBAR_WIDTH +#define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width +#define MAX_PAGE 9999 + +/* Is a scrollbar called for on the current screen? */ +#define NEED_SCROLLBAR() \ + ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON)) + +static void increment_current_line(void) +{ + if (cline < display_lines) + cline++; + else if (cpage < MAX_PAGE) + { + cpage++; + cline = 1; + } +} + +static void decrement_current_line(void) +{ + if (cline > 1) + cline--; + else if (cpage > 1) + { + cpage--; + cline = display_lines; + } +} + +static void viewer_scroll_up(void) +{ + unsigned char *p; + + p = find_prev_line(screen_top_ptr); + if (p == NULL && !BUFFER_BOF()) { + read_and_synch(-1); + p = find_prev_line(screen_top_ptr); + } + if (p != NULL) + screen_top_ptr = p; + + decrement_current_line(); +} + +static void viewer_scroll_down(bool autoscroll) +{ + if (cpage == lpage) + return; + + if (next_line_ptr != NULL) + screen_top_ptr = next_line_ptr; + + if (prefs.scroll_mode == LINE || autoscroll) + increment_current_line(); +} + +static void viewer_scroll_to_top_line(void) +{ + int line; + + for (line = cline; line > 1; line--) + viewer_scroll_up(); +} + +#ifdef HAVE_LCD_BITMAP +static void viewer_scrollbar(void) { + int items, min_shown, max_shown, sb_begin_y, sb_height; + + items = (int) file_size; /* (SH1 int is same as long) */ + min_shown = (int) file_pos + (screen_top_ptr - buffer); + + if (next_screen_ptr == NULL) + max_shown = items; + else + max_shown = min_shown + (next_screen_ptr - screen_top_ptr); + + sb_begin_y = header_height; + sb_height = LCD_HEIGHT - header_height - footer_height; + + rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, sb_begin_y, + SCROLLBAR_WIDTH-1, sb_height, + items, min_shown, max_shown, VERTICAL); +} + +static void viewer_show_header(void) +{ + if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH) + rb->gui_syncstatusbar_draw(rb->statusbars, true); + + if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH) + rb->lcd_putsxy(0, header_height - pf->height, file_name); +} + +static void viewer_show_footer(void) +{ + if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH) + rb->gui_syncstatusbar_draw(rb->statusbars, true); + + if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH) + { + unsigned char buf[12]; + + if (cline == 1) + rb->snprintf(buf, sizeof(buf), "%d", cpage); + else + rb->snprintf(buf, sizeof(buf), "%d - %d", cpage, cpage+1); + + rb->lcd_putsxy(0, LCD_HEIGHT - footer_height, buf); + } +} +#endif + +void viewer_draw(int col) +{ + int i, j, k, line_len, line_width, spaces, left_col=0; + int width, extra_spaces, indent_spaces, spaces_per_word; + bool multiple_spacing, line_is_short; + unsigned short ch; + unsigned char *str, *oldstr; + unsigned char *line_begin; + unsigned char *line_end; + unsigned char c; + unsigned char scratch_buffer[max_columns + 1]; + unsigned char utf8_buffer[max_columns*4 + 1]; + unsigned char *endptr; + + /* If col==-1 do all calculations but don't display */ + if (col != -1) { +#ifdef HAVE_LCD_BITMAP + left_col = prefs.need_scrollbar? SCROLLBAR_WIDTH:0; +#else + left_col = 0; +#endif + rb->lcd_clear_display(); + } + max_line_len = 0; + line_begin = line_end = screen_top_ptr; + + for (i = 0; i < display_lines; i++) { + if (BUFFER_OOB(line_end)) + { + if (lpage == cpage) + break; /* Happens after display last line at BUFFER_EOF() */ + + if (lpage == 0 && cline == 1) + { + lpage = cpage; + last_screen_top_ptr = screen_top_ptr; + last_file_pos = file_pos; + } + } + + get_next_line_position(&line_begin, &line_end, &line_is_short); + if (line_end == NULL) + { + if (BUFFER_OOB(line_begin)) + break; + line_end = buffer_end + 1; + } + + line_len = line_end - line_begin; + + /* calculate line_len */ + str = oldstr = line_begin; + j = -1; + while (str < line_end) { + oldstr = str; + str = crop_at_width(str); + j++; + } + line_width = j*draw_columns; + while (oldstr < line_end) { + oldstr = get_ucs(oldstr, &ch); + line_width += glyph_width(ch); + } + + if (prefs.line_mode == JOIN) { + if (line_begin[0] == 0) { + line_begin++; + if (prefs.word_mode == CHOP) + line_end++; + else + line_len--; + } + for (j=k=spaces=0; j < line_len; j++) { + if (k == max_columns) + break; + + c = line_begin[j]; + switch (c) { + case ' ': + spaces++; + break; + case 0: + spaces = 0; + scratch_buffer[k++] = ' '; + break; + default: + while (spaces) { + spaces--; + scratch_buffer[k++] = ' '; + if (k == max_columns - 1) + break; + } + scratch_buffer[k++] = c; + break; + } + } + if (col != -1) { + scratch_buffer[k] = 0; + endptr = decode2utf8(scratch_buffer, utf8_buffer, col, draw_columns); + *endptr = 0; + } + } + else if (prefs.line_mode == REFLOW) { + if (line_begin[0] == 0) { + line_begin++; + if (prefs.word_mode == CHOP) + line_end++; + else + line_len--; + } + + indent_spaces = 0; + if (!line_is_short) { + multiple_spacing = false; + width=spaces=0; + for (str = line_begin; str < line_end; ) { + str = get_ucs(str, &ch); + switch (ch) { + case ' ': + case 0: + if ((str == line_begin) && (prefs.word_mode==WRAP)) + /* special case: indent the paragraph, + * don't count spaces */ + indent_spaces = par_indent_spaces; + else if (!multiple_spacing) + spaces++; + multiple_spacing = true; + break; + default: + multiple_spacing = false; + width += glyph_width(ch); + break; + } + } + if (multiple_spacing) spaces--; + + if (spaces) { + /* total number of spaces to insert between words */ + extra_spaces = (max_width-width)/glyph_width(' ') + - indent_spaces; + /* number of spaces between each word*/ + spaces_per_word = extra_spaces / spaces; + /* number of words with n+1 spaces (to fill up) */ + extra_spaces = extra_spaces % spaces; + if (spaces_per_word > 2) { /* too much spacing is awful */ + spaces_per_word = 3; + extra_spaces = 0; + } + } else { /* this doesn't matter much... no spaces anyway */ + spaces_per_word = extra_spaces = 0; + } + } else { /* end of a paragraph: don't fill line */ + spaces_per_word = 1; + extra_spaces = 0; + } + + multiple_spacing = false; + for (j=k=spaces=0; j < line_len; j++) { + if (k == max_columns) + break; + + c = line_begin[j]; + switch (c) { + case ' ': + case 0: + if (j==0 && prefs.word_mode==WRAP) { /* indent paragraph */ + for (j=0; j col) { + str = oldstr = line_begin; + k = col; + width = 0; + while( (width 0) { + k -= glyph_width(ch); + line_begin = oldstr; + } else { + width += glyph_width(ch); + } + } + + if(prefs.view_mode==WIDE) + endptr = rb->iso_decode(line_begin, utf8_buffer, + prefs.encoding, oldstr-line_begin); + else + endptr = rb->iso_decode(line_begin, utf8_buffer, + prefs.encoding, line_end-line_begin); + *endptr = 0; + } + } + if (col != -1 && line_width > col) + { + int dpage = (cline+i <= display_lines)?cpage:cpage+1; + int dline = cline+i - ((cline+i <= display_lines)?0:display_lines); + bool bflag = (viewer_find_bookmark(dpage, dline) >= 0); +#ifdef HAVE_LCD_BITMAP + int dy = i * pf->height + header_height; +#endif + if (bflag) +#ifdef HAVE_LCD_BITMAP + { + rb->lcd_set_drawmode(DRMODE_BG|DRMODE_FG); + rb->lcd_fillrect(left_col, dy, LCD_WIDTH, pf->height); + rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + } + rb->lcd_putsxy(left_col, dy, utf8_buffer); + rb->lcd_set_drawmode(DRMODE_SOLID); +#else + { + rb->lcd_puts(left_col, i, BOOKMARK_ICON); + } + rb->lcd_puts(left_col+1, i, utf8_buffer); +#endif + } + if (line_width > max_line_len) + max_line_len = line_width; + + if (i == 0) + next_line_ptr = line_end; + } + next_screen_ptr = line_end; + if (BUFFER_OOB(next_screen_ptr)) + next_screen_ptr = NULL; + +#ifdef HAVE_LCD_BITMAP + next_screen_to_draw_ptr = prefs.page_mode==OVERLAP? line_begin: next_screen_ptr; + + if (prefs.need_scrollbar) + viewer_scrollbar(); +#else + next_screen_to_draw_ptr = next_screen_ptr; +#endif + +#ifdef HAVE_LCD_BITMAP + /* show header */ + viewer_show_header(); + + /* show footer */ + viewer_show_footer(); +#endif + + if (col != -1) + rb->lcd_update(); +} + +#ifdef HAVE_LCD_BITMAP +static void init_need_scrollbar(void) { + /* Call viewer_draw in quiet mode to initialize next_screen_ptr, + and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */ + viewer_draw(-1); + prefs.need_scrollbar = NEED_SCROLLBAR(); + draw_columns = prefs.need_scrollbar? display_columns-SCROLLBAR_WIDTH : display_columns; + par_indent_spaces = draw_columns/(5*glyph_width(' ')); + calc_max_width(); +} + +static void init_header_and_footer(void) +{ + header_height = 0; + footer_height = 0; + if (rb->global_settings->statusbar == STATUSBAR_TOP) + { + if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH) + header_height = STATUSBAR_HEIGHT; + + if (prefs.footer_mode == FT_SBAR) + prefs.footer_mode = FT_NONE; + else if (prefs.footer_mode == FT_BOTH) + prefs.footer_mode = FT_PAGE; + } + else if (rb->global_settings->statusbar == STATUSBAR_BOTTOM) + { + if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH) + footer_height = STATUSBAR_HEIGHT; + + if (prefs.header_mode == HD_SBAR) + prefs.header_mode = HD_NONE; + else if (prefs.header_mode == HD_BOTH) + prefs.header_mode = HD_PATH; + } + else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */ + { + if (prefs.header_mode == HD_SBAR) + prefs.header_mode = HD_NONE; + else if (prefs.header_mode == HD_BOTH) + prefs.header_mode = HD_PATH; + + if (prefs.footer_mode == FT_SBAR) + prefs.footer_mode = FT_NONE; + else if (prefs.footer_mode == FT_BOTH) + prefs.footer_mode = FT_PAGE; + } + + if (prefs.header_mode == HD_NONE || prefs.header_mode == HD_PATH || + prefs.footer_mode == FT_NONE || prefs.footer_mode == FT_PAGE) + rb->gui_syncstatusbar_draw(rb->statusbars, false); + + if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH) + header_height += pf->height; + if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH) + footer_height += pf->height; + + display_lines = (LCD_HEIGHT - header_height - footer_height) / pf->height; + + lpage = 0; + last_file_pos = 0; + last_screen_top_ptr = NULL; +} + +static void change_font(unsigned char *font) +{ + unsigned char buf[MAX_PATH]; + + if (font == NULL || *font == '\0') + return; + + rb->snprintf(buf, MAX_PATH, "%s/%s.fnt", FONT_DIR, font); + if (rb->font_load(NULL, buf) < 0) + rb->splash(HZ/2, "font load failed."); +} +#endif + +/* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8, + * then file size decreases only BOM_SIZE. + */ +static void get_filesize(void) +{ + file_size = rb->filesize(fd); + if (file_size == -1) + return; + + if (prefs.encoding == UTF_8 && is_bom) + file_size -= BOM_SIZE; +} -- cgit v1.2.3