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