/* * imaptool.c * Copyright (C) 1996-1998 Teemu Maijala - uucee@sci.fi * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "file2pixmap.h" #include "icon" #include "iconmask" #define proginfo "imaptool 0.6 (C) 1996-1998 Teemu Maijala - uucee@sci.fi\n\ imaptool comes with ABSOLUTELY NO WARRANTY; for details see LICENCE.TXT.\n" /* Shapes */ #define RECTANGLE 1 #define CIRCLE 2 #define POLYGON 3 /* Buttonstatus */ #define UP 0 #define DOWN 1 /* Maximum number of breakpoints in polygon */ #define POL_MAX_POINTS 100 /* Some macros */ #define min(a,b) (ab)?a:b /* Misc functions */ void createpicturewindow(); void parseparams(int argc, char *argv[]); void printusage(); void changeinfotext(char *infotext); void insert(char *position); /* Event handlers for vviewwindow */ void buttondown(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); void buttonup(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); void expose(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); void enterwindow(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); void leavewindow(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); void motion(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); /* Event handler for client_message & selections (for WM_DELETE_WINDOW) */ void event_handler(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); /* Callback functions */ void quit(Widget w, XtPointer call_data, XtPointer client_data); void shapeselect(Widget w, XtPointer call_data, XtPointer client_data); /* Functions to draw shapes on vviewwindow */ void drawcircle(Widget w); void drawpolygon(Widget w); void drawrectangle(Widget w); void erase_polygon_motionline(Widget w); /* Global variables */ Atom wm_protocols, wm_delete_window; char *picturefilename; /* name of current gif/jpeg-file */ GC defgc; /* GC for LineDoubleDash */ Pixmap pixmap; /* Pixmap for gif/jpeg-file */ Pixmap iconpixmap, iconmask; /* Pixmap for imaptool-icon and -mask*/ #define QUIT_SAVENOTIFY 1 #define OTHER_SAVENOTIFY 0 struct _pixmasize { int width, height; } pixmapsize; /* size of current pixmap */ int nextshape = RECTANGLE; /* shape selected in shapemenu */ int currentshape = RECTANGLE; /* shape on screen */ struct _rectangle { /* geometry of rectangle */ int x1, y1, x2, y2; } rectangle = {0,0,0,0}; struct _circle { /* geometry of circle */ int x, y, r; } circle = {0,0,0}; struct _polygon_motionline { /* motionline when drawing polygon */ int x, y; Boolean active; } polygon_motionline = {0,0, FALSE}; XPoint polygon[POL_MAX_POINTS]; /* A table containing brakpoints of polygon */ int polcount; /* total abount of breakpoints in polygon */ /* if active is true, drawcircle, drawrectangle and drawpolygon should draw polygon, otherwise they should erase it. Usually the functions are first called width active false and then with active true. */ Boolean active = FALSE; int buttonstatus; /* status of mousebuttons */ /* Widgets */ Widget root, picturewindow; Widget vform, vmenubox, vbox, vviewwindow, vquit, vinfobox; Widget vshapemenu, vshapemenubutton, vrectangle, vcircle, vpolygon; void main(int argc, char *argv[]) { int screennum; XtAppContext app_context; int cursor_shape = XC_tcross; Cursor cursor; XGCValues values; root = XtVaAppInitialize(&app_context, "imaptool", NULL, 0, &argc, argv, NULL, NULL); screennum = XScreenNumberOfScreen(XtScreen(root)); parseparams(argc, argv); /* loading picture to pixmap */ if (!load_file_to_pixmap(picturefilename, XtDisplay(root), screennum, &pixmapsize.width, &pixmapsize.height, &pixmap)) printusage(); /* creating pixmaps for icon & iconmask */ iconpixmap = XCreatePixmapFromBitmapData(XtDisplay(root), RootWindow(XtDisplay(root), screennum), (char*)icon_bits, icon_width, icon_height, WhitePixel(XtDisplay(root), screennum), BlackPixel(XtDisplay(root), screennum), DefaultDepth(XtDisplay(root), screennum)); iconmask = XCreatePixmapFromBitmapData(XtDisplay(root), RootWindow(XtDisplay(root), screennum), (char*)iconmask_bits, iconmask_width, iconmask_height, WhitePixel(XtDisplay(root), screennum), BlackPixel(XtDisplay(root), screennum), 1); /* creating window widgets */ createpicturewindow(); /* showing windows */ XtPopup(picturewindow, XtGrabNone); cursor = XCreateFontCursor(XtDisplay(vviewwindow), cursor_shape); XDefineCursor(XtDisplay(vviewwindow), XtWindow(vviewwindow), cursor); /* setting up default GC */ values.foreground = WhitePixel(XtDisplay(picturewindow), XScreenNumberOfScreen(XtScreen(picturewindow))); values.background = BlackPixel(XtDisplay(picturewindow), XScreenNumberOfScreen(XtScreen(picturewindow))); values.line_style = LineDoubleDash; defgc = XCreateGC(XtDisplay(picturewindow), XtWindow(picturewindow), (GCForeground|GCBackground|GCLineStyle), &values); XtAddEventHandler(vviewwindow, 0, TRUE, event_handler, (XtPointer)NULL); /* going to main loop */ XtAppMainLoop(app_context); } void createpicturewindow() { Pixel menuboxcolor; picturewindow = XtVaCreatePopupShell("picturewindow", applicationShellWidgetClass, root, XtNtitle, picturefilename, XtNiconName, picturefilename, XtNiconPixmap, iconpixmap, XtNiconMask, iconmask, NULL); vform = XtVaCreateManagedWidget("rootform", formWidgetClass, picturewindow, XtNresizable, TRUE, NULL); vmenubox = XtVaCreateManagedWidget("menubox", boxWidgetClass, vform, XtNborderWidth, 0, XtNtop, XawChainTop, XtNbottom, XawChainTop, XtNleft, XawChainLeft, XtNright, XawChainLeft, XtNorientation, XtorientHorizontal, XtNresizable, TRUE, NULL); XtVaGetValues(vmenubox, XtNbackground, &menuboxcolor, NULL); vquit = XtVaCreateManagedWidget("Quit", commandWidgetClass, vmenubox, NULL); XtAddCallback(vquit, XtNcallback, quit, (XtPointer)NULL); vshapemenu = XtVaCreatePopupShell("vshapemenu", simpleMenuWidgetClass, picturewindow, NULL); vshapemenubutton = XtVaCreateManagedWidget("vshapemenubutton", menuButtonWidgetClass, vmenubox, XtNmenuName, "vshapemenu", XtNlabel, "Shape", NULL); vrectangle = XtVaCreateManagedWidget("o Rectangle", smeBSBObjectClass, vshapemenu, NULL); vcircle = XtVaCreateManagedWidget(" Circle", smeBSBObjectClass, vshapemenu, NULL); vpolygon = XtVaCreateManagedWidget(" Polygon", smeBSBObjectClass, vshapemenu, NULL); XtAddCallback(vrectangle, XtNcallback, shapeselect, (XtPointer)RECTANGLE); XtAddCallback(vcircle, XtNcallback, shapeselect, (XtPointer)CIRCLE); XtAddCallback(vpolygon, XtNcallback, shapeselect, (XtPointer)POLYGON); vinfobox = XtVaCreateManagedWidget("infobox", labelWidgetClass, vmenubox, XtNborderWidth, 0, XtNbackground, menuboxcolor, XtNlabel, " ", XtNresizable, TRUE, NULL); vbox = XtVaCreateManagedWidget("box", boxWidgetClass, vform, XtNfromVert, vmenubox, XtNhSpace, 0, XtNvSpace, 0, XtNtop, XawChainTop, XtNbottom, XawChainTop, XtNleft, XawChainLeft, XtNright, XawChainLeft, NULL); vviewwindow = XtVaCreateManagedWidget("viewwindow", coreWidgetClass, vbox, XtNinternalHeight, 0, XtNinternalWidth, 0, XtNborderWidth, 0, NULL); XtAddEventHandler(vviewwindow, ButtonPressMask, FALSE, buttondown, (XtPointer)NULL); XtAddEventHandler(vviewwindow, ButtonReleaseMask, FALSE, buttonup, (XtPointer)NULL); XtAddEventHandler(vviewwindow, ExposureMask, FALSE, expose, (XtPointer)NULL); XtAddEventHandler(vviewwindow, PointerMotionMask, FALSE, motion, (XtPointer)NULL); XtAddEventHandler(vviewwindow, EnterWindowMask, FALSE, enterwindow, (XtPointer)NULL); XtAddEventHandler(vviewwindow, LeaveWindowMask, FALSE, leavewindow, (XtPointer)NULL); XtVaSetValues(vviewwindow, XtNwidth, pixmapsize.width, XtNheight, pixmapsize.height, NULL); } void parseparams(int argc, char *argv[]) { if (argc < 2) printusage(); picturefilename = argv[1]; } void printusage() { printf("%s\n", proginfo); printf("usage: imaptool \n\n"); exit(0); } void changeinfotext(char *text) { int width, height; XExposeEvent xeev; char *current_label; XtVaGetValues(vinfobox, XtNlabel, ¤t_label, NULL); if(strcmp(current_label, text)) { xeev.type = Expose; xeev.display = XtDisplay(vinfobox); xeev.window = XtWindow(vinfobox); xeev.x = xeev.y = 0; XtVaGetValues(vinfobox, XtNwidth, &width, XtNheight, &height, NULL); xeev.width = width; xeev.height = height; XtVaSetValues(vinfobox, XtNlabel, text, NULL); (XtClass(vinfobox))->core_class.expose (vinfobox, (XEvent*)&xeev, NULL); } } void buttondown(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { active = FALSE; switch(currentshape) { case RECTANGLE: drawrectangle(w); break; case CIRCLE: drawcircle(w); break; case POLYGON: if (nextshape!=POLYGON) drawpolygon(w); break; } switch(nextshape) { case RECTANGLE: currentshape = RECTANGLE; rectangle.x1 = event->xbutton.x; rectangle.y1 = event->xbutton.y; rectangle.x2 = event->xbutton.x; rectangle.y2 = event->xbutton.y; buttonstatus = DOWN; break; case CIRCLE: currentshape = CIRCLE; circle.x = event->xbutton.x; circle.y = event->xbutton.y; circle.r = 0; break; case POLYGON: currentshape = POLYGON; break; } buttonstatus = DOWN; } void buttonup(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { int x, y; XSetSelectionOwner(XtDisplay(w), XA_PRIMARY, XtWindow(w), CurrentTime); switch(currentshape) { case RECTANGLE: active = FALSE; drawrectangle(w); rectangle.x2 = event->xbutton.x; rectangle.y2 = event->xbutton.y; active = TRUE; drawrectangle(w); break; case CIRCLE: active = FALSE; drawcircle(w); x = circle.x-event->xbutton.x; y = circle.y-event->xbutton.y; circle.r = (int)sqrt(x*x+y*y); active = TRUE; drawcircle(w); break; case POLYGON: if (event->xbutton.button<3) { if (polcountxbutton.x; polygon[polcount].y = event->xbutton.y; polcount++; } active = TRUE; drawpolygon(w); } else { active = FALSE; drawpolygon(w); if (polygon_motionline.active == TRUE) erase_polygon_motionline(w); polcount = 1; polygon[0].x = event->xbutton.x; polygon[0].y = event->xbutton.y; active = TRUE; } break; } buttonstatus = UP; polygon_motionline.active = TRUE; } void expose(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { XCopyArea(XtDisplay(w), pixmap, XtWindow(w), defgc, event->xexpose.x, event->xexpose.y, event->xexpose.width, event->xexpose.height, event->xexpose.x, event->xexpose.y); switch(currentshape) { case RECTANGLE: drawrectangle(w); break; case CIRCLE: drawcircle(w); break; case POLYGON: drawpolygon(w); break; } } void enterwindow(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { if ((currentshape==POLYGON)&&(polygon_motionline.active==TRUE)) { polygon_motionline.x = event->xcrossing.x; polygon_motionline.y = event->xcrossing.y; XDrawLine(XtDisplay(w), XtWindow(w), defgc, polygon[polcount-1].x, polygon[polcount-1].y, polygon_motionline.x, polygon_motionline.y); } } void leavewindow(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { if ((currentshape==POLYGON)&&(polygon_motionline.active==TRUE)) { erase_polygon_motionline(w); active = TRUE; drawpolygon(w); } } void motion(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { char infotext[80]; int x1, x2, y1, y2; switch(currentshape) { case RECTANGLE: if (buttonstatus==DOWN) { active = FALSE; drawrectangle(w); rectangle.x2 = event->xmotion.x; rectangle.y2 = event->xmotion.y; active = TRUE; drawrectangle(w); } x1 = min(rectangle.x1, rectangle.x2); y1 = min(rectangle.y1, rectangle.y2); x2 = max(rectangle.x1, rectangle.x2); y2 = max(rectangle.y1, rectangle.y2); sprintf(infotext, "%d,%d : %d,%d,%d,%d", event->xmotion.x, event->xmotion.y, x1, y1, x2, y2); changeinfotext(infotext); break; case CIRCLE: if (buttonstatus==DOWN) { active = FALSE; drawcircle(w); circle.r = (int)hypot((circle.x-event->xbutton.x), (circle.y-event->xbutton.y)); active = TRUE; drawcircle(w); } sprintf(infotext, "%d,%d : %d,%d,%d", event->xmotion.x, event->xmotion.y, circle.x, circle.y, circle.r); changeinfotext(infotext); break; case POLYGON: if (polygon_motionline.active == TRUE) { erase_polygon_motionline(w); polygon_motionline.x = event->xmotion.x; polygon_motionline.y = event->xmotion.y; active = TRUE; drawpolygon(w); XDrawLine(XtDisplay(w), XtWindow(w), defgc, polygon_motionline.x, polygon_motionline.y, polygon[polcount-1].x, polygon[polcount-1].y); XFlush(XtDisplay(w)); } sprintf(infotext, "%d,%d : %d,%d - %d,%d", event->xmotion.x, event->xmotion.y, polygon[0].x, polygon[0].y, polygon[polcount-1].x, polygon[polcount-1].y); changeinfotext(infotext); break; } } void event_handler(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { if (event->type==SelectionClear) { active = FALSE; switch(currentshape) { case RECTANGLE: drawrectangle(w); break; case CIRCLE: drawcircle(w); break; case POLYGON: drawpolygon(w); polcount = 0; polygon_motionline.active = FALSE; break; } } if (event->type==SelectionRequest) { char position[1124]; int i; XEvent sendevent; insert(position); sendevent.type = SelectionNotify; sendevent.xselection.display = XtDisplay(w); sendevent.xselection.requestor = event->xselectionrequest.requestor; sendevent.xselection.selection = event->xselectionrequest.selection; sendevent.xselection.target = event->xselectionrequest.target; sendevent.xselection.property = event->xselectionrequest.property; sendevent.xselection.time = event->xselectionrequest.time; XChangeProperty(XtDisplay(root), event->xselectionrequest.requestor, event->xselectionrequest.property, event->xselectionrequest.target, 8, PropModeReplace, position, strlen(position)); XSendEvent(XtDisplay(root), event->xselectionrequest.requestor, True, 0, &sendevent); XFlush(XtDisplay(root)); } } void insert(char *position) { int x1, x2, y1, y2, i; char temp[255]; switch(currentshape) { case RECTANGLE: x1 = min(rectangle.x1, rectangle.x2); y1 = min(rectangle.y1, rectangle.y2); x2 = max(rectangle.x1, rectangle.x2); y2 = max(rectangle.y1, rectangle.y2); sprintf(position, "", x1, y1, x2, y2); break; case CIRCLE: sprintf(position, "", circle.x, circle.y, circle.r); break; case POLYGON: sprintf(position, "1020) break; } strcpy(position+strlen(position)-1, "\042 HREF=\042\042>"); } } void quit(Widget w, XtPointer client_data, XtPointer call_data) { XtPopdown(picturewindow); XFreePixmap(XtDisplay(root), pixmap); XtDestroyWidget(root); exit(0); } void shapeselect(Widget w, XtPointer call_data, XtPointer client_data) { switch(nextshape) { case RECTANGLE: XtVaSetValues(vrectangle, XtNlabel, " Rectangle", NULL); break; case CIRCLE: XtVaSetValues(vcircle, XtNlabel, " Circle", NULL); break; case POLYGON: XtVaSetValues(vpolygon, XtNlabel, " Polygon", NULL); break; } nextshape = (int)call_data; switch(nextshape) { case RECTANGLE: polygon_motionline.active = FALSE; XtVaSetValues(vrectangle, XtNlabel, "o Rectangle", NULL); break; case CIRCLE: polygon_motionline.active = FALSE; XtVaSetValues(vcircle, XtNlabel, "o Circle", NULL); break; case POLYGON: if (currentshape != POLYGON) { polcount = 0; polygon_motionline.active = FALSE; } XtVaSetValues(vpolygon, XtNlabel, "o Polygon", NULL); break; } } void drawcircle(Widget w) { if (active) { XDrawArc(XtDisplay(w), XtWindow(w), defgc, circle.x-circle.r, circle.y-circle.r, 2*circle.r, 2*circle.r, 0, 360*64); } else { int x, y; x = circle.x-circle.r; y = circle.y-circle.r; if (x<0) x=0; if (y<0) y=0; XCopyArea(XtDisplay(w), pixmap, XtWindow(w), defgc, x, y, 2*circle.r+1, 2*circle.r+1, x, y); } XFlush(XtDisplay(w)); } void drawpolygon(Widget w) { if (active) { XDrawLines(XtDisplay(w), XtWindow(w), defgc, polygon, polcount, CoordModeOrigin); } else { int minx, miny, maxx, maxy, i; minx = miny = maxx = maxy = 0; for (i=0;imaxx) maxx = polygon[i].x; if (polygon[i].y>maxy) maxy = polygon[i].y; } XCopyArea(XtDisplay(w), pixmap, XtWindow(w), defgc, minx, miny, maxx-minx+1, maxy-miny+1, minx, miny); } XFlush(XtDisplay(w)); } void drawrectangle(Widget w) { int x1, x2, y1, y2; x1 = min(rectangle.x1, rectangle.x2); y1 = min(rectangle.y1, rectangle.y2); x2 = max(rectangle.x1, rectangle.x2); y2 = max(rectangle.y1, rectangle.y2); if (active) { XDrawRectangle(XtDisplay(w), XtWindow(w), defgc, x1, y1, x2-x1, y2-y1); } else { GC gc; gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, NULL); if (x1<0) x1=0; if (y1<0) y1=0; XCopyArea(XtDisplay(w), pixmap, XtWindow(w), gc, x1, y1, x2-x1+1, y2-y1+1, x1, y1); XFreeGC(XtDisplay(w), gc); } XFlush(XtDisplay(w)); } void erase_polygon_motionline(Widget w) { int x1, y1, x2, y2; x1 = min(polygon[polcount-1].x, polygon_motionline.x); y1 = min(polygon[polcount-1].y, polygon_motionline.y); x2 = max(polygon[polcount-1].x, polygon_motionline.x); y2 = max(polygon[polcount-1].y, polygon_motionline.y); XCopyArea(XtDisplay(w), pixmap, XtWindow(w), defgc, x1, y1, x2-x1+1, y2-y1+1, x1, y1); XFlush(XtDisplay(w)); }