mirror of https://github.com/GNOME/gimp.git
1097 lines
31 KiB
C
1097 lines
31 KiB
C
/* GIMP - The GNU 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
#include "libgimpcolor/gimpcolor.h"
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
#include "display-types.h"
|
|
|
|
#include "config/gimpdisplayconfig.h"
|
|
|
|
#include "widgets/gimpcairo-wilber.h"
|
|
#include "widgets/gimpwidgets-utils.h"
|
|
|
|
#include "gimpcanvas.h"
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_CONFIG
|
|
};
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
static void gimp_canvas_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gimp_canvas_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_canvas_realize (GtkWidget *widget);
|
|
static void gimp_canvas_unrealize (GtkWidget *widget);
|
|
static void gimp_canvas_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation);
|
|
static void gimp_canvas_style_set (GtkWidget *widget,
|
|
GtkStyle *prev_style);
|
|
|
|
static GdkGC * gimp_canvas_gc_new (GimpCanvas *canvas,
|
|
GimpCanvasStyle style);
|
|
|
|
|
|
G_DEFINE_TYPE (GimpCanvas, gimp_canvas, GTK_TYPE_CONTAINER)
|
|
|
|
#define parent_class gimp_canvas_parent_class
|
|
|
|
|
|
static const guchar stipples[GIMP_CANVAS_NUM_STIPPLES][8] =
|
|
{
|
|
{
|
|
0xF0, /* ####---- */
|
|
0xE1, /* ###----# */
|
|
0xC3, /* ##----## */
|
|
0x87, /* #----### */
|
|
0x0F, /* ----#### */
|
|
0x1E, /* ---####- */
|
|
0x3C, /* --####-- */
|
|
0x78, /* -####--- */
|
|
},
|
|
{
|
|
0xE1, /* ###----# */
|
|
0xC3, /* ##----## */
|
|
0x87, /* #----### */
|
|
0x0F, /* ----#### */
|
|
0x1E, /* ---####- */
|
|
0x3C, /* --####-- */
|
|
0x78, /* -####--- */
|
|
0xF0, /* ####---- */
|
|
},
|
|
{
|
|
0xC3, /* ##----## */
|
|
0x87, /* #----### */
|
|
0x0F, /* ----#### */
|
|
0x1E, /* ---####- */
|
|
0x3C, /* --####-- */
|
|
0x78, /* -####--- */
|
|
0xF0, /* ####---- */
|
|
0xE1, /* ###----# */
|
|
},
|
|
{
|
|
0x87, /* #----### */
|
|
0x0F, /* ----#### */
|
|
0x1E, /* ---####- */
|
|
0x3C, /* --####-- */
|
|
0x78, /* -####--- */
|
|
0xF0, /* ####---- */
|
|
0xE1, /* ###----# */
|
|
0xC3, /* ##----## */
|
|
},
|
|
{
|
|
0x0F, /* ----#### */
|
|
0x1E, /* ---####- */
|
|
0x3C, /* --####-- */
|
|
0x78, /* -####--- */
|
|
0xF0, /* ####---- */
|
|
0xE1, /* ###----# */
|
|
0xC3, /* ##----## */
|
|
0x87, /* #----### */
|
|
},
|
|
{
|
|
0x1E, /* ---####- */
|
|
0x3C, /* --####-- */
|
|
0x78, /* -####--- */
|
|
0xF0, /* ####---- */
|
|
0xE1, /* ###----# */
|
|
0xC3, /* ##----## */
|
|
0x87, /* #----### */
|
|
0x0F, /* ----#### */
|
|
},
|
|
{
|
|
0x3C, /* --####-- */
|
|
0x78, /* -####--- */
|
|
0xF0, /* ####---- */
|
|
0xE1, /* ###----# */
|
|
0xC3, /* ##----## */
|
|
0x87, /* #----### */
|
|
0x0F, /* ----#### */
|
|
0x1E, /* ---####- */
|
|
},
|
|
{
|
|
0x78, /* -####--- */
|
|
0xF0, /* ####---- */
|
|
0xE1, /* ###----# */
|
|
0xC3, /* ##----## */
|
|
0x87, /* #----### */
|
|
0x0F, /* ----#### */
|
|
0x1E, /* ---####- */
|
|
0x3C, /* --####-- */
|
|
},
|
|
};
|
|
|
|
|
|
static void
|
|
gimp_canvas_class_init (GimpCanvasClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
object_class->set_property = gimp_canvas_set_property;
|
|
object_class->get_property = gimp_canvas_get_property;
|
|
|
|
widget_class->realize = gimp_canvas_realize;
|
|
widget_class->unrealize = gimp_canvas_unrealize;
|
|
widget_class->size_allocate = gimp_canvas_size_allocate;
|
|
widget_class->style_set = gimp_canvas_style_set;
|
|
|
|
g_object_class_install_property (object_class, PROP_CONFIG,
|
|
g_param_spec_object ("config", NULL, NULL,
|
|
GIMP_TYPE_DISPLAY_CONFIG,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
}
|
|
|
|
static void
|
|
gimp_canvas_init (GimpCanvas *canvas)
|
|
{
|
|
GtkWidget *widget = GTK_WIDGET (canvas);
|
|
gint i;
|
|
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
|
|
|
|
gtk_widget_set_extension_events (widget, GDK_EXTENSION_EVENTS_ALL);
|
|
|
|
for (i = 0; i < GIMP_CANVAS_NUM_STYLES; i++)
|
|
canvas->gc[i] = NULL;
|
|
|
|
for (i = 0; i < GIMP_CANVAS_NUM_STIPPLES; i++)
|
|
canvas->stipple[i] = NULL;
|
|
}
|
|
|
|
static void
|
|
gimp_canvas_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpCanvas *canvas = GIMP_CANVAS (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_CONFIG:
|
|
canvas->config = g_value_get_object (value); /* don't dup */
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_canvas_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpCanvas *canvas = GIMP_CANVAS (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_CONFIG:
|
|
g_value_set_object (value, canvas->config);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_canvas_realize (GtkWidget *widget)
|
|
{
|
|
GimpCanvas *canvas = GIMP_CANVAS (widget);
|
|
GdkWindowAttr attributes;
|
|
gint attributes_mask;
|
|
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
|
|
|
|
attributes.x = widget->allocation.x;
|
|
attributes.y = widget->allocation.y;
|
|
attributes.width = widget->allocation.width;
|
|
attributes.height = widget->allocation.height;
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
attributes.visual = gtk_widget_get_visual (widget);
|
|
attributes.colormap = gtk_widget_get_colormap (widget);
|
|
attributes.event_mask = (gtk_widget_get_events (widget) |
|
|
GIMP_CANVAS_EVENT_MASK);
|
|
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
|
|
|
|
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
|
|
&attributes, attributes_mask);
|
|
gdk_window_set_user_data (gtk_widget_get_window (widget), widget);
|
|
|
|
widget->style = gtk_style_attach (widget->style, widget->window);
|
|
gtk_style_set_background (widget->style, gtk_widget_get_window (widget),
|
|
GTK_STATE_NORMAL);
|
|
|
|
canvas->stipple[0] =
|
|
gdk_bitmap_create_from_data (gtk_widget_get_window (widget),
|
|
(const gchar *) stipples[0], 8, 8);
|
|
}
|
|
|
|
static void
|
|
gimp_canvas_unrealize (GtkWidget *widget)
|
|
{
|
|
GimpCanvas *canvas = GIMP_CANVAS (widget);
|
|
gint i;
|
|
|
|
for (i = 0; i < GIMP_CANVAS_NUM_STYLES; i++)
|
|
{
|
|
if (canvas->gc[i])
|
|
{
|
|
g_object_unref (canvas->gc[i]);
|
|
canvas->gc[i] = NULL;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < GIMP_CANVAS_NUM_STIPPLES; i++)
|
|
{
|
|
if (canvas->stipple[i])
|
|
{
|
|
g_object_unref (canvas->stipple[i]);
|
|
canvas->stipple[i] = NULL;
|
|
}
|
|
}
|
|
|
|
if (canvas->layout)
|
|
{
|
|
g_object_unref (canvas->layout);
|
|
canvas->layout = NULL;
|
|
}
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
|
|
}
|
|
|
|
static void
|
|
gimp_canvas_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation)
|
|
{
|
|
widget->allocation = *allocation;
|
|
|
|
if (GTK_WIDGET_REALIZED (widget))
|
|
gdk_window_move_resize (gtk_widget_get_window (widget),
|
|
allocation->x, allocation->y,
|
|
allocation->width, allocation->height);
|
|
}
|
|
|
|
static void
|
|
gimp_canvas_style_set (GtkWidget *widget,
|
|
GtkStyle *prev_style)
|
|
{
|
|
GimpCanvas *canvas = GIMP_CANVAS (widget);
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
|
|
|
|
if (canvas->layout)
|
|
{
|
|
g_object_unref (canvas->layout);
|
|
canvas->layout = NULL;
|
|
}
|
|
}
|
|
|
|
/* Returns: %TRUE if the XOR color is not white */
|
|
static gboolean
|
|
gimp_canvas_get_xor_color (GimpCanvas *canvas,
|
|
GdkColor *color)
|
|
{
|
|
guchar r, g, b;
|
|
|
|
gimp_rgb_get_uchar (&canvas->config->xor_color, &r, &g, &b);
|
|
|
|
color->red = (r << 8) | r;
|
|
color->green = (g << 8) | g;
|
|
color->blue = (b << 8) | b;
|
|
|
|
return (r != 255 || g != 255 || b != 255);
|
|
}
|
|
|
|
static GdkGC *
|
|
gimp_canvas_gc_new (GimpCanvas *canvas,
|
|
GimpCanvasStyle style)
|
|
{
|
|
GdkGC *gc;
|
|
GdkGCValues values;
|
|
GdkGCValuesMask mask = 0;
|
|
GdkColor fg = { 0, 0, 0, 0 };
|
|
GdkColor bg = { 0, 0, 0, 0 };
|
|
|
|
if (! GTK_WIDGET_REALIZED (canvas))
|
|
return NULL;
|
|
|
|
switch (style)
|
|
{
|
|
case GIMP_CANVAS_STYLE_BLACK:
|
|
case GIMP_CANVAS_STYLE_WHITE:
|
|
case GIMP_CANVAS_STYLE_SAMPLE_POINT_NORMAL:
|
|
case GIMP_CANVAS_STYLE_SAMPLE_POINT_ACTIVE:
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_RENDER:
|
|
mask |= GDK_GC_EXPOSURES;
|
|
values.graphics_exposures = TRUE;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_XOR_DOTTED:
|
|
case GIMP_CANVAS_STYLE_XOR_DASHED:
|
|
mask |= GDK_GC_LINE_STYLE;
|
|
values.line_style = GDK_LINE_ON_OFF_DASH;
|
|
/* fallthrough */
|
|
|
|
case GIMP_CANVAS_STYLE_XOR:
|
|
mask |= GDK_GC_FUNCTION | GDK_GC_CAP_STYLE | GDK_GC_JOIN_STYLE;
|
|
|
|
if (gimp_canvas_get_xor_color (canvas, &fg))
|
|
values.function = GDK_XOR;
|
|
else
|
|
values.function = GDK_INVERT;
|
|
|
|
values.cap_style = GDK_CAP_NOT_LAST;
|
|
values.join_style = GDK_JOIN_MITER;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_SELECTION_IN:
|
|
case GIMP_CANVAS_STYLE_SELECTION_OUT:
|
|
case GIMP_CANVAS_STYLE_LAYER_BOUNDARY:
|
|
case GIMP_CANVAS_STYLE_LAYER_GROUP_BOUNDARY:
|
|
case GIMP_CANVAS_STYLE_GUIDE_NORMAL:
|
|
case GIMP_CANVAS_STYLE_GUIDE_ACTIVE:
|
|
case GIMP_CANVAS_STYLE_LAYER_MASK_ACTIVE:
|
|
mask |= GDK_GC_CAP_STYLE | GDK_GC_FILL | GDK_GC_STIPPLE;
|
|
values.cap_style = GDK_CAP_NOT_LAST;
|
|
values.fill = GDK_OPAQUE_STIPPLED;
|
|
values.stipple = canvas->stipple[0];
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_CUSTOM:
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
gc = gdk_gc_new_with_values (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
&values, mask);
|
|
|
|
if (style == GIMP_CANVAS_STYLE_XOR_DOTTED)
|
|
{
|
|
gint8 one = 1;
|
|
gdk_gc_set_dashes (gc, 0, &one, 1);
|
|
}
|
|
|
|
switch (style)
|
|
{
|
|
default:
|
|
return gc;
|
|
|
|
case GIMP_CANVAS_STYLE_XOR_DOTTED:
|
|
case GIMP_CANVAS_STYLE_XOR_DASHED:
|
|
case GIMP_CANVAS_STYLE_XOR:
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_WHITE:
|
|
fg.red = 0xffff;
|
|
fg.green = 0xffff;
|
|
fg.blue = 0xffff;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_BLACK:
|
|
case GIMP_CANVAS_STYLE_SELECTION_IN:
|
|
fg.red = 0x0;
|
|
fg.green = 0x0;
|
|
fg.blue = 0x0;
|
|
|
|
bg.red = 0xffff;
|
|
bg.green = 0xffff;
|
|
bg.blue = 0xffff;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_SELECTION_OUT:
|
|
fg.red = 0xffff;
|
|
fg.green = 0xffff;
|
|
fg.blue = 0xffff;
|
|
|
|
bg.red = 0x7f7f;
|
|
bg.green = 0x7f7f;
|
|
bg.blue = 0x7f7f;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_LAYER_BOUNDARY:
|
|
fg.red = 0x0;
|
|
fg.green = 0x0;
|
|
fg.blue = 0x0;
|
|
|
|
bg.red = 0xffff;
|
|
bg.green = 0xffff;
|
|
bg.blue = 0x0;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_LAYER_GROUP_BOUNDARY:
|
|
fg.red = 0x0;
|
|
fg.green = 0x0;
|
|
fg.blue = 0x0;
|
|
|
|
bg.red = 0x0;
|
|
bg.green = 0xffff;
|
|
bg.blue = 0xffff;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_GUIDE_NORMAL:
|
|
fg.red = 0x0;
|
|
fg.green = 0x0;
|
|
fg.blue = 0x0;
|
|
|
|
bg.red = 0x0;
|
|
bg.green = 0x7f7f;
|
|
bg.blue = 0xffff;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_GUIDE_ACTIVE:
|
|
fg.red = 0x0;
|
|
fg.green = 0x0;
|
|
fg.blue = 0x0;
|
|
|
|
bg.red = 0xffff;
|
|
bg.green = 0x0;
|
|
bg.blue = 0x0;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_LAYER_MASK_ACTIVE:
|
|
fg.red = 0x0;
|
|
fg.green = 0x0;
|
|
fg.blue = 0x0;
|
|
|
|
bg.red = 0x0;
|
|
bg.green = 0xffff;
|
|
bg.blue = 0x0;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_SAMPLE_POINT_NORMAL:
|
|
fg.red = 0x0;
|
|
fg.green = 0x7f7f;
|
|
fg.blue = 0xffff;
|
|
break;
|
|
|
|
case GIMP_CANVAS_STYLE_SAMPLE_POINT_ACTIVE:
|
|
fg.red = 0xffff;
|
|
fg.green = 0x0;
|
|
fg.blue = 0x0;
|
|
break;
|
|
}
|
|
|
|
gdk_gc_set_rgb_fg_color (gc, &fg);
|
|
gdk_gc_set_rgb_bg_color (gc, &bg);
|
|
|
|
return gc;
|
|
}
|
|
|
|
static inline gboolean
|
|
gimp_canvas_ensure_style (GimpCanvas *canvas,
|
|
GimpCanvasStyle style)
|
|
{
|
|
return (canvas->gc[style] != NULL ||
|
|
(canvas->gc[style] = gimp_canvas_gc_new (canvas, style)) != NULL);
|
|
}
|
|
|
|
|
|
/* public functions */
|
|
|
|
/**
|
|
* gimp_canvas_new:
|
|
*
|
|
* Creates a new #GimpCanvas widget.
|
|
*
|
|
* The #GimpCanvas widget is a #GtkDrawingArea abstraction. It manages
|
|
* a set of graphic contexts for drawing on a GIMP display. If you
|
|
* draw using a #GimpCanvasStyle, #GimpCanvas makes sure that the
|
|
* associated #GdkGC is created. All drawing on the canvas needs to
|
|
* happen by means of the #GimpCanvas drawing functions. Besides from
|
|
* not needing a #GdkGC pointer, the #GimpCanvas drawing functions
|
|
* look and work like their #GdkDrawable counterparts. #GimpCanvas
|
|
* gracefully handles attempts to draw on the unrealized widget.
|
|
*
|
|
* Return value: a new #GimpCanvas widget
|
|
**/
|
|
GtkWidget *
|
|
gimp_canvas_new (GimpDisplayConfig *config)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_DISPLAY_CONFIG (config), NULL);
|
|
|
|
return g_object_new (GIMP_TYPE_CANVAS,
|
|
"name", "gimp-canvas",
|
|
"config", config,
|
|
NULL);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_scroll:
|
|
* @canvas: the #GimpCanvas widget to scroll.
|
|
* @offset_x: the x scroll amount.
|
|
* @offset_y: the y scroll amount.
|
|
*
|
|
* Scrolls the canvas using gdk_window_scroll() and makes sure the result
|
|
* is displayed immediately by calling gdk_window_process_updates().
|
|
**/
|
|
void
|
|
gimp_canvas_scroll (GimpCanvas *canvas,
|
|
gint offset_x,
|
|
gint offset_y)
|
|
{
|
|
GtkWidget *widget;
|
|
GdkWindow *window;
|
|
|
|
g_return_if_fail (GIMP_IS_CANVAS (canvas));
|
|
|
|
widget = GTK_WIDGET (canvas);
|
|
window = gtk_widget_get_window (widget);
|
|
|
|
gdk_window_scroll (window, offset_x, offset_y);
|
|
|
|
/* Make sure expose events are processed before scrolling again */
|
|
gdk_window_process_updates (window, FALSE);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_cursor:
|
|
* @canvas: the #GimpCanvas widget to draw on.
|
|
* @x: x coordinate
|
|
* @y: y coordinate
|
|
*
|
|
* Draws a plus-shaped black and white cursor, centered at the point
|
|
* @x, @y.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_cursor (GimpCanvas *canvas,
|
|
gint x,
|
|
gint y)
|
|
{
|
|
GtkWidget *widget = GTK_WIDGET (canvas);
|
|
GdkWindow *window = gtk_widget_get_window (widget);
|
|
|
|
if (! (gimp_canvas_ensure_style (canvas, GIMP_CANVAS_STYLE_BLACK) &&
|
|
gimp_canvas_ensure_style (canvas, GIMP_CANVAS_STYLE_WHITE)) )
|
|
return;
|
|
|
|
gdk_draw_line (window, canvas->gc[GIMP_CANVAS_STYLE_WHITE],
|
|
x - 7, y - 1, x + 7, y - 1);
|
|
gdk_draw_line (window, canvas->gc[GIMP_CANVAS_STYLE_BLACK],
|
|
x - 7, y, x + 7, y );
|
|
gdk_draw_line (window, canvas->gc[GIMP_CANVAS_STYLE_WHITE],
|
|
x - 7, y + 1, x + 7, y + 1);
|
|
gdk_draw_line (window, canvas->gc[GIMP_CANVAS_STYLE_WHITE],
|
|
x - 1, y - 7, x - 1, y + 7);
|
|
gdk_draw_line (window, canvas->gc[GIMP_CANVAS_STYLE_BLACK],
|
|
x, y - 7, x, y + 7);
|
|
gdk_draw_line (window, canvas->gc[GIMP_CANVAS_STYLE_WHITE],
|
|
x + 1, y - 7, x + 1, y + 7);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_point:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @x: x coordinate
|
|
* @y: y coordinate
|
|
*
|
|
* Draw a single pixel at the specified location in the specified
|
|
* style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_point (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
gint x,
|
|
gint y)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
gdk_draw_point (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
x, y);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_points:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @points: an array of GdkPoint x-y pairs.
|
|
* @num_points: the number of points in the array
|
|
*
|
|
* Draws a set of one-pixel points at the locations given in the
|
|
* @points argument, in the specified style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_points (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
GdkPoint *points,
|
|
gint num_points)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
gdk_draw_points (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
points, num_points);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_line:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @x1: X coordinate of the first point
|
|
* @y1: Y coordinate of the first point
|
|
* @x2: X coordinate of the second point
|
|
* @y2: Y coordinate of the second point
|
|
*
|
|
* Draw a line connecting the specified points, using the specified
|
|
* style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_line (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
gint x1,
|
|
gint y1,
|
|
gint x2,
|
|
gint y2)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
gdk_draw_line (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
x1, y1, x2, y2);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_lines:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @points: a #GdkPoint array.
|
|
* @num_points: the number of points in the array.
|
|
*
|
|
* Draws a set of lines connecting the specified points, in the
|
|
* specified style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_lines (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
GdkPoint *points,
|
|
gint num_points)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
gdk_draw_lines (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
points, num_points);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_rectangle:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @filled: %TRUE if the rectangle is to be filled.
|
|
* @x: X coordinate of the upper left corner.
|
|
* @y: Y coordinate of the upper left corner.
|
|
* @width: width of the rectangle.
|
|
* @height: height of the rectangle.
|
|
*
|
|
* Draws a rectangle in the specified style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_rectangle (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
gboolean filled,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
gdk_draw_rectangle (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
filled, x, y, width, height);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_arc:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @filled: %TRUE if the arc is to be filled, producing a 'pie slice'.
|
|
* @x: X coordinate of the left edge of the bounding rectangle.
|
|
* @y: Y coordinate of the top edge of the bounding rectangle.
|
|
* @width: width of the bounding rectangle.
|
|
* @height: height of the bounding rectangle.
|
|
* @angle1: the start angle of the arc.
|
|
* @angle2: the end angle of the arc.
|
|
*
|
|
* Draws an arc or pie slice, in the specified style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_arc (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
gboolean filled,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height,
|
|
gint angle1,
|
|
gint angle2)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
gdk_draw_arc (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
filled, x, y, width, height, angle1, angle2);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_polygon:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @filled: if %TRUE, fill the polygon.
|
|
* @points: a #GdkPoint array.
|
|
* @num_points: the number of points in the array.
|
|
*
|
|
* Draws a polygon connecting the specified points, in the specified
|
|
* style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_polygon (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
gboolean filled,
|
|
GdkPoint *points,
|
|
gint num_points)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
gdk_draw_polygon (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
filled, points, num_points);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_segments:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @segments: a #GdkSegment array.
|
|
* @num_segments: the number of segments in the array.
|
|
*
|
|
* Draws a set of line segments in the specified style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_segments (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
GdkSegment *segments,
|
|
gint num_segments)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
while (num_segments >= 32000)
|
|
{
|
|
gdk_draw_segments (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
segments, 32000);
|
|
num_segments -= 32000;
|
|
segments += 32000;
|
|
}
|
|
|
|
gdk_draw_segments (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
segments, num_segments);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_text:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @x: X coordinate of the left of the layout.
|
|
* @y: Y coordinate of the top of the layout.
|
|
* @format: a standard printf() format string.
|
|
* @Varargs: the parameters to insert into the format string.
|
|
*
|
|
* Draws a layout, in the specified style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_text (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
gint x,
|
|
gint y,
|
|
const gchar *format,
|
|
...)
|
|
{
|
|
va_list args;
|
|
gchar *text;
|
|
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
if (! canvas->layout)
|
|
canvas->layout = gtk_widget_create_pango_layout (GTK_WIDGET (canvas),
|
|
NULL);
|
|
|
|
va_start (args, format);
|
|
text = g_strdup_vprintf (format, args);
|
|
va_end (args);
|
|
|
|
pango_layout_set_text (canvas->layout, text, -1);
|
|
g_free (text);
|
|
|
|
gdk_draw_layout (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
x, y, canvas->layout);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_draw_rgb:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @x: X coordinate of the upper left corner.
|
|
* @y: Y coordinate of the upper left corner.
|
|
* @width: width of the rectangle to be drawn.
|
|
* @height: height of the rectangle to be drawn.
|
|
* @rgb_buf: pixel data for the image to be drawn.
|
|
* @rowstride: the rowstride in @rgb_buf.
|
|
* @xdith: x offset for dither alignment.
|
|
* @ydith: y offset for dither alignment.
|
|
*
|
|
* Draws an RGB image on the canvas in the specified style.
|
|
**/
|
|
void
|
|
gimp_canvas_draw_rgb (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height,
|
|
guchar *rgb_buf,
|
|
gint rowstride,
|
|
gint xdith,
|
|
gint ydith)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
gdk_draw_rgb_image_dithalign (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
canvas->gc[style],
|
|
x, y, width, height,
|
|
GDK_RGB_DITHER_MAX,
|
|
rgb_buf, rowstride, xdith, ydith);
|
|
}
|
|
|
|
void
|
|
gimp_canvas_draw_drop_zone (GimpCanvas *canvas,
|
|
cairo_t *cr)
|
|
{
|
|
GtkWidget *widget = GTK_WIDGET (canvas);
|
|
GtkStyle *style = gtk_widget_get_style (widget);
|
|
gdouble wilber_width;
|
|
gdouble wilber_height;
|
|
gdouble width;
|
|
gdouble height;
|
|
gdouble side;
|
|
gdouble factor;
|
|
|
|
gimp_cairo_wilber_get_size (cr, &wilber_width, &wilber_height);
|
|
|
|
wilber_width /= 2;
|
|
wilber_height /= 2;
|
|
|
|
side = MIN (MIN (widget->allocation.width, widget->allocation.height),
|
|
MAX (widget->allocation.width, widget->allocation.height) / 2);
|
|
|
|
width = MAX (wilber_width, side);
|
|
height = MAX (wilber_height, side);
|
|
|
|
factor = MIN (width / wilber_width, height / wilber_height);
|
|
|
|
cairo_scale (cr, factor, factor);
|
|
|
|
/* magic factors depend on the image used, everything else is generic
|
|
*/
|
|
gimp_cairo_wilber (cr,
|
|
- wilber_width * 0.6,
|
|
widget->allocation.height / factor - wilber_height * 1.1);
|
|
|
|
cairo_set_source_rgba (cr,
|
|
style->fg[widget->state].red / 65535.0,
|
|
style->fg[widget->state].green / 65535.0,
|
|
style->fg[widget->state].blue / 65535.0,
|
|
0.15);
|
|
cairo_fill (cr);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_set_clip_rect:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @rect: a #GdkRectangle to set the bounds of the clipping area.
|
|
*
|
|
* Sets a rectangular clipping area for the specified style.
|
|
**/
|
|
void
|
|
gimp_canvas_set_clip_rect (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
GdkRectangle *rect)
|
|
{
|
|
if (! canvas->gc[style])
|
|
{
|
|
if (! rect)
|
|
return;
|
|
|
|
canvas->gc[style] = gimp_canvas_gc_new (canvas, style);
|
|
}
|
|
|
|
gdk_gc_set_clip_rectangle (canvas->gc[style], rect);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_set_clip_region:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: one of the enumerated #GimpCanvasStyle's.
|
|
* @region: a #GdkRegion to set the bounds of the clipping area.
|
|
*
|
|
* Sets a clipping region for the specified style.
|
|
**/
|
|
void
|
|
gimp_canvas_set_clip_region (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
GdkRegion *region)
|
|
{
|
|
if (! canvas->gc[style])
|
|
{
|
|
if (! region)
|
|
return;
|
|
|
|
canvas->gc[style] = gimp_canvas_gc_new (canvas, style);
|
|
}
|
|
|
|
gdk_gc_set_clip_region (canvas->gc[style], region);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_set_stipple_index:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @style: the #GimpCanvasStyle to alter
|
|
* @index: the new stipple index
|
|
*
|
|
* Some styles of the #GimpCanvas do a stipple fill. #GimpCanvas has a
|
|
* set of %GIMP_CANVAS_NUM_STIPPLES stipple bitmaps. This function
|
|
* allows you to change the bitmap being used. This can be used to
|
|
* implement a marching ants effect. An older implementation used to
|
|
* use this feature and so it is included since it might be useful in
|
|
* the future. All stipple bitmaps but the default one are created on
|
|
* the fly.
|
|
*/
|
|
void
|
|
gimp_canvas_set_stipple_index (GimpCanvas *canvas,
|
|
GimpCanvasStyle style,
|
|
guint index)
|
|
{
|
|
if (! gimp_canvas_ensure_style (canvas, style))
|
|
return;
|
|
|
|
index = index % GIMP_CANVAS_NUM_STIPPLES;
|
|
|
|
if (! canvas->stipple[index])
|
|
{
|
|
canvas->stipple[index] =
|
|
gdk_bitmap_create_from_data (gtk_widget_get_window (GTK_WIDGET (canvas)),
|
|
(const gchar *) stipples[index], 8, 8);
|
|
}
|
|
|
|
gdk_gc_set_stipple (canvas->gc[style], canvas->stipple[index]);
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_set_custom_gc:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @gc: a #GdkGC;
|
|
*
|
|
* The #GimpCanvas widget has an extra style for a custom #GdkGC. This
|
|
* function allows you to set the @gc for the %GIMP_CANVAS_STYLE_CUSTOM.
|
|
* Drawing with the custom style only works if you set a #GdkGC
|
|
* earlier. Since the custom #GdkGC can under certain circumstances
|
|
* be destroyed by #GimpCanvas, you should always set the custom gc
|
|
* before calling a #GimpCanvas drawing function with
|
|
* %GIMP_CANVAS_STYLE_CUSTOM.
|
|
**/
|
|
void
|
|
gimp_canvas_set_custom_gc (GimpCanvas *canvas,
|
|
GdkGC *gc)
|
|
{
|
|
if (gc)
|
|
g_object_ref (gc);
|
|
|
|
if (canvas->gc[GIMP_CANVAS_STYLE_CUSTOM])
|
|
g_object_unref (canvas->gc[GIMP_CANVAS_STYLE_CUSTOM]);
|
|
|
|
canvas->gc[GIMP_CANVAS_STYLE_CUSTOM] = gc;
|
|
}
|
|
|
|
/**
|
|
* gimp_canvas_set_bg_color:
|
|
* @canvas: a #GimpCanvas widget
|
|
* @color: a color in #GimpRGB format
|
|
*
|
|
* Sets the background color of the canvas's window. This
|
|
* is the color the canvas is set to if it is cleared.
|
|
**/
|
|
void
|
|
gimp_canvas_set_bg_color (GimpCanvas *canvas,
|
|
GimpRGB *color)
|
|
{
|
|
GtkWidget *widget = GTK_WIDGET (canvas);
|
|
GdkColormap *colormap;
|
|
GdkColor gdk_color;
|
|
|
|
if (! GTK_WIDGET_REALIZED (widget))
|
|
return;
|
|
|
|
gimp_rgb_get_gdk_color (color, &gdk_color);
|
|
|
|
colormap = gdk_drawable_get_colormap (gtk_widget_get_window (widget));
|
|
g_return_if_fail (colormap != NULL);
|
|
gdk_colormap_alloc_color (colormap, &gdk_color, FALSE, TRUE);
|
|
|
|
gdk_window_set_background (gtk_widget_get_window (widget), &gdk_color);
|
|
}
|