source: trunk/athena/bin/xmore/ScrollByLine.c @ 1136

Revision 1136, 32.2 KB checked in by kit, 36 years ago (diff)
Initial revision
Line 
1#ifndef lint
2static char rcsid[] = "$Header: /afs/dev.mit.edu/source/repository/athena/bin/xmore/ScrollByLine.c,v 1.1 1988-05-24 14:04:40 kit Exp $";
3#endif lint
4
5/*
6 * ScrollByLine.c - This creates a widget the will text to
7 *                    be scrolled vertically.
8 *
9 * Author:      Chris Peterson
10 *              M. I. T. Project Athena.
11 *              Cambridge, Mass.
12 * Date:        12/5/87
13 *
14 */
15
16/*
17 * I wrote this widget before I knew what form did, and it shows, since
18 * the "right" way to do this widget would be to subclass it to form,
19 * and do it much more like the Viewport widget in the Athena widget set.
20 * But this works and time is short, so here it is.
21 *
22 *                                     Chris Peterson 1/30/88
23 */
24
25/*
26 * There is a horizontal scrollbar somewhat coded into this widget, the
27 * layout function should be fine with the current horizontal code, (RIGHT!)
28 *
29 * But I didn't really sit down and figure out what horizontal scrolling meant
30 * for this widget, as it displays the stuff by line.
31 *
32 * Any brilliant Ideas?
33 */
34
35#include        <X11/IntrinsicP.h>
36#include        "ScrollByLine.h"
37#include        "ScrollByLineP.h"
38#include        <X11/Scroll.h>
39#include        <X11/Atoms.h>
40#include        <X11/Misc.h>
41
42/* Default Translation Table */
43
44static char defaultTranslations[] =
45  "<Btn1Down>:  Page(Forward) \n\
46   <Btn3Down>:  Page(Back) \n\
47   <Key>f:      Page(Forward) \n\
48   <Key>b:      Page(Back) \n\
49   <Key>\\ :    Page(Forward)";
50
51     
52/****************************************************************
53 *
54 * ScrollByLine Resources
55 *
56 ****************************************************************/
57
58static XtResource resources[] = {
59    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
60         XtOffset(ScrollByLineWidget, scroll_by_line.foreground),
61         XtRString, "Black"},
62    {XtNinnerWidth, XtCWidth, XtRInt, sizeof(int),
63         XtOffset(ScrollByLineWidget, scroll_by_line.inner_width),
64         XtRString, "100"},
65    {XtNinnerHeight, XtCHeight, XtRInt, sizeof(int),
66         XtOffset(ScrollByLineWidget, scroll_by_line.inner_height),
67         XtRString, "100"},
68    {XtNforceBars, XtCBoolean, XtRBoolean, sizeof(Boolean),
69         XtOffset(ScrollByLineWidget, scroll_by_line.force_bars),
70         XtRString, "FALSE"},
71    {XtNallowHoriz, XtCBoolean, XtRBoolean, sizeof(Boolean),
72         XtOffset(ScrollByLineWidget, scroll_by_line.allow_horiz),
73         XtRString, "FALSE"},
74    {XtNallowVert, XtCBoolean, XtRBoolean, sizeof(Boolean),
75         XtOffset(ScrollByLineWidget, scroll_by_line.allow_vert),
76         XtRString, "FALSE"},
77    {XtNuseBottom, XtCBoolean, XtRBoolean, sizeof(Boolean),
78         XtOffset(ScrollByLineWidget, scroll_by_line.use_bottom),
79         XtRString, "FALSE"},
80    {XtNuseRight, XtCBoolean, XtRBoolean, sizeof(Boolean),
81         XtOffset(ScrollByLineWidget, scroll_by_line.use_right),
82         XtRString, "FALSE"},
83    {XtNlines, XtCLine, XtRInt, sizeof(int),
84         XtOffset(ScrollByLineWidget, scroll_by_line.lines),
85         XtRString, "0"},
86    {XtNfontHeight, XtCHeight,XtRInt, sizeof(int),
87         XtOffset(ScrollByLineWidget, scroll_by_line.font_height),
88         XtRString, "0"},
89    {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t),
90       XtOffset(ScrollByLineWidget, scroll_by_line.callbacks),
91       XtRString, "NULL"},
92    {XtNformOnInner, XtCBoolean, XtRBoolean, sizeof(Boolean),
93       XtOffset(ScrollByLineWidget, scroll_by_line.key),
94       XtRString, "FALSE"},
95};
96
97/****************************************************************
98 *
99 * Full class record constant
100 *
101 ****************************************************************/
102
103static void HorizontalThumb();
104static Boolean ScrollVerticalText();
105static void VerticalThumb();
106static void HorizontalScroll();
107static void VerticalScroll();
108static void Page();
109static void InitializeHook();
110static void Realize();
111static void Resize();
112static void ResetThumb();
113static void Redisplay();
114static void ChildExpose();
115static Boolean SetValues();
116static int MergeArglists();
117static Boolean Layout();
118static XtGeometryResult GeometryManager();
119static void ChangeManaged();
120static void ClassInitialize();
121
122static XtActionsRec actions[] = {
123  { "Page",   Page},
124  { NULL, NULL},
125};
126
127ScrollByLineClassRec scrollByLineClassRec = {
128  {
129/* core_class fields      */
130    /* superclass         */    (WidgetClass) &compositeClassRec,
131    /* class_name         */    "ScrollByLine",
132    /* widget_size        */    sizeof(ScrollByLineRec),
133    /* class_initialize   */    ClassInitialize,
134    /* class_part_init    */    NULL,
135    /* class_inited       */    FALSE,
136    /* initialize         */    NULL,
137    /* initialize_hook    */    InitializeHook,
138    /* realize            */    Realize,
139    /* actions            */    actions,
140    /* num_actions        */    XtNumber(actions),
141    /* resources          */    resources,
142    /* num_resources      */    XtNumber(resources),
143    /* xrm_class          */    NULLQUARK,
144    /* compress_motion    */    TRUE,
145    /* compress_exposure  */    FALSE,
146    /* compress_enterleave*/    TRUE,
147    /* visible_interest   */    FALSE,
148    /* destroy            */    NULL,
149    /* resize             */    Resize,
150    /* expose             */    Redisplay,
151    /* set_values         */    SetValues,
152    /* set_values_hook    */    NULL,
153    /* set_values_almost  */    XtInheritSetValuesAlmost,
154    /* get_values_hook    */    NULL,
155    /* accept_focus       */    NULL,
156    /* version            */    XtVersion,
157    /* callback_private   */    NULL,
158    /* tm_table           */    defaultTranslations,
159  },{
160/* composite_class fields */
161    /* geometry_manager   */    GeometryManager,
162    /* change_managed     */    ChangeManaged,
163    /* insert_child       */    NULL,   /* Inherit from superclass */
164    /* delete_child       */    NULL,   /* Inherit from superclass */
165    /* move_focus_to_next */    NULL,
166    /* move_focus_to_prev */    NULL
167  },{
168    /* mumble             */    0       /* Make C compiler happy   */
169  }
170};
171
172WidgetClass scrollByLineWidgetClass =
173            (WidgetClass) &scrollByLineClassRec;
174
175
176/****************************************************************
177 *
178 * Private Routines
179 *
180 ****************************************************************/
181
182/*      Function Name: ClassInitialize
183 *      Description: Used to initialize this class of widgets.
184 *      Arguments: none.
185 *      Returns: none.
186 */
187
188static void ClassInitialize()
189{
190     CompositeWidgetClass superclass;
191     ScrollByLineWidgetClass myclass;
192
193     myclass = (ScrollByLineWidgetClass) scrollByLineWidgetClass;
194     superclass = (CompositeWidgetClass) myclass->core_class.superclass;
195
196     /* Inherit insert_child and delete_child from Composite */
197     myclass->composite_class.insert_child =
198         superclass->composite_class.insert_child;
199     myclass->composite_class.delete_child =
200         superclass->composite_class.delete_child;
201}
202
203/*      Function Name: Layout
204 *      Description: This function lays out the scroll_by_line widget.
205 *      Arguments: w - the scroll_by_line widget.
206 *      Returns: TRUE if successful.
207 */
208
209static Boolean
210Layout(w,key)
211Widget w;
212int key;
213{   
214  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
215  Dimension width,height;       /* The size that the widget would like to be */
216  XtGeometryResult answer;      /* the answer from the parent. */
217  Widget hbar,vbar,child;       /* The three children of this
218                            scrolled widget. */
219  int vbar_x,vbar_y;            /* The locations of the various elements. */
220  int hbar_x,hbar_y;
221  int child_x,child_y;
222  int c_width,c_height;
223  Boolean make_bar;
224
225  vbar = sblw->composite.children[0];
226  hbar = sblw->composite.children[1];
227  child = sblw->composite.children[2];
228  height = sblw->core.height;
229  width = sblw->core.width;
230
231/* set the initial scroll bar positions. */
232
233  vbar_x = vbar_y = 0;
234  hbar_x = hbar_y = 0;
235
236/* Should I allow the vertical scrollbar to be seen */
237
238   make_bar = FALSE; 
239   if ( (!key) && (sblw->scroll_by_line.lines *
240        sblw->scroll_by_line.font_height > height) )
241     make_bar = TRUE;
242
243   else if ( (key) && (sblw->scroll_by_line.lines *
244             sblw->scroll_by_line.font_height > child->core.height) )
245     make_bar = TRUE;
246
247   if (sblw->scroll_by_line.allow_vert && (sblw->scroll_by_line.force_bars ||
248                                       make_bar) ) {
249 /*
250  * Resize the outer window to fit the child, or visa versa.  Also make scroll
251  * bar become placed in the correct location.
252  */
253     if (key)                   
254       width = child->core.width + vbar->core.width +
255               2 * vbar->core.border_width;
256     else
257       c_width = width - vbar->core.width -2 * vbar->core.border_width;
258
259/* Put Scrollbar on right side if scrolled window? */
260
261     if (sblw->scroll_by_line.use_right) {
262       vbar_x = width - vbar->core.width - 2 * vbar->core.border_width;
263       child_x = 0;
264     }
265     else {
266       child_x = vbar->core.width + 2 * vbar->core.border_width;
267       vbar_x = 0;
268     }
269   }
270   else {
271     /* Make the scroll bar dissappear, note how scroll bar is always there,
272        sometimes it is just that we cannot see them. */
273     vbar_x = - vbar->core.width - 10;
274     child_x = 0;
275     if (key)
276       width = child->core.width;
277     else
278       c_width = width;
279   }
280
281/* set the horizontal bar position. */
282
283/* should we allow the horiz. scroll bar. */
284
285   if (sblw->scroll_by_line.allow_horiz && (child->core.width >= width ||
286                                        sblw->scroll_by_line.force_bars)) {
287     if (key)
288       height = child->core.height + hbar->core.height +
289                2 * hbar->core.border_width;
290     else
291       c_height = height - hbar->core.height - 2 * hbar->core.border_width;
292
293     hbar_x = child_x;
294
295/* Should we put the scroll bar on the bottom?? */
296
297     if (sblw->scroll_by_line.use_bottom) {
298       hbar_y = height - hbar->core.height - 2 * hbar->core.border_width;
299       child_y = 0;
300     }
301     else {
302       child_y = hbar->core.height + 2 * hbar->core.border_width;
303       vbar_y = child_y;
304       hbar_y = 0;
305     }
306   }
307   else {
308     /* make this scroll bar disappear. */
309     hbar_y = - hbar->core.height - 10;
310     child_y = 0;
311     if (key)
312       height = child->core.height;
313     else
314       c_height = height;
315   }
316
317 /* if the windows are realized we have to move them. */
318
319   if (XtIsRealized( (Widget) sblw)) {
320     XtMoveWidget(hbar,hbar_x,hbar_y);
321     XtMoveWidget(vbar,vbar_x,vbar_y);
322     XtMoveWidget(child,child_x,child_y);
323
324 /* resize the children to be the correct height or width. */
325
326     XtResizeWidget(vbar,vbar->core.width,height -
327                    2 * vbar->core.border_width - vbar_y,
328                    vbar->core.border_width);
329
330     XtResizeWidget(hbar,width - hbar_x -
331                    2 * hbar->core.border_width,
332                    hbar->core.height,hbar->core.border_width);
333
334     if (!key)
335       XtResizeWidget(child, (Cardinal) c_width, (Cardinal) c_height,
336                      child->core.border_width);
337
338   }
339/*
340 * If they are not realized we do not need to move them then just set their
341 * core values, this saves a bit of time.
342 */
343  else {
344    hbar->core.x = hbar_x;
345    hbar->core.y = hbar_y;
346    vbar->core.x = vbar_x;
347    vbar->core.y = vbar_y;
348    child->core.x = child_x;
349    child->core.y = child_y;
350
351/* resize the scrollbars to be the correct height or width. */
352
353    XtResizeWidget(vbar,vbar->core.width,height -
354            2 * vbar->core.border_width - vbar_y,
355            vbar->core.border_width);
356
357    XtResizeWidget(hbar,width - hbar_x -
358            2 * hbar->core.border_width,
359            hbar->core.height,hbar->core.border_width);
360
361    if (!key) {
362      child->core.width = c_width;
363      child->core.height = c_height;
364    }
365  }   
366
367  height = height;
368  width = width;
369
370/* set the thumb size to be correct. */
371
372  ResetThumb( (Widget) sblw);
373
374  answer = XtMakeResizeRequest( (Widget) sblw, width, height, &width, &height);
375
376  switch(answer) {
377  case XtGeometryYes:
378    break;
379  case XtGeometryNo:
380    return(FALSE);
381  case XtGeometryAlmost:
382    (void) Layout( (Widget) sblw,FALSE);
383  }
384  return(TRUE);
385}
386
387/*      Function Name: ResetThumb
388 *      Description: This function resets the thumb's shown percentage only.
389 *      Arguments: w - the ScrollByLineWidget.
390 *      Returns: none;
391 */
392
393static void
394ResetThumb(w)
395Widget w;
396{
397  float shown;
398  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
399  Widget child,vbar,hbar;
400
401  vbar = sblw->composite.children[0];
402  hbar = sblw->composite.children[1];
403  child = sblw->composite.children[2];
404
405/* vertical */
406
407  shown = (float) child->core.height /(float) (sblw->scroll_by_line.lines *
408                                  sblw->scroll_by_line.font_height);
409  if (shown > 1.0)
410    shown = 1.0;
411
412  XtScrollBarSetThumb( vbar, (float) -1, shown );
413
414/* horizontal */
415
416  shown = (float) child->core.width / (float) child->core.width;
417  XtScrollBarSetThumb( hbar, (float) -1, shown );
418}
419
420/*
421 *
422 * Geometry Manager - If the height of width is changed then try a new layout.
423*                    else dissallow the requwest.
424*
425 */
426
427/*ARGSUSED*/
428static XtGeometryResult GeometryManager(w, request, reply)
429    Widget              w;
430    XtWidgetGeometry    *request;
431    XtWidgetGeometry    *reply; /* RETURN */
432
433{
434  ScrollByLineWidget sblw;
435
436  sblw = (ScrollByLineWidget) w->core.parent;
437  if ( request->width != 0 && request->height != 0 &&
438      (request->request_mode && (CWWidth || CWHeight)) ) {
439    w->core.height = request->height;
440    w->core.width = request->width;
441    (void) Layout( (Widget) sblw,TRUE);
442    return(XtGeometryYes);
443  }
444  return(XtGeometryNo);
445
446} /* Geometery Manager */
447
448/* ARGSUSED */
449static void ChildExpose(w,junk,event)
450Widget w;
451caddr_t junk;
452XEvent *event;
453{
454
455/*
456 * since we are realy concerned with the expose events that happen
457 * to the child, we have selected expose events on this window, and
458 * then I call the redisplay routine.
459 */
460
461  Redisplay(w->core.parent,event);
462} /* ChildExpose */
463
464/*
465 * Repaint the widget's child Window Widget.
466 */
467
468/* ARGSUSED */
469static void Redisplay(w, event)
470Widget w;
471XEvent *event;
472{
473  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
474
475  int top,bottom;               /* the locations of the top and
476                          bottom of the region that needs to be
477                          repainted. */
478  ScrollByLineStruct * sblw_struct;
479
480  sblw_struct = (ScrollByLineStruct *) malloc(sizeof(ScrollByLineStruct));
481
482/*
483 * This routine tells the client which sections of the window to
484 * repaint in his callback function which does the actual repainting.
485 */
486
487  if (event->type == Expose) {
488    top = event->xexpose.y;
489    bottom = event->xexpose.height + top;
490  }
491  else {
492    top = event->xgraphicsexpose.y;
493    bottom  = event->xgraphicsexpose.height + top;
494  }
495 
496  sblw_struct->start_line = top / sblw->scroll_by_line.font_height +
497                            sblw->scroll_by_line.line_pointer;
498/*
499 * If an expose event is called on a region that has no text assoicated
500 * with it then do not redisplay. Only nescessary for very short file.
501 */
502  if (sblw_struct->start_line > sblw->scroll_by_line.lines)
503    return;
504  sblw_struct->num_lines = (bottom - top) /
505                            sblw->scroll_by_line.font_height + 1;
506  sblw_struct->location =  top / sblw->scroll_by_line.font_height *
507                            sblw->scroll_by_line.font_height;
508
509  XtCallCallbacks( (Widget) sblw, XtNcallback, (caddr_t) sblw_struct);
510
511  free(sblw_struct);
512
513} /* redisplay (expose) */
514
515static void
516Resize(w)
517Widget w;
518{
519
520  (void) Layout(w,FALSE);
521
522} /* Resize */
523
524static void ChangeManaged(w)
525Widget w;
526{
527  /* note how we ignore bonus children, but since we control all children,
528   there should never be a problem anyway. */
529  ScrollByLineWidget sblw = (ScrollByLineWidget) w;;
530
531  if (sblw->composite.num_children == 3) {
532    (void) Layout( w,sblw->scroll_by_line.key);
533  }
534
535} /* Change Managed */
536
537/*      Function Name: Page
538 *      Description: This function pages the widget, by the amount it recieves
539 *                   from the translation Manager.
540 *      Arguments: w - the ScrollByLineWidget.
541 *                 event - the event that caused this return.
542 *                 params - the parameters passed to it.
543 *                 num_params - the number of parameters.
544 *      Returns: none.
545 */
546
547static void
548Page(w, event, params, num_params)
549Widget w;
550XEvent * event;
551String * params;
552Cardinal *num_params;
553{
554   ScrollByLineWidget sblw = (ScrollByLineWidget) w;
555   Widget vbar = sblw->composite.children[0];
556   char direction;
557
558   if (*num_params > 0)
559     direction = *params[0];
560   else
561     return;
562
563/*
564 * If no scroll bar is visible then do not page, as the entire window is shown,
565 * of scrolling has been turned off.
566 */
567
568   if (vbar->core.x < 0)
569     return;
570
571   switch ( direction ) {
572   case 'f':
573   case 'F':
574     /* move one page forward */
575     VerticalScroll(vbar,NULL, (int) vbar->core.height);
576     break;
577   case 'b':
578   case 'B':
579     /* move one page backward */
580     VerticalScroll(vbar,NULL, (int)  - vbar->core.height);
581     break;
582   case 'L':
583   case 'l':
584     /* move one line forward */
585     VerticalScroll(vbar,NULL, (int) sblw->scroll_by_line.font_height);
586     break;
587   default:
588     return;
589   }
590}
591
592/*      Function Name: ScrollVerticalText
593 *      Description: This accomplished the actual movement of the text.
594 *      Arguments: w - the ScrollByLine Widget.
595 *                 new_line - the new location for the line pointer
596 *                 force_redisplay - should we force this window to get
597 *                                   redisplayed?
598 *      Returns: True if the thumb needs to be moved.
599 */
600
601static Boolean
602ScrollVerticalText(w,new_line,force_redisp)
603Widget w;
604int new_line;
605Boolean force_redisp;
606{
607  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
608  int max_lines,                /* The location of top of the last screen. */
609    num_lines,                  /* The number of lines in one screen of text */
610    y_pos,                      /* The location to start displaying text. */
611    num_lines_disp,             /* The number of lines to display. */
612    start_line,                 /* The line to start displaying text. */
613    y_location,                 /* The y_location to for storing copy area. */
614    lines_to_move;              /* The number of lines to copy. */
615  GC gc;
616  Widget child,vbar;    /* Widgets. */
617  ScrollByLineStruct * sblw_struct;
618  Boolean move_thumb = FALSE;
619
620  child = sblw->composite.children[2];
621  vbar =  sblw->composite.children[0];
622
623  num_lines =  child->core.height / sblw->scroll_by_line.font_height;
624
625  gc = XCreateGC(XtDisplay( (Widget) sblw),XtWindow(child),NULL,0);
626  XSetGraphicsExposures(XtDisplay( (Widget) sblw),gc,TRUE);
627
628 /* do not let the window extend out of bounds */
629
630  if ( new_line < 0) {
631    move_thumb = TRUE;
632    new_line = 0;
633  }
634  else {
635    max_lines = sblw->scroll_by_line.lines -
636     child->core.height / sblw->scroll_by_line.font_height;
637
638    if ( new_line > max_lines ) {
639      new_line = max_lines;
640      move_thumb = TRUE;
641    }
642  }
643
644  if ( new_line == sblw->scroll_by_line.line_pointer && !force_redisp)
645/* No change in postion, and no action is nescessary */
646    return(move_thumb);
647  else if ( new_line <= sblw->scroll_by_line.line_pointer) { /* scroll back. */
648    if ( sblw->scroll_by_line.line_pointer - new_line >= num_lines
649        || force_redisp) {
650/*
651 * We have moved so far that no text that is currently on the screen can
652 * be saved thus there is no need to be clever just clear
653 * the window and display a full screen of text.
654 */
655      XClearWindow(XtDisplay(child),XtWindow(child));
656      y_pos = 0;
657      start_line = new_line;
658      num_lines_disp = num_lines;
659    }
660    else {
661/*
662 * Move text that is to remain on the screen to its new location, and then
663 * set up the proper callback values to display the rest of the text.
664 */
665      lines_to_move = num_lines - sblw->scroll_by_line.line_pointer + new_line;
666      y_location = sblw->scroll_by_line.line_pointer - new_line;
667      XCopyArea(XtDisplay(vbar),XtWindow(child),XtWindow(child),
668         gc,0,0,child->core.width,
669         (lines_to_move + 1) * sblw->scroll_by_line.font_height,
670         0,y_location * sblw->scroll_by_line.font_height);
671      XClearArea( XtDisplay(vbar),XtWindow(child),0,0,0,
672          (num_lines - lines_to_move)
673          * sblw->scroll_by_line.font_height,
674          FALSE );
675      y_pos = 0;
676      start_line = new_line;
677      num_lines_disp = num_lines - lines_to_move;
678    }
679  }
680  else {     /* scrolling forward */
681    if ( new_line - sblw->scroll_by_line.line_pointer >= num_lines
682        || force_redisp) {
683/*
684 * We have moved so far that no text that is currently on the screen can
685 * be saved thus there is no need to be clever just clear
686 * the window and display a full screen of text.
687 */
688      XClearWindow(XtDisplay(child),XtWindow(child));
689      y_pos = 0;
690      start_line = new_line;
691      num_lines_disp = num_lines;
692    }
693    else {
694/*
695 * Move text that is to remain on the screen to its new location, and then
696 * set up the proper callback values to display the rest of the text.
697 */
698      lines_to_move = num_lines - new_line + sblw->scroll_by_line.line_pointer;
699      y_location = new_line - sblw->scroll_by_line.line_pointer;
700      XCopyArea(XtDisplay(vbar),XtWindow(child),XtWindow(child),gc,0,
701                y_location * sblw->scroll_by_line.font_height,
702                child->core.width,
703                (lines_to_move)* sblw->scroll_by_line.font_height,0,0);
704
705      lines_to_move--;          /* make sure that we get the last,
706                                    (possibly) partial line, fully painted. */
707
708      /* we add 10% of a font height here to the vertical position
709       because some characters extend a little bit below the fontheight */
710
711      XClearArea(XtDisplay(vbar),XtWindow(child),0,lines_to_move *
712                 sblw->scroll_by_line.font_height + (int)
713                 (.1 * (float) sblw->scroll_by_line.font_height),0,0,FALSE);
714
715      y_pos = lines_to_move * sblw->scroll_by_line.font_height;
716      start_line = new_line + lines_to_move;
717      num_lines_disp = num_lines - lines_to_move;
718    }
719  }
720 
721  sblw->scroll_by_line.line_pointer = new_line;
722
723/*
724 * call the callbacks, this is the callback to the application to do the
725 * actual painting of the text.
726 */
727
728  sblw_struct = (ScrollByLineStruct *) malloc(sizeof(ScrollByLineStruct));
729
730  sblw_struct->location = y_pos;
731  sblw_struct->start_line = start_line;
732  sblw_struct->num_lines = num_lines_disp;
733
734  XtCallCallbacks( (Widget) sblw,XtNcallback, (caddr_t) sblw_struct);
735
736/* Save that memory */
737
738  XFreeGC(XtDisplay( (Widget) sblw), gc);
739  free(sblw_struct);
740
741  return(move_thumb);
742}
743
744/*      Function Name: VerticalThumb
745 *      Description: This function moves the postition of the interior window
746 *                   as the vertical scroll bar is moved.
747 *      Arguments: w - the scrollbar widget.
748 *                 junk - not used.
749 *                 percent - the position of the scrollbar.
750 *      Returns: none.
751 */
752
753static void
754VerticalThumb(w,junk,percent)
755Widget w;
756caddr_t junk;
757float percent;
758{
759  int new_line;                 /* The new location for the line pointer. */
760  float location;               /* The location of the thumb. */
761  Widget vbar;
762
763  ScrollByLineWidget sblw = (ScrollByLineWidget) w->core.parent;
764
765  vbar =  sblw->composite.children[0];
766
767  new_line = (int) ((float) sblw->scroll_by_line.lines * percent);
768
769  if (ScrollVerticalText( (Widget) sblw, new_line, FALSE)) {
770/* reposition the thumb */
771    location = (float) sblw->scroll_by_line.line_pointer /
772               (float) sblw->scroll_by_line.lines;
773    XtScrollBarSetThumb( vbar, location , (float) -1 );
774  }
775
776}
777
778/*      Function Name: VerticalScroll
779 *      Description: This function moves the postition of the interior window
780 *                   as the vertical scroll bar is moved.
781 *      Arguments: w - the scrollbar widget.
782 *                 junk - not used.
783 *                 pos - the position of the cursor.
784 *      Returns: none.
785 */
786
787static void
788VerticalScroll(w,junk,pos)
789Widget w;
790caddr_t junk;
791int pos;
792{
793  int new_line;                 /* The new location for the line pointer. */
794  float location;               /* The new location of the thumb. */
795  Widget vbar;
796
797  ScrollByLineWidget sblw = (ScrollByLineWidget) w->core.parent;
798
799  vbar =  sblw->composite.children[0];
800
801  new_line = sblw->scroll_by_line.line_pointer;
802  new_line += (int) pos / sblw->scroll_by_line.font_height;
803
804  (void) ScrollVerticalText( (Widget) sblw,new_line,FALSE);
805
806/* reposition the thumb */
807
808  location = (float) sblw->scroll_by_line.line_pointer /
809             (float) sblw->scroll_by_line.lines;
810  XtScrollBarSetThumb( vbar, location , (float) -1 );
811 
812
813}
814
815/*
816 * I have not thought out the horizontal scrolling yet, I am not sure what
817 * should be done here.  This code is questionable.
818 */
819 
820
821/*      Function Name: HorizontalThumb
822 *      Description: This function moves the postition of the interior window
823 *                   as the vertical scroll bar is moved.
824 *      Arguments: w - the scrollbar widget.
825 *                 junk - not used.
826 *                 percent - the position of the scrollbar.
827 *      Returns: none.
828 */
829
830static void
831HorizontalThumb(w,junk,percent)
832Widget w;
833caddr_t junk;
834float percent;
835{
836  int x, y;
837  Widget child,vbar;
838  ScrollByLineWidget sblw = (ScrollByLineWidget) w->core.parent;
839
840  /* reposition the client window (child[2]) */
841
842  vbar =  sblw->composite.children[0];
843  child = sblw->composite.children[2];
844
845  x = (int) ( (0.0 - percent) * ((float) child->core.width));
846  y = child->core.y;
847
848/*
849 * if there is a vertical scrollbar and it is on the left then
850 * allow room for it .
851 */
852
853  if (vbar->core.x == 0)
854    x += vbar->core.width + 2 * vbar->core.border_width;
855
856  XtMoveWidget(child,x,y);
857}
858
859/*      Function Name: HorizontalScroll
860 *      Description: This function moves the postition of the interior window
861 *                   as the horizontal scroll bar is moved.
862 *      Arguments: w - the scrollbar widget.
863 *                 junk - not used.
864 *                 pos - the position of the cursor.
865 *      Returns: none.
866 */
867
868static void
869HorizontalScroll(w,junk,pos)
870Widget w;
871caddr_t junk;
872int pos;
873{
874  int x, y, min_x;
875  float location;
876  Widget child,vbar,hbar;
877  ScrollByLineWidget sblw = (ScrollByLineWidget) w->core.parent;
878
879  /* reposition the client window (child[2]) */
880
881  vbar =  sblw->composite.children[0];
882  hbar =  sblw->composite.children[1];
883  child = sblw->composite.children[2];
884
885  x = child->core.x - pos;
886  y = child->core.y;
887 
888/*
889 * Keep us in bounds.
890 */
891
892  if ( x > 0 ) x = 0;
893  min_x = - (child->core.width - hbar->core.width -
894             2 * vbar->core.border_width);
895
896  if (vbar->core.y > 0)         /* vertical scrollbar is on right.*/
897    min_x -=  vbar->core.width +  2 * vbar->core.border_width;
898
899  if ( x < min_x ) x = min_x;
900
901/* reposition the thumb */
902
903  location = 0.0 - (float) y / (float) child->core.width;
904  XtScrollBarSetThumb( hbar, location , (float) -1 );
905 
906/*
907 * if there is a vertical scrollbar and it is on the left then
908 * allow room for it .
909 */
910
911  if (vbar->core.x == 0)
912    y += vbar->core.width + 2 * vbar->core.border_width;
913   
914  XtMoveWidget(child,x,y);      /* he's my child so I can move him. */
915}
916
917static void InitializeHook(new, args, num_args)
918    ScrollByLineWidget new;
919    ArgList args;
920    Cardinal *num_args;
921{
922  ScrollByLineWidget sblw = (ScrollByLineWidget) new;
923  Widget window;                /* Window widget. */
924  Arg arglist[50];              /* Must be large enough for the
925                                 arglist from the scrolled widget to
926                                 be added to it. */
927  Cardinal scrollbar_num;       /* the number of scrollbar args. */
928  Cardinal window_num;          /* the number of window args. */
929 
930  static XtCallbackRec scrollcallback[] = { /* The scroll callback function. */
931    { NULL, NULL },
932    { NULL, NULL },
933  };
934  static XtCallbackRec thumbcallback[] = { /* The thumb callback function. */
935    { NULL, NULL },
936    { NULL, NULL },
937  };
938
939  sblw->scroll_by_line.line_pointer = 0; /* initial point to line 0. */
940
941  if (sblw->core.height <= 0)
942    sblw->core.height = DEFAULT_HEIGHT;
943  if (sblw->core.width <= 0)
944    sblw->core.width = DEFAULT_WIDTH;
945
946  scrollbar_num = 0; 
947  XtSetArg(arglist[scrollbar_num], XtNheight, 10); /* changed in layout. */
948  scrollbar_num++;
949  XtSetArg(arglist[scrollbar_num], XtNwidth, 16);
950  scrollbar_num++;
951  XtSetArg(arglist[scrollbar_num], XtNorientation, XtorientVertical);
952  scrollbar_num++;
953  thumbcallback[0].callback = VerticalThumb; 
954  scrollcallback[0].callback = VerticalScroll;
955  XtSetArg(arglist[scrollbar_num], XtNthumbProc, thumbcallback);
956  scrollbar_num++;
957  XtSetArg(arglist[scrollbar_num], XtNscrollProc, scrollcallback);
958  scrollbar_num++;
959
960/*
961 * Merge the argument lists so but have the scrollbar arglist take
962 * control when there is a discrepency this causes us to get the
963 * correct height and width.
964 */
965
966  scrollbar_num = MergeArglists(args, *num_args,arglist,scrollbar_num);
967
968  XtCreateManagedWidget("Vertical Scroll Bar",
969                 scrollbarWidgetClass, (Widget) sblw,arglist,scrollbar_num);
970
971  scrollbar_num = 0; 
972  XtSetArg(arglist[scrollbar_num], XtNwidth, 10); /* changed in layout. */
973  scrollbar_num++;
974  XtSetArg(arglist[scrollbar_num], XtNheight, 16);
975  scrollbar_num++;
976  XtSetArg(arglist[scrollbar_num], XtNorientation, XtorientHorizontal);
977  scrollbar_num++;
978  thumbcallback[0].callback = HorizontalThumb;
979  scrollcallback[0].callback = HorizontalScroll;
980  XtSetArg(arglist[scrollbar_num], XtNthumbProc, thumbcallback);
981  scrollbar_num++;
982  XtSetArg(arglist[scrollbar_num], XtNscrollProc, scrollcallback);
983  scrollbar_num++;
984
985/*
986 * Merge the argument lists so but have the scrollbar arglist take
987 * control when there is a discrepency this causes us to get the
988 * correct height and width.
989 */
990
991  scrollbar_num = MergeArglists(args, *num_args,arglist,scrollbar_num);
992
993  XtCreateManagedWidget("Horizontal Scroll Bar",
994                 scrollbarWidgetClass, (Widget) sblw,arglist,scrollbar_num);
995
996  window_num = 0; 
997  XtSetArg(arglist[window_num], XtNwidth, sblw->scroll_by_line.inner_width);
998  window_num++;
999  XtSetArg(arglist[window_num], XtNheight, sblw->scroll_by_line.inner_height);
1000  window_num++;
1001  XtSetArg(arglist[window_num], XtNborderWidth, 0);
1002  window_num++; 
1003 
1004  window = XtCreateWidget("Window with file",widgetClass,(Widget) sblw,arglist,
1005                          window_num);
1006  XtManageChild(window);
1007
1008/* We want expose events for this window also. */
1009
1010  XtAddEventHandler(window, (Cardinal) ExposureMask, FALSE, ChildExpose, NULL);
1011 
1012} /* InitializeHook */
1013
1014static void Realize(w, valueMask, attributes)
1015    register Widget w;
1016    Mask *valueMask;
1017    XSetWindowAttributes *attributes;
1018{
1019    XtCreateWindow( w, (Cardinal) InputOutput, (Visual *)CopyFromParent,
1020        *valueMask, attributes);
1021} /* Realize */
1022
1023/*
1024 *
1025 * Set Values
1026 *
1027 */
1028
1029static Boolean SetValues (current, request, new)
1030    Widget current, request, new;
1031{
1032  ScrollByLineWidget sblw_new, sblw_current;
1033  Boolean ret = FALSE;
1034
1035  sblw_current = (ScrollByLineWidget) current;
1036  sblw_new = (ScrollByLineWidget) new;
1037
1038  if (sblw_current->scroll_by_line.lines != sblw_new->scroll_by_line.lines) {
1039    ResetThumb(new);
1040    ret = TRUE;
1041  }
1042  if (sblw_current->scroll_by_line.font_height !=
1043      sblw_new->scroll_by_line.font_height) {
1044    ResetThumb(new);
1045    ret = TRUE;
1046  }
1047  return(ret);
1048
1049} /* Set Values */
1050
1051/*      Function Name: MergeArglists
1052 *      Description: This function merges two arglists.
1053 *      Arguments: from,num_from - the number and list of args for the source.
1054 *                 to,num_to - the number and list of argument for the
1055 *                             destination.
1056 *      Returns: new number of argument in to.
1057 */
1058
1059/* Note: This function will be very unhappy with you if 'to' is not
1060 *       large enough to contain 'from', you will end up with pointers
1061 *       in space.
1062 */
1063
1064static int
1065MergeArglists(from,num_from,to,num_to)
1066Arg from[],to[];
1067Cardinal num_from,num_to;
1068{
1069  int i,j;                      /* a counter. */
1070
1071/* When there are two similar values ignore the from value. */
1072
1073  i = 0;
1074  while ( i < num_from ) {     
1075    j = 0;
1076    while ( j < num_to ) {
1077      if ( !strcmp(from[i].name,to[j].name) ) {
1078        /* if they are the same then goto next on the from list,
1079           i.e. ignore this entry, do not add to to list. */
1080        i++;
1081        if ( i > num_from)
1082          j = num_to + 100;
1083        else {
1084          j = 0;
1085          continue;
1086        }
1087      }
1088      j++;
1089    }
1090    /* add to to list */
1091    if (j < num_to + 100) {
1092      to[num_to].value = from[i].value;
1093      to[num_to].name = from[i].name;
1094      num_to++;
1095      i++;
1096    }
1097  }
1098  return(num_to);
1099}
1100
1101/* Public Routines. */
1102
1103/*      Function Name: XtScrollByLineWidget()
1104 *      Description: This function returns the window widget that the
1105 *                   ScrollByLine widget uses to display its text.
1106 *      Arguments: w - the ScrollByLine Widget.
1107 *      Returns: the widget to display the text into.
1108 */
1109
1110extern Widget XtScrollByLineWidget(w)
1111Widget w;
1112{
1113  ScrollByLineWidget sblw = (ScrollByLineWidget) w; /* the sblw widget. */
1114 
1115  return(sblw->composite.children[2]);
1116}
1117
1118/*      Function Name: XtResetScrollByLine
1119 *      Description: This function resets the scroll by line widget.
1120 *      Arguments: w - the sblw widget.
1121 *      Returns: none.
1122 */
1123
1124extern void
1125XtResetScrollByLine(w)
1126Widget w;
1127{
1128  float location;               /* the location of the thumb. */
1129  ScrollByLineWidget sblw = (ScrollByLineWidget) w; /* the sblw widget. */
1130  Widget vbar;
1131
1132  vbar =  sblw->composite.children[0];
1133
1134  (void) ScrollVerticalText( w, 0, TRUE);
1135 
1136  /* reposition the thumb */
1137
1138  location = (float) sblw->scroll_by_line.line_pointer /
1139             (float) sblw->scroll_by_line.lines;
1140  XtScrollBarSetThumb( vbar, location , (float) -1 );
1141
1142  ResetThumb(w);
1143}
Note: See TracBrowser for help on using the repository browser.