/* filemenu.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See COPYING for more details. The idea of this popup is lifted from xxgdb and adopted for xgammon. Especially the functions ScanDir (), Inlist () and changeDir () are almost literally copied. And the copied idea is visible in the functions File () CreateFilePopup () DisplayMenuFile (). * xdbx - X Window System interface to the dbx debugger * * Copyright 1989 The University of Texas at Austin * Copyright 1990 Microelectronics and Computer Technology Corporation * Copyright 1990 Thomson Consumer Electronics, Inc. */ #include #include /*#include */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" char cwd[MAXPATHLEN]; /* current working directory */ static char file_listDir[MAXPATHLEN]; /* current directory of file list */ static char **filelist; static int file_count = 0; static Widget popupshell, popup_pane, file_list, path_label; static Widget popup_form, dialog; extern Widget button_shell; extern void load (); extern void save (); void File (); void CreateSaveDialog (void); static void CreateFilePopup (char *dir); static void save_file (); static void changeDir (); static int InList (); static void ScanDir (); static void DisplayMenuFile (); static void CreateFilePopup (); static void PopdownPopup (); /* Change working directory to 'dir'. modify static global variable, cwd, to keep track of current working directory */ static void changeDir (char *dir) { char str[512]; int i,j; if (!strcmp (dir, "./")) return; if (!strcmp (dir, "../")) { for(i=0, j=0; cwd[i]; i++) if (cwd[i] == '/') j++; if( j == 1 ) strcpy (str, "/"); else { char *c; c = rindex (cwd, '/'); *c = '\0'; strcpy (str, cwd); } } else { if (!strcmp (cwd, "/")) cwd[0] = '\0'; sprintf (str, "%s/%s", cwd, dir); str[strlen (str) - 1]='\0'; } strcpy(cwd, str); } /* Determines if a directory entry should appear in the file list. The files included in the menu are: .. and directories files not having a .c .h .o .dvi suffix */ static int InList (const struct dirent *directory_entry) { char pathname[512]; struct stat statbuf; struct dirent *entry = (struct dirent *) directory_entry; if (entry->d_name[0] == '.' && entry->d_name[1] != '.') return False; /* ignore hidden files */ if (strcmp (cwd, "")) /* give full path name */ sprintf (pathname, "%s/%s", cwd, entry->d_name); else strcpy (pathname, entry->d_name); if (stat (pathname, &statbuf) == -1) return False; if (statbuf.st_mode & S_IFDIR) { /* is directory */ strcat(entry->d_name, "/"); ++(entry->d_reclen); return True; } if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".dvi") + 1, ".dvi") == 0) return False; else if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".c") + 1, ".c") == 0) return False; else if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".o") + 1, ".o") == 0) return False; else if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".h") + 1, ".h") == 0) return False; else if (*(entry)->d_name == '.') return False; /* hidden file */ else { ++(entry->d_reclen); return True; } return False; } /* Scans the working directory for files selected by InList (), sorted alphabetically, and stored in an array of pointers to directory entries called namelist. The names of the selected files are stored in filelist. */ static void ScanDir (char *dir) { extern int alphasort(); struct dirent **name; int i,j; file_count = scandir (dir, &name, InList, alphasort); if (file_count == -1) { fprintf (stderr,"scandir: cannot open %s", dir); return; } if (filelist) { for (i=0; filelist[i]; i++) XtFree((char *)filelist[i]); XtFree((char *)filelist); } filelist = (char **) XtMalloc((file_count+1) * sizeof(char *)); for (j=0; jd_name); XtFree((char *)name[j]); } filelist[j] = NULL; XtFree((char *)name); return; } /* Callback for the list widget: select a directory, display contents select a readable file, try load it */ static void DisplayMenuFile (Widget w, Widget popupshell, XawListReturnStruct *call_data) { char *filename, path_and_filename[MAXPATHLEN]; XtPopdown (popupshell); filename = call_data->string; if (filename == NULL) return; if (filename[ strlen (filename) - 1] == '/') { changeDir (filename); XtDestroyWidget (popupshell); CreateFilePopup (cwd); /* create new list */ File (); /* pop it up */ } else { char *v[2], *flag = "m"; sprintf(path_and_filename,"%s/%s", cwd, filename); v[0] = flag; v[1] = path_and_filename; load (0L, 0L, v, 0); } } static void PopdownPopup(Widget w, XtPointer calldata, XtPointer clientdata) { XtPopdown (popupshell); } /* Creates a popup shell with its child being a vpane widget containing * a file menu label, a file menu containing file names returned from * ScanDir(), and a cancel command button. * When an item in the list is selected, DisplayMenuFile is called. */ static void CreateFilePopup(char *dir) { Widget toplevel = Player[0].X11Set.toplevel; Widget cancel; Arg args[1]; popupshell = XtCreatePopupShell ("Select File", transientShellWidgetClass, toplevel, NULL, 0); popup_pane = XtCreateManagedWidget ("popup_pane", panedWidgetClass, popupshell, NULL, 0); ScanDir (dir); strcpy (file_listDir, dir); path_label = XtCreateManagedWidget (dir, labelWidgetClass, popup_pane, NULL, 0); XtSetArg (args[0], XtNlist, filelist); file_list = XtCreateManagedWidget ("file_list", listWidgetClass, popup_pane, args, 1); XtAddCallback(file_list, XtNcallback, (XtCallbackProc) DisplayMenuFile, popupshell); XtSetArg (args[0], XtNresize, False); cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, popup_pane, args, 1); XtAddCallback(cancel, XtNcallback, PopdownPopup, popupshell); } /* called by MenuSelect (xgammon.c) */ void File(void) { Widget text_display = Player[0].X11Set.text_display; Arg args[2]; Position x, y, offset; Dimension width, path_width, border_width, text_display_width; static int have_cwd = 0; if (!have_cwd) { getcwd ((char *) cwd, MAXPATHLEN); have_cwd = 1; } CreateFilePopup (cwd); XtSetArg (args[0], XtNwidth, &width); XtSetArg (args[1], XtNborderWidth, &border_width); XtGetValues (file_list, args, 2); XtSetArg (args[0], XtNwidth, &path_width); XtGetValues (path_label, args, 1); XtSetArg (args[0], XtNwidth, &text_display_width); XtGetValues (text_display, args, 1); if (path_width > width) width = path_width; offset = (Position) (text_display_width - width - border_width); XtTranslateCoords (text_display, offset, 0, &x, &y); x = (0 > x) ? 0 : x; y = (0 > y) ? 0 : y; XtSetArg (args[0], XtNx, x); XtSetArg (args[1], XtNy, y); XtSetValues (popupshell, args, 2); XtPopup (popupshell, XtGrabNonexclusive); } void CreateSaveDialog(void) { Widget toplevel = Player[0].X11Set.toplevel; Arg args[3]; Position x, y; XtSetArg (args[0], XtNx, &x); XtSetArg (args[1], XtNy, &y); XtGetValues (Player[turn-1].X11Set.button_shell, args, 2); XtSetArg (args[0], XtNx, x+50); /* pure arbitrary */ XtSetArg (args[1], XtNy, y+40); popupshell = XtCreatePopupShell ("XGammon-Save", transientShellWidgetClass, toplevel, args, 2); popup_form = XtCreateManagedWidget ("popup_form", formWidgetClass, popupshell, NULL, 0); XtSetArg (args[0], XtNlabel, "save as:"); XtSetArg (args[1], XtNvalue, ""); dialog = XtCreateManagedWidget ("dialog", dialogWidgetClass, popup_form, args, 2); XawDialogAddButton(dialog, "save", save_file, (XtPointer) dialog); XawDialogAddButton(dialog, "don't", PopdownPopup, NULL); XtPopup (popupshell, XtGrabExclusive); } void save_file (Widget w, XtPointer calldata, XtPointer clientdata) { char *v[2], *flag = "m"; v[0] = flag; v[1] = XawDialogGetValueString(dialog); XtPopdown (popupshell); if (!strlen (v[1])) return; else save (0L, 0L, v, 0); }