1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */ 2 /* 3 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation 4 * All rights reserved. 5 * 6 * This file is part of the Gnome Library. 7 * 8 * The Gnome Library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public License as 10 * published by the Free Software Foundation; either version 2 of the 11 * License, or (at your option) any later version. 12 * 13 * The Gnome Library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public 19 * License along with the Gnome Library; see the file COPYING.LIB. If not, 20 * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, 21 * Boston, MA 02110-1335, USA. 22 */ 23 /* 24 @NOTATION@ 25 */ 26 /* EelCanvas widget - Tk-like canvas widget for Gnome 27 * 28 * EelCanvas is basically a port of the Tk toolkit's most excellent canvas 29 * widget. Tk is copyrighted by the Regents of the University of California, 30 * Sun Microsystems, and other parties. 31 * 32 * 33 * Authors: Federico Mena <federico@nuclecu.unam.mx> 34 * Raph Levien <raph@gimp.org> 35 */ 36 37 #ifndef EEL_CANVAS_H 38 #define EEL_CANVAS_H 39 40 #include <gtk/gtk.h> 41 #include <gdk/gdk.h> 42 #include <stdarg.h> 43 44 G_BEGIN_DECLS 45 46 47 /* "Small" value used by canvas stuff */ 48 #define EEL_CANVAS_EPSILON 1e-10 49 50 51 /* Macros for building colors that fit in a 32-bit integer. The values are in 52 * [0, 255]. 53 */ 54 55 #define EEL_CANVAS_COLOR(r, g, b) ((((int) (r) & 0xff) << 24) \ 56 | (((int) (g) & 0xff) << 16) \ 57 | (((int) (b) & 0xff) << 8) \ 58 | 0xff) 59 60 #define EEL_CANVAS_COLOR_A(r, g, b, a) ((((int) (r) & 0xff) << 24) \ 61 | (((int) (g) & 0xff) << 16) \ 62 | (((int) (b) & 0xff) << 8) \ 63 | ((int) (a) & 0xff)) 64 65 66 typedef struct _EelCanvas EelCanvas; 67 typedef struct _EelCanvasClass EelCanvasClass; 68 typedef struct _EelCanvasItem EelCanvasItem; 69 typedef struct _EelCanvasItemClass EelCanvasItemClass; 70 typedef struct _EelCanvasGroup EelCanvasGroup; 71 typedef struct _EelCanvasGroupClass EelCanvasGroupClass; 72 73 74 /* EelCanvasItem - base item class for canvas items 75 * 76 * All canvas items are derived from EelCanvasItem. The only information a 77 * EelCanvasItem contains is its parent canvas, its parent canvas item group, 78 * and its bounding box in world coordinates. 79 * 80 * Items inside a canvas are organized in a tree of EelCanvasItemGroup nodes 81 * and EelCanvasItem leaves. Each canvas has a single root group, which can 82 * be obtained with the eel_canvas_get_root() function. 83 * 84 * The abstract EelCanvasItem class does not have any configurable or 85 * queryable attributes. 86 */ 87 88 /* Object flags for items */ 89 enum { 90 EEL_CANVAS_ITEM_REALIZED = 1 << 4, 91 EEL_CANVAS_ITEM_MAPPED = 1 << 5, 92 EEL_CANVAS_ITEM_ALWAYS_REDRAW = 1 << 6, 93 EEL_CANVAS_ITEM_VISIBLE = 1 << 7, 94 EEL_CANVAS_ITEM_NEED_UPDATE = 1 << 8, 95 EEL_CANVAS_ITEM_NEED_DEEP_UPDATE = 1 << 9 96 }; 97 98 /* Update flags for items */ 99 enum { 100 EEL_CANVAS_UPDATE_REQUESTED = 1 << 0, 101 EEL_CANVAS_UPDATE_DEEP = 1 << 1 102 }; 103 104 #define EEL_TYPE_CANVAS_ITEM (eel_canvas_item_get_type ()) 105 #define EEL_CANVAS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS_ITEM, EelCanvasItem)) 106 #define EEL_CANVAS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_ITEM, EelCanvasItemClass)) 107 #define EEL_IS_CANVAS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS_ITEM)) 108 #define EEL_IS_CANVAS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_ITEM)) 109 #define EEL_CANVAS_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS_ITEM, EelCanvasItemClass)) 110 111 112 struct _EelCanvasItem { 113 GInitiallyUnowned object; 114 115 /* Parent canvas for this item */ 116 EelCanvas *canvas; 117 118 /* Parent canvas group for this item (a EelCanvasGroup) */ 119 EelCanvasItem *parent; 120 121 /* Bounding box for this item (in canvas coordinates) */ 122 double x1, y1, x2, y2; 123 124 /* Object flags */ 125 guint flags; 126 }; 127 128 struct _EelCanvasItemClass { 129 GInitiallyUnownedClass parent_class; 130 131 void (* destroy) (EelCanvasItem *item); 132 133 /* Tell the item to update itself. The flags are from the update flags 134 * defined above. The item should update its internal state from its 135 * queued state, and recompute and request its repaint area. The 136 * update method also recomputes the bounding box of the item. 137 */ 138 void (* update) (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags); 139 140 /* Realize an item -- create GCs, etc. */ 141 void (* realize) (EelCanvasItem *item); 142 143 /* Unrealize an item */ 144 void (* unrealize) (EelCanvasItem *item); 145 146 /* Map an item - normally only need by items with their own GdkWindows */ 147 void (* map) (EelCanvasItem *item); 148 149 /* Unmap an item */ 150 void (* unmap) (EelCanvasItem *item); 151 152 /* Draw an item of this type. (x, y) are the upper-left canvas pixel 153 * coordinates of the drawable, a temporary pixmap, where things get 154 * drawn. (width, height) are the dimensions of the drawable. 155 */ 156 void (* draw) (EelCanvasItem *item, cairo_t *cr, cairo_region_t *region); 157 158 /* Calculate the distance from an item to the specified point. It also 159 * returns a canvas item which is the item itself in the case of the 160 * object being an actual leaf item, or a child in case of the object 161 * being a canvas group. (cx, cy) are the canvas pixel coordinates that 162 * correspond to the item-relative coordinates (x, y). 163 */ 164 double (* point) (EelCanvasItem *item, double x, double y, int cx, int cy, 165 EelCanvasItem **actual_item); 166 167 void (* translate) (EelCanvasItem *item, double dx, double dy); 168 169 /* Fetch the item's bounding box (need not be exactly tight). This 170 * should be in item-relative coordinates. 171 */ 172 void (* bounds) (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2); 173 174 /* Signal: an event ocurred for an item of this type. The (x, y) 175 * coordinates are in the canvas world coordinate system. 176 */ 177 gboolean (* event) (EelCanvasItem *item, GdkEvent *event); 178 179 /* Reserved for future expansion */ 180 gpointer spare_vmethods [4]; 181 }; 182 183 184 /* Standard Gtk function */ 185 GType eel_canvas_item_get_type (void) G_GNUC_CONST; 186 187 /* Create a canvas item using the standard Gtk argument mechanism. The item is 188 * automatically inserted at the top of the specified canvas group. The last 189 * argument must be a NULL pointer. 190 */ 191 EelCanvasItem *eel_canvas_item_new (EelCanvasGroup *parent, GType type, 192 const gchar *first_arg_name, ...); 193 194 void eel_canvas_item_destroy (EelCanvasItem *item); 195 196 /* Constructors for use in derived classes and language wrappers */ 197 void eel_canvas_item_construct (EelCanvasItem *item, EelCanvasGroup *parent, 198 const gchar *first_arg_name, va_list args); 199 200 /* Configure an item using the standard Gtk argument mechanism. The last 201 * argument must be a NULL pointer. 202 */ 203 void eel_canvas_item_set (EelCanvasItem *item, const gchar *first_arg_name, ...); 204 205 /* Used only for language wrappers and the like */ 206 void eel_canvas_item_set_valist (EelCanvasItem *item, 207 const gchar *first_arg_name, va_list args); 208 209 /* Move an item by the specified amount */ 210 void eel_canvas_item_move (EelCanvasItem *item, double dx, double dy); 211 212 /* Raise an item in the z-order of its parent group by the specified number of 213 * positions. 214 */ 215 void eel_canvas_item_raise (EelCanvasItem *item, int positions); 216 217 /* Lower an item in the z-order of its parent group by the specified number of 218 * positions. 219 */ 220 void eel_canvas_item_lower (EelCanvasItem *item, int positions); 221 222 /* Raise an item to the top of its parent group's z-order. */ 223 void eel_canvas_item_raise_to_top (EelCanvasItem *item); 224 225 /* Lower an item to the bottom of its parent group's z-order */ 226 void eel_canvas_item_lower_to_bottom (EelCanvasItem *item); 227 228 /* Send an item behind another item */ 229 void eel_canvas_item_send_behind (EelCanvasItem *item, 230 EelCanvasItem *behind_item); 231 232 233 /* Show an item (make it visible). If the item is already shown, it has no 234 * effect. 235 */ 236 void eel_canvas_item_show (EelCanvasItem *item); 237 238 /* Hide an item (make it invisible). If the item is already invisible, it has 239 * no effect. 240 */ 241 void eel_canvas_item_hide (EelCanvasItem *item); 242 243 /* Grab the mouse for the specified item. Only the events in event_mask will be 244 * reported. If cursor is non-NULL, it will be used during the duration of the 245 * grab. Time is a proper X event time parameter. Returns the same values as 246 * XGrabPointer(). 247 */ 248 GdkGrabStatus eel_canvas_item_grab (EelCanvasItem *item, 249 GdkEventMask event_mask, 250 GdkCursor *cursor, 251 guint32 etime); 252 253 /* Ungrabs the mouse -- the specified item must be the same that was passed to 254 * eel_canvas_item_grab(). Time is a proper X event time parameter. 255 */ 256 void eel_canvas_item_ungrab (EelCanvasItem *item, guint32 etime); 257 258 /* These functions convert from a coordinate system to another. "w" is world 259 * coordinates and "i" is item coordinates. 260 */ 261 void eel_canvas_item_w2i (EelCanvasItem *item, double *x, double *y); 262 void eel_canvas_item_i2w (EelCanvasItem *item, double *x, double *y); 263 264 /* Remove the item from its parent group and make the new group its parent. The 265 * item will be put on top of all the items in the new group. The item's 266 * coordinates relative to its new parent to *not* change -- this means that the 267 * item could potentially move on the screen. 268 * 269 * The item and the group must be in the same canvas. An item cannot be 270 * reparented to a group that is the item itself or that is an inferior of the 271 * item. 272 */ 273 void eel_canvas_item_reparent (EelCanvasItem *item, EelCanvasGroup *new_group); 274 275 /* Used to send all of the keystroke events to a specific item as well as 276 * GDK_FOCUS_CHANGE events. 277 */ 278 void eel_canvas_item_grab_focus (EelCanvasItem *item); 279 280 /* Fetch the bounding box of the item. The bounding box may not be exactly 281 * tight, but the canvas items will do the best they can. The returned bounding 282 * box is in the coordinate system of the item's parent. 283 */ 284 void eel_canvas_item_get_bounds (EelCanvasItem *item, 285 double *x1, double *y1, double *x2, double *y2); 286 287 /* Request that the update method eventually get called. This should be used 288 * only by item implementations. 289 */ 290 void eel_canvas_item_request_update (EelCanvasItem *item); 291 292 /* Request a redraw of the bounding box of the canvas item */ 293 void eel_canvas_item_request_redraw (EelCanvasItem *item); 294 295 /* EelCanvasGroup - a group of canvas items 296 * 297 * A group is a node in the hierarchical tree of groups/items inside a canvas. 298 * Groups serve to give a logical structure to the items. 299 * 300 * Consider a circuit editor application that uses the canvas for its schematic 301 * display. Hierarchically, there would be canvas groups that contain all the 302 * components needed for an "adder", for example -- this includes some logic 303 * gates as well as wires. You can move stuff around in a convenient way by 304 * doing a eel_canvas_item_move() of the hierarchical groups -- to move an 305 * adder, simply move the group that represents the adder. 306 * 307 * The following arguments are available: 308 * 309 * name type read/write description 310 * -------------------------------------------------------------------------------- 311 * x double RW X coordinate of group's origin 312 * y double RW Y coordinate of group's origin 313 */ 314 315 316 #define EEL_TYPE_CANVAS_GROUP (eel_canvas_group_get_type ()) 317 #define EEL_CANVAS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS_GROUP, EelCanvasGroup)) 318 #define EEL_CANVAS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_GROUP, EelCanvasGroupClass)) 319 #define EEL_IS_CANVAS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS_GROUP)) 320 #define EEL_IS_CANVAS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS_GROUP)) 321 #define EEL_CANVAS_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS_GROUP, EelCanvasGroupClass)) 322 323 324 struct _EelCanvasGroup { 325 EelCanvasItem item; 326 327 double xpos, ypos; 328 329 /* Children of the group */ 330 GList *item_list; 331 GList *item_list_end; 332 }; 333 334 struct _EelCanvasGroupClass { 335 EelCanvasItemClass parent_class; 336 }; 337 338 339 /* Standard Gtk function */ 340 GType eel_canvas_group_get_type (void) G_GNUC_CONST; 341 342 343 /*** EelCanvas ***/ 344 345 346 #define EEL_TYPE_CANVAS (eel_canvas_get_type ()) 347 #define EEL_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_CANVAS, EelCanvas)) 348 #define EEL_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS, EelCanvasClass)) 349 #define EEL_IS_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEL_TYPE_CANVAS)) 350 #define EEL_IS_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEL_TYPE_CANVAS)) 351 #define EEL_CANVAS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEL_TYPE_CANVAS, EelCanvasClass)) 352 353 354 struct _EelCanvas { 355 GtkLayout layout; 356 357 /* Root canvas group */ 358 EelCanvasItem *root; 359 360 /* The item containing the mouse pointer, or NULL if none */ 361 EelCanvasItem *current_item; 362 363 /* Item that is about to become current (used to track deletions and such) */ 364 EelCanvasItem *new_current_item; 365 366 /* Item that holds a pointer grab, or NULL if none */ 367 EelCanvasItem *grabbed_item; 368 369 /* If non-NULL, the currently focused item */ 370 EelCanvasItem *focused_item; 371 372 /* Event on which selection of current item is based */ 373 GdkEvent pick_event; 374 375 /* Scrolling region */ 376 double scroll_x1, scroll_y1; 377 double scroll_x2, scroll_y2; 378 379 /* Scaling factor to be used for display */ 380 double pixels_per_unit; 381 382 /* Idle handler ID */ 383 guint idle_id; 384 385 /* Signal handler ID for destruction of the root item */ 386 guint root_destroy_id; 387 388 /* Internal pixel offsets when zoomed out */ 389 int zoom_xofs, zoom_yofs; 390 391 /* Last known modifier state, for deferred repick when a button is down */ 392 int state; 393 394 /* Event mask specified when grabbing an item */ 395 guint grabbed_event_mask; 396 397 /* Tolerance distance for picking items */ 398 int close_enough; 399 400 /* Whether the canvas should center the canvas in the middle of 401 * the window if the scroll region is smaller than the window */ 402 unsigned int center_scroll_region : 1; 403 404 /* Whether items need update at next idle loop iteration */ 405 unsigned int need_update : 1; 406 407 /* Are we in the midst of an update */ 408 unsigned int doing_update : 1; 409 410 /* Whether the canvas needs redrawing at the next idle loop iteration */ 411 unsigned int need_redraw : 1; 412 413 /* Whether current item will be repicked at next idle loop iteration */ 414 unsigned int need_repick : 1; 415 416 /* For use by internal pick_current_item() function */ 417 unsigned int left_grabbed_item : 1; 418 419 /* For use by internal pick_current_item() function */ 420 unsigned int in_repick : 1; 421 }; 422 423 struct _EelCanvasClass { 424 GtkLayoutClass parent_class; 425 426 /* Draw the background for the area given. 427 */ 428 void (* draw_background) (EelCanvas *canvas, 429 cairo_t *cr); 430 431 /* Private Virtual methods for groping the canvas inside bonobo */ 432 void (* request_update) (EelCanvas *canvas); 433 434 /* Reserved for future expansion */ 435 gpointer spare_vmethods [4]; 436 }; 437 438 439 /* Standard Gtk function */ 440 GType eel_canvas_get_type (void) G_GNUC_CONST; 441 442 /* Creates a new canvas. You should check that the canvas is created with the 443 * proper visual and colormap. Any visual will do unless you intend to insert 444 * gdk_imlib images into it, in which case you should use the gdk_imlib visual. 445 * 446 * You should call eel_canvas_set_scroll_region() soon after calling this 447 * function to set the desired scrolling limits for the canvas. 448 */ 449 GtkWidget *eel_canvas_new (void); 450 451 /* Returns the root canvas item group of the canvas */ 452 EelCanvasGroup *eel_canvas_root (EelCanvas *canvas); 453 454 /* Sets the limits of the scrolling region, in world coordinates */ 455 void eel_canvas_set_scroll_region (EelCanvas *canvas, 456 double x1, double y1, double x2, double y2); 457 458 /* Gets the limits of the scrolling region, in world coordinates */ 459 void eel_canvas_get_scroll_region (EelCanvas *canvas, 460 double *x1, double *y1, double *x2, double *y2); 461 462 /* Sets the number of pixels that correspond to one unit in world coordinates */ 463 void eel_canvas_set_pixels_per_unit (EelCanvas *canvas, double n); 464 465 /* Wether the canvas centers the scroll region if it is smaller than the window */ 466 void eel_canvas_set_center_scroll_region (EelCanvas *canvas, gboolean center_scroll_region); 467 468 /* Scrolls the canvas to the specified offsets, given in canvas pixel coordinates */ 469 void eel_canvas_scroll_to (EelCanvas *canvas, int cx, int cy); 470 471 /* Returns the scroll offsets of the canvas in canvas pixel coordinates. You 472 * can specify NULL for any of the values, in which case that value will not be 473 * queried. 474 */ 475 void eel_canvas_get_scroll_offsets (EelCanvas *canvas, int *cx, int *cy); 476 477 /* Requests that the canvas be repainted immediately instead of in the idle 478 * loop. 479 */ 480 void eel_canvas_update_now (EelCanvas *canvas); 481 482 /* Returns the item that is at the specified position in world coordinates, or 483 * NULL if no item is there. 484 */ 485 EelCanvasItem *eel_canvas_get_item_at (EelCanvas *canvas, double x, double y); 486 487 /* For use only by item type implementations. Request that the canvas 488 * eventually redraw the specified region, specified in canvas pixel 489 * coordinates. The region contains (x1, y1) but not (x2, y2). 490 */ 491 void eel_canvas_request_redraw (EelCanvas *canvas, int x1, int y1, int x2, int y2); 492 493 /* These functions convert from a coordinate system to another. "w" is world 494 * coordinates, "c" is canvas pixel coordinates (pixel coordinates that are 495 * (0,0) for the upper-left scrolling limit and something else for the 496 * lower-left scrolling limit). 497 */ 498 void eel_canvas_w2c_rect_d (EelCanvas *canvas, 499 double *x1, double *y1, 500 double *x2, double *y2); 501 void eel_canvas_w2c (EelCanvas *canvas, double wx, double wy, int *cx, int *cy); 502 void eel_canvas_w2c_d (EelCanvas *canvas, double wx, double wy, double *cx, double *cy); 503 void eel_canvas_c2w (EelCanvas *canvas, int cx, int cy, double *wx, double *wy); 504 505 /* This function takes in coordinates relative to the GTK_LAYOUT 506 * (canvas)->bin_window and converts them to world coordinates. 507 * These days canvas coordinates and window coordinates are the same, but 508 * these are left for backwards compat reasons. 509 */ 510 void eel_canvas_window_to_world (EelCanvas *canvas, 511 double winx, double winy, double *worldx, double *worldy); 512 513 /* This is the inverse of eel_canvas_window_to_world() */ 514 void eel_canvas_world_to_window (EelCanvas *canvas, 515 double worldx, double worldy, double *winx, double *winy); 516 517 /* Accessible implementation */ 518 GType eel_canvas_accessible_get_type(void); 519 520 typedef struct _EelCanvasAccessible EelCanvasAccessible; 521 struct _EelCanvasAccessible 522 { 523 GtkAccessible parent; 524 }; 525 526 typedef struct _EelCanvasAccessibleClass EelCanvasAccessibleClass; 527 struct _EelCanvasAccessibleClass 528 { 529 GtkAccessibleClass parent_class; 530 }; 531 532 G_END_DECLS 533 534 #endif 535