marked more strings for translation
[xboard.git] / filebrowser / selfile.c
index c0a2ce2..e6edfe4 100644 (file)
@@ -60,7 +60,9 @@ extern int errno;
 #include <X11/Xaw/Label.h>
 #include <X11/Xaw/Cardinals.h>
 
+#include "xstat.h"
 #include "selfile.h"
+#include "../gettext.h"
 
 #ifndef MAXPATHLEN
 #define MAXPATHLEN 1024
@@ -70,17 +72,29 @@ extern int errno;
 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],
@@ -123,12 +137,16 @@ XtAppContext SFapp;
 
 int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
 
-char SFtextBuffer[MAXPATHLEN];
+char SFtextBuffer[MAXPATHLEN+1];
+
+char SFfilterBuffer[MAXPATHLEN+1];
 
 XtIntervalId SFdirModTimerId;
 
 int (*SFfunc)();
 
+Boolean SFpathFlag; // [HGM]
+
 static char *oneLineTextEditTranslations = "\
        <Key>Return:    redraw-display()\n\
        Ctrl<Key>M:     redraw-display()\n\
@@ -146,7 +164,14 @@ SFexposeList(w, n, event, cont)
                return;
        }
 
-       SFdrawList(n, SF_DO_NOT_SCROLL);
+       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 */
@@ -161,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;
        }
 }
 
@@ -219,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;
@@ -241,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 */
@@ -325,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++;
@@ -336,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++;
@@ -418,9 +510,9 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
                        scrollbarWidgetClass, selFileLists[n], arglist, i);
 
                XtAddCallback(selFileVScrolls[n], XtNjumpProc,
-                       SFvFloatSliderMovedCallback, (XtPointer) n);
+                       SFvFloatSliderMovedCallback, (XtPointer)(intptr_t) n);
                XtAddCallback(selFileVScrolls[n], XtNscrollProc,
-                       SFvAreaSelectedCallback, (XtPointer) n);
+                       SFvAreaSelectedCallback, (XtPointer)(intptr_t) n);
 
                i = 0;
 
@@ -435,9 +527,12 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
                        scrollbarWidgetClass, selFileLists[n], arglist, i);
 
                XtAddCallback(selFileHScrolls[n], XtNjumpProc,
-                       SFhSliderMovedCallback, (XtPointer) n);
+                       SFhSliderMovedCallback, (XtPointer)(intptr_t) n);
                XtAddCallback(selFileHScrolls[n], XtNscrollProc,
-                       SFhAreaSelectedCallback, (XtPointer) n);
+                       SFhAreaSelectedCallback, (XtPointer)(intptr_t) n);
+
+               XtAddEventHandler(selFileVScrolls[n], ButtonPressMask, False,
+                       SFwheelProc, (XtPointer)(intptr_t) n); // [HGM] couplemouse wheel to v-scroll
        }
 
        i = 0;
@@ -486,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]),
@@ -496,21 +592,24 @@ SFcreateWidgets(toplevel, prompt, ok, cancel)
 
        for (n = 0; n < NR; n++) {
                XtAddEventHandler(selFileLists[n], ExposureMask, True,
-                       SFexposeList, (XtPointer) n);
+                       SFexposeList, (XtPointer)(intptr_t) n);
                XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
-                       SFenterList, (XtPointer) n);
+                       SFenterList, (XtPointer)(intptr_t) n);
                XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
-                       SFleaveList, (XtPointer) n);
+                       SFleaveList, (XtPointer)(intptr_t) n);
                XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
-                       SFmotionList, (XtPointer) n);
+                       (XtEventHandler) SFmotionList, (XtPointer)(intptr_t) n);
                XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
-                       SFbuttonPressList, (XtPointer) n);
+                       SFbuttonPressList, (XtPointer)(intptr_t) n);
                XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
-                       SFbuttonReleaseList, (XtPointer) n);
+                       SFbuttonReleaseList, (XtPointer)(intptr_t) n);
        }
 
        XtAddEventHandler(selFileField, KeyPressMask, False,
                SFmodVerifyCallback, (XtPointer) NULL);
+       XtAddEventHandler(filterField, KeyReleaseMask, False,
+               SFmodVerifyCallback, (XtPointer) 1);
+       XtSetKeyboardFocus(selFileForm, selFileField);
 
        SFapp = XtWidgetToApplicationContext(selFile);
 
@@ -589,15 +688,42 @@ SFopenFile(name, mode, prompt, failed)
 }
 
 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) strcpy(SFcurrentPath, SFtextBuffer);
+         (void) strncpy(SFcurrentPath, SFtextBuffer, MAXPATHLEN);
 
                SFtextPos = XawTextGetInsertionPoint(selFileField);
        } else {
-               (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
+         (void) strcat(strncpy(SFcurrentPath, SFstartDir, MAXPATHLEN), SFtextBuffer);
 
                SFtextPos = XawTextGetInsertionPoint(selFileField) +
                        strlen(SFstartDir);
@@ -637,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;
@@ -655,15 +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') || strcmp(SFfilterBuffer, filter)) {
+               SFpurge();
+               SFpathFlag = (mode && mode[0] == 'p'); // [HGM] ignore everything that is not a directory
        }
 
        if (firstTime) {
@@ -685,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);
 
@@ -694,14 +834,14 @@ 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) strcpy(SFcurrentDir, SFstartDir);
+       (void) strncpy(SFcurrentDir, SFstartDir, MAXPATHLEN);
 
        if (init_path) {
                if (init_path[0] == '/') {
-                       (void) strcpy(SFcurrentPath, init_path);
+                 (void) strncpy(SFcurrentPath, init_path, MAXPATHLEN);
                        if (strncmp(
                                SFcurrentPath,
                                SFstartDir,
@@ -712,12 +852,12 @@ XsraSelFile(toplevel, prompt, ok, cancel, failed,
                                SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
                        }
                } else {
-                       (void) strcat(strcpy(SFcurrentPath, SFstartDir),
+                 (void) strcat(strncpy(SFcurrentPath, SFstartDir, MAXPATHLEN),
                                init_path);
                        SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
                }
        } else {
-               (void) strcpy(SFcurrentPath, SFstartDir);
+         (void) strncpy(SFcurrentPath, SFstartDir, MAXPATHLEN);
        }
 
        SFfunc = show_entry;
@@ -739,8 +879,12 @@ XsraSelFile(toplevel, prompt, ok, cancel, failed,
                        break;
                case SEL_FILE_OK:
                        *name_return = SFgetText();
-                       if (fp = SFopenFile(*name_return, mode,
-                                           prompt, failed)) {
+                       if(mode && (mode[0] == 'p' || mode[0] == 'f')) { // [HGM] for use in file-option browse button
+                               SFprepareToReturn();
+                               return stderr;
+                       }
+                       if ((*name_return)[strlen(*name_return)-1] != '/' &&         // [HGM] refuse directories
+                           (fp = SFopenFile(*name_return, mode, prompt, failed))) {
                                SFprepareToReturn();
                                return fp;
                        }
@@ -748,9 +892,11 @@ XsraSelFile(toplevel, prompt, ok, cancel, failed,
                        break;
                case SEL_FILE_CANCEL:
                        SFprepareToReturn();
+                       SFsetText(SFlastPath);
                        return NULL;
                case SEL_FILE_NULL:
                        break;
                }
        }
+
 }