1 //
2 // GOATTRACKER v2 file selector
3 //
4
5 #define GFILE_C
6
7 #ifdef __WIN32__
8 #include <windows.h>
9 #endif
10
11 #include "goattrk2.h"
12
13 DIRENTRY direntry[MAX_DIRFILES];
14
initpaths(void)15 void initpaths(void)
16 {
17 int c;
18
19 for (c = 0; c < MAX_DIRFILES; c++)
20 direntry[c].name = NULL;
21
22 memset(loadedsongfilename, 0, sizeof loadedsongfilename);
23 memset(songfilename, 0, sizeof songfilename);
24 memset(instrfilename, 0, sizeof instrfilename);
25 memset(songpath, 0, sizeof songpath);
26 memset(instrpath, 0, sizeof instrpath);
27 memset(packedpath, 0, sizeof packedpath);
28 strcpy(songfilter, "*.sng");
29 strcpy(instrfilter, "*.ins");
30
31 getcwd(songpath, MAX_PATHNAME);
32 strcpy(instrpath, songpath);
33 strcpy(packedpath, songpath);
34 }
35
fileselector(char * name,char * path,char * filter,char * title,int filemode)36 int fileselector(char *name, char *path, char *filter, char *title, int filemode)
37 {
38 int c, d, scrrep;
39 int color;
40 int files;
41 int filepos = 0;
42 int fileview = 0;
43 int lastclick = 0;
44 int lastfile = 0;
45 int lowest;
46 int exitfilesel;
47
48 DIR *dir;
49 struct dirent *de;
50 struct stat st;
51 #ifdef __WIN32__
52 char drivestr[] = "A:\\";
53 char driveexists[26];
54 #endif
55 char cmpbuf[MAX_PATHNAME];
56 char tempname[MAX_PATHNAME];
57
58 // Set initial path (if any)
59 if (strlen(path)) chdir(path);
60
61 // Scan for all existing drives
62 #ifdef __WIN32__
63 for (c = 0; c < 26; c++)
64 {
65 drivestr[0] = 'A'+c;
66 if (GetDriveType(drivestr) > 1) driveexists[c] = 1;
67 else driveexists[c] = 0;
68 }
69 #endif
70
71 // Read new directory
72 NEWPATH:
73 getcwd(path, MAX_PATHNAME);
74 files = 0;
75 // Deallocate old names
76 for (c = 0; c < MAX_DIRFILES; c++)
77 {
78 if (direntry[c].name)
79 {
80 free(direntry[c].name);
81 direntry[c].name = NULL;
82 }
83 }
84 #ifdef __WIN32__
85 // Create drive letters
86 for (c = 0; c < 26; c++)
87 {
88 if (driveexists[c])
89 {
90 drivestr[0] = 'A'+c;
91 direntry[files].name = strdup(drivestr);
92 direntry[files].attribute = 2;
93 files++;
94 }
95 }
96 #endif
97
98 // Process directory
99 #ifdef __amigaos__
100 dir = opendir("");
101 #else
102 dir = opendir(".");
103 #endif
104 if (dir)
105 {
106 char *filtptr = strstr(filter, "*");
107 if (!filtptr) filtptr = filter;
108 else filtptr++;
109 for (c = 0; c < strlen(filter); c++)
110 filter[c] = tolower(filter[c]);
111
112 while ((de = readdir(dir)))
113 {
114 if ((files < MAX_DIRFILES) && (strlen(de->d_name) < MAX_FILENAME))
115 {
116 direntry[files].name = strdup(de->d_name);
117 direntry[files].attribute = 0;
118 stat(de->d_name, &st);
119 if (st.st_mode & S_IFDIR)
120 {
121 direntry[files].attribute = 1;
122 files++;
123 }
124 else
125 {
126 int c;
127 // If a file, must match filter
128 strcpy(cmpbuf, de->d_name);
129 if ((!strcmp(filtptr, "*")) || (!strcmp(filtptr, ".*")))
130 files++;
131 else
132 {
133 for (c = 0; c < strlen(cmpbuf); c++)
134 cmpbuf[c] = tolower(cmpbuf[c]);
135 if (strstr(cmpbuf, filtptr))
136 files++;
137 else
138 {
139 free(direntry[files].name);
140 direntry[files].name = NULL;
141 }
142 }
143 }
144 }
145 }
146 closedir(dir);
147 }
148 // Sort the filelist in a most horrible fashion
149 for (c = 0; c < files; c++)
150 {
151 lowest = c;
152 for (d = c+1; d < files; d++)
153 {
154 if (direntry[d].attribute < direntry[lowest].attribute)
155 {
156 lowest = d;
157 }
158 else
159 {
160 if (direntry[d].attribute == direntry[lowest].attribute)
161 {
162 if (cmpname(direntry[d].name, direntry[lowest].name) < 0)
163 {
164 lowest = d;
165 }
166 }
167 }
168 }
169 if (lowest != c)
170 {
171 DIRENTRY swaptemp = direntry[c];
172 direntry[c] = direntry[lowest];
173 direntry[lowest] = swaptemp;
174 }
175 }
176
177 // Search for the current filename
178 fileview = 0;
179 filepos = 0;
180 for (c = 0; c < files; c++)
181 {
182 if ((!direntry[c].attribute) && (!cmpname(name, direntry[c].name)))
183 {
184 filepos = c;
185 }
186 }
187
188 exitfilesel = -1;
189 while (exitfilesel < 0)
190 {
191 int cc = cursorcolortable[cursorflash];
192 if (cursorflashdelay >= 6)
193 {
194 cursorflashdelay %= 6;
195 cursorflash++;
196 cursorflash &= 3;
197 }
198 fliptoscreen();
199 getkey();
200 if (lastclick) lastclick--;
201
202 if (win_quitted)
203 {
204 exitprogram = 1;
205 for (c = 0; c < MAX_DIRFILES; c++)
206 {
207 if (direntry[c].name)
208 {
209 free(direntry[c].name);
210 direntry[c].name = NULL;
211 }
212 }
213 return 0;
214 }
215
216 if (mouseb)
217 {
218 // Cancel (click outside)
219 if ((mousey < 3) || (mousey > 3+VISIBLEFILES+6) || (mousex <= 4+10) || (mousex >= 75+10))
220 {
221 if ((!prevmouseb) && (lastclick)) exitfilesel = 0;
222 }
223
224 // Select dir,name,filter
225 if ((mousey >= 3+VISIBLEFILES+3) && (mousey <= 3+VISIBLEFILES+5) && (mousex >= 14+10) && (mousex <= 73+10))
226 {
227 filemode = mousey - (3+VISIBLEFILES+3) + 1;
228 if ((filemode == 3) && (!prevmouseb) && (lastclick)) goto ENTERFILE;
229 }
230
231 // Select file from list
232 if ((mousey >= 3) && (mousey <= 3+VISIBLEFILES+2) && (mousex >= 6+10) && (mousex <= 73+10))
233 {
234 filemode = 0;
235 filepos = mousey - 4 - 1 + fileview;
236 if (filepos < 0) filepos = 0;
237 if (filepos > files-1) filepos = files - 1;
238
239 if (!direntry[filepos].attribute)
240 strcpy(name, direntry[filepos].name);
241
242 if ((!prevmouseb) && (lastclick) && (lastfile == filepos)) goto ENTERFILE;
243 }
244 }
245
246 if (!filemode)
247 {
248 if (((key >= '0') && (key <= '0')) || ((key >= 'a') && (key <= 'z')) || ((key >= 'A') && (key <= 'Z')))
249 {
250 char k = tolower(key);
251 int oldfilepos = filepos;
252
253 for (filepos = oldfilepos + 1; filepos < files; filepos++)
254 if (tolower(direntry[filepos].name[0]) == k) break;
255 if (filepos >= files)
256 {
257 for (filepos = 0; filepos < oldfilepos; filepos++)
258 if (tolower(direntry[filepos].name[0]) == k) break;
259 }
260
261 if (!direntry[filepos].attribute) strcpy(name, direntry[filepos].name);
262 }
263 }
264
265 switch(rawkey)
266 {
267 case KEY_ESC:
268 exitfilesel = 0;
269 break;
270
271 case KEY_BACKSPACE:
272 if (!filemode)
273 {
274 #ifdef __amigaos__
275 chdir("/");
276 #else
277 chdir("..");
278 #endif
279 goto NEWPATH;
280 }
281 break;
282
283 case KEY_HOME:
284 if (!filemode)
285 {
286 filepos = 0;
287 if (!direntry[filepos].attribute) strcpy(name, direntry[filepos].name);
288 }
289 break;
290
291 case KEY_END:
292 if (!filemode)
293 {
294 filepos = files-1;
295 if (!direntry[filepos].attribute) strcpy(name, direntry[filepos].name);
296 }
297 break;
298
299 case KEY_PGUP:
300 for (scrrep = PGUPDNREPEAT; scrrep; scrrep--)
301 {
302 if ((!filemode) && (filepos > 0))
303 {
304 filepos--;
305 if (!direntry[filepos].attribute) strcpy(name, direntry[filepos].name);
306 }
307 }
308 break;
309
310 case KEY_UP:
311 if ((!filemode) && (filepos > 0))
312 {
313 filepos--;
314 if (!direntry[filepos].attribute) strcpy(name, direntry[filepos].name);
315 }
316 break;
317
318 case KEY_PGDN:
319 for (scrrep = PGUPDNREPEAT; scrrep; scrrep--)
320 {
321 if ((!filemode) && (filepos < files-1))
322 {
323 filepos++;
324 if (!direntry[filepos].attribute) strcpy(name, direntry[filepos].name);
325 }
326 }
327 break;
328
329 case KEY_DOWN:
330 if ((!filemode) && (filepos < files-1))
331 {
332 filepos++;
333 if (!direntry[filepos].attribute) strcpy(name, direntry[filepos].name);
334 }
335 break;
336
337 case KEY_TAB:
338 if (!shiftpressed)
339 {
340 filemode++;
341 if (filemode > 3) filemode = 0;
342 }
343 else
344 {
345 filemode--;
346 if (filemode < 0) filemode = 3;
347 }
348 break;
349
350 case KEY_ENTER:
351 ENTERFILE:
352 switch(filemode)
353 {
354 case 0:
355 switch (direntry[filepos].attribute)
356 {
357 case 0:
358 strcpy(name, direntry[filepos].name);
359 exitfilesel = 1;
360 break;
361
362 case 1:
363 chdir(direntry[filepos].name);
364 goto NEWPATH;
365
366 case 2:
367 strcpy(tempname, direntry[filepos].name);
368 if (strlen(tempname))
369 {
370 if (tempname[strlen(tempname)-1] != '\\')
371 strcat(tempname, "\\");
372 }
373 chdir(tempname);
374 goto NEWPATH;
375 }
376 break;
377
378 case 1:
379 chdir(path);
380 case 2:
381 filemode = 0;
382 goto NEWPATH;
383
384 case 3:
385 exitfilesel = 1;
386 break;
387 }
388 break;
389 }
390
391 switch(filemode)
392 {
393 case 1:
394 editstring(path, MAX_PATHNAME);
395 break;
396
397 case 2:
398 editstring(filter, MAX_FILENAME);
399 break;
400
401 case 3:
402 editstring(name, MAX_FILENAME);
403 break;
404 }
405
406 // Validate filelist view
407 if (filepos < fileview) fileview = filepos;
408 if (filepos - fileview >= VISIBLEFILES) fileview = filepos - VISIBLEFILES + 1;
409
410 // Refresh fileselector display
411 if (isplaying()) printstatus();
412 for (c = 0; c < VISIBLEFILES+7; c++)
413 {
414 printblank(50-(MAX_FILENAME+10)/2, 3+c, MAX_FILENAME+10);
415 }
416 drawbox(50-(MAX_FILENAME+10)/2, 3, 15, MAX_FILENAME+10, VISIBLEFILES+7);
417 printblankc(50-(MAX_FILENAME+10)/2+1, 4, 15+16,MAX_FILENAME+8);
418 printtext(50-(MAX_FILENAME+10)/2+1, 4, 15+16, title);
419
420 for (c = 0; c < VISIBLEFILES; c++)
421 {
422 if ((fileview+c >= 0) && (fileview+c < files))
423 {
424 switch (direntry[fileview+c].attribute)
425 {
426 case 0:
427 sprintf(textbuffer, "%-60s ", direntry[fileview+c].name);
428 break;
429
430 case 1:
431 sprintf(textbuffer, "%-60s <DIR>", direntry[fileview+c].name);
432 break;
433
434 case 2:
435 sprintf(textbuffer, "%-60s <DRV>", direntry[fileview+c].name);
436 break;
437 }
438 }
439 else
440 {
441 sprintf(textbuffer, " ");
442 }
443 color = CNORMAL;
444 if ((fileview+c) == filepos) color = CEDIT;
445 textbuffer[68] = 0;
446 printtext(50-(MAX_FILENAME+10)/2+1, 5+c, color, textbuffer);
447 if ((!filemode) && ((fileview+c) == filepos)) printbg(50-(MAX_FILENAME+10)/2+1, 5+c, cc, 68);
448 }
449
450 printtext(50-(MAX_FILENAME+10)/2+1, 6+VISIBLEFILES, 15, "PATH: ");
451 sprintf(textbuffer, "%-60s", path);
452 textbuffer[MAX_FILENAME] = 0;
453 color = CNORMAL;
454 if (filemode == 1) color = CEDIT;
455 printtext(50-(MAX_FILENAME+10)/2+9, 6+VISIBLEFILES, color, textbuffer);
456 if ((filemode == 1) && (strlen(path) < MAX_FILENAME)) printbg(50-(MAX_FILENAME+10)/2+9+strlen(path), 6+VISIBLEFILES, cc, 1);
457
458 printtext(50-(MAX_FILENAME+10)/2+1, 7+VISIBLEFILES, 15, "FILTER: ");
459 sprintf(textbuffer, "%-60s", filter);
460 textbuffer[MAX_FILENAME] = 0;
461 color = CNORMAL;
462 if (filemode == 2) color = CEDIT;
463 printtext(50-(MAX_FILENAME+10)/2+9, 7+VISIBLEFILES, color, textbuffer);
464 if (filemode == 2) printbg(50-(MAX_FILENAME+10)/2+9+strlen(filter), 7+VISIBLEFILES, cc, 1);
465
466 printtext(50-(MAX_FILENAME+10)/2+1, 8+VISIBLEFILES, 15, "NAME: ");
467 sprintf(textbuffer, "%-60s", name);
468 textbuffer[MAX_FILENAME] = 0;
469 color = CNORMAL;
470 if (filemode == 3) color = CEDIT;
471 printtext(50-(MAX_FILENAME+10)/2+9, 8+VISIBLEFILES, color, textbuffer);
472 if (filemode == 3) printbg(50-(MAX_FILENAME+10)/2+9+strlen(name), 8+VISIBLEFILES, cc, 1);
473
474 if (win_quitted) exitfilesel = 0;
475
476 if ((mouseb) && (!prevmouseb))
477 {
478 lastclick = DOUBLECLICKDELAY;
479 lastfile = filepos;
480 }
481 }
482
483 // Deallocate all used names
484 for (c = 0; c < MAX_DIRFILES; c++)
485 {
486 if (direntry[c].name)
487 {
488 free(direntry[c].name);
489 direntry[c].name = NULL;
490 }
491 }
492
493 // Restore screen & exit
494 printmainscreen();
495 return exitfilesel;
496 }
497
editstring(char * buffer,int maxlength)498 void editstring(char *buffer, int maxlength)
499 {
500 int len = strlen(buffer);
501
502 if (key)
503 {
504 if ((key >= 32) && (key < 256))
505 {
506 if (len < maxlength-1)
507 {
508 buffer[len] = key;
509 buffer[len+1] = 0;
510 }
511 }
512 if ((key == 8) && (len > 0))
513 {
514 buffer[len-1] = 0;
515 }
516 }
517 }
518
cmpname(char * string1,char * string2)519 int cmpname(char *string1, char *string2)
520 {
521 for (;;)
522 {
523 unsigned char char1 = tolower(*string1++);
524 unsigned char char2 = tolower(*string2++);
525 if (char1 < char2) return -1;
526 if (char1 > char2) return 1;
527 if ((!char1) || (!char2)) return 0;
528 }
529 }
530
531