public import "ecere" #ifdef __WIN32__ static char * rootName = "Entire Computer"; static char * msNetwork = "Microsoft Windows Network"; #else static char * rootName = "File System"; #endif private: define guiApp = ((GuiApplication)__thisModule); define selectionColor = guiApp.currentSkin.selectionColor; //Color { 10, 36, 106 }; static char * fileIconNames[] = { "<:ecere>mimeTypes/file.png", /* none */ "<:ecere>mimeTypes/file.png", /* normalFile */ "<:ecere>mimeTypes/textEcereWorkspace.png", /* ewsFile */ "<:ecere>mimeTypes/textEcereProject.png", /* epjFile */ "<:ecere>mimeTypes/textEcereSource.png", /* ecFile */ "<:ecere>mimeTypes/textEcereHeader.png", /* ehFile */ "<:ecere>mimeTypes/textCSource.png", /* cFile */ "<:ecere>mimeTypes/textCHeader.png", /* hFile */ "<:ecere>mimeTypes/textC++Source.png", /* cppFile */ "<:ecere>mimeTypes/textC++Header.png", /* hppFile */ "<:ecere>mimeTypes/text.png", /* textFile */ "<:ecere>mimeTypes/textHyperTextMarkup.png", /* webFile */ "<:ecere>mimeTypes/image.png", /* pictureFile */ "<:ecere>status/audioVolumeHigh.png", /* soundFile */ "<:ecere>mimeTypes/package.png", /* archiveFile */ "<:ecere>mimeTypes/packageSoftware.png", /* packageFile */ "<:ecere>mimeTypes/packageOpticalDisc.png", /* opticalMediaImageFile */ "<:ecere>places/folder.png", /* folder */ "<:ecere>status/folderOpen.png", /* folderOpen */ "<:ecere>devices/computer.png", /* computer */ "<:ecere>devices/driveHardDisk.png", /* drive */ "<:ecere>places/driveRemote.png", /* netDrive */ "<:ecere>devices/mediaOptical.png", /* cdrom */ "<:ecere>devices/driveRemovableMedia.png", /* removable */ "<:ecere>devices/mediaFloppy.png", /* floppy */ "<:ecere>places/networkWorkgroup.png", /* network */ "<:ecere>places/networkServer.png", /* server */ "<:ecere>places/folderRemote.png", /* share */ "<:ecere>mimeTypes/package.png", /* treeLoader */ "<:ecere>places/startHere.png", /* lineNumbers */ "" }; public enum ExplorerFileType { none, normalFile, ewsFile, epjFile, ecFile, ehFile, cFile, hFile, cppFile, hppFile, textFile, webFile, pictureFile, soundFile, archiveFile, packageFile, opticalMediaImageFile, /* these (all previous) are sort equal */ folder, folderOpen, computer, drive, netDrive, cdrom, removable, floppy, network, server, share, // these are sort equal // utilities treeLoader, lineNumbers; /*property char * { set { this = SelectByExtension(value); } }*/ public property bool isFolderType { get { return this >= folder && this <= share; } } public property bool isFileType { get { return this >= normalFile && this <= opticalMediaImageFile; } } ExplorerFileType ::SelectByExtension(char * extension) { if(!strcmpi(extension, "ews")) return ewsFile; else if(!strcmpi(extension, "epj")) return epjFile; else if(!strcmpi(extension, "ec")) return ecFile; else if(!strcmpi(extension, "eh")) return ehFile; else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")) return cppFile; else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") || !strcmpi(extension, "hxx")) return hppFile; else if(!strcmpi(extension, "c")) return cFile; else if(!strcmpi(extension, "h")) return hFile; else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") || !strcmpi(extension, "nfo") || !strcmpi(extension, "info")) return textFile; else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") || !strcmpi(extension, "css") || !strcmpi(extension, "php") || !strcmpi(extension, "js")) return webFile; else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") || !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") || !strcmpi(extension, "gif") || !strcmpi(extension, "png") || !strcmpi(extension, "ico")) return pictureFile; else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") || !strcmpi(extension, "ogg") || !strcmpi(extension, "snd")) return soundFile; else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") || !strcmpi(extension, "rar") || !strcmpi(extension, "zip") || !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") || !strcmpi(extension, "tar") || !strcmpi(extension, "arj") || !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") || !strcmpi(extension, "cpio") || !strcmpi(extension, "z")) return archiveFile; else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") || !strcmpi(extension, "rpm")) return packageFile; else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") || !strcmpi(extension, "cue") || !strcmpi(extension, "bin") || !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") || !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg")) return opticalMediaImageFile; return normalFile; } }; class ExplorerControl : Window { bool previewPictures; BitmapResource fileIcons[ExplorerFileType]; ExplorerControl() { ExplorerFileType c; for(c = 0; c < ExplorerFileType::enumSize; c++) { fileIcons[c] = BitmapResource { fileIconNames[c], alphaBlend = true }; AddResource(fileIcons[c]); } } } #if 0 class ExplorerView : ExplorerControl { borderStyle = none; hasHorzScroll = false; hasVertScroll = false; virtual void Load(FileSystemNode parent); virtual void Refresh(); virtual void LaunchNotifyItemSelect(Window master, ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems) { view.NotifyItemSelect(master, view, item, selectedItems); } virtual bool Window::NotifyItemSelect(ExplorerView view, ExplorerFileItem item, ExplorerFileItemArray selectedItems); virtual bool Window::NotifyItemOpen(ExplorerView view, ExplorerFileItem item); ListBox list { master = master, parent = this; //this, master; borderStyle = none; hasHorzScroll = true; hasVertScroll = true; resizable = true; sortable = true; fullRowSelect = false; multiSelect = true; anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 }; bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods) { ExplorerView view = (ExplorerView)listBox.parent; if(listBox.currentRow) { DataRow listRow; ExplorerFileItemArray selectedItems { growingFactor = 16 }; for(listRow = listBox.firstRow; listRow; listRow = listRow.next) if(listRow.selected) selectedItems.Add((ExplorerFileItem)listRow.tag); //view.NotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag); view.LaunchNotifyItemSelect(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag, selectedItems); } return true; } bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods) { ExplorerView view = (ExplorerView)listBox.parent; view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag); return false; } bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch) { if((SmartKey)key == enter) { ExplorerView view = (ExplorerView)listBox.parent; view.NotifyItemOpen(listBox.parent.master, view, (ExplorerFileItem)listBox.currentRow.tag); } return true; } }; ExplorerView() { } } #endif #if 0 class ExplorerViewList : ExplorerView { FileSystemNode location; public: DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this }; ExplorerViewDetails() { list.AddField(nameField); } void Refresh() { Load(location); } void Load(FileSystemNode location) { char path[MAX_LOCATION]; this.location = location; location.GetPath(path); { FileListing listing { path }; ExplorerFileItem item; DataRow row; list.Clear(); while(listing.Find()) { item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem); row = list.AddRow(); row.tag = (int)item; row.SetData(nameField, item); } list.Sort(nameField, 1); } } } #endif #if 0 class ExplorerViewDetails : ExplorerView { list.hasHeader = true; list.moveFields = true; list.resizable = true; list.sortable = true; FileSystemNode location; public: DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this }; DataField typeField { header = "Type", dataType = /*"String"*/ "char *", width = 40 }; DataField sizeField { header = "Size", dataType = "FileSize", width = 96, alignment = right }; ExplorerViewDetails() { list.AddField(nameField); list.AddField(typeField); list.AddField(sizeField); } void Refresh() { Load(location); } void Load(FileSystemNode location) { char path[MAX_LOCATION]; this.location = location; location.GetPath(path); { FileListing listing { path }; ExplorerFileItem item; DataRow row; list.Clear(); while(listing.Find()) { item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem); row = list.AddRow(); row.tag = (int)item; row.SetData(nameField, item); row.SetData(typeField, CopyString(item.extension)); row.SetData(sizeField, (uint)listing.stats.size); } list.Sort(nameField, 1); } } } #endif #if 0 class ExplorerViewIcons : ExplorerView { FileSystemNode location; public: DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this }; ExplorerViewDetails() { list.AddField(nameField); } void Refresh() { Load(location); } void Load(FileSystemNode location) { char path[MAX_LOCATION]; this.location = location; location.GetPath(path); { FileListing listing { path }; ExplorerFileItem item; DataRow row; list.Clear(); while(listing.Find()) { item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem); row = list.AddRow(); row.tag = (int)item; row.SetData(nameField, item); } list.Sort(nameField, 1); } } } #endif #if 0 class ExplorerViewCards : ExplorerView { FileSystemNode location; public: DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this }; ExplorerViewDetails() { list.AddField(nameField); } void Refresh() { Load(location); } void Load(FileSystemNode location) { char path[MAX_LOCATION]; this.location = location; location.GetPath(path); { FileListing listing { path }; ExplorerFileItem item; DataRow row; list.Clear(); while(listing.Find()) { item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem); row = list.AddRow(); row.tag = (int)item; row.SetData(nameField, item); } list.Sort(nameField, 1); } } } #endif #if 0 public class BitmapArray : RedjArray { type = class(Bitmap); public: Bitmap * const _; Bitmap * Add(Bitmap bitmap) { uint pos = _count; Append(1); _[pos] = bitmap; return &_[pos]; } Bitmap * AddBefore(uint position, Bitmap bitmap) { Insert(position, 1); _[position] = bitmap; return &_[position]; } void Clear() { int c; for(c = 0; c < _count; c++) { _[c].Free(); delete _[c]; } count = 0; size = 0; } } #endif #if 0 class ExplorerViewShowcase : ExplorerView { list.anchor = Anchor { left = 0, top = 0, bottom = 0 }; list.size = Size { w = 200 }; FileSystemNode location; public: DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 180, editable = true, userData = this }; Bitmap bitmap; BitmapArray bitmaps { growingFactor = 16 }; Window show { this; borderStyle = none; anchor = Anchor { top = 0, right = 0, bottom = 0 }; void OnRedraw(Surface surface) { ExplorerViewShowcase view = (ExplorerViewShowcase)parent; if(view.bitmap) { int wBmp = view.bitmap.width; int hBmp = view.bitmap.height; int wWnd = clientSize.w; int hWnd = clientSize.h; int wList = view.list.size.w + view.split.size.w; float scale = Min((float)(wWnd - 10) / wBmp, (float)(hWnd - 10) / hBmp); int wDraw = (int)(wBmp * scale); int hDraw = (int)(hBmp * scale); #ifndef __linux__ surface.Filter(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw, wBmp, hBmp); #else // Until Filter / Stretch works with X surface.Blit(view.bitmap, (wWnd - wDraw) / 2, (hWnd - hDraw) / 2, 0, 0, wDraw, hDraw); #endif } else { surface.SetForeground(white); surface.Area(0, 0, view.clientSize.w - 1, view.clientSize.h - 1); } } } SplitWindow split { this; leftPane = list; rightPane = show; split = 200; tabCycle = true; }; ExplorerViewDetails() { list.AddField(nameField); } void LaunchNotifyItemSelect(Window master, ExplorerViewShowcase view, ExplorerFileItem item, ExplorerFileItemArray selectedItems) { int pos; ExplorerFileItem selItem; if(view.bitmap) view.bitmap.Free(); delete view.bitmap; if(item && item.type == pictureFile) { view.bitmap = Bitmap { }; view.bitmap.Load(item.path, null, displaySystem); } view.bitmaps.Clear(); view.bitmaps = BitmapArray { }; for(pos = 0; pos < selectedItems.count; pos++) { Bitmap bitmap { }; selItem = (ExplorerFileItem)selectedItems._[pos]; bitmap.Load(selItem.path, null, displaySystem); //view.bitmaps.Add(bitmap); } if(item && item.type == pictureFile) { view.bitmap = Bitmap { }; view.bitmap.Load(item.path, null, displaySystem); } view.show.Update(null); view.NotifyItemSelect(master, view, item, selectedItems); } void Refresh() { Load(location); } void Load(FileSystemNode location) { char path[MAX_LOCATION]; this.location = location; location.GetPath(path); { FileListing listing { path }; ExplorerFileItem item; DataRow row; list.Clear(); while(listing.Find()) { item = MakeFileItem(listing.stats.attribs, listing.name, listing.path, previewPictures, displaySystem); row = list.AddRow(); row.tag = (int)item; row.SetData(nameField, item); } list.Sort(nameField, 1); } } } #endif #if 0 class ExplorerTree : ExplorerControl { hasHorzScroll = false; hasVertScroll = false; menu = Menu { }; public: DataField nameField { dataType = "FileSystemNode", width = 240, userData = this }; FileSystemNode root; FileSystemNode selection; virtual bool Window::NotifyNodeSelect(ExplorerTree tree, FileSystemNode node); property FileSystemNode node { get { if(!tree) return null; if(!tree.currentRow) return null; if(!tree.currentRow.tag) return null; return (FileSystemNode)tree.currentRow.tag; } } void Select(FileSystemNode node) { if(node.row) { node.EnsureVisible(false); tree.SelectRow(node.row); } } FileSystemNode Find(const char * name, FileSystemNode parent) { FileSystemNode node; FileSystemNode start = parent ? parent : root; if(!start.loaded || !start.childrenLoaded) NodeLoad(start, tree); for(node = start.children.first; node; node = node.next) if(node.name && !strcmpi(node.name, name)) return node; return null; } ListBox tree { master = master, parent = this; //this, master; borderStyle = none; hasHorzScroll = true; hasVertScroll = true; fullRowSelect = false; treeNodees = true; collapseControl = true; rootCollapseButton = true; anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 }; // WHY is this not working ? /*void OnResize(int width, int height) { if(vertScroll.visible) nameField.width = width - vertScroll.size.w; else nameField.width = width; }*/ bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed) { if(row) { FileSystemNode node = (FileSystemNode)row.tag; FileSystemNode child; if(collapsed) { /* for(child = node.children.last; child; child = node.children.last) { listBox.DeleteRow(child.row); child.Free(); delete child; } node.childrenLoaded = false; */ } else { if(!node.loaded || !node.childrenLoaded) NodeLoad(node, tree); for(child = node.children.first; child && child.next; child = child.next); if(child) child.EnsureVisible(false); } } return true; } bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods) { DataRow row = listBox.currentRow; if(row) { FileSystemNode node = (FileSystemNode)row.tag; if(node) { PopupMenu popup; Menu menu { }; MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false }; MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false }; MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /*!clipboard*/ }; MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false }; //MenuDivider { menu }; popup = PopupMenu { master = this, menu = menu, position = { x + clientStart.x + absPosition.x - guiApp.desktop.position.x, y + clientStart.y + absPosition.y - guiApp.desktop.position.y } }; popup.Create(); } } return true; } bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods) { if(row) { FileSystemNode node = (FileSystemNode)row.tag; NotifyNodeSelect(listBox.parent.master, this, node); selection = node; } return true; } bool NotifyEditing(ListBox listBox, DataRow row) { if(row) { FileSystemNode node = (FileSystemNode)row.tag; } return true; } bool NotifyEdited(ListBox listBox, DataRow row) { if(row) { FileSystemNode node = (FileSystemNode)row.tag; } return true; } bool NotifyEditDone(ListBox listBox, DataRow row) { if(row) { FileSystemNode node = (FileSystemNode)row.tag; } return true; } }; // Edit Menu Menu editMenu { menu, "Edit", e }; MenuItem itemEditCut { editMenu, "Cut\tCtrl+X", t, disabled = true; bool NotifySelect(MenuItem selection, Modifiers mods) { //EditCut(); return true; } }; MenuItem itemEditCopy { editMenu, "Copy\tCtrl+C", c, disabled = true; bool NotifySelect(MenuItem selection, Modifiers mods) { //EditCopy(); return true; } }; MenuItem itemEditPaste { editMenu, "Paste\tCtrl+V", p; bool NotifySelect(MenuItem selection, Modifiers mods) { //EditPaste(); return true; } }; MenuItem itemEditDelete { editMenu, "Delete\tDel", d, disabled = true; bool NotifySelect(MenuItem selection, Modifiers mods) { //EditDelete(); return true; } }; // WHY is this crashing ? /*void OnResize(int width, int height) { if(this && nameField) nameField.width = width - 80; }*/ ExplorerTree() { tree.AddField(nameField); } void Load() { FileSystemNode parent; FileSystemNode node; FileListing listing { "/" }; tree.Clear(); root = FileSystemNode { type = computer, loaded = true, childrenLoaded = true }; #ifdef __WIN32__ root.name = rootName; #else root.name = "/"; #endif AddNode(root, true, false, null, tree); // How can this make sense for linux? #ifdef __WIN32__ while(listing.Find()) { int len = strlen(listing.name); char info[MAX_LOCATION]; char name[MAX_LOCATION]; if(listing.stats.attribs.isDrive && len > 3 && !strncmp(&listing.name[1], ": [", 3)) { strncpy(name, listing.name, 2); name[2] = 0; strncpy(info, &listing.name[4], len - 5); info[len - 5] = 0; } else { strcpy(name, listing.name); info[0] = 0; } parent = MakeFileNode(listing.stats, name); if(info[0]) parent.info = CopyString(info); parent.loaded = true; AddNode(parent, !listing.stats.attribs.isDirectory, listing.stats.attribs.isDirectory, root, tree); if(!listing.stats.attribs.isDirectory) parent.childrenLoaded = true; } node = FileSystemNode { name = msNetwork, type = network }; AddNode(node, false, true, null, tree); node.row.collapsed = true; tree.Sort(nameField, 1); tree.SelectRow(root.row); #endif } /* public class ClipBoardFiles { public: property } // CLIPBOARD void Copy() { if(this) { int size = SelSize(); if(size) { // Try to allocate memory ClipBoard clipBoard { }; if(clipBoard.Allocate(size+1)) { GetSel(clipBoard.memory, true); // Save clipboard clipBoard.Save(); } delete clipBoard; } } } void Paste() { if(this) { ClipBoard clipBoard { }; if(clipBoard.Load()) PutS(clipBoard.memory); delete clipBoard; } } void Cut() { if(this) { Copy(); DelSel(); SetViewToCursor(true); Modified(); } } Private Type DROPFILES pFiles As Long pt As POINTAPI fNC As Long fWide As Long End Type For iCounter = 0 To filelist.ListCount - 1 If filelist.Selected(iCounter) = True Then strFiles = strFiles & FixPath(filelist.Path) & filelist.List(iCounter) & vbNullChar End If Next 'all selected items are now put in strFiles hGlobal = GlobalAlloc(GHND, Len(DF) + Len(strFiles)) 'put all files to a exclusive number If hGlobal Then 'if the globalalloc worked lpGlobal = GlobalLock(hGlobal) 'lock the hGlobal DF.pFiles = Len(DF) 'set the size of the files Call CopyMem(ByVal lpGlobal, DF, Len(DF)) 'copy df to the lpglobal Call CopyMem(ByVal (lpGlobal + Len(DF)), ByVal strFiles, Len(strFiles)) 'copy strfiles to lpglobal Call GlobalUnlock(hGlobal) 'unlock hglobal again SetClipboardData CF_HDROP, hGlobal 'put files to the clipboard End If bool SaveFile(const char * filePath) { } */ } #endif #if 0 public class FileTreeNodeBSArray : ArrayBinarySorted { type = class(FileSystemNode); public: FileSystemNode * const _; BSloc Add(FileSystemNode item) { BSloc result = Find(item); if(!result.valid) { Insert(result.pos, 1); _[result.pos] = item; } return result; } BSloc Remove(FileSystemNode item) { } } #endif #if 0 public class FileTreeNodeArray : RedjArray { type = class(FileSystemNode); public: FileSystemNode * const _; FileSystemNode * Add(FileSystemNode item) { uint pos = _count; Append(1); _[pos] = item; return &_[pos]; } FileSystemNode * AddBefore(uint position, FileSystemNode item) { Insert(position, 1); _[position] = item; return &_[position]; } } #endif #if 0 public class ExplorerFileItem : struct { char * path; char * name; char * info; char * extension; ExplorerFileType type; int indent; Bitmap bitmap; void OnDisplay(Surface surface, int x, int y, int width, ExplorerControl control, Alignment alignment, DataDisplayFlags displayFlags) { int indentSize = (displayFlags.dropBox) ? 0 : 10; int textOffset; int len; char label[MAX_FILENAME]; //float scale = Min((float)clientSize.w / (float)bitmap.width, (float)clientSize.h / (float)bitmap.height); int w = 16; //(int)(bitmap.width * scale); int h = 16; //(int)(bitmap.height * scale); Bitmap icon; icon = control.fileIcons[type].bitmap; if(!icon) { if(type == folder || type == folderOpen) surface.SetForeground(red); //Color { 170, 170, 0 } // REDJ What is that color? indentSize = 8; } textOffset = indent * indentSize + (icon ? (icon.width + 6) : 0); if(info) sprintf(label, "%s [%s]", name, info); else strcpy(label, name); len = strlen(label); surface.WriteTextDots (alignment, x + textOffset, y + 2, width - textOffset, label, len); if(type == pictureFile && control.previewPictures && bitmap) { #ifndef __linux__ //surface.Filter(bitmap, (clientSize.w - w) / 2,(clientSize.h - h) / 2, 0,0, w, h, bitmap.width, bitmap.height); surface.Filter(bitmap, x + indent * indentSize + 2, y, 0, 0, w, h, bitmap.width, bitmap.height); #else // Until Filter / Stretch works with X //surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2,(clientSize.h - bitmap.height) / 2, 0,0, bitmap.width, bitmap.height); surface.blend = true; surface.Blit(bitmap, x + indent * indentSize + 2, y,0,0, w, h); #endif //bitmap.Free(); //delete bitmap; } else if(icon) surface.Blit(icon, x + indent * indentSize + 2, y,0,0, icon.width, icon.height); } int OnCompare(ExplorerFileItem b) { int result; if(type == b.type || (type < folder && b.type < folder) || (type >= drive)) result = strcmpi(name, b.name); else { if(type == folder && b.type < folder) result = -1; else if(type < folder && b.type == folder) result = 1; } return result; } void OnCopy(ExplorerFileItem newData) { type = newData.type; indent = newData.indent; if(newData.name) { int len = strlen(newData.name) + 1; name = new char[len]; CopyBytes(name, newData.name, len); } } bool OnGetDataFromString(char * string) { int len = strlen(string) + 1; name = new char[len]; CopyBytes(name, string, len); return true; } void OnFree() { delete path; delete name; delete info; delete extension; if(bitmap) bitmap.Free(); } char * OnGetString(char * string, void * fieldData, bool * needClass) { return name; } }; public class ExplorerFileItemArray : RedjArray { type = class(ExplorerFileItem); public: ExplorerFileItem * const _; ExplorerFileItem * Add(ExplorerFileItem item) { uint pos = _count; Append(1); _[pos] = item; return &_[pos]; } ExplorerFileItem * AddBefore(uint position, ExplorerFileItem item) { Insert(position, 1); _[position] = item; return &_[position]; } void Clear() { int c; for(c = 0; c < _count; c++) { //_[c].Free() delete _[c]; } count = 0; size = 0; } } ExplorerFileItem MakeFileItem(const FileAttribs attribs, const char * fileName, const char * filePath, const bool previewPicture, const DisplaySystem displaySystem) { int len = strlen(fileName); char info[MAX_LOCATION]; char name[MAX_LOCATION]; char extension[MAX_EXTENSION]; ExplorerFileItem item { }; //if(attribs.isFile) // TODO fix this in ecere if(attribs.isDirectory) { extension[0] = 0; item.type = (attribs.isDrive) ? drive : folder; if(attribs.isServer) item.type = server; if(attribs.isShare) item.type = share; if(attribs.isCDROM) item.type = cdrom; if(attribs.isRemote) item.type = netDrive; if(attribs.isRemovable) { if(fileName[0] == 'A' || fileName[0] == 'B') item.type = floppy; else item.type = removable; } } else { GetExtension(fileName, extension); //strupr(extension); strlwr(extension); item.type = ExplorerFileType::SelectByExtension(extension); } if(attribs.isDrive && len > 3 && !strncmp(&fileName[1], ": [", 3)) { strncpy(name, fileName, 2); name[2] = 0; strncpy(info, &fileName[4], len - 5); info[len - 5] = 0; } else { strcpy(name, fileName); info[0] = 0; } item.path = CopyString(filePath); item.name = CopyString(name); if(info[0]) item.info = CopyString(info); item.extension = CopyString(extension); if(item.type == pictureFile && previewPicture) { item.bitmap = Bitmap { }; item.bitmap.Load(filePath, null, displaySystem); } return item; } #endif public class FileSystemNode : struct { FileSystemNode prev, next; bool loaded, childrenLoaded; int indent; char * name; char * info; DataRow row; OldList children; ExplorerFileType type; FileSystemNode parent; FileStats stats; void GetPath(String outputPath) { FileSystemNode up; if(parent) { strcpy(outputPath, name); for(up = parent; up; up = up.parent) { char temp[MAX_LOCATION]; strcpy(temp, up.name); PathCat(temp, outputPath); strcpy(outputPath, temp); } } else #ifdef __WIN32__ strcpy(outputPath, "/"); #else strcpy(outputPath, name); #endif } bool IsChildOf(FileSystemNode node) { FileSystemNode test; for(test = parent; test; test = test.parent) if(test == node) return true; return false; } void DuplicateChildren(bool recursive, bool forceExpanded, FileSystemNode addTo, ListBox tree) { if(children.first) { FileSystemNode child; for(child = children.first; child; child = child.next) { FileSystemNode copy { }; copy.name = CopyString(child.name); copy.type = child.type; AddNode(copy, child.loaded, false, addTo, tree); if(forceExpanded) copy.row.collapsed = false; if(recursive) child.DuplicateChildren(recursive, forceExpanded, copy, tree); } } } void EnsureVisible(bool expand) { if(parent) parent.EnsureVisible(true); if(expand) row.collapsed = false; // TODO: row.EnsureVisible(); // making the row visible by scrolling } void OnFree() { //delete name; } void Free() { FileSystemNode child; for(; (child = children.first); ) { child.Free(); children.Delete(child); } //if(name) delete name; delete info; } void Delete() { Free(); if(parent) parent.children.Delete(this); } void OnDisplay(Surface surface, int x, int y, int width, ExplorerControl control, Alignment alignment, DataDisplayFlags displayFlags) { //int indentSize = (displayFlags.dropBox) ? 0 : 10; int indent = 16; int xStart; int len; int w, h; //int textOffset; char label[MAX_FILENAME]; Bitmap icon; if(!this) return; icon = control.fileIcons[type].bitmap; //xStart = indent * indent + x + (icon ? (icon.width + 5) : 0); xStart = x + (icon ? (icon.width + 5) : 0); if(!name) return; if(info) sprintf(label, "%s [%s]", name, info); else strcpy(label, name); len = strlen(label); if(!icon) { if(type == folder || type == folderOpen) surface.SetForeground(yellow); //indentSize = 8; indent = 8; } //textOffset = indent * indentSize + (icon ? (icon.width + 4) : 0); surface.TextOpacity(false); surface.TextExtent(label, len, &w, &h); h = Max(h, 16); // Draw the current row stipple if(displayFlags.selected) //surface.Area(xStart - 1, y, xStart - 1, y + h - 1); //surface.Area(xStart + w - 1, y, xStart + w + 1, y + h - 1); surface.Area(xStart - 3, y, xStart + w + 1, y + h - 1); //surface.WriteTextDots(alignment, x + textOffset, y + 2, width - textOffset, name, strlen(name)); surface.WriteTextDots(alignment, xStart, y + 2, width, label, len); if(!guiApp.textMode) { if(displayFlags.current) { if(displayFlags.active) { surface.LineStipple(0x5555); if(displayFlags.selected) surface.SetForeground(0xFFFFFF80); else surface.SetForeground(black); } else { surface.SetForeground(selectionColor); } surface.Rectangle(xStart - 3, y, xStart + w + 1, y + h - 1); surface.LineStipple(0); } if(icon) { //surface.blend = true; //surface.alphaWrite = blend; surface.SetForeground(white); //surface.Blit(icon, x + indent * indentSize, y,0,0, icon.width, icon.height); surface.Blit(icon, x,y,0,0, icon.width, icon.height); } } } int OnCompare(FileSystemNode b) { int result; if(type == b.type || (type < folder && b.type < folder) || (type >= drive)) result = strcmpi(name, b.name); else { if(type == folder && b.type < folder) result = -1; else if(type < folder && b.type == folder) result = 1; } return result; } char * OnGetString(char * tempString, FileSystemToolWindow fileSysToolWnd, bool * needClass) { return name ? name : ""; } }; FileSystemNode MakeFileNode(const FileStats stats, const char * name) { FileSystemNode fileTreeNode { stats = stats }; fileTreeNode.name = CopyString(name); if(!fileTreeNode.name) fileTreeNode.name = null; if(stats.attribs.isDirectory) { fileTreeNode.type = (stats.attribs.isDrive) ? drive : folder; if(stats.attribs.isServer) fileTreeNode.type = server; if(stats.attribs.isShare) fileTreeNode.type = share; if(stats.attribs.isCDROM) fileTreeNode.type = cdrom; if(stats.attribs.isRemote) fileTreeNode.type = netDrive; if(stats.attribs.isRemovable) { if(name[0] == 'A' || name[0] == 'B') fileTreeNode.type = floppy; else fileTreeNode.type = removable; } } else { char extension[MAX_EXTENSION]; GetExtension(fileTreeNode.name, extension); fileTreeNode.type = ExplorerFileType::SelectByExtension(extension); } return fileTreeNode; } void AddNode(FileSystemNode node, bool loaded, bool addLoader, FileSystemNode addTo, ListBox tree) { DataRow row = (addTo && addTo.row) ? addTo.row.AddRow() : tree.AddRow(); if(addTo) { node.parent = addTo; node.indent = addTo.indent + 1; addTo.children.Add(node); } row.tag = (int)node; node.row = row; row.SetData(null, node); node.loaded = loaded; if(addLoader) //AddNode(FileSystemNode { }, false, false, node, tree); // why would this create a compile error? AddNode(FileSystemNode { type = none }, false, false, node, tree); if(node.indent > 0) row.collapsed = true; else if(node.type == folder) node.type = folderOpen; } void NodeLoad(FileSystemNode node, ListBox tree) { if(!node.loaded) { char path[MAX_LOCATION]; node.GetPath(path); { FileListing listing { path }; if(node.children.count == 1) DeleteNode(node.children.first, tree); while(listing.Find()) { if(listing.stats.attribs.isDirectory) { FileSystemNode child = MakeFileNode(listing.stats, listing.name); AddNode(child, true, false, node, tree); NodeChildLoad(child, node, tree); } } } node.childrenLoaded = true; node.loaded = true; node.row.SortSubRows(false); } else if(!node.childrenLoaded) { FileSystemNode child; if(node.children.first) { for(child = node.children.first; child; child = child.next) { if(!child.loaded) NodeLoad(child, tree); else if(!child.childrenLoaded) NodeChildLoad(child, node, tree); } node.childrenLoaded = true; node.row.SortSubRows(false); } } } static void NodeChildLoad(FileSystemNode parent, FileSystemNode node, ListBox tree) { char path[MAX_LOCATION]; parent.GetPath(path); { bool added = false; FileListing listing { path }; while(listing.Find()) { if(listing.stats.attribs.isDirectory) { FileSystemNode child = MakeFileNode(listing.stats, listing.name); AddNode(child, true, false, parent, tree); added = true; } } if(!added) added = true; } //parent.childrenLoaded = true; } void DeleteNode(FileSystemNode node, ListBox tree) { FileSystemNode child; for(; (child = node.children.first); ) DeleteNode(child, tree); tree.DeleteRow(node.row); node.Delete(); }