89b8b6e4273a37fedf23f9458aad0e70006ff38d
[sdk] / ecere / src / gui / dialogs / FileDialog.ec
1 namespace gui::dialogs;
2
3 #ifdef __WIN32__
4 static char * rootName = "Entire Computer";
5 static char * msNetwork = "Microsoft Windows Network";
6 #endif
7
8 import "Window"
9
10 #define IS_ALUNDER(ch) ((ch) == '_' || isalnum((ch)))
11
12 default:
13 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
14 private:
15
16 static char * iconNames[] = 
17 {
18    "<:ecere>places/folder.png",
19    "<:ecere>status/folderOpen.png",
20    "<:ecere>devices/computer.png",
21    "<:ecere>devices/driveHardDisk.png",
22    "<:ecere>places/driveRemote.png",
23    "<:ecere>devices/mediaOptical.png",
24    "<:ecere>devices/driveRemovableMedia.png",
25    "<:ecere>devices/mediaFloppy.png",
26    "<:ecere>places/networkWorkgroup.png",
27    "<:ecere>places/networkServer.png",
28    "<:ecere>places/folderRemote.png",
29
30    "<:ecere>mimeTypes/file.png",                   /*normalFile*/
31    "<:ecere>mimeTypes/textEcereWorkspace.png",     /*ewsFile*/
32    "<:ecere>mimeTypes/textEcereProject.png",       /*epjFile*/
33    "<:ecere>mimeTypes/textEcereSource.png",        /*ecFile*/
34    "<:ecere>mimeTypes/textEcereHeader.png",        /*ehFile*/
35    "<:ecere>mimeTypes/textCSource.png",            /*cFile*/
36    "<:ecere>mimeTypes/textCHeader.png",            /*hFile*/
37    "<:ecere>mimeTypes/textC++Source.png",          /*cppFile*/
38    "<:ecere>mimeTypes/textC++Header.png",          /*hppFile*/
39    "<:ecere>mimeTypes/text.png",                   /*textFile*/
40    "<:ecere>mimeTypes/textHyperTextMarkup.png",    /*webFile*/
41    "<:ecere>mimeTypes/image.png",                  /*pictureFile*/
42    "<:ecere>status/audioVolumeHigh.png",           /*soundFile*/
43    "<:ecere>mimeTypes/package.png",                /*archiveFile*/
44    "<:ecere>mimeTypes/packageSoftware.png",        /*packageFile*/
45    "<:ecere>mimeTypes/packageOpticalDisc.png"      /*opticalMediaImageFile*/
46 };
47
48 public enum FileNameType     // Had to be private, since icons member of FileDialog is also private... (Static members? Not for a while...)
49 {
50    folder, folderOpen, computer,
51    drive, netDrive, cdrom, removable, floppy, network, server, share, // these are sort equal
52
53    normalFile, ewsFile, epjFile, ecFile, ehFile, cFile, hFile, cppFile, hppFile,
54    textFile, webFile, pictureFile, soundFile,
55    archiveFile, packageFile, opticalMediaImageFile; /* these (all previous) are sort equal */
56
57    /*property char * 
58    {
59       set
60       {
61          this = SelectByExtension(value);
62       }
63    }*/
64    public property bool isFolderType
65    {
66       get { return this >= folder && this <= share; }
67    }
68
69    public property bool isFileType
70    {
71       get { return this >= normalFile && this <= opticalMediaImageFile; }
72    }
73
74    FileNameType ::SelectByExtension(char * extension)
75    {
76       if(!strcmpi(extension, "ews"))
77          return ewsFile;
78       else if(!strcmpi(extension, "epj"))
79          return epjFile;
80       else if(!strcmpi(extension, "ec"))
81          return ecFile;
82       else if(!strcmpi(extension, "eh"))
83          return ehFile;
84       else if(!strcmpi(extension, "cpp") ||
85             !strcmpi(extension, "cc") || !strcmpi(extension, "cxx"))
86          return cppFile;
87       else if(!strcmpi(extension, "hpp") ||
88             !strcmpi(extension, "hh") || !strcmpi(extension, "hxx"))
89          return hppFile;
90       else if(!strcmpi(extension, "c"))
91          return cFile;
92       else if(!strcmpi(extension, "h"))
93          return hFile;
94       else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
95             !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
96          return textFile;
97       else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
98             !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
99             !strcmpi(extension, "js"))
100          return webFile;
101       else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
102             !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
103             !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
104             !strcmpi(extension, "ico"))
105          return pictureFile;
106       else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
107             !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
108          return soundFile;
109       else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
110             !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
111             !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
112             !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
113             !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
114             !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
115          return archiveFile;
116       else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
117             !strcmpi(extension, "rpm"))
118          return packageFile;
119       else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
120             !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
121             !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
122             !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
123          return opticalMediaImageFile;
124       return normalFile;
125    }
126 };
127
128 public enum FileDialogType { open, save, selectDir, multiOpen };
129 public struct FileFilter
130 {
131    char * name, * extensions;
132
133    bool ValidateFileName(char * name)
134    {
135       if(strcmp(name, "..") && strcmp(name, ".") && strcmp(name, ""))
136       {
137          if(extensions) // && !stats.attribs.isDirectory)
138          {
139             char extension[MAX_EXTENSION], compared[MAX_EXTENSION];
140             int c;
141
142             GetExtension(name, extension);
143             for(c = 0; extensions[c];)
144             {
145                int len = 0;
146                char ch;
147                for(;(ch = extensions[c]) && !IS_ALUNDER(ch); c++);
148                for(;(ch = extensions[c]) &&  IS_ALUNDER(ch); c++)
149                   compared[len++] = ch;
150                compared[len] = '\0';
151
152                if(!strcmpi(extension, compared))
153                   return true;
154             }
155          }
156          else
157             return true;
158       }
159       return false;
160    }
161 };
162 public enum FileForceExtension { never, always, whenNoneGiven };
163 public struct FileType
164 {
165    char * name, * typeExtension; 
166    FileForceExtension forceExtension;
167 };
168
169 static enum FileDialogSelectFrom { fromEditBox, fromListBox, fromDropBox };
170
171 public struct FileName
172 {
173    char * name;
174    FileNameType type;
175    int indent;
176
177    void OnDisplay(Surface surface, int x, int y, int width, FileDialog fileDialog, Alignment alignment, DataDisplayFlags displayFlags)
178    {
179       int indentSize = (displayFlags.dropBox) ? 0 : 10;
180       int textOffset;
181
182       Bitmap icon = fileDialog.icons[type].bitmap;
183       if(!icon && type > normalFile)
184          icon = fileDialog.icons[normalFile].bitmap;
185       if(!icon)
186       {
187          if(type == folder || type == folderOpen)
188             surface.SetForeground(red); //Color { 170, 170, 0 } // REDJ What is that color?
189          indentSize = 8;
190       }
191       textOffset = indent * indentSize + (icon ? (icon.width + 4) : 0);
192       
193       surface.WriteTextDots
194          (alignment, x + textOffset, y + 2, width - textOffset, name, strlen(name));
195       if(icon)
196          surface.Blit(icon, x + indent * indentSize, y,0,0, icon.width, icon.height);
197    }
198
199    int OnCompare(FileName b)
200    {
201       int result;
202       if(type == b.type || (type >= normalFile && b.type >= normalFile) || (type >= drive && type <= share))
203          result = strcmpi(name, b.name);
204       else
205       {
206          if(type == folder && b.type >= normalFile) result = -1;
207          else if(type >= normalFile && b.type == folder) result = 1;
208       }
209       return result;
210    }
211
212    void OnCopy(FileName newData)
213    {
214       type = newData.type;
215       indent = newData.indent;
216       if(newData.name)
217       {
218          int len = strlen(newData.name) + 1;
219          name = new char[len];
220          CopyBytes(name, newData.name, len);
221       }
222    }
223
224    bool OnGetDataFromString(char * string)
225    {
226       int len = strlen(string) + 1;
227       name = new char[len];
228       CopyBytes(name, string, len);
229       return true;
230    }
231
232    void OnFree()
233    {
234       delete name;
235    }
236
237    char * OnGetString(char * string, void * fieldData, bool * needClass)
238    {
239       return name;
240    }
241 };
242
243 public class FileDialog : Window
244 {
245    text = "Select a file...";
246    background = activeBorder;
247    hasClose = true;
248    borderStyle = sizable;
249    tabCycle = true;
250    autoCreate = false;
251 #ifdef __WIN32__
252    nativeDecorations = true;
253 #endif
254    minClientSize = { 500, 300 };
255
256 public:
257    property FileDialogType type
258    {
259       get { return style; }
260       set
261       {
262          int numTypes = sizeTypes / sizeof(FileType);
263          int rightOffset = (value != selectDir && numTypes > 0) ? 48 : 16;
264
265          style = value;
266
267          if(value == selectDir)
268          {
269             // Filters
270             filter.visible = false;
271             filterLabel.visible = false;
272             // Types
273             type.visible = false;
274             typeLabel.visible = false;
275
276             open.visible = true;
277             open.isDefault = true;
278
279             ok.text = "Select";
280             ok.id = DialogResult::ok;
281             ok.hotKey = altS;
282             ok.isDefault = false;
283          }
284          else
285          {
286             // Filters
287             filter.visible = true;
288             filterLabel.visible = true;
289
290             // Types
291             type.visible = numTypes != 0;
292             typeLabel.visible = numTypes != 0;
293
294             open.visible = false;
295             open.isDefault = false;
296
297             ok.text = "OK";
298             ok.id = 0;
299             ok.hotKey = 0;
300             ok.isDefault = true;
301          }
302          ok.anchor = { right = 10, bottom = 32 + rightOffset - 1 };
303
304          // Cancel Button
305          cancel.anchor = { right = 10, bottom = rightOffset - 1 };
306
307          listBox.anchor = { left = 8, right = 8, top = 40, bottom = 64 + rightOffset };
308          fileName.anchor = { left = 96, bottom = 32 + rightOffset, right = 104 };
309          fileNameLabel.anchor = { left = 8, bottom = 35 + rightOffset };
310
311          listBox.multiSelect = value == multiOpen;
312          fileName.text = (value == selectDir) ? "Directory:" : "File Name:";
313       }
314    };
315
316    // Stuff currently in config moving to FileDialog:
317    property char * filePath { set { strcpy(filePath, value); } get { return (char *)filePath; } };
318    property char * currentDirectory
319    { 
320       set
321       {
322          GetWorkingDir(currentDirectory, MAX_DIRECTORY);
323          PathCat(currentDirectory, value);
324          FileFixCase(currentDirectory);
325       }
326       get { return (char *)currentDirectory; }
327    };
328    property FileFilter * filters { set { filters = value; } get { return filters; } };
329    property FileType * types { set { types = value; } get { return types; } };
330
331    // Replace with Array system
332    property int sizeFilters
333    {
334       set
335       {
336          int numFilters = value / sizeof(FileFilter);
337          int c;
338
339          sizeFilters = value;
340
341          // File Extension Filter
342          filter.Clear();
343          // filter.AddField(null);
344          if(filters)
345          {
346             for(c = 0; c<numFilters; c++)
347             {
348                DataRow row = filter.AddString(filters[c].name);
349                row.tag = c;
350             }
351          }
352          if(!numFilters)
353             filter.AddString("All files");
354
355          if(fileFilter >= numFilters) fileFilter = 0;
356          filter.currentRow = filter.FindRow(fileFilter);
357       }
358       get { return sizeFilters; }
359    };
360    property int sizeTypes
361    {
362       set
363       {
364          int numTypes = value / sizeof(FileType);
365          int rightOffset = (numTypes > 0) ? 48 : 16;
366
367          sizeTypes = value;
368
369          // Filters
370          filter.anchor = { left = 96, right = 104, bottom = rightOffset };
371          filterLabel.anchor = { left = 8, bottom = 3 + rightOffset };
372
373          if(style != selectDir)
374          {
375             // Types
376             type.visible = numTypes ? true : false;
377             typeLabel.visible = numTypes ? true : false;
378
379             // Ok Button
380             ok.anchor = { right = 10, bottom = 32 + rightOffset - 1 };
381
382             // Cancel Button
383             cancel.anchor = { right = 10, bottom = rightOffset - 1 };
384          }
385
386          listBox.anchor = { left = 8, right = 8, top = 40, bottom = 64 + rightOffset };
387          fileName.anchor = { left = 96, bottom = 32 + rightOffset, right = 104 };
388          fileNameLabel.anchor = { left = 8, bottom = 35 + rightOffset };
389
390          // File Types
391          if(numTypes)
392          {
393             int c;
394
395             type.Clear();
396             // type.AddField(null);
397             if(types)
398             {
399                for(c = 0; c<numTypes; c++)
400                {
401                   DataRow row = type.AddString(types[c].name);
402                   row.tag = c;
403                }
404             }
405             if(fileType >= numTypes) fileType = 0;
406
407             type.currentRow = type.FindRow(fileType);
408          }
409       }
410       get { return sizeTypes; }
411    };
412
413    property int filter { set { fileFilter = value; } get { return fileFilter; } };
414    property int fileType { set { fileType = value; } get { return fileType; } };
415    property bool mayNotExist { set { mayNotExist = value; } get { return mayNotExist; } };
416
417    // Get only
418    property int numSelections { get { return numSelections; } };
419    property char ** multiFilePaths { get { return multiFilePaths; } };
420
421 private:
422    FileDialog()
423    {
424       FileNameType c;
425
426       lookIn.AddField(lookInField);
427       listBox.AddField(nameField);
428       listBox.AddField(typeField);
429       listBox.AddField(sizeField);
430
431       filter.currentRow = filter.AddString("All files");
432
433       GetWorkingDir(currentDirectory, MAX_DIRECTORY);
434       FileFixCase(currentDirectory);
435
436       // Resources
437       for(c = 0; c<FileNameType::enumSize; c++)
438       {
439          icons[c] = BitmapResource { iconNames[c], alphaBlend = true };
440          AddResource(icons[c]);
441       }
442    }
443
444    ~FileDialog()
445    {
446       delete customFilter.extensions;
447       if(multiFilePaths)
448       {
449          int c;
450          for(c = 0; c<numSelections; c++)
451             delete multiFilePaths[c];
452          delete multiFilePaths;
453       }
454    }
455
456    void ListDrives()
457    {
458       int start = 0;
459       char tmpDir[MAX_FILENAME];
460       DataRow row;
461       FileName fileName;
462       FileListing listing { "/" };
463       int c;
464
465       fileName.indent = 0;
466
467       // Fill the path dropbox
468       lookIn.Clear();
469
470       row = lookIn.AddRow();
471
472    #ifdef __WIN32__
473       fileName.name = rootName;
474    #else
475       fileName.name = "/";
476    #endif
477       fileName.type = computer;
478       row.SetData(null, fileName);
479       lookIn.currentRow = row;
480
481       start = 0;
482    #ifdef __WIN32__
483       while(listing.Find())
484       {
485          row = lookIn.AddRow();
486
487          fileName.name = listing.name;
488          fileName.type = drive;
489          if(listing.stats.attribs.isCDROM) fileName.type = cdrom;
490          if(listing.stats.attribs.isRemote) fileName.type = netDrive;
491          if(listing.stats.attribs.isRemovable)
492          {
493             if(listing.name[0] == 'A' || listing.name[0] == 'B')
494                fileName.type = floppy;
495             else
496                fileName.type = removable;
497          }
498
499          fileName.indent = 1;
500          row.SetData(null, fileName);
501
502          start = 2;
503          if(listing.name[0] == currentDirectory[0] &&
504             listing.name[1] == currentDirectory[1])
505          {
506    #endif
507             for(c = start; currentDirectory[c]; ) 
508             {
509                int len = 0;
510                char ch;
511                for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
512                for(;(ch = currentDirectory[c]) && (ch != '/' && ch != '\\'); c++)
513                {
514                   if(len < MAX_FILENAME)
515                      tmpDir[len++] = ch;  
516                }
517                for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
518                tmpDir[len] = '\0';
519
520                if(len > 0)
521                {
522                   row = lookIn.AddRow();
523                   fileName.name = tmpDir;
524                   fileName.type = ch ? folder : folderOpen;
525                   fileName.indent++;
526                   row.SetData(null, fileName);
527                }
528                if(!ch)
529                   lookIn.currentRow = row;
530             }
531    #ifdef __WIN32__
532             if(c == start)
533                lookIn.currentRow = row;
534          }
535          c++;
536       }
537
538       row = lookIn.AddRow();
539       fileName.name = msNetwork;
540       fileName.type = network;
541       fileName.indent = 0;
542       row.SetData(null, fileName);
543       if(!strcmp(currentDirectory, "\\\\"))
544          lookIn.currentRow = row;
545       else
546       {
547          if(currentDirectory[0] == '\\' && currentDirectory[1] == '\\')
548          {
549             for(c = 2; currentDirectory[c]; ) 
550             {
551                int len = 0;
552                char ch;
553                for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
554                for(;(ch = currentDirectory[c]) && (ch != '/' && ch != '\\'); c++)
555                {
556                   if(len < MAX_FILENAME)
557                      tmpDir[len++] = ch;  
558                }
559                for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
560                tmpDir[len] = '\0';
561
562                if(len > 0)
563                {
564                   row = lookIn.AddRow();
565                   fileName.name = tmpDir;
566                   fileName.indent++;
567                   if(fileName.indent == 1)
568                      fileName.type = server;
569                   else if(fileName.indent == 2)
570                      fileName.type = share;
571                   else
572                      fileName.type = ch ? folder : folderOpen;
573                   row.SetData(null, fileName);
574                }
575                if(!ch)
576                   lookIn.currentRow = row;
577             }
578             if(c == 2)
579                lookIn.currentRow = row;
580          }
581       }
582    #endif
583    }
584
585    // flag = false : Get Name From Edit Box, flag = true : Get Name From List Box
586    void GetNameFromListBox(bool flag)
587    {
588       bool okDisabled;
589       if(flag)
590       {
591          if(style == multiOpen)
592             okDisabled = listBox.numSelections == 0;
593          else
594             okDisabled = listBox.currentRow == null;
595          if(okDisabled) flag = false;
596       }
597       else
598          okDisabled = !fileName || !fileName.line.text[0];
599
600       getNameFromListBox = flag;
601       ok.disabled = okDisabled;
602       open.disabled = okDisabled;
603    }
604
605    void ListFiles()
606    {
607       FileListing listing { currentDirectory };
608       int c = 0;
609       FileName fileName;
610       DataRow row;
611
612       if(sizeFilters < sizeof(FileFilter) && !fileFilter)
613          listing.extensions = null;
614       else if(filters && fileFilter < sizeFilters / (int)sizeof(FileFilter))
615          listing.extensions = filters[fileFilter].extensions;    
616       else
617          listing.extensions = customFilter.extensions;
618      
619       listBox.Clear();
620
621       fileName.indent = 0;
622       while(listing.Find())
623       {
624          if(style != selectDir || (listing.stats.attribs.isDirectory))
625          {
626             row = listBox.AddRow();
627
628             fileName.name = listing.name;
629             if(listing.stats.attribs.isDirectory)
630             {
631                fileName.type = (listing.stats.attribs.isDrive) ? drive : folder;
632                if(listing.stats.attribs.isServer) fileName.type = server;
633                if(listing.stats.attribs.isShare) fileName.type = share;
634                if(listing.stats.attribs.isCDROM) fileName.type = cdrom;
635                if(listing.stats.attribs.isRemote) fileName.type = netDrive;
636                if(listing.stats.attribs.isRemovable) 
637                {
638                   if(listing.name[0] == 'A' || listing.name[0] == 'B')
639                      fileName.type = floppy;
640                   else
641                      fileName.type = removable;
642                }
643                row.SetData(nameField, fileName);
644                row.SetData(typeField, null);
645             }
646             else
647             {
648                char extension[MAX_EXTENSION];
649
650                GetExtension(fileName.name, extension);
651                fileName.type = FileNameType::SelectByExtension(extension);
652                strupr(extension);
653                row.SetData(nameField, fileName);
654                row.SetData(typeField, extension);
655                row.SetData(sizeField, listing.stats.size);
656             }
657          }
658          c++;
659       }
660
661       if(sortOrder && sortField != nameField)
662          listBox.Sort(nameField, 1);
663       listBox.Sort(sortField, sortOrder);
664
665       GetNameFromListBox(activeChild == listBox);
666
667       // Go up button
668       if(!strcmp(currentDirectory, "/"))
669       {
670    #ifdef __WIN32__
671          row = listBox.AddRow();
672          fileName.name = msNetwork;
673          fileName.type = network;
674          fileName.indent = 0;
675          row.SetData(nameField, fileName);
676          row.SetData(typeField, null);
677    #endif
678          goUp.disabled = true;
679       }
680       else 
681          goUp.disabled = false;
682
683       ListDrives();
684
685       listBox.typingTimeout = 0.5;
686    }
687
688
689    bool GetNamesFromRow(DataRow row, char ** selectedFileName)
690    {
691       FileName * fileName;
692
693       if(style == multiOpen)
694       {
695          OldList selection;
696          listBox.GetMultiSelection(selection);
697          if(selection.count)
698          {
699             int totalLen = 0;
700             OldLink item;
701
702             // First allocate enough memory
703             for(item = selection.first; item; item = item.next)
704             {
705                row = item.data;
706                fileName = row.GetData(nameField);
707    #ifdef __WIN32__
708                if(!strcmp(currentDirectory, "/"))
709                {
710                   if(!strcmp(fileName->name, msNetwork))
711                      totalLen += 2;
712                   else
713                      totalLen += 3;
714                }
715                else
716    #endif
717                totalLen += strlen(fileName->name);
718                if(item != selection.first)
719                   totalLen += 3;
720             }
721             if(selection.count > 1) totalLen += 2;
722             *selectedFileName = new char[totalLen + 1];
723             (*selectedFileName)[0] = '\0';
724
725             // Then build the string
726             for(item = selection.first; item; item = item.next)
727             {
728                row = item.data;
729                fileName = row.GetData(nameField);
730                if(item != selection.first) strcat(*selectedFileName, " ");
731                if(selection.count > 1) strcat(*selectedFileName, "\"");
732    #ifdef __WIN32__
733                if(!strcmp(currentDirectory, "/"))
734                {
735                   char name[3];
736                   if(!strcmp(fileName->name, msNetwork))
737                      strcpy(name, "\\\\");
738                   else
739                   {
740                      name[0] = fileName->name[0];
741                      name[1] = fileName->name[1];
742                      name[2] = '\0';
743                   }
744                   strcat(*selectedFileName, name);
745                }
746                else
747    #endif            
748                strcat(*selectedFileName, fileName->name);
749                if(selection.count > 1) strcat(*selectedFileName, "\"");
750             }
751             selection.Free(null);
752             return true;
753          }
754       }
755       else if(row)
756       {
757          fileName = row.GetData(nameField);
758          if(fileName != null)
759          {
760    #ifdef __WIN32__
761             if(!strcmp(currentDirectory, "/"))
762             {
763                *selectedFileName = new char[3];
764                if(!strcmp(fileName->name, msNetwork))
765                   strcpy(*selectedFileName, "\\\\");
766                else
767                {
768                   (*selectedFileName)[0] = fileName->name[0];
769                   (*selectedFileName)[1] = fileName->name[1];
770                   (*selectedFileName)[2] = '\0';
771                }
772             }
773             else
774    #endif
775             {
776                *selectedFileName = new char[strlen(fileName->name) + 1];
777                strcpy(*selectedFileName, fileName->name);
778             }
779             return true;
780          }
781       }
782       return false;
783    }
784
785    bool SelectFile(char * fileName, FileDialogSelectFrom from, bool isOK)
786    {
787       bool result = true;
788       FileAttribs exists;
789       char * wildcardPointer = strstr(fileName, "*");
790       
791       if(wildcardPointer)
792       {
793          if(style != selectDir)
794          {
795             int numFilters = sizeFilters / sizeof(FileFilter);
796             int numExtensions = 0;
797             char * pointer = wildcardPointer;
798
799             fileFilter = -1;
800
801             // Count the number of extensions in requested filter
802             while(pointer)
803             {
804                if(pointer[1] == '.' && pointer[2])
805                   pointer +=3; 
806                else 
807                   pointer ++;
808                pointer = strstr(pointer, "*");
809                numExtensions++;
810             }
811
812             // Try to match the extension(s) to an existing filter
813             if(numFilters)
814             {
815                int filter;
816                char extension[MAX_EXTENSION], compared[MAX_EXTENSION];
817                for(filter = 0; filter<numFilters; filter++)
818                {
819                   if(filters[filter].extensions)
820                   {
821                      int numMatched = 0;
822                      int c, d;
823
824                      for(c = 0; filters[filter].extensions[c];)
825                      {
826                         bool matched = false;
827                         int len = 0;
828                         char ch;
829                         for(;(ch = filters[filter].extensions[c]) && !IS_ALUNDER(ch); c++);
830                         for(;(ch = filters[filter].extensions[c]) &&  IS_ALUNDER(ch); c++)
831                            compared[len++] = ch;
832                         compared[len] = '\0';
833
834                         for(d = 0; wildcardPointer[d]; )
835                         {
836                            len = 0;
837                            for(;(ch = wildcardPointer[d]) && !IS_ALUNDER(ch); d++);
838                            for(;(ch = wildcardPointer[d]) && IS_ALUNDER(ch); d++)
839                            {
840                               if(len < MAX_EXTENSION)
841                                  extension[len++] = ch;
842                            }
843                            extension[len] = '\0';
844                      
845                            if(!strcmpi(extension, compared))
846                            {
847                               matched = true;
848                               break;
849                            }
850                         }
851
852                         if(matched)
853                            numMatched++;
854                         else
855                         {
856                            numMatched = 0;
857                            break;
858                         }
859                      }
860                      if(numMatched == numExtensions)
861                      {
862                         fileFilter = filter;
863                         break;
864                      }
865                   }
866                   else if(!strcmp(wildcardPointer, "*") || strstr(wildcardPointer, "*.*"))
867                   {
868                      fileFilter = filter;
869                      break;
870                   }
871                }
872             }
873             // Only have *.* to check for
874             else if(!strcmp(wildcardPointer, "*") || strstr(wildcardPointer, "*.*"))
875                this.fileFilter = 0;
876
877             // If we can't match it, use the custom extension
878             if(this.fileFilter == -1)
879             {
880                char extension[MAX_EXTENSION];
881                int c;
882                char * name = new char[numExtensions * (4 + MAX_EXTENSION)];
883
884                delete customFilter.extensions;
885             
886                if(!strcmp(wildcardPointer, "*") || strstr(wildcardPointer, "*.*"))
887                {
888                   strcpy(name, "All Files");
889                   customFilter.extensions = null;
890                }
891                else
892                {
893                   customFilter.extensions = new char[numExtensions * (2 + MAX_EXTENSION)];
894                   customFilter.extensions[0] = '\0';
895                   name[0] = '\0';
896             
897                   numExtensions = 0;
898                   for(c = 0; wildcardPointer[c]; )
899                   {
900                      int len = 0;
901                      char ch;
902                      for(;(ch = wildcardPointer[c]) && !IS_ALUNDER(ch); c++);
903                      for(;(ch = wildcardPointer[c]) && IS_ALUNDER(ch); c++)
904                      {
905                         if(len < MAX_EXTENSION)
906                            extension[len++] = ch;  
907                      }
908                      extension[len] = '\0';
909
910                      if(numExtensions)
911                      {
912                         strcat(name, ", ");
913                         strcat(customFilter.extensions, ", ");
914                      }
915                      strcat(name, "*.");
916                      strcat(name, extension);
917                      if(!extension[0]) 
918                         strcat(customFilter.extensions, ".");
919                      else
920                         strcat(customFilter.extensions, extension);
921
922                      numExtensions++;
923                   }
924                }
925
926                if(!customFilterRow)
927                {
928                   customFilterRow = filter.AddRow();
929                   customFilterRow.tag = numFilters + 1;
930                }
931
932                customFilterRow.SetData(null, name);
933
934                fileFilter = numFilters + 1;
935
936                delete name;
937             }
938          
939             filter.currentRow = filter.FindRow(fileFilter);
940             ListFiles();
941             result = true;
942          }
943          *wildcardPointer = '\0';
944       }
945
946       if(style == multiOpen)
947       {
948          int c;
949          bool quoted = false;
950          bool needQuotes = strchr(fileName, '\"') != null;
951          char currentFileName[MAX_LOCATION], * curFileName = currentFileName;
952          char ch;
953          OldList selections { };
954          OldLink selection = null;
955
956          for(c = 0;; c++)
957          {
958             ch = fileName[c];
959             switch(ch)
960             {
961                case '\0':
962                case '\"':
963                   if(!ch || quoted)
964                   {
965                      // Add filename
966                      (*curFileName) = '\0';
967
968                      selection = OldLink { data = new char[strlen(currentFileName)+1] };
969                      strcpy(selection.data, currentFileName);
970                      selections.Add(selection);
971
972                      curFileName = currentFileName;
973                   }
974                   quoted ^= true;
975                   break;
976                default:
977                   if(needQuotes && !quoted)
978                      break;
979                   // Add to filename
980                   *(curFileName++) = ch;
981             }
982             if(!ch) break;
983          }
984
985          numSelections = 0;
986          multiFilePaths = new char *[selections.count];
987
988          for(selection = selections.first; selection; selection = selection.next)
989          {
990             char * fileName = selection.data;
991             
992             // For every file
993             strcpy(currentFileName, currentDirectory);
994             if(PathCat(currentFileName, fileName))
995             {
996                FileFixCase(currentFileName);
997                exists = FileExists(currentFileName);
998                if(exists.isDirectory)
999                {
1000                   strcpy(currentDirectory, currentFileName);
1001                   ListFiles();
1002                   break;
1003                }
1004                else if(exists || mayNotExist)
1005                {
1006                   char ** path = &multiFilePaths[numSelections++];
1007                   *path = new char[strlen(currentFileName)+1];
1008                   strcpy(*path, currentFileName);
1009
1010                   result = false;
1011                }
1012                if(exists && result && from == fromListBox) // From List Box
1013                {
1014                   char pathName[MAX_LOCATION];
1015                   GetLastDirectory(this.fileName.line.text, pathName);
1016                   this.fileName.Clear();
1017                   if(!exists.isDirectory)
1018                      this.fileName.PutS(pathName);
1019                   break;
1020                }
1021             }
1022          }
1023          selections.Free(OldLink::Free);
1024          if(result)
1025          {
1026             if(multiFilePaths)
1027             {
1028                for(c = 0; c<numSelections; c++)
1029                   if(multiFilePaths[c])
1030                      delete multiFilePaths[c];
1031                delete multiFilePaths;
1032             }
1033          }
1034       }
1035       else
1036       {
1037          strcpy(filePath, currentDirectory);
1038          if(PathCat(filePath, fileName))
1039          {
1040             FileFixCase(filePath);
1041             exists = FileExists(filePath);
1042             if(exists.isDirectory && (style != selectDir || !isOK))
1043             {
1044                strcpy(currentDirectory, filePath);
1045
1046                ListFiles();
1047             }
1048             else 
1049             {
1050                // *** SAVING ONLY ****
1051                if(style == save)
1052                {
1053                   if(fileType >= 0 && fileType < sizeTypes)
1054                   {
1055                      FileType type = types[fileType];
1056                      if(type.forceExtension && type.typeExtension)
1057                      {
1058                         char extension[MAX_EXTENSION];
1059                         GetExtension(filePath, extension);
1060                         if(type.forceExtension == always || !extension[0])
1061                         {
1062                            ChangeExtension(filePath, type.typeExtension, filePath);
1063                            exists = FileExists(filePath);
1064                         }
1065                      }
1066                   }
1067                   if(!exists || MessageBox { master = this, type = yesNo, text = "File Already Exists", contents = "Replace existing file?" }.Modal() == yes)
1068                      result = false;
1069                }
1070                else if(exists || mayNotExist)
1071                {
1072                   if(style != selectDir ||
1073                      (strcmp(filePath, "\\\\") &&
1074                      strcmp(filePath, "\\\\") &&
1075                      !(exists.isServer)))
1076                         result = false;
1077                }
1078                // *** DIRECTORY SELECTION ONLY ****
1079                else if(isOK && style == selectDir &&
1080                   MessageBox { this, type = yesNo, text = "Directory doesn't exist", contents = "Create directory?" }.Modal() == yes)
1081                {
1082                   if(MakeDir(filePath))
1083                      result = false;
1084                }
1085             }
1086
1087             if(exists && result && from == fromListBox) // From List Box
1088             {
1089                char pathName[MAX_LOCATION];
1090                GetLastDirectory(this.fileName.line.text, pathName);
1091                this.fileName.Clear();
1092                if(!exists.isDirectory)
1093                   this.fileName.PutS(pathName);
1094             }
1095          }
1096       }
1097
1098       if(!exists && result && from == fromDropBox) // drive Drop Box
1099       {
1100          ListDrives();
1101       }
1102
1103       if(!result)
1104          Destroy(DialogResult::ok);
1105       return result;
1106    }
1107
1108    bool OnPostCreate()
1109    {
1110       if(multiFilePaths)
1111       {
1112          int c;
1113          for(c = 0; c<numSelections; c++)
1114             delete multiFilePaths[c];
1115          delete multiFilePaths;
1116       }
1117       numSelections = 0;
1118
1119       ListFiles();
1120       {
1121          // Fix up config input directory
1122          char fileName[MAX_FILENAME];
1123          #if defined(__WIN32__)
1124          char * dirOccur = SearchString(filePath, 0, currentDirectory, false, false);
1125          #else
1126          char * dirOccur = strstr(filePath, currentDirectory);
1127          #endif
1128          if(dirOccur)
1129          {
1130             dirOccur += strlen(currentDirectory);
1131             for(;*dirOccur && (*dirOccur == '/' || *dirOccur == '\\'); dirOccur++);
1132             strcpy(fileName, dirOccur);
1133          }
1134          else
1135             strcpy(fileName, filePath);
1136
1137          this.fileName.Clear();
1138          this.fileName.PutS(fileName);
1139       }
1140
1141       GetNameFromListBox(false);
1142
1143       fileName.Activate();
1144       return true;
1145    }
1146
1147    FileDialogType style;
1148    FileFilter customFilter;
1149    DataRow customFilterRow;
1150    bool getNameFromListBox;
1151    BitmapResource icons[FileNameType];
1152
1153    char currentDirectory[MAX_DIRECTORY];
1154    char filePath[MAX_LOCATION];
1155    FileFilter * filters;
1156    int sizeFilters;
1157    FileType * types;
1158    int sizeTypes;
1159    int fileFilter, fileType;
1160
1161    int numSelections;
1162    char ** multiFilePaths;
1163    bool mayNotExist;
1164
1165    // ListBox Configuration
1166    DataField sortField;
1167    int sortOrder;
1168
1169    // File Extension Filter
1170    DropBox filter
1171    {
1172       this, text = "Filter:", anchor = { left = 96, right = 104, bottom = 16 }, hotKey = altR;
1173       
1174       bool NotifySelect(DropBox control, DataRow row, Modifiers mods)
1175       {
1176          fileFilter = row ? row.tag : 0;
1177          ListFiles();
1178          return true;
1179       }
1180    };
1181
1182    Label filterLabel
1183    {
1184       this, inactive = true, anchor = { left = 8, bottom = 3 + 16 }, labeledWindow = filter
1185    };
1186
1187    // File Types
1188    DropBox type
1189    {
1190       this, text = "As Type:", visible = false, anchor = { left = 96, right = 104, bottom = 16 }, hotKey = altT;
1191
1192       bool NotifySelect(DropBox control, DataRow row, Modifiers mods)
1193       {
1194          char * selectedFileName = null;
1195          fileType = row ? row.tag : 0;
1196          if(style == save && types && types[fileType].typeExtension)
1197          {
1198             if(getNameFromListBox)
1199             {
1200                if(GetNamesFromRow(listBox.currentRow, &selectedFileName))
1201                   fileName.Clear();
1202             }
1203             else
1204             {
1205                char * fileName = this.fileName.line.text;
1206                //selectedFileName = new char[strlen(fileName)+1];      // Room to change extension???
1207                selectedFileName = new char[MAX_FILENAME];
1208                strcpy(selectedFileName, fileName);
1209             }
1210             ChangeExtension(selectedFileName, types[fileType].typeExtension, selectedFileName);
1211             fileName.Select(null,0,0, null,0,0);
1212             fileName.PutS(selectedFileName);
1213             GetNameFromListBox(false);
1214          }
1215          delete selectedFileName;
1216          return true;
1217       }
1218    };
1219       
1220    Label typeLabel
1221    {
1222       this, inactive = true, visible = false, anchor = { left = 8, bottom = 19 }, labeledWindow = type;
1223    };
1224
1225    // Ok Button
1226    Button ok
1227    {
1228       this, isDefault = true, text = "OK", anchor = { right = 10, bottom = 32 + 16 - 1 }, size = { 80 };
1229
1230       bool NotifyClicked(Button control, int x, int y, Modifiers mods)
1231       {
1232          bool result;
1233          char * selectedFileName = null;
1234          if(getNameFromListBox)
1235          {
1236             GetNamesFromRow(listBox.currentRow, &selectedFileName);
1237             result = SelectFile(selectedFileName, fromEditBox, control.id == DialogResult::ok);
1238             if(result && style == selectDir)
1239                listBox.Activate();
1240          }
1241          else
1242          {
1243             char * fileName = this.fileName.line.text;
1244             selectedFileName = new char[strlen(fileName)+1];
1245             strcpy(selectedFileName, fileName);
1246             result = SelectFile(selectedFileName, fromListBox, control.id == DialogResult::ok);
1247             if(result && style == selectDir)
1248                this.fileName.Activate();
1249          }
1250          delete selectedFileName;
1251          return result;
1252       }
1253    };
1254
1255    // Open Button (SelectDir only)
1256    Button open
1257    {
1258       this, visible = false, text = "Open", hotKey = altO, anchor = { right = 100, bottom = 16 - 1 }, size = { 80 };
1259       NotifyClicked = ok.NotifyClicked;
1260    };
1261
1262    // Cancel Button
1263    Button cancel
1264    {
1265       this, text = "Cancel", anchor = { right = 10, bottom = 16 - 1 }, size = { 80 }, hotKey = escape;
1266       bool NotifyClicked(Button control, int x, int y, Modifiers mods)
1267       {
1268          Destroy(DialogResult::cancel);
1269          return true;
1270       }
1271    };
1272
1273    // Look In Dropbox
1274    DropBox lookIn
1275    {
1276       this, text = "Look in:", anchor = { left = 81, top = 8, right = 109 }, hotKey = altL, maxShown = 12;
1277
1278       bool OnKeyHit(Key key, unichar ch)
1279       {
1280          if(key == wheelDown || key == wheelUp)
1281          {
1282             ((FileDialog)master).listBox.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, key, ch);
1283             return false;
1284          }
1285          return true;
1286       }
1287
1288       bool NotifySelect(DropBox control, DataRow row, Modifiers mods)
1289       {
1290          if(row)
1291          {
1292             FileName * fileName = row.GetData(null);
1293             char name[MAX_LOCATION] = "/";
1294             int indent = 0;
1295             int c = 0;
1296          #ifdef __WIN32__
1297             if(!strcmp(fileName->name, msNetwork) ||
1298                (currentDirectory[0] == '\\' &&
1299                 currentDirectory[1] == '\\' &&
1300                 strcmp(fileName->name, rootName) &&
1301                 (!fileName->name[0] || fileName->name[1] != ':')))
1302             {
1303                strcpy(name, "\\\\");
1304                c = 2;
1305             }
1306             else
1307             {
1308                if(fileName->indent > 1)
1309                {
1310                   name[0] = currentDirectory[0];
1311                   name[1] = ':';
1312                   name[2] = '\0';
1313                   indent++;
1314                   c = 2;
1315                }
1316                else if(fileName->indent == 1)
1317                {
1318                   name[0] = fileName->name[0];
1319                   name[1] = ':';
1320                   name[2] = '\0';
1321                   c = 2;
1322                   indent++;
1323                }
1324             }
1325          #endif
1326             if(indent < fileName->indent)
1327             {
1328                for(; currentDirectory[c]; ) 
1329                {
1330                   int len = 0;
1331                   char ch;
1332                   char directory[MAX_FILENAME];
1333                   for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
1334                   for(;(ch = currentDirectory[c]) && (ch != '/' && ch != '\\'); c++)
1335                   {
1336                      if(len < MAX_FILENAME)
1337                         directory[len++] = ch;  
1338                   }
1339                   for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
1340                   directory[len] = '\0';
1341
1342                   if(indent >= fileName->indent) break;
1343                   PathCat(name, directory);
1344                   indent++;
1345                }
1346             }
1347
1348             SelectFile(name, fromDropBox, false);
1349          }
1350          return true;
1351       }
1352    };
1353
1354    DataField lookInField { dataType = "FileName", userData = this };
1355    
1356    Label lookInLabel
1357    {
1358       this, position = { 10, 11 }, labeledWindow = lookIn;
1359    };
1360
1361    // Main Listbox
1362    ListBox listBox
1363    {
1364       this, borderStyle = deep, hasVertScroll = true, hasHorzScroll = true,
1365       anchor = { left = 8, right = 8, top = 40, bottom = 64 + 16 },
1366       hasHeader = true, moveFields = true, resizable = true, sortable = true;
1367
1368       bool NotifySelect(ListBox control, DataRow row, Modifiers mods)
1369       {
1370          GetNameFromListBox(true);
1371          return true;
1372       }
1373
1374       bool NotifyDoubleClick(ListBox control, int x, int y, Modifiers mods)
1375       {
1376          bool result = true;
1377          char * selectedFileName = null;
1378          if(GetNamesFromRow(control.currentRow, &selectedFileName))
1379          {
1380             result = SelectFile(selectedFileName, fromEditBox, false);
1381          }
1382          delete selectedFileName;
1383          return result;
1384       }
1385
1386       bool NotifyKeyDown(ListBox control, DataRow row, Key key, unichar ch)
1387       {
1388          if(key == backSpace)
1389          {
1390             if(strcmp(currentDirectory, "/"))
1391                goUp.NotifyClicked(this, goUp, 0,0, key.modifiers);
1392          }
1393          return true;
1394       }
1395
1396       bool NotifySort(ListBox control, DataField field, Modifiers mods)
1397       {
1398          sortField = field;
1399          sortOrder = field.sortOrder;
1400          return true;
1401       }
1402
1403       bool NotifyActivate(Window control, bool active, Window previous)
1404       {
1405          if(active)
1406             GetNameFromListBox(true);
1407          return true;
1408       }
1409    };
1410
1411    DataField nameField { header = "Name", dataType = "FileName", width = 304, userData = this }; // editable = true
1412    DataField typeField { header = "Type", dataType = /*"String"*/ "char *", width = 40 };
1413    DataField sizeField { header = "Size", dataType = "FileSize", width = 96, alignment = right };
1414
1415    // Go up button
1416    Button goUp
1417    {
1418       this, inactive = true, anchor = { right = 79, top = 8 }, size = { 24, 24 },
1419       bitmap = { "<:ecere>actions/goUp.png", alphaBlend = true };
1420       symbol = 30;
1421
1422       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1423       {
1424          char * notRoot;
1425          notRoot = StripLastDirectory(currentDirectory, currentDirectory);
1426          if(!notRoot)
1427             strcpy(currentDirectory, "/");
1428          ListFiles();
1429          return true;
1430       }
1431    };
1432
1433    Button createDirectory
1434    {
1435       this, inactive = true, anchor = { right = 51, top = 8 }, size = { 24, 24 },
1436       bitmap = { "<:ecere>actions/folderNew.png", alphaBlend = true };
1437       symbol = 30;    // what the heck is that?
1438
1439       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1440       {
1441          if(CreateDirectoryDialog { master = this, parent = parent, currentDirectory = currentDirectory }.Modal() == ok )
1442             ListFiles();
1443          return true;
1444       }
1445    };
1446
1447    // File name editbox
1448    EditBox fileName
1449    {
1450       this, text = "File Name:", anchor = { left = 96, bottom = 32 + 16, right = 104 }, size.h = 20, hotKey = altF;
1451
1452       bool NotifyActivate(Window control, bool active, Window previous)
1453       {
1454          if(active)
1455          {
1456             char * selectedFileName = null;
1457             char * editText;
1458             if(getNameFromListBox)
1459             {
1460                DataRow row = listBox.currentRow;
1461                if(row)
1462                {
1463                   if(GetNamesFromRow(row, &selectedFileName))
1464                   {
1465                      fileName.Clear();
1466                      fileName.PutS(selectedFileName);
1467                      fileName.Select(null,0,0, null,0,0);
1468                   }
1469                   GetNameFromListBox(false);
1470                }
1471             }
1472             delete selectedFileName;
1473             editText = fileName.contents;
1474             ok.disabled = !editText || !editText[0];
1475          }
1476          return true;
1477       }
1478
1479       void NotifyUpdate(EditBox control)
1480       {
1481          GetNameFromListBox(false);
1482       }
1483    };
1484
1485    Label fileNameLabel
1486    {
1487       this, inactive = true, anchor = { left = 8, bottom = 35 + 16 };
1488       labeledWindow = fileName;
1489    };
1490 };
1491
1492 public class CreateDirectoryDialog : Window
1493 {
1494    background = activeBorder;
1495    minClientSize = Size { 240, 100 };
1496    tabCycle = true;
1497    hasClose = true;
1498    text = "Create Directory";
1499
1500 public:
1501
1502    property char * currentDirectory
1503    {
1504       set
1505       {
1506          GetWorkingDir(currentDirectory, MAX_DIRECTORY);  // is this necessary?
1507          PathCat(currentDirectory, value);
1508          FileFixCase(currentDirectory);
1509       }
1510       get { return (char *)currentDirectory; }
1511    };
1512
1513 private:
1514
1515    char currentDirectory[MAX_DIRECTORY];
1516
1517    CreateDirectoryDialog()
1518    {
1519       FileNameType c;
1520
1521       GetWorkingDir(currentDirectory, MAX_DIRECTORY);
1522       FileFixCase(currentDirectory);
1523    }
1524
1525    ~CreateDirectoryDialog()
1526    {
1527    }
1528
1529    bool OnPostCreate()
1530    {
1531       newDirectoryName.SelectAll();
1532       return true;
1533    }
1534
1535    Button ok
1536    {
1537       parent = this, isDefault = true, position = { 70, 60 }, size = { 60 }, text = "OK";
1538       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1539       {
1540          if(newDirectoryName.contents && newDirectoryName.contents[0])
1541          {
1542             char newDirPath[MAX_DIRECTORY];
1543             strcpy(newDirPath, currentDirectory);
1544             PathCat(newDirPath, newDirectoryName.contents);
1545             if(!FileExists(newDirPath).isDirectory)
1546             {
1547                MakeDir(newDirPath);
1548                Destroy(DialogResult::ok);
1549             }
1550             else
1551                MessageBox { master = this, parent = parent, type = ok, text = "Create Directory Error", contents = "Directory already exists." }.Modal();
1552          }
1553          else
1554             MessageBox { master = this, parent = parent, type = ok, text = "Create Directory Error", contents = "Please enter a name." }.Modal();
1555          return true;
1556       }
1557    };
1558    
1559    Button cancel
1560    {
1561       parent = this, position = { 140, 60 }, size = { 60 }, hotKey = escape, text = "Cancel";
1562       NotifyClicked = ButtonCloseDialog;
1563    };
1564
1565    EditBox newDirectoryName
1566    {
1567       this, textHorzScroll = true, anchor = { left = 10, right = 10, top = 30 }, size = { 250 };
1568       hotKey = altN, text = "Name";
1569       contents = "New Directory";
1570    };
1571    Label { this, position = { 10, 10 }, labeledWindow = newDirectoryName };
1572
1573 }