1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/box.c,v 1.13 2011/06/09 16:11:41 cvsps Exp $
19  */
20 
21 #define _INCLUDE_FROM_BOX_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "attr.e"
26 #include "auxtext.e"
27 #include "box.e"
28 #include "choice.e"
29 #include "cmd.e"
30 #include "color.e"
31 #include "cursor.e"
32 #include "cutpaste.e"
33 #include "dialog.e"
34 #include "drawing.e"
35 #include "dup.e"
36 #include "file.e"
37 #include "grid.e"
38 #include "mainloop.e"
39 #include "mark.e"
40 #include "msg.e"
41 #include "obj.e"
42 #include "pattern.e"
43 #include "poly.e"
44 #include "ps.e"
45 #include "raster.e"
46 #include "rect.e"
47 #include "ruler.e"
48 #include "select.e"
49 #include "setup.e"
50 #include "strtbl.e"
51 #include "util.e"
52 #include "xpixmap.e"
53 
54 int boxDrawn=FALSE;
55 
56 static XPoint bv[5];
57 
MyBox(window,gc,x1,y1,x2,y2)58 void MyBox(window, gc, x1, y1, x2, y2)
59    /* Hollow box, solid outline with width=1 */
60    Window window;
61    GC gc;
62    int x1, y1, x2, y2;
63 {
64    bv[0].x = (short)x1; bv[0].y = (short)y1;
65    bv[1].x = (short)x1; bv[1].y = (short)y2;
66    bv[2].x = (short)x2; bv[2].y = (short)y2;
67    bv[3].x = (short)x2; bv[3].y = (short)y1;
68    bv[4].x = (short)x1; bv[4].y = (short)y1;
69    XDrawLines(mainDisplay, window, gc, bv, 5, CoordModeOrigin);
70 }
71 
72 static
DumpBoxPath(FP,ObjPtr,LtX,LtY,RbX,RbY,Width,Pen,Dash,TransPat)73 void DumpBoxPath(FP, ObjPtr, LtX, LtY, RbX, RbY, Width, Pen, Dash, TransPat)
74    FILE *FP;
75    struct ObjRec *ObjPtr;
76    int LtX, LtY, RbX, RbY, Width, Pen, Dash, TransPat;
77 {
78    register int i;
79    int w_is_int=TRUE;
80    char *width_spec=ObjPtr->detail.b->width_spec;
81    double dw=GetWidthInDouble(Width, width_spec, &w_is_int);
82 
83    fprintf(FP, "   %s\n", gPsCmd[PS_GSAVE]);
84    if (!colorDump && useGray && Pen > BACKPAT) {
85       GrayCheck(Pen);
86       fprintf(FP, "      %s %s\n", GrayStr(Pen), gPsCmd[PS_SETGRAY]);
87    }
88    DumpRectPath(FP, LtX, LtY, RbX, RbY, 6, TRUE);
89 
90    if (ObjPtr->ctm != NULL) {
91       fprintf(FP, "      %s\n", &(gPsCmd[PS_TGIFSETMATRIX])[1]);
92    }
93    if (w_is_int) {
94       if (Width != 1) {
95          fprintf(FP, "      %1d %s\n", Width, gPsCmd[PS_SETLINEWIDTH]);
96       }
97    } else {
98       fprintf(FP, "      %.3f %s\n", dw, gPsCmd[PS_SETLINEWIDTH]);
99    }
100    if (Dash != 0) {
101       fprintf(FP, "      [");
102       for (i = 0; i < dashListLength[Dash]-1; i++) {
103          fprintf(FP, "%1d ", (int)(dashList[Dash][i]));
104       }
105       fprintf(FP, "%1d] 0 %s\n",
106             (int)(dashList[Dash][dashListLength[Dash]-1]), gPsCmd[PS_SETDASH]);
107    }
108 
109    switch (Pen) {
110    case SOLIDPAT: fprintf(FP, "      %s\n", gPsCmd[PS_STROKE]); break;
111    case BACKPAT:
112       if (!TransPat) {
113          fprintf(FP, "      1 %s %s 0 %s\n",
114                gPsCmd[PS_SETGRAY], gPsCmd[PS_STROKE], gPsCmd[PS_SETGRAY]);
115       }
116       break;
117    default:
118       if (colorDump || !useGray) {
119          if (preDumpSetup) PSUseColorPattern();
120          fprintf(FP, "      %s\n", gPsCmd[PS_FLATTENPATH]);
121          DumpPatFill(FP, Pen, ObjPtr->bbox, 6, TRUE);
122       } else {
123          fprintf(FP, "      %s\n", gPsCmd[PS_STROKE]);
124       }
125       break;
126    }
127    fprintf(FP, "   %s\n", gPsCmd[PS_GRESTORE]);
128 }
129 
DumpBoxObj(FP,ObjPtr)130 void DumpBoxObj(FP, ObjPtr)
131    FILE *FP;
132    struct ObjRec *ObjPtr;
133 {
134    int ltx, lty, rbx, rby, fill, width, pen, dash, color_index, trans_pat;
135 
136    if (ObjPtr->ctm == NULL) {
137       ltx = ObjPtr->obbox.ltx;
138       lty = ObjPtr->obbox.lty;
139       rbx = ObjPtr->obbox.rbx;
140       rby = ObjPtr->obbox.rby;
141    } else {
142       ltx = ObjPtr->orig_obbox.ltx;
143       lty = ObjPtr->orig_obbox.lty;
144       rbx = ObjPtr->orig_obbox.rbx;
145       rby = ObjPtr->orig_obbox.rby;
146    }
147    trans_pat = ObjPtr->trans_pat;
148    fill = ObjPtr->detail.b->fill;
149    pen = ObjPtr->detail.b->pen;
150    width = ObjPtr->detail.b->width;
151    dash = ObjPtr->detail.b->dash;
152 
153    if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
154          (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
155       return;
156    }
157    fprintf(FP, "%% BOX\n");
158    if (ObjPtr->ctm != NULL) {
159       float m[6];
160 
161       fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
162       m[CTM_SX] = ((float)ObjPtr->ctm->m[CTM_SX])/((float)1000.0);
163       m[CTM_SY] = ((float)ObjPtr->ctm->m[CTM_SY])/((float)1000.0);
164       m[CTM_SIN] = ((float)ObjPtr->ctm->m[CTM_SIN])/((float)1000.0);
165       m[CTM_MSIN] = ((float)ObjPtr->ctm->m[CTM_MSIN])/((float)1000.0);
166       fprintf(FP, "   %1d %1d %s\n", ObjPtr->x, ObjPtr->y,
167             gPsCmd[PS_TRANSLATE]);
168       fprintf(FP, "   [%.3f %.3f %.3f %.3f %1d %1d] %s\n",
169             m[CTM_SX], m[CTM_SIN], m[CTM_MSIN], m[CTM_SY],
170             ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY], gPsCmd[PS_CONCAT]);
171       fprintf(FP, "   %1d %s %1d %s %s\n",
172             ObjPtr->x, gPsCmd[PS_NEG], ObjPtr->y, gPsCmd[PS_NEG],
173             gPsCmd[PS_TRANSLATE]);
174    }
175    color_index = ObjPtr->color;
176    DumpRGBColorLine(FP, color_index, 0, TRUE);
177 
178    switch (fill) {
179       case NONEPAT: break;
180       case SOLIDPAT:
181          /* solid black object */
182          DumpRectPath(FP, ltx, lty, rbx, rby, 0, FALSE);
183          fprintf(FP, "%s\n", gPsCmd[PS_FILL]);
184          break;
185       case BACKPAT:
186          if (!trans_pat) {
187             /* solid white object */
188             DumpRectPath(FP, ltx, lty, rbx, rby, 0, FALSE);
189             fprintf(FP, "1 %s %s\n", gPsCmd[PS_SETGRAY], gPsCmd[PS_FILL]);
190             DumpRGBColorLine(FP, color_index, 3, TRUE);
191          }
192          break;
193       default:
194          /* patterned */
195          fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
196          if (colorDump || !useGray) {
197             if (preDumpSetup) PSUseColorPattern();
198             if (!trans_pat) {
199                DumpRectPath(FP, ltx, lty, rbx, rby, 3, FALSE);
200                fprintf(FP, "1 %s %s\n", gPsCmd[PS_SETGRAY], gPsCmd[PS_FILL]);
201                DumpRGBColorLine(FP, color_index, 3, TRUE);
202             }
203             DumpRectPath(FP, ltx, lty, rbx, rby, 3, FALSE);
204             fprintf(FP, "%s %s\n", gPsCmd[PS_EOCLIP], gPsCmd[PS_NEWPATH]);
205             DumpPatFill(FP, fill, ObjPtr->bbox, 3, TRUE);
206          } else {
207             GrayCheck(fill);
208             fprintf(FP, "   %s %s\n", GrayStr(fill), gPsCmd[PS_SETGRAY]);
209             DumpRectPath(FP, ltx, lty, rbx, rby, 3, FALSE);
210             fprintf(FP, "%s\n", gPsCmd[PS_FILL]);
211          }
212          fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
213          break;
214    }
215 
216    if (pen == NONEPAT) {
217       if (ObjPtr->ctm != NULL) fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
218       fprintf(FP, "\n");
219       return;
220    }
221 
222    fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
223    fprintf(FP, "   10 %s\n", gPsCmd[PS_SETMITERLIMIT]);
224 
225    if ((colorDump || !useGray) && pen > BACKPAT) {
226       DumpBoxPath(FP, ObjPtr, ltx, lty, rbx, rby, width, BACKPAT, 0, trans_pat);
227       DumpRGBColorLine(FP, color_index, 3, TRUE);
228    }
229    DumpBoxPath(FP, ObjPtr, ltx, lty, rbx, rby, width, pen, dash, trans_pat);
230 
231    fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
232    if (ObjPtr->ctm != NULL) fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
233    fprintf(FP, "\n");
234 }
235 
DrawBoxObj(win,XOff,YOff,ObjPtr)236 void DrawBoxObj(win, XOff, YOff, ObjPtr)
237    Window win;
238    int XOff, YOff;
239    struct ObjRec *ObjPtr;
240 {
241    struct BoxRec *box_ptr=ObjPtr->detail.b;
242    int fill, pen, pixel, ltx, lty, rbx, rby, width, dash, trans_pat;
243    int real_x_off, real_y_off;
244    XGCValues values;
245 
246    trans_pat = ObjPtr->trans_pat;
247    pen = box_ptr->pen;
248    fill = box_ptr->fill;
249    width = box_ptr->width;
250    dash = box_ptr->dash;
251    pixel = colorPixels[ObjPtr->color];
252 
253    if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
254          (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
255       return;
256    }
257    real_x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
258    real_y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
259    ltx = ZOOMED_SIZE(ObjPtr->obbox.ltx - real_x_off);
260    lty = ZOOMED_SIZE(ObjPtr->obbox.lty - real_y_off);
261    rbx = ZOOMED_SIZE(ObjPtr->obbox.rbx - real_x_off);
262    rby = ZOOMED_SIZE(ObjPtr->obbox.rby - real_y_off);
263 
264    if (fill != NONEPAT) {
265       values.foreground = GetDrawingBgPixel(fill, pixel);
266       values.function = GXcopy;
267       values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
268       values.stipple = patPixmap[fill];
269       XChangeGC(mainDisplay, drawGC,
270             GCForeground | GCFunction | GCFillStyle | GCStipple, &values);
271       if (ObjPtr->ctm != NULL) {
272          XFillPolygon(mainDisplay, win, drawGC, ObjPtr->rotated_obbox, 5,
273                Convex, CoordModeOrigin);
274       } else {
275          XFillRectangle(mainDisplay, win, drawGC, ltx, lty, rbx-ltx, rby-lty);
276       }
277    }
278 
279    if (pen != NONEPAT) {
280       values.foreground = GetDrawingBgPixel(pen, pixel);
281       values.function = GXcopy;
282       values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
283       values.stipple = patPixmap[pen];
284       values.line_width = ZOOMED_SIZE(width);
285 #ifdef NO_THIN_LINE
286       if (values.line_width < 1) values.line_width = 1;
287 #endif
288       values.join_style = JoinMiter;
289       if (dash != 0) {
290          XSetDashes(mainDisplay, drawGC, 0, dashList[dash],
291                dashListLength[dash]);
292          values.line_style = LineOnOffDash;
293       } else {
294          values.line_style = LineSolid;
295       }
296       XChangeGC(mainDisplay, drawGC,
297             GCForeground | GCFunction | GCFillStyle | GCStipple | GCLineWidth |
298             GCLineStyle | GCJoinStyle, &values);
299       if (ObjPtr->ctm != NULL) {
300          XDrawLines(mainDisplay, win, drawGC, ObjPtr->rotated_obbox, 5,
301                CoordModeOrigin);
302       } else {
303          XDrawRectangle(mainDisplay, win, drawGC, ltx, lty, rbx-ltx, rby-lty);
304       }
305    }
306 }
307 
CreateBoxObj(X1,Y1,X2,Y2,CreateAbsolute)308 int CreateBoxObj(X1, Y1, X2, Y2, CreateAbsolute)
309    int X1, Y1, X2, Y2, CreateAbsolute;
310 {
311    struct BoxRec *box_ptr;
312    struct ObjRec *obj_ptr;
313    int width=0, w, ltx, lty, rbx, rby;
314 
315    if (X1 == X2 && Y1 == Y2) return FALSE;
316    box_ptr = (struct BoxRec *)malloc(sizeof(struct BoxRec));
317    if (box_ptr == NULL) FailAllocMessage();
318    memset(box_ptr, 0, sizeof(struct BoxRec));
319    if (mainDisplay != NULL) {
320       box_ptr->fill = objFill;
321       box_ptr->width = width = curWidthOfLine[lineWidth];
322       UtilStrCpyN(box_ptr->width_spec, sizeof(box_ptr->width_spec),
323             curWidthOfLineSpec[lineWidth]);
324       box_ptr->pen = penPat;
325       box_ptr->dash = curDash;
326    }
327    obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
328    if (obj_ptr == NULL) FailAllocMessage();
329    memset(obj_ptr, 0, sizeof(struct ObjRec));
330 
331    if (X1 < X2) {
332       if (Y1 < Y2) {
333          ltx = X1; lty = Y1; rbx = X2; rby = Y2;
334       } else {
335          ltx = X1; lty = Y2; rbx = X2; rby = Y1;
336       }
337    } else {
338       if (Y1 < Y2) {
339          ltx = X2; lty = Y1; rbx = X1; rby = Y2;
340       } else {
341          ltx = X2; lty = Y2; rbx = X1; rby = Y1;
342       }
343    }
344    if (CreateAbsolute) {
345       obj_ptr->bbox.ltx = obj_ptr->obbox.ltx = obj_ptr->x = ltx;
346       obj_ptr->bbox.lty = obj_ptr->obbox.lty = obj_ptr->y = lty;
347       obj_ptr->bbox.rbx = obj_ptr->obbox.rbx = rbx;
348       obj_ptr->bbox.rby = obj_ptr->obbox.rby = rby;
349    } else {
350       obj_ptr->bbox.ltx = obj_ptr->obbox.ltx = obj_ptr->x = ABS_X(ltx);
351       obj_ptr->bbox.lty = obj_ptr->obbox.lty = obj_ptr->y = ABS_Y(lty);
352       obj_ptr->bbox.rbx = obj_ptr->obbox.rbx = ABS_X(rbx);
353       obj_ptr->bbox.rby = obj_ptr->obbox.rby = ABS_Y(rby);
354    }
355    w = HALF_W(width);
356    obj_ptr->bbox.ltx -= w;
357    obj_ptr->bbox.lty -= w;
358    obj_ptr->bbox.rbx += w;
359    obj_ptr->bbox.rby += w;
360    obj_ptr->type = OBJ_BOX;
361    obj_ptr->color = colorIndex;
362    if (mainDisplay != NULL) {
363       UtilStrCpyN(obj_ptr->color_str, sizeof(obj_ptr->color_str),
364             colorMenuItems[colorIndex]);
365    }
366    obj_ptr->id = objId++;
367    obj_ptr->dirty = FALSE;
368    obj_ptr->rotation = 0;
369    obj_ptr->locked = FALSE;
370    obj_ptr->detail.b = box_ptr;
371    obj_ptr->fattr = obj_ptr->lattr = NULL;
372    obj_ptr->ctm = NULL;
373    obj_ptr->invisible = FALSE;
374    obj_ptr->trans_pat = transPat;
375 
376    AddObj(NULL, topObj, obj_ptr);
377 
378    return TRUE;
379 }
380 
381 static
ContinueBox(OrigX,OrigY)382 void ContinueBox(OrigX, OrigY)
383    int  OrigX, OrigY;
384 {
385    int end_x, end_y, grid_x, grid_y, saved_x, saved_y;
386    int done=FALSE, abort=FALSE;
387    char buf[80], w_buf[80], h_buf[80], x_buf[80], y_buf[80];
388    XEvent input, ev;
389    XMotionEvent *motion_ev;
390 
391    SetXorDrawGC(xorColorPixels[colorIndex]);
392 
393    saved_x = grid_x = OrigX;
394    saved_y = grid_y = OrigY;
395    PixelToMeasurementUnit(w_buf, 0);
396    PixelToMeasurementUnit(h_buf, 0);
397    PixelToMeasurementUnit(x_buf, ABS_X(grid_x));
398    PixelToMeasurementUnit(y_buf, ABS_Y(grid_y));
399    sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
400    StartShowMeasureCursor(grid_x, grid_y, buf, TRUE);
401    BeginIntervalRulers(grid_x, grid_y, grid_x, grid_y);
402    if (!debugNoPointerGrab) {
403       XGrabPointer(mainDisplay, drawWindow, FALSE,
404             PointerMotionMask | ButtonReleaseMask,
405             GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
406    }
407    while (!done) {
408       XNextEvent(mainDisplay, &input);
409 
410       if (input.type == Expose || input.type == VisibilityNotify) {
411          ExposeEventHandler(&input, TRUE);
412          SetXorDrawGC(xorColorPixels[colorIndex]);
413       } else if (input.type == ButtonRelease) {
414          XUngrabPointer(mainDisplay, CurrentTime);
415          MyBox(drawWindow, drawGC, OrigX, OrigY, saved_x, saved_y);
416          EndIntervalRulers(grid_x, grid_y);
417          PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(saved_x-OrigX)));
418          PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(saved_y-OrigY)));
419          PixelToMeasurementUnit(x_buf, ABS_X(saved_x));
420          PixelToMeasurementUnit(y_buf, ABS_Y(saved_y));
421          sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
422          EndShowMeasureCursor(saved_x, saved_y, buf, TRUE);
423          done = TRUE;
424       } else if (input.type == MotionNotify) {
425          motion_ev = &(input.xmotion);
426          end_x = motion_ev->x;
427          end_y = motion_ev->y;
428          GridXY(end_x, end_y, &grid_x, &grid_y);
429          if (motion_ev->state & (ShiftMask | ControlMask)) {
430             int w, h, pos_w=TRUE, pos_h=TRUE;
431 
432             w = grid_x - OrigX;
433             h = grid_y - OrigY;
434             if (w < 0) {
435                w = (-w);
436                pos_w = FALSE;
437             }
438             if (h < 0) {
439                h = (-h);
440                pos_h = FALSE;
441             }
442             if (w > h) {
443                grid_x = (pos_w ? (OrigX+h) : (OrigX-h));
444             } else {
445                grid_y = (pos_h ? (OrigY+w) : (OrigY-w));
446             }
447          }
448          if (grid_x != saved_x || grid_y != saved_y) {
449             PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(saved_x-OrigX)));
450             PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(saved_y-OrigY)));
451             PixelToMeasurementUnit(x_buf, ABS_X(saved_x));
452             PixelToMeasurementUnit(y_buf, ABS_Y(saved_y));
453             sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
454             ShowMeasureCursor(saved_x, saved_y, buf, TRUE);
455             MyBox(drawWindow, drawGC, OrigX, OrigY, saved_x, saved_y);
456             saved_x = grid_x;
457             saved_y = grid_y;
458             MyBox(drawWindow, drawGC, OrigX, OrigY, saved_x, saved_y);
459             PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(saved_x-OrigX)));
460             PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(saved_y-OrigY)));
461             PixelToMeasurementUnit(x_buf, ABS_X(saved_x));
462             PixelToMeasurementUnit(y_buf, ABS_Y(saved_y));
463             sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
464             ShowMeasureCursor(saved_x, saved_y, buf, TRUE);
465          }
466          DrawIntervalRulers(OrigX, OrigY, grid_x, grid_y, NULL);
467          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
468       } else if (input.type == KeyPress) {
469          if (KeyPressEventIsEscape(&input.xkey)) {
470             XUngrabPointer(mainDisplay, CurrentTime);
471             MyBox(drawWindow, drawGC, OrigX, OrigY, saved_x, saved_y);
472             EndIntervalRulers(grid_x, grid_y);
473             PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(saved_x-OrigX)));
474             PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(saved_y-OrigY)));
475             PixelToMeasurementUnit(x_buf, ABS_X(saved_x));
476             PixelToMeasurementUnit(y_buf, ABS_Y(saved_y));
477             sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
478             EndShowMeasureCursor(saved_x, saved_y, buf, TRUE);
479             abort = TRUE;
480             done = TRUE;
481          }
482       }
483    }
484    if (!abort && OrigX != grid_x && OrigY != grid_y) {
485       CreateBoxObj(OrigX, OrigY, grid_x, grid_y, FALSE);
486       RecordNewObjCmd();
487       DrawBoxObj(drawWindow, drawOrigX, drawOrigY, topObj);
488       boxDrawn = TRUE;
489       SetFileModified(TRUE);
490    }
491    XSync(mainDisplay, False);
492 }
493 
DrawBox(input)494 void DrawBox(input)
495    XEvent *input;
496 {
497    XButtonEvent *button_ev;
498    int mouse_x, mouse_y, grid_x, grid_y;
499 
500    if (input->type != ButtonPress) return;
501 
502    button_ev = &(input->xbutton);
503    if (button_ev->button == Button1) {
504       mouse_x = button_ev->x;
505       mouse_y = button_ev->y;
506       GridXY(mouse_x, mouse_y, &grid_x, &grid_y);
507       ContinueBox(grid_x, grid_y);
508    }
509 }
510 
MakeBoxObjFromBoundingBox()511 void MakeBoxObjFromBoundingBox()
512 {
513    if (topSel == NULL) {
514       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
515       return;
516    }
517    if (curChoice == VERTEXMODE) SetCurChoice(NOTHING);
518 
519    HighLightReverse();
520    CreateBoxObj(selObjLtX, selObjLtY, selObjRbX, selObjRbY, TRUE);
521    SelectTopObj();
522    RecordNewObjCmd();
523    RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
524          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
525    HighLightForward();
526    justDupped = FALSE;
527    SetFileModified(TRUE);
528 }
529 
SaveBoxObj(FP,ObjPtr)530 void SaveBoxObj(FP, ObjPtr)
531    FILE *FP;
532    struct ObjRec *ObjPtr;
533 {
534    struct BoxRec *box_ptr=ObjPtr->detail.b;
535 
536    if (fprintf(FP, "box('%s','',", colorMenuItems[ObjPtr->color]) == EOF) {
537       writeFileFailed = TRUE;
538    }
539    if (fprintf(FP,
540          "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,'%s',%1d,",
541          ObjPtr->obbox.ltx, ObjPtr->obbox.lty, ObjPtr->obbox.rbx,
542          ObjPtr->obbox.rby, box_ptr->fill, box_ptr->width, box_ptr->pen,
543          ObjPtr->id, box_ptr->dash, ObjPtr->rotation, ObjPtr->locked,
544          ObjPtr->ctm!=NULL, ObjPtr->invisible, box_ptr->width_spec,
545          ObjPtr->trans_pat) == EOF) {
546       writeFileFailed = TRUE;
547    }
548    if (ObjPtr->ctm != NULL && fprintf(FP,
549          "[\n    %1d,%1d,%1d,%1d,%1d,%1d,%g,%g,%g,%g,%1d,%1d],",
550          ObjPtr->x, ObjPtr->y,
551          ObjPtr->orig_obbox.ltx, ObjPtr->orig_obbox.lty,
552          ObjPtr->orig_obbox.rbx, ObjPtr->orig_obbox.rby,
553          ObjPtr->ctm->m[CTM_SX], ObjPtr->ctm->m[CTM_SIN],
554          ObjPtr->ctm->m[CTM_MSIN], ObjPtr->ctm->m[CTM_SY],
555          ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY]) == EOF) {
556       writeFileFailed = TRUE;
557    }
558    if (serializingFile) SaveCreatorID(FP, ObjPtr, "    ");
559    SaveAttrs(FP, ObjPtr->lattr);
560    if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
561 }
562 
ReadBoxObj(FP,Inbuf,ObjPtr)563 void ReadBoxObj(FP, Inbuf, ObjPtr)
564    FILE *FP;
565    char *Inbuf;
566    struct ObjRec **ObjPtr;
567 {
568    struct BoxRec *box_ptr;
569    char color_str[40], bg_color_str[40], *s, width_spec[40];
570    int ltx, lty, rbx, rby, fill, width, pen, dash, w, id=0, trans_pat=FALSE;
571    int new_alloc, rotation, locked=FALSE, transformed=FALSE, invisible=FALSE;
572 
573    *ObjPtr = NULL;
574 
575    s = FindChar((int)'(', Inbuf);
576    s = ParseStr(s, (int)',', color_str, sizeof(color_str));
577    if (fileVersion >= 37) {
578       s = ParseStr(s, (int)',', bg_color_str, sizeof(bg_color_str));
579    }
580    InitScan(s, "\t\n, ");
581 
582    dash = 0;
583    rotation = 0;
584    *width_spec = '\0';
585    if (fileVersion <= 5) {
586       if (GETINT("box", ltx,      "ltx") == INVALID ||
587           GETINT("box", lty,      "lty") == INVALID ||
588           GETINT("box", rbx,      "rbx") == INVALID ||
589           GETINT("box", rby,      "rby") == INVALID ||
590           GETINT("box", fill,     "fill") == INVALID ||
591           GETINT("box", width,    "width") == INVALID ||
592           GETINT("box", pen,      "pen") == INVALID)
593       {
594          return;
595       }
596       switch (width) {
597       case 1: width = 3; break;
598       case 2: width = 6; break;
599       }
600       id = objId++;
601    } else if (fileVersion <= 7) {
602       if (GETINT("box", ltx,      "ltx") == INVALID ||
603           GETINT("box", lty,      "lty") == INVALID ||
604           GETINT("box", rbx,      "rbx") == INVALID ||
605           GETINT("box", rby,      "rby") == INVALID ||
606           GETINT("box", fill,     "fill") == INVALID ||
607           GETINT("box", width,    "width") == INVALID ||
608           GETINT("box", pen,      "pen") == INVALID)
609       {
610          return;
611       }
612       id = objId++;
613    } else if (fileVersion <= 8) {
614       if (GETINT("box", ltx,      "ltx") == INVALID ||
615           GETINT("box", lty,      "lty") == INVALID ||
616           GETINT("box", rbx,      "rbx") == INVALID ||
617           GETINT("box", rby,      "rby") == INVALID ||
618           GETINT("box", fill,     "fill") == INVALID ||
619           GETINT("box", width,    "width") == INVALID ||
620           GETINT("box", pen,      "pen") == INVALID ||
621           GETINT("box", id,       "id") == INVALID)
622       {
623          return;
624       }
625       if (id >= objId) objId = id+1;
626    } else if (fileVersion <= 13) {
627       if (GETINT("box", ltx,      "ltx") == INVALID ||
628           GETINT("box", lty,      "lty") == INVALID ||
629           GETINT("box", rbx,      "rbx") == INVALID ||
630           GETINT("box", rby,      "rby") == INVALID ||
631           GETINT("box", fill,     "fill") == INVALID ||
632           GETINT("box", width,    "width") == INVALID ||
633           GETINT("box", pen,      "pen") == INVALID ||
634           GETINT("box", id,       "id") == INVALID ||
635           GETINT("box", dash,     "dash") == INVALID)
636       {
637          return;
638       }
639       if (id >= objId) objId = id+1;
640    } else if (fileVersion <= 25) {
641       if (GETINT("box", ltx,      "ltx") == INVALID ||
642           GETINT("box", lty,      "lty") == INVALID ||
643           GETINT("box", rbx,      "rbx") == INVALID ||
644           GETINT("box", rby,      "rby") == INVALID ||
645           GETINT("box", fill,     "fill") == INVALID ||
646           GETINT("box", width,    "width") == INVALID ||
647           GETINT("box", pen,      "pen") == INVALID ||
648           GETINT("box", id,       "id") == INVALID ||
649           GETINT("box", dash,     "dash") == INVALID ||
650           GETINT("box", rotation, "rotation") == INVALID)
651       {
652          return;
653       }
654       if (id >= objId) objId = id+1;
655    } else if (fileVersion <= 32) {
656       if (GETINT("box", ltx,      "ltx") == INVALID ||
657           GETINT("box", lty,      "lty") == INVALID ||
658           GETINT("box", rbx,      "rbx") == INVALID ||
659           GETINT("box", rby,      "rby") == INVALID ||
660           GETINT("box", fill,     "fill") == INVALID ||
661           GETINT("box", width,    "width") == INVALID ||
662           GETINT("box", pen,      "pen") == INVALID ||
663           GETINT("box", id,       "id") == INVALID ||
664           GETINT("box", dash,     "dash") == INVALID ||
665           GETINT("box", rotation, "rotation") == INVALID ||
666           GETINT("box", locked,   "locked") == INVALID)
667       {
668          return;
669       }
670       if (id >= objId) objId = id+1;
671    } else if (fileVersion <= 34) {
672       if (GETINT("box", ltx,         "ltx") == INVALID ||
673           GETINT("box", lty,         "lty") == INVALID ||
674           GETINT("box", rbx,         "rbx") == INVALID ||
675           GETINT("box", rby,         "rby") == INVALID ||
676           GETINT("box", fill,        "fill") == INVALID ||
677           GETINT("box", width,       "width") == INVALID ||
678           GETINT("box", pen,         "pen") == INVALID ||
679           GETINT("box", id,          "id") == INVALID ||
680           GETINT("box", dash,        "dash") == INVALID ||
681           GETINT("box", rotation,    "rotation") == INVALID ||
682           GETINT("box", locked,      "locked") == INVALID ||
683           GETINT("box", transformed, "transformed") == INVALID ||
684           GETINT("box", invisible,   "invisible") == INVALID ||
685           GETSTR("box", width_spec,  "width_spec") == INVALID)
686       {
687          return;
688       }
689       if (id >= objId) objId = id+1;
690       UtilRemoveQuotes(width_spec);
691    } else {
692       if (GETINT("box", ltx,         "ltx") == INVALID ||
693           GETINT("box", lty,         "lty") == INVALID ||
694           GETINT("box", rbx,         "rbx") == INVALID ||
695           GETINT("box", rby,         "rby") == INVALID ||
696           GETINT("box", fill,        "fill") == INVALID ||
697           GETINT("box", width,       "width") == INVALID ||
698           GETINT("box", pen,         "pen") == INVALID ||
699           GETINT("box", id,          "id") == INVALID ||
700           GETINT("box", dash,        "dash") == INVALID ||
701           GETINT("box", rotation,    "rotation") == INVALID ||
702           GETINT("box", locked,      "locked") == INVALID ||
703           GETINT("box", transformed, "transformed") == INVALID ||
704           GETINT("box", invisible,   "invisible") == INVALID ||
705           GETSTR("box", width_spec,  "width_spec") == INVALID ||
706           GETINT("box", trans_pat,   "trans_pat") == INVALID)
707       {
708          return;
709       }
710       if (id >= objId) objId = id+1;
711       UtilRemoveQuotes(width_spec);
712    }
713    if (fileVersion <= 16 && width <= 6) width = origWidthOfLine[width];
714    if (fileVersion <= 32) {
715       sprintf(width_spec, "%1d", width);
716    }
717    fill = UpgradePenFill(fill);
718    pen = UpgradePenFill(pen);
719 
720    *ObjPtr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
721    if (*ObjPtr == NULL) FailAllocMessage();
722    memset(*ObjPtr, 0, sizeof(struct ObjRec));
723    box_ptr = (struct BoxRec *)malloc(sizeof(struct BoxRec));
724    if (box_ptr == NULL) FailAllocMessage();
725    memset(box_ptr, 0, sizeof(struct BoxRec));
726 
727    if (ltx > rbx || lty > rby) {
728       int tmp_ltx, tmp_lty, tmp_rbx, tmp_rby;
729 
730       if (!PRTGIF) {
731          Msg(TgLoadCachedString(CSTID_BAD_BOX_BBOX_ADJUSTED));
732       }
733       CalcBBox(ltx, lty, rbx, rby, &tmp_ltx, &tmp_lty, &tmp_rbx, &tmp_rby);
734       ltx = tmp_ltx; lty = tmp_lty; rbx = tmp_rbx; rby = tmp_rby;
735    }
736 
737    (*ObjPtr)->trans_pat = trans_pat;
738    box_ptr->fill = fill;
739    box_ptr->width = width;
740    UtilStrCpyN(box_ptr->width_spec, sizeof(box_ptr->width_spec), width_spec);
741    box_ptr->pen = pen;
742    box_ptr->dash = dash;
743    (*ObjPtr)->x = ltx;
744    (*ObjPtr)->y = lty;
745    (*ObjPtr)->color = QuickFindColorIndex(*ObjPtr, color_str, &new_alloc, TRUE);
746    UtilStrCpyN((*ObjPtr)->color_str, sizeof((*ObjPtr)->color_str), color_str);
747    (*ObjPtr)->dirty = FALSE;
748    (*ObjPtr)->id = id;
749    (*ObjPtr)->rotation = rotation;
750    (*ObjPtr)->locked = locked;
751    (*ObjPtr)->type = OBJ_BOX;
752    (*ObjPtr)->obbox.ltx = ltx;
753    (*ObjPtr)->obbox.lty = lty;
754    (*ObjPtr)->obbox.rbx = rbx;
755    (*ObjPtr)->obbox.rby = rby;
756    w = HALF_W(width);
757    (*ObjPtr)->bbox.ltx = ltx - w;
758    (*ObjPtr)->bbox.lty = lty - w;
759    (*ObjPtr)->bbox.rbx = rbx + w;
760    (*ObjPtr)->bbox.rby = rby + w;
761    (*ObjPtr)->detail.b = box_ptr;
762    (*ObjPtr)->ctm = NULL;
763    (*ObjPtr)->invisible = invisible;
764 
765    if (fileVersion >= 33 && transformed) {
766       int real_x=0, real_y=0;
767       struct BBRec orig_obbox;
768       char inbuf[MAXSTRING+1];
769       struct XfrmMtrxRec *ctm;
770 
771       (void)fgets(inbuf, MAXSTRING, FP);
772       scanLineNum++;
773       InitScan(inbuf, "\t\n, ");
774 
775       ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec));
776       if (ctm == NULL) FailAllocMessage();
777       if (GETINT("box", real_x,           "real_x") == INVALID ||
778           GETINT("box", real_y,           "real_y") == INVALID ||
779           GETINT("box", orig_obbox.ltx,   "orig_obbox.ltx") == INVALID ||
780           GETINT("box", orig_obbox.lty,   "orig_obbox.lty") == INVALID ||
781           GETINT("box", orig_obbox.rbx,   "orig_obbox.rbx") == INVALID ||
782           GETINT("box", orig_obbox.rby,   "orig_obbox.rby") == INVALID ||
783           GETDBL("box", ctm->m[CTM_SX],   "CTM_SX") == INVALID ||
784           GETDBL("box", ctm->m[CTM_SIN],  "CTM_SIN") == INVALID ||
785           GETDBL("box", ctm->m[CTM_MSIN], "CTM_MSIN") == INVALID ||
786           GETDBL("box", ctm->m[CTM_SY],   "CTM_SY") == INVALID ||
787           GETINT("box", ctm->t[CTM_TX],   "CTM_TX") == INVALID ||
788           GETINT("box", ctm->t[CTM_TY],   "CTM_TY") == INVALID) {
789          return;
790       }
791       (*ObjPtr)->ctm = ctm;
792       if (ctm != NULL) {
793          memcpy(&(*ObjPtr)->orig_obbox, &orig_obbox, sizeof(struct BBRec));
794          (*ObjPtr)->x = real_x;
795          (*ObjPtr)->y = real_y;
796          GetTransformedOBBoxOffsetVs(*ObjPtr, (*ObjPtr)->rotated_obbox);
797       }
798    }
799 }
800 
SetBoxPropMask(ObjPtr,plMask,plSkip,pProp)801 void SetBoxPropMask(ObjPtr, plMask, plSkip, pProp)
802    struct ObjRec *ObjPtr;
803    long *plMask, *plSkip;
804    struct PropertiesRec *pProp;
805 {
806    struct BoxRec *box_ptr=ObjPtr->detail.b;
807 
808    SetCTMPropertyMask(ObjPtr->ctm, plMask, plSkip, pProp);
809 
810    SetIntPropertyMask(PROP_MASK_COLOR, ObjPtr->color,
811          colorMenuItems[ObjPtr->color], plMask, plSkip, pProp);
812    SetIntPropertyMask(PROP_MASK_WIDTH, box_ptr->width, box_ptr->width_spec,
813          plMask, plSkip, pProp);
814 
815    SetIntPropertyMask(PROP_MASK_TRANSPAT, ObjPtr->trans_pat, NULL,
816          plMask, plSkip, pProp);
817    SetIntPropertyMask(PROP_MASK_FILL, box_ptr->fill, NULL,
818          plMask, plSkip, pProp);
819    SetIntPropertyMask(PROP_MASK_PEN, box_ptr->pen, NULL,
820          plMask, plSkip, pProp);
821    SetIntPropertyMask(PROP_MASK_DASH, box_ptr->dash, NULL,
822          plMask, plSkip, pProp);
823 }
824 
FreeBoxObj(ObjPtr)825 void FreeBoxObj(ObjPtr)
826    struct ObjRec *ObjPtr;
827 {
828    free(ObjPtr->detail.b);
829    free(ObjPtr);
830 }
831