Graphviz  2.39.20141219.0545
gvevent.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17 
18 #include <string.h>
19 #include <stdlib.h>
20 #include <math.h>
21 
22 #include "gvplugin_layout.h"
23 #include "gvcint.h"
24 #include "gvcproc.h"
25 
26 extern char *strdup_and_subst_obj(char *str, void * n);
27 extern void emit_graph(GVJ_t * job, graph_t * g);
28 extern boolean overlap_edge(edge_t *e, boxf b);
29 extern boolean overlap_node(node_t *n, boxf b);
30 extern int gvLayout(GVC_t *gvc, graph_t *g, const char *engine);
31 extern int gvRenderFilename(GVC_t *gvc, graph_t *g, const char *format, const char *filename);
32 extern void graph_cleanup(graph_t *g);
33 
34 #define PANFACTOR 10
35 #define ZOOMFACTOR 1.1
36 #define EPSILON .0001
37 
38 static char *s_digraph = "digraph";
39 static char *s_graph = "graph";
40 static char *s_subgraph = "subgraph";
41 static char *s_node = "node";
42 static char *s_edge = "edge";
43 static char *s_tooltip = "tooltip";
44 static char *s_href = "href";
45 static char *s_URL = "URL";
46 static char *s_tailport = "tailport";
47 static char *s_headport = "headport";
48 static char *s_key = "key";
49 
50 static void gv_graph_state(GVJ_t *job, graph_t *g)
51 {
52  int j;
53  Agsym_t *a;
54  gv_argvlist_t *list;
55 
56  list = &(job->selected_obj_type_name);
57  j = 0;
58  if (g == agroot(g)) {
59  if (agisdirected(g))
60  gv_argvlist_set_item(list, j++, s_digraph);
61  else
62  gv_argvlist_set_item(list, j++, s_graph);
63  }
64  else {
65  gv_argvlist_set_item(list, j++, s_subgraph);
66  }
67  gv_argvlist_set_item(list, j++, agnameof(g));
68  list->argc = j;
69 
70  list = &(job->selected_obj_attributes);
71  a = NULL;
72  while ((a = agnxtattr(g, AGRAPH, a))) {
73  gv_argvlist_set_item(list, j++, a->name);
74  gv_argvlist_set_item(list, j++, agxget(g, a));
75  gv_argvlist_set_item(list, j++, (char*)GVATTR_STRING);
76  }
77  list->argc = j;
78 
79  a = agfindgraphattr(g, s_href);
80  if (!a)
81  a = agfindgraphattr(g, s_URL);
82  if (a)
83  job->selected_href = strdup_and_subst_obj(agxget(g, a), (void*)g);
84 }
85 
86 static void gv_node_state(GVJ_t *job, node_t *n)
87 {
88  int j;
89  Agsym_t *a;
90  Agraph_t *g;
91  gv_argvlist_t *list;
92 
93  list = &(job->selected_obj_type_name);
94  j = 0;
95  gv_argvlist_set_item(list, j++, s_node);
96  gv_argvlist_set_item(list, j++, agnameof(n));
97  list->argc = j;
98 
99  list = &(job->selected_obj_attributes);
100  g = agroot(agraphof(n));
101  a = NULL;
102  while ((a = agnxtattr(g, AGNODE, a))) {
103  gv_argvlist_set_item(list, j++, a->name);
104  gv_argvlist_set_item(list, j++, agxget(n, a));
105  }
106  list->argc = j;
107 
108  a = agfindnodeattr(agraphof(n), s_href);
109  if (!a)
110  a = agfindnodeattr(agraphof(n), s_URL);
111  if (a)
112  job->selected_href = strdup_and_subst_obj(agxget(n, a), (void*)n);
113 }
114 
115 static void gv_edge_state(GVJ_t *job, edge_t *e)
116 {
117  int j;
118  Agsym_t *a;
119  Agraph_t *g;
120  gv_argvlist_t *nlist, *alist;
121 
122  nlist = &(job->selected_obj_type_name);
123 
124  /* only tail, head, and key are strictly identifying properties,
125  * but we commonly alse use edge kind (e.g. "->") and tailport,headport
126  * in edge names */
127  j = 0;
128  gv_argvlist_set_item(nlist, j++, s_edge);
129  gv_argvlist_set_item(nlist, j++, agnameof(agtail(e)));
130  j++; /* skip tailport slot for now */
131  gv_argvlist_set_item(nlist, j++, agisdirected(agraphof(agtail(e)))?"->":"--");
132  gv_argvlist_set_item(nlist, j++, agnameof(aghead(e)));
133  j++; /* skip headport slot for now */
134  j++; /* skip key slot for now */
135  nlist->argc = j;
136 
137  alist = &(job->selected_obj_attributes);
138  g = agroot(agraphof(aghead(e)));
139  a = NULL;
140  while ((a = agnxtattr(g, AGEDGE, a))) {
141 
142  /* tailport and headport can be shown as part of the name, but they
143  * are not identifying properties of the edge so we
144  * also list them as modifyable attributes. */
145  if (strcmp(a->name,s_tailport) == 0)
146  gv_argvlist_set_item(nlist, 2, agxget(e, a));
147  else if (strcmp(a->name,s_headport) == 0)
148  gv_argvlist_set_item(nlist, 5, agxget(e, a));
149 
150  /* key is strictly an identifying property to distinguish multiple
151  * edges between the same node pair. Its non-writable, so
152  * no need to list it as an attribute as well. */
153  else if (strcmp(a->name,s_key) == 0) {
154  gv_argvlist_set_item(nlist, 6, agxget(e, a));
155  continue;
156  }
157 
158  gv_argvlist_set_item(alist, j++, a->name);
159  gv_argvlist_set_item(alist, j++, agxget(e, a));
160  }
161  alist->argc = j;
162 
163  a = agfindedgeattr(agraphof(aghead(e)), s_href);
164  if (!a)
165  a = agfindedgeattr(agraphof(aghead(e)), s_URL);
166  if (a)
167  job->selected_href = strdup_and_subst_obj(agxget(e, a), (void*)e);
168 }
169 
170 static void gvevent_refresh(GVJ_t * job)
171 {
172  graph_t *g = job->gvc->g;
173 
174  if (!job->selected_obj) {
175  job->selected_obj = g;
177  gv_graph_state(job, g);
178  }
179  emit_graph(job, g);
180  job->has_been_rendered = TRUE;
181 }
182 
183 /* recursively find innermost cluster containing the point */
184 static graph_t *gvevent_find_cluster(graph_t *g, boxf b)
185 {
186  int i;
187  graph_t *sg;
188  boxf bb;
189 
190  for (i = 1; i <= GD_n_cluster(g); i++) {
191  sg = gvevent_find_cluster(GD_clust(g)[i], b);
192  if (sg)
193  return(sg);
194  }
195  B2BF(GD_bb(g), bb);
196  if (OVERLAP(b, bb))
197  return g;
198  return NULL;
199 }
200 
201 static void * gvevent_find_obj(graph_t *g, boxf b)
202 {
203  graph_t *sg;
204  node_t *n;
205  edge_t *e;
206 
207  /* edges might overlap nodes, so search them first */
208  for (n = agfstnode(g); n; n = agnxtnode(g, n))
209  for (e = agfstout(g, n); e; e = agnxtout(g, e))
210  if (overlap_edge(e, b))
211  return (void *)e;
212  /* search graph backwards to get topmost node, in case of overlap */
213  for (n = aglstnode(g); n; n = agprvnode(g, n))
214  if (overlap_node(n, b))
215  return (void *)n;
216  /* search for innermost cluster */
217  sg = gvevent_find_cluster(g, b);
218  if (sg)
219  return (void *)sg;
220 
221  /* otherwise - we're always in the graph */
222  return (void *)g;
223 }
224 
225 static void gvevent_leave_obj(GVJ_t * job)
226 {
227  void *obj = job->current_obj;
228 
229  if (obj) {
230  switch (agobjkind(obj)) {
231  case AGRAPH:
233  break;
234  case AGNODE:
236  break;
237  case AGEDGE:
239  break;
240  }
241  }
242  job->active_tooltip = NULL;
243 }
244 
245 static void gvevent_enter_obj(GVJ_t * job)
246 {
247  void *obj;
248  graph_t *g;
249  edge_t *e;
250  node_t *n;
251  Agsym_t *a;
252 
253  if (job->active_tooltip) {
254  free(job->active_tooltip);
255  job->active_tooltip = NULL;
256  }
257  obj = job->current_obj;
258  if (obj) {
259  switch (agobjkind(obj)) {
260  case AGRAPH:
261  g = (graph_t*)obj;
263  a = agfindgraphattr(g, s_tooltip);
264  if (a)
265  job->active_tooltip = strdup_and_subst_obj(agxget(g, a), obj);
266  break;
267  case AGNODE:
268  n = (node_t*)obj;
270  a = agfindnodeattr(agraphof(n), s_tooltip);
271  if (a)
272  job->active_tooltip = strdup_and_subst_obj(agxget(n, a), obj);
273  break;
274  case AGEDGE:
275  e = (edge_t*)obj;
277  a = agfindedgeattr(agraphof(aghead(e)), s_tooltip);
278  if (a)
279  job->active_tooltip = strdup_and_subst_obj(agxget(e, a), obj);
280  break;
281  }
282  }
283 }
284 
285 static pointf pointer2graph (GVJ_t *job, pointf pointer)
286 {
287  pointf p;
288 
289  /* transform position in device units to position in graph units */
290  if (job->rotation) {
291  p.x = pointer.y / (job->zoom * job->devscale.y) - job->translation.x;
292  p.y = -pointer.x / (job->zoom * job->devscale.x) - job->translation.y;
293  }
294  else {
295  p.x = pointer.x / (job->zoom * job->devscale.x) - job->translation.x;
296  p.y = pointer.y / (job->zoom * job->devscale.y) - job->translation.y;
297  }
298  return p;
299 }
300 
301 /* CLOSEENOUGH is in 1/72 - probably should be a feature... */
302 #define CLOSEENOUGH 1
303 
304 static void gvevent_find_current_obj(GVJ_t * job, pointf pointer)
305 {
306  void *obj;
307  boxf b;
308  double closeenough;
309  pointf p;
310 
311  p = pointer2graph (job, pointer);
312 
313  /* convert window point to graph coordinates */
314  closeenough = CLOSEENOUGH / job->zoom;
315 
316  b.UR.x = p.x + closeenough;
317  b.UR.y = p.y + closeenough;
318  b.LL.x = p.x - closeenough;
319  b.LL.y = p.y - closeenough;
320 
321  obj = gvevent_find_obj(job->gvc->g, b);
322  if (obj != job->current_obj) {
323  gvevent_leave_obj(job);
324  job->current_obj = obj;
325  gvevent_enter_obj(job);
326  job->needs_refresh = 1;
327  }
328 }
329 
330 static void gvevent_select_current_obj(GVJ_t * job)
331 {
332  void *obj;
333 
334  obj = job->selected_obj;
335  if (obj) {
336  switch (agobjkind(obj)) {
337  case AGRAPH:
340  break;
341  case AGNODE:
344  break;
345  case AGEDGE:
348  break;
349  }
350  }
351 
352  if (job->selected_href) {
353  free(job->selected_href);
354  job->selected_href = NULL;
355  }
356 
357  obj = job->selected_obj = job->current_obj;
358  if (obj) {
359  switch (agobjkind(obj)) {
360  case AGRAPH:
362  gv_graph_state(job, (graph_t*)obj);
363  break;
364  case AGNODE:
366  gv_node_state(job, (node_t*)obj);
367  break;
368  case AGEDGE:
370  gv_edge_state(job, (edge_t*)obj);
371  break;
372  }
373  }
374 
375 #if 0
376 for (i = 0; i < job->selected_obj_type_name.argc; i++)
377  fprintf(stderr,"%s%s", job->selected_obj_type_name.argv[i],
378  (i==(job->selected_obj_type_name.argc - 1))?"\n":" ");
379 for (i = 0; i < job->selected_obj_attributes.argc; i++)
380  fprintf(stderr,"%s%s", job->selected_obj_attributes.argv[i], (i%2)?"\n":" = ");
381 fprintf(stderr,"\n");
382 #endif
383 }
384 
385 static void gvevent_button_press(GVJ_t * job, int button, pointf pointer)
386 {
387  switch (button) {
388  case 1: /* select / create in edit mode */
389  gvevent_find_current_obj(job, pointer);
390  gvevent_select_current_obj(job);
391  job->click = 1;
392  job->button = button;
393  job->needs_refresh = 1;
394  break;
395  case 2: /* pan */
396  job->click = 1;
397  job->button = button;
398  job->needs_refresh = 1;
399  break;
400  case 3: /* insert node or edge */
401  gvevent_find_current_obj(job, pointer);
402  job->click = 1;
403  job->button = button;
404  job->needs_refresh = 1;
405  break;
406  case 4:
407  /* scrollwheel zoom in at current mouse x,y */
408 /* FIXME - should code window 0,0 point as feature with Y_GOES_DOWN */
409  job->fit_mode = 0;
410  if (job->rotation) {
411  job->focus.x -= (pointer.y - job->height / 2.)
412  * (ZOOMFACTOR - 1.) / (job->zoom * job->devscale.y);
413  job->focus.y += (pointer.x - job->width / 2.)
414  * (ZOOMFACTOR - 1.) / (job->zoom * job->devscale.x);
415  }
416  else {
417  job->focus.x += (pointer.x - job->width / 2.)
418  * (ZOOMFACTOR - 1.) / (job->zoom * job->devscale.x);
419  job->focus.y += (pointer.y - job->height / 2.)
420  * (ZOOMFACTOR - 1.) / (job->zoom * job->devscale.y);
421  }
422  job->zoom *= ZOOMFACTOR;
423  job->needs_refresh = 1;
424  break;
425  case 5: /* scrollwheel zoom out at current mouse x,y */
426  job->fit_mode = 0;
427  job->zoom /= ZOOMFACTOR;
428  if (job->rotation) {
429  job->focus.x += (pointer.y - job->height / 2.)
430  * (ZOOMFACTOR - 1.) / (job->zoom * job->devscale.y);
431  job->focus.y -= (pointer.x - job->width / 2.)
432  * (ZOOMFACTOR - 1.) / (job->zoom * job->devscale.x);
433  }
434  else {
435  job->focus.x -= (pointer.x - job->width / 2.)
436  * (ZOOMFACTOR - 1.) / (job->zoom * job->devscale.x);
437  job->focus.y -= (pointer.y - job->height / 2.)
438  * (ZOOMFACTOR - 1.) / (job->zoom * job->devscale.y);
439  }
440  job->needs_refresh = 1;
441  break;
442  }
443  job->oldpointer = pointer;
444 }
445 
446 static void gvevent_button_release(GVJ_t *job, int button, pointf pointer)
447 {
448  job->click = 0;
449  job->button = 0;
450 }
451 
452 static void gvevent_motion(GVJ_t * job, pointf pointer)
453 {
454  /* dx,dy change in position, in device independent points */
455  double dx = (pointer.x - job->oldpointer.x) / job->devscale.x;
456  double dy = (pointer.y - job->oldpointer.y) / job->devscale.y;
457 
458  if (fabs(dx) < EPSILON && fabs(dy) < EPSILON) /* ignore motion events with no motion */
459  return;
460 
461  switch (job->button) {
462  case 0: /* drag with no button - */
463  gvevent_find_current_obj(job, pointer);
464  break;
465  case 1: /* drag with button 1 - drag object */
466  /* FIXME - to be implemented */
467  break;
468  case 2: /* drag with button 2 - pan graph */
469  if (job->rotation) {
470  job->focus.x -= dy / job->zoom;
471  job->focus.y += dx / job->zoom;
472  }
473  else {
474  job->focus.x -= dx / job->zoom;
475  job->focus.y -= dy / job->zoom;
476  }
477  job->needs_refresh = 1;
478  break;
479  case 3: /* drag with button 3 - drag inserted node or uncompleted edge */
480  break;
481  }
482  job->oldpointer = pointer;
483 }
484 
485 static int quit_cb(GVJ_t * job)
486 {
487  return 1;
488 }
489 
490 static int left_cb(GVJ_t * job)
491 {
492  job->fit_mode = 0;
493  job->focus.x += PANFACTOR / job->zoom;
494  job->needs_refresh = 1;
495  return 0;
496 }
497 
498 static int right_cb(GVJ_t * job)
499 {
500  job->fit_mode = 0;
501  job->focus.x -= PANFACTOR / job->zoom;
502  job->needs_refresh = 1;
503  return 0;
504 }
505 
506 static int up_cb(GVJ_t * job)
507 {
508  job->fit_mode = 0;
509  job->focus.y += -(PANFACTOR / job->zoom);
510  job->needs_refresh = 1;
511  return 0;
512 }
513 
514 static int down_cb(GVJ_t * job)
515 {
516  job->fit_mode = 0;
517  job->focus.y -= -(PANFACTOR / job->zoom);
518  job->needs_refresh = 1;
519  return 0;
520 }
521 
522 static int zoom_in_cb(GVJ_t * job)
523 {
524  job->fit_mode = 0;
525  job->zoom *= ZOOMFACTOR;
526  job->needs_refresh = 1;
527  return 0;
528 }
529 
530 static int zoom_out_cb(GVJ_t * job)
531 {
532  job->fit_mode = 0;
533  job->zoom /= ZOOMFACTOR;
534  job->needs_refresh = 1;
535  return 0;
536 }
537 
538 static int toggle_fit_cb(GVJ_t * job)
539 {
540 /*FIXME - should allow for margins */
541 /* - similar zoom_to_fit code exists in: */
542 /* plugin/gtk/callbacks.c */
543 /* plugin/xlib/gvdevice_xlib.c */
544 /* lib/gvc/gvevent.c */
545 
546  job->fit_mode = !job->fit_mode;
547  if (job->fit_mode) {
548  /* FIXME - this code looks wrong */
549  int dflt_width, dflt_height;
550  dflt_width = job->width;
551  dflt_height = job->height;
552  job->zoom =
553  MIN((double) job->width / (double) dflt_width,
554  (double) job->height / (double) dflt_height);
555  job->focus.x = 0.0;
556  job->focus.y = 0.0;
557  job->needs_refresh = 1;
558  }
559  return 0;
560 }
561 
562 static void gvevent_modify (GVJ_t * job, const char *name, const char *value)
563 {
564  /* FIXME */
565 }
566 
567 static void gvevent_delete (GVJ_t * job)
568 {
569  /* FIXME */
570 }
571 
572 static void gvevent_read (GVJ_t * job, const char *filename, const char *layout)
573 {
574  FILE *f;
575  GVC_t *gvc;
576  Agraph_t *g = NULL;
577  gvlayout_engine_t *gvle;
578 
579  gvc = job->gvc;
580  if (!filename) {
581  g = agopen("G", Agdirected, NIL(Agdisc_t *));
582  job->output_filename = "new.gv";
583  }
584  else {
585  f = fopen(filename, "r");
586  if (!f)
587  return; /* FIXME - need some error handling */
588  g = agread(f,NIL(Agdisc_t *));
589  fclose(f);
590  }
591  if (!g)
592  return; /* FIXME - need some error handling */
593 
594  if (gvc->g) {
595  gvle = gvc->layout.engine;
596  if (gvle && gvle->cleanup)
597  gvle->cleanup(gvc->g);
598  graph_cleanup(gvc->g);
599  agclose(gvc->g);
600  }
601 
602  aginit (g, AGRAPH, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);
603  aginit (g, AGNODE, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE);
604  aginit (g, AGEDGE, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);
605  gvc->g = g;
606  GD_gvc(g) = gvc;
607  if (gvLayout(gvc, g, layout) == -1)
608  return; /* FIXME - need some error handling */
609  job->selected_obj = NULL;
610  job->current_obj = NULL;
611  job->needs_refresh = 1;
612 }
613 
614 static void gvevent_layout (GVJ_t * job, const char *layout)
615 {
616  gvLayout(job->gvc, job->gvc->g, layout);
617 }
618 
619 static void gvevent_render (GVJ_t * job, const char *format, const char *filename)
620 {
621  gvRenderFilename(job->gvc, job->gvc->g, format, filename);
622 }
623 
624 
626  {"Q", quit_cb},
627  {"Left", left_cb},
628  {"KP_Left", left_cb},
629  {"Right", right_cb},
630  {"KP_Right", right_cb},
631  {"Up", up_cb},
632  {"KP_Up", up_cb},
633  {"Down", down_cb},
634  {"KP_Down", down_cb},
635  {"plus", zoom_in_cb},
636  {"KP_Add", zoom_in_cb},
637  {"minus", zoom_out_cb},
638  {"KP_Subtract", zoom_out_cb},
639  {"F", toggle_fit_cb},
640 };
641 
642 int gvevent_key_binding_size = ARRAY_SIZE(gvevent_key_binding);
643 
645  gvevent_refresh,
646  gvevent_button_press,
647  gvevent_button_release,
648  gvevent_motion,
649  gvevent_modify,
650  gvevent_delete,
651  gvevent_read,
652  gvevent_layout,
653  gvevent_render,
654 };
#define ZOOMFACTOR
Definition: gvevent.c:35
Agnode_t * agtail(Agedge_t *e)
Definition: edge.c:494
int rotation
Definition: gvcjob.h:328
#define GUI_STATE_SELECTED
Definition: types.h:257
int gvRenderFilename(GVC_t *gvc, graph_t *g, const char *format, const char *filename)
Definition: gvc.c:129
Agnode_t * aghead(Agedge_t *e)
Definition: edge.c:502
void graph_cleanup(graph_t *g)
Definition: input.c:841
void * current_obj
Definition: gvcjob.h:355
bool layout(Agraph_t *g, const char *engine)
Definition: gv.cpp:815
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
Definition: attr.c:340
#define MIN(a, b)
Definition: arith.h:38
#define GD_n_cluster(g)
Definition: types.h:376
int agobjkind(void *)
Definition: obj.c:264
void * selected_obj
Definition: gvcjob.h:357
char * name
Definition: cgraph.h:330
gvplugin_active_layout_t layout
Definition: gvcint.h:109
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition: edge.c:25
#define GUI_STATE_VISITED
Definition: types.h:258
Definition: geom.h:30
#define CLOSEENOUGH
Definition: gvevent.c:302
int agclose(Agraph_t *g)
Definition: graph.c:93
unsigned int width
Definition: gvcjob.h:336
pointf oldpointer
Definition: gvcjob.h:353
graph_t * g
Definition: gvcint.h:106
const char * output_filename
Definition: gvcjob.h:285
char * strdup_and_subst_obj(char *str, void *n)
Definition: labels.c:451
Definition: gvcjob.h:271
gvlayout_engine_t * engine
Definition: gvcint.h:29
void(* cleanup)(graph_t *g)
#define GD_gvc(g)
Definition: types.h:338
gvdevice_callbacks_t gvdevice_callbacks
Definition: gvevent.c:644
pointf devscale
Definition: gvcjob.h:343
char * active_tooltip
Definition: gvcjob.h:359
#define PANFACTOR
Definition: gvevent.c:34
gv_argvlist_t selected_obj_type_name
Definition: gvcjob.h:361
char * selected_href
Definition: gvcjob.h:360
int gvLayout(GVC_t *gvc, graph_t *g, const char *engine)
Definition: gvc.c:65
#define NIL(t)
Definition: dthdr.h:20
#define GUI_STATE_ACTIVE
Definition: types.h:256
void free()
int i
Definition: gvdevice.c:448
void emit_graph(GVJ_t *job, graph_t *g)
Definition: emit.c:3456
double y
Definition: geom.h:30
#define GD_gui_state(g)
Definition: types.h:350
Definition: gvcint.h:70
pointf focus
Definition: gvcjob.h:325
Agraph_t * agroot(void *obj)
Definition: obj.c:169
#define ND_gui_state(n)
Definition: types.h:461
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition: node.c:45
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
Definition: graph.c:44
Agnode_t * aglstnode(Agraph_t *g)
Definition: node.c:53
#define EPSILON
Definition: gvevent.c:36
boolean overlap_node(node_t *n, boxf b)
Definition: utils.c:1586
#define agfindedgeattr(g, a)
Definition: types.h:568
Agdesc_t Agdirected
Definition: graph.c:276
boolean click
Definition: gvcjob.h:345
GVC_t * gvc
Definition: gvcjob.h:272
Agnode_t * agfstnode(Agraph_t *g)
Definition: node.c:38
#define GD_clust(g)
Definition: types.h:344
#define AGNODE
Definition: cgraph.h:88
gvevent_key_binding_t gvevent_key_binding[]
Definition: gvevent.c:625
void aginit(Agraph_t *g, int kind, char *rec_name, int rec_size, int move_to_front)
Definition: rec.c:198
unsigned char button
Definition: gvcjob.h:351
#define ARRAY_SIZE(A)
Definition: gvcjob.h:26
Agraph_t * agraphof(void *obj)
Definition: obj.c:185
#define NULL
Definition: logic.h:50
int gvevent_key_binding_size
Definition: gvevent.c:642
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition: edge.c:40
#define agfindgraphattr(g, a)
Definition: types.h:566
gv_argvlist_t selected_obj_attributes
Definition: gvcjob.h:362
pointf translation
Definition: gvcjob.h:342
Agraph_t * agread(void *chan, Agdisc_t *disc)
Definition: grammar.c:2336
double x
Definition: geom.h:30
boolean has_been_rendered
Definition: gvcjob.h:345
GVC_t * gvc
Definition: htmlparse.c:87
boolean needs_refresh
Definition: gvcjob.h:345
char * agnameof(void *)
Definition: id.c:143
boolean overlap_edge(edge_t *e, boxf b)
Definition: utils.c:1650
pointf LL
Definition: geom.h:37
boolean fit_mode
Definition: gvcjob.h:345
#define ED_gui_state(e)
Definition: types.h:543
#define GD_bb(g)
Definition: types.h:337
Agnode_t * agprvnode(Agraph_t *g, Agnode_t *n)
Definition: node.c:60
agxbuf * str
Definition: htmlparse.c:85
int agisdirected(Agraph_t *g)
Definition: graph.c:182
char * agxget(void *obj, Agsym_t *sym)
Definition: attr.c:444
#define AGEDGE
Definition: cgraph.h:91
#define agfindnodeattr(g, a)
Definition: types.h:567
double zoom
Definition: gvcjob.h:327
pointf UR
Definition: geom.h:37
Definition: geom.h:37
unsigned int height
Definition: gvcjob.h:337
void gv_argvlist_set_item(gv_argvlist_t *list, int index, char *item)
Definition: gvjobs.c:112
char ** argv
Definition: gvcjob.h:151
#define AGRAPH
Definition: cgraph.h:87
#define TRUE
Definition: cgraph.h:27