FS#11399 by me: fix r26998 for text_viewer
[kugel-rb.git] / apps / plugins / text_viewer / tv_pager.c
blobe7016c7fef79597c58d05bc621de34a69c5b3aed
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Gilles Roux
11 * 2003 Garrett Derner
12 * 2010 Yoshihisa Uchida
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "plugin.h"
24 #include "tv_pager.h"
25 #include "tv_preferences.h"
26 #include "tv_reader.h"
27 #include "tv_window.h"
29 #if PLUGIN_BUFFER_SIZE < 0x13000
30 #define TV_MAX_PAGE 999
31 #else
32 #define TV_MAX_PAGE 9999
33 #endif
35 static unsigned char pager_buffer[4 * TV_MAX_PAGE];
37 static struct tv_screen_pos cur_pos;
39 static int parse_page;
40 static int last_page;
41 static int max_page;
43 static int lines_per_page;
45 static int line_pos[LCD_HEIGHT / 2];
46 static int parse_page;
47 static int parse_top_line;
48 static int parse_lines;
50 static void set_uint32(unsigned char *p, unsigned int val)
52 *p++ = val & 0xff;
53 *p++ = (val >> 8) & 0xff;
54 *p++ = (val >> 16) & 0xff;
55 *p = (val >> 24) & 0xff;
58 static unsigned int get_uint32(const unsigned char *p)
60 return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0];
63 static void tv_set_fpos(int page, off_t pos)
65 if (page >= 0 && page <= max_page)
66 set_uint32(pager_buffer + page * 4, pos);
69 static off_t tv_get_fpos(int page)
71 if (page >= 0 && page <= max_page)
72 return get_uint32(pager_buffer + page * 4);
73 return 0;
76 static void tv_change_preferences(const struct tv_preferences *oldp)
78 (void)oldp;
80 cur_pos.page = 0;
81 cur_pos.line = 0;
82 last_page = 0;
83 max_page = TV_MAX_PAGE - 1;
84 tv_set_fpos(cur_pos.page, 0);
85 tv_seek(0, SEEK_SET);
88 bool tv_init_pager(unsigned char **buf, size_t *size)
90 tv_set_screen_pos(&cur_pos);
91 tv_add_preferences_change_listner(tv_change_preferences);
93 /* valid page: 0, ..., max_page. */
94 max_page = TV_MAX_PAGE - 1;
96 line_pos[0] = 0;
98 return tv_init_reader(buf, size);
101 void tv_finalize_pager(void)
103 tv_finalize_reader();
106 void tv_reset_line_positions(void)
108 parse_page = cur_pos.page;
109 parse_top_line = cur_pos.line;
110 parse_lines = 0;
113 void tv_move_next_line(int size)
115 if (!tv_is_eof())
117 tv_seek(size, SEEK_CUR);
118 cur_pos.file_pos = tv_get_current_file_pos();
119 cur_pos.line++;
120 parse_lines++;
121 line_pos[cur_pos.line] = line_pos[cur_pos.line - 1] + size;
125 int tv_get_line_positions(int offset)
127 int line = cur_pos.line + offset;
129 if (line < 0)
130 line = 0;
131 else if (line > parse_lines)
132 line = parse_lines;
134 return line_pos[parse_top_line + line] - line_pos[parse_top_line];
137 void tv_new_page(void)
139 parse_page = cur_pos.page;
140 if (cur_pos.page == last_page && last_page < max_page)
142 if (!tv_is_eof())
143 tv_set_fpos(++last_page, tv_get_current_file_pos());
144 else
145 max_page = last_page;
148 if (++cur_pos.page > max_page)
149 cur_pos.page = max_page;
151 lines_per_page = cur_pos.line;
152 cur_pos.line = 0;
155 static void tv_seek_page(int offset, int whence)
157 int new_page = offset;
159 switch (whence)
161 case SEEK_CUR:
162 new_page += cur_pos.page;
163 break;
164 case SEEK_SET:
165 break;
166 case SEEK_END:
167 new_page += last_page;
168 whence = SEEK_SET;
169 break;
170 default:
171 return;
172 break;
174 if (new_page < 0)
175 new_page = 0;
176 else if (new_page >= last_page)
177 new_page = last_page;
179 cur_pos.page = new_page;
180 cur_pos.line = 0;
181 cur_pos.file_pos = tv_get_fpos(new_page);
182 tv_seek(cur_pos.file_pos, SEEK_SET);
185 static bool tv_create_line_positions(void)
187 bool res;
189 if (tv_is_eof())
190 return false;
192 cur_pos.line = 0;
193 tv_reset_line_positions();
194 res = tv_traverse_lines();
195 lines_per_page = cur_pos.line;
196 tv_new_page();
198 return res;
201 void tv_convert_fpos(off_t fpos, struct tv_screen_pos *pos)
203 int i;
205 for (i = 0; i < last_page; i++)
207 if (tv_get_fpos(i) <= fpos && tv_get_fpos(i + 1) > fpos)
208 break;
211 pos->page = i;
212 pos->line = 0;
213 pos->file_pos = fpos;
215 if (tv_get_fpos(i) == fpos)
216 return;
218 tv_seek_page(i, SEEK_SET);
219 while (tv_create_line_positions() && cur_pos.file_pos < fpos)
220 rb->splashf(0, "converting %ld%%...", 100 * cur_pos.file_pos / fpos);
222 if (cur_pos.page < max_page)
223 cur_pos.page--;
224 tv_seek_page(cur_pos.page, SEEK_SET);
225 for (i = 0; i < lines_per_page; i++)
227 if (cur_pos.file_pos + tv_get_line_positions(i) >= fpos)
228 break;
231 pos->page = cur_pos.page;
232 pos->line = i;
235 static void tv_seek_to_bottom_line(void)
237 off_t total_size = tv_get_file_size();
239 tv_seek_page(0, SEEK_END);
240 while (tv_create_line_positions())
241 rb->splashf(0, "loading %ld%%...", 100 * cur_pos.file_pos / total_size);
243 cur_pos.line = lines_per_page - 1;
246 void tv_move_screen(int page_offset, int line_offset, int whence)
248 struct tv_screen_pos new_pos;
249 int i;
251 switch (whence)
253 case SEEK_CUR:
254 cur_pos.page += page_offset;
255 cur_pos.line += line_offset;
256 break;
257 case SEEK_SET:
258 cur_pos.page = page_offset;
259 cur_pos.line = line_offset;
260 break;
261 case SEEK_END:
262 tv_seek_to_bottom_line();
263 cur_pos.page += page_offset;
264 cur_pos.line += line_offset;
265 break;
266 default:
267 return;
268 break;
271 if (cur_pos.page < 0 || (cur_pos.page == 0 && cur_pos.line < 0))
273 tv_seek_page(0, SEEK_SET);
274 return;
276 else if (cur_pos.page > max_page)
278 tv_seek_page(max_page, SEEK_SET);
279 return;
282 new_pos = cur_pos;
283 if (cur_pos.line < 0)
284 new_pos.page--;
286 tv_seek_page(new_pos.page, SEEK_SET);
287 while (cur_pos.page < new_pos.page && tv_create_line_positions())
288 rb->splashf(0, "loading %d%%...", 100 * cur_pos.page / new_pos.page);
290 if (new_pos.line == 0)
291 return;
293 if (parse_page == cur_pos.page)
295 if (cur_pos.page < max_page && new_pos.line == lines_per_page)
297 tv_seek(line_pos[lines_per_page], SEEK_CUR);
298 for (i = 0; i < parse_lines; i++)
299 line_pos[i] = line_pos[i + lines_per_page] - line_pos[lines_per_page];
301 cur_pos.page++;
302 cur_pos.line = 0;
303 parse_top_line = 0;
304 new_pos.line = 0;
307 else
309 tv_create_line_positions();
310 tv_seek_page(new_pos.page, SEEK_SET);
313 cur_pos.line = new_pos.line;
314 if (cur_pos.line >= lines_per_page)
315 cur_pos.line = lines_per_page - 1;
316 else if (cur_pos.line < 0)
318 cur_pos.line += lines_per_page;
319 if (cur_pos.line < 0)
320 cur_pos.line = 0;
322 tv_seek(line_pos[cur_pos.line], SEEK_CUR);
323 cur_pos.file_pos += line_pos[cur_pos.line];