Logo Search packages:      
Sourcecode: ardour version File versions  Download package

gtk-canvas-polygon.c

/* Polygon item type for GtkCanvas widget
 *
 * GtkCanvas 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.
 *
 * Copyright (C) 1998 The Free Software Foundation
 *
 * Author: Federico Mena <federico@nuclecu.unam.mx>
 */

#include <math.h>
#include <string.h>
#include "libart_lgpl/art_vpath.h"
#include "libart_lgpl/art_svp.h"
#include "libart_lgpl/art_svp_vpath.h"
#include "libart_lgpl/art_svp_vpath_stroke.h"
#include "gtk-canvas-polygon.h"
#include "gtk-canvas-util.h"
#include "gtk-canvastypebuiltins.h"


#define NUM_STATIC_POINTS 256 /* Number of static points to use to avoid allocating arrays */


#define GROW_BOUNDS(bx1, by1, bx2, by2, x, y) { \
      if (x < bx1)                        \
            bx1 = x;                \
                                    \
      if (x > bx2)                        \
            bx2 = x;                \
                                    \
      if (y < by1)                        \
            by1 = y;                \
                                    \
      if (y > by2)                        \
            by2 = y;                \
}


enum {
      ARG_0,
      ARG_POINTS,
      ARG_FILL_COLOR,
      ARG_FILL_COLOR_GDK,
      ARG_FILL_COLOR_RGBA,
      ARG_OUTLINE_COLOR,
      ARG_OUTLINE_COLOR_GDK,
      ARG_OUTLINE_COLOR_RGBA,
      ARG_FILL_STIPPLE,
      ARG_OUTLINE_STIPPLE,
      ARG_WIDTH_PIXELS,
      ARG_WIDTH_UNITS
};


static void gtk_canvas_polygon_class_init (GtkCanvasPolygonClass *class);
static void gtk_canvas_polygon_init       (GtkCanvasPolygon      *poly);
static void gtk_canvas_polygon_destroy    (GtkObject               *object);
static void gtk_canvas_polygon_set_arg    (GtkObject               *object,
                                   GtkArg                  *arg,
                                   guint                    arg_id);
static void gtk_canvas_polygon_get_arg    (GtkObject               *object,
                                   GtkArg                  *arg,
                                   guint                    arg_id);

static void   gtk_canvas_polygon_update      (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
static void   gtk_canvas_polygon_realize     (GtkCanvasItem *item);
static void   gtk_canvas_polygon_unrealize   (GtkCanvasItem *item);
static void   gtk_canvas_polygon_draw        (GtkCanvasItem *item, GdkDrawable *drawable,
                                    int x, int y, int width, int height);
static double gtk_canvas_polygon_point       (GtkCanvasItem *item, double x, double y,
                                    int cx, int cy, GtkCanvasItem **actual_item);
static void   gtk_canvas_polygon_translate   (GtkCanvasItem *item, double dx, double dy);
static void   gtk_canvas_polygon_bounds      (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
static void   gtk_canvas_polygon_render      (GtkCanvasItem *item, GtkCanvasBuf *buf);


static GtkCanvasItemClass *parent_class;


GtkType
gtk_canvas_polygon_get_type (void)
{
      static GtkType polygon_type = 0;

      if (!polygon_type) {
            GtkTypeInfo polygon_info = {
                  "GtkCanvasPolygon",
                  sizeof (GtkCanvasPolygon),
                  sizeof (GtkCanvasPolygonClass),
                  (GtkClassInitFunc) gtk_canvas_polygon_class_init,
                  (GtkObjectInitFunc) gtk_canvas_polygon_init,
                  NULL, /* reserved_1 */
                  NULL, /* reserved_2 */
                  (GtkClassInitFunc) NULL
            };

            polygon_type = gtk_type_unique (gtk_canvas_item_get_type (), &polygon_info);
      }

      return polygon_type;
}

static void
gtk_canvas_polygon_class_init (GtkCanvasPolygonClass *class)
{
      GtkObjectClass *object_class;
      GtkCanvasItemClass *item_class;

      object_class = (GtkObjectClass *) class;
      item_class = (GtkCanvasItemClass *) class;

      parent_class = gtk_type_class (gtk_canvas_item_get_type ());

      gtk_object_add_arg_type ("GtkCanvasPolygon::points", GTK_TYPE_CANVAS_POINTS, GTK_ARG_READWRITE, ARG_POINTS);
      gtk_object_add_arg_type ("GtkCanvasPolygon::fill_color", GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FILL_COLOR);
      gtk_object_add_arg_type ("GtkCanvasPolygon::fill_color_gdk", GTK_TYPE_GDK_COLOR, GTK_ARG_READWRITE, ARG_FILL_COLOR_GDK);
      gtk_object_add_arg_type ("GtkCanvasPolygon::fill_color_rgba", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_FILL_COLOR_RGBA);
      gtk_object_add_arg_type ("GtkCanvasPolygon::outline_color", GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_OUTLINE_COLOR);
      gtk_object_add_arg_type ("GtkCanvasPolygon::outline_color_gdk", GTK_TYPE_GDK_COLOR, GTK_ARG_READWRITE, ARG_OUTLINE_COLOR_GDK);
      gtk_object_add_arg_type ("GtkCanvasPolygon::outline_color_rgba", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_OUTLINE_COLOR_RGBA);
      gtk_object_add_arg_type ("GtkCanvasPolygon::fill_stipple", GTK_TYPE_GDK_WINDOW, GTK_ARG_READWRITE, ARG_FILL_STIPPLE);
      gtk_object_add_arg_type ("GtkCanvasPolygon::outline_stipple", GTK_TYPE_GDK_WINDOW, GTK_ARG_READWRITE, ARG_OUTLINE_STIPPLE);
      gtk_object_add_arg_type ("GtkCanvasPolygon::width_pixels", GTK_TYPE_UINT, GTK_ARG_WRITABLE, ARG_WIDTH_PIXELS);
      gtk_object_add_arg_type ("GtkCanvasPolygon::width_units", GTK_TYPE_DOUBLE, GTK_ARG_WRITABLE, ARG_WIDTH_UNITS);

      object_class->destroy = gtk_canvas_polygon_destroy;
      object_class->set_arg = gtk_canvas_polygon_set_arg;
      object_class->get_arg = gtk_canvas_polygon_get_arg;

      item_class->update = gtk_canvas_polygon_update;
      item_class->realize = gtk_canvas_polygon_realize;
      item_class->unrealize = gtk_canvas_polygon_unrealize;
      item_class->draw = gtk_canvas_polygon_draw;
      item_class->point = gtk_canvas_polygon_point;
      item_class->translate = gtk_canvas_polygon_translate;
      item_class->bounds = gtk_canvas_polygon_bounds;
      item_class->render = gtk_canvas_polygon_render;
}

static void
gtk_canvas_polygon_init (GtkCanvasPolygon *poly)
{
      poly->width = 0.0;
}

static void
gtk_canvas_polygon_destroy (GtkObject *object)
{
      GtkCanvasPolygon *poly;

      g_return_if_fail (object != NULL);
      g_return_if_fail (GTK_CANVAS_IS_CANVAS_POLYGON (object));

      poly = GTK_CANVAS_POLYGON (object);

      if (poly->coords)
            g_free (poly->coords);

      if (poly->fill_stipple)
            gdk_bitmap_unref (poly->fill_stipple);

      if (poly->outline_stipple)
            gdk_bitmap_unref (poly->outline_stipple);

      if (poly->fill_svp)
            art_svp_free (poly->fill_svp);

      if (poly->outline_svp)
            art_svp_free (poly->outline_svp);

      if (GTK_OBJECT_CLASS (parent_class)->destroy)
            (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}

/* Computes the bounding box of the polygon.  Assumes that the number of points in the polygon is
 * not zero.
 */
static void
get_bounds (GtkCanvasPolygon *poly, double *bx1, double *by1, double *bx2, double *by2)
{
      double *coords;
      double x1, y1, x2, y2;
      double width;
      int i;

      /* Compute bounds of vertices */

      x1 = x2 = poly->coords[0];
      y1 = y2 = poly->coords[1];

      for (i = 1, coords = poly->coords + 2; i < poly->num_points; i++, coords += 2) {
            GROW_BOUNDS (x1, y1, x2, y2, coords[0], coords[1]);
      }

      /* Add outline width */

      if (poly->width_pixels)
            width = poly->width / poly->item.canvas->pixels_per_unit;
      else
            width = poly->width;

      width /= 2.0;

      x1 -= width;
      y1 -= width;
      x2 += width;
      y2 += width;

      /* Done */

      *bx1 = x1;
      *by1 = y1;
      *bx2 = x2;
      *by2 = y2;
}

/* Computes the bounding box of the polygon, in canvas coordinates.  Assumes that the number of points in the polygon is
 * not zero.
 */
static void
get_bounds_canvas (GtkCanvasPolygon *poly, double *bx1, double *by1, double *bx2, double *by2, double affine[6])
{
      GtkCanvasItem *item;
      ArtDRect bbox_world;
      ArtDRect bbox_canvas;

      item = GTK_CANVAS_ITEM (poly);

      get_bounds (poly, &bbox_world.x0, &bbox_world.y0, &bbox_world.x1, &bbox_world.y1);

      art_drect_affine_transform (&bbox_canvas, &bbox_world, affine);
      /* include 1 pixel of fudge */
      *bx1 = bbox_canvas.x0 - 1;
      *by1 = bbox_canvas.y0 - 1;
      *bx2 = bbox_canvas.x1 + 1;
      *by2 = bbox_canvas.y1 + 1;
}

/* Recalculates the canvas bounds for the polygon */
static void
recalc_bounds (GtkCanvasPolygon *poly)
{
      GtkCanvasItem *item;
      double x1, y1, x2, y2;
      int cx1, cy1, cx2, cy2;
      double dx, dy;

      item = GTK_CANVAS_ITEM (poly);

      if (poly->num_points == 0) {
            item->x1 = item->y1 = item->x2 = item->y2 = 0;
            return;
      }

      /* Get bounds in world coordinates */

      get_bounds (poly, &x1, &y1, &x2, &y2);

      /* Convert to canvas pixel coords */

      dx = dy = 0.0;
      gtk_canvas_item_i2w (item, &dx, &dy);

      gtk_canvas_w2c (item->canvas, x1 + dx, y1 + dy, &cx1, &cy1);
      gtk_canvas_w2c (item->canvas, x2 + dx, y2 + dy, &cx2, &cy2);
      item->x1 = cx1;
      item->y1 = cy1;
      item->x2 = cx2;
      item->y2 = cy2;

      /* Some safety fudging */

      item->x1--;
      item->y1--;
      item->x2++;
      item->y2++;

      gtk_canvas_group_child_bounds (GTK_CANVAS_GROUP (item->parent), item);
}

/* Sets the points of the polygon item to the specified ones.  If needed, it will add a point to
 * close the polygon.
 */
static void
set_points (GtkCanvasPolygon *poly, GtkCanvasPoints *points)
{
      int duplicate;

      /* See if we need to duplicate the first point */

      duplicate = ((points->coords[0] != points->coords[2 * points->num_points - 2])
                 || (points->coords[1] != points->coords[2 * points->num_points - 1]));

      if (duplicate)
            poly->num_points = points->num_points + 1;
      else
            poly->num_points = points->num_points;

      poly->coords = g_new (double, 2 * poly->num_points);
      memcpy (poly->coords, points->coords, 2 * points->num_points * sizeof (double));

      if (duplicate) {
            poly->coords[2 * poly->num_points - 2] = poly->coords[0];
            poly->coords[2 * poly->num_points - 1] = poly->coords[1];
      }
}

/* 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)
            gdk_bitmap_unref (*internal_stipple);

      *internal_stipple = stipple;
      if (stipple && !reconfigure)
            gdk_bitmap_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 polygon and set it in its GC */
static void
set_outline_gc_width (GtkCanvasPolygon *poly)
{
      int width;

      if (!poly->outline_gc)
            return;

      if (poly->width_pixels)
            width = (int) poly->width;
      else
            width = (int) (poly->width * poly->item.canvas->pixels_per_unit + 0.5);

      gdk_gc_set_line_attributes (poly->outline_gc, width,
                            GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
}

static void
gtk_canvas_polygon_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
      GtkCanvasItem *item;
      GtkCanvasPolygon *poly;
      GtkCanvasPoints *points;
      GdkColor color = { 0, 0, 0, 0, };
      GdkColor *pcolor;
      int have_pixel;

      item = GTK_CANVAS_ITEM (object);
      poly = GTK_CANVAS_POLYGON (object);
      have_pixel = FALSE;

      switch (arg_id) {
      case ARG_POINTS:
            points = GTK_VALUE_POINTER (*arg);

            if (poly->coords) {
                  g_free (poly->coords);
                  poly->coords = NULL;
            }

            if (!points)
                  poly->num_points = 0;
            else
                  set_points (poly, points);

            gtk_canvas_item_request_update (item);
            break;

        case ARG_FILL_COLOR:
      case ARG_FILL_COLOR_GDK:
      case ARG_FILL_COLOR_RGBA:
            switch (arg_id) {
            case ARG_FILL_COLOR:
                  if (GTK_VALUE_STRING (*arg) &&
                      gdk_color_parse (GTK_VALUE_STRING (*arg), &color))
                        poly->fill_set = TRUE;
                  else
                        poly->fill_set = FALSE;

                  poly->fill_color = ((color.red & 0xff00) << 16 |
                                  (color.green & 0xff00) << 8 |
                                  (color.blue & 0xff00) |
                                  0xff);
                  break;

            case ARG_FILL_COLOR_GDK:
                  pcolor = GTK_VALUE_BOXED (*arg);
                  poly->fill_set = pcolor != NULL;

                  if (pcolor) {
                        color = *pcolor;
                        gdk_color_context_query_color (item->canvas->cc, &color);
                        have_pixel = TRUE;
                  }

                  poly->fill_color = ((color.red & 0xff00) << 16 |
                                  (color.green & 0xff00) << 8 |
                                  (color.blue & 0xff00) |
                                  0xff);
                  break;

            case ARG_FILL_COLOR_RGBA:
                  poly->fill_set = TRUE;
                  poly->fill_color = GTK_VALUE_UINT (*arg);
                  break;
            }
#ifdef VERBOSE
            g_print ("poly fill color = %08x\n", poly->fill_color);
#endif
            if (have_pixel)
                  poly->fill_pixel = color.pixel;
            else
                  poly->fill_pixel = gtk_canvas_get_color_pixel (item->canvas,
                                                       poly->fill_color);

            set_gc_foreground (poly->fill_gc, poly->fill_pixel);
                gtk_canvas_item_request_redraw_svp (item, poly->fill_svp);
            break;

        case ARG_OUTLINE_COLOR:
      case ARG_OUTLINE_COLOR_GDK:
      case ARG_OUTLINE_COLOR_RGBA:
            switch (arg_id) {
            case ARG_OUTLINE_COLOR:
                  if (GTK_VALUE_STRING (*arg) &&
                      gdk_color_parse (GTK_VALUE_STRING (*arg), &color))
                        poly->outline_set = TRUE;
                  else
                        poly->outline_set = FALSE;

                  poly->outline_color = ((color.red & 0xff00) << 16 |
                                     (color.green & 0xff00) << 8 |
                                     (color.blue & 0xff00) |
                                     0xff);
                  break;

            case ARG_OUTLINE_COLOR_GDK:
                  pcolor = GTK_VALUE_BOXED (*arg);
                  poly->outline_set = pcolor != NULL;

                  if (pcolor) {
                        color = *pcolor;
                        gdk_color_context_query_color (item->canvas->cc, &color);
                        have_pixel = TRUE;
                  }

                  poly->outline_color = ((color.red & 0xff00) << 16 |
                                     (color.green & 0xff00) << 8 |
                                     (color.blue & 0xff00) |
                                     0xff);
                  break;

            case ARG_OUTLINE_COLOR_RGBA:
                  poly->outline_set = TRUE;
                  poly->outline_color = GTK_VALUE_UINT (*arg);
                  break;
            }
#ifdef VERBOSE
            g_print ("poly outline color = %08x\n", poly->outline_color);
#endif
            if (have_pixel)
                  poly->outline_pixel = color.pixel;
            else
                  poly->outline_pixel = gtk_canvas_get_color_pixel (item->canvas,
                                                          poly->outline_color);

            set_gc_foreground (poly->outline_gc, poly->outline_pixel);
                gtk_canvas_item_request_redraw_svp (item, poly->outline_svp);
            break;

      case ARG_FILL_STIPPLE:
            set_stipple (poly->fill_gc, &poly->fill_stipple, GTK_VALUE_BOXED (*arg), FALSE);
            gtk_canvas_item_request_update (item);
            break;

      case ARG_OUTLINE_STIPPLE:
            set_stipple (poly->outline_gc, &poly->outline_stipple, GTK_VALUE_BOXED (*arg), FALSE);
            gtk_canvas_item_request_update (item);
            break;

      case ARG_WIDTH_PIXELS:
            poly->width = GTK_VALUE_UINT (*arg);
            poly->width_pixels = TRUE;
            set_outline_gc_width (poly);
#ifdef OLD_XFORM
            recalc_bounds (poly);
#else
            gtk_canvas_item_request_update (item);
#endif
            break;

      case ARG_WIDTH_UNITS:
            poly->width = fabs (GTK_VALUE_DOUBLE (*arg));
            poly->width_pixels = FALSE;
            set_outline_gc_width (poly);
#ifdef OLD_XFORM
            recalc_bounds (poly);
#else
            gtk_canvas_item_request_update (item);
#endif
            break;

      default:
            break;
      }
}

/* Allocates a GdkColor structure filled with the specified pixel, and puts it into the specified
 * arg for returning it in the get_arg method.
 */
static void
get_color_arg (GtkCanvasPolygon *poly, gulong pixel, GtkArg *arg)
{
      GdkColor *color;

      color = g_new (GdkColor, 1);
      color->pixel = pixel;
      gdk_color_context_query_color (poly->item.canvas->cc, color);
      GTK_VALUE_BOXED (*arg) = color;
}

static void
gtk_canvas_polygon_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
      GtkCanvasPolygon *poly;
      GtkCanvasPoints *points;

      poly = GTK_CANVAS_POLYGON (object);

      switch (arg_id) {
      case ARG_POINTS:
            if (poly->num_points != 0) {
                  points = gtk_canvas_points_new (poly->num_points);
                  memcpy (points->coords, poly->coords, 2 * poly->num_points * sizeof (double));
                  GTK_VALUE_POINTER (*arg) = points;
            } else
                  GTK_VALUE_POINTER (*arg) = NULL;
            break;

      case ARG_FILL_COLOR_GDK:
            get_color_arg (poly, poly->fill_pixel, arg);
            break;

      case ARG_OUTLINE_COLOR_GDK:
            get_color_arg (poly, poly->outline_pixel, arg);
            break;

      case ARG_FILL_COLOR_RGBA:
            GTK_VALUE_UINT (*arg) = poly->fill_color;
            break;

      case ARG_OUTLINE_COLOR_RGBA:
            GTK_VALUE_UINT (*arg) = poly->outline_color;
            break;

      case ARG_FILL_STIPPLE:
            GTK_VALUE_BOXED (*arg) = poly->fill_stipple;
            break;

      case ARG_OUTLINE_STIPPLE:
            GTK_VALUE_BOXED (*arg) = poly->outline_stipple;
            break;

      default:
            arg->type = GTK_TYPE_INVALID;
            break;
      }
}

static void
gtk_canvas_polygon_render (GtkCanvasItem *item,
                       GtkCanvasBuf *buf)
{
      GtkCanvasPolygon *poly;

      poly = GTK_CANVAS_POLYGON (item);

      if (poly->fill_svp != NULL) {
            gtk_canvas_render_svp (buf, poly->fill_svp, poly->fill_color);
      }

      if (poly->outline_svp != NULL)
            gtk_canvas_render_svp (buf, poly->outline_svp, poly->outline_color);
}

static void
gtk_canvas_polygon_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
{
      GtkCanvasPolygon *poly;
      ArtVpath *vpath;
      int i;
      ArtPoint pi, pc;
      ArtSVP *svp;
      double width;
      double x1, y1, x2, y2;
      int twice;

      poly = GTK_CANVAS_POLYGON (item);

      if (parent_class->update)
            (* parent_class->update) (item, affine, clip_path, flags);

      if (item->canvas->aa) {
            gtk_canvas_item_reset_bounds (item);

            vpath = art_new (ArtVpath, poly->num_points + 2);

            for (i = 0; i < poly->num_points; i++) {
                  pi.x = poly->coords[i * 2];
                  pi.y = poly->coords[i * 2 + 1];
                  art_affine_point (&pc, &pi, affine);
                  vpath[i].code = i == 0 ? ART_MOVETO : ART_LINETO;
                  vpath[i].x = pc.x;
                  vpath[i].y = pc.y;
            }
            vpath[i].code = ART_END;
            vpath[i].x = 0;
            vpath[i].y = 0;

            if (poly->fill_set) {
              again:
                  svp = art_svp_from_vpath (vpath);
                  twice = (poly->fill_svp == 0);
                  gtk_canvas_item_update_svp_clip (item, &poly->fill_svp, svp, clip_path);
                  if (twice) {
                        goto again;
                  }
            }

            if (poly->outline_set) {
                  if (poly->width_pixels)
                        width = poly->width;
                  else
                        width = poly->width * item->canvas->pixels_per_unit;

                  if (width < 0.5)
                        width = 0.5;

              again2:
                  svp = art_svp_vpath_stroke (vpath,
                                        ART_PATH_STROKE_JOIN_ROUND,
                                        ART_PATH_STROKE_CAP_ROUND,
                                        width,
                                        4,
                                        0.5);

                  twice = (poly->outline_svp == 0);
                  gtk_canvas_item_update_svp_clip (item, &poly->outline_svp, svp, clip_path);
                  if (twice) {
                        goto again2;
                  }
            }
            art_free (vpath);

      } else {
            set_outline_gc_width (poly);
            set_gc_foreground (poly->fill_gc, poly->fill_pixel);
            set_gc_foreground (poly->outline_gc, poly->outline_pixel);
            set_stipple (poly->fill_gc, &poly->fill_stipple, poly->fill_stipple, TRUE);
            set_stipple (poly->outline_gc, &poly->outline_stipple, poly->outline_stipple, TRUE);

            get_bounds_canvas (poly, &x1, &y1, &x2, &y2, affine);
            gtk_canvas_update_bbox (item, x1, y1, x2, y2);
      }
}

static void
gtk_canvas_polygon_realize (GtkCanvasItem *item)
{
      GtkCanvasPolygon *poly;

      poly = GTK_CANVAS_POLYGON (item);

      if (parent_class->realize)
            (* parent_class->realize) (item);

      poly->fill_gc = gdk_gc_new (item->canvas->layout.bin_window);
      poly->outline_gc = gdk_gc_new (item->canvas->layout.bin_window);

#ifdef OLD_XFORM
      (* GTK_CANVAS_ITEM_CLASS (item->object.klass)->update) (item, NULL, NULL, 0);
#endif
}

static void
gtk_canvas_polygon_unrealize (GtkCanvasItem *item)
{
      GtkCanvasPolygon *poly;

      poly = GTK_CANVAS_POLYGON (item);

      gdk_gc_unref (poly->fill_gc);
      poly->fill_gc = NULL;
      gdk_gc_unref (poly->outline_gc);
      poly->outline_gc = NULL;

      if (parent_class->unrealize)
            (* parent_class->unrealize) (item);
}

/* Converts an array of world coordinates into an array of canvas pixel coordinates.  Takes in the
 * item->world deltas and the drawable deltas.
 */
static void
item_to_canvas (GtkCanvas *canvas, double *item_coords, GdkPoint *canvas_coords, int num_points,
            double i2c[6])
{
      int i;
      ArtPoint pi, pc;

#ifdef VERBOSE
      {
            char str[128];
            art_affine_to_string (str, i2c);
            g_print ("polygon item_to_canvas %s\n", str);
      }
#endif

      for (i = 0; i < num_points; i++) {
            pi.x = item_coords[i * 2];
            pi.y = item_coords[i * 2 + 1];
            art_affine_point (&pc, &pi, i2c);
            canvas_coords->x = floor (pc.x + 0.5);
            canvas_coords->y = floor (pc.y + 0.5);
            canvas_coords++;
      }
}

static void
gtk_canvas_polygon_draw (GtkCanvasItem *item, GdkDrawable *drawable,
                     int x, int y, int width, int height)
{
      GtkCanvasPolygon *poly;
      GdkPoint static_points[NUM_STATIC_POINTS];
      GdkPoint *points;
      double i2c[6];

      poly = GTK_CANVAS_POLYGON (item);

      if (poly->num_points == 0)
            return;

      /* Build array of canvas pixel coordinates */

      if (poly->num_points <= NUM_STATIC_POINTS)
            points = static_points;
      else
            points = g_new (GdkPoint, poly->num_points);

      gtk_canvas_item_i2c_affine (item, i2c);

      i2c[4] -= x;
      i2c[5] -= y;

      item_to_canvas (item->canvas, poly->coords, points, poly->num_points, i2c);

      if (poly->fill_set) {
            if (poly->fill_stipple)
                  gtk_canvas_set_stipple_origin (item->canvas, poly->fill_gc);

            gdk_draw_polygon (drawable, poly->fill_gc, TRUE, points, poly->num_points);
      }

      if (poly->outline_set) {
            if (poly->outline_stipple)
                  gtk_canvas_set_stipple_origin (item->canvas, poly->outline_gc);

            gdk_draw_polygon (drawable, poly->outline_gc, FALSE, points, poly->num_points);
      }

      /* Done */

      if (points != static_points)
            g_free (points);
}

static double
gtk_canvas_polygon_point (GtkCanvasItem *item, double x, double y,
                      int cx, int cy, GtkCanvasItem **actual_item)
{
      GtkCanvasPolygon *poly;
      double dist;
      double width;

      poly = GTK_CANVAS_POLYGON (item);

      *actual_item = item;

      dist = gtk_canvas_polygon_to_point (poly->coords, poly->num_points, x, y);

      if (poly->outline_set) {
            if (poly->width_pixels)
                  width = poly->width / item->canvas->pixels_per_unit;
            else
                  width = poly->width;

            dist -= width / 2.0;

            if (dist < 0.0)
                  dist = 0.0;
      }

      return dist;
}

static void
gtk_canvas_polygon_translate (GtkCanvasItem *item, double dx, double dy)
{
      GtkCanvasPolygon *poly;
      int i;
      double *coords;

      poly = GTK_CANVAS_POLYGON (item);

      for (i = 0, coords = poly->coords; i < poly->num_points; i++, coords += 2) {
            coords[0] += dx;
            coords[1] += dy;
      }

      recalc_bounds (poly);
}

static void
gtk_canvas_polygon_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
      GtkCanvasPolygon *poly;

      g_return_if_fail (item != NULL);
      g_return_if_fail (GTK_CANVAS_IS_CANVAS_POLYGON (item));

      poly = GTK_CANVAS_POLYGON (item);

      if (poly->num_points == 0) {
            *x1 = *y1 = *x2 = *y2 = 0.0;
            return;
      }

      get_bounds (poly, x1, y1, x2, y2);
}

Generated by  Doxygen 1.6.0   Back to index