summaryrefslogtreecommitdiff
path: root/apps/plugins/text_viewer/tv_pager.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/text_viewer/tv_pager.c')
-rw-r--r--apps/plugins/text_viewer/tv_pager.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/apps/plugins/text_viewer/tv_pager.c b/apps/plugins/text_viewer/tv_pager.c
new file mode 100644
index 0000000000..d98fe4627d
--- /dev/null
+++ b/apps/plugins/text_viewer/tv_pager.c
@@ -0,0 +1,337 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Gilles Roux
11 * 2003 Garrett Derner
12 * 2010 Yoshihisa Uchida
13 *
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.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
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"
28
29#if PLUGIN_BUFFER_SIZE < 0x13000
30#define TV_MAX_PAGE 999
31#else
32#define TV_MAX_PAGE 9999
33#endif
34
35#define TV_PAGER_MEMSIZE (4 * TV_MAX_PAGE)
36
37static unsigned char *pager_buffer;
38
39static struct tv_screen_pos cur_pos;
40
41static int parse_page;
42static int last_page;
43static int max_page;
44
45static int lines_per_page;
46
47static int line_pos[LCD_HEIGHT / 2];
48static int parse_page;
49static int parse_top_line;
50static int parse_lines;
51
52static void set_uint32(unsigned char *p, unsigned int val)
53{
54 *p++ = val & 0xff;
55 *p++ = (val >> 8) & 0xff;
56 *p++ = (val >> 16) & 0xff;
57 *p = (val >> 24) & 0xff;
58}
59
60static unsigned int get_uint32(const unsigned char *p)
61{
62 return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0];
63}
64
65static void tv_set_fpos(int page, off_t pos)
66{
67 if (page >= 0 && page <= max_page)
68 set_uint32(pager_buffer + page * 4, pos);
69}
70
71static off_t tv_get_fpos(int page)
72{
73 if (page >= 0 && page <= max_page)
74 return get_uint32(pager_buffer + page * 4);
75 return 0;
76}
77
78static void tv_change_preferences(const struct tv_preferences *oldp)
79{
80 (void)oldp;
81
82 cur_pos.page = 0;
83 cur_pos.line = 0;
84 last_page = 0;
85 max_page = TV_MAX_PAGE - 1;
86 tv_set_fpos(cur_pos.page, 0);
87 tv_seek(0, SEEK_SET);
88}
89
90bool tv_init_pager(unsigned char *buf, size_t bufsize, size_t *used_size)
91{
92 if (bufsize < TV_PAGER_MEMSIZE)
93 return false;
94
95 pager_buffer = buf;
96 tv_set_screen_pos(&cur_pos);
97 tv_add_preferences_change_listner(tv_change_preferences);
98
99 /* valid page: 0, ..., max_page. */
100 max_page = TV_MAX_PAGE - 1;
101
102 line_pos[0] = 0;
103
104 buf += TV_PAGER_MEMSIZE;
105 bufsize -= TV_PAGER_MEMSIZE;
106 if (!tv_init_reader(buf, bufsize, used_size))
107 return false;
108
109 *used_size += TV_PAGER_MEMSIZE;
110
111 return true;
112}
113
114void tv_finalize_pager(void)
115{
116 tv_finalize_reader();
117}
118
119void tv_reset_line_positions(void)
120{
121 parse_page = cur_pos.page;
122 parse_top_line = cur_pos.line;
123 parse_lines = 0;
124}
125
126void tv_move_next_line(int size)
127{
128 if (!tv_is_eof())
129 {
130 tv_seek(size, SEEK_CUR);
131 cur_pos.file_pos = tv_get_current_file_pos();
132 cur_pos.line++;
133 parse_lines++;
134 line_pos[cur_pos.line] = line_pos[cur_pos.line - 1] + size;
135 }
136}
137
138int tv_get_line_positions(int offset)
139{
140 int line = cur_pos.line + offset;
141
142 if (line < 0)
143 line = 0;
144 else if (line > parse_lines)
145 line = parse_lines;
146
147 return line_pos[parse_top_line + line] - line_pos[parse_top_line];
148}
149
150void tv_new_page(void)
151{
152 parse_page = cur_pos.page;
153 if (cur_pos.page == last_page && last_page < max_page)
154 {
155 if (!tv_is_eof())
156 tv_set_fpos(++last_page, tv_get_current_file_pos());
157 else
158 max_page = last_page;
159 }
160
161 if (++cur_pos.page > max_page)
162 cur_pos.page = max_page;
163
164 lines_per_page = cur_pos.line;
165 cur_pos.line = 0;
166}
167
168static void tv_seek_page(int offset, int whence)
169{
170 int new_page = offset;
171
172 switch (whence)
173 {
174 case SEEK_CUR:
175 new_page += cur_pos.page;
176 break;
177 case SEEK_SET:
178 break;
179 case SEEK_END:
180 new_page += last_page;
181 whence = SEEK_SET;
182 break;
183 default:
184 return;
185 break;
186 }
187 if (new_page < 0)
188 new_page = 0;
189 else if (new_page >= last_page)
190 new_page = last_page;
191
192 cur_pos.page = new_page;
193 cur_pos.line = 0;
194 cur_pos.file_pos = tv_get_fpos(new_page);
195 tv_seek(cur_pos.file_pos, SEEK_SET);
196}
197
198static bool tv_create_line_positions(void)
199{
200 bool res;
201
202 if (tv_is_eof())
203 return false;
204
205 cur_pos.line = 0;
206 tv_reset_line_positions();
207 res = tv_traverse_lines();
208 lines_per_page = cur_pos.line;
209 tv_new_page();
210
211 return res;
212}
213
214void tv_convert_fpos(off_t fpos, struct tv_screen_pos *pos)
215{
216 int i;
217
218 for (i = 0; i < last_page; i++)
219 {
220 if (tv_get_fpos(i) <= fpos && tv_get_fpos(i + 1) > fpos)
221 break;
222 }
223
224 pos->page = i;
225 pos->line = 0;
226 pos->file_pos = fpos;
227
228 if (tv_get_fpos(i) == fpos)
229 return;
230
231 tv_seek_page(i, SEEK_SET);
232 while (tv_create_line_positions() && cur_pos.file_pos < fpos)
233 rb->splashf(0, "converting %ld%%...", 100 * cur_pos.file_pos / fpos);
234
235 if (cur_pos.page < max_page)
236 cur_pos.page--;
237 tv_seek_page(cur_pos.page, SEEK_SET);
238 for (i = 0; i < lines_per_page; i++)
239 {
240 if (cur_pos.file_pos + tv_get_line_positions(i) >= fpos)
241 break;
242 }
243
244 pos->page = cur_pos.page;
245 pos->line = i;
246}
247
248static void tv_seek_to_bottom_line(void)
249{
250 off_t total_size = tv_get_file_size();
251
252 tv_seek_page(0, SEEK_END);
253 while (tv_create_line_positions())
254 rb->splashf(0, "loading %ld%%...", 100 * cur_pos.file_pos / total_size);
255
256 cur_pos.line = lines_per_page - 1;
257}
258
259void tv_move_screen(int page_offset, int line_offset, int whence)
260{
261 struct tv_screen_pos new_pos;
262 int i;
263
264 switch (whence)
265 {
266 case SEEK_CUR:
267 cur_pos.page += page_offset;
268 cur_pos.line += line_offset;
269 break;
270 case SEEK_SET:
271 cur_pos.page = page_offset;
272 cur_pos.line = line_offset;
273 break;
274 case SEEK_END:
275 tv_seek_to_bottom_line();
276 cur_pos.page += page_offset;
277 cur_pos.line += line_offset;
278 break;
279 default:
280 return;
281 break;
282 }
283
284 if (cur_pos.page < 0 || (cur_pos.page == 0 && cur_pos.line < 0))
285 {
286 tv_seek_page(0, SEEK_SET);
287 return;
288 }
289 else if (cur_pos.page > max_page)
290 {
291 tv_seek_page(max_page, SEEK_SET);
292 return;
293 }
294
295 new_pos = cur_pos;
296 if (cur_pos.line < 0)
297 new_pos.page--;
298
299 tv_seek_page(new_pos.page, SEEK_SET);
300 while (cur_pos.page < new_pos.page && tv_create_line_positions())
301 rb->splashf(0, "loading %d%%...", 100 * cur_pos.page / new_pos.page);
302
303 if (new_pos.line == 0)
304 return;
305
306 if (parse_page == cur_pos.page)
307 {
308 if (cur_pos.page < max_page && new_pos.line == lines_per_page)
309 {
310 tv_seek(line_pos[lines_per_page], SEEK_CUR);
311 for (i = 0; i < parse_lines; i++)
312 line_pos[i] = line_pos[i + lines_per_page] - line_pos[lines_per_page];
313
314 cur_pos.page++;
315 cur_pos.line = 0;
316 parse_top_line = 0;
317 new_pos.line = 0;
318 }
319 }
320 else
321 {
322 tv_create_line_positions();
323 tv_seek_page(new_pos.page, SEEK_SET);
324 }
325
326 cur_pos.line = new_pos.line;
327 if (cur_pos.line >= lines_per_page)
328 cur_pos.line = lines_per_page - 1;
329 else if (cur_pos.line < 0)
330 {
331 cur_pos.line += lines_per_page;
332 if (cur_pos.line < 0)
333 cur_pos.line = 0;
334 }
335 tv_seek(line_pos[cur_pos.line], SEEK_CUR);
336 cur_pos.file_pos += line_pos[cur_pos.line];
337}