Mercurial > geeqie.yaz
comparison src/image.c @ 12:147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
##### an offical release when making enhancements and translation updates. #####
Tue Mar 1 11:32:26 2005 John Ellis <johne@verizon.net>
* src/Makefile.am: Add pan-view.[ch]:
* image.[ch]: Add support for using a grid of tiles as soource image. Added
scroll_notify callback for when the viewable regionis scrolled. Added ability
to set min and max for the zoom range. Removed unnecessary
gtk_widget_size_request from image_size_sync. Added image_scroll_to_point.
* layout_util.c: Add menu item and callback for the new 'Pan view'.
* pixbuf_util.c (pixbuf_draw_layout): Fix for when offset is non-zero.
* typedefs.h: Add source tile stuff for ImageWindow.
* ui_tabcomp.c: Fix tab completion pop-up menu placement.
* pan-view.[ch]: New files for the pan view - 2.1 is officially started :)
author | gqview |
---|---|
date | Tue, 01 Mar 2005 17:16:34 +0000 |
parents | d907d608745f |
children | ef790149ae21 |
comparison
equal
deleted
inserted
replaced
11:3c3b40dbde11 | 12:147f4c4b9025 |
---|---|
21 #include "ui_fileops.h" | 21 #include "ui_fileops.h" |
22 | 22 |
23 #include <math.h> | 23 #include <math.h> |
24 | 24 |
25 | 25 |
26 #define IMAGE_TILE_SIZE 128 | 26 #define IMAGE_TILE_SIZE 512 |
27 #define IMAGE_ZOOM_MIN -32.0 | 27 #define IMAGE_ZOOM_MIN -32.0 |
28 #define IMAGE_ZOOM_MAX 32.0 | 28 #define IMAGE_ZOOM_MAX 32.0 |
29 | 29 |
30 /* size of the image loader buffer (512 bytes x defined number) */ | 30 /* size of the image loader buffer (512 bytes x defined number) */ |
31 #define IMAGE_LOAD_BUFFER_COUNT 8 | 31 #define IMAGE_LOAD_BUFFER_COUNT 8 |
117 | 117 |
118 gint visible; | 118 gint visible; |
119 gint always; /* hide temporarily when scrolling */ | 119 gint always; /* hide temporarily when scrolling */ |
120 }; | 120 }; |
121 | 121 |
122 /* needed to be declared before the source_tile stuff */ | |
123 static void image_pixbuf_sync(ImageWindow *imd, gdouble zoom, gint blank, gint new); | |
124 static void image_zoom_sync(ImageWindow *imd, gdouble zoom, | |
125 gint force, gint blank, gint new, | |
126 gint center_point, gint px, gint py); | |
127 static void image_queue(ImageWindow *imd, gint x, gint y, gint w, gint h, | |
128 gint clamp, TileRenderType render, gint new_data); | |
129 | |
130 static gint util_clip_region(gint x, gint y, gint w, gint h, | |
131 gint clip_x, gint clip_y, gint clip_w, gint clip_h, | |
132 gint *rx, gint *ry, gint *rw, gint *rh); | |
133 | |
134 /* | |
135 *------------------------------------------------------------------- | |
136 * source tiles | |
137 *------------------------------------------------------------------- | |
138 */ | |
139 | |
140 typedef struct _SourceTile SourceTile; | |
141 struct _SourceTile | |
142 { | |
143 gint x; | |
144 gint y; | |
145 GdkPixbuf *pixbuf; | |
146 gint blank; | |
147 }; | |
148 | |
149 static void source_tile_free(SourceTile *st) | |
150 { | |
151 if (!st) return; | |
152 | |
153 if (st->pixbuf) gdk_pixbuf_unref(st->pixbuf); | |
154 g_free(st); | |
155 } | |
156 | |
157 static void source_tile_free_all(ImageWindow *imd) | |
158 { | |
159 GList *work; | |
160 | |
161 work = imd->source_tiles; | |
162 while (work) | |
163 { | |
164 SourceTile *st = work->data; | |
165 work = work->next; | |
166 | |
167 source_tile_free(st); | |
168 } | |
169 | |
170 g_list_free(imd->source_tiles); | |
171 imd->source_tiles = NULL; | |
172 } | |
173 | |
174 static gint source_tile_visible(ImageWindow *imd, SourceTile *st) | |
175 { | |
176 gint x, y, w, h; | |
177 | |
178 if (!st) return FALSE; | |
179 | |
180 x = (imd->x_scroll / IMAGE_TILE_SIZE) * IMAGE_TILE_SIZE; | |
181 y = (imd->y_scroll / IMAGE_TILE_SIZE) * IMAGE_TILE_SIZE; | |
182 w = ((imd->x_scroll + imd->vis_width) / IMAGE_TILE_SIZE) * IMAGE_TILE_SIZE + IMAGE_TILE_SIZE; | |
183 h = ((imd->y_scroll + imd->vis_height) / IMAGE_TILE_SIZE) * IMAGE_TILE_SIZE + IMAGE_TILE_SIZE; | |
184 | |
185 return !((double)st->x * imd->scale < (double)x || | |
186 (double)(st->x + imd->source_tile_width) * imd->scale > (double)w || | |
187 (double)st->y * imd->scale < (double)y || | |
188 (double)(st->y + imd->source_tile_height) * imd->scale > (double)h); | |
189 } | |
190 | |
191 static SourceTile *source_tile_new(ImageWindow *imd, gint x, gint y) | |
192 { | |
193 SourceTile *st = NULL; | |
194 gint count; | |
195 | |
196 if (imd->source_tiles_cache_size < 4) imd->source_tiles_cache_size = 4; | |
197 | |
198 if (imd->source_tile_width < 1 || imd->source_tile_height < 1) | |
199 { | |
200 printf("warning: source tile size too small %d x %d\n", imd->source_tile_width, imd->source_tile_height); | |
201 return NULL; | |
202 } | |
203 | |
204 count = g_list_length(imd->source_tiles); | |
205 if (count >= imd->source_tiles_cache_size) | |
206 { | |
207 GList *work; | |
208 | |
209 work = g_list_last(imd->source_tiles); | |
210 while (work && count >= imd->source_tiles_cache_size) | |
211 { | |
212 SourceTile *needle; | |
213 | |
214 needle = work->data; | |
215 work = work->prev; | |
216 | |
217 if (!source_tile_visible(imd, needle)) | |
218 { | |
219 imd->source_tiles = g_list_remove(imd->source_tiles, needle); | |
220 | |
221 if (imd->func_tile_dispose) | |
222 { | |
223 if (debug) printf("tile dispose: %d x %d @ %d x %d\n", | |
224 needle->x, needle->y, imd->x_scroll, imd->y_scroll); | |
225 imd->func_tile_dispose(imd, needle->x, needle->y, | |
226 imd->source_tile_width, imd->source_tile_height, | |
227 needle->pixbuf, imd->data_tile); | |
228 } | |
229 | |
230 if (!st) | |
231 { | |
232 st = needle; | |
233 } | |
234 else | |
235 { | |
236 source_tile_free(needle); | |
237 } | |
238 | |
239 count--; | |
240 } | |
241 else if (debug) | |
242 { | |
243 printf("we still think %d x %d is visble\n", needle->x, needle->y); | |
244 } | |
245 } | |
246 | |
247 if (debug) | |
248 { | |
249 printf("cache count %d, max is %d\n", count, imd->source_tiles_cache_size); | |
250 } | |
251 } | |
252 | |
253 if (!st) | |
254 { | |
255 st = g_new0(SourceTile, 1); | |
256 st->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, | |
257 imd->source_tile_width, imd->source_tile_height); | |
258 } | |
259 | |
260 st->x = (x / imd->source_tile_width) * imd->source_tile_width; | |
261 st->y = (y / imd->source_tile_height) * imd->source_tile_height; | |
262 st->blank = TRUE; | |
263 | |
264 imd->source_tiles = g_list_prepend(imd->source_tiles, st); | |
265 | |
266 if (debug) | |
267 { | |
268 printf("tile request: %d x %d\n", st->x, st->y); | |
269 if (!source_tile_visible(imd, st)) printf("tile request for invisible tile!\n"); | |
270 } | |
271 | |
272 return st; | |
273 } | |
274 | |
275 static void image_tile_invalidate(ImageWindow *imd, gint x, gint y, gint w, gint h) | |
276 { | |
277 gint i, j; | |
278 gint x1, x2; | |
279 gint y1, y2; | |
280 GList *work; | |
281 | |
282 x1 = (gint)floor(x / imd->tile_width) * imd->tile_width; | |
283 x2 = (gint)ceil((x + w) / imd->tile_width) * imd->tile_width; | |
284 | |
285 y1 = (gint)floor(y / imd->tile_height) * imd->tile_height; | |
286 y2 = (gint)ceil((y + h) / imd->tile_height) * imd->tile_height; | |
287 | |
288 work = g_list_nth(imd->tiles, y1 / imd->tile_height * imd->tile_cols + (x1 / imd->tile_width)); | |
289 for (j = y1; j <= y2; j += imd->tile_height) | |
290 { | |
291 GList *tmp; | |
292 tmp = work; | |
293 for (i = x1; i <= x2; i += imd->tile_width) | |
294 { | |
295 if (tmp) | |
296 { | |
297 ImageTile *it = tmp->data; | |
298 | |
299 it->render_done = TILE_RENDER_NONE; | |
300 it->render_todo = TILE_RENDER_ALL; | |
301 | |
302 tmp = tmp->next; | |
303 } | |
304 } | |
305 work = g_list_nth(work, imd->tile_cols); /* step 1 row */ | |
306 } | |
307 } | |
308 | |
309 static SourceTile *source_tile_request(ImageWindow *imd, gint x, gint y) | |
310 { | |
311 SourceTile *st; | |
312 | |
313 st = source_tile_new(imd, x, y); | |
314 | |
315 if (imd->func_tile_request && | |
316 imd->func_tile_request(imd, st->x, st->y, | |
317 imd->source_tile_width, imd->source_tile_height, st->pixbuf, imd->data_tile)) | |
318 { | |
319 st->blank = FALSE; | |
320 } | |
321 #if 0 | |
322 /* fixme: somehow invalidate the new st region */ | |
323 image_queue(imd, st->x, st->y, imd->source_tile_width, imd->source_tile_height, FALSE, TILE_RENDER_AREA, TRUE); | |
324 #endif | |
325 image_tile_invalidate(imd, st->x * imd->scale, st->y * imd->scale, | |
326 imd->source_tile_width * imd->scale, imd->source_tile_height * imd->scale); | |
327 | |
328 return st; | |
329 } | |
330 | |
331 static SourceTile *source_tile_find(ImageWindow *imd, gint x, gint y) | |
332 { | |
333 GList *work; | |
334 | |
335 work = imd->source_tiles; | |
336 while (work) | |
337 { | |
338 SourceTile *st = work->data; | |
339 | |
340 if (x >= st->x && x < st->x + imd->source_tile_width && | |
341 y >= st->y && y < st->y + imd->source_tile_height) | |
342 { | |
343 if (work != imd->source_tiles) | |
344 { | |
345 imd->source_tiles = g_list_remove_link(imd->source_tiles, work); | |
346 imd->source_tiles = g_list_concat(work, imd->source_tiles); | |
347 } | |
348 return st; | |
349 } | |
350 | |
351 work = work->next; | |
352 } | |
353 | |
354 return NULL; | |
355 } | |
356 | |
357 static GList *source_tile_compute_region(ImageWindow *imd, gint x, gint y, gint w, gint h, gint request) | |
358 { | |
359 gint x1, y1; | |
360 GList *list = NULL; | |
361 gint sx, sy; | |
362 | |
363 if (x < 0) x = 0; | |
364 if (y < 0) y = 0; | |
365 if (w > imd->image_width) w = imd->image_width; | |
366 if (h > imd->image_height) h = imd->image_height; | |
367 | |
368 sx = (x / imd->source_tile_width) * imd->source_tile_width; | |
369 sy = (y / imd->source_tile_height) * imd->source_tile_height; | |
370 | |
371 for (x1 = sx; x1 < x + w; x1+= imd->source_tile_width) | |
372 { | |
373 for (y1 = sy; y1 < y + h; y1 += imd->source_tile_height) | |
374 { | |
375 SourceTile *st; | |
376 | |
377 st = source_tile_find(imd, x1, y1); | |
378 if (!st && request) st = source_tile_request(imd, x1, y1); | |
379 | |
380 if (st) list = g_list_prepend(list, st); | |
381 } | |
382 } | |
383 | |
384 return g_list_reverse(list); | |
385 } | |
386 | |
387 static void source_tile_changed(ImageWindow *imd, gint x, gint y, gint width, gint height) | |
388 { | |
389 GList *work; | |
390 | |
391 work = imd->source_tiles; | |
392 while (work) | |
393 { | |
394 SourceTile *st; | |
395 gint rx, ry, rw, rh; | |
396 | |
397 st = work->data; | |
398 work = work->next; | |
399 | |
400 if (util_clip_region(st->x, st->y, imd->source_tile_width, imd->source_tile_height, | |
401 x, y, width, height, | |
402 &rx, &ry, &rw, &rh)) | |
403 { | |
404 GdkPixbuf *pixbuf; | |
405 | |
406 pixbuf = gdk_pixbuf_new_subpixbuf(st->pixbuf, rx - st->x, ry - st->y, rw, rh); | |
407 if (imd->func_tile_request && | |
408 imd->func_tile_request(imd, rx, ry, rw, rh, pixbuf, imd->data_tile)) | |
409 { | |
410 image_tile_invalidate(imd, rx * imd->scale, ry * imd->scale, rw * imd->scale, rh * imd->scale); | |
411 } | |
412 g_object_unref(pixbuf); | |
413 } | |
414 } | |
415 } | |
416 | |
417 | |
418 static gint source_tile_render(ImageWindow *imd, ImageTile *it, | |
419 gint x, gint y, gint w, gint h, | |
420 gint new_data, gint fast) | |
421 { | |
422 GList *list; | |
423 GList *work; | |
424 gint draw = FALSE; | |
425 | |
426 if (imd->zoom == 1.0 || imd->scale == 1.0) | |
427 { | |
428 list = source_tile_compute_region(imd, it->x + x, it->y + y, w, h, TRUE); | |
429 work = list; | |
430 while (work) | |
431 { | |
432 SourceTile *st; | |
433 gint rx, ry, rw, rh; | |
434 | |
435 st = work->data; | |
436 work = work->next; | |
437 | |
438 if (util_clip_region(st->x, st->y, imd->source_tile_width, imd->source_tile_height, | |
439 it->x + x, it->y + y, w, h, | |
440 &rx, &ry, &rw, &rh)) | |
441 { | |
442 if (st->blank) | |
443 { | |
444 gdk_draw_rectangle(it->pixmap, imd->image->style->black_gc, TRUE, | |
445 rx - st->x, ry - st->y, rw, rh); | |
446 } | |
447 else /* (imd->zoom == 1.0 || imd->scale == 1.0) */ | |
448 { | |
449 gdk_draw_pixbuf(it->pixmap, | |
450 imd->image->style->fg_gc[GTK_WIDGET_STATE(imd->image)], | |
451 st->pixbuf, | |
452 rx - st->x, ry - st->y, | |
453 rx - it->x, ry - it->y, | |
454 rw, rh, | |
455 (GdkRgbDither)dither_quality, rx, ry); | |
456 } | |
457 } | |
458 } | |
459 } | |
460 else | |
461 { | |
462 double scale_x, scale_y; | |
463 gint sx, sy, sw, sh; | |
464 | |
465 if (imd->image_width == 0 || imd->image_height == 0) return FALSE; | |
466 scale_x = (double)imd->width / imd->image_width; | |
467 scale_y = (double)imd->height / imd->image_height; | |
468 | |
469 sx = (double)(it->x + x) / scale_x; | |
470 sy = (double)(it->y + y) / scale_y; | |
471 sw = (double)w / scale_x; | |
472 sh = (double)h / scale_y; | |
473 | |
474 if (imd->width < IMAGE_MIN_SCALE_SIZE || imd->height < IMAGE_MIN_SCALE_SIZE) fast = TRUE; | |
475 | |
476 #if 0 | |
477 /* draws red over draw region, to check for leaks (regions not filled) */ | |
478 pixbuf_draw_rect(it->pixbuf, x, y, w, h, 255, 0, 0, 255, FALSE); | |
479 #endif | |
480 | |
481 list = source_tile_compute_region(imd, sx, sy, sw, sh, TRUE); | |
482 work = list; | |
483 while (work) | |
484 { | |
485 SourceTile *st; | |
486 gint rx, ry, rw, rh; | |
487 gint stx, sty, stw, sth; | |
488 | |
489 st = work->data; | |
490 work = work->next; | |
491 | |
492 stx = floor((double)st->x * scale_x); | |
493 sty = floor((double)st->y * scale_y); | |
494 stw = ceil ((double)(st->x + imd->source_tile_width) * scale_x) - stx; | |
495 sth = ceil ((double)(st->y + imd->source_tile_height) * scale_y) - sty; | |
496 | |
497 if (util_clip_region(stx, sty, stw, sth, | |
498 it->x + x, it->y + y, w, h, | |
499 &rx, &ry, &rw, &rh)) | |
500 { | |
501 if (st->blank) | |
502 { | |
503 gdk_draw_rectangle(it->pixmap, imd->image->style->black_gc, TRUE, | |
504 rx - st->x, ry - st->y, rw, rh); | |
505 } | |
506 else | |
507 { | |
508 double offset_x; | |
509 double offset_y; | |
510 | |
511 /* may need to use unfloored stx,sty values here */ | |
512 offset_x = ((double)stx < (double)it->x) ? | |
513 (double)stx - (double)it->x : 0.0; | |
514 offset_y = ((double)sty < (double)it->y) ? | |
515 (double)sty - (double)it->y : 0.0; | |
516 | |
517 gdk_pixbuf_scale(st->pixbuf, it->pixbuf, rx - it->x, ry - it->y, rw, rh, | |
518 (double) 0.0 + rx - it->x + offset_x, | |
519 (double) 0.0 + ry - it->y + offset_y, | |
520 scale_x, scale_y, | |
521 (fast) ? GDK_INTERP_NEAREST : (GdkInterpType)zoom_quality); | |
522 draw = TRUE; | |
523 } | |
524 } | |
525 } | |
526 } | |
527 | |
528 g_list_free(list); | |
529 | |
530 return draw; | |
531 } | |
532 | |
533 static void image_source_tile_unset(ImageWindow *imd) | |
534 { | |
535 source_tile_free_all(imd); | |
536 | |
537 imd->source_tiles_enabled = FALSE; | |
538 } | |
539 | |
540 void image_set_image_as_tiles(ImageWindow *imd, gint width, gint height, | |
541 gint tile_width, gint tile_height, gint cache_size, | |
542 ImageTileRequestFunc func_tile_request, | |
543 ImageTileDisposeFunc func_tile_dispose, | |
544 gpointer data, | |
545 gdouble zoom) | |
546 { | |
547 /* FIXME: unset any current image */ | |
548 image_source_tile_unset(imd); | |
549 | |
550 if (tile_width < 32 || tile_height < 32) | |
551 { | |
552 printf("warning: tile size too small %d x %d (min 32x32)\n", tile_width, tile_height); | |
553 return; | |
554 } | |
555 if (width < 32 || height < 32) | |
556 { | |
557 printf("warning: tile canvas too small %d x %d (min 32x32)\n", width, height); | |
558 return; | |
559 } | |
560 if (!func_tile_request) | |
561 { | |
562 printf("warning: tile request function is null\n"); | |
563 } | |
564 | |
565 printf("Setting source tiles to size %d x %d, grid is %d x %d\n", tile_width, tile_height, width, height); | |
566 | |
567 if (cache_size < 4) cache_size = 4; | |
568 | |
569 imd->source_tiles_enabled = TRUE; | |
570 imd->source_tiles_cache_size = cache_size; | |
571 imd->source_tile_width = tile_width; | |
572 imd->source_tile_height = tile_height; | |
573 | |
574 imd->image_width = width; | |
575 imd->image_height = height; | |
576 | |
577 imd->func_tile_request = func_tile_request; | |
578 imd->func_tile_dispose = func_tile_dispose; | |
579 imd->data_tile = data; | |
580 | |
581 image_zoom_sync(imd, zoom, TRUE, FALSE, TRUE, FALSE, 0, 0); | |
582 } | |
583 | |
122 | 584 |
123 static void image_queue_clear(ImageWindow *imd); | 585 static void image_queue_clear(ImageWindow *imd); |
124 | 586 |
125 static void image_update_title(ImageWindow *imd); | 587 static void image_update_title(ImageWindow *imd); |
126 static void image_update_util(ImageWindow *imd); | 588 static void image_update_util(ImageWindow *imd); |
208 g_free(cd); | 670 g_free(cd); |
209 } | 671 } |
210 | 672 |
211 static void image_tile_cache_free_space(ImageWindow *imd, gint space, ImageTile *it) | 673 static void image_tile_cache_free_space(ImageWindow *imd, gint space, ImageTile *it) |
212 { | 674 { |
213 GList *work = g_list_last(imd->tile_cache); | 675 GList *work; |
214 | 676 gint tile_max; |
215 while (work && imd->tile_cache_size > 0 && imd->tile_cache_size + space > tile_cache_max * 1048576) | 677 |
678 work = g_list_last(imd->tile_cache); | |
679 | |
680 if (imd->source_tiles_enabled && imd->scale < 1.0) | |
681 { | |
682 gint tiles; | |
683 | |
684 tiles = (imd->vis_width / IMAGE_TILE_SIZE + 1) * (imd->vis_width / IMAGE_TILE_SIZE + 1); | |
685 tile_max = MAX(tiles * IMAGE_TILE_SIZE * IMAGE_TILE_SIZE * 3, | |
686 (gint)((double)tile_cache_max * 1048576.0 * imd->scale)); | |
687 } | |
688 else | |
689 { | |
690 tile_max = tile_cache_max * 1048576; | |
691 } | |
692 | |
693 while (work && imd->tile_cache_size > 0 && imd->tile_cache_size + space > tile_max) | |
216 { | 694 { |
217 CacheData *cd = work->data; | 695 CacheData *cd = work->data; |
218 work = work->prev; | 696 work = work->prev; |
219 if (cd->it != it) image_tile_cache_free(imd, cd); | 697 if (cd->it != it) image_tile_cache_free(imd, cd); |
220 } | 698 } |
250 | 728 |
251 it->pixmap = pixmap; | 729 it->pixmap = pixmap; |
252 image_tile_cache_add(imd, it, pixmap, NULL, size); | 730 image_tile_cache_add(imd, it, pixmap, NULL, size); |
253 } | 731 } |
254 | 732 |
255 if ((imd->zoom != 1.0 || gdk_pixbuf_get_has_alpha(imd->pixbuf)) && | 733 if ((imd->zoom != 1.0 || imd->source_tiles_enabled || (imd->pixbuf && gdk_pixbuf_get_has_alpha(imd->pixbuf)) ) && |
256 !it->pixbuf) | 734 !it->pixbuf) |
257 { | 735 { |
258 GdkPixbuf *pixbuf; | 736 GdkPixbuf *pixbuf; |
259 guint size; | 737 guint size; |
260 | 738 |
261 pixbuf = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(imd->pixbuf), | 739 if (imd->pixbuf) |
262 gdk_pixbuf_get_has_alpha(imd->pixbuf), | 740 { |
263 gdk_pixbuf_get_bits_per_sample(imd->pixbuf), | 741 pixbuf = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(imd->pixbuf), |
264 imd->tile_width, imd->tile_height); | 742 gdk_pixbuf_get_has_alpha(imd->pixbuf), |
743 gdk_pixbuf_get_bits_per_sample(imd->pixbuf), | |
744 imd->tile_width, imd->tile_height); | |
745 } | |
746 else | |
747 { | |
748 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, imd->tile_width, imd->tile_height); | |
749 } | |
265 | 750 |
266 size = gdk_pixbuf_get_rowstride(pixbuf) * imd->tile_height; | 751 size = gdk_pixbuf_get_rowstride(pixbuf) * imd->tile_height; |
267 image_tile_cache_free_space(imd, size, it); | 752 image_tile_cache_free_space(imd, size, it); |
268 | 753 |
269 it->pixbuf = pixbuf; | 754 it->pixbuf = pixbuf; |
394 gint new_data, gint fast) | 879 gint new_data, gint fast) |
395 { | 880 { |
396 gint has_alpha; | 881 gint has_alpha; |
397 gint draw = FALSE; | 882 gint draw = FALSE; |
398 | 883 |
399 if (it->render_todo == TILE_RENDER_NONE && it->pixmap) return; | 884 if (it->render_todo == TILE_RENDER_NONE && it->pixmap && !new_data) return; |
400 | 885 |
401 if (it->render_done != TILE_RENDER_ALL) | 886 if (it->render_done != TILE_RENDER_ALL) |
402 { | 887 { |
403 x = 0; | 888 x = 0; |
404 y = 0; | 889 y = 0; |
415 if (!fast) it->render_todo = TILE_RENDER_NONE; | 900 if (!fast) it->render_todo = TILE_RENDER_NONE; |
416 | 901 |
417 if (new_data) it->blank = FALSE; | 902 if (new_data) it->blank = FALSE; |
418 | 903 |
419 image_tile_prepare(imd, it); | 904 image_tile_prepare(imd, it); |
420 has_alpha = gdk_pixbuf_get_has_alpha(imd->pixbuf); | 905 has_alpha = (imd->pixbuf && gdk_pixbuf_get_has_alpha(imd->pixbuf)); |
421 | 906 |
422 /* FIXME checker colors for alpha should be configurable, | 907 /* FIXME checker colors for alpha should be configurable, |
423 * also should be drawn for blank = TRUE | 908 * also should be drawn for blank = TRUE |
424 */ | 909 */ |
425 | 910 |
426 if (it->blank) | 911 if (it->blank) |
427 { | 912 { |
428 /* no data, do fast rect fill */ | 913 /* no data, do fast rect fill */ |
429 gdk_draw_rectangle(it->pixmap, imd->image->style->black_gc, TRUE, | 914 gdk_draw_rectangle(it->pixmap, imd->image->style->black_gc, TRUE, |
430 0, 0, it->w, it->h); | 915 0, 0, it->w, it->h); |
916 } | |
917 else if (imd->source_tiles_enabled) | |
918 { | |
919 draw = source_tile_render(imd, it, x, y, w, h, new_data, fast); | |
431 } | 920 } |
432 else if (imd->zoom == 1.0 || imd->scale == 1.0) | 921 else if (imd->zoom == 1.0 || imd->scale == 1.0) |
433 { | 922 { |
434 if (has_alpha) | 923 if (has_alpha) |
435 { | 924 { |
534 { | 1023 { |
535 ImageWindow *imd = data; | 1024 ImageWindow *imd = data; |
536 QueueData *qd; | 1025 QueueData *qd; |
537 gint fast; | 1026 gint fast; |
538 | 1027 |
539 if (!imd->pixbuf || (!imd->draw_queue && !imd->draw_queue_2pass) || imd->draw_idle_id == -1) | 1028 if ((!imd->pixbuf && !imd->source_tiles_enabled) || (!imd->draw_queue && !imd->draw_queue_2pass) || imd->draw_idle_id == -1) |
540 { | 1029 { |
541 if (!imd->completed) image_complete_util(imd, FALSE); | 1030 if (!imd->completed) image_complete_util(imd, FALSE); |
542 | 1031 |
543 imd->draw_idle_id = -1; | 1032 imd->draw_idle_id = -1; |
544 return FALSE; | 1033 return FALSE; |
860 { | 1349 { |
861 gint rx, ry, rw, rh; | 1350 gint rx, ry, rw, rh; |
862 | 1351 |
863 if (!imd->image->window) return; | 1352 if (!imd->image->window) return; |
864 | 1353 |
865 if (!imd->pixbuf) | 1354 if (!imd->pixbuf && !imd->source_tiles_enabled) |
866 { | 1355 { |
867 if (util_clip_region(x, y, w, h, | 1356 if (util_clip_region(x, y, w, h, |
868 0, 0, | 1357 0, 0, |
869 imd->window_width, imd->window_height, | 1358 imd->window_width, imd->window_height, |
870 &rx, &ry, &rw, &rh)) | 1359 &rx, &ry, &rw, &rh)) |
922 static void image_border_clear(ImageWindow *imd) | 1411 static void image_border_clear(ImageWindow *imd) |
923 { | 1412 { |
924 image_border_draw(imd, 0, 0, imd->window_width, imd->window_height); | 1413 image_border_draw(imd, 0, 0, imd->window_width, imd->window_height); |
925 } | 1414 } |
926 | 1415 |
1416 static void image_scroll_notify(ImageWindow *imd) | |
1417 { | |
1418 if (imd->func_scroll_notify && imd->scale) | |
1419 { | |
1420 imd->func_scroll_notify(imd, | |
1421 (gint)((gdouble)imd->x_scroll / imd->scale), | |
1422 (gint)((gdouble)imd->y_scroll / imd->scale), | |
1423 (gint)((gdouble)imd->image_width - imd->vis_width / imd->scale), | |
1424 (gint)((gdouble)imd->image_height - imd->vis_height / imd->scale), | |
1425 imd->data_scroll_notify); | |
1426 } | |
1427 } | |
1428 | |
927 static gint image_scroll_clamp(ImageWindow *imd) | 1429 static gint image_scroll_clamp(ImageWindow *imd) |
928 { | 1430 { |
929 gint old_xs; | 1431 gint old_xs; |
930 gint old_ys; | 1432 gint old_ys; |
931 | 1433 |
932 if (imd->zoom == 0.0) | 1434 if (imd->zoom == 0.0) |
933 { | 1435 { |
934 imd->x_scroll = 0; | 1436 imd->x_scroll = 0; |
935 imd->y_scroll = 0; | 1437 imd->y_scroll = 0; |
1438 | |
1439 image_scroll_notify(imd); | |
936 return FALSE; | 1440 return FALSE; |
937 } | 1441 } |
938 | 1442 |
939 old_xs = imd->x_scroll; | 1443 old_xs = imd->x_scroll; |
940 old_ys = imd->y_scroll; | 1444 old_ys = imd->y_scroll; |
955 else | 1459 else |
956 { | 1460 { |
957 imd->y_scroll = CLAMP(imd->y_scroll, 0, imd->height - imd->vis_height); | 1461 imd->y_scroll = CLAMP(imd->y_scroll, 0, imd->height - imd->vis_height); |
958 } | 1462 } |
959 | 1463 |
1464 image_scroll_notify(imd); | |
1465 | |
960 return (old_xs != imd->x_scroll || old_ys != imd->y_scroll); | 1466 return (old_xs != imd->x_scroll || old_ys != imd->y_scroll); |
961 } | 1467 } |
962 | 1468 |
963 static gint image_zoom_clamp(ImageWindow *imd, gdouble zoom, gint force, gint new) | 1469 static gint image_zoom_clamp(ImageWindow *imd, gdouble zoom, gint force, gint new) |
964 { | 1470 { |
965 gint w, h; | 1471 gint w, h; |
966 gdouble scale; | 1472 gdouble scale; |
967 | 1473 |
968 zoom = CLAMP(zoom, IMAGE_ZOOM_MIN, IMAGE_ZOOM_MAX); | 1474 zoom = CLAMP(zoom, imd->zoom_min, imd->zoom_max); |
969 | 1475 |
970 if (imd->zoom == zoom && !force) return FALSE; | 1476 if (imd->zoom == zoom && !force) return FALSE; |
971 | 1477 |
972 w = imd->image_width; | 1478 w = imd->image_width; |
973 h = imd->image_height; | 1479 h = imd->image_height; |
1088 if (imd->zoom == 0.0) image_zoom_clamp(imd, 0.0, TRUE, FALSE); | 1594 if (imd->zoom == 0.0) image_zoom_clamp(imd, 0.0, TRUE, FALSE); |
1089 | 1595 |
1090 image_size_clamp(imd); | 1596 image_size_clamp(imd); |
1091 image_scroll_clamp(imd); | 1597 image_scroll_clamp(imd); |
1092 | 1598 |
1599 #if 0 | |
1093 gtk_widget_set_size_request(imd->image, imd->window_width, imd->window_height); | 1600 gtk_widget_set_size_request(imd->image, imd->window_width, imd->window_height); |
1601 #endif | |
1094 | 1602 |
1095 /* ensure scroller remains visible */ | 1603 /* ensure scroller remains visible */ |
1096 if (imd->scroller_overlay != -1) | 1604 if (imd->scroller_overlay != -1) |
1097 { | 1605 { |
1098 gint update = FALSE; | 1606 gint update = FALSE; |
1209 { | 1717 { |
1210 gint old_x, old_y; | 1718 gint old_x, old_y; |
1211 gint x_off, y_off; | 1719 gint x_off, y_off; |
1212 gint w, h; | 1720 gint w, h; |
1213 | 1721 |
1214 if (!imd->pixbuf) return; | 1722 if (!imd->pixbuf && !imd->source_tiles_enabled) return; |
1215 | 1723 |
1216 old_x = imd->x_scroll; | 1724 old_x = imd->x_scroll; |
1217 old_y = imd->y_scroll; | 1725 old_y = imd->y_scroll; |
1218 | 1726 |
1219 imd->x_scroll += x; | 1727 imd->x_scroll += x; |
1950 | 2458 |
1951 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new) | 2459 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new) |
1952 { | 2460 { |
1953 gint sync = TRUE; | 2461 gint sync = TRUE; |
1954 | 2462 |
2463 image_source_tile_unset(imd); | |
2464 | |
1955 imd->zoom = zoom; /* store the zoom, needed by the loader */ | 2465 imd->zoom = zoom; /* store the zoom, needed by the loader */ |
1956 | 2466 |
1957 image_reset(imd); | 2467 image_reset(imd); |
1958 | 2468 |
1959 if (imd->image_path && isfile(imd->image_path)) | 2469 if (imd->image_path && isfile(imd->image_path)) |
2694 { | 3204 { |
2695 imd->func_scroll = func; | 3205 imd->func_scroll = func; |
2696 imd->data_scroll = data; | 3206 imd->data_scroll = data; |
2697 } | 3207 } |
2698 | 3208 |
3209 void image_set_scroll_notify_func(ImageWindow *imd, | |
3210 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data), | |
3211 gpointer data) | |
3212 { | |
3213 imd->func_scroll_notify = func; | |
3214 imd->data_scroll_notify = data; | |
3215 } | |
3216 | |
2699 /* path, name */ | 3217 /* path, name */ |
2700 | 3218 |
2701 const gchar *image_get_path(ImageWindow *imd) | 3219 const gchar *image_get_path(ImageWindow *imd) |
2702 { | 3220 { |
2703 return imd->image_path; | 3221 return imd->image_path; |
2724 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom) | 3242 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom) |
2725 { | 3243 { |
2726 if (imd->image_path == path || | 3244 if (imd->image_path == path || |
2727 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return; | 3245 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return; |
2728 | 3246 |
3247 image_source_tile_unset(imd); | |
3248 | |
2729 image_change_real(imd, path, NULL, NULL, zoom); | 3249 image_change_real(imd, path, NULL, NULL, zoom); |
2730 } | 3250 } |
2731 | 3251 |
2732 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom) | 3252 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom) |
2733 { | 3253 { |
3254 image_source_tile_unset(imd); | |
3255 | |
2734 image_set_pixbuf(imd, pixbuf, zoom, TRUE); | 3256 image_set_pixbuf(imd, pixbuf, zoom, TRUE); |
2735 image_new_util(imd); | 3257 image_new_util(imd); |
2736 } | 3258 } |
2737 | 3259 |
2738 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom) | 3260 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom) |
2739 { | 3261 { |
2740 if (!cd || !info || !g_list_find(cd->list, info)) return; | 3262 if (!cd || !info || !g_list_find(cd->list, info)) return; |
3263 | |
3264 image_source_tile_unset(imd); | |
2741 | 3265 |
2742 image_change_real(imd, info->path, cd, info, zoom); | 3266 image_change_real(imd, info->path, cd, info, zoom); |
2743 } | 3267 } |
2744 | 3268 |
2745 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info) | 3269 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info) |
2776 */ | 3300 */ |
2777 void image_change_from_image(ImageWindow *imd, ImageWindow *source) | 3301 void image_change_from_image(ImageWindow *imd, ImageWindow *source) |
2778 { | 3302 { |
2779 if (imd == source) return; | 3303 if (imd == source) return; |
2780 | 3304 |
3305 imd->zoom_min = source->zoom_min; | |
3306 imd->zoom_max = source->zoom_max; | |
3307 | |
2781 imd->unknown = source->unknown; | 3308 imd->unknown = source->unknown; |
2782 | 3309 |
2783 image_set_pixbuf(imd, source->pixbuf, image_zoom_get(source), TRUE); | 3310 image_set_pixbuf(imd, source->pixbuf, image_zoom_get(source), TRUE); |
2784 | 3311 |
2785 imd->collection = source->collection; | 3312 imd->collection = source->collection; |
2827 imd->completed = source->completed; | 3354 imd->completed = source->completed; |
2828 | 3355 |
2829 imd->x_scroll = source->x_scroll; | 3356 imd->x_scroll = source->x_scroll; |
2830 imd->y_scroll = source->y_scroll; | 3357 imd->y_scroll = source->y_scroll; |
2831 | 3358 |
3359 if (imd->source_tiles_enabled) | |
3360 { | |
3361 image_source_tile_unset(imd); | |
3362 } | |
3363 | |
3364 if (source->source_tiles_enabled) | |
3365 { | |
3366 imd->source_tiles_enabled = source->source_tiles_enabled; | |
3367 imd->source_tiles_cache_size = source->source_tiles_cache_size; | |
3368 imd->source_tiles = source->source_tiles; | |
3369 imd->source_tile_width = source->source_tile_width; | |
3370 imd->source_tile_height = source->source_tile_height; | |
3371 | |
3372 source->source_tiles_enabled = FALSE; | |
3373 source->source_tiles = NULL; | |
3374 | |
3375 imd->func_tile_request = source->func_tile_request; | |
3376 imd->func_tile_dispose = source->func_tile_dispose; | |
3377 imd->data_tile = source->data_tile; | |
3378 | |
3379 source->func_tile_request = NULL; | |
3380 source->func_tile_dispose = NULL; | |
3381 source->data_tile = NULL; | |
3382 | |
3383 imd->image_width = source->image_width; | |
3384 imd->image_height = source->image_height; | |
3385 | |
3386 if (image_zoom_clamp(imd, source->zoom, TRUE, TRUE)) | |
3387 { | |
3388 image_size_clamp(imd); | |
3389 image_scroll_clamp(imd); | |
3390 image_tile_sync(imd, imd->width, imd->height, FALSE); | |
3391 image_redraw(imd, FALSE); | |
3392 } | |
3393 return; | |
3394 } | |
3395 | |
2832 image_scroll_clamp(imd); | 3396 image_scroll_clamp(imd); |
2833 } | 3397 } |
2834 | 3398 |
2835 /* manipulation */ | 3399 /* manipulation */ |
2836 | 3400 |
2841 sx = (gint)floor((double)x * imd->scale); | 3405 sx = (gint)floor((double)x * imd->scale); |
2842 sy = (gint)floor((double)y * imd->scale); | 3406 sy = (gint)floor((double)y * imd->scale); |
2843 sw = (gint)ceil((double)width * imd->scale); | 3407 sw = (gint)ceil((double)width * imd->scale); |
2844 sh = (gint)ceil((double)height * imd->scale); | 3408 sh = (gint)ceil((double)height * imd->scale); |
2845 | 3409 |
3410 if (imd->source_tiles_enabled) | |
3411 { | |
3412 source_tile_changed(imd, x, y, width, height); | |
3413 } | |
3414 | |
2846 image_queue(imd, sx, sy, sw, sh, FALSE, TILE_RENDER_AREA, TRUE); | 3415 image_queue(imd, sx, sy, sw, sh, FALSE, TILE_RENDER_AREA, TRUE); |
2847 } | 3416 } |
2848 | 3417 |
2849 void image_reload(ImageWindow *imd) | 3418 void image_reload(ImageWindow *imd) |
2850 { | 3419 { |
3420 if (imd->source_tiles_enabled) return; | |
3421 | |
2851 image_change_complete(imd, imd->zoom, FALSE); | 3422 image_change_complete(imd, imd->zoom, FALSE); |
2852 } | 3423 } |
2853 | 3424 |
2854 void image_scroll(ImageWindow *imd, gint x, gint y) | 3425 void image_scroll(ImageWindow *imd, gint x, gint y) |
2855 { | 3426 { |
2856 image_scroll_real(imd, x, y); | 3427 image_scroll_real(imd, x, y); |
2857 } | 3428 } |
2858 | 3429 |
3430 void image_scroll_to_point(ImageWindow *imd, gint x, gint y) | |
3431 { | |
3432 gint px, py; | |
3433 | |
3434 px = (gdouble)x * imd->scale - imd->x_scroll; | |
3435 py = (gdouble)y * imd->scale - imd->y_scroll; | |
3436 | |
3437 image_scroll(imd, px, py); | |
3438 } | |
3439 | |
2859 void image_alter(ImageWindow *imd, AlterType type) | 3440 void image_alter(ImageWindow *imd, AlterType type) |
2860 { | 3441 { |
3442 if (imd->source_tiles_enabled) return; | |
3443 | |
2861 if (imd->il) | 3444 if (imd->il) |
2862 { | 3445 { |
2863 /* still loading, wait till done */ | 3446 /* still loading, wait till done */ |
2864 imd->delay_alter_type = type; | 3447 imd->delay_alter_type = type; |
2865 return; | 3448 return; |
2921 } | 3504 } |
2922 | 3505 |
2923 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y) | 3506 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y) |
2924 { | 3507 { |
2925 image_zoom_adjust_real(imd, increment, TRUE, x, y); | 3508 image_zoom_adjust_real(imd, increment, TRUE, x, y); |
3509 } | |
3510 | |
3511 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max) | |
3512 { | |
3513 if (min > 1.0 || max < 1.0) return; | |
3514 if (min < 1.0 && min > -1.0) return; | |
3515 if (min < -200.0 || max > 200.0) return; | |
3516 | |
3517 imd->zoom_min = min; | |
3518 imd->zoom_max = max; | |
2926 } | 3519 } |
2927 | 3520 |
2928 void image_zoom_set(ImageWindow *imd, gdouble zoom) | 3521 void image_zoom_set(ImageWindow *imd, gdouble zoom) |
2929 { | 3522 { |
2930 image_zoom_sync(imd, zoom, FALSE, FALSE, FALSE, FALSE, 0, 0); | 3523 image_zoom_sync(imd, zoom, FALSE, FALSE, FALSE, FALSE, 0, 0); |
3027 | 3620 |
3028 /* read ahead */ | 3621 /* read ahead */ |
3029 | 3622 |
3030 void image_prebuffer_set(ImageWindow *imd, const gchar *path) | 3623 void image_prebuffer_set(ImageWindow *imd, const gchar *path) |
3031 { | 3624 { |
3625 if (imd->source_tiles_enabled) return; | |
3626 | |
3032 if (path) | 3627 if (path) |
3033 { | 3628 { |
3034 image_read_ahead_set(imd, path); | 3629 image_read_ahead_set(imd, path); |
3035 } | 3630 } |
3036 else | 3631 else |
3061 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */ | 3656 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */ |
3062 | 3657 |
3063 void image_auto_refresh(ImageWindow *imd, gint interval) | 3658 void image_auto_refresh(ImageWindow *imd, gint interval) |
3064 { | 3659 { |
3065 if (!imd) return; | 3660 if (!imd) return; |
3661 if (imd->source_tiles_enabled) return; | |
3066 | 3662 |
3067 if (imd->auto_refresh_id > -1) | 3663 if (imd->auto_refresh_id > -1) |
3068 { | 3664 { |
3069 g_source_remove(imd->auto_refresh_id); | 3665 g_source_remove(imd->auto_refresh_id); |
3070 imd->auto_refresh_id = -1; | 3666 imd->auto_refresh_id = -1; |
3159 GdkWindow *rootwindow; | 3755 GdkWindow *rootwindow; |
3160 GdkPixmap *pixmap; | 3756 GdkPixmap *pixmap; |
3161 GdkPixbuf *pb; | 3757 GdkPixbuf *pb; |
3162 | 3758 |
3163 if (!imd || !imd->pixbuf) return; | 3759 if (!imd || !imd->pixbuf) return; |
3164 | |
3165 | 3760 |
3166 screen = gtk_widget_get_screen(imd->image); | 3761 screen = gtk_widget_get_screen(imd->image); |
3167 rootwindow = gdk_screen_get_root_window(screen); | 3762 rootwindow = gdk_screen_get_root_window(screen); |
3168 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return; | 3763 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return; |
3169 | 3764 |
3208 | 3803 |
3209 image_scroller_timer_set(imd, FALSE); | 3804 image_scroller_timer_set(imd, FALSE); |
3210 | 3805 |
3211 image_overlay_list_clear(imd); | 3806 image_overlay_list_clear(imd); |
3212 | 3807 |
3808 source_tile_free_all(imd); | |
3809 | |
3213 g_free(imd); | 3810 g_free(imd); |
3214 } | 3811 } |
3215 | 3812 |
3216 static void image_destroy_cb(GtkObject *widget, gpointer data) | 3813 static void image_destroy_cb(GtkObject *widget, gpointer data) |
3217 { | 3814 { |
3222 ImageWindow *image_new(gint frame) | 3819 ImageWindow *image_new(gint frame) |
3223 { | 3820 { |
3224 ImageWindow *imd; | 3821 ImageWindow *imd; |
3225 | 3822 |
3226 imd = g_new0(ImageWindow, 1); | 3823 imd = g_new0(ImageWindow, 1); |
3824 | |
3825 imd->zoom_min = IMAGE_ZOOM_MIN; | |
3826 imd->zoom_max = IMAGE_ZOOM_MAX; | |
3227 imd->zoom = 1.0; | 3827 imd->zoom = 1.0; |
3228 imd->scale = 1.0; | 3828 imd->scale = 1.0; |
3229 | 3829 |
3230 imd->draw_idle_id = -1; | 3830 imd->draw_idle_id = -1; |
3231 | 3831 |
3260 | 3860 |
3261 imd->delay_flip = FALSE; | 3861 imd->delay_flip = FALSE; |
3262 | 3862 |
3263 imd->func_update = NULL; | 3863 imd->func_update = NULL; |
3264 imd->func_complete = NULL; | 3864 imd->func_complete = NULL; |
3865 imd->func_tile_request = NULL; | |
3866 imd->func_tile_dispose = NULL; | |
3265 | 3867 |
3266 imd->func_button = NULL; | 3868 imd->func_button = NULL; |
3267 imd->func_scroll = NULL; | 3869 imd->func_scroll = NULL; |
3268 | 3870 |
3269 imd->scroller_id = -1; | 3871 imd->scroller_id = -1; |
3270 imd->scroller_overlay = -1; | 3872 imd->scroller_overlay = -1; |
3873 | |
3874 imd->source_tiles_enabled = FALSE; | |
3875 imd->source_tiles = NULL; | |
3271 | 3876 |
3272 imd->image = gtk_drawing_area_new(); | 3877 imd->image = gtk_drawing_area_new(); |
3273 gtk_widget_set_double_buffered(imd->image, FALSE); | 3878 gtk_widget_set_double_buffered(imd->image, FALSE); |
3274 | 3879 |
3275 if (imd->has_frame) | 3880 if (imd->has_frame) |