1 /*
2  * wmslib/src/but/slide.c, part of wmslib (Library functions)
3  * Copyright (C) 1994-1997 William Shubert.
4  * See "configure.h.in" for more copyright information.
5  */
6 
7 #include <configure.h>
8 
9 #ifdef  X11_DISP
10 
11 #ifdef  STDC_HEADERS
12 #include <stdlib.h>
13 #include <unistd.h>
14 #endif  /* STDC_HEADERS */
15 #include <stdio.h>
16 #include <X11/Xlib.h>
17 #include <X11/Xutil.h>
18 #include <X11/cursorfont.h>
19 #include <X11/Xatom.h>
20 #include <X11/keysym.h>
21 #include <sys/time.h>
22 #ifdef  HAVE_SYS_SELECT_H
23 #include <sys/select.h>
24 #endif
25 #include <wms.h>
26 #include <but/but.h>
27 #include <but/slide.h>
28 #include <but/box.h>
29 #include <but/timer.h>
30 
31 
32 /**********************************************************************
33  * Data Types
34  **********************************************************************/
35 typedef struct Slide_struct  {
36   int  maxval;
37   int  cval;
38   int  size;
39   bool  horiz;
40   bool  grip;
41   int  start_mloc, start_val, start_loc;
42   ButTimer  *timer;
43   int  timer_jump;
44   int  oldcur;
45 
46   /*
47    * Stuff calculated from dimensions.
48    * w and h are for a horizontal slider.  Reverse for vertical!
49    */
50   int  boxW, boxH, boxLoc;
51   int  lastW, lastH;
52 
53   ButOut  (*callback)(But *but, int setting, bool newPress);
54 } Slide;
55 
56 
57 /**********************************************************************
58  * Forward Declarations
59  **********************************************************************/
60 static ButOut  mmove(But *but, int x, int y);
61 static ButOut  mleave(But *but);
62 static ButOut  mpress(But *but, int butnum, int x, int y);
63 static ButOut  mrelease(But *but, int butnum, int x, int y);
64 static void  draw(But *but, int x, int y, int w, int h);
65 static ButOut  destroy(But *but);
66 static void  flags(But *but, uint flags);
67 static ButOut  slide_now(ButTimer *bt);
68 static void  specialDraw(But *but, Slide *slide, int x, int y, int w, int h);
69 static void  drawNewLoc(But *but);
70 static void  calcBoxLoc(But *but);
71 
72 
73 /**********************************************************************
74  * Globals
75  **********************************************************************/
76 static const ButAction  action = {
77   mmove, mleave, mpress, mrelease,
78   NULL, NULL, draw, destroy, flags, NULL};
79 
80 
81 /**********************************************************************
82  * Functions
83  **********************************************************************/
butSlide_hCreate(ButOut (* func)(But * but,int setting,bool newPress),void * packet,ButWin * win,int layer,int flags,int maxval,int cval,int size)84 But  *butSlide_hCreate(ButOut (*func)(But *but, int setting, bool newPress),
85 		       void *packet, ButWin *win, int layer, int flags,
86 		       int maxval, int cval, int size)  {
87   Slide  *slide;
88   But  *but;
89 
90   slide = wms_malloc(sizeof(Slide));
91   but = but_create(win, slide, &action);
92   but->uPacket = packet;
93   but->layer = layer;
94   but->flags = flags | BUT_OPAQUE;
95 
96   slide->maxval = maxval;
97   slide->cval = cval;
98   slide->size = size;
99   slide->horiz = TRUE;
100   slide->grip = FALSE;
101   slide->start_mloc = 0;
102   slide->start_val = 0;
103   slide->start_loc = 0;
104   slide->timer = NULL;
105   slide->timer_jump = 0;
106   slide->oldcur = butCur_idle;
107   slide->boxW = slide->boxH = slide->boxLoc = 0;
108   slide->lastW = 0;
109   slide->lastH = 0;
110   slide->callback = func;
111   but_init(but);
112   return(but);
113 }
114 
115 
butSlide_vCreate(ButOut (* func)(But * but,int setting,bool newPress),void * packet,ButWin * win,int layer,int flags,int maxval,int cval,int size)116 But  *butSlide_vCreate(ButOut (*func)(But *but, int setting, bool newPress),
117 		       void *packet, ButWin *win, int layer, int flags,
118 		       int maxval, int cval, int size)  {
119   Slide  *slide;
120   But  *but;
121 
122   slide = wms_malloc(sizeof(Slide));
123   but = but_create(win, slide, &action);
124   but->uPacket = packet;
125   but->layer = layer;
126   but->flags = flags | BUT_OPAQUE;
127 
128   slide->maxval = maxval;
129   slide->cval = cval;
130   slide->size = size;
131   slide->horiz = FALSE;
132   slide->grip = FALSE;
133   slide->start_mloc = 0;
134   slide->start_val = 0;
135   slide->start_loc = 0;
136   slide->timer = NULL;
137   slide->timer_jump = 0;
138   slide->oldcur = butCur_idle;
139   slide->boxW = slide->boxH = slide->boxLoc = 0;
140   slide->lastW = 0;
141   slide->lastH = 0;
142   slide->callback = func;
143   but_init(but);
144   return(but);
145 }
146 
147 
butSlide_set(But * but,int maxval,int cval,int size)148 void  butSlide_set(But *but, int maxval, int cval, int size)  {
149   Slide  *slide = but->iPacket;
150 
151   assert(but->action == &action);
152   if (maxval == BUT_NOCHANGE)
153     maxval = slide->maxval;
154   if (cval == BUT_NOCHANGE)
155     cval = slide->cval;
156   if (size == BUT_NOCHANGE)
157     size = slide->size;
158   if ((maxval != slide->maxval) || (cval != slide->cval) ||
159       (size != slide->size))  {
160     slide->maxval = maxval;
161     slide->cval = cval;
162     slide->size = size;
163     drawNewLoc(but);
164   }
165 }
166 
167 
butSlide_get(But * but)168 int  butSlide_get(But *but)  {
169   Slide  *slide = but->iPacket;
170 
171   return(slide->cval);
172 }
173 
174 
destroy(But * but)175 static ButOut  destroy(But *but)  {
176   Slide *slide = but->iPacket;
177 
178   if (slide->timer != NULL)
179     butTimer_destroy(slide->timer);
180   wms_free(slide);
181   return(0);
182 }
183 
184 
draw(But * but,int x,int y,int w,int h)185 static void  draw(But *but, int x, int y, int w, int h)  {
186   ButWin *win = but->win;
187   ButEnv *env = win->env;
188   Slide  *slide = but->iPacket;
189   int  bw = env->stdButBw;
190 
191   if ((w != slide->lastW) || (h != slide->lastH))
192     calcBoxLoc(but);
193   but_drawBox(win, but->x,but->y, but->w,but->h, 1, bw,
194 	      BUT_SLEFT|BUT_SRIGHT, BUT_LIT, BUT_SHAD, None, None);
195   butEnv_setXFg(env, BUT_PBG);
196   XFillRectangle(env->dpy, win->win, env->gc, but->x+bw,but->y+bw,
197 		 but->w-2*bw, but->h-2*bw);
198   if (slide->horiz)  {
199     but_drawBox(win, but->x+bw+slide->boxLoc, but->y+bw,
200 		slide->boxW, slide->boxH,
201 		but->flags & BUT_LOCKED, bw,
202 		BUT_SLEFT|BUT_SRIGHT, BUT_LIT, BUT_SHAD, None, None);
203     butEnv_setXFg(env, BUT_BG);
204     XFillRectangle(env->dpy, win->win, env->gc,
205 		   but->x + bw*2 + slide->boxLoc, but->y + bw * 2,
206 		   slide->boxW - bw * 2, slide->boxH - bw * 2);
207   } else /* !but->horiz */ {
208     but_drawBox(win, but->x+bw, but->y+bw+slide->boxLoc,
209 		slide->boxH, slide->boxW,
210 		but->flags & BUT_LOCKED, bw,
211 		BUT_SLEFT|BUT_SRIGHT, BUT_LIT, BUT_SHAD, None, None);
212     butEnv_setXFg(env, BUT_BG);
213     XFillRectangle(env->dpy, win->win, env->gc,
214 		   but->x + bw * 2, but->y + bw*2 + slide->boxLoc,
215 		   slide->boxH - bw * 2, slide->boxW - bw * 2);
216   }
217 }
218 
219 
calcBoxLoc(But * but)220 static void  calcBoxLoc(But *but)  {
221   Slide  *slide = but->iPacket;
222   ButEnv  *env = but->win->env;
223   int  allW, allH;
224   int  bw;
225 
226   bw = butEnv_stdBw(env);
227   if (slide->horiz)  {
228     allW = but->w - 2*bw;
229     allH = but->h - 2*bw;
230   } else  {
231     allW = but->h - 2*bw;
232     allH = but->w - 2*bw;
233   }
234   if (allW <= allH)  {
235     slide->boxW = allW;
236     slide->boxH = allH;
237     slide->boxLoc = 0;
238   } else  {
239     slide->boxW = (slide->size * allW + (slide->size + slide->maxval) / 2) /
240       (slide->size + slide->maxval);
241     slide->boxH = allH;
242     if (slide->boxW < slide->boxH)
243       slide->boxW = slide->boxH;
244     if (slide->maxval == 0)
245       slide->boxLoc = 0;
246     else
247       slide->boxLoc = ((allW - slide->boxW) * slide->cval +
248 		       slide->maxval / 2) / slide->maxval;
249   }
250   slide->lastW = but->w;
251   slide->lastH = but->h;
252 }
253 
254 
drawNewLoc(But * but)255 static void  drawNewLoc(But *but)  {
256   ButEnv *env = but->win->env;
257   Slide  *slide = but->iPacket;
258   int  bw = env->stdButBw;
259   int  boxW, boxH, boxLoc;
260   int  oldW, oldLoc;
261 
262   if ((but->w < 1) || (but->h < 1))
263     return;
264   oldW = slide->boxW;
265   oldLoc = slide->boxLoc;
266   calcBoxLoc(but);
267   boxW = slide->boxW;
268   boxH = slide->boxH;
269   boxLoc = slide->boxLoc;
270   if (boxLoc < oldLoc)  {
271     specialDraw(but, slide, boxLoc + bw, bw,
272 		oldLoc + bw - boxLoc, boxH);
273   } else if (boxLoc > oldLoc)  {
274     specialDraw(but, slide, oldLoc + bw, bw,
275 		boxLoc + bw - oldLoc, boxH);
276   }
277   if (boxLoc + boxW < oldLoc + oldW)  {
278     specialDraw(but, slide, boxLoc + boxW, bw,
279 		oldLoc + oldW + bw - boxLoc - boxW, boxH);
280   } else if (boxLoc + boxW > oldLoc + oldW)  {
281     specialDraw(but, slide, oldLoc + oldW, bw,
282 		boxLoc + boxW + bw - oldLoc - oldW, boxH);
283   }
284 }
285 
286 
specialDraw(But * but,Slide * slide,int x,int y,int w,int h)287 static void  specialDraw(But *but, Slide *slide, int x, int y, int w, int h)  {
288   if (slide->horiz)  {
289     butWin_redraw(but->win, but->x + x, but->y + y, w, h);
290   } else  {
291     butWin_redraw(but->win, but->x + y, but->y + x, h, w);
292   }
293 }
294 
295 
flags(But * but,uint flags)296 static void  flags(But *but, uint flags)  {
297   uint  ofl = but->flags;
298 
299   but->flags = flags;
300   if ((flags & (BUT_PRESSABLE|BUT_DRAWABLE|BUT_PRESSED|BUT_LOCKED)) !=
301       (ofl   & (BUT_PRESSABLE|BUT_DRAWABLE|BUT_PRESSED|BUT_LOCKED)))
302     but_draw(but);
303 }
304 
305 
mmove(But * but,int x,int y)306 static ButOut  mmove(But *but, int x, int y)  {
307   ButOut  retval = BUTOUT_CAUGHT;
308   int  newflags = but->flags;
309   ButEnv  *env = butWin_env(but_win(but));
310   Slide  *slide = but->iPacket;
311   int  newval, newloc, pitmax;
312   int  newcur = butCur_idle;
313 
314   if (slide->horiz)  {
315     if ((newflags & BUT_LOCKED) && slide->grip)  {
316       /* Slide it around! */
317       if (x == BUT_NOCHANGE)
318 	return(retval);
319       newloc = x - slide->start_mloc + slide->start_loc;
320       if (newloc < 0)
321 	newloc = 0;
322       pitmax = but->w - slide->boxW - env->stdButBw*2;
323       if (newloc > pitmax)
324 	newloc = pitmax;
325       if (pitmax == 0)
326 	newval = 0;
327       else
328 	newval = (newloc * slide->maxval + pitmax/2) / pitmax;
329       if (newval != slide->cval)  {
330 	slide->cval = newval;
331 	drawNewLoc(but);
332 	if (slide->callback != NULL)
333 	  return(retval | slide->callback(but, slide->cval, FALSE));
334       }
335       return(retval);
336     }
337     if ((x >= but->x+env->stdButBw) && (x < but->x+but->w-env->stdButBw) &&
338 	(y >= but->y+env->stdButBw) && (y < but->y+but->h-env->stdButBw))  {
339       newflags |= BUT_TWITCHED;
340       if (x < but->x + env->stdButBw + slide->boxLoc)
341 	newcur = butCur_left;
342       else if (x < but->x + env->stdButBw + slide->boxLoc + slide->boxW)
343 	newcur = butCur_lr;
344       else
345 	newcur = butCur_right;
346     } else  {
347       newflags &= ~BUT_TWITCHED;
348       if (!(newflags & BUT_LOCKED))
349 	retval &= ~BUTOUT_CAUGHT;
350     }
351     if (!(newflags & BUT_LOCKED) && (newcur != slide->oldcur))  {
352       butEnv_setCursor(env, but, newcur);
353       slide->oldcur = newcur;
354     }
355     if (newflags != but->flags)  {
356       but_newFlags(but, newflags);
357     }
358     return(retval);
359   } else /* !slide->horiz */ {
360     if ((newflags & BUT_LOCKED) && slide->grip)  {
361       /* Slide it around! */
362       if (y == BUT_NOCHANGE)
363 	return(retval);
364       newloc = y - slide->start_mloc + slide->start_loc;
365       if (newloc < 0)
366 	newloc = 0;
367       pitmax = but->h - slide->boxW - env->stdButBw*2;
368       if (newloc > pitmax)
369 	newloc = pitmax;
370       if (pitmax == 0)
371 	newval = 0;
372       else
373 	newval = (newloc * slide->maxval + pitmax/2) / pitmax;
374       if (newval != slide->cval)  {
375 	slide->cval = newval;
376 	drawNewLoc(but);
377 	if (slide->callback != NULL)
378 	  return(retval | slide->callback(but, slide->cval, FALSE));
379       }
380       return(retval);
381     }
382     if ((x >= but->x+env->stdButBw) && (x < but->x+but->w-env->stdButBw) &&
383 	(y >= but->y+env->stdButBw) && (y < but->y+but->h-env->stdButBw))  {
384       newflags |= BUT_TWITCHED;
385       if (y < but->y + env->stdButBw + slide->boxLoc)
386 	newcur = butCur_up;
387       else if (y < but->y + env->stdButBw + slide->boxLoc + slide->boxW)
388 	newcur = butCur_ud;
389       else
390 	newcur = butCur_down;
391     } else  {
392       newflags &= ~BUT_TWITCHED;
393       if (!(newflags & BUT_LOCKED))
394 	retval &= ~BUTOUT_CAUGHT;
395     }
396     if (!(newflags & BUT_LOCKED) && (newcur != slide->oldcur))  {
397       butEnv_setCursor(env, but, newcur);
398       slide->oldcur = newcur;
399     }
400     if (newflags != but->flags)  {
401       but_newFlags(but, newflags);
402     }
403     return(retval);
404   }
405 }
406 
407 
mleave(But * but)408 static ButOut  mleave(But *but)  {
409   int  newflags = but->flags;
410   Slide  *slide = but->iPacket;
411 
412   newflags &= ~BUT_TWITCHED;
413   butEnv_setCursor(but->win->env, but, butCur_idle);
414   slide->oldcur = butCur_idle;
415   if (newflags != but->flags)  {
416     but_newFlags(but, newflags);
417   }
418   return(BUTOUT_CAUGHT);
419 }
420 
421 
mpress(But * but,int butnum,int x,int y)422 static ButOut  mpress(But *but, int butnum, int x, int y)  {
423   int  retval = BUTOUT_CAUGHT, newflags = but->flags;
424   Slide  *slide = but->iPacket;
425   ButEnv  *env = but->win->env;
426 
427   if (!newflags & BUT_TWITCHED)
428     retval &= ~BUTOUT_CAUGHT;
429   else  {
430     if (slide->horiz)  {
431       if (but->w <= but->h)
432 	return(BUTOUT_CAUGHT | BUTOUT_ERR);
433       if (butnum == 1)  {
434 	newflags |= BUT_LOCKED;
435 	if (x < but->x + env->stdButBw + slide->boxLoc)  {
436 	  butSlide_startSlide(but, TRUE, -slide->size*2, FALSE);
437 	} else if (x >= but->x + env->stdButBw + slide->boxLoc +
438 		   slide->boxW)  {
439 	  butSlide_startSlide(but, TRUE, slide->size*2, FALSE);
440 	} else  {
441 	  /* The box has been "gripped." */
442 	  slide->grip = TRUE;
443 	  slide->start_mloc = x;
444 	  slide->start_loc = slide->boxLoc;
445 	  slide->start_val = slide->cval;
446 	}
447       } else
448 	return(BUTOUT_CAUGHT | BUTOUT_ERR);
449     } else /* !slide->horiz */ {
450       if (but->h <= but->w)
451 	return(BUTOUT_CAUGHT | BUTOUT_ERR);
452       if (butnum == 1)  {
453 	newflags |= BUT_LOCKED;
454 	if (y < but->y + env->stdButBw + slide->boxLoc)  {
455 	  butSlide_startSlide(but, TRUE, -slide->size*2, FALSE);
456 	} else if (y >= but->y + env->stdButBw + slide->boxLoc +
457 		   slide->boxW)  {
458 	  butSlide_startSlide(but, TRUE, slide->size*2, FALSE);
459 	} else  {
460 	  /* The box has been "gripped." */
461 	  slide->grip = TRUE;
462 	  slide->start_mloc = y;
463 	  slide->start_loc = slide->boxLoc;
464 	  slide->start_val = slide->cval;
465 	}
466       } else
467 	return(BUTOUT_CAUGHT | BUTOUT_ERR);
468     }
469     snd_play(&but_downSnd);
470     if (newflags != but->flags)
471       but_newFlags(but, newflags);
472     if (slide->callback != NULL)
473       return(retval | slide->callback(but, slide->cval, TRUE));
474   }
475   return(retval);
476 }
477 
478 
butSlide_startSlide(But * but,bool pause,int ssize,bool propagate)479 void  butSlide_startSlide(But *but, bool pause, int ssize, bool propagate)  {
480   Slide  *slide = but->iPacket;
481   struct timeval  delay;
482   int  atj;
483   bool  skipTimer = FALSE;
484 
485   if (slide->timer != NULL)
486     butTimer_destroy(slide->timer);
487   if (pause)  {
488     slide->cval += ssize/2;
489     if (slide->cval <= 0)  {
490       slide->cval = 0;
491       skipTimer = TRUE;
492     } else if (slide->cval >= slide->maxval - 1)  {
493       slide->cval = slide->maxval - 1;
494       skipTimer = TRUE;
495     }
496     drawNewLoc(but);
497     if (propagate && slide->callback)
498       slide->callback(but, slide->cval, TRUE);
499   }
500   if (!skipTimer)  {
501     slide->timer_jump = ssize;
502     if (pause)  {
503       delay.tv_sec = 0;
504       delay.tv_usec = 500000;
505     } else  {
506       delay.tv_sec = 0;
507       delay.tv_usec = 0;
508     }
509     if (slide->timer_jump > 0)
510       atj = slide->timer_jump;
511     else
512       atj = -slide->timer_jump;
513     slide->timer = butTimer_fCreate(NULL, but, delay, atj*2, FALSE, slide_now);
514   }
515 
516 }
517 
518 
slide_now(ButTimer * bt)519 static ButOut  slide_now(ButTimer *bt)  {
520   But  *but = bt->but;
521   Slide  *slide = but->iPacket;
522 
523   if (slide->timer_jump > 0)  {
524     slide->cval += bt->eventNum;
525     if (slide->cval > slide->maxval)  {
526       slide->cval = slide->maxval;
527       butTimer_destroy(bt);
528       slide->timer = NULL;
529     }
530   } else  {
531     slide->cval -= bt->eventNum;
532     if (slide->cval < 0)  {
533       slide->cval = 0;
534       butTimer_destroy(bt);
535       slide->timer = NULL;
536     }
537   }
538   bt->eventNum = 0;
539   drawNewLoc(but);
540   if (slide->callback != NULL)
541     return(slide->callback(but, slide->cval, FALSE));
542   return(0);
543 }
544 
545 
mrelease(But * but,int butnum,int x,int y)546 static ButOut  mrelease(But *but, int butnum, int x, int y)  {
547   ButOut  retval = BUTOUT_CAUGHT;
548   uint  newflags = but->flags;
549   Slide  *slide = but->iPacket;
550 
551   if (!newflags & BUT_TWITCHED)
552     butEnv_setCursor(but->win->env, but, slide->oldcur = butCur_idle);
553   if (slide->timer != NULL)  {
554     butTimer_destroy(slide->timer);
555     slide->timer = NULL;
556   }
557   slide->grip = FALSE;
558   newflags &= ~BUT_LOCKED;
559   if (newflags != but->flags)
560     but_newFlags(but, newflags);
561   snd_play(&but_upSnd);
562   return(retval);
563 }
564 
565 
butSlide_stopSlide(But * but)566 void  butSlide_stopSlide(But *but)  {
567   Slide  *slide = but->iPacket;
568 
569   if (slide->timer)  {
570     butTimer_destroy(slide->timer);
571     slide->timer = NULL;
572   }
573 }
574 
575 
576 #endif
577