5af120f1cb
* displays a scrollbar if there is more text than currently displayed. * enables to scroll text by scrollwheel. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27175 a1c6a512-1295-4272-9138-f99709370657
311 lines
7.8 KiB
C
311 lines
7.8 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* 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 <ctype.h>
|
|
|
|
struct view_info {
|
|
#ifdef HAVE_LCD_BITMAP
|
|
struct font* pf;
|
|
struct viewport scrollbar_vp; /* viewport for scrollbar */
|
|
#endif
|
|
struct viewport vp;
|
|
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)
|
|
{
|
|
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 > info->vp.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;
|
|
#ifdef HAVE_LCD_BITMAP
|
|
bool scrollbar = false;
|
|
#endif
|
|
|
|
while (*ptr)
|
|
{
|
|
ptr = get_next_line(ptr, info);
|
|
i++;
|
|
#ifdef HAVE_LCD_BITMAP
|
|
if (!scrollbar && i > info->display_lines)
|
|
{
|
|
ptr = info->text;
|
|
i = 0;
|
|
info->scrollbar_vp = info->vp;
|
|
info->scrollbar_vp.width = rb->global_settings->scrollbar_width;
|
|
info->vp.width -= info->scrollbar_vp.width;
|
|
if (rb->global_settings->scrollbar != SCROLLBAR_RIGHT)
|
|
info->vp.x = info->scrollbar_vp.width;
|
|
else
|
|
info->scrollbar_vp.x = info->vp.width;
|
|
scrollbar = true;
|
|
}
|
|
#endif
|
|
}
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
static int init_view(struct view_info *info,
|
|
const char *title, const char *text)
|
|
{
|
|
rb->viewport_set_defaults(&info->vp, SCREEN_MAIN);
|
|
#ifdef HAVE_LCD_BITMAP
|
|
info->pf = rb->font_get(FONT_UI);
|
|
info->display_lines = info->vp.height / info->pf->height;
|
|
#else
|
|
info->display_lines = info->vp.height;
|
|
#endif
|
|
|
|
info->title = title;
|
|
info->text = text;
|
|
info->line_count = 0;
|
|
info->line = 0;
|
|
info->start = 0;
|
|
|
|
#ifdef HAVE_LCD_BITMAP
|
|
/* no title for small screens. */
|
|
if (info->display_lines < 4)
|
|
{
|
|
info->title = NULL;
|
|
}
|
|
else
|
|
{
|
|
info->display_lines--;
|
|
info->vp.y += info->pf->height;
|
|
info->vp.height -= info->pf->height;
|
|
}
|
|
#endif
|
|
|
|
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 max_show, line;
|
|
struct screen* display = rb->screens[SCREEN_MAIN];
|
|
|
|
/* clear screen */
|
|
display->clear_display();
|
|
|
|
#ifdef HAVE_LCD_BITMAP
|
|
/* display title. */
|
|
if(info->title)
|
|
{
|
|
display->set_viewport(NULL);
|
|
display->puts(0, 0, info->title);
|
|
}
|
|
#endif
|
|
|
|
max_show = MIN(info->line_count - info->line, info->display_lines);
|
|
text = info->text + info->start;
|
|
|
|
display->set_viewport(&info->vp);
|
|
for (line = 0; line < max_show; line++)
|
|
{
|
|
int len;
|
|
ptr = get_next_line(text, info);
|
|
len = ptr-text;
|
|
while(len > 0 && isspace(text[len-1]))
|
|
len--;
|
|
rb->memcpy(output, text, len);
|
|
output[len] = 0;
|
|
display->puts(0, line, output);
|
|
text = ptr;
|
|
}
|
|
#ifdef HAVE_LCD_BITMAP
|
|
if (info->line_count > info->display_lines)
|
|
{
|
|
display->set_viewport(&info->scrollbar_vp);
|
|
rb->gui_scrollbar_draw(display, (info->scrollbar_vp.width? 0: 1), 0,
|
|
info->scrollbar_vp.width - 1, info->scrollbar_vp.height,
|
|
info->line_count, info->line, info->line + max_show,
|
|
VERTICAL);
|
|
}
|
|
#endif
|
|
|
|
display->set_viewport(NULL);
|
|
display->update();
|
|
}
|
|
|
|
static void scroll_up(struct view_info *info, int n)
|
|
{
|
|
if (info->line <= 0)
|
|
return;
|
|
|
|
calc_first_line(info, info->line-n);
|
|
draw_text(info);
|
|
}
|
|
|
|
static void scroll_down(struct view_info *info, int n)
|
|
{
|
|
if (info->line + info->display_lines >= info->line_count)
|
|
return;
|
|
|
|
calc_first_line(info, info->line+n);
|
|
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:
|
|
#ifdef HAVE_SCROLLWHEEL
|
|
case PLA_SCROLL_BACK:
|
|
case PLA_SCROLL_BACK_REPEAT:
|
|
#endif
|
|
scroll_up(&info, 1);
|
|
break;
|
|
case PLA_DOWN:
|
|
case PLA_DOWN_REPEAT:
|
|
#ifdef HAVE_SCROLLWHEEL
|
|
case PLA_SCROLL_FWD:
|
|
case PLA_SCROLL_FWD_REPEAT:
|
|
#endif
|
|
scroll_down(&info, 1);
|
|
break;
|
|
case PLA_LEFT:
|
|
scroll_up(&info, info.display_lines);
|
|
break;
|
|
case PLA_RIGHT:
|
|
scroll_down(&info, info.display_lines);
|
|
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;
|
|
}
|