Fix FS#11593 - %Vf() and %Vb() should be able to be used in conditionals. Remember...
[maemo-rb.git] / apps / plugins / text_viewer / tv_pager.c
blobe9886e09dd5d10722a21679118aa1a736a40948e
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 int 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);
86 return TV_CALLBACK_OK;
89 bool tv_init_pager(unsigned char **buf, size_t *size)
91 tv_set_screen_pos(&cur_pos);
92 tv_add_preferences_change_listner(tv_change_preferences);
94 /* valid page: 0, ..., max_page. */
95 max_page = TV_MAX_PAGE - 1;
97 line_pos[0] = 0;
99 return tv_init_reader(buf, size);
102 void tv_finalize_pager(void)
104 tv_finalize_reader();
107 void tv_reset_line_positions(void)
109 parse_page = cur_pos.page;
110 parse_top_line = cur_pos.line;
111 parse_lines = 0;
114 void tv_move_next_line(int size)
116 if (!tv_is_eof())
118 tv_seek(size, SEEK_CUR);
119 cur_pos.file_pos = tv_get_current_file_pos();
120 cur_pos.line++;
121 parse_lines++;
122 line_pos[cur_pos.line] = line_pos[cur_pos.line - 1] + size;
126 int tv_get_line_positions(int offset)
128 int line = cur_pos.line + offset;
130 if (line < 0)
131 line = 0;
132 else if (line > parse_lines)
133 line = parse_lines;
135 return line_pos[parse_top_line + line] - line_pos[parse_top_line];
138 void tv_new_page(void)
140 parse_page = cur_pos.page;
141 if (cur_pos.page == last_page && last_page < max_page)
143 if (!tv_is_eof())
144 tv_set_fpos(++last_page, tv_get_current_file_pos());
145 else
146 max_page = last_page;
149 if (++cur_pos.page > max_page)
150 cur_pos.page = max_page;
152 lines_per_page = cur_pos.line;
153 cur_pos.line = 0;
156 static void tv_seek_page(int offset, int whence)
158 int new_page = offset;
160 switch (whence)
162 case SEEK_CUR:
163 new_page += cur_pos.page;
164 break;
165 case SEEK_SET:
166 break;
167 case SEEK_END:
168 new_page += last_page;
169 whence = SEEK_SET;
170 break;
171 default:
172 return;
173 break;
175 if (new_page < 0)
176 new_page = 0;
177 else if (new_page >= last_page)
178 new_page = last_page;
180 cur_pos.page = new_page;
181 cur_pos.line = 0;
182 cur_pos.file_pos = tv_get_fpos(new_page);
183 tv_seek(cur_pos.file_pos, SEEK_SET);
186 static bool tv_create_line_positions(void)
188 bool res;
190 if (tv_is_eof())
191 return false;
193 cur_pos.line = 0;
194 tv_reset_line_positions();
195 res = tv_traverse_lines();
196 lines_per_page = cur_pos.line;
197 tv_new_page();
199 return res;
202 void tv_convert_fpos(off_t fpos, struct tv_screen_pos *pos)
204 int i;
206 for (i = 0; i < last_page; i++)
208 if (tv_get_fpos(i) <= fpos && tv_get_fpos(i + 1) > fpos)
209 break;
212 pos->page = i;
213 pos->line = 0;
214 pos->file_pos = fpos;
216 if (tv_get_fpos(i) == fpos)
217 return;
219 tv_seek_page(i, SEEK_SET);
220 while (tv_create_line_positions() && cur_pos.file_pos < fpos)
221 rb->splashf(0, "converting %ld%%...", 100 * cur_pos.file_pos / fpos);
223 if (i < max_page)
224 cur_pos.page--;
225 tv_seek_page(cur_pos.page, SEEK_SET);
226 for (i = 0; i < lines_per_page; i++)
228 if (cur_pos.file_pos + tv_get_line_positions(i) >= fpos)
229 break;
232 pos->page = cur_pos.page;
233 pos->line = i;
236 static void tv_seek_to_bottom_line(void)
238 off_t total_size = tv_get_file_size();
240 tv_seek_page(0, SEEK_END);
241 while (tv_create_line_positions())
242 rb->splashf(0, "loading %ld%%...", 100 * cur_pos.file_pos / total_size);
244 cur_pos.line = lines_per_page - 1;
247 void tv_move_screen(int page_offset, int line_offset, int whence)
249 struct tv_screen_pos new_pos;
250 int i;
252 switch (whence)
254 case SEEK_CUR:
255 cur_pos.page += page_offset;
256 cur_pos.line += line_offset;
257 break;
258 case SEEK_SET:
259 cur_pos.page = page_offset;
260 cur_pos.line = line_offset;
261 break;
262 case SEEK_END:
263 tv_seek_to_bottom_line();
264 cur_pos.page += page_offset;
265 cur_pos.line += line_offset;
266 break;
267 default:
268 return;
269 break;
272 if (cur_pos.page < 0 || (cur_pos.page == 0 && cur_pos.line < 0))
274 tv_seek_page(0, SEEK_SET);
275 return;
277 else if (cur_pos.page > max_page)
279 tv_seek_page(max_page, SEEK_SET);
280 return;
283 new_pos = cur_pos;
284 if (cur_pos.line < 0)
285 new_pos.page--;
287 tv_seek_page(new_pos.page, SEEK_SET);
288 while (cur_pos.page < new_pos.page && tv_create_line_positions())
289 rb->splashf(0, "loading %d%%...", 100 * cur_pos.page / new_pos.page);
291 if (new_pos.line == 0)
292 return;
294 if (parse_page == cur_pos.page)
296 if (cur_pos.page < max_page && new_pos.line == lines_per_page)
298 tv_seek(line_pos[lines_per_page], SEEK_CUR);
299 cur_pos.file_pos += line_pos[lines_per_page];
301 for (i = 0; i < parse_lines; i++)
302 line_pos[i] = line_pos[i + lines_per_page] - line_pos[lines_per_page];
304 cur_pos.page++;
305 cur_pos.line = 0;
306 parse_top_line = 0;
307 new_pos.line = 0;
310 else
312 tv_create_line_positions();
313 tv_seek_page(new_pos.page, SEEK_SET);
316 cur_pos.line = new_pos.line;
317 if (cur_pos.line >= lines_per_page)
318 cur_pos.line = lines_per_page - 1;
319 else if (cur_pos.line < 0)
321 cur_pos.line += lines_per_page;
322 if (cur_pos.line < 0)
323 cur_pos.line = 0;
325 tv_seek(line_pos[cur_pos.line], SEEK_CUR);
326 cur_pos.file_pos += line_pos[cur_pos.line];