1998-06-28 18:39:58 +08:00
|
|
|
/* The GIMP -- an image manipulation program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
2000-12-11 11:33:25 +08:00
|
|
|
|
2000-04-28 01:27:28 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
1998-09-01 01:31:19 +08:00
|
|
|
#include <string.h>
|
2000-04-28 01:27:28 +08:00
|
|
|
|
2000-12-17 05:37:03 +08:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
2001-01-24 02:49:44 +08:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
2001-01-24 07:56:18 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2001-05-21 21:58:46 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2001-01-24 02:49:44 +08:00
|
|
|
|
2001-05-10 06:34:59 +08:00
|
|
|
#include "core-types.h"
|
|
|
|
|
2001-05-15 19:25:25 +08:00
|
|
|
#include "base/pixel-region.h"
|
|
|
|
#include "base/temp-buf.h"
|
|
|
|
#include "base/tile-manager.h"
|
|
|
|
#include "base/tile.h"
|
2000-12-17 05:37:03 +08:00
|
|
|
|
2001-04-07 23:58:26 +08:00
|
|
|
#include "paint-funcs/paint-funcs.h"
|
|
|
|
|
2001-05-15 19:25:25 +08:00
|
|
|
/* FIXME: remove the Path <-> BezierSelect dependency */
|
|
|
|
#include "tools/tools-types.h"
|
|
|
|
|
2001-07-05 03:31:35 +08:00
|
|
|
#include "gimp.h"
|
1999-10-27 02:27:27 +08:00
|
|
|
#include "gimpcontext.h"
|
2000-12-29 23:22:01 +08:00
|
|
|
#include "gimpimage.h"
|
2001-05-15 19:25:25 +08:00
|
|
|
#include "gimpimage-colorhash.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
#include "gimpimage-mask.h"
|
2001-03-05 09:01:16 +08:00
|
|
|
#include "gimpimage-undo.h"
|
2001-02-02 02:44:22 +08:00
|
|
|
#include "gimplayer.h"
|
2001-01-29 00:44:22 +08:00
|
|
|
#include "gimplayermask.h"
|
2001-02-19 21:06:09 +08:00
|
|
|
#include "gimplist.h"
|
2001-01-10 08:36:54 +08:00
|
|
|
#include "gimpmarshal.h"
|
1998-12-17 19:40:19 +08:00
|
|
|
#include "gimpparasite.h"
|
2001-03-05 09:01:16 +08:00
|
|
|
#include "gimpundostack.h"
|
2001-07-05 03:31:35 +08:00
|
|
|
|
|
|
|
#include "app_procs.h"
|
|
|
|
#include "drawable.h"
|
|
|
|
#include "floating_sel.h"
|
|
|
|
#include "gdisplay.h"
|
|
|
|
#include "gimprc.h"
|
2000-12-29 23:22:01 +08:00
|
|
|
#include "parasitelist.h"
|
2000-02-16 21:52:33 +08:00
|
|
|
#include "path.h"
|
2000-12-29 23:22:01 +08:00
|
|
|
#include "undo.h"
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-04-28 01:27:28 +08:00
|
|
|
#include "libgimp/gimpintl.h"
|
|
|
|
|
1998-09-01 01:31:19 +08:00
|
|
|
|
comment typo fix, plus add %D* to default image-title-format string, so
Fri Oct 1 12:46:12 1999 Austin Donnelly <austin@gimp.org>
* gimprc.in: comment typo fix, plus add %D* to default
image-title-format string, so people get a '*' in the titlebar
if their image is dirty.
* app/fileops.c: initialise filename before using it.
* app/gdisplay.c: empty parameter list () is K&R - should be
stronger (void) in ANSI C.
* app/gimpdrawable.c: gimp_drawable_{dirty,clean} functions
removed - no one uses them anyway. Parasite undo type is
proper parasite undo type, not MISC_UNDO.
* app/gimpdrawableP.h: drawable dirty bit removed.
* app/gimpimage.c: don't change the resolution if there's no
difference from the old one. Call gdisplay_shrink_wrap() to
re-calculate scale factors and refresh the display on
resolution change. Layer undo doesn't have sub-types
anymore, uses main UndoType instead.
* app/layer.h: Remove LayerUndoType
* app/qmask.c: fix qmask undo so it actually works.
* app/undo.h: new types for undo_push_layer{,_mask} and
undo_push_qmask.
* app/undo.c: change way group boundaries are represented:
each Undo has a group_boundary boolean set to TRUE if this is
the start or the end of a group, and the type of the Undo is
the group's type. Within a group, each Undo keeps its own
type. This allows pop funcs and free funcs to do
type-specific things (eg needed by layer and channel stuff).
Don't maintain per-drawable dirty flags anymore. Floating
sel to layer and layer rename now uses meaningful undo types.
* app/undo_types.h: more specific undo types:
LAYER_{ADD,REMOVE}_UNDO, LAYER_MASK_{ADD,REMOVE}_UNDO,
LAYER_RENAME_UNDO, and PARASITE_{ATTACH,DETACH}_UNDO.
* app/undo_history.c: oops - undo stack was being placed into gtk
list in wrong order.
* app/edit_selection.c: push more descriptive LAYER_DISPLACE_UNDO
rather than MISC_UNDO.
* app/layers_dialog.c: better tagging of undo types
1999-10-02 02:43:24 +08:00
|
|
|
#ifdef DEBUG
|
|
|
|
#define TRC(x) printf x
|
|
|
|
#else
|
|
|
|
#define TRC(x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* Local function declarations */
|
2001-02-05 06:10:54 +08:00
|
|
|
static void gimp_image_class_init (GimpImageClass *klass);
|
|
|
|
static void gimp_image_init (GimpImage *gimage);
|
|
|
|
static void gimp_image_destroy (GtkObject *object);
|
|
|
|
static void gimp_image_name_changed (GimpObject *object);
|
|
|
|
static void gimp_image_invalidate_preview (GimpViewable *viewable);
|
2001-06-18 21:10:03 +08:00
|
|
|
static void gimp_image_size_changed (GimpViewable *viewable);
|
2001-05-15 19:25:25 +08:00
|
|
|
static void gimp_image_real_colormap_changed (GimpImage *gimage,
|
|
|
|
gint ncol);
|
2001-02-07 08:06:58 +08:00
|
|
|
static TempBuf *gimp_image_get_preview (GimpViewable *gimage,
|
2001-02-05 06:10:54 +08:00
|
|
|
gint width,
|
|
|
|
gint height);
|
2001-02-07 08:06:58 +08:00
|
|
|
static TempBuf *gimp_image_get_new_preview (GimpViewable *viewable,
|
2001-02-05 06:10:54 +08:00
|
|
|
gint width,
|
|
|
|
gint height);
|
|
|
|
static void gimp_image_free_projection (GimpImage *gimage);
|
|
|
|
static void gimp_image_allocate_shadow (GimpImage *gimage,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gint bpp);
|
|
|
|
static void gimp_image_allocate_projection (GimpImage *gimage);
|
|
|
|
static void gimp_image_construct_layers (GimpImage *gimage,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h);
|
|
|
|
static void gimp_image_construct_channels (GimpImage *gimage,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h);
|
|
|
|
static void gimp_image_initialize_projection (GimpImage *gimage,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h);
|
|
|
|
static void gimp_image_get_active_channels (GimpImage *gimage,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
gint *active);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* projection functions */
|
2001-02-05 06:10:54 +08:00
|
|
|
static void project_intensity (GimpImage *gimage,
|
|
|
|
GimpLayer *layer,
|
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask);
|
|
|
|
static void project_intensity_alpha (GimpImage *gimage,
|
|
|
|
GimpLayer *layer,
|
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask);
|
|
|
|
static void project_indexed (GimpImage *gimage,
|
|
|
|
GimpLayer *layer,
|
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *dest);
|
|
|
|
static void project_indexed_alpha (GimpImage *gimage,
|
|
|
|
GimpLayer *layer,
|
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask);
|
|
|
|
static void project_channel (GimpImage *gimage,
|
|
|
|
GimpChannel *channel,
|
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *src2);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Global variables
|
|
|
|
*/
|
2000-12-04 05:34:38 +08:00
|
|
|
gint valid_combinations[][MAX_CHANNELS + 1] =
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
/* RGB GIMAGE */
|
|
|
|
{ -1, -1, -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A },
|
|
|
|
/* RGBA GIMAGE */
|
|
|
|
{ -1, -1, -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A },
|
|
|
|
/* GRAY GIMAGE */
|
|
|
|
{ -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A, -1, -1 },
|
|
|
|
/* GRAYA GIMAGE */
|
|
|
|
{ -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A, -1, -1 },
|
|
|
|
/* INDEXED GIMAGE */
|
|
|
|
{ -1, COMBINE_INDEXED_INDEXED, COMBINE_INDEXED_INDEXED_A, -1, -1 },
|
|
|
|
/* INDEXEDA GIMAGE */
|
|
|
|
{ -1, -1, COMBINE_INDEXED_A_INDEXED_A, -1, -1 },
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Static variables
|
|
|
|
*/
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
enum
|
|
|
|
{
|
2001-05-07 00:14:34 +08:00
|
|
|
MODE_CHANGED,
|
2001-05-07 02:58:04 +08:00
|
|
|
ALPHA_CHANGED,
|
2001-05-08 09:32:25 +08:00
|
|
|
FLOATING_SELECTION_CHANGED,
|
2001-02-27 22:14:13 +08:00
|
|
|
ACTIVE_LAYER_CHANGED,
|
|
|
|
ACTIVE_CHANNEL_CHANGED,
|
2001-05-03 20:26:05 +08:00
|
|
|
COMPONENT_VISIBILITY_CHANGED,
|
|
|
|
COMPONENT_ACTIVE_CHANGED,
|
2001-06-01 03:53:13 +08:00
|
|
|
MASK_CHANGED,
|
2001-05-07 02:58:04 +08:00
|
|
|
|
1999-08-23 22:34:58 +08:00
|
|
|
CLEAN,
|
1998-06-28 18:39:58 +08:00
|
|
|
DIRTY,
|
|
|
|
REPAINT,
|
1999-01-08 03:53:05 +08:00
|
|
|
COLORMAP_CHANGED,
|
Honest, guv, it's not a feature - it's a tightly integrated package of
Mon Sep 20 12:51:30 EDT 1999 Austin Donnelly <austin@gimp.org>
Honest, guv, it's not a feature - it's a tightly integrated
package of undo system cleanups and fixes.
NEW FILES:
* app/undo_history.c: window showing recent undo (and redo) steps
available.
* app/undo_types.h: broken out of undo.h to fix circular includes.
MODIFIED FILES:
* app/Makefile.am: compile undo_history.c
* app/channel.h: use enum for channel undo type, not just magic
numbers.
* app/layer.h: same for layer undos.
* app/commands.c: edit_show_undo_history_cmd_callback() function to
pull up undo history window.
* app/commands.h: prototype for above.
* app/gdisplay.c: make undo / redo menu items sensitive according
to whether they would do anything. Would be easy to change
the text to say what would be undone/redone, but I don't know
the GTK.
* app/gimpimage.c: new signal emitted by gimage:
UNDO_EVENT. gimp_image_undo_event() function to emit it.
* app/gimpimage.h: prototype for above.
* app/gimpimageP.h: pushing_undo_group member is now an undo_type,
not an int. Keep undo history widget here too (if created).
* app/menus.c: add "Edit/Undo history..." to image menu.
* app/undo.c: new types: enums undo_type and undo_state rather than
ints and magic numbers. All undo_pop_* and undo_free_*
functions made static. New static function
undo_type_to_name(). Issue undo event signals on various
important events (eg undo pushed, undo popped etc).
undo_push() now takes a "dirties_image" arg to say whether
image should be dirtied. Layer moves now dirty the image. A
couple of g_return_if_fails () on undo_pop and undo_redo to
assert we're not in the middle of an undo group.
undo_get_{undo,redo}_name() to peek at names of top items on
undo and redo stacks resp. undo_map_over_{undo,redo}_stack()
to run a function for each item or group on stack. Layer and
channel undos use symbolic names rather than 0 or 1. Array
mapping undo types to names.
* app/undo.h: split out undo types to undo_types.h. Prototypes
for functions described above. undo_event_t enum.
undo_history_new() prototype lives here too.
Random other fixes:
* app/gimpdrawable.c
* app/image_render.c: default labels in switches to keep egcs happy.
* app/nav_window.c: some fixes to (sort of) cope with image res !=
screen res. Still needs work to handle non-square pixels
properly.
* app/paths_dialog.c: bad idea to call gimp_image_dirty()
directly. Even though it's currently commented out.
1999-09-21 01:15:20 +08:00
|
|
|
UNDO_EVENT,
|
1998-06-28 18:39:58 +08:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
1999-08-22 19:45:31 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
static guint gimp_image_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
static GimpViewableClass *parent_class = NULL;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-04-13 22:50:43 +08:00
|
|
|
static gint global_image_ID = 1;
|
|
|
|
static GHashTable *gimp_image_table = NULL;
|
|
|
|
|
2001-05-16 03:10:57 +08:00
|
|
|
static guint32 next_guide_id = 1;
|
|
|
|
|
2000-12-04 05:34:38 +08:00
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
GtkType
|
|
|
|
gimp_image_get_type (void)
|
|
|
|
{
|
|
|
|
static GtkType image_type = 0;
|
|
|
|
|
|
|
|
if (! image_type)
|
|
|
|
{
|
|
|
|
GtkTypeInfo image_info =
|
|
|
|
{
|
|
|
|
"GimpImage",
|
|
|
|
sizeof (GimpImage),
|
|
|
|
sizeof (GimpImageClass),
|
|
|
|
(GtkClassInitFunc) gimp_image_class_init,
|
|
|
|
(GtkObjectInitFunc) gimp_image_init,
|
|
|
|
/* reserved_1 */ NULL,
|
|
|
|
/* reserved_2 */ NULL,
|
|
|
|
(GtkClassInitFunc) NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
image_type = gtk_type_unique (GIMP_TYPE_VIEWABLE, &image_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return image_type;
|
|
|
|
}
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
static void
|
|
|
|
gimp_image_class_init (GimpImageClass *klass)
|
|
|
|
{
|
2001-02-05 06:10:54 +08:00
|
|
|
GtkObjectClass *object_class;
|
|
|
|
GimpObjectClass *gimp_object_class;
|
|
|
|
GimpViewableClass *viewable_class;
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2001-01-14 11:55:56 +08:00
|
|
|
object_class = (GtkObjectClass *) klass;
|
|
|
|
gimp_object_class = (GimpObjectClass *) klass;
|
2001-02-05 06:10:54 +08:00
|
|
|
viewable_class = (GimpViewableClass *) klass;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
parent_class = gtk_type_class (GIMP_TYPE_VIEWABLE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-05-07 00:14:34 +08:00
|
|
|
gimp_image_signals[MODE_CHANGED] =
|
|
|
|
gtk_signal_new ("mode_changed",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
mode_changed),
|
|
|
|
gtk_signal_default_marshaller,
|
|
|
|
GTK_TYPE_NONE, 0);
|
|
|
|
|
2001-05-07 02:58:04 +08:00
|
|
|
gimp_image_signals[ALPHA_CHANGED] =
|
|
|
|
gtk_signal_new ("alpha_changed",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
alpha_changed),
|
|
|
|
gtk_signal_default_marshaller,
|
|
|
|
GTK_TYPE_NONE, 0);
|
|
|
|
|
2001-05-08 09:32:25 +08:00
|
|
|
gimp_image_signals[FLOATING_SELECTION_CHANGED] =
|
|
|
|
gtk_signal_new ("floating_selection_changed",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
floating_selection_changed),
|
|
|
|
gtk_signal_default_marshaller,
|
|
|
|
GTK_TYPE_NONE, 0);
|
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
gimp_image_signals[ACTIVE_LAYER_CHANGED] =
|
|
|
|
gtk_signal_new ("active_layer_changed",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
active_layer_changed),
|
|
|
|
gtk_signal_default_marshaller,
|
|
|
|
GTK_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
gimp_image_signals[ACTIVE_CHANNEL_CHANGED] =
|
|
|
|
gtk_signal_new ("active_channel_changed",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
active_channel_changed),
|
|
|
|
gtk_signal_default_marshaller,
|
|
|
|
GTK_TYPE_NONE, 0);
|
|
|
|
|
2001-05-03 20:26:05 +08:00
|
|
|
gimp_image_signals[COMPONENT_VISIBILITY_CHANGED] =
|
|
|
|
gtk_signal_new ("component_visibility_changed",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
component_visibility_changed),
|
|
|
|
gtk_marshal_NONE__INT,
|
|
|
|
GTK_TYPE_NONE, 1,
|
|
|
|
GTK_TYPE_INT);
|
|
|
|
|
|
|
|
gimp_image_signals[COMPONENT_ACTIVE_CHANGED] =
|
|
|
|
gtk_signal_new ("component_active_changed",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
component_active_changed),
|
|
|
|
gtk_marshal_NONE__INT,
|
|
|
|
GTK_TYPE_NONE, 1,
|
|
|
|
GTK_TYPE_INT);
|
|
|
|
|
2001-06-01 03:53:13 +08:00
|
|
|
gimp_image_signals[MASK_CHANGED] =
|
|
|
|
gtk_signal_new ("mask_changed",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
mask_changed),
|
|
|
|
gtk_signal_default_marshaller,
|
|
|
|
GTK_TYPE_NONE, 0);
|
|
|
|
|
1999-08-23 22:34:58 +08:00
|
|
|
gimp_image_signals[CLEAN] =
|
2001-01-10 08:36:54 +08:00
|
|
|
gtk_signal_new ("clean",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
clean),
|
|
|
|
gtk_signal_default_marshaller,
|
|
|
|
GTK_TYPE_NONE, 0);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_signals[DIRTY] =
|
2001-01-10 08:36:54 +08:00
|
|
|
gtk_signal_new ("dirty",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
dirty),
|
|
|
|
gtk_signal_default_marshaller,
|
|
|
|
GTK_TYPE_NONE, 0);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_signals[REPAINT] =
|
2001-01-10 08:36:54 +08:00
|
|
|
gtk_signal_new ("repaint",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
repaint),
|
|
|
|
gimp_marshal_NONE__INT_INT_INT_INT,
|
|
|
|
GTK_TYPE_NONE, 4,
|
|
|
|
GTK_TYPE_INT,
|
|
|
|
GTK_TYPE_INT,
|
|
|
|
GTK_TYPE_INT,
|
|
|
|
GTK_TYPE_INT);
|
|
|
|
|
1999-01-08 03:53:05 +08:00
|
|
|
gimp_image_signals[COLORMAP_CHANGED] =
|
2001-01-10 08:36:54 +08:00
|
|
|
gtk_signal_new ("colormap_changed",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
colormap_changed),
|
|
|
|
gtk_marshal_NONE__INT,
|
|
|
|
GTK_TYPE_NONE, 1,
|
|
|
|
GTK_TYPE_INT);
|
|
|
|
|
Honest, guv, it's not a feature - it's a tightly integrated package of
Mon Sep 20 12:51:30 EDT 1999 Austin Donnelly <austin@gimp.org>
Honest, guv, it's not a feature - it's a tightly integrated
package of undo system cleanups and fixes.
NEW FILES:
* app/undo_history.c: window showing recent undo (and redo) steps
available.
* app/undo_types.h: broken out of undo.h to fix circular includes.
MODIFIED FILES:
* app/Makefile.am: compile undo_history.c
* app/channel.h: use enum for channel undo type, not just magic
numbers.
* app/layer.h: same for layer undos.
* app/commands.c: edit_show_undo_history_cmd_callback() function to
pull up undo history window.
* app/commands.h: prototype for above.
* app/gdisplay.c: make undo / redo menu items sensitive according
to whether they would do anything. Would be easy to change
the text to say what would be undone/redone, but I don't know
the GTK.
* app/gimpimage.c: new signal emitted by gimage:
UNDO_EVENT. gimp_image_undo_event() function to emit it.
* app/gimpimage.h: prototype for above.
* app/gimpimageP.h: pushing_undo_group member is now an undo_type,
not an int. Keep undo history widget here too (if created).
* app/menus.c: add "Edit/Undo history..." to image menu.
* app/undo.c: new types: enums undo_type and undo_state rather than
ints and magic numbers. All undo_pop_* and undo_free_*
functions made static. New static function
undo_type_to_name(). Issue undo event signals on various
important events (eg undo pushed, undo popped etc).
undo_push() now takes a "dirties_image" arg to say whether
image should be dirtied. Layer moves now dirty the image. A
couple of g_return_if_fails () on undo_pop and undo_redo to
assert we're not in the middle of an undo group.
undo_get_{undo,redo}_name() to peek at names of top items on
undo and redo stacks resp. undo_map_over_{undo,redo}_stack()
to run a function for each item or group on stack. Layer and
channel undos use symbolic names rather than 0 or 1. Array
mapping undo types to names.
* app/undo.h: split out undo types to undo_types.h. Prototypes
for functions described above. undo_event_t enum.
undo_history_new() prototype lives here too.
Random other fixes:
* app/gimpdrawable.c
* app/image_render.c: default labels in switches to keep egcs happy.
* app/nav_window.c: some fixes to (sort of) cope with image res !=
screen res. Still needs work to handle non-square pixels
properly.
* app/paths_dialog.c: bad idea to call gimp_image_dirty()
directly. Even though it's currently commented out.
1999-09-21 01:15:20 +08:00
|
|
|
gimp_image_signals[UNDO_EVENT] =
|
2001-01-10 08:36:54 +08:00
|
|
|
gtk_signal_new ("undo_event",
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
object_class->type,
|
|
|
|
GTK_SIGNAL_OFFSET (GimpImageClass,
|
|
|
|
undo_event),
|
|
|
|
gtk_marshal_NONE__INT,
|
|
|
|
GTK_TYPE_NONE, 1,
|
|
|
|
GTK_TYPE_INT);
|
2001-03-05 09:01:16 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
gtk_object_class_add_signals (object_class, gimp_image_signals, LAST_SIGNAL);
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2001-05-03 20:26:05 +08:00
|
|
|
object_class->destroy = gimp_image_destroy;
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2001-05-03 20:26:05 +08:00
|
|
|
gimp_object_class->name_changed = gimp_image_name_changed;
|
2001-01-14 11:55:56 +08:00
|
|
|
|
2001-05-03 20:26:05 +08:00
|
|
|
viewable_class->invalidate_preview = gimp_image_invalidate_preview;
|
2001-06-18 21:10:03 +08:00
|
|
|
viewable_class->size_changed = gimp_image_size_changed;
|
2001-05-03 20:26:05 +08:00
|
|
|
viewable_class->get_preview = gimp_image_get_preview;
|
|
|
|
viewable_class->get_new_preview = gimp_image_get_new_preview;
|
2001-02-05 06:10:54 +08:00
|
|
|
|
2001-05-07 01:56:10 +08:00
|
|
|
klass->mode_changed = NULL;
|
2001-05-07 02:58:04 +08:00
|
|
|
klass->alpha_changed = NULL;
|
2001-05-08 09:32:25 +08:00
|
|
|
klass->floating_selection_changed = NULL;
|
2001-05-03 20:26:05 +08:00
|
|
|
klass->active_layer_changed = NULL;
|
|
|
|
klass->active_channel_changed = NULL;
|
|
|
|
klass->component_visibility_changed = NULL;
|
|
|
|
klass->component_active_changed = NULL;
|
2001-06-01 03:53:13 +08:00
|
|
|
klass->mask_changed = NULL;
|
2001-05-07 01:56:10 +08:00
|
|
|
|
2001-05-03 20:26:05 +08:00
|
|
|
klass->clean = NULL;
|
|
|
|
klass->dirty = NULL;
|
|
|
|
klass->repaint = NULL;
|
2001-05-15 19:25:25 +08:00
|
|
|
klass->colormap_changed = gimp_image_real_colormap_changed;
|
2001-05-03 20:26:05 +08:00
|
|
|
klass->undo_event = NULL;
|
|
|
|
klass->undo = gimp_image_undo;
|
|
|
|
klass->redo = gimp_image_redo;
|
2001-05-15 19:25:25 +08:00
|
|
|
|
|
|
|
gimp_image_color_hash_init ();
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* static functions */
|
|
|
|
|
1999-07-20 03:46:05 +08:00
|
|
|
static void
|
|
|
|
gimp_image_init (GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-04-13 22:50:43 +08:00
|
|
|
gimage->ID = global_image_ID++;
|
|
|
|
|
2001-01-15 12:37:01 +08:00
|
|
|
gimage->save_proc = NULL;
|
|
|
|
|
|
|
|
gimage->width = 0;
|
|
|
|
gimage->height = 0;
|
2001-06-04 04:40:50 +08:00
|
|
|
gimage->xresolution = gimprc.default_xresolution;
|
|
|
|
gimage->yresolution = gimprc.default_yresolution;
|
|
|
|
gimage->unit = gimprc.default_units;
|
2001-01-15 12:37:01 +08:00
|
|
|
gimage->base_type = RGB;
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->cmap = NULL;
|
2001-01-15 12:37:01 +08:00
|
|
|
gimage->num_cols = 0;
|
|
|
|
|
2000-08-24 03:29:01 +08:00
|
|
|
gimage->dirty = 1;
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->undo_on = TRUE;
|
2001-01-15 12:37:01 +08:00
|
|
|
|
|
|
|
gimage->instance_count = 0;
|
|
|
|
gimage->disp_count = 0;
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->tattoo_state = 0;
|
2001-01-15 12:37:01 +08:00
|
|
|
|
|
|
|
gimage->shadow = NULL;
|
|
|
|
|
|
|
|
gimage->construct_flag = -1;
|
|
|
|
gimage->proj_type = RGBA_GIMAGE;
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->projection = NULL;
|
2001-01-15 12:37:01 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->guides = NULL;
|
2001-01-15 12:37:01 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gimage->layers = gimp_list_new (GIMP_TYPE_LAYER,
|
|
|
|
GIMP_CONTAINER_POLICY_STRONG);
|
|
|
|
gimage->channels = gimp_list_new (GIMP_TYPE_CHANNEL,
|
|
|
|
GIMP_CONTAINER_POLICY_STRONG);
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->layer_stack = NULL;
|
2001-01-15 12:37:01 +08:00
|
|
|
|
|
|
|
gimage->active_layer = NULL;
|
|
|
|
gimage->active_channel = NULL;
|
|
|
|
gimage->floating_sel = NULL;
|
|
|
|
gimage->selection_mask = NULL;
|
|
|
|
|
2001-07-05 06:59:25 +08:00
|
|
|
gimage->parasites = gimp_parasite_list_new ();
|
2001-01-15 12:37:01 +08:00
|
|
|
|
|
|
|
gimage->paths = NULL;
|
|
|
|
|
|
|
|
gimage->qmask_state = FALSE;
|
|
|
|
gimage->qmask_color.r = 1.0;
|
|
|
|
gimage->qmask_color.g = 0.0;
|
|
|
|
gimage->qmask_color.b = 0.0;
|
|
|
|
gimage->qmask_color.a = 0.5;
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->undo_stack = NULL;
|
|
|
|
gimage->redo_stack = NULL;
|
|
|
|
gimage->undo_bytes = 0;
|
|
|
|
gimage->undo_levels = 0;
|
1999-08-23 22:34:58 +08:00
|
|
|
gimage->group_count = 0;
|
1999-12-11 04:55:57 +08:00
|
|
|
gimage->pushing_undo_group = UNDO_NULL;
|
2001-01-15 12:37:01 +08:00
|
|
|
gimage->undo_history = NULL;
|
|
|
|
|
2001-03-05 09:01:16 +08:00
|
|
|
gimage->new_undo_stack = gimp_undo_stack_new (gimage);
|
|
|
|
gimage->new_redo_stack = gimp_undo_stack_new (gimage);
|
|
|
|
|
2001-01-15 12:37:01 +08:00
|
|
|
gimage->comp_preview = NULL;
|
2001-02-05 06:10:54 +08:00
|
|
|
gimage->comp_preview_valid = FALSE;
|
2001-04-13 22:50:43 +08:00
|
|
|
|
|
|
|
if (gimp_image_table == NULL)
|
|
|
|
gimp_image_table = g_hash_table_new (g_direct_hash, NULL);
|
|
|
|
|
|
|
|
g_hash_table_insert (gimp_image_table,
|
|
|
|
GINT_TO_POINTER (gimage->ID),
|
|
|
|
(gpointer) gimage);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
static void
|
|
|
|
gimp_image_destroy (GtkObject *object)
|
1999-07-20 03:46:05 +08:00
|
|
|
{
|
2001-04-13 22:50:43 +08:00
|
|
|
GimpImage *gimage;
|
|
|
|
|
|
|
|
gimage = GIMP_IMAGE (object);
|
|
|
|
|
|
|
|
g_hash_table_remove (gimp_image_table, GINT_TO_POINTER (gimage->ID));
|
2001-01-10 08:36:54 +08:00
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
gimp_image_free_projection (gimage);
|
|
|
|
gimp_image_free_shadow (gimage);
|
|
|
|
|
|
|
|
if (gimage->cmap)
|
|
|
|
g_free (gimage->cmap);
|
2001-02-19 21:06:09 +08:00
|
|
|
|
|
|
|
gtk_object_unref (GTK_OBJECT (gimage->layers));
|
|
|
|
gtk_object_unref (GTK_OBJECT (gimage->channels));
|
|
|
|
g_slist_free (gimage->layer_stack);
|
2001-02-05 06:10:54 +08:00
|
|
|
|
|
|
|
gtk_object_unref (GTK_OBJECT (gimage->selection_mask));
|
2001-01-10 08:36:54 +08:00
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
if (gimage->comp_preview)
|
|
|
|
temp_buf_free (gimage->comp_preview);
|
|
|
|
|
|
|
|
if (gimage->parasites)
|
|
|
|
gtk_object_unref (GTK_OBJECT (gimage->parasites));
|
2001-03-05 09:01:16 +08:00
|
|
|
|
2001-05-16 03:10:57 +08:00
|
|
|
g_list_foreach (gimage->guides, (GFunc) g_free, NULL);
|
|
|
|
g_list_free (gimage->guides);
|
|
|
|
|
2001-03-05 09:01:16 +08:00
|
|
|
gtk_object_unref (GTK_OBJECT (gimage->new_undo_stack));
|
|
|
|
gtk_object_unref (GTK_OBJECT (gimage->new_redo_stack));
|
2001-02-05 06:10:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_image_name_changed (GimpObject *object)
|
|
|
|
{
|
|
|
|
GimpImage *gimage;
|
|
|
|
const gchar *name;
|
|
|
|
|
|
|
|
if (GIMP_OBJECT_CLASS (parent_class)->name_changed)
|
|
|
|
GIMP_OBJECT_CLASS (parent_class)->name_changed (object);
|
|
|
|
|
|
|
|
gimage = GIMP_IMAGE (object);
|
|
|
|
name = gimp_object_get_name (object);
|
|
|
|
|
|
|
|
if (! (name && strlen (name)))
|
|
|
|
{
|
|
|
|
g_free (object->name);
|
|
|
|
object->name = NULL;
|
2001-01-10 08:36:54 +08:00
|
|
|
}
|
2001-02-05 06:10:54 +08:00
|
|
|
}
|
2001-01-10 08:36:54 +08:00
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
static void
|
|
|
|
gimp_image_invalidate_preview (GimpViewable *viewable)
|
|
|
|
{
|
|
|
|
GimpImage *gimage;
|
|
|
|
|
2001-05-07 00:14:34 +08:00
|
|
|
if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview)
|
|
|
|
GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable);
|
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
gimage = GIMP_IMAGE (viewable);
|
|
|
|
|
|
|
|
gimage->comp_preview_valid = FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-06-18 21:10:03 +08:00
|
|
|
static void
|
|
|
|
gimp_image_size_changed (GimpViewable *viewable)
|
|
|
|
{
|
|
|
|
GimpImage *gimage;
|
|
|
|
|
|
|
|
if (GIMP_VIEWABLE_CLASS (parent_class)->size_changed)
|
|
|
|
GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable);
|
|
|
|
|
|
|
|
gimage = GIMP_IMAGE (viewable);
|
|
|
|
|
|
|
|
gimp_image_invalidate_layer_previews (gimage);
|
|
|
|
gimp_image_invalidate_channel_previews (gimage);
|
|
|
|
}
|
|
|
|
|
2001-05-15 19:25:25 +08:00
|
|
|
static void
|
|
|
|
gimp_image_real_colormap_changed (GimpImage *gimage,
|
|
|
|
gint ncol)
|
|
|
|
{
|
|
|
|
if (gimp_image_base_type (gimage) == INDEXED)
|
|
|
|
gimp_image_color_hash_invalidate (gimage, ncol);
|
|
|
|
}
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
static void
|
|
|
|
gimp_image_allocate_projection (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
if (gimage->projection)
|
|
|
|
gimp_image_free_projection (gimage);
|
|
|
|
|
|
|
|
/* Find the number of bytes required for the projection.
|
|
|
|
* This includes the intensity channels and an alpha channel
|
|
|
|
* if one doesn't exist.
|
|
|
|
*/
|
|
|
|
switch (gimp_image_base_type (gimage))
|
|
|
|
{
|
|
|
|
case RGB:
|
|
|
|
case INDEXED:
|
|
|
|
gimage->proj_bytes = 4;
|
|
|
|
gimage->proj_type = RGBA_GIMAGE;
|
|
|
|
break;
|
|
|
|
case GRAY:
|
|
|
|
gimage->proj_bytes = 2;
|
|
|
|
gimage->proj_type = GRAYA_GIMAGE;
|
|
|
|
break;
|
|
|
|
default:
|
1999-08-22 19:45:31 +08:00
|
|
|
g_assert_not_reached ();
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate the new projection */
|
2001-01-15 12:37:01 +08:00
|
|
|
gimage->projection = tile_manager_new (gimage->width, gimage->height,
|
|
|
|
gimage->proj_bytes);
|
1998-07-29 07:13:36 +08:00
|
|
|
tile_manager_set_user_data (gimage->projection, (void *) gimage);
|
1998-06-28 18:39:58 +08:00
|
|
|
tile_manager_set_validate_proc (gimage->projection, gimp_image_validate);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_image_free_projection (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
if (gimage->projection)
|
|
|
|
tile_manager_destroy (gimage->projection);
|
|
|
|
|
|
|
|
gimage->projection = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-07-20 03:46:05 +08:00
|
|
|
gimp_image_allocate_shadow (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gint bpp)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
/* allocate the new projection */
|
|
|
|
gimage->shadow = tile_manager_new (width, height, bpp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* function definitions */
|
|
|
|
|
|
|
|
GimpImage *
|
2001-07-05 03:31:35 +08:00
|
|
|
gimp_image_new (Gimp *gimp,
|
|
|
|
gint width,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint height,
|
|
|
|
GimpImageBaseType base_type)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-07-05 03:31:35 +08:00
|
|
|
GimpImage *gimage;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_return_val_if_fail (gimp != NULL, NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
|
|
|
|
|
|
|
gimage = GIMP_IMAGE (gtk_type_new (GIMP_TYPE_IMAGE));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-07-05 03:31:35 +08:00
|
|
|
gimage->gimp = gimp;
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->width = width;
|
|
|
|
gimage->height = height;
|
1998-06-28 18:39:58 +08:00
|
|
|
gimage->base_type = base_type;
|
|
|
|
|
|
|
|
switch (base_type)
|
|
|
|
{
|
|
|
|
case RGB:
|
|
|
|
case GRAY:
|
|
|
|
break;
|
|
|
|
case INDEXED:
|
|
|
|
/* always allocate 256 colors for the colormap */
|
|
|
|
gimage->num_cols = 0;
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->cmap = (guchar *) g_malloc0 (COLORMAP_SIZE);
|
1998-06-28 18:39:58 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set all color channels visible and active */
|
|
|
|
for (i = 0; i < MAX_CHANNELS; i++)
|
|
|
|
{
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->visible[i] = TRUE;
|
|
|
|
gimage->active[i] = TRUE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* create the selection mask */
|
2001-01-29 10:45:02 +08:00
|
|
|
gimage->selection_mask = gimp_channel_new_mask (gimage,
|
|
|
|
gimage->width,
|
|
|
|
gimage->height);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
|
|
|
|
return gimage;
|
|
|
|
}
|
|
|
|
|
2001-04-13 22:50:43 +08:00
|
|
|
gint
|
|
|
|
gimp_image_get_ID (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (gimage != NULL, -1);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1);
|
|
|
|
|
|
|
|
return gimage->ID;
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpImage *
|
|
|
|
gimp_image_get_by_ID (gint image_id)
|
|
|
|
{
|
|
|
|
if (gimp_image_table == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return (GimpImage *) g_hash_table_lookup (gimp_image_table,
|
|
|
|
GINT_TO_POINTER (image_id));
|
|
|
|
}
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
void
|
2001-01-14 11:55:56 +08:00
|
|
|
gimp_image_set_filename (GimpImage *gimage,
|
|
|
|
const gchar *filename)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-14 11:55:56 +08:00
|
|
|
gimp_object_set_name (GIMP_OBJECT (gimage), filename);
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
1998-10-05 18:05:29 +08:00
|
|
|
void
|
1998-11-15 07:28:47 +08:00
|
|
|
gimp_image_set_resolution (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gdouble xresolution,
|
|
|
|
gdouble yresolution)
|
1998-10-05 18:05:29 +08:00
|
|
|
{
|
comment typo fix, plus add %D* to default image-title-format string, so
Fri Oct 1 12:46:12 1999 Austin Donnelly <austin@gimp.org>
* gimprc.in: comment typo fix, plus add %D* to default
image-title-format string, so people get a '*' in the titlebar
if their image is dirty.
* app/fileops.c: initialise filename before using it.
* app/gdisplay.c: empty parameter list () is K&R - should be
stronger (void) in ANSI C.
* app/gimpdrawable.c: gimp_drawable_{dirty,clean} functions
removed - no one uses them anyway. Parasite undo type is
proper parasite undo type, not MISC_UNDO.
* app/gimpdrawableP.h: drawable dirty bit removed.
* app/gimpimage.c: don't change the resolution if there's no
difference from the old one. Call gdisplay_shrink_wrap() to
re-calculate scale factors and refresh the display on
resolution change. Layer undo doesn't have sub-types
anymore, uses main UndoType instead.
* app/layer.h: Remove LayerUndoType
* app/qmask.c: fix qmask undo so it actually works.
* app/undo.h: new types for undo_push_layer{,_mask} and
undo_push_qmask.
* app/undo.c: change way group boundaries are represented:
each Undo has a group_boundary boolean set to TRUE if this is
the start or the end of a group, and the type of the Undo is
the group's type. Within a group, each Undo keeps its own
type. This allows pop funcs and free funcs to do
type-specific things (eg needed by layer and channel stuff).
Don't maintain per-drawable dirty flags anymore. Floating
sel to layer and layer rename now uses meaningful undo types.
* app/undo_types.h: more specific undo types:
LAYER_{ADD,REMOVE}_UNDO, LAYER_MASK_{ADD,REMOVE}_UNDO,
LAYER_RENAME_UNDO, and PARASITE_{ATTACH,DETACH}_UNDO.
* app/undo_history.c: oops - undo stack was being placed into gtk
list in wrong order.
* app/edit_selection.c: push more descriptive LAYER_DISPLACE_UNDO
rather than MISC_UNDO.
* app/layers_dialog.c: better tagging of undo types
1999-10-02 02:43:24 +08:00
|
|
|
/* nothing to do if setting res to the same as before */
|
|
|
|
if ((ABS (gimage->xresolution - xresolution) < 1e-5) &&
|
|
|
|
(ABS (gimage->yresolution - yresolution) < 1e-5))
|
|
|
|
return;
|
|
|
|
|
2000-01-08 20:42:53 +08:00
|
|
|
/* don't allow to set the resolution out of bounds */
|
|
|
|
if (xresolution < GIMP_MIN_RESOLUTION || xresolution > GIMP_MAX_RESOLUTION ||
|
|
|
|
yresolution < GIMP_MIN_RESOLUTION || yresolution > GIMP_MAX_RESOLUTION)
|
2000-01-08 18:55:05 +08:00
|
|
|
return;
|
|
|
|
|
1999-09-30 00:44:52 +08:00
|
|
|
undo_push_resolution (gimage);
|
comment typo fix, plus add %D* to default image-title-format string, so
Fri Oct 1 12:46:12 1999 Austin Donnelly <austin@gimp.org>
* gimprc.in: comment typo fix, plus add %D* to default
image-title-format string, so people get a '*' in the titlebar
if their image is dirty.
* app/fileops.c: initialise filename before using it.
* app/gdisplay.c: empty parameter list () is K&R - should be
stronger (void) in ANSI C.
* app/gimpdrawable.c: gimp_drawable_{dirty,clean} functions
removed - no one uses them anyway. Parasite undo type is
proper parasite undo type, not MISC_UNDO.
* app/gimpdrawableP.h: drawable dirty bit removed.
* app/gimpimage.c: don't change the resolution if there's no
difference from the old one. Call gdisplay_shrink_wrap() to
re-calculate scale factors and refresh the display on
resolution change. Layer undo doesn't have sub-types
anymore, uses main UndoType instead.
* app/layer.h: Remove LayerUndoType
* app/qmask.c: fix qmask undo so it actually works.
* app/undo.h: new types for undo_push_layer{,_mask} and
undo_push_qmask.
* app/undo.c: change way group boundaries are represented:
each Undo has a group_boundary boolean set to TRUE if this is
the start or the end of a group, and the type of the Undo is
the group's type. Within a group, each Undo keeps its own
type. This allows pop funcs and free funcs to do
type-specific things (eg needed by layer and channel stuff).
Don't maintain per-drawable dirty flags anymore. Floating
sel to layer and layer rename now uses meaningful undo types.
* app/undo_types.h: more specific undo types:
LAYER_{ADD,REMOVE}_UNDO, LAYER_MASK_{ADD,REMOVE}_UNDO,
LAYER_RENAME_UNDO, and PARASITE_{ATTACH,DETACH}_UNDO.
* app/undo_history.c: oops - undo stack was being placed into gtk
list in wrong order.
* app/edit_selection.c: push more descriptive LAYER_DISPLACE_UNDO
rather than MISC_UNDO.
* app/layers_dialog.c: better tagging of undo types
1999-10-02 02:43:24 +08:00
|
|
|
|
1998-11-15 07:28:47 +08:00
|
|
|
gimage->xresolution = xresolution;
|
|
|
|
gimage->yresolution = yresolution;
|
comment typo fix, plus add %D* to default image-title-format string, so
Fri Oct 1 12:46:12 1999 Austin Donnelly <austin@gimp.org>
* gimprc.in: comment typo fix, plus add %D* to default
image-title-format string, so people get a '*' in the titlebar
if their image is dirty.
* app/fileops.c: initialise filename before using it.
* app/gdisplay.c: empty parameter list () is K&R - should be
stronger (void) in ANSI C.
* app/gimpdrawable.c: gimp_drawable_{dirty,clean} functions
removed - no one uses them anyway. Parasite undo type is
proper parasite undo type, not MISC_UNDO.
* app/gimpdrawableP.h: drawable dirty bit removed.
* app/gimpimage.c: don't change the resolution if there's no
difference from the old one. Call gdisplay_shrink_wrap() to
re-calculate scale factors and refresh the display on
resolution change. Layer undo doesn't have sub-types
anymore, uses main UndoType instead.
* app/layer.h: Remove LayerUndoType
* app/qmask.c: fix qmask undo so it actually works.
* app/undo.h: new types for undo_push_layer{,_mask} and
undo_push_qmask.
* app/undo.c: change way group boundaries are represented:
each Undo has a group_boundary boolean set to TRUE if this is
the start or the end of a group, and the type of the Undo is
the group's type. Within a group, each Undo keeps its own
type. This allows pop funcs and free funcs to do
type-specific things (eg needed by layer and channel stuff).
Don't maintain per-drawable dirty flags anymore. Floating
sel to layer and layer rename now uses meaningful undo types.
* app/undo_types.h: more specific undo types:
LAYER_{ADD,REMOVE}_UNDO, LAYER_MASK_{ADD,REMOVE}_UNDO,
LAYER_RENAME_UNDO, and PARASITE_{ATTACH,DETACH}_UNDO.
* app/undo_history.c: oops - undo stack was being placed into gtk
list in wrong order.
* app/edit_selection.c: push more descriptive LAYER_DISPLACE_UNDO
rather than MISC_UNDO.
* app/layers_dialog.c: better tagging of undo types
1999-10-02 02:43:24 +08:00
|
|
|
|
|
|
|
/* really just want to recalc size and repaint */
|
|
|
|
gdisplays_shrink_wrap (gimage);
|
1998-10-05 18:05:29 +08:00
|
|
|
}
|
|
|
|
|
1998-11-15 07:28:47 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_resolution (const GimpImage *gimage,
|
|
|
|
gdouble *xresolution,
|
|
|
|
gdouble *yresolution)
|
1998-10-05 18:05:29 +08:00
|
|
|
{
|
1999-08-22 19:45:31 +08:00
|
|
|
g_return_if_fail (xresolution && yresolution);
|
|
|
|
|
1998-11-15 07:28:47 +08:00
|
|
|
*xresolution = gimage->xresolution;
|
|
|
|
*yresolution = gimage->yresolution;
|
1998-10-05 18:05:29 +08:00
|
|
|
}
|
|
|
|
|
Add default to Cancel button, remove unset GTK_RECEIVES_DEFAULT from
Sat Feb 20 16:12:33 CST 1999 Shawn T. Amundson <amundson@gimp.org>
* app/tips_dialog.c: Add default to Cancel button, remove
unset GTK_RECEIVES_DEFAULT from prev/next buttons (they
are like toolbar buttons), changed abreviated prev to
previous, prev/next button are now same size, cancel button
is in a button box. Added vboxes where necessary to prevent
prev/next and check button from filling vertically.
* app/app_procs.c: when splashscreen dialog is larger than the
logo, (due to huge font), center logo.
* app/file_new_dialog.c: patch from Marco Lamb <lm@geocities.com>
disallows resizing, changes vertical expanding of widgets to
not occur
* app/palette.c: patch from Marco Lamb <lm@geocities.com>. Makes
+/- buttons for zoom pixmaps (eventually, these can be replaced
with a magnifying glass with a little +/- I think), so that they
no longer expand as they did before. I modified his patch so it
did not create a misused toolbar. I did some other stuff here too,
moved Close button to the left, made it the window's default,
and unset GTK_RECEIVES_DEFAULT off of the non-bottom buttons.
* app/actionarea.c: another patch from Marco Lamb <lm@geocities.com>.
This one changes buttons to be put in a button box which is right
justified. If we decide later that spread is better, we can
change this easy enough.
* app/tools/zoom_in.xpm, app/tools/zoom_out.xpm: + and - graphics.
* libgimp/gimpunit.h
libgimp/gimpunit.c: New files from Michael Natterer
<mitschel@cs.tu-berlin.de>, gimp_unit_* routines.
* app/gimage.h
app/gimpimage.h
app/gimpimage.c
app/gimpimageP.h
app/xcf.c: Patches from Michael Natterer <mitschel@cs.tu-berlin.de>,
which keep a unit assocated with an image.
1999-02-21 10:08:15 +08:00
|
|
|
void
|
|
|
|
gimp_image_set_unit (GimpImage *gimage,
|
2000-02-08 04:35:13 +08:00
|
|
|
GimpUnit unit)
|
Add default to Cancel button, remove unset GTK_RECEIVES_DEFAULT from
Sat Feb 20 16:12:33 CST 1999 Shawn T. Amundson <amundson@gimp.org>
* app/tips_dialog.c: Add default to Cancel button, remove
unset GTK_RECEIVES_DEFAULT from prev/next buttons (they
are like toolbar buttons), changed abreviated prev to
previous, prev/next button are now same size, cancel button
is in a button box. Added vboxes where necessary to prevent
prev/next and check button from filling vertically.
* app/app_procs.c: when splashscreen dialog is larger than the
logo, (due to huge font), center logo.
* app/file_new_dialog.c: patch from Marco Lamb <lm@geocities.com>
disallows resizing, changes vertical expanding of widgets to
not occur
* app/palette.c: patch from Marco Lamb <lm@geocities.com>. Makes
+/- buttons for zoom pixmaps (eventually, these can be replaced
with a magnifying glass with a little +/- I think), so that they
no longer expand as they did before. I modified his patch so it
did not create a misused toolbar. I did some other stuff here too,
moved Close button to the left, made it the window's default,
and unset GTK_RECEIVES_DEFAULT off of the non-bottom buttons.
* app/actionarea.c: another patch from Marco Lamb <lm@geocities.com>.
This one changes buttons to be put in a button box which is right
justified. If we decide later that spread is better, we can
change this easy enough.
* app/tools/zoom_in.xpm, app/tools/zoom_out.xpm: + and - graphics.
* libgimp/gimpunit.h
libgimp/gimpunit.c: New files from Michael Natterer
<mitschel@cs.tu-berlin.de>, gimp_unit_* routines.
* app/gimage.h
app/gimpimage.h
app/gimpimage.c
app/gimpimageP.h
app/xcf.c: Patches from Michael Natterer <mitschel@cs.tu-berlin.de>,
which keep a unit assocated with an image.
1999-02-21 10:08:15 +08:00
|
|
|
{
|
1999-09-30 00:44:52 +08:00
|
|
|
undo_push_resolution (gimage);
|
|
|
|
|
Add default to Cancel button, remove unset GTK_RECEIVES_DEFAULT from
Sat Feb 20 16:12:33 CST 1999 Shawn T. Amundson <amundson@gimp.org>
* app/tips_dialog.c: Add default to Cancel button, remove
unset GTK_RECEIVES_DEFAULT from prev/next buttons (they
are like toolbar buttons), changed abreviated prev to
previous, prev/next button are now same size, cancel button
is in a button box. Added vboxes where necessary to prevent
prev/next and check button from filling vertically.
* app/app_procs.c: when splashscreen dialog is larger than the
logo, (due to huge font), center logo.
* app/file_new_dialog.c: patch from Marco Lamb <lm@geocities.com>
disallows resizing, changes vertical expanding of widgets to
not occur
* app/palette.c: patch from Marco Lamb <lm@geocities.com>. Makes
+/- buttons for zoom pixmaps (eventually, these can be replaced
with a magnifying glass with a little +/- I think), so that they
no longer expand as they did before. I modified his patch so it
did not create a misused toolbar. I did some other stuff here too,
moved Close button to the left, made it the window's default,
and unset GTK_RECEIVES_DEFAULT off of the non-bottom buttons.
* app/actionarea.c: another patch from Marco Lamb <lm@geocities.com>.
This one changes buttons to be put in a button box which is right
justified. If we decide later that spread is better, we can
change this easy enough.
* app/tools/zoom_in.xpm, app/tools/zoom_out.xpm: + and - graphics.
* libgimp/gimpunit.h
libgimp/gimpunit.c: New files from Michael Natterer
<mitschel@cs.tu-berlin.de>, gimp_unit_* routines.
* app/gimage.h
app/gimpimage.h
app/gimpimage.c
app/gimpimageP.h
app/xcf.c: Patches from Michael Natterer <mitschel@cs.tu-berlin.de>,
which keep a unit assocated with an image.
1999-02-21 10:08:15 +08:00
|
|
|
gimage->unit = unit;
|
|
|
|
}
|
|
|
|
|
2000-02-08 04:35:13 +08:00
|
|
|
GimpUnit
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_unit (const GimpImage *gimage)
|
Add default to Cancel button, remove unset GTK_RECEIVES_DEFAULT from
Sat Feb 20 16:12:33 CST 1999 Shawn T. Amundson <amundson@gimp.org>
* app/tips_dialog.c: Add default to Cancel button, remove
unset GTK_RECEIVES_DEFAULT from prev/next buttons (they
are like toolbar buttons), changed abreviated prev to
previous, prev/next button are now same size, cancel button
is in a button box. Added vboxes where necessary to prevent
prev/next and check button from filling vertically.
* app/app_procs.c: when splashscreen dialog is larger than the
logo, (due to huge font), center logo.
* app/file_new_dialog.c: patch from Marco Lamb <lm@geocities.com>
disallows resizing, changes vertical expanding of widgets to
not occur
* app/palette.c: patch from Marco Lamb <lm@geocities.com>. Makes
+/- buttons for zoom pixmaps (eventually, these can be replaced
with a magnifying glass with a little +/- I think), so that they
no longer expand as they did before. I modified his patch so it
did not create a misused toolbar. I did some other stuff here too,
moved Close button to the left, made it the window's default,
and unset GTK_RECEIVES_DEFAULT off of the non-bottom buttons.
* app/actionarea.c: another patch from Marco Lamb <lm@geocities.com>.
This one changes buttons to be put in a button box which is right
justified. If we decide later that spread is better, we can
change this easy enough.
* app/tools/zoom_in.xpm, app/tools/zoom_out.xpm: + and - graphics.
* libgimp/gimpunit.h
libgimp/gimpunit.c: New files from Michael Natterer
<mitschel@cs.tu-berlin.de>, gimp_unit_* routines.
* app/gimage.h
app/gimpimage.h
app/gimpimage.c
app/gimpimageP.h
app/xcf.c: Patches from Michael Natterer <mitschel@cs.tu-berlin.de>,
which keep a unit assocated with an image.
1999-02-21 10:08:15 +08:00
|
|
|
{
|
|
|
|
return gimage->unit;
|
|
|
|
}
|
|
|
|
|
1998-10-27 17:26:38 +08:00
|
|
|
void
|
1999-07-20 03:46:05 +08:00
|
|
|
gimp_image_set_save_proc (GimpImage *gimage,
|
|
|
|
PlugInProcDef *proc)
|
1998-10-27 17:26:38 +08:00
|
|
|
{
|
|
|
|
gimage->save_proc = proc;
|
|
|
|
}
|
|
|
|
|
|
|
|
PlugInProcDef *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_save_proc (const GimpImage *gimage)
|
1998-10-27 17:26:38 +08:00
|
|
|
{
|
|
|
|
return gimage->save_proc;
|
|
|
|
}
|
1998-10-05 18:05:29 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
gint
|
|
|
|
gimp_image_get_width (const GimpImage *gimage)
|
|
|
|
{
|
|
|
|
return gimage->width;
|
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
gimp_image_get_height (const GimpImage *gimage)
|
|
|
|
{
|
|
|
|
return gimage->height;
|
|
|
|
}
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_resize (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *channel;
|
|
|
|
GimpLayer *layer;
|
|
|
|
GimpLayer *floating_layer;
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2001-01-29 10:45:02 +08:00
|
|
|
GList *guide_list;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-05-14 05:51:20 +08:00
|
|
|
gimp_set_busy ();
|
1999-01-11 07:36:29 +08:00
|
|
|
|
1998-06-30 09:14:36 +08:00
|
|
|
g_assert (new_width > 0 && new_height > 0);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* Get the floating layer if one exists */
|
|
|
|
floating_layer = gimp_image_floating_sel (gimage);
|
|
|
|
|
1999-10-14 07:07:45 +08:00
|
|
|
undo_push_group_start (gimage, IMAGE_RESIZE_UNDO);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* Relax the floating selection */
|
|
|
|
if (floating_layer)
|
|
|
|
floating_sel_relax (floating_layer, TRUE);
|
|
|
|
|
|
|
|
/* Push the image size to the stack */
|
|
|
|
undo_push_gimage_mod (gimage);
|
|
|
|
|
|
|
|
/* Set the new width and height */
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->width = new_width;
|
1998-06-28 18:39:58 +08:00
|
|
|
gimage->height = new_height;
|
|
|
|
|
|
|
|
/* Resize all channels */
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->channels)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
channel = (GimpChannel *) list->data;
|
1999-07-10 02:15:39 +08:00
|
|
|
|
2001-01-29 10:45:02 +08:00
|
|
|
gimp_channel_resize (channel, new_width, new_height, offset_x, offset_y);
|
1999-07-10 02:15:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Reposition or remove any guides */
|
|
|
|
guide_list = gimage->guides;
|
|
|
|
while (guide_list)
|
|
|
|
{
|
2001-05-16 03:10:57 +08:00
|
|
|
GimpGuide *guide;
|
1999-07-10 02:15:39 +08:00
|
|
|
|
2001-05-16 03:10:57 +08:00
|
|
|
guide = (GimpGuide *) guide_list->data;
|
1999-07-20 03:46:05 +08:00
|
|
|
guide_list = g_list_next (guide_list);
|
1999-07-10 02:15:39 +08:00
|
|
|
|
|
|
|
switch (guide->orientation)
|
|
|
|
{
|
1999-07-29 07:00:08 +08:00
|
|
|
case ORIENTATION_HORIZONTAL:
|
1999-10-14 07:07:45 +08:00
|
|
|
undo_push_guide (gimage, guide);
|
1999-07-10 02:15:39 +08:00
|
|
|
guide->position += offset_y;
|
|
|
|
if (guide->position < 0 || guide->position > new_height)
|
|
|
|
gimp_image_delete_guide (gimage, guide);
|
|
|
|
break;
|
2000-12-28 02:15:37 +08:00
|
|
|
|
1999-07-29 07:00:08 +08:00
|
|
|
case ORIENTATION_VERTICAL:
|
1999-10-14 07:07:45 +08:00
|
|
|
undo_push_guide (gimage, guide);
|
1999-07-10 02:15:39 +08:00
|
|
|
guide->position += offset_x;
|
|
|
|
if (guide->position < 0 || guide->position > new_width)
|
|
|
|
gimp_image_delete_guide (gimage, guide);
|
|
|
|
break;
|
2000-12-28 02:15:37 +08:00
|
|
|
|
1999-07-10 02:15:39 +08:00
|
|
|
default:
|
2000-12-28 02:15:37 +08:00
|
|
|
g_error ("Unknown guide orientation\n");
|
1999-07-10 02:15:39 +08:00
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't forget the selection mask! */
|
2001-01-29 10:45:02 +08:00
|
|
|
gimp_channel_resize (gimage->selection_mask,
|
|
|
|
new_width, new_height, offset_x, offset_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
gimage_mask_invalidate (gimage);
|
|
|
|
|
|
|
|
/* Reposition all layers */
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
2000-12-28 02:15:37 +08:00
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
gimp_layer_translate (layer, offset_x, offset_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure the projection matches the gimage size */
|
|
|
|
gimp_image_projection_realloc (gimage);
|
|
|
|
|
|
|
|
/* Rigor the floating selection */
|
|
|
|
if (floating_layer)
|
|
|
|
floating_sel_rigor (floating_layer, TRUE);
|
|
|
|
|
2001-05-07 01:56:10 +08:00
|
|
|
undo_push_group_end (gimage);
|
|
|
|
|
2001-06-18 21:10:03 +08:00
|
|
|
gimp_viewable_size_changed (GIMP_VIEWABLE (gimage));
|
1999-01-11 07:36:29 +08:00
|
|
|
|
2001-05-14 05:51:20 +08:00
|
|
|
gimp_unset_busy ();
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_scale (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint new_width,
|
|
|
|
gint new_height)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *channel;
|
|
|
|
GimpLayer *layer;
|
|
|
|
GimpLayer *floating_layer;
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2001-01-29 10:45:02 +08:00
|
|
|
GSList *remove = NULL;
|
2001-02-19 21:06:09 +08:00
|
|
|
GSList *slist;
|
2001-05-16 03:10:57 +08:00
|
|
|
GimpGuide *guide;
|
2001-01-29 10:45:02 +08:00
|
|
|
gint old_width;
|
|
|
|
gint old_height;
|
|
|
|
gdouble img_scale_w = 1.0;
|
|
|
|
gdouble img_scale_h = 1.0;
|
2000-02-27 02:46:08 +08:00
|
|
|
|
2000-02-27 20:09:29 +08:00
|
|
|
if ((new_width == 0) || (new_height == 0))
|
2000-02-27 02:46:08 +08:00
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message ("%s(): Scaling to zero width or height has been rejected.",
|
|
|
|
G_GNUC_FUNCTION);
|
2000-02-27 02:46:08 +08:00
|
|
|
return;
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-05-14 05:51:20 +08:00
|
|
|
gimp_set_busy ();
|
1999-01-11 07:36:29 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* Get the floating layer if one exists */
|
|
|
|
floating_layer = gimp_image_floating_sel (gimage);
|
|
|
|
|
1999-10-14 07:07:45 +08:00
|
|
|
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* Relax the floating selection */
|
|
|
|
if (floating_layer)
|
|
|
|
floating_sel_relax (floating_layer, TRUE);
|
|
|
|
|
|
|
|
/* Push the image size to the stack */
|
|
|
|
undo_push_gimage_mod (gimage);
|
|
|
|
|
|
|
|
/* Set the new width and height */
|
2000-02-27 02:46:08 +08:00
|
|
|
|
|
|
|
old_width = gimage->width;
|
|
|
|
old_height = gimage->height;
|
1999-08-22 19:45:31 +08:00
|
|
|
gimage->width = new_width;
|
1998-06-28 18:39:58 +08:00
|
|
|
gimage->height = new_height;
|
2000-12-28 00:12:05 +08:00
|
|
|
img_scale_w = (gdouble) new_width / (gdouble) old_width;
|
|
|
|
img_scale_h = (gdouble) new_height / (gdouble) old_height;
|
2000-02-27 02:46:08 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* Scale all channels */
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->channels)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
channel = (GimpChannel *) list->data;
|
|
|
|
|
|
|
|
gimp_channel_scale (channel, new_width, new_height);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't forget the selection mask! */
|
2000-05-12 09:14:21 +08:00
|
|
|
/* if (channel_is_empty(gimage->selection_mask))
|
2001-01-29 10:45:02 +08:00
|
|
|
gimp_channel_resize(gimage->selection_mask, new_width, new_height, 0, 0)
|
2000-05-12 09:14:21 +08:00
|
|
|
else
|
|
|
|
*/
|
2001-06-05 07:11:31 +08:00
|
|
|
|
2001-01-29 10:45:02 +08:00
|
|
|
gimp_channel_scale (gimage->selection_mask, new_width, new_height);
|
1998-06-28 18:39:58 +08:00
|
|
|
gimage_mask_invalidate (gimage);
|
|
|
|
|
|
|
|
/* Scale all layers */
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
|
|
|
|
2001-06-05 07:11:31 +08:00
|
|
|
if (! gimp_layer_scale_by_factors (layer, img_scale_w, img_scale_h))
|
2000-02-27 02:46:08 +08:00
|
|
|
{
|
2000-12-28 00:12:05 +08:00
|
|
|
/* Since 0 < img_scale_w, img_scale_h, failure due to one or more
|
|
|
|
* vanishing scaled layer dimensions. Implicit delete implemented
|
|
|
|
* here. Upstream warning implemented in resize_check_layer_scaling()
|
|
|
|
* [resize.c line 1295], which offers the user the chance to bail out.
|
|
|
|
*/
|
2000-02-27 20:09:29 +08:00
|
|
|
remove = g_slist_append (remove, layer);
|
2000-02-27 02:46:08 +08:00
|
|
|
}
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-06-05 07:11:31 +08:00
|
|
|
/* We defer removing layers lost to scaling until now so as not to mix
|
|
|
|
* the operations of iterating over and removal from gimage->layers.
|
|
|
|
*/
|
2001-02-19 21:06:09 +08:00
|
|
|
for (slist = remove; slist; slist = g_slist_next (slist))
|
2000-02-27 02:46:08 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
layer = slist->data;
|
2000-12-29 23:22:01 +08:00
|
|
|
gimp_image_remove_layer (gimage, layer);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
2000-02-27 20:09:29 +08:00
|
|
|
g_slist_free (remove);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
1999-01-18 04:41:38 +08:00
|
|
|
/* Scale any Guides */
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = gimage->guides; list; list = g_list_next (list))
|
1999-01-18 04:41:38 +08:00
|
|
|
{
|
2001-05-16 03:10:57 +08:00
|
|
|
guide = (GimpGuide *) list->data;
|
1999-01-18 04:41:38 +08:00
|
|
|
|
|
|
|
switch (guide->orientation)
|
|
|
|
{
|
1999-07-29 07:00:08 +08:00
|
|
|
case ORIENTATION_HORIZONTAL:
|
1999-10-14 07:07:45 +08:00
|
|
|
undo_push_guide (gimage, guide);
|
1999-01-18 04:41:38 +08:00
|
|
|
guide->position = (guide->position * new_height) / old_height;
|
|
|
|
break;
|
1999-07-29 07:00:08 +08:00
|
|
|
case ORIENTATION_VERTICAL:
|
1999-10-14 07:07:45 +08:00
|
|
|
undo_push_guide (gimage, guide);
|
1999-01-18 04:41:38 +08:00
|
|
|
guide->position = (guide->position * new_width) / old_width;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_error("Unknown guide orientation II.\n");
|
|
|
|
}
|
|
|
|
}
|
1999-01-18 01:03:54 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* Make sure the projection matches the gimage size */
|
|
|
|
gimp_image_projection_realloc (gimage);
|
|
|
|
|
|
|
|
/* Rigor the floating selection */
|
|
|
|
if (floating_layer)
|
|
|
|
floating_sel_rigor (floating_layer, TRUE);
|
|
|
|
|
2001-05-07 01:56:10 +08:00
|
|
|
undo_push_group_end (gimage);
|
|
|
|
|
2001-06-18 21:10:03 +08:00
|
|
|
gimp_viewable_size_changed (GIMP_VIEWABLE (gimage));
|
1999-01-11 07:36:29 +08:00
|
|
|
|
2001-05-14 05:51:20 +08:00
|
|
|
gimp_unset_busy ();
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-06-05 07:11:31 +08:00
|
|
|
/**
|
|
|
|
* gimp_image_check_scaling:
|
|
|
|
* @gimage: A #GimpImage.
|
|
|
|
* @new_width: The new width.
|
|
|
|
* @new_height: The new height.
|
|
|
|
*
|
|
|
|
* Inventory the layer list in gimage and return #TRUE if, after
|
|
|
|
* scaling, they all retain positive x and y pixel dimensions.
|
|
|
|
*
|
|
|
|
* Return value: #TRUE if scaling the image will shrink none of it's
|
|
|
|
* layers completely away.
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
gimp_image_check_scaling (const GimpImage *gimage,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height)
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GimpLayer *layer;
|
|
|
|
|
|
|
|
layer = (GimpLayer *) list->data;
|
|
|
|
|
|
|
|
if (! gimp_layer_check_scaling (layer, new_width, new_height))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
TileManager *
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_shadow (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gint bpp)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
if (gimage->shadow &&
|
2001-01-23 21:01:48 +08:00
|
|
|
((width != tile_manager_width (gimage->shadow)) ||
|
|
|
|
(height != tile_manager_height (gimage->shadow)) ||
|
|
|
|
(bpp != tile_manager_bpp (gimage->shadow))))
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_free_shadow (gimage);
|
|
|
|
else if (gimage->shadow)
|
|
|
|
return gimage->shadow;
|
|
|
|
|
|
|
|
gimp_image_allocate_shadow (gimage, width, height, bpp);
|
|
|
|
|
|
|
|
return gimage->shadow;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_image_free_shadow (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
/* Free the shadow buffer from the specified gimage if it exists */
|
|
|
|
if (gimage->shadow)
|
|
|
|
tile_manager_destroy (gimage->shadow);
|
|
|
|
|
|
|
|
gimage->shadow = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-08-22 19:45:31 +08:00
|
|
|
gimp_image_apply_image (GimpImage *gimage,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
PixelRegion *src2PR,
|
2001-06-26 20:09:43 +08:00
|
|
|
gboolean undo,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint opacity,
|
|
|
|
LayerModeEffects mode,
|
1999-07-10 02:15:39 +08:00
|
|
|
/* alternative to using drawable tiles as src1: */
|
1999-08-22 19:45:31 +08:00
|
|
|
TileManager *src1_tiles,
|
|
|
|
gint x,
|
|
|
|
gint y)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *mask;
|
2000-12-04 05:34:38 +08:00
|
|
|
gint x1, y1, x2, y2;
|
|
|
|
gint offset_x, offset_y;
|
|
|
|
PixelRegion src1PR, destPR, maskPR;
|
|
|
|
gint operation;
|
|
|
|
gint active [MAX_CHANNELS];
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* get the selection mask if one exists */
|
1999-08-22 19:45:31 +08:00
|
|
|
mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* configure the active channel array */
|
|
|
|
gimp_image_get_active_channels (gimage, drawable, active);
|
|
|
|
|
|
|
|
/* determine what sort of operation is being attempted and
|
|
|
|
* if it's actually legal...
|
|
|
|
*/
|
2001-01-10 11:13:03 +08:00
|
|
|
operation = valid_combinations[gimp_drawable_type (drawable)][src2PR->bytes];
|
1998-06-28 18:39:58 +08:00
|
|
|
if (operation == -1)
|
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message ("%s(): illegal parameters", G_GNUC_FUNCTION);
|
1998-06-28 18:39:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the layer offsets */
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_drawable_offsets (drawable, &offset_x, &offset_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* make sure the image application coordinates are within gimage bounds */
|
2001-01-10 11:13:03 +08:00
|
|
|
x1 = CLAMP (x, 0, gimp_drawable_width (drawable));
|
|
|
|
y1 = CLAMP (y, 0, gimp_drawable_height (drawable));
|
|
|
|
x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable));
|
|
|
|
y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
/* make sure coordinates are in mask bounds ...
|
|
|
|
* we need to add the layer offset to transform coords
|
|
|
|
* into the mask coordinate system
|
|
|
|
*/
|
2001-01-10 11:13:03 +08:00
|
|
|
x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x);
|
|
|
|
y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y);
|
|
|
|
x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x);
|
|
|
|
y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If the calling procedure specified an undo step... */
|
|
|
|
if (undo)
|
1999-08-22 19:45:31 +08:00
|
|
|
undo_push_image (gimp_drawable_gimage (drawable), drawable, x1, y1, x2, y2);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* configure the pixel regions
|
|
|
|
* If an alternative to using the drawable's data as src1 was provided...
|
|
|
|
*/
|
|
|
|
if (src1_tiles)
|
2000-12-15 01:28:38 +08:00
|
|
|
pixel_region_init (&src1PR, src1_tiles,
|
|
|
|
x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
else
|
2001-01-10 11:13:03 +08:00
|
|
|
pixel_region_init (&src1PR, gimp_drawable_data (drawable),
|
2000-12-15 01:28:38 +08:00
|
|
|
x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
2001-01-10 11:13:03 +08:00
|
|
|
pixel_region_init (&destPR, gimp_drawable_data (drawable),
|
2000-12-15 01:28:38 +08:00
|
|
|
x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
|
|
pixel_region_resize (src2PR,
|
|
|
|
src2PR->x + (x1 - x), src2PR->y + (y1 - y),
|
|
|
|
(x2 - x1), (y2 - y1));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
2000-12-15 01:28:38 +08:00
|
|
|
gint mx, my;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* configure the mask pixel region
|
|
|
|
* don't use x1 and y1 because they are in layer
|
|
|
|
* coordinate system. Need mask coordinate system
|
|
|
|
*/
|
|
|
|
mx = x1 + offset_x;
|
|
|
|
my = y1 + offset_y;
|
|
|
|
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&maskPR,
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (mask)),
|
2000-12-04 05:34:38 +08:00
|
|
|
mx, my,
|
|
|
|
(x2 - x1), (y2 - y1),
|
|
|
|
FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
combine_regions (&src1PR, src2PR, &destPR, &maskPR, NULL,
|
|
|
|
opacity, mode, active, operation);
|
|
|
|
}
|
|
|
|
else
|
2000-12-28 00:12:05 +08:00
|
|
|
{
|
|
|
|
combine_regions (&src1PR, src2PR, &destPR, NULL, NULL,
|
|
|
|
opacity, mode, active, operation);
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Similar to gimp_image_apply_image but works in "replace" mode (i.e.
|
|
|
|
transparent pixels in src2 make the result transparent rather
|
|
|
|
than opaque.
|
|
|
|
|
|
|
|
Takes an additional mask pixel region as well.
|
|
|
|
*/
|
|
|
|
void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_replace_image (GimpImage *gimage,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
PixelRegion *src2PR,
|
2001-06-26 20:09:43 +08:00
|
|
|
gboolean undo,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint opacity,
|
1999-07-10 02:15:39 +08:00
|
|
|
PixelRegion *maskPR,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint x,
|
|
|
|
gint y)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *mask;
|
2000-12-04 05:34:38 +08:00
|
|
|
gint x1, y1, x2, y2;
|
|
|
|
gint offset_x, offset_y;
|
|
|
|
PixelRegion src1PR, destPR;
|
|
|
|
PixelRegion mask2PR, tempPR;
|
|
|
|
guchar *temp_data;
|
|
|
|
gint operation;
|
|
|
|
gint active [MAX_CHANNELS];
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* get the selection mask if one exists */
|
1999-08-22 19:45:31 +08:00
|
|
|
mask = (gimage_mask_is_empty (gimage)) ? NULL : gimp_image_get_mask (gimage);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* configure the active channel array */
|
|
|
|
gimp_image_get_active_channels (gimage, drawable, active);
|
|
|
|
|
|
|
|
/* determine what sort of operation is being attempted and
|
|
|
|
* if it's actually legal...
|
|
|
|
*/
|
2001-01-10 11:13:03 +08:00
|
|
|
operation = valid_combinations [gimp_drawable_type (drawable)][src2PR->bytes];
|
1998-06-28 18:39:58 +08:00
|
|
|
if (operation == -1)
|
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message ("%s(): got illegal parameters", G_GNUC_FUNCTION);
|
1998-06-28 18:39:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the layer offsets */
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_drawable_offsets (drawable, &offset_x, &offset_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* make sure the image application coordinates are within gimage bounds */
|
2001-01-10 11:13:03 +08:00
|
|
|
x1 = CLAMP (x, 0, gimp_drawable_width (drawable));
|
|
|
|
y1 = CLAMP (y, 0, gimp_drawable_height (drawable));
|
|
|
|
x2 = CLAMP (x + src2PR->w, 0, gimp_drawable_width (drawable));
|
|
|
|
y2 = CLAMP (y + src2PR->h, 0, gimp_drawable_height (drawable));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
/* make sure coordinates are in mask bounds ...
|
|
|
|
* we need to add the layer offset to transform coords
|
|
|
|
* into the mask coordinate system
|
|
|
|
*/
|
2001-01-10 11:13:03 +08:00
|
|
|
x1 = CLAMP (x1, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x);
|
|
|
|
y1 = CLAMP (y1, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y);
|
|
|
|
x2 = CLAMP (x2, -offset_x, gimp_drawable_width (GIMP_DRAWABLE (mask))-offset_x);
|
|
|
|
y2 = CLAMP (y2, -offset_y, gimp_drawable_height(GIMP_DRAWABLE (mask))-offset_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If the calling procedure specified an undo step... */
|
|
|
|
if (undo)
|
|
|
|
drawable_apply_image (drawable, x1, y1, x2, y2, NULL, FALSE);
|
|
|
|
|
|
|
|
/* configure the pixel regions
|
|
|
|
* If an alternative to using the drawable's data as src1 was provided...
|
|
|
|
*/
|
2001-01-10 11:13:03 +08:00
|
|
|
pixel_region_init (&src1PR, gimp_drawable_data (drawable),
|
2000-12-28 00:12:05 +08:00
|
|
|
x1, y1, (x2 - x1), (y2 - y1), FALSE);
|
2001-01-10 11:13:03 +08:00
|
|
|
pixel_region_init (&destPR, gimp_drawable_data (drawable),
|
2000-12-28 00:12:05 +08:00
|
|
|
x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
|
|
pixel_region_resize (src2PR,
|
|
|
|
src2PR->x + (x1 - x), src2PR->y + (y1 - y),
|
|
|
|
(x2 - x1), (y2 - y1));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
int mx, my;
|
|
|
|
|
|
|
|
/* configure the mask pixel region
|
|
|
|
* don't use x1 and y1 because they are in layer
|
|
|
|
* coordinate system. Need mask coordinate system
|
|
|
|
*/
|
|
|
|
mx = x1 + offset_x;
|
|
|
|
my = y1 + offset_y;
|
|
|
|
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&mask2PR,
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (mask)),
|
2000-12-04 05:34:38 +08:00
|
|
|
mx, my,
|
|
|
|
(x2 - x1), (y2 - y1),
|
|
|
|
FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
tempPR.bytes = 1;
|
|
|
|
tempPR.x = 0;
|
|
|
|
tempPR.y = 0;
|
|
|
|
tempPR.w = x2 - x1;
|
|
|
|
tempPR.h = y2 - y1;
|
2000-05-27 16:48:50 +08:00
|
|
|
tempPR.rowstride = tempPR.w * tempPR.bytes;
|
1998-06-28 18:39:58 +08:00
|
|
|
temp_data = g_malloc (tempPR.h * tempPR.rowstride);
|
|
|
|
tempPR.data = temp_data;
|
|
|
|
|
|
|
|
copy_region (&mask2PR, &tempPR);
|
|
|
|
|
|
|
|
/* apparently, region operations can mutate some PR data. */
|
|
|
|
tempPR.x = 0;
|
|
|
|
tempPR.y = 0;
|
|
|
|
tempPR.w = x2 - x1;
|
|
|
|
tempPR.h = y2 - y1;
|
|
|
|
tempPR.data = temp_data;
|
|
|
|
|
|
|
|
apply_mask_to_region (&tempPR, maskPR, OPAQUE_OPACITY);
|
|
|
|
|
|
|
|
tempPR.x = 0;
|
|
|
|
tempPR.y = 0;
|
|
|
|
tempPR.w = x2 - x1;
|
|
|
|
tempPR.h = y2 - y1;
|
|
|
|
tempPR.data = temp_data;
|
|
|
|
|
|
|
|
combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL,
|
|
|
|
opacity, active, operation);
|
|
|
|
|
|
|
|
g_free (temp_data);
|
|
|
|
}
|
|
|
|
else
|
2000-12-28 00:12:05 +08:00
|
|
|
{
|
|
|
|
combine_regions_replace (&src1PR, src2PR, &destPR, maskPR, NULL,
|
|
|
|
opacity, active, operation);
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get rid of these! A "foreground" is an UI concept.. */
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_foreground (const GimpImage *gimage,
|
|
|
|
const GimpDrawable *drawable,
|
|
|
|
guchar *fg)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-15 09:48:53 +08:00
|
|
|
GimpRGB color;
|
|
|
|
guchar pfg[3];
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-01-15 09:48:53 +08:00
|
|
|
gimp_context_get_foreground (NULL, &color);
|
|
|
|
|
|
|
|
gimp_rgb_get_uchar (&color, &pfg[0], &pfg[1], &pfg[2]);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
gimp_image_transform_color (gimage, drawable, pfg, fg, RGB);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_background (const GimpImage *gimage,
|
|
|
|
const GimpDrawable *drawable,
|
|
|
|
guchar *bg)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-15 09:48:53 +08:00
|
|
|
GimpRGB color;
|
|
|
|
guchar pbg[3];
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* Get the palette color */
|
2001-01-15 09:48:53 +08:00
|
|
|
gimp_context_get_background (NULL, &color);
|
|
|
|
|
|
|
|
gimp_rgb_get_uchar (&color, &pbg[0], &pbg[1], &pbg[2]);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
gimp_image_transform_color (gimage, drawable, pbg, bg, RGB);
|
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
guchar *
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_get_color_at (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint x,
|
|
|
|
gint y)
|
1999-02-16 16:53:54 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
Tile *tile;
|
1999-08-22 19:45:31 +08:00
|
|
|
guchar *src;
|
|
|
|
guchar *dest;
|
1999-02-16 16:53:54 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
1999-02-16 16:53:54 +08:00
|
|
|
if (x < 0 || y < 0 || x >= gimage->width || y >= gimage->height)
|
2000-12-14 02:53:35 +08:00
|
|
|
return NULL;
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
dest = g_new (guchar, 5);
|
1999-02-16 16:53:54 +08:00
|
|
|
tile = tile_manager_get_tile (gimp_image_composite (gimage), x, y,
|
|
|
|
TRUE, FALSE);
|
|
|
|
src = tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT);
|
|
|
|
gimp_image_get_color (gimage, gimp_image_composite_type (gimage), dest, src);
|
1999-08-22 19:45:31 +08:00
|
|
|
|
2000-12-14 02:53:35 +08:00
|
|
|
if (GIMP_IMAGE_TYPE_HAS_ALPHA (gimp_image_composite_type (gimage)))
|
1999-02-16 16:53:54 +08:00
|
|
|
dest[3] = src[gimp_image_composite_bytes (gimage) - 1];
|
|
|
|
else
|
|
|
|
dest[3] = 255;
|
1999-08-22 19:45:31 +08:00
|
|
|
|
1999-02-16 16:53:54 +08:00
|
|
|
dest[4] = 0;
|
|
|
|
tile_release (tile, FALSE);
|
1999-08-22 19:45:31 +08:00
|
|
|
|
1999-02-16 16:53:54 +08:00
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_color (const GimpImage *gimage,
|
|
|
|
GimpImageType d_type,
|
|
|
|
guchar *rgb,
|
|
|
|
guchar *src)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
switch (d_type)
|
|
|
|
{
|
|
|
|
case RGB_GIMAGE: case RGBA_GIMAGE:
|
|
|
|
map_to_color (0, NULL, src, rgb);
|
|
|
|
break;
|
|
|
|
case GRAY_GIMAGE: case GRAYA_GIMAGE:
|
|
|
|
map_to_color (1, NULL, src, rgb);
|
|
|
|
break;
|
|
|
|
case INDEXED_GIMAGE: case INDEXEDA_GIMAGE:
|
|
|
|
map_to_color (2, gimage->cmap, src, rgb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_transform_color (const GimpImage *gimage,
|
|
|
|
const GimpDrawable *drawable,
|
|
|
|
guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
GimpImageBaseType type)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpImageType d_type;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
d_type = (drawable != NULL) ? gimp_drawable_type (drawable) :
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_base_type_with_alpha (gimage);
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case RGB:
|
|
|
|
switch (d_type)
|
|
|
|
{
|
|
|
|
case RGB_GIMAGE: case RGBA_GIMAGE:
|
|
|
|
/* Straight copy */
|
|
|
|
*dest++ = *src++;
|
|
|
|
*dest++ = *src++;
|
|
|
|
*dest++ = *src++;
|
|
|
|
break;
|
|
|
|
case GRAY_GIMAGE: case GRAYA_GIMAGE:
|
|
|
|
/* NTSC conversion */
|
|
|
|
*dest = INTENSITY (src[RED_PIX],
|
|
|
|
src[GREEN_PIX],
|
|
|
|
src[BLUE_PIX]);
|
|
|
|
break;
|
|
|
|
case INDEXED_GIMAGE: case INDEXEDA_GIMAGE:
|
|
|
|
/* Least squares method */
|
2001-05-15 19:25:25 +08:00
|
|
|
*dest = gimp_image_color_hash_rgb_to_indexed (gimage,
|
|
|
|
src[RED_PIX],
|
|
|
|
src[GREEN_PIX],
|
|
|
|
src[BLUE_PIX]);
|
1998-06-28 18:39:58 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case GRAY:
|
|
|
|
switch (d_type)
|
|
|
|
{
|
|
|
|
case RGB_GIMAGE: case RGBA_GIMAGE:
|
|
|
|
/* Gray to RG&B */
|
|
|
|
*dest++ = *src;
|
|
|
|
*dest++ = *src;
|
|
|
|
*dest++ = *src;
|
|
|
|
break;
|
|
|
|
case GRAY_GIMAGE: case GRAYA_GIMAGE:
|
|
|
|
/* Straight copy */
|
|
|
|
*dest = *src;
|
|
|
|
break;
|
|
|
|
case INDEXED_GIMAGE: case INDEXEDA_GIMAGE:
|
|
|
|
/* Least squares method */
|
2001-05-15 19:25:25 +08:00
|
|
|
*dest = gimp_image_color_hash_rgb_to_indexed (gimage,
|
|
|
|
src[GRAY_PIX],
|
|
|
|
src[GRAY_PIX],
|
|
|
|
src[GRAY_PIX]);
|
1998-06-28 18:39:58 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-16 03:10:57 +08:00
|
|
|
GimpGuide *
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_add_hguide (GimpImage *gimage)
|
|
|
|
{
|
2001-05-16 03:10:57 +08:00
|
|
|
GimpGuide *guide;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-05-16 03:10:57 +08:00
|
|
|
guide = g_new (GimpGuide, 1);
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
guide->ref_count = 0;
|
|
|
|
guide->position = -1;
|
|
|
|
guide->guide_ID = next_guide_id++;
|
1999-07-29 07:00:08 +08:00
|
|
|
guide->orientation = ORIENTATION_HORIZONTAL;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
gimage->guides = g_list_prepend (gimage->guides, guide);
|
|
|
|
|
|
|
|
return guide;
|
|
|
|
}
|
|
|
|
|
2001-05-16 03:10:57 +08:00
|
|
|
GimpGuide *
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_add_vguide (GimpImage *gimage)
|
|
|
|
{
|
2001-05-16 03:10:57 +08:00
|
|
|
GimpGuide *guide;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-05-16 03:10:57 +08:00
|
|
|
guide = g_new (GimpGuide, 1);
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
guide->ref_count = 0;
|
|
|
|
guide->position = -1;
|
|
|
|
guide->guide_ID = next_guide_id++;
|
1999-07-29 07:00:08 +08:00
|
|
|
guide->orientation = ORIENTATION_VERTICAL;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
gimage->guides = g_list_prepend (gimage->guides, guide);
|
|
|
|
|
|
|
|
return guide;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_image_add_guide (GimpImage *gimage,
|
2001-05-16 03:10:57 +08:00
|
|
|
GimpGuide *guide)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
gimage->guides = g_list_prepend (gimage->guides, guide);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_image_remove_guide (GimpImage *gimage,
|
2001-05-16 03:10:57 +08:00
|
|
|
GimpGuide *guide)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
gimage->guides = g_list_remove (gimage->guides, guide);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_image_delete_guide (GimpImage *gimage,
|
2001-05-16 03:10:57 +08:00
|
|
|
GimpGuide *guide)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
1999-10-14 07:07:45 +08:00
|
|
|
guide->position = -1;
|
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
1999-10-14 07:07:45 +08:00
|
|
|
if (guide->ref_count <= 0)
|
|
|
|
{
|
|
|
|
gimage->guides = g_list_remove (gimage->guides, guide);
|
|
|
|
g_free (guide);
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
1999-10-14 07:07:45 +08:00
|
|
|
|
2000-05-27 06:28:40 +08:00
|
|
|
GimpParasite *
|
1999-10-17 08:07:55 +08:00
|
|
|
gimp_image_parasite_find (const GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
const gchar *name)
|
1998-10-08 16:15:21 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-07-05 06:59:25 +08:00
|
|
|
return gimp_parasite_list_find (gimage->parasites, name);
|
1998-10-08 16:15:21 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
static void
|
2000-05-27 06:28:40 +08:00
|
|
|
list_func (gchar *key,
|
|
|
|
GimpParasite *p,
|
|
|
|
gchar ***cur)
|
1999-02-14 02:19:44 +08:00
|
|
|
{
|
1999-08-22 19:45:31 +08:00
|
|
|
*(*cur)++ = (gchar *) g_strdup (key);
|
1999-02-14 02:19:44 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gchar **
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_parasite_list (const GimpImage *gimage,
|
|
|
|
gint *count)
|
1999-02-14 02:19:44 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
gchar **list;
|
|
|
|
gchar **cur;
|
1999-02-14 02:19:44 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-07-05 06:59:25 +08:00
|
|
|
*count = gimp_parasite_list_length (gimage->parasites);
|
2000-12-04 05:34:38 +08:00
|
|
|
cur = list = g_new (gchar*, *count);
|
1999-02-14 02:19:44 +08:00
|
|
|
|
2001-07-05 06:59:25 +08:00
|
|
|
gimp_parasite_list_foreach (gimage->parasites, (GHFunc) list_func, &cur);
|
1999-02-14 02:19:44 +08:00
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
1998-10-08 16:15:21 +08:00
|
|
|
void
|
2000-05-27 06:28:40 +08:00
|
|
|
gimp_image_parasite_attach (GimpImage *gimage,
|
|
|
|
GimpParasite *parasite)
|
1998-10-08 16:15:21 +08:00
|
|
|
{
|
2000-08-24 03:29:01 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage) && parasite != NULL);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
1999-04-23 14:07:09 +08:00
|
|
|
/* only set the dirty bit manually if we can be saved and the new
|
1999-07-20 03:46:05 +08:00
|
|
|
parasite differs from the current one and we aren't undoable */
|
2000-05-27 06:28:40 +08:00
|
|
|
if (gimp_parasite_is_undoable (parasite))
|
1999-04-23 14:07:09 +08:00
|
|
|
undo_push_image_parasite (gimage, parasite);
|
2000-08-24 03:29:01 +08:00
|
|
|
|
|
|
|
/* We used to push an cantundo on te stack here. This made the undo stack
|
|
|
|
unusable (NULL on the stack) and prevented people from undoing after a
|
|
|
|
save (since most save plug-ins attach an undoable comment parasite).
|
|
|
|
Now we simply attach the parasite without pushing an undo. That way it's
|
|
|
|
undoable but does not block the undo system. --Sven
|
2000-12-04 05:34:38 +08:00
|
|
|
*/
|
1999-08-22 19:45:31 +08:00
|
|
|
|
2001-07-05 06:59:25 +08:00
|
|
|
gimp_parasite_list_add (gimage->parasites, parasite);
|
1999-08-22 19:45:31 +08:00
|
|
|
|
2000-05-27 06:28:40 +08:00
|
|
|
if (gimp_parasite_has_flag (parasite, GIMP_PARASITE_ATTACH_PARENT))
|
1999-08-22 19:45:31 +08:00
|
|
|
{
|
2001-07-05 06:59:25 +08:00
|
|
|
gimp_parasite_shift_parent (parasite);
|
|
|
|
gimp_parasite_attach (gimage->gimp, parasite);
|
1999-08-22 19:45:31 +08:00
|
|
|
}
|
1998-10-08 16:15:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-10-17 08:07:55 +08:00
|
|
|
gimp_image_parasite_detach (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
const gchar *parasite)
|
1998-10-08 16:15:21 +08:00
|
|
|
{
|
2000-05-27 06:28:40 +08:00
|
|
|
GimpParasite *p;
|
1999-07-20 03:46:05 +08:00
|
|
|
|
2000-08-24 03:29:01 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage) && parasite != NULL);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-07-05 06:59:25 +08:00
|
|
|
if (!(p = gimp_parasite_list_find (gimage->parasites, parasite)))
|
1998-12-16 19:23:30 +08:00
|
|
|
return;
|
1999-08-22 19:45:31 +08:00
|
|
|
|
2000-05-27 06:28:40 +08:00
|
|
|
if (gimp_parasite_is_undoable (p))
|
|
|
|
undo_push_image_parasite_remove (gimage, gimp_parasite_name (p));
|
2000-08-24 03:29:01 +08:00
|
|
|
|
2001-07-05 06:59:25 +08:00
|
|
|
gimp_parasite_list_remove (gimage->parasites, parasite);
|
1998-10-08 16:15:21 +08:00
|
|
|
}
|
|
|
|
|
1998-10-30 18:21:33 +08:00
|
|
|
Tattoo
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_get_new_tattoo (GimpImage *image)
|
1998-10-14 10:54:02 +08:00
|
|
|
{
|
1998-10-30 18:21:33 +08:00
|
|
|
image->tattoo_state++;
|
2000-12-29 00:19:55 +08:00
|
|
|
|
1998-10-30 18:21:33 +08:00
|
|
|
if (image->tattoo_state <= 0)
|
2000-02-16 09:47:22 +08:00
|
|
|
g_warning ("Tattoo state has become corrupt (2.1 billion operation limit exceded)");
|
2000-12-29 00:19:55 +08:00
|
|
|
|
|
|
|
return image->tattoo_state;
|
1998-10-14 10:54:02 +08:00
|
|
|
}
|
|
|
|
|
2000-02-16 07:49:03 +08:00
|
|
|
Tattoo
|
2000-02-16 09:47:22 +08:00
|
|
|
gimp_image_get_tattoo_state (GimpImage *image)
|
2000-02-16 07:49:03 +08:00
|
|
|
{
|
|
|
|
return (image->tattoo_state);
|
|
|
|
}
|
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
gboolean
|
2000-02-16 09:47:22 +08:00
|
|
|
gimp_image_set_tattoo_state (GimpImage *gimage,
|
|
|
|
Tattoo val)
|
2000-02-16 07:49:03 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2001-01-29 10:45:02 +08:00
|
|
|
gboolean retval = TRUE;
|
|
|
|
GimpChannel *channel;
|
|
|
|
Tattoo maxval = 0;
|
|
|
|
Path *pptr = NULL;
|
|
|
|
PathList *plist;
|
2000-02-16 07:49:03 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
2000-02-16 07:49:03 +08:00
|
|
|
{
|
|
|
|
Tattoo ltattoo;
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
ltattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (list->data));
|
2000-03-09 19:58:03 +08:00
|
|
|
if (ltattoo > maxval)
|
2000-02-16 07:49:03 +08:00
|
|
|
maxval = ltattoo;
|
2000-03-09 19:58:03 +08:00
|
|
|
if (gimp_image_get_channel_by_tattoo (gimage, ltattoo) != NULL)
|
2000-02-16 07:49:03 +08:00
|
|
|
{
|
|
|
|
retval = FALSE; /* Oopps duplicated tattoo in channel */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now check path an't got this tattoo */
|
2000-03-09 19:58:03 +08:00
|
|
|
if (path_get_path_by_tattoo (gimage, ltattoo) != NULL)
|
2000-02-16 07:49:03 +08:00
|
|
|
{
|
|
|
|
retval = FALSE; /* Oopps duplicated tattoo in layer */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now check that the paths channel tattoos don't overlap */
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->channels)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
2000-02-16 07:49:03 +08:00
|
|
|
{
|
|
|
|
Tattoo ctattoo;
|
2001-02-19 21:06:09 +08:00
|
|
|
channel = (GimpChannel *) list->data;
|
2000-02-16 07:49:03 +08:00
|
|
|
|
2001-01-29 08:46:04 +08:00
|
|
|
ctattoo = gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel));
|
2000-03-09 19:58:03 +08:00
|
|
|
if (ctattoo > maxval)
|
2000-02-16 07:49:03 +08:00
|
|
|
maxval = ctattoo;
|
|
|
|
/* Now check path an't got this tattoo */
|
2000-03-09 19:58:03 +08:00
|
|
|
if (path_get_path_by_tattoo (gimage, ctattoo) != NULL)
|
2000-02-16 07:49:03 +08:00
|
|
|
{
|
|
|
|
retval = FALSE; /* Oopps duplicated tattoo in layer */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the max tatto value in the paths */
|
|
|
|
plist = gimage->paths;
|
|
|
|
|
|
|
|
if (plist && plist->bz_paths)
|
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
Tattoo ptattoo;
|
2000-12-28 02:15:37 +08:00
|
|
|
GSList *pl;
|
2000-02-16 07:49:03 +08:00
|
|
|
|
2000-12-28 02:15:37 +08:00
|
|
|
for (pl = plist->bz_paths; pl; pl = g_slist_next (pl))
|
2000-02-16 07:49:03 +08:00
|
|
|
{
|
|
|
|
pptr = pl->data;
|
|
|
|
|
2000-02-16 09:47:22 +08:00
|
|
|
ptattoo = path_get_tattoo (pptr);
|
2000-02-16 07:49:03 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
if (ptattoo > maxval)
|
2000-02-16 07:49:03 +08:00
|
|
|
maxval = ptattoo;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-03-10 06:41:19 +08:00
|
|
|
if (val < maxval)
|
2000-02-16 07:49:03 +08:00
|
|
|
retval = FALSE;
|
|
|
|
/* Must check the state is valid */
|
2000-03-09 19:58:03 +08:00
|
|
|
if (retval == TRUE)
|
2000-02-16 07:49:03 +08:00
|
|
|
gimage->tattoo_state = val;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
1999-03-06 07:50:24 +08:00
|
|
|
void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_set_paths (GimpImage *gimage,
|
2000-02-16 09:47:22 +08:00
|
|
|
PathList *paths)
|
1999-03-06 07:50:24 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
1999-03-06 07:50:24 +08:00
|
|
|
gimage->paths = paths;
|
|
|
|
}
|
|
|
|
|
2000-02-16 09:47:22 +08:00
|
|
|
PathList *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_paths (const GimpImage *gimage)
|
1999-03-06 07:50:24 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
1999-03-06 07:50:24 +08:00
|
|
|
return gimage->paths;
|
|
|
|
}
|
2001-05-07 02:58:04 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
void
|
2001-05-07 00:14:34 +08:00
|
|
|
gimp_image_colormap_changed (GimpImage *gimage,
|
|
|
|
gint col)
|
2000-12-29 00:19:55 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
g_return_if_fail (col < gimage->num_cols);
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[COLORMAP_CHANGED],
|
|
|
|
col);
|
|
|
|
}
|
|
|
|
|
2001-05-07 00:14:34 +08:00
|
|
|
void
|
|
|
|
gimp_image_mode_changed (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage), gimp_image_signals[MODE_CHANGED]);
|
|
|
|
}
|
|
|
|
|
2001-06-01 03:53:13 +08:00
|
|
|
void
|
|
|
|
gimp_image_mask_changed (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage), gimp_image_signals[MASK_CHANGED]);
|
|
|
|
}
|
|
|
|
|
2001-05-07 02:58:04 +08:00
|
|
|
void
|
|
|
|
gimp_image_alpha_changed (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage), gimp_image_signals[ALPHA_CHANGED]);
|
|
|
|
}
|
|
|
|
|
2001-05-08 09:32:25 +08:00
|
|
|
void
|
|
|
|
gimp_image_floating_selection_changed (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[FLOATING_SELECTION_CHANGED]);
|
|
|
|
}
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/************************************************************/
|
|
|
|
/* Projection functions */
|
|
|
|
/************************************************************/
|
|
|
|
|
|
|
|
static void
|
1999-07-10 02:15:39 +08:00
|
|
|
project_intensity (GimpImage *gimage,
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer,
|
1999-07-10 02:15:39 +08:00
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
|
|
|
PixelRegion *mask)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
if (! gimage->construct_flag)
|
|
|
|
initial_region (src, dest, mask, NULL, layer->opacity,
|
|
|
|
layer->mode, gimage->visible, INITIAL_INTENSITY);
|
|
|
|
else
|
|
|
|
combine_regions (dest, src, dest, mask, NULL, layer->opacity,
|
|
|
|
layer->mode, gimage->visible, COMBINE_INTEN_A_INTEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-07-10 02:15:39 +08:00
|
|
|
project_intensity_alpha (GimpImage *gimage,
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer,
|
2001-02-19 21:06:09 +08:00
|
|
|
PixelRegion *src,
|
1999-07-10 02:15:39 +08:00
|
|
|
PixelRegion *dest,
|
1998-06-28 18:39:58 +08:00
|
|
|
PixelRegion *mask)
|
|
|
|
{
|
|
|
|
if (! gimage->construct_flag)
|
|
|
|
initial_region (src, dest, mask, NULL, layer->opacity,
|
|
|
|
layer->mode, gimage->visible, INITIAL_INTENSITY_ALPHA);
|
|
|
|
else
|
|
|
|
combine_regions (dest, src, dest, mask, NULL, layer->opacity,
|
|
|
|
layer->mode, gimage->visible, COMBINE_INTEN_A_INTEN_A);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-07-10 02:15:39 +08:00
|
|
|
project_indexed (GimpImage *gimage,
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer,
|
1999-07-10 02:15:39 +08:00
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *dest)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
if (! gimage->construct_flag)
|
|
|
|
initial_region (src, dest, NULL, gimage->cmap, layer->opacity,
|
|
|
|
layer->mode, gimage->visible, INITIAL_INDEXED);
|
|
|
|
else
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message ("%s(): unable to project indexed image.", G_GNUC_FUNCTION);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-07-10 02:15:39 +08:00
|
|
|
project_indexed_alpha (GimpImage *gimage,
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer,
|
1999-07-10 02:15:39 +08:00
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *dest,
|
1998-06-28 18:39:58 +08:00
|
|
|
PixelRegion *mask)
|
|
|
|
{
|
|
|
|
if (! gimage->construct_flag)
|
|
|
|
initial_region (src, dest, mask, gimage->cmap, layer->opacity,
|
|
|
|
layer->mode, gimage->visible, INITIAL_INDEXED_ALPHA);
|
|
|
|
else
|
|
|
|
combine_regions (dest, src, dest, mask, gimage->cmap, layer->opacity,
|
|
|
|
layer->mode, gimage->visible, COMBINE_INTEN_A_INDEXED_A);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-07-10 02:15:39 +08:00
|
|
|
project_channel (GimpImage *gimage,
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *channel,
|
1999-07-10 02:15:39 +08:00
|
|
|
PixelRegion *src,
|
|
|
|
PixelRegion *src2)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-15 12:37:01 +08:00
|
|
|
guchar col[3];
|
|
|
|
guchar opacity;
|
|
|
|
gint type;
|
|
|
|
|
|
|
|
gimp_rgba_get_uchar (&channel->color,
|
|
|
|
&col[0], &col[1], &col[2], &opacity);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
if (! gimage->construct_flag)
|
|
|
|
{
|
|
|
|
type = (channel->show_masked) ?
|
|
|
|
INITIAL_CHANNEL_MASK : INITIAL_CHANNEL_SELECTION;
|
2001-01-15 12:37:01 +08:00
|
|
|
|
|
|
|
initial_region (src2, src, NULL, col, opacity,
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
NORMAL_MODE, NULL, type);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
type = (channel->show_masked) ?
|
|
|
|
COMBINE_INTEN_A_CHANNEL_MASK : COMBINE_INTEN_A_CHANNEL_SELECTION;
|
2001-01-15 12:37:01 +08:00
|
|
|
|
|
|
|
combine_regions (src, src2, src, NULL, col, opacity,
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
NORMAL_MODE, NULL, type);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************/
|
|
|
|
/* Layer/Channel functions */
|
|
|
|
/************************************************************/
|
|
|
|
|
|
|
|
static void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_construct_layers (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer;
|
2000-12-04 05:34:38 +08:00
|
|
|
gint x1, y1, x2, y2;
|
|
|
|
PixelRegion src1PR, src2PR, maskPR;
|
1998-06-28 18:39:58 +08:00
|
|
|
PixelRegion * mask;
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2000-12-04 05:34:38 +08:00
|
|
|
GSList *reverse_list = NULL;
|
|
|
|
gint off_x;
|
|
|
|
gint off_y;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* composite the floating selection if it exists */
|
|
|
|
if ((layer = gimp_image_floating_sel (gimage)))
|
|
|
|
floating_sel_composite (layer, x, y, w, h, FALSE);
|
|
|
|
|
|
|
|
/* Note added by Raph Levien, 27 Jan 1998
|
|
|
|
|
|
|
|
This looks it was intended as an optimization, but it seems to
|
|
|
|
have correctness problems. In particular, if all channels are
|
|
|
|
turned off, the screen simply does not update the projected
|
|
|
|
image. It should be black. Turning off this optimization seems to
|
|
|
|
restore correct behavior. At some future point, it may be
|
|
|
|
desirable to turn the optimization back on.
|
|
|
|
|
|
|
|
*/
|
|
|
|
#if 0
|
|
|
|
/* If all channels are not visible, simply return */
|
|
|
|
switch (gimp_image_base_type (gimage))
|
|
|
|
{
|
|
|
|
case RGB:
|
1999-04-27 12:57:59 +08:00
|
|
|
if (! gimp_image_get_component_visible (gimage, RED_CHANNEL) &&
|
|
|
|
! gimp_image_get_component_visible (gimage, GREEN_CHANNEL) &&
|
|
|
|
! gimp_image_get_component_visible (gimage, BLUE_CHANNEL))
|
1998-06-28 18:39:58 +08:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
case GRAY:
|
1999-04-27 12:57:59 +08:00
|
|
|
if (! gimp_image_get_component_visible (gimage, GRAY_CHANNEL))
|
1998-06-28 18:39:58 +08:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
case INDEXED:
|
1999-04-27 12:57:59 +08:00
|
|
|
if (! gimp_image_get_component_visible (gimage, INDEXED_CHANNEL))
|
1998-06-28 18:39:58 +08:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-12-04 05:34:38 +08:00
|
|
|
/* only add layers that are visible and not floating selections
|
|
|
|
to the list */
|
2001-01-29 07:25:25 +08:00
|
|
|
if (! gimp_layer_is_floating_sel (layer) &&
|
2001-03-05 00:52:37 +08:00
|
|
|
gimp_drawable_get_visible (GIMP_DRAWABLE (layer)))
|
|
|
|
{
|
|
|
|
reverse_list = g_slist_prepend (reverse_list, layer);
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
while (reverse_list)
|
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) reverse_list->data;
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
x1 = CLAMP (off_x, x, x + w);
|
|
|
|
y1 = CLAMP (off_y, y, y + h);
|
2001-01-10 11:13:03 +08:00
|
|
|
x2 = CLAMP (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)), x, x + w);
|
|
|
|
y2 = CLAMP (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)), y, y + h);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* configure the pixel regions */
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&src1PR, gimp_image_projection (gimage),
|
|
|
|
x1, y1, (x2 - x1), (y2 - y1),
|
|
|
|
TRUE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* If we're showing the layer mask instead of the layer... */
|
2001-03-06 21:28:39 +08:00
|
|
|
if (layer->mask && layer->mask->show_mask)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&src2PR,
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (layer->mask)),
|
1998-06-28 18:39:58 +08:00
|
|
|
(x1 - off_x), (y1 - off_y),
|
|
|
|
(x2 - x1), (y2 - y1), FALSE);
|
|
|
|
|
|
|
|
copy_gray_to_region (&src2PR, &src1PR);
|
|
|
|
}
|
|
|
|
/* Otherwise, normal */
|
|
|
|
else
|
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&src2PR,
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (layer)),
|
1998-06-28 18:39:58 +08:00
|
|
|
(x1 - off_x), (y1 - off_y),
|
|
|
|
(x2 - x1), (y2 - y1), FALSE);
|
|
|
|
|
2001-03-06 21:28:39 +08:00
|
|
|
if (layer->mask && layer->mask->apply_mask)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&maskPR,
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (layer->mask)),
|
1998-06-28 18:39:58 +08:00
|
|
|
(x1 - off_x), (y1 - off_y),
|
|
|
|
(x2 - x1), (y2 - y1), FALSE);
|
|
|
|
mask = &maskPR;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
mask = NULL;
|
|
|
|
|
|
|
|
/* Based on the type of the layer, project the layer onto the
|
|
|
|
* projection image...
|
|
|
|
*/
|
2001-01-10 11:13:03 +08:00
|
|
|
switch (gimp_drawable_type (GIMP_DRAWABLE (layer)))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
case RGB_GIMAGE: case GRAY_GIMAGE:
|
|
|
|
/* no mask possible */
|
|
|
|
project_intensity (gimage, layer, &src2PR, &src1PR, mask);
|
|
|
|
break;
|
2000-12-04 05:34:38 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
case RGBA_GIMAGE: case GRAYA_GIMAGE:
|
|
|
|
project_intensity_alpha (gimage, layer, &src2PR, &src1PR, mask);
|
|
|
|
break;
|
2000-12-04 05:34:38 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
case INDEXED_GIMAGE:
|
|
|
|
/* no mask possible */
|
|
|
|
project_indexed (gimage, layer, &src2PR, &src1PR);
|
|
|
|
break;
|
2000-12-04 05:34:38 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
case INDEXEDA_GIMAGE:
|
|
|
|
project_indexed_alpha (gimage, layer, &src2PR, &src1PR, mask);
|
|
|
|
break;
|
2000-12-04 05:34:38 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gimage->construct_flag = 1; /* something was projected */
|
|
|
|
|
|
|
|
reverse_list = g_slist_next (reverse_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_slist_free (reverse_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_construct_channels (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *channel;
|
2000-12-28 00:12:05 +08:00
|
|
|
PixelRegion src1PR;
|
|
|
|
PixelRegion src2PR;
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2000-12-04 05:34:38 +08:00
|
|
|
GSList *reverse_list = NULL;
|
1999-01-21 06:41:38 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* reverse the channel list */
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->channels)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
2000-12-04 05:34:38 +08:00
|
|
|
reverse_list = g_slist_prepend (reverse_list, list->data);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
while (reverse_list)
|
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
channel = (GimpChannel *) reverse_list->data;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-03-05 00:52:37 +08:00
|
|
|
if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel)))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
/* configure the pixel regions */
|
2001-01-10 11:13:03 +08:00
|
|
|
pixel_region_init (&src1PR,
|
|
|
|
gimp_image_projection (gimage),
|
2000-12-04 05:34:38 +08:00
|
|
|
x, y, w, h,
|
|
|
|
TRUE);
|
2001-01-10 11:13:03 +08:00
|
|
|
pixel_region_init (&src2PR,
|
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (channel)),
|
2000-12-04 05:34:38 +08:00
|
|
|
x, y, w, h,
|
|
|
|
FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
project_channel (gimage, channel, &src1PR, &src2PR);
|
|
|
|
|
|
|
|
gimage->construct_flag = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
reverse_list = g_slist_next (reverse_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_slist_free (reverse_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_initialize_projection (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
|
|
|
|
GList *list;
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer;
|
2000-12-04 05:34:38 +08:00
|
|
|
gint coverage = 0;
|
|
|
|
PixelRegion PR;
|
|
|
|
guchar clear[4] = { 0, 0, 0, 0 };
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* this function determines whether a visible layer
|
|
|
|
* provides complete coverage over the image. If not,
|
|
|
|
* the projection is initialized to transparent
|
|
|
|
*/
|
2000-12-04 05:34:38 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
gint off_x, off_y;
|
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
|
2000-12-04 05:34:38 +08:00
|
|
|
|
2001-03-05 00:52:37 +08:00
|
|
|
if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer)) &&
|
2001-01-29 07:25:25 +08:00
|
|
|
! gimp_layer_has_alpha (layer) &&
|
1998-06-28 18:39:58 +08:00
|
|
|
(off_x <= x) &&
|
|
|
|
(off_y <= y) &&
|
2001-01-10 11:13:03 +08:00
|
|
|
(off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)) >= x + w) &&
|
|
|
|
(off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)) >= y + h))
|
1999-07-15 00:02:32 +08:00
|
|
|
{
|
|
|
|
coverage = 1;
|
|
|
|
break;
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!coverage)
|
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&PR, gimp_image_projection (gimage),
|
|
|
|
x, y, w, h, TRUE);
|
1998-06-28 18:39:58 +08:00
|
|
|
color_region (&PR, clear);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_get_active_channels (GimpImage *gimage,
|
|
|
|
GimpDrawable *drawable,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint *active)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer;
|
|
|
|
gint i;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* first, blindly copy the gimage active channels */
|
|
|
|
for (i = 0; i < MAX_CHANNELS; i++)
|
|
|
|
active[i] = gimage->active[i];
|
|
|
|
|
|
|
|
/* If the drawable is a channel (a saved selection, etc.)
|
|
|
|
* make sure that the alpha channel is not valid
|
|
|
|
*/
|
1998-06-30 23:31:32 +08:00
|
|
|
if (GIMP_IS_CHANNEL (drawable))
|
1998-06-28 18:39:58 +08:00
|
|
|
active[ALPHA_G_PIX] = 0; /* no alpha values in channels */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* otherwise, check whether preserve transparency is
|
|
|
|
* enabled in the layer and if the layer has alpha
|
|
|
|
*/
|
1999-08-22 19:45:31 +08:00
|
|
|
if (GIMP_IS_LAYER (drawable))
|
|
|
|
{
|
|
|
|
layer = GIMP_LAYER (drawable);
|
2001-01-29 07:25:25 +08:00
|
|
|
if (gimp_layer_has_alpha (layer) && layer->preserve_trans)
|
2001-01-10 11:13:03 +08:00
|
|
|
active[gimp_drawable_bytes (drawable) - 1] = 0;
|
1999-08-22 19:45:31 +08:00
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_construct (GimpImage *gimage,
|
2000-12-28 00:12:05 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
2000-12-29 00:19:55 +08:00
|
|
|
gint h)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
1999-01-21 08:17:43 +08:00
|
|
|
#if 0
|
2000-12-04 05:34:38 +08:00
|
|
|
gint xoff;
|
|
|
|
gint yoff;
|
1999-01-21 06:41:38 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
/* set the construct flag, used to determine if anything
|
|
|
|
* has been written to the gimage raw image yet.
|
|
|
|
*/
|
|
|
|
gimage->construct_flag = 0;
|
|
|
|
|
|
|
|
if (gimage->layers)
|
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
gimp_drawable_offsets (GIMP_DRAWABLE ((GimpLayer*) gimage->layers->data),
|
1999-08-22 19:45:31 +08:00
|
|
|
&xoff, &yoff);
|
|
|
|
}
|
1999-01-19 06:59:51 +08:00
|
|
|
|
2000-12-28 00:12:05 +08:00
|
|
|
if ((gimage->layers) && /* There's a layer. */
|
2001-01-29 07:25:25 +08:00
|
|
|
(! g_slist_next (gimage->layers)) && /* It's the only layer. */
|
|
|
|
(gimp_layer_has_alpha ((GimpLayer *) (gimage->layers->data))) && /* It's !flat. */
|
1999-01-19 06:59:51 +08:00
|
|
|
/* It's visible. */
|
2001-03-05 00:52:37 +08:00
|
|
|
(gimp_drawable_get_visible (GIMP_DRAWABLE (gimage->layers->data))) &&
|
2001-01-29 07:25:25 +08:00
|
|
|
(gimp_drawable_width (GIMP_DRAWABLE (gimage->layers->data)) ==
|
1999-01-19 06:59:51 +08:00
|
|
|
gimage->width) &&
|
2001-01-29 07:25:25 +08:00
|
|
|
(gimp_drawable_height (GIMP_DRAWABLE (gimage->layers->data)) ==
|
1999-01-19 06:59:51 +08:00
|
|
|
gimage->height) && /* Covers all. */
|
|
|
|
/* Not indexed. */
|
2001-01-29 07:25:25 +08:00
|
|
|
(!gimp_drawable_is_indexed (GIMP_DRAWABLE (gimage->layers->data))) &&
|
|
|
|
(((GimpLayer *)(gimage->layers->data))->opacity == OPAQUE_OPACITY) /*opaq */
|
1999-01-19 06:59:51 +08:00
|
|
|
)
|
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
gint xoff;
|
|
|
|
gint yoff;
|
1999-01-19 06:59:51 +08:00
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
gimp_drawable_offsets (GIMP_DRAWABLE (gimage->layers->data),
|
1999-01-19 06:59:51 +08:00
|
|
|
&xoff, &yoff);
|
|
|
|
|
|
|
|
if ((xoff==0) && (yoff==0)) /* Starts at 0,0 */
|
1999-08-22 19:45:31 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, destPR;
|
2000-12-04 05:34:38 +08:00
|
|
|
gpointer pr;
|
1999-01-19 06:59:51 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
g_warning("Can use cow-projection hack. Yay!");
|
|
|
|
|
|
|
|
pixel_region_init (&srcPR, gimp_drawable_data
|
2001-01-29 07:25:25 +08:00
|
|
|
(GIMP_DRAWABLE (gimage->layers->data)),
|
1999-08-22 19:45:31 +08:00
|
|
|
x, y, w,h, FALSE);
|
|
|
|
pixel_region_init (&destPR,
|
|
|
|
gimp_image_projection (gimage),
|
|
|
|
x, y, w,h, TRUE);
|
|
|
|
|
|
|
|
for (pr = pixel_regions_register (2, &srcPR, &destPR);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
|
|
|
{
|
|
|
|
tile_manager_map_over_tile (destPR.tiles,
|
|
|
|
destPR.curtile, srcPR.curtile);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimage->construct_flag = 1;
|
|
|
|
gimp_image_construct_channels (gimage, x, y, w, h);
|
2000-12-04 05:34:38 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
return;
|
|
|
|
}
|
1999-01-19 06:59:51 +08:00
|
|
|
}
|
1999-02-07 23:16:45 +08:00
|
|
|
#else
|
|
|
|
gimage->construct_flag = 0;
|
1999-01-19 06:59:51 +08:00
|
|
|
#endif
|
|
|
|
|
1998-08-20 08:35:40 +08:00
|
|
|
/* First, determine if the projection image needs to be
|
|
|
|
* initialized--this is the case when there are no visible
|
|
|
|
* layers that cover the entire canvas--either because layers
|
|
|
|
* are offset or only a floating selection is visible
|
|
|
|
*/
|
|
|
|
gimp_image_initialize_projection (gimage, x, y, w, h);
|
|
|
|
|
|
|
|
/* call functions which process the list of layers and
|
|
|
|
* the list of channels
|
|
|
|
*/
|
|
|
|
gimp_image_construct_layers (gimage, x, y, w, h);
|
|
|
|
gimp_image_construct_channels (gimage, x, y, w, h);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-07-20 03:46:05 +08:00
|
|
|
gimp_image_invalidate_without_render (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h,
|
|
|
|
gint x1,
|
|
|
|
gint y1,
|
|
|
|
gint x2,
|
|
|
|
gint y2)
|
1999-02-07 23:16:45 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
Tile *tile;
|
1999-02-07 23:16:45 +08:00
|
|
|
TileManager *tm;
|
2000-12-04 05:34:38 +08:00
|
|
|
gint i, j;
|
1999-02-07 23:16:45 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
1999-02-07 23:16:45 +08:00
|
|
|
tm = gimp_image_projection (gimage);
|
|
|
|
|
|
|
|
/* invalidate all tiles which are located outside of the displayed area
|
|
|
|
* all tiles inside the displayed area are constructed.
|
|
|
|
*/
|
|
|
|
for (i = y; i < (y + h); i += (TILE_HEIGHT - (i % TILE_HEIGHT)))
|
|
|
|
for (j = x; j < (x + w); j += (TILE_WIDTH - (j % TILE_WIDTH)))
|
|
|
|
{
|
|
|
|
tile = tile_manager_get_tile (tm, j, i, FALSE, FALSE);
|
|
|
|
|
|
|
|
/* check if the tile is outside the bounds */
|
|
|
|
if ((MIN ((j + tile_ewidth(tile)), x2) - MAX (j, x1)) <= 0)
|
|
|
|
{
|
|
|
|
tile_invalidate_tile (&tile, tm, j, i);
|
|
|
|
}
|
|
|
|
else if (MIN ((i + tile_eheight(tile)), y2) - MAX (i, y1) <= 0)
|
|
|
|
{
|
|
|
|
tile_invalidate_tile (&tile, tm, j, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_invalidate (GimpImage *gimage,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h,
|
|
|
|
gint x1,
|
|
|
|
gint y1,
|
|
|
|
gint x2,
|
|
|
|
gint y2)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
Tile *tile;
|
1998-06-28 18:39:58 +08:00
|
|
|
TileManager *tm;
|
2000-12-04 05:34:38 +08:00
|
|
|
gint i, j;
|
|
|
|
gint startx, starty;
|
|
|
|
gint endx, endy;
|
|
|
|
gint tilex, tiley;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
tm = gimp_image_projection (gimage);
|
|
|
|
|
|
|
|
startx = x;
|
|
|
|
starty = y;
|
2000-12-04 05:34:38 +08:00
|
|
|
endx = x + w;
|
|
|
|
endy = y + h;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* invalidate all tiles which are located outside of the displayed area
|
|
|
|
* all tiles inside the displayed area are constructed.
|
|
|
|
*/
|
|
|
|
for (i = y; i < (y + h); i += (TILE_HEIGHT - (i % TILE_HEIGHT)))
|
|
|
|
for (j = x; j < (x + w); j += (TILE_WIDTH - (j % TILE_WIDTH)))
|
|
|
|
{
|
1998-08-16 03:17:36 +08:00
|
|
|
tile = tile_manager_get_tile (tm, j, i, FALSE, FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
1998-08-20 08:35:40 +08:00
|
|
|
/* check if the tile is outside the bounds */
|
|
|
|
if ((MIN ((j + tile_ewidth(tile)), x2) - MAX (j, x1)) <= 0)
|
|
|
|
{
|
|
|
|
tile_invalidate_tile (&tile, tm, j, i);
|
|
|
|
if (j < x1)
|
|
|
|
startx = MAX (startx, (j + tile_ewidth(tile)));
|
|
|
|
else
|
|
|
|
endx = MIN (endx, j);
|
|
|
|
}
|
|
|
|
else if (MIN ((i + tile_eheight(tile)), y2) - MAX (i, y1) <= 0)
|
|
|
|
{
|
|
|
|
tile_invalidate_tile (&tile, tm, j, i);
|
|
|
|
if (i < y1)
|
|
|
|
starty = MAX (starty, (i + tile_eheight(tile)));
|
|
|
|
else
|
|
|
|
endy = MIN (endy, i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If the tile is not valid, make sure we get the entire tile
|
|
|
|
* in the construction extents
|
|
|
|
*/
|
2000-12-28 00:12:05 +08:00
|
|
|
if (tile_is_valid (tile) == FALSE)
|
1998-08-20 08:35:40 +08:00
|
|
|
{
|
|
|
|
tilex = j - (j % TILE_WIDTH);
|
|
|
|
tiley = i - (i % TILE_HEIGHT);
|
|
|
|
|
|
|
|
startx = MIN (startx, tilex);
|
2000-12-28 00:12:05 +08:00
|
|
|
endx = MAX (endx, tilex + tile_ewidth (tile));
|
1998-08-20 08:35:40 +08:00
|
|
|
starty = MIN (starty, tiley);
|
2000-12-28 00:12:05 +08:00
|
|
|
endy = MAX (endy, tiley + tile_eheight (tile));
|
1998-08-20 08:35:40 +08:00
|
|
|
|
|
|
|
tile_mark_valid (tile); /* hmmmmmmm..... */
|
|
|
|
}
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
1998-08-20 08:35:40 +08:00
|
|
|
if ((endx - startx) > 0 && (endy - starty) > 0)
|
2000-12-04 05:34:38 +08:00
|
|
|
gimp_image_construct (gimage,
|
|
|
|
startx, starty,
|
2000-12-29 00:19:55 +08:00
|
|
|
(endx - startx), (endy - starty));
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_validate (TileManager *tm,
|
|
|
|
Tile *tile)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
GimpImage *gimage;
|
2000-12-04 05:34:38 +08:00
|
|
|
gint x, y;
|
|
|
|
gint w, h;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-05-14 05:51:20 +08:00
|
|
|
gimp_set_busy_until_idle ();
|
1999-01-18 01:03:54 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* Get the gimage from the tilemanager */
|
1998-07-29 07:13:36 +08:00
|
|
|
gimage = (GimpImage *) tile_manager_get_user_data (tm);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* Find the coordinates of this tile */
|
1998-07-29 07:13:36 +08:00
|
|
|
tile_manager_get_tile_coordinates (tm, tile, &x, &y);
|
1999-08-22 19:45:31 +08:00
|
|
|
w = tile_ewidth (tile);
|
|
|
|
h = tile_eheight (tile);
|
1999-01-19 06:59:51 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_construct (gimage, x, y, w, h);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-01-29 00:44:22 +08:00
|
|
|
void
|
|
|
|
gimp_image_invalidate_layer_previews (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_if_fail (gimage != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_container_foreach (gimage->layers,
|
|
|
|
(GFunc) gimp_viewable_invalidate_preview,
|
|
|
|
NULL);
|
2001-01-29 00:44:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_image_invalidate_channel_previews (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_if_fail (gimage != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_container_foreach (gimage->channels,
|
|
|
|
(GFunc) gimp_viewable_invalidate_preview,
|
|
|
|
NULL);
|
2001-01-29 00:44:22 +08:00
|
|
|
}
|
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
GimpContainer *
|
|
|
|
gimp_image_get_layers (const GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (gimage != NULL, NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
|
|
|
return gimage->layers;
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpContainer *
|
|
|
|
gimp_image_get_channels (const GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (gimage != NULL, NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
|
|
|
return gimage->channels;
|
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gint
|
|
|
|
gimp_image_get_layer_index (const GimpImage *gimage,
|
|
|
|
const GimpLayer *layer)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, -1);
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1);
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (layer != NULL, -1);
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), -1);
|
2000-12-28 00:12:05 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return gimp_container_get_child_index (gimage->layers,
|
|
|
|
GIMP_OBJECT (layer));
|
2000-12-28 00:12:05 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gint
|
|
|
|
gimp_image_get_channel_index (const GimpImage *gimage,
|
|
|
|
const GimpChannel *channel)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-28 00:12:05 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, -1);
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1);
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (channel != NULL, -1);
|
|
|
|
g_return_val_if_fail (GIMP_IS_CHANNEL (channel), -1);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return gimp_container_get_child_index (gimage->channels,
|
|
|
|
GIMP_OBJECT (channel));
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_active_layer (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-28 00:12:05 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, NULL);
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
return gimage->active_layer;
|
|
|
|
}
|
|
|
|
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_active_channel (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
return gimage->active_channel;
|
|
|
|
}
|
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_layer_by_tattoo (const GimpImage *gimage,
|
|
|
|
Tattoo tattoo)
|
1998-10-14 10:54:02 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer;
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
1998-10-14 10:54:02 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1999-08-22 19:45:31 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer)) == tattoo)
|
1999-08-22 19:45:31 +08:00
|
|
|
return layer;
|
|
|
|
}
|
1998-10-14 10:54:02 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_channel_by_tattoo (const GimpImage *gimage,
|
|
|
|
Tattoo tattoo)
|
1998-10-14 10:54:02 +08:00
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *channel;
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2000-03-09 19:58:03 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
1998-10-14 10:54:02 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->channels)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1999-08-22 19:45:31 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
channel = (GimpChannel *) list->data;
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2001-01-29 08:46:04 +08:00
|
|
|
if (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)) == tattoo)
|
1999-08-22 19:45:31 +08:00
|
|
|
return channel;
|
|
|
|
}
|
1998-10-14 10:54:02 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_channel_by_name (const GimpImage *gimage,
|
|
|
|
const gchar *name)
|
1999-07-07 11:18:54 +08:00
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *channel;
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2000-03-09 19:58:03 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
1999-07-07 11:18:54 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->channels)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1999-08-22 19:45:31 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
channel = (GimpChannel *) list->data;
|
2001-01-10 11:13:03 +08:00
|
|
|
if (! strcmp (gimp_object_get_name (GIMP_OBJECT (channel)), name))
|
1999-07-07 11:18:54 +08:00
|
|
|
return channel;
|
1999-08-22 19:45:31 +08:00
|
|
|
}
|
1999-07-07 11:18:54 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
1999-08-22 19:45:31 +08:00
|
|
|
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_get_mask (const GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
|
|
|
return gimage->selection_mask;
|
|
|
|
}
|
|
|
|
|
2001-05-07 00:14:34 +08:00
|
|
|
void
|
|
|
|
gimp_image_set_component_active (GimpImage *gimage,
|
|
|
|
ChannelType type,
|
|
|
|
gboolean active)
|
|
|
|
{
|
|
|
|
gint pixel = -1;
|
|
|
|
|
|
|
|
g_return_if_fail (gimage != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case RED_CHANNEL: pixel = RED_PIX; break;
|
|
|
|
case GREEN_CHANNEL: pixel = GREEN_PIX; break;
|
|
|
|
case BLUE_CHANNEL: pixel = BLUE_PIX; break;
|
|
|
|
case GRAY_CHANNEL: pixel = GRAY_PIX; break;
|
|
|
|
case INDEXED_CHANNEL: pixel = INDEXED_PIX; break;
|
|
|
|
case ALPHA_CHANNEL:
|
|
|
|
switch (gimp_image_base_type (gimage))
|
|
|
|
{
|
|
|
|
case RGB: pixel = ALPHA_PIX; break;
|
|
|
|
case GRAY: pixel = ALPHA_G_PIX; break;
|
|
|
|
case INDEXED: pixel = ALPHA_I_PIX; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pixel != -1 && active != gimage->active[pixel])
|
|
|
|
{
|
|
|
|
gimage->active[pixel] = active ? TRUE : FALSE;
|
|
|
|
|
|
|
|
/* If there is an active channel and we mess with the components,
|
|
|
|
* the active channel gets unset...
|
|
|
|
*/
|
|
|
|
gimp_image_unset_active_channel (gimage);
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[COMPONENT_ACTIVE_CHANGED],
|
|
|
|
type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
gboolean
|
|
|
|
gimp_image_get_component_active (const GimpImage *gimage,
|
|
|
|
ChannelType type)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
/* No sanity checking here... */
|
|
|
|
switch (type)
|
|
|
|
{
|
2001-05-07 00:14:34 +08:00
|
|
|
case RED_CHANNEL: return gimage->active[RED_PIX]; break;
|
|
|
|
case GREEN_CHANNEL: return gimage->active[GREEN_PIX]; break;
|
|
|
|
case BLUE_CHANNEL: return gimage->active[BLUE_PIX]; break;
|
|
|
|
case GRAY_CHANNEL: return gimage->active[GRAY_PIX]; break;
|
1999-04-27 12:57:59 +08:00
|
|
|
case INDEXED_CHANNEL: return gimage->active[INDEXED_PIX]; break;
|
2001-05-07 00:14:34 +08:00
|
|
|
case ALPHA_CHANNEL:
|
|
|
|
switch (gimp_image_base_type (gimage))
|
|
|
|
{
|
|
|
|
case RGB: return gimage->active[ALPHA_PIX]; break;
|
|
|
|
case GRAY: return gimage->active[ALPHA_G_PIX]; break;
|
|
|
|
case INDEXED: return gimage->active[ALPHA_I_PIX]; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_image_set_component_visible (GimpImage *gimage,
|
|
|
|
ChannelType type,
|
|
|
|
gboolean visible)
|
|
|
|
{
|
|
|
|
gint pixel = -1;
|
|
|
|
|
|
|
|
g_return_if_fail (gimage != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case RED_CHANNEL: pixel = RED_PIX; break;
|
|
|
|
case GREEN_CHANNEL: pixel = GREEN_PIX; break;
|
|
|
|
case BLUE_CHANNEL: pixel = BLUE_PIX; break;
|
|
|
|
case GRAY_CHANNEL: pixel = GRAY_PIX; break;
|
|
|
|
case INDEXED_CHANNEL: pixel = INDEXED_PIX; break;
|
|
|
|
case ALPHA_CHANNEL:
|
|
|
|
switch (gimp_image_base_type (gimage))
|
|
|
|
{
|
|
|
|
case RGB: pixel = ALPHA_PIX; break;
|
|
|
|
case GRAY: pixel = ALPHA_G_PIX; break;
|
|
|
|
case INDEXED: pixel = ALPHA_I_PIX; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pixel != -1 && visible != gimage->visible[pixel])
|
|
|
|
{
|
|
|
|
gimage->visible[pixel] = visible ? TRUE : FALSE;
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[COMPONENT_VISIBILITY_CHANGED],
|
|
|
|
type);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
gboolean
|
|
|
|
gimp_image_get_component_visible (const GimpImage *gimage,
|
|
|
|
ChannelType type)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
/* No sanity checking here... */
|
|
|
|
switch (type)
|
|
|
|
{
|
2001-05-07 00:14:34 +08:00
|
|
|
case RED_CHANNEL: return gimage->visible[RED_PIX]; break;
|
|
|
|
case GREEN_CHANNEL: return gimage->visible[GREEN_PIX]; break;
|
|
|
|
case BLUE_CHANNEL: return gimage->visible[BLUE_PIX]; break;
|
|
|
|
case GRAY_CHANNEL: return gimage->visible[GRAY_PIX]; break;
|
1999-04-27 12:57:59 +08:00
|
|
|
case INDEXED_CHANNEL: return gimage->visible[INDEXED_PIX]; break;
|
2001-05-07 00:14:34 +08:00
|
|
|
case ALPHA_CHANNEL:
|
|
|
|
switch (gimp_image_base_type (gimage))
|
|
|
|
{
|
|
|
|
case RGB: return gimage->visible[ALPHA_PIX]; break;
|
|
|
|
case GRAY: return gimage->visible[ALPHA_G_PIX]; break;
|
|
|
|
case INDEXED: return gimage->visible[ALPHA_I_PIX]; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
2001-05-07 00:14:34 +08:00
|
|
|
|
|
|
|
return FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_layer_boundary (const GimpImage *gimage,
|
|
|
|
BoundSeg **segs,
|
|
|
|
gint *n_segs)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
2000-12-29 00:19:55 +08:00
|
|
|
g_return_val_if_fail (segs != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (n_segs != NULL, FALSE);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* The second boundary corresponds to the active layer's
|
|
|
|
* perimeter...
|
|
|
|
*/
|
2001-02-25 22:37:12 +08:00
|
|
|
layer = gimp_image_get_active_layer (gimage);
|
|
|
|
|
|
|
|
if (layer)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
*segs = gimp_layer_boundary (layer, n_segs);
|
1999-08-22 19:45:31 +08:00
|
|
|
return TRUE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*segs = NULL;
|
2000-12-29 00:19:55 +08:00
|
|
|
*n_segs = 0;
|
1999-08-22 19:45:31 +08:00
|
|
|
return FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_set_active_layer (GimpImage *gimage,
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
2000-12-29 00:19:55 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* First, find the layer in the gimage
|
|
|
|
* If it isn't valid, find the first layer that is
|
|
|
|
*/
|
2001-02-19 21:06:09 +08:00
|
|
|
if (! gimp_container_have (gimage->layers, GIMP_OBJECT (layer)))
|
|
|
|
layer = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers, 0);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
if (layer)
|
2001-02-19 21:06:09 +08:00
|
|
|
{
|
2001-02-27 22:14:13 +08:00
|
|
|
/* Configure the layer stack to reflect this change */
|
|
|
|
gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer);
|
|
|
|
gimage->layer_stack = g_slist_prepend (gimage->layer_stack, layer);
|
|
|
|
|
|
|
|
/* invalidate the selection boundary because of a layer modification */
|
|
|
|
gimp_layer_invalidate_boundary (layer);
|
2001-02-19 21:06:09 +08:00
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
if (layer != gimage->active_layer)
|
|
|
|
{
|
|
|
|
gimage->active_layer = layer;
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[ACTIVE_LAYER_CHANGED]);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
if (gimage->active_channel)
|
|
|
|
{
|
|
|
|
gimage->active_channel = NULL;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[ACTIVE_CHANNEL_CHANGED]);
|
|
|
|
}
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* return the layer */
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *
|
|
|
|
gimp_image_set_active_channel (GimpImage *gimage,
|
|
|
|
GimpChannel *channel)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* Not if there is a floating selection */
|
|
|
|
if (gimp_image_floating_sel (gimage))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* First, find the channel
|
|
|
|
* If it doesn't exist, find the first channel that does
|
|
|
|
*/
|
2001-02-19 21:06:09 +08:00
|
|
|
if (! gimp_container_have (gimage->channels, GIMP_OBJECT (channel)))
|
|
|
|
channel = (GimpChannel *) gimp_container_get_child_by_index (gimage->channels, 0);
|
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
if (channel != gimage->active_channel)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-27 22:14:13 +08:00
|
|
|
gimage->active_channel = channel;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[ACTIVE_CHANNEL_CHANGED]);
|
|
|
|
|
|
|
|
if (gimage->active_layer)
|
|
|
|
{
|
|
|
|
gimage->active_layer = NULL;
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[ACTIVE_LAYER_CHANGED]);
|
|
|
|
}
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* return the channel */
|
|
|
|
return channel;
|
|
|
|
}
|
|
|
|
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_unset_active_channel (GimpImage *gimage)
|
|
|
|
{
|
2001-01-29 10:45:02 +08:00
|
|
|
GimpChannel *channel;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
channel = gimp_image_get_active_channel (gimage);
|
|
|
|
|
|
|
|
if (channel)
|
|
|
|
{
|
|
|
|
gimage->active_channel = NULL;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[ACTIVE_CHANNEL_CHANGED]);
|
|
|
|
|
|
|
|
if (gimage->layer_stack)
|
|
|
|
{
|
|
|
|
GimpLayer *layer;
|
|
|
|
|
|
|
|
layer = (GimpLayer *) gimage->layer_stack->data;
|
|
|
|
|
|
|
|
gimp_image_set_active_layer (gimage, layer);
|
|
|
|
}
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
return channel;
|
|
|
|
}
|
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_pick_correlate_layer (const GimpImage *gimage,
|
|
|
|
gint x,
|
|
|
|
gint y)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer;
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
2000-12-28 02:15:37 +08:00
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
if (gimp_layer_pick_correlate (layer, x, y))
|
1998-06-28 18:39:58 +08:00
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_raise_layer (GimpImage *gimage,
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpLayer *layer)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
gint curpos;
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (layer != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
|
|
|
|
curpos = gimp_container_get_child_index (gimage->layers,
|
|
|
|
GIMP_OBJECT (layer));
|
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
/* is this the top layer already? */
|
|
|
|
if (curpos == 0)
|
1999-10-02 07:13:13 +08:00
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message (_("%s(): layer cannot be raised any further"),
|
|
|
|
G_GNUC_FUNCTION);
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return gimp_image_position_layer (gimage, layer, curpos - 1, TRUE);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_lower_layer (GimpImage *gimage,
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpLayer *layer)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
gint curpos;
|
|
|
|
gint length;
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (layer != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
|
|
|
|
curpos = gimp_container_get_child_index (gimage->layers,
|
|
|
|
GIMP_OBJECT (layer));
|
2000-03-09 19:58:03 +08:00
|
|
|
|
|
|
|
/* is this the bottom layer already? */
|
2001-02-19 21:06:09 +08:00
|
|
|
length = gimp_container_num_children (gimage->layers);
|
|
|
|
if (curpos >= length - 1)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message (_("%s(): layer cannot be lowered any further"),
|
|
|
|
G_GNUC_FUNCTION);
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return gimp_image_position_layer (gimage, layer, curpos + 1, TRUE);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
1999-07-27 10:41:34 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_raise_layer_to_top (GimpImage *gimage,
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpLayer *layer)
|
1998-11-16 01:02:59 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
gint curpos;
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (layer != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
|
|
|
|
curpos = gimp_container_get_child_index (gimage->layers,
|
|
|
|
GIMP_OBJECT (layer));
|
2000-03-09 19:58:03 +08:00
|
|
|
|
|
|
|
if (curpos == 0)
|
1998-11-16 01:02:59 +08:00
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message (_("%s(): layer is already on top"),
|
|
|
|
G_GNUC_FUNCTION);
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
1998-11-16 01:02:59 +08:00
|
|
|
}
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
if (! gimp_layer_has_alpha (layer))
|
1998-11-16 01:02:59 +08:00
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message (_("%s(): can't raise Layer without alpha"), G_GNUC_FUNCTION);
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
1998-11-16 01:02:59 +08:00
|
|
|
}
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return gimp_image_position_layer (gimage, layer, 0, TRUE);
|
1998-11-16 01:02:59 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_lower_layer_to_bottom (GimpImage *gimage,
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpLayer *layer)
|
1998-11-16 01:02:59 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
gint curpos;
|
|
|
|
gint length;
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
|
|
|
g_return_val_if_fail (layer != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
2001-01-29 07:25:25 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
curpos = gimp_container_get_child_index (gimage->layers,
|
|
|
|
GIMP_OBJECT (layer));
|
|
|
|
|
|
|
|
length = gimp_container_num_children (gimage->layers);
|
2001-01-29 07:25:25 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
if (curpos >= length - 1)
|
1999-10-02 07:13:13 +08:00
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message (_("%s(): layer is already on bottom"), G_GNUC_FUNCTION);
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
1999-10-02 07:13:13 +08:00
|
|
|
}
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return gimp_image_position_layer (gimage, layer, length - 1, TRUE);
|
1998-11-16 01:02:59 +08:00
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
1999-07-27 10:41:34 +08:00
|
|
|
gimp_image_position_layer (GimpImage *gimage,
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpLayer *layer,
|
1999-10-02 07:13:13 +08:00
|
|
|
gint new_index,
|
|
|
|
gboolean push_undo)
|
1999-07-27 10:41:34 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
gint x_min, y_min, x_max, y_max;
|
|
|
|
gint off_x, off_y;
|
|
|
|
gint index;
|
|
|
|
gint num_layers;
|
1999-07-27 10:41:34 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
|
|
|
g_return_val_if_fail (layer != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
1999-07-27 10:41:34 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
index = gimp_container_get_child_index (gimage->layers,
|
|
|
|
GIMP_OBJECT (layer));
|
1999-10-02 07:13:13 +08:00
|
|
|
if (index < 0)
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
num_layers = gimp_container_num_children (gimage->layers);
|
1999-07-27 10:41:34 +08:00
|
|
|
|
|
|
|
if (new_index < 0)
|
|
|
|
new_index = 0;
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
if (new_index >= num_layers)
|
|
|
|
new_index = num_layers - 1;
|
1999-07-27 10:41:34 +08:00
|
|
|
|
|
|
|
if (new_index == index)
|
2001-02-19 21:06:09 +08:00
|
|
|
return TRUE;
|
1999-07-27 10:41:34 +08:00
|
|
|
|
|
|
|
/* check if we want to move it below a bottom layer without alpha */
|
2001-02-19 21:06:09 +08:00
|
|
|
if (new_index == num_layers - 1)
|
1999-07-27 10:41:34 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpLayer *tmp;
|
|
|
|
|
|
|
|
tmp = (GimpLayer *) gimp_container_get_child_by_index (gimage->layers,
|
|
|
|
num_layers - 1);
|
|
|
|
|
|
|
|
if (new_index == num_layers - 1 &&
|
|
|
|
! gimp_layer_has_alpha (tmp))
|
|
|
|
{
|
|
|
|
g_message (_("BG has no alpha, layer was placed above"));
|
|
|
|
new_index--;
|
|
|
|
}
|
1999-07-27 10:41:34 +08:00
|
|
|
}
|
|
|
|
|
1999-10-02 07:13:13 +08:00
|
|
|
if (push_undo)
|
2001-02-25 22:37:12 +08:00
|
|
|
undo_push_layer_reposition (gimage, layer);
|
1999-10-02 07:13:13 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_container_reorder (gimage->layers, GIMP_OBJECT (layer), new_index);
|
1999-07-27 10:41:34 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
|
1999-07-27 10:41:34 +08:00
|
|
|
x_min = off_x;
|
|
|
|
y_min = off_y;
|
2001-02-19 21:06:09 +08:00
|
|
|
x_max = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer));
|
|
|
|
y_max = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer));
|
1999-07-27 10:41:34 +08:00
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[REPAINT],
|
|
|
|
x_min, y_min, x_max, y_max);
|
|
|
|
|
|
|
|
/* invalidate the composite preview */
|
2001-02-05 06:10:54 +08:00
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage));
|
1999-07-27 10:41:34 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return TRUE;
|
1999-07-27 10:41:34 +08:00
|
|
|
}
|
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_merge_visible_layers (GimpImage *gimage,
|
|
|
|
MergeType merge_type)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2001-01-29 07:25:25 +08:00
|
|
|
GSList *merge_list = NULL;
|
|
|
|
gboolean had_floating_sel = FALSE;
|
|
|
|
GimpLayer *layer = NULL;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2000-01-05 17:09:46 +08:00
|
|
|
/* if there's a floating selection, anchor it */
|
|
|
|
if (gimp_image_floating_sel (gimage))
|
|
|
|
{
|
|
|
|
floating_sel_anchor (gimage->floating_sel);
|
|
|
|
had_floating_sel = TRUE;
|
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-03-05 00:52:37 +08:00
|
|
|
if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer)))
|
2000-12-28 02:15:37 +08:00
|
|
|
merge_list = g_slist_append (merge_list, layer);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (merge_list && merge_list->next)
|
|
|
|
{
|
2001-05-14 05:51:20 +08:00
|
|
|
gimp_set_busy ();
|
2000-12-28 02:15:37 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
layer = gimp_image_merge_layers (gimage, merge_list, merge_type);
|
|
|
|
g_slist_free (merge_list);
|
2000-12-28 02:15:37 +08:00
|
|
|
|
2001-05-14 05:51:20 +08:00
|
|
|
gimp_unset_busy ();
|
2000-12-04 05:34:38 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_slist_free (merge_list);
|
2000-01-05 17:09:46 +08:00
|
|
|
|
|
|
|
/* If there was a floating selection, we have done something.
|
|
|
|
No need to warn the user. Return the active layer instead */
|
|
|
|
if (had_floating_sel)
|
|
|
|
return layer;
|
|
|
|
else
|
|
|
|
g_message (_("There are not enough visible layers for a merge.\nThere must be at least two."));
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_flatten (GimpImage *gimage)
|
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2001-01-29 07:25:25 +08:00
|
|
|
GSList *merge_list = NULL;
|
|
|
|
GimpLayer *layer;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-05-14 05:51:20 +08:00
|
|
|
gimp_set_busy ();
|
1999-01-11 07:36:29 +08:00
|
|
|
|
2000-01-05 17:09:46 +08:00
|
|
|
/* if there's a floating selection, anchor it */
|
|
|
|
if (gimp_image_floating_sel (gimage))
|
|
|
|
floating_sel_anchor (gimage->floating_sel);
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
2000-12-28 02:15:37 +08:00
|
|
|
|
2001-03-05 00:52:37 +08:00
|
|
|
if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer)))
|
1998-06-28 18:39:58 +08:00
|
|
|
merge_list = g_slist_append (merge_list, layer);
|
|
|
|
}
|
|
|
|
|
1999-04-27 12:57:59 +08:00
|
|
|
layer = gimp_image_merge_layers (gimage, merge_list, FLATTEN_IMAGE);
|
1998-06-28 18:39:58 +08:00
|
|
|
g_slist_free (merge_list);
|
1999-01-11 07:36:29 +08:00
|
|
|
|
2001-05-07 02:58:04 +08:00
|
|
|
gimp_image_alpha_changed (gimage);
|
|
|
|
|
2001-05-14 05:51:20 +08:00
|
|
|
gimp_unset_busy ();
|
1999-01-11 07:36:29 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *
|
1998-09-01 05:41:43 +08:00
|
|
|
gimp_image_merge_down (GimpImage *gimage,
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *current_layer,
|
1999-07-10 02:15:39 +08:00
|
|
|
MergeType merge_type)
|
1998-09-01 05:41:43 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpLayer *layer;
|
|
|
|
GList *list;
|
|
|
|
GList *layer_list;
|
|
|
|
GSList *merge_list;
|
1998-09-01 05:41:43 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list, layer_list = NULL;
|
|
|
|
list && !layer_list;
|
|
|
|
list = g_list_next (list))
|
1998-09-01 05:41:43 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
|
|
|
|
1998-09-01 05:41:43 +08:00
|
|
|
if (layer == current_layer)
|
2001-02-19 21:06:09 +08:00
|
|
|
break;
|
1998-09-01 05:41:43 +08:00
|
|
|
}
|
2001-02-19 21:06:09 +08:00
|
|
|
|
|
|
|
for (layer_list = g_list_next (list), merge_list = NULL;
|
|
|
|
layer_list && !merge_list;
|
|
|
|
layer_list = g_list_next (layer_list))
|
|
|
|
{
|
|
|
|
layer = (GimpLayer *) layer_list->data;
|
|
|
|
|
2001-03-05 00:52:37 +08:00
|
|
|
if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer)))
|
2001-02-19 21:06:09 +08:00
|
|
|
merge_list = g_slist_append (NULL, layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (merge_list)
|
1998-09-01 05:41:43 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
merge_list = g_slist_prepend (merge_list, current_layer);
|
2001-05-14 05:51:20 +08:00
|
|
|
|
|
|
|
gimp_set_busy ();
|
|
|
|
|
1998-09-01 05:41:43 +08:00
|
|
|
layer = gimp_image_merge_layers (gimage, merge_list, merge_type);
|
|
|
|
g_slist_free (merge_list);
|
2001-05-14 05:51:20 +08:00
|
|
|
|
|
|
|
gimp_unset_busy ();
|
|
|
|
|
1998-09-01 05:41:43 +08:00
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-11-23 22:47:09 +08:00
|
|
|
g_message (_("There are not enough visible layers for a merge down."));
|
1998-09-01 05:41:43 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_merge_layers (GimpImage *gimage,
|
|
|
|
GSList *merge_list,
|
|
|
|
MergeType merge_type)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2000-12-04 05:34:38 +08:00
|
|
|
GSList *reverse_list = NULL;
|
|
|
|
PixelRegion src1PR, src2PR, maskPR;
|
|
|
|
PixelRegion *mask;
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *merge_layer;
|
|
|
|
GimpLayer *layer;
|
2001-05-07 02:58:04 +08:00
|
|
|
GimpLayer *bottom_layer;
|
2000-12-04 05:34:38 +08:00
|
|
|
LayerModeEffects bottom_mode;
|
|
|
|
guchar bg[4] = {0, 0, 0, 0};
|
|
|
|
GimpImageType type;
|
|
|
|
gint count;
|
|
|
|
gint x1, y1, x2, y2;
|
|
|
|
gint x3, y3, x4, y4;
|
|
|
|
gint operation;
|
|
|
|
gint position;
|
|
|
|
gint active[MAX_CHANNELS] = {1, 1, 1, 1};
|
|
|
|
gint off_x, off_y;
|
|
|
|
gchar *name;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-05-07 02:58:04 +08:00
|
|
|
layer = NULL;
|
|
|
|
type = RGBA_GIMAGE;
|
|
|
|
x1 = y1 = 0;
|
|
|
|
x2 = y2 = 0;
|
|
|
|
bottom_layer = NULL;
|
|
|
|
bottom_mode = NORMAL_MODE;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* Get the layer extents */
|
|
|
|
count = 0;
|
|
|
|
while (merge_list)
|
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) merge_list->data;
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
switch (merge_type)
|
|
|
|
{
|
1999-04-27 12:57:59 +08:00
|
|
|
case EXPAND_AS_NECESSARY:
|
|
|
|
case CLIP_TO_IMAGE:
|
1998-06-28 18:39:58 +08:00
|
|
|
if (!count)
|
|
|
|
{
|
|
|
|
x1 = off_x;
|
|
|
|
y1 = off_y;
|
2001-02-25 22:37:12 +08:00
|
|
|
x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer));
|
|
|
|
y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer));
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (off_x < x1)
|
|
|
|
x1 = off_x;
|
|
|
|
if (off_y < y1)
|
|
|
|
y1 = off_y;
|
2001-02-25 22:37:12 +08:00
|
|
|
if ((off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))) > x2)
|
|
|
|
x2 = (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)));
|
|
|
|
if ((off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))) > y2)
|
|
|
|
y2 = (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)));
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
1999-04-27 12:57:59 +08:00
|
|
|
if (merge_type == CLIP_TO_IMAGE)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
x1 = CLAMP (x1, 0, gimage->width);
|
|
|
|
y1 = CLAMP (y1, 0, gimage->height);
|
|
|
|
x2 = CLAMP (x2, 0, gimage->width);
|
|
|
|
y2 = CLAMP (y2, 0, gimage->height);
|
|
|
|
}
|
|
|
|
break;
|
2000-12-04 05:34:38 +08:00
|
|
|
|
1999-04-27 12:57:59 +08:00
|
|
|
case CLIP_TO_BOTTOM_LAYER:
|
1998-06-28 18:39:58 +08:00
|
|
|
if (merge_list->next == NULL)
|
|
|
|
{
|
|
|
|
x1 = off_x;
|
|
|
|
y1 = off_y;
|
2001-02-25 22:37:12 +08:00
|
|
|
x2 = off_x + gimp_drawable_width (GIMP_DRAWABLE (layer));
|
|
|
|
y2 = off_y + gimp_drawable_height (GIMP_DRAWABLE (layer));
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
break;
|
2000-12-04 05:34:38 +08:00
|
|
|
|
1999-04-27 12:57:59 +08:00
|
|
|
case FLATTEN_IMAGE:
|
1998-06-28 18:39:58 +08:00
|
|
|
if (merge_list->next == NULL)
|
|
|
|
{
|
|
|
|
x1 = 0;
|
|
|
|
y1 = 0;
|
|
|
|
x2 = gimage->width;
|
|
|
|
y2 = gimage->height;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
count ++;
|
|
|
|
reverse_list = g_slist_prepend (reverse_list, layer);
|
|
|
|
merge_list = g_slist_next (merge_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((x2 - x1) == 0 || (y2 - y1) == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Start a merge undo group */
|
|
|
|
undo_push_group_start (gimage, LAYER_MERGE_UNDO);
|
|
|
|
|
2001-01-10 11:13:03 +08:00
|
|
|
name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer)));
|
2000-05-12 09:14:21 +08:00
|
|
|
|
1999-04-27 12:57:59 +08:00
|
|
|
if (merge_type == FLATTEN_IMAGE ||
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_type (GIMP_DRAWABLE (layer)) == INDEXED_GIMAGE)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
switch (gimp_image_base_type (gimage))
|
|
|
|
{
|
|
|
|
case RGB: type = RGB_GIMAGE; break;
|
|
|
|
case GRAY: type = GRAY_GIMAGE; break;
|
|
|
|
case INDEXED: type = INDEXED_GIMAGE; break;
|
|
|
|
}
|
2000-12-04 05:34:38 +08:00
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
merge_layer = gimp_layer_new (gimage, (x2 - x1), (y2 - y1),
|
|
|
|
type,
|
|
|
|
gimp_object_get_name (GIMP_OBJECT (layer)),
|
|
|
|
OPAQUE_OPACITY, NORMAL_MODE);
|
1999-08-22 19:45:31 +08:00
|
|
|
if (!merge_layer)
|
|
|
|
{
|
1999-09-23 19:49:16 +08:00
|
|
|
g_message ("gimp_image_merge_layers: could not allocate merge layer");
|
1999-08-22 19:45:31 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-12-04 05:34:38 +08:00
|
|
|
GIMP_DRAWABLE (merge_layer)->offset_x = x1;
|
|
|
|
GIMP_DRAWABLE (merge_layer)->offset_y = y1;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* get the background for compositing */
|
2000-12-04 05:34:38 +08:00
|
|
|
gimp_image_get_background (gimage, GIMP_DRAWABLE (merge_layer), bg);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* init the pixel region */
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&src1PR,
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (merge_layer)),
|
2000-12-04 05:34:38 +08:00
|
|
|
0, 0,
|
|
|
|
gimage->width, gimage->height,
|
|
|
|
TRUE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* set the region to the background color */
|
|
|
|
color_region (&src1PR, bg);
|
|
|
|
|
|
|
|
position = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-09-01 05:41:43 +08:00
|
|
|
/* The final merged layer inherits the name of the bottom most layer
|
|
|
|
* and the resulting layer has an alpha channel
|
1998-06-28 18:39:58 +08:00
|
|
|
* whether or not the original did
|
1998-09-01 05:41:43 +08:00
|
|
|
* Opacity is set to 100% and the MODE is set to normal
|
1998-06-28 18:39:58 +08:00
|
|
|
*/
|
2000-05-12 09:14:21 +08:00
|
|
|
|
2001-01-15 05:11:52 +08:00
|
|
|
merge_layer =
|
2001-01-29 07:25:25 +08:00
|
|
|
gimp_layer_new (gimage, (x2 - x1), (y2 - y1),
|
|
|
|
gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)),
|
|
|
|
"merged layer",
|
|
|
|
OPAQUE_OPACITY, NORMAL_MODE);
|
2000-05-12 09:14:21 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
if (!merge_layer)
|
|
|
|
{
|
1999-09-23 19:49:16 +08:00
|
|
|
g_message ("gimp_image_merge_layers: could not allocate merge layer");
|
1999-08-22 19:45:31 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-12-04 05:34:38 +08:00
|
|
|
GIMP_DRAWABLE (merge_layer)->offset_x = x1;
|
|
|
|
GIMP_DRAWABLE (merge_layer)->offset_y = y1;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* Set the layer to transparent */
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&src1PR,
|
2001-02-25 22:37:12 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (merge_layer)),
|
2000-12-04 05:34:38 +08:00
|
|
|
0, 0,
|
|
|
|
(x2 - x1), (y2 - y1),
|
|
|
|
TRUE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* set the region to 0's */
|
|
|
|
color_region (&src1PR, bg);
|
|
|
|
|
|
|
|
/* Find the index in the layer list of the bottom layer--we need this
|
|
|
|
* in order to add the final, merged layer to the layer list correctly
|
|
|
|
*/
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) reverse_list->data;
|
2000-12-04 05:34:38 +08:00
|
|
|
position =
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_container_num_children (gimage->layers) -
|
|
|
|
gimp_container_get_child_index (gimage->layers, GIMP_OBJECT (layer));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* set the mode of the bottom layer to normal so that the contents
|
|
|
|
* aren't lost when merging with the all-alpha merge_layer
|
2000-12-04 05:34:38 +08:00
|
|
|
* Keep a pointer to it so that we can set the mode right after it's
|
|
|
|
* been merged so that undo works correctly.
|
1998-06-28 18:39:58 +08:00
|
|
|
*/
|
2001-05-07 02:58:04 +08:00
|
|
|
bottom_layer = layer;
|
|
|
|
bottom_mode = bottom_layer->mode;
|
2000-12-04 05:34:38 +08:00
|
|
|
|
|
|
|
/* DISSOLVE_MODE is special since it is the only mode that does not
|
|
|
|
* work on the projection with the lower layer, but only locally on
|
|
|
|
* the layers alpha channel.
|
|
|
|
*/
|
2001-05-07 02:58:04 +08:00
|
|
|
if (bottom_layer->mode != DISSOLVE_MODE)
|
|
|
|
gimp_layer_set_mode (bottom_layer, NORMAL_MODE);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2000-05-12 09:14:21 +08:00
|
|
|
/* Copy the tattoo and parasites of the bottom layer to the new layer */
|
2001-01-29 07:25:25 +08:00
|
|
|
gimp_drawable_set_tattoo (GIMP_DRAWABLE (merge_layer),
|
|
|
|
gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer)));
|
2001-02-19 21:06:09 +08:00
|
|
|
GIMP_DRAWABLE (merge_layer)->parasites =
|
2001-07-05 06:59:25 +08:00
|
|
|
gimp_parasite_list_copy (GIMP_DRAWABLE (layer)->parasites);
|
2000-05-12 09:14:21 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
while (reverse_list)
|
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) reverse_list->data;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* determine what sort of operation is being attempted and
|
|
|
|
* if it's actually legal...
|
|
|
|
*/
|
2000-12-28 02:15:37 +08:00
|
|
|
operation =
|
2001-01-15 05:11:52 +08:00
|
|
|
valid_combinations[gimp_drawable_type (GIMP_DRAWABLE (merge_layer))][gimp_drawable_bytes (GIMP_DRAWABLE (layer))];
|
2000-12-28 02:15:37 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
if (operation == -1)
|
|
|
|
{
|
1999-09-23 19:49:16 +08:00
|
|
|
g_message ("gimp_image_merge_layers attempting to merge incompatible layers\n");
|
1998-06-28 18:39:58 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
x3 = CLAMP (off_x, x1, x2);
|
|
|
|
y3 = CLAMP (off_y, y1, y2);
|
2001-01-15 05:11:52 +08:00
|
|
|
x4 = CLAMP (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer)), x1, x2);
|
|
|
|
y4 = CLAMP (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer)), y1, y2);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* configure the pixel regions */
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&src1PR,
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (merge_layer)),
|
2000-12-04 05:34:38 +08:00
|
|
|
(x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3),
|
|
|
|
TRUE);
|
|
|
|
pixel_region_init (&src2PR,
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (layer)),
|
2000-12-04 05:34:38 +08:00
|
|
|
(x3 - off_x), (y3 - off_y),
|
|
|
|
(x4 - x3), (y4 - y3),
|
|
|
|
FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-03-06 21:28:39 +08:00
|
|
|
if (layer->mask && layer->mask->apply_mask)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
pixel_region_init (&maskPR,
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_data (GIMP_DRAWABLE (layer->mask)),
|
2000-12-04 05:34:38 +08:00
|
|
|
(x3 - off_x), (y3 - off_y),
|
|
|
|
(x4 - x3), (y4 - y3),
|
|
|
|
FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
mask = &maskPR;
|
|
|
|
}
|
|
|
|
else
|
2000-12-28 02:15:37 +08:00
|
|
|
{
|
|
|
|
mask = NULL;
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL,
|
|
|
|
layer->opacity, layer->mode, active, operation);
|
|
|
|
|
|
|
|
gimp_image_remove_layer (gimage, layer);
|
|
|
|
reverse_list = g_slist_next (reverse_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save old mode in undo */
|
2001-05-07 02:58:04 +08:00
|
|
|
if (bottom_layer)
|
|
|
|
gimp_layer_set_mode (bottom_layer, bottom_mode);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
g_slist_free (reverse_list);
|
|
|
|
|
|
|
|
/* if the type is flatten, remove all the remaining layers */
|
1999-04-27 12:57:59 +08:00
|
|
|
if (merge_type == FLATTEN_IMAGE)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
while (list)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
2001-01-29 07:25:25 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
list = g_list_next (list);
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_remove_layer (gimage, layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_image_add_layer (gimage, merge_layer, position);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add the layer to the gimage */
|
1999-08-22 19:45:31 +08:00
|
|
|
gimp_image_add_layer (gimage, merge_layer,
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_container_num_children (gimage->layers) - position + 1);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-01-15 01:11:14 +08:00
|
|
|
/* set the name after the original layers have been removed so we
|
|
|
|
* don't end up with #2 appended to the name
|
|
|
|
*/
|
2001-01-10 11:13:03 +08:00
|
|
|
gimp_object_set_name (GIMP_OBJECT (merge_layer), name);
|
2000-12-04 05:34:38 +08:00
|
|
|
g_free (name);
|
2000-05-12 09:14:21 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* End the merge undo group */
|
|
|
|
undo_push_group_end (gimage);
|
|
|
|
|
2001-03-05 00:52:37 +08:00
|
|
|
gimp_drawable_set_visible (GIMP_DRAWABLE (merge_layer), TRUE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-12-28 02:15:37 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE (merge_layer),
|
2000-12-04 05:34:38 +08:00
|
|
|
0, 0,
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_width (GIMP_DRAWABLE (merge_layer)),
|
|
|
|
gimp_drawable_height (GIMP_DRAWABLE (merge_layer)));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
1998-09-27 04:07:46 +08:00
|
|
|
/*reinit_layer_idlerender (gimage, merge_layer);*/
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
return merge_layer;
|
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_add_layer (GimpImage *gimage,
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpLayer *layer,
|
1999-08-22 19:45:31 +08:00
|
|
|
gint position)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
LayerUndo *lu;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
|
|
|
g_return_val_if_fail (layer != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
|
|
|
|
if (GIMP_DRAWABLE (layer)->gimage != NULL &&
|
|
|
|
GIMP_DRAWABLE (layer)->gimage != gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
1999-09-23 19:49:16 +08:00
|
|
|
g_message ("gimp_image_add_layer: attempt to add layer to wrong image");
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
if (gimp_container_have (gimage->layers, GIMP_OBJECT (layer)))
|
|
|
|
{
|
|
|
|
g_message ("gimp_image_add_layer: trying to add layer to image twice");
|
|
|
|
return FALSE;
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* Prepare a layer undo and push it */
|
1999-08-22 19:45:31 +08:00
|
|
|
lu = g_new (LayerUndo, 1);
|
2001-02-19 21:06:09 +08:00
|
|
|
lu->layer = layer;
|
1998-06-28 18:39:58 +08:00
|
|
|
lu->prev_position = 0;
|
2001-02-25 22:37:12 +08:00
|
|
|
lu->prev_layer = gimp_image_get_active_layer (gimage);
|
comment typo fix, plus add %D* to default image-title-format string, so
Fri Oct 1 12:46:12 1999 Austin Donnelly <austin@gimp.org>
* gimprc.in: comment typo fix, plus add %D* to default
image-title-format string, so people get a '*' in the titlebar
if their image is dirty.
* app/fileops.c: initialise filename before using it.
* app/gdisplay.c: empty parameter list () is K&R - should be
stronger (void) in ANSI C.
* app/gimpdrawable.c: gimp_drawable_{dirty,clean} functions
removed - no one uses them anyway. Parasite undo type is
proper parasite undo type, not MISC_UNDO.
* app/gimpdrawableP.h: drawable dirty bit removed.
* app/gimpimage.c: don't change the resolution if there's no
difference from the old one. Call gdisplay_shrink_wrap() to
re-calculate scale factors and refresh the display on
resolution change. Layer undo doesn't have sub-types
anymore, uses main UndoType instead.
* app/layer.h: Remove LayerUndoType
* app/qmask.c: fix qmask undo so it actually works.
* app/undo.h: new types for undo_push_layer{,_mask} and
undo_push_qmask.
* app/undo.c: change way group boundaries are represented:
each Undo has a group_boundary boolean set to TRUE if this is
the start or the end of a group, and the type of the Undo is
the group's type. Within a group, each Undo keeps its own
type. This allows pop funcs and free funcs to do
type-specific things (eg needed by layer and channel stuff).
Don't maintain per-drawable dirty flags anymore. Floating
sel to layer and layer rename now uses meaningful undo types.
* app/undo_types.h: more specific undo types:
LAYER_{ADD,REMOVE}_UNDO, LAYER_MASK_{ADD,REMOVE}_UNDO,
LAYER_RENAME_UNDO, and PARASITE_{ATTACH,DETACH}_UNDO.
* app/undo_history.c: oops - undo stack was being placed into gtk
list in wrong order.
* app/edit_selection.c: push more descriptive LAYER_DISPLACE_UNDO
rather than MISC_UNDO.
* app/layers_dialog.c: better tagging of undo types
1999-10-02 02:43:24 +08:00
|
|
|
undo_push_layer (gimage, LAYER_ADD_UNDO, lu);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* If the layer is a floating selection, set the ID */
|
2001-02-19 21:06:09 +08:00
|
|
|
if (gimp_layer_is_floating_sel (layer))
|
|
|
|
gimage->floating_sel = layer;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* let the layer know about the gimage */
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_drawable_set_gimage (GIMP_DRAWABLE (layer), gimage);
|
1998-10-14 10:54:02 +08:00
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
/* If the layer has a mask, set the mask's gimage */
|
2001-02-19 21:06:09 +08:00
|
|
|
if (layer->mask)
|
1999-08-22 19:45:31 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_drawable_set_gimage (GIMP_DRAWABLE (layer->mask), gimage);
|
1999-08-22 19:45:31 +08:00
|
|
|
}
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* add the layer to the list at the specified position */
|
|
|
|
if (position == -1)
|
2001-02-27 22:14:13 +08:00
|
|
|
{
|
|
|
|
GimpLayer *active_layer;
|
1999-08-22 19:45:31 +08:00
|
|
|
|
2001-02-27 22:14:13 +08:00
|
|
|
active_layer = gimp_image_get_active_layer (gimage);
|
|
|
|
|
|
|
|
if (active_layer)
|
|
|
|
{
|
|
|
|
position = gimp_container_get_child_index (gimage->layers,
|
|
|
|
GIMP_OBJECT (active_layer));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
position = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there is a floating selection (and this isn't it!),
|
|
|
|
* make sure the insert position is greater than 0
|
|
|
|
*/
|
|
|
|
if (position == 0 &&
|
|
|
|
gimp_image_floating_sel (gimage) &&
|
|
|
|
(gimage->floating_sel != layer))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-27 22:14:13 +08:00
|
|
|
position = 1;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_container_insert (gimage->layers, GIMP_OBJECT (layer), position);
|
1999-08-22 19:45:31 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* notify the layers dialog of the currently active layer */
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_image_set_active_layer (gimage, layer);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* update the new layer's area */
|
2001-02-19 21:06:09 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE (layer),
|
1999-08-22 19:45:31 +08:00
|
|
|
0, 0,
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_drawable_width (GIMP_DRAWABLE (layer)),
|
|
|
|
gimp_drawable_height (GIMP_DRAWABLE (layer)));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* invalidate the composite preview */
|
2001-02-05 06:10:54 +08:00
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return TRUE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
void
|
1999-07-10 02:15:39 +08:00
|
|
|
gimp_image_remove_layer (GimpImage *gimage,
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
LayerUndo *lu;
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_if_fail (gimage != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
|
|
|
g_return_if_fail (layer != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_if_fail (gimp_container_have (gimage->layers,
|
|
|
|
GIMP_OBJECT (layer)));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
/* Push a layer undo */
|
|
|
|
lu = g_new (LayerUndo, 1);
|
|
|
|
lu->layer = layer;
|
|
|
|
lu->prev_position = gimp_container_get_child_index (gimage->layers,
|
|
|
|
GIMP_OBJECT (layer));
|
|
|
|
lu->prev_layer = layer;
|
|
|
|
|
|
|
|
undo_push_layer (gimage, LAYER_REMOVE_UNDO, lu);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gtk_object_ref (GTK_OBJECT (layer));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_container_remove (gimage->layers, GIMP_OBJECT (layer));
|
|
|
|
gimage->layer_stack = g_slist_remove (gimage->layer_stack, layer);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
/* If this was the floating selection, reset the fs pointer */
|
|
|
|
if (gimage->floating_sel == layer)
|
|
|
|
{
|
|
|
|
gimage->floating_sel = NULL;
|
|
|
|
|
|
|
|
floating_sel_reset (layer);
|
|
|
|
}
|
1999-05-27 17:10:10 +08:00
|
|
|
|
2001-02-25 22:37:12 +08:00
|
|
|
if (layer == gimp_image_get_active_layer (gimage))
|
2001-02-19 21:06:09 +08:00
|
|
|
{
|
|
|
|
if (gimage->layer_stack)
|
2001-02-27 22:14:13 +08:00
|
|
|
{
|
|
|
|
gimp_image_set_active_layer (gimage, gimage->layer_stack->data);
|
|
|
|
}
|
2001-02-19 21:06:09 +08:00
|
|
|
else
|
2001-02-27 22:14:13 +08:00
|
|
|
{
|
|
|
|
gimage->active_layer = NULL;
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage),
|
|
|
|
gimp_image_signals[ACTIVE_LAYER_CHANGED]);
|
|
|
|
}
|
2001-02-19 21:06:09 +08:00
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
/* Send out REMOVED signal from layer */
|
|
|
|
gimp_drawable_removed (GIMP_DRAWABLE (layer));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gtk_object_unref (GTK_OBJECT (layer));
|
|
|
|
|
|
|
|
/* invalidate the composite preview */
|
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage));
|
|
|
|
gdisplays_update_full (gimage);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
2001-01-29 10:45:02 +08:00
|
|
|
gimp_image_raise_channel (GimpImage *gimage,
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpChannel *channel)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
gint index;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (channel != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
index = gimp_container_get_child_index (gimage->channels,
|
|
|
|
GIMP_OBJECT (channel));
|
|
|
|
if (index == 0)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-06-14 22:52:20 +08:00
|
|
|
g_message (_("Channel cannot be raised any further"));
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-03-06 21:28:39 +08:00
|
|
|
return gimp_image_position_channel (gimage, channel, index - 1, TRUE);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
2001-01-29 10:45:02 +08:00
|
|
|
gimp_image_lower_channel (GimpImage *gimage,
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpChannel *channel)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
gint index;
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (channel != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE);
|
|
|
|
|
|
|
|
index = gimp_container_get_child_index (gimage->channels,
|
|
|
|
GIMP_OBJECT (channel));
|
|
|
|
if (index == gimp_container_num_children (gimage->channels) - 1)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
g_message (_("Channel cannot be lowered any further"));
|
|
|
|
return FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-03-06 21:28:39 +08:00
|
|
|
return gimp_image_position_channel (gimage, channel, index + 1, TRUE);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
2001-01-29 10:45:02 +08:00
|
|
|
gimp_image_position_channel (GimpImage *gimage,
|
2001-02-19 21:06:09 +08:00
|
|
|
GimpChannel *channel,
|
2001-03-06 21:28:39 +08:00
|
|
|
gint new_index,
|
|
|
|
gboolean push_undo /* FIXME unused */)
|
1999-08-21 03:59:06 +08:00
|
|
|
{
|
2001-02-19 21:06:09 +08:00
|
|
|
gint index;
|
|
|
|
gint num_channels;
|
1999-08-21 03:59:06 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (channel != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE);
|
1999-08-21 03:59:06 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
index = gimp_container_get_child_index (gimage->channels,
|
|
|
|
GIMP_OBJECT (channel));
|
|
|
|
if (index < 0)
|
|
|
|
return FALSE;
|
1999-08-21 03:59:06 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
num_channels = gimp_container_num_children (gimage->channels);
|
1999-08-21 03:59:06 +08:00
|
|
|
|
2001-03-06 21:28:39 +08:00
|
|
|
new_index = CLAMP (new_index, 0, num_channels - 1);
|
1999-08-21 03:59:06 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
if (new_index == index)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
gimp_container_reorder (gimage->channels,
|
|
|
|
GIMP_OBJECT (channel), new_index);
|
1999-08-21 03:59:06 +08:00
|
|
|
|
|
|
|
drawable_update (GIMP_DRAWABLE (channel),
|
|
|
|
0, 0,
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_width (GIMP_DRAWABLE (channel)),
|
|
|
|
gimp_drawable_height (GIMP_DRAWABLE (channel)));
|
1999-08-21 03:59:06 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return TRUE;
|
1999-08-21 03:59:06 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gboolean
|
2001-01-29 10:45:02 +08:00
|
|
|
gimp_image_add_channel (GimpImage *gimage,
|
|
|
|
GimpChannel *channel,
|
|
|
|
gint position)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
ChannelUndo *cu;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
|
|
|
g_return_val_if_fail (channel != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2001-02-25 22:37:12 +08:00
|
|
|
if (GIMP_DRAWABLE (channel)->gimage != NULL &&
|
|
|
|
GIMP_DRAWABLE (channel)->gimage != gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message ("%s(): attempt to add channel to wrong image",
|
|
|
|
G_GNUC_FUNCTION);
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
if (gimp_container_have (gimage->channels, GIMP_OBJECT (channel)))
|
|
|
|
{
|
2001-02-25 22:37:12 +08:00
|
|
|
g_message ("%s(): trying to add channel to image twice",
|
|
|
|
G_GNUC_FUNCTION);
|
2001-02-19 21:06:09 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
/* Push a channel undo */
|
1999-08-22 19:45:31 +08:00
|
|
|
cu = g_new (ChannelUndo, 1);
|
|
|
|
cu->channel = channel;
|
1998-06-28 18:39:58 +08:00
|
|
|
cu->prev_position = 0;
|
2001-02-25 22:37:12 +08:00
|
|
|
cu->prev_channel = gimp_image_get_active_channel (gimage);
|
1999-10-02 03:26:56 +08:00
|
|
|
undo_push_channel (gimage, CHANNEL_ADD_UNDO, cu);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* add the channel to the list */
|
2001-02-19 21:06:09 +08:00
|
|
|
gimp_container_add (gimage->channels, GIMP_OBJECT (channel));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* notify this gimage of the currently active channel */
|
|
|
|
gimp_image_set_active_channel (gimage, channel);
|
|
|
|
|
|
|
|
/* if channel is visible, update the image */
|
2001-03-05 00:52:37 +08:00
|
|
|
if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel)))
|
2001-01-15 05:11:52 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE (channel),
|
2000-12-04 05:34:38 +08:00
|
|
|
0, 0,
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_width (GIMP_DRAWABLE (channel)),
|
|
|
|
gimp_drawable_height (GIMP_DRAWABLE (channel)));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return TRUE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
void
|
2001-01-29 10:45:02 +08:00
|
|
|
gimp_image_remove_channel (GimpImage *gimage,
|
|
|
|
GimpChannel *channel)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
ChannelUndo *cu;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
g_return_if_fail (gimage != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
|
|
|
g_return_if_fail (channel != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_CHANNEL (channel));
|
|
|
|
|
|
|
|
g_return_if_fail (gimp_container_have (gimage->channels,
|
|
|
|
GIMP_OBJECT (channel)));
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
/* Prepare a channel undo--push it below */
|
|
|
|
cu = g_new (ChannelUndo, 1);
|
|
|
|
cu->channel = channel;
|
2001-02-19 21:06:09 +08:00
|
|
|
cu->prev_position = gimp_container_get_child_index (gimage->channels,
|
|
|
|
GIMP_OBJECT (channel));
|
2001-02-25 22:37:12 +08:00
|
|
|
cu->prev_channel = gimp_image_get_active_channel (gimage);
|
2001-02-19 21:06:09 +08:00
|
|
|
undo_push_channel (gimage, CHANNEL_REMOVE_UNDO, cu);
|
2001-02-25 22:37:12 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
gtk_object_ref (GTK_OBJECT (channel));
|
|
|
|
|
|
|
|
gimp_container_remove (gimage->channels, GIMP_OBJECT (channel));
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
/* Send out REMOVED signal from channel */
|
2001-01-15 01:11:14 +08:00
|
|
|
gimp_drawable_removed (GIMP_DRAWABLE (channel));
|
2001-02-19 21:06:09 +08:00
|
|
|
|
2001-02-25 22:37:12 +08:00
|
|
|
if (channel == gimp_image_get_active_channel (gimage))
|
|
|
|
{
|
2001-05-03 20:26:05 +08:00
|
|
|
if (gimp_container_num_children (gimage->channels) > 0)
|
|
|
|
{
|
|
|
|
gimp_image_set_active_channel
|
|
|
|
(gimage,
|
|
|
|
GIMP_CHANNEL (gimp_container_get_child_by_index (gimage->channels,
|
|
|
|
0)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_image_unset_active_channel (gimage);
|
|
|
|
}
|
2001-02-25 22:37:12 +08:00
|
|
|
}
|
2001-02-19 21:06:09 +08:00
|
|
|
|
|
|
|
gtk_object_unref (GTK_OBJECT (channel));
|
|
|
|
|
|
|
|
/* invalidate the composite preview */
|
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage));
|
|
|
|
gdisplays_update_full (gimage);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************/
|
|
|
|
/* Access functions */
|
|
|
|
/************************************************************/
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_is_empty (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, TRUE);
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), TRUE);
|
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
return (gimp_container_num_children (gimage->layers) == 0);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GimpDrawable *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_active_drawable (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, NULL);
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
/* If there is an active channel (a saved selection, etc.),
|
|
|
|
* we ignore the active layer
|
|
|
|
*/
|
2001-02-25 22:37:12 +08:00
|
|
|
if (gimage->active_channel)
|
2000-12-29 00:19:55 +08:00
|
|
|
{
|
|
|
|
return GIMP_DRAWABLE (gimage->active_channel);
|
|
|
|
}
|
2001-02-25 22:37:12 +08:00
|
|
|
else if (gimage->active_layer)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-27 22:14:13 +08:00
|
|
|
GimpLayer *layer;
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
layer = gimage->active_layer;
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2001-03-06 21:28:39 +08:00
|
|
|
if (layer->mask && layer->mask->edit_mask)
|
2000-12-29 00:19:55 +08:00
|
|
|
return GIMP_DRAWABLE (layer->mask);
|
1998-06-28 18:39:58 +08:00
|
|
|
else
|
2000-12-29 00:19:55 +08:00
|
|
|
return GIMP_DRAWABLE (layer);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
2000-12-29 00:19:55 +08:00
|
|
|
|
|
|
|
return NULL;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpImageBaseType
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_base_type (const GimpImage *gimage)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (gimage != NULL, -1);
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
return gimage->base_type;
|
|
|
|
}
|
|
|
|
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpImageType
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_base_type_with_alpha (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-12-29 00:19:55 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, -1);
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
switch (gimage->base_type)
|
|
|
|
{
|
|
|
|
case RGB:
|
|
|
|
return RGBA_GIMAGE;
|
|
|
|
case GRAY:
|
|
|
|
return GRAYA_GIMAGE;
|
|
|
|
case INDEXED:
|
|
|
|
return INDEXEDA_GIMAGE;
|
|
|
|
}
|
|
|
|
return RGB_GIMAGE;
|
|
|
|
}
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
const gchar *
|
|
|
|
gimp_image_filename (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-15 00:26:04 +08:00
|
|
|
const gchar *filename;
|
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
g_return_val_if_fail (gimage != NULL, NULL);
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
2001-01-15 00:26:04 +08:00
|
|
|
filename = gimp_object_get_name (GIMP_OBJECT (gimage));
|
|
|
|
|
|
|
|
return filename ? filename : _("Untitled");
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
1999-11-25 04:11:03 +08:00
|
|
|
gboolean
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_undo_is_enabled (const GimpImage *gimage)
|
1999-11-25 04:11:03 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
1999-11-25 04:11:03 +08:00
|
|
|
return gimage->undo_on;
|
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
1999-10-17 08:07:55 +08:00
|
|
|
gimp_image_undo_freeze (GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
1999-08-22 00:15:58 +08:00
|
|
|
gimage->undo_on = FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
1999-10-17 08:07:55 +08:00
|
|
|
gimp_image_undo_thaw (GimpImage *gimage)
|
1999-08-22 00:15:58 +08:00
|
|
|
{
|
2000-08-24 03:29:01 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
gimage->undo_on = TRUE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
1999-10-17 08:07:55 +08:00
|
|
|
gimp_image_undo_disable (GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
1999-10-17 08:07:55 +08:00
|
|
|
return gimp_image_undo_freeze (gimage);
|
1999-08-22 00:15:58 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
1999-10-17 08:07:55 +08:00
|
|
|
gimp_image_undo_enable (GimpImage *gimage)
|
1999-08-22 00:15:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
1999-08-22 00:15:58 +08:00
|
|
|
/* Free all undo steps as they are now invalidated */
|
|
|
|
undo_free (gimage);
|
|
|
|
|
1999-10-17 08:07:55 +08:00
|
|
|
return gimp_image_undo_thaw (gimage);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
Honest, guv, it's not a feature - it's a tightly integrated package of
Mon Sep 20 12:51:30 EDT 1999 Austin Donnelly <austin@gimp.org>
Honest, guv, it's not a feature - it's a tightly integrated
package of undo system cleanups and fixes.
NEW FILES:
* app/undo_history.c: window showing recent undo (and redo) steps
available.
* app/undo_types.h: broken out of undo.h to fix circular includes.
MODIFIED FILES:
* app/Makefile.am: compile undo_history.c
* app/channel.h: use enum for channel undo type, not just magic
numbers.
* app/layer.h: same for layer undos.
* app/commands.c: edit_show_undo_history_cmd_callback() function to
pull up undo history window.
* app/commands.h: prototype for above.
* app/gdisplay.c: make undo / redo menu items sensitive according
to whether they would do anything. Would be easy to change
the text to say what would be undone/redone, but I don't know
the GTK.
* app/gimpimage.c: new signal emitted by gimage:
UNDO_EVENT. gimp_image_undo_event() function to emit it.
* app/gimpimage.h: prototype for above.
* app/gimpimageP.h: pushing_undo_group member is now an undo_type,
not an int. Keep undo history widget here too (if created).
* app/menus.c: add "Edit/Undo history..." to image menu.
* app/undo.c: new types: enums undo_type and undo_state rather than
ints and magic numbers. All undo_pop_* and undo_free_*
functions made static. New static function
undo_type_to_name(). Issue undo event signals on various
important events (eg undo pushed, undo popped etc).
undo_push() now takes a "dirties_image" arg to say whether
image should be dirtied. Layer moves now dirty the image. A
couple of g_return_if_fails () on undo_pop and undo_redo to
assert we're not in the middle of an undo group.
undo_get_{undo,redo}_name() to peek at names of top items on
undo and redo stacks resp. undo_map_over_{undo,redo}_stack()
to run a function for each item or group on stack. Layer and
channel undos use symbolic names rather than 0 or 1. Array
mapping undo types to names.
* app/undo.h: split out undo types to undo_types.h. Prototypes
for functions described above. undo_event_t enum.
undo_history_new() prototype lives here too.
Random other fixes:
* app/gimpdrawable.c
* app/image_render.c: default labels in switches to keep egcs happy.
* app/nav_window.c: some fixes to (sort of) cope with image res !=
screen res. Still needs work to handle non-square pixels
properly.
* app/paths_dialog.c: bad idea to call gimp_image_dirty()
directly. Even though it's currently commented out.
1999-09-21 01:15:20 +08:00
|
|
|
void
|
2000-03-09 19:58:03 +08:00
|
|
|
gimp_image_undo_event (GimpImage *gimage,
|
2000-12-29 00:19:55 +08:00
|
|
|
gint event)
|
Honest, guv, it's not a feature - it's a tightly integrated package of
Mon Sep 20 12:51:30 EDT 1999 Austin Donnelly <austin@gimp.org>
Honest, guv, it's not a feature - it's a tightly integrated
package of undo system cleanups and fixes.
NEW FILES:
* app/undo_history.c: window showing recent undo (and redo) steps
available.
* app/undo_types.h: broken out of undo.h to fix circular includes.
MODIFIED FILES:
* app/Makefile.am: compile undo_history.c
* app/channel.h: use enum for channel undo type, not just magic
numbers.
* app/layer.h: same for layer undos.
* app/commands.c: edit_show_undo_history_cmd_callback() function to
pull up undo history window.
* app/commands.h: prototype for above.
* app/gdisplay.c: make undo / redo menu items sensitive according
to whether they would do anything. Would be easy to change
the text to say what would be undone/redone, but I don't know
the GTK.
* app/gimpimage.c: new signal emitted by gimage:
UNDO_EVENT. gimp_image_undo_event() function to emit it.
* app/gimpimage.h: prototype for above.
* app/gimpimageP.h: pushing_undo_group member is now an undo_type,
not an int. Keep undo history widget here too (if created).
* app/menus.c: add "Edit/Undo history..." to image menu.
* app/undo.c: new types: enums undo_type and undo_state rather than
ints and magic numbers. All undo_pop_* and undo_free_*
functions made static. New static function
undo_type_to_name(). Issue undo event signals on various
important events (eg undo pushed, undo popped etc).
undo_push() now takes a "dirties_image" arg to say whether
image should be dirtied. Layer moves now dirty the image. A
couple of g_return_if_fails () on undo_pop and undo_redo to
assert we're not in the middle of an undo group.
undo_get_{undo,redo}_name() to peek at names of top items on
undo and redo stacks resp. undo_map_over_{undo,redo}_stack()
to run a function for each item or group on stack. Layer and
channel undos use symbolic names rather than 0 or 1. Array
mapping undo types to names.
* app/undo.h: split out undo types to undo_types.h. Prototypes
for functions described above. undo_event_t enum.
undo_history_new() prototype lives here too.
Random other fixes:
* app/gimpdrawable.c
* app/image_render.c: default labels in switches to keep egcs happy.
* app/nav_window.c: some fixes to (sort of) cope with image res !=
screen res. Still needs work to handle non-square pixels
properly.
* app/paths_dialog.c: bad idea to call gimp_image_dirty()
directly. Even though it's currently commented out.
1999-09-21 01:15:20 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage), gimp_image_signals[UNDO_EVENT], event);
|
Honest, guv, it's not a feature - it's a tightly integrated package of
Mon Sep 20 12:51:30 EDT 1999 Austin Donnelly <austin@gimp.org>
Honest, guv, it's not a feature - it's a tightly integrated
package of undo system cleanups and fixes.
NEW FILES:
* app/undo_history.c: window showing recent undo (and redo) steps
available.
* app/undo_types.h: broken out of undo.h to fix circular includes.
MODIFIED FILES:
* app/Makefile.am: compile undo_history.c
* app/channel.h: use enum for channel undo type, not just magic
numbers.
* app/layer.h: same for layer undos.
* app/commands.c: edit_show_undo_history_cmd_callback() function to
pull up undo history window.
* app/commands.h: prototype for above.
* app/gdisplay.c: make undo / redo menu items sensitive according
to whether they would do anything. Would be easy to change
the text to say what would be undone/redone, but I don't know
the GTK.
* app/gimpimage.c: new signal emitted by gimage:
UNDO_EVENT. gimp_image_undo_event() function to emit it.
* app/gimpimage.h: prototype for above.
* app/gimpimageP.h: pushing_undo_group member is now an undo_type,
not an int. Keep undo history widget here too (if created).
* app/menus.c: add "Edit/Undo history..." to image menu.
* app/undo.c: new types: enums undo_type and undo_state rather than
ints and magic numbers. All undo_pop_* and undo_free_*
functions made static. New static function
undo_type_to_name(). Issue undo event signals on various
important events (eg undo pushed, undo popped etc).
undo_push() now takes a "dirties_image" arg to say whether
image should be dirtied. Layer moves now dirty the image. A
couple of g_return_if_fails () on undo_pop and undo_redo to
assert we're not in the middle of an undo group.
undo_get_{undo,redo}_name() to peek at names of top items on
undo and redo stacks resp. undo_map_over_{undo,redo}_stack()
to run a function for each item or group on stack. Layer and
channel undos use symbolic names rather than 0 or 1. Array
mapping undo types to names.
* app/undo.h: split out undo types to undo_types.h. Prototypes
for functions described above. undo_event_t enum.
undo_history_new() prototype lives here too.
Random other fixes:
* app/gimpdrawable.c
* app/image_render.c: default labels in switches to keep egcs happy.
* app/nav_window.c: some fixes to (sort of) cope with image res !=
screen res. Still needs work to handle non-square pixels
properly.
* app/paths_dialog.c: bad idea to call gimp_image_dirty()
directly. Even though it's currently commented out.
1999-09-21 01:15:20 +08:00
|
|
|
}
|
|
|
|
|
1999-08-23 22:34:58 +08:00
|
|
|
|
|
|
|
/* NOTE about the gimage->dirty counter:
|
|
|
|
* If 0, then the image is clean (ie, copy on disk is the same as the one
|
|
|
|
* in memory).
|
|
|
|
* If positive, then that's the number of dirtying operations done
|
|
|
|
* on the image since the last save.
|
|
|
|
* If negative, then user has hit undo and gone back in time prior
|
|
|
|
* to the saved copy. Hitting redo will eventually come back to
|
|
|
|
* the saved copy.
|
|
|
|
*
|
|
|
|
* The image is dirty (ie, needs saving) if counter is non-zero.
|
|
|
|
*
|
|
|
|
* If the counter is around 10000, this is due to undo-ing back
|
|
|
|
* before a saved version, then mutating the image (thus destroying
|
|
|
|
* the redo stack). Once this has happened, it's impossible to get
|
|
|
|
* the image back to the state on disk, since the redo info has been
|
|
|
|
* freed. See undo.c for the gorey details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NEVER CALL gimp_image_dirty() directly!
|
|
|
|
*
|
|
|
|
* If your code has just dirtied the image, push an undo instead.
|
|
|
|
* Failing that, push the trivial undo which tells the user the
|
|
|
|
* command is not undoable: undo_push_cantundo() (But really, it would
|
|
|
|
* be best to push a proper undo). If you just dirty the image
|
|
|
|
* without pushing an undo then the dirty count is increased, but
|
|
|
|
* popping that many undo actions won't lead to a clean image.
|
|
|
|
*/
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gint
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_dirty (GimpImage *gimage)
|
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
gimage->dirty++;
|
2000-12-29 00:19:55 +08:00
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage), gimp_image_signals[DIRTY]);
|
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
TRC (("dirty %d -> %d\n", gimage->dirty-1, gimage->dirty));
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
return gimage->dirty;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gint
|
1998-06-28 18:39:58 +08:00
|
|
|
gimp_image_clean (GimpImage *gimage)
|
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
comment typo fix, plus add %D* to default image-title-format string, so
Fri Oct 1 12:46:12 1999 Austin Donnelly <austin@gimp.org>
* gimprc.in: comment typo fix, plus add %D* to default
image-title-format string, so people get a '*' in the titlebar
if their image is dirty.
* app/fileops.c: initialise filename before using it.
* app/gdisplay.c: empty parameter list () is K&R - should be
stronger (void) in ANSI C.
* app/gimpdrawable.c: gimp_drawable_{dirty,clean} functions
removed - no one uses them anyway. Parasite undo type is
proper parasite undo type, not MISC_UNDO.
* app/gimpdrawableP.h: drawable dirty bit removed.
* app/gimpimage.c: don't change the resolution if there's no
difference from the old one. Call gdisplay_shrink_wrap() to
re-calculate scale factors and refresh the display on
resolution change. Layer undo doesn't have sub-types
anymore, uses main UndoType instead.
* app/layer.h: Remove LayerUndoType
* app/qmask.c: fix qmask undo so it actually works.
* app/undo.h: new types for undo_push_layer{,_mask} and
undo_push_qmask.
* app/undo.c: change way group boundaries are represented:
each Undo has a group_boundary boolean set to TRUE if this is
the start or the end of a group, and the type of the Undo is
the group's type. Within a group, each Undo keeps its own
type. This allows pop funcs and free funcs to do
type-specific things (eg needed by layer and channel stuff).
Don't maintain per-drawable dirty flags anymore. Floating
sel to layer and layer rename now uses meaningful undo types.
* app/undo_types.h: more specific undo types:
LAYER_{ADD,REMOVE}_UNDO, LAYER_MASK_{ADD,REMOVE}_UNDO,
LAYER_RENAME_UNDO, and PARASITE_{ATTACH,DETACH}_UNDO.
* app/undo_history.c: oops - undo stack was being placed into gtk
list in wrong order.
* app/edit_selection.c: push more descriptive LAYER_DISPLACE_UNDO
rather than MISC_UNDO.
* app/layers_dialog.c: better tagging of undo types
1999-10-02 02:43:24 +08:00
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
gimage->dirty--;
|
2000-12-29 00:19:55 +08:00
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage), gimp_image_signals[CLEAN]);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
|
|
|
TRC (("clean %d -> %d\n", gimage->dirty+1, gimage->dirty));
|
|
|
|
|
|
|
|
return gimage->dirty;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_image_clean_all (GimpImage *gimage)
|
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
gimage->dirty = 0;
|
1999-08-23 22:34:58 +08:00
|
|
|
|
2000-12-29 00:19:55 +08:00
|
|
|
gtk_signal_emit (GTK_OBJECT (gimage), gimp_image_signals[CLEAN]);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_floating_sel (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
if (gimage->floating_sel == NULL)
|
|
|
|
return NULL;
|
1999-08-22 19:45:31 +08:00
|
|
|
else
|
|
|
|
return gimage->floating_sel;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2000-03-09 19:58:03 +08:00
|
|
|
guchar *
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_cmap (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-15 05:11:52 +08:00
|
|
|
return gimp_drawable_cmap (gimp_image_active_drawable (gimage));
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************/
|
|
|
|
/* Projection access functions */
|
|
|
|
/************************************************************/
|
|
|
|
|
|
|
|
TileManager *
|
|
|
|
gimp_image_projection (GimpImage *gimage)
|
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
|
|
|
|
|
1998-08-20 08:35:40 +08:00
|
|
|
if ((gimage->projection == NULL) ||
|
2001-01-23 21:01:48 +08:00
|
|
|
(tile_manager_width (gimage->projection) != gimage->width) ||
|
|
|
|
(tile_manager_height (gimage->projection) != gimage->height))
|
2000-12-29 00:19:55 +08:00
|
|
|
{
|
|
|
|
gimp_image_allocate_projection (gimage);
|
|
|
|
}
|
1998-08-20 08:35:40 +08:00
|
|
|
|
|
|
|
return gimage->projection;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpImageType
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_projection_type (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1);
|
|
|
|
|
1998-08-20 08:35:40 +08:00
|
|
|
return gimage->proj_type;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gint
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_projection_bytes (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1);
|
|
|
|
|
1998-08-20 08:35:40 +08:00
|
|
|
return gimage->proj_bytes;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gint
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_projection_opacity (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2000-03-09 19:58:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1);
|
|
|
|
|
1998-08-20 08:35:40 +08:00
|
|
|
return OPAQUE_OPACITY;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_image_projection_realloc (GimpImage *gimage)
|
|
|
|
{
|
1998-08-20 08:35:40 +08:00
|
|
|
gimp_image_allocate_projection (gimage);
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************/
|
|
|
|
/* Composition access functions */
|
|
|
|
/************************************************************/
|
|
|
|
|
|
|
|
TileManager *
|
|
|
|
gimp_image_composite (GimpImage *gimage)
|
|
|
|
{
|
|
|
|
return gimp_image_projection (gimage);
|
|
|
|
}
|
|
|
|
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpImageType
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_composite_type (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
return gimp_image_projection_type (gimage);
|
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gint
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_image_composite_bytes (const GimpImage *gimage)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
return gimp_image_projection_bytes (gimage);
|
|
|
|
}
|
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
gboolean
|
|
|
|
gimp_image_preview_valid (const GimpImage *gimage)
|
|
|
|
{
|
|
|
|
return gimage->comp_preview_valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static TempBuf *
|
2001-02-07 08:06:58 +08:00
|
|
|
gimp_image_get_preview (GimpViewable *viewable,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
2001-02-05 06:10:54 +08:00
|
|
|
{
|
|
|
|
GimpImage *gimage;
|
|
|
|
|
|
|
|
gimage = GIMP_IMAGE (viewable);
|
|
|
|
|
|
|
|
if (gimage->comp_preview_valid &&
|
|
|
|
gimage->comp_preview->width == width &&
|
|
|
|
gimage->comp_preview->height == height)
|
|
|
|
{
|
|
|
|
/* The easy way */
|
|
|
|
return gimage->comp_preview;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* The hard way */
|
|
|
|
if (gimage->comp_preview)
|
|
|
|
temp_buf_free (gimage->comp_preview);
|
|
|
|
|
|
|
|
/* Actually construct the composite preview from the layer previews!
|
|
|
|
* This might seem ridiculous, but it's actually the best way, given
|
|
|
|
* a number of unsavory alternatives.
|
|
|
|
*/
|
2001-02-07 08:06:58 +08:00
|
|
|
gimage->comp_preview = gimp_image_get_new_preview (viewable,
|
|
|
|
width, height);
|
2001-02-05 06:10:54 +08:00
|
|
|
|
|
|
|
gimage->comp_preview_valid = TRUE;
|
|
|
|
|
|
|
|
return gimage->comp_preview;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static TempBuf *
|
2001-02-07 08:06:58 +08:00
|
|
|
gimp_image_get_new_preview (GimpViewable *viewable,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-05 06:10:54 +08:00
|
|
|
GimpImage *gimage;
|
2001-01-29 07:25:25 +08:00
|
|
|
GimpLayer *layer;
|
|
|
|
GimpLayer *floating_sel;
|
2000-12-04 05:34:38 +08:00
|
|
|
PixelRegion src1PR, src2PR, maskPR;
|
1999-11-05 22:39:04 +08:00
|
|
|
PixelRegion *mask;
|
2000-12-04 05:34:38 +08:00
|
|
|
TempBuf *comp;
|
|
|
|
TempBuf *layer_buf;
|
|
|
|
TempBuf *mask_buf;
|
2001-02-19 21:06:09 +08:00
|
|
|
GList *list;
|
2000-12-04 05:34:38 +08:00
|
|
|
GSList *reverse_list = NULL;
|
|
|
|
gdouble ratio;
|
|
|
|
gint x, y, w, h;
|
|
|
|
gint x1, y1, x2, y2;
|
|
|
|
gint bytes;
|
2001-02-04 06:05:41 +08:00
|
|
|
gboolean construct_flag;
|
2001-02-05 06:10:54 +08:00
|
|
|
gint visible[MAX_CHANNELS] = { 1, 1, 1, 1 };
|
2000-12-04 05:34:38 +08:00
|
|
|
gint off_x, off_y;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-05 06:10:54 +08:00
|
|
|
gimage = GIMP_IMAGE (viewable);
|
2000-03-09 19:58:03 +08:00
|
|
|
|
2000-12-12 06:46:40 +08:00
|
|
|
ratio = (gdouble) width / (gdouble) gimage->width;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
switch (gimp_image_base_type (gimage))
|
|
|
|
{
|
|
|
|
case RGB:
|
|
|
|
case INDEXED:
|
|
|
|
bytes = 4;
|
|
|
|
break;
|
|
|
|
case GRAY:
|
|
|
|
bytes = 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
bytes = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The construction buffer */
|
|
|
|
comp = temp_buf_new (width, height, bytes, 0, 0, NULL);
|
2001-01-03 03:14:24 +08:00
|
|
|
temp_buf_data_clear (comp);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
1999-11-05 22:39:04 +08:00
|
|
|
floating_sel = NULL;
|
2001-05-30 08:20:48 +08:00
|
|
|
|
2001-02-19 21:06:09 +08:00
|
|
|
for (list = GIMP_LIST (gimage->layers)->list;
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) list->data;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
1999-11-05 22:39:04 +08:00
|
|
|
/* only add layers that are visible to the list */
|
2001-03-05 00:52:37 +08:00
|
|
|
if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer)))
|
1999-11-05 22:39:04 +08:00
|
|
|
{
|
2000-12-04 05:34:38 +08:00
|
|
|
/* floating selections are added right above the layer
|
2001-05-30 08:20:48 +08:00
|
|
|
* they are attached to
|
|
|
|
*/
|
2001-01-29 07:25:25 +08:00
|
|
|
if (gimp_layer_is_floating_sel (layer))
|
|
|
|
{
|
|
|
|
floating_sel = layer;
|
|
|
|
}
|
1999-11-05 22:39:04 +08:00
|
|
|
else
|
|
|
|
{
|
2001-05-30 08:20:48 +08:00
|
|
|
if (floating_sel &&
|
2000-12-04 05:34:38 +08:00
|
|
|
floating_sel->fs.drawable == GIMP_DRAWABLE (layer))
|
2001-05-30 08:20:48 +08:00
|
|
|
{
|
|
|
|
reverse_list = g_slist_prepend (reverse_list, floating_sel);
|
|
|
|
}
|
1999-11-05 22:39:04 +08:00
|
|
|
|
|
|
|
reverse_list = g_slist_prepend (reverse_list, layer);
|
|
|
|
}
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
2001-02-04 06:05:41 +08:00
|
|
|
construct_flag = FALSE;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-05-30 08:20:48 +08:00
|
|
|
for (; reverse_list; reverse_list = g_slist_next (reverse_list))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-01-29 07:25:25 +08:00
|
|
|
layer = (GimpLayer *) reverse_list->data;
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-01-15 05:11:52 +08:00
|
|
|
gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2000-12-15 23:54:17 +08:00
|
|
|
x = (gint) RINT (ratio * off_x);
|
2001-05-30 08:20:48 +08:00
|
|
|
y = (gint) RINT (ratio * off_y);
|
|
|
|
w = (gint) RINT (ratio * gimp_drawable_width (GIMP_DRAWABLE (layer)));
|
|
|
|
h = (gint) RINT (ratio * gimp_drawable_height (GIMP_DRAWABLE (layer)));
|
|
|
|
|
|
|
|
if (w < 1 || h < 1)
|
|
|
|
continue;
|
2001-02-10 05:49:47 +08:00
|
|
|
|
1998-06-28 18:39:58 +08:00
|
|
|
x1 = CLAMP (x, 0, width);
|
|
|
|
y1 = CLAMP (y, 0, height);
|
|
|
|
x2 = CLAMP (x + w, 0, width);
|
|
|
|
y2 = CLAMP (y + h, 0, height);
|
|
|
|
|
2000-12-04 05:34:38 +08:00
|
|
|
src1PR.bytes = comp->bytes;
|
2000-12-14 21:52:16 +08:00
|
|
|
src1PR.x = x1;
|
2000-12-04 05:34:38 +08:00
|
|
|
src1PR.y = y1;
|
|
|
|
src1PR.w = (x2 - x1);
|
|
|
|
src1PR.h = (y2 - y1);
|
1998-06-28 18:39:58 +08:00
|
|
|
src1PR.rowstride = comp->width * src1PR.bytes;
|
2001-03-12 09:21:43 +08:00
|
|
|
src1PR.data = (temp_buf_data (comp) +
|
|
|
|
y1 * src1PR.rowstride + x1 * src1PR.bytes);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-02-07 08:06:58 +08:00
|
|
|
layer_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer), w, h);
|
2000-12-04 05:34:38 +08:00
|
|
|
src2PR.bytes = layer_buf->bytes;
|
|
|
|
src2PR.w = src1PR.w;
|
|
|
|
src2PR.h = src1PR.h;
|
2000-12-14 21:52:16 +08:00
|
|
|
src2PR.x = src1PR.x;
|
2000-12-04 05:34:38 +08:00
|
|
|
src2PR.y = src1PR.y;
|
1998-06-28 18:39:58 +08:00
|
|
|
src2PR.rowstride = layer_buf->width * src2PR.bytes;
|
2001-03-12 09:21:43 +08:00
|
|
|
src2PR.data = (temp_buf_data (layer_buf) +
|
|
|
|
(y1 - y) * src2PR.rowstride +
|
|
|
|
(x1 - x) * src2PR.bytes);
|
1998-06-28 18:39:58 +08:00
|
|
|
|
2001-03-06 21:28:39 +08:00
|
|
|
if (layer->mask && layer->mask->apply_mask)
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
2001-02-07 08:06:58 +08:00
|
|
|
mask_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer->mask),
|
|
|
|
w, h);
|
2000-12-04 05:34:38 +08:00
|
|
|
maskPR.bytes = mask_buf->bytes;
|
1998-06-28 18:39:58 +08:00
|
|
|
maskPR.rowstride = mask_buf->width;
|
2001-03-12 09:21:43 +08:00
|
|
|
maskPR.data = (mask_buf_data (mask_buf) +
|
|
|
|
(y1 - y) * maskPR.rowstride +
|
|
|
|
(x1 - x) * maskPR.bytes);
|
1998-06-28 18:39:58 +08:00
|
|
|
mask = &maskPR;
|
|
|
|
}
|
|
|
|
else
|
2001-01-29 21:51:23 +08:00
|
|
|
{
|
|
|
|
mask = NULL;
|
|
|
|
}
|
1998-06-28 18:39:58 +08:00
|
|
|
|
|
|
|
/* Based on the type of the layer, project the layer onto the
|
|
|
|
* composite preview...
|
|
|
|
* Indexed images are actually already converted to RGB and RGBA,
|
|
|
|
* so just project them as if they were type "intensity"
|
1999-08-22 00:15:58 +08:00
|
|
|
* Send in all TRUE for visible since that info doesn't matter
|
|
|
|
* for previews
|
1998-06-28 18:39:58 +08:00
|
|
|
*/
|
2001-02-05 06:10:54 +08:00
|
|
|
switch (gimp_drawable_type (GIMP_DRAWABLE (layer)))
|
1998-06-28 18:39:58 +08:00
|
|
|
{
|
|
|
|
case RGB_GIMAGE: case GRAY_GIMAGE: case INDEXED_GIMAGE:
|
|
|
|
if (! construct_flag)
|
2000-12-04 05:34:38 +08:00
|
|
|
initial_region (&src2PR, &src1PR,
|
|
|
|
mask, NULL, layer->opacity,
|
1998-06-28 18:39:58 +08:00
|
|
|
layer->mode, visible, INITIAL_INTENSITY);
|
|
|
|
else
|
2000-12-04 05:34:38 +08:00
|
|
|
combine_regions (&src1PR, &src2PR, &src1PR,
|
|
|
|
mask, NULL, layer->opacity,
|
1998-06-28 18:39:58 +08:00
|
|
|
layer->mode, visible, COMBINE_INTEN_A_INTEN);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RGBA_GIMAGE: case GRAYA_GIMAGE: case INDEXEDA_GIMAGE:
|
|
|
|
if (! construct_flag)
|
2000-12-04 05:34:38 +08:00
|
|
|
initial_region (&src2PR, &src1PR,
|
|
|
|
mask, NULL, layer->opacity,
|
1998-06-28 18:39:58 +08:00
|
|
|
layer->mode, visible, INITIAL_INTENSITY_ALPHA);
|
|
|
|
else
|
2000-12-04 05:34:38 +08:00
|
|
|
combine_regions (&src1PR, &src2PR, &src1PR,
|
|
|
|
mask, NULL, layer->opacity,
|
1998-06-28 18:39:58 +08:00
|
|
|
layer->mode, visible, COMBINE_INTEN_A_INTEN_A);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-02-04 06:05:41 +08:00
|
|
|
construct_flag = TRUE;
|
1998-06-28 18:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
g_slist_free (reverse_list);
|
|
|
|
|
|
|
|
return comp;
|
|
|
|
}
|