diff --git a/apps/plugins/dict.c b/apps/plugins/dict.c index 8c262923b7..13fe8e3cc6 100644 --- a/apps/plugins/dict.c +++ b/apps/plugins/dict.c @@ -20,11 +20,11 @@ ****************************************************************************/ #include "plugin.h" +#include "lib/simple_viewer.h" PLUGIN_HEADER -/* screen info */ -static int display_columns, display_lines; +#define MIN_DESC_BUF_SIZE 0x400 /* arbitrary minimum size for description */ /* Some lenghts */ #define WORDLEN 32 /* has to be the same in rdf2binary.c */ @@ -44,50 +44,6 @@ struct stWord long offset; } STRUCT_PACKED; -/* A funtion to get width and height etc (from viewer.c) */ -void init_screen(void) -{ -#ifdef HAVE_LCD_BITMAP - int w,h; - - rb->lcd_getstringsize("o", &w, &h); - display_lines = LCD_HEIGHT / h; - display_columns = LCD_WIDTH / w; -#else - - display_lines = 2; - display_columns = 11; -#endif -} - -/* global vars for pl_malloc() */ -void *bufptr; -size_t bufleft; - -/* simple function to "allocate" memory in pluginbuffer. */ -void *pl_malloc(size_t size) -{ - void *ptr; - ptr = bufptr; - - if (bufleft < size) - { - return NULL; - } - else - { - bufptr += size; - bufleft -= size; - return ptr; - } -} - -/* init function for pl_malloc() */ -void pl_malloc_init(void) -{ - bufptr = rb->plugin_get_buffer(&bufleft); -} - /* for endian problems */ #ifdef ROCKBOX_BIG_ENDIAN #define reverse(x) x @@ -102,59 +58,6 @@ long reverse (long N) { } #endif -/* Button definitions */ -#if CONFIG_KEYPAD == PLAYER_PAD -#define LP_QUIT BUTTON_STOP -#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ - (CONFIG_KEYPAD == IPOD_3G_PAD) || \ - (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define LP_QUIT BUTTON_MENU -#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD -#define LP_QUIT BUTTON_PLAY -#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == GIGABEAT_PAD -#define LP_QUIT BUTTON_POWER -#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \ - (CONFIG_KEYPAD == SANSA_C200_PAD) || \ - (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \ - (CONFIG_KEYPAD == SANSA_M200_PAD) -#define LP_QUIT BUTTON_POWER -#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) -#define LP_QUIT (BUTTON_HOME|BUTTON_REPEAT) -#elif CONFIG_KEYPAD == IRIVER_H10_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == MROBE500_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == MROBE100_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == GIGABEAT_S_PAD -#define LP_QUIT BUTTON_BACK -#elif CONFIG_KEYPAD == IAUDIO_M3_PAD -#define LP_QUIT BUTTON_RC_REC -#elif CONFIG_KEYPAD == COWON_D2_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == IAUDIO67_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == CREATIVEZVM_PAD -#define LP_QUIT BUTTON_BACK -#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == ONDAVX747_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == ONDAVX777_PAD -#define LP_QUIT BUTTON_POWER -#elif CONFIG_KEYPAD == SAMSUNG_YH_PAD -#define LP_QUIT BUTTON_LEFT -#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD -#define LP_QUIT BUTTON_CANCEL -#elif CONFIG_KEYPAD == MPIO_HD200_PAD -#define LP_QUIT (BUTTON_REC|BUTTON_PLAY) -#else -#define LP_QUIT BUTTON_OFF -#endif /* data files */ #define DICT_INDEX PLUGIN_APPS_DIR "/dict.index" @@ -165,42 +68,32 @@ enum plugin_status plugin_start(const void* parameter) { char searchword[WORDLEN]; /* word to search for */ char *description; /* pointer to description buffer */ - char *output; /* pointer to output buffer */ - char *ptr, *space; struct stWord word; /* the struct to read into */ int fIndex, fData; /* files */ int filesize, high, low, probe; - int lines, len, outputted, next; + char *buffer; + size_t buffer_size; /* plugin stuff */ (void)parameter; - /* get screen info */ - init_screen(); - - /* get pl_malloc() buffer ready. */ - pl_malloc_init(); - - /* init description buffer (size is because we don't have scrolling)*/ - description = (char *)pl_malloc(display_columns * display_lines); - if (description == NULL) + /* allocate buffer. */ + buffer = rb->plugin_get_buffer(&buffer_size); + if (buffer == NULL || buffer_size < MIN_DESC_BUF_SIZE) { - DEBUGF("Err: failed to allocate description buffer."); + DEBUGF("Err: Failed to allocate buffer.\n"); + rb->splash(HZ*2, "Failed to allocate buffer."); return PLUGIN_ERROR; } - /* init output buffer */ - output = (char *)pl_malloc(display_columns); - if (output == NULL) - { - DEBUGF("Err: failed to allocate output buffer."); - return PLUGIN_ERROR; - } + description = buffer; /* "clear" input buffer */ searchword[0] = '\0'; - rb->kbd_input(searchword, sizeof(searchword)); /* get the word to search */ + /* get the word to search */ + if (rb->kbd_input(searchword, sizeof(searchword)) < 0) + return PLUGIN_OK; /* input cancelled */ fIndex = rb->open(DICT_INDEX, O_RDONLY); /* index file */ if (fIndex < 0) @@ -241,13 +134,13 @@ enum plugin_status plugin_start(const void* parameter) /* read in the word */ rb->lseek(fIndex, sizeof(struct stWord) * low, SEEK_SET); rb->read(fIndex, &word, sizeof(struct stWord)); + rb->close(fIndex); /* Check if we found something */ if (low == -1 || rb->strcasecmp(searchword, word.word) != 0) { DEBUGF("Not found.\n"); rb->splash(HZ*2, "Not found."); - rb->close(fIndex); return PLUGIN_OK; } @@ -259,7 +152,6 @@ enum plugin_status plugin_start(const void* parameter) { DEBUGF("Err: Failed to open description file.\n"); rb->splash(HZ*2, "Failed to open descriptions."); - rb->close(fIndex); return PLUGIN_ERROR; } @@ -267,83 +159,15 @@ enum plugin_status plugin_start(const void* parameter) rb->lseek(fData, (off_t)reverse(word.offset), SEEK_SET); /* Read in the description */ - rb->read_line(fData, description, display_columns * display_lines); + rb->read_line(fData, description, buffer_size); /* And print it to debug. */ DEBUGF("Description: %s\n", description); - /* get pointer to first char */ - ptr = description; - - lines = 0; - outputted = 0; - len = rb->strlen(description); - - /* clear screen */ - rb->lcd_clear_display(); - - /* for large screens display the searched word. */ - if(display_lines > 4) - { - rb->lcd_puts(0, lines, searchword); - lines++; - } - - /* TODO: Scroll, or just stop when there are to much lines. */ - while (1) - { - /* copy one lcd line */ - rb->strlcpy(output, ptr, display_columns + 1); - - /* typecast to kill a warning... */ - if((int)rb->strlen(ptr) < display_columns) - { - rb->lcd_puts(0, lines, output); - lines++; - break; - } - - - /* get the last spacechar */ - space = rb->strrchr(output, ' '); - - if (space != NULL) - { - *space = '\0'; - next = (space - (char*)output) + 1; - } - else - { - next = display_columns; - } - - /* put the line on screen */ - rb->lcd_puts(0, lines, output); - - /* get output count */ - outputted += rb->strlen(output); - - if (outputted < len) - { - /* set pointer to the next part */ - ptr += next; - lines++; - } - else - { - break; - } - } - rb->lcd_update(); - - /* wait for keypress */ - while(rb->button_get(true) != LP_QUIT) - { - /* do nothing */ - /* maybe define some keys for navigation here someday. */ - } - - rb->close(fIndex); rb->close(fData); + + /* display description. */ + view_text(searchword, description); + return PLUGIN_OK; } diff --git a/apps/plugins/lib/SOURCES b/apps/plugins/lib/SOURCES index 8c160e1cc4..5ed163f951 100644 --- a/apps/plugins/lib/SOURCES +++ b/apps/plugins/lib/SOURCES @@ -9,6 +9,7 @@ fixedpoint.c playback_control.c rgb_hsv.c buflib.c +simple_viewer.c display_text.c strncpy.c diff --git a/apps/plugins/lib/simple_viewer.c b/apps/plugins/lib/simple_viewer.c new file mode 100644 index 0000000000..c83f005ef4 --- /dev/null +++ b/apps/plugins/lib/simple_viewer.c @@ -0,0 +1,260 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* Copyright (C) 2010 Teruaki Kawashima +* +* 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 "config.h" +#include "plugin.h" +#include "pluginlib_actions.h" +#include "simple_viewer.h" +#include + +struct view_info { +#ifdef HAVE_LCD_BITMAP + struct font* pf; +#endif + const char *title; + const char *text; /* displayed text */ + int display_lines; /* number of lines can be displayed */ + int line_count; /* number of lines */ + int line; /* current fisrt line */ + int start; /* possition of first line in text */ +}; + +static const char* get_next_line(const char *text, struct view_info *info) +{ + (void) info; + const char *ptr = text; + const char *space = NULL; + int total, n, w; + total = 0; + while(*ptr) + { +#ifdef HAVE_LCD_CHARCELLS + n = rb->utf8seek(ptr, 1); + w = 1; +#else + unsigned short ch; + n = ((long)rb->utf8decode(ptr, &ch) - (long)ptr); + w = rb->font_get_width(info->pf, ch); +#endif + if (isspace(*ptr)) + space = ptr+n; + if (*ptr == '\n') + { + ptr += n; + break; + } + if (total + w > LCD_WIDTH) + break; + ptr += n; + total += w; + } + return *ptr && space? space: ptr; +} + +static void calc_line_count(struct view_info *info) +{ + const char *ptr = info->text; + int i = 0; + + while (*ptr) + { + ptr = get_next_line(ptr, info); + i++; + } + info->line_count = i; +} + +static void calc_first_line(struct view_info *info, int line) +{ + const char *ptr = info->text; + int i = 0; + + if (line > info->line_count - info->display_lines) + line = info->line_count - info->display_lines; + if (line < 0) + line = 0; + + DEBUGF("%d -> %d\n", info->line, line); + if (info->line <= line) + { + ptr += info->start; + i = info->line; + } + while (*ptr && i < line) + { + ptr = get_next_line(ptr, info); + i++; + } + info->start = ptr - info->text; + info->line = i; + DEBUGF("%d: %d\n", info->line, info->start); +} + +static int init_view(struct view_info *info, + const char *title, const char *text) +{ +#ifdef HAVE_LCD_BITMAP + info->pf = rb->font_get(FONT_UI); + info->display_lines = LCD_HEIGHT / info->pf->height; +#else + + info->display_lines = LCD_HEIGHT; +#endif + + info->title = title; + info->text = text; + info->line_count = 0; + info->line = 0; + info->start = 0; + + /* no title for small screens. */ + if (info->display_lines < 4) + { + info->title = NULL; + } + else + { + info->display_lines--; + } + + calc_line_count(info); + return 0; +} + +static void draw_text(struct view_info *info) +{ +#ifdef HAVE_LCD_BITMAP +#define OUTPUT_SIZE LCD_WIDTH+1 +#else +#define OUTPUT_SIZE LCD_WIDTH*3+1 +#endif + static char output[OUTPUT_SIZE]; + const char *text, *ptr; + int i, max_show, lines = 0; + + /* clear screen */ + rb->lcd_clear_display(); + + /* display title. */ + if(info->title) + { + rb->lcd_puts(0, lines, info->title); + lines++; + } + + max_show = MIN(info->line_count - info->line, info->display_lines); + DEBUGF("draw_text: %d-%d/%d\n", + info->line, info->line + max_show, info->line_count); + text = info->text + info->start; + + for (i = 0; i < max_show; i++, lines++) + { + ptr = get_next_line(text, info); + DEBUGF("%d>%d-%d, ", i, text-info->text, ptr-text); + rb->strlcpy(output, text, ptr-text+1); + rb->lcd_puts(0, lines, output); + text = ptr; + } + DEBUGF("\n"); + + rb->lcd_update(); +} + +static void scroll_up(struct view_info *info) +{ + if (info->line <= 0) + return; + calc_first_line(info, info->line-1); + draw_text(info); + return; +} + +static void scroll_down(struct view_info *info) +{ + if (info->line + info->display_lines >= info->line_count) + return; + + calc_first_line(info, info->line+1); + draw_text(info); +} + +static void scroll_to_top(struct view_info *info) +{ + if (info->line <= 0) + return; + + calc_first_line(info, 0); + draw_text(info); +} + +static void scroll_to_bottom(struct view_info *info) +{ + if (info->line + info->display_lines >= info->line_count) + return; + + calc_first_line(info, info->line_count - info->display_lines); + draw_text(info); +} + +int view_text(const char *title, const char *text) +{ + struct view_info info; + const struct button_mapping *view_contexts[] = { + pla_main_ctx, + }; + int button; + + init_view(&info, title, text); + draw_text(&info); + + /* wait for keypress */ + while(1) + { + button = pluginlib_getaction(TIMEOUT_BLOCK, view_contexts, + ARRAYLEN(view_contexts)); + switch (button) + { + case PLA_UP: + case PLA_UP_REPEAT: + scroll_up(&info); + break; + case PLA_DOWN: + case PLA_DOWN_REPEAT: + scroll_down(&info); + break; + case PLA_LEFT_REPEAT: + scroll_to_top(&info); + break; + case PLA_RIGHT_REPEAT: + scroll_to_bottom(&info); + break; + case PLA_EXIT: + case PLA_CANCEL: + return PLUGIN_OK; + default: + if (rb->default_event_handler(button) == SYS_USB_CONNECTED) + return PLUGIN_USB_CONNECTED; + break; + } + } + + return PLUGIN_OK; +} diff --git a/apps/plugins/lib/simple_viewer.h b/apps/plugins/lib/simple_viewer.h new file mode 100644 index 0000000000..ff3ef23f14 --- /dev/null +++ b/apps/plugins/lib/simple_viewer.h @@ -0,0 +1,28 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* Copyright (C) 2010 Teruaki Kawashima +* +* 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 __PLUGINLIB_VIEWER_H__ +#define __PLUGINLIB_VIEWER_H__ + +#include "plugin.h" +int view_text(const char *title, const char *text); + +#endif /* __PLUGINLIB_VIEWER_H__ */