====== Projekt 1 ====== [[http://www.flickr.com/photos/pitel/5210871835|{{ http://farm5.static.flickr.com/4111/5210871835_7a262a0a1d.jpg |draw by Pitel, on Flickr}}]] #include #include #include #include #include #include #include #include #include #include #include #include #include GC inputGC; /* GC used for final drawing and GC used for drawing current position */ Widget question; int x1, y1, x2, y2; /* input points */ unsigned short button_pressed = 0; /* input state */ Colormap cmap; short fill = 0; XColor red, green, blue, black, white; XColor *lineFgColor = &black; XColor *lineBgColor = &white; XColor *fillFgColor = &red; XColor *fillBgColor = &blue; unsigned int line_width = 0; int line_style = LineSolid; int cap_style = CapButt; int join_style = JoinMiter; typedef enum toolkit {POINT, LINE, RECTANGLE, ELLIPSE} toolkit; toolkit tool = LINE; struct drawing { toolkit tool; GC gc; short fill; XColor fillColor; int x1, y1, x2, y2; }; struct drawing *drawings = NULL; size_t allocated = 1; size_t ndrawings = 0; /* Save drawing */ void saveDrawing(Widget w) { ndrawings++; if (allocated <= ndrawings) { drawings = (struct drawing *) realloc(drawings, 2 * allocated * sizeof(struct drawing)); if (drawings != NULL) { allocated *= 2; } else { fprintf(stderr, "Can't allocate more drawings!\n"); exit(1); } } drawings[ndrawings - 1].gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, NULL); XSetForeground(XtDisplay(w), drawings[ndrawings - 1].gc, lineFgColor->pixel); XSetBackground(XtDisplay(w), drawings[ndrawings - 1].gc, lineBgColor->pixel); XCopyGC(XtDisplay(w), inputGC, GCLineWidth | GCLineStyle, drawings[ndrawings - 1].gc); drawings[ndrawings - 1].tool = tool; drawings[ndrawings - 1].x1 = x1; drawings[ndrawings - 1].x2 = x2; drawings[ndrawings - 1].y1 = y1; drawings[ndrawings - 1].y2 = y2; drawings[ndrawings - 1].fill = fill; drawings[ndrawings - 1].fillColor = *fillFgColor; drawings[ndrawings].gc = NULL; /* Sentinel */ } /* Input event handler */ void DrawEH(Widget w, XtPointer client_data, XEvent *event, Boolean *cont) { Pixel fg, bg; if (button_pressed) { if (!inputGC) { inputGC = XCreateGC(XtDisplay(w), XtWindow(w), 0, NULL); /*XSetPlaneMask(XtDisplay(w), inputGC, ~0);*/ } XtVaGetValues(w, XmNforeground, &fg, XmNbackground, &bg, NULL); XSetForeground(XtDisplay(w), inputGC, bg ^ lineFgColor->pixel); XSetBackground(XtDisplay(w), inputGC, bg ^ lineBgColor->pixel); XSetLineAttributes(XtDisplay(w), inputGC, line_width, line_style, cap_style, join_style); if (button_pressed > 1) { XSetFunction(XtDisplay(w), inputGC, GXxor); /* Kreslime znovu ten samy objekt pres sebe, cimz ho smazeme */ switch (tool) { case LINE: XDrawLine(XtDisplay(w), XtWindow(w), inputGC, x1, y1, x2, y2); break; case RECTANGLE: if (fill) { XSetForeground(XtDisplay(w), inputGC, bg ^ fillFgColor->pixel); XFillRectangle(XtDisplay(w), XtWindow(w), inputGC, (x1 < x2) ? x1 : x2, (y1 < y2) ? y1 : y2, abs(x2 - x1), abs(y2 - y1)); XSetForeground(XtDisplay(w), inputGC, bg ^ lineFgColor->pixel); } XDrawRectangle(XtDisplay(w), XtWindow(w), inputGC, (x1 < x2) ? x1 : x2, (y1 < y2) ? y1 : y2, abs(x2 - x1), abs(y2 - y1)); break; case ELLIPSE: if (fill) { XSetForeground(XtDisplay(w), inputGC, bg ^ fillFgColor->pixel); XFillArc(XtDisplay(w), XtWindow(w), inputGC, x1 - abs(x2 - x1), y1 - abs(y2 - y1), abs(x2 - x1) * 2, abs(y2 - y1) * 2, 0, 360 * 64); XSetForeground(XtDisplay(w), inputGC, bg ^ lineFgColor->pixel); } XDrawArc(XtDisplay(w), XtWindow(w), inputGC, x1 - abs(x2 - x1), y1 - abs(y2 - y1), abs(x2 - x1) * 2, abs(y2 - y1) * 2, 0, 360 * 64); break; default: break; } } else { /* remember first MotionNotify */ button_pressed = 2; } x2 = event->xmotion.x; y2 = event->xmotion.y; switch (tool) { case LINE: XDrawLine(XtDisplay(w), XtWindow(w), inputGC, x1, y1, x2, y2); break; case RECTANGLE: if (fill) { XSetForeground(XtDisplay(w), inputGC, bg ^ fillFgColor->pixel); XFillRectangle(XtDisplay(w), XtWindow(w), inputGC, (x1 < x2) ? x1 : x2, (y1 < y2) ? y1 : y2, abs(x2 - x1), abs(y2 - y1)); XSetForeground(XtDisplay(w), inputGC, bg ^ lineFgColor->pixel); } XDrawRectangle(XtDisplay(w), XtWindow(w), inputGC, (x1 < x2) ? x1 : x2, (y1 < y2) ? y1 : y2, abs(x2 - x1), abs(y2 - y1)); break; case ELLIPSE: if (fill) { XSetForeground(XtDisplay(w), inputGC, bg ^ fillFgColor->pixel); XFillArc(XtDisplay(w), XtWindow(w), inputGC, x1 - abs(x2 - x1), y1 - abs(y2 - y1), abs(x2 - x1) * 2, abs(y2 - y1) * 2, 0, 360 * 64); XSetForeground(XtDisplay(w), inputGC, bg ^ lineFgColor->pixel); } XDrawArc(XtDisplay(w), XtWindow(w), inputGC, x1 - abs(x2 - x1), y1 - abs(y2 - y1), abs(x2 - x1) * 2, abs(y2 - y1) * 2, 0, 360 * 64); break; default: saveDrawing(w); XDrawPoint(XtDisplay(w), XtWindow(w), inputGC, x2, y2); } } } /* Save callback function */ void SaveCB(Widget w, XtPointer client_data, XtPointer call_data) { XmDrawingAreaCallbackStruct *d = (XmDrawingAreaCallbackStruct*) call_data; switch (d->event->type) { case ButtonPress: if (d->event->xbutton.button == Button1) { button_pressed = 1; x1 = d->event->xbutton.x; y1 = d->event->xbutton.y; } break; case ButtonRelease: if (d->event->xbutton.button == Button1) { saveDrawing(w); button_pressed = 0; XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True); /* Force expose */ } break; } } /* "Expose" callback function */ void ExposeCB(Widget w, XtPointer client_data, XtPointer call_data) { size_t i = 0; XGCValues lineColor; for (; i < ndrawings; i++) { x1 = drawings[i].x1; x2 = drawings[i].x2; y1 = drawings[i].y1; y2 = drawings[i].y2; if (drawings[i].fill) { XGetGCValues(XtDisplay(w), drawings[i].gc, GCForeground, &lineColor); } switch (drawings[i].tool) { case LINE: XDrawLine(XtDisplay(w), XtWindow(w), drawings[i].gc, x1, y1, x2, y2); break; case RECTANGLE: if (drawings[i].fill) { XSetForeground(XtDisplay(w), drawings[i].gc, drawings[i].fillColor.pixel); XFillRectangle(XtDisplay(w), XtWindow(w), drawings[i].gc, (x1 < x2) ? x1 : x2, (y1 < y2) ? y1 : y2, abs(x2 - x1), abs(y2 - y1)); XSetForeground(XtDisplay(w), drawings[i].gc, lineColor.foreground); } XDrawRectangle(XtDisplay(w), XtWindow(w), drawings[i].gc, (x1 < x2) ? x1 : x2, (y1 < y2) ? y1 : y2, abs(x2 - x1), abs(y2 - y1)); break; case ELLIPSE: if (drawings[i].fill) { XSetForeground(XtDisplay(w), drawings[i].gc, drawings[i].fillColor.pixel); XFillArc(XtDisplay(w), XtWindow(w), drawings[i].gc, x1 - abs(x2 - x1), y1 - abs(y2 - y1), abs(x2 - x1) * 2, abs(y2 - y1) * 2, 0, 360 * 64); XSetForeground(XtDisplay(w), drawings[i].gc, lineColor.foreground); } XDrawArc(XtDisplay(w), XtWindow(w), drawings[i].gc, x1 - abs(x2 - x1), y1 - abs(y2 - y1), abs(x2 - x1) * 2, abs(y2 - y1) * 2, 0, 360 * 64); break; case POINT: XDrawPoint(XtDisplay(w), XtWindow(w), drawings[i].gc, x1, y1); XDrawPoint(XtDisplay(w), XtWindow(w), drawings[i].gc, x2, y2); break; default: fprintf(stderr, "Unknown tool!\n"); } } } /* "Clear" button callback function */ void ClearCB(Widget w, XtPointer client_data, XtPointer call_data) { Widget wcd = (Widget) client_data; ndrawings = 0; XClearWindow(XtDisplay(wcd), XtWindow(wcd)); } /* Nastaveni nastroje */ void setTool(Widget w, XtPointer newtool, XtPointer call_data) { tool = (toolkit) newtool; } /* Nastaveni barvy popredi */ void setColor(Widget w, XtPointer color, XtPointer call_data) { unsigned long pixel = (*((XColor**)color))->pixel; /* I can't touch the stars :'( */ if (pixel == black.pixel) { *((XColor**) color) = &white; } else if (pixel == white.pixel) { *((XColor**) color) = &red; } else if (pixel == red.pixel) { *((XColor**) color) = &green; } else if (pixel == green.pixel) { *((XColor**) color) = &blue; } else if (pixel == blue.pixel) { *((XColor**) color) = &black; } /*fprintf(stderr, "%u %u %u\n", (*((XColor**)color))->red, (*((XColor**)color))->green, (*((XColor**)color))->blue);*/ XtVaSetValues(w, XtNforeground, (*((XColor**)color))->pixel, NULL); } /* Nastaveni tloustky cary */ void setLineWidth(Widget w, XtPointer client_data, XtPointer call_data) { XmString label; switch (line_width) { case 0: line_width = 3; label = XmStringCreateSimple("Width 3"); XtVaSetValues(w, XmNlabelString, label, NULL); break; case 3: line_width = 8; label = XmStringCreateSimple("Width 8"); XtVaSetValues(w, XmNlabelString, label, NULL); break; default: line_width = 0; label = XmStringCreateSimple("Width 0"); XtVaSetValues(w, XmNlabelString, label, NULL); } XmStringFree(label); } /* Nastaveni stylu cary */ void setLineStyle(Widget w, XtPointer client_data, XtPointer call_data) { XmString label; switch (line_style) { case LineSolid: line_style = LineDoubleDash; label = XmStringCreateSimple("LineDoubleDash"); XtVaSetValues(w, XmNlabelString, label, NULL); break; case LineDoubleDash: line_style = LineSolid; label = XmStringCreateSimple(" LineSolid "); XtVaSetValues(w, XmNlabelString, label, NULL); break; default: label = XmStringCreateSimple(""); } XmStringFree(label); } /* Nastaveni vyplnovani */ void setFill(Widget w, XtPointer client_data, XtPointer call_data) { XmString label; if (fill) { fill = 0; label = XmStringCreateSimple("Transparent"); } else { fill = 1; label = XmStringCreateSimple(" Filled "); } XtVaSetValues(w, XmNlabelString, label, NULL); XmStringFree(label); } /* "Quit" button callback function */ void quitCB(Widget w, XtPointer client_data, XtPointer call_data) { XtManageChild(question); } /* Konecny callback */ void questionCB(Widget w, XtPointer client_data, XtPointer call_data) { size_t i = 0; if ((int)client_data) { for (; i < allocated; i++) { if (drawings != NULL && drawings[i].gc != NULL) { XFreeGC(XtDisplay(w), drawings[i].gc); } else { /*fprintf(stderr, "%lu", i);*/ break; } } if (inputGC != NULL) { XFreeGC(XtDisplay(w), inputGC); } exit(0); } } int main(int argc, char **argv) { XtAppContext app_context; XmString label; Atom wm_delete; Widget topLevel, mainWin, frame, drawArea, command_window, toolbox, pointBtn, lineBtn, rectBtn, ellipseBtn, colors, lineFgBtn, lineBgBtn, fillFgBtn, fillBgBtn, style, lineSizeBtn, lineStyleBtn, fillBtn, sys, quitBtn, clearBtn; char *fallback_resources[] = { "*question.dialogTitle: MalĂĄ otĂĄzka", "*question.messageString: Konec aplikace?", "*question.okLabelString: Ano", "*question.cancelLabelString: Ne", "*question.messageAlignment: XmALIGNMENT_CENTER", NULL }; XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL); /* Register the default language procedure */ topLevel = XtVaAppInitialize( &app_context, /* Application context */ "Draw", /* Application class */ NULL, 0, /* command line option list */ &argc, argv, /* command line args */ fallback_resources, /* for missing app-defaults file */ XmNdeleteResponse, XmDO_NOTHING, NULL); /* terminate varargs list */ mainWin = XtVaCreateManagedWidget( "mainWin", /* widget name */ xmMainWindowWidgetClass, /* widget class */ topLevel, /* parent widget */ XmNcommandWindowLocation, XmCOMMAND_BELOW_WORKSPACE, NULL); /* terminate varargs list */ frame = XtVaCreateManagedWidget( "frame", /* widget name */ xmFrameWidgetClass, /* widget class */ mainWin, /* parent widget */ NULL); /* terminate varargs list */ drawArea = XtVaCreateManagedWidget( "drawingArea", /* widget name */ xmDrawingAreaWidgetClass, /* widget class */ frame, /* parent widget */ XmNwidth, 320, /* set startup width */ XmNheight, 240, /* set startup height */ NULL); /* terminate varargs list */ command_window = XtVaCreateManagedWidget( "Command window", /* widget name */ xmRowColumnWidgetClass, /* widget class */ mainWin, /* parent widget */ NULL); /* terminate varargs list */ toolbox = XtVaCreateManagedWidget( "Toolbox", /* widget name */ xmRowColumnWidgetClass, /* widget class */ command_window, /* parent widget */ XmNentryAlignment, XmALIGNMENT_CENTER, /* alignment */ XmNorientation, XmHORIZONTAL, /* orientation */ XmNpacking, XmPACK_COLUMN, /* packing mode */ NULL); /* terminate varargs list */ colors = XtVaCreateManagedWidget( "Color picker", /* widget name */ xmRowColumnWidgetClass, /* widget class */ command_window, /* parent widget */ XmNentryAlignment, XmALIGNMENT_CENTER, /* alignment */ XmNorientation, XmHORIZONTAL, /* orientation */ XmNpacking, XmPACK_COLUMN, /* packing mode */ NULL); /* terminate varargs list */ style = XtVaCreateManagedWidget( "Style", /* widget name */ xmRowColumnWidgetClass, /* widget class */ command_window, /* parent widget */ XmNentryAlignment, XmALIGNMENT_CENTER, /* alignment */ XmNorientation, XmHORIZONTAL, /* orientation */ XmNpacking, XmPACK_COLUMN, /* packing mode */ NULL); /* terminate varargs list */ sys = XtVaCreateManagedWidget( "System buttons", /* widget name */ xmRowColumnWidgetClass, /* widget class */ command_window, /* parent widget */ XmNentryAlignment, XmALIGNMENT_CENTER, /* alignment */ XmNorientation, XmHORIZONTAL, /* orientation */ XmNpacking, XmPACK_COLUMN, /* packing mode */ NULL); /* terminate varargs list */ clearBtn = XtVaCreateManagedWidget( "Clear", /* widget name */ xmPushButtonWidgetClass, /* widget class */ sys, /* parent widget */ NULL); /* terminate varargs list */ pointBtn = XtVaCreateManagedWidget( "Point", /* widget name */ xmPushButtonWidgetClass, /* widget class */ toolbox, /* parent widget */ NULL); /* terminate varargs list */ lineBtn = XtVaCreateManagedWidget( "Line", /* widget name */ xmPushButtonWidgetClass, /* widget class */ toolbox, /* parent widget */ NULL); /* terminate varargs list */ rectBtn = XtVaCreateManagedWidget( "Rectangle", /* widget name */ xmPushButtonWidgetClass, /* widget class */ toolbox, /* parent widget */ NULL); /* terminate varargs list */ ellipseBtn = XtVaCreateManagedWidget( "Ellipse", /* widget name */ xmPushButtonWidgetClass, /* widget class */ toolbox, /* parent widget */ NULL); /* terminate varargs list */ lineFgBtn = XtVaCreateManagedWidget( "LineFG", /* widget name */ xmPushButtonWidgetClass, /* widget class */ colors, /* parent widget */ NULL); /* terminate varargs list */ lineBgBtn = XtVaCreateManagedWidget( "LineBG", /* widget name */ xmPushButtonWidgetClass, /* widget class */ colors, /* parent widget */ NULL); /* terminate varargs list */ fillFgBtn = XtVaCreateManagedWidget( "FillFG", /* widget name */ xmPushButtonWidgetClass, /* widget class */ colors, /* parent widget */ NULL); /* terminate varargs list */ fillBgBtn = XtVaCreateManagedWidget( "FillBG", /* widget name */ xmPushButtonWidgetClass, /* widget class */ colors, /* parent widget */ NULL); /* terminate varargs list */ label = XmStringCreateSimple("Width 0"); lineSizeBtn = XtVaCreateManagedWidget( "LineSize", /* widget name */ xmPushButtonWidgetClass, /* widget class */ style, /* parent widget */ XmNlabelString, label, NULL); /* terminate varargs list */ XmStringFree(label); label = XmStringCreateSimple(" LineSolid "); lineStyleBtn = XtVaCreateManagedWidget( "LineStyle", /* widget name */ xmPushButtonWidgetClass, /* widget class */ style, /* parent widget */ XmNlabelString, label, NULL); /* terminate varargs list */ XmStringFree(label); label = XmStringCreateSimple("Transparent"); fillBtn = XtVaCreateManagedWidget( "Fill", /* widget name */ xmPushButtonWidgetClass, /* widget class */ style, /* parent widget */ XmNlabelString, label, NULL); /* terminate varargs list */ XmStringFree(label); quitBtn = XtVaCreateManagedWidget( "Quit", /* widget name */ xmPushButtonWidgetClass, /* widget class */ sys, /* parent widget */ NULL); /* terminate varargs list */ question = XmCreateQuestionDialog(topLevel, "question", NULL, 0); XtVaSetValues(question, XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL, NULL); XtUnmanageChild(XmMessageBoxGetChild(question, XmDIALOG_HELP_BUTTON)); XtAddCallback(question, XmNokCallback, questionCB, (XtPointer) 1); /*XtAddCallback(question, XmNcancelCallback, questionCB, (XtPointer) 1);*/ wm_delete = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW", False); XmAddWMProtocolCallback(topLevel, wm_delete, quitCB, NULL); XmActivateWMProtocol(topLevel, wm_delete); XtAddEventHandler(topLevel, 0, True, _XEditResCheckMessages, NULL); XmMainWindowSetAreas(mainWin, NULL, command_window, NULL, NULL, frame); cmap = DefaultColormap(XtDisplay(drawArea), DefaultScreen(XtDisplay(drawArea))); if ( !XAllocNamedColor(XtDisplay(drawArea), cmap, "red", &red, &red) || !XAllocNamedColor(XtDisplay(drawArea), cmap, "green", &green, &green) || !XAllocNamedColor(XtDisplay(drawArea), cmap, "black", &black, &black) || !XAllocNamedColor(XtDisplay(drawArea), cmap, "white", &white, &white) || !XAllocNamedColor(XtDisplay(drawArea), cmap, "blue", &blue, &blue) ) { fprintf(stderr, "Can't alloc color!\n"); return 1; } XtVaSetValues(lineFgBtn, XtNforeground, lineFgColor->pixel, NULL); XtVaSetValues(lineBgBtn, XtNforeground, lineBgColor->pixel, NULL); XtVaSetValues(fillFgBtn, XtNforeground, fillFgColor->pixel, NULL); XtVaSetValues(fillBgBtn, XtNforeground, fillBgColor->pixel, NULL); XtAddCallback(drawArea, XmNinputCallback, SaveCB, drawArea); XtAddEventHandler(drawArea, ButtonMotionMask, False, DrawEH, NULL); XtAddCallback(drawArea, XmNexposeCallback, ExposeCB, drawArea); XtAddCallback(clearBtn, XmNactivateCallback, ClearCB, drawArea); XtAddCallback(lineFgBtn, XmNactivateCallback, setColor, &lineFgColor); XtAddCallback(lineBgBtn, XmNactivateCallback, setColor, &lineBgColor); XtAddCallback(fillFgBtn, XmNactivateCallback, setColor, &fillFgColor); XtAddCallback(fillBgBtn, XmNactivateCallback, setColor, &fillBgColor); XtAddCallback(lineSizeBtn, XmNactivateCallback, setLineWidth, NULL); XtAddCallback(lineStyleBtn, XmNactivateCallback, setLineStyle, NULL); XtAddCallback(fillBtn, XmNactivateCallback, setFill, NULL); XtAddCallback(pointBtn, XmNactivateCallback, setTool, (XtPointer)POINT); XtAddCallback(lineBtn, XmNactivateCallback, setTool, (XtPointer)LINE); XtAddCallback(rectBtn, XmNactivateCallback, setTool, (XtPointer)RECTANGLE); XtAddCallback(ellipseBtn, XmNactivateCallback, setTool, (XtPointer)ELLIPSE); XtAddCallback(quitBtn, XmNactivateCallback, quitCB, NULL); XtRealizeWidget(topLevel); XtAppMainLoop(app_context); return 0; } #include #include CC=gcc CCOPTIONS=-O2 -pipe -pedantic-errors -Wall -Wextra -march=native -ansi CDEBUGFLAGS=-g LOCAL_LIBRARIES = XmClientLibs $(XMULIB) MSimpleProgramTarget(draw) clean:: $(RM) Makefile