1 /*
2 **
3 ** Vlist.c
4 **
5 ** Copyright (C) 1995, 1996, 1997 Johannes Plass
6 ** Copyright (C) 2004 Jose E. Marchesi
7 ** modified 2008 by Bernhard R. Link
8 **
9 ** This program is free software; you can redistribute it and/or modify
10 ** it under the terms of the GNU General Public License as published by
11 ** the Free Software Foundation; either version 3 of the License, or
12 ** (at your option) any later version.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with GNU gv; see the file COPYING.  If not, write to
21 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ** Boston, MA 02111-1307, USA.
23 **
24 ** Author:   Johannes Plass (plass@thep.physik.uni-mainz.de)
25 **           Department of Physics
26 **           Johannes Gutenberg-University
27 **           Mainz, Germany
28 **
29 **           Jose E. Marchesi (jemarch@gnu.org)
30 **           GNU Project
31 **
32 */
33 
34 #include "ac_config.h"
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <math.h>
39 /*
40 #define MESSAGES
41 */
42 #include "message.h"
43 
44 #include "paths.h"
45 #include INC_X11(IntrinsicP.h)
46 #include INC_X11(StringDefs.h)
47 #include INC_XMU(Misc.h)
48 #include INC_XAW(XawInit.h)
49 #include "VlistP.h"
50 #include "Frame.h"
51 #include INC_XMU(Converters.h)
52 
53 #define VLIST_MARK_LEFT_INDENT  4
54 #define VLIST_MARK_LABEL_INTERNAL_WIDTH 11
55 #define VLIST_MARK_LABEL_INDENT 4
56 #define VLIST_MARK_VERTICAL_INDENT 3
57 #define VLIST_MARK_WIDTH 5
58 
59 /****************************************************************
60  *
61  * Full class record constant
62  *
63  ****************************************************************/
64 
65 /* Private Data */
66 
67 static char defaultTranslations[] = "";
68 
69 #define offset(field) XtOffsetOf(VlistRec, field)
70 static XtResource resources[] = {
71    {XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer),
72 	offset(vlist.report_callbacks), XtRCallback, (XtPointer) NULL },
73    {XtNselectedShadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
74 	offset(vlist.selected_shadow_width), XtRImmediate, (XtPointer) 1},
75    {XtNmarkShadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
76 	offset(vlist.mark_shadow_width), XtRImmediate, (XtPointer) 1},
77    {XtNhighlightedShadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
78 	offset(vlist.highlighted_shadow_width), XtRImmediate, (XtPointer) 1},
79    {XtNhighlightedGeometry, XtCHighlightedGeometry, XtRString, sizeof(String),
80       offset(vlist.highlighted_geometry), XtRImmediate, (XtPointer)"2 0 -2 1"},
81    {XtNselectedGeometry, XtCSelectedGeometry, XtRString, sizeof(String),
82       offset(vlist.selected_geometry), XtRImmediate, (XtPointer)"12 0 -2 1"},
83    {XtNvlist,  XtCVlist, XtRString, sizeof(String),
84       offset(vlist.vlist), XtRString, NULL},
85    {XtNmarkBackground, XtCMarkBackground, XtRPixel, sizeof(Pixel),
86 	offset(vlist.mark_background), XtRString, XtDefaultBackground},
87    {XtNselectedBackground, XtCSelectedBackground, XtRPixel, sizeof(Pixel),
88 	offset(vlist.selected_background), XtRString, XtDefaultBackground},
89    {XtNhighlightedBackground, XtCHighlightedBackground, XtRPixel, sizeof(Pixel),
90 	offset(vlist.highlighted_background), XtRString, XtDefaultBackground},
91    {XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
92       offset(threeD.shadow_width), XtRImmediate, (XtPointer) 2},
93    {XtNallowMarks, XtCAllowMarks, XtRBoolean, sizeof(Boolean),
94       offset(vlist.allow_marks), XtRImmediate, (XtPointer)True},
95    {XtNinternalWidth, XtCWidth, XtRDimension,  sizeof(Dimension),
96 	offset(label.internal_width), XtRImmediate, (XtPointer)VLIST_MARK_LABEL_INTERNAL_WIDTH},
97    {XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
98       XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate,
99       (XtPointer)0}
100 };
101 #undef offset
102 
103 static Boolean SetValues(Widget,Widget,Widget,ArgList,Cardinal*);
104 static void Initialize(Widget,Widget,ArgList,Cardinal*);
105 static void Redisplay(Widget,XEvent*,Region);
106 static void Destroy(Widget);
107 static void PaintVlistWidget(Widget,XEvent*,Region);
108 static void ClassInitialize(void);
109 static void Resize(Widget);
110 static void PaintMarkOfEntry(Widget,Region,int,int,Boolean);
111 static void PaintMarkMarkOfEntry(Widget,Region,int,Boolean);
112 
113 
114 #define SuperClass ((LabelWidgetClass)&labelClassRec)
115 
116 VlistClassRec vlistClassRec = {
117   {
118     (WidgetClass) SuperClass,		/* superclass		  */
119     "Vlist",				/* class_name		  */
120     sizeof(VlistRec),			/* size			  */
121     ClassInitialize,			/* class_initialize	  */
122     NULL,				/* class_part_initialize  */
123     FALSE,				/* class_inited		  */
124     Initialize,				/* initialize		  */
125     NULL,				/* initialize_hook	  */
126     XtInheritRealize,			/* realize		  */
127     NULL,				/* actions		  */
128     0,					/* num_actions		  */
129     resources,				/* resources		  */
130     XtNumber(resources),		/* resource_count	  */
131     NULLQUARK,				/* xrm_class		  */
132     TRUE,				/* compress_motion	  */
133     TRUE,				/* compress_exposure	  */
134     TRUE,				/* compress_enterleave    */
135     FALSE,				/* visible_interest	  */
136     Destroy,				/* destroy		  */
137     Resize,				/* resize		  */
138     Redisplay,				/* expose		  */
139     SetValues,				/* set_values		  */
140     NULL,				/* set_values_hook	  */
141     XtInheritSetValuesAlmost,		/* set_values_almost	  */
142     NULL,				/* get_values_hook	  */
143     NULL,				/* accept_focus		  */
144     XtVersion,				/* version		  */
145     NULL,				/* callback_private	  */
146     defaultTranslations,		/* tm_table		  */
147     XtInheritQueryGeometry,		/* query_geometry	  */
148     XtInheritDisplayAccelerator,	/* display_accelerator	  */
149     NULL				/* extension		  */
150   },  /* CoreClass fields initialization */
151   {
152     XtInheritChangeSensitive		/* change_sensitive	*/
153   },  /* SimpleClass fields initialization */
154   {
155     XtInheritXaw3dShadowDraw,           /* shadowdraw           */
156   },  /* ThreeD Class fields initialization */
157   {
158     0,                                     /* field not used    */
159   },  /* LabelClass fields initialization */
160   {
161     0,                                     /* field not used    */
162   },  /* VlistClass fields initialization */
163 };
164 
165   /* for public consumption */
166 WidgetClass vlistWidgetClass = (WidgetClass) &vlistClassRec;
167 
168 /*---------------------------------------------------*/
169 /* ClassInitialize */
170 /*---------------------------------------------------*/
171 
ClassInitialize(void)172 static void ClassInitialize(void)
173 {
174   BEGINMESSAGE(ClassInitialize)
175   XawInitializeWidgetSet();
176   ENDMESSAGE(ClassInitialize)
177 }
178 
179 /*---------------------------------------------------*/
180 /* Initialize */
181 /*---------------------------------------------------*/
182 
183 static void
Initialize(Widget request _GL_UNUSED,Widget new,ArgList args _GL_UNUSED,Cardinal * num_args _GL_UNUSED)184 Initialize(Widget request _GL_UNUSED, Widget new, ArgList args _GL_UNUSED, Cardinal *num_args _GL_UNUSED)
185 {
186   VlistWidget vw = (VlistWidget) new;
187   String s="";
188   char *c;
189   XGCValues values;
190 
191   BEGINMESSAGE(Initialize)
192   if (vw->vlist.vlist) s = vw->vlist.vlist;
193   vw->vlist.vlist = XtNewString(s);
194   c = vw->vlist.vlist;
195   vw->vlist.firstVisible = 0;
196   vw->vlist.selected = -1;
197   vw->vlist.highlighted = -1;
198   vw->vlist.entries = (int)strlen(vw->vlist.vlist);
199   sscanf(vw->vlist.highlighted_geometry,"%d %d %d %d",
200         &(vw->vlist.hulx),&(vw->vlist.huly),&(vw->vlist.hlrx),&(vw->vlist.hlry));
201   sscanf(vw->vlist.selected_geometry,"%d %d %d %d",
202         &(vw->vlist.sulx),&(vw->vlist.suly),&(vw->vlist.slrx),&(vw->vlist.slry));
203   /* mark background GC */
204   values.foreground	= vw->vlist.mark_background;
205   vw->vlist.mark_background_GC = XtGetGC((Widget)vw,(unsigned) GCForeground,&values);
206   /* selected background GC */
207   values.foreground = vw->vlist.selected_background;
208   vw->vlist.selected_background_GC = XtGetGC((Widget)vw,(unsigned) GCForeground,&values);
209   /* highlighted background GC */
210   values.foreground = vw->vlist.highlighted_background;
211   vw->vlist.highlighted_background_GC = XtGetGC((Widget)vw,(unsigned) GCForeground,&values);
212   /* background GC */
213   values.foreground	= vw->core.background_pixel;
214   values.graphics_exposures = False;
215   vw->vlist.background_GC = XtGetGC((Widget)vw,(unsigned) GCForeground | GCGraphicsExposures,&values);
216 
217   /* TODO: check if this works here in international mode, or if it has
218    * to be moved to Realize... */
219 #ifdef HAVE_XAW3D_INTERNATIONAL
220   if( vw->simple.international == True ) {
221     XFontSetExtents *ext = XExtentsOfFontSet(vw->label.fontset);
222     vw->vlist.yofs = (ext->max_ink_extent.y<0)?-ext->max_ink_extent.y:ext->max_ink_extent.y;
223     vw->vlist.ydelta = ext->max_ink_extent.height;
224   } else {
225 #endif
226     vw->vlist.yofs = vw->label.font->max_bounds.ascent;
227     vw->vlist.ydelta = vw->label.font->max_bounds.ascent + vw->label.font->max_bounds.descent;
228 #ifdef HAVE_XAW3D_INTERNATIONAL
229   }
230 #endif
231 
232   ENDMESSAGE(Initialize)
233 }
234 
235 /*---------------------------------------------------*/
236 /* Redisplay */
237 /*---------------------------------------------------*/
238 
239 static void
Redisplay(Widget w,XEvent * event,Region region)240 Redisplay(Widget w, XEvent *event, Region region)
241 {
242   BEGINMESSAGE(Redisplay)
243   PaintVlistWidget(w, event, region);
244   ENDMESSAGE(Redisplay)
245 }
246 
247 /*---------------------------------------------------*/
248 /* Resize */
249 /*---------------------------------------------------*/
250 
shiftLabel(VlistWidget vw)251 static void shiftLabel(VlistWidget vw)
252 {
253   BEGINMESSAGE(shiftLabel)
254   if (vw->vlist.allow_marks) {
255     vw->label.label_x = vw->label.internal_width +
256                         vw->threeD.shadow_width  +
257                         VLIST_MARK_LABEL_INDENT;
258   }
259   ENDMESSAGE(shiftLabel)
260 }
261 
Resize(Widget w)262 static void Resize(Widget w)
263 {
264   VlistWidget vw = (VlistWidget) w;
265   BEGINMESSAGE(Resize)
266   (*vlistWidgetClass->core_class.superclass->core_class.resize)(w);
267   shiftLabel(vw);
268   ENDMESSAGE(Resize)
269 }
270 
271 /*---------------------------------------------------*/
272 /* SetValues */
273 /*---------------------------------------------------*/
274 
275 static Boolean
SetValues(Widget current,Widget request _GL_UNUSED,Widget new,ArgList args _GL_UNUSED,Cardinal * num_args _GL_UNUSED)276 SetValues (Widget current, Widget request _GL_UNUSED, Widget new, ArgList args _GL_UNUSED, Cardinal *num_args _GL_UNUSED)
277 {
278   VlistWidget cvw = (VlistWidget) current;
279   VlistWidget nvw = (VlistWidget) new;
280   Boolean changed = False;
281 
282   BEGINMESSAGE(SetValues)
283   if (nvw->vlist.vlist == NULL) nvw->vlist.vlist = "";
284   if (cvw->vlist.vlist != nvw->vlist.vlist) {
285     XtFree((char *)cvw->vlist.vlist);
286     nvw->vlist.vlist = XtNewString(nvw->vlist.vlist);
287     nvw->vlist.entries = (int)strlen(nvw->vlist.vlist);
288     if (!nvw->vlist.entries) nvw->vlist.entries =- 1;
289     SMESSAGE(nvw->vlist.vlist)
290     IMESSAGE(nvw->vlist.entries)
291     changed = True;
292   }
293   ENDMESSAGE(SetValues)
294   return (changed);
295 }
296 
297 /*---------------------------------------------------*/
298 /* Destroy */
299 /*---------------------------------------------------*/
300 
301 static void
Destroy(Widget w)302 Destroy(Widget w)
303 {
304   VlistWidget vw = (VlistWidget)w;
305 
306   BEGINMESSAGE(Destroy)
307   XtFree(vw->vlist.vlist);
308   XtReleaseGC(w,vw->vlist.background_GC);
309   XtReleaseGC(w,vw->vlist.mark_background_GC);
310   XtReleaseGC(w,vw->vlist.selected_background_GC);
311   XtReleaseGC(w,vw->vlist.highlighted_background_GC);
312   ENDMESSAGE(Destroy)
313 }
314 
315 /*---------------------------------------------------*/
316 /* PaintEntryString */
317 /*---------------------------------------------------*/
318 
319 static void
PaintEntryString(Widget w,int entry)320 PaintEntryString(Widget w, int entry)
321 {
322   VlistWidget vw = (VlistWidget)w;
323   char * s;
324   int i;
325   int yofs = vw->vlist.yofs, ydelta = vw->vlist.ydelta;
326 
327   yofs -= ydelta * vw->vlist.firstVisible;
328 
329   BEGINMESSAGE1(PaintEntryString)
330   s = vw->label.label;
331   i = entry;
332   if (s) while (i > 0 && (s = strchr(s,'\n'))) { s++; i--; }
333   if (s) {
334     char *nl = strchr(s,'\n');
335     int len;
336     if (nl)
337       len = nl - s;
338     else
339       len = strlen(s);
340 #ifdef HAVE_XAW3D_INTERNATIONAL
341     if( vw->simple.international == True )
342       XmbDrawString(XtDisplay(w), XtWindow(w), vw->label.fontset,
343 		    vw->label.normal_GC,
344 		    vw->label.label_x, vw->label.label_y + yofs + entry*ydelta,
345 		    s, len);
346     else
347 #endif
348       XDrawString(XtDisplay(w), XtWindow(w), vw->label.normal_GC,
349 		vw->label.label_x, vw->label.label_y + yofs + entry*ydelta,
350 		s, len);
351   }
352   ENDMESSAGE1(PaintEntryString)
353 }
354 
355 /*---------------------------------------------------*/
356 /* PaintMarkOfEntry */
357 /*---------------------------------------------------*/
358 
359 static int
PaintMark(Widget w,Region region,int entry,int style,Boolean erase)360 PaintMark(Widget w, Region region, int entry, int style, Boolean erase)
361 {
362   VlistWidget vw = (VlistWidget)w;
363   int ss,ulx,uly,lrx,lry,ret=0;
364   Position x,y;
365   Dimension width,height;
366   Dimension sw;
367   GC gc;
368 
369   BEGINMESSAGE(PaintMark)
370   IIMESSAGE(entry,erase)
371   if (entry < 0 || entry >= vw->vlist.entries) {
372     INFMESSAGE(invalid entry)
373     ENDMESSAGE(PaintMark)
374     return(ret);
375   }
376   if (entry < vw->vlist.firstVisible) {
377     ENDMESSAGE(PaintMark)
378     return 0;
379   }
380   if (style<0) { /* highlighted */
381     INFMESSAGE(highlighted entry)
382     ulx = vw->vlist.hulx;
383     uly = vw->vlist.huly;
384     lrx = vw->vlist.hlrx;
385     lry = vw->vlist.hlry;
386     sw  = vw->vlist.highlighted_shadow_width;
387     gc  = vw->vlist.highlighted_background_GC;
388   } else { /* selected */
389     INFMESSAGE(selected entry)
390     ulx = vw->vlist.sulx;
391     uly = vw->vlist.suly;
392     lrx = vw->vlist.slrx;
393     lry = vw->vlist.slry;
394     sw  = vw->vlist.selected_shadow_width;
395     gc  = vw->vlist.selected_background_GC;
396   }
397   x = (Position) ulx;
398   y = (Position) (((int) vw->label.label_y) +
399 		  ((entry - vw->vlist.firstVisible)*vw->vlist.ydelta) +
400 		  uly);
401   width = (Dimension)((int) vw->core.width - ulx + lrx);
402   height= (Dimension)(vw->vlist.ydelta - uly + lry + .5);
403   ss = XawSUNKEN;
404   if (region == NULL || XRectInRegion(region,x,y,width,height) != RectangleOut) {
405     if (erase) {
406       INFMESSAGE(clearing entry)
407       XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w),vw->vlist.background_GC,x,y,width,height);
408     } else {
409       INFMESSAGE(drawing entry)
410       XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w),gc,x,y,width,height);
411       FrameDrawFrame(w,x,y,width,height,ss,sw,
412 		vw->threeD.top_shadow_GC,
413 		vw->threeD.bot_shadow_GC);
414     }
415     ret=1;
416   }
417   ENDMESSAGE(PaintMark)
418   return ret;
419 }
420 
421 static void
PaintMarkOfEntry(Widget w,Region region,int entry,int style,Boolean erase)422 PaintMarkOfEntry(Widget w, Region region, int entry, int style, Boolean erase)
423 {
424   VlistWidget vw = (VlistWidget)w;
425   int pstyle,dstyle,d,p;
426   int drawn=0,pdrawn=0;
427   int order=0;
428 
429   BEGINMESSAGE(PaintMarkOfEntry)
430   if (entry < 0 || entry >= vw->vlist.entries) {
431     INFMESSAGE(invalid entry)
432     ENDMESSAGE(PaintMarkOfEntry)
433     return;
434   }
435   d = entry; dstyle=style;
436   if (style<0) { p=vw->vlist.selected; pstyle=1; }
437   else         { p=vw->vlist.highlighted; pstyle=-1; }
438   if (d+1 == p)      order = 10;
439   else if (d-1 == p) { if (erase) order=10; else order=01; }
440   else if (d==p)     { if (dstyle<0) order=10; else order=01; }
441   else order = 999;
442   IIMESSAGE(d,p)
443   IMESSAGE(order)
444   if (order==10 || order == 999) {
445     drawn = PaintMark(w, region, d, dstyle,erase);
446     if (order==10) pdrawn = PaintMark(w, region, p, pstyle,False);
447   } else if (order==01) {
448     pdrawn = PaintMark(w, region, p, pstyle,False);
449     drawn = PaintMark(w, region, d, dstyle,erase);
450   }
451   if (pdrawn) {
452     PaintEntryString(w,p);
453     PaintMarkMarkOfEntry(w,region,p,False);
454   }
455   if (drawn && p!=d) {
456     PaintEntryString(w,d);
457     PaintMarkMarkOfEntry(w,region,d,False);
458   }
459   ENDMESSAGE(PaintMarkOfEntry)
460 }
461 
462 /*---------------------------------------------------*/
463 /* PaintMarkMarkOfEntry */
464 /*---------------------------------------------------*/
465 
466 static void
PaintMarkMarkOfEntry(Widget w,Region region,int entry,Boolean erase)467 PaintMarkMarkOfEntry(Widget w, Region region, int entry, Boolean erase)
468 {
469   VlistWidget vw = (VlistWidget)w;
470 
471   BEGINMESSAGE1(PaintMarkMarkOfEntry)
472   if (vw->vlist.allow_marks) {
473     int ss;
474     Position x,y;
475     Dimension width,height;
476     char *vlist = vw->vlist.vlist;
477     Boolean paint=False;
478 
479     if (entry < vw->vlist.firstVisible)
480       return;
481 
482     if (vlist[entry] == '*') paint = True;
483     if (paint || erase) {
484       x = (Position) (VLIST_MARK_LEFT_INDENT);
485       y = (Position) (((int) vw->label.label_y) +
486 		      VLIST_MARK_VERTICAL_INDENT +
487 		      ((entry-vw->vlist.firstVisible)*vw->vlist.ydelta));
488       width = (Dimension) (VLIST_MARK_WIDTH);
489       height= (Dimension)(vw->vlist.ydelta + 0.5 - 2*VLIST_MARK_VERTICAL_INDENT);
490       ss = XawSUNKEN;
491       if (region == NULL || XRectInRegion(region,x,y,width,height) != RectangleOut) {
492 	if (paint) {
493 	  INFMESSAGE(drawing mark)
494 	    XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w),vw->vlist.mark_background_GC,x,y,width,height);
495 	  FrameDrawFrame(w,x,y,width,height,ss,vw->vlist.mark_shadow_width,
496 			 vw->threeD.top_shadow_GC,
497 			 vw->threeD.bot_shadow_GC);
498 	} else {
499 	  INFMESSAGE(clearing mark)
500 	    XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w),
501 			   (entry == vw->vlist.highlighted) ? vw->vlist.highlighted_background_GC : vw->vlist.background_GC,
502 			   x,y,width,height);
503 	}
504       }
505     }
506   }
507   ENDMESSAGE1(PaintMarkMarkOfEntry)
508 }
509 
510 /*---------------------------------------------------*/
511 /* PaintMarksOfEntries */
512 /*---------------------------------------------------*/
513 
514 static void
PaintMarksOfEntries(Widget w,XEvent * event _GL_UNUSED,Region region)515 PaintMarksOfEntries(Widget w, XEvent *event _GL_UNUSED, Region region)
516 {
517   VlistWidget vw = (VlistWidget)w;
518 
519   BEGINMESSAGE(PaintMarksOfEntries)
520   PaintMarkOfEntry(w, region, vw->vlist.highlighted,-1, False);
521   if (vw->vlist.allow_marks) {
522     int i= vw->vlist.firstVisible;
523     while (i < vw->vlist.entries) {
524       if (i != vw->vlist.highlighted)
525 	PaintMarkMarkOfEntry(w, region, i, False);
526       i++;
527     }
528   }
529   if (vw->vlist.selected != vw->vlist.highlighted && vw->vlist.entries >= 0)
530     PaintMarkOfEntry(w, region, vw->vlist.selected,1, False);
531   ENDMESSAGE(PaintMarksOfEntries)
532 }
533 
534 /*---------------------------------------------------*/
535 /* PaintVlistWidget */
536 /*---------------------------------------------------*/
537 
538 static void
PaintVlistWidget(Widget w,XEvent * event,Region region)539 PaintVlistWidget(Widget w, XEvent *event, Region region)
540 {
541   Dimension width;
542   char *s, *o;
543   int i, y;
544   VlistWidget vw = (VlistWidget)w;
545   XRectangle rectangle;
546 
547   BEGINMESSAGE(PaintVlistWidget)
548   /* better not allow the widget to grow that large, but that needs fixing
549    * of the Clip widget */
550   shiftLabel(vw);
551   PaintMarksOfEntries(w, event, region);
552   width = vw->threeD.shadow_width;
553   o = vw->label.label;
554   s = vw->label.label;
555   i = vw->vlist.firstVisible;
556   if (s) while (i > 0 && (s = strchr(s,'\n'))) { s++; i--; }
557   /* This still fails when the list is too long and does not print anything.
558    * Though that is perhaps best fixed by making Clip to enforce a real window
559    * height...
560   vw->label.label = s;
561   vw->threeD.shadow_width = 0;
562   (*SuperClass->core_class.expose) (w, event, region);
563   vw->threeD.shadow_width =  width;
564   vw->label.label = o;
565   until Clip is extended, just manually draw each line:
566   */
567   if (region)
568     XClipBox(region, &rectangle);
569   else {
570     rectangle.x = 0;
571     rectangle.y = 0;
572     rectangle.width = vw->core.width;
573     rectangle.height = vw->core.height;
574     if( rectangle.height >= 0x4000 )
575 	    rectangle.height = 0x3fff;
576   }
577   y = vw->label.label_y + vw->vlist.yofs;
578   i = 0;
579 
580   while (s != NULL) {
581     char *nl = strchr(s, '\n');
582     int len;
583     if (nl)
584       len = nl - s;
585     else
586       len = strlen(s);
587     if (y - vw->vlist.yofs > rectangle.y + rectangle.height)
588       break;
589     if (y + (vw->vlist.ydelta - vw->vlist.yofs) >= rectangle.y) {
590 #ifdef HAVE_XAW3D_INTERNATIONAL
591       if( vw->simple.international == True )
592 	XmbDrawString(XtDisplay(w), XtWindow(w), vw->label.fontset,
593 		      vw->label.normal_GC, vw->label.label_x, y, s, len);
594       else
595 #endif
596 	XDrawString(XtDisplay(w), XtWindow(w), vw->label.normal_GC,
597 		    vw->label.label_x, y, s, len);
598     }
599     if (nl)
600       s = nl + 1;
601     else
602       s = NULL;
603     y += vw->vlist.ydelta;
604   }
605   ENDMESSAGE(PaintVlistWidget)
606 }
607 
608 /*####################################################################*/
609 /*####################################################################*/
610 /* Public Routines */
611 /*####################################################################*/
612 /*####################################################################*/
613 
614 /*###################################################*/
615 /* VlistSelected */
616 /*###################################################*/
617 
618 int
VlistSelected(Widget w)619 VlistSelected(Widget w)
620 {
621   VlistWidget vw = (VlistWidget)w;
622 
623   BEGINMESSAGE(VlistSelected)
624   ENDMESSAGE(VlistSelected)
625   return(vw->vlist.selected);
626 }
627 
628 /*###################################################*/
629 /* VlistHighlighted */
630 /*###################################################*/
631 
632 int
VlistHighlighted(Widget w)633 VlistHighlighted(Widget w)
634 {
635   VlistWidget vw = (VlistWidget)w;
636 
637   BEGINMESSAGE(VlistHighlighted)
638   ENDMESSAGE(VlistHighlighted)
639   return(vw->vlist.highlighted);
640 }
641 
642 /*###################################################*/
643 /* VlistEntries */
644 /*###################################################*/
645 
646 int
VlistEntries(Widget w)647 VlistEntries(Widget w)
648 {
649   VlistWidget vw = (VlistWidget)w;
650 
651   BEGINMESSAGE(VlistEntries)
652   ENDMESSAGE(VlistEntries)
653   return(vw->vlist.entries);
654 }
655 
656 /*###################################################*/
657 /* VlistVlist */
658 /*###################################################*/
659 
660 char*
VlistVlist(Widget w)661 VlistVlist(Widget w)
662 {
663   VlistWidget vw = (VlistWidget)w;
664 
665   BEGINMESSAGE(VlistVlist)
666   ENDMESSAGE(VlistVlist)
667   return(vw->vlist.vlist);
668 }
669 
670 /*###################################################*/
671 /* VlistEntryOfPosition */
672 /*###################################################*/
673 
674 int
VlistEntryOfPosition(Widget w,int y)675 VlistEntryOfPosition(Widget w, int y)
676 {
677   VlistWidget vw = (VlistWidget)w;
678   int entry = -1;
679 
680   BEGINMESSAGE(VlistEntryOfPosition)
681   y = y - (int) vw->label.label_y;
682   if (vw->vlist.ydelta > 0) {
683     if (y < 0) entry = -1;
684     else       entry = y/vw->vlist.ydelta;
685   }
686   if (entry >= vw->vlist.entries)
687 	  entry = vw->vlist.entries-1;
688   if (entry >= 0)
689     entry += vw->vlist.firstVisible;
690   IMESSAGE(entry)
691   ENDMESSAGE(VlistEntryOfPosition)
692   return(entry);
693 }
694 
695 /*###################################################*/
696 /* VlistPositionOfEntry */
697 /*###################################################*/
698 
699 void
VlistPositionOfEntry(Widget w,int e,int * yuP,int * ylP)700 VlistPositionOfEntry(Widget w, int e, int *yuP, int *ylP)
701 {
702   VlistWidget vw = (VlistWidget)w;
703   float h;
704   BEGINMESSAGE(VlistPositionOfEntry)
705   *yuP = *ylP = (int) vw->label.label_y;
706   if (e >= vw->vlist.firstVisible && vw->vlist.entries > 0) {
707     e -= vw->vlist.firstVisible;
708     h = vw->vlist.ydelta;
709     *yuP += (int)((float)e*h);
710     *ylP += (int)((float)(e+1)*h);
711   }
712   ENDMESSAGE(VlistPositionOfEntry)
713 }
714 
715 /*###################################################*/
716 /* VlistChangeMark */
717 /*###################################################*/
718 
719 void
VlistChangeMark(Widget w,int entry,int change)720 VlistChangeMark(Widget w, int entry,int change)
721 {
722   VlistWidget vw = (VlistWidget)w;
723   char *vlist=vw->vlist.vlist;
724   Boolean paint;
725   int lb,ub,st;
726 
727   BEGINMESSAGE(VlistChangeMark)
728   switch (entry) {
729     case XawVlistAll:
730       lb=0;
731       ub=vw->vlist.entries-1;
732       st=1;
733       break;
734     case XawVlistEven:
735       lb=1;
736       ub=vw->vlist.entries-1;
737       st=2;
738       break;
739     case XawVlistOdd:
740       lb=0;
741       ub=vw->vlist.entries-1;
742       st=2;
743       break;
744     case XawVlistCurrent:
745       lb=vw->vlist.selected;
746       ub=vw->vlist.selected;
747       st=1;
748       break;
749     default:
750       lb=entry;
751       ub=entry;
752       st=1;
753       break;
754   }
755 
756   if (ub < 0 || ub >= vw->vlist.entries) {
757     INFMESSAGE(invalid setup)
758     ENDMESSAGE(VlistChangeMark)
759     return;
760   }
761 
762   entry=lb;
763   while (entry <= ub) {
764     paint=False;
765     switch (change) {
766       case XawVlistToggle:
767 	switch (vlist[entry]) {
768           case '*':
769 	    vlist[entry]=' ';
770 	    paint=True;
771 	    break;
772           default:
773 	    vlist[entry]='*';
774 	    paint=True;
775 	    break;
776         }
777 	break;
778       case XawVlistSet:
779 	vlist[entry]='*';
780 	paint=True;
781 	break;
782       case XawVlistUnset:
783 	vlist[entry]=' ';
784 	paint=True;
785 	break;
786       default:
787 	INFMESSAGE(invalid action)
788 	break;
789     }
790     if (paint) PaintMarkMarkOfEntry(w,NULL,entry,True);
791     entry += st;
792   }
793   ENDMESSAGE(VlistChangeMark)
794 }
795 
796 /*---------------------------------------------------*/
797 /* vlist_change_mark */
798 /*---------------------------------------------------*/
799 
800 static void
vlist_change_mark(Widget w,int e,int change,int kind)801 vlist_change_mark(Widget w, int e, int change, int kind)
802 {
803   VlistWidget vw = (VlistWidget)w;
804   int *eP;
805 
806   BEGINMESSAGE(vlist_change_mark)
807   if (kind < 0) eP = &(vw->vlist.highlighted);
808   else eP = &(vw->vlist.selected);
809   switch (change) {
810     case XawVlistSet:
811       if (*eP >= 0 && *eP < vw->vlist.entries) PaintMarkOfEntry(w,NULL,*eP,kind,True);
812       *eP = -1;
813       if (e >= 0 && e < vw->vlist.entries) {
814 	PaintMarkOfEntry(w,NULL,e,kind,False);
815 	*eP = e;
816       }
817       break;
818     case XawVlistUnset:
819       if (*eP >= 0 && *eP < vw->vlist.entries) PaintMarkOfEntry(w,NULL,*eP,kind,True);
820       *eP = -1;
821       break;
822     default:
823       INFMESSAGE(invalid action)
824       break;
825   }
826   ENDMESSAGE(vlist_change_mark)
827 }
828 
829 /*###################################################*/
830 /* VlistChangeSelected */
831 /*###################################################*/
832 
833 void
VlistChangeSelected(Widget w,int entry,int change)834 VlistChangeSelected(Widget w, int entry, int change)
835 {
836   BEGINMESSAGE(VlistChangeSelected)
837   vlist_change_mark(w,entry,change,1);
838   ENDMESSAGE(VlistChangeSelected)
839 }
840 
841 /*###################################################*/
842 /* VlistChangeHighlighted */
843 /*###################################################*/
844 
845 void
VlistChangeHighlighted(Widget w,int entry,int change)846 VlistChangeHighlighted(Widget w, int entry, int change)
847 {
848   BEGINMESSAGE(VlistChangeHighlighted)
849   vlist_change_mark(w,entry,change,-1);
850   ENDMESSAGE(VlistChangeHighlighted)
851 }
852 
853 /*###################################################*/
854 /* VlistGetFirstVisible */
855 /*###################################################*/
856 
VlistGetFirstVisible(Widget w)857 int VlistGetFirstVisible(Widget w)
858 {
859   VlistWidget vw = (VlistWidget)w;
860 
861   return vw->vlist.firstVisible;
862 }
863 
864 /*###################################################*/
865 /* VlistSetFirstVisible */
866 /*###################################################*/
867 
VlistSetFirstVisible(Widget w,int newf)868 void VlistSetFirstVisible(Widget w, int newf)
869 {
870   VlistWidget vw = (VlistWidget)w;
871   unsigned int height;
872 
873   BEGINMESSAGE(VlistSetFirstVisible)
874   IIMESSAGE(newf,vw->vlist.entries)
875   if (newf < 0)
876     newf = 0;
877   else if (newf >= vw->vlist.entries)
878     newf = vw->vlist.entries - 1;
879   if (newf == -1) {
880     ENDMESSAGE(VlistSetFirstVisible)
881     return;
882   }
883   IIMESSAGE(newf,vw->vlist.firstVisible)
884   if (newf != vw->vlist.firstVisible) {
885     vw->vlist.firstVisible = newf;
886     /* better not allow the widget to grow that large, but that needs fixing
887      * of the Clip widget */
888     height = vw->core.height;
889     if( height >= 0x8000 )
890 	    height = 0x3fff;
891     IIMESSAGE(vw->core.height,height)
892     XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w), vw->vlist.background_GC,
893 		    vw->core.x, vw->core.y, vw->core.width, height);
894     Redisplay(w, NULL, NULL);
895     if (vw->vlist.report_callbacks)
896       XtCallCallbackList (w, vw->vlist.report_callbacks, (XtPointer)0);
897   }
898   ENDMESSAGE(VlistSetFirstVisible)
899 }
900 /*###################################################*/
901 /* VlistMoveFirstVisible */
902 /*###################################################*/
903 
904 extern int debug_p;
905 
VlistMoveFirstVisible(Widget w,int start,int ydiff)906 void VlistMoveFirstVisible(Widget w, int start, int ydiff)
907 {
908   VlistWidget vw = (VlistWidget)w;
909   int ly;
910   int newf;
911 
912   BEGINMESSAGE(VlistMoveFirstVisible)
913   IIMESSAGE(start,ydiff)
914   ly = vw->vlist.ydelta;
915   if (debug_p) fprintf(stderr, "move: start=%d ydiff=%d ly=%d\n", start, ydiff, ly);
916 
917   if (ydiff > 0 && ly > ydiff) ydiff=ly;
918   if (ydiff < 0 && ly > -ydiff) ydiff=-ly;
919 
920   if (ydiff >= 0)
921 	  ydiff += ly/2;
922   else
923 	  ydiff -= ly/2;
924 
925   newf = start + ydiff/ly;
926   VlistSetFirstVisible(w, newf);
927   ENDMESSAGE(VlistMoveFirstVisible)
928 }
929 
930 /*###################################################*/
931 /* VlistScrollPosition */
932 /*###################################################*/
933 
VlistScrollPosition(Widget w)934 float VlistScrollPosition(Widget w)
935 {
936   VlistWidget vw = (VlistWidget)w;
937   float position;
938 
939 #if 0
940   printf("Scroll position %d/%d=%f\n",
941 		  vw->vlist.firstVisible,(int)(vw->vlist.entries),
942 		  vw->vlist.firstVisible/(float)(vw->vlist.entries));
943 #endif
944   position = vw->vlist.firstVisible/(float)vw->vlist.entries;
945   INFMESSAGE(VlistScrollPosition)
946   IIMESSAGE(vw->vlist.firstVisible,vw->vlist.entries)
947   FMESSAGE(position)
948   return position;
949 }
950 
VlistVisibleLength(Widget w,unsigned int height)951 float VlistVisibleLength(Widget w, unsigned int height)
952 {
953   VlistWidget vw = (VlistWidget)w;
954   float percent;
955   int entriesvisible = -1;
956 
957   if (vw->vlist.ydelta > 0) {
958     entriesvisible = height/vw->vlist.ydelta;
959   }
960 #if 0
961   printf("fitting %d entries of height %d in %d",
962 		  entriesvisible, (int)vw->vlist.ydelta, (int)height);
963 #endif
964   if (entriesvisible >= vw->vlist.entries)
965 	  entriesvisible = vw->vlist.entries;
966 #if 0
967   printf(", visible percents %d/%d=%f\n",
968 		  entriesvisible,(int)(vw->vlist.entries),
969 		  entriesvisible/(float)(vw->vlist.entries));
970 #endif
971   percent = entriesvisible/(float)(vw->vlist.entries);
972   INFMESSAGE(VlistVisibleLength)
973   IIMESSAGE(entriesvisible,vw->vlist.entries)
974   FMESSAGE(percent)
975   return percent;
976 }
977 
VlistMaxEntriesVisible(Widget w,int height)978 int VlistMaxEntriesVisible(Widget w, int height)
979 {
980   VlistWidget vw = (VlistWidget)w;
981   int entriesvisible = -1;
982 
983   if (vw->vlist.ydelta > 0) {
984     entriesvisible = (height - vw->label.label_y)/vw->vlist.ydelta;
985   }
986 
987   INFIMESSAGE(VlistMaxEntriesVisible,entriesvisible)
988 
989   return entriesvisible;
990 }
991