gimp/app/layer_select.c
Michael Natterer 2fd2a4e6b5 app/channel_ops.c app/channels_dialog.c app/commands.c app/floating_sel.c
2001-02-25  Michael Natterer  <mitch@gimp.org>

	* app/channel_ops.c
	* app/channels_dialog.c
	* app/commands.c
	* app/floating_sel.c
	* app/gdisplay.c
	* app/gimpimage.[ch]
	* app/layer_select.c
	* app/layers_dialog.c
	* app/undo.c
	* app/xcf.c
	* app/tools/move.c: remove direct access of gimage->active_layer and
	gimage->active_channel. Reading access is of course harmless, but
	gimp_image_set_active_blah() will trigger a signal emission soon.

	It will probably be neccessary to change the functions to accept
	NULL layers and channels to acheive exactly what weird places like
	floating_sel.c did before by setting it directly.

	* gimptool-1.4.in
	* libgimp/Makefile.am
	* libgimpcolor/Makefile.am
	* libgimpmath/Makefile.am
	* libgimpwidgets/Makefile.am
	* plug-ins/libgck/gck/Makefile.am: made linking against stable
	GIMP installed in the same prefix work again by renaming all our
	libraries explicitly to libgimp<foo>-1.3.* (not as part of the
	libtool revision but as part of the library name). Removed the
	libtool revision to avoid double versioning. This has to be
	hardcoded in the libraries' Makefile.am ...

	* app/Makefile.am
	* plug-ins/FractalExplorer/Makefile.am
	* plug-ins/Lighting/Makefile.am
	* plug-ins/MapObject/Makefile.am
	* plug-ins/bmp/Makefile.am
	* plug-ins/common/Makefile.am
	* plug-ins/common/mkgen.pl
	* plug-ins/dbbrowser/Makefile.am
	* plug-ins/faxg3/Makefile.am
	* plug-ins/fits/Makefile.am
	* plug-ins/flame/Makefile.am
	* plug-ins/fp/Makefile.am
	* plug-ins/gap/Makefile.am
	* plug-ins/gdyntext/Makefile.am
	* plug-ins/gfig/Makefile.am
	* plug-ins/gflare/Makefile.am
	* plug-ins/gfli/Makefile.am
	* plug-ins/gimpressionist/Makefile.am
	* plug-ins/helpbrowser/Makefile.am
	* plug-ins/ifscompose/Makefile.am
	* plug-ins/imagemap/Makefile.am
	* plug-ins/maze/Makefile.am
	* plug-ins/mosaic/Makefile.am
	* plug-ins/pagecurl/Makefile.am
	* plug-ins/plugin-helper/Makefile.am
	* plug-ins/print/Makefile.am
	* plug-ins/rcm/Makefile.am
	* plug-ins/script-fu/Makefile.am
	* plug-ins/sel2path/Makefile.am
	* plug-ins/sgi/Makefile.am
	* plug-ins/webbrowser/Makefile.am
	* plug-ins/xjt/Makefile.am: ... while all other Makefiles can simply
	link against "libgimp<foo>-$(LT_REVISION).la"
2001-02-25 14:37:12 +00:00

483 lines
13 KiB
C

/* 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.
*/
#include "config.h"
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "apptypes.h"
#include "gdisplay.h"
#include "gimpdrawable.h"
#include "gimpimage.h"
#include "gimplayer.h"
#include "gimprc.h"
#include "layer_select.h"
#include "layers_dialogP.h"
#include "temp_buf.h"
#include "libgimp/gimpintl.h"
#define PREVIEW_EVENT_MASK GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK
typedef struct _LayerSelect LayerSelect;
struct _LayerSelect
{
GtkWidget *shell;
GtkWidget *layer_preview;
GtkWidget *label;
GdkPixmap *layer_pixmap;
GtkWidget *preview;
GImage *gimage;
GimpLayer *current_layer;
gboolean dirty;
gint image_width;
gint image_height;
gdouble ratio;
};
/* layer widget function prototypes */
static void layer_select_advance (LayerSelect *layer_select,
gint move);
static void layer_select_forward (LayerSelect *layer_select);
static void layer_select_backward (LayerSelect *layer_select);
static void layer_select_end (LayerSelect *layer_select,
guint32 time);
static void layer_select_set_gimage (LayerSelect *layer_select,
GImage *gimage);
static void layer_select_set_layer (LayerSelect *layer_select);
static gint layer_select_events (GtkWidget *widget,
GdkEvent *event);
static gint preview_events (GtkWidget *widget,
GdkEvent *event);
static void preview_redraw (LayerSelect *layer_select);
/*
* Local variables
*/
LayerSelect *layer_select = NULL;
/**********************/
/* Public functions */
/**********************/
void
layer_select_init (GImage *gimage,
gint move,
guint32 time)
{
GtkWidget *frame1;
GtkWidget *frame2;
GtkWidget *hbox;
GtkWidget *alignment;
if (!layer_select)
{
layer_select = g_malloc (sizeof (LayerSelect));
layer_select->layer_pixmap = NULL;
layer_select->layer_preview = NULL;
layer_select->preview = NULL;
layer_select->image_width = layer_select->image_height = 0;
layer_select_set_gimage (layer_select, gimage);
layer_select_advance (layer_select, move);
if (preview_size)
{
layer_select->preview = gtk_preview_new (GTK_PREVIEW_COLOR);
gtk_preview_size (GTK_PREVIEW (layer_select->preview),
preview_size, preview_size);
}
/* The shell and main vbox */
layer_select->shell = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_wmclass (GTK_WINDOW (layer_select->shell),
"layer_select", "Gimp");
gtk_window_set_title (GTK_WINDOW (layer_select->shell),
_("Layer Select"));
gtk_window_set_position (GTK_WINDOW (layer_select->shell),
GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (layer_select->shell), "event",
(GtkSignalFunc) layer_select_events,
layer_select);
gtk_widget_set_events (layer_select->shell, (GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK |
GDK_BUTTON_PRESS_MASK));
frame1 = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame1), GTK_SHADOW_OUT);
gtk_container_add (GTK_CONTAINER (layer_select->shell), frame1);
frame2 = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (frame1), frame2);
hbox = gtk_hbox_new (FALSE, 1);
gtk_container_add (GTK_CONTAINER (frame2), hbox);
/* The preview */
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (hbox), alignment, FALSE, FALSE, 0);
gtk_widget_show (alignment);
layer_select->layer_preview = gtk_drawing_area_new ();
gtk_drawing_area_size (GTK_DRAWING_AREA (layer_select->layer_preview),
layer_select->image_width,
layer_select->image_height);
gtk_widget_set_events (layer_select->layer_preview, PREVIEW_EVENT_MASK);
gtk_signal_connect (GTK_OBJECT (layer_select->layer_preview), "event",
(GtkSignalFunc) preview_events, layer_select);
gtk_object_set_user_data (GTK_OBJECT (layer_select->layer_preview),
layer_select);
gtk_container_add (GTK_CONTAINER (alignment),
layer_select->layer_preview);
gtk_widget_show (layer_select->layer_preview);
gtk_widget_show (alignment);
/* the layer name label */
layer_select->label = gtk_label_new (_("Layer"));
gtk_box_pack_start (GTK_BOX (hbox),
layer_select->label, FALSE, FALSE, 2);
gtk_widget_show (layer_select->label);
gtk_widget_show (hbox);
gtk_widget_show (frame1);
gtk_widget_show (frame2);
gtk_widget_show (layer_select->shell);
}
else
{
layer_select_set_gimage (layer_select, gimage);
layer_select_advance (layer_select, move);
if (! GTK_WIDGET_VISIBLE (layer_select->shell))
gtk_widget_show (layer_select->shell);
else
gtk_widget_draw (layer_select->layer_preview, NULL);
}
gdk_key_repeat_disable ();
gdk_keyboard_grab (layer_select->shell->window, FALSE, time);
}
void
layer_select_update_preview_size (void)
{
if (layer_select != NULL)
{ gtk_preview_size (GTK_PREVIEW (layer_select->preview),
preview_size, preview_size);
if (GTK_WIDGET_VISIBLE (layer_select->shell))
gtk_widget_draw (layer_select->layer_preview, NULL);
}
}
/***********************/
/* Private functions */
/***********************/
static void
layer_select_advance (LayerSelect *layer_select,
gint move)
{
gint index;
gint count;
GSList *list;
GSList *nth;
GimpLayer *layer;
index = 0;
if (move == 0)
return;
/* If there is a floating selection, allow no advancement */
if (gimp_image_floating_sel (layer_select->gimage))
return;
for (list = layer_select->gimage->layer_stack, count = 0;
list;
list = g_slist_next (list), count++)
{
layer = (GimpLayer *) list->data;
if (layer == layer_select->current_layer)
index = count;
}
index += move;
index = CLAMP (index, 0, count - 1);
nth = g_slist_nth (layer_select->gimage->layer_stack, index);
if (nth)
{
layer = (GimpLayer *) nth->data;
layer_select->current_layer = layer;
}
}
static void
layer_select_forward (LayerSelect *layer_select)
{
layer_select_advance (layer_select, 1);
layer_select->dirty = TRUE;
gtk_widget_draw (layer_select->layer_preview, NULL);
}
static void
layer_select_backward (LayerSelect *layer_select)
{
layer_select_advance (layer_select, -1);
layer_select->dirty = TRUE;
gtk_widget_draw (layer_select->layer_preview, NULL);
}
static void
layer_select_end (LayerSelect *layer_select,
guint32 time)
{
gdk_key_repeat_restore ();
gdk_keyboard_ungrab (time);
gtk_widget_hide (layer_select->shell);
/* only reset the active layer if a new layer was specified */
if (layer_select->current_layer !=
gimp_image_get_active_layer (layer_select->gimage))
{
gimp_image_set_active_layer (layer_select->gimage,
layer_select->current_layer);
gdisplays_flush ();
}
}
static void
layer_select_set_gimage (LayerSelect *layer_select,
GImage *gimage)
{
gint image_width;
gint image_height;
layer_select->gimage = gimage;
layer_select->current_layer = gimp_image_get_active_layer (gimage);
layer_select->dirty = TRUE;
/* Get the image width and height variables, based on the gimage */
if (gimage->width > gimage->height)
layer_select->ratio =
MIN (1.0, (gdouble) preview_size / (gdouble) gimage->width);
else
layer_select->ratio =
MIN (1.0, (gdouble) preview_size / (gdouble) gimage->height);
image_width = (gint) (layer_select->ratio * gimage->width);
image_height = (gint) (layer_select->ratio * gimage->height);
if (layer_select->image_width != image_width ||
layer_select->image_height != image_height)
{
layer_select->image_width = image_width;
layer_select->image_height = image_height;
if (layer_select->layer_preview)
gtk_widget_set_usize (layer_select->layer_preview,
layer_select->image_width,
layer_select->image_height);
if (layer_select->layer_pixmap)
{
gdk_pixmap_unref (layer_select->layer_pixmap);
layer_select->layer_pixmap = NULL;
}
}
}
static void
layer_select_set_layer (LayerSelect *layer_select)
{
GimpLayer *layer;
if (! (layer = (layer_select->current_layer)))
return;
/* Set the layer label */
gtk_label_set_text (GTK_LABEL (layer_select->label),
gimp_object_get_name (GIMP_OBJECT (layer)));
}
static gint
layer_select_events (GtkWidget *widget,
GdkEvent *event)
{
GdkEventKey *kevent;
GdkEventButton *bevent;
switch (event->type)
{
case GDK_BUTTON_PRESS:
bevent = (GdkEventButton *) event;
layer_select_end (layer_select, bevent->time);
break;
case GDK_KEY_PRESS:
kevent = (GdkEventKey *) event;
switch (kevent->keyval)
{
case GDK_Tab:
if (kevent->state & GDK_MOD1_MASK)
layer_select_forward (layer_select);
else if (kevent->state & GDK_CONTROL_MASK)
layer_select_backward (layer_select);
break;
}
return TRUE;
break;
case GDK_KEY_RELEASE:
kevent = (GdkEventKey *) event;
switch (kevent->keyval)
{
case GDK_Alt_L: case GDK_Alt_R:
kevent->state &= ~GDK_MOD1_MASK;
break;
case GDK_Control_L: case GDK_Control_R:
kevent->state &= ~GDK_CONTROL_MASK;
break;
}
if (! (kevent->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK)))
layer_select_end (layer_select, kevent->time);
return TRUE;
break;
default:
break;
}
return FALSE;
}
static gint
preview_events (GtkWidget *widget,
GdkEvent *event)
{
switch (event->type)
{
case GDK_EXPOSE:
if (layer_select->dirty)
{
/* If a preview exists, draw it */
if (preview_size)
preview_redraw (layer_select);
/* Change the layer name label */
layer_select_set_layer (layer_select);
layer_select->dirty = FALSE;
}
if (preview_size)
gdk_draw_pixmap (layer_select->layer_preview->window,
layer_select->layer_preview->style->black_gc,
layer_select->layer_pixmap,
0, 0, 0, 0,
layer_select->image_width,
layer_select->image_height);
break;
default:
break;
}
return FALSE;
}
static void
preview_redraw (LayerSelect *layer_select)
{
GimpLayer *layer;
TempBuf *preview_buf;
gint w, h;
gint offx, offy;
if (! (layer = (layer_select->current_layer)))
return;
if (! layer_select->layer_pixmap)
layer_select->layer_pixmap =
gdk_pixmap_new (layer_select->layer_preview->window,
layer_select->image_width,
layer_select->image_height,
-1);
if (gimp_layer_is_floating_sel (layer))
{
render_fs_preview (layer_select->layer_preview,
layer_select->layer_pixmap);
}
else
{
gint off_x;
gint off_y;
gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
/* determine width and height */
w = (gint) (layer_select->ratio *
gimp_drawable_width (GIMP_DRAWABLE (layer)));
h = (gint) (layer_select->ratio *
gimp_drawable_height (GIMP_DRAWABLE (layer)));
offx = (gint) (layer_select->ratio * off_x);
offy = (gint) (layer_select->ratio * off_y);
preview_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer), w, h);
preview_buf->x = offx;
preview_buf->y = offy;
render_preview (preview_buf,
layer_select->preview,
layer_select->image_width,
layer_select->image_height,
-1);
/* Set the layer pixmap */
gtk_preview_put (GTK_PREVIEW (layer_select->preview),
layer_select->layer_pixmap,
layer_select->layer_preview->style->black_gc,
0, 0, 0, 0,
layer_select->image_width, layer_select->image_height);
/* make sure the image has been transfered completely
* to the pixmap before we use it again...
*/
gdk_flush ();
}
}