home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / nav_window.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  44.2 KB  |  1,769 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22.  
  23. #include <gtk/gtk.h>
  24. #include <gdk/gdkkeysyms.h>
  25.  
  26. #include "apptypes.h"
  27.  
  28. #include "appenv.h"
  29. #include "cursorutil.h"
  30. #include "dialog_handler.h"
  31. #include "info_dialog.h"
  32. #include "info_window.h"
  33. #include "gdisplay.h"
  34. #include "gimpcontext.h"
  35. #include "gimppreviewcache.h"
  36. #include "gimpset.h"
  37. #include "gimprc.h"
  38. #include "gimpui.h"
  39. #include "gximage.h"
  40. #include "nav_window.h"
  41. #include "scroll.h"
  42. #include "scale.h"
  43.  
  44. #include "libgimp/gimpunit.h"
  45.  
  46. #include "libgimp/gimpintl.h"
  47.  
  48. #include "pixmaps/zoom_in.xpm"
  49. #include "pixmaps/zoom_out.xpm"
  50.  
  51.  
  52. #define MAX_BUF 256
  53.  
  54. #define PREVIEW_MASK   GDK_EXPOSURE_MASK        | \
  55.                        GDK_BUTTON_PRESS_MASK    | \
  56.                        GDK_KEY_PRESS_MASK       | \
  57.                        GDK_KEY_RELEASE_MASK     | \
  58.                GDK_POINTER_MOTION_MASK
  59.  
  60.                                                           
  61. /* Navigation preview sizes */
  62. #define NAV_PREVIEW_WIDTH  112
  63. #define NAV_PREVIEW_HEIGHT 112
  64. #define BORDER_PEN_WIDTH   3
  65.  
  66. #define MAX_SCALE_BUF 20
  67.  
  68. typedef enum
  69. {
  70.   NAV_WINDOW,
  71.   NAV_POPUP
  72. } NavWinType;
  73.  
  74. /* Timeout before preview is updated */
  75. #define PREVIEW_UPDATE_TIMEOUT  1100
  76.  
  77. typedef struct _NavWinData NavWinData;
  78. struct _NavWinData
  79. {
  80.   NavWinType  ptype;
  81.   gboolean    showingPreview;
  82.   gboolean    installedDirtyTimer;
  83.   InfoDialog *info_win;
  84.   GtkWidget  *previewBox;
  85.   GtkWidget  *previewAlign;
  86.   GtkWidget  *zoom_label;
  87.   GtkObject  *zoom_adjustment;
  88.   GtkWidget  *preview;
  89.   void       *gdisp_ptr;    /* I'm not happy 'bout this one */
  90.   GdkGC      *gc;
  91.   gint        dispx;        /* x pos of top left corner of display area */
  92.   gint        dispy;        /* y pos of top left corner of display area */
  93.   gint        dispwidth;    /* width of display area */
  94.   gint        dispheight;   /* height of display area */
  95.   gint        sig_hand_id;
  96.   gboolean    sq_grabbed;   /* In the process of moving the preview square */
  97.   gint        motion_offsetx;
  98.   gint        motion_offsety;
  99.   gint        pwidth;       /* real preview width */
  100.   gint        pheight;      /* real preview height */
  101.   gint        imagewidth;   /* width of the real image */
  102.   gint        imageheight;  /* height of real image */
  103.   gdouble     ratio;
  104.   gboolean    block_window_marker; /* Block redraws of window marker */
  105.   gint        nav_preview_width;
  106.   gint        nav_preview_height;
  107.   gboolean    block_adj_sig; 
  108.   gboolean    frozen;       /* Has the dialog been frozen ? */
  109.   guint       timer_id;
  110. };
  111.  
  112.  
  113. static gint nav_window_preview_events       (GtkWidget  *widget, 
  114.                          GdkEvent   *event, 
  115.                          gpointer    data);
  116. static gint nav_window_expose_events        (GtkWidget  *widget, 
  117.                          GdkEvent   *event, 
  118.                          gpointer    data);
  119. static void nav_window_update_preview       (NavWinData *iwd);
  120. static void nav_window_update_preview_blank (NavWinData *iwd);
  121. static void destroy_preview_widget          (NavWinData *iwd);
  122. static void create_preview_widget           (NavWinData *iwd);
  123. static void nav_window_draw_sqr             (NavWinData *iwd, 
  124.                          gboolean    undraw,
  125.                          gint        x,
  126.                          gint        y,
  127.                          gint        w,
  128.                          gint        h);
  129. static void set_size_data                   (NavWinData *iwd);
  130. static gint nav_preview_update_do_timer     (NavWinData *iwd);
  131.  
  132.  
  133. static void 
  134. nav_window_destroy_callback (GtkWidget *widget,
  135.                  gpointer   client_data)
  136. {
  137.   InfoDialog *info_win;
  138.   
  139.   info_win = (InfoDialog *)client_data;
  140.   dialog_unregister(info_win->shell);
  141. }
  142.  
  143. static void
  144. nav_window_close_callback (GtkWidget *widget,
  145.                gpointer   client_data)
  146. {
  147.   InfoDialog *info_win;
  148.   NavWinData *iwd;
  149.   
  150.   info_win = (InfoDialog *)client_data;
  151.   iwd = (NavWinData *)info_win->user_data;
  152.  
  153.   iwd->showingPreview = FALSE;
  154.   info_dialog_popdown ((InfoDialog *) client_data);
  155. }
  156.  
  157. static void
  158. nav_window_disp_area (NavWinData *iwd,
  159.               GDisplay   *gdisp)
  160. {
  161.   GimpImage *gimage;
  162.   gint       newwidth;
  163.   gint       newheight;
  164.   gdouble    xratio;
  165.   gdouble    yratio;     /* Screen res ratio */
  166.   gboolean   need_update = FALSE;
  167.  
  168.   /* Calculate preview size */
  169.   gimage = gdisp->gimage;
  170.  
  171.   xratio = SCALEFACTOR_X (gdisp);
  172.   yratio = SCALEFACTOR_Y (gdisp);
  173.  
  174.   iwd->dispx = gdisp->offset_x * iwd->ratio / xratio + 0.5;
  175.   iwd->dispy = gdisp->offset_y * iwd->ratio/yratio + 0.5;
  176.   iwd->dispwidth  = (gdisp->disp_width * iwd->ratio) / xratio + 0.5;
  177.   iwd->dispheight = (gdisp->disp_height * iwd->ratio) / yratio + 0.5;
  178.  
  179.   newwidth  = gimage->width;
  180.   newheight = gimage->height;
  181.  
  182.   if (!gdisp->dot_for_dot)
  183.     {
  184.       newwidth = (newwidth * 
  185.           gdisp->gimage->yresolution) / gdisp->gimage->xresolution;
  186.       iwd->dispx = ((gdisp->offset_x * 
  187.              gdisp->gimage->yresolution * iwd->ratio) / 
  188.             (gdisp->gimage->xresolution *  xratio)) + 0.5;     /*here*/
  189.       iwd->dispwidth = ((gdisp->disp_width * 
  190.              gdisp->gimage->yresolution * iwd->ratio) / 
  191.             (gdisp->gimage->xresolution *  xratio)) + 0.5; /*here*/
  192.     }
  193.  
  194.   if ((iwd->imagewidth > 0 && newwidth != iwd->imagewidth) ||
  195.       (iwd->imageheight > 0 && newheight != iwd->imageheight))
  196.     {
  197.       /* Must change the preview size */
  198.       if (iwd->ptype != NAV_POPUP)
  199.     {
  200.       gtk_window_set_focus (GTK_WINDOW (iwd->info_win->shell), NULL);  
  201.     }
  202.       destroy_preview_widget (iwd);
  203.       create_preview_widget (iwd);
  204.       need_update = TRUE;
  205.     }
  206.  
  207.   iwd->imagewidth  = newwidth;
  208.   iwd->imageheight = newheight;
  209.  
  210.   /* Normalise */
  211.   iwd->dispwidth  = MAX (iwd->dispwidth, 2);
  212.   iwd->dispheight = MAX (iwd->dispheight, 2);
  213.  
  214.   iwd->dispwidth = MIN (iwd->dispwidth, iwd->pwidth /* - BORDER_PEN_WIDTH */);
  215.   iwd->dispheight = MIN (iwd->dispheight, iwd->pheight /* - BORDER_PEN_WIDTH */);
  216.  
  217.   if (need_update)
  218.     {
  219.       gtk_widget_hide (iwd->previewAlign);
  220.       nav_window_update_preview_blank (iwd); 
  221.       gtk_widget_show (iwd->preview);
  222.       gtk_widget_draw (iwd->preview, NULL); 
  223.       gtk_widget_show (iwd->previewAlign);
  224.       nav_window_draw_sqr (iwd, FALSE,
  225.                iwd->dispx, iwd->dispy,
  226.                iwd->dispwidth, iwd->dispheight);
  227.       if (iwd->ptype != NAV_POPUP)
  228.     {
  229.       gtk_window_set_focus (GTK_WINDOW (iwd->info_win->shell),
  230.                 iwd->preview);  
  231.       iwd->timer_id = 
  232.         gtk_timeout_add (PREVIEW_UPDATE_TIMEOUT,
  233.                  (GtkFunction) nav_preview_update_do_timer,
  234.                  (gpointer) iwd); 
  235.     }
  236.       else
  237.     {
  238.       nav_window_update_preview (iwd);
  239.       gtk_widget_draw (iwd->preview, NULL); 
  240.     }
  241.     }
  242. }
  243.  
  244. static void
  245. nav_window_draw_sqr (NavWinData *iwd,
  246.              gboolean    undraw,
  247.              gint        x,
  248.              gint        y,
  249.              gint        w,
  250.              gint        h)
  251. {
  252.   GDisplay *gdisp;
  253.  
  254.   gdisp = (GDisplay *) iwd->gdisp_ptr;
  255.  
  256.   gdk_gc_set_function (iwd->gc, GDK_INVERT);
  257.  
  258.   if (undraw)
  259.     {
  260.       if (iwd->dispx != 0 || iwd->dispy != 0 ||
  261.       iwd->pwidth != iwd->dispwidth || iwd->pheight != iwd->dispheight)
  262.     {
  263.       /* first undraw from last co-ords */
  264.       gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, 
  265.                   iwd->dispx, iwd->dispy, 
  266.                   iwd->dispwidth - BORDER_PEN_WIDTH + 1, 
  267.                   iwd->dispheight - BORDER_PEN_WIDTH + 1);
  268.     }
  269.     }
  270.  
  271.   if (x != 0 || y != 0 ||
  272.       w != iwd->pwidth || h != iwd->pheight)
  273.     {
  274.       gdk_draw_rectangle (iwd->preview->window, iwd->gc, FALSE, 
  275.               x, y, 
  276.               w - BORDER_PEN_WIDTH + 1,
  277.               h - BORDER_PEN_WIDTH + 1);
  278.     }
  279.  
  280.   iwd->dispx      = x;
  281.   iwd->dispy      = y;
  282.   iwd->dispwidth  = w;
  283.   iwd->dispheight = h;
  284. }
  285.  
  286. static void 
  287. destroy_preview_widget (NavWinData *iwd)
  288. {
  289.   if(!iwd->preview)
  290.     return;
  291.  
  292.   gtk_widget_hide(iwd->previewBox);
  293.   gtk_widget_destroy(iwd->previewBox);
  294.   iwd->previewBox = NULL;
  295.   iwd->preview = NULL;
  296. }
  297.  
  298. static void
  299. set_size_data (NavWinData *iwd)
  300. {
  301.   gint sel_width;
  302.   gint sel_height;
  303.   gint pwidth;
  304.   gint pheight;
  305.   GDisplay  *gdisp;
  306.   GimpImage *gimage;
  307.  
  308.   gdisp = (GDisplay *)(iwd->gdisp_ptr);
  309.   gimage = gdisp->gimage;
  310.  
  311.   sel_width = gimage->width;
  312.   sel_height = gimage->height;
  313.  
  314.   if (!gdisp->dot_for_dot)
  315.     sel_width = 
  316.       (sel_width * gdisp->gimage->yresolution) / gdisp->gimage->xresolution;
  317.  
  318.   if (sel_width > sel_height) 
  319.     {
  320.       pwidth  = iwd->nav_preview_width;
  321.       /*     pheight  = sel_height * pwidth / sel_width; */
  322.       /*iwd->ratio = MIN (1.0, (gdouble) pwidth / (gdouble) sel_width);*/
  323.       iwd->ratio = (gdouble) pwidth / (gdouble) sel_width;
  324.     } 
  325.   else 
  326.     {
  327.       pheight = iwd->nav_preview_height;
  328.       /*     pwidth  = sel_width * pheight / sel_height; */
  329.       /*iwd->ratio = MIN (1.0, (gdouble) pheight / (gdouble) sel_height);*/
  330.       iwd->ratio = (gdouble) pheight / (gdouble) sel_height;
  331.     }
  332.  
  333.   pwidth  = sel_width  * iwd->ratio + 0.5;
  334.   pheight = sel_height * iwd->ratio + 0.5;
  335.  
  336.   iwd->pwidth  = pwidth;
  337.   iwd->pheight = pheight;
  338. }
  339.  
  340. static void 
  341. create_preview_widget (NavWinData *iwd)
  342. {
  343.   GtkWidget *hbox;  
  344.   GtkWidget *image;
  345.   GtkWidget *frame;
  346.   GDisplay  *gdisp;
  347.  
  348.   gdisp = (GDisplay *)(iwd->gdisp_ptr);
  349.  
  350.   hbox = gtk_hbox_new (FALSE,0);
  351.   iwd->previewBox = hbox;
  352.   gtk_widget_show (hbox);
  353.   gtk_container_add (GTK_CONTAINER (iwd->previewAlign), hbox);
  354.  
  355.   image = gtk_preview_new (GTK_PREVIEW_COLOR);
  356.   gtk_widget_set_events (GTK_WIDGET(image), PREVIEW_MASK);
  357.   iwd->preview = image;
  358.   gtk_widget_show (image);
  359.  
  360.   gtk_preview_set_dither (GTK_PREVIEW (image), GDK_RGB_DITHER_MAX);
  361.  
  362.   set_size_data (iwd);
  363.  
  364.   gtk_preview_size (GTK_PREVIEW (iwd->preview),
  365.             iwd->pwidth,
  366.             iwd->pheight);
  367.  
  368.   gtk_widget_set_usize (iwd->preview,  
  369.             iwd->pwidth, 
  370.             iwd->pheight); 
  371.  
  372.   frame = gtk_frame_new(NULL);
  373.   gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN);
  374.   gtk_container_add (GTK_CONTAINER (iwd->previewBox), frame);
  375.   gtk_container_add (GTK_CONTAINER (frame), iwd->preview);
  376.   gtk_widget_show (frame);
  377.  
  378.   iwd->sig_hand_id = 
  379.     gtk_signal_connect_after (GTK_OBJECT (image), "expose_event",
  380.                   (GtkSignalFunc) nav_window_expose_events,
  381.                   iwd);
  382.  
  383.   gtk_signal_connect (GTK_OBJECT (image), "event",
  384.               (GtkSignalFunc) nav_window_preview_events,
  385.               iwd);
  386.  
  387. /*   gtk_signal_connect (GTK_OBJECT (image), "size_allocate", */
  388. /*               (GtkSignalFunc) nav_window_preview_resized, */
  389. /*               iwd); */
  390.  
  391.   GTK_WIDGET_SET_FLAGS (image, GTK_CAN_FOCUS);
  392. }
  393.  
  394. static void
  395. update_real_view (NavWinData *iwd,
  396.           gint        tx,
  397.           gint        ty)
  398. {
  399.   GDisplay *gdisp;
  400.   gdouble   xratio;
  401.   gdouble   yratio;
  402.   gint xoffset;
  403.   gint yoffset;
  404.   gint xpnt;
  405.   gint ypnt;
  406.  
  407.   gdisp = (GDisplay *) iwd->gdisp_ptr;
  408.  
  409.   xratio = SCALEFACTOR_X (gdisp);
  410.   yratio = SCALEFACTOR_Y (gdisp);
  411.  
  412.   if ((tx + iwd->dispwidth) >= iwd->pwidth)
  413.     {
  414.       tx = iwd->pwidth; /* Actually should be less... 
  415.              * but bound check will save us.
  416.              */
  417.     }
  418.  
  419.   xpnt = (gint) (((gdouble) (tx) * xratio) / iwd->ratio + 0.5);
  420.  
  421.   if ((ty + iwd->dispheight) >= iwd->pheight)
  422.     ty = iwd->pheight; /* Same comment as for xpnt above. */
  423.  
  424.   ypnt = (gint) (((gdouble) (ty) * yratio) / iwd->ratio + 0.5);
  425.  
  426.   if (!gdisp->dot_for_dot) /* here */
  427.       xpnt = ((gdouble) xpnt * 
  428.           gdisp->gimage->xresolution) / gdisp->gimage->yresolution + 0.5;
  429.  
  430.   xoffset = xpnt - gdisp->offset_x;
  431.   yoffset = ypnt - gdisp->offset_y;
  432.   
  433.   iwd->block_window_marker = TRUE;
  434.   scroll_display (iwd->gdisp_ptr, xoffset, yoffset);
  435.   iwd->block_window_marker = FALSE;
  436. }
  437.  
  438. static void 
  439. nav_window_update_preview (NavWinData *iwd)
  440. {
  441.   GDisplay  *gdisp;
  442.   TempBuf   *preview_buf;
  443.   TempBuf   *preview_buf_ptr;
  444.   TempBuf   *preview_buf_notdot = NULL;
  445.   guchar    *src, *buf, *dest;
  446.   gint       x, y;
  447.   gint       pwidth, pheight;
  448.   GimpImage *gimage;
  449.   gdouble    r, g, b, a, chk;
  450.   gint       xoff = 0;
  451.   gint       yoff = 0;
  452.  
  453.   gimp_add_busy_cursors (); 
  454.  
  455.   gdisp = (GDisplay *) iwd->gdisp_ptr;
  456.  
  457.   /* Calculate preview size */
  458.   gimage = ((GDisplay *) (iwd->gdisp_ptr))->gimage;
  459.  
  460.   /* Min size is 2 */
  461.   pwidth  = iwd->pwidth;
  462.   pheight = iwd->pheight;
  463.  
  464.   /* we need a large normal preview which we will cut down later.
  465.    *  gimp_image_construct_composite_preview() can't cope with 
  466.    *  dot_for_dot not been set.
  467.    */
  468.   if (!gdisp->dot_for_dot) /* ALT */ 
  469.     {
  470.       gint    sel_width  = gimage->width;
  471.       gint    sel_height = gimage->height;
  472.       gdouble tratio;
  473.       
  474.       if (sel_width > sel_height) 
  475.     tratio = (gdouble) iwd->nav_preview_width / ((gdouble) sel_width);
  476.       else
  477.     tratio = (gdouble) iwd->nav_preview_height / ((gdouble) sel_height);
  478.  
  479.       pwidth  = sel_width  * tratio + 0.5;
  480.       pheight = sel_height * tratio + 0.5;
  481.     }
  482.  
  483.   if (iwd->ratio > 1.0)    /*  Preview is scaling up!  */
  484.     {
  485.       TempBuf *tmp;
  486.  
  487.       tmp = gimp_image_construct_composite_preview (gimage,
  488.                             gimage->width,
  489.                             gimage->height);
  490.       preview_buf = gimp_preview_scale (tmp, 
  491.                     pwidth, 
  492.                     pheight);
  493.       temp_buf_free (tmp);
  494.     } 
  495.   else 
  496.     {
  497.       preview_buf = gimp_image_construct_composite_preview (gimage,
  498.                                 MAX (pwidth, 2),
  499.                                 MAX (pheight, 2));
  500.     }
  501.  
  502.   /* reset & get new preview */
  503.   /*  FIXME: should use gimp_preview_scale()  */
  504.   if (!gdisp->dot_for_dot)
  505.     {
  506.       gint     loop1, loop2;
  507.       gdouble  x_ratio, y_ratio;
  508.       guchar  *src_data;
  509.       guchar  *dest_data;
  510.  
  511.       preview_buf_notdot = temp_buf_new (iwd->pwidth,
  512.                      iwd->pheight,
  513.                      preview_buf->bytes, 
  514.                      0, 0, NULL);
  515.  
  516.       x_ratio = (gdouble) pwidth  / (gdouble) iwd->pwidth;
  517.       y_ratio = (gdouble) pheight / (gdouble) iwd->pheight;
  518.  
  519.       src_data  = temp_buf_data (preview_buf);
  520.       dest_data = temp_buf_data (preview_buf_notdot);
  521.  
  522.       for (loop1 = 0 ; loop1 < iwd->pheight ; loop1++)
  523.     for (loop2 = 0 ; loop2 < iwd->pwidth ; loop2++)
  524.       {
  525.         gint    i;
  526.         guchar *src_pixel;
  527.         guchar *dest_pixel;
  528.  
  529.         src_pixel = src_data +
  530.           ((gint) (loop2 * x_ratio)) * preview_buf->bytes +
  531.           ((gint) (loop1 * y_ratio)) * pwidth * preview_buf->bytes;
  532.         dest_pixel = dest_data +
  533.           (loop2 + loop1 * iwd->pwidth) * preview_buf->bytes;
  534.  
  535.         for (i = 0 ; i < preview_buf->bytes; i++)
  536.           *dest_pixel++ = *src_pixel++;
  537.       }
  538.  
  539.       pwidth  = iwd->pwidth;
  540.       pheight = iwd->pheight;
  541.  
  542.       src = temp_buf_data (preview_buf_notdot);
  543.       preview_buf_ptr = preview_buf_notdot;
  544.     }
  545.   else
  546.     {
  547.       src = temp_buf_data (preview_buf);
  548.       preview_buf_ptr = preview_buf;
  549.     }
  550.   
  551.   buf = g_new (gchar, preview_buf_ptr->width * 3);
  552.  
  553.   for (y = 0; y < preview_buf_ptr->height ; y++)
  554.     {
  555.       dest = buf;
  556.       switch (preview_buf_ptr->bytes)
  557.     {
  558.     case 4:
  559.       for (x = 0; x < preview_buf_ptr->width; x++)
  560.         {
  561.           r = ((gdouble) (*(src++))) / 255.0;
  562.           g = ((gdouble) (*(src++))) / 255.0;
  563.           b = ((gdouble) (*(src++))) / 255.0;
  564.           a = ((gdouble) (*(src++))) / 255.0;
  565.           chk = ((gdouble) ((( (x^y) & 4 ) << 4) | 128)) / 255.0;
  566.           *(dest++) = (guchar) ((chk + (r - chk) * a) * 255.0);
  567.           *(dest++) = (guchar) ((chk + (g - chk) * a) * 255.0);
  568.           *(dest++) = (guchar) ((chk + (b - chk) * a) * 255.0);
  569.         }
  570.       break;
  571.  
  572.     case 2:
  573.       for (x = 0; x < preview_buf_ptr->width; x++)
  574.         {
  575.           r = ((gdouble) (*(src++))) / 255.0;
  576.           a = ((gdouble) (*(src++))) / 255.0;
  577.           chk = ((gdouble) ((( (x^y) & 4 ) << 4) | 128)) / 255.0;
  578.           *(dest++) = (guchar) ((chk + (r - chk) * a) * 255.0);
  579.           *(dest++) = (guchar) ((chk + (r - chk) * a) * 255.0);
  580.           *(dest++) = (guchar) ((chk + (r - chk) * a) * 255.0);
  581.         }
  582.       break;
  583.  
  584.     default:
  585.       g_warning ("UNKNOWN TempBuf bpp in nav_window_update_preview()");
  586.     }
  587.       
  588.       gtk_preview_draw_row (GTK_PREVIEW (iwd->preview),
  589.                 (guchar *) buf, 
  590.                 xoff, yoff + y, 
  591.                 preview_buf_ptr->width);
  592.     }
  593.  
  594.   g_free (buf);
  595.  
  596.   temp_buf_free (preview_buf);
  597.   if (preview_buf_notdot)
  598.     temp_buf_free (preview_buf_notdot);
  599.  
  600.   gimp_remove_busy_cursors (NULL);
  601. }
  602.  
  603. static void 
  604. nav_window_update_preview_blank (NavWinData *iwd)
  605. {
  606.  
  607.   guchar  *buf;
  608.   guchar  *dest;
  609.   gint     x, y;
  610.   gdouble  chk;
  611.  
  612. #if 0 
  613.   GimpImage *gimage;
  614.   GDisplay  *gdisp;
  615.  
  616.   gdisp = (GDisplay *) iwd->gdisp_ptr;
  617.  
  618.   /* Calculate preview size */
  619.   gimage = ((GDisplay *) (iwd->gdisp_ptr))->gimage;
  620.  
  621. #endif /* 0 */
  622.   
  623.   buf = g_new (gchar,  iwd->pwidth * 3);
  624.  
  625.   for (y = 0; y < iwd->pheight ; y++)
  626.     {
  627.       dest = buf;
  628.       for (x = 0; x < iwd->pwidth; x++)
  629.     {
  630.       chk = ((gdouble) ((( (x^y) & 4 ) << 4) | 128))/255.0;
  631.       chk *= 128.0;
  632.       *(dest++) = (guchar) chk;
  633.       *(dest++) = (guchar) chk;
  634.       *(dest++) = (guchar) chk;
  635.     }
  636.       
  637.       gtk_preview_draw_row (GTK_PREVIEW (iwd->preview),
  638.                 (guchar *) buf, 
  639.                 0, y, iwd->pwidth);
  640.     }
  641.  
  642.   g_free (buf);
  643.  
  644.   gdk_flush ();
  645. }
  646.  
  647. static gint
  648. inside_preview_square (NavWinData *iwd,
  649.                gint        x,
  650.                gint        y)
  651. {
  652.   if (x > iwd->dispx &&
  653.       x < (iwd->dispx + iwd->dispwidth) &&
  654.       y > iwd->dispy &&
  655.       y < iwd->dispy + iwd->dispheight)
  656.     return TRUE;
  657.  
  658.   return FALSE;
  659. }
  660.  
  661. static void
  662. update_zoom_label (NavWinData *iwd)
  663. {
  664.   gchar scale_str[MAX_SCALE_BUF];
  665.  
  666.   if(!iwd->zoom_label)
  667.     return;
  668.  
  669.   /* Update the zoom scale string */
  670.   g_snprintf (scale_str, MAX_SCALE_BUF, "%d:%d",
  671.           SCALEDEST (((GDisplay *)iwd->gdisp_ptr)), 
  672.           SCALESRC (((GDisplay *)iwd->gdisp_ptr)));
  673.   
  674.   gtk_label_set_text (GTK_LABEL (iwd->zoom_label), scale_str);
  675. }
  676.  
  677. static void 
  678. update_zoom_adjustment (NavWinData *iwd)
  679. {
  680.   GtkAdjustment *adj;
  681.   gdouble f;
  682.   gdouble val;
  683.  
  684.   if (! iwd->zoom_adjustment)
  685.     return;
  686.  
  687.   adj = GTK_ADJUSTMENT (iwd->zoom_adjustment);
  688.  
  689.   f = 
  690.     ((gdouble) SCALEDEST (((GDisplay *) iwd->gdisp_ptr))) / 
  691.     ((gdouble) SCALESRC (((GDisplay *) iwd->gdisp_ptr)));
  692.   
  693.   if (f < 1.0)
  694.     {
  695.       val = -1.0 / f;
  696.     }
  697.   else
  698.     {
  699.       val = f;
  700.     }
  701.  
  702.   if (abs ((gint) adj->value) != (gint)(val - 1) && iwd->block_adj_sig != TRUE)
  703.     {
  704.       adj->value = val;
  705.       gtk_signal_emit_by_name (GTK_OBJECT (iwd->zoom_adjustment), "changed");
  706.     }
  707. }
  708.  
  709. static void
  710. move_to_point (NavWinData *iwd,
  711.            gint        tx,
  712.            gint        ty)
  713. {
  714.   tx = CLAMP (tx, 0, iwd->pwidth);
  715.   ty = CLAMP (ty, 0, iwd->pheight);
  716.   
  717.   if ((tx + iwd->dispwidth) >= iwd->pwidth)
  718.     {
  719.       tx = iwd->pwidth - iwd->dispwidth;
  720.     }
  721.   
  722.   if ((ty + iwd->dispheight) >= iwd->pheight)
  723.     {
  724.       ty = iwd->pheight - iwd->dispheight;
  725.     }
  726.   
  727.   if (iwd->dispx == tx && iwd->dispy == ty)
  728.     return;
  729.  
  730.   /* Update the real display */
  731.   update_real_view (iwd, tx, ty);
  732.   
  733.   nav_window_draw_sqr (iwd,
  734.                TRUE,
  735.                tx, ty,
  736.                iwd->dispwidth, iwd->dispheight);
  737.   
  738. }
  739.  
  740. static void
  741. nav_window_grab_pointer (NavWinData *iwd,
  742.              GtkWidget  *widget)
  743. {
  744.   GdkCursor *cursor;
  745.  
  746.   iwd->sq_grabbed = TRUE;
  747.   gtk_grab_add (widget);
  748.  
  749.   cursor = gdk_cursor_new (GDK_CROSSHAIR); 
  750.  
  751.   gdk_pointer_grab (widget->window, TRUE,
  752.             GDK_BUTTON_RELEASE_MASK |
  753.             GDK_POINTER_MOTION_HINT_MASK |
  754.             GDK_BUTTON_MOTION_MASK |
  755.             GDK_EXTENSION_EVENTS_ALL,
  756.             widget->window, cursor, 0);
  757.   
  758.   gdk_cursor_destroy (cursor); 
  759. }
  760.  
  761. static gint
  762. nav_window_preview_events (GtkWidget *widget,
  763.                GdkEvent  *event,
  764.                gpointer   data)
  765. {
  766.   NavWinData      *iwd;
  767.   GDisplay        *gdisp;
  768.   GdkEventButton  *bevent;
  769.   GdkEventMotion  *mevent;
  770.   GdkEventKey     *kevent;
  771.   GdkModifierType  mask;
  772.   gint     tx = 0;
  773.   gint     ty = 0;
  774.   gint     mx;
  775.   gint     my;
  776.   gboolean arrowKey = FALSE;
  777.  
  778.   iwd = (NavWinData *)data;
  779.  
  780.   if(!iwd || iwd->frozen == TRUE)
  781.     return FALSE;
  782.  
  783.   gdisp = (GDisplay *) iwd->gdisp_ptr;
  784.  
  785.   switch (event->type)
  786.     {
  787.     case GDK_EXPOSE:
  788.       break;
  789.  
  790.     case GDK_MAP:
  791.       if (iwd->ptype == NAV_POPUP)
  792.     {
  793.       nav_window_update_preview (iwd);
  794.       /* First time displayed.... get the pointer! */
  795.       nav_window_grab_pointer (iwd, iwd->preview);
  796.     }
  797.       else
  798.     {
  799.       nav_window_update_preview_blank (iwd); 
  800.       iwd->timer_id = 
  801.         gtk_timeout_add (PREVIEW_UPDATE_TIMEOUT,
  802.                  (GtkFunction) nav_preview_update_do_timer,
  803.                  (gpointer) iwd); 
  804.     }
  805.       break;
  806.  
  807.     case GDK_BUTTON_PRESS:
  808.       bevent = (GdkEventButton *) event;
  809.       tx = bevent->x;
  810.       ty = bevent->y;
  811.  
  812.       /* Must start the move */
  813.       switch (bevent->button)
  814.     {
  815.     case 1:
  816.       if (! inside_preview_square (iwd, tx, ty))
  817.         {
  818.           /* Direct scroll to the location */
  819.           /* view scrolled to the center or nearest possible point */
  820.           
  821.           tx -= iwd->dispwidth / 2;
  822.           ty -= iwd->dispheight / 2;
  823.  
  824.           if(tx < 0)
  825.         tx = 0;
  826.  
  827.           if((tx + iwd->dispwidth) > iwd->pwidth)
  828.         tx = iwd->pwidth - iwd->dispwidth;
  829.  
  830.           if(ty < 0)
  831.         ty = 0;
  832.  
  833.           if((ty + iwd->dispheight) > iwd->pheight)
  834.         ty = iwd->pheight - iwd->dispheight;
  835.  
  836.           update_real_view(iwd,tx,ty);
  837.  
  838.           nav_window_draw_sqr (iwd,
  839.                    TRUE,
  840.                    tx, ty,
  841.                    iwd->dispwidth, iwd->dispheight);
  842.           iwd->motion_offsetx = iwd->dispwidth / 2;
  843.           iwd->motion_offsety = iwd->dispheight / 2;
  844.         }
  845.       else
  846.         {
  847.           iwd->motion_offsetx = tx - iwd->dispx;
  848.           iwd->motion_offsety = ty - iwd->dispy;
  849.         }
  850.       
  851.       nav_window_grab_pointer (iwd, widget);
  852.  
  853.       break;
  854.  
  855.       /*  wheelmouse support  */
  856.     case 4:
  857.       if (bevent->state & GDK_SHIFT_MASK)
  858.         {
  859.           change_scale (gdisp, ZOOMIN);
  860.         }
  861.       else
  862.         {
  863.           GtkAdjustment *adj =
  864.         (bevent->state & GDK_CONTROL_MASK) ?
  865.         gdisp->hsbdata : gdisp->vsbdata;
  866.           gfloat new_value = adj->value - adj->page_increment / 2;
  867.           new_value =
  868.         CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
  869.           gtk_adjustment_set_value (adj, new_value);
  870.         }
  871.       break;
  872.  
  873.     case 5:
  874.       if (bevent->state & GDK_SHIFT_MASK)
  875.         {
  876.           change_scale (gdisp, ZOOMOUT);
  877.         }
  878.       else
  879.         {
  880.           GtkAdjustment *adj =
  881.         (bevent->state & GDK_CONTROL_MASK) ?
  882.         gdisp->hsbdata : gdisp->vsbdata;
  883.           gfloat new_value = adj->value + adj->page_increment / 2;
  884.           new_value = CLAMP (new_value,
  885.                  adj->lower, adj->upper - adj->page_size);
  886.           gtk_adjustment_set_value (adj, new_value);
  887.         }
  888.       break;
  889.  
  890.     default:
  891.       break;
  892.     }
  893.       break;
  894.  
  895.     case GDK_BUTTON_RELEASE:
  896.       bevent = (GdkEventButton *) event;
  897.       tx = bevent->x;
  898.       ty = bevent->y;
  899.  
  900.       switch (bevent->button)
  901.     {
  902.     case 1:
  903.       iwd->sq_grabbed = FALSE;
  904.       gtk_grab_remove (widget);
  905.       gdk_pointer_ungrab (0);
  906.       if(iwd->ptype == NAV_POPUP)
  907.         {
  908.           gtk_widget_hide (gdisp->nav_popup);
  909.         }
  910.       gdk_flush ();
  911.       break;
  912.     default:
  913.       break;
  914.     }
  915.       break;
  916.  
  917.     case GDK_KEY_PRESS:
  918.       /* hack for the update preview... needs to be fixed */
  919.       kevent = (GdkEventKey *) event;
  920.       
  921.       switch (kevent->keyval)
  922.     {
  923.     case GDK_space:
  924.       gdk_window_raise(gdisp->shell->window);
  925.       break;
  926.     case GDK_Up:
  927.       arrowKey = TRUE;
  928.       tx = iwd->dispx;
  929.       ty = iwd->dispy - 1;
  930.       break;
  931.     case GDK_Left:
  932.       arrowKey = TRUE;
  933.       tx = iwd->dispx - 1;
  934.       ty = iwd->dispy;
  935.       break;
  936.     case GDK_Right:
  937.       arrowKey = TRUE;
  938.       tx = iwd->dispx + 1;
  939.       ty = iwd->dispy;
  940.       break;
  941.     case GDK_Down:
  942.       arrowKey = TRUE;
  943.       tx = iwd->dispx;
  944.       ty = iwd->dispy + 1;
  945.       break;
  946.     case GDK_equal:
  947.       change_scale (gdisp, ZOOMIN);
  948.       break;
  949.     case GDK_minus:
  950.       change_scale (gdisp, ZOOMOUT);
  951.       break;
  952.     default:
  953.       break;
  954.     }
  955.  
  956.       if (arrowKey)
  957.     {
  958.       move_to_point (iwd, tx, ty);
  959.       return TRUE;
  960.     }
  961.       break;
  962.  
  963.     case GDK_MOTION_NOTIFY:
  964.       mevent = (GdkEventMotion *) event;
  965.  
  966.       if (!iwd->sq_grabbed)
  967.     break;
  968.  
  969.       gdk_window_get_pointer (widget->window, &mx, &my, &mask);
  970.       tx = mx;
  971.       ty = my;
  972.  
  973.       tx = tx - iwd->motion_offsetx;
  974.       ty = ty - iwd->motion_offsety;
  975.  
  976.       move_to_point (iwd, tx, ty);
  977.      break;
  978.  
  979.     default:
  980.       break;
  981.     }
  982.  
  983.   return FALSE;
  984. }
  985.  
  986. static gint
  987. nav_window_expose_events (GtkWidget *widget,
  988.               GdkEvent  *event,
  989.               gpointer   data)
  990. {
  991.   NavWinData *iwd;
  992.   GDisplay   *gdisp;
  993.  
  994.   iwd = (NavWinData *) data;
  995.  
  996.   if(!iwd || iwd->frozen == TRUE)
  997.     return FALSE;
  998.  
  999.   gdisp = (GDisplay *) iwd->gdisp_ptr;
  1000.  
  1001.   switch (event->type)
  1002.     {
  1003.     case GDK_EXPOSE:
  1004.       /* we must have the grab if in nav_popup*/
  1005.       gtk_signal_handler_block (GTK_OBJECT(widget), iwd->sig_hand_id); 
  1006.       gtk_widget_draw (iwd->preview, NULL); 
  1007.       gtk_signal_handler_unblock (GTK_OBJECT(widget), iwd->sig_hand_id); 
  1008.       
  1009.       nav_window_draw_sqr (iwd,FALSE,
  1010.                iwd->dispx, iwd->dispy,
  1011.                iwd->dispwidth, iwd->dispheight);
  1012.       if (! gtk_grab_get_current() && iwd->ptype == NAV_POPUP)
  1013.     nav_window_grab_pointer (iwd, iwd->preview);
  1014.       break;
  1015.  
  1016.     default:
  1017.       break;
  1018.     }
  1019.  
  1020.   return FALSE;
  1021. }
  1022.  
  1023. static gint 
  1024. nav_preview_update_do (NavWinData *iwd)
  1025. {
  1026.   /* If the gdisp_ptr has gone then don't do anything in this timer */
  1027.   if (!iwd->gdisp_ptr)
  1028.     return FALSE;
  1029.  
  1030.   nav_window_update_preview (iwd);
  1031.   nav_window_disp_area (iwd, iwd->gdisp_ptr);
  1032.   gtk_widget_queue_draw (iwd->preview); 
  1033.  
  1034.   iwd->installedDirtyTimer = FALSE;
  1035.  
  1036.   return FALSE;
  1037. }
  1038.  
  1039. static gint 
  1040. nav_preview_update_do_timer (NavWinData *iwd)
  1041. {
  1042.   iwd->timer_id = 0;
  1043.   gtk_idle_add ((GtkFunction) nav_preview_update_do, (gpointer) iwd);
  1044.  
  1045.   return FALSE;
  1046. }
  1047.  
  1048. static void
  1049. nav_image_need_update (GtkObject *obj,
  1050.                gpointer   client_data)
  1051. {
  1052.   NavWinData *iwd;
  1053.  
  1054.   iwd = (NavWinData *)client_data;
  1055.  
  1056.   if(!iwd || 
  1057.      !iwd->showingPreview || 
  1058.      iwd->installedDirtyTimer == TRUE ||
  1059.      iwd->frozen == TRUE)
  1060.     return;
  1061.  
  1062.   iwd->installedDirtyTimer = TRUE;
  1063.  
  1064.   /* Update preview at a less busy time */
  1065.   nav_window_update_preview_blank (iwd); 
  1066.   gtk_widget_draw (iwd->preview, NULL); 
  1067.   iwd->timer_id = gtk_timeout_add (PREVIEW_UPDATE_TIMEOUT, 
  1068.                    (GtkFunction) nav_preview_update_do_timer,
  1069.                    (gpointer) iwd); 
  1070. }
  1071.  
  1072. static void
  1073. navwindow_zoomin (GtkWidget *widget,
  1074.           gpointer   data)
  1075. {
  1076.   NavWinData *iwd;
  1077.   GDisplay   *gdisp;
  1078.  
  1079.   iwd = (NavWinData *)data;
  1080.  
  1081.   if(!iwd || iwd->frozen == TRUE)
  1082.     return;
  1083.  
  1084.   gdisp = (GDisplay *) iwd->gdisp_ptr;
  1085.  
  1086.   change_scale (gdisp, ZOOMIN);
  1087. }
  1088.  
  1089. static void
  1090. navwindow_zoomout (GtkWidget *widget,
  1091.            gpointer   data)
  1092. {
  1093.   NavWinData *iwd;
  1094.   GDisplay   *gdisp;
  1095.  
  1096.   iwd = (NavWinData *)data;
  1097.  
  1098.   if (!iwd || iwd->frozen == TRUE)
  1099.     return;
  1100.  
  1101.   gdisp = (GDisplay *) iwd->gdisp_ptr;
  1102.  
  1103.   change_scale (gdisp, ZOOMOUT);
  1104. }
  1105.  
  1106. static void
  1107. zoom_adj_changed (GtkAdjustment *adj, 
  1108.           gpointer       data)
  1109. {
  1110.   NavWinData *iwd;
  1111.   GDisplay   *gdisp;
  1112.   gint scalesrc;
  1113.   gint scaledest;
  1114.  
  1115.   iwd = (NavWinData *)data;
  1116.  
  1117.   if (!iwd || iwd->frozen == TRUE)
  1118.     return;
  1119.   
  1120.   gdisp = (GDisplay *) iwd->gdisp_ptr;
  1121.  
  1122.   if (adj->value < 0.0)
  1123.     {
  1124.       scalesrc = abs ((gint) adj->value - 1);
  1125.       scaledest = 1;
  1126.     }
  1127.   else
  1128.     {
  1129.       scaledest = abs ((gint) adj->value + 1);
  1130.       scalesrc = 1;
  1131.     }
  1132.  
  1133.   iwd->block_adj_sig = TRUE;
  1134.   change_scale (gdisp, (scaledest * 100) + scalesrc);
  1135.   iwd->block_adj_sig = FALSE;
  1136. }
  1137.  
  1138. static GtkWidget *
  1139. nav_create_button_area (InfoDialog *info_win)
  1140. {
  1141.   GtkWidget  *hbox1;  
  1142.   GtkWidget  *vbox1;
  1143.   GtkWidget  *button;
  1144.   GtkWidget  *hscale1;
  1145.   GtkWidget  *label1;
  1146.   GtkObject  *adjustment;
  1147.   NavWinData *iwd;
  1148.   gchar       scale_str[MAX_SCALE_BUF];
  1149.  
  1150.   iwd = (NavWinData *) info_win->user_data;
  1151.  
  1152.   hbox1 = gtk_hbox_new (FALSE, 0);
  1153.   gtk_widget_show (hbox1);
  1154.  
  1155.   button = gimp_pixmap_button_new (zoom_out_xpm, NULL);
  1156.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1157.   gtk_signal_connect (GTK_OBJECT (button), "clicked", 
  1158.               GTK_SIGNAL_FUNC (navwindow_zoomout),
  1159.               (gpointer) info_win->user_data);
  1160.   gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, FALSE, 0);
  1161.   gtk_widget_show (button);
  1162.  
  1163.   vbox1 = gtk_vbox_new (FALSE, 0);
  1164.   gtk_widget_show (vbox1);
  1165.   gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0);
  1166.  
  1167.   /*  user zoom ratio  */
  1168.   g_snprintf (scale_str, MAX_SCALE_BUF, "%d:%d",
  1169.           SCALEDEST (((GDisplay *)iwd->gdisp_ptr)), 
  1170.           SCALESRC (((GDisplay *)iwd->gdisp_ptr)));
  1171.   
  1172.   label1 = gtk_label_new (scale_str);
  1173.   gtk_widget_show (label1);
  1174.   iwd->zoom_label = label1;
  1175.   gtk_box_pack_start (GTK_BOX (hbox1), label1, TRUE, TRUE, 0);
  1176.  
  1177.   adjustment = gtk_adjustment_new (0.0, -15.0, 16.0, 1.0, 1.0, 1.0);
  1178.   hscale1 = gtk_hscale_new (GTK_ADJUSTMENT (adjustment));
  1179.   gtk_scale_set_digits (GTK_SCALE (hscale1), 0);
  1180.   iwd->zoom_adjustment = adjustment;
  1181.   gtk_widget_show (hscale1);
  1182.  
  1183.   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
  1184.               GTK_SIGNAL_FUNC (zoom_adj_changed),
  1185.               iwd);
  1186.  
  1187.   gtk_box_pack_start (GTK_BOX (vbox1), hscale1, TRUE, TRUE, 0);
  1188.   gtk_scale_set_draw_value (GTK_SCALE (hscale1), FALSE);
  1189.  
  1190.   button = gimp_pixmap_button_new (zoom_in_xpm, NULL);
  1191.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1192.   gtk_signal_connect (GTK_OBJECT (button), "clicked", 
  1193.               GTK_SIGNAL_FUNC (navwindow_zoomin),
  1194.               (gpointer) info_win->user_data); 
  1195.   gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, FALSE, 0);
  1196.   gtk_widget_show (button);
  1197.  
  1198.   return vbox1;
  1199. }
  1200.  
  1201. static GtkWidget *
  1202. create_preview_containers (NavWinData *iwd,
  1203.                GtkWidget  *shell)
  1204. {
  1205.   GtkWidget *hbox1;
  1206.   GtkWidget *vbox1;
  1207.   GtkWidget *alignment;
  1208.  
  1209.   hbox1 = gtk_hbox_new (FALSE, 0);
  1210.   gtk_widget_show (hbox1);
  1211.  
  1212.   vbox1 = gtk_vbox_new (FALSE, 0);
  1213.   gtk_widget_show (vbox1);
  1214.  
  1215.   gtk_widget_realize (shell);
  1216.  
  1217.   /* need gc to draw the preview sqr with */
  1218.   iwd->gc = gdk_gc_new (shell->window);
  1219.   gdk_gc_set_function (iwd->gc, GDK_INVERT);
  1220.   gdk_gc_set_line_attributes (iwd->gc, BORDER_PEN_WIDTH, 
  1221.                   GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_ROUND);
  1222.  
  1223.   alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  1224.   iwd->previewAlign = alignment;
  1225.   gtk_widget_show (alignment);
  1226.   
  1227.   /* Create the preview in which to draw the thumbnail image */
  1228.  
  1229.   create_preview_widget (iwd);
  1230.  
  1231.   gtk_box_pack_start (GTK_BOX (hbox1), alignment, TRUE, TRUE, 0);
  1232.   gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0);
  1233.  
  1234.   return vbox1;
  1235. }
  1236.  
  1237. static GtkWidget *
  1238. info_window_image_preview_new (InfoDialog *info_win)
  1239. {
  1240.   GtkWidget *button_area;
  1241.   GtkWidget *vbox1;
  1242.  
  1243.   NavWinData *iwd;
  1244.  
  1245.   iwd = (NavWinData *) info_win->user_data;
  1246.  
  1247.   vbox1 = create_preview_containers (iwd, info_win->shell);
  1248.  
  1249.   /* This one has (may) have the buttons in */
  1250.   button_area = nav_create_button_area (info_win);
  1251.   gtk_box_pack_start (GTK_BOX (vbox1), button_area, TRUE, TRUE, 0);
  1252.  
  1253.   return vbox1;
  1254. }
  1255.  
  1256. NavWinData *
  1257. create_dummy_iwd (void       *gdisp_ptr,
  1258.           NavWinType  ptype)
  1259. {
  1260.   NavWinData *iwd;
  1261.  
  1262.   iwd = (NavWinData *) g_malloc (sizeof (NavWinData));
  1263.   iwd->ptype               = ptype;
  1264.   iwd->info_win            = NULL;
  1265.   iwd->showingPreview      = TRUE;
  1266.   iwd->installedDirtyTimer = FALSE;
  1267.   iwd->preview             = NULL;
  1268.   iwd->zoom_label          = NULL;
  1269.   iwd->zoom_adjustment     = NULL;
  1270.   iwd->gdisp_ptr           = gdisp_ptr;
  1271.   iwd->dispx               = -1;
  1272.   iwd->dispy               = -1;
  1273.   iwd->dispwidth           = -1;
  1274.   iwd->dispheight          = -1;
  1275.   iwd->imagewidth          = -1;
  1276.   iwd->imageheight         = -1;
  1277.   iwd->sq_grabbed          = FALSE;
  1278.   iwd->ratio               = 1.0;
  1279.   iwd->block_window_marker = FALSE;
  1280.   iwd->nav_preview_width   = 
  1281.     (nav_preview_size < 0 || nav_preview_size > 256) ? 
  1282.     NAV_PREVIEW_WIDTH : nav_preview_size;
  1283.   iwd->nav_preview_height  = 
  1284.     (nav_preview_size < 0 || nav_preview_size > 256) ? 
  1285.     NAV_PREVIEW_HEIGHT : nav_preview_size;
  1286.   iwd->block_adj_sig       = FALSE;
  1287.   iwd->frozen              = FALSE;
  1288.   iwd->timer_id            = 0;
  1289.   
  1290.   return(iwd);
  1291. }
  1292.  
  1293. /* Create a version of the nav window that follows the active
  1294.  * image.
  1295.  */
  1296.  
  1297. static InfoDialog *nav_window_auto = NULL;
  1298.  
  1299. static gchar *
  1300. nav_window_title(GDisplay   *gdisp)
  1301. {
  1302.   gchar *title;
  1303.   gchar *title_buf;
  1304.  
  1305.   title = g_basename (gimage_filename (gdisp->gimage));
  1306.  
  1307.   /*  create the info dialog  */
  1308.   title_buf = g_strdup_printf (_("Navigation: %s-%d.%d"), 
  1309.                    title,
  1310.                    pdb_image_to_id (gdisp->gimage),
  1311.                    gdisp->instance);
  1312.  
  1313.   return title_buf;
  1314. }
  1315.  
  1316. static void
  1317. nav_window_change_display (GimpContext *context, /* NOT USED */
  1318.                GDisplay    *newdisp,
  1319.                gpointer     data /* Not used */)
  1320. {
  1321.   GDisplay   *gdisp = newdisp;
  1322.   GDisplay   *old_gdisp;
  1323.   GimpImage  *gimage;
  1324.   NavWinData *iwd;
  1325.   gchar      *title_buf;
  1326.  
  1327.   iwd = (NavWinData *)nav_window_auto->user_data;
  1328.   old_gdisp = (GDisplay *) iwd->gdisp_ptr;
  1329.  
  1330.   if (!nav_window_auto || gdisp == old_gdisp || !gdisp)
  1331.     {
  1332.       return;
  1333.     }
  1334.  
  1335.   gtk_widget_set_sensitive (nav_window_auto->vbox, TRUE);
  1336.   iwd->frozen = FALSE;
  1337.  
  1338.   title_buf = nav_window_title (gdisp);
  1339.  
  1340.   gtk_window_set_title (GTK_WINDOW (nav_window_auto->shell), title_buf);
  1341.  
  1342.   g_free (title_buf);
  1343.  
  1344.   gimage = gdisp->gimage;
  1345.  
  1346.   if (gimage && gimp_set_have (image_context, gimage))
  1347.     {
  1348.       iwd->gdisp_ptr = gdisp;
  1349.  
  1350.       /* Update preview to new display */
  1351.       nav_window_preview_resized (nav_window_auto);
  1352.  
  1353.       /* Tie into the dirty signal so we can update the preview */
  1354.       /* provided we haven't already */
  1355.       if (!gtk_object_get_data (GTK_OBJECT (gdisp->gimage),
  1356.                 "nav_handlers_installed"))
  1357.     {
  1358.       gtk_signal_connect_after (GTK_OBJECT (gdisp->gimage), "dirty",
  1359.                     GTK_SIGNAL_FUNC (nav_image_need_update),
  1360.                     iwd);
  1361.       
  1362.       /* Also clean signal so undos get caught as well..*/
  1363.       gtk_signal_connect_after (GTK_OBJECT (gdisp->gimage), "clean",
  1364.                     GTK_SIGNAL_FUNC (nav_image_need_update),
  1365.                     iwd);
  1366.       gtk_object_set_data (GTK_OBJECT (gdisp->gimage),
  1367.                    "nav_handlers_installed",iwd);
  1368.     }
  1369.     }
  1370. }
  1371.  
  1372. void
  1373. nav_window_follow_auto (void)
  1374. {
  1375.   GDisplay   *gdisp;
  1376.   NavWinData *iwd;
  1377.  
  1378.   gdisp = gdisplay_active (); 
  1379.   
  1380.   if (!gdisp) 
  1381.     return;
  1382.  
  1383.   if(!nav_window_auto)
  1384.     {
  1385.       nav_window_auto = nav_window_create ((void *) gdisp);
  1386.       gtk_signal_connect (GTK_OBJECT (gimp_context_get_user ()), 
  1387.               "display_changed",
  1388.               GTK_SIGNAL_FUNC (nav_window_change_display), 
  1389.               NULL);
  1390.     }
  1391.  
  1392.   nav_dialog_popup (nav_window_auto);
  1393.  
  1394.   iwd = (NavWinData *) nav_window_auto->user_data;
  1395.   gtk_widget_set_sensitive (nav_window_auto->vbox, TRUE);
  1396.   iwd->frozen = FALSE;
  1397. }
  1398.  
  1399.  
  1400. InfoDialog *
  1401. nav_window_create (void *gdisp_ptr)
  1402. {
  1403.   InfoDialog *info_win;
  1404.   GDisplay   *gdisp;
  1405.   NavWinData *iwd;
  1406.   GtkWidget  *container;
  1407.   gchar      *title_buf;
  1408.   GimpImageBaseType type;
  1409.  
  1410.   gdisp = (GDisplay *) gdisp_ptr;
  1411.   
  1412.   type = gimage_base_type (gdisp->gimage);
  1413.  
  1414.   title_buf = nav_window_title(gdisp);
  1415.  
  1416.   info_win = info_dialog_new (title_buf,
  1417.                   gimp_standard_help_func,
  1418.                   "dialogs/navigation_window.html");
  1419.   g_free (title_buf);
  1420.  
  1421.   dialog_register (info_win->shell);
  1422.  
  1423.   /*  create the action area  */
  1424.   gimp_dialog_create_action_area (GTK_DIALOG (info_win->shell),
  1425.  
  1426.                   _("Close"), nav_window_close_callback,
  1427.                   info_win, NULL, NULL, TRUE, FALSE,
  1428.  
  1429.                   NULL);
  1430.  
  1431.   gtk_signal_connect (GTK_OBJECT (info_win->shell), "destroy",
  1432.               (GtkSignalFunc) nav_window_destroy_callback,
  1433.               info_win);
  1434.  
  1435.   iwd = create_dummy_iwd (gdisp_ptr, NAV_WINDOW);
  1436.   info_win->user_data = iwd;
  1437.   iwd->info_win = info_win;
  1438.  
  1439.   /* Add preview */
  1440.   container = info_window_image_preview_new (info_win);
  1441.   gtk_table_attach_defaults (GTK_TABLE (info_win->info_table), container, 
  1442.                   0, 2, 0, 1); 
  1443.  
  1444.   /* Tie into the dirty signal so we can update the preview */
  1445.   gtk_signal_connect_after (GTK_OBJECT (gdisp->gimage), "dirty",
  1446.                 GTK_SIGNAL_FUNC(nav_image_need_update),iwd);
  1447.  
  1448.   /* Also clean signal so undos get caught as well..*/
  1449.   gtk_signal_connect_after (GTK_OBJECT (gdisp->gimage), "clean",
  1450.                 GTK_SIGNAL_FUNC(nav_image_need_update),iwd);
  1451.  
  1452.  
  1453.   /* Mark the image as having the handlers installed...
  1454.    */
  1455.   gtk_object_set_data (GTK_OBJECT (gdisp->gimage), 
  1456.                "nav_handlers_installed", iwd);
  1457.   
  1458.   return info_win;
  1459. }
  1460.  
  1461. void
  1462. nav_window_update_window_marker (InfoDialog *info_win)
  1463. {
  1464.   NavWinData *iwd;
  1465.  
  1466.   /* So this functions works both ways..
  1467.    * it will come in here with info_win == null
  1468.    * if the auto mode is on...
  1469.    */
  1470.  
  1471.   if (!info_win && nav_window_auto)
  1472.     {
  1473.       iwd = (NavWinData *) nav_window_auto->user_data;
  1474.       if(iwd->frozen)
  1475.     return;
  1476.  
  1477.       nav_window_update_window_marker (nav_window_auto);
  1478.  
  1479.       return;
  1480.     }
  1481.  
  1482.   if (!info_win)
  1483.     return;
  1484.  
  1485.   iwd = (NavWinData *) info_win->user_data;
  1486.  
  1487.   if (!iwd || 
  1488.       iwd->showingPreview == FALSE || 
  1489.       iwd->block_window_marker == TRUE)
  1490.     return;
  1491.  
  1492.   update_zoom_label (iwd);
  1493.   update_zoom_adjustment (iwd);
  1494.  
  1495.   /* Undraw old size */
  1496.   nav_window_draw_sqr (iwd,
  1497.                FALSE,
  1498.                iwd->dispx, iwd->dispy,
  1499.                iwd->dispwidth, iwd->dispheight);
  1500.  
  1501.   /* Update to new size */
  1502.   nav_window_disp_area (iwd, iwd->gdisp_ptr);
  1503.  
  1504.   /* and redraw */
  1505.   nav_window_draw_sqr (iwd,
  1506.                FALSE,
  1507.                iwd->dispx, iwd->dispy,
  1508.                iwd->dispwidth, iwd->dispheight);
  1509. }
  1510.  
  1511. void
  1512. nav_dialog_popup (InfoDialog *idialog)
  1513. {
  1514.   NavWinData *iwd;
  1515.  
  1516.   if (!idialog)
  1517.     return;
  1518.  
  1519.   iwd = (NavWinData *) idialog->user_data;
  1520.   iwd->showingPreview = TRUE;
  1521.  
  1522.   if (! GTK_WIDGET_VISIBLE (idialog->shell))
  1523.     {
  1524.       gtk_widget_show (idialog->shell);
  1525.       nav_window_update_preview_blank (iwd); 
  1526.       nav_window_update_window_marker (idialog);
  1527.       iwd->timer_id = 
  1528.     gtk_timeout_add (PREVIEW_UPDATE_TIMEOUT,
  1529.              (GtkFunction) nav_preview_update_do_timer,
  1530.              (gpointer) iwd); 
  1531.     }
  1532.  
  1533.   gdk_window_raise (GTK_WIDGET (idialog->shell)->window);
  1534. }
  1535.  
  1536. /* Chose the first image.. */
  1537. static void
  1538. gimlist_cb (gpointer im, 
  1539.         gpointer data)
  1540. {
  1541.   GSList **list_ptr;
  1542.  
  1543.   list_ptr = (GSList **) data;
  1544.   *list_ptr = g_slist_prepend (*list_ptr, im);
  1545. }
  1546.  
  1547. static GDisplay *
  1548. nav_window_get_gdisp (void)
  1549. {
  1550.   GSList    *list    = NULL;
  1551.   GSList    *listPtr = NULL;
  1552.   GDisplay  *gdisp   = NULL;
  1553.   GimpImage *gimage;
  1554.  
  1555.   gimage_foreach (gimlist_cb, &list);
  1556.  
  1557.   if (!list)
  1558.     return NULL;
  1559.   
  1560.   /* Find first valid image */
  1561.   for (listPtr = list; listPtr; listPtr = g_slist_next (listPtr))
  1562.     {
  1563.       gimage = GIMP_IMAGE (listPtr->data);
  1564.       gdisp = gdisplays_check_valid (NULL,gimage);
  1565.       if (gdisp)
  1566.     break;
  1567.     }
  1568.   
  1569.   g_slist_free (list);
  1570.  
  1571.   return (gdisp);
  1572. }
  1573.  
  1574.  
  1575. void
  1576. nav_window_free (GDisplay   *del_gdisp,
  1577.          InfoDialog *info_win)
  1578. {
  1579.   NavWinData *iwd;
  1580.  
  1581.   /* So this functions works both ways..
  1582.    * it will come in here with info_win == null
  1583.    * if the auto mode is on...
  1584.    */
  1585.  
  1586.   if (!info_win)
  1587.     {
  1588.       if (nav_window_auto != NULL)
  1589.     {
  1590.       GDisplay * gdisp;
  1591.  
  1592.       iwd = (NavWinData *) nav_window_auto->user_data;
  1593.  
  1594.       /* Only freeze if we are displaying the image we have deleted */
  1595.       if ((GDisplay *) iwd->gdisp_ptr != del_gdisp)
  1596.         return;
  1597.  
  1598.       if (iwd->timer_id)
  1599.         gtk_timeout_remove (iwd->timer_id);
  1600.  
  1601.       iwd->timer_id = 0;
  1602.  
  1603.       gdisp = nav_window_get_gdisp ();
  1604.  
  1605.       if (gdisp)
  1606.         nav_window_change_display (NULL, gdisp, NULL);
  1607.       else
  1608.         {
  1609.           /* Clear window and freeze */
  1610.           iwd->frozen = TRUE;
  1611.           nav_window_update_preview_blank (iwd); 
  1612.           gtk_window_set_title (GTK_WINDOW (nav_window_auto->shell), 
  1613.                     _("Navigation: No Image"));
  1614.  
  1615.           gtk_widget_set_sensitive (nav_window_auto->vbox, FALSE);
  1616.           iwd->gdisp_ptr = NULL;
  1617.           gtk_widget_hide (GTK_WIDGET (nav_window_auto->shell));
  1618.         }
  1619.     }
  1620.       return;
  1621.     }
  1622.  
  1623.   /* We are actually freeing a window here so remove any timers left. */
  1624.   iwd = (NavWinData *)info_win->user_data;
  1625.   if (iwd->timer_id)
  1626.     gtk_timeout_remove (iwd->timer_id);
  1627.  
  1628.   g_free (info_win->user_data);
  1629.   info_dialog_free (info_win);
  1630. }
  1631.  
  1632.  
  1633. /* nav popup ...
  1634.  * should share code with the nav_window dialog since they are 
  1635.  * essentially the same.
  1636.  */
  1637.  
  1638. void 
  1639. nav_popup_click_handler (GtkWidget      *widget, 
  1640.              GdkEventButton *event, 
  1641.              gpointer        data)
  1642. {
  1643.   GdkEventButton *bevent;
  1644.   GDisplay       *gdisp = data;
  1645.   NavWinData     *iwp;  /* dummy shorter version for the popups */
  1646.   gint x, y;
  1647.   gint x_org, y_org;
  1648.   gint scr_w, scr_h;
  1649.  
  1650.   bevent = (GdkEventButton *)event;
  1651.  
  1652.   if(!gdisp->nav_popup)
  1653.     {
  1654.       /* popup a simplfied window with the nav box in it */
  1655.       GtkWidget *frame;
  1656.       GtkWidget *vbox;
  1657.  
  1658.       iwp = create_dummy_iwd (gdisp, NAV_POPUP); 
  1659.       gdisp->nav_popup = gtk_window_new (GTK_WINDOW_POPUP);
  1660.       gtk_widget_set_events (gdisp->nav_popup, PREVIEW_MASK);
  1661.  
  1662.       gtk_window_set_policy (GTK_WINDOW (gdisp->nav_popup),
  1663.                  FALSE, FALSE, TRUE);
  1664.       frame = gtk_frame_new (NULL);
  1665.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
  1666.       gtk_container_add (GTK_CONTAINER (gdisp->nav_popup), frame);
  1667.       gtk_widget_show (frame);
  1668.  
  1669.       vbox = create_preview_containers (iwp,gdisp->nav_popup);
  1670.       gtk_widget_set_extension_events (iwp->preview, GDK_EXTENSION_EVENTS_ALL);
  1671.  
  1672.       gtk_container_add (GTK_CONTAINER (frame), vbox);
  1673.       gtk_object_set_data (GTK_OBJECT (gdisp->nav_popup),"navpop_prt",
  1674.                (gpointer) iwp);
  1675.       nav_window_disp_area (iwp, iwp->gdisp_ptr);
  1676.     }
  1677.   else
  1678.     {
  1679.       gtk_widget_hide (gdisp->nav_popup);
  1680.       iwp = (NavWinData *) gtk_object_get_data (GTK_OBJECT (gdisp->nav_popup), 
  1681.                         "navpop_prt");
  1682.       nav_window_disp_area (iwp, iwp->gdisp_ptr);
  1683.       nav_window_update_preview (iwp); 
  1684.     }
  1685.  
  1686.   /* decide where to put the popup */
  1687.   gdk_window_get_origin (widget->window, &x_org, &y_org);
  1688.  
  1689.   scr_w = gdk_screen_width ();
  1690.   scr_h = gdk_screen_height ();
  1691.  
  1692.   x = x_org + bevent->x - iwp->dispx - 
  1693.     ((iwp->dispwidth - BORDER_PEN_WIDTH + 1) * 0.5) - 2;
  1694.   y = y_org + bevent->y - iwp->dispy - 
  1695.     ((iwp->dispheight - BORDER_PEN_WIDTH + 1)* 0.5) - 2;
  1696.  
  1697.   /* If the popup doesn't fit into the screen, we have a problem.
  1698.    * We move the popup onscreen and risk that the pointer is not
  1699.    * in the square representing the viewable area anymore. Moving
  1700.    * the pointer will make the image scroll by a large amount,
  1701.    * but then it works as usual. Probably better than a popup that
  1702.    * is completely unusable in the lower right of the screen.
  1703.    *
  1704.    * Warping the pointer would be another solution ... 
  1705.    */
  1706.   x = (x < 0) ? 0 : x;
  1707.   y = (y < 0) ? 0 : y;
  1708.   x = (x + iwp->pwidth > scr_w) ? scr_w - iwp->pwidth - 2: x;
  1709.   y = (y + iwp->pheight > scr_h) ? scr_h - iwp->pheight - 2: y;
  1710.  
  1711.   gtk_widget_popup (gdisp->nav_popup, x, y);
  1712.   gdk_flush();
  1713.  
  1714.   /* fill in then set up handlers for mouse motion etc */
  1715.   iwp->motion_offsetx = (iwp->dispwidth  - BORDER_PEN_WIDTH + 1) * 0.5;
  1716.   iwp->motion_offsety = (iwp->dispheight - BORDER_PEN_WIDTH + 1) * 0.5;
  1717.  
  1718.   if(GTK_WIDGET_VISIBLE(iwp->preview))
  1719.     nav_window_grab_pointer (iwp, iwp->preview);
  1720. }
  1721.  
  1722. void
  1723. nav_popup_free (GtkWidget *nav_popup)
  1724. {
  1725.   gtk_widget_destroy (nav_popup);
  1726. }
  1727.  
  1728. void 
  1729. nav_window_preview_resized (InfoDialog *idialog)
  1730. {
  1731.   NavWinData *iwd;
  1732.  
  1733.   if (!idialog)
  1734.     return;
  1735.  
  1736.   iwd = (NavWinData *)idialog->user_data;
  1737.  
  1738.   /* force regeneration of the widgets */
  1739.   /* bit of a fiddle... could cause if the image really is 1x1
  1740.    * but the preview would not really matter in that case.
  1741.    */
  1742.   iwd->imagewidth = 1;
  1743.   iwd->imageheight = 1;
  1744.  
  1745.   iwd->nav_preview_width = 
  1746.     (nav_preview_size < 0 || nav_preview_size > 256) ? 
  1747.     NAV_PREVIEW_WIDTH : nav_preview_size;
  1748.   iwd->nav_preview_height = 
  1749.     (nav_preview_size < 0 || nav_preview_size > 256) ? 
  1750.     NAV_PREVIEW_HEIGHT : nav_preview_size;
  1751.  
  1752.   nav_window_update_window_marker (idialog); 
  1753. }
  1754.  
  1755. void 
  1756. nav_window_popup_preview_resized (GtkWidget **widget)
  1757. {
  1758.   NavWinData *iwp;  /* dummy shorter version for the popups */
  1759.  
  1760.   iwp = (NavWinData *) gtk_object_get_data (GTK_OBJECT (*widget), 
  1761.                         "navpop_prt");
  1762.  
  1763.   g_free (iwp);
  1764.  
  1765.   gtk_widget_destroy (*widget);
  1766.  
  1767.   *widget = NULL;
  1768. }
  1769.