Creating New Items

## Creating New Items Creating New Items — how to create new canvas items. |

## How to Create New Canvas Items

Here's an example of how to create a new simple canvas item. (Note that this item doesn't have a model-view split.)

Here's the header file - a fairly standard GObject header file. Our item derives from GooCanvasItemSimple and just has its own x, y, width and height variables:

      /*
       * GooCanvas Demo. Copyright (C) 2006 Damon Chaplin.
       * Released under the GNU LGPL license. See COPYING for details.
       *
       * demo-item.c - a simple demo item.
       */
      #ifndef __GOO_DEMO_ITEM_H__
      #define __GOO_DEMO_ITEM_H__

      #include <gtk/gtk.h>
      #include "goocanvasitemsimple.h"

      G_BEGIN_DECLS

      #define GOO_TYPE_DEMO_ITEM            (goo_demo_item_get_type ())
      #define GOO_DEMO_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOO_TYPE_DEMO_ITEM, GooDemoItem))
      #define GOO_DEMO_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GOO_TYPE_DEMO_ITEM, GooDemoItemClass))
      #define GOO_IS_DEMO_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOO_TYPE_DEMO_ITEM))
      #define GOO_IS_DEMO_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GOO_TYPE_DEMO_ITEM))
      #define GOO_DEMO_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GOO_TYPE_DEMO_ITEM, GooDemoItemClass))

      typedef struct _GooDemoItem       GooDemoItem;
      typedef struct _GooDemoItemClass  GooDemoItemClass;

      struct _GooDemoItem
      {
        GooCanvasItemSimple parent_object;

        gdouble x, y, width, height;
      };

      struct _GooDemoItemClass
      {
        GooCanvasItemSimpleClass parent_class;
      };

      GType               goo_demo_item_get_type  (void) G_GNUC_CONST;

      GooCanvasItem*      goo_demo_item_new       (GooCanvasItem      *parent,
                                                   gdouble             x,
                                                   gdouble             y,
                                                   gdouble             width,
                                                   gdouble             height,
                                                   ...);

      G_END_DECLS

      #endif /* __GOO_DEMO_ITEM_H__ */

And here's the source file:

      /*
       * GooCanvas Demo. Copyright (C) 2006 Damon Chaplin.
       * Released under the GNU LGPL license. See COPYING for details.
       *
       * demo-item.c - a simple demo item.
       */
      #include <config.h>
      #include "goocanvas.h"
      #include "demo-item.h"

      /* Use the GLib convenience macro to define the type. GooDemoItem is the
         class struct, goo_demo_item is the function prefix, and our class is a
         subclass of GOO_TYPE_CANVAS_ITEM_SIMPLE. */
      G_DEFINE_TYPE (GooDemoItem, goo_demo_item, GOO_TYPE_CANVAS_ITEM_SIMPLE)

      /* The standard object initialization function. */
      static void
      goo_demo_item_init (GooDemoItem *demo_item)
      {
        demo_item->x = 0.0;
        demo_item->y = 0.0;
        demo_item->width = 0.0;
        demo_item->height = 0.0;
      }

      /* The convenience function to create new items. This should start with a
         parent argument and end with a variable list of object properties to fit
         in with the standard canvas items. */
      GooCanvasItem*
      goo_demo_item_new (GooCanvasItem      *parent,
                         gdouble             x,
                         gdouble             y,
                         gdouble             width,
                         gdouble             height,
                         ...)
      {
        GooCanvasItem *item;
        GooDemoItem *demo_item;
        const char *first_property;
        va_list var_args;

        item = g_object_new (GOO_TYPE_DEMO_ITEM, NULL);

        demo_item = (GooDemoItem*) item;
        demo_item->x = x;
        demo_item->y = y;
        demo_item->width = width;
        demo_item->height = height;

        va_start (var_args, height);
        first_property = va_arg (var_args, char*);
        if (first_property)
          g_object_set_valist ((GObject*) item, first_property, var_args);
        va_end (var_args);

        if (parent)
          {
            goo_canvas_item_add_child (parent, item, -1);
            g_object_unref (item);
          }

        return item;
      }

      /* The update method. This is called when the canvas is initially shown and
         also whenever the object is updated and needs to change its size and/or
         shape. It should calculate its new bounds in its own coordinate space,
         storing them in simple->bounds. */
      static void
      goo_demo_item_update  (GooCanvasItemSimple *simple,
                             cairo_t             *cr)
      {
        GooDemoItem *demo_item = (GooDemoItem*) simple;

        /* Compute the new bounds. */
        simple->bounds.x1 = demo_item->x;
        simple->bounds.y1 = demo_item->y;
        simple->bounds.x2 = demo_item->x + demo_item->width;
        simple->bounds.y2 = demo_item->y + demo_item->height;
      }

      /* The paint method. This should draw the item on the given cairo_t, using
         the item's own coordinate space. */
      static void
      goo_demo_item_paint (GooCanvasItemSimple   *simple,
                           cairo_t               *cr,
                           const GooCanvasBounds *bounds)
      {
        GooDemoItem *demo_item = (GooDemoItem*) simple;

        cairo_move_to (cr, demo_item->x, demo_item->y);
        cairo_line_to (cr, demo_item->x, demo_item->y + demo_item->height);
        cairo_line_to (cr, demo_item->x + demo_item->width,
                       demo_item->y + demo_item->height);
        cairo_line_to (cr, demo_item->x + demo_item->width, demo_item->y);
        cairo_close_path (cr);
        goo_canvas_style_set_fill_options (simple->simple_data->style, cr);
        cairo_fill (cr);
      }

      /* Hit detection. This should check if the given coordinate (in the item's
         coordinate space) is within the item. If it is it should return TRUE,
         otherwise it should return FALSE. */
      static gboolean
      goo_demo_item_is_item_at (GooCanvasItemSimple *simple,
                                gdouble              x,
                                gdouble              y,
                                cairo_t             *cr,
                                gboolean             is_pointer_event)
      {
        GooDemoItem *demo_item = (GooDemoItem*) simple;

        if (x < demo_item->x || (x > demo_item->x + demo_item->width)
            || y < demo_item->y || (y > demo_item->y + demo_item->height))
          return FALSE;

        return TRUE;
      }

      /* The class initialization function. Here we set the class' update(), paint()
         and is_item_at() methods. */
      static void
      goo_demo_item_class_init (GooDemoItemClass *klass)
      {
        GooCanvasItemSimpleClass *simple_class = (GooCanvasItemSimpleClass*) klass;

        simple_class->update        = goo_demo_item_update;
        simple_class->paint         = goo_demo_item_paint;
        simple_class->is_item_at    = goo_demo_item_is_item_at;
      }