diff options
Diffstat (limited to 'apps/plugins/text_viewer/tv_pager.c')
-rw-r--r-- | apps/plugins/text_viewer/tv_pager.c | 337 |
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 | |||
37 | static unsigned char *pager_buffer; | ||
38 | |||
39 | static struct tv_screen_pos cur_pos; | ||
40 | |||
41 | static int parse_page; | ||
42 | static int last_page; | ||
43 | static int max_page; | ||
44 | |||
45 | static int lines_per_page; | ||
46 | |||
47 | static int line_pos[LCD_HEIGHT / 2]; | ||
48 | static int parse_page; | ||
49 | static int parse_top_line; | ||
50 | static int parse_lines; | ||
51 | |||
52 | static 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 | |||
60 | static unsigned int get_uint32(const unsigned char *p) | ||
61 | { | ||
62 | return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; | ||
63 | } | ||
64 | |||
65 | static 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 | |||
71 | static 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 | |||
78 | static 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 | |||
90 | bool 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 | |||
114 | void tv_finalize_pager(void) | ||
115 | { | ||
116 | tv_finalize_reader(); | ||
117 | } | ||
118 | |||
119 | void 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 | |||
126 | void 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 | |||
138 | int 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 | |||
150 | void 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 | |||
168 | static 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 | |||
198 | static 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 | |||
214 | void 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 | |||
248 | static 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 | |||
259 | void 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 | } | ||