1 /*
2  *     *********************************************************************
3  *     * Copyright (C) 1988, 1990 Stanford University.                     *
4  *     * Permission to use, copy, modify, and distribute this              *
5  *     * software and its documentation for any purpose and without        *
6  *     * fee is hereby granted, provided that the above copyright          *
7  *     * notice appear in all copies.  Stanford University                 *
8  *     * makes no representations about the suitability of this            *
9  *     * software for any purpose.  It is provided "as is" without         *
10  *     * express or implied warranty.  Export of this software outside     *
11  *     * of the United States of America may require an export license.    *
12  *     *********************************************************************
13  */
14 
15 /*
16  * Scrollbar manager.
17  */
18 #include "ana.h"
19 #include "ana_glob.h"
20 #include "graphics.h"
21 
22 public
23 #define	SCROLLBARHEIGHT		16
24 public
25 #define	ARROW_WIDTH		32
26 
27 
28 private	void    StretchLeft(), StretchRight(), MoveBar();
29 private	void    MoveLeft(), MoveRight();
30 
31 
DrawScrollBar(isExpose)32 public void DrawScrollBar( isExpose )
33   int  isExpose;
34   {
35     static Coord  lastLeft = 0;
36     static Coord  lastRight = 0;
37 
38     if( isExpose or (scrollBox.left > lastLeft) )
39 	FillAREA( window, 0, scrollBox.top, scrollBox.left, SCROLLBARHEIGHT,
40 	 gcs.white );
41     if( isExpose or (scrollBox.right < lastRight) )
42 	FillAREA( window, scrollBox.right, scrollBox.top,
43 	 XWINDOWSIZE - scrollBox.right, SCROLLBARHEIGHT, gcs.white );
44     HLine( window, textBox.left, textBox.right, textBox.top, gcs.black );
45     lastLeft = scrollBox.left;
46     lastRight = scrollBox.right;
47     XCopyArea( display, pix.left_arrows, window, gcs.black, 0, 0, ARROW_WIDTH,
48      SCROLLBARHEIGHT, scrollBox.left, scrollBox.top );
49     XCopyArea( display, pix.right_arrows, window, gcs.black, 0, 0, ARROW_WIDTH,
50      SCROLLBARHEIGHT, scrollBox.right - ARROW_WIDTH, scrollBox.top );
51     UpdateScrollBar();
52   }
53 
54 
55 /*
56  * Update and redraw the scrollbar.
57  */
UpdateScrollBar()58 public void UpdateScrollBar()
59   {
60     float  tmp;
61 
62     if( tims.last == tims.first  )
63       {
64 	barPos.left = traceBox.left;
65 	barPos.right = traceBox.right;
66       }
67     else
68       {
69         TimeType  maxTime;
70 
71 	maxTime = max( tims.last, tims.end );
72 	tmp = (float)(traceBox.right - traceBox.left) / (maxTime-tims.first);
73 	barPos.left = traceBox.left + round( tmp * (tims.start-tims.first) );
74 	barPos.right = barPos.left + round( tmp * tims.steps );
75 	if( barPos.right - barPos.left < 3 )
76 	  {
77 	    if( barPos.left + 3 > traceBox.right )
78 		barPos.left = barPos.right - 3;
79 	    else
80 		barPos.right = barPos.left + 3;
81 	  }
82       }
83     FillAREA( window, traceBox.left + 1, scrollBox.top + 1,
84       traceBox.right - traceBox.left - 1, SCROLLBARHEIGHT - 2, gcs.gray );
85     VLine( window, traceBox.left, scrollBox.bot, scrollBox.top, gcs.black );
86     VLine( window, traceBox.right, scrollBox.bot, scrollBox.top, gcs.black );
87 
88     FillBox( window, barPos, gcs.white );
89     OutlineBox( window, barPos, gcs.black );
90   }
91 
92 
93 
94 /*
95  * Handle button clicks within the scrollbar.
96  */
DoScrollBar(ev)97 public void DoScrollBar( ev )
98   XButtonEvent  *ev;
99   {
100     TimeType  oldStart, oldSteps;
101 
102     if( (ev->x < scrollBox.left) or (ev->x > scrollBox.right) )
103 	return;
104 
105     if( ev->x < scrollBox.left + (ARROW_WIDTH / 2 - 1) )
106 	MoveLeft( 2 );
107     else if( ev->x < traceBox.left )
108 	MoveLeft( 1 );
109     else if( ev->x <= traceBox.right )
110       {
111 	oldStart = tims.start;
112 	oldSteps = tims.steps;
113 
114 	switch( ev->button & (Button1 | Button2 | Button3) )
115 	  {
116 	    case Button1 :
117 		StretchLeft( ev->x );
118 		break;
119 	    case Button2 :
120 		MoveBar( ev->x );
121 		break;
122 	    case Button3 :
123 		StretchRight( ev->x );
124 		break;
125 	  }
126 	UpdateScrollBar();
127 	if( (oldStart != tims.start) or (oldSteps != tims.steps) )
128 	  {
129 	    DrawTraces( tims.start, tims.end );
130 	    RedrawTimes();
131 	  }
132       }
133     else if( ev->x < scrollBox.right - (ARROW_WIDTH / 2 - 1) )
134       {
135 	MoveRight( 1 );
136       }
137     else		    /* ( x < scrol.right ) */
138 	MoveRight( 2 );
139   }
140 
141 
142 /*
143  * Stretch the scroll bar to the left, up to the current right side.
144  */
StretchLeft(x)145 private void StretchLeft( x )
146   Coord  x;
147   {
148     Coord     xmax;
149     XEvent    ev;
150     float     tmp;
151     TimeType  maxTime, ti;
152     BBox      b;
153 
154     maxTime = max( tims.last, tims.end );
155     if( maxTime <= tims.first )
156 	return;
157 
158     tmp = (float)(maxTime - tims.first) / (traceBox.right - traceBox.left);
159     xmax = barPos.right - max( 3, round( 10.0 / tmp ) );
160 
161     b.top = barPos.top + 1;
162     b.bot = barPos.bot - 1;
163     b.left = barPos.left;
164     b.right = barPos.right - 1;
165     FillBox( window, b, gcs.gray );
166     b.left = min( x, xmax );
167     FillBox( window, b, gcs.white );
168 
169     GrabMouse( window, ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
170      None );
171 
172     UpdateTimes( tims.start, tims.end );	/* initialize it */
173 
174     do
175       {
176 	XNextEvent( display, &ev );
177 	if( ev.type == MotionNotify )
178 	    x = ev.xmotion.x;
179 	else if( ev.type == ButtonRelease )
180 	    x = ev.xbutton.x;
181 	else
182 	    continue;
183 
184 	FillBox( window, b, gcs.gray );
185 	if( x < traceBox.left )
186 	    b.left = traceBox.left;
187 	else if( x > xmax )
188 	    b.left = xmax;
189 	else
190 	    b.left = x;
191 	FillBox( window, b, gcs.white );
192 	ti = tims.first + round( (b.left - traceBox.left) * tmp );
193 	UpdateTimes( ti, tims.end );
194       }
195     while( ev.type != ButtonRelease );
196 
197     XUngrabPointer( display, CurrentTime );
198     XFlush( display );
199 
200     barPos.left = b.left;
201     tims.start = tims.first + round( (b.left - traceBox.left) * tmp );
202     tims.steps = tims.end - tims.start;
203   }
204 
205 
206 
207 /*
208  * Stretch the scroll bar to the right, up to the current left side.
209  */
StretchRight(x)210 private void StretchRight( x )
211   Coord  x;
212   {
213     Coord     xmin;
214     XEvent    ev;
215     float     tmp;
216     TimeType  maxTime, ti;
217     BBox      b;
218 
219     maxTime = max( tims.last, tims.end );
220     if( maxTime <= tims.first )
221 	return;
222 
223     tmp = (float)(maxTime - tims.first) / (traceBox.right - traceBox.left);
224     xmin = barPos.left + max( 3, round( 10.0/tmp ) );
225 
226     b.top = barPos.top + 1;
227     b.bot = barPos.bot - 1;
228     b.left = barPos.left + 1;
229     b.right = barPos.right;
230     FillBox( window, b, gcs.gray );
231     b.right = max( x, xmin );
232     FillBox( window, b, gcs.white );
233 
234     GrabMouse( window, ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
235      None );
236 
237     UpdateTimes( tims.start, tims.end );	/* initialize it */
238 
239     do
240       {
241 	XNextEvent( display, &ev );
242 	if( ev.type == MotionNotify )
243 	    x = ev.xmotion.x;
244 	else if( ev.type == ButtonRelease )
245 	    x = ev.xbutton.x;
246 	else
247 	    continue;
248 
249 	FillBox( window, b, gcs.gray );
250 	if( x < xmin )
251 	    b.right = xmin;
252 	else if( x > traceBox.right )
253 	    b.right = traceBox.right;
254 	else
255 	    b.right = x;
256 	FillBox( window, b, gcs.white );
257 	ti = tims.first + round( (b.right - traceBox.left) * tmp );
258 	UpdateTimes( tims.start, ti );
259       }
260     while( ev.type != ButtonRelease );
261 
262     XUngrabPointer( display, CurrentTime );
263     XFlush( display );
264 
265     barPos.right = b.right;
266     tims.end = tims.first + round( (b.right - traceBox.left) * tmp );
267     tims.steps = tims.end - tims.start;
268   }
269 
270 
271 /*
272  * Move the scrollbar left or right, always within the scrollbar bounds.
273  */
MoveBar(x)274 private void MoveBar( x )
275   Coord     x;
276   {
277     XEvent    ev;
278     Coord     width, handle;
279     Coord     top, height;
280     float     tmp;
281     TimeType  maxTime, t1, t2;
282 
283     maxTime = max( tims.last, tims.end );
284     if( maxTime <= tims.first )
285 	return;
286 
287     tmp = (float)(maxTime - tims.first) / (traceBox.right - traceBox.left);
288 
289     top = barPos.top + 1;
290     height = barPos.bot - barPos.top - 1;	/* bot - top - 1 - 1 + 1 */
291     width = barPos.right - barPos.left + 1;
292 
293     if( x >= barPos.left and x <= barPos.right )
294 	handle = x - barPos.left;
295     else if( (x > barPos.right) and (x + width - 1 > traceBox.right) )
296 	handle = x + width - traceBox.right - 1;
297     else
298 	handle = 0;
299 
300     FillAREA( window, barPos.left, top, width, height, gcs.gray );
301     FillAREA( window, x - handle, top, width, height, gcs.white );
302 
303     GrabMouse( window, ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
304      None );
305 
306     UpdateTimes( tims.start, tims.end );	/* initialize it */
307 
308     do
309       {
310 	XNextEvent( display, &ev );
311 	if( ev.type != MotionNotify and ev.type != ButtonRelease )
312 	    continue;
313 
314 	FillAREA( window, x - handle, top, width, height, gcs.gray );
315 	x = (ev.type == MotionNotify) ? ev.xmotion.x : ev.xbutton.x;
316 	if( x - handle + width - 1 > traceBox.right )
317 	  {
318 	    if( x > traceBox.right )
319 		x = traceBox.right;
320 	    handle = x - (traceBox.right - width + 1);
321 	  }
322 	else if( x - handle < traceBox.left )
323 	  {
324 	    if( x < traceBox.left )
325 		x = traceBox.left;
326 	    handle = x - traceBox.left;
327 	  }
328 	FillAREA( window, x - handle, top, width, height, gcs.white );
329 	t1 = round( (x - handle - traceBox.left) * tmp ) + tims.first;
330 	t2 = t1 + tims.steps;
331 	UpdateTimes( t1, t2 );
332       }
333     while( ev.type != ButtonRelease );
334 
335     XUngrabPointer( display, CurrentTime );
336     XFlush( display );
337 
338     barPos.left = x - handle;
339     barPos.right = x - handle + width - 1;
340 
341     tims.start = round( (barPos.left - traceBox.left) * tmp ) + tims.first;
342     tims.end = tims.start + tims.steps;
343   }
344 
345 
346 /*
347  * Scroll left by 'hpages' half-pages.
348  */
MoveLeft(hpages)349 private void MoveLeft( hpages )
350   int  hpages;
351   {
352     TimeType  start;
353 
354     start = tims.start - (hpages * tims.steps) / 2;
355 
356     if( start < tims.first )
357 	start = tims.first;
358 
359     if( start == tims.start )
360 	return;
361 
362     tims.start = start;
363     tims.end = start + tims.steps;
364 
365     RedrawTimes();
366     UpdateScrollBar();
367     DrawTraces( start, tims.end );
368   }
369 
370 
371 /*
372  * Scroll right by 'hpages' half-pages.
373  */
MoveRight(hpages)374 private void MoveRight( hpages )
375   int  hpages;
376   {
377     TimeType  start;
378 
379     start = tims.start + (hpages * tims.steps) / 2;
380 
381     if( (start >= tims.last) or (start == tims.start) or
382       (start + tims.steps >= MAX_TIME ) )
383 	return;
384 
385     tims.start = start;
386     tims.end = start + tims.steps;
387     RedrawTimes();
388     UpdateScrollBar();
389     DrawTraces( start, tims.end );
390   }
391