home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / channel_ops.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  23.9 KB  |  819 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 <string.h>
  22.  
  23. #include <gtk/gtk.h>
  24.  
  25. #include "apptypes.h"
  26.  
  27. #include "appenv.h"
  28. #include "apptypes.h"
  29. #include "channel_ops.h"
  30. #include "cursorutil.h"
  31. #include "drawable.h"
  32. #include "floating_sel.h"
  33. #include "gdisplay.h"
  34. #include "gimpcontext.h"
  35. #include "gimpui.h"
  36. #include "parasitelist.h"
  37.  
  38. #include "channel_pvt.h"
  39. #include "layer_pvt.h"
  40.  
  41. #include "libgimp/gimpmath.h"
  42.  
  43. #include "libgimp/gimpintl.h"
  44.  
  45.  
  46. #define ENTRY_WIDTH  60
  47.  
  48. typedef struct _OffsetDialog OffsetDialog;
  49.  
  50. struct _OffsetDialog
  51. {
  52.   GtkWidget         *dlg;
  53.   GtkWidget         *off_se;
  54.  
  55.   gboolean           wrap_around;
  56.   ChannelOffsetType  fill_type;
  57.  
  58.   GimpImage         *gimage;
  59. };
  60.  
  61. /*  Forward declarations  */
  62. static void  offset_ok_callback         (GtkWidget *, gpointer);
  63. static void  offset_cancel_callback     (GtkWidget *, gpointer);
  64.  
  65. static void  offset_halfheight_callback (GtkWidget *, gpointer);
  66.  
  67.  
  68. void
  69. channel_ops_offset (GimpImage* gimage)
  70. {
  71.   OffsetDialog *off_d;
  72.   GtkWidget *label;
  73.   GtkWidget *check;
  74.   GtkWidget *push;
  75.   GtkWidget *vbox;
  76.   GtkWidget *table;
  77.   GtkObject *adjustment;
  78.   GtkWidget *spinbutton;
  79.   GtkWidget *frame;
  80.   GtkWidget *radio_button;
  81.  
  82.   GimpDrawable *drawable;
  83.  
  84.   drawable = gimage_active_drawable (gimage);
  85.  
  86.   off_d = g_new (OffsetDialog, 1);
  87.   off_d->wrap_around = TRUE;
  88.   off_d->fill_type   = drawable_has_alpha (drawable);
  89.   off_d->gimage      = gimage;
  90.  
  91.   off_d->dlg = gimp_dialog_new (_("Offset"), "offset",
  92.                 gimp_standard_help_func,
  93.                 "dialogs/offset.html",
  94.                 GTK_WIN_POS_NONE,
  95.                 FALSE, TRUE, FALSE,
  96.  
  97.                 _("OK"), offset_ok_callback,
  98.                 off_d, NULL, NULL, TRUE, FALSE,
  99.                 _("Cancel"), offset_cancel_callback,
  100.                 off_d, NULL, NULL, FALSE, TRUE,
  101.  
  102.                 NULL);
  103.                 
  104.   /*  The vbox for first column of options  */
  105.   vbox = gtk_vbox_new (FALSE, 2);
  106.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  107.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (off_d->dlg)->vbox), vbox);
  108.  
  109.   /*  The table for the offsets  */
  110.   table = gtk_table_new (3, 2, FALSE);
  111.   gtk_table_set_col_spacing (GTK_TABLE (table), 0, 4);
  112.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  113.  
  114.   /*  The offset labels  */
  115.   label = gtk_label_new (_("Offset X:"));
  116.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  117.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
  118.                     GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 0);
  119.   gtk_widget_show (label);
  120.  
  121.   label = gtk_label_new (_("Y:"));
  122.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  123.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
  124.                     GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 0);
  125.   gtk_widget_show (label);
  126.  
  127.   /*  The offset sizeentry  */
  128.   adjustment = gtk_adjustment_new (1, 1, 1, 1, 10, 1);
  129.   spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 1, 2);
  130.   gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton),
  131.                                    GTK_SHADOW_NONE);
  132.   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
  133.   gtk_widget_set_usize (spinbutton, 75, 0);
  134.   
  135.   off_d->off_se = gimp_size_entry_new (1, gimage->unit, "%a",
  136.                        TRUE, TRUE, FALSE, 75,
  137.                        GIMP_SIZE_ENTRY_UPDATE_SIZE);
  138.   gimp_size_entry_add_field (GIMP_SIZE_ENTRY (off_d->off_se),
  139.                              GTK_SPIN_BUTTON (spinbutton), NULL);
  140.   gtk_table_attach_defaults (GTK_TABLE (off_d->off_se), spinbutton,
  141.                              1, 2, 0, 1);
  142.   gtk_widget_show (spinbutton);
  143.   gtk_table_attach (GTK_TABLE (table), off_d->off_se, 1, 2, 0, 2,
  144.                     GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  145.   gtk_widget_show (off_d->off_se);
  146.  
  147.   gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (off_d->off_se), GIMP_UNIT_PIXEL);
  148.  
  149.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (off_d->off_se), 0,
  150.                                   gimage->xresolution, FALSE);
  151.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (off_d->off_se), 1,
  152.                                   gimage->yresolution, FALSE);
  153.  
  154.   gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (off_d->off_se), 0,
  155.                                          -gimage->width, gimage->width);
  156.   gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (off_d->off_se), 1,
  157.                      -gimage->height, gimage->height);
  158.  
  159.   gimp_size_entry_set_size (GIMP_SIZE_ENTRY (off_d->off_se), 0,
  160.                             0, gimage->width);
  161.   gimp_size_entry_set_size (GIMP_SIZE_ENTRY (off_d->off_se), 1,
  162.                             0, gimage->height);
  163.  
  164.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (off_d->off_se), 0, 0);
  165.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (off_d->off_se), 1, 0);
  166.  
  167.   gtk_widget_show (table);
  168.  
  169.   /*  The wrap around option  */
  170.   check = gtk_check_button_new_with_label (_("Wrap Around"));
  171.   gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0);
  172.   gtk_widget_show (check);
  173.  
  174.   /*  The fill options  */
  175.   frame =
  176.     gimp_radio_group_new2 (TRUE, _("Fill Type"),
  177.                gimp_radio_button_update,
  178.                &off_d->fill_type, (gpointer) off_d->fill_type,
  179.  
  180.                _("Background"), (gpointer) OFFSET_BACKGROUND, NULL,
  181.                _("Transparent"), (gpointer) OFFSET_TRANSPARENT,
  182.                &radio_button,
  183.  
  184.                NULL);
  185.  
  186.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  187.   gtk_widget_show (frame);
  188.  
  189.   if (!drawable_has_alpha (drawable))
  190.     gtk_widget_set_sensitive (radio_button, FALSE);
  191.  
  192.   /*  The by half height and half width option */
  193.   push = gtk_button_new_with_label (_("Offset by (x/2),(y/2)"));
  194.   gtk_container_set_border_width (GTK_CONTAINER (push), 2);
  195.   gtk_box_pack_start (GTK_BOX (vbox), push, FALSE, FALSE, 0);
  196.   gtk_widget_show (push);
  197.  
  198.   /*  Hook up the wrap around  */
  199.   gtk_signal_connect (GTK_OBJECT (check), "toggled",
  200.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  201.               &off_d->wrap_around);
  202.   gtk_object_set_data (GTK_OBJECT (check), "inverse_sensitive", frame);
  203.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), off_d->wrap_around);
  204.  
  205.   /*  Hook up the by half  */
  206.   gtk_signal_connect (GTK_OBJECT (push), "clicked",
  207.               (GtkSignalFunc) offset_halfheight_callback,
  208.               off_d);
  209.  
  210.   gtk_widget_show (vbox);
  211.   gtk_widget_show (off_d->dlg);
  212. }
  213.  
  214. void
  215. offset (GimpImage         *gimage,
  216.     GimpDrawable      *drawable,
  217.     gboolean           wrap_around,
  218.     ChannelOffsetType  fill_type,
  219.     gint               offset_x,
  220.     gint               offset_y)
  221. {
  222.   PixelRegion srcPR, destPR;
  223.   TileManager *new_tiles;
  224.   int width, height;
  225.   int src_x, src_y;
  226.   int dest_x, dest_y;
  227.   unsigned char fill[MAX_CHANNELS] = { 0 };
  228.  
  229.   if (!drawable) 
  230.     return;
  231.  
  232.   width = drawable_width (drawable);
  233.   height = drawable_height (drawable);
  234.  
  235.   if (wrap_around)
  236.     {
  237.       /*  avoid modulo operation on negative values  */
  238.       while (offset_x < 0)
  239.     offset_x += width;
  240.       while (offset_y < 0)
  241.     offset_y += height;
  242.       
  243.       offset_x %= width;
  244.       offset_y %= height;
  245.     }
  246.   else
  247.     {
  248.       offset_x = CLAMP (offset_x, -width, width);
  249.       offset_y = CLAMP (offset_y, -height, height);
  250.     }
  251.  
  252.   if (offset_x == 0 && offset_y == 0)
  253.     return;
  254.  
  255.   new_tiles = tile_manager_new (width, height, drawable_bytes (drawable));
  256.   if (offset_x >= 0)
  257.     {
  258.       src_x = 0;
  259.       dest_x = offset_x;
  260.       width = CLAMP ((width - offset_x), 0, width);
  261.     }
  262.   else
  263.     {
  264.       src_x = -offset_x;
  265.       dest_x = 0;
  266.       width = CLAMP ((width + offset_x), 0, width);
  267.     }
  268.  
  269.   if (offset_y >= 0)
  270.     {
  271.       src_y = 0;
  272.       dest_y = offset_y;
  273.       height = CLAMP ((height - offset_y), 0, height);
  274.     }
  275.   else
  276.     {
  277.       src_y = -offset_y;
  278.       dest_y = 0;
  279.       height = CLAMP ((height + offset_y), 0, height);
  280.     }
  281.  
  282.   /*  Copy the center region  */
  283.   if (width && height)
  284.     {
  285.       pixel_region_init (&srcPR, drawable_data (drawable), src_x, src_y, width, height, FALSE);
  286.       pixel_region_init (&destPR, new_tiles, dest_x, dest_y, width, height, TRUE);
  287.  
  288.       copy_region (&srcPR, &destPR);
  289.     }
  290.  
  291.   /*  Copy appropriately for wrap around  */
  292.   if (wrap_around == TRUE)
  293.     {
  294.       if (offset_x >= 0 && offset_y >= 0)
  295.     {
  296.       src_x = drawable_width (drawable) - offset_x;
  297.       src_y = drawable_height (drawable) - offset_y;
  298.     }
  299.       else if (offset_x >= 0 && offset_y < 0)
  300.     {
  301.       src_x = drawable_width (drawable) - offset_x;
  302.       src_y = 0;
  303.     }
  304.       else if (offset_x < 0 && offset_y >= 0)
  305.     {
  306.       src_x = 0;
  307.       src_y = drawable_height (drawable) - offset_y;
  308.     }
  309.       else if (offset_x < 0 && offset_y < 0)
  310.     {
  311.       src_x = 0;
  312.       src_y = 0;
  313.     }
  314.  
  315.       dest_x = (src_x + offset_x) % drawable_width (drawable);
  316.       if (dest_x < 0)
  317.     dest_x = drawable_width (drawable) + dest_x;
  318.       dest_y = (src_y + offset_y) % drawable_height (drawable);
  319.       if (dest_y < 0)
  320.     dest_y = drawable_height (drawable) + dest_y;
  321.  
  322.       /*  intersecting region  */
  323.       if (offset_x != 0 && offset_y != 0)
  324.     {
  325.       pixel_region_init (&srcPR, drawable_data (drawable), src_x, src_y,
  326.                  ABS (offset_x), ABS (offset_y), FALSE);
  327.       pixel_region_init (&destPR, new_tiles, dest_x, dest_y, ABS (offset_x), ABS (offset_y), TRUE);
  328.       copy_region (&srcPR, &destPR);
  329.     }
  330.  
  331.       /*  X offset  */
  332.       if (offset_x != 0)
  333.     {
  334.       if (offset_y >= 0)
  335.         {
  336.           pixel_region_init (&srcPR, drawable_data (drawable), src_x, 0,
  337.                  ABS (offset_x), drawable_height (drawable) - ABS (offset_y), FALSE);
  338.           pixel_region_init (&destPR, new_tiles, dest_x, dest_y + offset_y,
  339.                  ABS (offset_x), drawable_height (drawable) - ABS (offset_y), TRUE);
  340.         }
  341.       else if (offset_y < 0)
  342.         {
  343.           pixel_region_init (&srcPR, drawable_data (drawable), src_x, src_y - offset_y,
  344.                  ABS (offset_x), drawable_height (drawable) - ABS (offset_y), FALSE);
  345.           pixel_region_init (&destPR, new_tiles, dest_x, 0,
  346.                  ABS (offset_x), drawable_height (drawable) - ABS (offset_y), TRUE);
  347.         }
  348.  
  349.       copy_region (&srcPR, &destPR);
  350.     }
  351.  
  352.       /*  X offset  */
  353.       if (offset_y != 0)
  354.     {
  355.       if (offset_x >= 0)
  356.         {
  357.           pixel_region_init (&srcPR, drawable_data (drawable), 0, src_y,
  358.                  drawable_width (drawable) - ABS (offset_x),
  359.                  ABS (offset_y), FALSE);
  360.           pixel_region_init (&destPR, new_tiles, dest_x + offset_x, dest_y,
  361.                  drawable_width (drawable) - ABS (offset_x),
  362.                  ABS (offset_y), TRUE);
  363.         }
  364.       else if (offset_x < 0)
  365.         {
  366.           pixel_region_init (&srcPR, drawable_data (drawable),
  367.                  src_x - offset_x, src_y,
  368.                  drawable_width (drawable) - ABS (offset_x),
  369.                  ABS (offset_y), FALSE);
  370.           pixel_region_init (&destPR, new_tiles, 0, dest_y,
  371.                  drawable_width (drawable) - ABS (offset_x),
  372.                  ABS (offset_y), TRUE);
  373.         }
  374.  
  375.       copy_region (&srcPR, &destPR);
  376.     }
  377.     }
  378.   /*  Otherwise, fill the vacated regions  */
  379.   else
  380.     {
  381.       if (fill_type == OFFSET_BACKGROUND)
  382.     {
  383.       gimp_context_get_background (NULL, &fill[0], &fill[1], &fill[2]);
  384.       if (drawable_has_alpha (drawable))
  385.         fill[drawable_bytes (drawable) - 1] = OPAQUE_OPACITY;
  386.     }
  387.  
  388.       if (offset_x >= 0 && offset_y >= 0)
  389.     {
  390.       dest_x = 0;
  391.       dest_y = 0;
  392.     }
  393.       else if (offset_x >= 0 && offset_y < 0)
  394.     {
  395.       dest_x = 0;
  396.       dest_y = drawable_height (drawable) + offset_y;
  397.     }
  398.       else if (offset_x < 0 && offset_y >= 0)
  399.     {
  400.       dest_x = drawable_width (drawable) + offset_x;
  401.       dest_y = 0;
  402.     }
  403.       else if (offset_x < 0 && offset_y < 0)
  404.     {
  405.       dest_x = drawable_width (drawable) + offset_x;
  406.       dest_y = drawable_height (drawable) + offset_y;
  407.     }
  408.  
  409.       /*  intersecting region  */
  410.       if (offset_x != 0 && offset_y != 0)
  411.     {
  412.       pixel_region_init (&destPR, new_tiles, dest_x, dest_y,
  413.                  ABS (offset_x), ABS (offset_y), TRUE);
  414.       color_region (&destPR, fill);
  415.     }
  416.  
  417.       /*  X offset  */
  418.       if (offset_x != 0)
  419.     {
  420.       if (offset_y >= 0)
  421.         pixel_region_init (&destPR, new_tiles, dest_x, dest_y + offset_y,
  422.                    ABS (offset_x), drawable_height (drawable) - ABS (offset_y), TRUE);
  423.       else if (offset_y < 0)
  424.         pixel_region_init (&destPR, new_tiles, dest_x, 0,
  425.                    ABS (offset_x), drawable_height (drawable) - ABS (offset_y), TRUE);
  426.  
  427.       color_region (&destPR, fill);
  428.     }
  429.  
  430.       /*  X offset  */
  431.       if (offset_y != 0)
  432.     {
  433.       if (offset_x >= 0)
  434.         pixel_region_init (&destPR, new_tiles, dest_x + offset_x, dest_y,
  435.                    drawable_width (drawable) - ABS (offset_x), ABS (offset_y), TRUE);
  436.       else if (offset_x < 0)
  437.         pixel_region_init (&destPR, new_tiles, 0, dest_y,
  438.                    drawable_width (drawable) - ABS (offset_x), ABS (offset_y), TRUE);
  439.  
  440.       color_region (&destPR, fill);
  441.     }
  442.     }
  443.  
  444.   /*  push an undo  */
  445.   drawable_apply_image (drawable, 0, 0,
  446.             drawable_width (drawable), drawable_height (drawable),
  447.             drawable_data (drawable), FALSE);
  448.  
  449.   /*  swap the tiles  */
  450.   drawable->tiles = new_tiles;
  451.  
  452.  
  453.   /*  update the drawable  */
  454.   drawable_update (drawable, 0, 0,
  455.            drawable_width (drawable), drawable_height (drawable));
  456. }
  457.  
  458. /*
  459.  *  Interface callbacks
  460.  */
  461.  
  462. static void
  463. offset_ok_callback (GtkWidget *widget,
  464.             gpointer   data)
  465. {
  466.   OffsetDialog *off_d;
  467.   GImage       *gimage;
  468.   GimpDrawable *drawable;
  469.   gint offset_x;
  470.   gint offset_y;
  471.  
  472.   off_d = (OffsetDialog *) data;
  473.  
  474.   if ((gimage = off_d->gimage) != NULL)
  475.     {
  476.       drawable = gimage_active_drawable (gimage);
  477.  
  478.       offset_x = (gint)
  479.     RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (off_d->off_se), 0));
  480.       offset_y = (gint)
  481.     RINT (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (off_d->off_se), 1));
  482.  
  483.       offset (gimage, drawable, off_d->wrap_around, off_d->fill_type,
  484.           offset_x, offset_y);
  485.       gdisplays_flush ();
  486.     }
  487.  
  488.   gtk_widget_destroy (off_d->dlg);
  489.   g_free (off_d);
  490. }
  491.  
  492. static void
  493. offset_cancel_callback (GtkWidget *widget,
  494.             gpointer   data)
  495. {
  496.   OffsetDialog *off_d;
  497.  
  498.   off_d = (OffsetDialog *) data;
  499.   gtk_widget_destroy (off_d->dlg);
  500.   g_free (off_d);
  501. }
  502.  
  503. static void
  504. offset_halfheight_callback (GtkWidget *widget,
  505.                 gpointer   data)
  506. {
  507.   OffsetDialog *off_d;
  508.   GImage *gimage;
  509.  
  510.   off_d = (OffsetDialog *) data;
  511.   gimage = off_d->gimage;
  512.  
  513.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (off_d->off_se),
  514.                   0, gimage->width / 2);
  515.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (off_d->off_se),
  516.                   1, gimage->height / 2);
  517. }
  518.  
  519. GimpImage *
  520. duplicate (GimpImage *gimage)
  521. {
  522.   PixelRegion srcPR, destPR;
  523.   GimpImage *new_gimage;
  524.   Layer *layer, *new_layer;
  525.   Layer *floating_layer;
  526.   Channel *channel, *new_channel;
  527.   GSList *list;
  528.   GList *glist;
  529.   Guide *guide = NULL;
  530.   Layer *active_layer = NULL;
  531.   Channel *active_channel = NULL;
  532.   GimpDrawable *new_floating_sel_drawable = NULL;
  533.   GimpDrawable *floating_sel_drawable = NULL;
  534.   ParasiteList *parasites;
  535.   PathList *paths;
  536.   gint count;
  537.  
  538.   gimp_add_busy_cursors_until_idle ();
  539.  
  540.   /*  Create a new image  */
  541.   new_gimage = gimage_new (gimage->width, gimage->height, gimage->base_type);
  542.   gimage_disable_undo (new_gimage);
  543.  
  544.   /*  Copy resolution and unit information  */
  545.   new_gimage->xresolution = gimage->xresolution;
  546.   new_gimage->yresolution = gimage->yresolution;
  547.   new_gimage->unit = gimage->unit;
  548.  
  549.   /*  Copy floating layer  */
  550.   floating_layer = gimage_floating_sel (gimage);
  551.   if (floating_layer)
  552.     {
  553.       floating_sel_relax (floating_layer, FALSE);
  554.  
  555.       floating_sel_drawable = floating_layer->fs.drawable;
  556.       floating_layer = NULL;
  557.     }
  558.  
  559.   /*  Copy the layers  */
  560.   list = gimage->layers;
  561.   count = 0;
  562.   layer = NULL;
  563.   while (list)
  564.     {
  565.       layer = (Layer *) list->data;
  566.       list = g_slist_next (list);
  567.  
  568.       new_layer = layer_copy (layer, FALSE);
  569.  
  570.       gimp_drawable_set_gimage(GIMP_DRAWABLE(new_layer), new_gimage);
  571.  
  572.       /*  Make sure the copied layer doesn't say: "<old layer> copy"  */
  573.       layer_set_name(GIMP_LAYER(new_layer),
  574.              layer_get_name(GIMP_LAYER(layer)));
  575.  
  576.       /*  Make sure if the layer has a layer mask, it's name isn't screwed up  */
  577.       if (new_layer->mask)
  578.     {
  579.       gimp_drawable_set_name(GIMP_DRAWABLE(new_layer->mask),
  580.               gimp_drawable_get_name(GIMP_DRAWABLE(layer->mask)));
  581.     }
  582.  
  583.       if (gimage->active_layer == layer)
  584.     active_layer = new_layer;
  585.  
  586.       if (gimage->floating_sel == layer)
  587.     floating_layer = new_layer;
  588.  
  589.       if (floating_sel_drawable == GIMP_DRAWABLE(layer))
  590.     new_floating_sel_drawable = GIMP_DRAWABLE(new_layer);
  591.  
  592.       /*  Add the layer  */
  593.       if (floating_layer != new_layer)
  594.     gimage_add_layer (new_gimage, new_layer, count++);
  595.     }
  596.  
  597.   /*  Copy the channels  */
  598.   list = gimage->channels;
  599.   count = 0;
  600.   while (list)
  601.     {
  602.       channel = (Channel *) list->data;
  603.       list = g_slist_next (list);
  604.  
  605.       new_channel = channel_copy (channel);
  606.  
  607.       gimp_drawable_set_gimage(GIMP_DRAWABLE(new_channel), new_gimage);
  608.  
  609.       /*  Make sure the copied channel doesn't say: "<old channel> copy"  */
  610.       gimp_drawable_set_name(GIMP_DRAWABLE(new_channel),
  611.                  gimp_drawable_get_name(GIMP_DRAWABLE(channel)));
  612.  
  613.       if (gimage->active_channel == channel)
  614.     active_channel = (new_channel);
  615.  
  616.       if (floating_sel_drawable == GIMP_DRAWABLE(channel))
  617.     new_floating_sel_drawable = GIMP_DRAWABLE(new_channel);
  618.  
  619.       /*  Add the channel  */
  620.       gimage_add_channel (new_gimage, new_channel, count++);
  621.     }
  622.  
  623.   /*  Copy the selection mask  */
  624.   pixel_region_init (&srcPR, drawable_data (GIMP_DRAWABLE(gimage->selection_mask)), 
  625.              0, 0, gimage->width, gimage->height, FALSE);
  626.   pixel_region_init (&destPR, drawable_data (GIMP_DRAWABLE(new_gimage->selection_mask)), 
  627.              0, 0, gimage->width, gimage->height, TRUE);
  628.   copy_region (&srcPR, &destPR);
  629.   new_gimage->selection_mask->bounds_known = FALSE;
  630.   new_gimage->selection_mask->boundary_known = FALSE;
  631.  
  632.   /*  Set active layer, active channel  */
  633.   new_gimage->active_layer = active_layer;
  634.   new_gimage->active_channel = active_channel;
  635.   if (floating_layer)
  636.     floating_sel_attach (floating_layer, new_floating_sel_drawable);
  637.  
  638.   /*  Copy the colormap if necessary  */
  639.   if (new_gimage->base_type == INDEXED)
  640.     memcpy (new_gimage->cmap, gimage->cmap, gimage->num_cols * 3);
  641.   new_gimage->num_cols = gimage->num_cols;
  642.  
  643.   /*  copy state of all color channels  */
  644.   for (count = 0; count < MAX_CHANNELS; count++)
  645.     {
  646.       new_gimage->visible[count] = gimage->visible[count];
  647.       new_gimage->active[count] = gimage->active[count];
  648.     }
  649.  
  650.   /*  Copy any Guides  */
  651.   glist = gimage->guides;
  652.   while (glist)
  653.     {
  654.       Guide* new_guide;
  655.  
  656.       guide = (Guide*) glist->data;
  657.       glist = g_list_next (glist);
  658.  
  659.       switch (guide->orientation)
  660.     {
  661.     case ORIENTATION_HORIZONTAL:
  662.       new_guide = gimp_image_add_hguide(new_gimage);
  663.       new_guide->position = guide->position;
  664.       break;
  665.     case ORIENTATION_VERTICAL:
  666.       new_guide = gimp_image_add_vguide(new_gimage);
  667.       new_guide->position = guide->position;
  668.       break;
  669.     default:
  670.       g_error("Unknown guide orientation.\n");
  671.     }
  672.     }
  673.   /* Copy the qmask info */
  674.   new_gimage->qmask_state = gimage->qmask_state;
  675.   for (count=0;count<3;count++)
  676.     new_gimage->qmask_color[count] = gimage->qmask_color[count];
  677.   new_gimage->qmask_opacity = gimage->qmask_opacity;
  678.  
  679.   /* Copy parasites */
  680.   parasites = gimage->parasites;
  681.   if (parasites)
  682.     new_gimage->parasites = parasite_list_copy (parasites);
  683.  
  684.   /* Copy paths */
  685.   paths = gimp_image_get_paths (gimage);
  686.   if (paths)
  687.     {
  688.       GSList *plist = NULL;
  689.       GSList *new_plist = NULL;
  690.       Path *path;
  691.       PathList *new_paths;
  692.       
  693.       for (plist = paths->bz_paths; plist; plist = plist->next)
  694.     {
  695.       path = plist->data;
  696.       new_plist = g_slist_append (new_plist, path_copy (new_gimage, path));
  697.     }
  698.       
  699.       new_paths = path_list_new (new_gimage, paths->last_selected_row, new_plist);
  700.       gimp_image_set_paths (new_gimage, new_paths);
  701.     }
  702.  
  703.   gimage_enable_undo (new_gimage);
  704.  
  705.   return new_gimage;
  706. }
  707.  
  708.  
  709. #ifdef I_LIKE_BOGUS_CRAP
  710. static void
  711. duplicate_projection (GimpImage *oldgimage, GimpImage *newgimage,
  712.               GDisplay *newgdisplay)
  713. {
  714.   PixelRegion srcPR, destPR;
  715.  
  716.   /*  Copy-on-write the projection tilemanager so we don't have
  717.    *  to reproject the new gimage - since if we do the duplicate
  718.    *  operation correctly, the projection for the new gimage is
  719.    *  identical to that of the source.  (Is this true?  View-only
  720.    *  attributes vs. image meta-attributes? -- View-only attributes
  721.    *  *should* strictly be applied post-projection.)
  722.    */
  723.  
  724. #if 0
  725.   newgimage->construct_flag = oldgimage->construct_flag;
  726.  
  727.   g_warning("CONSTR:%d %dx%dx%d",newgimage->construct_flag,
  728.         tile_manager_level_width(gimp_image_projection (newgimage)),
  729.         tile_manager_level_height(gimp_image_projection (newgimage)),
  730.         tile_manager_level_bpp(gimp_image_projection (newgimage))
  731.         );
  732.  
  733.   gdisplay_expose_area(newgdisplay,
  734.                newgdisplay->disp_xoffset, newgdisplay->disp_yoffset,
  735.                newgdisplay->disp_width, newgdisplay->disp_height);
  736.   
  737.   if (newgimage->construct_flag)
  738. #endif
  739.     {
  740.       tile_manager_set_user_data(gimp_image_projection (newgimage),
  741.                  (void *) newgimage);
  742.  
  743.       /*
  744.       newgimage->proj_type = oldgimage->proj_type;
  745.       newgimage->proj_bytes = oldgimage->proj_bytes;
  746.       newgimage->proj_level = oldgimage->proj_level;
  747.       
  748.       gimage_projection_realloc (new_gimage);*/
  749.  
  750.       
  751.       pixel_region_init (&srcPR, gimp_image_projection (oldgimage), 0, 0,
  752.              oldgimage->width, oldgimage->height, FALSE);
  753.       pixel_region_init (&destPR, gimp_image_projection (newgimage), 0, 0,
  754.              newgimage->width, newgimage->height, TRUE);
  755.       copy_region(&srcPR, &destPR);
  756.       
  757.       /*
  758.       pixel_region_init (&srcPR, gimp_image_projection (oldgimage),
  759.              newgdisplay->disp_xoffset, newgdisplay->disp_yoffset,
  760.              newgdisplay->disp_width, newgdisplay->disp_height,
  761.              FALSE);
  762.       pixel_region_init (&destPR, gimp_image_projection (newgimage),
  763.              newgdisplay->disp_xoffset, newgdisplay->disp_yoffset,
  764.              newgdisplay->disp_width, newgdisplay->disp_height,
  765.              TRUE);
  766.       copy_region(&srcPR, &destPR);
  767.       */
  768.  
  769.       if (1)
  770.       {
  771.     GDisplay* gdisp;
  772.     int x,y,w,h;
  773.     int x1, y1, x2, y2;
  774.     
  775.     gdisp = newgdisplay;
  776.  
  777.     fprintf (stderr, " [pointers: %p, %p ] ", oldgimage, gdisp->gimage);
  778.  
  779.     gdisplay_untransform_coords (gdisp, 0, 0, &x1, &y1, FALSE, FALSE);
  780.     gdisplay_untransform_coords (gdisp, gdisp->disp_width, gdisp->disp_height,
  781.                      &x2, &y2, FALSE, FALSE);
  782.  
  783.     fprintf(stderr," <%dx%d %dx%d %d,%d->%d,%d> ",
  784.         oldgimage->width, oldgimage->height,
  785.         newgimage->width, newgimage->height,
  786.         x1,y1, x2,y2);
  787.  
  788.     gimage_invalidate_without_render (gdisp->gimage, 0,0,
  789.                       gdisp->gimage->width,
  790.                       gdisp->gimage->height,
  791.                             64,64,128,128);
  792.                       /*                      newgdisplay->disp_width,newgdisplay->disp_height,
  793.                                             newgdisplay->disp_width+newgdisplay->disp_xoffset,newgdisplay->disp_height+newgdisplay->disp_yoffset */
  794.                       x1, y1, x2, y2
  795.                       );
  796.     
  797.       }
  798.     }
  799. }
  800. #endif
  801.  
  802.  
  803. void
  804. channel_ops_duplicate (GimpImage *gimage)
  805. {
  806.   GDisplay *new_gdisp;
  807.   GImage   *new_gimage;
  808.  
  809.   new_gimage = duplicate (gimage);
  810.  
  811.   /* We don't want to copy a half-redrawn projection, so force a flush. */
  812.   /* gdisplays_finish_draw();
  813.   gdisplays_flush_now(); */
  814.  
  815.   new_gdisp = gdisplay_new (new_gimage, 0x0101);
  816.  
  817.   /* duplicate_projection(gimage, new_gimage, new_gdisp);*/
  818. }
  819.