fbpdf: preserve head position in marks when zoom value changes
[fbpdf.git] / fbpdf.c
bloba02d6aab9783b3dbc9eebc2c6899f7cb387a3f72
1 /*
2 * fbpdf - a small framebuffer pdf viewer using mupdf
4 * Copyright (C) 2009-2011 Ali Gholami Rudi
6 * This program is released under GNU GPL version 2.
7 */
8 #include <ctype.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <pty.h>
15 #include "draw.h"
16 #include "doc.h"
18 #define MIN(a, b) ((a) < (b) ? (a) : (b))
19 #define MAX(a, b) ((a) > (b) ? (a) : (b))
21 #define PAGESTEPS 8
22 #define CTRLKEY(x) ((x) - 96)
23 #define MAXWIDTH 2
24 #define MAXHEIGHT 3
25 #define PDFCOLS (1 << 11)
26 #define PDFROWS (1 << 12)
28 static fbval_t pbuf[PDFROWS * PDFCOLS];
29 static struct doc *doc;
31 static int num = 1;
32 static struct termios termios;
33 static char filename[256];
34 static int mark[128]; /* mark page number */
35 static int mark_head[128]; /* mark head position */
36 static int zoom = 15;
37 static int rotate;
38 static int head;
39 static int left;
40 static int count;
42 static void draw(void)
44 int i;
45 for (i = head; i < MIN(head + fb_rows(), PDFROWS); i++)
46 fb_set(i - head, 0, pbuf + i * PDFCOLS + left, fb_cols());
49 static int showpage(int p, int h)
51 if (p < 1 || p > doc_pages(doc))
52 return 0;
53 memset(pbuf, 0x00, sizeof(pbuf));
54 doc_draw(doc, pbuf, p, PDFROWS, PDFCOLS, zoom, rotate);
55 num = p;
56 head = h;
57 draw();
58 return 0;
61 static int readkey(void)
63 unsigned char b;
64 if (read(STDIN_FILENO, &b, 1) <= 0)
65 return -1;
66 return b;
69 static int getcount(int def)
71 int result = count ? count : def;
72 count = 0;
73 return result;
76 static void printinfo(void)
78 printf("\x1b[H");
79 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K",
80 filename, num, doc_pages(doc), zoom * 10);
81 fflush(stdout);
84 static void term_setup(void)
86 struct termios newtermios;
87 tcgetattr(STDIN_FILENO, &termios);
88 newtermios = termios;
89 newtermios.c_lflag &= ~ICANON;
90 newtermios.c_lflag &= ~ECHO;
91 tcsetattr(STDIN_FILENO, TCSAFLUSH, &newtermios);
94 static void term_cleanup(void)
96 tcsetattr(STDIN_FILENO, 0, &termios);
99 static void sigcont(int sig)
101 term_setup();
104 static void reload(void)
106 doc_close(doc);
107 doc = doc_open(filename);
108 showpage(num, head);
111 static void mainloop(void)
113 int step = fb_rows() / PAGESTEPS;
114 int hstep = fb_cols() / PAGESTEPS;
115 int c, c2;
116 int _zoom;
117 term_setup();
118 signal(SIGCONT, sigcont);
119 showpage(num, 0);
120 while ((c = readkey()) != -1) {
121 int maxhead = PDFROWS - fb_rows();
122 int maxleft = PDFCOLS - fb_cols();
123 switch (c) {
124 case CTRLKEY('f'):
125 case 'J':
126 showpage(num + getcount(1), 0);
127 break;
128 case CTRLKEY('b'):
129 case 'K':
130 showpage(num - getcount(1), 0);
131 break;
132 case 'G':
133 showpage(getcount(doc_pages(doc)), 0);
134 break;
135 case 'z':
136 _zoom = zoom;
137 zoom = getcount(15);
138 showpage(num, MIN(maxhead, head * zoom / _zoom));
139 break;
140 case 'r':
141 rotate = getcount(0);
142 showpage(num, 0);
143 break;
144 case 'i':
145 printinfo();
146 break;
147 case 'q':
148 term_cleanup();
149 return;
150 case 27:
151 count = 0;
152 break;
153 case 'm':
154 c2 = readkey();
155 if (isalpha(c2)) {
156 mark[c2] = num;
157 mark_head[c2] = head / zoom;
159 break;
160 case 'e':
161 reload();
162 break;
163 case '`':
164 case '\'':
165 c2 = readkey();
166 if (isalpha(c2) && mark[c2])
167 showpage(mark[c2], c == '`' ? mark_head[c2] * zoom : 0);
168 break;
169 default:
170 if (isdigit(c))
171 count = count * 10 + c - '0';
173 switch (c) {
174 case 'j':
175 head += step * getcount(1);
176 break;
177 case 'k':
178 head -= step * getcount(1);
179 break;
180 case 'l':
181 left += hstep * getcount(1);
182 break;
183 case 'h':
184 left -= hstep * getcount(1);
185 break;
186 case 'H':
187 head = 0;
188 break;
189 case 'L':
190 head = maxhead;
191 break;
192 case 'M':
193 head = maxhead / 2;
194 break;
195 case ' ':
196 case CTRL('d'):
197 head += fb_rows() * getcount(1) - step;
198 break;
199 case 127:
200 case CTRL('u'):
201 head -= fb_rows() * getcount(1) - step;
202 break;
203 case CTRLKEY('l'):
204 break;
205 default:
206 /* no need to redraw */
207 continue;
209 head = MAX(0, MIN(maxhead, head));
210 left = MAX(0, MIN(maxleft, left));
211 draw();
215 static char *usage =
216 "usage: fbpdf [-r rotation] [-z zoom x10] [-p page] filename\n";
218 int main(int argc, char *argv[])
220 char *hide = "\x1b[?25l";
221 char *show = "\x1b[?25h";
222 char *clear = "\x1b[2J";
223 int i = 1;
224 if (argc < 2) {
225 printf(usage);
226 return 1;
228 strcpy(filename, argv[argc - 1]);
229 doc = doc_open(filename);
230 if (!doc) {
231 fprintf(stderr, "cannot open <%s>\n", filename);
232 return 1;
234 while (i + 2 < argc && argv[i][0] == '-') {
235 if (argv[i][1] == 'r')
236 rotate = atoi(argv[i + 1]);
237 if (argv[i][1] == 'z')
238 zoom = atoi(argv[i + 1]);
239 if (argv[i][1] == 'p')
240 num = atoi(argv[i + 1]);
241 i += 2;
244 write(STDIN_FILENO, hide, strlen(hide));
245 write(STDOUT_FILENO, clear, strlen(clear));
246 printinfo();
247 if (fb_init())
248 return 1;
249 left = (PDFCOLS - fb_cols()) / 2;
250 if (FBM_BPP(fb_mode()) != sizeof(fbval_t))
251 fprintf(stderr, "fbpdf: fbval_t doesn't match fb depth\n");
252 else
253 mainloop();
254 fb_free();
255 write(STDIN_FILENO, show, strlen(show));
256 printf("\n");
257 doc_close(doc);
258 return 0;