/* rubber2.c rubber band with snap to grid */ /* Draw rectangle. left mouse down=first point */ /* Drag to second point. left mouse up=final point */ /* right mouse changes color of first figure area */ /* show grid and snap to grid */ #include #include #include #include #include /* macro definitions */ #undef max #define max(a,b) (a)>(b)?(a):(b) #undef min #define min(a,b) (a)<(b)?(a):(b) #undef abs #define abs(a) (a)<0?(-(a)):(a) /* local functions */ static void StartRubberBand ( Widget w, XtPointer clientData, XEvent *event, Boolean *flag ); static void EndRubberBand ( Widget w, XtPointer clientData, XEvent *event, Boolean *flag ); static void TrackRubberBand ( Widget w, XtPointer clientData, XEvent *event, Boolean *flag ); static void redraw(void); static void pick(int x, int y); static void draw_clear(XColor background_color); static void grid_snap(int * x, int * y); static void draw_grid(void); static void draw_line_rectangle(int x0, int y0, int width, int height, XColor line_color, int line_width); static XtAppContext app_context; static Display *display; static Window windowId; static int screen_num; static GC gc_line; static GC gc_grid; static int startX, startY, lastX, lastY; static GC gc_rubber; static XGCValues xgcvalues; static XColor white_c, black_c, red_c, green_c, exact_c; static Colormap cmap; static Pixel fg, bg; static Status status; static Pixel draw_a_bg; static int winWidth = 500; static int winHeight = 500; static int x0, y0, x1, y1; /* x = ((xg-xoff)*scale)+winWidth */ static int grid_snap_on=1; /* grid stuff */ static int grid_spacing=20; static int grid_displayed=1; #define RECTANGLE 1 static int obj_kind = RECTANGLE; /* only one kind, could be many */ /* widgets indented according to heirarchy */ Widget toplevel; Widget main_w; Widget draw_a; typedef struct{int kind; int x0; int y0; int width; int height; XColor c; int thick;} fig; static fig figure[100]; /* list of figures to draw */ static int num_fig = 0; static int iselect = 0; static void redraw(void) { int i; draw_clear(white_c); if(grid_snap_on) draw_grid(); /* call things to draw from display list */ for(i=0; ifigure[i].x0+figure[i].width) continue; if(yfigure[i].y0+figure[i].height) continue; /* select here by just changing color */ figure[iselect].c = red_c; iselect = i; figure[iselect].c = green_c; break; } redraw(); } /* main - sets up all windows and widgets then performs initialization then receives messages */ int main(int argc, char *argv[]) { /* callback functions, just dummies */ void expose_CB(); /* Initialize toolkit, open display and create application shell. */ toplevel = XtVaAppInitialize(&app_context, "Draw0", NULL, 0, &argc, argv, NULL, NULL); /* Create MainWindow. */ main_w = XtVaCreateManagedWidget("main", xmMainWindowWidgetClass, toplevel, XmNshadowThickness, 0, NULL); draw_a = XtVaCreateManagedWidget ("canvas", xmDrawingAreaWidgetClass, main_w, XmNwidth, winWidth, XmNheight, winHeight, NULL); XtAddEventHandler ( draw_a, ButtonPressMask, FALSE, StartRubberBand, NULL ); XtAddEventHandler ( draw_a, ButtonMotionMask, FALSE, TrackRubberBand, NULL ); XtAddEventHandler ( draw_a, ButtonReleaseMask, FALSE, EndRubberBand, NULL ); XtAddCallback(draw_a, XmNexposeCallback, (XtCallbackProc)(expose_CB), NULL); XtManageChild(draw_a); XtVaSetValues(toplevel, XmNworkWindow, draw_a, NULL); XtRealizeWidget(toplevel); display = XtDisplay(toplevel); screen_num = XDefaultScreen(display); cmap = XDefaultColormap(display, screen_num); status = XAllocNamedColor(display, cmap, "white", &white_c, &exact_c); if (!status) printf("no white \n"); status = XAllocNamedColor(display, cmap, "black", &black_c, &exact_c); if (!status) printf("no black \n"); status = XAllocNamedColor(display, cmap, "red", &red_c, &exact_c); if (!status) printf("no red \n"); status = XAllocNamedColor(display, cmap, "green", &green_c, &exact_c); if (!status) printf("no green \n"); gc_line = XCreateGC(XtDisplay(draw_a), XtWindow(draw_a), 0, &xgcvalues); gc_grid = XCreateGC(XtDisplay(draw_a), XtWindow(draw_a), 0, &xgcvalues); gc_rubber = XDefaultGC(display, screen_num); /* Establish a passive grab, for any button press. Force the mouse cursor to stay within the canvas window, and change the mouse cursor to a cross_hair. */ XGrabButton ( XtDisplay ( draw_a ), AnyButton, AnyModifier, XtWindow ( draw_a ), TRUE, ButtonPressMask | ButtonMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, XtWindow ( draw_a ), XCreateFontCursor (XtDisplay(draw_a), XC_crosshair)); /* Create the GC used by the rubber banding functions. */ XtVaGetValues ( draw_a, XmNforeground, &xgcvalues.foreground, XmNbackground, &xgcvalues.background, NULL ); /* Set the foreground color to the XOR of the foreground and background colors, so that if an image is drawn on the background using this GC, it will be displayed as the foreground color, and vice-versa. */ xgcvalues.foreground = xgcvalues.foreground ^ xgcvalues.background; /* Set the rubber band gc to use XOR mode and draw dashed line. */ xgcvalues.line_style = LineOnOffDash; xgcvalues.function = GXxor; gc_rubber = XtGetGC ( draw_a, GCForeground | GCBackground | GCFunction | GCLineStyle, &xgcvalues ); draw_a_bg = white_c.pixel; XSetLineAttributes(display, gc_line, 1, 0, 2, 1); XSetBackground(display, gc_line, white_c.pixel); XSetBackground(display, gc_grid, white_c.pixel); XSetForeground(display, gc_grid, black_c.pixel); XtVaSetValues(draw_a, XmNbackground, white_c.pixel, NULL); XSetBackground(display, gc_line, white_c.pixel); draw_a_bg = white_c.pixel; XtVaSetValues(draw_a, XmNbackground, draw_a_bg, NULL); XtAppMainLoop(app_context); return 0; } /* end main */ /* callbacks */ /* expose_CB - redraw contents of drawing area when exposed */ void expose_CB(Widget w, XtPointer users, XmAnyCallbackStruct *call_data) { /* send expose message to draw object */ redraw(); } /* StartRubberBand - reacts to button press in drawing area */ static void StartRubberBand ( Widget w, XtPointer clientData, XEvent *event, Boolean *flag ) { startX = event->xbutton.x; startY = event->xbutton.y; if(grid_snap_on) grid_snap(&startX, &startY); lastX = startX; lastY = startY; /* printf("button down B,startX,startY = %d %d,%d \n", event->xbutton.button, startX, startY); */ if(event->xbutton.button==1) obj_kind=RECTANGLE; if(event->xbutton.button==2 || event->xbutton.button==3) { pick(startX, startY); } } /* reacts to mouse motion in drawing area */ static void TrackRubberBand ( Widget w, XtPointer clientData, XEvent *event, Boolean *flag ) { /* button 1 motion thus outline obj_kind object */ if (obj_kind == RECTANGLE ) { XDrawRectangle( XtDisplay ( w ), XtWindow ( w ), gc_rubber, min(startX,lastX), min(startY,lastY), abs(lastX-startX), abs(lastY-startY) ); lastX = event->xbutton.x; lastY = event->xbutton.y; /* printf("track B,startX,startY = %d %d,%d \n", event->xbutton.button, lastX, lastY); */ if(grid_snap_on) grid_snap(&lastX, &lastY); XDrawRectangle( XtDisplay ( w ), XtWindow ( w ), gc_rubber, min(startX,lastX), min(startY,lastY), abs(lastX-startX), abs(lastY-startY) ); } } /* reacts to button release in drawing area */ static void EndRubberBand ( Widget w, XtPointer clientData, XEvent *event, Boolean *flag ) { if (obj_kind == RECTANGLE) { XDrawRectangle( XtDisplay ( w ), XtWindow ( w ), gc_rubber, min(startX,lastX), min(startY,lastY), abs(lastX-startX), abs(lastY-startY) ); lastX = event->xbutton.x; lastY = event->xbutton.y; /* printf("end B,startX,startY = %d %d,%d \n", event->xbutton.button, lastX, lastY); */ if(grid_snap_on) grid_snap(&lastX, &lastY); if(event->xbutton.button==1) create_rectangle(min(startX,lastX), min(startY,lastY), abs(lastX-startX), abs(lastY-startY)); } } /* end EndRubberBand callback */ static void draw_clear(XColor background_color) { XClearArea(XtDisplay(draw_a), XtWindow(draw_a), 0, 0, 0, 0, False); XtVaSetValues(draw_a, XmNbackground, background_color.pixel, NULL); } static void draw_line_rectangle(int x0, int y0, int width, int height, XColor line_color, int line_width) { int line_style = 0; /* LineSolid */ int cap_style = 2; /* CapRound */ int join_style = 1; /* JoinRound */ XSetLineAttributes(display, gc_line, line_width, line_style, cap_style, join_style); XSetForeground(display, gc_line, line_color.pixel); XDrawRectangle(display, XtWindow ( draw_a ), gc_line, x0, y0, width, height); } /* end draw_line_rectangle */ static void grid_snap(int *x, int *y) { int xg, yg; /* snap to real world coordinates grid */ if(!grid_snap_on) return; xg = (*x/grid_spacing)*grid_spacing; yg = (*y/grid_spacing)*grid_spacing; *x = xg; *y = yg; } static void draw_grid(void) { int i, j, x, y; /* screen */ for(i=grid_spacing; i