fbvis: limit scrolling height when fullscreen
[fbvis.git] / fbvis.c
blobe746426530a96dff1f5e7e432d912b256bf92184
1 /*
2 * fbvis - a framebuffer image viewer
4 * Copyright (C) 2013 Ali Gholami Rudi
6 * This file is released under the modified BSD license.
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 "lodepng.h"
18 /* optimized version of fb_val() */
19 #define FB_VAL(r, g, b) (((r) << 16) | ((g) << 8) | (b))
21 #define PAGESTEPS 8
22 #define CTRLKEY(x) ((x) - 96)
23 #define MIN(a, b) ((a) < (b) ? (a) : (b))
24 #define MAX(a, b) ((a) > (b) ? (a) : (b))
25 #define REGION(a, b, x) (MIN(b, MAX(x, a)))
27 static int cols, rows, ch;
28 static char *buf;
29 static int head, left;
30 static int count;
31 static struct termios termios;
32 static int fullscreen;
34 static void draw(void)
36 char row[1 << 14];
37 int bpp = FBM_BPP(fb_mode());
38 int rs = head;
39 int re = rs + MIN(rows - rs, fb_rows());
40 int cs = left;
41 int ce = cs + MIN(cols - cs, fb_cols());
42 int fbr = (fb_rows() - (re - rs)) >> 1;
43 int fbc = (fb_cols() - (ce - cs)) >> 1;
44 int i, j;
45 for (i = rs; i < re; i++) {
46 for (j = cs; j < ce; j++) {
47 unsigned char *src = (void *) (buf + (i * cols + j) * ch);
48 unsigned int *dst = (void *) (row + (j - cs) * bpp);
49 *dst = FB_VAL(src[0], src[1], src[2]);
51 fb_set(fbr + i - rs, fbc, row, ce - cs);
55 static void drawfs(void)
57 char row[1 << 14];
58 int fsrows = rows * fb_cols() / cols;
59 int rs = head * MAX(0, fsrows - fb_rows()) / MAX(1, rows - fb_rows());
60 int bpp = FBM_BPP(fb_mode());
61 int i, j;
62 for (i = 0; i < fb_rows(); i++) {
63 int r = (rs + i) * rows / fsrows;
64 if (r >= rows)
65 memset(row, 0, fb_cols() * bpp);
66 for (j = 0; j < fb_cols() && r < rows; j++) {
67 int c = j * cols / fb_cols();
68 unsigned char *src = (void *) (buf + (r * cols + c) * ch);
69 unsigned int *dst = (void *) (row + j * bpp);
70 *dst = FB_VAL(src[0], src[1], src[2]);
72 fb_set(i, 0, row, fb_cols());
76 static int readkey(void)
78 unsigned char b;
79 if (read(0, &b, 1) <= 0)
80 return -1;
81 return b;
84 static int getcount(int def)
86 int result = count ? count : def;
87 count = 0;
88 return result;
91 static void term_setup(void)
93 struct termios newtermios;
94 tcgetattr(0, &termios);
95 newtermios = termios;
96 newtermios.c_lflag &= ~ICANON;
97 newtermios.c_lflag &= ~ECHO;
98 tcsetattr(0, TCSAFLUSH, &newtermios);
101 static void term_cleanup(void)
103 tcsetattr(0, 0, &termios);
106 static void mainloop(void)
108 int step = fb_rows() / PAGESTEPS;
109 int hstep = fb_cols() / PAGESTEPS;
110 int c;
111 term_setup();
112 draw();
113 while ((c = readkey()) != -1) {
114 switch (c) {
115 case 'd':
116 sleep(getcount(1));
117 break;
118 case 'q':
119 term_cleanup();
120 return;
121 case 27:
122 count = 0;
123 break;
124 default:
125 if (isdigit(c))
126 count = count * 10 + c - '0';
128 switch (c) {
129 case 'j':
130 head += step * getcount(1);
131 break;
132 case 'k':
133 head -= step * getcount(1);
134 break;
135 case 'l':
136 left += hstep * getcount(1);
137 break;
138 case 'h':
139 left -= hstep * getcount(1);
140 break;
141 case 'H':
142 head = 0;
143 break;
144 case 'L':
145 head = MAX(0, rows - fb_rows());
146 break;
147 case 'M':
148 head = MAX(0, (rows - fb_rows()) >> 1);
149 break;
150 case ' ':
151 case CTRL('d'):
152 head += fb_rows() * getcount(1) - step;
153 break;
154 case 127:
155 case CTRL('u'):
156 head -= fb_rows() * getcount(1) - step;
157 break;
158 case 'f':
159 if (cols > fb_cols())
160 fullscreen = 1 - fullscreen;
161 break;
162 case 'r':
163 case CTRLKEY('l'):
164 break;
165 default:
166 /* no need to redraw */
167 continue;
169 head = REGION(0, MAX(0, rows - fb_rows()), head);
170 left = REGION(0, MAX(0, cols - fb_cols()), left);
171 if (fullscreen)
172 drawfs();
173 else
174 draw();
178 unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp);
180 static char *loadstbi(char *path, int *h, int *w, int *ch)
182 return (void *) stbi_load(path, w, h, ch, 3);
185 static char *loadlode(char *path, int *h, int *w, int *ch)
187 char *s = NULL;
188 *ch = 4;
189 lodepng_decode32_file((void *) &s, (void *) w, (void *) h, path);
190 return s;
193 int main(int argc, char *argv[])
195 if (argc < 2) {
196 printf("usage: %s file\n", argv[0]);
197 return 0;
199 buf = loadlode(argv[1], &rows, &cols, &ch);
200 if (!buf)
201 buf = loadstbi(argv[1], &rows, &cols, &ch);
202 if (!buf) {
203 printf("failed to load image <%s>\n", argv[1]);
204 return 1;
206 if (fb_init())
207 return 1;
208 mainloop();
209 fb_free();
210 printf("\n");
211 free(buf);
212 return 0;