mirror of
https://gitlab.gnome.org/GNOME/nautilus
synced 2024-08-25 10:45:41 +00:00
![Alexander Larsson](/assets/img/avatar_default.png)
2008-12-15 Alexander Larsson <alexl@redhat.com> * Makefile.am: * acconfig.h: * configure.in: * eel/ * libnautilus-private/Makefile.am: Import eel into nautilus. svn path=/trunk/; revision=14815
1490 lines
36 KiB
C
1490 lines
36 KiB
C
/*
|
|
* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
|
|
* All rights reserved.
|
|
*
|
|
* This file is part of the Gnome Library.
|
|
*
|
|
* The Gnome Library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* The Gnome Library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with the Gnome Library; see the file COPYING.LIB. If not,
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
/*
|
|
@NOTATION@
|
|
*/
|
|
/* Rectangle and ellipse item types for EelCanvas widget
|
|
*
|
|
* EelCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
|
|
* copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
|
|
*
|
|
*
|
|
* Author: Federico Mena <federico@nuclecu.unam.mx>
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <math.h>
|
|
#include "eel-canvas-rect-ellipse.h"
|
|
#include "eel-canvas-util.h"
|
|
#include <string.h>
|
|
|
|
#ifdef HAVE_RENDER
|
|
#include <gdk/gdkx.h>
|
|
#include <X11/extensions/Xrender.h>
|
|
#endif
|
|
|
|
/* Base class for rectangle and ellipse item types */
|
|
|
|
#define noVERBOSE
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_X1,
|
|
PROP_Y1,
|
|
PROP_X2,
|
|
PROP_Y2,
|
|
PROP_FILL_COLOR,
|
|
PROP_FILL_COLOR_GDK,
|
|
PROP_FILL_COLOR_RGBA,
|
|
PROP_OUTLINE_COLOR,
|
|
PROP_OUTLINE_COLOR_GDK,
|
|
PROP_OUTLINE_COLOR_RGBA,
|
|
PROP_FILL_STIPPLE,
|
|
PROP_OUTLINE_STIPPLE,
|
|
PROP_WIDTH_PIXELS,
|
|
PROP_WIDTH_UNITS
|
|
};
|
|
|
|
|
|
static void eel_canvas_re_class_init (EelCanvasREClass *class);
|
|
static void eel_canvas_re_init (EelCanvasRE *re);
|
|
static void eel_canvas_re_destroy (GtkObject *object);
|
|
static void eel_canvas_re_set_property (GObject *object,
|
|
guint param_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void eel_canvas_re_get_property (GObject *object,
|
|
guint param_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static void eel_canvas_re_update_shared (EelCanvasItem *item,
|
|
double i2w_dx, double i2w_dy, int flags);
|
|
static void eel_canvas_re_realize (EelCanvasItem *item);
|
|
static void eel_canvas_re_unrealize (EelCanvasItem *item);
|
|
static void eel_canvas_re_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
|
|
static void eel_canvas_re_translate (EelCanvasItem *item, double dx, double dy);
|
|
static void eel_canvas_rect_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags);
|
|
static void eel_canvas_ellipse_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags);
|
|
|
|
typedef struct {
|
|
/*< public >*/
|
|
int x0, y0, x1, y1;
|
|
} Rect;
|
|
|
|
static Rect make_rect (int x0, int y0, int x1, int y1);
|
|
static void diff_rects (Rect r1, Rect r2, int *count, Rect result[4]);
|
|
|
|
static EelCanvasItemClass *re_parent_class;
|
|
static EelCanvasREClass *rect_parent_class;
|
|
|
|
|
|
GType
|
|
eel_canvas_re_get_type (void)
|
|
{
|
|
static GType re_type = 0;
|
|
|
|
if (!re_type) {
|
|
GTypeInfo re_info = {
|
|
sizeof (EelCanvasREClass),
|
|
(GBaseInitFunc) NULL,
|
|
(GBaseFinalizeFunc) NULL,
|
|
(GClassInitFunc) eel_canvas_re_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (EelCanvasRE),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) eel_canvas_re_init
|
|
};
|
|
|
|
re_type = g_type_register_static (eel_canvas_item_get_type (),
|
|
"EelCanvasRE",
|
|
&re_info,
|
|
0);
|
|
}
|
|
|
|
return re_type;
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_class_init (EelCanvasREClass *class)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
GtkObjectClass *object_class;
|
|
EelCanvasItemClass *item_class;
|
|
|
|
gobject_class = (GObjectClass *) class;
|
|
object_class = (GtkObjectClass *) class;
|
|
item_class = (EelCanvasItemClass *) class;
|
|
|
|
re_parent_class = g_type_class_peek_parent (class);
|
|
|
|
gobject_class->set_property = eel_canvas_re_set_property;
|
|
gobject_class->get_property = eel_canvas_re_get_property;
|
|
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_X1,
|
|
g_param_spec_double ("x1", NULL, NULL,
|
|
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_Y1,
|
|
g_param_spec_double ("y1", NULL, NULL,
|
|
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_X2,
|
|
g_param_spec_double ("x2", NULL, NULL,
|
|
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_Y2,
|
|
g_param_spec_double ("y2", NULL, NULL,
|
|
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_FILL_COLOR,
|
|
g_param_spec_string ("fill_color", NULL, NULL,
|
|
NULL,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_FILL_COLOR_GDK,
|
|
g_param_spec_boxed ("fill_color_gdk", NULL, NULL,
|
|
GDK_TYPE_COLOR,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_FILL_COLOR_RGBA,
|
|
g_param_spec_uint ("fill_color_rgba", NULL, NULL,
|
|
0, G_MAXUINT, 0,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_FILL_STIPPLE,
|
|
g_param_spec_object ("fill_stipple", NULL, NULL,
|
|
GDK_TYPE_DRAWABLE,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_OUTLINE_COLOR,
|
|
g_param_spec_string ("outline_color", NULL, NULL,
|
|
NULL,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_OUTLINE_COLOR_GDK,
|
|
g_param_spec_boxed ("outline_color_gdk", NULL, NULL,
|
|
GDK_TYPE_COLOR,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_OUTLINE_COLOR_RGBA,
|
|
g_param_spec_uint ("outline_color_rgba", NULL, NULL,
|
|
0, G_MAXUINT, 0,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_OUTLINE_STIPPLE,
|
|
g_param_spec_object ("outline_stipple", NULL, NULL,
|
|
GDK_TYPE_DRAWABLE,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_WIDTH_PIXELS,
|
|
g_param_spec_uint ("width_pixels", NULL, NULL,
|
|
0, G_MAXUINT, 0,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
g_object_class_install_property
|
|
(gobject_class,
|
|
PROP_WIDTH_UNITS,
|
|
g_param_spec_double ("width_units", NULL, NULL,
|
|
0.0, G_MAXDOUBLE, 0.0,
|
|
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
|
|
|
|
object_class->destroy = eel_canvas_re_destroy;
|
|
|
|
item_class->realize = eel_canvas_re_realize;
|
|
item_class->unrealize = eel_canvas_re_unrealize;
|
|
item_class->translate = eel_canvas_re_translate;
|
|
item_class->bounds = eel_canvas_re_bounds;
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_init (EelCanvasRE *re)
|
|
{
|
|
re->x1 = 0.0;
|
|
re->y1 = 0.0;
|
|
re->x2 = 0.0;
|
|
re->y2 = 0.0;
|
|
re->width = 0.0;
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_destroy (GtkObject *object)
|
|
{
|
|
EelCanvasRE *re;
|
|
|
|
g_assert (object != NULL);
|
|
g_assert (EEL_IS_CANVAS_RE (object));
|
|
|
|
re = EEL_CANVAS_RE (object);
|
|
|
|
/* remember, destroy can be run multiple times! */
|
|
|
|
if (re->fill_stipple)
|
|
g_object_unref (re->fill_stipple);
|
|
re->fill_stipple = NULL;
|
|
|
|
if (re->outline_stipple)
|
|
g_object_unref (re->outline_stipple);
|
|
re->outline_stipple = NULL;
|
|
|
|
if (GTK_OBJECT_CLASS (re_parent_class)->destroy)
|
|
(* GTK_OBJECT_CLASS (re_parent_class)->destroy) (object);
|
|
}
|
|
|
|
static void get_bounds (EelCanvasRE *re, double *px1, double *py1, double *px2, double *py2)
|
|
{
|
|
EelCanvasItem *item;
|
|
double x1, y1, x2, y2;
|
|
int cx1, cy1, cx2, cy2;
|
|
double hwidth;
|
|
|
|
#ifdef VERBOSE
|
|
g_print ("re get_bounds\n");
|
|
#endif
|
|
item = EEL_CANVAS_ITEM (re);
|
|
|
|
if (re->width_pixels)
|
|
hwidth = (re->width / item->canvas->pixels_per_unit) / 2.0;
|
|
else
|
|
hwidth = re->width / 2.0;
|
|
|
|
x1 = re->x1;
|
|
y1 = re->y1;
|
|
x2 = re->x2;
|
|
y2 = re->y2;
|
|
|
|
eel_canvas_item_i2w (item, &x1, &y1);
|
|
eel_canvas_item_i2w (item, &x2, &y2);
|
|
eel_canvas_w2c (item->canvas, x1 - hwidth, y1 - hwidth, &cx1, &cy1);
|
|
eel_canvas_w2c (item->canvas, x2 + hwidth, y2 + hwidth, &cx2, &cy2);
|
|
*px1 = cx1;
|
|
*py1 = cy1;
|
|
*px2 = cx2;
|
|
*py2 = cy2;
|
|
|
|
/* Some safety fudging */
|
|
|
|
*px1 -= 2;
|
|
*py1 -= 2;
|
|
*px2 += 2;
|
|
*py2 += 2;
|
|
}
|
|
|
|
/* Convenience function to set a GC's foreground color to the specified pixel value */
|
|
static void
|
|
set_gc_foreground (GdkGC *gc, gulong pixel)
|
|
{
|
|
GdkColor c;
|
|
|
|
if (!gc)
|
|
return;
|
|
|
|
c.pixel = pixel;
|
|
gdk_gc_set_foreground (gc, &c);
|
|
}
|
|
|
|
/* Sets the stipple pattern for the specified gc */
|
|
static void
|
|
set_stipple (GdkGC *gc, GdkBitmap **internal_stipple, GdkBitmap *stipple, int reconfigure)
|
|
{
|
|
if (*internal_stipple && !reconfigure)
|
|
g_object_unref (*internal_stipple);
|
|
|
|
*internal_stipple = stipple;
|
|
if (stipple && !reconfigure)
|
|
g_object_ref (stipple);
|
|
|
|
if (gc) {
|
|
if (stipple) {
|
|
gdk_gc_set_stipple (gc, stipple);
|
|
gdk_gc_set_fill (gc, GDK_STIPPLED);
|
|
} else
|
|
gdk_gc_set_fill (gc, GDK_SOLID);
|
|
}
|
|
}
|
|
|
|
/* Recalculate the outline width of the rectangle/ellipse and set it in its GC */
|
|
static void
|
|
set_outline_gc_width (EelCanvasRE *re)
|
|
{
|
|
int width;
|
|
|
|
if (!re->outline_gc)
|
|
return;
|
|
|
|
if (re->width_pixels)
|
|
width = (int) re->width;
|
|
else
|
|
width = (int) (re->width * re->item.canvas->pixels_per_unit + 0.5);
|
|
|
|
gdk_gc_set_line_attributes (re->outline_gc, width,
|
|
GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_set_fill (EelCanvasRE *re, gboolean fill_set)
|
|
{
|
|
if (re->fill_set != fill_set) {
|
|
re->fill_set = fill_set;
|
|
eel_canvas_item_request_update (EEL_CANVAS_ITEM (re));
|
|
}
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_set_outline (EelCanvasRE *re, gboolean outline_set)
|
|
{
|
|
if (re->outline_set != outline_set) {
|
|
re->outline_set = outline_set;
|
|
eel_canvas_item_request_update (EEL_CANVAS_ITEM (re));
|
|
}
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_set_property (GObject *object,
|
|
guint param_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
EelCanvasItem *item;
|
|
EelCanvasRE *re;
|
|
GdkColor color = { 0, 0, 0, 0, };
|
|
GdkColor *pcolor;
|
|
int have_pixel;
|
|
|
|
g_assert (object != NULL);
|
|
g_assert (EEL_IS_CANVAS_RE (object));
|
|
|
|
item = EEL_CANVAS_ITEM (object);
|
|
re = EEL_CANVAS_RE (object);
|
|
have_pixel = FALSE;
|
|
|
|
switch (param_id) {
|
|
case PROP_X1:
|
|
re->x1 = g_value_get_double (value);
|
|
|
|
eel_canvas_item_request_update (item);
|
|
break;
|
|
|
|
case PROP_Y1:
|
|
re->y1 = g_value_get_double (value);
|
|
|
|
eel_canvas_item_request_update (item);
|
|
break;
|
|
|
|
case PROP_X2:
|
|
re->x2 = g_value_get_double (value);
|
|
|
|
eel_canvas_item_request_update (item);
|
|
break;
|
|
|
|
case PROP_Y2:
|
|
re->y2 = g_value_get_double (value);
|
|
|
|
eel_canvas_item_request_update (item);
|
|
break;
|
|
|
|
case PROP_FILL_COLOR:
|
|
case PROP_FILL_COLOR_GDK:
|
|
case PROP_FILL_COLOR_RGBA:
|
|
switch (param_id) {
|
|
case PROP_FILL_COLOR:
|
|
if (g_value_get_string (value) &&
|
|
gdk_color_parse (g_value_get_string (value), &color))
|
|
eel_canvas_re_set_fill (re, TRUE);
|
|
else
|
|
eel_canvas_re_set_fill (re, FALSE);
|
|
|
|
re->fill_color = ((color.red & 0xff00) << 16 |
|
|
(color.green & 0xff00) << 8 |
|
|
(color.blue & 0xff00) |
|
|
0xff);
|
|
break;
|
|
|
|
case PROP_FILL_COLOR_GDK:
|
|
pcolor = g_value_get_boxed (value);
|
|
eel_canvas_re_set_fill (re, pcolor != NULL);
|
|
|
|
if (pcolor) {
|
|
GdkColormap *colormap;
|
|
|
|
color = *pcolor;
|
|
colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
|
|
gdk_rgb_find_color (colormap, &color);
|
|
have_pixel = TRUE;
|
|
}
|
|
|
|
re->fill_color = ((color.red & 0xff00) << 16 |
|
|
(color.green & 0xff00) << 8 |
|
|
(color.blue & 0xff00) |
|
|
0xff);
|
|
break;
|
|
|
|
case PROP_FILL_COLOR_RGBA:
|
|
eel_canvas_re_set_fill (re, TRUE);
|
|
re->fill_color = g_value_get_uint (value);
|
|
break;
|
|
}
|
|
#ifdef VERBOSE
|
|
g_print ("re fill color = %08x\n", re->fill_color);
|
|
#endif
|
|
if (have_pixel)
|
|
re->fill_pixel = color.pixel;
|
|
else
|
|
re->fill_pixel = eel_canvas_get_color_pixel (item->canvas, re->fill_color);
|
|
|
|
set_gc_foreground (re->fill_gc, re->fill_pixel);
|
|
|
|
eel_canvas_item_request_redraw (item);
|
|
break;
|
|
|
|
case PROP_OUTLINE_COLOR:
|
|
case PROP_OUTLINE_COLOR_GDK:
|
|
case PROP_OUTLINE_COLOR_RGBA:
|
|
switch (param_id) {
|
|
case PROP_OUTLINE_COLOR:
|
|
if (g_value_get_string (value) &&
|
|
gdk_color_parse (g_value_get_string (value), &color))
|
|
eel_canvas_re_set_outline (re, TRUE);
|
|
else
|
|
eel_canvas_re_set_outline (re, FALSE);
|
|
|
|
re->outline_color = ((color.red & 0xff00) << 16 |
|
|
(color.green & 0xff00) << 8 |
|
|
(color.blue & 0xff00) |
|
|
0xff);
|
|
break;
|
|
|
|
case PROP_OUTLINE_COLOR_GDK:
|
|
pcolor = g_value_get_boxed (value);
|
|
eel_canvas_re_set_outline (re, pcolor != NULL);
|
|
|
|
if (pcolor) {
|
|
GdkColormap *colormap;
|
|
|
|
color = *pcolor;
|
|
colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
|
|
gdk_rgb_find_color (colormap, &color);
|
|
|
|
have_pixel = TRUE;
|
|
}
|
|
|
|
re->outline_color = ((color.red & 0xff00) << 16 |
|
|
(color.green & 0xff00) << 8 |
|
|
(color.blue & 0xff00) |
|
|
0xff);
|
|
break;
|
|
|
|
case PROP_OUTLINE_COLOR_RGBA:
|
|
eel_canvas_re_set_outline (re, TRUE);
|
|
re->outline_color = g_value_get_uint (value);
|
|
break;
|
|
}
|
|
#ifdef VERBOSE
|
|
g_print ("re outline color %x %x %x\n", color.red, color.green, color.blue);
|
|
#endif
|
|
if (have_pixel)
|
|
re->outline_pixel = color.pixel;
|
|
else
|
|
re->outline_pixel = eel_canvas_get_color_pixel (item->canvas,
|
|
re->outline_color);
|
|
|
|
set_gc_foreground (re->outline_gc, re->outline_pixel);
|
|
|
|
eel_canvas_item_request_redraw (item);
|
|
break;
|
|
|
|
case PROP_FILL_STIPPLE:
|
|
set_stipple (re->fill_gc, &re->fill_stipple, (GdkBitmap *) g_value_get_object (value), FALSE);
|
|
|
|
break;
|
|
|
|
case PROP_OUTLINE_STIPPLE:
|
|
set_stipple (re->outline_gc, &re->outline_stipple, (GdkBitmap *) g_value_get_object (value), FALSE);
|
|
break;
|
|
|
|
case PROP_WIDTH_PIXELS:
|
|
re->width = g_value_get_uint (value);
|
|
re->width_pixels = TRUE;
|
|
set_outline_gc_width (re);
|
|
|
|
eel_canvas_item_request_update (item);
|
|
break;
|
|
|
|
case PROP_WIDTH_UNITS:
|
|
re->width = fabs (g_value_get_double (value));
|
|
re->width_pixels = FALSE;
|
|
set_outline_gc_width (re);
|
|
|
|
eel_canvas_item_request_update (item);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Allocates a GdkColor structure filled with the specified pixel, and puts it into the specified
|
|
* value for returning it in the get_property method.
|
|
*/
|
|
static void
|
|
get_color_value (EelCanvasRE *re, gulong pixel, GValue *value)
|
|
{
|
|
GdkColor color;
|
|
EelCanvasItem *item = (EelCanvasItem *) re;
|
|
GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
|
|
|
|
gdk_colormap_query_color (colormap, pixel, &color);
|
|
g_value_set_boxed (value, &color);
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_get_property (GObject *object,
|
|
guint param_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
EelCanvasRE *re;
|
|
|
|
g_assert (object != NULL);
|
|
g_assert (EEL_IS_CANVAS_RE (object));
|
|
|
|
re = EEL_CANVAS_RE (object);
|
|
|
|
switch (param_id) {
|
|
case PROP_X1:
|
|
g_value_set_double (value, re->x1);
|
|
break;
|
|
|
|
case PROP_Y1:
|
|
g_value_set_double (value, re->y1);
|
|
break;
|
|
|
|
case PROP_X2:
|
|
g_value_set_double (value, re->x2);
|
|
break;
|
|
|
|
case PROP_Y2:
|
|
g_value_set_double (value, re->y2);
|
|
break;
|
|
|
|
case PROP_FILL_COLOR_GDK:
|
|
get_color_value (re, re->fill_pixel, value);
|
|
break;
|
|
|
|
case PROP_OUTLINE_COLOR_GDK:
|
|
get_color_value (re, re->outline_pixel, value);
|
|
break;
|
|
|
|
case PROP_FILL_COLOR_RGBA:
|
|
g_value_set_uint (value, re->fill_color);
|
|
break;
|
|
|
|
case PROP_OUTLINE_COLOR_RGBA:
|
|
g_value_set_uint (value, re->outline_color);
|
|
break;
|
|
|
|
case PROP_FILL_STIPPLE:
|
|
g_value_set_object (value, (GObject *) re->fill_stipple);
|
|
break;
|
|
|
|
case PROP_OUTLINE_STIPPLE:
|
|
g_value_set_object (value, (GObject *) re->outline_stipple);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_colors_and_stipples (EelCanvasRE *re)
|
|
{
|
|
set_gc_foreground (re->fill_gc, re->fill_pixel);
|
|
set_gc_foreground (re->outline_gc, re->outline_pixel);
|
|
set_stipple (re->fill_gc, &re->fill_stipple, re->fill_stipple, TRUE);
|
|
set_stipple (re->outline_gc, &re->outline_stipple, re->outline_stipple, TRUE);
|
|
set_outline_gc_width (re);
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_update_shared (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags)
|
|
{
|
|
EelCanvasRE *re;
|
|
|
|
#ifdef VERBOSE
|
|
g_print ("eel_canvas_re_update_shared\n");
|
|
#endif
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
if (re_parent_class->update)
|
|
(* re_parent_class->update) (item, i2w_dx, i2w_dy, flags);
|
|
|
|
set_colors_and_stipples (re);
|
|
|
|
#ifdef OLD_XFORM
|
|
recalc_bounds (re);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_realize (EelCanvasItem *item)
|
|
{
|
|
EelCanvasRE *re;
|
|
|
|
#ifdef VERBOSE
|
|
g_print ("eel_canvas_re_realize\n");
|
|
#endif
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
if (re_parent_class->realize)
|
|
(* re_parent_class->realize) (item);
|
|
|
|
re->fill_gc = gdk_gc_new (item->canvas->layout.bin_window);
|
|
re->fill_pixel = eel_canvas_get_color_pixel (item->canvas, re->fill_color);
|
|
re->outline_gc = gdk_gc_new (item->canvas->layout.bin_window);
|
|
re->outline_pixel = eel_canvas_get_color_pixel (item->canvas, re->outline_color);
|
|
set_colors_and_stipples (re);
|
|
|
|
#ifdef OLD_XFORM
|
|
(* EEL_CANVAS_ITEM_CLASS (item->object.klass)->update) (item, NULL, NULL, 0);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_unrealize (EelCanvasItem *item)
|
|
{
|
|
EelCanvasRE *re;
|
|
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
g_object_unref (re->fill_gc);
|
|
re->fill_gc = NULL;
|
|
g_object_unref (re->outline_gc);
|
|
re->outline_gc = NULL;
|
|
|
|
if (re_parent_class->unrealize)
|
|
(* re_parent_class->unrealize) (item);
|
|
}
|
|
|
|
static void
|
|
eel_canvas_re_translate (EelCanvasItem *item, double dx, double dy)
|
|
{
|
|
EelCanvasRE *re;
|
|
|
|
#ifdef VERBOSE
|
|
g_print ("eel_canvas_re_translate\n");
|
|
#endif
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
re->x1 += dx;
|
|
re->y1 += dy;
|
|
re->x2 += dx;
|
|
re->y2 += dy;
|
|
}
|
|
|
|
|
|
static void
|
|
eel_canvas_re_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
|
|
{
|
|
EelCanvasRE *re;
|
|
double hwidth;
|
|
|
|
#ifdef VERBOSE
|
|
g_print ("eel_canvas_re_bounds\n");
|
|
#endif
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
if (re->width_pixels)
|
|
hwidth = (re->width / item->canvas->pixels_per_unit) / 2.0;
|
|
else
|
|
hwidth = re->width / 2.0;
|
|
|
|
*x1 = re->x1 - hwidth;
|
|
*y1 = re->y1 - hwidth;
|
|
*x2 = re->x2 + hwidth;
|
|
*y2 = re->y2 + hwidth;
|
|
}
|
|
|
|
/* Rectangle item */
|
|
|
|
|
|
static void eel_canvas_rect_class_init (EelCanvasRectClass *class);
|
|
static void eel_canvas_rect_init (EelCanvasRect *rect);
|
|
static void eel_canvas_rect_finalize (GObject *object);
|
|
static void eel_canvas_rect_realize (EelCanvasItem *item);
|
|
|
|
static void eel_canvas_rect_draw (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose);
|
|
static double eel_canvas_rect_point (EelCanvasItem *item, double x, double y, int cx, int cy,
|
|
EelCanvasItem **actual_item);
|
|
|
|
struct _EelCanvasRectPrivate {
|
|
Rect last_update_rect;
|
|
Rect last_outline_update_rect;
|
|
int last_outline_update_width;
|
|
|
|
#ifdef HAVE_RENDER
|
|
gboolean use_render;
|
|
XRenderPictFormat *format;
|
|
#endif
|
|
};
|
|
|
|
GType
|
|
eel_canvas_rect_get_type (void)
|
|
{
|
|
static GType rect_type = 0;
|
|
|
|
if (!rect_type) {
|
|
GTypeInfo rect_info = {
|
|
sizeof (EelCanvasRectClass),
|
|
(GBaseInitFunc) NULL,
|
|
(GBaseFinalizeFunc) NULL,
|
|
(GClassInitFunc) eel_canvas_rect_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (EelCanvasRect),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) eel_canvas_rect_init
|
|
};
|
|
|
|
rect_type = g_type_register_static (eel_canvas_re_get_type (),
|
|
"EelCanvasRect",
|
|
&rect_info,
|
|
0);
|
|
}
|
|
|
|
return rect_type;
|
|
}
|
|
|
|
static void
|
|
eel_canvas_rect_class_init (EelCanvasRectClass *class)
|
|
{
|
|
EelCanvasItemClass *item_class;
|
|
|
|
rect_parent_class = g_type_class_peek_parent (class);
|
|
|
|
item_class = (EelCanvasItemClass *) class;
|
|
|
|
item_class->draw = eel_canvas_rect_draw;
|
|
item_class->point = eel_canvas_rect_point;
|
|
item_class->update = eel_canvas_rect_update;
|
|
item_class->realize = eel_canvas_rect_realize;
|
|
|
|
G_OBJECT_CLASS (class)->finalize = eel_canvas_rect_finalize;
|
|
|
|
}
|
|
|
|
static void
|
|
eel_canvas_rect_init (EelCanvasRect *rect)
|
|
{
|
|
rect->priv = g_new0 (EelCanvasRectPrivate, 1);
|
|
}
|
|
|
|
static void
|
|
eel_canvas_rect_finalize (GObject *object)
|
|
{
|
|
EelCanvasRect *rect = EEL_CANVAS_RECT (object);
|
|
|
|
if (rect->priv) {
|
|
g_free (rect->priv);
|
|
}
|
|
|
|
G_OBJECT_CLASS (rect_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
eel_canvas_rect_realize (EelCanvasItem *item)
|
|
{
|
|
#ifdef HAVE_RENDER
|
|
EelCanvasRectPrivate *priv;
|
|
int event_base, error_base;
|
|
|
|
priv = EEL_CANVAS_RECT (item)->priv;
|
|
|
|
priv->use_render = XRenderQueryExtension (gdk_display, &event_base, &error_base);
|
|
|
|
if (priv->use_render) {
|
|
Display *dpy;
|
|
GdkVisual *gdk_visual;
|
|
Visual *visual;
|
|
|
|
dpy = gdk_x11_drawable_get_xdisplay (GTK_WIDGET (item->canvas)->window);
|
|
gdk_visual = gtk_widget_get_visual (GTK_WIDGET (item->canvas));
|
|
visual = gdk_x11_visual_get_xvisual (gdk_visual);
|
|
|
|
priv->format = XRenderFindVisualFormat (dpy, visual);
|
|
}
|
|
#endif
|
|
|
|
if (EEL_CANVAS_ITEM_CLASS (rect_parent_class)->realize) {
|
|
(* EEL_CANVAS_ITEM_CLASS (rect_parent_class)->realize) (item);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
render_rect_alpha (EelCanvasRect *rect,
|
|
GdkDrawable *drawable,
|
|
int x, int y,
|
|
int width, int height,
|
|
guint32 rgba)
|
|
{
|
|
GdkPixbuf *pixbuf;
|
|
guchar *data;
|
|
int rowstride, i;
|
|
guchar r, g, b, a;
|
|
EelCanvasRectPrivate *priv;
|
|
|
|
if (width <= 0 || height <= 0 ) {
|
|
return;
|
|
}
|
|
|
|
priv = rect->priv;
|
|
|
|
r = (rgba >> 24) & 0xff;
|
|
g = (rgba >> 16) & 0xff;
|
|
b = (rgba >> 8) & 0xff;
|
|
a = (rgba >> 0) & 0xff;
|
|
|
|
#ifdef HAVE_RENDER
|
|
/* Every visual is not guaranteed to have a matching
|
|
* XRenderPictFormat. So make sure that format is not null before
|
|
* trying to render using Xrender calls.
|
|
*/
|
|
if (priv->use_render && (priv->format != NULL)) {
|
|
GdkDrawable *real_drawable;
|
|
int x_offset, y_offset;
|
|
|
|
Display *dpy;
|
|
Picture pict;
|
|
XRenderPictureAttributes attributes;
|
|
XRenderColor color;
|
|
|
|
gdk_window_get_internal_paint_info (drawable, &real_drawable,
|
|
&x_offset, &y_offset);
|
|
|
|
dpy = gdk_x11_drawable_get_xdisplay (real_drawable);
|
|
|
|
pict = XRenderCreatePicture (dpy,
|
|
gdk_x11_drawable_get_xid (real_drawable),
|
|
priv->format,
|
|
0,
|
|
&attributes);
|
|
|
|
|
|
/* Convert to premultiplied alpha: */
|
|
r = r * a / 255;
|
|
g = g * a / 255;
|
|
b = b * a / 255;
|
|
|
|
color.red = (r << 8) + r;
|
|
color.green = (g << 8) + g;
|
|
color.blue = (b << 8) + b;
|
|
color.alpha = (a << 8) + a;
|
|
|
|
XRenderFillRectangle (dpy,
|
|
PictOpOver,
|
|
pict,
|
|
&color,
|
|
x - x_offset, y - y_offset,
|
|
width, height);
|
|
|
|
XRenderFreePicture (dpy, pict);
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
|
|
data = gdk_pixbuf_get_pixels (pixbuf);
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
|
|
r = (rgba >> 24) & 0xff;
|
|
g = (rgba >> 16) & 0xff;
|
|
b = (rgba >> 8) & 0xff;
|
|
a = (rgba >> 0) & 0xff;
|
|
|
|
for (i = 0; i < width*4; ) {
|
|
data[i++] = r;
|
|
data[i++] = g;
|
|
data[i++] = b;
|
|
data[i++] = a;
|
|
}
|
|
|
|
for (i = 1; i < height; i++) {
|
|
memcpy (data + i*rowstride, data, width*4);
|
|
}
|
|
|
|
gdk_draw_pixbuf (drawable, NULL, pixbuf,
|
|
0, 0, x, y, width, height,
|
|
GDK_RGB_DITHER_NONE, 0, 0);
|
|
g_object_unref (pixbuf);
|
|
}
|
|
|
|
|
|
static void
|
|
eel_canvas_rect_draw (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose)
|
|
{
|
|
EelCanvasRE *re;
|
|
double x1, y1, x2, y2;
|
|
int cx1, cy1, cx2, cy2;
|
|
double i2w_dx, i2w_dy;
|
|
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
/* Get canvas pixel coordinates */
|
|
i2w_dx = 0.0;
|
|
i2w_dy = 0.0;
|
|
eel_canvas_item_i2w (item, &i2w_dx, &i2w_dy);
|
|
|
|
x1 = re->x1 + i2w_dx;
|
|
y1 = re->y1 + i2w_dy;
|
|
x2 = re->x2 + i2w_dx;
|
|
y2 = re->y2 + i2w_dy;
|
|
|
|
eel_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1);
|
|
eel_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2);
|
|
|
|
if (re->fill_set) {
|
|
if ((re->fill_color & 0xff) != 255) {
|
|
GdkRectangle *rectangles;
|
|
gint i, n_rectangles;
|
|
GdkRectangle draw_rect;
|
|
GdkRectangle part;
|
|
|
|
draw_rect.x = cx1;
|
|
draw_rect.y = cy1;
|
|
draw_rect.width = cx2 - cx1 + 1;
|
|
draw_rect.height = cy2 - cy1 + 1;
|
|
|
|
/* For alpha mode, only render the parts of the region
|
|
that are actually exposed */
|
|
gdk_region_get_rectangles (expose->region,
|
|
&rectangles,
|
|
&n_rectangles);
|
|
|
|
for (i = 0; i < n_rectangles; i++) {
|
|
if (gdk_rectangle_intersect (&rectangles[i],
|
|
&draw_rect,
|
|
&part)) {
|
|
render_rect_alpha (EEL_CANVAS_RECT (item),
|
|
drawable,
|
|
part.x, part.y,
|
|
part.width, part.height,
|
|
re->fill_color);
|
|
}
|
|
}
|
|
|
|
g_free (rectangles);
|
|
} else {
|
|
if (re->fill_stipple)
|
|
eel_canvas_set_stipple_origin (item->canvas, re->fill_gc);
|
|
|
|
gdk_draw_rectangle (drawable,
|
|
re->fill_gc,
|
|
TRUE,
|
|
cx1, cy1,
|
|
cx2 - cx1 + 1,
|
|
cy2 - cy1 + 1);
|
|
}
|
|
}
|
|
|
|
if (re->outline_set) {
|
|
if (re->outline_stipple)
|
|
eel_canvas_set_stipple_origin (item->canvas, re->outline_gc);
|
|
|
|
gdk_draw_rectangle (drawable,
|
|
re->outline_gc,
|
|
FALSE,
|
|
cx1,
|
|
cy1,
|
|
cx2 - cx1,
|
|
cy2 - cy1);
|
|
}
|
|
}
|
|
|
|
static double
|
|
eel_canvas_rect_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item)
|
|
{
|
|
EelCanvasRE *re;
|
|
double x1, y1, x2, y2;
|
|
double hwidth;
|
|
double dx, dy;
|
|
double tmp;
|
|
|
|
#ifdef VERBOSE
|
|
g_print ("eel_canvas_rect_point\n");
|
|
#endif
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
*actual_item = item;
|
|
|
|
/* Find the bounds for the rectangle plus its outline width */
|
|
|
|
x1 = re->x1;
|
|
y1 = re->y1;
|
|
x2 = re->x2;
|
|
y2 = re->y2;
|
|
|
|
if (re->outline_set) {
|
|
if (re->width_pixels)
|
|
hwidth = (re->width / item->canvas->pixels_per_unit) / 2.0;
|
|
else
|
|
hwidth = re->width / 2.0;
|
|
|
|
x1 -= hwidth;
|
|
y1 -= hwidth;
|
|
x2 += hwidth;
|
|
y2 += hwidth;
|
|
} else
|
|
hwidth = 0.0;
|
|
|
|
/* Is point inside rectangle (which can be hollow if it has no fill set)? */
|
|
|
|
if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
|
|
if (re->fill_set || !re->outline_set)
|
|
return 0.0;
|
|
|
|
dx = x - x1;
|
|
tmp = x2 - x;
|
|
if (tmp < dx)
|
|
dx = tmp;
|
|
|
|
dy = y - y1;
|
|
tmp = y2 - y;
|
|
if (tmp < dy)
|
|
dy = tmp;
|
|
|
|
if (dy < dx)
|
|
dx = dy;
|
|
|
|
dx -= 2.0 * hwidth;
|
|
|
|
if (dx < 0.0)
|
|
return 0.0;
|
|
else
|
|
return dx;
|
|
}
|
|
|
|
/* Point is outside rectangle */
|
|
|
|
if (x < x1)
|
|
dx = x1 - x;
|
|
else if (x > x2)
|
|
dx = x - x2;
|
|
else
|
|
dx = 0.0;
|
|
|
|
if (y < y1)
|
|
dy = y1 - y;
|
|
else if (y > y2)
|
|
dy = y - y2;
|
|
else
|
|
dy = 0.0;
|
|
|
|
return sqrt (dx * dx + dy * dy);
|
|
}
|
|
|
|
static void
|
|
request_redraw_borders (EelCanvas *canvas,
|
|
Rect *update_rect,
|
|
int width)
|
|
{
|
|
eel_canvas_request_redraw (canvas,
|
|
update_rect->x0, update_rect->y0,
|
|
update_rect->x1, update_rect->y0 + width);
|
|
eel_canvas_request_redraw (canvas,
|
|
update_rect->x0, update_rect->y1-width,
|
|
update_rect->x1, update_rect->y1);
|
|
eel_canvas_request_redraw (canvas,
|
|
update_rect->x0, update_rect->y0,
|
|
update_rect->x0+width, update_rect->y1);
|
|
eel_canvas_request_redraw (canvas,
|
|
update_rect->x1-width, update_rect->y0,
|
|
update_rect->x1, update_rect->y1);
|
|
}
|
|
|
|
|
|
static void
|
|
eel_canvas_rect_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, gint flags)
|
|
{
|
|
EelCanvasRE *re;
|
|
double x1, y1, x2, y2;
|
|
int cx1, cy1, cx2, cy2;
|
|
int repaint_rects_count, i;
|
|
int width_pixels;
|
|
int width_lt, width_rb;
|
|
Rect update_rect, repaint_rects[4];
|
|
EelCanvasRectPrivate *priv;
|
|
|
|
eel_canvas_re_update_shared (item, i2w_dx, i2w_dy, flags);
|
|
|
|
re = EEL_CANVAS_RE (item);
|
|
priv = EEL_CANVAS_RECT (item)->priv;
|
|
|
|
x1 = re->x1 + i2w_dx;
|
|
y1 = re->y1 + i2w_dy;
|
|
x2 = re->x2 + i2w_dx;
|
|
y2 = re->y2 + i2w_dy;
|
|
|
|
eel_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1);
|
|
eel_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2);
|
|
|
|
update_rect = make_rect (cx1, cy1, cx2+1, cy2+1);
|
|
#if 0
|
|
eel_canvas_request_redraw (item->canvas,
|
|
update_rect.x0, update_rect.y0,
|
|
update_rect.x1, update_rect.y1);
|
|
eel_canvas_request_redraw (item->canvas,
|
|
priv->last_update_rect.x0, priv->last_update_rect.y0,
|
|
priv->last_update_rect.x1, priv->last_update_rect.y1);
|
|
#else
|
|
diff_rects (update_rect, priv->last_update_rect,
|
|
&repaint_rects_count, repaint_rects);
|
|
for (i = 0; i < repaint_rects_count; i++) {
|
|
eel_canvas_request_redraw (item->canvas,
|
|
repaint_rects[i].x0, repaint_rects[i].y0,
|
|
repaint_rects[i].x1, repaint_rects[i].y1);
|
|
}
|
|
#endif
|
|
priv->last_update_rect = update_rect;
|
|
|
|
if (re->outline_set) {
|
|
/* Outline and bounding box */
|
|
if (re->width_pixels)
|
|
width_pixels = (int) re->width;
|
|
else
|
|
width_pixels = (int) floor (re->width * re->item.canvas->pixels_per_unit + 0.5);
|
|
|
|
width_lt = width_pixels / 2;
|
|
width_rb = (width_pixels + 1) / 2;
|
|
|
|
cx1 -= width_lt;
|
|
cy1 -= width_lt;
|
|
cx2 += width_rb;
|
|
cy2 += width_rb;
|
|
|
|
update_rect = make_rect (cx1, cy1, cx2, cy2);
|
|
request_redraw_borders (item->canvas, &update_rect,
|
|
(width_lt + width_rb));
|
|
request_redraw_borders (item->canvas, &priv->last_outline_update_rect,
|
|
priv->last_outline_update_width);
|
|
priv->last_outline_update_rect = update_rect;
|
|
priv->last_outline_update_width = width_lt + width_rb;
|
|
|
|
item->x1 = cx1;
|
|
item->y1 = cy1;
|
|
item->x2 = cx2+1;
|
|
item->y2 = cy2+1;
|
|
} else {
|
|
item->x1 = cx1;
|
|
item->y1 = cy1;
|
|
item->x2 = cx2+1;
|
|
item->y2 = cy2+1;
|
|
}
|
|
}
|
|
|
|
/* Ellipse item */
|
|
|
|
|
|
static void eel_canvas_ellipse_class_init (EelCanvasEllipseClass *class);
|
|
|
|
static void eel_canvas_ellipse_draw (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose);
|
|
static double eel_canvas_ellipse_point (EelCanvasItem *item, double x, double y, int cx, int cy,
|
|
EelCanvasItem **actual_item);
|
|
|
|
|
|
GType
|
|
eel_canvas_ellipse_get_type (void)
|
|
{
|
|
static GType ellipse_type = 0;
|
|
|
|
if (!ellipse_type) {
|
|
GTypeInfo ellipse_info = {
|
|
sizeof (EelCanvasEllipseClass),
|
|
(GBaseInitFunc) NULL,
|
|
(GBaseFinalizeFunc) NULL,
|
|
(GClassInitFunc) eel_canvas_ellipse_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (EelCanvasEllipse),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) NULL
|
|
|
|
};
|
|
|
|
ellipse_type = g_type_register_static (eel_canvas_re_get_type (),
|
|
"EelCanvasEllipse",
|
|
&ellipse_info,
|
|
0);
|
|
}
|
|
|
|
return ellipse_type;
|
|
}
|
|
|
|
static void
|
|
eel_canvas_ellipse_class_init (EelCanvasEllipseClass *class)
|
|
{
|
|
EelCanvasItemClass *item_class;
|
|
|
|
item_class = (EelCanvasItemClass *) class;
|
|
|
|
item_class->draw = eel_canvas_ellipse_draw;
|
|
item_class->point = eel_canvas_ellipse_point;
|
|
item_class->update = eel_canvas_ellipse_update;
|
|
}
|
|
|
|
static void
|
|
eel_canvas_ellipse_draw (EelCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose)
|
|
{
|
|
EelCanvasRE *re;
|
|
int x1, y1, x2, y2;
|
|
double i2w_dx, i2w_dy;
|
|
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
/* Get canvas pixel coordinates */
|
|
|
|
i2w_dx = 0.0;
|
|
i2w_dy = 0.0;
|
|
eel_canvas_item_i2w (item, &i2w_dx, &i2w_dy);
|
|
|
|
eel_canvas_w2c (item->canvas,
|
|
re->x1 + i2w_dx,
|
|
re->y1 + i2w_dy,
|
|
&x1, &y1);
|
|
eel_canvas_w2c (item->canvas,
|
|
re->x2 + i2w_dx,
|
|
re->y2 + i2w_dy,
|
|
&x2, &y2);
|
|
|
|
if (re->fill_set) {
|
|
if (re->fill_stipple)
|
|
eel_canvas_set_stipple_origin (item->canvas, re->fill_gc);
|
|
|
|
gdk_draw_arc (drawable,
|
|
re->fill_gc,
|
|
TRUE,
|
|
x1,
|
|
y1,
|
|
x2 - x1,
|
|
y2 - y1,
|
|
0 * 64,
|
|
360 * 64);
|
|
}
|
|
|
|
if (re->outline_set) {
|
|
if (re->outline_stipple)
|
|
eel_canvas_set_stipple_origin (item->canvas, re->outline_gc);
|
|
|
|
gdk_draw_arc (drawable,
|
|
re->outline_gc,
|
|
FALSE,
|
|
x1,
|
|
y1,
|
|
x2 - x1,
|
|
y2 - y1,
|
|
0 * 64,
|
|
360 * 64);
|
|
}
|
|
}
|
|
|
|
static double
|
|
eel_canvas_ellipse_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item)
|
|
{
|
|
EelCanvasRE *re;
|
|
double dx, dy;
|
|
double scaled_dist;
|
|
double outline_dist;
|
|
double center_dist;
|
|
double width;
|
|
double a, b;
|
|
double diamx, diamy;
|
|
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
*actual_item = item;
|
|
|
|
if (re->outline_set) {
|
|
if (re->width_pixels)
|
|
width = re->width / item->canvas->pixels_per_unit;
|
|
else
|
|
width = re->width;
|
|
} else
|
|
width = 0.0;
|
|
|
|
/* Compute the distance between the center of the ellipse and the point, with the ellipse
|
|
* considered as being scaled to a circle.
|
|
*/
|
|
|
|
dx = x - (re->x1 + re->x2) / 2.0;
|
|
dy = y - (re->y1 + re->y2) / 2.0;
|
|
center_dist = sqrt (dx * dx + dy * dy);
|
|
|
|
a = dx / ((re->x2 + width - re->x1) / 2.0);
|
|
b = dy / ((re->y2 + width - re->y1) / 2.0);
|
|
scaled_dist = sqrt (a * a + b * b);
|
|
|
|
/* If the scaled distance is greater than 1, then we are outside. Compute the distance from
|
|
* the point to the edge of the circle, then scale back to the original un-scaled coordinate
|
|
* system.
|
|
*/
|
|
|
|
if (scaled_dist > 1.0)
|
|
return (center_dist / scaled_dist) * (scaled_dist - 1.0);
|
|
|
|
/* We are inside the outer edge of the ellipse. If it is filled, then we are "inside".
|
|
* Otherwise, do the same computation as above, but also check whether we are inside the
|
|
* outline.
|
|
*/
|
|
|
|
if (re->fill_set)
|
|
return 0.0;
|
|
|
|
if (scaled_dist > EEL_CANVAS_EPSILON)
|
|
outline_dist = (center_dist / scaled_dist) * (1.0 - scaled_dist) - width;
|
|
else {
|
|
/* Handle very small distance */
|
|
|
|
diamx = re->x2 - re->x1;
|
|
diamy = re->y2 - re->y1;
|
|
|
|
if (diamx < diamy)
|
|
outline_dist = (diamx - width) / 2.0;
|
|
else
|
|
outline_dist = (diamy - width) / 2.0;
|
|
}
|
|
|
|
if (outline_dist < 0.0)
|
|
return 0.0;
|
|
|
|
return outline_dist;
|
|
}
|
|
|
|
static void
|
|
eel_canvas_ellipse_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, gint flags)
|
|
{
|
|
EelCanvasRE *re;
|
|
double x0, y0, x1, y1;
|
|
|
|
#ifdef VERBOSE
|
|
g_print ("eel_canvas_sllipse_update item %x\n", item);
|
|
#endif
|
|
|
|
eel_canvas_re_update_shared (item, i2w_dx, i2w_dy, flags);
|
|
re = EEL_CANVAS_RE (item);
|
|
|
|
get_bounds (re, &x0, &y0, &x1, &y1);
|
|
eel_canvas_update_bbox (item, x0, y0, x1, y1);
|
|
}
|
|
|
|
static int
|
|
rect_empty (const Rect *src) {
|
|
return (src->x1 <= src->x0 || src->y1 <= src->y0);
|
|
}
|
|
|
|
static Rect
|
|
make_rect (int x0, int y0, int x1, int y1)
|
|
{
|
|
Rect r;
|
|
|
|
r.x0 = x0;
|
|
r.y0 = y0;
|
|
r.x1 = x1;
|
|
r.y1 = y1;
|
|
return r;
|
|
}
|
|
|
|
static gboolean
|
|
rects_intersect (Rect r1, Rect r2)
|
|
{
|
|
if (r1.x0 >= r2.x1) {
|
|
return FALSE;
|
|
}
|
|
if (r2.x0 >= r1.x1) {
|
|
return FALSE;
|
|
}
|
|
if (r1.y0 >= r2.y1) {
|
|
return FALSE;
|
|
}
|
|
if (r2.y0 >= r1.y1) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
diff_rects_guts (Rect ra, Rect rb, int *count, Rect result[4])
|
|
{
|
|
if (ra.x0 < rb.x0) {
|
|
result[(*count)++] = make_rect (ra.x0, ra.y0, rb.x0, ra.y1);
|
|
}
|
|
if (ra.y0 < rb.y0) {
|
|
result[(*count)++] = make_rect (ra.x0, ra.y0, ra.x1, rb.y0);
|
|
}
|
|
if (ra.x1 < rb.x1) {
|
|
result[(*count)++] = make_rect (ra.x1, rb.y0, rb.x1, rb.y1);
|
|
}
|
|
if (ra.y1 < rb.y1) {
|
|
result[(*count)++] = make_rect (rb.x0, ra.y1, rb.x1, rb.y1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
diff_rects (Rect r1, Rect r2, int *count, Rect result[4])
|
|
{
|
|
g_assert (count != NULL);
|
|
g_assert (result != NULL);
|
|
|
|
*count = 0;
|
|
|
|
if (rects_intersect (r1, r2)) {
|
|
diff_rects_guts (r1, r2, count, result);
|
|
diff_rects_guts (r2, r1, count, result);
|
|
} else {
|
|
if (!rect_empty (&r1)) {
|
|
result[(*count)++] = r1;
|
|
}
|
|
if (!rect_empty (&r2)) {
|
|
result[(*count)++] = r2;
|
|
}
|
|
}
|
|
}
|