2 * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Software Research Associates not be used
9 * in advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. Software Research Associates
11 * makes no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
16 * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
17 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
18 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
19 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
22 * Author: Erik M. van der Poel
23 * Software Research Associates, Inc., Tokyo, Japan
31 #include <X11/StringDefs.h>
32 #include <X11/Xaw/Scrollbar.h>
33 #include <X11/Xaw/Cardinals.h>
35 #define SF_DEFAULT_FONT "9x15"
40 #define ABS(x) (((x) < 0) ? (-(x)) : (x))
46 int SFcharWidth, SFcharAscent, SFcharHeight;
48 int SFcurrentInvert[3] = { -1, -1, -1 };
50 static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
52 static XtResource textResources[] = {
53 {XtNfont, XtCFont, XtRString, sizeof (char *),
54 XtOffset(textPtr, fontname), XtRString, SF_DEFAULT_FONT},
58 extern XFontSet fontSet; //XXX should really be in a .h file
60 static XFontStruct *SFfont;
63 static int SFcurrentListY;
65 static XtIntervalId SFscrollTimerId;
71 XFontSetExtents *fse = XExtentsOfFontSet(fontSet);
72 SFcharWidth = fse->max_logical_extent.width;
73 SFcharAscent = -fse->max_logical_extent.y;
74 SFcharHeight = fse->max_logical_extent.height;
78 data = XtNew(TextData);
80 XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
81 XtNumber(textResources), (Arg *) NULL, ZERO);
83 SFfont = XLoadQueryFont(SFdisplay, data->fontname);
85 SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
89 (void) sprintf(sbuf, "XsraSelFile: can't get font %s",
92 XtAppError(SFapp, sbuf);
96 SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
97 SFcharAscent = SFfont->max_bounds.ascent;
98 SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
107 XRectangle rectangles[1];
109 gcValues.foreground = SFfore;
119 SFscrollGC = XtGetGC(
126 gcValues.function = GXinvert;
127 gcValues.plane_mask = (SFfore ^ SFback);
129 SFinvertGC = XtGetGC(
138 gcValues.foreground = SFfore;
139 gcValues.background = SFback;
141 gcValues.font = SFfont->fid;
144 SFtextGC = XCreateGC(
146 XtWindow(selFileLists[0]),
157 rectangles[0].x = SFlineToTextH + SFbesideText;
159 rectangles[0].width = SFcharsPerEntry * SFcharWidth;
160 rectangles[0].height = SFupperY + 1;
175 SFclearList(n, doScroll)
181 SFcurrentInvert[n] = -1;
183 XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
185 XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs,
189 dir = &(SFdirs[SFdirPtr + n]);
191 if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars) {
192 XawScrollbarSetThumb(
194 (float) (((double) dir->vOrigin) /
196 (float) (((double) ((dir->nEntries < SFlistSize)
197 ? dir->nEntries : SFlistSize)) /
201 XawScrollbarSetThumb(
203 (float) (((double) dir->hOrigin) / dir->nChars),
204 (float) (((double) ((dir->nChars <
205 SFcharsPerEntry) ? dir->nChars :
206 SFcharsPerEntry)) / dir->nChars)
209 XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
211 XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
219 SFdeleteEntry(dir, entry)
224 register SFEntry *end;
228 idx = entry - dir->entries;
230 if (idx < dir->beginSelection) {
231 dir->beginSelection--;
233 if (idx <= dir->endSelection) {
236 if (dir->beginSelection > dir->endSelection) {
237 dir->beginSelection = dir->endSelection = -1;
240 if (idx < dir->vOrigin) {
246 end = &(dir->entries[dir->nEntries - 1]);
248 for (e = entry; e < end; e++) {
252 if (!(--dir->nEntries)) {
256 n = dir - &(SFdirs[SFdirPtr]);
257 if ((n < 0) || (n > 2)) {
261 XawScrollbarSetThumb(
263 (float) (((double) dir->vOrigin) / dir->nEntries),
264 (float) (((double) ((dir->nEntries < SFlistSize) ?
265 dir->nEntries : SFlistSize)) / dir->nEntries)
271 SFwriteStatChar(name, last, statBuf)
274 struct stat *statBuf;
276 name[last] = SFstatChar(statBuf);
281 SFstatAndCheck(dir, entry)
290 * must be restored before returning
295 if (!SFchdir(SFcurrentPath)) {
296 last = strlen(entry->real) - 1;
297 entry->real[last] = 0;
300 (!stat(entry->real, &statBuf))
304 || (!lstat(entry->real, &statBuf))
306 #endif /* ndef S_IFLNK */
313 if (SFfunc(entry->real, &shown, &statBuf)) {
318 entry->shown = XtMalloc(
321 (void) strcpy(entry->shown,
328 entry->shown[len + 1] = 0;
331 SFdeleteEntry(dir, entry);
337 SFwriteStatChar(entry->real, last, &statBuf);
339 entry->real[last] = ' ';
348 SFdrawStrings(w, dir, from, to)
355 register SFEntry *entry;
358 x = SFtextX - dir->hOrigin * SFcharWidth;
360 if (dir->vOrigin + to >= dir->nEntries) {
361 to = dir->nEntries - dir->vOrigin - 1;
363 for (i = from; i <= to; i++) {
364 entry = &(dir->entries[dir->vOrigin + i]);
365 if (!(entry->statDone)) {
366 if (SFstatAndCheck(dir, entry)) {
367 if (dir->vOrigin + to >= dir->nEntries) {
368 to = dir->nEntries - dir->vOrigin - 1;
381 SFtextYoffset + i * SFentryHeight,
391 SFtextYoffset + i * SFentryHeight,
396 if (dir->vOrigin + i == dir->beginSelection) {
402 SFlowerY + i * SFentryHeight,
403 SFlineToTextH + SFentryWidth - 2,
404 SFlowerY + i * SFentryHeight
408 (dir->vOrigin + i >= dir->beginSelection) &&
409 (dir->vOrigin + i <= dir->endSelection)
411 SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
412 SFlowerY + i * SFentryHeight;
413 SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
414 SFlowerY + (i + 1) * SFentryHeight - 1;
423 if (dir->vOrigin + i == dir->endSelection) {
429 SFlowerY + (i + 1) * SFentryHeight - 1,
430 SFlineToTextH + SFentryWidth - 2,
431 SFlowerY + (i + 1) * SFentryHeight - 1
439 SFdrawList(n, doScroll)
446 SFclearList(n, doScroll);
448 if (SFdirPtr + (3-NR) + n < SFdirEnd) {
449 dir = &(SFdirs[SFdirPtr + n + (3-NR)]);
450 w = XtWindow(selFileLists[n]);
457 SFtextX - dir->hOrigin * SFcharWidth,
458 SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
467 SFtextX - dir->hOrigin * SFcharWidth,
468 SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
473 SFdrawStrings(w, dir, 0, SFlistSize - 1);
479 SFdrawLists(doScroll)
484 for (i = 0; i < NR; i++) {
485 SFdrawList(i, doScroll);
496 XtWindow(selFileLists[n]),
499 SFcurrentInvert[n] * SFentryHeight + SFlowerY,
507 SFscrollTimerInterval()
509 static int maxVal = 200;
510 static int varyDist = 50;
511 static int minDist = 50;
515 if (SFcurrentListY < SFlowerY) {
516 dist = SFlowerY - SFcurrentListY;
517 } else if (SFcurrentListY > SFupperY) {
518 dist = SFcurrentListY - SFupperY;
520 return (unsigned long) 1;
523 t = maxVal - ((maxVal / varyDist) * (dist - minDist));
533 return (unsigned long) t;
545 n = (int)(intptr_t) p;
547 dir = &(SFdirs[SFdirPtr + n]);
550 if (SFcurrentListY < SFlowerY) {
551 if (dir->vOrigin > 0) {
552 SFvSliderMovedCallback(selFileVScrolls[n], n,
555 } else if (SFcurrentListY > SFupperY) {
556 if (dir->vOrigin < dir->nEntries - SFlistSize) {
557 SFvSliderMovedCallback(selFileVScrolls[n], n,
562 if (dir->vOrigin != save) {
564 XawScrollbarSetThumb(
566 (float) (((double) dir->vOrigin) / dir->nEntries),
567 (float) (((double) ((dir->nEntries < SFlistSize) ?
568 dir->nEntries : SFlistSize)) / dir->nEntries)
573 if (SFbuttonPressed) {
574 SFscrollTimerId = XtAppAddTimeOut(SFapp,
575 SFscrollTimerInterval(), SFscrollTimer, (XtPointer)(intptr_t) n);
580 SFnewInvertEntry(n, event)
582 register XMotionEvent *event;
586 static int SFscrollTimerAdded = 0;
591 if (SFdirPtr + n >= SFdirEnd) {
594 (x >= 0) && (x <= SFupperX) &&
595 (y >= SFlowerY) && (y <= SFupperY)
597 register SFDir *dir = &(SFdirs[SFdirPtr + n]);
599 if (SFscrollTimerAdded) {
600 SFscrollTimerAdded = 0;
601 XtRemoveTimeOut(SFscrollTimerId);
604 new = (y - SFlowerY) / SFentryHeight;
605 if (dir->vOrigin + new >= dir->nEntries) {
610 if (SFbuttonPressed) {
612 if (!SFscrollTimerAdded) {
613 SFscrollTimerAdded = 1;
614 SFscrollTimerId = XtAppAddTimeOut(SFapp,
615 SFscrollTimerInterval(), SFscrollTimer,
616 (XtPointer)(intptr_t) n);
626 SFenterList(w, n, event)
629 register XEnterWindowEvent *event;
634 if (SFcurrentInvert[n] != -1) {
636 SFcurrentInvert[n] = -1;
639 new = SFnewInvertEntry(n, (XMotionEvent *) event);
641 SFcurrentInvert[n] = new;
648 SFleaveList(w, n, event)
653 if (SFcurrentInvert[n] != -1) {
655 SFcurrentInvert[n] = -1;
661 SFmotionList(w, n, event)
664 register XMotionEvent *event;
668 new = SFnewInvertEntry(n, event);
670 if (new != SFcurrentInvert[n]) {
671 if (SFcurrentInvert[n] != -1) {
674 SFcurrentInvert[n] = new;
684 SFvSliderMovedCallback(w, n, new)
693 dir = &(SFdirs[SFdirPtr + n]);
697 if(new == -1) new = old + 1; else if(new == -2) new = old - 1; // [HGM] indicates scroll direction on mousewheel event
698 if(new < 0 || new > dir->nEntries - SFlistSize) return;
705 win = XtWindow(selFileLists[n]);
707 if (ABS(new - old) < SFlistSize) {
715 SFlowerY + (new - old) * SFentryHeight,
716 SFentryWidth + SFlineToTextH,
717 (SFlistSize - (new - old)) * SFentryHeight,
725 SFlowerY + (SFlistSize - (new - old)) *
727 SFentryWidth + SFlineToTextH,
728 (new - old) * SFentryHeight,
731 SFdrawStrings(win, dir, SFlistSize - (new - old),
741 SFentryWidth + SFlineToTextH,
742 (SFlistSize - (old - new)) * SFentryHeight,
744 SFlowerY + (old - new) * SFentryHeight
751 SFentryWidth + SFlineToTextH,
752 (old - new) * SFentryHeight,
755 SFdrawStrings(win, dir, 0, old - new);
763 SFentryWidth + SFlineToTextH,
764 SFlistSize * SFentryHeight,
767 SFdrawStrings(win, dir, 0, SFlistSize - 1);
773 SFvFloatSliderMovedCallback(w, n, fnew)
780 new = (*fnew) * SFdirs[SFdirPtr + n].nEntries;
782 SFvSliderMovedCallback(w, n, new);
788 SFvAreaSelectedCallback(w, n, pnew)
796 dir = &(SFdirs[SFdirPtr + n]);
799 (((double) pnew) / SFvScrollHeight) * dir->nEntries;
801 if (new > dir->nEntries - SFlistSize) {
802 new = dir->nEntries - SFlistSize;
812 f = ((double) new) / dir->nEntries;
814 XawScrollbarSetThumb(
817 (float) (((double) ((dir->nEntries < SFlistSize) ?
818 dir->nEntries : SFlistSize)) / dir->nEntries)
822 SFvSliderMovedCallback(w, n, new);
827 SFhSliderMovedCallback(w, n, new)
835 dir = &(SFdirs[SFdirPtr + n]);
837 dir->hOrigin = (*new) * dir->nChars;
838 if (dir->hOrigin == save) {
842 SFdrawList(n, SF_DO_NOT_SCROLL);
847 SFhAreaSelectedCallback(w, n, pnew)
855 dir = &(SFdirs[SFdirPtr + n]);
858 (((double) pnew) / SFhScrollWidth) * dir->nChars;
860 if (new > dir->nChars - SFcharsPerEntry) {
861 new = dir->nChars - SFcharsPerEntry;
871 f = ((double) new) / dir->nChars;
873 XawScrollbarSetThumb(
876 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
877 dir->nChars : SFcharsPerEntry)) / dir->nChars)
880 SFhSliderMovedCallback(w, n, &f);
886 SFpathSliderMovedCallback(w, client_data, new)
888 XtPointer client_data;
896 SFdirPtrSave = SFdirPtr;
897 SFdirPtr = (*new) * SFdirEnd;
898 if (SFdirPtr == SFdirPtrSave) {
902 SFdrawLists(SF_DO_SCROLL);
905 while (SFdirPtr + n >= SFdirEnd) {
909 dir = &(SFdirs[SFdirPtr + n]);
911 pos = dir->path - SFcurrentPath;
913 if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
914 pos -= strlen(SFstartDir);
920 XawTextSetInsertionPoint(selFileField, pos);
926 SFpathAreaSelectedCallback(w, client_data, pnew)
928 XtPointer client_data;
934 new = SFdirPtr + (((double) pnew) / SFpathScrollWidth) * SFdirEnd;
936 if (new > SFdirEnd - 3) {
944 f = ((double) new) / SFdirEnd;
946 XawScrollbarSetThumb(
949 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
953 SFpathSliderMovedCallback(w, (XtPointer) NULL, &f);
960 register SFEntry *entry;
962 for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) {
963 if (!(dir->nEntries)) {
967 entry = &(dir->entries[dir->nEntries - 1]);
968 entry >= dir->entries;
971 if (!(entry->statDone)) {
972 (void) SFstatAndCheck(dir, entry);