1 namespace gui::dialogs;
3 //#ifdef __WIN32__ // We want the strings in the .pot when building on Unix
4 static define rootName = $"Entire Computer";
5 static define msNetwork = $"Microsoft Windows Network";
10 #define IS_ALUNDER(ch) ((ch) == '_' || isalnum((ch)))
13 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
16 static const char * iconNames[] =
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",
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*/
48 public enum FileNameType // Had to be private, since icons member of FileDialog is also private... (Static members? Not for a while...)
50 folder, folderOpen, computer,
51 drive, netDrive, cdrom, removable, floppy, network, server, share, // these are sort equal
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 */
61 this = SelectByExtension(value);
64 public property bool isFolderType
66 get { return this >= folder && this <= share; }
69 public property bool isFileType
71 get { return this >= normalFile && this <= opticalMediaImageFile; }
74 FileNameType ::SelectByExtension(const char * extension)
76 if(!strcmpi(extension, "ews"))
78 else if(!strcmpi(extension, "epj"))
80 else if(!strcmpi(extension, "ec"))
82 else if(!strcmpi(extension, "eh"))
84 else if(!strcmpi(extension, "cpp") ||
85 !strcmpi(extension, "cc") || !strcmpi(extension, "cxx"))
87 else if(!strcmpi(extension, "hpp") ||
88 !strcmpi(extension, "hh") || !strcmpi(extension, "hxx"))
90 else if(!strcmpi(extension, "c"))
92 else if(!strcmpi(extension, "h"))
94 else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
95 !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
97 else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
98 !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
99 !strcmpi(extension, "js"))
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"))
106 else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
107 !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
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"))
116 else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
117 !strcmpi(extension, "rpm"))
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;
128 public enum FileDialogType { open, save, selectDir, multiOpen };
129 public struct FileFilter
132 const char * extensions;
134 bool ValidateFileName(const char * name)
136 if(strcmp(name, "..") && strcmp(name, ".") && strcmp(name, ""))
138 if(extensions) // && !stats.attribs.isDirectory)
140 char extension[MAX_EXTENSION], compared[MAX_EXTENSION];
143 GetExtension(name, extension);
144 for(c = 0; extensions[c];)
148 for(;(ch = extensions[c]) && !IS_ALUNDER(ch); c++);
149 for(;(ch = extensions[c]) && IS_ALUNDER(ch); c++)
150 compared[len++] = ch;
151 compared[len] = '\0';
153 if(!strcmpi(extension, compared))
163 public enum FileForceExtension { never, always, whenNoneGiven };
164 public struct FileType
166 const char * name, * typeExtension;
167 FileForceExtension forceExtension;
170 static enum FileDialogSelectFrom { fromEditBox, fromListBox, fromDropBox };
172 public struct FileName
178 void OnDisplay(Surface surface, int x, int y, int width, FileDialog fileDialog, Alignment alignment, DataDisplayFlags displayFlags)
180 int indentSize = (displayFlags.dropBox) ? 0 : 10;
183 Bitmap icon = fileDialog.icons[type].bitmap;
184 if(!icon && type > normalFile)
185 icon = fileDialog.icons[normalFile].bitmap;
188 if(type == folder || type == folderOpen)
189 surface.SetForeground(red); //Color { 170, 170, 0 } // REDJ What is that color?
192 textOffset = indent * indentSize + (icon ? (icon.width + 4) : 0);
194 surface.WriteTextDots
195 (alignment, x + textOffset, y + 2, width - textOffset, name, strlen(name));
197 surface.Blit(icon, x + indent * indentSize, y,0,0, icon.width, icon.height);
200 int OnCompare(FileName b)
203 if(type == b.type || (type >= normalFile && b.type >= normalFile) || (type >= drive && type <= share))
204 result = strcmpi(name, b.name);
207 if(type == folder && b.type >= normalFile) result = -1;
208 else if(type >= normalFile && b.type == folder) result = 1;
213 void OnCopy(FileName newData)
216 indent = newData.indent;
219 int len = strlen(newData.name) + 1;
220 name = new char[len];
221 CopyBytes((char *)name, newData.name, len);
225 bool OnGetDataFromString(const char * string)
227 int len = strlen(string) + 1;
228 name = new char[len];
229 CopyBytes((char *)name, string, len);
235 char * n = (char *)name;
240 const char * OnGetString(char * string, void * fieldData, bool * needClass)
246 public class FileDialog : Window
248 text = $"Select a file...";
249 background = formColor;
251 borderStyle = sizable;
254 minClientSize = { 500, 300 };
257 property FileDialogType type
259 get { return style; }
262 int numTypes = sizeTypes / sizeof(FileType);
263 int rightOffset = (value != selectDir && numTypes > 0) ? 48 : 16;
267 if(value == selectDir)
270 filter.visible = false;
271 filterLabel.visible = false;
273 type.visible = false;
274 typeLabel.visible = false;
277 open.isDefault = true;
280 ok.id = DialogResult::ok;
282 ok.isDefault = false;
287 filter.visible = true;
288 filterLabel.visible = true;
291 type.visible = numTypes != 0;
292 typeLabel.visible = numTypes != 0;
294 open.visible = false;
295 open.isDefault = false;
302 ok.anchor = { right = 10, bottom = 32 + rightOffset - 1 };
305 cancel.anchor = { right = 10, bottom = rightOffset - 1 };
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 };
311 listBox.multiSelect = value == multiOpen;
312 fileName.text = (value == selectDir) ? $"Directory:" : $"File Name:";
316 // Stuff currently in config moving to FileDialog:
317 property const char * filePath { set { strcpy(filePath, value); } get { return (char *)filePath; } };
318 property const char * currentDirectory
322 GetWorkingDir(currentDirectory, MAX_DIRECTORY);
323 PathCat(currentDirectory, value);
324 FileFixCase(currentDirectory);
326 get { return currentDirectory; }
328 property FileFilter * filters { set { filters = value; } get { return filters; } };
329 property FileType * types { set { types = value; } get { return types; } };
331 // Replace with Array system
332 property int sizeFilters
336 int numFilters = value / sizeof(FileFilter);
341 // File Extension Filter
343 // filter.AddField(null);
346 for(c = 0; c<numFilters; c++)
348 DataRow row = filter.AddString(filters[c].name);
353 filter.AddString($"All files");
355 if(fileFilter >= numFilters) fileFilter = 0;
356 filter.currentRow = filter.FindRow(fileFilter);
358 get { return sizeFilters; }
360 property int sizeTypes
364 int numTypes = value / sizeof(FileType);
365 int rightOffset = (numTypes > 0) ? 48 : 16;
370 filter.anchor = { left = 96, right = 104, bottom = rightOffset };
371 filterLabel.anchor = { left = 8, bottom = 3 + rightOffset };
373 if(style != selectDir)
376 type.visible = numTypes ? true : false;
377 typeLabel.visible = numTypes ? true : false;
380 ok.anchor = { right = 10, bottom = 32 + rightOffset - 1 };
383 cancel.anchor = { right = 10, bottom = rightOffset - 1 };
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 };
396 // type.AddField(null);
399 for(c = 0; c<numTypes; c++)
401 DataRow row = type.AddString(types[c].name);
405 if(fileType >= numTypes) fileType = 0;
407 type.currentRow = type.FindRow(fileType);
410 get { return sizeTypes; }
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; } };
418 property int numSelections { get { return numSelections; } };
419 property const char * const * multiFilePaths { get { return (const char * const *)multiFilePaths; } };
426 lookIn.AddField(lookInField);
427 listBox.AddField(nameField);
428 listBox.AddField(typeField);
429 listBox.AddField(sizeField);
431 filter.currentRow = filter.AddString($"All files");
433 GetWorkingDir(currentDirectory, MAX_DIRECTORY);
434 FileFixCase(currentDirectory);
437 for(c = 0; c<FileNameType::enumSize; c++)
439 icons[c] = BitmapResource { iconNames[c], alphaBlend = true };
440 AddResource(icons[c]);
446 char * customExtensions = (char *)customFilter.extensions;
447 delete customExtensions;
448 customFilter.extensions = null;
452 for(c = 0; c<numSelections; c++)
453 delete multiFilePaths[c];
454 delete multiFilePaths;
461 char tmpDir[MAX_FILENAME];
465 FileListing listing { "/" };
471 // Fill the path dropbox
474 row = lookIn.AddRow();
477 fileName.name = rootName;
481 fileName.type = computer;
482 row.SetData(null, fileName);
483 lookIn.currentRow = row;
487 while(listing.Find())
489 row = lookIn.AddRow();
491 fileName.name = listing.name;
492 fileName.type = drive;
493 if(listing.stats.attribs.isCDROM) fileName.type = cdrom;
494 if(listing.stats.attribs.isRemote) fileName.type = netDrive;
495 if(listing.stats.attribs.isRemovable)
497 if(listing.name[0] == 'A' || listing.name[0] == 'B')
498 fileName.type = floppy;
500 fileName.type = removable;
504 row.SetData(null, fileName);
507 if(listing.name[0] == currentDirectory[0] &&
508 listing.name[1] == currentDirectory[1])
511 for(c = start; currentDirectory[c]; )
515 for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
516 for(;(ch = currentDirectory[c]) && (ch != '/' && ch != '\\'); c++)
518 if(len < MAX_FILENAME)
521 for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
526 row = lookIn.AddRow();
527 fileName.name = tmpDir;
528 fileName.type = ch ? folder : folderOpen;
530 row.SetData(null, fileName);
533 lookIn.currentRow = row;
537 lookIn.currentRow = row;
542 row = lookIn.AddRow();
543 fileName.name = msNetwork;
544 fileName.type = network;
546 row.SetData(null, fileName);
547 if(!strcmp(currentDirectory, "\\\\"))
548 lookIn.currentRow = row;
551 if(currentDirectory[0] == '\\' && currentDirectory[1] == '\\')
553 for(c = 2; currentDirectory[c]; )
557 for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
558 for(;(ch = currentDirectory[c]) && (ch != '/' && ch != '\\'); c++)
560 if(len < MAX_FILENAME)
563 for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
568 row = lookIn.AddRow();
569 fileName.name = tmpDir;
571 if(fileName.indent == 1)
572 fileName.type = server;
573 else if(fileName.indent == 2)
574 fileName.type = share;
576 fileName.type = ch ? folder : folderOpen;
577 row.SetData(null, fileName);
580 lookIn.currentRow = row;
583 lookIn.currentRow = row;
589 // flag = false : Get Name From Edit Box, flag = true : Get Name From List Box
590 void GetNameFromListBox(bool flag)
595 if(style == multiOpen)
596 okDisabled = listBox.numSelections == 0;
598 okDisabled = listBox.currentRow == null;
599 if(okDisabled) flag = false;
602 okDisabled = !fileName || !fileName.line.text[0];
604 getNameFromListBox = flag;
605 ok.disabled = okDisabled;
606 open.disabled = okDisabled;
608 if(style == selectDir)
613 ok.caption = $"Select Here";
615 open.isDefault = false;
617 // Never use contents of editbox for 'Select Here'
618 getNameFromListBox = true;
622 ok.caption = $"Select";
623 ok.isDefault = false;
624 open.isDefault = true;
631 FileListing listing { currentDirectory };
636 if(sizeFilters < sizeof(FileFilter) && !fileFilter)
637 listing.extensions = null;
638 else if(filters && fileFilter < sizeFilters / (int)sizeof(FileFilter))
639 listing.extensions = filters[fileFilter].extensions;
641 listing.extensions = customFilter.extensions;
646 while(listing.Find())
648 if(style != selectDir || (listing.stats.attribs.isDirectory))
650 row = listBox.AddRow();
652 fileName.name = listing.name;
653 if(listing.stats.attribs.isDirectory)
655 fileName.type = (listing.stats.attribs.isDrive) ? drive : folder;
656 if(listing.stats.attribs.isServer) fileName.type = server;
657 if(listing.stats.attribs.isShare) fileName.type = share;
658 if(listing.stats.attribs.isCDROM) fileName.type = cdrom;
659 if(listing.stats.attribs.isRemote) fileName.type = netDrive;
660 if(listing.stats.attribs.isRemovable)
662 if(listing.name[0] == 'A' || listing.name[0] == 'B')
663 fileName.type = floppy;
665 fileName.type = removable;
667 row.SetData(nameField, fileName);
668 row.SetData(typeField, null);
672 char extension[MAX_EXTENSION];
674 GetExtension(fileName.name, extension);
675 fileName.type = FileNameType::SelectByExtension(extension);
677 row.SetData(nameField, fileName);
678 row.SetData(typeField, extension);
679 row.SetData(sizeField, listing.stats.size);
685 if(sortOrder && sortField != nameField)
686 listBox.Sort(nameField, 1);
687 listBox.Sort(sortField, sortOrder);
689 GetNameFromListBox(activeChild == listBox);
692 if(!strcmp(currentDirectory, "/"))
695 row = listBox.AddRow();
696 fileName.name = msNetwork;
697 fileName.type = network;
699 row.SetData(nameField, fileName);
700 row.SetData(typeField, null);
702 goUp.disabled = true;
705 goUp.disabled = false;
709 listBox.typingTimeout = 0.5;
713 bool GetNamesFromRow(DataRow row, char ** selectedFileName)
717 if(style == multiOpen)
720 listBox.GetMultiSelection(selection);
726 // First allocate enough memory
727 for(item = selection.first; item; item = item.next)
730 fileName = row.GetData(nameField);
732 if(!strcmp(currentDirectory, "/"))
734 if(!strcmp(fileName->name, msNetwork))
741 totalLen += strlen(fileName->name);
742 if(item != selection.first)
745 if(selection.count > 1) totalLen += 2;
746 *selectedFileName = new char[totalLen + 1];
747 (*selectedFileName)[0] = '\0';
749 // Then build the string
750 for(item = selection.first; item; item = item.next)
753 fileName = row.GetData(nameField);
754 if(item != selection.first) strcat(*selectedFileName, " ");
755 if(selection.count > 1) strcat(*selectedFileName, "\"");
757 if(!strcmp(currentDirectory, "/"))
760 if(!strcmp(fileName->name, msNetwork))
761 strcpy(name, "\\\\");
764 name[0] = fileName->name[0];
765 name[1] = fileName->name[1];
768 strcat(*selectedFileName, name);
772 strcat(*selectedFileName, fileName->name);
773 if(selection.count > 1) strcat(*selectedFileName, "\"");
775 selection.Free(null);
781 fileName = row.GetData(nameField);
785 if(!strcmp(currentDirectory, "/"))
787 *selectedFileName = new char[3];
788 if(!strcmp(fileName->name, msNetwork))
789 strcpy(*selectedFileName, "\\\\");
792 (*selectedFileName)[0] = fileName->name[0];
793 (*selectedFileName)[1] = fileName->name[1];
794 (*selectedFileName)[2] = '\0';
800 *selectedFileName = new char[strlen(fileName->name) + 1];
801 strcpy(*selectedFileName, fileName->name);
809 bool SelectFile(const char * fileName, FileDialogSelectFrom from, bool isOK)
812 FileAttribs exists = 0;
813 char * wildcardPointer = fileName ? strstr(fileName, "*") : null;
817 if(style != selectDir)
819 int numFilters = sizeFilters / sizeof(FileFilter);
820 int numExtensions = 0;
821 char * pointer = wildcardPointer;
825 // Count the number of extensions in requested filter
828 if(pointer[1] == '.' && pointer[2])
832 pointer = strstr(pointer, "*");
836 // Try to match the extension(s) to an existing filter
840 char extension[MAX_EXTENSION], compared[MAX_EXTENSION];
841 for(filter = 0; filter<numFilters; filter++)
843 if(filters[filter].extensions)
848 for(c = 0; filters[filter].extensions[c];)
850 bool matched = false;
853 for(;(ch = filters[filter].extensions[c]) && !IS_ALUNDER(ch); c++);
854 for(;(ch = filters[filter].extensions[c]) && IS_ALUNDER(ch); c++)
855 compared[len++] = ch;
856 compared[len] = '\0';
858 for(d = 0; wildcardPointer[d]; )
861 for(;(ch = wildcardPointer[d]) && !IS_ALUNDER(ch); d++);
862 for(;(ch = wildcardPointer[d]) && IS_ALUNDER(ch); d++)
864 if(len < MAX_EXTENSION)
865 extension[len++] = ch;
867 extension[len] = '\0';
869 if(!strcmpi(extension, compared))
884 if(numMatched == numExtensions)
890 else if(!strcmp(wildcardPointer, "*") || strstr(wildcardPointer, "*.*"))
897 // Only have *.* to check for
898 else if(!strcmp(wildcardPointer, "*") || strstr(wildcardPointer, "*.*"))
901 // If we can't match it, use the custom extension
902 if(this.fileFilter == -1)
904 char extension[MAX_EXTENSION];
906 char * name = new char[numExtensions * (4 + MAX_EXTENSION)];
907 char * customExtensions = (char *)customFilter.extensions;
908 delete customExtensions;
909 customFilter.extensions = null;
911 if(!strcmp(wildcardPointer, "*") || strstr(wildcardPointer, "*.*"))
913 strcpy(name, $"All Files");
914 customFilter.extensions = null;
918 customFilter.extensions = new char[numExtensions * (2 + MAX_EXTENSION)];
919 ((char *)customFilter.extensions)[0] = '\0';
923 for(c = 0; wildcardPointer[c]; )
927 for(;(ch = wildcardPointer[c]) && !IS_ALUNDER(ch); c++);
928 for(;(ch = wildcardPointer[c]) && IS_ALUNDER(ch); c++)
930 if(len < MAX_EXTENSION)
931 extension[len++] = ch;
933 extension[len] = '\0';
938 strcat((char *)customFilter.extensions, ", ");
941 strcat(name, extension);
943 strcat((char *)customFilter.extensions, ".");
945 strcat((char *)customFilter.extensions, extension);
953 customFilterRow = filter.AddRow();
954 customFilterRow.tag = numFilters + 1;
957 customFilterRow.SetData(null, name);
959 fileFilter = numFilters + 1;
964 filter.currentRow = filter.FindRow(fileFilter);
968 *wildcardPointer = '\0';
971 if(style == multiOpen)
975 bool needQuotes = strchr(fileName, '\"') != null;
976 char currentFileName[MAX_LOCATION], * curFileName = currentFileName;
978 OldList selections { };
979 OldLink selection = null;
991 (*curFileName) = '\0';
993 selection = OldLink { data = new char[strlen(currentFileName)+1] };
994 strcpy(selection.data, currentFileName);
995 selections.Add(selection);
997 curFileName = currentFileName;
1002 if(needQuotes && !quoted)
1005 *(curFileName++) = ch;
1011 multiFilePaths = new char *[selections.count];
1013 for(selection = selections.first; selection; selection = selection.next)
1015 char * fileName = selection.data;
1018 strcpy(currentFileName, currentDirectory);
1019 if(PathCat(currentFileName, fileName))
1021 FileFixCase(currentFileName);
1022 exists = FileExists(currentFileName);
1023 if(exists.isDirectory)
1025 strcpy(currentDirectory, currentFileName);
1029 else if(exists || mayNotExist)
1031 char ** path = &multiFilePaths[numSelections++];
1032 *path = new char[strlen(currentFileName)+1];
1033 strcpy(*path, currentFileName);
1037 if(exists && result && from == fromListBox) // From List Box
1039 char pathName[MAX_LOCATION];
1040 GetLastDirectory(this.fileName.line.text, pathName);
1041 this.fileName.Clear();
1042 if(!exists.isDirectory)
1043 this.fileName.PutS(pathName);
1048 selections.Free(OldLink::Free);
1053 for(c = 0; c<numSelections; c++)
1054 if(multiFilePaths[c])
1055 delete multiFilePaths[c];
1056 delete multiFilePaths;
1062 strcpy(filePath, currentDirectory);
1063 if((style == selectDir && !fileName) || PathCat(filePath, fileName) || style == selectDir)
1065 FileFixCase(filePath);
1066 exists = FileExists(filePath);
1067 if(exists.isDirectory && (style != selectDir || !isOK))
1069 strcpy(currentDirectory, filePath);
1075 // *** SAVING ONLY ****
1078 if(fileType >= 0 && fileType < sizeTypes)
1080 FileType type = types[fileType];
1081 if(type.forceExtension && type.typeExtension)
1083 char extension[MAX_EXTENSION];
1084 GetExtension(filePath, extension);
1085 if(type.forceExtension == always || !extension[0])
1087 ChangeExtension(filePath, type.typeExtension, filePath);
1088 exists = FileExists(filePath);
1092 if(!exists || MessageBox { master = this, type = yesNo, text = $"File Already Exists", contents = $"Replace existing file?" }.Modal() == yes)
1095 else if(exists || mayNotExist)
1097 if(style != selectDir ||
1098 (strcmp(filePath, "\\\\") &&
1099 strcmp(filePath, "\\\\") &&
1100 !(exists.isServer)))
1103 // *** DIRECTORY SELECTION ONLY ****
1104 else if(isOK && style == selectDir &&
1105 MessageBox { this, type = yesNo, text = $"Directory doesn't exist", contents = $"Create directory?" }.Modal() == yes)
1107 if(MakeDir(filePath))
1112 if(exists && result && from == fromListBox) // From List Box
1114 char pathName[MAX_LOCATION];
1115 GetLastDirectory(this.fileName.line.text, pathName);
1116 this.fileName.Clear();
1117 if(!exists.isDirectory)
1118 this.fileName.PutS(pathName);
1123 if(result && !exists && from == fromDropBox) // drive Drop Box
1129 Destroy(DialogResult::ok);
1138 for(c = 0; c<numSelections; c++)
1139 delete multiFilePaths[c];
1140 delete multiFilePaths;
1146 // Fix up config input directory
1147 char fileName[MAX_FILENAME];
1148 #if defined(__WIN32__)
1149 char * dirOccur = SearchString(filePath, 0, currentDirectory, false, false);
1151 char * dirOccur = strstr(filePath, currentDirectory);
1155 dirOccur += strlen(currentDirectory);
1156 for(;*dirOccur && (*dirOccur == '/' || *dirOccur == '\\'); dirOccur++);
1157 strcpy(fileName, dirOccur);
1160 strcpy(fileName, filePath);
1162 this.fileName.Clear();
1163 this.fileName.PutS(fileName);
1166 GetNameFromListBox(false);
1168 fileName.MakeActive();
1172 FileDialogType style;
1173 FileFilter customFilter;
1174 DataRow customFilterRow;
1175 bool getNameFromListBox;
1176 BitmapResource icons[FileNameType];
1178 char currentDirectory[MAX_DIRECTORY];
1179 char filePath[MAX_LOCATION];
1180 FileFilter * filters;
1184 int fileFilter, fileType;
1187 char ** multiFilePaths;
1190 // ListBox Configuration
1191 DataField sortField;
1194 // File Extension Filter
1197 this, text = $"Filter:", anchor = { left = 96, right = 104, bottom = 16 }, hotKey = altR;
1199 bool NotifySelect(DropBox control, DataRow row, Modifiers mods)
1201 fileFilter = (int)(row ? row.tag : 0);
1209 this, inactive = true, anchor = { left = 8, bottom = 3 + 16 }, labeledWindow = filter
1215 this, text = $"As Type:", visible = false, anchor = { left = 96, right = 104, bottom = 16 }, hotKey = altT;
1217 bool NotifySelect(DropBox control, DataRow row, Modifiers mods)
1219 char * selectedFileName = null;
1220 fileType = (int)(row ? row.tag : 0);
1221 if(style == save && types && types[fileType].typeExtension)
1223 if(getNameFromListBox)
1225 if(GetNamesFromRow(listBox.currentRow, &selectedFileName))
1230 const char * fileName = this.fileName.line.text;
1231 //selectedFileName = new char[strlen(fileName)+1]; // Room to change extension???
1232 selectedFileName = new char[MAX_FILENAME];
1233 strcpy(selectedFileName, fileName);
1235 ChangeExtension(selectedFileName, types[fileType].typeExtension, selectedFileName);
1236 fileName.Select(null,0,0, null,0,0);
1237 fileName.PutS(selectedFileName);
1238 GetNameFromListBox(false);
1240 delete selectedFileName;
1247 this, inactive = true, visible = false, anchor = { left = 8, bottom = 19 }, labeledWindow = type;
1253 this, isDefault = true, text = $"OK", anchor = { right = 10, bottom = 32 + 16 - 1 }, size = { 80 };
1255 bool NotifyClicked(Button control, int x, int y, Modifiers mods)
1258 char * selectedFileName = null;
1259 if(getNameFromListBox)
1261 GetNamesFromRow(listBox.currentRow, &selectedFileName);
1262 result = SelectFile(selectedFileName, fromListBox, control.id == DialogResult::ok);
1263 if(result && style == selectDir)
1264 listBox.MakeActive();
1268 const char * fileName = this.fileName.line.text;
1269 selectedFileName = new char[strlen(fileName)+1];
1270 strcpy(selectedFileName, fileName);
1271 result = SelectFile(selectedFileName, fromEditBox, control.id == DialogResult::ok);
1272 if(result && style == selectDir)
1273 this.fileName.MakeActive();
1275 delete selectedFileName;
1280 // Open Button (SelectDir only)
1283 this, visible = false, text = $"Open", hotKey = altO, anchor = { right = 100, bottom = 16 - 1 }, size = { 80 };
1284 NotifyClicked = ok.NotifyClicked;
1290 this, text = $"Cancel", anchor = { right = 10, bottom = 16 - 1 }, size = { 80 }, hotKey = escape;
1291 bool NotifyClicked(Button control, int x, int y, Modifiers mods)
1293 Destroy(DialogResult::cancel);
1301 this, text = $"Look in:", anchor = { left = 81, top = 8, right = 109 }, hotKey = altL, maxShown = 12;
1303 bool OnKeyHit(Key key, unichar ch)
1305 if(key == wheelDown || key == wheelUp)
1307 ((FileDialog)master).listBox.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, key, ch);
1313 bool NotifySelect(DropBox control, DataRow row, Modifiers mods)
1317 FileName * fileName = row.GetData(null);
1318 char name[MAX_LOCATION] = "/";
1322 if(!strcmp(fileName->name, msNetwork) ||
1323 (currentDirectory[0] == '\\' &&
1324 currentDirectory[1] == '\\' &&
1325 strcmp(fileName->name, rootName) &&
1326 (!fileName->name[0] || fileName->name[1] != ':')))
1328 strcpy(name, "\\\\");
1333 if(fileName->indent > 1)
1335 name[0] = currentDirectory[0];
1341 else if(fileName->indent == 1)
1343 name[0] = fileName->name[0];
1351 if(indent < fileName->indent)
1353 for(; currentDirectory[c]; )
1357 char directory[MAX_FILENAME];
1358 for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
1359 for(;(ch = currentDirectory[c]) && (ch != '/' && ch != '\\'); c++)
1361 if(len < MAX_FILENAME)
1362 directory[len++] = ch;
1364 for(;(ch = currentDirectory[c]) && (ch == '/' || ch == '\\'); c++);
1365 directory[len] = '\0';
1367 if(indent >= fileName->indent) break;
1368 PathCat(name, directory);
1373 SelectFile(name, fromDropBox, false);
1379 DataField lookInField { dataType = "FileName", userData = this };
1383 this, position = { 10, 11 }, labeledWindow = lookIn;
1389 this, borderStyle = deep, hasVertScroll = true, hasHorzScroll = true,
1390 anchor = { left = 8, right = 8, top = 40, bottom = 64 + 16 },
1391 hasHeader = true, moveFields = true, resizable = true, sortable = true;
1393 bool NotifySelect(ListBox control, DataRow row, Modifiers mods)
1395 GetNameFromListBox(true);
1399 bool NotifyDoubleClick(ListBox control, int x, int y, Modifiers mods)
1402 char * selectedFileName = null;
1403 if(GetNamesFromRow(control.currentRow, &selectedFileName))
1405 result = SelectFile(selectedFileName, fromEditBox, false);
1407 delete selectedFileName;
1411 bool NotifyKeyDown(ListBox control, DataRow row, Key key, unichar ch)
1413 if(key == backSpace)
1415 if(strcmp(currentDirectory, "/"))
1416 goUp.NotifyClicked(this, goUp, 0,0, key.modifiers);
1421 bool NotifySort(ListBox control, DataField field, Modifiers mods)
1424 sortOrder = field.sortOrder;
1428 bool NotifyActivate(Window control, bool active, Window previous)
1431 GetNameFromListBox(true);
1436 DataField nameField { header = $"Name", dataType = "FileName", width = 304, userData = this }; // editable = true
1437 DataField typeField { header = $"Type", dataType = /*"String"*/ "char *", width = 40 };
1438 DataField sizeField { header = $"Size", dataType = "FileSize", width = 96, alignment = right };
1443 this, inactive = true, anchor = { right = 79, top = 8 }, size = { 24, 24 },
1444 bitmap = { "<:ecere>actions/goUp.png", alphaBlend = true };
1447 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1450 notRoot = StripLastDirectory(currentDirectory, currentDirectory);
1452 strcpy(currentDirectory, "/");
1458 Button createDirectory
1460 this, inactive = true, anchor = { right = 51, top = 8 }, size = { 24, 24 },
1461 bitmap = { "<:ecere>actions/folderNew.png", alphaBlend = true };
1462 symbol = 30; // what the heck is that?
1464 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1466 if(CreateDirectoryDialog { master = this, parent = parent, currentDirectory = currentDirectory }.Modal() == ok )
1472 // File name editbox
1475 this, text = $"File Name:", anchor = { left = 96, bottom = 32 + 16, right = 104 }, size.h = 20, hotKey = altF;
1477 bool NotifyActivate(Window control, bool active, Window previous)
1481 char * selectedFileName = null;
1482 const char * editText;
1483 if(getNameFromListBox)
1485 DataRow row = listBox.currentRow;
1488 if(GetNamesFromRow(row, &selectedFileName))
1491 fileName.PutS(selectedFileName);
1492 fileName.Select(null,0,0, null,0,0);
1494 GetNameFromListBox(false);
1497 delete selectedFileName;
1498 editText = fileName.contents;
1499 if(style != selectDir)
1500 ok.disabled = !editText || !editText[0];
1505 void NotifyUpdate(EditBox control)
1507 GetNameFromListBox(false);
1513 this, inactive = true, anchor = { left = 8, bottom = 35 + 16 };
1514 labeledWindow = fileName;
1518 public class CreateDirectoryDialog : Window
1520 background = formColor;
1521 minClientSize = Size { 240, 100 };
1524 text = $"Create Directory";
1528 property const char * currentDirectory
1532 GetWorkingDir(currentDirectory, MAX_DIRECTORY); // is this necessary?
1533 PathCat(currentDirectory, value);
1534 FileFixCase(currentDirectory);
1536 get { return (char *)currentDirectory; }
1541 char currentDirectory[MAX_DIRECTORY];
1543 CreateDirectoryDialog()
1545 GetWorkingDir(currentDirectory, MAX_DIRECTORY);
1546 FileFixCase(currentDirectory);
1549 ~CreateDirectoryDialog()
1555 newDirectoryName.SelectAll();
1561 parent = this, isDefault = true, position = { 70, 60 }, size = { 60 }, text = $"OK";
1562 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1564 if(newDirectoryName.contents && newDirectoryName.contents[0])
1566 char newDirPath[MAX_DIRECTORY];
1567 strcpy(newDirPath, currentDirectory);
1568 PathCat(newDirPath, newDirectoryName.contents);
1569 if(!FileExists(newDirPath).isDirectory)
1571 MakeDir(newDirPath);
1572 Destroy(DialogResult::ok);
1575 MessageBox { master = this, parent = parent, type = ok, text = $"Create Directory Error", contents = $"Directory already exists." }.Modal();
1578 MessageBox { master = this, parent = parent, type = ok, text = $"Create Directory Error", contents = $"Please enter a name." }.Modal();
1585 parent = this, position = { 140, 60 }, size = { 60 }, hotKey = escape, text = $"Cancel";
1586 NotifyClicked = ButtonCloseDialog;
1589 EditBox newDirectoryName
1591 this, textHorzScroll = true, anchor = { left = 10, right = 10, top = 30 }, size = { 250 };
1592 hotKey = altN, text = $"Name";
1593 contents = $"New Directory";
1595 Label { this, position = { 10, 10 }, labeledWindow = newDirectoryName };