1 | /* |
---|
2 | * xman - X window system manual page display program. |
---|
3 | * |
---|
4 | * $XConsortium: ScrollByL.c,v 1.5 89/01/06 18:41:40 kit Exp $ |
---|
5 | * $Header: /afs/dev.mit.edu/source/repository/athena/bin/xmore/ScrollByLine.c,v 1.4 1990-05-01 14:49:05 epeisach Exp $ |
---|
6 | * |
---|
7 | * Copyright 1987, 1988 Massachusetts Institute of Technology |
---|
8 | * |
---|
9 | * Permission to use, copy, modify, and distribute this software and its |
---|
10 | * documentation for any purpose and without fee is hereby granted, provided |
---|
11 | * that the above copyright notice appear in all copies and that both that |
---|
12 | * copyright notice and this permission notice appear in supporting |
---|
13 | * documentation, and that the name of M.I.T. not be used in advertising or |
---|
14 | * publicity pertaining to distribution of the software without specific, |
---|
15 | * written prior permission. M.I.T. makes no representations about the |
---|
16 | * suitability of this software for any purpose. It is provided "as is" |
---|
17 | * without express or implied warranty. |
---|
18 | * |
---|
19 | * Author: Chris D. Peterson, MIT Project Athena |
---|
20 | * Created: December 5, 1987 |
---|
21 | */ |
---|
22 | |
---|
23 | #if ( !defined(lint) && !defined(SABER)) |
---|
24 | static char rcs_version[] = "$Athena: ScrollByL.c,v 4.5 88/12/19 13:46:04 kit Exp $"; |
---|
25 | #endif |
---|
26 | |
---|
27 | /* |
---|
28 | * I wrote this widget before I knew what form did, and it shows, since |
---|
29 | * the "right" way to do this widget would be to subclass it to form, |
---|
30 | * and do it much more like the Viewport widget in the Athena widget set. |
---|
31 | * But this works and time is short, so here it is. |
---|
32 | * |
---|
33 | * Chris D. Peterson 1/30/88 |
---|
34 | * |
---|
35 | * I removed all the code for horizontal scrolling here, since is was a crock |
---|
36 | * anyway. |
---|
37 | * |
---|
38 | * Chris D. Peterson 11/13/88 |
---|
39 | */ |
---|
40 | |
---|
41 | #include <X11/IntrinsicP.h> |
---|
42 | #include "ScrollByLine.h" |
---|
43 | #include "ScrollByLineP.h" |
---|
44 | #include <X11/StringDefs.h> |
---|
45 | #if XtSpecificationRelease < 4 |
---|
46 | #include <X11/Scroll.h> |
---|
47 | #include <X11/XawMisc.h> |
---|
48 | #else |
---|
49 | #include <X11/Xaw/Scrollbar.h> |
---|
50 | #define XtScrollBarSetThumb XawScrollbarSetThumb |
---|
51 | #endif |
---|
52 | |
---|
53 | /* Default Translation Table */ |
---|
54 | |
---|
55 | static char defaultTranslations[] = |
---|
56 | "<Btn1Down>: Page(Forward) \n\ |
---|
57 | <Btn3Down>: Page(Back) \n\ |
---|
58 | <Key>f: Page(Forward) \n\ |
---|
59 | <Key>b: Page(Back) \n\ |
---|
60 | <Key>\\ : Page(Forward)"; |
---|
61 | |
---|
62 | |
---|
63 | /**************************************************************** |
---|
64 | * |
---|
65 | * ScrollByLine Resources |
---|
66 | * |
---|
67 | ****************************************************************/ |
---|
68 | |
---|
69 | static XtResource resources[] = { |
---|
70 | {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), |
---|
71 | XtOffset(ScrollByLineWidget, scroll_by_line.foreground), |
---|
72 | XtRString, "XtDefaultForeground"}, |
---|
73 | {XtNinnerWidth, XtCWidth, XtRInt, sizeof(int), |
---|
74 | XtOffset(ScrollByLineWidget, scroll_by_line.inner_width), |
---|
75 | XtRString, "100"}, |
---|
76 | {XtNinnerHeight, XtCHeight, XtRInt, sizeof(int), |
---|
77 | XtOffset(ScrollByLineWidget, scroll_by_line.inner_height), |
---|
78 | XtRString, "100"}, |
---|
79 | {XtNforceBars, XtCBoolean, XtRBoolean, sizeof(Boolean), |
---|
80 | XtOffset(ScrollByLineWidget, scroll_by_line.force_bars), |
---|
81 | XtRString, "FALSE"}, |
---|
82 | {XtNallowVert, XtCBoolean, XtRBoolean, sizeof(Boolean), |
---|
83 | XtOffset(ScrollByLineWidget, scroll_by_line.allow_vert), |
---|
84 | XtRString, "FALSE"}, |
---|
85 | {XtNuseRight, XtCBoolean, XtRBoolean, sizeof(Boolean), |
---|
86 | XtOffset(ScrollByLineWidget, scroll_by_line.use_right), |
---|
87 | XtRString, "FALSE"}, |
---|
88 | {XtNlines, XtCLine, XtRInt, sizeof(int), |
---|
89 | XtOffset(ScrollByLineWidget, scroll_by_line.lines), |
---|
90 | XtRString, "1"}, |
---|
91 | {XtNfontHeight, XtCHeight,XtRInt, sizeof(int), |
---|
92 | XtOffset(ScrollByLineWidget, scroll_by_line.font_height), |
---|
93 | XtRString, "0"}, |
---|
94 | {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t), |
---|
95 | XtOffset(ScrollByLineWidget, scroll_by_line.callbacks), |
---|
96 | XtRCallback, (caddr_t) NULL}, |
---|
97 | {XtNformOnInner, XtCBoolean, XtRBoolean, sizeof(Boolean), |
---|
98 | XtOffset(ScrollByLineWidget, scroll_by_line.key), |
---|
99 | XtRString, "FALSE"}, |
---|
100 | }; |
---|
101 | |
---|
102 | /**************************************************************** |
---|
103 | * |
---|
104 | * Full class record constant |
---|
105 | * |
---|
106 | ****************************************************************/ |
---|
107 | |
---|
108 | static Boolean ScrollVerticalText(); |
---|
109 | static void VerticalThumb(); |
---|
110 | static void VerticalScroll(); |
---|
111 | static void Page(); |
---|
112 | static void InitializeHook(); |
---|
113 | static void Initialize(); |
---|
114 | static void Realize(); |
---|
115 | static void Resize(); |
---|
116 | static void ResetThumb(); |
---|
117 | static void Redisplay(); |
---|
118 | static void ChildExpose(); |
---|
119 | static Boolean SetValues(); |
---|
120 | static Boolean Layout(); |
---|
121 | static XtGeometryResult GeometryManager(); |
---|
122 | static void ChangeManaged(); |
---|
123 | |
---|
124 | static XtActionsRec actions[] = { |
---|
125 | { "Page", Page}, |
---|
126 | { NULL, NULL}, |
---|
127 | }; |
---|
128 | |
---|
129 | ScrollByLineClassRec scrollByLineClassRec = { |
---|
130 | { |
---|
131 | /* core_class fields */ |
---|
132 | /* superclass */ (WidgetClass) &compositeClassRec, |
---|
133 | /* class_name */ "ScrollByLine", |
---|
134 | /* widget_size */ sizeof(ScrollByLineRec), |
---|
135 | /* class_initialize */ NULL, |
---|
136 | /* class_part_init */ NULL, |
---|
137 | /* class_inited */ FALSE, |
---|
138 | /* initialize */ Initialize, |
---|
139 | /* initialize_hook */ InitializeHook, |
---|
140 | /* realize */ Realize, |
---|
141 | /* actions */ actions, |
---|
142 | /* num_actions */ XtNumber(actions), |
---|
143 | /* resources */ resources, |
---|
144 | /* num_resources */ XtNumber(resources), |
---|
145 | /* xrm_class */ NULLQUARK, |
---|
146 | /* compress_motion */ TRUE, |
---|
147 | /* compress_exposure */ FALSE, |
---|
148 | /* compress_enterleave*/ TRUE, |
---|
149 | /* visible_interest */ FALSE, |
---|
150 | /* destroy */ NULL, |
---|
151 | /* resize */ Resize, |
---|
152 | /* expose */ Redisplay, |
---|
153 | /* set_values */ SetValues, |
---|
154 | /* set_values_hook */ NULL, |
---|
155 | /* set_values_almost */ XtInheritSetValuesAlmost, |
---|
156 | /* get_values_hook */ NULL, |
---|
157 | /* accept_focus */ NULL, |
---|
158 | /* version */ XtVersion, |
---|
159 | /* callback_private */ NULL, |
---|
160 | /* tm_table */ defaultTranslations, |
---|
161 | /* query_geometry */ XtInheritQueryGeometry, |
---|
162 | /* display_accelerator*/ XtInheritDisplayAccelerator, |
---|
163 | /* extension */ NULL, |
---|
164 | },{ |
---|
165 | /* composite_class fields */ |
---|
166 | /* geometry_manager */ GeometryManager, |
---|
167 | /* change_managed */ ChangeManaged, |
---|
168 | /* insert_child */ XtInheritInsertChild, |
---|
169 | /* delete_child */ XtInheritDeleteChild, |
---|
170 | /* extension */ NULL, |
---|
171 | },{ |
---|
172 | /* mumble */ 0 /* Make C compiler happy */ |
---|
173 | } |
---|
174 | }; |
---|
175 | |
---|
176 | WidgetClass scrollByLineWidgetClass = |
---|
177 | (WidgetClass) &scrollByLineClassRec; |
---|
178 | |
---|
179 | |
---|
180 | /**************************************************************** |
---|
181 | * |
---|
182 | * Private Routines |
---|
183 | * |
---|
184 | ****************************************************************/ |
---|
185 | |
---|
186 | |
---|
187 | /* Function Name: Layout |
---|
188 | * Description: This function lays out the scroll_by_line widget. |
---|
189 | * Arguments: w - the scroll_by_line widget. |
---|
190 | * key - a boolean: if true then resize the widget to the child |
---|
191 | * if false the resize children to fit widget. |
---|
192 | * Returns: TRUE if successful. |
---|
193 | */ |
---|
194 | |
---|
195 | static Boolean |
---|
196 | Layout(w,key) |
---|
197 | Widget w; |
---|
198 | int key; |
---|
199 | { |
---|
200 | ScrollByLineWidget sblw = (ScrollByLineWidget) w; |
---|
201 | Dimension width,height; /* The size that the widget would like to be */ |
---|
202 | XtGeometryResult answer; /* the answer from the parent. */ |
---|
203 | Widget vbar,child; /* The two children of this scrolled widget. */ |
---|
204 | int vbar_x,vbar_y; /* The locations of the various elements. */ |
---|
205 | int child_x; |
---|
206 | int c_width; |
---|
207 | Boolean make_bar; |
---|
208 | |
---|
209 | vbar = sblw->composite.children[0]; |
---|
210 | child = sblw->composite.children[1]; |
---|
211 | height = sblw->core.height; |
---|
212 | width = sblw->core.width; |
---|
213 | |
---|
214 | /* set the initial scroll bar positions. */ |
---|
215 | |
---|
216 | vbar_x = vbar_y = - vbar->core.border_width; |
---|
217 | |
---|
218 | /* Should I allow the vertical scrollbar to be seen */ |
---|
219 | |
---|
220 | make_bar = FALSE; |
---|
221 | if ( (!key) && (sblw->scroll_by_line.lines * |
---|
222 | sblw->scroll_by_line.font_height > height) ) |
---|
223 | make_bar = TRUE; |
---|
224 | |
---|
225 | else if ( (key) && (sblw->scroll_by_line.lines * |
---|
226 | sblw->scroll_by_line.font_height > child->core.height) ) |
---|
227 | make_bar = TRUE; |
---|
228 | |
---|
229 | if (sblw->scroll_by_line.allow_vert && (sblw->scroll_by_line.force_bars || |
---|
230 | make_bar) ) { |
---|
231 | /* |
---|
232 | * Resize the outer window to fit the child, or visa versa. Also make scroll |
---|
233 | * bar become placed in the correct location. |
---|
234 | */ |
---|
235 | if (key) |
---|
236 | width = child->core.width + vbar->core.width + |
---|
237 | 2 * vbar->core.border_width; |
---|
238 | else |
---|
239 | c_width = width - vbar->core.width -2 * vbar->core.border_width; |
---|
240 | |
---|
241 | /* Put Scrollbar on right side if scrolled window? */ |
---|
242 | |
---|
243 | if (sblw->scroll_by_line.use_right) { |
---|
244 | vbar_x = width - vbar->core.width - 2 * vbar->core.border_width; |
---|
245 | child_x = 0; |
---|
246 | } |
---|
247 | else |
---|
248 | child_x = vbar->core.width + vbar->core.border_width; |
---|
249 | } |
---|
250 | else { |
---|
251 | /* Make the scroll bar dissappear, note how scroll bar is always there, |
---|
252 | sometimes it is just that we cannot see them. */ |
---|
253 | vbar_x = - vbar->core.width - 2 * vbar->core.border_width - 10; |
---|
254 | child_x = 0; |
---|
255 | if (key) |
---|
256 | width = child->core.width; |
---|
257 | else |
---|
258 | c_width = width; |
---|
259 | } |
---|
260 | |
---|
261 | /* Move child and v_bar to correct location. */ |
---|
262 | |
---|
263 | XtMoveWidget(vbar, vbar_x, vbar_y); |
---|
264 | XtMoveWidget(child, child_x, 0); |
---|
265 | |
---|
266 | /* resize the children to be the correct height or width. */ |
---|
267 | |
---|
268 | XtResizeWidget(vbar, vbar->core.width, height, vbar->core.border_width); |
---|
269 | |
---|
270 | if (!key) |
---|
271 | XtResizeWidget(child, (Cardinal) (c_width - 20), (Cardinal) height, |
---|
272 | child->core.border_width); |
---|
273 | |
---|
274 | /* set the thumb size to be correct. */ |
---|
275 | |
---|
276 | ResetThumb( (Widget) sblw); |
---|
277 | |
---|
278 | answer = XtMakeResizeRequest( (Widget) sblw, width, height, &width, &height); |
---|
279 | |
---|
280 | switch(answer) { |
---|
281 | case XtGeometryYes: |
---|
282 | break; |
---|
283 | case XtGeometryNo: |
---|
284 | return(FALSE); |
---|
285 | case XtGeometryAlmost: |
---|
286 | (void) Layout( (Widget) sblw,FALSE); |
---|
287 | } |
---|
288 | return(TRUE); |
---|
289 | } |
---|
290 | |
---|
291 | /* Function Name: ResetThumb |
---|
292 | * Description: This function resets the thumb's shown percentage only. |
---|
293 | * Arguments: w - the ScrollByLineWidget. |
---|
294 | * Returns: none; |
---|
295 | */ |
---|
296 | |
---|
297 | static void |
---|
298 | ResetThumb(w) |
---|
299 | Widget w; |
---|
300 | { |
---|
301 | float shown; |
---|
302 | ScrollByLineWidget sblw = (ScrollByLineWidget) w; |
---|
303 | Widget child,vbar; |
---|
304 | |
---|
305 | vbar = sblw->composite.children[0]; |
---|
306 | child = sblw->composite.children[1]; |
---|
307 | |
---|
308 | /* vertical */ |
---|
309 | |
---|
310 | shown = (float) child->core.height /(float) (sblw->scroll_by_line.lines * |
---|
311 | sblw->scroll_by_line.font_height); |
---|
312 | if (shown > 1.0) |
---|
313 | shown = 1.0; |
---|
314 | |
---|
315 | XtScrollBarSetThumb( vbar, (float) -1, shown ); |
---|
316 | } |
---|
317 | |
---|
318 | /* |
---|
319 | * |
---|
320 | * Geometry Manager - If the height of width is changed then try a new layout. |
---|
321 | * else dissallow the requwest. |
---|
322 | * |
---|
323 | */ |
---|
324 | |
---|
325 | /*ARGSUSED*/ |
---|
326 | static XtGeometryResult GeometryManager(w, request, reply) |
---|
327 | Widget w; |
---|
328 | XtWidgetGeometry *request; |
---|
329 | XtWidgetGeometry *reply; /* RETURN */ |
---|
330 | |
---|
331 | { |
---|
332 | ScrollByLineWidget sblw; |
---|
333 | |
---|
334 | sblw = (ScrollByLineWidget) w->core.parent; |
---|
335 | if ( request->width != 0 && request->height != 0 && |
---|
336 | (request->request_mode && (CWWidth || CWHeight)) ) { |
---|
337 | w->core.height = request->height; |
---|
338 | w->core.width = request->width; |
---|
339 | (void) Layout( (Widget) sblw,TRUE); |
---|
340 | return(XtGeometryYes); |
---|
341 | } |
---|
342 | return(XtGeometryNo); |
---|
343 | |
---|
344 | } /* Geometery Manager */ |
---|
345 | |
---|
346 | /* ARGSUSED */ |
---|
347 | static void ChildExpose(w,junk,event) |
---|
348 | Widget w; |
---|
349 | caddr_t junk; |
---|
350 | XEvent *event; |
---|
351 | { |
---|
352 | |
---|
353 | /* |
---|
354 | * since we are realy concerned with the expose events that happen |
---|
355 | * to the child, we have selected expose events on this window, and |
---|
356 | * then I call the redisplay routine. |
---|
357 | */ |
---|
358 | |
---|
359 | if ((event->type == Expose) || (event->type == GraphicsExpose)) |
---|
360 | Redisplay(w->core.parent, event, NULL); |
---|
361 | |
---|
362 | } /* ChildExpose */ |
---|
363 | |
---|
364 | /* |
---|
365 | * Repaint the widget's child Window Widget. |
---|
366 | */ |
---|
367 | |
---|
368 | /* ARGSUSED */ |
---|
369 | static void Redisplay(w, event, region) |
---|
370 | Widget w; |
---|
371 | XEvent *event; |
---|
372 | Region region; |
---|
373 | { |
---|
374 | ScrollByLineWidget sblw = (ScrollByLineWidget) w; |
---|
375 | |
---|
376 | int top,bottom; /* the locations of the top and |
---|
377 | bottom of the region that needs to be |
---|
378 | repainted. */ |
---|
379 | ScrollByLineStruct sblw_struct; |
---|
380 | |
---|
381 | /* |
---|
382 | * This routine tells the client which sections of the window to |
---|
383 | * repaint in his callback function which does the actual repainting. |
---|
384 | */ |
---|
385 | |
---|
386 | if (event->type == Expose) { |
---|
387 | top = event->xexpose.y; |
---|
388 | bottom = event->xexpose.height + top; |
---|
389 | } |
---|
390 | else { |
---|
391 | top = event->xgraphicsexpose.y; |
---|
392 | bottom = event->xgraphicsexpose.height + top; |
---|
393 | } |
---|
394 | |
---|
395 | sblw_struct.start_line = top / sblw->scroll_by_line.font_height + |
---|
396 | sblw->scroll_by_line.line_pointer; |
---|
397 | /* |
---|
398 | * If an expose event is called on a region that has no text assoicated |
---|
399 | * with it then do not redisplay. Only nescessary for very short file. |
---|
400 | */ |
---|
401 | if (sblw_struct.start_line > sblw->scroll_by_line.lines) |
---|
402 | return; |
---|
403 | sblw_struct.num_lines = (bottom - top) / |
---|
404 | sblw->scroll_by_line.font_height + 1; |
---|
405 | sblw_struct.location = top / sblw->scroll_by_line.font_height * |
---|
406 | sblw->scroll_by_line.font_height; |
---|
407 | |
---|
408 | XtCallCallbacks( (Widget) sblw, XtNcallback, (caddr_t) &sblw_struct); |
---|
409 | |
---|
410 | } /* redisplay (expose) */ |
---|
411 | |
---|
412 | static void |
---|
413 | Resize(w) |
---|
414 | Widget w; |
---|
415 | { |
---|
416 | |
---|
417 | (void) Layout(w,FALSE); |
---|
418 | |
---|
419 | } /* Resize */ |
---|
420 | |
---|
421 | static void ChangeManaged(w) |
---|
422 | Widget w; |
---|
423 | { |
---|
424 | /* note how we ignore bonus children, but since we control all children, |
---|
425 | there should never be a problem anyway. */ |
---|
426 | ScrollByLineWidget sblw = (ScrollByLineWidget) w;; |
---|
427 | |
---|
428 | if (sblw->composite.num_children == 3) { |
---|
429 | (void) Layout( w,sblw->scroll_by_line.key); |
---|
430 | } |
---|
431 | |
---|
432 | } /* Change Managed */ |
---|
433 | |
---|
434 | /* Function Name: Page |
---|
435 | * Description: This function pages the widget, by the amount it recieves |
---|
436 | * from the translation Manager. |
---|
437 | * Arguments: w - the ScrollByLineWidget. |
---|
438 | * event - the event that caused this return. |
---|
439 | * params - the parameters passed to it. |
---|
440 | * num_params - the number of parameters. |
---|
441 | * Returns: none. |
---|
442 | */ |
---|
443 | |
---|
444 | static void |
---|
445 | Page(w, event, params, num_params) |
---|
446 | Widget w; |
---|
447 | XEvent * event; |
---|
448 | String * params; |
---|
449 | Cardinal *num_params; |
---|
450 | { |
---|
451 | ScrollByLineWidget sblw = (ScrollByLineWidget) w; |
---|
452 | Widget vbar = sblw->composite.children[0]; |
---|
453 | char direction; |
---|
454 | |
---|
455 | if (*num_params > 0) |
---|
456 | direction = *params[0]; |
---|
457 | else |
---|
458 | return; |
---|
459 | |
---|
460 | /* |
---|
461 | * If no scroll bar is visible then do not page, as the entire window is shown, |
---|
462 | * of scrolling has been turned off. |
---|
463 | */ |
---|
464 | |
---|
465 | if (vbar->core.x < - vbar->core.border_width) |
---|
466 | return; |
---|
467 | |
---|
468 | switch ( direction ) { |
---|
469 | case 'f': |
---|
470 | case 'F': |
---|
471 | /* move one page forward */ |
---|
472 | VerticalScroll(vbar,NULL, (int) vbar->core.height); |
---|
473 | break; |
---|
474 | case 'b': |
---|
475 | case 'B': |
---|
476 | /* move one page backward */ |
---|
477 | VerticalScroll(vbar,NULL, - (int) vbar->core.height); |
---|
478 | break; |
---|
479 | case 'L': |
---|
480 | case 'l': |
---|
481 | /* move one line forward */ |
---|
482 | VerticalScroll(vbar,NULL, (int) sblw->scroll_by_line.font_height); |
---|
483 | break; |
---|
484 | default: |
---|
485 | return; |
---|
486 | } |
---|
487 | } |
---|
488 | |
---|
489 | /* Function Name: ScrollVerticalText |
---|
490 | * Description: This accomplished the actual movement of the text. |
---|
491 | * Arguments: w - the ScrollByLine Widget. |
---|
492 | * new_line - the new location for the line pointer |
---|
493 | * force_redisplay - should we force this window to get |
---|
494 | * redisplayed? |
---|
495 | * Returns: True if the thumb needs to be moved. |
---|
496 | */ |
---|
497 | |
---|
498 | static Boolean |
---|
499 | ScrollVerticalText(w,new_line,force_redisp) |
---|
500 | Widget w; |
---|
501 | int new_line; |
---|
502 | Boolean force_redisp; |
---|
503 | { |
---|
504 | ScrollByLineWidget sblw = (ScrollByLineWidget) w; |
---|
505 | int max_lines, /* The location of top of the last screen. */ |
---|
506 | num_lines, /* The number of lines in one screen of text */ |
---|
507 | y_pos, /* The location to start displaying text. */ |
---|
508 | num_lines_disp, /* The number of lines to display. */ |
---|
509 | start_line, /* The line to start displaying text. */ |
---|
510 | y_location, /* The y_location to for storing copy area. */ |
---|
511 | lines_to_move; /* The number of lines to copy. */ |
---|
512 | GC gc; |
---|
513 | Widget child,vbar; /* Widgets. */ |
---|
514 | ScrollByLineStruct sblw_struct; |
---|
515 | Boolean move_thumb = FALSE; |
---|
516 | |
---|
517 | vbar = sblw->composite.children[0]; |
---|
518 | child = sblw->composite.children[1]; |
---|
519 | |
---|
520 | num_lines = child->core.height / sblw->scroll_by_line.font_height; |
---|
521 | |
---|
522 | gc = XCreateGC(XtDisplay( (Widget) sblw),XtWindow(child),NULL,0); |
---|
523 | XSetGraphicsExposures(XtDisplay( (Widget) sblw),gc,TRUE); |
---|
524 | |
---|
525 | /* do not let the window extend out of bounds */ |
---|
526 | |
---|
527 | if ( new_line < 0) { |
---|
528 | move_thumb = TRUE; |
---|
529 | new_line = 0; |
---|
530 | } |
---|
531 | else { |
---|
532 | max_lines = sblw->scroll_by_line.lines - |
---|
533 | child->core.height / sblw->scroll_by_line.font_height; |
---|
534 | |
---|
535 | if (max_lines < 0) max_lines = 0; |
---|
536 | |
---|
537 | if ( new_line > max_lines ) { |
---|
538 | new_line = max_lines; |
---|
539 | move_thumb = TRUE; |
---|
540 | } |
---|
541 | } |
---|
542 | |
---|
543 | if ( new_line == sblw->scroll_by_line.line_pointer && !force_redisp) |
---|
544 | /* No change in postion, and no action is nescessary */ |
---|
545 | return(move_thumb); |
---|
546 | else if ( new_line <= sblw->scroll_by_line.line_pointer) { /* scroll back. */ |
---|
547 | if ( sblw->scroll_by_line.line_pointer - new_line >= num_lines |
---|
548 | || force_redisp) { |
---|
549 | /* |
---|
550 | * We have moved so far that no text that is currently on the screen can |
---|
551 | * be saved thus there is no need to be clever just clear |
---|
552 | * the window and display a full screen of text. |
---|
553 | */ |
---|
554 | XClearWindow(XtDisplay(child),XtWindow(child)); |
---|
555 | y_pos = 0; |
---|
556 | start_line = new_line; |
---|
557 | num_lines_disp = num_lines; |
---|
558 | } |
---|
559 | else { |
---|
560 | /* |
---|
561 | * Move text that is to remain on the screen to its new location, and then |
---|
562 | * set up the proper callback values to display the rest of the text. |
---|
563 | */ |
---|
564 | lines_to_move = num_lines - sblw->scroll_by_line.line_pointer + new_line; |
---|
565 | y_location = sblw->scroll_by_line.line_pointer - new_line; |
---|
566 | XCopyArea(XtDisplay(vbar),XtWindow(child),XtWindow(child), |
---|
567 | gc,0,0,child->core.width, |
---|
568 | (lines_to_move + 1) * sblw->scroll_by_line.font_height, |
---|
569 | 0,y_location * sblw->scroll_by_line.font_height); |
---|
570 | XClearArea( XtDisplay(vbar),XtWindow(child),0,0,0, |
---|
571 | (num_lines - lines_to_move) |
---|
572 | * sblw->scroll_by_line.font_height, |
---|
573 | FALSE ); |
---|
574 | y_pos = 0; |
---|
575 | start_line = new_line; |
---|
576 | num_lines_disp = num_lines - lines_to_move; |
---|
577 | } |
---|
578 | } |
---|
579 | else { /* scrolling forward */ |
---|
580 | if ( new_line - sblw->scroll_by_line.line_pointer >= num_lines |
---|
581 | || force_redisp) { |
---|
582 | /* |
---|
583 | * We have moved so far that no text that is currently on the screen can |
---|
584 | * be saved thus there is no need to be clever just clear |
---|
585 | * the window and display a full screen of text. |
---|
586 | */ |
---|
587 | XClearWindow(XtDisplay(child),XtWindow(child)); |
---|
588 | y_pos = 0; |
---|
589 | start_line = new_line; |
---|
590 | num_lines_disp = num_lines; |
---|
591 | } |
---|
592 | else { |
---|
593 | /* |
---|
594 | * Move text that is to remain on the screen to its new location, and then |
---|
595 | * set up the proper callback values to display the rest of the text. |
---|
596 | */ |
---|
597 | lines_to_move = num_lines - new_line + sblw->scroll_by_line.line_pointer; |
---|
598 | y_location = new_line - sblw->scroll_by_line.line_pointer; |
---|
599 | XCopyArea(XtDisplay(vbar),XtWindow(child),XtWindow(child),gc,0, |
---|
600 | y_location * sblw->scroll_by_line.font_height, |
---|
601 | child->core.width, |
---|
602 | (lines_to_move)* sblw->scroll_by_line.font_height,0,0); |
---|
603 | |
---|
604 | lines_to_move--; /* make sure that we get the last, |
---|
605 | (possibly) partial line, fully painted. */ |
---|
606 | |
---|
607 | /* we add 10% of a font height here to the vertical position |
---|
608 | because some characters extend a little bit below the fontheight */ |
---|
609 | |
---|
610 | XClearArea(XtDisplay(vbar),XtWindow(child),0,lines_to_move * |
---|
611 | sblw->scroll_by_line.font_height + (int) |
---|
612 | (.1 * (float) sblw->scroll_by_line.font_height),0,0,FALSE); |
---|
613 | |
---|
614 | y_pos = lines_to_move * sblw->scroll_by_line.font_height; |
---|
615 | start_line = new_line + lines_to_move; |
---|
616 | num_lines_disp = num_lines - lines_to_move; |
---|
617 | } |
---|
618 | } |
---|
619 | |
---|
620 | sblw->scroll_by_line.line_pointer = new_line; |
---|
621 | |
---|
622 | /* |
---|
623 | * call the callbacks, this is the callback to the application to do the |
---|
624 | * actual painting of the text. |
---|
625 | */ |
---|
626 | |
---|
627 | sblw_struct.location = y_pos; |
---|
628 | sblw_struct.start_line = start_line; |
---|
629 | sblw_struct.num_lines = num_lines_disp; |
---|
630 | |
---|
631 | XtCallCallbacks( (Widget) sblw,XtNcallback, (caddr_t) &sblw_struct); |
---|
632 | |
---|
633 | /* Save that memory */ |
---|
634 | |
---|
635 | XFreeGC(XtDisplay( (Widget) sblw), gc); |
---|
636 | |
---|
637 | return(move_thumb); |
---|
638 | } |
---|
639 | |
---|
640 | /* Function Name: VerticalThumb |
---|
641 | * Description: This function moves the postition of the interior window |
---|
642 | * as the vertical scroll bar is moved. |
---|
643 | * Arguments: w - the scrollbar widget. |
---|
644 | * junk - not used. |
---|
645 | * percent - the position of the scrollbar. |
---|
646 | * Returns: none. |
---|
647 | */ |
---|
648 | |
---|
649 | static void |
---|
650 | VerticalThumb(w,junk,percent) |
---|
651 | Widget w; |
---|
652 | caddr_t junk; |
---|
653 | float *percent; |
---|
654 | { |
---|
655 | int new_line; /* The new location for the line pointer. */ |
---|
656 | float location; /* The location of the thumb. */ |
---|
657 | Widget vbar; |
---|
658 | |
---|
659 | ScrollByLineWidget sblw = (ScrollByLineWidget) w->core.parent; |
---|
660 | |
---|
661 | vbar = sblw->composite.children[0]; |
---|
662 | |
---|
663 | new_line = (int) ((float) sblw->scroll_by_line.lines * (*percent)); |
---|
664 | |
---|
665 | if (ScrollVerticalText( (Widget) sblw, new_line, FALSE)) { |
---|
666 | /* reposition the thumb */ |
---|
667 | location = (float) sblw->scroll_by_line.line_pointer / |
---|
668 | (float) sblw->scroll_by_line.lines; |
---|
669 | XtScrollBarSetThumb( vbar, location , (float) -1 ); |
---|
670 | } |
---|
671 | |
---|
672 | } |
---|
673 | |
---|
674 | /* Function Name: VerticalScroll |
---|
675 | * Description: This function moves the postition of the interior window |
---|
676 | * as the vertical scroll bar is moved. |
---|
677 | * Arguments: w - the scrollbar widget. |
---|
678 | * junk - not used. |
---|
679 | * pos - the position of the cursor. |
---|
680 | * Returns: none. |
---|
681 | */ |
---|
682 | |
---|
683 | static void |
---|
684 | VerticalScroll(w,junk,pos) |
---|
685 | Widget w; |
---|
686 | caddr_t junk; |
---|
687 | int pos; |
---|
688 | { |
---|
689 | int new_line; /* The new location for the line pointer. */ |
---|
690 | float location; /* The new location of the thumb. */ |
---|
691 | Widget vbar; |
---|
692 | |
---|
693 | ScrollByLineWidget sblw = (ScrollByLineWidget) w->core.parent; |
---|
694 | |
---|
695 | vbar = sblw->composite.children[0]; |
---|
696 | |
---|
697 | new_line = sblw->scroll_by_line.line_pointer; |
---|
698 | new_line += (int) pos / sblw->scroll_by_line.font_height; |
---|
699 | |
---|
700 | (void) ScrollVerticalText( (Widget) sblw,new_line,FALSE); |
---|
701 | |
---|
702 | /* reposition the thumb */ |
---|
703 | |
---|
704 | location = (float) sblw->scroll_by_line.line_pointer / |
---|
705 | (float) sblw->scroll_by_line.lines; |
---|
706 | XtScrollBarSetThumb( vbar, location , (float) -1 ); |
---|
707 | } |
---|
708 | |
---|
709 | static void |
---|
710 | Initialize(req, new) |
---|
711 | Widget req, new; |
---|
712 | { |
---|
713 | ScrollByLineWidget sblw = (ScrollByLineWidget) new; |
---|
714 | |
---|
715 | sblw->scroll_by_line.line_pointer = 0; /* initially point to line 0. */ |
---|
716 | |
---|
717 | if (sblw->core.height <= 0) |
---|
718 | sblw->core.height = DEFAULT_HEIGHT; |
---|
719 | if (sblw->core.width <= 0) |
---|
720 | sblw->core.width = DEFAULT_WIDTH; |
---|
721 | } /* Initialize. */ |
---|
722 | |
---|
723 | static void |
---|
724 | InitializeHook(new, args, num_args) |
---|
725 | ScrollByLineWidget new; |
---|
726 | ArgList args; |
---|
727 | Cardinal *num_args; |
---|
728 | { |
---|
729 | ScrollByLineWidget sblw = (ScrollByLineWidget) new; |
---|
730 | Widget window, s_bar; /* Window widget, and scollbar. */ |
---|
731 | Arg arglist[10]; /* an arglist. */ |
---|
732 | ArgList merged_list, XtMergeArgLists(); /* The merged arglist. */ |
---|
733 | Cardinal window_num, merged_num; /* The number of window args. */ |
---|
734 | |
---|
735 | s_bar = XtCreateManagedWidget("verticalScrollBar", scrollbarWidgetClass, |
---|
736 | (Widget) sblw, args, *num_args); |
---|
737 | XtAddCallback(s_bar, XtNjumpProc, VerticalThumb, NULL); |
---|
738 | XtAddCallback(s_bar, XtNscrollProc, VerticalScroll, NULL); |
---|
739 | |
---|
740 | window_num = 0; |
---|
741 | XtSetArg(arglist[window_num], XtNwidth, sblw->scroll_by_line.inner_width); |
---|
742 | window_num++; |
---|
743 | XtSetArg(arglist[window_num], XtNheight, sblw->scroll_by_line.inner_height); |
---|
744 | window_num++; |
---|
745 | XtSetArg(arglist[window_num], XtNborderWidth, 0); |
---|
746 | window_num++; |
---|
747 | |
---|
748 | /* |
---|
749 | * I hope this will cause my args to override those passed to the SBL widget. |
---|
750 | */ |
---|
751 | |
---|
752 | merged_list = XtMergeArgLists(args, *num_args, arglist, window_num); |
---|
753 | merged_num = *num_args + window_num; |
---|
754 | |
---|
755 | window = XtCreateWidget("windowWithFile",widgetClass,(Widget) sblw, |
---|
756 | merged_list, merged_num); |
---|
757 | XtManageChild(window); |
---|
758 | XtFree(merged_list); /* done, free it. */ |
---|
759 | |
---|
760 | /* |
---|
761 | * We want expose (and graphic exposuer) events for this window also. |
---|
762 | */ |
---|
763 | |
---|
764 | XtAddEventHandler(window, (Cardinal) ExposureMask, TRUE, ChildExpose, NULL); |
---|
765 | |
---|
766 | } /* InitializeHook */ |
---|
767 | |
---|
768 | static void Realize(w, valueMask, attributes) |
---|
769 | register Widget w; |
---|
770 | Mask *valueMask; |
---|
771 | XSetWindowAttributes *attributes; |
---|
772 | { |
---|
773 | XtCreateWindow( w, (Cardinal) InputOutput, (Visual *)CopyFromParent, |
---|
774 | *valueMask, attributes); |
---|
775 | } /* Realize */ |
---|
776 | |
---|
777 | /* |
---|
778 | * |
---|
779 | * Set Values |
---|
780 | * |
---|
781 | */ |
---|
782 | |
---|
783 | static Boolean SetValues (current, request, new) |
---|
784 | Widget current, request, new; |
---|
785 | { |
---|
786 | ScrollByLineWidget sblw_new, sblw_current; |
---|
787 | Boolean ret = FALSE; |
---|
788 | |
---|
789 | sblw_current = (ScrollByLineWidget) current; |
---|
790 | sblw_new = (ScrollByLineWidget) new; |
---|
791 | |
---|
792 | if (sblw_current->scroll_by_line.lines != sblw_new->scroll_by_line.lines) { |
---|
793 | ResetThumb(new); |
---|
794 | ret = TRUE; |
---|
795 | } |
---|
796 | if (sblw_current->scroll_by_line.font_height != |
---|
797 | sblw_new->scroll_by_line.font_height) { |
---|
798 | ResetThumb(new); |
---|
799 | ret = TRUE; |
---|
800 | } |
---|
801 | return(ret); |
---|
802 | |
---|
803 | } /* Set Values */ |
---|
804 | |
---|
805 | /* Public Routines. */ |
---|
806 | |
---|
807 | /* Function Name: XtScrollByLineWidget() |
---|
808 | * Description: This function returns the window widget that the |
---|
809 | * ScrollByLine widget uses to display its text. |
---|
810 | * Arguments: w - the ScrollByLine Widget. |
---|
811 | * Returns: the widget to display the text into. |
---|
812 | */ |
---|
813 | |
---|
814 | extern Widget XtScrollByLineWidget(w) |
---|
815 | Widget w; |
---|
816 | { |
---|
817 | ScrollByLineWidget sblw = (ScrollByLineWidget) w; /* the sblw widget. */ |
---|
818 | |
---|
819 | return(sblw->composite.children[1]); |
---|
820 | } |
---|
821 | |
---|
822 | /* Function Name: XtResetScrollByLine |
---|
823 | * Description: This function resets the scroll by line widget. |
---|
824 | * Arguments: w - the sblw widget. |
---|
825 | * Returns: none. |
---|
826 | */ |
---|
827 | |
---|
828 | extern void |
---|
829 | XtResetScrollByLine(w) |
---|
830 | Widget w; |
---|
831 | { |
---|
832 | float location; /* the location of the thumb. */ |
---|
833 | ScrollByLineWidget sblw = (ScrollByLineWidget) w; /* the sblw widget. */ |
---|
834 | Widget vbar; |
---|
835 | |
---|
836 | vbar = sblw->composite.children[0]; |
---|
837 | |
---|
838 | (void) ScrollVerticalText( w, 0, TRUE); |
---|
839 | |
---|
840 | /* reposition the thumb */ |
---|
841 | |
---|
842 | location = (float) sblw->scroll_by_line.line_pointer / |
---|
843 | (float) sblw->scroll_by_line.lines; |
---|
844 | XtScrollBarSetThumb( vbar, location , (float) -1 ); |
---|
845 | |
---|
846 | Layout(w, FALSE); /* see if new layout is required. */ |
---|
847 | } |
---|