1 /*
2  * xvscrl.c - Scroll Bar handling functions
3  *
4  * callable functions:
5  *
6  *   SCCreate()   -  creates the Scroll Bar window.
7  *   SCChange()   -  resize/repositions the Scroll Bar window.
8  *   SCSetRange() -  sets min/max/current values of control
9  *   SCSetVal()   -  sets value of control
10  *   SCRedraw()   -  redraws scroll bar
11  *   SCTrack()    -  called when clicked.  Operates control 'til mouseup
12  */
13 
14 #include "copyright.h"
15 
16 #include "xv.h"
17 
18 #include "bits/up"
19 #include "bits/down"
20 #include "bits/up1"
21 #include "bits/down1"
22 #include "bits/uph"
23 #include "bits/downh"
24 #include "bits/uph1"
25 #include "bits/downh1"
26 #include "bits/scrlgray"
27 
28 
29 static Pixmap upPix,  downPix;   /* up/down arrows */
30 static Pixmap up1Pix, down1Pix;  /* up/down arrows (lit up) */
31 static Pixmap uphPix, downhPix;  /* up/down arrows, for horizontal scrl */
32 static Pixmap uph1Pix,downh1Pix; /* up/down arrows, horizontal (lit up) */
33 static Pixmap sgray;             /* gray stipple for lit scrollbar */
34 static int    pixmaps_built=0;   /* true if pixmaps created already */
35 
36 
37 /* scroll regions */
38 #define UPLINE 0
39 #define UPPAGE 1
40 #define DNLINE 2
41 #define DNPAGE 3
42 #define THUMB  4
43 
44 #define SCRLWAIT 80   /* milliseconds to wait between scrolls */
45 
46 /* local functions */
47 static int  whereInScrl PARM((SCRL *, int, int));
48 static void drawArrow   PARM((SCRL *, int));
49 static void drawThumb   PARM((SCRL *));
50 
51 
52 /***************************************************/
SCCreate(sp,parent,x,y,vert,len,minv,maxv,curv,page,fg,bg,hi,lo,func)53 void SCCreate(sp, parent, x, y, vert, len, minv, maxv, curv, page,
54 	          fg, bg, hi, lo, func)
55 SCRL         *sp;
56 Window        parent;
57 int           x,y,vert,len,minv,maxv,curv,page;
58 unsigned long fg,bg,hi,lo;
59 
60 void          (*func)PARM((int, SCRL *));
61 {
62 
63 
64   if (!pixmaps_built) {
65     upPix    = MakePix1(parent, up_bits,     up_width,     up_height);
66     downPix  = MakePix1(parent, down_bits,   down_width,   down_height);
67     up1Pix   = MakePix1(parent, up1_bits,    up1_width,    up1_height);
68     down1Pix = MakePix1(parent, down1_bits,  down1_width,  down1_height);
69 
70     uphPix   = MakePix1(parent, uph_bits,    uph_width,    uph_height);
71     downhPix = MakePix1(parent, downh_bits,  downh_width,  downh_height);
72     uph1Pix  = MakePix1(parent, uph1_bits,   uph1_width,   uph1_height);
73     downh1Pix= MakePix1(parent, downh1_bits, downh1_width, downh1_height);
74 
75     sgray    = XCreatePixmapFromBitmapData(theDisp, parent,
76 		(char *) scrlgray_bits, scrlgray_width, scrlgray_height,
77 					   fg,bg,dispDEEP);
78   }
79 
80   sp->x    = x;
81   sp->y    = y;
82 
83   sp->vert = vert;
84   sp->len  = len;
85   sp->fg   = fg;
86   sp->bg   = bg;
87   sp->hi   = hi;
88   sp->lo   = lo;
89   sp->uplit = sp->dnlit = 0;
90   sp->tsize  =  19;
91 
92   if (vert) {
93     sp->win = XCreateSimpleWindow(theDisp,parent,x,y,
94 				  (u_int) sp->tsize, (u_int) len,1,fg,bg);
95     sp->w = sp->tsize;
96     sp->h = len;
97   }
98   else {
99     sp->win = XCreateSimpleWindow(theDisp,parent,x,y,
100 				  (u_int) len, (u_int) sp->tsize,1,fg,bg);
101     sp->w = len;
102     sp->h = sp->tsize;
103   }
104 
105 
106   if (!sp->win) FatalError("can't create scrollbar window");
107 
108   sp->tmin   =  sp->tsize+1;
109   sp->tmax   =  len - (sp->tsize+1) - sp->tsize;
110 
111   sp->drawobj = func;
112 
113   SCSetRange(sp, minv, maxv, curv, page);
114   XSelectInput(theDisp, sp->win, ExposureMask | ButtonPressMask);
115 }
116 
117 
118 /***************************************************/
SCChange(sp,x,y,vert,len,minv,maxv,curv,page)119 void SCChange(sp, x, y, vert, len, minv, maxv, curv, page)
120 SCRL         *sp;
121 int           x,y,vert,len,minv,maxv,curv,page;
122 {
123   sp->vert = vert;
124   sp->len  = len;
125   sp->uplit = sp->dnlit = 0;
126 
127   if (vert) XMoveResizeWindow(theDisp, sp->win, x,y,
128 			      (u_int) sp->tsize,(u_int) len);
129   else      XMoveResizeWindow(theDisp, sp->win, x,y,
130 			      (u_int) len, (u_int) sp->tsize);
131 
132   sp->tmin   =  sp->tsize+1;
133   sp->tmax   =  len - (sp->tsize+1) - sp->tsize;
134 
135   SCSetRange(sp, minv, maxv, curv, page);
136 }
137 
138 
139 /***************************************************/
SCSetRange(sp,minv,maxv,curv,page)140 void SCSetRange(sp, minv, maxv, curv, page)
141      SCRL *sp;
142      int   minv, maxv, curv, page;
143 {
144   if (maxv<minv) maxv=minv;
145   sp->min = minv;    sp->max = maxv;    sp->page = page;
146   sp->active =  (minv < maxv);
147 
148   /* adjust scroll bar background */
149   if (sp->active) {
150     if (ctrlColor) XSetWindowBackground(theDisp, sp->win, sp->lo);
151               else XSetWindowBackgroundPixmap(theDisp, sp->win, sgray);
152   }
153   else XSetWindowBackground(theDisp, sp->win, sp->bg);
154 
155   sp->val = -99999;  /* force redraw */
156   SCSetVal(sp, curv);
157 }
158 
159 
160 /***************************************************/
SCSetVal(sp,curv)161 int SCSetVal(sp, curv)
162 SCRL *sp;
163 int   curv;
164 {
165   /* returns '0' if no redraw was done */
166   int oldval;
167 
168   RANGE(curv, sp->min, sp->max);   /* make sure curv is in-range */
169 
170   if (sp->val == curv) return 0;
171 
172   oldval = sp->val;
173   if (oldval == -99999) oldval = curv;   /* ignore kludge */
174 
175   sp->val = curv;
176 
177   if (sp->active)
178     sp->tpos = sp->tmin + ((sp->tmax - sp->tmin)*(curv - sp->min))
179                / (sp->max - sp->min);
180 
181   drawThumb(sp);
182   (sp->drawobj)(curv-oldval, sp);   /* redraw what the scrlbar controls */
183 
184   XFlush(theDisp);
185   return 1;
186 }
187 
188 
189 /***************************************************/
SCRedraw(sp)190 void SCRedraw(sp)
191 SCRL *sp;
192 {
193   XSetForeground(theDisp, theGC, sp->fg);
194   XSetBackground(theDisp, theGC, sp->bg);
195 
196   XClearWindow(theDisp, sp->win);
197 
198   drawArrow(sp,UPLINE);      /* draw up/down arrows */
199   drawArrow(sp,DNLINE);
200 
201   XSetForeground(theDisp, theGC, sp->fg);
202 
203   if (sp->vert) {
204     XDrawLine(theDisp, sp->win, theGC, 0, sp->tsize, sp->tsize, sp->tsize);
205     XDrawLine(theDisp, sp->win, theGC, 0, sp->len-sp->tsize-1,
206 	      sp->tsize, sp->len-sp->tsize-1);
207   }
208   else {                       /* horizontal version */
209     XDrawLine(theDisp, sp->win, theGC, sp->tsize, 0, sp->tsize, sp->tsize);
210     XDrawLine(theDisp, sp->win, theGC, sp->len - sp->tsize-1, 0,
211 	      sp->len - sp->tsize-1, sp->tsize);
212   }
213 
214   drawThumb(sp);
215 }
216 
217 
218 
219 /***************************************************/
drawArrow(sp,arr)220 static void drawArrow(sp,arr)
221 SCRL *sp;
222 int arr;
223 {
224   Pixmap butpix;
225 
226   if (arr == UPLINE) {
227     XSetForeground(theDisp, theGC, sp->bg);
228     XFillRectangle(theDisp, sp->win, theGC, 0, 0,
229 		   (u_int) sp->tsize, (u_int) sp->tsize);
230 
231     if (sp->vert) butpix = (sp->uplit) ? up1Pix  : upPix;
232              else butpix = (sp->uplit) ? uph1Pix : uphPix;
233 
234     XSetForeground(theDisp, theGC, sp->fg);
235     XSetBackground(theDisp, theGC, sp->bg);
236     XCopyPlane(theDisp, butpix, sp->win, theGC, 0, 0, up_width,up_height,
237 	       3,3, 1L);
238     Draw3dRect(sp->win, 0,0, (u_int) sp->tsize-1, (u_int) sp->tsize-1,
239 	       (sp->uplit) ? R3D_IN : R3D_OUT, 2, sp->hi, sp->lo, sp->bg);
240   }
241 
242   else if (arr == DNLINE) {
243     if (sp->vert) {
244       XSetForeground(theDisp, theGC, sp->bg);
245       XFillRectangle(theDisp, sp->win, theGC, 0, sp->len - sp->tsize,
246 		     (u_int) sp->tsize, (u_int) sp->tsize);
247       butpix = (sp->dnlit) ? down1Pix : downPix;
248 
249       XSetForeground(theDisp, theGC, sp->fg);
250       XSetBackground(theDisp, theGC, sp->bg);
251       XCopyPlane(theDisp, butpix, sp->win, theGC, 0, 0, up_width,up_height,
252 		 3, sp->len - 3 - up_height, 1L);
253 
254       Draw3dRect(sp->win, 0, sp->len - sp->tsize,
255 		 (u_int) sp->tsize-1, (u_int) sp->tsize-1,
256 		 (sp->dnlit) ? R3D_IN : R3D_OUT, 2, sp->hi, sp->lo, sp->bg);
257     }
258 
259     else {     /* horizontal scroll bar */
260       XSetForeground(theDisp, theGC, sp->bg);
261       XFillRectangle(theDisp, sp->win, theGC, sp->len - sp->tsize, 0,
262 		     (u_int) sp->tsize, (u_int) sp->tsize);
263       butpix = (sp->dnlit) ? downh1Pix : downhPix;
264 
265       XSetForeground(theDisp, theGC, sp->fg);
266       XSetBackground(theDisp, theGC, sp->bg);
267       XCopyPlane(theDisp, butpix, sp->win, theGC, 0, 0, up_width,up_height,
268 		 sp->len - 3 - up_width, 3, 1L);
269 
270       Draw3dRect(sp->win, sp->len - sp->tsize, 0,
271 		 (u_int) sp->tsize-1, (u_int) sp->tsize-1,
272 		 (sp->dnlit) ? R3D_IN : R3D_OUT, 2, sp->hi, sp->lo, sp->bg);
273     }
274   }
275 
276   XFlush(theDisp);
277 }
278 
279 
280 /***************************************************/
drawThumb(sp)281 static void drawThumb(sp)
282 SCRL *sp;
283 {
284   if (sp->vert) {
285     /* clear out thumb area with background color */
286     XClearArea(theDisp, sp->win, 0, sp->tsize+1, (u_int) sp->tsize,
287 	       (u_int) ((sp->len-sp->tsize-1)-(sp->tsize+1)), False);
288 
289     if (sp->active) {  /* a thumb is necessary */
290 
291       XSetForeground(theDisp, theGC, sp->bg);
292       XFillRectangle(theDisp, sp->win, theGC, 1, sp->tpos+1,
293 		     (u_int) (sp->tsize-2), (u_int) (sp->tsize-2));
294 
295       XSetForeground(theDisp, theGC, sp->fg);
296       XDrawRectangle(theDisp, sp->win, theGC, 0, sp->tpos,
297 		     (u_int) (sp->tsize-1), (u_int) (sp->tsize-1));
298 
299       XDrawLine(theDisp, sp->win, theGC, 9-3, sp->tpos+6, 9+3, sp->tpos+6);
300       XDrawLine(theDisp, sp->win, theGC, 9-3, sp->tpos+8, 9+3, sp->tpos+8);
301       XDrawLine(theDisp, sp->win, theGC, 9-3, sp->tpos+10,9+3, sp->tpos+10);
302       XDrawLine(theDisp, sp->win, theGC, 9-3, sp->tpos+12,9+3, sp->tpos+12);
303 
304       Draw3dRect(sp->win, 1, sp->tpos+1,
305 		 (u_int) sp->tsize-3, (u_int) sp->tsize-3, R3D_OUT,2,
306 		 sp->hi, sp->lo, sp->bg);
307     }
308   }
309 
310   else {   /* horizontal */
311     /* clear out thumb area with background color */
312     XClearArea(theDisp, sp->win, sp->tsize+1, 0,
313 	       (u_int) ((sp->len-sp->tsize-1)-(sp->tsize+1)),
314 	       (u_int) sp->tsize, False);
315 
316     if (sp->active) {  /* a thumb is necessary */
317       XSetForeground(theDisp, theGC, sp->bg);
318       XFillRectangle(theDisp, sp->win, theGC, sp->tpos+1, 1,
319 		     (u_int) (sp->tsize-2), (u_int) (sp->tsize-2));
320 
321       XSetForeground(theDisp, theGC, sp->fg);
322       XDrawRectangle(theDisp, sp->win, theGC, sp->tpos, 0,
323 		     (u_int) (sp->tsize-1), (u_int) (sp->tsize-1));
324 
325       XDrawLine(theDisp, sp->win, theGC, sp->tpos+6, 9-3, sp->tpos+6, 9+3);
326       XDrawLine(theDisp, sp->win, theGC, sp->tpos+8, 9-3, sp->tpos+8, 9+3);
327       XDrawLine(theDisp, sp->win, theGC, sp->tpos+10,9-3, sp->tpos+10,9+3);
328       XDrawLine(theDisp, sp->win, theGC, sp->tpos+12,9-3, sp->tpos+12,9+3);
329 
330       Draw3dRect(sp->win, sp->tpos+1, 1,
331 		 (u_int) sp->tsize-3, (u_int) sp->tsize-3, R3D_OUT,2,
332 		 sp->hi, sp->lo, sp->bg);
333     }
334   }
335 }
336 
337 
338 
339 /***************************************************/
whereInScrl(sp,x,y)340 static int whereInScrl(sp,x,y)
341 SCRL *sp;
342 int x,y;
343 {
344   int v;
345 
346   /* returns region # that x,y is in.  Returns '-1' if none */
347 
348   v=0;
349   if (sp->vert) {
350     if (x<0 || x>sp->tsize || y<0 || y>sp->len) return -1;
351     v = y;
352   }
353   else {
354     if (y<0 || y>sp->tsize || x<0 || x>sp->len) return -1;
355     v = x;
356   }
357 
358   /* once we know it's in scroll bar, only have to check 'v' versus len */
359   if (v < sp->tmin)               return UPLINE;
360   if (sp->active) {
361     if (v <  sp->tpos)             return UPPAGE;
362     if (v <  sp->tpos + sp->tsize) return THUMB;
363     if (v <= sp->tmax + sp->tsize) return DNPAGE;
364   }
365   if (v > sp->tmax+sp->tsize)    return DNLINE;
366 
367   return -1;
368 }
369 
370 
371 /***************************************************/
SCTrack(sp,mx,my)372 void SCTrack(sp,mx,my)
373 SCRL *sp;
374 int mx,my;
375 {
376   Window       rW,cW;
377   int          rx,ry, x,y, ipos, pos, lit, tx, ty, tyoff, txoff, ty1, tx1;
378   unsigned int mask;
379 
380   /* determine in which of the five regions of the scroll bar the mouse
381      was clicked (upline, downline, uppage, downpage, thumb) */
382 
383   tx = ty = txoff = tyoff = 0;
384 
385   if (!sp->active) return;
386 
387   XSetForeground(theDisp, theGC, sp->fg);
388   XSetBackground(theDisp, theGC, sp->bg);
389 
390   /* light up appropriate bit of scroll bar */
391   ipos = whereInScrl(sp,mx,my);
392   lit = 1;
393 
394   switch (ipos) {
395   case UPLINE:  sp->uplit = 1;
396                 drawArrow(sp, UPLINE);
397                 if (sp->val > sp->min) SCSetVal(sp,sp->val-1);
398                 Timer(SCRLWAIT*3);
399                 break;
400 
401   case DNLINE:  sp->dnlit = 1;
402                 drawArrow(sp, DNLINE);
403                 if (sp->val < sp->max) SCSetVal(sp,sp->val+1);
404                 Timer(SCRLWAIT*3);
405                 break;
406 
407   case UPPAGE:  SCSetVal(sp,sp->val - sp->page);  break;
408   case DNPAGE:  SCSetVal(sp,sp->val + sp->page);  break;
409   case THUMB:   tyoff = sp->tpos - my;
410                 txoff = sp->tpos - mx;
411                 ty = sp->tpos;
412                 tx = sp->tpos;
413                 break;
414   }
415 
416   while (XQueryPointer(theDisp,sp->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
417     if (!(mask & Button1Mask)) break;    /* button released */
418 
419     switch (ipos) {
420 
421     case THUMB:
422       /* do thumb tracking */
423 
424       if (sp->vert) {
425 	ty1 = y+tyoff;
426 	RANGE(ty1, sp->tmin, sp->tmax);
427 	if (ty != ty1) {    /* but only if mouse has moved */
428 	  int dt, dv;
429 	  dt = sp->tmax - sp->tmin;
430 	  dv = sp->max  - sp->min;
431 	  ty = ty1;
432 	  SCSetVal(sp, sp->min + (dv*(ty - sp->tmin)+dt/2) / dt);
433 	}
434       }
435       else {
436 	tx1 = x+txoff;
437 	RANGE(tx1, sp->tmin, sp->tmax);
438 	if (tx != tx1) {    /* but only if mouse has moved */
439 	  int dt, dv;
440 	  dt = sp->tmax - sp->tmin;
441 	  dv = sp->max  - sp->min;
442 	  tx = tx1;
443 	  SCSetVal(sp, sp->min + (dv*(tx - sp->tmin)+dt/2) / dt);
444 	}
445       }
446       break;
447 
448 
449     case UPLINE:
450     case DNLINE:                     /* arrows */
451       pos = whereInScrl(sp,x,y);
452       if (pos == ipos) {
453 	if (!lit) {
454 	  lit = 1;
455 	  if (ipos == UPLINE) { sp->uplit = 1;  drawArrow(sp,UPLINE); }
456 	                 else { sp->dnlit = 1;  drawArrow(sp,DNLINE); }
457 	}
458 
459 	else {
460 	  if (sp->val > sp->min && pos==UPLINE) {
461 	    SCSetVal(sp, sp->val-1);
462 	    Timer(SCRLWAIT);
463 	  }
464 	  else if (sp->val < sp->max && pos==DNLINE) {
465 	    SCSetVal(sp, sp->val+1);
466 	    Timer(SCRLWAIT);
467 	  }
468 	}
469       }
470 
471       else {
472 	if (lit) {
473 	  lit = 0;
474 	  if (ipos == UPLINE) { sp->uplit = 0;  drawArrow(sp,UPLINE); }
475 	                 else { sp->dnlit = 0;  drawArrow(sp,DNLINE); }
476 	}
477       }
478       break;
479 
480     }
481   }
482 
483 
484   if (lit && ipos == UPLINE) { sp->uplit = 0; drawArrow(sp, UPLINE); }
485   if (lit && ipos == DNLINE) { sp->dnlit = 0; drawArrow(sp, DNLINE); }
486 }
487 
488 
489 
490 
491 
492 
493 
494 
495 
496 
497 
498 
499 
500 
501 
502 
503 
504 
505