Index: src/Vlist.c =================================================================== RCS file: /sources/gv/gv/src/Vlist.c,v retrieving revision 1.7 diff -u -r1.7 Vlist.c --- src/Vlist.c 8 Jun 2008 14:08:31 -0000 1.7 +++ src/Vlist.c 20 Nov 2008 17:13:19 -0000 @@ -4,6 +4,7 @@ ** ** Copyright (C) 1995, 1996, 1997 Johannes Plass ** Copyright (C) 2004 Jose E. Marchesi +** modified 2008 by Bernhard R. Link ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by @@ -34,6 +35,7 @@ #include #include +#include /* #define MESSAGES */ @@ -68,6 +70,8 @@ #define offset(field) XtOffsetOf(VlistRec, field) static XtResource resources[] = { + {XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer), + offset(vlist.report_callbacks), XtRCallback, (XtPointer) NULL }, {XtNselectedShadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension), offset(vlist.selected_shadow_width), XtRImmediate, (XtPointer) 1}, {XtNmarkShadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension), @@ -193,6 +197,7 @@ if (vw->vlist.vlist) s = vw->vlist.vlist; vw->vlist.vlist = GV_XtNewString(s); c = vw->vlist.vlist; + vw->vlist.firstVisible = 0; vw->vlist.selected = -1; vw->vlist.highlighted = -1; vw->vlist.entries = (int)strlen(vw->vlist.vlist); @@ -214,6 +219,17 @@ values.graphics_exposures = False; vw->vlist.background_GC = XtGetGC((Widget)vw,(unsigned) GCForeground | GCGraphicsExposures,&values); + /* TODO: check if this works here in international mode, or if it has + * to be moved to Realize... */ + if( vw->simple.international == True ) { + XFontSetExtents *ext = XExtentsOfFontSet(vw->label.fontset); + vw->vlist.yofs = (ext->max_ink_extent.y<0)?-ext->max_ink_extent.y:ext->max_ink_extent.y; + vw->vlist.ydelta = ext->max_ink_extent.height; + } else { + vw->vlist.yofs = vw->label.font->max_bounds.ascent; + vw->vlist.ydelta = vw->label.font->max_bounds.ascent + vw->label.font->max_bounds.descent; + } + ENDMESSAGE(Initialize) } @@ -318,16 +334,9 @@ VlistWidget vw = (VlistWidget)w; char * s; int i; - int yofs, ydelta; + int yofs = vw->vlist.yofs, ydelta = vw->vlist.ydelta; - if( vw->simple.international == True ) { - XFontSetExtents *ext = XExtentsOfFontSet(vw->label.fontset); - yofs = (ext->max_ink_extent.y<0)?-ext->max_ink_extent.y:ext->max_ink_extent.y; - ydelta = ext->max_ink_extent.height; - } else { - yofs = vw->label.font->max_bounds.ascent; - ydelta = vw->label.font->max_bounds.ascent + vw->label.font->max_bounds.descent; - } + yofs -= ydelta * vw->vlist.firstVisible; BEGINMESSAGE1(PaintEntryString) s = vw->label.label; @@ -378,6 +387,10 @@ ENDMESSAGE(PaintMark) return(ret); } + if (entry < vw->vlist.firstVisible) { + ENDMESSAGE(PaintMark) + return 0; + } if (style<0) { /* highlighted */ INFMESSAGE(highlighted entry) ulx = vw->vlist.hulx; @@ -397,11 +410,10 @@ } x = (Position) ulx; y = (Position) (((int) vw->label.label_y) + - (entry*(vw->label.label_height))/vw->vlist.entries + + ((entry - vw->vlist.firstVisible)*vw->vlist.ydelta) + uly); width = (Dimension)((int) vw->core.width - ulx + lrx); - height= (Dimension)(((int) vw->label.label_height)/vw->vlist.entries + - - uly + lry + .5); + height= (Dimension)(vw->vlist.ydelta - uly + lry + .5); ss = XawSUNKEN; if (region == NULL || XRectInRegion(region,x,y,width,height) != RectangleOut) { if (erase) { @@ -487,14 +499,17 @@ char *vlist = vw->vlist.vlist; Boolean paint=False; + if (entry < vw->vlist.firstVisible) + return; + if (vlist[entry] == '*') paint = True; if (paint || erase) { x = (Position) (VLIST_MARK_LEFT_INDENT); y = (Position) (((int) vw->label.label_y) + VLIST_MARK_VERTICAL_INDENT + - (entry*(vw->label.label_height))/vw->vlist.entries); + ((entry-vw->vlist.firstVisible)*vw->vlist.ydelta)); width = (Dimension) (VLIST_MARK_WIDTH); - height= (Dimension)(((int) vw->label.label_height)/vw->vlist.entries + 0.5 - 2*VLIST_MARK_VERTICAL_INDENT); + height= (Dimension)(vw->vlist.ydelta + 0.5 - 2*VLIST_MARK_VERTICAL_INDENT); ss = XawSUNKEN; if (region == NULL || XRectInRegion(region,x,y,width,height) != RectangleOut) { if (paint) { @@ -530,7 +545,7 @@ BEGINMESSAGE(PaintMarksOfEntries) PaintMarkOfEntry(w, region, vw->vlist.highlighted,-1, False); if (vw->vlist.allow_marks) { - int i=0; + int i= vw->vlist.firstVisible; while (i < vw->vlist.entries) { if (i != vw->vlist.highlighted) PaintMarkMarkOfEntry(w, region, i, False); @@ -553,14 +568,67 @@ Region region; { Dimension width; + char *s, *o; + int i, y; VlistWidget vw = (VlistWidget)w; + XRectangle rectangle; + BEGINMESSAGE(PaintVlistWidget) + /* better not allow the widget to grow that large, but that needs fixing + * of the Clip widget */ shiftLabel(vw); PaintMarksOfEntries(w, event, region); width = vw->threeD.shadow_width; + o = vw->label.label; + s = vw->label.label; + i = vw->vlist.firstVisible; + if (s) while (i > 0 && (s = strchr(s,'\n'))) { s++; i--; } + /* This still fails when the list is too long and does not print anything. + * Though that is perhaps best fixed by making Clip to enforce a real window + * height... + vw->label.label = s; vw->threeD.shadow_width = 0; (*SuperClass->core_class.expose) (w, event, region); - vw->threeD.shadow_width = width; + vw->threeD.shadow_width = width; + vw->label.label = o; + until Clip is extended, just manually draw each line: + */ + if (region) + XClipBox(region, &rectangle); + else { + rectangle.x = 0; + rectangle.y = 0; + rectangle.width = vw->core.width; + rectangle.height = vw->core.height; + if( rectangle.height >= 0x4000 ) + rectangle.height = 0x3fff; + } + y = vw->label.label_y + vw->vlist.yofs; + i = 0; + + while (s != NULL) { + char *nl = strchr(s, '\n'); + int len; + if (nl) + len = nl - s; + else + len = strlen(s); + if (y - vw->vlist.yofs > rectangle.y + rectangle.height) + break; + if (y + (vw->vlist.ydelta - vw->vlist.yofs) >= rectangle.y) { + if( vw->simple.international == True ) + XmbDrawString(XtDisplay(w), XtWindow(w), vw->label.fontset, + vw->label.normal_GC, vw->label.label_x, y, s, len); + else + XDrawString(XtDisplay(w), XtWindow(w), vw->label.normal_GC, + vw->label.label_x, y, s, len); + } + if (nl) + s = nl + 1; + else + s = NULL; + y += vw->vlist.ydelta; + } ENDMESSAGE(PaintVlistWidget) } @@ -644,12 +712,14 @@ BEGINMESSAGE(VlistEntryOfPosition) y = y - (int) vw->label.label_y; - if (vw->label.label_height > 0) { + if (vw->vlist.ydelta > 0) { if (y < 0) entry = -1; - else entry = (vw->vlist.entries*y)/(int)vw->label.label_height; + else entry = y/vw->vlist.ydelta; } if (entry >= vw->vlist.entries) entry = vw->vlist.entries-1; + if (entry >= 0) + entry += vw->vlist.firstVisible; IMESSAGE(entry) ENDMESSAGE(VlistEntryOfPosition) return(entry); @@ -670,8 +740,9 @@ float h; BEGINMESSAGE(VlistPositionOfEntry) *yuP = *ylP = (int) vw->label.label_y; - if (e>=0 && vw->vlist.entries > 0) { - h = (float)vw->label.label_height/(float)vw->vlist.entries; + if (e >= vw->vlist.firstVisible && vw->vlist.entries > 0) { + e -= vw->vlist.firstVisible; + h = vw->vlist.ydelta; *yuP += (int)((float)e*h); *ylP += (int)((float)(e+1)*h); } @@ -828,3 +899,78 @@ vlist_change_mark(w,entry,change,-1); ENDMESSAGE(VlistChangeHighlighted) } + +/*###################################################*/ +/* VlistGetFirstVisible */ +/*###################################################*/ + +int VlistGetFirstVisible(Widget w) +{ + VlistWidget vw = (VlistWidget)w; + + return vw->vlist.firstVisible; +} + +/*###################################################*/ +/* VlistSetFirstVisible */ +/*###################################################*/ + +void VlistSetFirstVisible(Widget w, int newf) +{ + VlistWidget vw = (VlistWidget)w; + unsigned int height; + + BEGINMESSAGE(VlistSetFirstVisible) + if (newf < 0) + newf = 0; + else if (newf >= vw->vlist.entries) + newf = vw->vlist.entries - 1; + if (newf == -1) + return; + if (newf != vw->vlist.firstVisible) { + vw->vlist.firstVisible = newf; + /* better not allow the widget to grow that large, but that needs fixing + * of the Clip widget */ + height = vw->core.height; + if( height >= 0x8000 ) + height = 0x3fff; + XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w), vw->vlist.background_GC, + vw->core.x, vw->core.y, vw->core.width, height); + Redisplay(w, NULL, NULL); + if (vw->vlist.report_callbacks) + XtCallCallbackList (w, vw->vlist.report_callbacks, (XtPointer)0); + } + ENDMESSAGE(VlistMoveFirstVisible) +} +/*###################################################*/ +/* VlistMoveFirstVisible */ +/*###################################################*/ + +void VlistMoveFirstVisible(Widget w, int start, int ydiff) +{ + VlistWidget vw = (VlistWidget)w; + int ly; + int newf; + + BEGINMESSAGE(VlistMoveFirstVisible) + ly = vw->vlist.ydelta; + fprintf(stderr, "move: start=%d ydiff=%d ly=%d\n", start, ydiff, ly); + if (ydiff >= 0) + ydiff += ly/2; + else + ydiff -= ly/2; + newf = start + ydiff/ly; + VlistSetFirstVisible(w, newf); + ENDMESSAGE(VlistMoveFirstVisible) +} + +/*###################################################*/ +/* VlistScrollPosition */ +/*###################################################*/ + +float VlistScrollPosition(Widget w) +{ + VlistWidget vw = (VlistWidget)w; + + return vw->vlist.firstVisible/(float)vw->vlist.entries; +} Index: src/Vlist.h =================================================================== RCS file: /sources/gv/gv/src/Vlist.h,v retrieving revision 1.3 diff -u -r1.3 Vlist.h --- src/Vlist.h 7 Jun 2008 18:39:19 -0000 1.3 +++ src/Vlist.h 20 Nov 2008 17:13:19 -0000 @@ -35,6 +35,7 @@ #include "paths.h" #include INC_XAW(Label.h) +#include INC_XAW(Reports.h) #define XawVlistAll -13 #define XawVlistEven -12 @@ -131,5 +132,9 @@ int #endif ); +extern int VlistGetFirstVisible(Widget); +extern void VlistSetFirstVisible(Widget, int); +extern void VlistMoveFirstVisible(Widget, int, int); +float VlistScrollPosition(Widget); #endif /* _Vlist_h_ */ Index: src/VlistP.h =================================================================== RCS file: /sources/gv/gv/src/VlistP.h,v retrieving revision 1.3 diff -u -r1.3 VlistP.h --- src/VlistP.h 7 Jun 2008 18:39:19 -0000 1.3 +++ src/VlistP.h 20 Nov 2008 17:13:19 -0000 @@ -69,6 +69,7 @@ GC mark_background_GC; GC selected_background_GC; GC highlighted_background_GC; + int firstVisible; int selected; int highlighted; int hulx; @@ -79,6 +80,9 @@ int suly; int slrx; int slry; + int ydelta; + int yofs; + XtCallbackList report_callbacks; } VlistPart; typedef struct _VlistRec { Index: src/actions.c =================================================================== RCS file: /sources/gv/gv/src/actions.c,v retrieving revision 1.17 diff -u -r1.17 actions.c --- src/actions.c 2 Aug 2008 16:48:10 -0000 1.17 +++ src/actions.c 20 Nov 2008 17:13:19 -0000 @@ -379,6 +379,7 @@ { static int xf,yf,xo,yo,xp,yp,dyo; static Boolean scroll_initialized=False; + static int startvisible; static Boolean scrolling=False; static int entryo = -1; Boolean toggle_mark=False; @@ -397,8 +398,7 @@ if (!app_res.reverse_scrolling) dy = -dy; m = 1.3*((float)slider->core.height/(float)ph); if (m<=1) m = 1; - y = yp +(int)(m*dy); - if (y0) y=0; + y = yp -(int)(m*dy); yo = (int) event->xbutton.y_root; ph = (int)panner->core.width; if (ph<1) ph = 1; @@ -411,9 +411,12 @@ if (x0) x=0; xo = (int) event->xbutton.x_root; - if (x!=xp || y!=yp) { - ClipWidgetSetCoordinates(panner,x,y); + if (x!=xp) { + ClipWidgetSetCoordinates(panner,x,0); xp = x; + } + if (y!=yp) { + VlistMoveFirstVisible(newtoc, startvisible, y); yp = y; } if (abs(xf-xo) > 6 || abs(yf-yo) > 6) scrolling = True; @@ -422,7 +425,8 @@ scroll_initialized = True; scrolling = False; xp = (int) slider->core.x; xf = xo = (int) event->xbutton.x_root; - yp = (int) slider->core.y; yf = yo = (int) event->xbutton.y_root; + yp = 0; yf = yo = (int) event->xbutton.y_root; + startvisible = VlistGetFirstVisible(newtoc); } else if (!strcmp(params[0],"scrolloff")) { scroll_initialized = False; Index: src/callbacks.c =================================================================== RCS file: /sources/gv/gv/src/callbacks.c,v retrieving revision 1.21 diff -u -r1.21 callbacks.c --- src/callbacks.c 2 Sep 2008 11:42:43 -0000 1.21 +++ src/callbacks.c 20 Nov 2008 17:13:19 -0000 @@ -156,32 +156,36 @@ Widget w; XtPointer client_data, call_data; { - int x,y; - BEGINMESSAGE(cb_newtocScrollbar) - x = (int) newtocControl->core.x; if (((int)(intptr_t)client_data)==1) { int dy = (int)(intptr_t)call_data; - y = (int) newtocControl->core.y - dy; + VlistMoveFirstVisible(newtoc, VlistGetFirstVisible(newtoc), dy); } else { float *percent = (float *) call_data; - y = (int)(-*percent * newtocControl->core.height); + VlistSetFirstVisible(newtoc, (int)(VlistEntries(newtoc)**percent)); } - ClipWidgetSetCoordinates(newtocClip, x, y); ENDMESSAGE(cb_newtocScrollbar) } /*##################################################################*/ -/* cb_newtocClipAdjust */ +/* cb_newtocVisibleAdjust */ /*##################################################################*/ -void cb_newtocClipAdjust(w, client_data, call_data) +void cb_newtocVisibleAdjust(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { + int entries; + BEGINMESSAGE(cb_newtocClipAdjust) - XawScrollbarSetThumb(newtocScroll, - -(float)newtocControl->core.y/(float)newtocControl->core.height, + + entries = VlistEntries(newtoc); + + if (entries <= 0) + XawScrollbarSetThumb(newtocScroll, 0.0, 1.0); + else + XawScrollbarSetThumb(newtocScroll, + VlistScrollPosition(newtoc), (float)newtocClip->core.height/(float)newtocControl->core.height); ENDMESSAGE(cb_newtocClipAdjust) } Index: src/callbacks.h =================================================================== RCS file: /sources/gv/gv/src/callbacks.h,v retrieving revision 1.5 diff -u -r1.5 callbacks.h --- src/callbacks.h 23 Aug 2008 18:18:55 -0000 1.5 +++ src/callbacks.h 20 Nov 2008 17:13:19 -0000 @@ -49,7 +49,7 @@ #endif ); -extern void cb_newtocClipAdjust ( +extern void cb_newtocVisibleAdjust ( #if NeedFunctionPrototypes Widget, XtPointer, Index: src/main.c =================================================================== RCS file: /sources/gv/gv/src/main.c,v retrieving revision 1.44 diff -u -r1.44 main.c --- src/main.c 24 Aug 2008 10:33:48 -0000 1.44 +++ src/main.c 20 Nov 2008 17:13:19 -0000 @@ -1128,11 +1128,11 @@ cont_child[cont_child_num] = newtocFrame; cont_child_num++; n=0; newtocClip = XtCreateManagedWidget("newtocClip", clipWidgetClass,newtocFrame, args, n); - XtAddCallback(newtocClip, XtNreportCallback,cb_newtocClipAdjust, (XtPointer)NULL); n=0; newtocControl = XtCreateManagedWidget("newtocControl", aaaWidgetClass,newtocClip, args, n); n=0; newtoc = XtCreateManagedWidget("newtoc", vlistWidgetClass,newtocControl, args, n); + XtAddCallback(newtoc, XtNreportCallback,cb_newtocVisibleAdjust, (XtPointer)NULL); n=0; newtocScroll = XtCreateWidget("newtocScroll", scrollbarWidgetClass,control, args, n); XtAddCallback(newtocScroll, XtNscrollProc,cb_newtocScrollbar, (XtPointer)1); Index: src/misc.c =================================================================== RCS file: /sources/gv/gv/src/misc.c,v retrieving revision 1.26 diff -u -r1.26 misc.c --- src/misc.c 9 Sep 2008 17:11:04 -0000 1.26 +++ src/misc.c 20 Nov 2008 17:13:19 -0000 @@ -303,41 +303,43 @@ XEvent *event; Boolean check_toc; { - int x,y,yl,yu,ny=99999; + int firstvisible, lastvisible; Boolean b = False; INFMESSAGE(misc_setPageMarker) if (toc_text && (entry >= 0)) { - if (kind == 0 && VlistSelected(newtoc) != entry) + if (kind == 0 && VlistSelected(newtoc) != entry) VlistChangeSelected(newtoc,entry,XawVlistSet); - else if (kind == 1 && VlistHighlighted(newtoc) != entry) + else if (kind == 1 && VlistHighlighted(newtoc) != entry) VlistChangeHighlighted(newtoc,entry,XawVlistSet); else if (kind == 2) { entry=VlistSelected(newtoc); if (entry<0) return; } - VlistPositionOfEntry(newtoc,entry,&yu,&yl); - x = newtocControl->core.x; - y = newtocControl->core.y; - IIMESSAGE(x,y) - IIMESSAGE(yu,yl) - IIMESSAGE(y,newtoc->core.y) - if (yu != yl) { - ny = -((int)newtoc->core.y + yu) + 14; - if (y<0 && y < ny) b = True; - if (!b) { - ny = (int)newtocClip->core.height - ((int)newtoc->core.y + yl + 14); - if (y>ny) b = True; + firstvisible = VlistGetFirstVisible(newtoc); + if (firstvisible > entry || (entry > 0 && firstvisible >= entry)) { + if (entry > 0) + VlistSetFirstVisible(newtoc, entry - 1); + else + VlistSetFirstVisible(newtoc, entry); + b = True; + } else { + /* sadly newtoc does not know it's height, so it cannot be told + * to made an item visible and we need to trick: */ + lastvisible = VlistEntryOfPosition(newtoc, newtocClip->core.height); + if (entry > firstvisible && entry >= lastvisible) { + VlistSetFirstVisible(newtoc, entry - (lastvisible - firstvisible - 1)); + b = True; } - if (b) { - INFIMESSAGE(jumping to,ny) - ClipWidgetSetCoordinates(newtocClip,x,ny); - if (event) + } + /* if this happened by mouse, we have the information to get the + * highlight up to date again: */ + if (b) { + if (event) { - entry = VlistEntryOfPosition(newtoc,(int)event->xbutton.y+(y-ny)); - if (entry != VlistHighlighted(newtoc) && check_toc) - VlistChangeHighlighted(newtoc,entry,XawVlistSet); - } - } + entry = VlistEntryOfPosition(newtoc, (int)event->xbutton.y); + if (entry != VlistHighlighted(newtoc) && check_toc) + VlistChangeHighlighted(newtoc,entry,XawVlistSet); + } } } }