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
30 #include <X11/StringDefs.h>
31 #include <X11/Xaw/Scrollbar.h>
32 #include <X11/Xaw/Cardinals.h>
34 #define SF_DEFAULT_FONT "9x15"
39 #define ABS(x) (((x) < 0) ? (-(x)) : (x))
41 /* added missing prototypes */
42 extern char SFstatChar(struct stat*);
43 extern int SFchdir(char *);
44 void SFvSliderMovedCallback(Widget, int, int);
50 int SFcharWidth, SFcharAscent, SFcharHeight;
52 int SFcurrentInvert[3] = { -1, -1, -1 };
54 static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
56 static XtResource textResources[] = {
57 {XtNfont, XtCFont, XtRString, sizeof (char *),
58 XtOffset(textPtr, fontname), XtRString, SF_DEFAULT_FONT},
61 static XFontStruct *SFfont;
63 static int SFcurrentListY;
65 static XtIntervalId SFscrollTimerId;
72 data = XtNew(TextData);
74 XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
75 XtNumber(textResources), (Arg *) NULL, ZERO);
77 SFfont = XLoadQueryFont(SFdisplay, data->fontname);
79 SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
83 (void) sprintf(sbuf, "XsraSelFile: can't get font %s",
86 XtAppError(SFapp, sbuf);
90 SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
91 SFcharAscent = SFfont->max_bounds.ascent;
92 SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
100 XRectangle rectangles[1];
102 gcValues.foreground = SFfore;
112 SFscrollGC = XtGetGC(
119 gcValues.function = GXinvert;
120 gcValues.plane_mask = (SFfore ^ SFback);
122 SFinvertGC = XtGetGC(
131 gcValues.foreground = SFfore;
132 gcValues.background = SFback;
133 gcValues.font = SFfont->fid;
135 SFtextGC = XCreateGC(
137 XtWindow(selFileLists[0]),
146 rectangles[0].x = SFlineToTextH + SFbesideText;
148 rectangles[0].width = SFcharsPerEntry * SFcharWidth;
149 rectangles[0].height = SFupperY + 1;
164 SFclearList(n, doScroll)
170 SFcurrentInvert[n] = -1;
172 XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
174 XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs,
178 dir = &(SFdirs[SFdirPtr + n]);
180 if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars) {
181 XawScrollbarSetThumb(
183 (float) (((double) dir->vOrigin) /
185 (float) (((double) ((dir->nEntries < SFlistSize)
186 ? dir->nEntries : SFlistSize)) /
190 XawScrollbarSetThumb(
192 (float) (((double) dir->hOrigin) / dir->nChars),
193 (float) (((double) ((dir->nChars <
194 SFcharsPerEntry) ? dir->nChars :
195 SFcharsPerEntry)) / dir->nChars)
198 XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
200 XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
208 SFdeleteEntry(dir, entry)
213 register SFEntry *end;
217 idx = entry - dir->entries;
219 if (idx < dir->beginSelection) {
220 dir->beginSelection--;
222 if (idx <= dir->endSelection) {
225 if (dir->beginSelection > dir->endSelection) {
226 dir->beginSelection = dir->endSelection = -1;
229 if (idx < dir->vOrigin) {
235 end = &(dir->entries[dir->nEntries - 1]);
237 for (e = entry; e < end; e++) {
241 if (!(--dir->nEntries)) {
245 n = dir - &(SFdirs[SFdirPtr]);
246 if ((n < 0) || (n > 2)) {
250 XawScrollbarSetThumb(
252 (float) (((double) dir->vOrigin) / dir->nEntries),
253 (float) (((double) ((dir->nEntries < SFlistSize) ?
254 dir->nEntries : SFlistSize)) / dir->nEntries)
260 SFwriteStatChar(name, last, statBuf)
263 struct stat *statBuf;
265 name[last] = SFstatChar(statBuf);
270 SFstatAndCheck(dir, entry)
279 * must be restored before returning
284 if (!SFchdir(SFcurrentPath)) {
285 last = strlen(entry->real) - 1;
286 entry->real[last] = 0;
289 (!stat(entry->real, &statBuf))
293 || (!lstat(entry->real, &statBuf))
295 #endif /* ndef S_IFLNK */
302 if (SFfunc(entry->real, &shown, &statBuf)) {
307 entry->shown = XtMalloc(
310 (void) strcpy(entry->shown,
317 entry->shown[len + 1] = 0;
320 SFdeleteEntry(dir, entry);
326 SFwriteStatChar(entry->real, last, &statBuf);
328 entry->real[last] = ' ';
337 SFdrawStrings(w, dir, from, to)
344 register SFEntry *entry;
347 x = SFtextX - dir->hOrigin * SFcharWidth;
349 if (dir->vOrigin + to >= dir->nEntries) {
350 to = dir->nEntries - dir->vOrigin - 1;
352 for (i = from; i <= to; i++) {
353 entry = &(dir->entries[dir->vOrigin + i]);
354 if (!(entry->statDone)) {
355 if (SFstatAndCheck(dir, entry)) {
356 if (dir->vOrigin + to >= dir->nEntries) {
357 to = dir->nEntries - dir->vOrigin - 1;
368 SFtextYoffset + i * SFentryHeight,
372 if (dir->vOrigin + i == dir->beginSelection) {
378 SFlowerY + i * SFentryHeight,
379 SFlineToTextH + SFentryWidth - 2,
380 SFlowerY + i * SFentryHeight
384 (dir->vOrigin + i >= dir->beginSelection) &&
385 (dir->vOrigin + i <= dir->endSelection)
387 SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
388 SFlowerY + i * SFentryHeight;
389 SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
390 SFlowerY + (i + 1) * SFentryHeight - 1;
399 if (dir->vOrigin + i == dir->endSelection) {
405 SFlowerY + (i + 1) * SFentryHeight - 1,
406 SFlineToTextH + SFentryWidth - 2,
407 SFlowerY + (i + 1) * SFentryHeight - 1
415 SFdrawList(n, doScroll)
422 SFclearList(n, doScroll);
424 if (SFdirPtr + (3-NR) + n < SFdirEnd) {
425 dir = &(SFdirs[SFdirPtr + n + (3-NR)]);
426 w = XtWindow(selFileLists[n]);
431 SFtextX - dir->hOrigin * SFcharWidth,
432 SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
436 SFdrawStrings(w, dir, 0, SFlistSize - 1);
442 SFdrawLists(doScroll)
447 for (i = 0; i < NR; i++) {
448 SFdrawList(i, doScroll);
459 XtWindow(selFileLists[n]),
462 SFcurrentInvert[n] * SFentryHeight + SFlowerY,
470 SFscrollTimerInterval()
472 static int maxVal = 200;
473 static int varyDist = 50;
474 static int minDist = 50;
478 if (SFcurrentListY < SFlowerY) {
479 dist = SFlowerY - SFcurrentListY;
480 } else if (SFcurrentListY > SFupperY) {
481 dist = SFcurrentListY - SFupperY;
483 return (unsigned long) 1;
486 t = maxVal - ((maxVal / varyDist) * (dist - minDist));
496 return (unsigned long) t;
508 n = (int)(intptr_t) p;
510 dir = &(SFdirs[SFdirPtr + n]);
513 if (SFcurrentListY < SFlowerY) {
514 if (dir->vOrigin > 0) {
515 SFvSliderMovedCallback(selFileVScrolls[n], n,
518 } else if (SFcurrentListY > SFupperY) {
519 if (dir->vOrigin < dir->nEntries - SFlistSize) {
520 SFvSliderMovedCallback(selFileVScrolls[n], n,
525 if (dir->vOrigin != save) {
527 XawScrollbarSetThumb(
529 (float) (((double) dir->vOrigin) / dir->nEntries),
530 (float) (((double) ((dir->nEntries < SFlistSize) ?
531 dir->nEntries : SFlistSize)) / dir->nEntries)
536 if (SFbuttonPressed) {
537 SFscrollTimerId = XtAppAddTimeOut(SFapp,
538 SFscrollTimerInterval(), SFscrollTimer, (XtPointer)(intptr_t) n);
543 SFnewInvertEntry(n, event)
545 register XMotionEvent *event;
549 static int SFscrollTimerAdded = 0;
554 if (SFdirPtr + n >= SFdirEnd) {
557 (x >= 0) && (x <= SFupperX) &&
558 (y >= SFlowerY) && (y <= SFupperY)
560 register SFDir *dir = &(SFdirs[SFdirPtr + n]);
562 if (SFscrollTimerAdded) {
563 SFscrollTimerAdded = 0;
564 XtRemoveTimeOut(SFscrollTimerId);
567 new = (y - SFlowerY) / SFentryHeight;
568 if (dir->vOrigin + new >= dir->nEntries) {
573 if (SFbuttonPressed) {
575 if (!SFscrollTimerAdded) {
576 SFscrollTimerAdded = 1;
577 SFscrollTimerId = XtAppAddTimeOut(SFapp,
578 SFscrollTimerInterval(), SFscrollTimer,
579 (XtPointer)(intptr_t) n);
589 SFenterList(w, n, event)
592 register XEnterWindowEvent *event;
597 if (SFcurrentInvert[n] != -1) {
599 SFcurrentInvert[n] = -1;
602 new = SFnewInvertEntry(n, (XMotionEvent *) event);
604 SFcurrentInvert[n] = new;
611 SFleaveList(w, n, event)
616 if (SFcurrentInvert[n] != -1) {
618 SFcurrentInvert[n] = -1;
624 SFmotionList(w, n, event)
627 register XMotionEvent *event;
631 new = SFnewInvertEntry(n, event);
633 if (new != SFcurrentInvert[n]) {
634 if (SFcurrentInvert[n] != -1) {
637 SFcurrentInvert[n] = new;
647 SFvSliderMovedCallback(w, n, new)
656 dir = &(SFdirs[SFdirPtr + n]);
660 if(new == -1) new = old + 1; else if(new == -2) new = old - 1; // [HGM] indicates scroll direction on mousewheel event
661 if(new < 0 || new > dir->nEntries - SFlistSize) return;
668 win = XtWindow(selFileLists[n]);
670 if (ABS(new - old) < SFlistSize) {
678 SFlowerY + (new - old) * SFentryHeight,
679 SFentryWidth + SFlineToTextH,
680 (SFlistSize - (new - old)) * SFentryHeight,
688 SFlowerY + (SFlistSize - (new - old)) *
690 SFentryWidth + SFlineToTextH,
691 (new - old) * SFentryHeight,
694 SFdrawStrings(win, dir, SFlistSize - (new - old),
704 SFentryWidth + SFlineToTextH,
705 (SFlistSize - (old - new)) * SFentryHeight,
707 SFlowerY + (old - new) * SFentryHeight
714 SFentryWidth + SFlineToTextH,
715 (old - new) * SFentryHeight,
718 SFdrawStrings(win, dir, 0, old - new);
726 SFentryWidth + SFlineToTextH,
727 SFlistSize * SFentryHeight,
730 SFdrawStrings(win, dir, 0, SFlistSize - 1);
736 SFvFloatSliderMovedCallback(w, n, fnew)
743 new = (*fnew) * SFdirs[SFdirPtr + n].nEntries;
745 SFvSliderMovedCallback(w, n, new);
751 SFvAreaSelectedCallback(w, n, pnew)
759 dir = &(SFdirs[SFdirPtr + n]);
762 (((double) pnew) / SFvScrollHeight) * dir->nEntries;
764 if (new > dir->nEntries - SFlistSize) {
765 new = dir->nEntries - SFlistSize;
775 f = ((double) new) / dir->nEntries;
777 XawScrollbarSetThumb(
780 (float) (((double) ((dir->nEntries < SFlistSize) ?
781 dir->nEntries : SFlistSize)) / dir->nEntries)
785 SFvSliderMovedCallback(w, n, new);
790 SFhSliderMovedCallback(w, n, new)
798 dir = &(SFdirs[SFdirPtr + n]);
800 dir->hOrigin = (*new) * dir->nChars;
801 if (dir->hOrigin == save) {
805 SFdrawList(n, SF_DO_NOT_SCROLL);
810 SFhAreaSelectedCallback(w, n, pnew)
818 dir = &(SFdirs[SFdirPtr + n]);
821 (((double) pnew) / SFhScrollWidth) * dir->nChars;
823 if (new > dir->nChars - SFcharsPerEntry) {
824 new = dir->nChars - SFcharsPerEntry;
834 f = ((double) new) / dir->nChars;
836 XawScrollbarSetThumb(
839 (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
840 dir->nChars : SFcharsPerEntry)) / dir->nChars)
843 SFhSliderMovedCallback(w, n, &f);
849 SFpathSliderMovedCallback(w, client_data, new)
851 XtPointer client_data;
859 SFdirPtrSave = SFdirPtr;
860 SFdirPtr = (*new) * SFdirEnd;
861 if (SFdirPtr == SFdirPtrSave) {
865 SFdrawLists(SF_DO_SCROLL);
868 while (SFdirPtr + n >= SFdirEnd) {
872 dir = &(SFdirs[SFdirPtr + n]);
874 pos = dir->path - SFcurrentPath;
876 if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
877 pos -= strlen(SFstartDir);
883 XawTextSetInsertionPoint(selFileField, pos);
889 SFpathAreaSelectedCallback(w, client_data, pnew)
891 XtPointer client_data;
897 new = SFdirPtr + (((double) pnew) / SFpathScrollWidth) * SFdirEnd;
899 if (new > SFdirEnd - 3) {
907 f = ((double) new) / SFdirEnd;
909 XawScrollbarSetThumb(
912 (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
916 SFpathSliderMovedCallback(w, (XtPointer) NULL, &f);
923 register SFEntry *entry;
925 for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) {
926 if (!(dir->nEntries)) {
930 entry = &(dir->entries[dir->nEntries - 1]);
931 entry >= dir->entries;
934 if (!(entry->statDone)) {
935 (void) SFstatAndCheck(dir, entry);