home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / align_layers.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  13.7 KB  |  562 lines

  1. /* align_layers.c -- This is a plug-in for the GIMP (1.0's API)
  2.  * Author: Shuji Narazaki <narazaki@InetQ.or.jp>
  3.  * Time-stamp: <1999-12-18 05:48:38 yasuhiro>
  4.  * Version:  0.26
  5.  *
  6.  * Copyright (C) 1997-1998 Shuji Narazaki <narazaki@InetQ.or.jp>
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include "config.h"
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28.  
  29. #include <gtk/gtk.h>
  30.  
  31. #include <libgimp/gimp.h>
  32. #include <libgimp/gimpui.h>
  33.  
  34. #include "libgimp/stdplugins-intl.h"
  35.  
  36. #define    PLUG_IN_NAME "plug_in_align_layers"
  37. #define SHORT_NAME   "align_layers"
  38. #define SCALE_WIDTH  150
  39.  
  40. enum
  41. {
  42.   H_NONE,
  43.   H_COLLECT,
  44.   LEFT2RIGHT,
  45.   RIGHT2LEFT,
  46.   SNAP2HGRID
  47. };
  48.  
  49. enum
  50. {
  51.   H_BASE_LEFT,
  52.   H_BASE_CENTER,
  53.   H_BASE_RIGHT
  54. };
  55.  
  56. enum
  57. {
  58.   V_NONE,
  59.   V_COLLECT,
  60.   TOP2BOTTOM,
  61.   BOTTOM2TOP,
  62.   SNAP2VGRID
  63. };
  64.  
  65. enum
  66. {
  67.   V_BASE_TOP,
  68.   V_BASE_CENTER,
  69.   V_BASE_BOTTOM
  70. };
  71.  
  72. static void    query    (void);
  73. static void    run    (gchar   *name,
  74.              gint     nparams,
  75.              GimpParam  *param,
  76.              gint    *nreturn_vals,
  77.              GimpParam **return_vals);
  78.  
  79. static GimpPDBStatusType align_layers                   (gint32  image_id);
  80. static void        align_layers_get_align_offsets (gint32  drawable_id,
  81.                            gint      *x,
  82.                            gint      *y);
  83.  
  84. static gint align_layers_dialog      (void);
  85. static void align_layers_ok_callback (GtkWidget *widget,
  86.                       gpointer   data);
  87.  
  88. GimpPlugInInfo PLUG_IN_INFO =
  89. {
  90.   NULL,  /* init_proc  */
  91.   NULL,  /* quit_proc  */
  92.   query, /* query_proc */
  93.   run,   /* run_proc   */
  94. };
  95.  
  96.  
  97. /* dialog variables */
  98. typedef struct
  99. {
  100.   gint    h_style;
  101.   gint    h_base;
  102.   gint    v_style;
  103.   gint    v_base;
  104.   gint    ignore_bottom;
  105.   gint    base_is_bottom_layer;
  106.   gint    grid_size;
  107. } ValueType;
  108.  
  109. static ValueType VALS = 
  110. {
  111.   H_NONE,
  112.   H_BASE_LEFT,
  113.   V_NONE,
  114.   V_BASE_TOP,
  115.   TRUE,
  116.   FALSE,
  117.   10
  118. };
  119.  
  120. typedef struct 
  121. {
  122.   gint run;
  123. } Interface;
  124.  
  125. static Interface INTERFACE =
  126. {
  127.   FALSE
  128. };
  129.  
  130.  
  131. MAIN ()
  132.  
  133. static void
  134. query (void)
  135. {
  136.   static GimpParamDef args [] =
  137.   {
  138.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
  139.     { GIMP_PDB_IMAGE, "image", "Input image"},
  140.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable (not used)"},
  141.     { GIMP_PDB_INT32, "link-afteer-alignment", "Link the visible layers after alignment"},
  142.     { GIMP_PDB_INT32, "use-bottom", "use the bottom layer as the base of alignment"}
  143.   };
  144.   static gint nargs = sizeof (args) / sizeof (args[0]);
  145.  
  146.   gimp_install_procedure (PLUG_IN_NAME,
  147.               "Align visible layers",
  148.               "Align visible layers",
  149.               "Shuji Narazaki <narazaki@InetQ.or.jp>",
  150.               "Shuji Narazaki",
  151.               "1997",
  152.               N_("<Image>/Layers/Align Visible Layers..."),
  153.               "RGB*,GRAY*",
  154.               GIMP_PLUGIN,
  155.               nargs, 0,
  156.               args, NULL);
  157. }
  158.  
  159. static void
  160. run (gchar   *name,
  161.      gint     nparams,
  162.      GimpParam  *param,
  163.      gint    *nreturn_vals,
  164.      GimpParam **return_vals)
  165. {
  166.   static GimpParam    values[1];
  167.   GimpPDBStatusType    status = GIMP_PDB_EXECUTION_ERROR;
  168.   GimpRunModeType    run_mode;
  169.   gint        image_id, layer_num;
  170.   
  171.   run_mode = param[0].data.d_int32;
  172.   image_id = param[1].data.d_int32;
  173.  
  174.   *nreturn_vals = 1;
  175.   *return_vals = values;
  176.   
  177.   values[0].type = GIMP_PDB_STATUS;
  178.   values[0].data.d_status = status;
  179.  
  180.   switch ( run_mode )
  181.     {
  182.     case GIMP_RUN_INTERACTIVE:
  183.       INIT_I18N_UI();
  184.       gimp_image_get_layers (image_id, &layer_num);
  185.       if (layer_num < 2)
  186.     {
  187.       g_message (_("Align Visible Layers: there are too few layers."));
  188.       return;
  189.     }
  190.       gimp_get_data (PLUG_IN_NAME, &VALS);
  191.       if (! align_layers_dialog ())
  192.     return;
  193.       break;
  194.     case GIMP_RUN_NONINTERACTIVE:
  195.       INIT_I18N();
  196.       break;
  197.     case GIMP_RUN_WITH_LAST_VALS:
  198.       INIT_I18N();
  199.       gimp_get_data (PLUG_IN_NAME, &VALS);
  200.       break;
  201.     }
  202.  
  203.   status = align_layers (image_id);
  204.  
  205.   if (run_mode != GIMP_RUN_NONINTERACTIVE)
  206.     gimp_displays_flush ();
  207.   if (run_mode == GIMP_RUN_INTERACTIVE && status == GIMP_PDB_SUCCESS)
  208.     gimp_set_data (PLUG_IN_NAME, &VALS, sizeof (ValueType));
  209.  
  210.   values[0].type = GIMP_PDB_STATUS;
  211.   values[0].data.d_status = status;
  212. }
  213.  
  214. static GimpPDBStatusType
  215. align_layers (gint32 image_id)
  216. {
  217.   gint    layer_num = 0;
  218.   gint    visible_layer_num = 0;
  219.   gint *layers = NULL;
  220.   gint    index;
  221.   gint  vindex;
  222.   gint    step_x   = 0;
  223.   gint    step_y   = 0;
  224.   gint    x        = 0;
  225.   gint    y        = 0;
  226.   gint    orig_x   = 0;
  227.   gint    orig_y   = 0;
  228.   gint    offset_x = 0;
  229.   gint    offset_y = 0;
  230.   gint    base_x   = 0;
  231.   gint    base_y   = 0;
  232.   gint  bg_index = 0;
  233.  
  234.   layers = gimp_image_get_layers (image_id, &layer_num);
  235.   bg_index = layer_num - 1;
  236.  
  237.   for (index = 0; index < layer_num; index++)
  238.     {
  239.       if (gimp_layer_get_visible (layers[index]))
  240.     visible_layer_num++;
  241.     }
  242.  
  243.   if (VALS.ignore_bottom)
  244.     {
  245.       layer_num--;
  246.       if (gimp_layer_get_visible (layers[bg_index]))
  247.     visible_layer_num--;
  248.     }
  249.  
  250.   if (0 < visible_layer_num)
  251.     {
  252.       gboolean    uninitialized = TRUE;
  253.       gint    min_x = 0;
  254.       gint    min_y = 0;
  255.       gint    max_x = 0;
  256.       gint    max_y = 0;
  257.       
  258.       /* 0 is the top layer */
  259.       for (index = 0; index < layer_num; index++)
  260.     {
  261.       if (gimp_layer_get_visible (layers[index]))
  262.         {
  263.           gimp_drawable_offsets (layers[index], &orig_x, &orig_y);
  264.           align_layers_get_align_offsets (layers[index], &offset_x, &offset_y);
  265.           orig_x += offset_x;
  266.           orig_y += offset_y;
  267.           
  268.           if (uninitialized)
  269.         {
  270.           base_x = min_x = max_x = orig_x;
  271.           base_y = min_y = max_y = orig_y;
  272.  
  273.           uninitialized = FALSE;
  274.         }
  275.           else
  276.         {
  277.           if ( orig_x < min_x ) min_x = orig_x;
  278.           if ( max_x < orig_x ) max_x = orig_x;
  279.           if ( orig_y < min_y ) min_y = orig_y;
  280.           if ( max_y < orig_y ) max_y = orig_y;
  281.         }
  282.         }
  283.     }
  284.  
  285.       if (VALS.base_is_bottom_layer)
  286.     {
  287.       gimp_drawable_offsets (layers[bg_index], &orig_x, &orig_y);
  288.       align_layers_get_align_offsets (layers[bg_index], &offset_x, &offset_y);
  289.       orig_x += offset_x;
  290.       orig_y += offset_y;
  291.       base_x = min_x = orig_x;
  292.       base_y = min_y = orig_y;
  293.     }
  294.  
  295.       if (visible_layer_num > 1)
  296.     {
  297.       step_x = (max_x - min_x) / (visible_layer_num - 1);
  298.       step_y = (max_y - min_y) / (visible_layer_num - 1);
  299.     }
  300.  
  301.       if ( (VALS.h_style == LEFT2RIGHT) || (VALS.h_style == RIGHT2LEFT))
  302.     base_x = min_x;
  303.  
  304.       if ( (VALS.v_style == TOP2BOTTOM) || (VALS.v_style == BOTTOM2TOP))
  305.     base_y = min_y;
  306.     }
  307.   
  308.   gimp_undo_push_group_start (image_id);
  309.   
  310.   for (vindex = -1, index = 0; index < layer_num; index++)
  311.     {
  312.       if (gimp_layer_get_visible (layers[index])) 
  313.     vindex++;
  314.       else 
  315.     continue;
  316.  
  317.       gimp_drawable_offsets (layers[index], &orig_x, &orig_y);
  318.       align_layers_get_align_offsets (layers[index], &offset_x, &offset_y);
  319.       
  320.       switch (VALS.h_style)
  321.     {
  322.     case H_NONE:
  323.       x = orig_x;
  324.       break;
  325.     case H_COLLECT:
  326.       x = base_x - offset_x;
  327.       break;
  328.     case LEFT2RIGHT:
  329.       x = (base_x + vindex * step_x) - offset_x;
  330.       break;
  331.     case RIGHT2LEFT:
  332.       x = (base_x + (visible_layer_num - vindex - 1) * step_x) - offset_x;
  333.       break;
  334.     case SNAP2HGRID:
  335.       x = VALS.grid_size
  336.         * (int) ((orig_x + offset_x + VALS.grid_size /2) / VALS.grid_size)
  337.         - offset_x;
  338.       break;
  339.     }
  340.       switch (VALS.v_style)
  341.     {
  342.     case V_NONE:
  343.       y = orig_y;
  344.       break;
  345.     case V_COLLECT:
  346.       y = base_y - offset_y;
  347.       break;
  348.     case TOP2BOTTOM:
  349.       y = (base_y + vindex * step_y) - offset_y;
  350.       break;
  351.     case BOTTOM2TOP:
  352.       y = (base_y + (visible_layer_num - vindex - 1) * step_y) - offset_y;
  353.       break;
  354.     case SNAP2VGRID:
  355.       y = VALS.grid_size 
  356.         * (int) ((orig_y + offset_y + VALS.grid_size / 2) / VALS.grid_size)
  357.         - offset_y;
  358.       break;
  359.     }
  360.       gimp_layer_set_offsets (layers[index], x, y);
  361.     }
  362.   
  363.   gimp_undo_push_group_end (image_id);
  364.  
  365.   return GIMP_PDB_SUCCESS;
  366. }
  367.  
  368. static void
  369. align_layers_get_align_offsets (gint32    drawable_id,
  370.                 gint   *x,
  371.                 gint   *y)
  372. {
  373.   GimpDrawable    *layer = gimp_drawable_get (drawable_id);
  374.   
  375.   switch (VALS.h_base)
  376.     {
  377.     case H_BASE_LEFT:
  378.       *x = 0;
  379.       break;
  380.     case H_BASE_CENTER:
  381.       *x = (gint) (layer->width / 2);
  382.       break;
  383.     case H_BASE_RIGHT:
  384.       *x = layer->width;
  385.       break;
  386.     default:
  387.       *x = 0;
  388.       break;
  389.     }
  390.   switch (VALS.v_base)
  391.     {
  392.     case V_BASE_TOP:
  393.       *y = 0;
  394.       break;
  395.     case V_BASE_CENTER:
  396.       *y = (gint) (layer->height / 2);
  397.       break;
  398.     case V_BASE_BOTTOM:
  399.       *y = layer->height;
  400.       break;
  401.     default:
  402.       *y = 0;
  403.       break;
  404.     }
  405. }
  406.  
  407. /* dialog stuff */
  408. static int
  409. align_layers_dialog (void)
  410. {
  411.   GtkWidget *dlg;
  412.   GtkWidget *frame;
  413.   GtkWidget *table;
  414.   GtkWidget *optionmenu;
  415.   GtkWidget *toggle;
  416.   GtkObject *adj;
  417.  
  418.   gimp_ui_init (SHORT_NAME, FALSE);
  419.  
  420.   dlg = gimp_dialog_new (_("Align Visible Layers"), SHORT_NAME,
  421.              gimp_standard_help_func, "filters/align_layers.html",
  422.              GTK_WIN_POS_MOUSE,
  423.              FALSE, TRUE, FALSE,
  424.  
  425.              _("OK"), align_layers_ok_callback,
  426.              NULL, NULL, NULL, TRUE, FALSE,
  427.              _("Cancel"), gtk_widget_destroy,
  428.              NULL, 1, NULL, FALSE, TRUE,
  429.  
  430.              NULL);
  431.  
  432.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  433.               GTK_SIGNAL_FUNC (gtk_main_quit),
  434.               NULL);
  435.  
  436.   frame = gtk_frame_new (_("Parameter Settings"));
  437.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  438.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, FALSE, FALSE, 0);
  439.   gtk_widget_show (frame);
  440.  
  441.   table = gtk_table_new (7, 3, FALSE);
  442.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  443.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  444.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  445.   gtk_container_add (GTK_CONTAINER (frame), table);
  446.   gtk_widget_show (table);
  447.  
  448.   optionmenu =
  449.     gimp_option_menu_new2 (FALSE, gimp_menu_item_update,
  450.                &VALS.h_style, (gpointer) VALS.h_style,
  451.  
  452.                _("None"),
  453.                (gpointer) H_NONE, NULL,
  454.                _("Collect"),
  455.                (gpointer) H_COLLECT, NULL,
  456.                _("Fill (left to right)"),
  457.                (gpointer) LEFT2RIGHT, NULL,
  458.                _("Fill (right to left)"),
  459.                (gpointer) RIGHT2LEFT, NULL,
  460.                _("Snap to Grid"),
  461.                (gpointer) SNAP2HGRID, NULL,
  462.  
  463.                NULL);
  464.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  465.                  _("Horizontal Style:"), 1.0, 0.5,
  466.                  optionmenu, 1, FALSE);
  467.  
  468.   optionmenu =
  469.     gimp_option_menu_new2 (FALSE, gimp_menu_item_update,
  470.                &VALS.h_base, (gpointer) VALS.h_base,
  471.  
  472.                _("Left Edge"),  (gpointer) H_BASE_LEFT, NULL,
  473.                _("Center"),     (gpointer) H_BASE_CENTER, NULL,
  474.                _("Right Edge"), (gpointer) H_BASE_RIGHT, NULL,
  475.  
  476.                NULL);
  477.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
  478.                  _("Horizontal Base:"), 1.0, 0.5,
  479.                  optionmenu, 1, FALSE);
  480.  
  481.   optionmenu =
  482.     gimp_option_menu_new2 (FALSE, gimp_menu_item_update,
  483.                &VALS.v_style, (gpointer) VALS.v_style,
  484.  
  485.                _("None"),
  486.                (gpointer) V_NONE, NULL,
  487.                _("Collect"),
  488.                (gpointer) V_COLLECT, NULL,
  489.                _("Fill (top to bottom)"),
  490.                (gpointer) TOP2BOTTOM, NULL,
  491.                _("Fill (bottom to top)"),
  492.                (gpointer) BOTTOM2TOP, NULL,
  493.                _("Snap to Grid"),
  494.                (gpointer) SNAP2VGRID, NULL,
  495.  
  496.                NULL);
  497.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
  498.                  _("Vertical Style:"), 1.0, 0.5,
  499.                  optionmenu, 1, FALSE);
  500.  
  501.   optionmenu =
  502.     gimp_option_menu_new2 (FALSE, gimp_menu_item_update,
  503.                &VALS.v_base, (gpointer) VALS.v_base,
  504.  
  505.                _("Top Edge"),    (gpointer) V_BASE_TOP, NULL,
  506.                _("Center"),      (gpointer) V_BASE_CENTER, NULL,
  507.                _("Bottom Edge"), (gpointer) V_BASE_BOTTOM, NULL,
  508.  
  509.                NULL);
  510.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
  511.                  _("Vertical Base:"), 1.0, 0.5,
  512.                  optionmenu, 1, FALSE);
  513.  
  514.   toggle =
  515.     gtk_check_button_new_with_label
  516.     (_("Ignore the Bottom Layer even if Visible"));
  517.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), VALS.ignore_bottom);
  518.   gtk_table_attach_defaults (GTK_TABLE (table), toggle, 0, 2, 4, 5);
  519.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  520.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  521.               &VALS.ignore_bottom);
  522.   gtk_widget_show (toggle);
  523.  
  524.   toggle =
  525.     gtk_check_button_new_with_label
  526.     (_("Use the (Invisible) Bottom Layer as the Base"));
  527.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
  528.                 VALS.base_is_bottom_layer);
  529.   gtk_table_attach_defaults (GTK_TABLE (table), toggle, 0, 2, 5, 6);
  530.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  531.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  532.               &VALS.base_is_bottom_layer);
  533.   gtk_widget_show (toggle);
  534.  
  535.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 6,
  536.                   _("Grid Size:"), SCALE_WIDTH, 0,
  537.                   VALS.grid_size, 0, 200, 1, 10, 0,
  538.                   TRUE, 0, 0,
  539.                   NULL, NULL);
  540.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  541.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  542.               &VALS.grid_size);
  543.  
  544.   gtk_widget_show (table);
  545.   gtk_widget_show (frame);
  546.   gtk_widget_show (dlg);
  547.   
  548.   gtk_main ();
  549.   gdk_flush ();
  550.  
  551.   return INTERFACE.run;
  552. }
  553.  
  554. static void
  555. align_layers_ok_callback (GtkWidget *widget,
  556.               gpointer   data)
  557. {
  558.   INTERFACE.run = TRUE;
  559.  
  560.   gtk_widget_destroy (GTK_WIDGET (data));
  561. }
  562.