/* This file is part of Ganv. * Copyright 2007-2011 David Robillard * * Ganv 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 any later version. * * Ganv 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 details. * * You should have received a copy of the GNU General Public License along * with Ganv. If not, see . */ /* Based on GnomeCanvas, by Federico Mena * and Raph Levien * Copyright 1997-2000 Free Software Foundation */ #ifndef GANV_CANVAS_BASE_H #define GANV_CANVAS_BASE_H #include #include #include G_BEGIN_DECLS /* "Small" value used by canvas stuff */ #define GANV_CANVAS_BASE_EPSILON 1e-10 typedef struct _GanvCanvasBase GanvCanvasBase; typedef struct _GanvCanvasBaseClass GanvCanvasBaseClass; typedef struct _GanvItem GanvItem; typedef struct _GanvItemClass GanvItemClass; typedef struct _GanvGroup GanvGroup; typedef struct _GanvGroupClass GanvGroupClass; /* GanvItem - base item class for canvas items * * All canvas items are derived from GanvItem. The only information a * GanvItem contains is its parent canvas, its parent canvas item group, * its bounding box in world coordinates, and its current affine transformation. * * Items inside a canvas are organized in a tree of GanvItemGroup nodes * and GanvItem leaves. Each canvas has a single root group, which can * be obtained with the ganv_canvas_base_get_root() function. * * The abstract GanvItem class does not have any configurable or * queryable attributes. */ /* Object flags for items */ enum { GANV_ITEM_REALIZED = 1 << 1, GANV_ITEM_MAPPED = 1 << 2, GANV_ITEM_ALWAYS_REDRAW = 1 << 3, GANV_ITEM_VISIBLE = 1 << 4, GANV_ITEM_NEED_UPDATE = 1 << 5, GANV_ITEM_NEED_CLIP = 1 << 6, GANV_ITEM_NEED_VIS = 1 << 7, }; /* Update flags for items */ enum { GANV_CANVAS_BASE_UPDATE_REQUESTED = 1 << 0, GANV_CANVAS_BASE_UPDATE_AFFINE = 1 << 1, GANV_CANVAS_BASE_UPDATE_CLIP = 1 << 2, GANV_CANVAS_BASE_UPDATE_VISIBILITY = 1 << 3, GANV_CANVAS_BASE_UPDATE_IS_VISIBLE = 1 << 4 /* Deprecated. FIXME: remove this */ }; #define GANV_TYPE_ITEM (ganv_item_get_type()) #define GANV_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GANV_TYPE_ITEM, GanvItem)) #define GANV_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GANV_TYPE_ITEM, GanvItemClass)) #define GANV_IS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GANV_TYPE_ITEM)) #define GANV_IS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GANV_TYPE_ITEM)) #define GANV_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GANV_TYPE_ITEM, GanvItemClass)) struct _GanvItem { GtkObject object; /* Parent canvas for this item */ GanvCanvasBase* canvas; /* Parent canvas group for this item (a GanvGroup) */ GanvItem* parent; /* Position in parent-relative coordinates. */ double x, y; /* Bounding box for this item (in canvas coordinates) */ double x1, y1, x2, y2; }; struct _GanvItemClass { GtkObjectClass parent_class; /* Tell the item to update itself. The flags are from the update flags * defined above. The item should update its internal state from its * queued state, and recompute and request its repaint area. The update * method also recomputes the bounding box of the item. */ void (* update)(GanvItem* item, int flags); /* Realize an item -- create GCs, etc. */ void (* realize)(GanvItem* item); /* Unrealize an item */ void (* unrealize)(GanvItem* item); /* Map an item - normally only need by items with their own GdkWindows */ void (* map)(GanvItem* item); /* Unmap an item */ void (* unmap)(GanvItem* item); /* Draw an item of this type. (x, y) are the upper-left canvas pixel * coordinates of the drawable, a temporary pixmap, where things get * drawn. (width, height) are the dimensions of the drawable. */ void (* draw)(GanvItem* item, cairo_t* cr, int x, int y, int width, int height); /* Calculate the distance from an item to the specified point. It also * returns a canvas item which is the item itself in the case of the * object being an actual leaf item, or a child in case of the object * being a canvas group. (cx, cy) are the canvas pixel coordinates that * correspond to the item-relative coordinates (x, y). */ double (* point)(GanvItem* item, double x, double y, int cx, int cy, GanvItem** actual_item); /* Fetch the item's bounding box (need not be exactly tight). This * should be in item-relative coordinates. */ void (* bounds)(GanvItem* item, double* x1, double* y1, double* x2, double* y2); /* Signal: an event occurred for an item of this type. The (x, y) * coordinates are in the canvas world coordinate system. */ gboolean (* event)(GanvItem* item, GdkEvent* event); /* Reserved for future expansion */ gpointer spare_vmethods [4]; }; GType ganv_item_get_type(void) G_GNUC_CONST; /* Create a canvas item using the standard Gtk argument mechanism. The item is * automatically inserted at the top of the specified canvas group. The last * argument must be a NULL pointer. */ GanvItem* ganv_item_new(GanvItem* parent, GType type, const gchar* first_arg_name, ...); /* Constructors for use in derived classes and language wrappers */ void ganv_item_construct(GanvItem* item, GanvItem* parent, const gchar* first_arg_name, va_list args); /* Configure an item using the standard Gtk argument mechanism. The last * argument must be a NULL pointer. */ void ganv_item_set(GanvItem* item, const gchar* first_arg_name, ...); /* Used only for language wrappers and the like */ void ganv_item_set_valist(GanvItem* item, const gchar* first_arg_name, va_list args); /* Move an item by the specified amount */ void ganv_item_move(GanvItem* item, double dx, double dy); /* Raise an item in the z-order of its parent group by the specified number of * positions. */ void ganv_item_raise(GanvItem* item, int positions); /* Lower an item in the z-order of its parent group by the specified number of * positions. */ void ganv_item_lower(GanvItem* item, int positions); /* Raise an item to the top of its parent group's z-order. */ void ganv_item_raise_to_top(GanvItem* item); /* Lower an item to the bottom of its parent group's z-order */ void ganv_item_lower_to_bottom(GanvItem* item); /* Show an item (make it visible). If the item is already shown, it has no * effect. */ void ganv_item_show(GanvItem* item); /* Hide an item (make it invisible). If the item is already invisible, it has * no effect. */ void ganv_item_hide(GanvItem* item); /* Grab the mouse for the specified item. Only the events in event_mask will be * reported. If cursor is non-NULL, it will be used during the duration of the * grab. Time is a proper X event time parameter. Returns the same values as * XGrabPointer(). */ int ganv_item_grab(GanvItem* item, unsigned int event_mask, GdkCursor* cursor, guint32 etime); /* Ungrabs the mouse -- the specified item must be the same that was passed to * ganv_item_grab(). Time is a proper X event time parameter. */ void ganv_item_ungrab(GanvItem* item, guint32 etime); /* These functions convert from a coordinate system to another. "w" is world * coordinates and "i" is item coordinates. */ void ganv_item_w2i(GanvItem* item, double* x, double* y); void ganv_item_i2w(GanvItem* item, double* x, double* y); /* Gets the affine transform that converts from item-relative coordinates to * world coordinates. */ void ganv_item_i2w_affine(GanvItem* item, cairo_matrix_t* matrix); /* Gets the affine transform that converts from item-relative coordinates to * canvas pixel coordinates. */ void ganv_item_i2c_affine(GanvItem* item, cairo_matrix_t* matrix); /* Remove the item from its parent group and make the new group its parent. The * item will be put on top of all the items in the new group. The item's * coordinates relative to its new parent to *not* change -- this means that the * item could potentially move on the screen. * * The item and the group must be in the same canvas. An item cannot be * reparented to a group that is the item itself or that is an inferior of the * item. */ void ganv_item_reparent(GanvItem* item, GanvGroup* new_group); /* Used to send all of the keystroke events to a specific item as well as * GDK_FOCUS_CHANGE events. */ void ganv_item_grab_focus(GanvItem* item); /* Fetch the bounding box of the item. The bounding box may not be exactly * tight, but the canvas items will do the best they can. The returned bounding * box is in the coordinate system of the item's parent. */ void ganv_item_get_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2); /* Request that the update method eventually get called. This should be used * only by item implementations. */ void ganv_item_request_update(GanvItem* item); /* GanvGroup - a group of canvas items * * A group is a node in the hierarchical tree of groups/items inside a canvas. * Groups serve to give a logical structure to the items. * * Consider a circuit editor application that uses the canvas for its schematic * display. Hierarchically, there would be canvas groups that contain all the * components needed for an "adder", for example -- this includes some logic * gates as well as wires. You can move stuff around in a convenient way by * doing a ganv_item_move() of the hierarchical groups -- to move an * adder, simply move the group that represents the adder. * * The following arguments are available: * * name type read/write description * -------------------------------------------------------------------------------- * x double RW X coordinate of group's origin * y double RW Y coordinate of group's origin */ #define GANV_TYPE_GROUP (ganv_group_get_type()) #define GANV_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GANV_TYPE_GROUP, GanvGroup)) #define GANV_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GANV_TYPE_GROUP, GanvGroupClass)) #define GANV_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GANV_TYPE_GROUP)) #define GANV_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GANV_TYPE_GROUP)) #define GANV_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GANV_TYPE_GROUP, GanvGroupClass)) struct _GanvGroup { GanvItem item; /* Children of the group */ GList* item_list; GList* item_list_end; }; struct _GanvGroupClass { GanvItemClass parent_class; }; GType ganv_group_get_type(void) G_GNUC_CONST; /*** GanvCanvasBase ***/ #define GANV_TYPE_CANVAS_BASE (ganv_canvas_base_get_type()) #define GANV_CANVAS_BASE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GANV_TYPE_CANVAS_BASE, GanvCanvasBase)) #define GANV_CANVAS_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GANV_TYPE_CANVAS_BASE, GanvCanvasBaseClass)) #define GANV_IS_CANVAS_BASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GANV_TYPE_CANVAS_BASE)) #define GANV_IS_CANVAS_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GANV_TYPE_CANVAS_BASE)) #define GANV_CANVAS_BASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GANV_TYPE_CANVAS_BASE, GanvCanvasBaseClass)) struct _GanvCanvasBase { GtkLayout layout; /* Root canvas group */ GanvItem* root; /* Region that needs redrawing, stored as a microtile array */ cairo_region_t* redraw_region; /* The item containing the mouse pointer, or NULL if none */ GanvItem* current_item; /* Item that is about to become current (used to track deletions and such) */ GanvItem* new_current_item; /* Item that holds a pointer grab, or NULL if none */ GanvItem* grabbed_item; /* If non-NULL, the currently focused item */ GanvItem* focused_item; /* GC for temporary draw pixmap */ GdkGC* pixmap_gc; /* Event on which selection of current item is based */ GdkEvent pick_event; /* Scrolling region */ double scroll_x1, scroll_y1; double scroll_x2, scroll_y2; /* Scaling factor to be used for display */ double pixels_per_unit; /* Idle handler ID */ guint idle_id; /* Signal handler ID for destruction of the root item */ guint root_destroy_id; /* Area that is being redrawn. Contains (x1, y1) but not (x2, y2). * Specified in canvas pixel coordinates. */ int redraw_x1, redraw_y1; int redraw_x2, redraw_y2; /* Offsets of the temprary drawing pixmap */ int draw_xofs, draw_yofs; /* Internal pixel offsets when zoomed out */ int zoom_xofs, zoom_yofs; /* Last known modifier state, for deferred repick when a button is down */ int state; /* Event mask specified when grabbing an item */ guint grabbed_event_mask; /* Tolerance distance for picking items */ int close_enough; /* Whether the canvas should center the scroll region in the middle of * the window if the scroll region is smaller than the window. */ unsigned int center_scroll_region : 1; /* Whether items need update at next idle loop iteration */ unsigned int need_update : 1; /* Whether the canvas needs redrawing at the next idle loop iteration */ unsigned int need_redraw : 1; /* Whether current item will be repicked at next idle loop iteration */ unsigned int need_repick : 1; /* For use by internal pick_current_item() function */ unsigned int left_grabbed_item : 1; /* For use by internal pick_current_item() function */ unsigned int in_repick : 1; }; struct _GanvCanvasBaseClass { GtkLayoutClass parent_class; /* Draw the background for the area given. This method is only used * for non-antialiased canvases. */ void (* draw_background)(GanvCanvasBase* canvas, GdkDrawable* drawable, int x, int y, int width, int height); /* Private Virtual methods for groping the canvas inside bonobo */ void (* request_update)(GanvCanvasBase* canvas); /* Reserved for future expansion */ gpointer spare_vmethods [4]; }; GType ganv_canvas_base_get_type(void) G_GNUC_CONST; /* Creates a new canvas. You should check that the canvas is created with the * proper visual and colormap. Any visual will do unless you intend to insert * gdk_imlib images into it, in which case you should use the gdk_imlib visual. * * You should call ganv_canvas_base_set_scroll_region() soon after calling this * function to set the desired scrolling limits for the canvas. */ GtkWidget* ganv_canvas_base_new(void); /* Returns the root canvas item group of the canvas */ GanvGroup* ganv_canvas_base_root(GanvCanvasBase* canvas); /* Sets the limits of the scrolling region, in world coordinates */ void ganv_canvas_base_set_scroll_region(GanvCanvasBase* canvas, double x1, double y1, double x2, double y2); /* Gets the limits of the scrolling region, in world coordinates */ void ganv_canvas_base_get_scroll_region(GanvCanvasBase* canvas, double* x1, double* y1, double* x2, double* y2); /* Whether the canvas centers the scroll region if it is smaller than the window */ void ganv_canvas_base_set_center_scroll_region(GanvCanvasBase* canvas, gboolean center_scroll_region); /* Returns whether the canvas is set to center the scroll region if it is smaller than the window */ gboolean ganv_canvas_base_get_center_scroll_region(GanvCanvasBase* canvas); /* Sets the number of pixels that correspond to one unit in world coordinates */ void ganv_canvas_base_set_pixels_per_unit(GanvCanvasBase* canvas, double n); /* Scrolls the canvas to the specified offsets, given in canvas pixel coordinates */ void ganv_canvas_base_scroll_to(GanvCanvasBase* canvas, int cx, int cy); /* Returns the scroll offsets of the canvas in canvas pixel coordinates. You * can specify NULL for any of the values, in which case that value will not be * queried. */ void ganv_canvas_base_get_scroll_offsets(GanvCanvasBase* canvas, int* cx, int* cy); /* Requests that the canvas be repainted immediately instead of in the idle * loop. */ void ganv_canvas_base_update_now(GanvCanvasBase* canvas); /* Returns the item that is at the specified position in world coordinates, or * NULL if no item is there. */ GanvItem* ganv_canvas_base_get_item_at(GanvCanvasBase* canvas, double x, double y); /* For use only by item type implementations. Request that the canvas * eventually redraw the specified region, specified in canvas pixel * coordinates. The region contains (x1, y1) but not (x2, y2). */ void ganv_canvas_base_request_redraw(GanvCanvasBase* canvas, int x1, int y1, int x2, int y2); /* Gets the affine transform that converts world coordinates into canvas pixel * coordinates. */ void ganv_canvas_base_w2c_affine(GanvCanvasBase* canvas, cairo_matrix_t* matrix); /* These functions convert from a coordinate system to another. "w" is world * coordinates, "c" is canvas pixel coordinates (pixel coordinates that are * (0,0) for the upper-left scrolling limit and something else for the * lower-left scrolling limit). */ void ganv_canvas_base_w2c(GanvCanvasBase* canvas, double wx, double wy, int* cx, int* cy); void ganv_canvas_base_w2c_d(GanvCanvasBase* canvas, double wx, double wy, double* cx, double* cy); void ganv_canvas_base_c2w(GanvCanvasBase* canvas, int cx, int cy, double* wx, double* wy); /* This function takes in coordinates relative to the GTK_LAYOUT * (canvas)->bin_window and converts them to world coordinates. */ void ganv_canvas_base_window_to_world(GanvCanvasBase* canvas, double winx, double winy, double* worldx, double* worldy); /* This is the inverse of ganv_canvas_base_window_to_world() */ void ganv_canvas_base_world_to_window(GanvCanvasBase* canvas, double worldx, double worldy, double* winx, double* winy); G_END_DECLS #endif