]> granicus.if.org Git - graphviz/commitdiff
initial mouse -> graph object events.
authorellson <devnull@localhost>
Thu, 28 Apr 2005 20:48:56 +0000 (20:48 +0000)
committerellson <devnull@localhost>
Thu, 28 Apr 2005 20:48:56 +0000 (20:48 +0000)
lib/gvc/gvcint.h
lib/gvc/gvevent.c

index 378b16284b4656891f5f7912faa2fe89ca52b8b8..8e9be29bb140f81d10d3660ec86a71776c496282 100644 (file)
@@ -121,6 +121,7 @@ extern "C" {
        
        boolean fit_mode, needs_refresh, click, active, has_grown;
        double oldx, oldy;      /* old pointer position in pixels */
+       void *current_obj;      /* graph object that pointer is in currrently */
 
        void *window;           /* display-specific data for gvrender plugin */
     };
index 7cdccefeb561c3089ce81670665b4d7bd5b42ae2..6bcd21030549b0ef9565b377dc2d2938682725aa 100644 (file)
@@ -37,12 +37,135 @@ void gvevent_refresh(GVJ_t * job)
     emit_graph(job, job->g);
 }
 
+static boolean inside_node_bb(node_t *n, pointf P)
+{
+    boxf bb;
+
+    bb.UR.x = ND_coord_i(n).x + ND_rw_i(n);
+    bb.UR.y = ND_coord_i(n).y + ND_ht_i(n) / 2.;
+    bb.LL.x = ND_coord_i(n).x - ND_lw_i(n);
+    bb.LL.y = ND_coord_i(n).y - ND_ht_i(n) / 2.;
+    return (INSIDE(P, bb));
+}
+
+static boolean inside_node(node_t *n, pointf p)
+{
+    inside_t ictxt;
+
+    ictxt.s.n = n;
+    ictxt.s.bp = NULL;
+
+//    return ND_shape(n)->fns->insidefn(&ictxt, p);
+    return TRUE;
+}
+
+static boolean inside_edge_bb(edge_t *e, pointf P)
+{
+    int i, j, k;
+    bezier bz;
+    boxf BB;
+    box bb;
+    
+    for (i = 0; i < ED_spl(e)->size; i++) {
+       bz = ED_spl(e)->list[i];
+       for (j = 0; j < bz.size -1; j += 3) {
+           /* compute a bb for the bezier segment */
+           bb.LL = bb.UR = bz.list[j];
+           for (k = j+1; k < j+4; k++) {
+               bb.LL.x = MIN(bb.LL.x,bz.list[k].x);
+               bb.LL.y = MIN(bb.LL.y,bz.list[k].y);
+               bb.UR.x = MAX(bb.UR.x,bz.list[k].x);
+               bb.UR.y = MAX(bb.UR.y,bz.list[k].y);
+           }
+           B2BF(bb,BB);
+           if (INSIDE(P,BB))
+               return TRUE;
+       }
+    }
+    return FALSE;
+}
+
+static boolean inside_edge(edge_t *n, pointf p)
+{
+    return TRUE;
+}
+
+static graph_t *gvevent_find_cluster(graph_t *g, pointf P)
+{
+    int i;
+    graph_t *sg;
+    boxf BB;
+
+    for (i = 1; i <= GD_n_cluster(g); i++) {
+       sg = gvevent_find_cluster(GD_clust(g)[i], P);
+       if (sg)
+           return(sg);
+    }
+    B2BF(GD_bb(g), BB);
+    if (INSIDE(P, BB))
+       return g;
+    return NULL;
+}
+
+static void * gvevent_find_obj(GVJ_t * job, pointf p)
+{
+    graph_t *sg, *g = job->g;
+    node_t *n;
+    edge_t *e;
+    pointf P; /* point in graph coordinates */
+
+    /* convert point to graph coordinates */
+    if (job->rotation) {
+       P.x = job->focus.y - (p.y - job->height / 2.) / job->compscale.x;
+       P.y = (p.x - job->width / 2.) / job->compscale.y + job->focus.x;
+    }
+    else {
+       P.x = (p.x - job->width / 2.) / job->compscale.x + job->focus.x;
+       P.y = (p.y - job->height / 2.) / job->compscale.y + job->focus.y;
+    }
+
+    /* search graph backwards to get topmost node, in case of overlap */
+    for (n = aglstnode(g); n; n = agprvnode(g, n)) {
+       if (inside_node_bb(n, P) && inside_node(n, p))
+           return (void *)n;
+       for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
+           if (inside_edge_bb(e, P) && inside_edge(e, p))
+               return (void *)e;
+       }
+    }
+    
+    /* search for innermost cluster */
+
+    sg = gvevent_find_cluster(g, P);
+    if (sg)
+       return (void *)sg;
+
+    /* otherwise - we're always in the graph */
+    return (void *)g;
+}
+
+static void gvevent_find_current_obj(GVJ_t * job, double x, double y)
+{
+    void *obj;
+    pointf p;
+
+    p.x = x;
+    p.y = y;
+    obj = gvevent_find_obj(job, p);
+    if (obj != job->current_obj) {
+       job->current_obj = obj;
+fprintf(stderr,"obj=%x kind=%d\n",obj,agobjkind(obj));
+    }
+}
+
 void gvevent_button_press(GVJ_t * job, int button, double x, double y)
 {
     switch (button) {
     case 1: /* select / create in edit mode */
+    case 3: /* insert node or edge */
+       gvevent_find_current_obj(job, x, y);
+        /* fall through */
     case 2: /* pan */
-    case 3: /*        / delete in edit mode */
         job->click = 1;
        job->active = button;
        job->needs_refresh = 1;
@@ -81,7 +204,7 @@ void gvevent_motion(GVJ_t * job, double x, double y)
 
     switch (job->active) {
     case 0: /* drag with no button - */
-       return;
+       gvevent_find_current_obj(job, x, y);
        break;
     case 1: /* drag with button 1 - drag object */
        /* FIXME - to be implemented */
@@ -91,7 +214,7 @@ void gvevent_motion(GVJ_t * job, double x, double y)
        job->focus.y -= -dy / job->zoom;
        job->needs_refresh = 1;
        break;
-    case 3: /* drag with button 3 - unused */
+    case 3: /* drag with button 3 - drag inserted node or uncompleted edge */
        break;
     }
     job->oldx = x;