Logo Search packages:      
Sourcecode: vertex version File versions

imgviewcrop.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include "guiutils.h"
#include "imgview.h"
#include "imgviewcrop.h"

#include "images/icon_cut_20x20.xpm"
#include "images/icon_cancel_20x20.xpm"


/* Callbacks. */
static gint ImgViewCropDialogCloseCB(
        GtkWidget *widget, GdkEvent *event, gpointer data
);
static void ImgViewCropDialogDestroyCB(GtkObject *object, gpointer data);
static void ImgViewCropDialogCropCB(GtkWidget *widget, gpointer data);
static void ImgViewCropDialogCancelCB(GtkWidget *widget, gpointer data);

/* Utilities. */
static void ImgViewCropDialogCrop(
        imgview_struct *iv, gint x, gint y, gint width, gint height
);

/* Public. */
imgview_crop_dialog_struct *ImgViewCropDialogNew(
        imgview_struct *iv
);
void ImgViewCropDialogMapValues(
        imgview_crop_dialog_struct *cd,
        gint x0, gint x1,
        gint y0, gint y1
);
void ImgViewCropDialogMap(imgview_crop_dialog_struct *cd);
void ImgViewCropDialogUnmap(imgview_crop_dialog_struct *cd);
void ImgViewCropDialogDelete(imgview_crop_dialog_struct *cd);


#define MAX(a,b)  (((a) > (b)) ? (a) : (b))
#define MIN(a,b)  (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define ABSOLUTE(x)     (((x) < 0) ? ((x) * -1) : (x))

#define BTN_WIDTH (100 + (2 * 3))
#define BTN_HEIGHT      (30 + (2 * 3))

#define DEF_TITLE "Crop Selection"


/*
 *    Close callback.
 */
static gint ImgViewCropDialogCloseCB(
        GtkWidget *widget, GdkEvent *event, gpointer data
)
{
      ImgViewCropDialogCancelCB(widget, data);
      return(TRUE);
}

/*
 *    Destroy callback.
 */
static void ImgViewCropDialogDestroyCB(GtkObject *object, gpointer data)
{
      return;
}

/*
 *    Crop callback.
 */
static void ImgViewCropDialogCropCB(GtkWidget *widget, gpointer data)
{
      static gboolean reenterent = FALSE;
        imgview_struct *iv;
        imgview_crop_dialog_struct *cd = (imgview_crop_dialog_struct *)data;
        if(cd == NULL)
            return;

        iv = IMGVIEW(cd->imgview);
        if(iv == NULL)
            return;

      if(reenterent)
          return;
      else
          reenterent = TRUE;

        /* Reset crop marks on image viewer by marking its crop as
         * undefined.
         */
        iv->crop_flags &= ~IMGVIEW_CROP_DEFINED;

        /* Perform crop procedure, this will cause the image viewer to
       * load a new cropped image and redraw itself.
       */
      ImgViewCropDialogCrop(iv, cd->x, cd->y, cd->width, cd->height);

        /* Unmap crop dialog. */
        ImgViewCropDialogUnmap(cd);

      reenterent = FALSE;
}

/*
 *    Cancel callback.
 */
static void ImgViewCropDialogCancelCB(GtkWidget *widget, gpointer data)
{
      static gboolean reenterent = FALSE;
      imgview_struct *iv;
      imgview_crop_dialog_struct *cd = (imgview_crop_dialog_struct *)data;
      if(cd == NULL)
          return;

        iv = IMGVIEW(cd->imgview);
        if(iv == NULL)
            return;

        if(reenterent)
            return;
        else
            reenterent = TRUE;

      /* Reset crop marks on image viewer by marking its crop as
       * undefined.
       */
      iv->crop_flags &= ~IMGVIEW_CROP_DEFINED;

      /* Redraw the image viewer and update its menus. */
      ImgViewDraw(iv);
      ImgViewUpdateMenus(iv);


      /* Unmap crop dialog. */
      ImgViewCropDialogUnmap(cd);

      reenterent = FALSE;
}

/*
 *    Crops the image on the given image viewer. A new image is
 *    created and the current image on the image viewer is read to it
 *    at a smaller (cropped) size.
 *
 *    The image viewer is then instructed to load the new image,
 *    thus automatically destroying the old image.
 */
static void ImgViewCropDialogCrop(
      imgview_struct *iv, gint x, gint y, gint width, gint height
)
{
      imgview_image_struct *src_img;
      gint swidth, sheight, sbpl;
      const guint8 *src_data, *src_ptr;

      gint tx, ty, twidth, theight, tbpl;
      guint8 *tar_data, *tar_ptr;

      gint bc, bpp, format;


      if((iv == NULL) || (width < 1) || (height < 1))
          return;

      /* Get source image geometry. */
      src_img = iv->orig_img;
      if(src_img == NULL)
          return;

      bpp = src_img->bpp;           /* Tar and src use same bpp. */
      sbpl = src_img->bpl;
      src_data = src_img->mem;
      swidth = src_img->width;
      sheight = src_img->height;
      if((swidth < 1) || (sheight < 1) || (bpp < 1) || (src_data == NULL))
          return;

      /* Get format based on bpp. */
      switch(bpp)
      {
        case 4:
          format = IMGVIEW_FORMAT_RGBA;
          break;
        case 3:
          format = IMGVIEW_FORMAT_RGB;
          break;
        case 2:
          format = IMGVIEW_FORMAT_GREYSCALE16;
          break;
        case 1:
          format = IMGVIEW_FORMAT_GREYSCALE8;
          break;
        default:
          return;
          break;
      }

      /* Reduce crop geometry size to fit in source image. */
      if((x + width) > swidth)
          width = swidth - x;
        if((y + height) > sheight)
            height = sheight - y;


      /* Get target image geometry. */
      tx = x;
      ty = y;
      twidth = MIN(width, swidth);
      theight = MIN(height, sheight);

      /* Sanitize crop coordinates so they lie within the source image. */
      if(tx > (swidth - twidth))
          tx = swidth - twidth;
        if(ty > (sheight - theight))
            ty = sheight - theight;
      if(tx < 0)
          tx = 0;
      if(ty < 0)
          ty = 0;

      if((twidth < 1) || (theight < 1))
          return;

      tbpl = twidth * bpp;

      /* Note x and y are now garbage. */


      /* Allocate target image. */
      tar_data = (guint8 *)g_malloc(tbpl * theight);
      if(tar_data == NULL)
          return;

      /* Iterate through target image. */
      for(y = 0; y < theight; y++)
      {
          for(x = 0; x < twidth; x++)
          {
            src_ptr = &src_data[
                ((ty + y) * sbpl) + ((tx + x) * bpp)
            ];
            tar_ptr = &tar_data[
                (y * tbpl) + (x * bpp)
            ];

            for(bc = 0; bc < bpp; bc++)
                *tar_ptr++ = *src_ptr++;
          }
      }

      /* Source image data should now be considered invalid when we
       * instruct the image viewer to load the new cropped image data.
       */
      src_data = NULL;
      ImgViewLoad(
          iv, twidth, theight, tbpl, format, tar_data
      );

      /* Deallocate target image data, we don't need it anymore. */
      g_free(tar_data);
      tar_data = NULL;

      /* Call image viewer's changed callback. */
      if(iv->changed_cb != NULL)
          iv->changed_cb(
            iv, iv->orig_img, iv->changed_data
          );
}


/*
 *    Creates a new crop dialog.
 */
imgview_crop_dialog_struct *ImgViewCropDialogNew(
        imgview_struct *iv
)
{
        gint    width = 320,
            height = -1,
            bw = BTN_WIDTH,
                bh = BTN_HEIGHT,
            border_major = 5,
            border_minor = 2;
        GdkWindow *window;
        GtkAccelGroup *accelgrp;
        GtkWidget *w, *parent, *parent2;
        GtkWidget *main_vbox;
      imgview_crop_dialog_struct *cd = (imgview_crop_dialog_struct *)g_malloc0(
          sizeof(imgview_crop_dialog_struct)
      );
      if(cd == NULL)
          return(NULL);

      /* Reset values. */
      cd->map_state = FALSE;
      cd->imgview = iv;

      /* Create keyboard accelerator group. */
      cd->accelgrp = accelgrp = gtk_accel_group_new();

        /* Create toplevel. */
      cd->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
        gtk_widget_set_usize(w, width, height);
        gtk_widget_realize(w);
        gtk_window_set_title(GTK_WINDOW(w), DEF_TITLE);
        window = w->window;
        if(window != NULL)
        {
            gdk_window_set_decorations(
                window,
                GDK_DECOR_TITLE | GDK_DECOR_MENU | GDK_DECOR_MINIMIZE
            );
            gdk_window_set_functions(
                window,
                GDK_FUNC_MOVE | GDK_FUNC_MINIMIZE | GDK_FUNC_CLOSE
            );
            GUISetWMIcon(window, (u_int8_t **)icon_cut_20x20_xpm);
        }
        gtk_signal_connect(
            GTK_OBJECT(w), "delete_event",
            GTK_SIGNAL_FUNC(ImgViewCropDialogCloseCB),
            (gpointer)cd
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "destroy",
            GTK_SIGNAL_FUNC(ImgViewCropDialogDestroyCB),
            (gpointer)cd
        );
        gtk_container_border_width(GTK_CONTAINER(w), 0);
        gtk_accel_group_attach(accelgrp, GTK_OBJECT(w));
        if(ImgViewToplevelIsWindow(iv))
      {
          GtkWidget *ref_toplevel = ImgViewGetToplevelWidget(iv);
          if(ref_toplevel != NULL)
          {
/* Do not set modal as user may want to work with image viewer
 * some more and key events still need to be sent to the image
 * viewer's view window.
 */
/*          gtk_window_set_modal(GTK_WINDOW(w), TRUE); */
            gtk_window_set_transient_for(
                GTK_WINDOW(w), GTK_WINDOW(ref_toplevel)
            );
          }
      }
      parent = w;

        main_vbox = w = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(parent), w);
        gtk_widget_show(w);
        parent = w;

        w = gtk_vbox_new(FALSE, border_major);
        gtk_container_border_width(GTK_CONTAINER(w), border_major);
        gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
        gtk_widget_show(w);
        parent2 = w;

      w = gtk_hbox_new(FALSE, border_minor);
        gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
        gtk_widget_show(w);
      parent2 = w;

      /* Crop geometry label. */
      cd->label = w = gtk_label_new("");
      gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
      gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
        gtk_widget_show(w);


        w = gtk_hseparator_new();
        gtk_box_pack_start(GTK_BOX(main_vbox), w, FALSE, FALSE, 0);
        gtk_widget_show(w);

        /* Buttons. */
        w = gtk_hbox_new(TRUE, 0);
        gtk_box_pack_start(GTK_BOX(main_vbox), w, FALSE, FALSE, border_major);
        gtk_widget_show(w);
        parent2 = w;

        /* Crop button. */
      cd->crop_btn = w = GUIButtonPixmapLabelH(
            (u_int8_t **)icon_cut_20x20_xpm, "Crop", NULL
        );
        gtk_widget_set_usize(w, bw, bh);
        GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
        gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(ImgViewCropDialogCropCB),
            (gpointer)cd
        );
        gtk_accel_group_add(
            accelgrp, ' ', 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_accel_group_add(
            accelgrp, GDK_KP_Space, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_accel_group_add(
            accelgrp, GDK_Return, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_accel_group_add(
            accelgrp, GDK_3270_Enter, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_accel_group_add(
            accelgrp, GDK_KP_Enter, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_accel_group_add(
            accelgrp, GDK_ISO_Enter, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_widget_show(w);

        /* Cancel button. */
      cd->cancel_btn = w = GUIButtonPixmapLabelH(
            (u_int8_t **)icon_cancel_20x20_xpm, "Cancel", NULL
        );
        gtk_widget_set_usize(w, bw, bh);
        GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
        gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(ImgViewCropDialogCancelCB),
            (gpointer)cd
        );
        gtk_accel_group_add(
            accelgrp, GDK_Escape, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_widget_show(w);


      return(cd);
}

/*
 *    Maps the crop dialog with the specified crop rectangle.
 */
void ImgViewCropDialogMapValues(
        imgview_crop_dialog_struct *cd,
        gint x0, gint x1,
        gint y0, gint y1
)
{
      GtkWidget *w;
      imgview_struct *iv;


        if(cd == NULL)
            return;

      iv = IMGVIEW(cd->imgview);
      if(iv == NULL)
            return;

      cd->x = MIN(x0, x1);
      cd->y = MIN(y0, y1);
      cd->width = ABSOLUTE(x1 - x0);
      cd->height = ABSOLUTE(y1 - y0);

      /* Get crop geometry label. */
      w = cd->label;
      if(w != NULL)
      {
          gchar *buf = (gchar *)g_strdup_printf(
"X Origin: %i\n\
Y Origin: %i\n\
Width: %i\n\
Height: %i",
            cd->x, cd->y, cd->width, cd->height
          );
          gtk_label_set_text(GTK_LABEL(w), buf);
          g_free(buf);
      }

      /* Map crop dialog. */
      ImgViewCropDialogMap(cd);
}

/*
 *      Maps the image viewer crop dialog.
 */
void ImgViewCropDialogMap(imgview_crop_dialog_struct *cd)
{
        if(cd == NULL)
            return;

        if(!cd->map_state)
        {
            GtkWidget *w;

            w = cd->crop_btn;
            if(w != NULL)
                gtk_widget_grab_default(w);

          w = cd->toplevel;
            if(w != NULL)
            gtk_widget_show(w);
            cd->map_state = TRUE;
        }
}

/*
 *      Unmaps the image viewer crop dialog.
 */
void ImgViewCropDialogUnmap(imgview_crop_dialog_struct *cd)
{
        if(cd == NULL)
            return;

        if(cd->map_state)
        {
            GtkWidget *w = cd->toplevel;
            if(w != NULL)
                gtk_widget_hide(w);
            cd->map_state = FALSE;
        }
}

/*
 *    Deletes the given image viewer crop dialog.
 */
void ImgViewCropDialogDelete(imgview_crop_dialog_struct *cd)
{
        GtkWidget **w;


      if(cd == NULL)
          return;

        if(TRUE)
        {
#define DO_DESTROY_WIDGET     \
{ if((*w) != NULL) { gtk_widget_destroy(*w); *w = NULL; } }

            w = &cd->toplevel;
            DO_DESTROY_WIDGET

            if(cd->accelgrp != NULL)
            {
                gtk_accel_group_unref(cd->accelgrp);
                cd->accelgrp = NULL;
            }
#undef DO_DESTROY_WIDGET
      }

      /* Deallocate the structure itself. */
      g_free(cd);
}



Generated by  Doxygen 1.6.0   Back to index