ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/dlgFileSelect.cpp
Revision: 1.2
Committed: 2007-03-28T06:54:42Z (15 years, 8 months ago) by berlac
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +4 -4 lines
Log Message:
Minor code clean up.

File Contents

# Content
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 screenlock();
212 oldcursorstate = SDL_ShowCursor(SDL_QUERY);
213 if (oldcursorstate == SDL_DISABLE)
214 SDL_ShowCursor(SDL_ENABLE);
215 screenunlock();
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 screenlock();
393 if (oldcursorstate == SDL_DISABLE)
394 SDL_ShowCursor(SDL_DISABLE);
395 screenunlock();
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 */