Hi Henner, The way I did it in the Piglet hierarchical drawing editor[1] was to put a function in each primitive that is responsible for drawing rubberband representations of the primitive. The drawing function gets fed a sequence of transformed mouse coordinates by a callback in the eventloop.
So for my line drawing primitive, when my parser decides something needs to be moved, I set a callback with the event loop with: `rubber_set_callback(draw_line); draw_line(double x, double y, int count) is my callback function and is different for each primitive. It is always called with the current x,y mouse coordinates and a count. The count starts at zero and increments for every new coordinate. After the parser is done with the rubber band drawing and has accepted the pick, it calls rubber_clear_callback(); to clear the callback. After receiving rubber_clear_callback(), the event loop sends one final call to draw_line, this time with a count of -1. The draw_line function in geom_line.c looks like this: void draw_line(double x2, double y2, int count) { ... if (count == 0) { /* first call */ jump(&bb, D_RUBBER); /* draw new shape */ do_line(&dbdeflist, &bb, D_RUBBER); } else if (count > 0) { /* intermediate calls */ jump(&bb, D_RUBBER); /* erase old shape */ do_line(&dbdeflist, &bb, D_RUBBER); jump(&bb, D_RUBBER); /* draw new shape */ coord_swap_last(CP, x2, y2); /* update new coords */ do_line(&dbdeflist, &bb, D_RUBBER); } else { /* last call, cleanup */ jump(&bb, D_RUBBER); /* erase old shape */ do_line(&dbdeflist, &bb, D_RUBBER); } .... /* save old values */ x1old=x1; y1old=yy1; x2old=x2; y2old=y2; jump(&bb, D_RUBBER); } The jump() starts a new disconnected segment and turns the drawing engine to XOR mode (D_RUBBER). Then I just call the main line drawing routine with the current list of coords. The key thing is that the XWIN event loop calls the draw_line routine through the callback with an integer count argument. On the first time we just do an XOR. The second and subsequent times, we remember our old position and unwrite it with an XOR before drawing the new coordinate. Finally, after the event loop gets a rubber_clear_callback(), the last call has count=-1. This causees the last drawing to be erased and no new one to be made. Every primitive has its own specific callback for rubber band drawing. For instance, I represent hierarchical sub-cells by just a bounding box so that I don't have to render all the details. I found that having a centralized callback from the event loop that simply sends back the mouse coordinates to the rubber band drawing routine simplified my code and gave me a standard way to handle the XOR cleanup problem. Here's the callback hook from the xwin.c event loop. while (XCheckMaskEvent(dpy, all, &xe)) { /* pending X Event */ switch (xe.type) { case MotionNotify: ... if (xold != x || yold != y) { if (xwin_display_state() == D_ON) { rubber_draw(x, y); } xold=x; yold=y; } ... Here's the code for rubber.c /* ************************************************************* this set of routines manages the rubber band drawing function for interactive point selection. The rubber band shapes are drawn with an xor function such that drawing a line twice will erase it. We need to ensure that the first shape drawn after rubber_set_callback() gets erased before the second shape is drawn, and so on, until the last call is made by rubber_clear_callback(). rubber_set_callback(); First call (x1,y1,0): draw x1, y1 Second call (x2,y2,1) draw x1, y1 # erase last shape draw x2, y2 # drawn new shape (N-1)th call (x(n-1),y(n-1), n-1) draw x(n-2), y(n-2) # erase last shape draw x(n-1), y(n-1) # draw new shape rubber_clear_callback(); Last call (xn, yn, -1) draw x(n-1), y(n-1) # erase last shape # and DONT draw new shape The callback function manages this behavior by the count variable passed in the third argument. When count==0, it only draws the specified shape. When count>=0 it always undraws the old shape prior to drawing the new shape. When count<=0 it will undraw the old shape, and NOT draw a new shape. rubber_clear_callback() is responsible for making the last call with count=-1. ************************************************************* */ #include <stdio.h> #include "rubber.h" typedef int Function (); static int count=0; Function * rubber_callback = NULL; void rubber_set_callback(func) Function * func; { count=0; rubber_callback = func; } void rubber_clear_callback() { /* let callback do final erase */ if (rubber_callback != NULL) { (*(rubber_callback)) (0.0, 0.0, -1); } /* clear the callback function */ rubber_callback = (Function *) NULL; count=0; } /* called with count == 0 on first call, count++ subsequent calls, and * -1 on final call. The drawing routine must erase previous draws on * all calls with count >0. */ void rubber_draw(x,y) double x, y; { int debug=0; if (rubber_callback != NULL) { if (debug) printf("rubber_draw: drawing: %g %g %d\n", x,y, count); (*(rubber_callback)) (x, y, count); count++; } } Hope that gives you some ideas... kind regards, -- Rick Walker [1] www.github.com/omnister/piglet _______________________________________________ Mailing list: https://launchpad.net/~kicad-developers Post to : kicad-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~kicad-developers More help : https://help.launchpad.net/ListHelp