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/ruler.c,v 1.20 2011/05/16 16:21:59 william Exp $
19 */
20
21 #define _INCLUDE_FROM_RULER_C_
22
23 #include "tgifdefs.h"
24
25 #include "choice.e"
26 #include "cursor.e"
27 #include "dialog.e"
28 #include "file.e"
29 #include "font.e"
30 #include "grid.e"
31 #include "mainloop.e"
32 #include "mainmenu.e"
33 #include "menu.e"
34 #include "msg.e"
35 #include "raster.e"
36 #include "rect.e"
37 #include "ruler.e"
38 #include "select.e"
39 #include "setup.e"
40 #include "strtbl.e"
41 #include "text.e"
42 #include "util.e"
43 #include "xpixmap.e"
44
45 #define INCH_H (RULER_W-2)
46
47 #define HALF_INCH_H 10
48 #define QUARTER_INCH_H 6
49 #define MIN_INCH_H 3
50
51 #define HALF_CM_H 8
52 #define MIN_CM_H 4
53
54 int showMeasurement=FALSE;
55 int showMeasurementInTooltip=TRUE;
56 int simpleMotionInDrawWin=FALSE;
57 int showCrossHair=FALSE;
58
59 static int measureTooltipVerbose=FALSE;
60
61 static float gfPixelsPerUnit=(float)1.0;
62 static float gfNumUnits=(float)1.0;
63 static float gfNumFracUnits=(float)1.0;
64
65 static char numUnitStr[80], baseUnitStr[80], unitStr[80], formatUnitStr[80];
66
67 static GC rulerGC;
68
69 static int oldXOff=(-1), oldYOff=(-1);
70 static int rulerLen=0;
71 static int hRulerJustRedrawn=TRUE, justUnFrozen=FALSE;
72 static int freezeMarkRulerText=FALSE, frozenXOff=0, frozenYOff=0;
73 static char *gpszFrozenDeltaStr=NULL;
74
75 static char *gpszOldDeltaStr=NULL;
76
GetUnitSpec(buf)77 void GetUnitSpec(buf)
78 char *buf;
79 {
80 if (*formatUnitStr == '\0') {
81 sprintf(buf, "%s %s/%s",
82 (*numUnitStr)=='\0' ? "1" : numUnitStr,
83 (*baseUnitStr)=='\0' ? "pixel" : baseUnitStr,
84 (*unitStr)=='\0' ? "pixel" : unitStr);
85 } else {
86 char buf1[80];
87
88 FormatFloat(&gfNumFracUnits, buf1);
89 sprintf(buf, "%s %s/%s;%s;%s",
90 (*numUnitStr)=='\0' ? "1" : numUnitStr,
91 (*baseUnitStr)=='\0' ? "pixel" : baseUnitStr,
92 (*unitStr)=='\0' ? "pixel" : unitStr, formatUnitStr, buf1);
93 }
94 }
95
ShowUnitMsg()96 void ShowUnitMsg()
97 {
98 sprintf(gszMsgBox, TgLoadString(STID_MEASUREMENT_SHOWN_IN_UNIT),
99 (*unitStr)=='\0' ? "pixel" : unitStr,
100 (*numUnitStr)=='\0' ? "1" : numUnitStr,
101 (*baseUnitStr)=='\0' ? "pixel" : baseUnitStr);
102 Msg(gszMsgBox);
103 }
104
105 static
BadUnit(spec)106 int BadUnit(spec)
107 char *spec;
108 {
109 if (msgWindow != None) {
110 sprintf(gszMsgBox, TgLoadString(STID_BAD_MEASUREMENT_UNIT_SPEC), spec);
111 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
112 }
113 return FALSE;
114 }
115
116 static
VerifyFormatUnitStr(format_unit_str)117 int VerifyFormatUnitStr(format_unit_str)
118 char *format_unit_str;
119 {
120 char *c_ptr=format_unit_str, *semi_ptr=NULL;
121 int seek_percent=TRUE, count=0;
122
123 if ((semi_ptr=strchr(format_unit_str, ';')) == NULL) {
124 return FALSE;
125 } else {
126 float fval;
127
128 *semi_ptr++ = '\0';
129 UtilTrimBlanks(semi_ptr);
130 if (sscanf(semi_ptr, "%f", &fval) != 1) {
131 return FALSE;
132 }
133 gfNumFracUnits = fval;
134 }
135 for (c_ptr=format_unit_str; *c_ptr != '\0'; c_ptr++) {
136 if (seek_percent) {
137 if (*c_ptr == '%') {
138 seek_percent = FALSE;
139 }
140 } else if (*c_ptr == 'f') {
141 seek_percent = TRUE;
142 count++;
143 } else if (!(*c_ptr == '.' || (*c_ptr >= '0' && *c_ptr <= '9'))) {
144 return FALSE;
145 }
146 }
147 if (seek_percent && count==2) {
148 strcpy(formatUnitStr, format_unit_str);
149 return TRUE;
150 }
151 return FALSE;
152 }
153
SetUnit(spec)154 int SetUnit(spec)
155 char *spec;
156 {
157 char *spec_copy=UtilStrDup(spec);
158 char *num_ptr=NULL, *base_ptr=NULL, *unit_ptr=NULL, *semi_ptr=NULL;
159 int ok=TRUE;
160
161 if (spec_copy == NULL) {
162 return FALSE;
163 }
164 if ((semi_ptr=strchr(spec_copy, ';')) != NULL) {
165 *semi_ptr++ = '\0';
166 if (!VerifyFormatUnitStr(semi_ptr)) {
167 ok = BadUnit(spec);
168 }
169 } else {
170 *formatUnitStr = '\0';
171 }
172 if ((num_ptr=strtok(spec_copy, " \t\n\r")) != NULL &&
173 (base_ptr=strtok(NULL, "/ \t\n\r")) != NULL &&
174 (unit_ptr=strtok(NULL, "/ \t\n\r")) != NULL) {
175 float fval;
176
177 if (sscanf(num_ptr, "%f", &fval) == 1 && fval > INT_TOL &&
178 *base_ptr != '\0' && *unit_ptr != '\0') {
179 gfNumUnits = fval;
180 strcpy(numUnitStr, num_ptr);
181 if (UtilStrICmp("pixel", unit_ptr) == 0) {
182 *unitStr = '\0';
183 } else {
184 strcpy(unitStr, unit_ptr);
185 }
186 switch (*base_ptr) {
187 case 'i':
188 case 'I':
189 gfPixelsPerUnit = gfNumUnits * ((float)ONE_INCH);
190 strcpy(baseUnitStr, "in");
191 break;
192 case 'c':
193 case 'C':
194 gfPixelsPerUnit = gfNumUnits * ((float)ONE_CM);
195 strcpy(baseUnitStr, "cm");
196 break;
197 case 'p':
198 case 'P':
199 gfPixelsPerUnit = gfNumUnits;
200 *baseUnitStr = '\0';
201 break;
202 default: ok = BadUnit(spec); break;
203 }
204 } else {
205 ok = BadUnit(spec);
206 }
207 } else {
208 ok = BadUnit(spec);
209 }
210 if (!ok) {
211 gfPixelsPerUnit = gfNumUnits = (float)1.0;
212 *numUnitStr = *baseUnitStr = *unitStr = *formatUnitStr = '\0';
213 }
214 free(spec_copy);
215 return ok;
216 }
217
InitRuler()218 void InitRuler()
219 {
220 XGCValues values;
221 char *c_ptr;
222
223 values.foreground = myFgPixel;
224 values.background = (threeDLook ? myLtGryPixel : myBgPixel);
225 values.fill_style = FillSolid;
226 values.font = rulerFontPtr->fid;
227
228 rulerGC = XCreateGC(mainDisplay, mainWindow,
229 GCForeground | GCBackground | GCFillStyle | GCFont, &values);
230
231 showMeasurement = FALSE;
232 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME, "ShowMeasurement")) != NULL &&
233 UtilStrICmp(c_ptr, "true") == 0) {
234 showMeasurement = TRUE;
235 }
236 showCrossHair = FALSE;
237 /* if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME, "ShowCrossHair")) != NULL &&
238 UtilStrICmp(c_ptr, "true") == 0) {
239 showCrossHair = TRUE;
240 } */
241
242 gfPixelsPerUnit = gfNumUnits = (float)1.0;
243 *numUnitStr = *baseUnitStr = *unitStr = *formatUnitStr = '\0';
244 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME, "ShowMeasurementUnit")) !=
245 NULL) {
246 char spec[80];
247
248 if (strcmp("pixel", c_ptr) == 0) {
249 strcpy(spec, "1 pixel/pixel");
250 } else if (strcmp("inch", c_ptr) == 0) {
251 sprintf(spec, "%1d pixel/in", ONE_INCH);
252 } else if (strcmp("cm", c_ptr) == 0) {
253 sprintf(spec, "%1d pixel/cm", ONE_CM);
254 } else {
255 strcpy(spec, c_ptr);
256 }
257 if (!SetUnit(spec)) {
258 fprintf(stderr, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
259 TOOL_NAME, "ShowMeasurementUnit", spec, "pixel");
260 fprintf(stderr, "\n");
261 }
262 }
263 rulerLen = rulerW-1;
264 }
265
CleanUpRuler()266 void CleanUpRuler()
267 {
268 XFreeGC(mainDisplay, rulerGC);
269 }
270
PixelToMeasurementUnit(Buf,NumPixels)271 void PixelToMeasurementUnit(Buf, NumPixels)
272 char *Buf;
273 int NumPixels;
274 {
275 float fval;
276 int ival;
277
278 if (*unitStr == '\0') {
279 sprintf(Buf, "%+1d", NumPixels);
280 } else {
281 fval = (float)((float)NumPixels*1000.0)/(gfPixelsPerUnit);
282 ival = ((int)round(fval));
283 fval = ((float)ival)/((float)1000.0);
284 if (*formatUnitStr == '\0') {
285 sprintf(Buf, "%+.3f%s", fval, unitStr);
286 } else {
287 float frac;
288
289 ival = (int)fval;
290 frac = ((ival >= 0) ? fval-((float)ival) : ((float)ival)-fval);
291 fval = (float)ival;
292 sprintf(Buf, formatUnitStr, fval, frac*gfNumFracUnits);
293 }
294 }
295 }
296
SquarePixelToMeasurementUnit(Buf,NumSquarePixels)297 void SquarePixelToMeasurementUnit(Buf, NumSquarePixels)
298 char *Buf;
299 int NumSquarePixels;
300 {
301 float fval;
302 int ival;
303
304 if (*unitStr == '\0') {
305 sprintf(Buf, "%+1d", NumSquarePixels);
306 } else {
307 fval = (float)((float)NumSquarePixels*1000.0)/(gfPixelsPerUnit);
308 fval = (float)(fval/gfPixelsPerUnit);
309 ival = ((int)round(fval));
310 fval = ((float)ival)/((float)1000.0);
311 if (*formatUnitStr == '\0') {
312 sprintf(Buf, "%+.3f sq %s", fval, unitStr);
313 } else {
314 float frac;
315
316 ival = (int)fval;
317 frac = ((ival >= 0) ? fval-((float)ival) : ((float)ival)-fval);
318 fval = (float)ival;
319 sprintf(Buf, formatUnitStr, fval, frac*gfNumFracUnits);
320 }
321 }
322 }
323
PixelToCurrentUnit(Buf,NumPixels)324 void PixelToCurrentUnit(Buf, NumPixels)
325 char *Buf;
326 int NumPixels;
327 {
328 int unit_str_was_empty=(*unitStr == '\0');
329 char num_unit_str[80], base_unit_str[80];
330 float pixel_per_unit=gfPixelsPerUnit, num_units=gfNumUnits;
331
332 if (unit_str_was_empty) {
333 UtilStrCpyN(num_unit_str, sizeof(num_unit_str), numUnitStr);
334 UtilStrCpyN(base_unit_str, sizeof(base_unit_str), baseUnitStr);
335 switch (gridSystem) {
336 case ENGLISH_GRID:
337 gfPixelsPerUnit = 128;
338 gfNumUnits = 1;
339 UtilStrCpyN(unitStr, sizeof(unitStr), "inch");
340 break;
341 case METRIC_GRID:
342 gfPixelsPerUnit = 50;
343 gfNumUnits = 2.5;
344 UtilStrCpyN(unitStr, sizeof(unitStr), "cm");
345 break;
346 }
347 PixelToMeasurementUnit(Buf, NumPixels);
348 } else {
349 PixelToMeasurementUnit(Buf, NumPixels);
350 }
351 if (unit_str_was_empty) {
352 gfPixelsPerUnit = pixel_per_unit;
353 gfNumUnits = num_units;
354 *unitStr = '\0';
355 UtilStrCpyN(numUnitStr, sizeof(numUnitStr), num_unit_str);
356 UtilStrCpyN(baseUnitStr, sizeof(baseUnitStr), base_unit_str);
357 }
358 }
359
360 static
RightMarginMarkVisible()361 int RightMarginMarkVisible()
362 {
363 return ((rightMarginEnabled == TRUE) && (drawOrigX+drawWinW >
364 paperWidth-(rightMargin>>TIK_PER_PIXEL_SHIFTS)));
365 }
366
367 static
GetRightMarginMarkVs(vs)368 void GetRightMarginMarkVs(vs)
369 XPoint vs[6];
370 {
371 int x=OFFSET_X(paperWidth-(rightMargin>>TIK_PER_PIXEL_SHIFTS))-1;
372 int delta=(rulerW>>2);
373 int y_end=rulerW-(threeDLook ? ((windowPadding>>1)+2) : 1);
374 int y_start=(threeDLook ? ((windowPadding>>1)-2) : (-1))+(delta<<1);
375
376 vs[0].x = x; vs[0].y = y_start;
377 vs[1].x = x-delta; vs[1].y = y_start+delta;
378 vs[2].x = x-delta; vs[2].y = y_end;
379 vs[3].x = x+delta; vs[3].y = y_end;
380 vs[4].x = x+delta; vs[4].y = y_start+delta;
381 vs[5].x = x; vs[5].y = y_start;
382 }
383
384 static
PtInRightMarginMark(button_x,button_y)385 int PtInRightMarginMark(button_x, button_y)
386 int button_x, button_y;
387 {
388 XPoint vs[6];
389
390 GetRightMarginMarkVs(vs);
391
392 return PointInPolygon(button_x, button_y, 6, vs);
393 }
394
395 static
RedrawRightMargin(dpy,win)396 void RedrawRightMargin(dpy, win)
397 Display *dpy;
398 Window win;
399 {
400 if (rightMarginEnabled != TRUE) return;
401
402 if (drawOrigX+drawWinW > paperWidth-(rightMargin>>TIK_PER_PIXEL_SHIFTS)) {
403 int delta=(rulerW>>2);
404 int x=OFFSET_X(paperWidth-(rightMargin>>TIK_PER_PIXEL_SHIFTS))-1;
405 int y_end=rulerW-(threeDLook ? ((windowPadding>>1)+2) : 1);
406 int y_start=(threeDLook ? ((windowPadding>>1)-2) : (-1))+(delta<<1);
407 int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
408 GC gc=defaultGC;
409 XPoint vs[6];
410
411 GetRightMarginMarkVs(vs);
412 if (threeDLook) {
413 XSetForeground(mainDisplay, textMenuGC, bg_pixel);
414 XFillPolygon(dpy, win, textMenuGC, vs, 6, Convex, CoordModeOrigin);
415 XDrawLines(dpy, win, gc, vs, 6, CoordModeOrigin);
416 } else {
417 XDrawLines(dpy, win, gc, vs, 6, CoordModeOrigin);
418 }
419 rightMarginActive = ShouldRightMarginBeActive();
420 if (!rightMarginActive) {
421 XDrawLine(dpy, win, gc, x-delta, y_start+1, x+delta-1, y_end);
422 XDrawLine(dpy, win, gc, x-delta+1, y_start+1, x+delta, y_end);
423 /*
424 * The code doesn't look right, but it look symmetrical on the screen!
425 *
426 * XDrawLine(dpy, win, gc, x+delta, y_start+1, x-delta+1, y_end);
427 * XDrawLine(dpy, win, gc, x+delta-1, y_start+1, x-delta, y_end);
428 */
429 XDrawLine(dpy, win, gc, x+delta+1, y_start, x-delta+1, y_end);
430 XDrawLine(dpy, win, gc, x+delta, y_start, x-delta, y_end);
431 }
432 }
433 }
434
RedrawHRuler(dpy,win)435 void RedrawHRuler(dpy, win)
436 Display *dpy;
437 Window win;
438 {
439 register int i, pos, len, index;
440 int inc, abs_inc, y=rulerW-(threeDLook ? (windowPadding>>1) : 0);
441 char s[5];
442
443 switch (gridSystem) {
444 case ENGLISH_GRID:
445 inc = (zoomedIn ? (xyEnglishGrid<<zoomScale) : xyEnglishGrid);
446 abs_inc = ABS_SIZE(inc);
447
448 if (drawOrigX % abs_inc == 0) {
449 i = 0;
450 pos = 0;
451 } else {
452 i = ((int)(drawOrigX / abs_inc) + 1) * abs_inc - drawOrigX;
453 pos = ZOOMED_SIZE(i);
454 }
455 pos--; /* since drawWindow has no border */
456 for ( ; i<drawWinW; i+=abs_inc, pos+=inc) {
457 if ((GRID_ZOOMED_SIZE(i+drawOrigX)) % ONE_INCH == 0) {
458 index = (int)((GRID_ZOOMED_SIZE(i+drawOrigX)) / ONE_INCH);
459 sprintf(s, "%1d", GRID_ABS_SIZE(index));
460 len = strlen(s);
461 XDrawString(dpy, win, rulerGC, pos+2, y-INCH_H+rulerFontAsc,
462 s, len);
463 XDrawLine(dpy, win, defaultGC, pos, y, pos, y-INCH_H);
464 } else if ((GRID_ZOOMED_SIZE(i+drawOrigX)) % HALF_INCH == 0) {
465 XDrawLine(dpy, win, defaultGC, pos, y, pos, y-HALF_INCH_H);
466 } else if ((GRID_ZOOMED_SIZE(i+drawOrigX)) % QUARTER_INCH == 0) {
467 XDrawLine(dpy, win, defaultGC, pos, y, pos, y-QUARTER_INCH_H);
468 } else {
469 XDrawLine(dpy, win, defaultGC, pos, y, pos, y-MIN_INCH_H);
470 }
471 }
472 break;
473 case METRIC_GRID:
474 inc = (zoomedIn ? (xyMetricGrid<<zoomScale) : xyMetricGrid);
475 abs_inc = ABS_SIZE(inc);
476
477 if (drawOrigX % abs_inc == 0) {
478 i = 0;
479 pos = 0;
480 } else {
481 i = ((int)(drawOrigX / abs_inc) + 1) * abs_inc - drawOrigX;
482 pos = ZOOMED_SIZE(i);
483 }
484 pos--; /* since drawWindow has no border */
485 for ( ; i<drawWinW; i+=abs_inc, pos+=inc) {
486 if ((GRID_ZOOMED_SIZE(i+drawOrigX)) % ONE_CM == 0) {
487 index = (int)((GRID_ZOOMED_SIZE(i+drawOrigX)) / ONE_CM);
488 sprintf(s, "%1d", GRID_ABS_SIZE(index));
489 len = strlen(s);
490 XDrawString(dpy, win, rulerGC, pos+2, y-INCH_H+rulerFontAsc,
491 s, len);
492 XDrawLine(dpy, win, defaultGC, pos, y, pos, y-INCH_H);
493 } else if ((GRID_ZOOMED_SIZE(i+drawOrigX)) % FIVE_MM == 0) {
494 XDrawLine(dpy, win, defaultGC, pos, y, pos, y-HALF_CM_H);
495 } else {
496 XDrawLine(dpy, win, defaultGC, pos, y, pos, y-MIN_CM_H);
497 }
498 }
499 break;
500 }
501 RedrawRightMargin(dpy, win);
502 }
503
504 static
DrawHRuleTick(XOff)505 void DrawHRuleTick(XOff)
506 int XOff;
507 {
508 XDrawLine(mainDisplay, hRuleWindow, revDefaultGC, XOff, 0, XOff, rulerLen);
509 }
510
511 static
DrawVRuleTick(YOff)512 void DrawVRuleTick(YOff)
513 {
514 XDrawLine(mainDisplay, vRuleWindow, revDefaultGC, 0, YOff, rulerLen, YOff);
515 }
516
RedrawHRulerWindow()517 void RedrawHRulerWindow()
518 {
519 XEvent ev;
520
521 XClearWindow(mainDisplay, hRuleWindow);
522
523 XSync(mainDisplay, False);
524 while (XCheckWindowEvent(mainDisplay, hRuleWindow, ExposureMask, &ev)) ;
525
526 RedrawHRuler(mainDisplay, hRuleWindow);
527
528 oldXOff = (-1);
529 DrawHRuleTick(oldXOff-1);
530 hRulerJustRedrawn = TRUE;
531 justUnFrozen = FALSE;
532 }
533
RedrawVRuler(dpy,win)534 void RedrawVRuler(dpy, win)
535 Display *dpy;
536 Window win;
537 {
538 register int i, pos, len, index;
539 int inc, abs_inc, x=rulerW-(threeDLook ? (windowPadding>>1) : 0);
540 char s[5];
541
542 switch (gridSystem) {
543 case ENGLISH_GRID:
544 inc = (zoomedIn ? (xyEnglishGrid<<zoomScale) : xyEnglishGrid);
545 abs_inc = ABS_SIZE(inc);
546
547 if (drawOrigY % abs_inc == 0) {
548 i = 0;
549 pos = 0;
550 } else {
551 i = ((int)(drawOrigY / abs_inc) + 1) * abs_inc - drawOrigY;
552 pos = ZOOMED_SIZE(i);
553 }
554 pos--; /* since drawWindow has no border */
555 for ( ; i<drawWinH; i+=abs_inc, pos+=inc) {
556 if ((GRID_ZOOMED_SIZE(i+drawOrigY)) % ONE_INCH == 0) {
557 index = (int)((GRID_ZOOMED_SIZE(i+drawOrigY)) / ONE_INCH);
558 sprintf(s, "%1d", GRID_ABS_SIZE(index));
559 len = strlen(s);
560 XDrawString(dpy, win, rulerGC, 1, pos+rulerFontAsc+2, s, len);
561 XDrawLine(dpy, win, defaultGC, x, pos, x-INCH_H, pos);
562 } else if ((GRID_ZOOMED_SIZE(i+drawOrigY)) % HALF_INCH == 0) {
563 XDrawLine(dpy, win, defaultGC, x, pos, x-HALF_INCH_H, pos);
564 } else if ((GRID_ZOOMED_SIZE(i+drawOrigY)) % QUARTER_INCH == 0) {
565 XDrawLine(dpy, win, defaultGC, x, pos, x-QUARTER_INCH_H, pos);
566 } else {
567 XDrawLine(dpy, win, defaultGC, x, pos, x-MIN_INCH_H, pos);
568 }
569 }
570 break;
571 case METRIC_GRID:
572 inc = (zoomedIn ? (xyMetricGrid<<zoomScale) : xyMetricGrid);
573 abs_inc = ABS_SIZE(inc);
574
575 if (drawOrigY % abs_inc == 0) {
576 i = 0;
577 pos = 0;
578 } else {
579 i = ((int)(drawOrigY / abs_inc) + 1) * abs_inc - drawOrigY;
580 pos = ZOOMED_SIZE(i);
581 }
582 pos--; /* since drawWindow has no border */
583 for ( ; i<drawWinH; i+=abs_inc, pos+=inc) {
584 if ((GRID_ZOOMED_SIZE(i+drawOrigY)) % ONE_CM == 0) {
585 index = (int)((GRID_ZOOMED_SIZE(i+drawOrigY)) / ONE_CM);
586 sprintf(s, "%1d", GRID_ABS_SIZE(index));
587 len = strlen(s);
588 XDrawString(dpy, win, rulerGC, 1, pos+rulerFontAsc+2, s, len);
589 XDrawLine(dpy, win, defaultGC, x, pos, x-INCH_H, pos);
590 } else if ((GRID_ZOOMED_SIZE(i+drawOrigY)) % FIVE_MM == 0) {
591 XDrawLine(dpy, win, defaultGC, x, pos, x-HALF_CM_H, pos);
592 } else {
593 XDrawLine(dpy, win, defaultGC, x, pos, x-MIN_CM_H, pos);
594 }
595 }
596 break;
597 }
598 }
599
RedrawVRulerWindow()600 void RedrawVRulerWindow()
601 {
602 XEvent ev;
603
604 XClearWindow(mainDisplay, vRuleWindow);
605
606 XSync(mainDisplay, False);
607 while (XCheckWindowEvent(mainDisplay, vRuleWindow, ExposureMask, &ev)) ;
608
609 RedrawVRuler(mainDisplay, vRuleWindow);
610
611 if (!freezeMarkRulerText && showMeasurement && !hRulerJustRedrawn &&
612 oldYOff != 0) {
613 char x_buf[80], y_buf[80], buf[80];
614
615 PixelToMeasurementUnit(x_buf, ABS_X(oldXOff));
616 PixelToMeasurementUnit(y_buf, ABS_Y(oldYOff));
617 sprintf(buf, "[%s,%s]", x_buf, y_buf);
618 if (!showMeasurementInTooltip) {
619 XDrawString(mainDisplay, hRuleWindow, revDefaultGC,
620 8, 2+defaultFontAsc, buf, strlen(buf));
621 }
622 hRulerJustRedrawn = TRUE;
623 }
624 oldYOff = (-1);
625 DrawVRuleTick(oldYOff-1);
626 }
627
MarkRulers(XOff,YOff)628 void MarkRulers(XOff, YOff)
629 int XOff, YOff;
630 {
631 char x_buf[80], y_buf[80], buf[MAXSTRING];
632
633 DrawHRuleTick(oldXOff-1);
634 DrawVRuleTick(oldYOff-1);
635 if (showCrossHair) {
636 XDrawLine(mainDisplay, drawWindow, revDefaultGC, oldXOff, 0,
637 oldXOff, ZOOMED_SIZE(drawWinH));
638 XDrawLine(mainDisplay, drawWindow, revDefaultGC, 0, oldYOff,
639 ZOOMED_SIZE(drawWinW), oldYOff);
640 }
641 if (hRulerJustRedrawn) {
642 hRulerJustRedrawn= FALSE;
643 } else if (!freezeMarkRulerText && showMeasurement) {
644 if (justUnFrozen) {
645 justUnFrozen = FALSE;
646 PixelToMeasurementUnit(x_buf, ABS_X(frozenXOff));
647 PixelToMeasurementUnit(y_buf, ABS_Y(frozenYOff));
648 sprintf(buf, "[%s,%s]", x_buf, y_buf);
649 } else {
650 PixelToMeasurementUnit(x_buf, ABS_X(oldXOff));
651 PixelToMeasurementUnit(y_buf, ABS_Y(oldYOff));
652 sprintf(buf, "[%s,%s]", x_buf, y_buf);
653 }
654 if (!showMeasurementInTooltip) {
655 XDrawString(mainDisplay, hRuleWindow, revDefaultGC,
656 8, 2+defaultFontAsc, buf, strlen(buf));
657 }
658 }
659 DrawHRuleTick(XOff-1);
660 DrawVRuleTick(YOff-1);
661
662 if (showCrossHair) {
663 XDrawLine(mainDisplay, drawWindow, revDefaultGC, XOff, 0,
664 XOff, ZOOMED_SIZE(drawWinH));
665 XDrawLine(mainDisplay, drawWindow, revDefaultGC, 0, YOff,
666 ZOOMED_SIZE(drawWinW), YOff);
667 }
668 if (!freezeMarkRulerText && showMeasurement) {
669 PixelToMeasurementUnit(x_buf, ABS_X(XOff));
670 PixelToMeasurementUnit(y_buf, ABS_Y(YOff));
671 if (simpleMotionInDrawWin && curChoice == NOTHING && topSel != NULL &&
672 VerboseMeasureTooltip()) {
673 char w_buf[80], h_buf[80];
674 char lx_buf[80], ty_buf[80], rx_buf[80], by_buf[80];
675
676 PixelToMeasurementUnit(w_buf, selObjRbX-selObjLtX);
677 PixelToMeasurementUnit(h_buf, selObjRbY-selObjLtY);
678 PixelToMeasurementUnit(lx_buf, selObjLtX);
679 PixelToMeasurementUnit(rx_buf, selObjRbX);
680 PixelToMeasurementUnit(ty_buf, selObjLtY);
681 PixelToMeasurementUnit(by_buf, selObjRbY);
682 sprintf(buf,
683 "[%s,%s]\nsel_lx=%s sel_rx=%s\nsel_ty=%s sel_by=%s\nsel_w=%s sel_h=%s",
684 x_buf, y_buf, lx_buf, rx_buf, ty_buf, by_buf, w_buf, h_buf);
685 } else {
686 sprintf(buf, "[%s,%s]", x_buf, y_buf);
687 }
688 if (showMeasurementInTooltip) {
689 SetMeasureTooltip(buf);
690 } else {
691 XDrawString(mainDisplay, hRuleWindow, revDefaultGC,
692 8, 2+defaultFontAsc, buf, strlen(buf));
693 }
694 } else if (VerboseMeasureTooltip()) {
695 switch (curChoice) {
696 case NOTHING:
697 case DRAWPOLY:
698 case DRAWPOLYGON:
699 case VERTEXMODE:
700 DoIntervalMeasureTooltip(frozenXOff, frozenYOff, XOff, YOff,
701 (frozenXOff+XOff)>>1, (frozenYOff+YOff)>>1, gpszFrozenDeltaStr);
702 break;
703 }
704 }
705 oldXOff = XOff;
706 oldYOff = YOff;
707 }
708
RedrawRulers()709 void RedrawRulers()
710 {
711 RedrawHRulerWindow();
712 RedrawVRulerWindow();
713 }
714
GetCrossHairPosition(pnXOff,pnYOff,pnShown)715 void GetCrossHairPosition(pnXOff, pnYOff, pnShown)
716 int *pnXOff, *pnYOff, *pnShown;
717 {
718 if (pnXOff != NULL) *pnXOff = oldXOff;
719 if (pnYOff != NULL) *pnYOff = oldYOff;
720 if (pnShown != NULL) *pnShown = showCrossHair;
721 }
722
RedrawCrossHair()723 void RedrawCrossHair()
724 {
725 if (showCrossHair) {
726 XDrawLine(mainDisplay, drawWindow, revDefaultGC, oldXOff, 0,
727 oldXOff, ZOOMED_SIZE(drawWinH));
728 XDrawLine(mainDisplay, drawWindow, revDefaultGC, 0, oldYOff,
729 ZOOMED_SIZE(drawWinW), oldYOff);
730 }
731 }
732
ToggleShowCrossHair()733 void ToggleShowCrossHair()
734 {
735 /* the cross-hair stuff is disabled -- cannot get it to work right */
736 if (!showCrossHair) return;
737
738 RedrawCrossHair();
739
740 /* showCrossHair = !showCrossHair; */
741 showCrossHair = FALSE;
742 RedrawRulers();
743 if (showCrossHair) {
744 Msg(TgLoadString(STID_SHOW_CROSSHAIR_ENABLED));
745 SetNullCursor(drawWindow);
746 } else {
747 SetDefaultCursor(drawWindow);
748 ShowCursor();
749 Msg(TgLoadString(STID_SHOW_CROSSHAIR_DISABLED));
750 }
751 }
752
753 static
ContinueMoveRightMarginMark(dpy,OrigX,OrigY)754 void ContinueMoveRightMarginMark(dpy, OrigX, OrigY)
755 Display *dpy;
756 int OrigX, OrigY; /* these are mouse coordinates */
757 {
758 int moving=TRUE, dx=0, grid_x=0, grid_y=0, h=ZOOMED_SIZE(drawWinH);
759 int prev_x=0, orig_grid_x=0, orig_grid_y=0, orig_right_margin=0;
760 char buf[80], buf2[80];
761 double dval=(double)0;
762 XPoint orig_vs[6], vs[6];
763 XEvent ev;
764
765 XFlush(dpy);
766 XSync(dpy, False);
767
768 if (XCheckMaskEvent(dpy, ExposureMask, &ev) ||
769 XCheckMaskEvent(dpy, VisibilityChangeMask, &ev)) {
770 ExposeEventHandler(&ev, TRUE);
771 }
772 GridXY(OrigX, OrigY, &grid_x, &grid_y);
773 orig_grid_x = grid_x;
774 orig_grid_y = grid_y;
775 orig_right_margin = OFFSET_X(paperWidth-(rightMargin>>TIK_PER_PIXEL_SHIFTS));
776 prev_x = orig_right_margin+0;
777 GetRightMarginMarkVs(orig_vs);
778 memcpy(vs, orig_vs, 6*sizeof(XPoint));
779 dval = ((double)rightMargin) * ((double)printMag) / ((double)TIK_PER_PIXEL);
780 dval /= ((double)100);
781 PixelToMeasurementUnit(buf, round(dval));
782 sprintf(buf2, "margin=%s", buf);
783 StartShowMeasureCursor(OrigX, 4, buf2, FALSE);
784
785 /* draw */
786 XDrawLine(dpy, drawWindow, revDefaultGC, prev_x, 0, prev_x, h);
787 XDrawLines(dpy, hRuleWindow, revDefaultGC, vs, 6, CoordModeOrigin);
788 if (!debugNoPointerGrab) {
789 XGrabPointer(dpy, drawWindow, FALSE,
790 PointerMotionMask | ButtonReleaseMask,
791 GrabModeAsync, GrabModeAsync, None, moveCursor, CurrentTime);
792 }
793 while (moving) {
794 XEvent input;
795
796 XNextEvent(dpy, &input);
797
798 if (input.type == Expose || input.type == VisibilityNotify) {
799 ExposeEventHandler(&input, TRUE);
800 } else if (input.type == ButtonRelease) {
801 int abs_dx=ABS_SIZE(dx);
802
803 XUngrabPointer(dpy, CurrentTime);
804 XSync(dpy, False);
805
806 moving = FALSE;
807
808 /* erase */
809 XDrawLine(dpy, drawWindow, revDefaultGC, prev_x, 0, prev_x, h);
810 XDrawLines(dpy, hRuleWindow, revDefaultGC, vs, 6, CoordModeOrigin);
811 EndShowMeasureCursor(OrigX+dx, 4, buf2, FALSE);
812
813 rightMargin -= (abs_dx<<TIK_PER_PIXEL_SHIFTS);
814 RedrawHRulerWindow();
815 } else if (input.type == MotionNotify) {
816 int i=0, mouse_x=0, mouse_y=0;
817
818 /* erase */
819 XDrawLine(dpy, drawWindow, revDefaultGC, prev_x, 0, prev_x, h);
820 XDrawLines(dpy, hRuleWindow, revDefaultGC, vs, 6, CoordModeOrigin);
821 ShowMeasureCursor(OrigX+dx, 4, buf2, FALSE);
822
823 mouse_x = input.xmotion.x;
824 mouse_y = input.xmotion.y;
825 GridXY(mouse_x, mouse_y, &grid_x, &grid_y);
826
827 dx = grid_x - orig_grid_x;
828 prev_x = orig_right_margin+0+dx;
829 for (i=0; i < 6; i++) {
830 vs[i].x = orig_vs[i].x+dx;
831 }
832 /* draw */
833 XDrawLine(dpy, drawWindow, revDefaultGC, prev_x, 0, prev_x, h);
834 XDrawLines(dpy, hRuleWindow, revDefaultGC, vs, 6, CoordModeOrigin);
835
836 dval = (((double)(rightMargin-(ABS_SIZE(dx)<<TIK_PER_PIXEL_SHIFTS))) *
837 ((double)printMag) / ((double)TIK_PER_PIXEL)) / ((double)100);
838 PixelToMeasurementUnit(buf, round(dval));
839 sprintf(buf2, "margin=%s", buf);
840 ShowMeasureCursor(OrigX+dx, 4, buf2, FALSE);
841 }
842 }
843 }
844
RulersEventHandler(input)845 void RulersEventHandler(input)
846 XEvent *input;
847 {
848 if (input->type == ButtonPress) {
849 XButtonEvent *button_ev=(&input->xbutton);
850 int mouse_x=button_ev->x, mouse_y=button_ev->y;
851
852 if (RightMarginMarkVisible() && PtInRightMarginMark(mouse_x, mouse_y)) {
853 ContinueMoveRightMarginMark(mainDisplay, mouse_x, mouse_y);
854 } else if (button_ev->button == Button1) {
855 IncGrid();
856 } else if (button_ev->button == Button2) {
857 GridMenu(button_ev->x_root, button_ev->y_root, FALSE);
858 } else if (button_ev->button == Button3) {
859 DecGrid();
860 }
861 } else if (input->xany.window == vRuleWindow) {
862 if (input->type == Expose) {
863 RedrawVRulerWindow();
864 } else if (input->type == EnterNotify) {
865 SetMouseStatus(TgLoadCachedString(CSTID_INC_GRID_SIZE),
866 TgLoadCachedString(CSTID_GRID_MENU),
867 TgLoadCachedString(CSTID_DEC_GRID_SIZE));
868 }
869 } else if (input->xany.window == hRuleWindow) {
870 if (input->type == Expose) {
871 RedrawHRulerWindow();
872 } else if (input->type == EnterNotify) {
873 SetMouseStatus(TgLoadCachedString(CSTID_INC_GRID_SIZE),
874 TgLoadCachedString(CSTID_GRID_MENU),
875 TgLoadCachedString(CSTID_DEC_GRID_SIZE));
876 }
877 }
878 }
879
FreezeMarkRulerText()880 void FreezeMarkRulerText()
881 {
882 if (!freezeMarkRulerText) {
883 EndMeasureTooltip(FALSE);
884 }
885 freezeMarkRulerText = TRUE;
886 frozenXOff = oldXOff;
887 frozenYOff = oldYOff;
888 UtilFree(gpszFrozenDeltaStr);
889 if (gpszOldDeltaStr != NULL) {
890 gpszFrozenDeltaStr = UtilStrDup(gpszOldDeltaStr);
891 if (gpszFrozenDeltaStr == NULL) FailAllocMessage();
892 }
893 }
894
UnFreezeMarkRulerText()895 void UnFreezeMarkRulerText()
896 {
897 freezeMarkRulerText = FALSE;
898 justUnFrozen = TRUE;
899 }
900
901 static int oldLtX, oldLtY, oldRbX, oldRbY, oldMdX, oldMdY;
902
VerboseMeasureTooltip()903 int VerboseMeasureTooltip()
904 {
905 return (showMeasurement && showMeasurementInTooltip &&
906 measureTooltipVerbose);
907 }
908
909 static
DoIntervalRulers()910 void DoIntervalRulers()
911 {
912 if (oldLtX == oldRbX) {
913 XDrawLine(mainDisplay, hRuleWindow, revDefaultGC, oldLtX-1, 0, oldLtX-1,
914 rulerLen);
915 } else if (oldLtX==oldMdX || oldRbX==oldMdX) {
916 XDrawLine(mainDisplay, hRuleWindow, revDefaultGC, oldLtX-1, 0, oldLtX-1,
917 rulerLen);
918 XDrawLine(mainDisplay, hRuleWindow, revDefaultGC, oldRbX-1, 0, oldRbX-1,
919 rulerLen);
920 } else {
921 XDrawLine(mainDisplay, hRuleWindow, revDefaultGC, oldLtX-1, 0, oldLtX-1,
922 rulerLen);
923 XDrawLine(mainDisplay, hRuleWindow, revDefaultGC, oldMdX-1, 0, oldMdX-1,
924 rulerLen);
925 XDrawLine(mainDisplay, hRuleWindow, revDefaultGC, oldRbX-1, 0, oldRbX-1,
926 rulerLen);
927 }
928 if (oldLtY == oldRbY) {
929 XDrawLine(mainDisplay, vRuleWindow, revDefaultGC, 0, oldLtY-1, rulerLen-1,
930 oldLtY);
931 } else if (oldLtY==oldMdY || oldRbY==oldMdY) {
932 XDrawLine(mainDisplay, vRuleWindow, revDefaultGC, 0, oldLtY-1, rulerLen-1,
933 oldLtY);
934 XDrawLine(mainDisplay, vRuleWindow, revDefaultGC, 0, oldRbY-1, rulerLen-1,
935 oldRbY);
936 } else {
937 XDrawLine(mainDisplay, vRuleWindow, revDefaultGC, 0, oldLtY-1, rulerLen,
938 oldLtY-1);
939 XDrawLine(mainDisplay, vRuleWindow, revDefaultGC, 0, oldMdY-1, rulerLen,
940 oldMdY-1);
941 XDrawLine(mainDisplay, vRuleWindow, revDefaultGC, 0, oldRbY-1, rulerLen,
942 oldRbY-1);
943 }
944 if (showCrossHair) {
945 XDrawLine(mainDisplay, drawWindow, revDefaultGC, oldRbX, 0,
946 oldRbX, ZOOMED_SIZE(drawWinH));
947 XDrawLine(mainDisplay, drawWindow, revDefaultGC, 0, oldRbY,
948 ZOOMED_SIZE(drawWinW), oldRbY);
949 }
950 if (VerboseMeasureTooltip()) {
951 DoIntervalMeasureTooltip(oldLtX, oldLtY, oldRbX, oldRbY, oldMdX, oldMdY,
952 gpszOldDeltaStr);
953 }
954 }
955
BeginIntervalRulers(ltx,lty,rbx,rby)956 void BeginIntervalRulers(ltx, lty, rbx, rby)
957 int ltx, lty, rbx, rby;
958 {
959 DrawHRuleTick(oldXOff-1);
960 DrawVRuleTick(oldYOff-1);
961 if (showCrossHair) {
962 XDrawLine(mainDisplay, drawWindow, revDefaultGC, oldXOff, 0,
963 oldXOff, ZOOMED_SIZE(drawWinH));
964 XDrawLine(mainDisplay, drawWindow, revDefaultGC, 0, oldYOff,
965 ZOOMED_SIZE(drawWinW), oldYOff);
966 }
967 oldLtX = ltx; oldLtY = lty;
968 oldRbX = rbx; oldRbY = rby;
969 oldMdX = (oldLtX+oldRbX)>>1;
970 oldMdY = (oldLtY+oldRbY)>>1;
971 gpszOldDeltaStr = NULL;
972 if (showMeasurement) FreezeMarkRulerText();
973 DoIntervalRulers();
974 }
975
DrawIntervalRulers(ltx,lty,rbx,rby,delta_str)976 void DrawIntervalRulers(ltx, lty, rbx, rby, delta_str)
977 int ltx, lty, rbx, rby;
978 char *delta_str;
979 {
980 DoIntervalRulers();
981 oldLtX = ltx; oldLtY = lty;
982 oldRbX = rbx; oldRbY = rby;
983 oldMdX = (oldLtX+oldRbX)>>1; oldMdY = (oldLtY+oldRbY)>>1;
984 if (delta_str != NULL) {
985 gpszOldDeltaStr = UtilStrDup(delta_str);
986 if (gpszOldDeltaStr == NULL) FailAllocMessage();
987 }
988 DoIntervalRulers();
989 if (showMeasurement) UnFreezeMarkRulerText();
990 }
991
EndIntervalRulers(x,y)992 void EndIntervalRulers(x, y)
993 int x, y;
994 {
995 DoIntervalRulers();
996 oldXOff = x;
997 oldYOff = y;
998 UtilFree(gpszOldDeltaStr);
999 gpszOldDeltaStr = NULL;
1000 DrawHRuleTick(oldXOff-1);
1001 DrawVRuleTick(oldYOff-1);
1002 if (showCrossHair) {
1003 XDrawLine(mainDisplay, drawWindow, revDefaultGC, oldXOff, 0,
1004 oldXOff, ZOOMED_SIZE(drawWinH));
1005 XDrawLine(mainDisplay, drawWindow, revDefaultGC, 0, oldYOff,
1006 ZOOMED_SIZE(drawWinW), oldYOff);
1007 }
1008 MarkRulers(x, y);
1009 frozenXOff = oldXOff;
1010 frozenYOff = oldYOff;
1011 }
1012
StartShowMeasureCursor(XOff,YOff,Str,ExtraSpace)1013 void StartShowMeasureCursor(XOff, YOff, Str, ExtraSpace)
1014 int XOff, YOff, ExtraSpace;
1015 char *Str;
1016 {
1017 if (!showMeasurement) return;
1018 MarkRulers(XOff, YOff);
1019 FreezeMarkRulerText();
1020 if (Str == NULL || *Str == '\0') return;
1021
1022 if (showMeasurementInTooltip) {
1023 if (!measureTooltipVerbose) {
1024 StartMeasureTooltip(Str);
1025 }
1026 } else {
1027 int x=(ExtraSpace ? XOff+18 : XOff+4), y=YOff+defaultFontAsc;
1028 char *c_ptr=strchr(Str, '\n'), *line=Str;
1029
1030 while (line != NULL) {
1031 if (c_ptr != NULL) *c_ptr = '\0';
1032 XDrawString(mainDisplay, drawWindow, revDefaultGC, x, y,
1033 line, strlen(line));
1034 if (c_ptr != NULL) {
1035 *c_ptr++ = '\n';
1036 line = c_ptr;
1037 c_ptr = strchr(line, '\n');
1038 y += defaultFontHeight;
1039 } else {
1040 break;
1041 }
1042 }
1043 }
1044 }
1045
ShowMeasureCursor(XOff,YOff,Str,ExtraSpace)1046 void ShowMeasureCursor(XOff, YOff, Str, ExtraSpace)
1047 int XOff, YOff, ExtraSpace;
1048 char *Str;
1049 {
1050 if (!showMeasurement) return;
1051 if (Str == NULL || *Str == '\0') return;
1052
1053 if (showMeasurementInTooltip) {
1054 if (measureTooltipVerbose) {
1055 switch (curChoice) {
1056 case DRAWARC:
1057 case DRAWEDGEARC:
1058 case FREEHAND:
1059 case ROTATEMODE:
1060 SetMeasureTooltip(Str);
1061 break;
1062 }
1063 } else {
1064 SetMeasureTooltip(Str);
1065 }
1066 } else {
1067 int x=(ExtraSpace ? XOff+18 : XOff+4), y=YOff+defaultFontAsc;
1068 char *c_ptr=strchr(Str, '\n'), *line=Str;
1069
1070 while (line != NULL) {
1071 if (c_ptr != NULL) *c_ptr = '\0';
1072 XDrawString(mainDisplay, drawWindow, revDefaultGC, x, y,
1073 line, strlen(line));
1074 if (c_ptr != NULL) {
1075 *c_ptr++ = '\n';
1076 line = c_ptr;
1077 c_ptr = strchr(line, '\n');
1078 y += defaultFontHeight;
1079 } else {
1080 break;
1081 }
1082 }
1083 }
1084 }
1085
EndShowMeasureCursor(XOff,YOff,Str,ExtraSpace)1086 void EndShowMeasureCursor(XOff, YOff, Str, ExtraSpace)
1087 int XOff, YOff, ExtraSpace;
1088 char *Str;
1089 {
1090 if (!showMeasurement) return;
1091 if (Str == NULL || *Str == '\0') return;
1092
1093 if (showMeasurementInTooltip) {
1094 if (!measureTooltipVerbose) {
1095 StartMeasureTooltip(Str);
1096 }
1097 } else {
1098 int x=(ExtraSpace ? XOff+18 : XOff+4), y=YOff+defaultFontAsc;
1099 char *c_ptr=strchr(Str, '\n'), *line=Str;
1100
1101 while (line != NULL) {
1102 if (c_ptr != NULL) *c_ptr = '\0';
1103 XDrawString(mainDisplay, drawWindow, revDefaultGC, x, y,
1104 line, strlen(line));
1105 if (c_ptr != NULL) {
1106 *c_ptr++ = '\n';
1107 line = c_ptr;
1108 c_ptr = strchr(line, '\n');
1109 y += defaultFontHeight;
1110 } else {
1111 break;
1112 }
1113 }
1114 }
1115 UnFreezeMarkRulerText();
1116 }
1117
ToggleShowMeasurement()1118 void ToggleShowMeasurement()
1119 {
1120 showMeasurement = !showMeasurement;
1121 RedrawRulers();
1122 if (showMeasurement) {
1123 Msg(TgLoadString(STID_SHOW_MEASUREMENT_ENABLED));
1124 } else {
1125 Msg(TgLoadString(STID_SHOW_MEASUREMENT_DISABLED));
1126 }
1127 }
1128
ToggleShowMeasurementInTooltip()1129 void ToggleShowMeasurementInTooltip()
1130 {
1131 showMeasurementInTooltip = !showMeasurementInTooltip;
1132 RedrawRulers();
1133 if (showMeasurementInTooltip) {
1134 Msg(TgLoadString(STID_SHOW_MEASUREMENT_IN_TT_ENAB));
1135 } else {
1136 Msg(TgLoadString(STID_SHOW_MEASUREMENT_IN_TT_DISB));
1137 }
1138 EndMeasureTooltip(TRUE);
1139 }
1140
1141 /* ------------------- Measure Tooltip Related Routines ------------------- */
1142
1143 /*
1144 * Some code in the rest of this file is based on the contributed code
1145 * by Raphael Dechenaux <raph_d@club-internet.fr>.
1146 */
1147
1148 typedef struct tagMeasureTooltipInfo {
1149 int ltx, lty, w, h; /* this is for the window */
1150 int bbox_w, bbox_h; /* this is for the text */
1151 int x_padding, y_padding; /* padding around the text */
1152 int mapped;
1153 Window win;
1154 GC gc;
1155 /* configuration parameters -- how to display */
1156 int x_follow_mouse, y_follow_mouse, position_x, position_y;
1157 } MeasureTooltipInfo;
1158
1159 static MeasureTooltipInfo gmti;
1160
1161 static Pixmap tooltipBgPixmap=None;
1162
1163 static
CalcMeasureTooltipPosition()1164 void CalcMeasureTooltipPosition()
1165 {
1166 if (gmti.x_follow_mouse || gmti.y_follow_mouse) {
1167 Window root_win=None, child_win=None;
1168 unsigned int status;
1169 int root_x=0, root_y=0;
1170
1171 XQueryPointer(mainDisplay, rootWindow, &root_win, &child_win,
1172 &root_x, &root_y, &gmti.ltx, &gmti.lty, &status);
1173 if (gmti.x_follow_mouse) gmti.ltx += 16;
1174 if (gmti.y_follow_mouse) gmti.lty += 16;
1175 if (gmti.x_follow_mouse && gmti.y_follow_mouse) {
1176 return;
1177 }
1178 }
1179 if (!gmti.x_follow_mouse) {
1180 int dpy_w=DisplayWidth(mainDisplay,mainScreen);
1181
1182 switch (gmti.position_x) {
1183 case ALIGN_L: gmti.ltx = 0; break;
1184 case ALIGN_C: gmti.ltx = ((dpy_w-gmti.bbox_w-gmti.x_padding)>>1); break;
1185 case ALIGN_R: gmti.ltx = (dpy_w-gmti.bbox_w-(gmti.x_padding<<1)); break;
1186 default: gmti.ltx = 0; break;
1187 }
1188 }
1189 if (!gmti.y_follow_mouse) {
1190 int dpy_h=DisplayHeight(mainDisplay,mainScreen);
1191
1192 switch (gmti.position_y) {
1193 case ALIGN_T: gmti.lty = 0; break;
1194 case ALIGN_M: gmti.lty = ((dpy_h-gmti.bbox_h-gmti.y_padding)>>1); break;
1195 case ALIGN_B: gmti.lty = (dpy_h-gmti.bbox_h-(gmti.y_padding<<1)); break;
1196 default: gmti.lty = 0; break;
1197 }
1198 }
1199 }
1200
1201 static
SetMeasureTooltipBBox(msg)1202 void SetMeasureTooltipBBox(msg)
1203 char *msg;
1204 {
1205 int bbox_w=0, bbox_h=0;
1206 char *psz=NULL, *line=NULL;
1207
1208 bbox_h = ((msgFontSet==NULL && msgFontPtr==NULL) ? defaultFontHeight :
1209 msgFontHeight);
1210 line = msg;
1211 psz = strchr(line, '\n');
1212 while (line != NULL) {
1213 char saved_ch='\0';
1214 int len=0, w=0;
1215
1216 if (psz != NULL) {
1217 saved_ch = (*psz);
1218 *psz = '\0';
1219 }
1220 len = strlen(line);
1221 if (msgFontSet == NULL && msgFontPtr == NULL) {
1222 w = (defaultFontWidth*len);
1223 } else {
1224 w = MsgTextWidth(msgFontPtr, line, len);
1225 }
1226 if (w > bbox_w) bbox_w = w;
1227
1228 if (psz == NULL) {
1229 break;
1230 }
1231 *psz = saved_ch;
1232 line = &psz[1];
1233 psz = strchr(line, '\n');
1234
1235 bbox_h += ((msgFontSet==NULL && msgFontPtr==NULL) ? defaultFontHeight :
1236 msgFontHeight);
1237 }
1238 gmti.bbox_w = bbox_w;
1239 gmti.bbox_h = bbox_h;
1240 gmti.w = bbox_w+((gmti.x_padding)<<1);
1241 gmti.h = bbox_h+((gmti.y_padding)<<1);
1242
1243 CalcMeasureTooltipPosition();
1244 }
1245
DoIntervalMeasureTooltip(ltx,lty,rbx,rby,mdx,mdy,delta_str)1246 void DoIntervalMeasureTooltip(ltx, lty, rbx, rby, mdx, mdy, delta_str)
1247 int ltx, lty, rbx, rby, mdx, mdy;
1248 char *delta_str;
1249 {
1250 char w_buf[80], h_buf[80], buf[256];
1251 char lx_buf[80], cx_buf[80], rx_buf[80];
1252 char ty_buf[80], my_buf[80], by_buf[80];
1253
1254 PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(rbx-ltx)));
1255 PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(rby-lty)));
1256 PixelToMeasurementUnit(lx_buf, ABS_X(ltx < rbx ? ltx : rbx));
1257 PixelToMeasurementUnit(cx_buf, ABS_X(mdx));
1258 PixelToMeasurementUnit(rx_buf, ABS_X(ltx > rbx ? ltx : rbx));
1259 PixelToMeasurementUnit(ty_buf, ABS_Y(lty < rby ? lty : rby));
1260 PixelToMeasurementUnit(my_buf, ABS_Y(mdy));
1261 PixelToMeasurementUnit(by_buf, ABS_Y(lty > rby ? lty : rby));
1262 if (delta_str != NULL) {
1263 sprintf(buf, "lx=%s cx=%s rx=%s\nty=%s my=%s by=%s\nw=%s h=%s\n%s",
1264 lx_buf, cx_buf, rx_buf, ty_buf, my_buf, by_buf, w_buf, h_buf,
1265 delta_str);
1266 } else {
1267 sprintf(buf, "lx=%s cx=%s rx=%s\nty=%s my=%s by=%s\nw=%s h=%s",
1268 lx_buf, cx_buf, rx_buf, ty_buf, my_buf, by_buf, w_buf, h_buf);
1269 }
1270 SetMeasureTooltip(buf);
1271 }
1272
StartMeasureTooltip(msg)1273 void StartMeasureTooltip(msg)
1274 char *msg;
1275 {
1276 SetMeasureTooltip(msg);
1277 }
1278
SetMeasureTooltip(msg)1279 void SetMeasureTooltip(msg)
1280 char *msg;
1281 {
1282 int x=0, y=0;
1283 char *psz=NULL, *line=NULL;
1284
1285 if (!showMeasurementInTooltip) return;
1286
1287 if (!gmti.mapped) {
1288 XMapWindow(mainDisplay, gmti.win);
1289 gmti.mapped = TRUE;
1290 }
1291 XRaiseWindow(mainDisplay, gmti.win);
1292
1293 SetMeasureTooltipBBox(msg);
1294 XMoveResizeWindow(mainDisplay, gmti.win, gmti.ltx, gmti.lty, gmti.w, gmti.h);
1295
1296 XClearWindow(mainDisplay, gmti.win);
1297
1298 x = gmti.x_padding;
1299 y = gmti.y_padding + ((msgFontSet==NULL && msgFontPtr==NULL) ?
1300 defaultFontAsc : msgFontAsc);;
1301 line = msg;
1302 psz = strchr(line, '\n');
1303 while (line != NULL) {
1304 char saved_ch='\0';
1305
1306 if (psz != NULL) {
1307 saved_ch = (*psz);
1308 *psz = '\0';
1309 }
1310 DrawMsgString(mainDisplay, gmti.win, gmti.gc, x, y, line, strlen(line));
1311 if (psz == NULL) {
1312 break;
1313 }
1314 *psz = saved_ch;
1315 line = &psz[1];
1316 psz = strchr(line, '\n');
1317
1318 y += ((msgFontSet==NULL && msgFontPtr==NULL) ? defaultFontHeight :
1319 msgFontHeight);
1320 }
1321 }
1322
EndMeasureTooltip(force)1323 void EndMeasureTooltip(force)
1324 int force;
1325 {
1326 if (force || (showMeasurement && showMeasurementInTooltip)) {
1327 if (gmti.mapped) {
1328 XUnmapWindow(mainDisplay, gmti.win);
1329 gmti.mapped = FALSE;
1330 }
1331 }
1332 }
1333
CleanUpMeasureTooltip()1334 void CleanUpMeasureTooltip()
1335 {
1336 if (tooltipBgPixmap != None) {
1337 XFreePixmap(mainDisplay, tooltipBgPixmap);
1338 tooltipBgPixmap = None;
1339 }
1340 if (gmti.gc != NULL) {
1341 XFreeGC(mainDisplay, gmti.gc);
1342 }
1343 if (gmti.win != None) {
1344 XDestroyWindow(mainDisplay, gmti.win);
1345 }
1346 memset(&gmti, 0, sizeof(MeasureTooltipInfo));
1347 showMeasurementInTooltip = FALSE;
1348 gmti.win = None;
1349 }
1350
1351 static
CreateMeasureTooltipWindow()1352 int CreateMeasureTooltipWindow()
1353 {
1354 int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
1355 XGCValues values;
1356 XWMHints wmhints;
1357 XSizeHints sizehints;
1358 XSetWindowAttributes win_attrs;
1359
1360 if ((gmti.win=XCreateSimpleWindow(mainDisplay, rootWindow, 0, 0, 10, 10,
1361 1, myBorderPixel, bg_pixel)) == 0) {
1362 return FailToCreateWindowMessage("CreateMeasureTooltipWindow()", NULL,
1363 FALSE);
1364 }
1365 win_attrs.save_under = True;
1366 win_attrs.override_redirect = True;
1367 win_attrs.colormap = mainColormap;
1368 XChangeWindowAttributes(mainDisplay, gmti.win,
1369 CWSaveUnder | CWOverrideRedirect | CWColormap, &win_attrs);
1370
1371 wmhints.flags = InputHint | StateHint;
1372 wmhints.input = True;
1373 wmhints.initial_state = NormalState;
1374 XSetWMHints(mainDisplay, gmti.win, &wmhints);
1375
1376 sizehints.flags = PPosition | PSize | USPosition | PMinSize | PMaxSize;
1377 sizehints.x = 0;
1378 sizehints.y = 0;
1379 sizehints.width = sizehints.min_width = sizehints.max_width = 10;
1380 sizehints.height = sizehints.min_height = sizehints.max_height = 10;
1381 #ifdef NOTR4MODE
1382 XSetNormalHints(mainDisplay, gmti.win, &sizehints);
1383 #else
1384 XSetWMNormalHints(mainDisplay, gmti.win, &sizehints);
1385 #endif
1386
1387 XSetTransientForHint(mainDisplay, gmti.win, mainWindow);
1388
1389 values.foreground = myFgPixel;
1390 values.background = bg_pixel;
1391 values.font = (msgFontPtr==NULL ? defaultFontPtr->fid : msgFontPtr->fid);
1392 gmti.gc = XCreateGC(mainDisplay, gmti.win,
1393 GCForeground | GCBackground | GCFont, &values);
1394 return TRUE;
1395 }
1396
1397 static
CreateLightYellowBackgroundPixmapForTooltip()1398 void CreateLightYellowBackgroundPixmapForTooltip()
1399 {
1400 XImage *image=NULL;
1401
1402 tooltipBgPixmap = XCreatePixmap(mainDisplay, mainWindow, 2, 2, mainDepth);
1403 XSetForeground(mainDisplay, xpmGC, myYellowPixel);
1404 XFillRectangle(mainDisplay, tooltipBgPixmap, xpmGC, 0, 0, 2, 2);
1405 XSetForeground(mainDisplay, xpmGC, myFgPixel);
1406 image = XGetImage(mainDisplay, tooltipBgPixmap, 0, 0, 2, 2, AllPlanes,
1407 ZPixmap);
1408 XPutPixel(image, 0, 0, myWhitePixel);
1409 XPutPixel(image, 1, 1, myWhitePixel);
1410 XPutImage(mainDisplay, tooltipBgPixmap, xpmGC, image, 0, 0, 0, 0, 2, 2);
1411 XDestroyImage(image);
1412
1413 XSetWindowBackgroundPixmap(mainDisplay, gmti.win, tooltipBgPixmap);
1414 }
1415
InitMeasureTooltip()1416 int InitMeasureTooltip()
1417 {
1418 char *c_ptr=NULL;
1419
1420 tooltipBgPixmap = None;
1421
1422 memset(&gmti, 0, sizeof(MeasureTooltipInfo));
1423 gmti.win = None;
1424 gmti.mapped = FALSE;
1425 gmti.x_padding = 4;
1426 gmti.y_padding = 2;
1427
1428 showMeasurementInTooltip = FALSE;
1429 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME,
1430 "UseMeasureTooltip")) != NULL &&
1431 UtilStrICmp(c_ptr, "true") == 0) {
1432 showMeasurementInTooltip = TRUE;
1433 }
1434 measureTooltipVerbose = FALSE;
1435 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME,
1436 "MeasureTooltipVerbose")) != NULL &&
1437 UtilStrICmp(c_ptr, "true") == 0) {
1438 measureTooltipVerbose = TRUE;
1439 }
1440 gmti.x_follow_mouse = gmti.y_follow_mouse = FALSE;
1441 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME,
1442 "MeasureTooltipXFollowMouse")) != NULL &&
1443 UtilStrICmp(c_ptr, "true") == 0) {
1444 gmti.x_follow_mouse = TRUE;
1445 }
1446 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME,
1447 "MeasureTooltipYFollowMouse")) != NULL &&
1448 UtilStrICmp(c_ptr, "true") == 0) {
1449 gmti.y_follow_mouse = TRUE;
1450 }
1451 gmti.position_y = ALIGN_T;
1452 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME,
1453 "MeasureTooltipVerticalPosition")) != NULL) {
1454 if (UtilStrICmp(c_ptr, "top") == 0) {
1455 gmti.position_y = ALIGN_T;
1456 } else if (UtilStrICmp(c_ptr, "middle") == 0) {
1457 gmti.position_y = ALIGN_M;
1458 } else if (UtilStrICmp(c_ptr, "bottom") == 0) {
1459 gmti.position_y = ALIGN_B;
1460 } else {
1461 fprintf(stderr, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
1462 TOOL_NAME, "MeasureTooltipVerticalPosition", c_ptr, "Top");
1463 fprintf(stderr, "\n");
1464 }
1465 }
1466 gmti.position_x = ALIGN_L;
1467 if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME,
1468 "MeasureTooltipHorizontalPosition")) != NULL) {
1469 if (UtilStrICmp(c_ptr, "left") == 0) {
1470 gmti.position_x = ALIGN_L;
1471 } else if (UtilStrICmp(c_ptr, "center") == 0) {
1472 gmti.position_x = ALIGN_C;
1473 } else if (UtilStrICmp(c_ptr, "right") == 0) {
1474 gmti.position_x = ALIGN_R;
1475 } else {
1476 fprintf(stderr, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
1477 TOOL_NAME, "MeasureTooltipHorizontalPosition", c_ptr, "Left");
1478 fprintf(stderr, "\n");
1479 }
1480 }
1481 if (!CreateMeasureTooltipWindow()) {
1482 gmti.win = None;
1483 } else if (threeDLook) {
1484 CreateLightYellowBackgroundPixmapForTooltip();
1485 }
1486 return TRUE;
1487 }
1488