1 /*
2  * xvctrl.c - Control box handling functions
3  *
4  * callable functions:
5  *
6  *   CreateCtrl(geom)       -  creates the ctrlW window.  Doesn't map it.
7  *   CtrlBox(vis)           -  random processing based on value of 'vis'
8  *                             maps/unmaps window, etc.
9  *   RedrawCtrl(x,y,w,h)    -  called by 'expose' events
10  *   ClickCtrl(x,y)
11  *   DrawCtrlStr()          -  called to redraw 'ISTR_INFO' string in ctrlW
12  *   ScrollToCurrent()      -  called when list selection is changed
13  *
14  *   LSCreate()             -  creates a listbox
15  *   LSRedraw()             -  redraws 'namelist' box
16  *   LSClick()              -  operates list box
17  *   LSChangeData()         -  like LSNewData(), but tries not to repos list
18  *   LSNewData()            -  called when strings or number of them change
19  *   LSKey()                -  called to handle page up/down, arrows
20  *
21  */
22 
23 #include "copyright.h"
24 
25 #include "xv.h"
26 
27 #include "bits/gray25"
28 #include "bits/gray50"
29 #include "bits/i_fifo"
30 #include "bits/i_chr"
31 #include "bits/i_dir"
32 #include "bits/i_blk"
33 #include "bits/i_lnk"
34 #include "bits/i_sock"
35 #include "bits/i_exe"
36 #include "bits/i_reg"
37 #include "bits/h_rotl"
38 #include "bits/h_rotr"
39 #include "bits/fliph"
40 #include "bits/flipv"
41 #include "bits/p10"
42 #include "bits/m10"
43 #include "bits/cut"
44 #include "bits/copy"
45 #include "bits/clear"
46 #include "bits/paste"
47 #include "bits/padimg"
48 #include "bits/annot"
49 #include "bits/uicon"
50 #include "bits/oicon1"
51 #include "bits/oicon2"
52 #ifdef REGSTR
53 #  define OMIT_ICON_BITS
54 #  include "bits/icon"
55 #endif
56 
57 #define CTRLWIDE 440               /* (fixed) size of control window */
58 #define CTRLHIGH 348 /* 379 */
59 
60 #define DBLCLKTIME 500             /* double-click speed in milliseconds */
61 
62 #define INACTIVE(lptr, item) ((lptr)->filetypes && (lptr)->dirsonly && \
63 			      (item) >= 0 && (item) < (lptr)->nstr && \
64 			      (lptr)->str[(item)][0] != C_DIR && \
65 			      (lptr)->str[(item)][0] != C_LNK)
66 
67 #define NLINES  11                 /* # of lines in list control (keep odd) */
68 
69 #define BUTTW   71                 /* keep odd for 'half' buttons to work   */
70 #define BUTTH   24
71 #define SBUTTH  21
72 
73 static int    ptop;                /* y-coord of top of button area in ctrlW */
74 
75 static Pixmap fifoPix, chrPix, dirPix, blkPix, lnkPix, sockPix, exePix, regPix;
76 static Pixmap rotlPix, rotrPix, fliphPix, flipvPix, p10Pix, m10Pix;
77 static Pixmap cutPix, copyPix, pastePix, clearPix, oiconPix, uiconPix;
78 static Pixmap padPix, annotPix;
79 
80 static XRectangle butrect;
81 
82 /* NOTE: make these string arrays match up with their respective #defines
83    in xv.h */
84 
85 
86 static const char *dispMList[] = { "Raw\tr",
87 				   "Dithered\td",
88 				   "Smooth\ts",
89 				   MBSEP,
90 				   "Read/Write Colors",
91 				   MBSEP,
92 				   "Normal Colors",
93 				   "Perfect Colors",
94 				   "Use Own Colormap",
95 				   "Use Std. Colormap" };
96 
97 static const char *rootMList[] = { "Window",
98 				   "Root: tiled",
99 				   "Root: integer tiled",
100 				   "Root: mirrored",
101 				   "Root: integer mirrored",
102 				   "Root: center tiled",
103 				   "Root: centered",
104 				   "Root: centered, warp",
105 				   "Root: centered, brick",
106 				   "Root: symmetrical tiled",
107 				   "Root: symmetrical mirrored",
108 				   "Root: upper left corner" };
109 
110 static const char *conv24MList[] = { "8-bit mode\t\2448",
111 				     "24-bit mode\t\2448",
112 				     MBSEP,
113 				     "Lock current mode",
114 				     MBSEP,
115 				     "Quick 24->8",
116 				     "Slow 24->8",
117 				     "Best 24->8" };
118 
119 static const char *algMList[] = { "Undo All\t\244u",
120 				  MBSEP,
121 				  "Blur...\t\244b",
122 				  "Sharpen...\t\244s",
123 				  "Edge Detect\t\244e",
124 				  "Emboss\t\244m",
125 				  "Oil Painting\t\244o",
126 				  "Blend\t\244B",
127 				  "Copy Rotate...\t\244t",
128 				  "Clear Rotate...\t\244T",
129 				  "Pixelize...\t\244p",
130 				  "Spread...\t\244S",
131 				  "DeSpeckle...\t\244k"};
132 
133 static const char *sizeMList[] = { "Normal\tn",
134 				   "Max Size\tm",
135 				   "Maxpect\tM",
136 				   "Double Size\t>",
137 				   "Half Size\t<",
138 				   "10% Larger\t.",
139 				   "10% Smaller\t,",
140 				   MBSEP,
141 				   "Set Size\tS",
142 				   "Re-Aspect\ta",
143 				   "4x3\t4",
144 				   "Int. Expand\tI" };
145 
146 static const char *windowMList[] = { "Visual Schnauzer\t^v",
147 				     "Color Editor\te",
148 				     "Image Info\ti",
149 				     "Image Comments\t^c",
150 				     "Text View\t^t",
151 				     MBSEP,
152 				     "About XV\t^a",
153 				     "XV Keyboard Help"};
154 
155 
156 
157 static void drawSel      PARM((LIST *, int));
158 static void RedrawNList  PARM((int, SCRL *));
159 static void ls3d         PARM((LIST *));
160 
161 
162 /***************************************************/
CreateCtrl(geom)163 void CreateCtrl(geom)
164      const char *geom;
165 {
166   int listh, topskip;
167   double skip;
168   XSetWindowAttributes xswa;
169   Pixmap oicon1Pix, oicon2Pix;
170 
171   ctrlW = CreateWindow("xv controls", "XVcontrols", geom,
172 		       CTRLWIDE, CTRLHIGH, infofg, infobg, 0);
173   if (!ctrlW) FatalError("can't create controls window!");
174 
175 #ifdef BACKING_STORE
176   xswa.backing_store = WhenMapped;
177   XChangeWindowAttributes(theDisp, ctrlW, CWBackingStore, &xswa);
178 #endif
179 
180   grayTile = XCreatePixmapFromBitmapData(theDisp, rootW, (char *) gray25_bits,
181 		   gray25_width, gray25_height, infofg, infobg, dispDEEP);
182 
183   dimStip  = MakePix1(ctrlW, gray50_bits, gray50_width, gray50_height);
184   fifoPix  = MakePix1(ctrlW, i_fifo_bits, i_fifo_width, i_fifo_height);
185   chrPix   = MakePix1(ctrlW, i_chr_bits,  i_chr_width,  i_chr_height);
186   dirPix   = MakePix1(ctrlW, i_dir_bits,  i_dir_width,  i_dir_height);
187   blkPix   = MakePix1(ctrlW, i_blk_bits,  i_blk_width,  i_blk_height);
188   lnkPix   = MakePix1(ctrlW, i_lnk_bits,  i_lnk_width,  i_lnk_height);
189   sockPix  = MakePix1(ctrlW, i_sock_bits, i_sock_width, i_sock_height);
190   exePix   = MakePix1(ctrlW, i_exe_bits,  i_exe_width,  i_exe_height);
191   regPix   = MakePix1(ctrlW, i_reg_bits,  i_reg_width,  i_reg_height);
192   rotlPix  = MakePix1(ctrlW, h_rotl_bits, h_rotl_width, h_rotl_height);
193   rotrPix  = MakePix1(ctrlW, h_rotr_bits, h_rotr_width, h_rotr_height);
194   fliphPix = MakePix1(ctrlW, fliph_bits,  fliph_width,  fliph_height);
195   flipvPix = MakePix1(ctrlW, flipv_bits,  flipv_width,  flipv_height);
196   p10Pix   = MakePix1(ctrlW, p10_bits,    p10_width,    p10_height);
197   m10Pix   = MakePix1(ctrlW, m10_bits,    m10_width,    m10_height);
198   cutPix   = MakePix1(ctrlW, cut_bits,    cut_width,    cut_height);
199   copyPix  = MakePix1(ctrlW, copy_bits,   copy_width,   copy_height);
200   pastePix = MakePix1(ctrlW, paste_bits,  paste_width,  paste_height);
201   clearPix = MakePix1(ctrlW, clear_bits,  clear_width,  clear_height);
202   uiconPix = MakePix1(ctrlW, uicon_bits,  uicon_width,  uicon_height);
203   padPix   = MakePix1(ctrlW, padimg_bits, padimg_width, padimg_height);
204   annotPix = MakePix1(ctrlW, annot_bits,  annot_width,  annot_height);
205 
206   /* make multi-plane oiconPix pixmap */
207   oiconPix = XCreatePixmap(theDisp,rootW,oicon1_width,oicon1_height,dispDEEP);
208   oicon1Pix = MakePix1(ctrlW, oicon1_bits,  oicon1_width,  oicon1_height);
209   oicon2Pix = MakePix1(ctrlW, oicon2_bits,  oicon2_width,  oicon2_height);
210 
211   if (!grayTile  || !dimStip  || !fifoPix   || !chrPix    || !dirPix    ||
212       !blkPix    || !lnkPix   || !regPix    || !rotlPix   || !fliphPix  ||
213       !flipvPix  || !p10Pix   || !m10Pix    || !cutPix    || !copyPix   ||
214       !pastePix  || !clearPix || !uiconPix  || !oiconPix  || !oicon1Pix ||
215       !oicon2Pix || !padPix   || !annotPix)
216     FatalError("unable to create all pixmaps in CreateCtrl()\n");
217 
218 
219   /* build multi-color XV pixmap */
220   XSetForeground(theDisp, theGC, infobg);
221   XFillRectangle(theDisp, oiconPix, theGC, 0,0,oicon1_width,oicon1_height);
222   XSetFillStyle(theDisp, theGC, FillStippled);
223   XSetStipple(theDisp, theGC, oicon1Pix);
224   XSetForeground(theDisp, theGC, (ctrlColor) ? locol : infofg);
225   XFillRectangle(theDisp, oiconPix, theGC, 0,0,oicon1_width,oicon1_height);
226   XSetStipple(theDisp, theGC, oicon2Pix);
227   XSetForeground(theDisp, theGC, (ctrlColor) ? infofg : infofg);
228   XFillRectangle(theDisp, oiconPix, theGC, 0,0,oicon1_width,oicon1_height);
229   XSetFillStyle(theDisp, theGC, FillSolid);
230   XFreePixmap(theDisp, oicon1Pix);
231   XFreePixmap(theDisp, oicon2Pix);
232 
233 
234 
235   if (ctrlColor) XSetWindowBackground(theDisp, ctrlW, locol);
236             else XSetWindowBackgroundPixmap(theDisp, ctrlW, grayTile);
237 
238   listh = LINEHIGH * NLINES;
239 
240   LSCreate(&nList, ctrlW, 5, 52, (CTRLWIDE-BUTTW-18),
241 	   LINEHIGH*NLINES, NLINES, dispnames, numnames,
242 	   infofg, infobg, hicol, locol, RedrawNList, 0, 0);
243   nList.selected = 0;  /* default to first name selected */
244 
245 
246 #define BCLS infofg, infobg, hicol, locol
247 
248   /* expressions for positioning right-side buttons */
249 
250   topskip = nList.y;
251   skip =  ((double) (nList.h - (CHIGH+5))) / 6.0;
252   if (skip > SBUTTH+8) {
253     skip = SBUTTH + 7;
254     topskip = nList.y + (nList.h - (6*skip + (CHIGH+5))) / 2;
255   }
256 
257 #define R_BW1 BUTTW
258 #define R_BX0 (CTRLWIDE - R_BW1 - 1 - 5)
259 #define R_BY0 (topskip)
260 #define R_BY1 (topskip + (int)(1*skip))
261 #define R_BY2 (topskip + (int)(2*skip))
262 #define R_BY3 (topskip + (int)(3*skip))
263 #define R_BY4 (topskip + (int)(4*skip))
264 #define R_BY5 (topskip + (int)(5*skip))
265 
266   BTCreate(&but[BNEXT],    ctrlW, R_BX0, R_BY0, R_BW1, SBUTTH, "Next",   BCLS);
267   BTCreate(&but[BPREV],    ctrlW, R_BX0, R_BY1, R_BW1, SBUTTH, "Prev",   BCLS);
268   BTCreate(&but[BLOAD],    ctrlW, R_BX0, R_BY2, R_BW1, SBUTTH, "Load",   BCLS);
269   BTCreate(&but[BSAVE],    ctrlW, R_BX0, R_BY3, R_BW1, SBUTTH, "Save",   BCLS);
270   BTCreate(&but[BPRINT],   ctrlW, R_BX0, R_BY4, R_BW1, SBUTTH, "Print",  BCLS);
271   BTCreate(&but[BDELETE],  ctrlW, R_BX0, R_BY5, R_BW1, SBUTTH, "Delete", BCLS);
272 
273 
274   /* expressions for positioning bottom buttons (6x2 array) */
275 
276 #define BXSPACE (BUTTW+1)
277 #define BYSPACE (BUTTH+1)
278 
279   ptop = CTRLHIGH - (2*BYSPACE + 5 + 4);
280 
281 #define BX0 ((CTRLWIDE - (BXSPACE*6))/2)
282 #define BX1 (BX0 + BXSPACE)
283 #define BX2 (BX0 + BXSPACE*2)
284 #define BX3 (BX0 + BXSPACE*3)
285 #define BX4 (BX0 + BXSPACE*4)
286 #define BX5 (BX0 + BXSPACE*5)
287 #define BY0 (ptop+5)
288 #define BY1 (BY0 + BYSPACE)
289 
290   butrect.x = BX0-1;  butrect.y = BY0-1;
291   butrect.width = 6*BXSPACE + 1;
292   butrect.height = 2*BYSPACE + 1;
293 
294   BTCreate(&but[BCOPY],  ctrlW,BX0,            BY0,BUTTW/2,BUTTH, "",    BCLS);
295   BTCreate(&but[BCUT],   ctrlW,BX0+BUTTW/2 + 1,BY0,BUTTW/2,BUTTH, "",    BCLS);
296   BTCreate(&but[BPASTE], ctrlW,BX1,            BY0,BUTTW/2,BUTTH, "",    BCLS);
297   BTCreate(&but[BCLEAR], ctrlW,BX1+BUTTW/2 + 1,BY0,BUTTW/2,BUTTH, "",    BCLS);
298   BTCreate(&but[BDN10],  ctrlW,BX2,            BY0,BUTTW/2,BUTTH, "",    BCLS);
299   BTCreate(&but[BUP10],  ctrlW,BX2+BUTTW/2 + 1,BY0,BUTTW/2,BUTTH, "",    BCLS);
300   BTCreate(&but[BROTL],  ctrlW,BX3,            BY0,BUTTW/2,BUTTH, "",    BCLS);
301   BTCreate(&but[BROTR],  ctrlW,BX3+BUTTW/2 + 1,BY0,BUTTW/2,BUTTH, "",    BCLS);
302   BTCreate(&but[BFLIPH], ctrlW,BX4,            BY0,BUTTW/2,BUTTH, "",    BCLS);
303   BTCreate(&but[BFLIPV], ctrlW,BX4+BUTTW/2 + 1,BY0,BUTTW/2,BUTTH, "",    BCLS);
304   BTCreate(&but[BGRAB],  ctrlW,BX5,            BY0,BUTTW,  BUTTH, "Grab",BCLS);
305 
306 
307   BTCreate(&but[BPAD],    ctrlW,BX0,          BY1,BUTTW/2,BUTTH,"",BCLS);
308   BTCreate(&but[BANNOT],  ctrlW,BX0+BUTTW/2+1,BY1,BUTTW/2,BUTTH,"",BCLS);
309 
310   BTCreate(&but[BCROP],   ctrlW,BX1,  BY1,BUTTW,BUTTH,"Crop",    BCLS);
311   BTCreate(&but[BUNCROP], ctrlW,BX2,  BY1,BUTTW,BUTTH,"UnCrop",  BCLS);
312   BTCreate(&but[BACROP],  ctrlW,BX3,  BY1,BUTTW,BUTTH,"AutoCrop",BCLS);
313   BTCreate(&but[BABOUT],  ctrlW,BX4,  BY1,BUTTW,BUTTH,"About XV",BCLS);
314   BTCreate(&but[BQUIT],   ctrlW,BX5,  BY1,BUTTW,BUTTH,"Quit",    BCLS);
315 
316   BTCreate(&but[BXV],     ctrlW,5,5, 100, (u_int) nList.y - 5 - 2 - 5,
317 	   "", BCLS);
318 
319   SetButtPix(&but[BCOPY],  copyPix,  copy_width,   copy_height);
320   SetButtPix(&but[BCUT],   cutPix,   cut_width,    cut_height);
321   SetButtPix(&but[BPASTE], pastePix, paste_width,  paste_height);
322   SetButtPix(&but[BCLEAR], clearPix, clear_width,  clear_height);
323   SetButtPix(&but[BUP10],  p10Pix,   p10_width,    p10_height);
324   SetButtPix(&but[BDN10],  m10Pix,   m10_width,    m10_height);
325   SetButtPix(&but[BROTL],  rotlPix,  h_rotl_width, h_rotl_height);
326   SetButtPix(&but[BROTR],  rotrPix,  h_rotr_width, h_rotr_height);
327   SetButtPix(&but[BFLIPH], fliphPix, fliph_width,  fliph_height);
328   SetButtPix(&but[BFLIPV], flipvPix, flipv_width,  flipv_height);
329   SetButtPix(&but[BPAD],   padPix,   padimg_width, padimg_height);
330   SetButtPix(&but[BANNOT], annotPix, annot_width,  annot_height);
331 
332 #ifdef REGSTR
333   if (ctrlColor) {
334     SetButtPix(&but[BXV], oiconPix, oicon1_width,  oicon1_height);
335     but[BXV].colorpix = 1;
336   }
337   else SetButtPix(&but[BXV], iconPix, icon_width,  icon_height);
338 #else
339   SetButtPix(&but[BXV], uiconPix, uicon_width,  uicon_height);
340 #endif
341 
342   XMapSubwindows(theDisp, ctrlW);
343 
344 
345   /* have to create menu buttons after XMapSubWindows, as we *don't* want
346      the popup menus mapped */
347 
348   MBCreate(&dispMB,   ctrlW, CTRLWIDE - 8 - 112 - 2*(112+2), 5,112,19,
349 	   "Display",    dispMList,   DMB_MAX,    BCLS);
350   MBCreate(&conv24MB, ctrlW, CTRLWIDE - 8 - 112 - (112+2),   5,112,19,
351 	   "24/8 Bit",   conv24MList, CONV24_MAX, BCLS);
352   MBCreate(&algMB,    ctrlW, CTRLWIDE - 8 - 112,             5,112,19,
353 	   "Algorithms", algMList,    ALG_MAX,    BCLS);
354 
355   MBCreate(&rootMB,   ctrlW, CTRLWIDE - 8 - 112 - 2*(112+2), 5+21,112,19,
356 	   "Root",       rootMList,   RMB_MAX,    BCLS);
357   MBCreate(&windowMB, ctrlW, CTRLWIDE - 8 - 112 - (112+2),   5+21,112,19,
358 	   "Windows",    windowMList, WMB_MAX,    BCLS);
359   MBCreate(&sizeMB,   ctrlW, CTRLWIDE - 8 - 112,             5+21,112,19,
360 	   "Image Size", sizeMList,   SZMB_MAX,   BCLS);
361 
362 
363 
364 #undef BCLS
365 
366 
367   /* set up initial state for various controls */
368 
369   but[BXV].w = dispMB.x - 5 - but[BXV].x;
370 
371   dispMB.flags[DMB_COLRW] = (allocMode == AM_READWRITE);
372   dispMB.flags[colorMapMode + DMB_COLNORM - CM_NORMAL] = 1;
373 
374   conv24MB.flags[conv24] = 1;
375 
376   if (!useroot) dispMode = RMB_WINDOW;
377            else dispMode = rootMode + (RMB_ROOT - RM_NORMAL);
378   rootMB.flags[dispMode] = 1;
379 
380   windowMB.dim[WMB_TEXTVIEW] = (numnames<1);
381 
382   BTSetActive(&but[BDELETE], (numnames>=1));
383 }
384 
385 /***************************************************/
SetButtPix(bp,pix,w,h)386 void SetButtPix(bp, pix, w,h)
387      BUTT *bp;
388      Pixmap pix;
389      int    w,h;
390 {
391   if (!bp) return;
392   bp->pix = pix;  bp->pw = w;  bp->ph = h;
393 }
394 
395 
396 /***************************************************/
MakePix1(win,bits,w,h)397 Pixmap MakePix1(win, bits, w, h)
398      Window win;
399      byte *bits;
400      int   w,h;
401 {
402   return XCreatePixmapFromBitmapData(theDisp, win, (char *) bits,
403 				     (u_int) w, (u_int) h, 1L,0L,1);
404 }
405 
406 
407 /***************************************************/
CtrlBox(vis)408 void CtrlBox(vis)
409 int vis;
410 {
411   if (vis) XMapRaised(theDisp, ctrlW);
412   else     XUnmapWindow(theDisp, ctrlW);
413 
414   ctrlUp = vis;
415 }
416 
417 
418 /***************************************************/
RedrawCtrl(x,y,w,h)419 void RedrawCtrl(x,y,w,h)
420 int x,y,w,h;
421 {
422   int i;
423 
424   RANGE(w, 0, CTRLWIDE);
425   RANGE(h, 0, CTRLHIGH);
426 
427 #ifdef CLIPRECT
428   xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
429   XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
430 #endif
431 
432   DrawCtrlNumFiles();
433 
434   XSetForeground(theDisp,theGC,infofg);
435   XDrawRectangles(theDisp, ctrlW, theGC, &butrect, 1);
436 
437   for (i=0; i<NBUTTS; i++)
438     BTRedraw(&but[i]);
439 
440   MBRedraw(&dispMB);
441   MBRedraw(&conv24MB);
442   MBRedraw(&algMB);
443   MBRedraw(&rootMB);
444   MBRedraw(&windowMB);
445   MBRedraw(&sizeMB);
446 
447   DrawCtrlStr();
448 
449 #ifdef CLIPRECT
450   XSetClipMask(theDisp, theGC, None);
451 #endif
452 }
453 
454 
455 /***************************************************/
DrawCtrlNumFiles()456 void DrawCtrlNumFiles()
457 {
458   int x,y,w;
459   char foo[40];
460 
461   x  = but[BNEXT].x;
462   y  = nList.y + nList.h - (CHIGH+5);
463   w  = but[BNEXT].w;
464 
465   XSetForeground(theDisp, theGC, infofg);
466   XSetBackground(theDisp, theGC, infobg);
467 
468   sprintf(foo, "%d file%s", numnames, (numnames==1) ? "" : "s");
469 
470   XSetForeground(theDisp, theGC, infobg);
471   XFillRectangle(theDisp,ctrlW, theGC, x+1,y+1, (u_int) w-1, (u_int) CHIGH+5);
472 
473   XSetForeground(theDisp,theGC,infofg);
474   XDrawRectangle(theDisp,ctrlW, theGC, x,y,     (u_int) w,   (u_int) CHIGH+6);
475 
476   Draw3dRect(ctrlW, x+1,y+1,                    (u_int) w-2, (u_int) CHIGH+4,
477 	     R3D_IN, 2, hicol, locol, infobg);
478 
479   XSetForeground(theDisp,theGC,infofg);
480   CenterString(ctrlW, x+w/2, y+(CHIGH+6)/2, foo);
481 }
482 
483 
484 /***************************************************/
DrawCtrlStr()485 void DrawCtrlStr()
486 {
487   int   y;
488   char *st,*st1;
489 
490   y = ptop - (CHIGH + 4)*2 - 2;
491   st  = GetISTR(ISTR_INFO);
492   st1 = GetISTR(ISTR_WARNING);
493 
494   XSetForeground(theDisp, theGC, infobg);
495   XFillRectangle(theDisp, ctrlW, theGC, 0, y+1,
496 		 CTRLWIDE, (u_int)((CHIGH+4)*2+1));
497 
498   XSetForeground(theDisp, theGC, infofg);
499   XDrawLine(theDisp, ctrlW, theGC, 0, y,   CTRLWIDE, y);
500   XDrawLine(theDisp, ctrlW, theGC, 0, y+CHIGH+4, CTRLWIDE, y+CHIGH+4);
501   XDrawLine(theDisp, ctrlW, theGC, 0, y+(CHIGH+4)*2, CTRLWIDE, y+(CHIGH+4)*2);
502 
503   if (ctrlColor) {
504     XSetForeground(theDisp, theGC, locol);
505     XDrawLine(theDisp, ctrlW, theGC, 0, y+1,   CTRLWIDE, y+1);
506     XDrawLine(theDisp, ctrlW, theGC, 0, y+CHIGH+5, CTRLWIDE, y+CHIGH+5);
507     XDrawLine(theDisp, ctrlW, theGC, 0, y+(CHIGH+4)*2+1,
508 	      CTRLWIDE, y+(CHIGH+4)*2+1);
509   }
510 
511   if (ctrlColor) XSetForeground(theDisp, theGC, hicol);
512   XDrawLine(theDisp, ctrlW, theGC, 0, y+2, CTRLWIDE, y+2);
513   XDrawLine(theDisp, ctrlW, theGC, 0, y+CHIGH+6, CTRLWIDE, y+CHIGH+6);
514   if (ctrlColor) XSetForeground(theDisp, theGC, infobg);
515   XDrawLine(theDisp, ctrlW, theGC, 0, ptop, CTRLWIDE, ptop);
516 
517   XSetForeground(theDisp, theGC, infofg);
518   DrawString(ctrlW, 10, y+ASCENT+3,       st);
519   DrawString(ctrlW, 10, y+ASCENT+CHIGH+7, st1);
520 }
521 
522 
523 /***************************************************/
ClickCtrl(x,y)524 int ClickCtrl(x,y)
525 int x,y;
526 {
527   BUTT *bp;
528   int   i;
529 
530   for (i=0; i<NBUTTS; i++) {
531     bp = &but[i];
532     if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
533   }
534 
535   if (i<NBUTTS) {                   /* found one */
536     if (BTTrack(bp)) return (i);    /* and it was clicked */
537   }
538 
539   return -1;
540 }
541 
542 
543 
544 /***************************************************/
ScrollToCurrent(lst)545 void ScrollToCurrent(lst)
546 LIST *lst;
547 {
548   /* called when selected item on list is changed.  Makes the selected
549      item visible.  If it already is, nothing happens.  Otherwise, it
550      attempts to scroll so that the selection appears in the middle of
551      the list window */
552 
553   int halfway;
554 
555   if (lst->selected < 0) return;  /* no selection, do nothing */
556 
557   if (lst->selected > lst->scrl.val &&
558       lst->selected <  lst->scrl.val + lst->nlines-1) LSRedraw(lst, 0);
559   else {
560     halfway = (lst->nlines)/2;   /* offset to the halfway pt. of the list */
561     if (!SCSetVal(&lst->scrl, lst->selected - halfway)) LSRedraw(lst, 0);
562   }
563 }
564 
565 
566 /***************************************************/
RedrawNList(delta,sptr)567 static void RedrawNList(delta, sptr)
568      int delta;
569      SCRL *sptr;
570 {
571   LSRedraw(&nList, delta);
572 }
573 
574 
575 
576 
577 /***************** LIST STUFF *********************/
578 
579 /***************************************************/
LSCreate(lp,win,x,y,w,h,nlines,strlist,nstr,fg,bg,hi,lo,fptr,typ,donly)580 void LSCreate(lp, win, x, y, w, h, nlines, strlist, nstr, fg, bg, hi, lo,
581 	      fptr, typ, donly)
582 LIST         *lp;
583 Window        win;
584 int           x,y,w,h,nlines,nstr,typ,donly;
585 unsigned long fg, bg, hi, lo;
586 char        **strlist;    /* a pointer to a list of strings */
587 
588 void        (*fptr)PARM((int,SCRL *));
589 
590 {
591   if (ctrlColor) h += 4;
592 
593   lp->win = XCreateSimpleWindow(theDisp,win,x,y,(u_int) w, (u_int) h,1,fg,bg);
594   if (!lp->win) FatalError("can't create list window!");
595 
596   lp->x = x;    lp->y = y;
597   lp->w = w;    lp->h = h;
598   lp->fg = fg;  lp->bg = bg;
599   lp->hi = hi;  lp->lo = lo;
600   lp->str      = strlist;
601   lp->nstr     = nstr;
602   lp->selected = -1;   /* no initial selection */
603   lp->nlines   = nlines;
604   lp->filetypes= typ;
605   lp->dirsonly = donly;
606 
607   XSelectInput(theDisp, lp->win, ExposureMask | ButtonPressMask);
608 
609   SCCreate(&lp->scrl, lp->win, w-20, -1, 1, h, 0,
610 	   nstr-nlines, 0, nlines-1, fg, bg, hi, lo, fptr);
611 
612   XMapSubwindows(theDisp, lp->win);
613 }
614 
615 
616 
617 /***************************************************/
LSChangeData(lp,strlist,nstr)618 void LSChangeData(lp, strlist, nstr)
619 LIST         *lp;
620 char        **strlist;
621 int           nstr;
622 {
623   /* tries to keep list selection and scrollbar in same place, if possible */
624 
625   lp->str = strlist;
626   lp->nstr = nstr;
627   if (lp->selected >= nstr) lp->selected = -1;
628 
629   RANGE(lp->scrl.val, 0, nstr - lp->nlines);
630   SCSetRange(&lp->scrl, 0, nstr - lp->nlines, lp->scrl.val, lp->nlines-1);
631 }
632 
633 
634 /***************************************************/
LSNewData(lp,strlist,nstr)635 void LSNewData(lp, strlist, nstr)
636 LIST         *lp;
637 char        **strlist;
638 int           nstr;
639 {
640   lp->str = strlist;
641   lp->nstr = nstr;
642   lp->selected = -1;   /* no initial selection */
643   SCSetRange(&lp->scrl, 0, nstr - lp->nlines, 0, lp->nlines-1);
644 }
645 
646 
647 /***************************************************/
ls3d(lp)648 static void ls3d(lp)
649 LIST *lp;
650 {
651   /* redraws lists 3d-effect, which can be trounced by drawSel() */
652   Draw3dRect(lp->win, 0, 0, lp->w-1, lp->h-1, R3D_IN, 2,
653 	     lp->hi, lp->lo, lp->bg);
654 }
655 
656 
657 /***************************************************/
drawSel(lp,j)658 static void drawSel(lp,j)
659 LIST *lp;
660 int j;
661 {
662   int i, inactive, x0,y0,wide, selected;
663   unsigned long fg, bg;
664 
665   x0 = 0;  y0 = 0;  wide = lp->w;
666   if (ctrlColor) { x0 = y0 = 2;  wide -= 6; }
667 
668   inactive = INACTIVE(lp,j);
669 
670   i = j - lp->scrl.val;
671   if (i<0 || i>=lp->nlines) return;  /* off screen */
672 
673   selected = (j == lp->selected && !inactive && j<lp->nstr);
674   if (selected) {  /* inverse colors */
675     if (ctrlColor) { fg = lp->fg;  bg = lp->lo; }
676               else { fg = lp->bg;  bg = lp->fg; }
677   }
678   else { fg = lp->fg;  bg = lp->bg; }
679 
680   XSetForeground(theDisp, theGC, bg);
681   XFillRectangle(theDisp, lp->win, theGC, x0, y0+i*LINEHIGH,
682 		 (u_int) wide+1, (u_int) LINEHIGH);
683 
684   if (j>=0 && j<lp->nstr) {   /* only draw string if valid */
685     XSetForeground(theDisp, theGC, fg);
686     XSetBackground(theDisp, theGC, bg);
687 
688     if (!lp->filetypes)
689       DrawString(lp->win, x0+3, y0+i*LINEHIGH + ASCENT + 1, lp->str[j]);
690     else {
691       int ypos = y0 + i*LINEHIGH + (LINEHIGH - i_fifo_height)/2;
692 
693       if (lp->str[j][0] == C_FIFO)
694 	XCopyPlane(theDisp, fifoPix, lp->win, theGC, 0, 0,
695 		   i_fifo_width, i_fifo_height, x0+3, ypos, 1L);
696 
697       else if (lp->str[j][0] == C_CHR)
698 	XCopyPlane(theDisp, chrPix, lp->win, theGC, 0, 0,
699 		   i_chr_width, i_chr_height, x0+3, ypos, 1L);
700 
701       else if (lp->str[j][0] == C_DIR)
702 	XCopyPlane(theDisp, dirPix, lp->win, theGC, 0, 0,
703 		   i_dir_width, i_dir_height, x0+3, ypos, 1L);
704 
705       else if (lp->str[j][0] == C_BLK)
706 	XCopyPlane(theDisp, blkPix, lp->win, theGC, 0, 0,
707 		   i_blk_width, i_blk_height, x0+3, ypos, 1L);
708 
709       else if (lp->str[j][0] == C_LNK)
710 	XCopyPlane(theDisp, lnkPix, lp->win, theGC, 0, 0,
711 		   i_lnk_width, i_lnk_height, x0+3, ypos, 1L);
712 
713       else if (lp->str[j][0] == C_SOCK)
714 	XCopyPlane(theDisp, sockPix, lp->win, theGC, 0, 0,
715 		   i_sock_width, i_sock_height, x0+3, ypos, 1L);
716 
717       else if (lp->str[j][0] == C_EXE)
718 	XCopyPlane(theDisp, exePix, lp->win, theGC, 0, 0,
719 		   i_exe_width, i_exe_height, x0+3, ypos, 1L);
720 
721       else  /* lp->str[j][0] == C_REG */
722 	XCopyPlane(theDisp, regPix, lp->win, theGC, 0, 0,
723 		   i_reg_width, i_reg_height, x0+3, ypos, 1L);
724 
725 
726       DrawString(lp->win, x0+3 + i_fifo_width + 3,
727 		  y0+i*LINEHIGH + ASCENT + 1,
728 		  lp->str[j]+1);
729     }
730   }
731 }
732 
733 
734 /***************************************************/
LSRedraw(lp,delta)735 void LSRedraw(lp, delta)
736 LIST *lp;
737 int   delta;
738 {
739   int  i;
740 
741   for (i = lp->scrl.val; i < lp->scrl.val + lp->nlines; i++)
742     drawSel(lp,i);
743   ls3d(lp);
744 }
745 
746 
747 /***************************************************/
LSClick(lp,ev)748 int LSClick(lp,ev)
749 LIST *lp;
750 XButtonEvent *ev;
751 {
752   /* returns '-1' normally.  returns 0 -> numnames-1 for a goto */
753 
754   Window       rW, cW;
755   int          rx, ry, x, y, sel, oldsel, y0, high;
756   unsigned int mask;
757   static Time  lasttime=0;
758   static int   lastsel = -1;
759 
760   y0   = (ctrlColor) ? 2 : 0;
761   high = (ctrlColor) ? lp->h - 4 : lp->h;
762 
763   x = ev->x;  y = ev->y;
764   sel = lp->scrl.val + (y-y0)/LINEHIGH;
765   if (sel >= lp->nstr) sel = lp->selected;
766 
767   /* see if it's a double click */
768   if (ev->time - lasttime < DBLCLKTIME && sel==lastsel
769       && (lp->scrl.val + (y-y0)/LINEHIGH) < lp->nstr
770       && !INACTIVE(lp,sel)) {
771     return (sel);
772   }
773 
774   lasttime = ev->time;  lastsel = sel;
775 
776   /* if not clicked on selected, turn off selected and select new one */
777   if (sel != lp->selected) {
778     oldsel = lp->selected;
779     lp->selected = sel;
780     drawSel(lp,sel);  drawSel(lp,oldsel);
781     ls3d(lp);
782     XFlush(theDisp);
783   }
784 
785   while (XQueryPointer(theDisp,lp->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
786     if (!(mask & Button1Mask)) break;    /* button released */
787 
788     if (y<y0) { /* scroll up in list */
789       if (lp->scrl.val > lp->scrl.min) {
790 	lp->selected = lp->scrl.val - 1;
791 	SCSetVal(&lp->scrl, lp->scrl.val - 1);
792 	Timer(100);
793       }
794     }
795 
796     else if (y>high) { /* scroll down in list */
797       if (lp->scrl.val < lp->scrl.max) {
798 	lp->selected = lp->scrl.val + lp->nlines;
799 	if (lp->selected >= lp->nstr) lp->selected = lp->nstr - 1;
800 	SCSetVal(&lp->scrl, lp->scrl.val + 1);
801 	Timer(100);
802       }
803     }
804 
805     else {
806       sel = lp->scrl.val + (y-y0)/LINEHIGH;
807       if (sel >= lp->nstr) sel = lp->nstr - 1;
808 
809       if (sel != lp->selected && sel >= lp->scrl.val &&
810 	  sel < lp->scrl.val + lp->nlines) {
811 	/* dragged to another on current page */
812 	oldsel = lp->selected;
813 	lp->selected = sel;
814 	drawSel(lp, sel);  drawSel(lp, oldsel);
815 	ls3d(lp);
816 	XFlush(theDisp);
817       }
818     }
819   }
820 
821   return(-1);
822 }
823 
824 
825 
826 /***************************************************/
LSKey(lp,key)827 void LSKey(lp, key)
828      LIST         *lp;
829      int           key;
830 {
831   if      (key==LS_PAGEUP)   SCSetVal(&lp->scrl,lp->scrl.val - (lp->nlines-1));
832   else if (key==LS_PAGEDOWN) SCSetVal(&lp->scrl,lp->scrl.val + (lp->nlines-1));
833   else if (key==LS_HOME)     SCSetVal(&lp->scrl,lp->scrl.min);
834   else if (key==LS_END)      SCSetVal(&lp->scrl,lp->scrl.max);
835 
836   else if (key==LS_LINEUP)   {
837     /* if the selected item visible, but not the top line */
838     if (lp->selected > lp->scrl.val &&
839 	lp->selected <= lp->scrl.val + lp->nlines - 1) {
840       /* then just move it */
841       lp->selected--;
842       drawSel(lp, lp->selected);  drawSel(lp, lp->selected+1);
843       ls3d(lp);
844     }
845 
846     /* if it's the top line... */
847     else if (lp->selected == lp->scrl.val) {
848       if (lp->selected > 0) {
849 	lp->selected--;
850 	SCSetVal(&lp->scrl, lp->selected);
851       }
852     }
853 
854     /* if it's not visible, put it on the bottom line */
855     else {
856       lp->selected = lp->scrl.val + lp->nlines - 1;
857       if (lp->selected >= lp->nstr) lp->selected = lp->nstr - 1;
858       drawSel(lp, lp->selected);
859       ls3d(lp);
860     }
861   }
862 
863   else if (key==LS_LINEDOWN)   {
864     /* if the selected item visible, but not the bottom line */
865     if (lp->selected >= lp->scrl.val &&
866 	lp->selected < lp->scrl.val + lp->nlines - 1) {
867       if (lp->selected < lp->nstr-1) {
868 	/* then just move it */
869 	lp->selected++;
870 	drawSel(lp, lp->selected);  drawSel(lp, lp->selected-1);
871 	ls3d(lp);
872       }
873     }
874 
875     /* if it's the bottom line... */
876     else if (lp->selected == lp->scrl.val + lp->nlines - 1) {
877       if (lp->selected < lp->nstr-1) {
878 	lp->selected++;
879 	SCSetVal(&lp->scrl, lp->scrl.val+1);
880       }
881     }
882 
883     /* if it's not visible, put it on the top line */
884     else {
885       lp->selected = lp->scrl.val;
886       drawSel(lp, lp->selected);
887       ls3d(lp);
888     }
889   }
890 }
891 
892