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