1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/scroll.c,v 1.8 2011/05/16 16:21:59 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_SCROLL_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "choice.e"
26 #include "cursor.e"
27 #include "dialog.e"
28 #include "drawing.e"
29 #include "dup.e"
30 #include "exec.e"
31 #include "grid.e"
32 #include "mainloop.e"
33 #include "menu.e"
34 #include "miniline.e"
35 #include "msg.e"
36 #include "obj.e"
37 #include "page.e"
38 #include "raster.e"
39 #include "rect.e"
40 #include "ruler.e"
41 #include "scroll.e"
42 #include "setup.e"
43 #include "strtbl.e"
44 #include "text.e"
45 #include "util.e"
46 
47 #include "xbm/scrl_up.xbm"
48 
49 #define FAKE_CM 80
50 
51 int autoPan=TRUE;
52 
53 int scrollingCanvas=INVALID;
54 int smoothScrollingCanvas=JUMP_SCROLLING;
55 
56 int resetOriginOnAdvancePage=FALSE;
57 
58 static int scrollAreaH=0, scrollAreaW=0;
59 
TgAnyButtonDown(dpy,win)60 int TgAnyButtonDown(dpy, win)
61    Display *dpy;
62    Window win;
63 {
64    Window root_win=None, child_win=None;
65    unsigned int status;
66    int parent_root_x, parent_root_y, x=0, y=0;
67 
68    XQueryPointer(dpy, win, &root_win, &child_win,
69          &parent_root_x, &parent_root_y, &x, &y, &status);
70    return ((status & BUTTONSMASK) != 0);
71 }
72 
TgPressButtonLoop(dpy,win,pbbox,psbci)73 int TgPressButtonLoop(dpy, win, pbbox, psbci)
74    Display *dpy;
75    Window win;
76    struct BBRec *pbbox;
77    ScrollBtnCallbackInfo *psbci;
78    /* returns TRUE if need to scroll one more time */
79 {
80    time_t tv_usec=(time_t)0;
81    int done=FALSE, need_to_scroll_once=TRUE, initial_timeout=TRUE;
82 
83    if (pbbox != NULL) {
84       TgDrawThreeDButton(dpy, win, textMenuGC, pbbox, TGBS_LOWRED, 2, FALSE);
85    }
86    if (!TgAnyButtonDown(dpy, win)) {
87       if (pbbox != NULL) {
88          TgDrawThreeDButton(dpy, win, textMenuGC, pbbox, TGBS_RAISED, 2, FALSE);
89       }
90       return need_to_scroll_once;
91    }
92    tv_usec = (psbci->ms*1000);
93 
94    XGrabPointer(dpy, win, False,
95          ButtonReleaseMask, GrabModeAsync,
96          GrabModeAsync, None, handCursor, CurrentTime);
97 
98    do {
99       struct timeval timeout;
100       fd_set fdset;
101       int select_width=XConnectionNumber(dpy)+1, status=0;
102 
103       timeout.tv_sec = 0;
104       timeout.tv_usec = (initial_timeout ? 600000 : tv_usec);
105       FD_ZERO(&fdset);
106       FD_SET(select_width-1, &fdset);
107 #ifdef __hpux
108       status = select(select_width, (int*)&fdset, NULL, NULL, &timeout);
109 #else /* !__hpux */
110       status = select(select_width, &fdset, NULL, NULL, &timeout);
111 #endif /* __hpux */
112       initial_timeout = FALSE;
113 
114       if (status < 0) {
115          if (errno == EINTR) {
116             /* interrupted by a system call, do it again */
117             if (TgAnyButtonDown(dpy, win)) {
118                need_to_scroll_once = FALSE;
119                if ((psbci->pf_scroll_btn_callback)(psbci->pv_userdata)) {
120                   XUngrabPointer(dpy, CurrentTime);
121                   return TRUE;
122                }
123             }
124          } else {
125             XUngrabPointer(dpy, CurrentTime);
126             sprintf(gszMsgBox, TgLoadString(STID_FUNC_SELECT_SYS_CALL_FAILED),
127                   "TgPressButtonLoop()");
128             MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
129             break;
130          }
131       } else if (status == 0 && TgAnyButtonDown(dpy, win)) {
132          need_to_scroll_once = FALSE;
133          if ((psbci->pf_scroll_btn_callback)(psbci->pv_userdata)) {
134             XUngrabPointer(dpy, CurrentTime);
135             return TRUE;
136          }
137       } else {
138          XUngrabPointer(dpy, CurrentTime);
139          XFlush(dpy);
140          XSync(dpy, False);
141          if (pbbox != NULL) {
142             TgDrawThreeDButton(dpy, win, textMenuGC, pbbox, TGBS_RAISED, 2,
143                   FALSE);
144          }
145          done = TRUE;
146          return need_to_scroll_once;
147       }
148    } while (!done);
149 
150    return need_to_scroll_once;
151 }
152 
TgGetScrollHit(x,y,orientation,scroll_area_w,scroll_area_h,start_frac,length,total,pn_btn_offset)153 int TgGetScrollHit(x, y, orientation, scroll_area_w, scroll_area_h,
154       start_frac, length, total, pn_btn_offset)
155    int x, y, scroll_area_w, scroll_area_h, length, total, *pn_btn_offset;
156    double start_frac;
157 {
158    int block_start=0, block_size=0, min_block_size=1+(windowPadding<<1);
159    int block_area=((orientation==VERT_SCROLLBAR)?scroll_area_h:scroll_area_w);
160    double frac=(double)0;
161 
162    if (pn_btn_offset != NULL) *pn_btn_offset = 0;
163    if (orientation == VERT_SCROLLBAR) {
164       y -= scrollBarW;
165    } else {
166       x -= scrollBarW;
167    }
168    block_area -= (scrollBarW<<1);
169    if (total == 0) {
170       frac = (double)1.0;
171    } else {
172       frac = (double)((double)length / (double)total);
173    }
174    if (frac > 1.0) frac = 1.0;
175    block_start = ((int)(block_area * start_frac));
176    if (start_frac + frac >= 1.0) {
177       block_size = block_area - block_start;
178    } else {
179       block_size = (int)(block_area * frac);
180    }
181    if (block_size < min_block_size) block_size = min_block_size;
182    if (orientation == VERT_SCROLLBAR) {
183       if (block_start > scroll_area_h-min_block_size) {
184          block_start = scroll_area_h-min_block_size;
185       }
186    } else {
187       if (block_start > scroll_area_w-min_block_size) {
188          block_start = scroll_area_w-min_block_size;
189       }
190    }
191    if (orientation == VERT_SCROLLBAR) {
192       if (y < block_start) {
193          return (-1);
194       } else if (y < block_start+block_size) {
195          if (pn_btn_offset != NULL) *pn_btn_offset = block_start-y;
196          return 0;
197       }
198    } else {
199       if (x < block_start) {
200          return (-1);
201       } else if (x < block_start+block_size) {
202          if (pn_btn_offset != NULL) *pn_btn_offset = block_start-x;
203          return 0;
204       }
205    }
206    return 1;
207 }
208 
TgDrawScrollBar(dpy,win,orientation,x_off,y_off,scroll_area_w,scroll_area_h,start_frac,length,total)209 void TgDrawScrollBar(dpy, win, orientation, x_off, y_off, scroll_area_w,
210       scroll_area_h, start_frac, length, total)
211    Display *dpy;
212    Window win;
213    int x_off, y_off, scroll_area_w, scroll_area_h, length, total;
214    double start_frac;
215 {
216    int block_start=0, block_size=0, min_block_size=1+(windowPadding<<1);
217    int block_area=((orientation==VERT_SCROLLBAR)?scroll_area_h:scroll_area_w);
218    double frac=(double)0;
219    XGCValues values;
220 
221    if (threeDLook) {
222       struct BBRec bbox;
223 
224       if (orientation == VERT_SCROLLBAR) {
225          values.foreground = myFgPixel;
226          values.background = myLtGryPixel;
227          values.fill_style = FillOpaqueStippled;
228          values.stipple = scrlBitmap[SCRL_UP];
229          values.ts_x_origin = x_off+(windowPadding<<1);
230          values.ts_y_origin = y_off+1+(windowPadding<<1);
231          XChangeGC(mainDisplay, textMenuGC,
232                GCForeground | GCBackground | GCFillStyle | GCStipple |
233                GCTileStipXOrigin | GCTileStipYOrigin, &values);
234          XFillRectangle(dpy, win, textMenuGC, values.ts_x_origin,
235                values.ts_y_origin, scrl_up_width, scrl_up_height);
236          values.stipple = scrlBitmap[SCRL_DN];
237          values.ts_y_origin =
238                y_off+scroll_area_h-scrollBarW+1+(windowPadding<<1);
239          XChangeGC(mainDisplay, textMenuGC,
240                GCStipple | GCTileStipYOrigin, &values);
241          XFillRectangle(dpy, win, textMenuGC, values.ts_x_origin,
242                values.ts_y_origin, scrl_up_width, scrl_up_height);
243          values.fill_style = FillSolid;
244          values.ts_x_origin = 0;
245          values.ts_y_origin = 0;
246          XChangeGC(mainDisplay, textMenuGC,
247                GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin, &values);
248          SetBBRec(&bbox, x_off, y_off, x_off+scrollBarW, y_off+scrollBarW);
249          TgDrawThreeDButton(dpy, win, textMenuGC, &bbox, TGBS_RAISED, 2, FALSE);
250          SetBBRec(&bbox, x_off, y_off+scroll_area_h-scrollBarW,
251                x_off+scrollBarW, y_off+scroll_area_h);
252          TgDrawThreeDButton(dpy, win, textMenuGC, &bbox, TGBS_RAISED, 2, FALSE);
253       } else {
254          values.foreground = myFgPixel;
255          values.background = myLtGryPixel;
256          values.fill_style = FillOpaqueStippled;
257          values.stipple = scrlBitmap[SCRL_LF];
258          values.ts_x_origin = x_off+(windowPadding<<1);
259          values.ts_y_origin = y_off+(windowPadding<<1);
260          XChangeGC(mainDisplay, textMenuGC,
261                GCForeground | GCBackground | GCFillStyle | GCStipple |
262                GCTileStipXOrigin | GCTileStipYOrigin, &values);
263          XFillRectangle(dpy, win, textMenuGC, values.ts_x_origin,
264                values.ts_y_origin, scrl_up_width, scrl_up_height);
265          values.stipple = scrlBitmap[SCRL_RT];
266          values.ts_x_origin = x_off+scroll_area_w-scrollBarW+(windowPadding<<1);
267          XChangeGC(mainDisplay, textMenuGC,
268                GCStipple | GCTileStipXOrigin, &values);
269          XFillRectangle(dpy, win, textMenuGC, values.ts_x_origin,
270                values.ts_y_origin, scrl_up_width, scrl_up_height);
271          values.fill_style = FillSolid;
272          values.ts_x_origin = 0;
273          values.ts_y_origin = 0;
274          XChangeGC(mainDisplay, textMenuGC,
275                GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin, &values);
276          SetBBRec(&bbox, x_off, y_off, x_off+scrollBarW, y_off+scrollBarW);
277          TgDrawThreeDButton(dpy, win, textMenuGC, &bbox, TGBS_RAISED, 2, FALSE);
278          SetBBRec(&bbox, x_off+scroll_area_w-scrollBarW, y_off,
279                x_off+scroll_area_w, y_off+scrollBarW);
280          TgDrawThreeDButton(dpy, win, textMenuGC, &bbox, TGBS_RAISED, 2, FALSE);
281       }
282       block_area -= (scrollBarW<<1);
283       if (total == 0) {
284          frac = (double)1.0;
285       } else {
286          frac = (double)((double)length / (double)total);
287       }
288       if (frac > 1.0) frac = 1.0;
289       block_start = scrollBarW + ((int)(block_area * start_frac));
290       if (start_frac + frac >= 1.0) {
291          block_size = block_area - block_start + scrollBarW;
292       } else {
293          block_size = (int)(block_area * frac);
294       }
295       if (block_size < min_block_size) block_size = min_block_size;
296       if (orientation == VERT_SCROLLBAR) {
297          if (block_start > scroll_area_h-scrollBarW-min_block_size) {
298             block_start = scroll_area_h-scrollBarW-min_block_size;
299          }
300       } else {
301          if (block_start > scroll_area_w-scrollBarW-min_block_size) {
302             block_start = scroll_area_w-scrollBarW-min_block_size;
303          }
304       }
305       values.foreground = myLtGryPixel;
306       values.background = myBgPixel;
307       values.fill_style = FillOpaqueStippled;
308       values.stipple = patPixmap[SCROLLPAT];
309       XChangeGC(dpy, patGC,
310             GCForeground | GCBackground | GCFillStyle | GCStipple, &values);
311       if (orientation == VERT_SCROLLBAR) {
312          XFillRectangle(dpy, win, patGC, x_off, y_off+scrollBarW, scroll_area_w,
313                scroll_area_h-(scrollBarW<<1));
314       } else {
315          XFillRectangle(dpy, win, patGC, x_off+scrollBarW, y_off,
316                scroll_area_w-(scrollBarW<<1), scroll_area_h);
317       }
318       values.foreground = myLtGryPixel;
319       values.background = myLtGryPixel;
320       values.function = GXcopy;
321       values.fill_style = FillSolid;
322       XChangeGC(dpy, patGC,
323             GCForeground | GCBackground | GCFunction | GCFillStyle, &values);
324       if (orientation == VERT_SCROLLBAR) {
325          XFillRectangle(dpy, win, patGC, x_off, y_off+block_start,
326                scroll_area_w, block_size);
327          SetBBRec(&bbox, x_off, y_off+block_start, x_off+scroll_area_w,
328                y_off+block_start+block_size);
329       } else {
330          XFillRectangle(dpy, win, patGC, x_off+block_start, y_off, block_size,
331                scroll_area_h);
332          SetBBRec(&bbox, x_off+block_start, y_off, x_off+block_start+block_size,
333                y_off+scroll_area_h);
334       }
335       TgDrawThreeDButton(dpy, win, textMenuGC, &bbox, TGBS_RAISED, 2, FALSE);
336    } else {
337       if (total == 0) {
338          frac = (double)1.0;
339       } else {
340          frac = (double)((double)length / (double)total);
341       }
342       if (frac > 1.0) frac = 1.0;
343       block_start = (int)(block_area * start_frac);
344       if (start_frac + frac >= 1.0) {
345          block_size = block_area - block_start;
346       } else {
347          block_size = (int)(block_area * frac);
348       }
349       if (block_size <= 0) block_size = 1;
350 
351       values.foreground = myBgPixel;
352       values.background = myFgPixel;
353       values.function = GXcopy;
354       values.fill_style = FillSolid;
355       XChangeGC(dpy, patGC,
356             GCForeground | GCBackground | GCFunction | GCFillStyle, &values);
357       XFillRectangle(dpy, win, patGC, x_off, y_off, scroll_area_w,
358             scroll_area_h);
359 
360       values.foreground = myFgPixel;
361       values.background = myBgPixel;
362       values.fill_style = FillOpaqueStippled;
363       values.stipple = patPixmap[SCROLLPAT];
364       XChangeGC(dpy, patGC,
365             GCForeground | GCBackground | GCFillStyle | GCStipple, &values);
366       if (orientation == VERT_SCROLLBAR) {
367          XFillRectangle(dpy, win, patGC, x_off, y_off+block_start,
368                scroll_area_w, block_size);
369       } else {
370          XFillRectangle(dpy, win, patGC, x_off+block_start, y_off, block_size,
371                scroll_area_h);
372       }
373    }
374 }
375 
RedrawVScrollWindow()376 void RedrawVScrollWindow()
377 {
378    double start_frac=(double)0;
379    int total=max(paperHeight,(drawOrigY+drawWinH));
380    XEvent ev;
381 
382    XSync(mainDisplay, False);
383    while (XCheckWindowEvent(mainDisplay, vSBarWindow, ExposureMask, &ev)) ;
384 
385    if (total == 0) {
386       start_frac = (double)1.0;
387    } else {
388       start_frac = (double)((double)drawOrigY / (double)total);
389    }
390    if (start_frac > 1.0) start_frac = 1.0;
391    TgDrawScrollBar(mainDisplay, vSBarWindow, VERT_SCROLLBAR,
392          0, 0, scrollBarW, scrollAreaH, start_frac, drawWinH, total);
393 }
394 
RedrawHScrollWindow()395 void RedrawHScrollWindow()
396 {
397    double start_frac=(double)0;
398    int total=max(paperWidth,(drawOrigX+drawWinW));
399    XEvent ev;
400 
401    XSync(mainDisplay, False);
402    while (XCheckWindowEvent(mainDisplay, hSBarWindow, ExposureMask, &ev)) ;
403 
404    if (total == 0) {
405       start_frac = (double)1.0;
406    } else {
407       start_frac = (double)((double)drawOrigX / (double)total);
408    }
409    if (start_frac > 1.0) start_frac = 1.0;
410    TgDrawScrollBar(mainDisplay, hSBarWindow, HORI_SCROLLBAR,
411          0, 0, scrollAreaW, scrollBarW, start_frac, drawWinW, total);
412 }
413 
RedrawScrollBars()414 void RedrawScrollBars()
415 {
416    if (vSBarWindow != None) RedrawVScrollWindow();
417    if (hSBarWindow != None) RedrawHScrollWindow();
418 }
419 
GetMaxScrollOrigin(pn_orig_x,pn_orig_y)420 void GetMaxScrollOrigin(pn_orig_x, pn_orig_y)
421    int *pn_orig_x, *pn_orig_y;
422 {
423    if (pn_orig_y != NULL) {
424       if (paperHeight <= drawWinH) {
425          *pn_orig_y = 0;
426       } else {
427          switch (gridSystem) {
428          case ENGLISH_GRID:
429             if ((paperHeight-drawWinH) % ABS_SIZE(HALF_INCH) == 0) {
430                *pn_orig_y = paperHeight-drawWinH;
431             } else {
432                *pn_orig_y = max(0, ((int)((paperHeight-drawWinH)/
433                      ABS_SIZE(HALF_INCH)) + 1) * ABS_SIZE(HALF_INCH));
434             }
435             break;
436          case METRIC_GRID:
437             if (zoomedIn && zoomScale > 1) {
438                if ((paperHeight-drawWinH) % ABS_SIZE(FAKE_CM) == 0) {
439                   *pn_orig_y = paperHeight-drawWinH;
440                } else {
441                   *pn_orig_y = max(0, ((int)((paperHeight-drawWinH)/
442                         ABS_SIZE(FAKE_CM)) + 1) * ABS_SIZE(FAKE_CM));
443                }
444             } else {
445                if ((paperHeight-drawWinH) % ABS_SIZE(ONE_CM) == 0) {
446                   *pn_orig_y = paperHeight-drawWinH;
447                } else {
448                   *pn_orig_y = max(0, ((int)((paperHeight-drawWinH)/
449                         ABS_SIZE(ONE_CM)) + 1) * ABS_SIZE(ONE_CM));
450                }
451             }
452             break;
453          }
454       }
455       *pn_orig_y = ABS_SIZE(ZOOMED_SIZE(*pn_orig_y));
456    }
457    if (pn_orig_x != NULL) {
458       if (paperWidth <= drawWinW) {
459           *pn_orig_x = 0;
460       } else {
461          switch (gridSystem) {
462          case ENGLISH_GRID:
463             if ((paperWidth-drawWinW) % ABS_SIZE(HALF_INCH) == 0) {
464                *pn_orig_x = paperWidth-drawWinW;
465             } else {
466                *pn_orig_x = max(0, ((int)((paperWidth-drawWinW)/
467                      ABS_SIZE(HALF_INCH)) + 1) * ABS_SIZE(HALF_INCH));
468             }
469             break;
470          case METRIC_GRID:
471             if (zoomedIn && zoomScale > 1) {
472                if ((paperWidth-drawWinW) % ABS_SIZE(FAKE_CM) == 0) {
473                   *pn_orig_x = paperWidth-drawWinW;
474                } else {
475                   *pn_orig_x = max(0, ((int)((paperWidth-drawWinW)/
476                         ABS_SIZE(FAKE_CM)) + 1) * ABS_SIZE(FAKE_CM));
477                }
478             } else {
479                if ((paperWidth-drawWinW) % ABS_SIZE(ONE_CM) == 0) {
480                   *pn_orig_x = paperWidth-drawWinW;
481                } else {
482                   *pn_orig_x = max(0, ((int)((paperWidth-drawWinW)/
483                         ABS_SIZE(ONE_CM)) + 1) * ABS_SIZE(ONE_CM));
484                }
485             }
486             break;
487          }
488       }
489       *pn_orig_x = ABS_SIZE(ZOOMED_SIZE(*pn_orig_x));
490    }
491 }
492 
ScrollTo(XOff,YOff)493 void ScrollTo(XOff, YOff)
494    int XOff, YOff;
495 {
496    int h_adjust=0, v_adjust=0;
497    static int first_auto_pan_msg=TRUE;
498 
499    if (!autoPan || (XOff >= 0 && ABS_SIZE(XOff) < drawWinW &&
500          YOff >= 0 && ABS_SIZE(YOff) < drawWinH)) {
501       return;
502    }
503    if (XOff < 0) {
504       if (ABS_SIZE(-XOff) > drawOrigX) {
505          h_adjust = (-ZOOMED_SIZE(drawOrigX));
506       } else {
507          switch (gridSystem) {
508          case ENGLISH_GRID:
509             h_adjust = ((-XOff) % HALF_INCH == 0) ? (XOff) :
510                   (((int)((-XOff)/HALF_INCH))+1) * (-HALF_INCH);
511             break;
512          case METRIC_GRID:
513             if (zoomedIn && zoomScale > 1) {
514                h_adjust = ((-XOff) % FAKE_CM == 0) ? (XOff) :
515                      (((int)((-XOff)/FAKE_CM))+1) * (-FAKE_CM);
516             } else {
517                h_adjust = ((-XOff) % ONE_CM == 0) ? (XOff) :
518                      (((int)((-XOff)/ONE_CM))+1) * (-ONE_CM);
519             }
520             break;
521          }
522       }
523    } else if (ABS_SIZE(XOff) >= drawWinW) {
524       switch (gridSystem) {
525       case ENGLISH_GRID:
526          h_adjust = (((int)((XOff-ZOOMED_SIZE(drawWinW))/HALF_INCH))+1) *
527                HALF_INCH;
528          break;
529       case METRIC_GRID:
530          if (zoomedIn && zoomScale > 1) {
531             h_adjust = (((int)((XOff-ZOOMED_SIZE(drawWinW))/FAKE_CM))+1) *
532                   FAKE_CM;
533          } else {
534             h_adjust = (((int)((XOff-ZOOMED_SIZE(drawWinW))/ONE_CM))+1) *
535                   ONE_CM;
536          }
537          break;
538       }
539    }
540    if (YOff < 0) {
541       if (ABS_SIZE(-YOff) > drawOrigY) {
542          v_adjust = (-ZOOMED_SIZE(drawOrigY));
543       } else {
544          switch (gridSystem) {
545          case ENGLISH_GRID:
546             v_adjust = ((-YOff) % HALF_INCH == 0) ? (YOff) :
547                   (((int)((-YOff)/HALF_INCH))+1) * (-HALF_INCH);
548             break;
549          case METRIC_GRID:
550             if (zoomedIn && zoomScale > 1) {
551                v_adjust = ((-YOff) % FAKE_CM == 0) ? (YOff) :
552                      (((int)((-YOff)/FAKE_CM))+1) * (-FAKE_CM);
553             } else {
554                v_adjust = ((-YOff) % ONE_CM == 0) ? (YOff) :
555                      (((int)((-YOff)/ONE_CM))+1) * (-ONE_CM);
556             }
557             break;
558          }
559       }
560    } else if (ABS_SIZE(YOff+(textCursorH>>1)) >= drawWinH) {
561       switch (gridSystem) {
562       case ENGLISH_GRID:
563          v_adjust = (((int)((YOff+(textCursorH>>1) -
564                ZOOMED_SIZE(drawWinH))/HALF_INCH))+1) * HALF_INCH;
565          break;
566       case METRIC_GRID:
567          if (zoomedIn && zoomScale > 1) {
568             v_adjust = (((int)((YOff+(textCursorH>>1) -
569                   ZOOMED_SIZE(drawWinH))/FAKE_CM))+1) * FAKE_CM;
570          } else {
571             v_adjust = (((int)((YOff+(textCursorH>>1) -
572                   ZOOMED_SIZE(drawWinH))/ONE_CM))+1) * ONE_CM;
573          }
574          break;
575       }
576    }
577    if (h_adjust == 0 && v_adjust == 0) return;
578 
579    if (first_auto_pan_msg) {
580       first_auto_pan_msg = FALSE;
581       sprintf(gszMsgBox, TgLoadString(STID_TURN_OFF_AUTO_PAN_SET_XDEF),
582             TOOL_NAME, "AutoPanInEditText");
583       Msg(gszMsgBox);
584    }
585    drawOrigX += ABS_SIZE(h_adjust);
586    drawOrigY += ABS_SIZE(v_adjust);
587    RedrawScrollBars();
588    UpdDrawWinBBox();
589    AdjSplineVs();
590    AdjustCurText((-h_adjust), (-v_adjust));
591    RedrawRulers();
592    ClearAndRedrawDrawWindow();
593 }
594 
ScrollUp(button_ev)595 void ScrollUp(button_ev)
596    XButtonEvent *button_ev;
597 {
598    int adjustment=0;
599 
600    if (drawOrigY != 0) {
601       switch (gridSystem) {
602       case ENGLISH_GRID:
603          if (button_ev!=NULL &&
604                (button_ev->state & (ShiftMask|ControlMask))) {
605             adjustment = ((int)(ZOOMED_SIZE(drawWinH)/HALF_INCH))*HALF_INCH;
606             if (drawOrigY-ABS_SIZE(adjustment) < 0) {
607                adjustment = ZOOMED_SIZE(drawOrigY);
608             }
609          } else {
610             adjustment = HALF_INCH;
611          }
612          break;
613       case METRIC_GRID:
614          if (zoomedIn && zoomScale > 1) {
615             if (button_ev!=NULL &&
616                   (button_ev->state & (ShiftMask|ControlMask))) {
617                adjustment = ((int)(ZOOMED_SIZE(drawWinH)/FAKE_CM))*FAKE_CM;
618                if (drawOrigY-ABS_SIZE(adjustment) < 0)
619                   adjustment = ZOOMED_SIZE(drawOrigY);
620             } else {
621                adjustment = FAKE_CM;
622             }
623          } else {
624             if (button_ev!=NULL &&
625                   (button_ev->state & (ShiftMask|ControlMask))) {
626                adjustment = ((int)(ZOOMED_SIZE(drawWinH)/ONE_CM))*ONE_CM;
627                if (drawOrigY-ABS_SIZE(adjustment) < 0)
628                   adjustment = ZOOMED_SIZE(drawOrigY);
629             } else {
630                adjustment = ONE_CM;
631             }
632          }
633          break;
634       }
635       if (drawOrigY >= ABS_SIZE(adjustment)) {
636          drawOrigY -= ABS_SIZE(adjustment);
637       } else {
638          adjustment = ZOOMED_SIZE(drawOrigY);
639          drawOrigY -= ABS_SIZE(adjustment);
640          if (drawOrigY < 0) drawOrigY = 0;
641       }
642       RedrawVScrollWindow();
643       UpdDrawWinBBox();
644       AdjSplineVs();
645       AdjustCurText(0, adjustment);
646       RedrawRulers();
647       ClearAndRedrawDrawWindow();
648    }
649 }
650 
ForceScrollDown(ScrollAFullWindow)651 void ForceScrollDown(ScrollAFullWindow)
652    int ScrollAFullWindow;
653 {
654    int adjustment=0;
655 
656    switch (gridSystem) {
657    case ENGLISH_GRID:
658       if (ScrollAFullWindow) {
659          adjustment = ((int)(ZOOMED_SIZE(drawWinH)/HALF_INCH))*HALF_INCH;
660       } else {
661          adjustment = HALF_INCH;
662       }
663       break;
664    case METRIC_GRID:
665       if (zoomedIn && zoomScale > 1) {
666          if (ScrollAFullWindow) {
667             adjustment = ((int)(ZOOMED_SIZE(drawWinH)/FAKE_CM))*FAKE_CM;
668          } else {
669             adjustment = FAKE_CM;
670          }
671       } else {
672          if (ScrollAFullWindow) {
673             adjustment = ((int)(ZOOMED_SIZE(drawWinH)/ONE_CM))*ONE_CM;
674          } else {
675             adjustment = ONE_CM;
676          }
677       }
678       break;
679    }
680    drawOrigY += ABS_SIZE(adjustment);
681    RedrawVScrollWindow();
682    UpdDrawWinBBox();
683    AdjSplineVs();
684    AdjustCurText(0, -adjustment);
685    RedrawRulers();
686    ClearAndRedrawDrawWindow();
687 }
688 
ScrollDown(button_ev)689 void ScrollDown(button_ev)
690    XButtonEvent *button_ev;
691 {
692    if (paperHeight <= drawWinH) return;
693 
694    if (drawOrigY+drawWinH < paperHeight) {
695       ForceScrollDown(button_ev != NULL &&
696             (button_ev->state & (ShiftMask|ControlMask)));
697    }
698 }
699 
700 typedef struct tagSBarInfo {
701    int scroll_page, scroll_dir;
702 } SBarInfo;
703 
704 static
ScrollBtnCallback(pv_userdata)705 int ScrollBtnCallback(pv_userdata)
706    void *pv_userdata;
707    /* returns TRUE to cancel scrolling */
708 {
709    SBarInfo *psbi=((SBarInfo*)(pv_userdata));
710    XButtonEvent btn_ev;
711 
712    btn_ev.state = (psbi->scroll_page ? ShiftMask : 0);
713    switch (psbi->scroll_dir) {
714    case SCRL_UP: ScrollUp(&btn_ev); break;
715    case SCRL_DN: ScrollDown(&btn_ev); break;
716    case SCRL_LF: ScrollLeft(&btn_ev); break;
717    case SCRL_RT: ScrollRight(&btn_ev); break;
718    }
719    return FALSE;
720 }
721 
722 static
DoSBarBtnScroll(dpy,win,scroll_page,scroll_dir,pbbox)723 int DoSBarBtnScroll(dpy, win, scroll_page, scroll_dir, pbbox)
724    Display *dpy;
725    Window win;
726    int scroll_page, scroll_dir;
727    struct BBRec *pbbox;
728    /* returns TRUE if the done scrolling */
729 {
730    ScrollBtnCallbackInfo sbci;
731    SBarInfo sbi;
732 
733    memset(&sbi, 0, sizeof(SBarInfo));
734    sbi.scroll_page = scroll_page;
735    sbi.scroll_dir = scroll_dir;
736 
737    memset(&sbci, 0, sizeof(ScrollBtnCallbackInfo));
738    sbci.ms = (scroll_page ? 300 : 200);
739    sbci.pv_userdata = ((void*)(&sbi));
740    sbci.pf_scroll_btn_callback = ScrollBtnCallback;
741    if (TgPressButtonLoop(dpy, win, pbbox, &sbci)) {
742       XButtonEvent btn_ev;
743 
744       btn_ev.state = (scroll_page ? ShiftMask : 0);
745       switch (scroll_dir) {
746       case SCRL_UP: ScrollUp(&btn_ev); break;
747       case SCRL_DN: ScrollDown(&btn_ev); break;
748       case SCRL_LF: ScrollLeft(&btn_ev); break;
749       case SCRL_RT: ScrollRight(&btn_ev); break;
750       }
751    }
752    return FALSE;
753 }
754 
755 static
DragToInVSBar(lty,block_start,block_h)756 void DragToInVSBar(lty, block_start, block_h)
757    int lty, block_start, block_h;
758 {
759    double start_frac=(double)0.0;
760    int saved_y=drawOrigY, adjustment=0, scroll_all_the_way=FALSE;
761 
762    if (threeDLook) {
763       start_frac = (double)(((double)(lty-scrollBarW)) /
764             ((double)(scrollAreaH-(scrollBarW<<1))));
765       if (lty+block_h >= scrollAreaH-scrollBarW) {
766          scroll_all_the_way = TRUE;
767       }
768    } else {
769       start_frac = (double)(((double)block_start)/((double)scrollAreaH));
770       if (block_start+block_h >= scrollAreaH) {
771          scroll_all_the_way = TRUE;
772       }
773    }
774    if (start_frac < 0.0) start_frac = 0.0;
775    if (start_frac > 1.0) start_frac = 1.0;
776    if (scroll_all_the_way) {
777       GetMaxScrollOrigin(NULL, &drawOrigY);
778    } else {
779       double dv=(double)0;
780 
781       switch (gridSystem) {
782       case ENGLISH_GRID:
783          dv = ((double)paperHeight) * start_frac;
784          break;
785       case METRIC_GRID:
786          if (zoomedIn && zoomScale > 1) {
787             dv = ((double)paperHeight) * start_frac;
788          } else {
789             dv = ((double)paperHeight) * start_frac;
790          }
791          break;
792       }
793       drawOrigY = round(dv);
794       drawOrigY = ABS_SIZE(ZOOMED_SIZE(drawOrigY));
795    }
796    adjustment = saved_y - drawOrigY;
797    if (adjustment != 0) {
798       RedrawVScrollWindow();
799       UpdDrawWinBBox();
800       AdjSplineVs();
801       AdjustCurText(0, ZOOMED_SIZE(adjustment));
802       RedrawRulers();
803       ClearAndRedrawDrawWindow();
804    } else {
805       RedrawVScrollWindow();
806    }
807 }
808 
809 static
DoDragInVSBar(btn_y,btn_offset)810 void DoDragInVSBar(btn_y, btn_offset)
811    int btn_y, btn_offset;
812 {
813    double frac=(double)0.0, start_frac=(double)0.0;
814    int block_h=0, block_start=0, continuous_drag=FALSE;
815    int done=FALSE, lty=0, min_block_size=1+(windowPadding<<1);
816    int total=max(paperHeight,(drawOrigY+drawWinH));
817    XEvent ev;
818 
819    scrollingCanvas = SCRL_UP;
820    if (smoothScrollingCanvas == SMOOTH_SCROLLING) {
821       BeginExecAnimate();
822       if (!TgAnyButtonDown(mainDisplay, vSBarWindow)) {
823          EndExecAnimate();
824          ClearAndRedrawDrawWindow();
825          return;
826       }
827       continuous_drag = execAnimating;
828    }
829    block_start = btn_y+btn_offset;
830    frac = (double)((double)drawWinH / (double)(paperHeight));
831    if (threeDLook) {
832       start_frac = (double)(((double)(block_start-scrollBarW)) /
833             ((double)(scrollAreaH-(scrollBarW<<1))));
834       block_h = (frac >= 1.0) ? (scrollAreaH-(scrollBarW<<1)) :
835             (int)(((double)(scrollAreaH-(scrollBarW<<1))) * frac);
836       if (block_h < min_block_size) block_h = min_block_size;
837       lty = (start_frac + frac >= 1.0) ? scrollAreaH-scrollBarW-block_h :
838             block_start;
839       start_frac = (double)(((double)(lty-scrollBarW)) /
840             ((double)(scrollAreaH-(scrollBarW<<1))));
841    } else {
842       start_frac = (double)(((double)block_start)/((double)scrollAreaH));
843       block_h = (frac >= 1.0) ? scrollAreaH :
844             (int)(((double)scrollAreaH) * frac);
845       if (block_h < 1) block_h = 1;
846       lty = (start_frac + frac >= 1.0) ? scrollAreaH-block_h : block_start;
847       start_frac = (double)(((double)lty)/((double)scrollAreaH));
848    }
849    TgDrawScrollBar(mainDisplay, vSBarWindow, VERT_SCROLLBAR, 0, 0, scrollBarW,
850          scrollAreaH, start_frac, drawWinH, total);
851    XGrabPointer(mainDisplay, vSBarWindow, False,
852          PointerMotionMask | ButtonReleaseMask, GrabModeAsync,
853          GrabModeAsync, None, handCursor, CurrentTime);
854 
855    while (!done) {
856       XNextEvent(mainDisplay, &ev);
857 
858       if (ev.type == Expose || ev.type == VisibilityNotify) {
859          ExposeEventHandler(&ev, TRUE);
860       } else if (ev.type == ButtonRelease) {
861          XUngrabPointer(mainDisplay, CurrentTime);
862          done = TRUE;
863       } else if (ev.type == MotionNotify) {
864          int new_y=0;
865 
866          block_start = ev.xmotion.y;
867 
868          if (threeDLook) {
869             new_y = ev.xmotion.y+btn_offset;
870             if (new_y < scrollBarW) {
871                new_y = scrollBarW;
872             } else if (new_y+block_h >= scrollAreaH-scrollBarW) {
873                new_y = scrollAreaH-block_h-scrollBarW;
874             }
875             if (new_y != lty) {
876                lty = new_y;
877                start_frac = (double)(((double)(lty-scrollBarW)) /
878                      ((double)(scrollAreaH-(scrollBarW<<1))));
879                TgDrawScrollBar(mainDisplay, vSBarWindow, VERT_SCROLLBAR, 0, 0,
880                      scrollBarW, scrollAreaH, start_frac, drawWinH, total);
881             }
882          } else {
883             if (block_start <= 0) {
884                new_y = 0;
885             } else if (block_start+block_h >= scrollAreaH) {
886                new_y = scrollAreaH-block_h;
887             } else {
888                new_y = block_start;
889             }
890             if (new_y != lty) {
891                lty = new_y;
892                start_frac = (double)(((double)lty)/((double)scrollAreaH));
893                TgDrawScrollBar(mainDisplay, vSBarWindow, VERT_SCROLLBAR, 0, 0,
894                      scrollBarW, scrollAreaH, start_frac, drawWinH, total);
895             }
896          }
897          if (continuous_drag) {
898             int scroll_all_the_way=FALSE;
899 
900             if (threeDLook) {
901                start_frac = (double)(((double)(lty-scrollBarW)) /
902                      ((double)(scrollAreaH-(scrollBarW<<1))));
903                if (lty+block_h >= scrollAreaH-scrollBarW) {
904                   scroll_all_the_way = TRUE;
905                }
906             } else {
907                start_frac = (double)(((double)lty)/((double)scrollAreaH));
908                if (block_start+block_h >= scrollAreaH) {
909                   scroll_all_the_way = TRUE;
910                }
911             }
912             RedrawAreaFromCache(start_frac, scroll_all_the_way);
913          } else if (smoothScrollingCanvas == JUMP_SCROLLING) {
914             DragToInVSBar(lty, block_start, block_h);
915          }
916          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
917       }
918    }
919    if (smoothScrollingCanvas == SMOOTH_SCROLLING) {
920       EndExecAnimate();
921       RedrawCurText();
922    }
923    scrollingCanvas = INVALID;
924 
925    DragToInVSBar(lty, block_start, block_h);
926 }
927 
928 static
VSBarHandler(button_ev)929 void VSBarHandler(button_ev)
930    XButtonEvent *button_ev;
931 {
932    int do_drag=FALSE, btn_offset=0;
933    int total=max(paperHeight,(drawOrigY+drawWinH));
934 
935    if (!threeDLook && button_ev->button == Button3 &&
936          button_ev->type == ButtonPress) {
937       DoSBarBtnScroll(mainDisplay, vSBarWindow,
938             ((button_ev->state & (ShiftMask|ControlMask)) != 0), SCRL_UP, NULL);
939    } else if (!threeDLook && button_ev->button == Button1 &&
940          button_ev->type == ButtonPress) {
941       DoSBarBtnScroll(mainDisplay, vSBarWindow,
942             ((button_ev->state & (ShiftMask|ControlMask)) != 0), SCRL_DN, NULL);
943    } else if (button_ev->button == Button1 && button_ev->type == ButtonPress) {
944       if (button_ev->y < scrollBarW ||
945             button_ev->y >= scrollAreaH-scrollBarW) {
946          int which=0;
947          struct BBRec bbox;
948 
949          if (button_ev->y < scrollBarW) {
950             which = SCRL_UP;
951             SetBBRec(&bbox, 0, 0, scrollBarW, scrollBarW);
952          } else {
953             which = SCRL_DN;
954             SetBBRec(&bbox, 0, scrollAreaH-scrollBarW, scrollBarW,
955                   scrollAreaH);
956          }
957          DoSBarBtnScroll(mainDisplay, vSBarWindow, FALSE, which, &bbox);
958       } else {
959          double start_frac=(double)0.0;
960          int hit=0;
961 
962          if (total == 0) {
963             start_frac = (double)1.0;
964          } else {
965             start_frac = (double)((double)drawOrigY / (double)total);
966          }
967          if (start_frac > 1.0) start_frac = 1.0;
968          hit = TgGetScrollHit(button_ev->x, button_ev->y, VERT_SCROLLBAR,
969                scrollBarW, scrollAreaH, start_frac, drawWinH, total,
970                &btn_offset);
971          if (hit == 0) {
972             do_drag = TRUE;
973          } else {
974             DoSBarBtnScroll(mainDisplay, vSBarWindow, TRUE,
975                   (hit < 0 ? SCRL_UP : SCRL_DN), NULL);
976          }
977       }
978    } else if (!threeDLook && button_ev->button == Button2 &&
979          button_ev->type == ButtonPress) {
980       do_drag = TRUE;
981    }
982    if (do_drag) {
983       DoDragInVSBar(button_ev->y, btn_offset);
984    }
985 }
986 
ScrollLeft(button_ev)987 void ScrollLeft(button_ev)
988    XButtonEvent *button_ev;
989 {
990    int adjustment=0;
991 
992    if (drawOrigX != 0) {
993       switch (gridSystem) {
994       case ENGLISH_GRID:
995          if (button_ev!=NULL &&
996                (button_ev->state & (ShiftMask|ControlMask))) {
997             adjustment = ((int)(ZOOMED_SIZE(drawWinW)/HALF_INCH))*HALF_INCH;
998             if (drawOrigX-ABS_SIZE(adjustment) < 0) {
999                adjustment = ZOOMED_SIZE(drawOrigX);
1000             }
1001          } else {
1002             adjustment = HALF_INCH;
1003          }
1004          break;
1005       case METRIC_GRID:
1006          if (zoomedIn && zoomScale > 1) {
1007             if (button_ev!=NULL &&
1008                   (button_ev->state & (ShiftMask|ControlMask))) {
1009                adjustment = ((int)(ZOOMED_SIZE(drawWinW)/FAKE_CM))*FAKE_CM;
1010                if (drawOrigX-ABS_SIZE(adjustment) < 0) {
1011                   adjustment = ZOOMED_SIZE(drawOrigX);
1012                }
1013             } else {
1014                adjustment = FAKE_CM;
1015             }
1016          } else {
1017             if (button_ev!=NULL &&
1018                   (button_ev->state & (ShiftMask|ControlMask))) {
1019                adjustment = ((int)(ZOOMED_SIZE(drawWinW)/ONE_CM))*ONE_CM;
1020                if (drawOrigX-ABS_SIZE(adjustment) < 0) {
1021                   adjustment = ZOOMED_SIZE(drawOrigX);
1022                }
1023             } else {
1024                adjustment = ONE_CM;
1025             }
1026          }
1027          break;
1028       }
1029       if (drawOrigX >= ABS_SIZE(adjustment)) {
1030          drawOrigX -= ABS_SIZE(adjustment);
1031       } else {
1032          adjustment = ZOOMED_SIZE(drawOrigX);
1033          drawOrigX -= ABS_SIZE(adjustment);
1034          if (drawOrigX < 0) drawOrigX = 0;
1035       }
1036       RedrawHScrollWindow();
1037       UpdDrawWinBBox();
1038       AdjSplineVs();
1039       AdjustCurText(adjustment, 0);
1040       RedrawHRulerWindow();
1041       ClearAndRedrawDrawWindow();
1042    }
1043 }
1044 
ScrollRight(button_ev)1045 void ScrollRight(button_ev)
1046    XButtonEvent *button_ev;
1047 {
1048    int adjustment=0;
1049 
1050    if (paperWidth <= drawWinW) return;
1051 
1052    if (drawOrigX+drawWinW < paperWidth) {
1053       switch (gridSystem) {
1054       case ENGLISH_GRID:
1055          if (button_ev!=NULL && (button_ev->state & (ShiftMask|ControlMask))) {
1056             adjustment = ((int)(ZOOMED_SIZE(drawWinW)/HALF_INCH))*HALF_INCH;
1057          } else {
1058             adjustment = HALF_INCH;
1059          }
1060          break;
1061       case METRIC_GRID:
1062          if (zoomedIn && zoomScale > 1) {
1063             if (button_ev!=NULL &&
1064                   (button_ev->state & (ShiftMask|ControlMask))) {
1065                adjustment = ((int)(ZOOMED_SIZE(drawWinW)/FAKE_CM))*FAKE_CM;
1066             } else {
1067                adjustment = FAKE_CM;
1068             }
1069          } else {
1070             if (button_ev!=NULL &&
1071                   (button_ev->state & (ShiftMask|ControlMask))) {
1072                adjustment = ((int)(ZOOMED_SIZE(drawWinW)/ONE_CM))*ONE_CM;
1073             } else {
1074                adjustment = ONE_CM;
1075             }
1076          }
1077          break;
1078       }
1079       drawOrigX += ABS_SIZE(adjustment);
1080       RedrawHScrollWindow();
1081       UpdDrawWinBBox();
1082       AdjSplineVs();
1083       AdjustCurText(-adjustment, 0);
1084       RedrawHRulerWindow();
1085       ClearAndRedrawDrawWindow();
1086    }
1087 }
1088 
1089 static
DragToInHSBar(ltx,block_start,block_w)1090 void DragToInHSBar(ltx, block_start, block_w)
1091    int ltx, block_start, block_w;
1092 {
1093    double start_frac=(double)0.0;
1094    int saved_x=drawOrigX, adjustment=0, scroll_all_the_way=FALSE;
1095 
1096    if (threeDLook) {
1097       start_frac = (double)((double)(ltx-scrollBarW) /
1098             (double)(scrollAreaW-(scrollBarW<<1)));
1099       if (ltx+block_w >= scrollAreaW-scrollBarW) {
1100          scroll_all_the_way = TRUE;
1101       }
1102    } else {
1103       start_frac = (double)((double)(block_start)/(double)(scrollAreaW));
1104       if (block_start+block_w >= scrollAreaW) {
1105          scroll_all_the_way = TRUE;
1106       }
1107    }
1108    if (start_frac < 0.0) start_frac = 0.0;
1109    if (start_frac > 1.0) start_frac = 1.0;
1110    if (scroll_all_the_way) {
1111       GetMaxScrollOrigin(&drawOrigX, NULL);
1112    } else {
1113       double dv=(double)0;
1114 
1115       switch (gridSystem) {
1116       case ENGLISH_GRID:
1117          dv = ((double)paperWidth) * start_frac;
1118          break;
1119       case METRIC_GRID:
1120          if (zoomedIn && zoomScale > 1) {
1121             dv = ((double)paperWidth) * start_frac;
1122          } else {
1123             dv = ((double)paperWidth) * start_frac;
1124          }
1125          break;
1126       }
1127       drawOrigX = round(dv);
1128       drawOrigX = ABS_SIZE(ZOOMED_SIZE(drawOrigX));
1129    }
1130    adjustment = saved_x - drawOrigX;
1131    if (adjustment != 0) {
1132       RedrawHScrollWindow();
1133       UpdDrawWinBBox();
1134       AdjSplineVs();
1135       AdjustCurText(ZOOMED_SIZE(adjustment), 0);
1136       RedrawHRulerWindow();
1137       ClearAndRedrawDrawWindow();
1138    } else {
1139       RedrawHScrollWindow();
1140    }
1141 }
1142 
1143 static
DoDragInHSBar(btn_x,btn_offset)1144 void DoDragInHSBar(btn_x, btn_offset)
1145    int btn_x, btn_offset;
1146 {
1147    double frac=(double)0.0, start_frac=(double)0.0;
1148    int block_w=0, block_start=0, continuous_drag=FALSE;
1149    int done=FALSE, ltx=0, min_block_size=1+(windowPadding<<1);
1150    int total=max(paperWidth,(drawOrigX+drawWinW));
1151    XEvent ev;
1152 
1153    scrollingCanvas = SCRL_LF;
1154    if (smoothScrollingCanvas == SMOOTH_SCROLLING) {
1155       BeginExecAnimate();
1156       if (!TgAnyButtonDown(mainDisplay, vSBarWindow)) {
1157          EndExecAnimate();
1158          ClearAndRedrawDrawWindow();
1159          return;
1160       }
1161       continuous_drag = execAnimating;
1162    }
1163    block_start = btn_x+btn_offset;
1164    frac = (double)(((double)drawWinW) / ((double)paperWidth));
1165    if (threeDLook) {
1166       start_frac = (double)(((double)(block_start-scrollBarW)) /
1167             ((double)(scrollAreaW-(scrollBarW<<1))));
1168       block_w = (frac >= 1.0) ? (scrollAreaW-(scrollBarW<<1)) :
1169             (int)(((double)(scrollAreaW-(scrollBarW<<1))) * frac);
1170       if (block_w < min_block_size) block_w = min_block_size;
1171       ltx = (start_frac + frac >= 1.0) ? scrollAreaW-scrollBarW-block_w :
1172             block_start;
1173       start_frac = (double)(((double)(ltx-scrollBarW)) /
1174             ((double)(scrollAreaW-(scrollBarW<<1))));
1175    } else {
1176       start_frac = (double)(((double)block_start)/((double)scrollAreaW));
1177       block_w = (frac >= 1.0) ? scrollAreaW :
1178             (int)(((double)scrollAreaW) * frac);
1179       if (block_w <= 0) block_w = 1;
1180       ltx = (start_frac + frac >= 1.0) ? scrollAreaW-block_w : block_start;
1181       start_frac = (double)(((double)ltx)/((double)scrollAreaW));
1182    }
1183    TgDrawScrollBar(mainDisplay, hSBarWindow, HORI_SCROLLBAR,
1184          0, 0, scrollAreaW, scrollBarW, start_frac, drawWinW, total);
1185    XGrabPointer(mainDisplay, hSBarWindow, False,
1186          PointerMotionMask | ButtonReleaseMask, GrabModeAsync,
1187          GrabModeAsync, None, handCursor, CurrentTime);
1188 
1189    while (!done) {
1190       XNextEvent(mainDisplay, &ev);
1191 
1192       if (ev.type == Expose || ev.type == VisibilityNotify) {
1193          ExposeEventHandler(&ev, TRUE);
1194       } else if (ev.type == ButtonRelease) {
1195          XUngrabPointer(mainDisplay, CurrentTime);
1196          done = TRUE;
1197       } else if (ev.type == MotionNotify) {
1198          int new_x=0;
1199 
1200          block_start = ev.xmotion.x;
1201 
1202          if (threeDLook) {
1203             new_x = ev.xmotion.x+btn_offset;
1204             if (new_x < scrollBarW) {
1205                new_x = scrollBarW;
1206             } else if (new_x+block_w >= scrollAreaW-scrollBarW) {
1207                new_x = scrollAreaW-block_w-scrollBarW;
1208             }
1209             if (new_x != ltx) {
1210                ltx = new_x;
1211                start_frac = (double)(((double)(ltx-scrollBarW)) /
1212                      ((double)(scrollAreaW-(scrollBarW<<1))));
1213                TgDrawScrollBar(mainDisplay, hSBarWindow, HORI_SCROLLBAR, 0, 0,
1214                      scrollAreaW, scrollBarW, start_frac, drawWinW, total);
1215             }
1216          } else {
1217             if (block_start <= 0) {
1218                new_x = 0;
1219             } else if (block_start+block_w >= scrollAreaW) {
1220                new_x = scrollAreaW-block_w;
1221             } else {
1222                new_x = block_start;
1223             }
1224             if (new_x != ltx) {
1225                ltx = new_x;
1226                start_frac = (double)(((double)ltx)/((double)scrollAreaW));
1227                TgDrawScrollBar(mainDisplay, hSBarWindow, HORI_SCROLLBAR, 0, 0,
1228                      scrollAreaW, scrollBarW, start_frac, drawWinW, total);
1229             }
1230          }
1231          if (continuous_drag) {
1232             int scroll_all_the_way=FALSE;
1233 
1234             if (threeDLook) {
1235                start_frac = (double)(((double)(ltx-scrollBarW)) /
1236                      ((double)(scrollAreaW-(scrollBarW<<1))));
1237                if (ltx+block_w >= scrollAreaW-scrollBarW) {
1238                   scroll_all_the_way = TRUE;
1239                }
1240             } else {
1241                start_frac = (double)(((double)ltx)/((double)scrollAreaW));
1242                if (block_start+block_w >= scrollAreaW) {
1243                   scroll_all_the_way = TRUE;
1244                }
1245             }
1246             RedrawAreaFromCache(start_frac, scroll_all_the_way);
1247          } else if (smoothScrollingCanvas == JUMP_SCROLLING) {
1248             DragToInHSBar(ltx, block_start, block_w);
1249          }
1250          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1251       }
1252    }
1253    if (smoothScrollingCanvas == SMOOTH_SCROLLING) {
1254       EndExecAnimate();
1255       RedrawCurText();
1256    }
1257    scrollingCanvas = INVALID;
1258 
1259    DragToInHSBar(ltx, block_start, block_w);
1260 }
1261 
1262 static
HSBarHandler(button_ev)1263 void HSBarHandler(button_ev)
1264    XButtonEvent *button_ev;
1265 {
1266    int do_drag=FALSE, btn_offset=0;
1267    int total=max(paperWidth,(drawOrigX+drawWinW));
1268 
1269    if (!threeDLook && button_ev->button == Button3 &&
1270          button_ev->type == ButtonPress) {
1271       DoSBarBtnScroll(mainDisplay, hSBarWindow,
1272             ((button_ev->state & (ShiftMask|ControlMask)) != 0), SCRL_LF, NULL);
1273    } else if (!threeDLook && button_ev->button == Button1 &&
1274          button_ev->type == ButtonPress) {
1275       DoSBarBtnScroll(mainDisplay, hSBarWindow,
1276             ((button_ev->state & (ShiftMask|ControlMask)) != 0), SCRL_RT, NULL);
1277    } else if (button_ev->button == Button1 && button_ev->type == ButtonPress) {
1278       if (button_ev->x < scrollBarW ||
1279             button_ev->x >= scrollAreaW-scrollBarW) {
1280          int which=0;
1281          struct BBRec bbox;
1282 
1283          if (button_ev->x < scrollBarW) {
1284             which = SCRL_LF;
1285             SetBBRec(&bbox, 0, 0, scrollBarW, scrollBarW);
1286          } else {
1287             which = SCRL_RT;
1288             SetBBRec(&bbox, scrollAreaW-scrollBarW, 0, scrollAreaW,
1289                   scrollBarW);
1290          }
1291          DoSBarBtnScroll(mainDisplay, hSBarWindow, FALSE, which, &bbox);
1292       } else {
1293          double start_frac=(double)0.0;
1294          int hit=0;
1295 
1296          if (total == 0) {
1297             start_frac = (double)1.0;
1298          } else {
1299             start_frac = (double)((double)drawOrigX / (double)total);
1300          }
1301          if (start_frac > 1.0) start_frac = 1.0;
1302          hit = TgGetScrollHit(button_ev->x, button_ev->y, HORI_SCROLLBAR,
1303                scrollAreaW, scrollBarW, start_frac, drawWinW, total,
1304                &btn_offset);
1305          if (hit == 0) {
1306             do_drag = TRUE;
1307          } else {
1308             DoSBarBtnScroll(mainDisplay, hSBarWindow, TRUE,
1309                   (hit < 0 ? SCRL_LF : SCRL_RT), NULL);
1310          }
1311       }
1312    } else if (!threeDLook && button_ev->button == Button2 &&
1313          button_ev->type == ButtonPress) {
1314       do_drag = TRUE;
1315    }
1316    if (do_drag) {
1317       DoDragInHSBar(button_ev->x, btn_offset);
1318    }
1319 }
1320 
ScrollEventHandler(input)1321 void ScrollEventHandler(input)
1322    XEvent *input;
1323 {
1324    if (input->xany.window == vSBarWindow) {
1325       if (input->type == Expose) {
1326          XSync(mainDisplay, False);
1327          RedrawVScrollWindow();
1328          return;
1329       } else if (input->type == MotionNotify) {
1330          if (threeDLook) {
1331             if (input->xmotion.y < scrollBarW) {
1332                SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_UP), "", "");
1333             } else if (input->xmotion.y >= scrollAreaH-scrollBarW) {
1334                SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_DOWN), "", "");
1335             } else {
1336                int total=max(paperHeight,(drawOrigY+drawWinH)), hit=FALSE;
1337                double start_frac=(double)0.0;
1338 
1339                if (total == 0) {
1340                   start_frac = (double)1.0;
1341                } else {
1342                   start_frac = (double)((double)drawOrigY / (double)total);
1343                }
1344                if (start_frac > 1.0) start_frac = 1.0;
1345                hit = TgGetScrollHit(input->xmotion.x, input->xmotion.y,
1346                      VERT_SCROLLBAR, scrollBarW, scrollAreaH, start_frac,
1347                      drawWinH, total, NULL);
1348                if (hit < 0) {
1349                   SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_PAGE_UP),
1350                         "", "");
1351                } else if (hit > 0) {
1352                   SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_PAGE_DOWN),
1353                         "", "");
1354                } else {
1355                   SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_VERTICALLY),
1356                         "", "");
1357                }
1358             }
1359          }
1360          return;
1361       } else if (input->type == EnterNotify) {
1362          if (threeDLook) {
1363             SetMouseStatus("", "", "");
1364          } else {
1365             SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_DOWN),
1366                   TgLoadCachedString(CSTID_SCROLL_VERTICALLY),
1367                   TgLoadCachedString(CSTID_SCROLL_UP));
1368          }
1369          return;
1370       }
1371       Msg("");
1372       VSBarHandler(&(input->xbutton));
1373       return;
1374    } else if (input->xany.window == hSBarWindow) {
1375       if (input->type == Expose) {
1376          XSync(mainDisplay, False);
1377          RedrawHScrollWindow();
1378          return;
1379       } else if (input->type == MotionNotify) {
1380          if (threeDLook) {
1381             if (input->xmotion.x < scrollBarW) {
1382                SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_LEFT), "", "");
1383             } else if (input->xmotion.x >= scrollAreaW-scrollBarW) {
1384                SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_RIGHT), "", "");
1385             } else {
1386                int total=max(paperWidth,(drawOrigX+drawWinW)), hit=FALSE;
1387                double start_frac=(double)0.0;
1388 
1389                if (total == 0) {
1390                   start_frac = (double)1.0;
1391                } else {
1392                   start_frac=(double)((double)drawOrigX / (double)total);
1393                }
1394                if (start_frac > 1.0) start_frac = 1.0;
1395                hit = TgGetScrollHit(input->xmotion.x, input->xmotion.y,
1396                      HORI_SCROLLBAR, scrollAreaW, scrollBarW, start_frac,
1397                      drawWinW, total, NULL);
1398                if (hit < 0) {
1399                   SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_PAGE_LEFT),
1400                         "", "");
1401                } else if (hit > 0) {
1402                   SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_PAGE_RIGHT),
1403                         "", "");
1404                } else {
1405                   SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_HORIZONTALLY),
1406                         "", "");
1407                }
1408             }
1409          }
1410          return;
1411       } else if (input->type == EnterNotify) {
1412          if (threeDLook) {
1413             SetMouseStatus("", "", "");
1414          } else {
1415             SetMouseStatus(TgLoadCachedString(CSTID_SCROLL_RIGHT),
1416                   TgLoadCachedString(CSTID_SCROLL_HORIZONTALLY),
1417                   TgLoadCachedString(CSTID_SCROLL_LEFT));
1418          }
1419          return;
1420       }
1421       Msg("");
1422       HSBarHandler(&(input->xbutton));
1423       return;
1424    }
1425 }
1426 
ScrollToSpecifiedOrigin(cur_page_num,orig_x,orig_y,zoom_scale,zoomed_in)1427 void ScrollToSpecifiedOrigin(cur_page_num, orig_x, orig_y, zoom_scale,
1428       zoomed_in)
1429    int cur_page_num, orig_x, orig_y, zoom_scale, zoomed_in;
1430 {
1431    int adj_caches=(zoomScale != zoom_scale || zoomedIn != zoomed_in);
1432 
1433    if (cur_page_num <= 0 || cur_page_num > lastPageNum) return;
1434    if (drawOrigX == orig_x && drawOrigY == orig_y &&
1435          cur_page_num == curPageNum && !adj_caches) {
1436       return;
1437    }
1438    drawOrigX = orig_x;
1439    drawOrigY = orig_y;
1440    zoomScale = zoom_scale;
1441    zoomedIn = zoomed_in;
1442    UpdDrawWinWH();
1443 
1444    UpdDrawWinBBox();
1445    AdjSplineVs();
1446    if (adj_caches) { AdjCaches(); ShowZoom(); }
1447 
1448    if (cur_page_num != curPageNum) {
1449       GotoPageNum(cur_page_num);
1450       ShowPage();
1451    }
1452    ClearAndRedrawDrawWindow();
1453    RedrawRulers();
1454    RedrawScrollBars();
1455    justDupped = FALSE;
1456 }
1457 
1458 static int xOrigin=0, yOrigin=0, zoomScaleOrigin=0, zoomedInOrigin=FALSE;
1459 
ScrollToOrigin()1460 int ScrollToOrigin()
1461    /*
1462     * return TRUE of scrolled or zoomed
1463     */
1464 {
1465    int adj_caches=(zoomScale!=zoomScaleOrigin || zoomedIn!=zoomedInOrigin);
1466 
1467    if (drawOrigX==xOrigin && drawOrigY==yOrigin && !adj_caches) {
1468       return FALSE;
1469    }
1470    TieLooseEnds();
1471    SetCurChoice(NOTHING);
1472 
1473    drawOrigX = xOrigin;
1474    drawOrigY = yOrigin;
1475    zoomScale = zoomScaleOrigin;
1476    zoomedIn = zoomedInOrigin;
1477    UpdDrawWinWH();
1478 
1479    UpdDrawWinBBox();
1480    AdjSplineVs();
1481    if (adj_caches) { AdjCaches(); ShowZoom(); }
1482    ClearAndRedrawDrawWindow();
1483    RedrawRulers();
1484    RedrawScrollBars();
1485    justDupped = FALSE;
1486 
1487    return TRUE;
1488 }
1489 
SaveOrigin()1490 void SaveOrigin()
1491 {
1492    xOrigin = drawOrigX;
1493    yOrigin = drawOrigY;
1494    zoomScaleOrigin = zoomScale;
1495    zoomedInOrigin = zoomedIn;
1496 }
1497 
SetOrigin(x,y,zoom_scale,zoomed_in)1498 void SetOrigin(x, y, zoom_scale, zoomed_in)
1499    int x, y, zoom_scale, zoomed_in;
1500 {
1501    xOrigin = x;
1502    yOrigin = y;
1503    zoomScaleOrigin = zoom_scale;
1504    zoomedInOrigin = zoomed_in;
1505 }
1506 
GetOrigin(pn_x,pn_y,pn_zoom_scale,pn_zoomed_in)1507 void GetOrigin(pn_x, pn_y, pn_zoom_scale, pn_zoomed_in)
1508    int *pn_x, *pn_y, *pn_zoom_scale, *pn_zoomed_in;
1509 {
1510    *pn_x = xOrigin;
1511    *pn_y = yOrigin;
1512    *pn_zoom_scale = zoomScaleOrigin;
1513    *pn_zoomed_in = zoomedInOrigin;
1514 }
1515 
CleanUpScrolls()1516 void CleanUpScrolls()
1517 {
1518    if (scrl_up_bits == NULL) { }
1519 }
1520 
UpdScrollWinWH()1521 void UpdScrollWinWH()
1522 {
1523    scrollAreaH = vSBarH;
1524    scrollAreaW = hSBarW;
1525    RedrawScrollBars();
1526 }
1527 
InitScroll()1528 void InitScroll()
1529 {
1530    char *c_ptr=NULL;
1531 
1532    smoothScrollingCanvas = JUMP_SCROLLING;
1533    if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME, "SmoothScrollingCanvas")) !=
1534          NULL) {
1535       if (UtilStrICmp(c_ptr, "smooth") == 0) {
1536          smoothScrollingCanvas = SMOOTH_SCROLLING;
1537       } else if (UtilStrICmp(c_ptr, "jump") == 0) {
1538          smoothScrollingCanvas = JUMP_SCROLLING;
1539       } else if (UtilStrICmp(c_ptr, "off") == 0) {
1540          smoothScrollingCanvas = NO_UPDATE_SCROLLING;
1541       } else {
1542          fprintf(stderr, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
1543                TOOL_NAME, "SmoothScrollingCanvas", c_ptr, "jump");
1544          fprintf(stderr, "\n");
1545       }
1546    }
1547    resetOriginOnAdvancePage = FALSE;
1548    if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"ResetOriginOnAdvancePage")) !=
1549          NULL && UtilStrICmp(c_ptr, "true") == 0) {
1550       resetOriginOnAdvancePage = TRUE;
1551    }
1552    UpdScrollWinWH();
1553 }
1554 
ChangeScrollMode(ModeIndex)1555 void ChangeScrollMode(ModeIndex)
1556    int ModeIndex;
1557 {
1558    smoothScrollingCanvas = ModeIndex;
1559 
1560    switch (smoothScrollingCanvas) {
1561    case SMOOTH_SCROLLING:
1562       sprintf(gszMsgBox, TgLoadString(STID_WILL_UPD_WIN_SMOOTH_SCROLL));
1563       break;
1564    case JUMP_SCROLLING:
1565       sprintf(gszMsgBox, TgLoadString(STID_WILL_UPD_WIN_JUMP_SCROLL));
1566       break;
1567    case NO_UPDATE_SCROLLING:
1568       sprintf(gszMsgBox, TgLoadString(STID_WILL_NOT_UPD_WIN_SCROLL));
1569       break;
1570    }
1571    Msg(gszMsgBox);
1572 }
1573 
RefreshScrollModeMenu(menu)1574 int RefreshScrollModeMenu(menu)
1575    TgMenu *menu;
1576 {
1577    int i, rc=TRUE, num_items=menu->num_items;
1578    TgMenuItem *menuitems=menu->menuitems;
1579 
1580    for (i=0; i < num_items; i++) {
1581       TgMenuItem *menu_item=(&menuitems[i]);
1582       TgMenuItem stMenuItem;
1583 
1584       memset(&stMenuItem, 0, sizeof(TgMenuItem));
1585       stMenuItem.state = TGBS_NORMAL;
1586       stMenuItem.checked = (i == smoothScrollingCanvas);
1587       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_RADIO,
1588             &stMenuItem)) {
1589          rc = FALSE;
1590       }
1591    }
1592    return rc;
1593 }
1594 
CreateScrollModeMenu(parent_menu,x,y,menu_info,status_str_xlated)1595 TgMenu *CreateScrollModeMenu(parent_menu, x, y, menu_info, status_str_xlated)
1596    TgMenu *parent_menu;
1597    int x, y;
1598    TgMenuInfo *menu_info;
1599    int status_str_xlated; /* ignored, always 0 */
1600 {
1601    TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
1602 
1603    if (menu != NULL) {
1604       menu->track_menubar = TRUE;
1605       if (!RefreshScrollModeMenu(menu)) {
1606          return TgDestroyMenu(menu, TRUE);
1607       }
1608       menu->refresh_proc = ((RefreshMenuFunc*)RefreshScrollModeMenu);
1609    }
1610    return menu;
1611 }
1612