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

gtk-canvas-widget.c

/* Widget 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 <gtk/gtksignal.h>
#include "gtk-canvas-widget.h"

enum {
      ARG_0,
      ARG_WIDGET,
      ARG_X,
      ARG_Y,
      ARG_WIDTH,
      ARG_HEIGHT,
      ARG_ANCHOR,
      ARG_SIZE_PIXELS
};


static void gtk_canvas_widget_class_init (GtkCanvasWidgetClass *class);
static void gtk_canvas_widget_init       (GtkCanvasWidget      *witem);
static void gtk_canvas_widget_destroy    (GtkObject              *object);
static void gtk_canvas_widget_set_arg    (GtkObject              *object,
                                  GtkArg                 *arg,
                                  guint                   arg_id);
static void gtk_canvas_widget_get_arg    (GtkObject              *object,
                                  GtkArg                 *arg,
                                  guint                   arg_id);

static void   gtk_canvas_widget_update      (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
static double gtk_canvas_widget_point       (GtkCanvasItem *item, double x, double y,
                                     int cx, int cy, GtkCanvasItem **actual_item);
static void   gtk_canvas_widget_translate   (GtkCanvasItem *item, double dx, double dy);
static void   gtk_canvas_widget_bounds      (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2);

static void gtk_canvas_widget_render (GtkCanvasItem *item,
                              GtkCanvasBuf *buf);
static void gtk_canvas_widget_draw (GtkCanvasItem *item,
                              GdkDrawable *drawable,
                              int x, int y,
                              int width, int height);

static GtkCanvasItemClass *parent_class;


GtkType
gtk_canvas_widget_get_type (void)
{
      static GtkType witem_type = 0;

      if (!witem_type) {
            GtkTypeInfo witem_info = {
                  "GtkCanvasWidget",
                  sizeof (GtkCanvasWidget),
                  sizeof (GtkCanvasWidgetClass),
                  (GtkClassInitFunc) gtk_canvas_widget_class_init,
                  (GtkObjectInitFunc) gtk_canvas_widget_init,
                  NULL, /* reserved_1 */
                  NULL, /* reserved_2 */
                  (GtkClassInitFunc) NULL
            };

            witem_type = gtk_type_unique (gtk_canvas_item_get_type (), &witem_info);
      }

      return witem_type;
}

static void
gtk_canvas_widget_class_init (GtkCanvasWidgetClass *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 ("GtkCanvasWidget::widget", GTK_TYPE_OBJECT, GTK_ARG_READWRITE, ARG_WIDGET);
      gtk_object_add_arg_type ("GtkCanvasWidget::x", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X);
      gtk_object_add_arg_type ("GtkCanvasWidget::y", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y);
      gtk_object_add_arg_type ("GtkCanvasWidget::width", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH);
      gtk_object_add_arg_type ("GtkCanvasWidget::height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT);
      gtk_object_add_arg_type ("GtkCanvasWidget::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR);
      gtk_object_add_arg_type ("GtkCanvasWidget::size_pixels", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SIZE_PIXELS);

      object_class->destroy = gtk_canvas_widget_destroy;
      object_class->set_arg = gtk_canvas_widget_set_arg;
      object_class->get_arg = gtk_canvas_widget_get_arg;

      item_class->update = gtk_canvas_widget_update;
      item_class->point = gtk_canvas_widget_point;
      item_class->translate = gtk_canvas_widget_translate;
      item_class->bounds = gtk_canvas_widget_bounds;
      item_class->render = gtk_canvas_widget_render;
      item_class->draw = gtk_canvas_widget_draw;
}

static void
gtk_canvas_widget_init (GtkCanvasWidget *witem)
{
      witem->x = 0.0;
      witem->y = 0.0;
      witem->width = 0.0;
      witem->height = 0.0;
      witem->anchor = GTK_ANCHOR_NW;
      witem->size_pixels = FALSE;
}

static void
gtk_canvas_widget_destroy (GtkObject *object)
{
      GtkCanvasWidget *witem;

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

      witem = GTK_CANVAS_WIDGET (object);

      if (witem->widget && !witem->in_destroy) {
            gtk_signal_disconnect (GTK_OBJECT (witem->widget), witem->destroy_id);
            gtk_widget_destroy (witem->widget);
      }

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

static void
recalc_bounds (GtkCanvasWidget *witem)
{
      GtkCanvasItem *item;
      double wx, wy;

      item = GTK_CANVAS_ITEM (witem);

      /* Get world coordinates */

      wx = witem->x;
      wy = witem->y;
      gtk_canvas_item_i2w (item, &wx, &wy);

      /* Get canvas pixel coordinates */

      gtk_canvas_w2c (item->canvas, wx, wy, &witem->cx, &witem->cy);

      /* Anchor widget item */

      switch (witem->anchor) {
      case GTK_ANCHOR_NW:
      case GTK_ANCHOR_W:
      case GTK_ANCHOR_SW:
            break;

      case GTK_ANCHOR_N:
      case GTK_ANCHOR_CENTER:
      case GTK_ANCHOR_S:
            witem->cx -= witem->cwidth / 2;
            break;

      case GTK_ANCHOR_NE:
      case GTK_ANCHOR_E:
      case GTK_ANCHOR_SE:
            witem->cx -= witem->cwidth;
            break;
      }

      switch (witem->anchor) {
      case GTK_ANCHOR_NW:
      case GTK_ANCHOR_N:
      case GTK_ANCHOR_NE:
            break;

      case GTK_ANCHOR_W:
      case GTK_ANCHOR_CENTER:
      case GTK_ANCHOR_E:
            witem->cy -= witem->cheight / 2;
            break;

      case GTK_ANCHOR_SW:
      case GTK_ANCHOR_S:
      case GTK_ANCHOR_SE:
            witem->cy -= witem->cheight;
            break;
      }

      /* Bounds */

      item->x1 = witem->cx;
      item->y1 = witem->cy;
      item->x2 = witem->cx + witem->cwidth;
      item->y2 = witem->cy + witem->cheight;

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

      if (witem->widget)
            gtk_layout_move (GTK_LAYOUT (item->canvas), witem->widget,
                         witem->cx + item->canvas->zoom_xofs,
                         witem->cy + item->canvas->zoom_yofs);
}

static void
do_destroy (GtkObject *object, gpointer data)
{
      GtkCanvasWidget *witem;

      witem = data;

      witem->in_destroy = TRUE;

      gtk_object_destroy (data);
}

static void
gtk_canvas_widget_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
      GtkCanvasItem *item;
      GtkCanvasWidget *witem;
      GtkObject *obj;
      int update;
      int calc_bounds;

      item = GTK_CANVAS_ITEM (object);
      witem = GTK_CANVAS_WIDGET (object);

      update = FALSE;
      calc_bounds = FALSE;

      switch (arg_id) {
      case ARG_WIDGET:
            if (witem->widget) {
                  gtk_signal_disconnect (GTK_OBJECT (witem->widget), witem->destroy_id);
                  gtk_container_remove (GTK_CONTAINER (item->canvas), witem->widget);
            }

            obj = GTK_VALUE_OBJECT (*arg);
            if (obj) {
                  witem->widget = GTK_WIDGET (obj);
                  witem->destroy_id = gtk_signal_connect (obj, "destroy",
                                                (GtkSignalFunc) do_destroy,
                                                witem);
                  gtk_layout_put (GTK_LAYOUT (item->canvas), witem->widget,
                              witem->cx + item->canvas->zoom_xofs,
                              witem->cy + item->canvas->zoom_yofs);
            }

            update = TRUE;
            break;

      case ARG_X:
              if (witem->x != GTK_VALUE_DOUBLE (*arg))
            {
                    witem->x = GTK_VALUE_DOUBLE (*arg);
                  calc_bounds = TRUE;
            }
            break;

      case ARG_Y:
              if (witem->y != GTK_VALUE_DOUBLE (*arg))
            {
                    witem->y = GTK_VALUE_DOUBLE (*arg);
                  calc_bounds = TRUE;
            }
            break;

      case ARG_WIDTH:
              if (witem->width != fabs (GTK_VALUE_DOUBLE (*arg)))
            {
                    witem->width = fabs (GTK_VALUE_DOUBLE (*arg));
                  update = TRUE;
            }
            break;

      case ARG_HEIGHT:
              if (witem->height != fabs (GTK_VALUE_DOUBLE (*arg)))
            {
                    witem->height = fabs (GTK_VALUE_DOUBLE (*arg));
                  update = TRUE;
            }
            break;

      case ARG_ANCHOR:
              if (witem->anchor != GTK_VALUE_ENUM (*arg))
            {
                    witem->anchor = GTK_VALUE_ENUM (*arg);
                  update = TRUE;
            }
            break;

      case ARG_SIZE_PIXELS:
              if (witem->size_pixels != GTK_VALUE_BOOL (*arg))
            {
                    witem->size_pixels = GTK_VALUE_BOOL (*arg);
                  update = TRUE;
            }
            break;

      default:
            break;
      }

      if (update)
            (* GTK_CANVAS_ITEM_CLASS (item->object.klass)->update) (item, NULL, NULL, 0);

      if (calc_bounds)
            recalc_bounds (witem);
}

static void
gtk_canvas_widget_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
      GtkCanvasWidget *witem;

      witem = GTK_CANVAS_WIDGET (object);

      switch (arg_id) {
      case ARG_WIDGET:
            GTK_VALUE_OBJECT (*arg) = GTK_OBJECT (witem->widget);
            break;

      case ARG_X:
            GTK_VALUE_DOUBLE (*arg) = witem->x;
            break;

      case ARG_Y:
            GTK_VALUE_DOUBLE (*arg) = witem->y;
            break;

      case ARG_WIDTH:
            GTK_VALUE_DOUBLE (*arg) = witem->width;
            break;

      case ARG_HEIGHT:
            GTK_VALUE_DOUBLE (*arg) = witem->height;
            break;

      case ARG_ANCHOR:
            GTK_VALUE_ENUM (*arg) = witem->anchor;
            break;

      case ARG_SIZE_PIXELS:
            GTK_VALUE_BOOL (*arg) = witem->size_pixels;
            break;

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

static void
gtk_canvas_widget_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
{
      GtkCanvasWidget *witem;

      witem = GTK_CANVAS_WIDGET (item);

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

      if (witem->widget) {
            if (witem->size_pixels) {
                  witem->cwidth = (int) (witem->width + 0.5);
                  witem->cheight = (int) (witem->height + 0.5);
            } else {
                  witem->cwidth = (int) (witem->width * item->canvas->pixels_per_unit + 0.5);
                  witem->cheight = (int) (witem->height * item->canvas->pixels_per_unit + 0.5);
            }

            gtk_widget_set_usize (witem->widget, witem->cwidth, witem->cheight);
      } else {
            witem->cwidth = 0.0;
            witem->cheight = 0.0;
      }

      recalc_bounds (witem);
}

static void
gtk_canvas_widget_render (GtkCanvasItem *item,
                      GtkCanvasBuf *buf)
{
      GtkCanvasWidget *witem;

      witem = GTK_CANVAS_WIDGET (item);

      if (witem->widget) 
            gtk_widget_queue_draw (witem->widget);
}

static void
gtk_canvas_widget_draw (GtkCanvasItem *item,
                    GdkDrawable *drawable,
                    int x, int y,
                    int width, int height)
{
      GtkCanvasWidget *witem;

      witem = GTK_CANVAS_WIDGET (item);

      if (witem->widget)
            gtk_widget_queue_draw (witem->widget);
}

static double
gtk_canvas_widget_point (GtkCanvasItem *item, double x, double y,
                     int cx, int cy, GtkCanvasItem **actual_item)
{
      GtkCanvasWidget *witem;
      double x1, y1, x2, y2;
      double dx, dy;

      witem = GTK_CANVAS_WIDGET (item);

      *actual_item = item;

      gtk_canvas_c2w (item->canvas, witem->cx, witem->cy, &x1, &y1);

      x2 = x1 + (witem->cwidth - 1) / item->canvas->pixels_per_unit;
      y2 = y1 + (witem->cheight - 1) / item->canvas->pixels_per_unit;

      /* Is point inside widget bounds? */

      if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2))
            return 0.0;

      /* Point is outside widget bounds */

      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
gtk_canvas_widget_translate (GtkCanvasItem *item, double dx, double dy)
{
      GtkCanvasWidget *witem;

      witem = GTK_CANVAS_WIDGET (item);

      witem->x = dx;
      witem->y = dy;

      recalc_bounds (witem);
}

static void
gtk_canvas_widget_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
      GtkCanvasWidget *witem;

      witem = GTK_CANVAS_WIDGET (item);

      *x1 = witem->x;
      *y1 = witem->y;

      switch (witem->anchor) {
      case GTK_ANCHOR_NW:
      case GTK_ANCHOR_W:
      case GTK_ANCHOR_SW:
            break;

      case GTK_ANCHOR_N:
      case GTK_ANCHOR_CENTER:
      case GTK_ANCHOR_S:
            *x1 -= witem->width / 2.0;
            break;

      case GTK_ANCHOR_NE:
      case GTK_ANCHOR_E:
      case GTK_ANCHOR_SE:
            *x1 -= witem->width;
            break;
      }

      switch (witem->anchor) {
      case GTK_ANCHOR_NW:
      case GTK_ANCHOR_N:
      case GTK_ANCHOR_NE:
            break;

      case GTK_ANCHOR_W:
      case GTK_ANCHOR_CENTER:
      case GTK_ANCHOR_E:
            *y1 -= witem->height / 2.0;
            break;

      case GTK_ANCHOR_SW:
      case GTK_ANCHOR_S:
      case GTK_ANCHOR_SE:
            *y1 -= witem->height;
            break;
      }

      *x2 = *x1 + witem->width;
      *y2 = *y1 + witem->height;
}

Generated by  Doxygen 1.6.0   Back to index