Implement -autoCopyPV
[xboard.git] / filebrowser / selfile.c
index 2e34955..729453b 100644 (file)
@@ -60,17 +60,9 @@ extern int errno;
 #include <X11/Xaw/Label.h>
 #include <X11/Xaw/Cardinals.h>
 
-#include "selfile.h"
 #include "xstat.h"
-
-/* added missing prototypes */
-extern void SFdrawList(int,int);
-extern void SFinitFont();
-extern void SFcreateGC();
-extern int SFchdir(char *);
-extern void SFupdatePath();
-extern void SFsetText(char *);
-extern char SFstatChar(struct stat*);
+#include "selfile.h"
+#include "../gettext.h"
 
 #ifndef MAXPATHLEN
 #define MAXPATHLEN 1024
@@ -80,17 +72,29 @@ extern char SFstatChar(struct stat*);
 extern char *getwd();
 #endif /* !defined(SVR4) && !defined(SYSV) && !defined(USG) */
 
+#ifdef ENABLE_NLS
+# define  _(s) gettext (s)
+# define N_(s) gettext_noop (s)
+#else
+# define  _(s) (s)
+# define N_(s)  s
+#endif
+
+
 int SFstatus = SEL_FILE_NULL;
 
 char
-       SFstartDir[MAXPATHLEN],
-       SFcurrentPath[MAXPATHLEN],
-       SFcurrentDir[MAXPATHLEN];
+       SFstartDir[MAXPATHLEN+1],
+       SFcurrentPath[MAXPATHLEN+1],
+       SFlastPath[MAXPATHLEN+1],
+       SFcurrentDir[MAXPATHLEN+1];
 
 Widget
        selFile,
        selFileCancel,
        selFileField,
+       selFileMess,
+       filterField,
        selFileForm,
        selFileHScroll,
        selFileHScrolls[3],
@@ -133,7 +137,9 @@ XtAppContext SFapp;
 
 int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
 
-char SFtextBuffer[MAXPATHLEN];
+char SFtextBuffer[MAXPATHLEN+1];
+
+char SFfilterBuffer[MAXPATHLEN+1];
 
 XtIntervalId SFdirModTimerId;
 
@@ -161,6 +167,13 @@ SFexposeList(w, n, event, cont)
        SFdrawList((int)(intptr_t)n, SF_DO_NOT_SCROLL);
 }
 
+void
+SFpurge()
+{
+       if(SFdirs) XtFree((XtPointer) SFdirs);
+       SFdirs = NULL; // kludge to throw away all cached info
+}
+
 /* ARGSUSED */
 static void
 SFmodVerifyCallback(w, client_data, event, cont)
@@ -173,11 +186,30 @@ SFmodVerifyCallback(w, client_data, event, cont)
 
        if (
                (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
-               ((*buf) == '\r')
+               ((*buf) == '\r' || *buf == 033)
        ) {
-               SFstatus = SEL_FILE_OK;
+               if(client_data) {
+                   Arg args[10]; char *p;
+                   if(*buf == 033) { // [HGM] esc in filter: restore and give focus to path
+                       XtSetArg(args[0], XtNstring, SFfilterBuffer);
+                       XtSetValues(filterField, args, 1);
+                       XtSetKeyboardFocus(selFileForm, selFileField);
+                       SFstatus = SEL_FILE_TEXT;
+                       return;
+                   } else
+                   if(!SFpathFlag) // [HGM] cr: fetch current extenson filter
+                   {   
+                       XtSetArg(args[0], XtNstring, &p);
+                       XtGetValues(filterField, args, 1);
+                       if(strcmp(SFfilterBuffer, p)) SFpurge();
+                       strncpy(SFfilterBuffer, p, 40);
+                       SFstatus = SEL_FILE_TEXT;
+                   }
+                   return;
+               }
+               SFstatus = (*buf == 033 ? SEL_FILE_CANCEL : SEL_FILE_OK);
        } else {
-               SFstatus = SEL_FILE_TEXT;
+               if(!client_data) SFstatus = SEL_FILE_TEXT;
        }
 }
 
@@ -231,6 +263,19 @@ static XtActionsRec actions[] = {
        {"SelFileDismiss",      SFdismissAction},
 };
 
+void SFsetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b)
+{
+    XtSetKeyboardFocus((Widget) data, w);
+}
+
+void SFwheelProc(Widget w, XtPointer data, XEvent *event, Boolean *b)
+{   // [HGM] mouse-wheel callback scrolls lists
+    int dir, n = (intptr_t) data;
+    if(event->xbutton.button == Button4) dir = -2; // kludge to indicate relative motion
+    if(event->xbutton.button == Button5) dir = -1;
+    SFvSliderMovedCallback(w, n, dir);
+}
+
 static void
 SFcreateWidgets(toplevel, prompt, ok, cancel)
        Widget  toplevel;
@@ -253,7 +298,7 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
        i = 0;
        XtSetArg(arglist[i], XtNtransientFor, toplevel);                i++;
 
-       selFile = XtAppCreateShell("Browse", "SelFile",
+       selFile = XtAppCreateShell(_("Browse"), "SelFile",
                transientShellWidgetClass, SFdisplay, arglist, i);
 
        /* Add WM_DELETE_WINDOW protocol */
@@ -337,7 +382,7 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
        XtSetArg(arglist[i], XtNborderColor, SFfore);                   i++;
 
        XtSetArg(arglist[i], XtNfromVert, selFilePrompt);               i++;
-       XtSetArg(arglist[i], XtNvertDistance, 10);                      i++;
+       XtSetArg(arglist[i], XtNvertDistance, 5);                       i++;
        XtSetArg(arglist[i], XtNresizable, True);                       i++;
        XtSetArg(arglist[i], XtNtop, XtChainTop);                       i++;
        XtSetArg(arglist[i], XtNbottom, XtChainTop);                    i++;
@@ -348,21 +393,56 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
        XtSetArg(arglist[i], XtNeditType, XawtextEdit);                 i++;
        XtSetArg(arglist[i], XtNwrap, XawtextWrapWord);                 i++;
        XtSetArg(arglist[i], XtNresize, XawtextResizeHeight);           i++;
-       XtSetArg(arglist[i], XtNuseStringInPlace, True);                i++;
        selFileField = XtCreateManagedWidget("selFileField",
                asciiTextWidgetClass, selFileForm, arglist, i);
 
        XtOverrideTranslations(selFileField,
                XtParseTranslationTable(oneLineTextEditTranslations));
-       XtSetKeyboardFocus(selFileForm, selFileField);
+       XtAddEventHandler(selFileField, ButtonPressMask, False, SFsetFocus, (XtPointer) selFileForm);
+
+       i = 0;
+       XtSetArg(arglist[i], XtNlabel, _("Filter on extensions:"));     i++;
+       XtSetArg(arglist[i], XtNvertDistance, 5);                       i++;
+       XtSetArg(arglist[i], XtNfromVert, selFileField);                i++;
+       XtSetArg(arglist[i], XtNresizable, True);                       i++;
+       XtSetArg(arglist[i], XtNtop, XtChainTop);                       i++;
+       XtSetArg(arglist[i], XtNbottom, XtChainTop);                    i++;
+       XtSetArg(arglist[i], XtNleft, XtChainLeft);                     i++;
+       XtSetArg(arglist[i], XtNright, XtChainLeft);                    i++;
+       XtSetArg(arglist[i], XtNborderWidth, 0);                        i++;
+       selFileMess = XtCreateManagedWidget("selFileMess",
+               labelWidgetClass, selFileForm, arglist, i);
+
+       i = 0;
+       XtSetArg(arglist[i], XtNwidth, NR * listWidth + (NR - 1) * listSpacing + 4);
+                                                                       i++;
+       XtSetArg(arglist[i], XtNborderColor, SFfore);                   i++;
+       XtSetArg(arglist[i], XtNvertDistance, 5);                       i++;
+       XtSetArg(arglist[i], XtNfromVert, selFileMess);                 i++;
+       XtSetArg(arglist[i], XtNresizable, True);                       i++;
+       XtSetArg(arglist[i], XtNtop, XtChainTop);                       i++;
+       XtSetArg(arglist[i], XtNbottom, XtChainTop);                    i++;
+       XtSetArg(arglist[i], XtNleft, XtChainLeft);                     i++;
+       XtSetArg(arglist[i], XtNright, XtChainLeft);                    i++;
+       XtSetArg(arglist[i], XtNlength, MAXPATHLEN);                    i++;
+       XtSetArg(arglist[i], XtNeditType, XawtextEdit);                 i++;
+       XtSetArg(arglist[i], XtNwrap, XawtextWrapWord);                 i++;
+       XtSetArg(arglist[i], XtNresize, XawtextResizeHeight);           i++;
+       XtSetArg(arglist[i], XtNuseStringInPlace, False);               i++;
+       filterField = XtCreateManagedWidget("filterField",
+               asciiTextWidgetClass, selFileForm, arglist, i);
+
+       XtOverrideTranslations(filterField,
+               XtParseTranslationTable(oneLineTextEditTranslations));
+       XtAddEventHandler(filterField, ButtonPressMask, False, SFsetFocus, (XtPointer) selFileForm);
 
        i = 0;
        XtSetArg(arglist[i], XtNorientation, XtorientHorizontal);       i++;
        XtSetArg(arglist[i], XtNwidth, SFpathScrollWidth);              i++;
        XtSetArg(arglist[i], XtNheight, scrollThickness);               i++;
        XtSetArg(arglist[i], XtNborderColor, SFfore);                   i++;
-       XtSetArg(arglist[i], XtNfromVert, selFileField);                i++;
-       XtSetArg(arglist[i], XtNvertDistance, 30);                      i++;
+       XtSetArg(arglist[i], XtNfromVert, filterField);                 i++;
+       XtSetArg(arglist[i], XtNvertDistance, 10);                      i++;
        XtSetArg(arglist[i], XtNtop, XtChainTop);                       i++;
        XtSetArg(arglist[i], XtNbottom, XtChainTop);                    i++;
        XtSetArg(arglist[i], XtNleft, XtChainLeft);                     i++;
@@ -450,6 +530,9 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
                        SFhSliderMovedCallback, (XtPointer)(intptr_t) n);
                XtAddCallback(selFileHScrolls[n], XtNscrollProc,
                        SFhAreaSelectedCallback, (XtPointer)(intptr_t) n);
+
+               XtAddEventHandler(selFileVScrolls[n], ButtonPressMask, False,
+                       SFwheelProc, (XtPointer)(intptr_t) n); // [HGM] couplemouse wheel to v-scroll
        }
 
        i = 0;
@@ -498,6 +581,7 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
 
        XDefineCursor(SFdisplay, XtWindow(selFileForm), xtermCursor);
        XDefineCursor(SFdisplay, XtWindow(selFileField), xtermCursor);
+       XDefineCursor(SFdisplay, XtWindow(filterField), xtermCursor);
 
        for (n = 0; n < NR; n++) {
                XDefineCursor(SFdisplay, XtWindow(selFileLists[n]),
@@ -514,7 +598,7 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
                XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
                        SFleaveList, (XtPointer)(intptr_t) n);
                XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
-                       SFmotionList, (XtPointer)(intptr_t) n);
+                       (XtEventHandler) SFmotionList, (XtPointer)(intptr_t) n);
                XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
                        SFbuttonPressList, (XtPointer)(intptr_t) n);
                XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
@@ -523,6 +607,9 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
 
        XtAddEventHandler(selFileField, KeyPressMask, False,
                SFmodVerifyCallback, (XtPointer) NULL);
+       XtAddEventHandler(filterField, KeyReleaseMask, False,
+               SFmodVerifyCallback, (XtPointer) 1);
+       XtSetKeyboardFocus(selFileForm, selFileField);
 
        SFapp = XtWidgetToApplicationContext(selFile);
 
@@ -600,9 +687,36 @@ SFopenFile(name, mode, prompt, failed)
     return fp;
 }
 
+void
+SFupdateTextBuffer()
+{
+       Arg arglist[2];
+       int i;
+       char *v;
+
+       i = 0;
+       XtSetArg(arglist[i], XtNstring, &v);  i++;
+       XtGetValues(selFileField, arglist, i);
+       strncpy(SFtextBuffer, v, MAXPATHLEN);
+}
+
+void
+SFsetText(path)
+       char    *path;
+{
+       Arg arglist[2];
+       int i;
+
+       i = 0;
+       XtSetArg(arglist[i], XtNstring, path);  i++;
+       XtSetValues(selFileField, arglist, i);
+       XawTextSetInsertionPoint(selFileField, strlen(path));
+}
+
 void
 SFtextChanged()
 {
+       SFupdateTextBuffer();
 
        if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~')) {
          (void) strncpy(SFcurrentPath, SFtextBuffer, MAXPATHLEN);
@@ -649,13 +763,14 @@ SFprepareToReturn()
 
 FILE *
 XsraSelFile(toplevel, prompt, ok, cancel, failed,
-           init_path, mode, show_entry, name_return)
+           init_path, filter, mode, show_entry, name_return)
        Widget          toplevel;
        char            *prompt;
        char            *ok;
        char            *cancel;
        char            *failed;
        char            *init_path;
+       char            *filter;
        char            *mode;
        int             (*show_entry)();
        char            **name_return;
@@ -667,21 +782,20 @@ XsraSelFile(toplevel, prompt, ok, cancel, failed,
        FILE            *fp;
 
        if (!prompt) {
-               prompt = "Pathname:";
+               prompt = _("Pathname:");
        }
 
        if (!ok) {
-               ok = "OK";
+               ok = _("OK");
        }
 
        if (!cancel) {
-               cancel = "Cancel";
+               cancel = _("Cancel");
        }
 
-       if(SFpathFlag != (mode && mode[0] == 'p')) { // [HGM] ignore everything that is not a directory
-               if(SFdirs) XtFree(SFdirs);
-               SFdirs = NULL; // kludge to throw away all cached info
-               SFpathFlag = !SFpathFlag;
+       if(SFpathFlag != (mode && mode[0] == 'p') || strcmp(SFfilterBuffer, filter)) {
+               SFpurge();
+               SFpathFlag = (mode && mode[0] == 'p'); // [HGM] ignore everything that is not a directory
        }
 
        if (firstTime) {
@@ -703,6 +817,14 @@ XsraSelFile(toplevel, prompt, ok, cancel, failed,
                XtSetValues(selFileCancel, arglist, i);
        }
 
+       i = 0;
+       XtSetArg(arglist[i], XtNstring, filter);                        i++;
+       XtSetValues(filterField, arglist, i);
+
+       strncpy(SFfilterBuffer, filter, MAXPATHLEN-1);
+       SFupdateTextBuffer();
+       strncpy(SFlastPath, SFtextBuffer, MAXPATHLEN-1); // remember for cancel
+
        SFpositionWidget(selFile);
        XtMapWidget(selFile);
 
@@ -712,7 +834,7 @@ XsraSelFile(toplevel, prompt, ok, cancel, failed,
        if (!getwd(SFstartDir)) {
 #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
 
-               XtAppError(SFapp, "XsraSelFile: can't get current directory");
+         XtAppError(SFapp, _("XsraSelFile: can't get current directory"));
        }
        (void) strcat(SFstartDir, "/");
        (void) strncpy(SFcurrentDir, SFstartDir, MAXPATHLEN);
@@ -761,8 +883,8 @@ XsraSelFile(toplevel, prompt, ok, cancel, failed,
                                SFprepareToReturn();
                                return stderr;
                        }
-                       if (fp = SFopenFile(*name_return, mode,
-                                           prompt, failed)) {
+                       if ((!(*name_return)[0] || (*name_return)[strlen(*name_return)-1] != '/') &&      // [HGM] refuse directories
+                           (fp = SFopenFile(*name_return, mode, prompt, failed))) {
                                SFprepareToReturn();
                                return fp;
                        }
@@ -770,9 +892,11 @@ XsraSelFile(toplevel, prompt, ok, cancel, failed,
                        break;
                case SEL_FILE_CANCEL:
                        SFprepareToReturn();
+                       SFsetText(SFlastPath);
                        return NULL;
                case SEL_FILE_NULL:
                        break;
                }
        }
+
 }