1 #include <cstdlib>
2 #include <cstring>
3 #include <cassert>
4
5 #include "config.h"
6 #include "filter.h"
7 #include "ui_helper.h"
8 #include "grlib.h"
9
10 /* The "windows" implemented here are just regions of the image, not user
11 * interface windows. They are used to save the pixels that are going to
12 * be drawn over (e.g., with a text message) so they can be restored when the
13 * overlay should disappear. Windows are redrawn every frame and removed before
14 * calculation.
15 */
16
uih_registerw(struct uih_context * uih,uih_getposfunc getpos,uih_drawfunc draw,void * data,int flags)17 struct uih_window *uih_registerw(struct uih_context *uih, uih_getposfunc getpos,
18 uih_drawfunc draw, void *data, int flags)
19 {
20 struct uih_window *w =
21 (struct uih_window *)calloc(1, sizeof(struct uih_window));
22 struct uih_window *w1;
23 assert(uih != NULL && getpos != NULL && draw != NULL && flags >= 0);
24 if (w == NULL)
25 return NULL;
26 uih_clearwindows(uih);
27 w1 = uih->wtop;
28 w->getpos = getpos;
29 w->draw = draw;
30 w->data = data;
31 w->flags = flags;
32 w->savedline = -1;
33 w->saveddata = NULL;
34 w->next = NULL;
35 if (w1 == NULL) {
36 uih->wtop = w;
37 } else {
38 while (w1->next != NULL)
39 w1 = w1->next;
40 w1->next = w;
41 }
42 w->previous = w1;
43 w->x = -65536;
44 return w;
45 }
46
uih_setline(struct uih_context * uih,struct uih_window * w,int color,int x1,int y1,int x2,int y2)47 void uih_setline(struct uih_context *uih, struct uih_window *w, int color,
48 int x1, int y1, int x2, int y2)
49 {
50 if (w->savedline != color || w->x != x1 || w->y != y1 ||
51 w->width != x2 - x1 || w->height != y2 - y1) {
52 uih_clearwindows(uih);
53 uih->display = 1;
54 w->savedline = color;
55 w->x = x1;
56 w->y = y1;
57 w->width = x2 - x1;
58 w->height = y2 - y1;
59 }
60 }
61
uih_registerline(struct uih_context * uih,int color,int x1,int y1,int x2,int y2)62 struct uih_window *uih_registerline(struct uih_context *uih, int color, int x1,
63 int y1, int x2, int y2)
64 {
65 struct uih_window *w =
66 (struct uih_window *)calloc(1, sizeof(struct uih_window));
67 struct uih_window *w1;
68 if (w == NULL)
69 return NULL;
70 uih_clearwindows(uih);
71 w1 = uih->wtop;
72 uih->display = 1;
73 w->getpos = NULL;
74 w->savedline = color;
75 w->flags = 0;
76 w->x = x1;
77 w->y = y1;
78 w->width = x2 - x1;
79 w->height = y2 - y1;
80 w->saveddata = NULL;
81 w->next = NULL;
82 if (w1 == NULL) {
83 uih->wtop = w;
84 } else {
85 while (w1->next != NULL)
86 w1 = w1->next;
87 w1->next = w;
88 }
89 w->previous = w1;
90 return w;
91 }
92
uih_removew(struct uih_context * uih,struct uih_window * w)93 void uih_removew(struct uih_context *uih, struct uih_window *w)
94 {
95 uih_clearwindows(uih);
96 assert(uih->wtop != NULL);
97 assert(w != NULL);
98 uih->display = 1;
99
100 if (w->previous == NULL) {
101 assert(uih->wtop == w);
102 uih->wtop = w->next;
103 } else {
104 w->previous->next = w->next;
105 }
106 if (w->next != NULL) {
107 w->next->previous = w->previous;
108 }
109 free(w);
110 }
111
112 /*Remove all drawn windows from screen */
uih_clearwindows(struct uih_context * uih)113 void uih_clearwindows(struct uih_context *uih)
114 {
115 struct uih_window *w = uih->wtop;
116 int savedline = 0;
117 int savedpos = 0;
118 int destwidth = uih->image->width * uih->image->bytesperpixel;
119 if (!uih->wdisplayed)
120 return;
121 if (!uih->image->bytesperpixel) {
122 destwidth = (w->x + uih->image->width + 7) / 8;
123 }
124 uih->wdisplayed = 0;
125 if (uih->wflipped)
126 uih->image->flip(uih->image), uih->wflipped = 0;
127 while (w) {
128 if (w->getpos == NULL) {
129 if (w->saveddata != NULL) {
130 xrestoreline(uih->image, w->saveddata, w->x, w->y,
131 w->width + w->x, w->height + w->y);
132 free(w->saveddata);
133 w->saveddata = NULL;
134 }
135 } else {
136 if (w->savedline != -1 || w->saveddata != NULL) {
137 int i;
138 int xskip = w->x * uih->image->bytesperpixel;
139 int width = w->width * uih->image->bytesperpixel;
140 if (!uih->image->bytesperpixel) {
141 xskip = w->x / 8;
142 width = (w->x + w->width + 7) / 8 - xskip;
143 }
144 assert(w->width);
145 assert(w->height);
146 assert(w->x >= 0);
147 assert(w->y >= 0);
148 assert(w->x + w->width <= uih->image->width);
149 assert(w->y + w->height <= uih->image->height);
150 if (w->savedline != -1) {
151 savedline = w->savedline;
152 savedpos = w->savedpos;
153 for (i = w->y; i < w->y + w->height; i++) {
154 unsigned char *data = uih->image->currlines[i] + xskip;
155 assert(savedline < uih->image->height);
156 assert(savedline >= 0);
157 assert(savedpos >= 0 && savedpos <= destwidth);
158 if (width + savedpos > destwidth) {
159 int width1;
160 memcpy(data,
161 uih->image->oldlines[savedline] + savedpos,
162 destwidth - savedpos);
163 savedline++;
164 width1 = width - destwidth + savedpos;
165 memcpy(data + (destwidth - savedpos),
166 uih->image->oldlines[savedline], width1);
167 savedpos = width1;
168 } else
169 memcpy(data,
170 uih->image->oldlines[savedline] + savedpos,
171 width),
172 savedpos += width;
173 }
174 w->savedline = -1;
175 } else {
176 assert(w->saveddata);
177 for (i = w->y; i < w->y + w->height; i++) {
178 unsigned char *data = uih->image->currlines[i] + xskip;
179 memcpy(data, w->saveddata + (i - w->y) * width, width);
180 }
181 free(w->saveddata);
182 w->saveddata = NULL;
183 }
184 }
185 }
186 w = w->next;
187 }
188 }
189
uih_drawwindows(struct uih_context * uih)190 void uih_drawwindows(struct uih_context *uih)
191 {
192 struct uih_window *w = uih->wtop;
193 struct image *img = uih->image;
194 int size = 0;
195 int nocopy = 0;
196 int savedline = 0;
197 int savedpos = 0;
198 int destwidth = uih->image->width * uih->image->bytesperpixel;
199 if (!uih->image->bytesperpixel) {
200 destwidth = (w->x + uih->image->width + 7) / 8;
201 }
202 if (uih->wdisplayed)
203 return;
204 uih->wdisplayed = 1;
205 while (w) {
206 if (w->getpos != NULL) {
207 w->getpos(uih, &w->x, &w->y, &w->width, &w->height, w->data);
208 if (w->x < 0)
209 w->width -= w->x, w->x = 0;
210 if (w->y < 0)
211 w->height -= w->y, w->y = 0;
212 if (w->x > img->width)
213 w->width = 0, w->height = 0, w->x = 0;
214 if (w->y > img->height)
215 w->width = 0, w->height = 0, w->y = 0;
216 if (w->x + w->width > img->width)
217 w->width = img->width - w->x;
218 if (w->y + w->height > img->height)
219 w->height = img->height - w->y;
220 if (w->width < 0)
221 w->width = 0;
222 if (w->height < 0)
223 w->height = 0;
224 size += w->width * w->height;
225 if (w->x == 0 && w->y == 0 && w->width == img->width &&
226 w->height == img->height)
227 nocopy = 1;
228 assert(w->width >= 0);
229 assert(w->height >= 0);
230 assert(w->x >= 0);
231 assert(w->y >= 0);
232 assert(w->x + w->width <= uih->image->width);
233 assert(w->y + w->height <= uih->image->height);
234 }
235 w = w->next;
236 }
237 if (size > img->width * img->height / 2) {
238 int i;
239 int width = img->width * img->bytesperpixel;
240 if (!width)
241 width = (img->width + 7) / 8;
242 uih->wflipped = 1;
243 if (!nocopy)
244 for (i = 0; i < img->height; i++)
245 memcpy(img->oldlines[i], img->currlines[i], width);
246 uih->image->flip(uih->image);
247 } else {
248 int savedminx = -1;
249 int savedmaxx = -1;
250 int savedminy = -1;
251 int savedmaxy = -1;
252 uih->wflipped = 0;
253 w = uih->wtop;
254 while (w) {
255 int i;
256 assert(w->saveddata == NULL);
257 if (w->getpos == NULL) {
258 if ((w->x < savedminx || w->y < savedminy ||
259 w->x + w->width > savedmaxx ||
260 w->x + w->height > savedmaxy ||
261 w->x + w->width < savedminx ||
262 w->y + w->height < savedminy || w->x > savedmaxx ||
263 w->y > savedmaxy)) {
264 w->saveddata = xsaveline(uih->image, w->x, w->y,
265 w->width + w->x, w->height + w->y);
266 }
267 } else {
268 assert(w->savedline == -1);
269 if (w->width && w->height &&
270 (w->x < savedminx || w->y < savedminy ||
271 w->x + w->width > savedmaxx ||
272 w->y + w->height > savedmaxy)) {
273 int xskip = w->x * uih->image->bytesperpixel;
274 int width = w->width * uih->image->bytesperpixel;
275 savedminx = w->x;
276 savedminy = w->y;
277 savedmaxx = w->x + w->width;
278 savedmaxy = w->y + w->height;
279 if (!uih->image->bytesperpixel) {
280 xskip = w->x / 8;
281 width = (w->x + w->width + 7) / 8 - xskip;
282 }
283 if (uih->image->flags & PROTECTBUFFERS) {
284 w->saveddata = (char *)malloc(width * w->height + 1);
285 if (w->saveddata != NULL)
286 for (i = w->y; i < w->y + w->height; i++) {
287 unsigned char *data = img->currlines[i] + xskip;
288 memcpy(w->saveddata + (i - w->y) * width, data,
289 width);
290 }
291
292 } else {
293 w->savedline = savedline;
294 w->savedpos = savedpos;
295 for (i = w->y; i < w->y + w->height; i++) {
296 unsigned char *data = img->currlines[i] + xskip;
297 if (width + savedpos > destwidth) {
298 int width1;
299 memcpy(uih->image->oldlines[savedline] +
300 savedpos,
301 data, destwidth - savedpos);
302 savedline++;
303 width1 = width - destwidth + savedpos;
304 memcpy(uih->image->oldlines[savedline],
305 data + (destwidth - savedpos), width1);
306 savedpos = width1;
307 } else
308 memcpy(uih->image->oldlines[savedline] +
309 savedpos,
310 data, width),
311 savedpos += width;
312 }
313 }
314 }
315 }
316 w = w->next;
317 }
318 }
319 w = uih->wtop;
320 while (w) {
321 if (w->getpos == NULL) {
322 #define lwi 0
323 #define lwj 0
324 xline(uih->image, w->x + lwi, w->y + lwj, w->width + w->x + lwi,
325 w->height + w->y + lwj, w->savedline);
326 } else if (w->width && w->height) {
327 w->draw(uih, w->data);
328 }
329 w = w->next;
330 }
331 }
332