/* CS 476 DCG (Connect nodes with lines) Adam Palmer */ /* ??? Verify which files really need to be included */ #include #include #include #include #include #include #include #include #include #include #define DRAW 1 #define DELETE 2 #define QUIT 3 #define ERASE 4 /* Function definitions. Only interaction is through button clicks, which call one of the functions below*/ void QuitCallBack ( Widget w, XtPointer clientData, XtPointer callData ); void EraseCallBack ( Widget w, XtPointer clientData, XtPointer callData ); void DeleteCallBack ( Widget w, XtPointer clientData, XtPointer callData ); void DrawCallBack ( Widget w, XtPointer clientData, XtPointer callData ); void YesCallBack ( Widget w, XtPointer clientData, XtPointer callData ); void NoCallBack ( Widget w, XtPointer clientData, XtPointer callData ); void HandleBoardEvents ( Widget w, XtPointer clientData, XEvent *event, Boolean *flag ); //void ReDraw (Widget w, XtPointer clientData, XEvent *event); // Variable declarations for motif and xlib function calls Widget shell, panel, commands, confirm, canvas, quit, erase, delete, draw, sure, yes, no; Arg wargs[1]; Display *display; int screen; long fgcolor, bgcolor; XGCValues gcval; GC draw_pen; Colormap cmap; XColor color; Window window; /* Max of 500 nodes on canvas. Array usage Nodes[i].x, Nodes[i].y refer to the x,y coordinates of the node */ typedef struct Node { int x; int y; } Node; Node Nodes[500]; int pointx = 0; int pointy = 0; int mode = DRAW; // 1 = draw, 2 = delete, ... DEFINED constants int n = 0; int i = 0; int j = 0; int radius = 10; // radius of the node in pixels int del_candidate = 0; double del_distance = 10; double test_distance = 0; double x_diff = 0; double y_diff = 0; int max_y = 0; int max_x = 0; int pt_y = 0; int pt_x = 0; char output[20]; int main ( int argc, char **argv ){ XtAppContext app; /* * Initialize Xt. */ if ( putenv("XENVIRONMENT=dcg_environment") < 0) printf("can't set XENVIRONMENT\n"); shell = XtAppInitialize ( &app, "DrawGraph", NULL, 0, &argc, argv, NULL, NULL, 0 ); /* These commands are in support o xlib drawing functions */ display = XtDisplay(shell); screen = DefaultScreen(display); cmap = DefaultColormap (display, screen); /* * The overall window layout is handled by an XmForm widget. */ panel = XtVaCreateManagedWidget ( "panel", xmFormWidgetClass, shell, NULL, 0 ); /* * An XmRowColumn widget holds the buttons along the top * of the window. The confirm window will replace it once the * user has selected either quit or erase in order to confirm * the users choice. */ commands = XtVaCreateManagedWidget ( "commands", xmRowColumnWidgetClass, panel, XmNnumColumns, 3, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNwidth,400, XmNheight,50, NULL ); confirm = XtVaCreateManagedWidget ( "confirm", xmRowColumnWidgetClass, panel, XmNnumColumns, 3, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNwidth,400, XmNheight,50, NULL); /* The canvas is the drawing area for the nodes and lines */ canvas = XtVaCreateManagedWidget ( "canvas", xmDrawingAreaWidgetClass, panel, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, commands, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment,XmATTACH_FORM, XmNwidth,400,XmNheight,400, NULL ); /* * The buttons in the commands and options panels are * created as XmPushButton widgets. */ quit = XtCreateManagedWidget ( "Quit", xmPushButtonWidgetClass, commands, NULL, 0 ); erase = XtCreateManagedWidget ( "Erase", xmPushButtonWidgetClass, commands, NULL, 0 ); delete = XtCreateManagedWidget ( "Delete", xmPushButtonWidgetClass, commands, NULL, 0 ); draw = XtCreateManagedWidget ( "Draw", xmPushButtonWidgetClass, commands, NULL, 0 ); sure = XtCreateManagedWidget ( "sure", xmPushButtonWidgetClass, confirm, NULL, 0 ); yes = XtCreateManagedWidget ( "Yes", xmPushButtonWidgetClass, confirm, NULL, 0 ); no = XtCreateManagedWidget ( "No", xmPushButtonWidgetClass, confirm, NULL, 0 ); /*Identify function calls for screen actions */ XtAddCallback ( quit, XmNactivateCallback,QuitCallBack, NULL ); XtAddCallback ( erase, XmNactivateCallback, EraseCallBack, NULL ); XtAddCallback ( delete, XmNactivateCallback, DeleteCallBack, NULL ); XtAddCallback ( draw, XmNactivateCallback, DrawCallBack, NULL ); XtAddCallback ( yes, XmNactivateCallback, YesCallBack, NULL ); XtAddCallback ( no, XmNactivateCallback, NoCallBack, NULL ); display= XtDisplay(shell); screen = DefaultScreen(display); XtVaGetValues ( canvas, XmNforeground, &gcval.foreground, XmNbackground, &gcval.background, NULL ); XtAddEventHandler(canvas,ButtonPressMask, FALSE,HandleBoardEvents, NULL); mode = DRAW; XtVaSetValues(draw, XmNsensitive, False, NULL); XtVaSetValues(delete, XmNsensitive, True, NULL); // Initial curses screen and then the motif interface getmaxyx(initscr(), max_y, max_x); clear(); refresh(); noecho(); /* stop echo of input */ XtRealizeWidget ( shell ); XtAppMainLoop ( app ); } void QuitCallBack ( Widget w, XtPointer clientData, XtPointer callData){ mode = QUIT; XtSetArg(wargs[0], XmNlabelString, XmStringCreateLocalized("Are you sure you want to quit?")); XtSetValues(sure,wargs,1); //XtVaSetValues(sure, XmNsensitive, False, NULL); XtUnmapWidget(commands); XtMapWidget(confirm); } void EraseCallBack ( Widget w, XtPointer clientData, XtPointer callData ){ mode = ERASE; XtSetArg(wargs[0], XmNlabelString, XmStringCreateLocalized("Are you sure you want to erase all?")); XtSetValues(sure,wargs,1); //XtVaSetValues(sure, XmNsensitive, False, NULL); XtUnmapWidget(commands); XtMapWidget(confirm); } void YesCallBack ( Widget w, XtPointer clientData, XtPointer callData){ /* Action varies based on the button that initiated the confirmation */ switch (mode) { case QUIT: endwin(); exit(0); break; case ERASE: XtUnmapWidget(confirm); XtMapWidget(commands); XClearWindow(display, XtWindow(canvas)); XtVaSetValues(draw, XmNsensitive, False, NULL); XtVaSetValues(delete, XmNsensitive, True, NULL); mode = DRAW; n = 0; // Clears the Nodes array of all x,y pairs clear(); refresh(); break; } } void NoCallBack ( Widget w, XtPointer clientData, XtPointer callData){ XtUnmapWidget(confirm); XtMapWidget(commands); XtVaSetValues(draw, XmNsensitive, False, NULL); XtVaSetValues(delete, XmNsensitive, True, NULL); mode = DRAW; } void DeleteCallBack ( Widget w, XtPointer clientData, XtPointer callData ){ mode = DELETE; XtVaSetValues(delete, XmNsensitive, False, NULL); XtVaSetValues(draw, XmNsensitive, True, NULL); } void DrawCallBack ( Widget w, XtPointer clientData, XtPointer callData ){ mode = DRAW; XtVaSetValues(draw, XmNsensitive, False, NULL); XtVaSetValues(delete, XmNsensitive, True, NULL); } void HandleBoardEvents ( Widget w, XtPointer clientData, XEvent *event, Boolean *flag ){ draw_pen = XDefaultGC(display,screen); if(mode == DRAW) { // Upon click, Update array, draw node, then connect with lines to all other nodes n = n + 1; Nodes[n].x = event->xbutton.x; Nodes[n].y = event->xbutton.y; pointx = Nodes[n].x; pointy = Nodes[n].y; pt_y = (pointy * (max_y - 1)) / 400; pt_x = (pointx * (max_x -1)) / 400; sprintf(output,"o%d(%d,%d)",n,pointx,pointy); move(pt_y,pt_x); // move function is backwards with format y,x addstr(output); refresh(); XDrawArc (XtDisplay(canvas),XtWindow(canvas),draw_pen, pointx - radius, pointy - radius,2*radius, 2*radius,0,360*64); for (i = 1; i < n; i++) XDrawLine(XtDisplay(canvas),XtWindow(canvas),draw_pen,Nodes[i].x,Nodes[i].y,Nodes[n].x,Nodes[n].y); } if(mode == DELETE) { del_candidate = 0; Nodes[0].x = event->xbutton.x; Nodes[0].y = event->xbutton.y; for (i = 1; i <= n; i++) { x_diff = Nodes[0].x - Nodes[i].x; y_diff = Nodes[0].y - Nodes[i].y; test_distance = sqrt((x_diff * x_diff) + (y_diff * y_diff)); if (test_distance < del_distance) del_candidate = i; } if (del_candidate > 0) { pointy = Nodes[del_candidate].y; pointx = Nodes[del_candidate].x; pt_y = (pointy * (max_y - 1)) / 400; pt_x = (pointx * (max_x -1)) / 400; sprintf(output,"o%d(%d,%d)",del_candidate,pointx,pointy); move(pt_y,pt_x); // move function is backwards with format y,x for (i = 1; i <= strlen(output); i++) { addch(' '); } refresh(); Nodes[del_candidate].x = Nodes[n].x; Nodes[del_candidate].y = Nodes[n].y; n = n - 1; //ReDraw(canvas, clientData, &event); XClearWindow(XtDisplay(canvas), XtWindow(canvas)); for (i = 1; i <= n; i++) { XDrawArc (XtDisplay(canvas),XtWindow(canvas),draw_pen, Nodes[i].x - radius, Nodes[i].y - radius,2*radius, 2*radius,0,360*64); for (j = i + 1 ; j <= n; j++) { XDrawLine(XtDisplay(canvas),XtWindow(canvas),draw_pen,Nodes[i].x,Nodes[i].y,Nodes[j].x,Nodes[j].y); } } /*if (n = 0) { mode = DRAW; // No more nodes to delete, so revert to draw XtVaSetValues(draw, XmNsensitive, False, NULL); XtVaSetValues(delete, XmNsensitive, True, NULL); }*/ } } }