1 /*
2 * xvpopup.c - pop up "Are you sure? Yes/No/Maybe" sort of dialog box
3 *
4 * callable functions:
5 *
6 * CenterMapWindow(win,x,y) - maps and centers a window around the mouse
7 * PopUp(str,...) - maps, sets up popW
8 * ErrPopUp(str,str) - maps, sets up popW
9 * GetStrPopUp(...) - opens a 1-line, editable text popup window
10 * GrabPopUp(*hide,*del) - opens 'grab' popup dialog
11 * PadPopUp() - opens 'grab' popup dialog
12 * ClosePopUp() - closes pop-up or alert window, if open
13 * OpenAlert(str) - maps a button-less window
14 * CloseAlert() - closes a button-less window
15 * PUCheckEvent(event) - called by event handler
16 */
17
18 #include "copyright.h"
19
20 #include "xv.h"
21
22 #define OMIT_ICON_BITS
23 #include "bits/icon" /* icon_bits[] not used, but icon_width/height are */
24
25 #define PUWIDE 480
26 #define PUHIGH 170
27
28 #define PAD_PUWIDE 480
29 #define PAD_PUHIGH 215
30
31 #define BUTTH 24
32
33 static int doPopUp PARM((const char *, const char **, int, int, const char *));
34 static void attachPUD PARM((void));
35 static void TextRect PARM((Window, const char *, int, int, int, int, u_long));
36 static void createPUD PARM((void));
37 static void drawPUD PARM((int, int, int, int));
38 static void drawPadOMStr PARM((void));
39 static void clickPUD PARM((int, int));
40 static void doGetStrKey PARM((int));
41 static int doGSKey PARM((int));
42 static void changedGSBuf PARM((void));
43 static void drawGSBuf PARM((void));
44 static void buildPadLists PARM((void));
45 static void build1PadList PARM((const char *, const char **, const char **, int *,
46 const char **, const char **, int));
47
48
49 /* values 'popUp' can take */
50 #define ISPOPUP 1
51 #define ISALERT 2
52 #define ISGETSTR 3
53 #define ISGRAB 4
54 #define ISPAD 5
55
56 #define DELAYSTR "Delay:"
57 #define SECSTR "seconds"
58 #define HIDESTR "Hide XV windows"
59
60 /* local variables */
61 static Window popW;
62 static int nbts, selected, popUp=0, firsttime=1;
63 static int puwide = PUWIDE;
64 static int puhigh = PUHIGH;
65 static BUTT *bts;
66 static const char *text;
67 static char accel[8];
68
69 static char *gsBuf; /* stuff needed for GetStrPopUp() handling */
70 static const char *gsFilter;
71 static int gsBufLen, gsAllow, gsCurPos, gsStPos, gsEnPos;
72 static int gsx, gsy, gsw, gsh;
73
74 /* stuff for GrabPopUp */
75 static CBUTT ahideCB;
76
77
78 /*** stuff for PadPopUp ***/
79 static char padSbuf[256], padBbuf[256], padLbuf[256], padBuf[256];
80 static char *padInst, padSinst[200], padBinst[200], padLinst[200];
81 static MBUTT padDfltMB, padMthdMB;
82 static BUTT padDButt, padOMButt;
83 static int padHaveDooDads = 0;
84 static int padMode, padOMode;
85 static DIAL padWDial, padHDial, padODial;
86
87 static int padMthdLen=3;
88 static const char *padMthdNames[] = { "Solid Fill", "Run 'bggen'", "Load Image" };
89
90 static int padColDefLen = 9;
91 static const char *padColDefNames[] = { "black", "red", "yellow", "green",
92 "cyan", "blue", "magenta", "white",
93 "50% gray" };
94
95 static const char *padColDefVals[] = { "black", "red", "yellow", "green",
96 "cyan", "blue", "magenta", "white",
97 "gray50" };
98
99 static int padBgDefLen = 8;
100 static const char *padBgDefNames[] = { "Black->White",
101 "Blue Gradient",
102 "RGB Rainbow",
103 "Full Rainbow",
104 "Color Assortment",
105 "Green Tiles",
106 "Red Balls",
107 "Red+Yellow Diamonds" };
108
109 static const char *padBgDefVals[] = { "black white",
110 "100 100 255 50 50 150",
111 "red green blue",
112 "black red yellow green blue purple black",
113 "black white red black yellow white green black cyan white blue black magenta white red yellow green cyan blue magenta red",
114 "green black -r 30 -G 32x32",
115 "red black -r 45 -G 32x32",
116 "red yellow -r 45 -G 32x32" };
117
118
119 /* this should match with PAD_O* defs in xv.h */
120 static const char *padOMStr[] = { "RGB", "Int.", "Hue", "Sat." };
121
122 #define PAD_MAXDEFLEN 10
123 static int padColLen = 0;
124 static const char *padColNames [PAD_MAXDEFLEN];
125 static const char *padColVals [PAD_MAXDEFLEN];
126 static int padBgLen = 0;
127 static const char *padBgNames [PAD_MAXDEFLEN];
128 static const char *padBgVals [PAD_MAXDEFLEN];
129 static int padLoadLen = 0;
130 static const char *padLoadNames[PAD_MAXDEFLEN];
131 static const char *padLoadVals [PAD_MAXDEFLEN];
132
133
134 /***************************************************/
CenterMapWindow(win,dx,dy,w,h)135 void CenterMapWindow(win, dx, dy, w, h)
136 Window win;
137 int dx, dy, w, h;
138 {
139 XSizeHints hints;
140 Window rW,cW;
141 int rx,ry,x,y,wx,wy;
142 unsigned int mask;
143
144
145 if (!XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
146 /* couldn't query mouse. just center on screen */
147 wx = (dispWIDE-w)/2; wy = (dispHIGH-h)/2;
148 }
149 else {
150 wx = x - dx;
151 wy = y - dy;
152 if (wx<0) wx = 0;
153 if (wy<0) wy = 0;
154 if (wx + w > dispWIDE) wx = dispWIDE - w;
155 if (wy + h > dispHIGH) wy = dispHIGH - h;
156 }
157
158
159 if (winCtrPosKludge) {
160 wx -= (p_offx + ch_offx);
161 wy -= (p_offy + ch_offy);
162 }
163 else {
164 wx -= (ch_offx);
165 wy -= (ch_offy);
166 }
167
168 if (!XGetNormalHints(theDisp, win, &hints)) hints.flags = 0;
169 hints.width = hints.min_width = hints.max_width = w;
170 hints.height = hints.min_height = hints.max_height = h;
171 hints.x = wx; hints.y = wy;
172 hints.flags |= (USSize | PMinSize | PMaxSize | USPosition);
173 XSetNormalHints(theDisp, win, &hints);
174
175 XMoveWindow(theDisp, win, wx, wy);
176 XMapRaised(theDisp, win);
177 }
178
179
180 /***************************************************/
PopUp(txt,labels,n)181 int PopUp(txt, labels, n)
182 const char *txt;
183 const char *labels[];
184 int n;
185 {
186 return doPopUp(txt, labels, n, ISPOPUP, "xv confirm");
187 }
188
189
190 /***************************************************/
doPopUp(txt,labels,n,poptyp,wname)191 static int doPopUp(txt, labels, n, poptyp, wname)
192 const char *txt;
193 const char *labels[];
194 int n, poptyp;
195 const char *wname;
196 {
197 int i;
198 XEvent event;
199
200 if (firsttime) createPUD();
201
202 if (poptyp != ISPAD) { puwide = PUWIDE; puhigh = PUHIGH; }
203 else { puwide = PAD_PUWIDE; puhigh = PAD_PUHIGH; }
204
205
206 /* attach controls to popW, now that it exists */
207 if (poptyp==ISGRAB) ahideCB.win = popW;
208 else if (poptyp == ISPAD) {
209
210 if (!padHaveDooDads) {
211 DCreate(&padWDial, popW, 16, puhigh-16-100-1,75,100,
212 1.0, 2048.0, (double)pWIDE, 1.0, 10.0,
213 infofg, infobg, hicol, locol, "Width", NULL);
214 DCreate(&padHDial, popW, 16+1+75, puhigh-16-100-1,75,100,
215 1.0, 2048.0, (double)pHIGH, 1.0, 10.0,
216 infofg, infobg, hicol, locol, "Height", NULL);
217
218 DCreate(&padODial, popW, 16+1+75+75+9, puhigh-16-100-1,75,100,
219 0.0, 100.0, 100.0, 1.0, 10.0,
220 infofg, infobg, hicol, locol, "Opaque", NULL);
221
222 MBCreate(&padMthdMB, popW, 100-2+44, 10, 140, 19, NULL,
223 padMthdNames, padMthdLen, infofg, infobg, hicol, locol);
224 padMthdMB.hascheck = 1;
225 padMthdMB.flags[0] = 1;
226
227 MBCreate(&padDfltMB, popW, 250-2+44, 10, 140, 19, "Defaults",
228 padColNames, padColLen, infofg, infobg, hicol, locol);
229
230 BTCreate(&padDButt, popW, padHDial.x+padHDial.w-12, puhigh-140+6,
231 13,13, "", infofg, infobg, hicol, locol);
232
233 BTCreate(&padOMButt, popW, padODial.x+padODial.w-12, puhigh-140+6,
234 13,13, "", infofg, infobg, hicol, locol);
235
236 padHaveDooDads = 1;
237 }
238
239 XMapWindow(theDisp, padWDial.win);
240 XMapWindow(theDisp, padHDial.win);
241 XMapWindow(theDisp, padODial.win);
242 }
243
244
245 XResizeWindow(theDisp, popW, (u_int) puwide, (u_int) puhigh);
246 XStoreName (theDisp, popW, wname);
247 XSetIconName (theDisp, popW, wname);
248 attachPUD();
249
250 bts = (BUTT *) malloc(n * sizeof(BUTT));
251 if (!bts) FatalError("unable to malloc buttons in popup\n");
252 nbts = n;
253 selected = 0;
254 text = txt;
255
256 for (i=0; i<n; i++) {
257 BTCreate(&bts[i], popW, puwide - (n-i) * (80 + 10), puhigh - 10 - BUTTH,
258 80, BUTTH, labels[i]+1, infofg, infobg, hicol, locol);
259 accel[i] = labels[i][0];
260 }
261
262
263 if (poptyp == ISGRAB) {
264 BTSetActive(&bts[0], (int) strlen(gsBuf));
265 BTSetActive(&bts[1], (strlen(gsBuf)>(size_t)0 && atoi(gsBuf)>(size_t)0));
266 }
267 else if (poptyp == ISPAD) {
268 BTSetActive(&bts[0], (int) strlen(gsBuf));
269 i = pWIDE * 3; RANGE(i,2048,9999);
270 DSetRange(&padWDial, 1.0, (double)i, padWDial.val, 1.0, 10.0);
271 i = pHIGH * 3; RANGE(i,2048,9999);
272 DSetRange(&padHDial, 1.0, (double)i, padHDial.val, 1.0, 10.0);
273
274 DSetActive(&padWDial, (padMode!=PAD_LOAD)); /* DSetRange activates dial */
275 DSetActive(&padHDial, (padMode!=PAD_LOAD));
276 DSetActive(&padODial, 1);
277
278 switch (padMode) {
279 case PAD_SOLID:
280 padDfltMB.list = padColNames;
281 padDfltMB.nlist = padColLen;
282 break;
283 case PAD_BGGEN:
284 padDfltMB.list = padBgNames;
285 padDfltMB.nlist = padBgLen;
286 break;
287 case PAD_LOAD:
288 padDfltMB.list = padLoadNames;
289 padDfltMB.nlist = padLoadLen;
290 break;
291 default: break; /* shouldn't happen */
292 }
293 }
294
295 /* center first button in window around mouse position, with constraint that
296 window be fully on the screen */
297
298 popUp = poptyp;
299 if (startGrab == 2)
300 startGrab = 4;
301 else {
302 CenterMapWindow(popW, 40 + bts[0].x, BUTTH/2 + bts[0].y, puwide, puhigh);
303
304 /* MUST wait for VisibilityNotify event to come in, else we run the risk
305 of UnMapping the window *before* the Map request completed. This
306 appears to be bad, (It leaves an empty window frame up.) though it
307 generally only happens on slow servers. Better safe than screwed... */
308
309 XWindowEvent(theDisp, popW, VisibilityChangeMask, &event);
310 }
311
312 /* block until this window gets closed */
313 while (popUp) {
314 XNextEvent(theDisp, &event);
315 HandleEvent(&event, &i);
316 }
317
318 /* free stuff */
319 XUnmapWindow(theDisp, popW);
320 free(bts);
321
322 return(selected);
323 }
324
325
326 /***************************************************/
ErrPopUp(txt,label)327 void ErrPopUp(txt, label)
328 const char *txt;
329 const char *label;
330 {
331 /* simplified interface to PopUp. Takes a string and the label for the
332 (one) button */
333
334 PopUp(txt, &label, 1);
335 }
336
337
338 /***************************************************/
GetStrPopUp(txt,labels,n,buf,buflen,filstr,allow)339 int GetStrPopUp(txt, labels, n, buf, buflen, filstr, allow)
340 const char *txt;
341 const char *labels[];
342 char *buf;
343 const char *filstr;
344 int n, buflen, allow;
345 {
346 /* pops up a window with a prompt string, a 1-line editable
347 text thingy, and a row of buttons. 'txt' is the prompt
348 string, 'labels' are the labels for the buttons, 'n' is the
349 number of buttons, 'buf' is the buffer displayed and edited
350 in the window, buflen is its length, filstr is a filter string, of
351 characters to block from entry (or, if 'allow' is '1', a list
352 of the *only* characters allowed for entry)
353
354 It returns the index of the button clicked on. Note that the
355 button labels have 1-character accellerators at the front, same
356 as in PopUp(). Note that it would be suboptimal to make any
357 of the 1-character accellerators be the same character as one of
358 the edit-text command keys
359
360 Also note that the filter string should only contain normal printable
361 characters (' ' through '\177'), as ctrl chars are pre-filtered
362 (ie, interpreted as emacs-like commands) */
363
364 gsBuf = buf; gsBufLen = buflen;
365 gsFilter = filstr; gsAllow = allow;
366
367 gsCurPos = strlen(gsBuf);
368 gsStPos = gsEnPos = 0;
369
370 gsh = LINEHIGH+5;
371 gsx = 10 + icon_width + 20;
372 gsy = 10+(PUHIGH-30-BUTTH-gsh)/2;
373
374 if (strlen(txt) > (size_t) 60)
375 gsy = PUHIGH - 10 - BUTTH - 10 - gsh - 20;
376
377 gsw = PUWIDE - gsx - 10;
378
379 changedGSBuf(); /* careful! popW doesn't exist yet! */
380
381 return doPopUp(txt, labels, n, ISGETSTR, "xv prompt");
382 }
383
384
385 /***************************************************/
GrabPopUp(pHide,pDelay)386 int GrabPopUp(pHide, pDelay)
387 int *pHide, *pDelay;
388 {
389 /* pops up Grab options dialog box */
390
391 int rv;
392 char delaybuf[32], grabTxt[1024];
393 static const char *grabLabels[] = { "\nGrab", "aAutoGrab", "\033Cancel" };
394
395 sprintf(delaybuf,"%d", *pDelay);
396 gsBuf = delaybuf; gsBufLen = 3;
397 gsFilter = "0123456789"; gsAllow = 1;
398
399 gsCurPos = strlen(gsBuf);
400 gsStPos = gsEnPos = 0;
401
402 gsw = 32;
403 gsh = LINEHIGH+5;
404 gsx = 10 + StringWidth(DELAYSTR) + 5;
405 gsy = (PUHIGH-BUTTH-10-5-gsh);
406
407 changedGSBuf(); /* careful! popW doesn't exist yet! */
408
409 /* window value gets filled in in doPopUp() */
410 CBCreate(&ahideCB, (Window) NULL,
411 PUWIDE-10-18-StringWidth(HIDESTR),
412 gsy+2, HIDESTR, infofg, infobg, hicol, locol);
413 ahideCB.val = *pHide;
414
415 sprintf(grabTxt, "Grab: after delay, Left button grabs a window, ");
416 strcat (grabTxt, "Middle button ");
417 strcat (grabTxt, "grabs a rectangular area, Right button cancels.\n\n");
418 strcat (grabTxt, "AutoGrab: after delay, grabs ");
419 strcat (grabTxt, "the window the cursor is positioned in. ");
420 strcat (grabTxt, "Delay must be non-zero.");
421
422 rv = doPopUp(grabTxt, grabLabels, 3, ISGRAB, "xv grab");
423
424 *pHide = ahideCB.val;
425 *pDelay = atoi(delaybuf);
426 return rv;
427 }
428
429
430 /***************************************************/
PadPopUp(pMode,pStr,pWide,pHigh,pOpaque,pOmode)431 int PadPopUp(pMode, pStr, pWide,pHigh, pOpaque, pOmode)
432 int *pMode, *pWide, *pHigh, *pOpaque, *pOmode;
433 char **pStr;
434 {
435 /* pops up 'Pad' options dialog box */
436
437 int rv, oldW, oldH, oldO;
438 static int firsttime=1;
439 static const char *labels[] = { "\nOk", "\033Cancel" };
440
441 if (firsttime) {
442 padSbuf[0] = '\0';
443 padBbuf[0] = '\0';
444 padLbuf[0] = '\0';
445
446 sprintf(padSinst, "Enter a color name ('orange'), %s%s",
447 "or an RGB color specification. ",
448 "(e.g. 'r,g,b' or '0xrrggbb')");
449 sprintf(padBinst, "Enter command line options for 'bggen'. (%s)",
450 "No '-w', '-h', or '-g' options allowed.");
451 sprintf(padLinst, "Enter a filename. The padded image %s",
452 "will be the same size as the loaded image.");
453
454 /* can't create MBUTT or DIALs here, parent window must exist first... */
455
456 padMode = PAD_SOLID;
457 padInst = padSinst;
458 padOMode = PAD_ORGB;
459 firsttime = 0;
460 }
461
462
463 buildPadLists();
464
465 switch (padMode) {
466 case PAD_SOLID: strcpy(padBuf, padSbuf); break;
467 case PAD_BGGEN: strcpy(padBuf, padBbuf); break;
468 case PAD_LOAD: strcpy(padBuf, padLbuf); break;
469 }
470
471
472 gsBuf = padBuf; gsBufLen = 256;
473 gsFilter = ""; gsAllow = 0;
474 gsCurPos = strlen(gsBuf);
475 gsStPos = gsEnPos = 0;
476
477 gsw = PAD_PUWIDE - 20;
478 gsh = LINEHIGH+5;
479 gsx = 10;
480 gsy = 40;
481
482 changedGSBuf(); /* careful! popW doesn't exist yet! */
483
484 if (padHaveDooDads) {
485 oldW = (int)padWDial.val;
486 oldH = (int)padHDial.val;
487 oldO = (int)padODial.val;
488 }
489 else { oldW = pWIDE; oldH = pHIGH; oldO = 100; }
490
491
492
493 rv = doPopUp("", labels, 2, ISPAD, "xv pad");
494
495
496
497 if (rv == 0) { /* copy padBuf to appropriate mode buffer */
498 switch (padMode) {
499 case PAD_SOLID: strcpy(padSbuf, padBuf); break;
500 case PAD_BGGEN: strcpy(padBbuf, padBuf); break;
501 case PAD_LOAD: strcpy(padLbuf, padBuf); break;
502 }
503 }
504
505 if (rv == 1) { /* cancelled: restore normal values */
506 DSetVal(&padWDial, (double)oldW);
507 DSetVal(&padHDial, (double)oldH);
508 DSetVal(&padODial, (double)oldO);
509 }
510
511 XUnmapWindow(theDisp, padWDial.win);
512 XUnmapWindow(theDisp, padHDial.win);
513 XUnmapWindow(theDisp, padODial.win);
514
515 /* load up return values */
516 *pMode = padMode;
517 *pStr = padBuf;
518 *pWide = (int)padWDial.val;
519 *pHigh = (int)padHDial.val;
520 *pOpaque = (int)padODial.val;
521 *pOmode = padOMode;
522
523 return rv;
524 }
525
526
527 /***************************************************/
buildPadLists()528 static void buildPadLists()
529 {
530 /* generates padCol* and padBg* lists used in 'Defaults' MBUTT. Grabs
531 all the X resources values it can, and adds appropriate defaults */
532
533 rd_str_cl("foo", "", 1); /* rebuild database */
534
535 build1PadList("color", padColVals, padColNames, &padColLen,
536 padColDefVals, padColDefNames, padColDefLen);
537
538 build1PadList("bggen", padBgVals, padBgNames, &padBgLen,
539 padBgDefVals, padBgDefNames, padBgDefLen);
540
541 build1PadList("load", padLoadVals, padLoadNames, &padLoadLen,
542 (const char **) NULL, (const char **) NULL, 0);
543 }
544
545
546 /***************************************************/
build1PadList(typstr,vals,nams,lenp,dvals,dnams,dlen)547 static void build1PadList(typstr, vals, nams, lenp, dvals, dnams, dlen)
548 const char *typstr;
549 const char **vals, **nams;
550 const char **dvals, **dnams;
551 int *lenp, dlen;
552 {
553 int i;
554 char resname[128];
555 char *copy;
556
557 for (i=0; i<*lenp; i++) { /* kill old lists */
558 free((char *) nams[i]);
559 free((char *) vals[i]);
560 }
561 *lenp = 0;
562
563 for (i=0; i<10; i++) {
564 sprintf(resname, "pad.%s.val%d", typstr, i);
565 if (rd_str_cl(resname, "Dialog.Menu.Slot",0)) { /* got one! */
566 copy = strdup(def_str);
567 if (!copy) continue;
568 vals[*lenp] = copy;
569
570 sprintf(resname, "pad.%s.name%d", typstr, i);
571 if (rd_str_cl(resname, "Dialog.Menu.Slot",0)) { /* and it has a name! */
572 copy = strdup(def_str);
573 if (!copy) { free((char *) vals[*lenp]); continue; }
574 }
575 else { /* it doesn't have a name. fabricate one */
576 copy = malloc((size_t) 32);
577 if (!copy) { free((char *) vals[*lenp]); continue; }
578 strncpy(copy, vals[*lenp], (size_t) 31);
579 copy[31] = '\0';
580 }
581 if (strlen(copy) > (size_t) 20) { /* fix long names */
582 char *sp = copy + 18;
583
584 *sp++ = '.'; *sp++ = '.'; *sp++ = '.'; *sp++ = '\0';
585 }
586 nams[*lenp] = copy;
587
588 *lenp = (*lenp) + 1;
589 }
590 }
591
592
593 /* add 'built-in' defaults to the lists */
594 for (i=0; i<dlen && *lenp<PAD_MAXDEFLEN; i++) {
595 copy = strdup(dvals[i]);
596 if (!copy) break;
597 vals[*lenp] = copy;
598
599 copy = strdup(dnams[i]);
600 if (!copy) { free((char *) vals[*lenp]); break; }
601 nams[*lenp] = copy;
602
603 *lenp = (*lenp) + 1;
604 }
605 }
606
607
608
609 /***************************************************/
ClosePopUp()610 void ClosePopUp()
611 {
612 /* closes popW: if it's a pop-up, returns 'cancel'. If it's an alert,
613 simply closes it */
614
615 if (popUp == ISALERT) CloseAlert();
616 else if (popUp == ISPOPUP) {
617 popUp = 0;
618 selected = nbts-1;
619 }
620 }
621
622
623 /***************************************************/
OpenAlert(txt)624 void OpenAlert(txt)
625 const char *txt;
626 {
627 /* pops up a window with txt displayed in it (*no buttons*).
628 returns immediately. window is closed by 'CloseAlert()'.
629 No 'PopUp()' calls are allowed while an Alert is displayed. */
630
631 XEvent event;
632
633 if (firsttime) createPUD();
634
635 XStoreName(theDisp, popW, "xv notice");
636 XSetIconName(theDisp, popW, "xv notice");
637 attachPUD();
638
639 nbts = 0;
640 selected = 0;
641 text = txt;
642
643 puwide = PUWIDE; puhigh = PUHIGH;
644 XResizeWindow(theDisp, popW, (u_int) puwide, (u_int) puhigh);
645
646 /* center last button in window around mouse position, with constraint that
647 window be fully on the screen */
648
649 CenterMapWindow(popW, puwide/2, puhigh/2, puwide, puhigh);
650 popUp = ISALERT;
651
652 /* MUST wait for VisibilityNotify event to come in, else we run the risk
653 of UnMapping the window *before* the Map request completed. This
654 appears to be bad, (It leaves an empty window frame up.) though it
655 generally only happens on slow servers. Better safe than screwed... */
656
657 XWindowEvent(theDisp, popW, VisibilityChangeMask, &event);
658 drawPUD(0, 0, puwide, puhigh);
659 XFlush(theDisp);
660 }
661
662
663 /***************************************************/
CloseAlert()664 void CloseAlert()
665 {
666 popUp = 0;
667 XUnmapWindow(theDisp, popW);
668 }
669
670
671 /***************************************************/
PUCheckEvent(xev)672 int PUCheckEvent(xev)
673 XEvent *xev;
674 {
675 /* check event to see if it's for us. If so, return 1, otherwise 0 */
676
677 int rv = 0;
678
679 if (!popUp) return(0);
680
681 if (xev->type == Expose) {
682 XExposeEvent *e = (XExposeEvent *) xev;
683 if (e->window == popW) {
684 drawPUD(e->x, e->y, e->width, e->height);
685 rv = 1;
686 }
687 else if (popUp == ISPAD && padHaveDooDads && e->window == padWDial.win)
688 { DRedraw(&padWDial); rv = 1; }
689 else if (popUp == ISPAD && padHaveDooDads && e->window == padHDial.win)
690 { DRedraw(&padHDial); rv = 1; }
691 else if (popUp == ISPAD && padHaveDooDads && e->window == padODial.win)
692 { DRedraw(&padODial); rv = 1; }
693 }
694
695 else if (xev->type == ButtonPress) {
696 XButtonEvent *e = (XButtonEvent *) xev;
697
698 if (e->button == Button1) {
699 if (e->window == popW) {
700 clickPUD(e->x,e->y);
701 rv = 1;
702 }
703 else if (popUp == ISPAD && padHaveDooDads && e->window == padWDial.win)
704 { DTrack(&padWDial, e->x, e->y); rv = 1; }
705 else if (popUp == ISPAD && padHaveDooDads && e->window == padHDial.win)
706 { DTrack(&padHDial, e->x, e->y); rv = 1; }
707 else if (popUp == ISPAD && padHaveDooDads && e->window == padODial.win)
708 { DTrack(&padODial, e->x, e->y); rv = 1; }
709 }
710 }
711
712
713 else if (xev->type == KeyPress) {
714 XKeyEvent *e = (XKeyEvent *) xev;
715 char buf[128]; KeySym ks;
716 int stlen, i, shift, ck;
717
718 stlen = XLookupString(e,buf,128,&ks,(XComposeStatus *) NULL);
719 shift = e->state & ShiftMask;
720 ck = CursorKey(ks, shift, 0);
721 buf[stlen] = '\0';
722
723 RemapKeyCheck(ks, buf, &stlen);
724
725 /* check cursor keys, which may or may not have a str assoc'd with them */
726 if (popUp==ISGETSTR || popUp==ISGRAB || popUp==ISPAD) {
727 if (ck==CK_LEFT) { doGetStrKey('\002'); rv = 1; }
728 else if (ck==CK_RIGHT) { doGetStrKey('\006'); rv = 1; }
729 }
730
731 if (stlen && !rv) { /* note: we accept kbd accel's in any win */
732 if (buf[0] == '\r') buf[0] = '\n';
733
734 /* search for character in accel table */
735 for (i=0; i<nbts; i++) {
736 if (buf[0] == accel[i] && buf[0] != ' ') {
737 FakeButtonPress(&bts[i]);
738 rv = 1;
739 }
740 }
741
742 if (!rv && buf[0]=='\033' && nbts==1) { /* ESC accepted in 1-but pu's */
743 FakeButtonPress(&bts[0]);
744 rv = 1;
745 }
746
747 if (!rv && (popUp==ISGETSTR || popUp==ISGRAB || popUp==ISPAD)) {
748 if (e->window == popW) { doGetStrKey(buf[0]); rv = 1; }
749 }
750 }
751
752 if (!stlen) rv = 1; /* quietly eat mute keys */
753 }
754
755
756 else if (xev->type == ClientMessage) {
757 Atom proto, delwin;
758 XClientMessageEvent *client_event = (XClientMessageEvent *) xev;
759
760 proto = XInternAtom(theDisp, "WM_PROTOCOLS", FALSE);
761 delwin = XInternAtom(theDisp, "WM_DELETE_WINDOW", FALSE);
762
763 if (client_event->message_type == proto &&
764 client_event->data.l[0] == delwin) {
765 /* it's a WM_DELETE_WINDOW event */
766
767 if (client_event->window == popW) {
768 FakeButtonPress(&bts[(nbts>1) ? nbts-1 : 0]);
769 rv = 1;
770 }
771 }
772 }
773
774 if (rv==0 && (xev->type == KeyPress || xev->type == ButtonPress)) {
775 XBell(theDisp, 0);
776 rv = 1; /* eat it */
777 }
778
779 return rv;
780 }
781
782
783
784 #define TR_MAXLN 10
785
786 /***************************************************/
TextRect(win,txt,x,y,w,h,fg)787 static void TextRect(win, txt, x, y, w, h, fg)
788 Window win;
789 const char *txt;
790 int x,y,w,h;
791 u_long fg;
792 {
793 /* draws semi-complex strings in a rectangle */
794
795 const char *sp;
796 const char *ep;
797 const char *oldep;
798 const char *start[TR_MAXLN];
799 int i, inbreak, lineno, top, hardcr, maxln, len[TR_MAXLN];
800
801 XSetForeground(theDisp, theGC, fg);
802
803 sp = txt; lineno = hardcr = 0;
804
805 maxln = h / LINEHIGH;
806 RANGE(maxln,0,TR_MAXLN);
807 while (*sp && lineno<maxln) {
808
809 /* drop off any leading spaces (except on first line or after \n) */
810 if (sp!=txt && !hardcr) {
811 while (*sp==' ') sp++;
812 }
813
814 hardcr = 0; ep = sp;
815
816 /* increment ep until we A) get too wide, B) hit eos or
817 C) hit a '\n' character */
818
819 /* NOTE: ep points to the character AFTER the end of the line */
820
821 while (XTextWidth(mfinfo, sp, (int)(ep-sp))<= w && *ep && *ep!='\n') ep++;
822 if (*ep=='\n') { ep++; hardcr=1; } /* eat newline */
823
824 /* if we got too wide, back off until we find a break position
825 (last char before a space or a '/') */
826
827 if (XTextWidth(mfinfo, sp, (int)(ep-sp)) > w) {
828 oldep = ep; inbreak = 0;
829 while (ep!=sp) {
830 ep--;
831 if ( inbreak && *ep!=' ') { ep++; break; }
832 if (!inbreak && *ep==' ') inbreak = 1;
833 if (*ep=='/') { ep++; break; }
834 }
835 if (ep==sp) ep = oldep-1; /* can't break this line. oh well */
836 }
837
838 start[lineno] = sp; len[lineno] = ep-sp;
839
840 /* make sure we don't print a trailing '\n' character! */
841 if (len[lineno] > 0) {
842 while (sp[len[lineno]-1] == '\n') len[lineno] = len[lineno] - 1;
843 }
844
845 sp = ep;
846 lineno++;
847 }
848
849 top = y + h/2 + (ASCENT-DESCENT)/2 - ((lineno-1)*LINEHIGH)/2;
850 if (top<y+ASCENT) top = y+ASCENT;
851
852 for (i=0, y=top; i<lineno; i++, y+=LINEHIGH) {
853 if (start[i][0] != '\n')
854 XDrawString(theDisp, win, theGC, x, y, start[i], len[i]);
855 }
856 }
857
858
859 /***************************************************/
createPUD()860 static void createPUD()
861 {
862 popW = CreateWindow("xv confirm", "XVconfirm", "+0+0",
863 PUWIDE, PUHIGH, infofg, infobg, 0);
864 if (!popW) FatalError("can't create popup window!");
865
866 XSelectInput(theDisp, popW, ExposureMask | ButtonPressMask | KeyPressMask
867 | VisibilityChangeMask);
868 /* XSetTransientForHint(theDisp, popW, mainW); */
869
870 XDefineCursor(theDisp, popW, arrow);
871 bts = (BUTT *) NULL;
872 nbts = selected = firsttime = 0;
873 }
874
875
876 /***************************************************/
attachPUD()877 static void attachPUD()
878 {
879 /* used to make PUD a transient window of something. Doesn't
880 do anything anymore, as I got tired of having window layering
881 shifted around everytime a popup window happened. Screw the
882 business about having the popup iconify when you iconify the
883 appropriate XV window. There generally ISN'T an appropriate
884 XV window... */
885 }
886
887
888 /***************************************************/
drawPUD(x,y,w,h)889 static void drawPUD(x,y,w,h)
890 int x,y,w,h;
891 {
892 int i,xt,yt;
893 XRectangle xr;
894
895 xr.x = x; xr.y = y; xr.width = w; xr.height = h;
896 XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
897
898 XSetForeground(theDisp, theGC, infofg);
899 XSetBackground(theDisp, theGC, infobg);
900
901 if (popUp == ISGRAB) {
902 xt = 10; yt = 10;
903 TextRect(popW, text, xt, yt, puwide-10-xt, gsy-20, infofg);
904 drawGSBuf();
905
906 XSetForeground(theDisp, theGC, infofg);
907 DrawString(popW, 10, gsy+ASCENT+4, DELAYSTR);
908 DrawString(popW, gsx+gsw+5, gsy+ASCENT+4, SECSTR);
909
910 CBRedraw(&ahideCB);
911 }
912
913 else if (popUp == ISPAD) {
914 drawGSBuf();
915
916 XSetForeground(theDisp, theGC, infofg);
917 DrawString(popW, 10+44,10+ASCENT+4,"Pad Method:");
918
919 MBRedraw(&padMthdMB);
920 MBRedraw(&padDfltMB);
921 DRedraw (&padWDial);
922 DRedraw (&padHDial);
923 BTRedraw(&padDButt);
924 BTRedraw(&padOMButt);
925
926 XSetForeground(theDisp, theGC, infofg);
927 drawPadOMStr();
928
929 XDrawRectangle(theDisp, popW, theGC, 10, puhigh-140, 16+2*74+84, 130);
930 Draw3dRect(popW, 10+1, puhigh-140+1, 16+2*74+84-2, 130-2,
931 R3D_IN,2,hicol,locol,infobg);
932 XSetForeground(theDisp, theGC, infofg);
933 CenterString(popW, 16+1+75-13, puhigh-16-100-12, "New Image Size");
934
935 if (ctrlColor) {
936 XSetForeground(theDisp, theGC, locol);
937 XDrawLine(theDisp, popW, theGC, 16+1+75+75+5, puhigh-140 + 6+8,
938 16+1+75+75+5, puhigh-10-4);
939 }
940
941
942 XSetForeground(theDisp, theGC, infofg);
943 XDrawRectangle(theDisp, popW, theGC, 268, puhigh-140,
944 (u_int) puwide - 10 - 268, 130-BUTTH-10);
945 Draw3dRect(popW, 268+1, puhigh-140+1, (u_int) puwide -10-268-2,
946 130-2 - BUTTH-10, R3D_IN,2,hicol,locol,infobg);
947
948 TextRect(popW,padInst,268+5, puhigh-140+3, puwide-10-268-10,
949 130-6 - BUTTH-10, infofg);
950 }
951
952 else {
953 XCopyPlane(theDisp, iconPix, popW, theGC, 0,0, icon_width, icon_height,
954 10,10+(puhigh-30-BUTTH-icon_height)/2, 1L);
955
956 xt = 10+icon_width+20; yt = 10;
957
958 if (popUp == ISGETSTR) {
959 TextRect(popW, text, xt, yt, puwide-10-xt, gsy-20, infofg);
960 drawGSBuf();
961 }
962 else TextRect(popW,text,xt,yt,puwide-10-xt,puhigh-10-BUTTH-20,infofg);
963 }
964
965
966 for (i=0; i<nbts; i++) BTRedraw(&bts[i]);
967 XSetClipMask(theDisp, theGC, None);
968 }
969
970
971 /***************************************************/
drawPadOMStr()972 static void drawPadOMStr()
973 {
974 CenterString(popW, padODial.x + (padODial.w - 13)/2,
975 puhigh-16-100-12, padOMStr[padOMode]);
976 }
977
978 /***************************************************/
clickPUD(x,y)979 static void clickPUD(x,y)
980 int x,y;
981 {
982 int i;
983 BUTT *bp = NULL;
984
985 for (i=0; i<nbts; i++) {
986 bp = &bts[i];
987 if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
988 }
989
990 if (i<nbts && bp && BTTrack(bp)) {
991 popUp = 0; selected = i; return;
992 }
993
994 if (popUp==ISGRAB && CBClick(&ahideCB, x,y)) CBTrack(&ahideCB);
995
996 else if (popUp == ISPAD) {
997 if (PTINRECT(x, y, padDButt.x, padDButt.y, padDButt.w, padDButt.h)) {
998 if (BTTrack(&padDButt)) {
999 DSetVal(&padWDial, (double)pWIDE);
1000 DSetVal(&padHDial, (double)pHIGH);
1001 }
1002 }
1003
1004 else if (PTINRECT(x,y,padOMButt.x,padOMButt.y,padOMButt.w,padOMButt.h)) {
1005 if (BTTrack(&padOMButt)) {
1006 XSetForeground(theDisp, theGC, infobg);
1007 drawPadOMStr();
1008 padOMode = (padOMode + 1) % PAD_OMAX;
1009 XSetForeground(theDisp, theGC, infofg);
1010 drawPadOMStr();
1011 }
1012 }
1013
1014
1015 else if (MBClick(&padMthdMB, x,y)) {
1016 i = MBTrack(&padMthdMB);
1017 if (i<0 || i==padMode) return;
1018
1019 switch (i) {
1020 case PAD_SOLID:
1021 strcpy(padBuf, padSbuf);
1022 padDfltMB.list = padColNames;
1023 padDfltMB.nlist = padColLen;
1024 padInst = padSinst;
1025 break;
1026 case PAD_BGGEN:
1027 strcpy(padBuf, padBbuf);
1028 padDfltMB.list = padBgNames;
1029 padDfltMB.nlist = padBgLen;
1030 padInst = padBinst;
1031 break;
1032 case PAD_LOAD:
1033 strcpy(padBuf, padLbuf);
1034 padDfltMB.list = padLoadNames;
1035 padDfltMB.nlist = padLoadLen;
1036 padInst = padLinst;
1037 break;
1038 default: break; /* shouldn't happen */
1039 }
1040
1041 gsCurPos = strlen(gsBuf);
1042 gsStPos = gsEnPos = 0;
1043 changedGSBuf();
1044 if (ctrlColor)
1045 XClearArea(theDisp, popW, gsx+3,gsy+3,
1046 (u_int)gsw-5, (u_int)gsh-5, False);
1047 else
1048 XClearArea(theDisp, popW, gsx+1,gsy+1,
1049 (u_int)gsw-1, (u_int)gsh-1, False);
1050 drawGSBuf();
1051
1052 BTSetActive(&bts[0], (int) strlen(gsBuf));
1053
1054 MBSelect(&padMthdMB, i);
1055 MBSetActive(&padDfltMB, 1);
1056 DSetActive (&padWDial, (i!=PAD_LOAD));
1057 DSetActive (&padHDial, (i!=PAD_LOAD));
1058
1059 XClearArea(theDisp, popW, 184+5, puhigh-140+3,
1060 (u_int) puwide-10-184-10, 130-6 - BUTTH-10, True);
1061
1062 padMode = i;
1063 }
1064
1065 else if (MBClick(&padDfltMB, x,y)) {
1066 i = MBTrack(&padDfltMB);
1067 if (i<0) return;
1068
1069 if (padMode == PAD_SOLID) strcpy(padBuf, padColVals[i]);
1070 else if (padMode == PAD_BGGEN) strcpy(padBuf, padBgVals[i]);
1071 else if (padMode == PAD_LOAD) strcpy(padBuf, padLoadVals[i]);
1072
1073 gsCurPos = strlen(gsBuf);
1074 gsStPos = gsEnPos = 0;
1075 changedGSBuf();
1076 if (ctrlColor)
1077 XClearArea(theDisp, popW, gsx+3,gsy+3,
1078 (u_int)gsw-5, (u_int)gsh-5, False);
1079 else
1080 XClearArea(theDisp, popW, gsx+1,gsy+1,
1081 (u_int)gsw-1, (u_int)gsh-1, False);
1082 drawGSBuf();
1083
1084 BTSetActive(&bts[0], (int) strlen(gsBuf));
1085 }
1086 }
1087 }
1088
1089
1090
1091 /***************************************************/
doGetStrKey(c)1092 static void doGetStrKey(c)
1093 int c;
1094 {
1095 if (doGSKey(c)) XBell(theDisp, 0);
1096 }
1097
1098
1099 /***************************************************/
doGSKey(c)1100 static int doGSKey(c)
1101 int c;
1102 {
1103 /* handle characters typed at GetStrPopUp window. Button accel. keys
1104 have already been checked for elsewhere. Practical upshot is that
1105 we don't have to do anything with ESC or Return (as these will normally
1106 be Cancel and Ok buttons)
1107
1108 Normally returns '0'. Returns '1' if character wasn't accepted, for
1109 whatever reason. */
1110
1111 int i, len, flen;
1112
1113 len = strlen(gsBuf);
1114 if (gsFilter) flen = strlen(gsFilter);
1115 else flen = 0;
1116
1117
1118 if (c>=' ' && c<'\177') { /* 'NORMAL' CHARACTERS */
1119 if (flen) { /* check filter string */
1120 for (i=0; i<flen && c!=gsFilter[i]; i++);
1121 if (!gsAllow && i< flen) return 1; /* found in 'disallow' filter */
1122 if ( gsAllow && i==flen) return 1; /* not found in 'allow' filter */
1123 }
1124
1125 if (len >= gsBufLen-1) return 1; /* at max length */
1126
1127 xvbcopy(&gsBuf[gsCurPos], &gsBuf[gsCurPos+1], (size_t) len-gsCurPos+1);
1128 gsBuf[gsCurPos]=c; gsCurPos++;
1129 }
1130
1131
1132 else if (c=='\010') { /* BS */
1133 if (gsCurPos==0) return 1; /* at beginning of str */
1134 xvbcopy(&gsBuf[gsCurPos], &gsBuf[gsCurPos-1], (size_t) len-gsCurPos+1);
1135 gsCurPos--;
1136 }
1137
1138 else if (c=='\025') { /* ^U: clear entire line */
1139 gsBuf[0] = '\0';
1140 gsCurPos = 0;
1141 }
1142
1143 else if (c=='\013') { /* ^K: clear to end of line */
1144 gsBuf[gsCurPos] = '\0';
1145 }
1146
1147 else if (c=='\001') { /* ^A: move to beginning */
1148 gsCurPos = 0;
1149 }
1150
1151 else if (c=='\005') { /* ^E: move to end */
1152 gsCurPos = len;
1153 }
1154
1155 else if (c=='\004' || c=='\177') { /* ^D or DEL: delete character at gsCurPos */
1156 if (gsCurPos==len) return 1;
1157 xvbcopy(&gsBuf[gsCurPos+1], &gsBuf[gsCurPos], (size_t) len-gsCurPos);
1158 }
1159
1160 else if (c=='\002') { /* ^B: move backwards char */
1161 if (gsCurPos==0) return 1;
1162 gsCurPos--;
1163 }
1164
1165 else if (c=='\006') { /* ^F: move forwards char */
1166 if (gsCurPos==len) return 1;
1167 gsCurPos++;
1168 }
1169
1170 else return 1; /* unhandled character */
1171
1172 changedGSBuf(); /* compute gsEnPos, gsStPos */
1173
1174 if (ctrlColor)
1175 XClearArea(theDisp, popW, gsx+3,gsy+3, (u_int)gsw-5, (u_int)gsh-5, False);
1176 else
1177 XClearArea(theDisp, popW, gsx+1,gsy+1, (u_int)gsw-1, (u_int)gsh-1, False);
1178
1179 drawGSBuf();
1180
1181 if (popUp == ISGETSTR || popUp == ISPAD) {
1182 /* if we have a string of any sort, turn on the default '\n' button
1183 (if there is one) */
1184 for (i=0; i<nbts && accel[i]!='\n'; i++);
1185 if (i<nbts) BTSetActive(&bts[i], (strlen(gsBuf) > (size_t) 0));
1186 }
1187 else if (popUp == ISGRAB) {
1188 /* need a string of length 1 to enable Grab (bts[0]), and a string
1189 with an atoi() of at least '1' to enable AutoGrab (bts[1]) */
1190 BTSetActive(&bts[0], (strlen(gsBuf) > (size_t) 0));
1191 BTSetActive(&bts[1], (strlen(gsBuf)>(size_t)0 && atoi(gsBuf)>(size_t)0));
1192 }
1193
1194 return(0);
1195 }
1196
1197
1198
1199 /***************************************************/
changedGSBuf()1200 static void changedGSBuf()
1201 {
1202 /* cursor position (or whatever) may have changed. adjust displayed
1203 portion of gsBuf */
1204
1205 int len;
1206
1207 len = strlen(gsBuf);
1208
1209 if (gsCurPos < gsStPos) gsStPos = gsCurPos;
1210 if (gsCurPos > gsEnPos) gsEnPos = gsCurPos;
1211
1212 if (gsStPos>len) gsStPos = (len>0) ? len-1 : 0;
1213 if (gsEnPos>len) gsEnPos = (len>0) ? len-1 : 0;
1214
1215 /* while substring is shorter than window, inc enPos */
1216
1217 while (XTextWidth(mfinfo, &gsBuf[gsStPos], gsEnPos-gsStPos) < (gsw-6)
1218 && gsEnPos<len) { gsEnPos++; }
1219
1220 /* while substring is longer than window, dec enpos, unless enpos==curpos,
1221 in which case, inc stpos */
1222
1223 while (XTextWidth(mfinfo, &gsBuf[gsStPos], gsEnPos-gsStPos) > (gsw-6)) {
1224 if (gsEnPos != gsCurPos) gsEnPos--;
1225 else gsStPos++;
1226 }
1227 }
1228
1229
1230 /***************************************************/
drawGSBuf()1231 static void drawGSBuf()
1232 {
1233 /* draw edittext thingy in GetStrPopUp window */
1234
1235 int cpos;
1236
1237 XSetForeground(theDisp, theGC, infofg);
1238 XDrawRectangle(theDisp, popW, theGC, gsx, gsy, (u_int) gsw, (u_int) gsh);
1239 Draw3dRect(popW, gsx+1, gsy+1, (u_int) gsw-2, (u_int) gsh-2,
1240 R3D_IN, 2, hicol,locol,infobg);
1241
1242 XSetForeground(theDisp, theGC, infofg);
1243
1244 if (gsStPos>0) { /* draw a "there's more over here" doowah */
1245 XDrawLine(theDisp, popW, theGC, gsx+1, gsy+1, gsx+1, gsy + gsh-1);
1246 XDrawLine(theDisp, popW, theGC, gsx+2, gsy+1, gsx+2, gsy + gsh-1);
1247 XDrawLine(theDisp, popW, theGC, gsx+3, gsy+1, gsx+3, gsy + gsh-1);
1248 }
1249
1250 if ((size_t) gsEnPos < strlen(gsBuf)) {
1251 /* draw a "there's more over here" doowah */
1252 XDrawLine(theDisp, popW, theGC, gsx+gsw-3, gsy+1, gsx+gsw-3, gsy+gsh-1);
1253 XDrawLine(theDisp, popW, theGC, gsx+gsw-2, gsy+1, gsx+gsw-2, gsy+gsh-1);
1254 XDrawLine(theDisp, popW, theGC, gsx+gsw-1, gsy+1, gsx+gsw-1, gsy+gsh-1);
1255 }
1256
1257 XDrawString(theDisp, popW, theGC, gsx+4, gsy+ASCENT+4,
1258 gsBuf+gsStPos, gsEnPos-gsStPos);
1259
1260 cpos = gsx+XTextWidth(mfinfo, &gsBuf[gsStPos], gsCurPos-gsStPos);
1261 XDrawLine(theDisp,popW,theGC, 4+cpos, gsy+3, 4+cpos, gsy+2+CHIGH+1);
1262 XDrawLine(theDisp,popW,theGC, 4+cpos, gsy+2+CHIGH+1, 6+cpos, gsy+2+CHIGH+3);
1263 XDrawLine(theDisp,popW,theGC, 4+cpos, gsy+2+CHIGH+1, 2+cpos, gsy+2+CHIGH+3);
1264 }
1265