Thu Dec 16 20:15:25 CET 1999 Olof S Kylande <olof@gimp.org>
Fix of KDE/Kwm selection add/sub/inter problem
NOTE: This is a workaround, not a real fix.
Many Thanks to Matthias Ettrich
* app/disp_callbacks.c
Updated unsharp-mask to version 0.10
* plug-ins/unsharp/dialog_f.c
* plug-ins/unsharp/dialog_f.h
* plug-ins/unsharp/dialog_i.c
* plug-ins/unsharp/dialog_i.h
* plug-ins/unsharp/unsharp.c
Updated print plug-in to version 3.0.1
* plug-ins/print/README (new file)
* plug-ins/print/print-escp2.c
* plug-ins/print/print-pcl.c
* plug-ins/print/print-ps.c
* plug-ins/print/print-util.c
* plug-ins/print/print.c
* plug-ins/print/print.h
Updated all files in the help/C/dialogs dir. This is
a first alpha glimpse of the help system. Please give
me feedback of the content. However since it's in alpha
stage it means that there is spell, grammatical, etc errors.
There is may also be pure errors which I hope "you" will
report to either olof@gimp.org or karin@gimp.org. Please
don't report spell, grammatical, etc error at this stage in dev.
If you have any plans to commit to the help system please write
to olof@gimp.org. (This is mandatory not a please ;-).
* help/C/welcome.html
* help/C/dialogs/about.html ..............
892 lines
23 KiB
C
892 lines
23 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 <stdlib.h>
|
|
#include "gdk/gdkkeysyms.h"
|
|
#include "appenv.h"
|
|
#include "bucket_fill.h"
|
|
#include "colormaps.h"
|
|
#include "cursorutil.h"
|
|
#include "devices.h"
|
|
#include "disp_callbacks.h"
|
|
#include "gdisplay.h"
|
|
#include "general.h"
|
|
#include "gimpcontext.h"
|
|
#include "gimprc.h"
|
|
#include "info_window.h"
|
|
#include "interface.h"
|
|
#include "layer_select.h"
|
|
#include "move.h"
|
|
#include "patterns.h"
|
|
#include "scale.h"
|
|
#include "scroll.h"
|
|
#include "tools.h"
|
|
#include "undo.h"
|
|
#include "gimage.h"
|
|
#include "dialog_handler.h"
|
|
|
|
#include "libgimp/gimpintl.h"
|
|
|
|
/* Function declarations */
|
|
|
|
static void gdisplay_check_device_cursor (GDisplay *gdisp);
|
|
|
|
static void
|
|
redraw (GDisplay *gdisp,
|
|
int x,
|
|
int y,
|
|
int w,
|
|
int h)
|
|
{
|
|
long x1, y1, x2, y2; /* coordinate of rectangle corners */
|
|
|
|
x1 = x;
|
|
y1 = y;
|
|
x2 = (x+w);
|
|
y2 = (y+h);
|
|
x1 = BOUNDS (x1, 0, gdisp->disp_width);
|
|
y1 = BOUNDS (y1, 0, gdisp->disp_height);
|
|
x2 = BOUNDS (x2, 0, gdisp->disp_width);
|
|
y2 = BOUNDS (y2, 0, gdisp->disp_height);
|
|
if ((x2 - x1) && (y2 - y1))
|
|
{
|
|
gdisplay_expose_area (gdisp, x1, y1, (x2 - x1), (y2 - y1));
|
|
gdisplay_flush_displays_only (gdisp);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdisplay_check_device_cursor (GDisplay *gdisp)
|
|
{
|
|
GList *list;
|
|
|
|
/* gdk_input_list_devices returns an internal list, so we shouldn't
|
|
free it afterwards */
|
|
|
|
for (list = gdk_input_list_devices(); list; list = g_list_next (list))
|
|
{
|
|
GdkDeviceInfo *info = (GdkDeviceInfo *) list->data;
|
|
|
|
if (info->deviceid == current_device)
|
|
{
|
|
gdisp->draw_cursor = !info->has_cursor;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
key_to_state (int key)
|
|
{
|
|
switch (key)
|
|
{
|
|
case GDK_Alt_L: case GDK_Alt_R:
|
|
return GDK_MOD1_MASK;
|
|
case GDK_Shift_L: case GDK_Shift_R:
|
|
return GDK_SHIFT_MASK;
|
|
case GDK_Control_L: case GDK_Control_R:
|
|
return GDK_CONTROL_MASK;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
gint
|
|
gdisplay_shell_events (GtkWidget *widget,
|
|
GdkEvent *event,
|
|
GDisplay *gdisp)
|
|
{
|
|
switch (event->type)
|
|
{
|
|
case GDK_BUTTON_PRESS:
|
|
case GDK_KEY_PRESS:
|
|
/* Setting the context's display automatically sets the image, too */
|
|
gimp_context_set_display (gimp_context_get_user (), gdisp);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
gint
|
|
gdisplay_canvas_events (GtkWidget *canvas,
|
|
GdkEvent *event)
|
|
{
|
|
GDisplay *gdisp;
|
|
GdkEventExpose *eevent;
|
|
GdkEventMotion *mevent;
|
|
GdkEventButton *bevent;
|
|
GdkEventKey *kevent;
|
|
gdouble tx, ty;
|
|
guint state = 0;
|
|
gint return_val = FALSE;
|
|
static gboolean scrolled = FALSE;
|
|
static guint key_signal_id = 0;
|
|
int update_cursor = FALSE;
|
|
|
|
tx = ty = 0;
|
|
|
|
gdisp = (GDisplay *) gtk_object_get_user_data (GTK_OBJECT (canvas));
|
|
|
|
if (!canvas->window)
|
|
return FALSE;
|
|
|
|
/* If this is the first event... */
|
|
if (!gdisp->select)
|
|
{
|
|
/* create the selection object */
|
|
gdisp->select = selection_create (gdisp->canvas->window, gdisp,
|
|
gdisp->gimage->height,
|
|
gdisp->gimage->width, marching_speed);
|
|
|
|
gdisp->disp_width = gdisp->canvas->allocation.width;
|
|
gdisp->disp_height = gdisp->canvas->allocation.height;
|
|
|
|
/* create GC for scrolling */
|
|
gdisp->scroll_gc = gdk_gc_new (gdisp->canvas->window);
|
|
gdk_gc_set_exposures (gdisp->scroll_gc, TRUE);
|
|
|
|
/* set up the scrollbar observers */
|
|
gtk_signal_connect (GTK_OBJECT (gdisp->hsbdata), "value_changed",
|
|
(GtkSignalFunc) scrollbar_horz_update,
|
|
gdisp);
|
|
gtk_signal_connect (GTK_OBJECT (gdisp->vsbdata), "value_changed",
|
|
(GtkSignalFunc) scrollbar_vert_update,
|
|
gdisp);
|
|
|
|
/* setup scale properly */
|
|
setup_scale (gdisp);
|
|
}
|
|
|
|
/* Find out what device the event occurred upon */
|
|
if (devices_check_change (event))
|
|
gdisplay_check_device_cursor (gdisp);
|
|
|
|
switch (event->type)
|
|
{
|
|
case GDK_EXPOSE:
|
|
eevent = (GdkEventExpose *) event;
|
|
/*printf(" EXP:%d,%d(%dx%d) ",eevent->area.x, eevent->area.y,
|
|
eevent->area.width, eevent->area.height);fflush(stdout);*/
|
|
redraw (gdisp, eevent->area.x, eevent->area.y,
|
|
eevent->area.width, eevent->area.height);
|
|
break;
|
|
|
|
case GDK_CONFIGURE:
|
|
/*printf(" CNF ");fflush(stdout);*/
|
|
if ((gdisp->disp_width != gdisp->canvas->allocation.width) ||
|
|
(gdisp->disp_height != gdisp->canvas->allocation.height))
|
|
{
|
|
gdisp->disp_width = gdisp->canvas->allocation.width;
|
|
gdisp->disp_height = gdisp->canvas->allocation.height;
|
|
resize_display (gdisp, 0, FALSE);
|
|
}
|
|
break;
|
|
|
|
case GDK_LEAVE_NOTIFY:
|
|
if ( ( (GdkEventCrossing*) event)->mode != GDK_CROSSING_NORMAL )
|
|
return TRUE;
|
|
gdisplay_update_cursor (gdisp, 0, 0);
|
|
gtk_label_set_text (GTK_LABEL (gdisp->cursor_label), "");
|
|
info_window_update_RGB (gdisp, -1, -1);
|
|
|
|
case GDK_PROXIMITY_OUT:
|
|
gdisp->proximity = FALSE;
|
|
break;
|
|
|
|
case GDK_ENTER_NOTIFY:
|
|
if ( ( (GdkEventCrossing*) event)->mode != GDK_CROSSING_NORMAL )
|
|
return TRUE;
|
|
/* Actually, should figure out tx,ty here */
|
|
break;
|
|
|
|
case GDK_BUTTON_PRESS:
|
|
bevent = (GdkEventButton *) event;
|
|
state = bevent->state;
|
|
|
|
switch (bevent->button)
|
|
{
|
|
case 1:
|
|
state |= GDK_BUTTON1_MASK;
|
|
gtk_grab_add (canvas);
|
|
|
|
/* This is a hack to prevent other stuff being run in the middle of
|
|
a tool operation (like changing image types.... brrrr). We just
|
|
block all the keypress event. A better solution is to implement
|
|
some sort of locking for images.
|
|
Note that this is dependent on specific GTK behavior, and isn't
|
|
guaranteed to work in future versions of GTK.
|
|
-Yosh
|
|
*/
|
|
if (key_signal_id == 0)
|
|
key_signal_id = gtk_signal_connect (GTK_OBJECT (canvas),
|
|
"key_press_event",
|
|
GTK_SIGNAL_FUNC (gtk_true),
|
|
NULL);
|
|
|
|
if (active_tool && ((active_tool->type == MOVE) ||
|
|
!gimage_is_empty (gdisp->gimage)))
|
|
{
|
|
if (active_tool->auto_snap_to)
|
|
{
|
|
gdisplay_snap_point (gdisp, bevent->x, bevent->y, &tx, &ty);
|
|
bevent->x = tx;
|
|
bevent->y = ty;
|
|
update_cursor = TRUE;
|
|
}
|
|
|
|
/* reset the current tool if ... */
|
|
if ((/* it has no drawable */
|
|
! active_tool->drawable ||
|
|
|
|
/* or a drawable different from the current one */
|
|
(gimage_active_drawable (gdisp->gimage) !=
|
|
active_tool->drawable)) &&
|
|
|
|
/* and doesn't want to be preserved across drawable changes */
|
|
! active_tool->preserve)
|
|
{
|
|
tools_initialize (active_tool->type, gdisp);
|
|
}
|
|
|
|
/* otherwise set it's drawable if it has none */
|
|
else if (! active_tool->drawable)
|
|
{
|
|
active_tool->drawable = gimage_active_drawable (gdisp->gimage);
|
|
}
|
|
|
|
(* active_tool->button_press_func) (active_tool, bevent, gdisp);
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
state |= GDK_BUTTON2_MASK;
|
|
scrolled = TRUE;
|
|
gtk_grab_add (canvas);
|
|
start_grab_and_scroll (gdisp, bevent);
|
|
break;
|
|
|
|
case 3:
|
|
state |= GDK_BUTTON3_MASK;
|
|
gtk_menu_popup (GTK_MENU (gdisp->popup),
|
|
NULL, NULL, NULL, NULL, 3, bevent->time);
|
|
return_val = TRUE;
|
|
break;
|
|
|
|
/* wheelmouse support */
|
|
case 4:
|
|
state |= GDK_BUTTON4_MASK;
|
|
if (state & GDK_SHIFT_MASK)
|
|
{
|
|
change_scale (gdisp, ZOOMIN);
|
|
}
|
|
else
|
|
{
|
|
GtkAdjustment *adj =
|
|
(state & GDK_CONTROL_MASK) ? gdisp->hsbdata : gdisp->vsbdata;
|
|
gfloat new_value = adj->value - adj->page_increment / 2;
|
|
new_value =
|
|
CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
|
|
gtk_adjustment_set_value (adj, new_value);
|
|
}
|
|
return_val = TRUE;
|
|
break;
|
|
|
|
case 5:
|
|
state |= GDK_BUTTON5_MASK;
|
|
if (state & GDK_SHIFT_MASK)
|
|
{
|
|
change_scale (gdisp, ZOOMOUT);
|
|
}
|
|
else
|
|
{
|
|
GtkAdjustment *adj =
|
|
(state & GDK_CONTROL_MASK) ? gdisp->hsbdata : gdisp->vsbdata;
|
|
gfloat new_value = adj->value + adj->page_increment / 2;
|
|
new_value = CLAMP (new_value,
|
|
adj->lower, adj->upper - adj->page_size);
|
|
gtk_adjustment_set_value (adj, new_value);
|
|
}
|
|
return_val = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GDK_BUTTON_RELEASE:
|
|
bevent = (GdkEventButton *) event;
|
|
state = bevent->state;
|
|
|
|
switch (bevent->button)
|
|
{
|
|
case 1:
|
|
state &= ~GDK_BUTTON1_MASK;
|
|
|
|
/* Lame hack. See above */
|
|
if (key_signal_id)
|
|
{
|
|
gtk_signal_disconnect (GTK_OBJECT (canvas), key_signal_id);
|
|
key_signal_id = 0;
|
|
}
|
|
|
|
gtk_grab_remove (canvas);
|
|
gdk_pointer_ungrab (bevent->time); /* fixes pointer grab bug */
|
|
if (active_tool && ((active_tool->type == MOVE) ||
|
|
!gimage_is_empty (gdisp->gimage)))
|
|
{
|
|
if (active_tool->state == ACTIVE)
|
|
{
|
|
if (active_tool->auto_snap_to)
|
|
{
|
|
gdisplay_snap_point (gdisp, bevent->x, bevent->y, &tx, &ty);
|
|
bevent->x = tx;
|
|
bevent->y = ty;
|
|
update_cursor = TRUE;
|
|
}
|
|
|
|
(* active_tool->button_release_func) (active_tool, bevent,
|
|
gdisp);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
state &= ~GDK_BUTTON2_MASK;
|
|
scrolled = FALSE;
|
|
gtk_grab_remove (canvas);
|
|
end_grab_and_scroll (gdisp, bevent);
|
|
break;
|
|
|
|
case 3:
|
|
state &= ~GDK_BUTTON3_MASK;
|
|
break;
|
|
|
|
/* wheelmouse support */
|
|
case 4:
|
|
state &= ~GDK_BUTTON4_MASK;
|
|
return_val = TRUE;
|
|
break;
|
|
|
|
case 5:
|
|
state &= ~GDK_BUTTON5_MASK;
|
|
return_val = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GDK_MOTION_NOTIFY:
|
|
mevent = (GdkEventMotion *) event;
|
|
state = mevent->state;
|
|
|
|
/* Ask for the pointer position, but ignore it except for cursor
|
|
* handling, so motion events sync with the button press/release events */
|
|
|
|
if (mevent->is_hint)
|
|
gdk_input_window_get_pointer (canvas->window, current_device, &tx, &ty,
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
#else /* !GTK_HAVE_SIX_VALUATORS */
|
|
NULL, NULL, NULL, NULL);
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
|
else
|
|
{
|
|
tx = mevent->x;
|
|
ty = mevent->y;
|
|
}
|
|
update_cursor = TRUE;
|
|
|
|
if (!gdisp->proximity)
|
|
{
|
|
gdisp->proximity = TRUE;
|
|
gdisplay_check_device_cursor (gdisp);
|
|
}
|
|
|
|
if (active_tool && ((active_tool->type == MOVE) ||
|
|
!gimage_is_empty (gdisp->gimage)) &&
|
|
(mevent->state & GDK_BUTTON1_MASK))
|
|
{
|
|
if (active_tool->state == ACTIVE)
|
|
{
|
|
/* if the first mouse button is down, check for automatic
|
|
* scrolling...
|
|
*/
|
|
if ((mevent->state & GDK_BUTTON1_MASK) && !active_tool->scroll_lock)
|
|
{
|
|
if (mevent->x < 0 || mevent->y < 0 ||
|
|
mevent->x > gdisp->disp_width ||
|
|
mevent->y > gdisp->disp_height)
|
|
scroll_to_pointer_position (gdisp, mevent);
|
|
}
|
|
|
|
if (active_tool->auto_snap_to)
|
|
{
|
|
gdisplay_snap_point (gdisp, mevent->x, mevent->y, &tx, &ty);
|
|
mevent->x = tx;
|
|
mevent->y = ty;
|
|
update_cursor = TRUE;
|
|
}
|
|
|
|
(* active_tool->motion_func) (active_tool, mevent, gdisp);
|
|
}
|
|
}
|
|
else if ((mevent->state & GDK_BUTTON2_MASK) && scrolled)
|
|
{
|
|
grab_and_scroll (gdisp, mevent);
|
|
}
|
|
break;
|
|
|
|
case GDK_KEY_PRESS:
|
|
kevent = (GdkEventKey *) event;
|
|
state = kevent->state;
|
|
|
|
switch (kevent->keyval)
|
|
{
|
|
case GDK_Left: case GDK_Right:
|
|
case GDK_Up: case GDK_Down:
|
|
if (active_tool && !gimage_is_empty (gdisp->gimage))
|
|
(* active_tool->arrow_keys_func) (active_tool, kevent, gdisp);
|
|
return_val = TRUE;
|
|
break;
|
|
|
|
case GDK_Tab:
|
|
if (kevent->state & GDK_MOD1_MASK && !gimage_is_empty (gdisp->gimage))
|
|
layer_select_init (gdisp->gimage, 1, kevent->time);
|
|
if (kevent->state & GDK_CONTROL_MASK && !gimage_is_empty (gdisp->gimage))
|
|
layer_select_init (gdisp->gimage, -1, kevent->time);
|
|
|
|
/* Hide or show all dialogs */
|
|
if (!kevent->state)
|
|
dialog_toggle();
|
|
|
|
return_val = TRUE;
|
|
break;
|
|
|
|
/* Update the state based on modifiers being pressed */
|
|
case GDK_Alt_L: case GDK_Alt_R:
|
|
case GDK_Shift_L: case GDK_Shift_R:
|
|
case GDK_Control_L: case GDK_Control_R:
|
|
state |= key_to_state(kevent->keyval);
|
|
/* For all modifier keys: call the tools modifier_key_func */
|
|
if (active_tool && !gimage_is_empty (gdisp->gimage))
|
|
{
|
|
gdk_input_window_get_pointer (canvas->window, current_device,
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
&tx, &ty, NULL, NULL, NULL, NULL, NULL);
|
|
#else /* !GTK_HAVE_SIX_VALUATORS */
|
|
&tx, &ty, NULL, NULL, NULL, NULL);
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
|
(* active_tool->modifier_key_func) (active_tool, kevent, gdisp);
|
|
return_val = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GDK_KEY_RELEASE:
|
|
kevent = (GdkEventKey *) event;
|
|
state = kevent->state;
|
|
|
|
switch (kevent->keyval)
|
|
{
|
|
case GDK_Alt_L: case GDK_Alt_R:
|
|
case GDK_Shift_L: case GDK_Shift_R:
|
|
case GDK_Control_L: case GDK_Control_R:
|
|
state &= ~key_to_state(kevent->keyval);
|
|
/* For all modifier keys: call the tools modifier_key_func */
|
|
if (active_tool && !gimage_is_empty (gdisp->gimage))
|
|
{
|
|
gdk_input_window_get_pointer (canvas->window, current_device,
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
&tx, &ty, NULL, NULL, NULL, NULL, NULL);
|
|
#else /* !GTK_HAVE_SIX_VALUATORS */
|
|
&tx, &ty, NULL, NULL, NULL, NULL);
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
|
(* active_tool->modifier_key_func) (active_tool, kevent, gdisp);
|
|
return_val = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return_val = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (no_cursor_updating == 0)
|
|
{
|
|
if (active_tool && !gimage_is_empty (gdisp->gimage) &&
|
|
!(state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)))
|
|
{
|
|
GdkEventMotion me;
|
|
me.x = tx; me.y = ty;
|
|
me.state = state;
|
|
(* active_tool->cursor_update_func) (active_tool, &me, gdisp);
|
|
}
|
|
else if (gimage_is_empty (gdisp->gimage))
|
|
gdisplay_install_tool_cursor (gdisp, GDK_TOP_LEFT_ARROW);
|
|
}
|
|
|
|
if (update_cursor)
|
|
gdisplay_update_cursor (gdisp, tx, ty);
|
|
|
|
return return_val;
|
|
}
|
|
|
|
gint
|
|
gdisplay_hruler_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
GDisplay *gdisp;
|
|
|
|
if (event->button == 1)
|
|
{
|
|
gdisp = data;
|
|
|
|
gimp_context_set_tool (gimp_context_get_user (), MOVE);
|
|
move_tool_start_hguide (active_tool, gdisp);
|
|
gtk_grab_add (gdisp->canvas);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
gint
|
|
gdisplay_vruler_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
GDisplay *gdisp;
|
|
|
|
if (event->button == 1)
|
|
{
|
|
gdisp = data;
|
|
|
|
gimp_context_set_tool (gimp_context_get_user (), MOVE);
|
|
move_tool_start_vguide (active_tool, gdisp);
|
|
gtk_grab_add (gdisp->canvas);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
gint
|
|
gdisplay_origin_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
GDisplay *gdisp;
|
|
|
|
if (event->button == 1)
|
|
{
|
|
gdisp = data;
|
|
gtk_menu_popup (GTK_MENU (gdisp->popup),
|
|
NULL, NULL, NULL, NULL, 1, event->time);
|
|
}
|
|
|
|
/* Stop the signal emission so the button doesn't grab the
|
|
* pointer away from us */
|
|
gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "button_press_event");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
gdisplay_drag_drop (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
guint time,
|
|
gpointer data)
|
|
{
|
|
GDisplay *gdisp;
|
|
GtkWidget *src_widget;
|
|
gboolean return_val = FALSE;
|
|
|
|
gdisp = (GDisplay *) data;
|
|
|
|
if ((src_widget = gtk_drag_get_source_widget (context)))
|
|
{
|
|
GimpDrawable *drawable = NULL;
|
|
Layer *layer = NULL;
|
|
Channel *channel = NULL;
|
|
LayerMask *layer_mask = NULL;
|
|
GImage *component = NULL;
|
|
ChannelType component_type = -1;
|
|
|
|
layer = (Layer *) gtk_object_get_data (GTK_OBJECT (src_widget),
|
|
"gimp_layer");
|
|
channel = (Channel *) gtk_object_get_data (GTK_OBJECT (src_widget),
|
|
"gimp_channel");
|
|
layer_mask = (LayerMask *) gtk_object_get_data (GTK_OBJECT (src_widget),
|
|
"gimp_layer_mask");
|
|
component = (GImage *) gtk_object_get_data (GTK_OBJECT (src_widget),
|
|
"gimp_component");
|
|
|
|
if (layer)
|
|
{
|
|
drawable = GIMP_DRAWABLE (layer);
|
|
}
|
|
else if (channel)
|
|
{
|
|
drawable = GIMP_DRAWABLE (channel);
|
|
}
|
|
else if (layer_mask)
|
|
{
|
|
drawable = GIMP_DRAWABLE (layer_mask);
|
|
}
|
|
else if (component)
|
|
{
|
|
component_type =
|
|
(ChannelType) gtk_object_get_data (GTK_OBJECT (src_widget),
|
|
"gimp_component_type");
|
|
}
|
|
|
|
/* FIXME: implement special treatment of channel etc.
|
|
*/
|
|
if (drawable)
|
|
{
|
|
GImage *gimage;
|
|
Layer *new_layer;
|
|
GImage *dest_gimage;
|
|
gint width, height;
|
|
gint dest_width, dest_height;
|
|
gint off_x, off_y;
|
|
TileManager *tiles;
|
|
PixelRegion srcPR, destPR;
|
|
guchar bg[MAX_CHANNELS];
|
|
gint bytes, type;
|
|
|
|
gimage = gimp_drawable_gimage (drawable);
|
|
width = gimp_drawable_width (drawable);
|
|
height = gimp_drawable_height (drawable);
|
|
|
|
/* How many bytes in the temp buffer? */
|
|
switch (drawable_type (drawable))
|
|
{
|
|
case RGB_GIMAGE: case RGBA_GIMAGE:
|
|
bytes = 4; type = RGB;
|
|
break;
|
|
case GRAY_GIMAGE: case GRAYA_GIMAGE:
|
|
bytes = 2; type = GRAY;
|
|
break;
|
|
case INDEXED_GIMAGE: case INDEXEDA_GIMAGE:
|
|
bytes = 4; type = INDEXED;
|
|
break;
|
|
default:
|
|
bytes = 3; type = RGB;
|
|
break;
|
|
}
|
|
|
|
gimage_get_background (gimage, drawable, bg);
|
|
|
|
tiles = tile_manager_new (width, height, bytes);
|
|
|
|
pixel_region_init (&srcPR, drawable_data (drawable),
|
|
0, 0, width, height, FALSE);
|
|
pixel_region_init (&destPR, tiles,
|
|
0, 0, width, height, TRUE);
|
|
|
|
if (type == INDEXED)
|
|
/* If the layer is indexed...we need to extract pixels */
|
|
extract_from_region (&srcPR, &destPR, NULL,
|
|
drawable_cmap (drawable), bg, type,
|
|
drawable_has_alpha (drawable), FALSE);
|
|
else if (bytes > srcPR.bytes)
|
|
/* If the layer doesn't have an alpha channel, add one */
|
|
add_alpha_region (&srcPR, &destPR);
|
|
else
|
|
/* Otherwise, do a straight copy */
|
|
copy_region (&srcPR, &destPR);
|
|
|
|
dest_gimage = gdisp->gimage;
|
|
dest_width = dest_gimage->width;
|
|
dest_height = dest_gimage->height;
|
|
|
|
new_layer =
|
|
layer_from_tiles (dest_gimage,
|
|
GIMP_DRAWABLE (gimage_get_active_layer (dest_gimage)),
|
|
tiles, _("Pasted Layer"),
|
|
OPAQUE_OPACITY, NORMAL_MODE);
|
|
|
|
tile_manager_destroy (tiles);
|
|
|
|
if (new_layer)
|
|
{
|
|
undo_push_group_start (dest_gimage, EDIT_PASTE_UNDO);
|
|
|
|
gimp_drawable_set_gimage (GIMP_DRAWABLE (new_layer), dest_gimage);
|
|
|
|
off_x = (dest_gimage->width - width) / 2;
|
|
off_y = (dest_gimage->height - height) / 2;
|
|
|
|
layer_translate (new_layer, off_x, off_y);
|
|
|
|
gimage_add_layer (dest_gimage, new_layer, -1);
|
|
|
|
gdisplays_flush ();
|
|
|
|
return_val = TRUE;
|
|
|
|
undo_push_group_end (dest_gimage);
|
|
}
|
|
}
|
|
}
|
|
|
|
gtk_drag_finish (context, return_val, FALSE, time);
|
|
|
|
if (return_val)
|
|
gimp_context_set_display (gimp_context_get_user (), gdisp);
|
|
|
|
return return_val;
|
|
}
|
|
|
|
static void
|
|
gdisplay_bucket_fill (GtkWidget *widget,
|
|
BucketFillMode fill_mode,
|
|
guchar orig_color[],
|
|
TempBuf *orig_pat_buf,
|
|
gpointer data)
|
|
{
|
|
GimpImage *gimage;
|
|
GimpDrawable *drawable;
|
|
TileManager *buf_tiles;
|
|
PixelRegion bufPR;
|
|
GimpContext *context;
|
|
gint x1, x2, y1, y2;
|
|
gint bytes;
|
|
gboolean has_alpha;
|
|
|
|
guchar color[3];
|
|
TempBuf *pat_buf = NULL;
|
|
gboolean new_buf = FALSE;
|
|
|
|
gimage = ((GDisplay *) data)->gimage;
|
|
drawable = gimage_active_drawable (gimage);
|
|
if (!drawable)
|
|
return;
|
|
|
|
gimp_add_busy_cursors ();
|
|
|
|
/* Get the bucket fill context */
|
|
if (! global_paint_options)
|
|
context = tool_info[BUCKET_FILL].tool_context;
|
|
else
|
|
context = gimp_context_get_user ();
|
|
|
|
/* Transform the passed data for the dest image */
|
|
if (fill_mode == FG_BUCKET_FILL)
|
|
{
|
|
gimp_image_transform_color (gimage, drawable, orig_color, color, RGB);
|
|
}
|
|
else
|
|
{
|
|
if (((orig_pat_buf->bytes == 3) && !drawable_color (drawable)) ||
|
|
((orig_pat_buf->bytes == 1) && !drawable_gray (drawable)))
|
|
{
|
|
guchar *d1, *d2;
|
|
gint size;
|
|
|
|
if ((orig_pat_buf->bytes == 1) && drawable_color (drawable))
|
|
pat_buf = temp_buf_new (orig_pat_buf->width, orig_pat_buf->height,
|
|
3, 0, 0, NULL);
|
|
else
|
|
pat_buf = temp_buf_new (orig_pat_buf->width, orig_pat_buf->height,
|
|
1, 0, 0, NULL);
|
|
|
|
d1 = temp_buf_data (orig_pat_buf);
|
|
d2 = temp_buf_data (pat_buf);
|
|
|
|
size = orig_pat_buf->width * orig_pat_buf->height;
|
|
while (size--)
|
|
{
|
|
gimage_transform_color (gimage, drawable, d1, d2,
|
|
(orig_pat_buf->bytes == 3) ? RGB : GRAY);
|
|
d1 += orig_pat_buf->bytes;
|
|
d2 += pat_buf->bytes;
|
|
}
|
|
|
|
new_buf = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pat_buf = orig_pat_buf;
|
|
}
|
|
}
|
|
|
|
drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
|
|
bytes = drawable_bytes (drawable);
|
|
has_alpha = drawable_has_alpha (drawable);
|
|
|
|
/* Fill the region */
|
|
buf_tiles = tile_manager_new ((x2 - x1), (y2 - y1), bytes);
|
|
pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE);
|
|
bucket_fill_region (fill_mode, &bufPR, NULL,
|
|
color, pat_buf, x1, y1, has_alpha);
|
|
|
|
/* Apply it to the image */
|
|
pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), FALSE);
|
|
gimage_apply_image (gimage, drawable, &bufPR, TRUE,
|
|
gimp_context_get_opacity (context) * 255,
|
|
gimp_context_get_paint_mode (context),
|
|
NULL, x1, y1);
|
|
tile_manager_destroy (buf_tiles);
|
|
|
|
/* Update the displays */
|
|
drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
|
|
gdisplays_flush ();
|
|
|
|
if (new_buf)
|
|
temp_buf_free (pat_buf);
|
|
|
|
gimp_remove_busy_cursors (NULL);
|
|
}
|
|
|
|
void
|
|
gdisplay_drop_color (GtkWidget *widget,
|
|
guchar r,
|
|
guchar g,
|
|
guchar b,
|
|
gpointer data)
|
|
{
|
|
guchar color[3];
|
|
|
|
color[0] = r;
|
|
color[1] = g;
|
|
color[2] = b;
|
|
|
|
gdisplay_bucket_fill (widget, FG_BUCKET_FILL, color, NULL, data);
|
|
}
|
|
|
|
void
|
|
gdisplay_drop_pattern (GtkWidget *widget,
|
|
GPattern *pattern,
|
|
gpointer data)
|
|
{
|
|
gdisplay_bucket_fill (widget, PATTERN_BUCKET_FILL, NULL, pattern->mask, data);
|
|
}
|