ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/dlgFileSelect.cpp
Revision: 1.1
Committed: 2007-01-28T18:50:22Z (16 years ago) by berlac
Branch: MAIN
Log Message:
Initial revision.

File Contents

# User Rev Content
1 berlac 1.1 /*
2     * dlgFileselect.cpp - dialog for selecting files (fileselector box)
3     *
4     * This file is taken from the ARAnyM project which builds a new and powerful
5     * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
6     *
7     * Originally taken from the hatari project, thanks Thothy!
8     *
9     * Copyright (c) 2003-2005 ARAnyM dev team (see AUTHORS)
10     *
11     * Frodo is free software; you can redistribute it and/or modify
12     * it under the terms of the GNU General Public License as published by
13     * the Free Software Foundation; either version 2 of the License, or
14     * (at your option) any later version.
15     *
16     * Frodo is distributed in the hope that it will be useful,
17     * but WITHOUT ANY WARRANTY; without even the implied warranty of
18     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19     * GNU General Public License for more details.
20     *
21     * You should have received a copy of the GNU General Public License
22     * along with Frodo; if not, write to the Free Software
23     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24     */
25    
26     #include <SDL.h>
27     #include <sys/stat.h>
28     #include <unistd.h>
29     #include <stdlib.h>
30     #include <string.h>
31     #include <dirent.h>
32    
33     #include <debug.h>
34    
35     #include "sdlgui.h"
36     #include "file.h"
37    
38     #define SGFSDLG_FILENAME 5
39     #define SGFSDLG_UPDIR 6
40     #define SGFSDLG_ROOTDIR 7
41     #define SGFSDLG_FIRSTENTRY 10
42     #define SGFSDLG_LASTENTRY 24
43     #define SGFSDLG_UP 25
44     #define SGFSDLG_DOWN 26
45     #define SGFSDLG_OKAY 27
46     #define SGFSDLG_CANCEL 28
47    
48     #define ENTRY_COUNT (SGFSDLG_LASTENTRY - SGFSDLG_FIRSTENTRY + 1)
49     #define ENTRY_LENGTH 30
50    
51    
52     static char dlgpath[39], dlgfname[33]; /* File and path name in the dialog */
53     static char dlgfilenames[ENTRY_COUNT][ENTRY_LENGTH + 1];
54    
55     /* The dialog data: */
56     static SGOBJ fsdlg[] = {
57     {SGBOX, SG_BACKGROUND, 0, 0, 0, 35, 25, NULL},
58     {SGTEXT, 0, 0, 10, 1, 13, 1, "Choose a file"},
59     {SGTEXT, 0, 0, 1, 2, 7, 1, "Folder:"},
60     {SGTEXT, 0, 0, 1, 3, 33, 1, dlgpath},
61     {SGTEXT, 0, 0, 1, 4, 6, 1, "File:"},
62     {SGTEXT, 0, 0, 7, 4, 26, 1, dlgfname},
63     {SGBUTTON, SG_SELECTABLE | SG_EXIT, 0, 26, 1, 4, 1, ".."},
64     {SGBUTTON, SG_SELECTABLE | SG_EXIT, 0, 31, 1, 3, 1, "/"},
65     {SGBOX, 0, 0, 1, 6, 33, 15, NULL},
66     {SGBOX, 0, 0, 33, 6, 1, 15, NULL},
67     {SGTEXT, 0, 0, 2, 6, ENTRY_LENGTH, 1, dlgfilenames[0]},
68     {SGTEXT, 0, 0, 2, 7, ENTRY_LENGTH, 1, dlgfilenames[1]},
69     {SGTEXT, 0, 0, 2, 8, ENTRY_LENGTH, 1, dlgfilenames[2]},
70     {SGTEXT, 0, 0, 2, 9, ENTRY_LENGTH, 1, dlgfilenames[3]},
71     {SGTEXT, 0, 0, 2, 10, ENTRY_LENGTH, 1, dlgfilenames[4]},
72     {SGTEXT, 0, 0, 2, 11, ENTRY_LENGTH, 1, dlgfilenames[5]},
73     {SGTEXT, 0, 0, 2, 12, ENTRY_LENGTH, 1, dlgfilenames[6]},
74     {SGTEXT, 0, 0, 2, 13, ENTRY_LENGTH, 1, dlgfilenames[7]},
75     {SGTEXT, 0, 0, 2, 14, ENTRY_LENGTH, 1, dlgfilenames[8]},
76     {SGTEXT, 0, 0, 2, 15, ENTRY_LENGTH, 1, dlgfilenames[9]},
77     {SGTEXT, 0, 0, 2, 16, ENTRY_LENGTH, 1, dlgfilenames[10]},
78     {SGTEXT, 0, 0, 2, 17, ENTRY_LENGTH, 1, dlgfilenames[11]},
79     {SGTEXT, 0, 0, 2, 18, ENTRY_LENGTH, 1, dlgfilenames[12]},
80     {SGTEXT, 0, 0, 2, 19, ENTRY_LENGTH, 1, dlgfilenames[13]},
81     {SGTEXT, 0, 0, 2, 20, ENTRY_LENGTH, 1, dlgfilenames[14]},
82     {SGBUTTON, SG_SELECTABLE | SG_TOUCHEXIT, 0, 33, 6, 1, 1, "\x01"},
83     /* Arrow up */
84     {SGBUTTON, SG_SELECTABLE | SG_TOUCHEXIT, 0, 33, 20, 1, 1, "\x02"},
85     /* Arrow down */
86     {SGBUTTON, SG_SELECTABLE | SG_EXIT | SG_DEFAULT, 0, 7, 23, 8, 1,
87     "OK"},
88     {SGBUTTON, SG_SELECTABLE | SG_EXIT, 0, 21, 23, 8, 1, "Cancel"},
89     {-1, 0, 0, 0, 0, 0, 0, NULL}
90     };
91    
92     struct listentry {
93     char *filename;
94     bool directory;
95     struct listentry *next;
96     };
97    
98     /* Create a sorted list from the directory listing of path */
99     struct listentry *create_list(char *path)
100     {
101     struct listentry *list = NULL;
102     struct listentry *newentry;
103     DIR *dd;
104     struct dirent *direntry;
105     char tempstr[MAX_FILENAME_LENGTH];
106     struct stat filestat;
107    
108     if ((dd = opendir(path)) == NULL)
109     return NULL;
110    
111     while ((direntry = readdir(dd)) != NULL) {
112     // skip "." name
113     if (strcmp(direntry->d_name, ".") == 0)
114     continue;
115    
116     /* Allocate enough memory to store a new list entry and
117     its filemane */
118     newentry =
119     (struct listentry *) malloc(sizeof(struct listentry) +
120     strlen(direntry->d_name) + 1);
121    
122     /* Store filename */
123     newentry->filename = (char *) (newentry + 1);
124     strcpy(newentry->filename, direntry->d_name);
125    
126     /* Is this entry a directory ? */
127     strcpy(tempstr, path);
128     strcat(tempstr, newentry->filename);
129     if (stat(tempstr, &filestat) == 0 && S_ISDIR(filestat.st_mode))
130     newentry->directory = true;
131     else
132     newentry->directory = false;
133    
134     /* Search for right place to insert new entry */
135     struct listentry **prev = &list;
136     struct listentry *next = list;
137     while (next != NULL) {
138     /* directory first, then files */
139     if ((newentry->directory == true)
140     && (next->directory == false))
141     break;
142    
143     /* Sort by name */
144     if ((newentry->directory == next->directory)
145     && (strcmp(newentry->filename, next->filename) < 0))
146     break;
147    
148     prev = &(next->next);
149     next = next->next;
150     }
151    
152     /* Insert new entry */
153     newentry->next = next;
154     *prev = newentry;
155     }
156    
157     if (closedir(dd) != 0)
158     bug("Error on closedir.");
159    
160     return list;
161     }
162    
163     /* Free memory allocated for each member of list */
164     void free_list(struct listentry *list)
165     {
166     while (list != NULL) {
167     struct listentry *temp = list;
168     list = list->next;
169     free(temp);
170     }
171     }
172    
173     /*-----------------------------------------------------------------------*/
174     /*
175     Show and process a file selection dialog.
176     Returns TRUE if user selected "OK", FALSE if "cancel".
177     bAllowNew: TRUE if the user is allowed to insert new file names.
178     */
179     int SDLGui_FileSelect(char *path_and_name, bool bAllowNew)
180     {
181     int i;
182     int ypos = 0;
183     struct listentry *list = NULL;
184     /* The actual file and path names */
185     char path[MAX_FILENAME_LENGTH], fname[128];
186     /* Do we have to reload the directory file list? */
187     bool reloaddir = true;
188     /* Do we have to update the file names in the dialog? */
189     bool refreshentries = true;
190     int retbut;
191     int oldcursorstate;
192     /* The actual selection, -1 if none selected */
193     int selection = -1;
194     bool eol = true;
195    
196     if (bAllowNew)
197     fsdlg[SGFSDLG_FILENAME].type = SGEDITFIELD;
198     else
199     fsdlg[SGFSDLG_FILENAME].type = SGTEXT;
200    
201     /* Prepare the path and filename variables */
202     File_splitpath(path_and_name, path, fname, NULL);
203     if (strlen(path) == 0) {
204     getcwd(path, sizeof(path));
205     File_AddSlashToEndFileName(path);
206     }
207     File_ShrinkName(dlgpath, path, 38);
208     File_ShrinkName(dlgfname, fname, 32);
209    
210     /* Save old mouse cursor state and enable cursor anyway */
211     SCRLOCK;
212     oldcursorstate = SDL_ShowCursor(SDL_QUERY);
213     if (oldcursorstate == SDL_DISABLE)
214     SDL_ShowCursor(SDL_ENABLE);
215     SCRUNLOCK;
216    
217     do {
218     if (reloaddir) {
219     if (strlen(path) >= MAX_FILENAME_LENGTH) {
220     fprintf(stderr,
221     "SDLGui_FileSelect: Path name too long!\n");
222     return false;
223     }
224    
225     free_list(list);
226    
227     /* Load directory entries: */
228     list = create_list(path);
229     if (list == NULL) {
230     fprintf(stderr, "SDLGui_FileSelect: Path not found.\n");
231     /* reset path and reload entries */
232     strcpy(path, "/");
233     strcpy(dlgpath, path);
234     list = create_list(path);
235     if (list == NULL)
236     /* we're really lost if even root is
237     unreadable */
238     return false;
239     }
240     reloaddir = false;
241     refreshentries = true;
242     }
243    
244     if (refreshentries) {
245     struct listentry *temp = list;
246     for (i = 0; i < ypos; i++)
247     temp = temp->next;
248    
249     /* Copy entries to dialog: */
250     for (i = 0; i < ENTRY_COUNT; i++) {
251     if (temp != NULL) {
252     char tempstr[MAX_FILENAME_LENGTH];
253     /* Prepare entries: */
254     strcpy(tempstr, " ");
255     strcat(tempstr, temp->filename);
256     File_ShrinkName(dlgfilenames[i], tempstr,
257     ENTRY_LENGTH);
258     /* Mark folders: */
259     if (temp->directory)
260     dlgfilenames[i][0] = SGFOLDER;
261     fsdlg[SGFSDLG_FIRSTENTRY + i].flags =
262     (SG_SELECTABLE | SG_EXIT | SG_RADIO);
263     temp = temp->next;
264     }
265     else {
266     /* Clear entry */
267     dlgfilenames[i][0] = 0;
268     fsdlg[SGFSDLG_FIRSTENTRY + i].flags = 0;
269     }
270     fsdlg[SGFSDLG_FIRSTENTRY + i].state = 0;
271     }
272    
273     if (temp == NULL)
274     eol = true;
275     else
276     eol = false;
277    
278     refreshentries = false;
279     }
280    
281     /* Show dialog: */
282     retbut = SDLGui_DoDialog(fsdlg);
283    
284     /* Has the user clicked on a file or folder? */
285     if ((retbut >= SGFSDLG_FIRSTENTRY)
286     && (retbut <= SGFSDLG_LASTENTRY)) {
287     char tempstr[MAX_FILENAME_LENGTH];
288     struct stat filestat;
289     struct listentry *temp = list;
290    
291     strcpy(tempstr, path);
292     for (int i = 0; i < ((retbut - SGFSDLG_FIRSTENTRY) + ypos);
293     i++)
294     temp = temp->next;
295     strcat(tempstr, temp->filename);
296     if (stat(tempstr, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
297     /* Set the new directory */
298     strcpy(path, tempstr);
299     if (strlen(path) >= 3) {
300     if ((path[strlen(path) - 2] == '/')
301     && (path[strlen(path) - 1] == '.'))
302     /* Strip a single dot at the
303     end of the path name */
304     path[strlen(path) - 2] = 0;
305     if ((path[strlen(path) - 3] == '/')
306     && (path[strlen(path) - 2] == '.')
307     && (path[strlen(path) - 1] == '.')) {
308     /* Handle the ".." folder */
309     char *ptr;
310     if (strlen(path) == 3)
311     path[1] = 0;
312     else {
313     path[strlen(path) - 3] = 0;
314     ptr = strrchr(path, '/');
315     if (ptr)
316     *(ptr + 1) = 0;
317     }
318     }
319     }
320     File_AddSlashToEndFileName(path);
321     reloaddir = true;
322     /* Copy the path name to the dialog */
323     File_ShrinkName(dlgpath, path, 38);
324     selection = -1; /* Remove old selection */
325     // fname[0] = 0;
326     dlgfname[0] = 0;
327     ypos = 0;
328     }
329     else {
330     /* Select a file */
331     selection = retbut - SGFSDLG_FIRSTENTRY + ypos;
332     strcpy(fname, temp->filename);
333     File_ShrinkName(dlgfname, fname, 32);
334     }
335     }
336     else {
337     /* Has the user clicked on another button? */
338     switch (retbut) {
339     case SGFSDLG_UPDIR:
340     /* Change path to parent directory */
341     if (strlen(path) > 2) {
342     char *ptr;
343     File_CleanFileName(path);
344     ptr = strrchr(path, '/');
345     if (ptr)
346     *(ptr + 1) = 0;
347     File_AddSlashToEndFileName(path);
348     reloaddir = true;
349     /* Copy the path name to the dialog */
350     File_ShrinkName(dlgpath, path, 38);
351     /* Remove old selection */
352     selection = -1;
353     fname[0] = 0;
354     dlgfname[0] = 0;
355     ypos = 0;
356     }
357     break;
358     case SGFSDLG_ROOTDIR:
359     /* Change to root directory */
360     strcpy(path, "/");
361     reloaddir = true;
362     strcpy(dlgpath, path);
363     /* Remove old selection */
364     selection = -1;
365     fname[0] = 0;
366     dlgfname[0] = 0;
367     ypos = 0;
368     break;
369     case SGFSDLG_UP:
370     /* Scroll up */
371     if (ypos > 0) {
372     --ypos;
373     refreshentries = true;
374     }
375     SDL_Delay(20);
376     break;
377     case SGFSDLG_DOWN:
378     /* Scroll down */
379     if (eol == false) {
380     ++ypos;
381     refreshentries = true;
382     }
383     SDL_Delay(20);
384     break;
385     } /* switch */
386     } /* other button code */
387    
388     }
389     while ((retbut != SGFSDLG_OKAY) && (retbut != SGFSDLG_CANCEL)
390     && (retbut != -1));
391    
392     SCRLOCK;
393     if (oldcursorstate == SDL_DISABLE)
394     SDL_ShowCursor(SDL_DISABLE);
395     SCRUNLOCK;
396    
397     {
398     /* if user edited filename, use new one */
399     char dlgfname2[33];
400     File_ShrinkName(dlgfname2, fname, 32);
401     if (strcmp(dlgfname, dlgfname2) != 0)
402     strcpy(fname, dlgfname);
403     }
404    
405     File_makepath(path_and_name, path, fname, NULL);
406    
407     free_list(list);
408    
409     return (retbut == SGFSDLG_OKAY);
410     }
411    
412     /*
413     vim:ts=4:sw=4:
414     */