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