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)