#define DEFAULT_COLOR "black"
#define DEFAULT_ACTIVEPENCOLOR "yellow"
#define DEFAULT_ACTIVEFILLCOLOR "yellow"
+#define DEFAULT_SELECTEDPENCOLOR "orange"
+#define DEFAULT_SELECTEDFILLCOLOR "orange"
#define DEFAULT_FONTSIZE 14.0
#define DEFAULT_LABEL_FONTSIZE 11.0 /* for head/taillabel */
#define MIN_FONTSIZE 1.0
if (*p == ':')
numc++;
- if (ED_active(e)) {
+ if (ED_selected(e)) {
+ color = late_nnstring(e, E_selectedpencolor, DEFAULT_SELECTEDPENCOLOR);
+ gvrender_set_pencolor(job, color);
+ color = late_nnstring(e, E_selectedfillcolor, DEFAULT_SELECTEDFILLCOLOR);
+ gvrender_set_fillcolor(job, color);
+ }
+ else if (ED_active(e)) {
color = late_nnstring(e, E_activepencolor, DEFAULT_ACTIVEPENCOLOR);
gvrender_set_pencolor(job, color);
color = late_nnstring(e, E_activefillcolor, DEFAULT_ACTIVEFILLCOLOR);
colors = strdup(color);
for (cnum = 0, color = strtok(colors, ":"); color;
cnum++, color = strtok(0, ":")) {
- if (! ED_active(e)) {
+ if (! ED_active(e) && ! ED_selected(e)) {
if (color[0]) {
gvrender_set_pencolor(job, color);
gvrender_set_fillcolor(job, color);
free(offspl.list);
free(tmpspl.list);
} else {
- if (! ED_active(e)) {
+ if (! ED_active(e) && ! ED_selected(e)) {
if (color[0]) {
gvrender_set_pencolor(job, color);
gvrender_set_fillcolor(job, color);
break;
}
}
- if (GD_active(sg)) {
+ if (GD_selected(sg)) {
+ color = late_nnstring(sg, G_activepencolor, DEFAULT_SELECTEDPENCOLOR);
+ gvrender_set_pencolor(job, color);
+ color = late_nnstring(sg, G_activefillcolor, DEFAULT_SELECTEDFILLCOLOR);
+ gvrender_set_fillcolor(job, color);
+ }
+ else if (GD_active(sg)) {
color = late_nnstring(sg, G_activepencolor, DEFAULT_ACTIVEPENCOLOR);
gvrender_set_pencolor(job, color);
color = late_nnstring(sg, G_activefillcolor, DEFAULT_ACTIVEFILLCOLOR);
EXTERN attrsym_t
*G_activepencolor, *G_activefillcolor,
+ *G_selectedpencolor, *G_selectedfillcolor,
*G_peripheries;
EXTERN attrsym_t
*N_height, *N_width, *N_shape, *N_color, *N_fillcolor,
*N_activepencolor, *N_activefillcolor,
+ *N_selectedpencolor, *N_selectedfillcolor,
*N_fontsize, *N_fontname, *N_fontcolor,
*N_label, *N_nojustify, *N_style, *N_showboxes,
*N_sides, *N_peripheries, *N_orientation,
EXTERN attrsym_t
*E_weight, *E_minlen, *E_color,
*E_activepencolor, *E_activefillcolor,
+ *E_selectedpencolor, *E_selectedfillcolor,
*E_fontsize, *E_fontname, *E_fontcolor,
*E_label, *E_dir, *E_style, *E_decorate,
*E_showboxes, *E_arrowsz, *E_constr, *E_layer,
return (s0 == s1);
}
-static
-void activepencolor(GVJ_t * job, node_t * n)
-{
- char *color;
-
- color = late_nnstring(n, N_activepencolor, DEFAULT_ACTIVEPENCOLOR);
- gvrender_set_pencolor(job, color);
-}
-
-static
-void activefillcolor(GVJ_t * job, node_t * n)
-{
- char *color;
-
- color = late_nnstring(n, N_activefillcolor, DEFAULT_ACTIVEFILLCOLOR);
- gvrender_set_fillcolor(job, color);
-}
-
static
void pencolor(GVJ_t * job, node_t * n)
{
return color;
}
-static void fillcolor(GVJ_t * job, node_t * n)
-{
- gvrender_set_fillcolor(job, findFill(n));
-}
-
static char **checkStyle(node_t * n, int *flagp)
{
char *style;
} else { /* diagonals are weird. rewrite someday. */
pencolor(job, n);
if (style & FILLED)
- fillcolor(job, n); /* emit fill color */
+ gvrender_set_fillcolor(job, findFill(n)); /* emit fill color */
gvrender_polygon(job, A, sides, style & FILLED);
for (seg = 0; seg < sides; seg++) {
#ifdef NOTDEF
static int A_size;
boolean filled;
extern int xdemitState;
+ char *color;
xdemitState = EMIT_DRAW;
poly = (polygon_t *) ND_shape_info(n);
} else {
style = stylenode(job, n);
}
- if (ND_active(n)) {
- activefillcolor(job,n);
+ if (ND_selected(n)) {
+ color = late_nnstring(n, N_selectedpencolor, DEFAULT_SELECTEDPENCOLOR);
+ gvrender_set_pencolor(job, color);
+ color = late_nnstring(n, N_selectedfillcolor, DEFAULT_SELECTEDFILLCOLOR);
+ gvrender_set_fillcolor(job, color);
+ filled = TRUE;
+ }
+ else if (ND_active(n)) {
+ color = late_nnstring(n, N_activepencolor, DEFAULT_ACTIVEPENCOLOR);
+ gvrender_set_pencolor(job, color);
+ color = late_nnstring(n, N_activefillcolor, DEFAULT_ACTIVEFILLCOLOR);
+ gvrender_set_fillcolor(job, color);
filled = TRUE;
- activepencolor(job,n);
}
else {
if (style & FILLED) {
- fillcolor(job, n); /* emit fill color */
+ gvrender_set_fillcolor(job, findFill(n)); /* emit fill color */
filled = TRUE;
} else {
filled = FALSE;
style = stylenode(job, n);
pencolor(job, n);
if (style & FILLED)
- fillcolor(job, n); /* emit fill color */
+ gvrender_set_fillcolor(job, findFill(n)); /* emit fill color */
if (streq(ND_shape(n)->name, "Mrecord"))
style |= ROUNDED;
if (style & (ROUNDED | DIAGONALS))
0, R_VALUE, R_FILL, R_COMPRESS, R_AUTO, R_EXPAND } ratio_t;
typedef struct layout_t {
- double quantum, scale;
+ double quantum;
+ double scale;
double ratio; /* set only if ratio_kind == R_VALUE */
double dpi;
- point margin, page, size;
- boolean filled, landscape, centered;
+ point margin;
+ point page;
+ point size;
+ boolean filled;
+ boolean landscape;
+ boolean centered;
ratio_t ratio_kind;
} layout_t;
textlabel_t *label; /* if the cluster has a title */
box bb; /* bounding box */
point border[4]; /* sizes of margins for graph labels */
- boolean has_labels, has_images, active;
+ boolean has_labels;
+ boolean has_images;
+ boolean active;
+ boolean selected;
unsigned char charset; /* input character set */
int rankdir;
int ht1, ht2; /* below and above extremal ranks */
/* various flags */
boolean has_flat_edges;
- boolean showboxes;
+ boolean showboxes;
boolean cluster_was_collapsed;
int nodesep, ranksep;
#define GD_rankleader(g) (g)->u.rankleader
#define GD_ranksep(g) (g)->u.ranksep
#define GD_rn(g) (g)->u.rn
+#define GD_selected(g) (g)->u.selected
#define GD_set_type(g) (g)->u.set_type
#define GD_label_pos(g) (g)->u.label_pos
#define GD_showboxes(g) (g)->u.showboxes
void *alg;
char state;
boolean clustnode;
- boolean active;
+ boolean active;
+ boolean selected;
#ifndef DOT_ONLY
boolean pinned;
double *pos, dist;
#endif
#ifndef NEATO_ONLY
- boolean showboxes, has_port;
+ boolean showboxes;
+ boolean has_port;
/* fast graph */
char node_type, mark, onstack;
#define ND_rw_i(n) (n)->u.rw
#define ND_save_in(n) (n)->u.save_in
#define ND_save_out(n) (n)->u.save_out
+#define ND_selected(n) (n)->u.selected
#define ND_shape(n) (n)->u.shape
#define ND_shape_info(n) (n)->u.shape_info
#define ND_showboxes(n) (n)->u.showboxes
edge_t *to_orig; /* for dot's shapes.c */
void *alg;
boolean active;
+ boolean selected;
#ifndef DOT_ONLY
double factor;
#define ED_label_ontop(e) (e)->u.label_ontop
#define ED_minlen(e) (e)->u.minlen
#define ED_path(e) (e)->u.path
+#define ED_selected(e) (e)->u.selected
#define ED_showboxes(e) (e)->u.showboxes
#define ED_spl(e) (e)->u.spl
#define ED_tail_label(e) (e)->u.tail_label
double x0; double y0;
} gv_matrix_t;
+ typedef struct gv_argvlist_s {
+ char **argv;
+ int argc;
+ int alloc;
+ } gv_argvlist_t;
+
struct GVJ_s {
GVJ_t *next; /* linked list of jobs */
GVJ_t *next_active; /* linked list of active jobs (e.g. multiple windows) */
pointf compscale; /* composite device scale incl: scale, zoom, dpi, y_goes_down */
pointf offset; /* composite translation */
- boolean fit_mode, needs_refresh, click, active, has_grown;
+ boolean fit_mode,
+ needs_refresh,
+ click,
+ active,
+ has_grown;
+
pointf pointer; /* pointer position in device units */
pointf oldpointer; /* old pointer position in device units */
+
void *current_obj; /* graph object that pointer is in currently */
+ void *selected_obj; /* graph object that has been selected */
+ /* (e.g. button 1 clicked on current obj) */
+ char *selected_obj_type; /* "graph", "node", "edge" */
+ gv_argvlist_t selected_obj_pathname; /* e.g. "G" "cluster0" "node3" */
+ gv_argvlist_t selected_obj_attributes; /* even args are attribute names, odd are values */
+ /* e.g. "color" "red" "style" "filled" */
+
void *window; /* display-specific data for gvrender plugin */
};
}
}
+/* FIXME - gv_argvlist_set_item and gv_argvlist_free should be in a utilities sourcefile */
+static void gv_argvlist_set_item(gv_argvlist_t *list, int index, char *item)
+{
+ if (index >= list->alloc) {
+ list->alloc = index + 10;
+ list->argv = realloc(list->argv, (list->alloc)*(sizeof(char*)));
+ }
+ list->argv[index] = item;
+}
+
+static void gv_graph_attributes(gv_argvlist_t *list, graph_t *g)
+{
+ int i, j;
+ Agsym_t *a;
+
+ for (i = 0, j = 0; i < dtsize(g->univ->globattr->dict); i++) {
+ a = g->univ->globattr->list[i];
+ gv_argvlist_set_item(list, j++, a->name);
+ gv_argvlist_set_item(list, j++, agxget(g, a->index));
+ }
+ list->argc = j;
+}
+
+static void gv_node_attributes(gv_argvlist_t *list, node_t *n)
+{
+ int i, j;
+ Agsym_t *a;
+ Agraph_t *g;
+
+ g = n -> graph -> root;
+ for (i = 0, j = 0; i < dtsize(g->univ->nodeattr->dict); i++) {
+ a = g->univ->nodeattr->list[i];
+ gv_argvlist_set_item(list, j++, a->name);
+ gv_argvlist_set_item(list, j++, agxget(n, a->index));
+ }
+ list->argc = j;
+}
+
+static void gv_edge_attributes(gv_argvlist_t *list, edge_t *e)
+{
+ int i, j;
+ Agsym_t *a;
+ Agraph_t *g;
+
+ g = e -> head -> graph -> root;
+ for (i = 0, j = 0; i < dtsize(g->univ->edgeattr->dict); i++) {
+ a = g->univ->edgeattr->list[i];
+ gv_argvlist_set_item(list, j++, a->name);
+ gv_argvlist_set_item(list, j++, agxget(e, a->index));
+ }
+ list->argc = j;
+}
+
+static void gvevent_select_current_obj(GVJ_t * job)
+{
+ void *obj;
+ int i;
+
+ obj = job->selected_obj;
+ if (obj) {
+ switch (agobjkind(obj)) {
+ case AGGRAPH:
+ GD_selected((graph_t*)obj) = FALSE;
+ break;
+ case AGNODE:
+ ND_selected((node_t*)obj) = FALSE;
+ break;
+ case AGEDGE:
+ ED_selected((edge_t*)obj) = FALSE;
+ break;
+ }
+ }
+ job->selected_obj_type = "";
+
+ obj = job->current_obj;
+ if (obj) {
+ switch (agobjkind(obj)) {
+ case AGGRAPH:
+ GD_selected((graph_t*)obj) = TRUE;
+ job->selected_obj_type = "graph";
+ gv_graph_attributes(&(job->selected_obj_attributes), (graph_t*)obj);
+ break;
+ case AGNODE:
+ ND_selected((node_t*)obj) = TRUE;
+ job->selected_obj_type = "node";
+ gv_node_attributes(&(job->selected_obj_attributes), (node_t*)obj);
+ break;
+ case AGEDGE:
+ ED_selected((edge_t*)obj) = TRUE;
+ job->selected_obj_type = "edge";
+ gv_edge_attributes(&(job->selected_obj_attributes), (edge_t*)obj);
+ break;
+ }
+ }
+ job->selected_obj = obj;
+
+#if 0
+fprintf(stderr,"type = %s\n", job->selected_obj_type);
+
+for (i = 0; i < job->selected_obj_attributes.argc; i++) {
+ fprintf(stderr,"%s%s", job->selected_obj_attributes.argv[i], (i%2)?"\n":" = ");
+}
+#endif
+}
+
void gvevent_button_press(GVJ_t * job, int button, pointf pointer)
{
switch (button) {
case 1: /* select / create in edit mode */
- case 3: /* insert node or edge */
gvevent_find_current_obj(job, pointer);
- /* fall through */
+ gvevent_select_current_obj(job);
+ job->click = 1;
+ job->active = button;
+ job->needs_refresh = 1;
+ break;
case 2: /* pan */
job->click = 1;
job->active = button;
job->needs_refresh = 1;
break;
+ case 3: /* insert node or edge */
+ gvevent_find_current_obj(job, pointer);
+ job->click = 1;
+ job->active = button;
+ job->needs_refresh = 1;
+ break;
case 4:
/* scrollwheel zoom in at current mouse x,y */
job->fit_mode = 0;
return FALSE;
}
-#if 0
-/* -R switches */
-void gvrender_output_option_job(GVC_t * gvc, char *name, char *value)
-{
-}
-#endif
-
GVJ_t *gvrender_first_job(GVC_t * gvc)
{
return (gvc->job = gvc->jobs);
return (gvc->job = job);
}
+/* FIXME - gv_argvlist_append_item and gv_argvlist_free should be in a utilities sourcefile */
+static void gv_argvlist_free(gv_argvlist_t *list)
+{
+ if (list->argv)
+ free(list->argv);
+ list->argv = NULL;
+ list->alloc = 0;
+ list->argc = 0;
+}
+
void gvrender_delete_jobs(GVC_t * gvc)
{
GVJ_t *job, *j;
job = gvc->jobs;
while ((j = job)) {
job = job->next;
+ gv_argvlist_free(&(j->selected_obj_pathname));
+ gv_argvlist_free(&(j->selected_obj_attributes));
free(j);
}
gvc->jobs = gvc->job = output_filename_job = output_langname_job =