/* * Copyright 1991 Klaus Zitzmann, 1993-1996 Johannes Sixt * * Permission to use, copy, modify and distribute this software and its * documentation for any purpose other than its commercial exploitation * is hereby granted without fee, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation. The authors * make no representations about the suitability of this software for * any purpose. It is provided "as is" without express or implied warranty. * * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Authors: Klaus Zitzmann * Johannes Sixt */ #include #include #include #include #include #include #include #include #include /*#include included by */ /*#include included by */ #include #if !defined(XtSpecificationRelease) || XtSpecificationRelease < 5 #define XawRubber XtRubber #define XawChainBottom XtChainBottom #define XawChainTop XtChainTop #define XawChainLeft XtChainLeft #define XawChainRight XtChainRight #endif /* pre Release 5 */ #include #include #include #include #include "objects.h" #include "io_trans.h" #include "modify.h" #include "graphics.h" Boolean cross, ruler; GraphMode graphMode; /* what currently is drawn */ static TeXPictType graphToType[GRAPH_MODE_MAX + 1]; static XPoint points[MAX_POINTS]; /* points defined by button press */ static int pointsSet; /* no. of points/obj defined so far */ static Boolean newText; /* flag for text placment callbacks */ static char textInput[MAX_TEXT_LEN + 1]; static char textPlaceTitle[] = "Text Placement"; static char framedPlaceTitle[] = "Framed Box Text Placement"; static char dashedPlaceTitle[] = "Dashed Box Text Placement"; static float rast_height; static Boolean crossDrawn; static int crossX, crossY; static GC crossGC, rGC; static XFontStruct *ruler_font; static Widget textEntry; static Widget textPlacement; static Widget shadowSelector; static Widget position; /* radio group of position */ static Widget shadow; /* radio group of shadow */ static void InitTextAndPosition(Widget parent); static void SetNewPoint(int x, int y); static void GetSomeText(char *title, Boolean shadowed); static void AbortGraph(GraphMode mode); static void TextPlaceNewCB(Widget cmd, XtPointer acc, XtPointer call_data); static void TextPlaceModCB(Widget cmd, XtPointer acc, XtPointer call_data); static void track_it(int x, int y); static void DrawCross(Widget wid, int x, int y, Boolean redraw); static void WriteCoords(int x, int y, Widget coord); static void MotionHandler(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); static void LeaveHandler(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); static void Redraw(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd); static void DrawRuler(void); static void DrawRaster(void); /* Action procedures */ #define actionparams Widget w, XEvent *event, String *id, Cardinal *num static void track_it_act (actionparams); static void abortObjectAct (actionparams); static void setPointAct (actionparams); #undef actionparams void GraphicsInit(XtAppContext context, Widget parent, Widget coord, XFontStruct *ruler_font_p, Pixel foreground, Pixel background) { int i; XGCValues values; static XtActionsRec actions[] = { {"track-it", track_it_act}, {"set-point", setPointAct}, {"abort-object", abortObjectAct} }; static char drawTrans[] = "\ :set-point()\n\ :abort-object()\n\ :abort-object()\n\ :track-it()"; XtAppAddActions(context, actions, XtNumber(actions)); XtOverrideTranslations(pboard, XtParseTranslationTable(drawTrans)); /* create GCs for cross hair, ruler, and raster */ values.foreground = foreground ^ background; values.function = GXxor; crossGC = XCreateGC(XtDisplay(pboard), XtWindow(pboard), GCForeground | GCFunction, &values); ruler_font = ruler_font_p; values.foreground = foreground; values.function = GXcopy; values.font = ruler_font->fid; rGC = XCreateGC(XtDisplay(pboard), XtWindow(pboard), GCForeground | GCFunction | GCFont, &values); /* install event handlers */ XtAddEventHandler(pboard, PointerMotionMask | EnterWindowMask, False, MotionHandler, (XtPointer) coord); XtAddEventHandler(pboard, LeaveWindowMask, False, LeaveHandler, (XtPointer) coord); XtAddEventHandler(pboard, ExposureMask, False, Redraw, NULL); InitTextAndPosition(parent); crossDrawn = False; crossX = -1; crossY = -1; /* conversion GraphMode to TeXPictType */ for (i = 0; i <= GRAPH_MODE_MAX; i++) graphToType[i] = -1; graphToType[graphLine] = TeXLine; graphToType[graphVector] = TeXVector; graphToType[graphBezier] = TeXBezier; graphToType[graphFramed] = TeXFramedText; graphToType[graphDashed] = TeXDashedText; graphToType[graphFilled] = TeXFilled; graphToType[graphText] = TeXText; graphToType[graphOval] = TeXOval; graphToType[graphCircle] = TeXCircle; graphToType[graphDisc] = TeXDisc; pointsSet = 0; graphMode = graphEditPick; ModifyInit(); } void transform(char *name) { /* eliminates all special characters in name */ char buffer[MAX_TEXT_LEN+1], *p, *q; strcpy(buffer, name); q = name; for (p = buffer; *p != '\0'; p++) { if (isprint(*p)) *q++ = *p; } *q = '\0'; } /*ARGSUSED*/ void CommandCB(Widget w, XtPointer client_data, XtPointer call_data) { /* delete old object */ AbortGraph((GraphMode) graphMode); /* prepare for new object */ graphMode = (GraphMode) client_data; pointsSet = 0; switch (graphMode) { case graphZoom: /* %%%%%% will not happen currently */ break; case graphEditPick: PrepareSelect(); break; default: ; } } /*ARGSUSED*/ void AbortGraphCB(Widget w, XtPointer client_data, XtPointer call_data) { AbortGraph(graphMode); } /*ARGSUSED*/ static void abortObjectAct(Widget w, XEvent *event, String *id, Cardinal *num) { AbortGraph(graphMode); } /*ARGSUSED*/ static void setPointAct(Widget w, XEvent *event, String *id, Cardinal *num) { int x = event->xbutton.x; int y = event->xbutton.y; XPoint newPoint; switch (graphMode) { case graphText: newPoint.x = x; newPoint.y = y; SnapPosition(&newPoint.x, &newPoint.y); points[0].x = newPoint.x; points[0].y = newPoint.y; pointsSet = 1; GetSomeText(textPlaceTitle, False); break; case graphEditPick: SelectObj(x, y); break; case graphZoom: case graphCopy: fprintf(stderr, "warning: setPointAct: unallowed graphMode\n"); break; default: SetNewPoint(x, y); } } static void SetNewPoint(int x, int y) { Display *disp; Drawable win; TeXPictObj *newObj; disp = XtDisplay(pboard); win = XtWindow(pboard); /* update rubber band */ track_it(x, y); /* also sets the new point */ /* erase rubber line */ ObjRubber(graphToType[graphMode], disp, win, points, pointsSet+1); /* new point is set */ ++ pointsSet; /* create new object if possible */ switch (graphMode) { case graphBezier: if (pointsSet == 3) { newObj = ObjCreate(graphToType[graphMode]); newObj->next = objList; objList = newObj; ObjStore(newObj, points, pointsSet); ObjDraw(newObj, disp, win); changeMade = True; /* reset for new bezier */ pointsSet = 0; } break; case graphVector: case graphLine: if (pointsSet == 2) { newObj = ObjCreate(graphToType[graphMode]); newObj->next = objList; objList = newObj; ObjStore(newObj, points, pointsSet); ObjDraw(newObj, disp, win); changeMade = True; /* end point is Starting point for next line */ points[0] = points[1]; pointsSet = 1; } break; case graphFramed: case graphDashed: if (pointsSet == 2) { GetSomeText(graphMode == graphFramed ? framedPlaceTitle : dashedPlaceTitle, True); /* resetting of points will be done at pop down */ return; /* Must not draw rubber band!!! */ } break; case graphCircle: case graphDisc: case graphOval: case graphFilled: if (pointsSet == 2) { newObj = ObjCreate(graphToType[graphMode]); newObj->next = objList; objList = newObj; ObjStore(newObj, points, pointsSet); ObjDraw(newObj, disp, win); changeMade = True; pointsSet = 0; } break; default: break; } /* switch */ /* draw new rubber line */ ObjRubber(graphToType[graphMode], disp, win, points, pointsSet+1); } static void GetSomeText(char *title, Boolean shadowed) { Position x_rel, y_rel, x_abs, y_abs; /* set new object indicator */ newText = True; /* draw a rubber band */ ObjRubber(graphToType[graphMode], XtDisplay(pboard), XtWindow(pboard), points, pointsSet); /* setup pop-up */ /* get the relative coordinates of widget canvas */ XtVaGetValues(pboard, XtNx, &x_rel, XtNy, &y_rel, NULL); XtTranslateCoords(pboard, x_rel, y_rel, &x_abs, &y_abs); XtVaSetValues(textPlacement, XtNtitle, (XtArgVal) title, NULL); /*%%%%%% R4-compat needed */ XtSetSensitive(shadowSelector, shadowed); XtPopupSpringLoaded(textPlacement); } /*ARGSUSED*/ static void track_it_act(Widget w, XEvent *event, String *id, Cardinal *num) { track_it(event->xmotion.x, event->xmotion.y); } static void track_it(int x, int y) { Display *disp; Drawable win; XPoint oldPoint, newPoint; disp = XtDisplay(pboard); win = XtWindow(pboard); oldPoint = points[pointsSet]; points[pointsSet].x = x; points[pointsSet].y = y; ObjValidate(graphToType[graphMode], points, pointsSet+1, pointsSet); newPoint = points[pointsSet]; if (newPoint.x != oldPoint.x || newPoint.y != oldPoint.y) { /* redraw necessary */ /* erase old rubber band */ points[pointsSet] = oldPoint; ObjRubber(graphToType[graphMode], disp, win, points, pointsSet+1); /* draw new rubber band */ points[pointsSet] = newPoint; ObjRubber(graphToType[graphMode], disp, win, points, pointsSet+1); } } /*ARGSUSED*/ static void MotionHandler(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { Position x, y; if (event->xany.type == EnterNotify) { x = event->xcrossing.x; y = event->xcrossing.y; } else if (event->xany.type == MotionNotify) { x = event->xmotion.x; y = event->xmotion.y; } else return; SnapPosition(&x, &y); if (crossX != x || crossY != y) { WriteCoords((int) x, (int) y, (Widget) client_data); if (cross) { DrawCross(w, x, y, True); } crossX = x; crossY = y; } } /*ARGSUSED*/ static void LeaveHandler(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { /* erase coordinates window */ XtVaSetValues((Widget) client_data, XtNlabel, (XtArgVal) "", NULL); /* erase Cross */ if (cross) { DrawCross(w, 0, 0, False); } crossX = -1; crossY = -1; } static void DrawCross(Widget wid, int x, int y, Boolean redraw) { Display *disp = XtDisplay(wid); Window win = XtWindow(wid); Dimension w, h; XtVaGetValues(wid, XtNwidth, &w, XtNheight, &h, NULL); /* erase old cross */ if (crossDrawn) { /* %%%%% erasing is not perfect: w & h */ XDrawLine(disp, win, crossGC, crossX, 0, crossX, h); XDrawLine(disp, win, crossGC, 0, crossY, w, crossY); } if ((crossDrawn = redraw)) { /* paint new cross */ XDrawLine(disp, win, crossGC, x, 0, x, h); XDrawLine(disp, win, crossGC, 0, y, w, y); } } static void WriteCoords(int x, int y, Widget coord) { static char buf[32]; float xf, yf; GetCoords(x, y, &xf, &yf); sprintf(buf, "x=%6.1f y=%6.1f", xf, yf); XtVaSetValues(coord, XtNlabel, (XtArgVal) buf, NULL); } static void AbortGraph(GraphMode mode) { if (mode == graphEditPick) return; /* erase drawing */ ObjRubber(graphToType[graphMode], XtDisplay(pboard), XtWindow(pboard), points, pointsSet+1); pointsSet = 0; #if 0 /* %%%%% assumes that if pointsSet == 0 nothing will be drawn */ ObjRubber(graphToType[graphMode], XtDisplay(pboard), XtWindow(pboard), points, pointsSet+1); #endif } void norm_rectangle(float *x, float *y, float *h, float *v) {/* (x,y) and (h,v) are opposite (diagonal) coordinates of a rectangle */ /* this routine transforms (x,y) to the upper left... */ float help; if (*x > *h) { help = *x; *x = *h; *h = help; } if (*y > *v) { help = *y; *y = *v; *v = help; } } /*ARGSUSED*//* %%%%%% stupid routine */ static void Redraw(Widget w, XtPointer client_data, XEvent *event, Boolean *ctd) { if (event->xexpose.count != 0) return; /* needed for correct cross painting */ crossDrawn = False; if (ruler) DrawRuler(); if (raster) DrawRaster(); } void InitTextAndPosition(Widget parent) { /* builds popup for text-queries and text-alignments */ Widget container, posForm, doneBox, cancel, quit, center, tl, bl, b, t, l; XtTranslations oneOfMany, okAcc, cancelAcc; static char oneOfManyTrans[] = ": highlight(Always)\n" ": unhighlight()\n" ",: set() notify()"; static char okAccelTable[] = "#override " "Return: set() notify() unset()\n" "KP_Enter: set() notify() unset()"; static char cancelAccelTable[] = "#override " "Escape: set() notify() unset()"; textPlacement = XtCreatePopupShell("textPlacement", topLevelShellWidgetClass, parent, NULL,0); container = XtVaCreateManagedWidget("pane", panedWidgetClass, textPlacement, NULL); textEntry = XtVaCreateManagedWidget("text", asciiTextWidgetClass, container, XtNuseStringInPlace, (XtArgVal) True, XtNstring, (XtArgVal) textInput, XtNlength, (XtArgVal) MAX_TEXT_LEN, XtNeditType, (XtArgVal) XawtextEdit, XtNresize, (XtArgVal) XawtextResizeWidth, NULL); posForm = XtVaCreateManagedWidget("position", formWidgetClass, container, XtNshowGrip, (XtArgVal) True, NULL); oneOfMany = XtParseTranslationTable(oneOfManyTrans); tl = XtVaCreateManagedWidget("justTopLeft", toggleWidgetClass, posForm, XtNradioData, (XtArgVal) (ALIGN_H_LEFT | ALIGN_V_TOP), XtNtranslations, (XtArgVal) oneOfMany, /* constraints */ XtNtop, (XtArgVal) XawChainTop, XtNbottom, (XtArgVal) XawRubber, XtNleft, (XtArgVal) XawChainLeft, XtNright, (XtArgVal) XawRubber, NULL); /* initialize radio group */ position = tl; t = XtVaCreateManagedWidget("justTop", toggleWidgetClass, posForm, XtNradioData, (XtArgVal) (ALIGN_H_CENTER | ALIGN_V_TOP), XtNradioGroup, (XtArgVal) position, XtNtranslations, (XtArgVal) oneOfMany, /* constraints */ XtNfromHoriz, (XtArgVal) tl, XtNtop, (XtArgVal) XawChainTop, XtNbottom, (XtArgVal) XawRubber, XtNleft, (XtArgVal) XawRubber, XtNright, (XtArgVal) XawRubber, NULL); (void) XtVaCreateManagedWidget("justTopRight", toggleWidgetClass, posForm, XtNradioData, (XtArgVal) (ALIGN_H_RIGHT | ALIGN_V_TOP), XtNradioGroup, (XtArgVal) position, XtNtranslations, (XtArgVal) oneOfMany, /* constraints */ XtNfromHoriz, (XtArgVal) t, XtNtop, (XtArgVal) XawChainTop, XtNbottom, (XtArgVal) XawRubber, XtNleft, (XtArgVal) XawRubber, XtNright, (XtArgVal) XawChainRight, NULL); l = XtVaCreateManagedWidget("justLeft", toggleWidgetClass, posForm, XtNradioData, (XtArgVal) (ALIGN_H_LEFT | ALIGN_V_CENTER), XtNradioGroup, (XtArgVal) position, XtNtranslations, (XtArgVal) oneOfMany, /* constraints */ XtNfromVert, (XtArgVal) tl, XtNtop, (XtArgVal) XawRubber, XtNbottom, (XtArgVal) XawRubber, XtNleft, (XtArgVal) XawChainLeft, XtNright, (XtArgVal) XawRubber, NULL); center = XtVaCreateManagedWidget("justCenter", toggleWidgetClass, posForm, XtNradioData, (XtArgVal) (ALIGN_H_CENTER | ALIGN_V_CENTER), XtNradioGroup, (XtArgVal) position, XtNstate, (XtArgVal) True, XtNtranslations, (XtArgVal) oneOfMany, /* constraints */ XtNfromHoriz, (XtArgVal) l, XtNfromVert, (XtArgVal) tl, XtNtop, (XtArgVal) XawRubber, XtNbottom, (XtArgVal) XawRubber, XtNleft, (XtArgVal) XawRubber, XtNright, (XtArgVal) XawRubber, NULL); (void) XtVaCreateManagedWidget("justRight", toggleWidgetClass, posForm, XtNradioData, (XtArgVal) (ALIGN_H_RIGHT | ALIGN_V_CENTER), XtNradioGroup, (XtArgVal) position, XtNtranslations, (XtArgVal) oneOfMany, /* constraints */ XtNfromHoriz, (XtArgVal) center, XtNfromVert, (XtArgVal) tl, XtNtop, (XtArgVal) XawRubber, XtNbottom, (XtArgVal) XawRubber, XtNleft, (XtArgVal) XawRubber, XtNright, (XtArgVal) XawChainRight, NULL); bl = XtVaCreateManagedWidget("justBottomLeft", toggleWidgetClass, posForm, XtNradioData, (XtArgVal) (ALIGN_H_LEFT | ALIGN_V_BOTTOM), XtNradioGroup, (XtArgVal) position, XtNtranslations, (XtArgVal) oneOfMany, /* constraints */ XtNfromVert, (XtArgVal) l, XtNtop, (XtArgVal) XawRubber, XtNbottom, (XtArgVal) XawChainBottom, XtNleft, (XtArgVal) XawChainLeft, XtNright, (XtArgVal) XawRubber, NULL); b = XtVaCreateManagedWidget("justBottom", toggleWidgetClass, posForm, XtNradioData, (XtArgVal) (ALIGN_H_CENTER | ALIGN_V_BOTTOM), XtNradioGroup, (XtArgVal) position, XtNtranslations, (XtArgVal) oneOfMany, /* constraints */ XtNfromHoriz, (XtArgVal) bl, XtNfromVert, (XtArgVal) l, XtNtop, (XtArgVal) XawRubber, XtNbottom, (XtArgVal) XawChainBottom, XtNleft, (XtArgVal) XawRubber, XtNright, (XtArgVal) XawRubber, NULL); (void) XtVaCreateManagedWidget("justBottomRight", toggleWidgetClass, posForm, XtNradioData, (XtArgVal) (ALIGN_H_RIGHT | ALIGN_V_BOTTOM), XtNradioGroup, (XtArgVal) position, XtNtranslations, (XtArgVal) oneOfMany, /* constraints */ XtNfromHoriz, (XtArgVal) b, XtNfromVert, (XtArgVal) l, XtNtop, (XtArgVal) XawRubber, XtNbottom, (XtArgVal) XawChainBottom, XtNleft, (XtArgVal) XawRubber, XtNright, (XtArgVal) XawChainRight, NULL); shadowSelector = XtVaCreateManagedWidget("shadow", boxWidgetClass, container, NULL); shadow = XtVaCreateManagedWidget("noShadow", toggleWidgetClass, shadowSelector, XtNradioData, (XtArgVal) ShadowNone, XtNstate, (XtArgVal) True, XtNtranslations, (XtArgVal) oneOfMany, NULL); (void) XtVaCreateManagedWidget("framedShadow", toggleWidgetClass, shadowSelector, XtNradioData, (XtArgVal) ShadowFramed, XtNradioGroup, (XtArgVal) shadow, XtNtranslations, (XtArgVal) oneOfMany, NULL); (void) XtVaCreateManagedWidget("filledShadow", toggleWidgetClass, shadowSelector, XtNradioData, (XtArgVal) ShadowFilled, XtNradioGroup, (XtArgVal) shadow, XtNtranslations, (XtArgVal) oneOfMany, NULL); doneBox = XtVaCreateManagedWidget("popDown", boxWidgetClass, container, NULL); okAcc = XtParseAcceleratorTable(okAccelTable); quit = XtVaCreateManagedWidget("confirm", commandWidgetClass, doneBox, XtNaccelerators, (XtArgVal) okAcc, NULL); XtAddCallback(quit, XtNcallback, TextPlaceNewCB, (XtPointer) True); XtAddCallback(quit, XtNcallback, TextPlaceModCB, (XtPointer) True); cancelAcc = XtParseAcceleratorTable(cancelAccelTable); cancel = XtVaCreateManagedWidget("cancel", commandWidgetClass, doneBox, XtNaccelerators, (XtArgVal) cancelAcc, NULL); XtAddCallback(cancel, XtNcallback, TextPlaceNewCB, (XtPointer) False); XtAddCallback(cancel, XtNcallback, TextPlaceModCB, (XtPointer) False); XtInstallAllAccelerators(textEntry, container); XtSetKeyboardFocus(container, textEntry); } /*ARGSUSED*/ static void TextPlaceNewCB(Widget cmd, XtPointer acc, XtPointer call_data) { TeXPictObj *newObj; Boolean accepted = (Boolean) (int) acc; Display *disp; Window win; if (!newText) return; disp = XtDisplay(pboard); win = XtWindow(pboard); /* erase rubber band */ ObjRubber(graphToType[graphMode], disp, win, points, pointsSet); if (accepted) { transform(textInput); /* remove special chars */ newObj = ObjCreate(graphToType[graphMode]); newObj->next = objList; objList = newObj; ObjStore(newObj, points, pointsSet); strcpy(newObj->data.rectangular.text, textInput); newObj->data.rectangular.align = (unsigned) XawToggleGetCurrent(position); newObj->data.rectangular.shadow = (Shadow) XawToggleGetCurrent(shadow); ObjDraw(newObj, disp, win); changeMade = True; } pointsSet = 0; XtPopdown(textPlacement); } /*ARGSUSED*/ static void TextPlaceModCB(Widget cmd, XtPointer acc, XtPointer call_data) { Boolean accepted = (Boolean) (int) acc; if (newText) return; if (accepted) { transform(textInput); /* remove special chars */ strcpy(selected->data.rectangular.text, textInput); selected->data.rectangular.align = (unsigned) XawToggleGetCurrent(position); selected->data.rectangular.shadow = (Shadow) XawToggleGetCurrent(shadow); /* redraw %%%%% */ ObjDraw(selected, XtDisplay(pboard), XtWindow(pboard)); changeMade = True; } XtPopdown(textPlacement); } /*ARGSUSED*/ void ToggleRuler(Widget w, XtPointer client_data, XtPointer call_data) { XtVaGetValues(w, XtNstate, &ruler, NULL); if (ruler) DrawRuler(); else if (XtIsRealized(pboard)) XClearArea(XtDisplay(pboard), XtWindow(pboard), 0, 0, 0, 0, True); } /*ARGSUSED*/ void ToggleRaster(Widget w, XtPointer client_data, XtPointer call_data) { XtVaGetValues(w, XtNstate, &raster, NULL); if (raster) { if (sscanf(rasterHeightStr, "%f", &rast_height) != 1 || !SetRaster(rast_height)) { /* not allowed */ raster = False; XtVaSetValues(w, XtNstate, (XtArgVal) raster, NULL); } else { DrawRaster(); } } else if (XtIsRealized(pboard)) XClearArea(XtDisplay(pboard), XtWindow(pboard), 0, 0, 0, 0, True); } static void DrawRuler(void) { /*%%%%%%%% ruler depends on zoom */ char s[10]; int slen; float sf, step = 5.0, xn, yn, xd, yd; int x, y; int xtick, ytick; Dimension width, height; int dir, font_asc, font_desc; XCharStruct overall; Display *disp = XtDisplay(pboard); Window win = XtWindow(pboard); if (!XtIsRealized(pboard)) return; XtVaGetValues(pboard, XtNwidth, &width, XtNheight, &height, NULL); sf = step*zoomFactor; xn = ((float) width)/(sf); yn = ((float) height)/(sf); for (x = 1; x < xn; x++) { xtick = (int) ((float)x * sf + 0.5); if ((x % 10) == 0) { XDrawLine(disp, win, rGC, xtick, 0, xtick, 7); GetCoords(xtick, 0, &xd, &yd); sprintf(s, "%.1f", xd); slen = strlen(s); /* center string correctly */ XTextExtents(ruler_font, s, slen, &dir, &font_asc, &font_desc, &overall); xtick -= overall.width/2; /* draw string 3 pixels below tick mark */ XDrawString(disp, win, rGC, xtick, overall.ascent+10, s, slen); } else if ((x % 5) == 0) XDrawLine(disp, win, rGC, xtick, 0, xtick, 4); else XDrawLine(disp, win, rGC, xtick, 0, xtick, 2); } for (y = 1; y < yn; y++) { ytick = (int) ((float) y * sf + 0.5); if ((y % 10) == 0) { XDrawLine(disp, win, rGC, 0, ytick, 7, ytick); GetCoords(0, ytick, &xd, &yd); sprintf(s, "%.1f", yd); slen = strlen(s); /* center string correctly * this more tedious than for horizontal rule */ XTextExtents(ruler_font, s, slen, &dir, &font_asc, &font_desc, &overall); ytick += overall.ascent - (overall.ascent + overall.descent)/2; XDrawString(disp, win, rGC, 10, ytick, s, slen); } else if ((y % 5) == 0) XDrawLine(disp, win, rGC, 0, ytick, 4, ytick); else XDrawLine(disp, win, rGC, 0, ytick, 2, ytick); } } static void DrawRaster(void) { float sf; int xn, yn; int x, y; int xf, yf; Display *disp = XtDisplay(pboard); Window win = XtWindow(pboard); Dimension width, height; XSegment *segs, *si; if (!XtIsRealized(pboard)) return; XtVaGetValues(pboard, XtNwidth, &width, XtNheight, &height, NULL); sf = rast_height*zoomFactor*fileScale; /* don't draw raster if points are too close: just return * silently. Probably zoom factor was reduced recently. * %%%% Should one toggle value of Boolean raster and of * %%%% widget rasterOn ? */ if (sf < MIN_RASTER){ return; } xn = (int) ((float)width / sf); yn = (int) ((float)height / sf); segs = (XSegment *) XtCalloc(2 * ((int) xn + 1) * ((int) yn + 1), sizeof(XSegment)); si = segs; for (x = 0; x <= xn; x++) { xf = (int) ((float)x * sf + 0.5); for (y = 0; y <= yn; y++) { yf = (int) ((float)y * sf + 0.5); si->x1 = xf-1; si->y1 = yf; si->x2 = xf+1; si->y2 = yf; si++; si->x1 = xf; si->y1 = yf-1; si->x2 = xf; si->y2 = yf+1; si++; } } XDrawSegments(disp, win, rGC, segs, si - segs); XtFree((XtPointer) segs); } /*ARGSUSED*/ void EditTextCB(Widget w, XtPointer client_data, XtPointer call_data) { Position x_rel, y_rel, x_abs, y_abs; char *title; if (objList == NULL || selected == NULL || (selected->type != TeXFramedText && selected->type != TeXDashedText && selected->type != TeXText)) { /*%%%% beep */ return; } switch (selected->type) { case TeXFramedText: title = framedPlaceTitle; break; case TeXDashedText: title = dashedPlaceTitle; break; case TeXText: title = textPlaceTitle; break; default: /*%%%% beep*/ return; } /* set new object indicator */ newText = False; /* setup pop-up */ XtVaGetValues(pboard, XtNx, &x_rel, XtNy, &y_rel, NULL); XtTranslateCoords(pboard, x_rel, y_rel, &x_abs, &y_abs); XtVaSetValues(textPlacement, XtNtitle, (XtArgVal) title, NULL); strcpy(textInput, selected->data.rectangular.text); XawToggleSetCurrent(position, (XtPointer) selected->data.rectangular.align); XawToggleSetCurrent(shadow, (XtPointer) selected->data.rectangular.shadow); /* notify text entry of change in text */ XtVaSetValues(textEntry, XtNstring, (XtArgVal) textInput, NULL); /*%%%%%% R4-compat needed */ XtSetSensitive(shadowSelector, selected->type != TeXText); XtPopupSpringLoaded(textPlacement); }