--- /dev/null
+{
+ "Version" : 0.2,
+ "ModuleName" : "Explorer",
+ "Options" : {
+ "Warnings" : "All",
+ "MemoryGuard" : false,
+ "Profile" : false,
+ "StrictNameSpaces" : false,
+ "TargetType" : "Executable",
+ "Libraries" : [
+ "ecere"
+ ],
+ "Console" : false
+ },
+ "Configurations" : [
+ {
+ "Name" : "Debug",
+ "Options" : {
+ "Debug" : true,
+ "Optimization" : "None",
+ "PreprocessorDefinitions" : [
+ "_DEBUG"
+ ],
+ "TargetFileName" : "Explorer",
+ "TargetDirectory" : "debug",
+ "ObjectsDirectory" : "debug"
+ }
+ },
+ {
+ "Name" : "Release",
+ "Options" : {
+ "Debug" : false,
+ "Optimization" : "Speed",
+ "TargetFileName" : "Explorer",
+ "TargetDirectory" : "release",
+ "ObjectsDirectory" : "release"
+ }
+ }
+ ],
+ "Files" : [
+ {
+ "Folder" : "notes",
+ "Files" : [
+ "Info.txt",
+ "Todo.txt"
+ ]
+ },
+ {
+ "Folder" : "src",
+ "Files" : [
+ "Explorer.ec",
+ "ExplorerTree.ec",
+ "DeleteBox.ec",
+ "Finder.ec",
+ "NotificationBox.ec",
+ "Panels.ec",
+ "Search.ec"
+ ]
+ },
+ {
+ "Folder" : "outside",
+ "Files" : [
+ "src/SplitWindow.ec",
+ "src/Structures/ArrayFactoredGrowth.ec",
+ "src/Structures/ArrayUtilities.ec",
+ "src/Skin.ec"
+ ]
+ }
+ ],
+ "ResourcesPath" : "",
+ "Resources" : [
+ "res/panel-tree.png",
+ "res/view-cards.png",
+ "res/view-details.png",
+ "res/view-icons.png",
+ "res/view-list.png",
+ "res/view-showcase-right.png",
+ "res/browse.png"
+ ]
+}
\ No newline at end of file
--- /dev/null
+public import "ecere"
+
+import "ExplorerTree"
+
+public class DeleteBox : Window
+{
+ background = activeBorder;
+ hasClose = true;
+ tabCycle = true;
+ size = Size { 400, 300 };
+ text = "Delete Confirmation";
+
+public:
+ ListBox source;
+
+private:
+
+ ListBox list
+ {
+ parent = this, borderStyle = deep, hasVertScroll = true, hasHorzScroll = true;
+ fullRowSelect = false, treeBranches = true, collapseControl = true, rootCollapseButton = true;
+ multiSelect = true;
+ size = Size { 624, 268 }, anchor = Anchor { left = 248, right = 8, bottom = 8 };
+ text = "Browser", hotKey = Key { e, alt = true };
+
+ /*hasHeader = true, moveFields = true, resizable = true, sortable = true;*/
+ anchor = Anchor { left = 8, top = 8, right = 8, bottom = 48 };
+ };
+ DataField listNameField { header = "Name", dataType = "ExplorerFileBranch", width = 304, userData = this }; // editable = true
+
+ DeleteBox()
+ {
+ list.AddField(listNameField);
+ }
+
+ ~DeleteBox()
+ {
+ }
+
+ /*
+ bool OnPostCreate()
+ {
+ if(source)
+ {
+ Link item;
+ OldList selection;
+ FileTreeBranchArray copies { growingFactor = 2 };
+ FileTreeBranchBSArray branches { };
+ FileTreeBranchArray parents { growingFactor = 4 };
+
+ source.GetMultiSelection(selection);
+
+ for(item = selection.first; item; item = item.next)
+ {
+ DataRow row = item.data;
+ ExplorerFileBranch branch = (ExplorerFileBranch)row.tag;
+ if(parents.count)
+ {
+ uint c;
+ for(c = 0; c < parents.count; c++)
+ {
+ if(branch.IsChildOf(parents._[c]))
+ break;
+ }
+ if(c == parents.count)
+ {
+ parents.Add(branch);
+ }
+ }
+ else
+ {
+ parents.Add(branch);
+ }
+ // what if a child of some parent was added before that parent, should check to remove
+ // or is it imposible to get the backwards order from GetMultiSelection
+
+ //for(branch = (ExplorerFileBranch)row.tag; branch; branch = branch.parent)
+ // branches.Add(branch);
+ }
+ selection.Free(null);
+
+ {
+ uint c;
+ char path[MAX_LOCATION];
+ for(c = 0; c < parents.count; c++)
+ {
+ ExplorerFileBranch parent = parents._[c];
+ ExplorerFileBranch root { };
+ parent.GetPath(path);
+ root.name = CopyString(path);
+ root.childrenLoaded = true;
+ root.type = parent.type;
+ AddBranch(root, true, false, null, list);
+ parent.DuplicateChildren(true, true, root, list);
+ }
+ }
+
+ */
+ /*
+ copies.count = branches.count;
+
+ {
+ bool added = true;
+ uint b;
+ int i = 0;
+ while(added)
+ {
+ for(b = 0; b < branches.count; b++)
+ {
+ if(branches._[b].indent == i)
+ {
+ ExplorerFileBranch copy;
+ //copy = branches._[b].Copy();
+ added = true;
+ }
+ }
+ i++;
+ }
+ }
+ */
+ /*
+
+ */
+ /*
+ char path[MAX_LOCATION];
+ DataRow row = item.data;
+ ExplorerFileBranch branch = (ExplorerFileBranch)row.tag;
+ branch.GetPath(path);
+ if(FileExists(path))
+ DeleteFile(path);
+ if(!FileExists(path))
+ DeleteBranch(branch, source);
+ */
+ /*
+
+ }
+ }
+ */
+};
--- /dev/null
+public import "ecere"
+import "SplitWindow"
+
+import "ExplorerTree" // meant to be called ExplorerTools
+import "Finder"
+import "Search" // meant to be called ExplorerSearch
+import "Panels"
+
+/*
+#ifdef __WIN32__
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+*/
+
+enum ExplorerToolId
+{
+ none,
+ newWindow, goBack, goForward, goUp, goHome,
+ browse,
+ panelTree, panelSearch,
+ addressBar,
+ refreshView,
+ viewList, viewDetails, viewIcons, viewCards, viewShowcase, viewCustom,
+ previewPictures
+};
+
+static char * toolIconNames[] =
+{
+ "<:ecere>emblems/unreadable.png", /* none */
+
+ "<:ecere>actions/windowNew.png", /* newWindow */
+ "<:ecere>actions/goPrevious.png", /* goBack */
+ "<:ecere>actions/goNext.png", /* goForward */
+ "<:ecere>actions/goUp.png", /* goUp */
+ "<:ecere>actions/goHome.png", /* goHome */
+
+ ":browse.png", /* browse */
+
+ ":panel-tree.png", /* panelTree */
+ "<:ecere>actions/editFind.png", /* panelSearch */
+
+ "<:ecere>emblems/unreadable.png", /* addressBar */
+
+ "<:ecere>actions/viewRefresh.png", /* refreshView */
+
+ ":view-list.png", /* viewList */
+ ":view-details.png", /* viewDetails */
+ ":view-icons.png", /* viewIcons */
+ ":view-cards.png", /* viewCards */
+ ":view-showcase-right.png", /* viewShowcase */
+ ":view-custom.png", /* viewCustom */
+
+ "<:ecere>mimetypes/image.png", /* previewPictures */
+
+ ""
+};
+
+class ToolButton : Button
+{
+ size = Size { 24, 24 };
+
+ property int toolId
+ {
+ set
+ {
+ bitmap = BitmapResource { fileName = toolIconNames[value], alphaBlend = true };
+ id = value;
+ }
+ }
+
+ bool TestToolBar::NotifyClicked(ToolButton button, int x, int y, Modifiers mods)
+ {
+ NotifyToolClick(this.parent, this, button.id);
+ return true;
+ }
+}
+
+class ToggleToolButton : ToolButton
+{
+ toggle = true;
+ size = Size { 24, 24 };
+
+ bool TestToolBar::NotifyClicked(ToggleToolButton button, int x, int y, Modifiers mods)
+ {
+ NotifyToolClick(this.parent, this, button.id);
+ return true;
+ }
+}
+
+class GroupToggleToolButton : ToolButton
+{
+ toggle = true;
+ size = Size { 24, 24 };
+ GroupToggleToolButton * selected;
+ bool TestToolBar::NotifyClicked(GroupToggleToolButton button, int x, int y, Modifiers mods)
+ {
+ bool configured = (bool)button.selected;
+ bool preselection = (configured && (*button.selected));
+ bool reclick = preselection ? (*button.selected == button) : false;
+ if(configured && preselection && !reclick)
+ {
+ (*button.selected).checked = false;
+ *button.selected = button;
+ }
+ NotifyToolClick(this.parent, this, button.id);
+ return true;
+ }
+}
+
+class OptionToolButton : ToolButton
+{
+ toggle = true;
+ size = Size { 24, 24 };
+ OptionToolButton * selected;
+ bool TestToolBar::NotifyClicked(OptionToolButton button, int x, int y, Modifiers mods)
+ {
+ bool configured = (bool)button.selected;
+ bool preselection = (configured && (*button.selected));
+ bool reclick = preselection ? (*button.selected == button) : false;
+ if(configured && !preselection)
+ *button.selected = button;
+ else if(configured && !reclick)
+ {
+ (*button.selected).checked = false;
+ *button.selected = button;
+ }
+ button.checked = true;
+ if(!reclick)
+ NotifyToolClick(this.parent, this, button.id);
+ return true;
+ }
+}
+
+class TestToolBar : Window
+{
+ int xL, xR;
+
+ borderStyle = bevel;
+ inactive = true;
+ background = activeBorder;
+ size = Size { h = 32 };
+ anchor = Anchor { left = 0, top = 0, right = 0 };
+
+ virtual void Window::NotifyToolClick(TestToolBar toolBar, int id);
+
+ xL = 0;
+
+ ToolButton newWindow { this, anchor = { left = (xL += 20) }, toolId = ExplorerToolId::newWindow };
+
+ ToolButton goBack { this, anchor = { left = (xL += 46) }, toolId = ExplorerToolId::goBack };
+ ToolButton goForward { this, anchor = { left = (xL += 26) }, toolId = ExplorerToolId::goForward };
+ ToolButton goUp { this, anchor = { left = (xL += 30) }, toolId = ExplorerToolId::goUp };
+ ToolButton goHome { this, anchor = { left = (xL += 30) }, toolId = ExplorerToolId::goHome };
+
+ GroupToggleToolButton panelTree { this, anchor = { left = (xL += 46) }, toolId = ExplorerToolId::panelTree, selected = &selectedPanel, checked = true };
+ GroupToggleToolButton panelSearch { this, anchor = { left = (xL += 26) }, toolId = ExplorerToolId::panelSearch, selected = &selectedPanel };
+ GroupToggleToolButton selectedPanel;
+ selectedPanel = panelTree;
+
+ xR = 0;
+
+ OptionToolButton viewList { this, anchor = { right = (xR += 20) }, toolId = ExplorerToolId::viewList, selected = &selectedView, checked = true };
+ OptionToolButton viewDetails { this, anchor = { right = (xR += 26) }, toolId = ExplorerToolId::viewDetails, selected = &selectedView };
+ OptionToolButton viewIcons { this, anchor = { right = (xR += 26) }, toolId = ExplorerToolId::viewIcons, selected = &selectedView };
+ OptionToolButton viewTiles { this, anchor = { right = (xR += 26) }, toolId = ExplorerToolId::viewCards, selected = &selectedView };
+ OptionToolButton viewShowcase { this, anchor = { right = (xR += 26) }, toolId = ExplorerToolId::viewShowcase, selected = &selectedView };
+ OptionToolButton selectedView;
+ selectedView = viewList;
+
+ ToggleToolButton previewPictures { this, anchor = { right = (xR += 46) }, toolId = ExplorerToolId::previewPictures };
+
+ ToolButton refreshView { this, anchor = { right = (xR += 46) }, toolId = ExplorerToolId::refreshView };
+
+ EditBox addressBar
+ {
+ this, master;
+ size = { w = 250 }, anchor = { left = (xL += 30), right = (xR += 30) }, id = ExplorerToolId::addressBar;
+ };
+
+ /*DropBox tileSet
+ {
+ this,
+ anchor = { left = (xPos += 88) };
+ inactive = true;
+
+ bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
+ {
+ return true;
+ }
+ };*/
+
+ TestToolBar()
+ {
+ /*tileSet.AddString("Forest").tag = 0;
+ tileSet.AddString("Winter").tag = 0;
+ tileSet.AddString("Wasteland").tag = 0;*/
+ }
+};
+
+class ExplorerWindow : Window
+{
+ text = "Ecere Explorer";
+ background = activeBorder;
+ borderStyle = sizable;
+ hasMaximize = true;
+ hasMinimize = true;
+ hasClose = true;
+ hasMenuBar = true;
+ tabCycle = true;
+ size = Size { 888, 840 };
+
+ bool userMode;
+ bool clipboard;
+
+ int treeSplit;
+ int searchSplit;
+
+ ExplorerToolId lastViewId;
+
+ menu = Menu { };
+
+ Menu fileMenu { menu, "File", f };
+ Menu windowMenu { menu, "Window", w };
+ MenuItem newWindow
+ {
+ windowMenu, "New Window", n;
+
+ bool NotifySelect(MenuItem selection, Modifiers mods)
+ {
+ ExplorerWindow { }.Create();
+ return true;
+ }
+ };
+
+ TestToolBar toolBar
+ {
+ this;
+
+ void NotifyToolClick(TestToolBar toolBar, int id)
+ {
+ ExplorerToolId toolId = (ExplorerToolId)id;
+ switch(toolId)
+ {
+ case none:
+ break;
+ case newWindow:
+ ExplorerWindow { }.Create();
+ break;
+ case goBack:
+ case goForward:
+ break;
+ case goUp:
+ {
+ ExplorerFileBranch branch = tree.branch;
+ if(branch && branch.parent)
+ tree.Select(branch.parent);
+ break;
+ }
+ case panelTree:
+ if(tree.visible)
+ {
+ split.leftPane = null;
+ split.visible = false;
+ tree.visible = false;
+ treeSplit = split.split;
+ split.OnResize(split.size.w, split.size.h);
+ }
+ else
+ {
+ if(search.visible)
+ {
+ search.visible = false;
+ searchSplit = split.split;
+ }
+ tree.visible = true;
+ split.leftPane = tree;
+ split.visible = true;
+ split.split = treeSplit;
+ split.OnResize(split.size.w, split.size.h);
+ SwitchViews(lastViewId);
+ }
+ break;
+ case panelSearch:
+ if(search.visible)
+ {
+ split.leftPane = null;
+ split.visible = false;
+ search.visible = false;
+ searchSplit = split.split;
+ split.OnResize(split.size.w, split.size.h);
+ SwitchViews(lastViewId);
+ }
+ else
+ {
+ if(tree.visible)
+ {
+ tree.visible = false;
+ treeSplit = split.split;
+ }
+ search.visible = true;
+ split.leftPane = search;
+ split.visible = true;
+ split.split = searchSplit;
+
+ view = ExplorerSearchViewTree { viewHolder, this };
+ view.previewPictures = toolBar.previewPictures.checked;
+ view.anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
+ view.NotifyItemOpen = ViewNotifyItemOpen;
+ view.Create();
+ search.view = (ExplorerSearchViewTree)view;
+
+ split.OnResize(split.size.w, split.size.h);
+ }
+ break;
+ case refreshView:
+ if(view)
+ view.Refresh();
+ break;
+ case previewPictures:
+ if(view)
+ view.previewPictures = toolBar.previewPictures.checked;
+ break;
+ case viewList:
+ case viewDetails:
+ case viewIcons:
+ case viewCards:
+ case viewShowcase:
+ SwitchViews(toolId);
+ break;
+ }
+ }
+ };
+
+ void SwitchViews(ExplorerToolId viewId)
+ {
+ ExplorerFileBranch branch = tree.branch;
+ view.Destroy(0);
+ switch(viewId)
+ {
+ case viewList: view = ExplorerViewList { parent = viewHolder, master = this }; break;
+ case viewDetails: view = ExplorerViewDetails { parent = viewHolder, master = this }; break;
+ case viewIcons: view = ExplorerViewIcons { parent = viewHolder, master = this }; break;
+ case viewCards: view = ExplorerViewCards { parent = viewHolder, master = this }; break;
+ case viewShowcase: view = ExplorerViewShowcase { parent = viewHolder, master = this }; break;
+ }
+ view.tabCycle = true;
+ view.previewPictures = toolBar.previewPictures.checked;
+ view.anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
+ view.NotifyItemOpen = ViewNotifyItemOpen;
+ view.Create();
+ view.Load(branch);
+ lastViewId = viewId;
+ }
+
+ Window deep
+ {
+ this;
+ borderStyle = deep;
+ tabCycle = true;
+ anchor = Anchor { left = 0, top = 34, right = 0, bottom = 0 };
+ };
+
+ ExplorerTree tree
+ {
+ deep, this;
+ //visible = false;
+ tabCycle = true;
+ size = Size { 624, 268 };
+ anchor = Anchor { left = 0, top = 0, bottom = 0 };
+ text = "Browser", hotKey = Key { e, alt = true };
+ NotifyBranchSelect = TreeNotifyBranchSelect;
+ };
+
+ ExplorerView view;
+
+ ExplorerSearch search
+ {
+ deep, this;
+ visible = false;
+ tabCycle = true;
+ size = Size { 624, 268 };
+ anchor = Anchor { left = 0, top = 0, bottom = 0 };
+ };
+
+ ExplorerViewSearch results;
+
+ bool TreeNotifyBranchSelect(ExplorerTree tree, ExplorerFileBranch branch)
+ {
+ if(branch)
+ {
+ char path[MAX_LOCATION];
+ branch.GetPath(path);
+ toolBar.addressBar.contents = path;
+ view.Load(branch);
+ }
+ return true;
+ }
+
+ bool ViewNotifyItemOpen(ExplorerView view, ExplorerFileItem item)
+ {
+ ExplorerFileBranch branch = tree.branch;
+ if(item && branch)
+ {
+ if(item.type.isFolderType)
+ {
+ ExplorerFileBranch child;
+
+ if(!branch.loaded || !branch.childrenLoaded)
+ BranchLoad(branch, tree.tree);
+
+ for(child = branch.children.first; child; child = child.next)
+ if(!strcmp(child.name, item.name))
+ break;
+
+ if(child)
+ {
+ if(branch.row.collapsed)
+ child.row.collapsed = true;
+ child.EnsureVisible(false);
+ tree.Select(child);
+ }
+ }
+ else
+ {
+ char path[MAX_LOCATION];
+ branch.GetPath(path);
+ PathCat(path, item.name);
+ ShellOpen(path);
+ }
+ }
+ }
+
+ Window viewHolder
+ {
+ parent = deep, master = this;
+ tabCycle = true;
+ anchor = Anchor { top = 0, bottom = 0, right = 0 };
+ };
+
+ SplitWindow split
+ {
+ deep, this;
+ leftPane = tree, rightPane = viewHolder;
+ split = 300;
+ };
+
+ void GoToLocation(char * location)
+ {
+ int c;
+ char * temp;
+ char step[MAX_LOCATION];
+
+ StringArray steps { growingFactor = 4 };
+ ExplorerFileBranch last = null;
+
+ temp = CopyString(location);
+ while(strlen(temp))
+ {
+ GetLastDirectory(temp, step);
+ StripLastDirectory(temp, temp);
+ steps.Add(CopyString(step));
+ }
+
+ for(c = steps._count - 1; c >= 0; c--)
+ {
+ last = tree.Find(steps._[c], last);
+ if(!last)
+ break;
+ tree.Select(last);
+ }
+
+ delete temp;
+ delete steps;
+ }
+
+ void SearchLocation(char * location)
+ {
+ GoToLocation(location);
+ search.location.editBox.contents = location;
+ }
+
+ bool OnPostCreate()
+ {
+ userMode = true;
+ return true;
+ }
+
+ ExplorerWindow()
+ {
+ userMode = false;
+
+ treeSplit = 300;
+ searchSplit = 200;
+
+ view = ExplorerViewList
+ {
+ parent = viewHolder, master = this;
+ tabCycle = true;
+ previewPictures = toolBar.previewPictures.checked;
+ anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
+ NotifyItemOpen = ViewNotifyItemOpen;
+ };
+ lastViewId = viewList;
+
+ tree.Load();
+ view.Load(tree.root);
+ }
+
+ void InitTree()
+ {
+ }
+
+ void InitSearch()
+ {
+ }
+}
+
+class ExplorerApp : GuiApplication
+{
+ //skin = "Acovel";
+
+ bool Init()
+ {
+ QuickPathTool goPath { };
+ QuickPathTool searchPath { };
+ char * findWhat = null;
+ SetLoggingMode(debug, null);
+ if(argc > 1)
+ {
+ if(!strcmpi(argv[1], "go") && argc > 2)
+ goPath = argv[2];
+ else if(!strcmpi(argv[1], "find") && argc > 2)
+ {
+ char * unquoted;
+ if(argv[2][0] == '\"')
+ StripQuotes(argv[2], unquoted);
+ else
+ unquoted = argv[2];
+ findWhat = CopyString(unquoted);
+ if(argc > 3)
+ {
+ if(!strcmpi(argv[3], "in") && argc > 4)
+ searchPath = argv[4];
+ else
+ searchPath = ""; // this should make it current dir
+ }
+ else
+ searchPath = ""; // same
+ }
+ else if(!strcmpi(argv[1], "search") && argc > 2)
+ searchPath = argv[2];
+ else if(!strcmpi(argv[1], "image") && argc > 2)
+ ;
+ else if(!strcmpi(argv[1], "slides") && argc > 2)
+ ;
+ else
+ goPath = argv[1];
+ }
+ else
+ goPath = "";
+ if(goPath)
+ {
+ ExplorerWindow explorerWnd { };
+ explorerWnd.Create();
+ explorerWnd.GoToLocation(goPath);
+ }
+ else if(searchPath)
+ {
+ ExplorerWindow explorerWnd { };
+ explorerWnd.Create();
+ explorerWnd.SearchLocation(searchPath);
+ }
+ return true;
+ }
+}
+
+struct QuickPathTool
+{
+ char path[MAX_LOCATION];
+
+ property char *
+ {
+ set
+ {
+ char * unquoted;
+ GetWorkingDir(path, MAX_LOCATION);
+ if(value[0] == '\"')
+ StripQuotes(value, unquoted);
+ else
+ unquoted = value;
+ PathCat(path, unquoted);
+ if(!FileExists(path))
+ {
+ // this incomplete functionality is not quite at it's place in this class
+ int len;
+ char * original = CopyString(path);
+ while((len = strlen(path)))
+ {
+ StripLastDirectory(path, path);
+ if(FileExists(path))
+ {
+ // TODO: message location does not exist,
+ // this higher location exists though
+ // go there?
+ break;
+ }
+ }
+ if(!len)
+ {
+ // TODO: message location does not exist,
+ // unable to select alternate location
+ }
+ path[0] = '\0';
+ delete original;
+ }
+ }
+ get { return path[0] ? path : null; }
+ }
+ property bool { get { return (bool)path[0]; } }
+};
+
+define app = ((ExplorerApp)__thisModule);
--- /dev/null
+public import "ecere"
+import "SplitWindow"
+import "ArrayFactoredGrowth"
+
+//import "ArrayFactoredGrowth"
+//import "ArrayBinarySorted"
+
+#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]);
+ }
+ }
+}
+
+class ExplorerView : ExplorerControl
+{
+ borderStyle = none;
+ hasHorzScroll = false;
+ hasVertScroll = false;
+
+ virtual void Load(ExplorerFileBranch 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()
+ {
+ }
+}
+
+class ExplorerViewList : ExplorerView
+{
+
+ ExplorerFileBranch location;
+
+public:
+
+ DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
+
+ ExplorerViewDetails()
+ {
+ list.AddField(nameField);
+ }
+
+ void Refresh()
+ {
+ Load(location);
+ }
+
+ void Load(ExplorerFileBranch 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);
+ }
+ }
+}
+
+class ExplorerViewDetails : ExplorerView
+{
+ list.hasHeader = true;
+ list.moveFields = true;
+ list.resizable = true;
+ list.sortable = true;
+
+ ExplorerFileBranch 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(ExplorerFileBranch 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, (void *)listing.stats.size);
+ }
+ list.Sort(nameField, 1);
+ }
+ }
+}
+
+class ExplorerViewIcons : ExplorerView
+{
+
+ ExplorerFileBranch location;
+
+public:
+
+ DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
+
+ ExplorerViewDetails()
+ {
+ list.AddField(nameField);
+ }
+
+ void Refresh()
+ {
+ Load(location);
+ }
+
+ void Load(ExplorerFileBranch 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);
+ }
+ }
+}
+
+class ExplorerViewCards : ExplorerView
+{
+
+ ExplorerFileBranch location;
+
+public:
+
+ DataField nameField { header = "Name", dataType = "ExplorerFileItem", width = 304, editable = true, userData = this };
+
+ ExplorerViewDetails()
+ {
+ list.AddField(nameField);
+ }
+
+ void Refresh()
+ {
+ Load(location);
+ }
+
+ void Load(ExplorerFileBranch 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);
+ }
+ }
+}
+
+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;
+ }
+}
+
+class ExplorerViewShowcase : ExplorerView
+{
+ list.anchor = Anchor { left = 0, top = 0, bottom = 0 };
+ list.size = Size { w = 200 };
+
+ ExplorerFileBranch 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(ExplorerFileBranch 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);
+ }
+ }
+}
+
+class ExplorerTree : ExplorerControl
+{
+ hasHorzScroll = false;
+ hasVertScroll = false;
+
+ menu = Menu { };
+
+public:
+
+ DataField nameField { dataType = "ExplorerFileBranch", width = 240, userData = this };
+
+ ExplorerFileBranch root;
+ ExplorerFileBranch selection;
+
+ virtual bool Window::NotifyBranchSelect(ExplorerTree tree, ExplorerFileBranch branch);
+
+ property ExplorerFileBranch branch
+ {
+ get
+ {
+ if(!tree)
+ return null;
+ if(!tree.currentRow)
+ return null;
+ if(!tree.currentRow.tag)
+ return null;
+ return (ExplorerFileBranch)tree.currentRow.tag;
+ }
+ }
+
+ void Select(ExplorerFileBranch branch)
+ {
+ if(branch.row)
+ {
+ branch.EnsureVisible(false);
+ tree.SelectRow(branch.row);
+ }
+ }
+
+ ExplorerFileBranch Find(const char * name, ExplorerFileBranch parent)
+ {
+ ExplorerFileBranch branch;
+ ExplorerFileBranch start = parent ? parent : root;
+ if(!start.loaded || !start.childrenLoaded)
+ BranchLoad(start, tree);
+ for(branch = start.children.first; branch; branch = branch.next)
+ if(branch.name && !strcmpi(branch.name, name))
+ return branch;
+ return null;
+ }
+
+ ListBox tree
+ {
+ master = master, parent = this;
+ //this, master;
+ borderStyle = none;
+ hasHorzScroll = true;
+ hasVertScroll = true;
+ fullRowSelect = false;
+ treeBranches = 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)
+ {
+ ExplorerFileBranch branch = (ExplorerFileBranch)row.tag;
+ ExplorerFileBranch child;
+ if(collapsed)
+ {
+ /*
+ for(child = branch.children.last; child; child = branch.children.last)
+ {
+ listBox.DeleteRow(child.row);
+ child.Free();
+ delete child;
+ }
+ branch.childrenLoaded = false;
+ */
+ }
+ else
+ {
+ if(!branch.loaded || !branch.childrenLoaded)
+ BranchLoad(branch, tree);
+ for(child = branch.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)
+ {
+ ExplorerFileBranch branch = (ExplorerFileBranch)row.tag;
+ if(branch)
+ {
+ 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)
+ {
+ ExplorerFileBranch branch = (ExplorerFileBranch)row.tag;
+ NotifyBranchSelect(listBox.parent.master, this, branch);
+ selection = branch;
+ }
+ return true;
+ }
+
+ bool NotifyEditing(ListBox listBox, DataRow row)
+ {
+ if(row)
+ {
+ ExplorerFileBranch branch = (ExplorerFileBranch)row.tag;
+ }
+ return true;
+ }
+
+ bool NotifyEdited(ListBox listBox, DataRow row)
+ {
+ if(row)
+ {
+ ExplorerFileBranch branch = (ExplorerFileBranch)row.tag;
+ }
+ return true;
+ }
+
+ bool NotifyEditDone(ListBox listBox, DataRow row)
+ {
+ if(row)
+ {
+ ExplorerFileBranch branch = (ExplorerFileBranch)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()
+ {
+ ExplorerFileBranch parent;
+ ExplorerFileBranch branch;
+ FileListing listing { "/" };
+
+ tree.Clear();
+
+ root = ExplorerFileBranch { type = computer, loaded = true, childrenLoaded = true };
+ #ifdef __WIN32__
+ root.name = rootName;
+ #else
+ root.name = "/";
+ #endif
+ AddBranch(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 = MakeFileBranch(listing.stats, name);
+ if(info[0])
+ parent.info = CopyString(info);
+ parent.loaded = true;
+ AddBranch(parent, !listing.stats.attribs.isDirectory, listing.stats.attribs.isDirectory, root, tree);
+ if(!listing.stats.attribs.isDirectory)
+ parent.childrenLoaded = true;
+ }
+
+ branch = ExplorerFileBranch { name = msNetwork, type = network };
+ AddBranch(branch, false, true, null, tree);
+ branch.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)
+ {
+ }
+*/
+
+}
+
+/*public class FileTreeBranchBSArray : ArrayBinarySorted
+{
+ type = class(ExplorerFileBranch);
+public:
+ ExplorerFileBranch * const _;
+ BSloc Add(ExplorerFileBranch item)
+ {
+ BSloc result = Find(item);
+ if(!result.valid)
+ {
+ Insert(result.pos, 1);
+ _[result.pos] = item;
+ }
+ return result;
+ }
+ BSloc Remove(ExplorerFileBranch item)
+ {
+
+ }
+}*/
+
+/*public class FileTreeBranchArray : RedjArray
+{
+ type = class(ExplorerFileBranch);
+public:
+ ExplorerFileBranch * const _;
+ ExplorerFileBranch * Add(ExplorerFileBranch item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ ExplorerFileBranch * AddBefore(uint position, ExplorerFileBranch item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}*/
+
+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;
+}
+
+public class ExplorerFileBranch : struct
+{
+ ExplorerFileBranch prev, next;
+
+ bool loaded, childrenLoaded;
+ int indent;
+ char * name;
+ char * info;
+ DataRow row;
+ OldList children;
+ ExplorerFileType type;
+ ExplorerFileBranch parent;
+
+ FileStats stats;
+
+ void GetPath(String outputPath)
+ {
+ ExplorerFileBranch 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(ExplorerFileBranch branch)
+ {
+ ExplorerFileBranch test;
+ for(test = parent; test; test = test.parent)
+ if(test == branch)
+ return true;
+ return false;
+ }
+
+ void DuplicateChildren(bool recursive, bool forceExpanded, ExplorerFileBranch addTo, ListBox tree)
+ {
+ if(children.first)
+ {
+ ExplorerFileBranch child;
+
+ for(child = children.first; child; child = child.next)
+ {
+ ExplorerFileBranch copy { };
+ copy.name = CopyString(child.name);
+ copy.type = child.type;
+ AddBranch(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()
+ {
+ ExplorerFileBranch 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(ExplorerFileBranch 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 : "";
+ }
+};
+
+ExplorerFileBranch MakeFileBranch(const FileStats stats, const char * name)
+{
+ ExplorerFileBranch fileTreeBranch { stats = stats };
+ fileTreeBranch.name = CopyString(name);
+ if(!fileTreeBranch.name)
+ fileTreeBranch.name = null;
+ if(stats.attribs.isDirectory)
+ {
+ fileTreeBranch.type = (stats.attribs.isDrive) ? drive : folder;
+ if(stats.attribs.isServer) fileTreeBranch.type = server;
+ if(stats.attribs.isShare) fileTreeBranch.type = share;
+ if(stats.attribs.isCDROM) fileTreeBranch.type = cdrom;
+ if(stats.attribs.isRemote) fileTreeBranch.type = netDrive;
+ if(stats.attribs.isRemovable)
+ {
+ if(name[0] == 'A' || name[0] == 'B')
+ fileTreeBranch.type = floppy;
+ else
+ fileTreeBranch.type = removable;
+ }
+ }
+ else
+ {
+ char extension[MAX_EXTENSION];
+ GetExtension(fileTreeBranch.name, extension);
+ fileTreeBranch.type = ExplorerFileType::SelectByExtension(extension);
+ }
+ return fileTreeBranch;
+}
+
+void AddBranch(ExplorerFileBranch branch, bool loaded, bool addLoader, ExplorerFileBranch addTo, ListBox tree)
+{
+ DataRow row = (addTo && addTo.row) ? addTo.row.AddRow() : tree.AddRow();
+ if(addTo)
+ {
+ branch.parent = addTo;
+ branch.indent = addTo.indent + 1;
+ addTo.children.Add(branch);
+ }
+ row.tag = (int)branch;
+ branch.row = row;
+ row.SetData(null, branch);
+
+ branch.loaded = loaded;
+ if(addLoader)
+ //AddBranch(ExplorerFileBranch { }, false, false, branch, tree); // why would this create a compile error?
+ AddBranch(ExplorerFileBranch { type = none }, false, false, branch, tree);
+
+ if(branch.indent > 0)
+ row.collapsed = true;
+ else if(branch.type == folder)
+ branch.type = folderOpen;
+}
+
+void BranchLoad(ExplorerFileBranch branch, ListBox tree)
+{
+ if(!branch.loaded)
+ {
+ char path[MAX_LOCATION];
+ branch.GetPath(path);
+ {
+ FileListing listing { path };
+ if(branch.children.count == 1)
+ DeleteBranch(branch.children.first, tree);
+
+ while(listing.Find())
+ {
+ if(listing.stats.attribs.isDirectory)
+ {
+ ExplorerFileBranch child = MakeFileBranch(listing.stats, listing.name);
+ AddBranch(child, true, false, branch, tree);
+ BranchChildLoad(child, branch, tree);
+ }
+ }
+ }
+ branch.childrenLoaded = true;
+ branch.loaded = true;
+ branch.row.SortSubRows(false);
+ }
+ else if(!branch.childrenLoaded)
+ {
+ ExplorerFileBranch child;
+ if(branch.children.first)
+ {
+ for(child = branch.children.first; child; child = child.next)
+ {
+ if(!child.loaded)
+ BranchLoad(child, tree);
+ else if(!child.childrenLoaded)
+ BranchChildLoad(child, branch, tree);
+ }
+ branch.childrenLoaded = true;
+ branch.row.SortSubRows(false);
+ }
+ }
+}
+
+static void BranchChildLoad(ExplorerFileBranch parent, ExplorerFileBranch branch, ListBox tree)
+{
+ char path[MAX_LOCATION];
+ parent.GetPath(path);
+ {
+ bool added = false;
+ FileListing listing { path };
+ while(listing.Find())
+ {
+ if(listing.stats.attribs.isDirectory)
+ {
+ ExplorerFileBranch child = MakeFileBranch(listing.stats, listing.name);
+ AddBranch(child, true, false, parent, tree);
+ added = true;
+ }
+ }
+ if(!added)
+ added = true;
+ }
+ //parent.childrenLoaded = true;
+}
+
+void DeleteBranch(ExplorerFileBranch branch, ListBox tree)
+{
+ ExplorerFileBranch child;
+ for(; (child = branch.children.first); )
+ DeleteBranch(child, tree);
+ tree.DeleteRow(branch.row);
+ branch.Delete();
+}
+
--- /dev/null
+public import "ecere"
+
+private:
+define guiApp = ((GuiApplication)__thisModule);
+define selectionColor = guiApp.currentSkin.selectionColor; //Color { 10, 36, 106 };
+
+static char * iconNames[] =
+{
+ "<:ecere>tango/16x16/mimetypes/file-x-generic.png", /*none*/
+
+ "<:ecere>tango/16x16/mimetypes/file-x-generic.png", /*normalFile*/
+ "<:ecere>tango/16x16/mimetypes/text-ews-work.png", /*ewsFile*/
+ "<:ecere>tango/16x16/mimetypes/text-epj-assembly.png", /*epjFile*/
+ "<:ecere>tango/16x16/mimetypes/text-ec-source.png", /*ecFile*/
+ "<:ecere>tango/16x16/mimetypes/text-eh-header.png", /*ehFile*/
+ "<:ecere>tango/16x16/mimetypes/text-c-source.png", /*cFile*/
+ "<:ecere>tango/16x16/mimetypes/text-h-header.png", /*hFile*/
+ "<:ecere>tango/16x16/mimetypes/text-cpp-source.png", /*cppFile*/
+ "<:ecere>tango/16x16/mimetypes/text-hpp-header.png", /*hppFile*/
+ "<:ecere>tango/16x16/mimetypes/text-x-generic.png", /*textFile*/
+ "<:ecere>tango/16x16/mimetypes/text-html.png", /*webFile*/
+ "<:ecere>tango/16x16/mimetypes/image-x-generic.png", /*pictureFile*/
+ "<:ecere>tango/16x16/status/audio-volume-high.png", /*soundFile*/
+ "<:ecere>tango/16x16/mimetypes/package-x-generic.png", /*archiveFile*/
+ "<:ecere>tango/16x16/mimetypes/package-x-software.png", /*packageFile*/
+ "<:ecere>tango/16x16/mimetypes/package-x-optical-disc.png", /*opticalMediaImageFile*/
+
+ "<:ecere>tango/16x16/places/folder.png",
+ "<:ecere>tango/16x16/status/folder-open.png",
+ "<:ecere>tango/16x16/devices/computer.png",
+ "<:ecere>tango/16x16/devices/drive-harddisk.png",
+ "<:ecere>tango/16x16/places/folder-remote.png",
+ "<:ecere>tango/16x16/devices/media-optical.png",
+ "<:ecere>tango/16x16/devices/drive-removable-media.png",
+ "<:ecere>tango/16x16/devices/media-floppy.png",
+ "<:ecere>tango/16x16/places/network-workgroup.png",
+ "<:ecere>tango/16x16/places/network-server.png",
+ "<:ecere>tango/16x16/places/folder-remote.png",
+
+ "<:ecere>tango/16x16/mimetypes/package-x-generic.png", /*treeLoader*/
+ "<:ecere>tango/16x16/places/start-here.png" /*lineNumbers*/
+};
+
+public class FileSystemToolWindow : public Window
+{
+ BitmapResource icons[FileItemType];
+
+ FileSystemToolWindow()
+ {
+ FileItemType c;
+ for(c = 0; c < FileItemType::enumSize; c++)
+ {
+ icons[c] = BitmapResource { iconNames[c], alphaBlend = true };
+ AddResource(icons[c]);
+ }
+ }
+}
+
--- /dev/null
+public import "ecere"
+
+import "ExplorerTree"
+
+public class FileListItem : struct
+{
+ char * name;
+ char * info;
+ FileItemType type;
+ int indent;
+
+ void OnDisplay(Surface surface, int x, int y, int width, ExplorerListBox icons, Alignment alignment, DataDisplayFlags displayFlags)
+ {
+ int indentSize = (displayFlags.dropBox) ? 0 : 10;
+ int textOffset;
+ int len;
+ char label[MAX_FILENAME];
+
+ Bitmap icon = icons.icons[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 + 4) : 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(icon)
+ surface.Blit(icon, x + indent * indentSize, y,0,0, icon.width, icon.height);
+ }
+
+ int OnCompare(FileListItem 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(FileListItem 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 name;
+ delete info;
+ }
+
+ char * OnGetString(char * string, void * fieldData, bool * needClass)
+ {
+ return name;
+ }
+};
+
+FileListItem MakeFileListItem(const FileAttribs attribs, const char * name, const char * extension)
+{
+ FileListItem fileListRow { };
+ fileListRow.name = CopyString(name);
+ if(attribs.isDirectory)
+ {
+ fileListRow.type = (attribs.isDrive) ? drive : folder;
+ if(attribs.isServer) fileListRow.type = server;
+ if(attribs.isShare) fileListRow.type = share;
+ if(attribs.isCDROM) fileListRow.type = cdrom;
+ if(attribs.isRemote) fileListRow.type = netDrive;
+ if(attribs.isRemovable)
+ {
+ if(name[0] == 'A' || name[0] == 'B')
+ fileListRow.type = floppy;
+ else
+ fileListRow.type = removable;
+ }
+ }
+ else
+ fileListRow.type = FileItemType::SelectByExtension(extension);
+ return fileListRow;
+}
+
--- /dev/null
+public import "ecere"
+
+import "ArrayFactoredGrowth"
+import "ArrayBinarySorted"
+
+import "ExplorerTree"
+
+public class FileTreeBranchBSArray : ArrayBinarySorted
+{
+ type = class(FileTreeBranch);
+public:
+ FileTreeBranch * const _;
+ BSloc Add(FileTreeBranch item)
+ {
+ BSloc result = Find(item);
+ if(!result.valid)
+ {
+ Insert(result.pos, 1);
+ _[result.pos] = item;
+ }
+ return result;
+ }
+ BSloc Remove(FileTreeBranch item)
+ {
+
+ }
+}
+
+public class FileTreeBranchArray : Array
+{
+ type = class(FileTreeBranch);
+public:
+ FileTreeBranch * const _;
+ FileTreeBranch * Add(FileTreeBranch item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ FileTreeBranch * AddBefore(uint position, FileTreeBranch item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}
+
+public class FileTreeBranch : struct
+{
+ FileTreeBranch prev, next;
+
+ bool loaded, childrenLoaded;
+ int indent;
+ char * name;
+ char * info;
+ DataRow row;
+ List children;
+ FileItemType type;
+ FileTreeBranch parent;
+
+ FileStats stats;
+
+ void GetPath(String outputPath)
+ {
+ FileTreeBranch up;
+ strcpy(outputPath, name);
+ if(parent)
+ {
+ for(up = parent; up; up = up.parent)
+ {
+ char temp[MAX_LOCATION];
+ strcpy(temp, up.name);
+ PathCat(temp, outputPath);
+ strcpy(outputPath, temp);
+ }
+ }
+ }
+
+ bool IsChildOf(FileTreeBranch branch)
+ {
+ FileTreeBranch test;
+ for(test = parent; test; test = test.parent)
+ if(test == branch)
+ return true;
+ return false;
+ }
+
+ void DuplicateChildren(bool recursive, bool forceExpanded, FileTreeBranch addTo, ListBox tree)
+ {
+ if(children.first)
+ {
+ FileTreeBranch child;
+
+ for(child = children.first; child; child = child.next)
+ {
+ FileTreeBranch copy { };
+ copy.name = CopyString(child.name);
+ copy.type = child.type;
+ AddBranch(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;
+ }
+
+ void OnFree()
+ {
+ }
+
+ void Free()
+ {
+ FileTreeBranch 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, ExplorerListBox icons, 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;
+
+ /*Bitmap*/
+ icon = icons.icons[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(FileTreeBranch 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 : "";
+ }
+};
+
+FileTreeBranch MakeFileTreeBranch(const FileStats stats, const char * name)
+{
+ FileTreeBranch fileTreeBranch { stats = stats };
+ fileTreeBranch.name = CopyString(name);
+ if(!fileTreeBranch.name)
+ fileTreeBranch.name = null;
+ if(stats.attribs.isDirectory)
+ {
+ fileTreeBranch.type = (stats.attribs.isDrive) ? drive : folder;
+ if(stats.attribs.isServer) fileTreeBranch.type = server;
+ if(stats.attribs.isShare) fileTreeBranch.type = share;
+ if(stats.attribs.isCDROM) fileTreeBranch.type = cdrom;
+ if(stats.attribs.isRemote) fileTreeBranch.type = netDrive;
+ if(stats.attribs.isRemovable)
+ {
+ if(name[0] == 'A' || name[0] == 'B')
+ fileTreeBranch.type = floppy;
+ else
+ fileTreeBranch.type = removable;
+ }
+ }
+ else
+ {
+ char extension[MAX_EXTENSION];
+ GetExtension(fileTreeBranch.name, extension);
+ fileTreeBranch.type = FileItemType::SelectByExtension(extension);
+ }
+ return fileTreeBranch;
+}
+
+void AddBranch(FileTreeBranch branch, bool loaded, bool addLoader, FileTreeBranch addTo, ListBox tree)
+{
+ DataRow row = (addTo && addTo.row) ? addTo.row.AddRow() : tree.AddRow();
+ if(addTo)
+ {
+ branch.parent = addTo;
+ branch.indent = addTo.indent + 1;
+ addTo.children.Add(branch);
+ }
+ row.tag = (int)branch;
+ branch.row = row;
+ row.SetData(null, branch);
+
+ branch.loaded = loaded;
+ if(addLoader)
+ //AddBranch(FileTreeBranch { }, false, false, branch, tree); // why would this create a compile error?
+ AddBranch(FileTreeBranch { type = none }, false, false, branch, tree);
+
+ if(branch.indent > 0)
+ row.collapsed = true;
+ else if(branch.type == folder)
+ branch.type = folderOpen;
+}
+
+void BranchLoad(FileTreeBranch branch, ListBox tree)
+{
+ if(!branch.loaded)
+ {
+ char path[MAX_LOCATION];
+ branch.GetPath(path);
+ {
+ FileListing listing { path };
+ if(branch.children.count == 1)
+ DeleteBranch(branch.children.first, tree);
+
+ while(listing.Find())
+ {
+ if(listing.stats.attribs.isDirectory)
+ {
+ FileTreeBranch child = MakeFileTreeBranch(listing.stats, listing.name);
+ AddBranch(child, true, false, branch, tree);
+ BranchChildLoad(child, branch, tree);
+ }
+ }
+ }
+ branch.childrenLoaded = true;
+ branch.loaded = true;
+ }
+ else if(!branch.childrenLoaded)
+ {
+ FileTreeBranch child;
+ if(branch.children.first)
+ {
+ for(child = branch.children.first; child; child = child.next)
+ {
+ if(!child.loaded)
+ BranchLoad(child, tree);
+ else if(!child.childrenLoaded)
+ BranchChildLoad(child, branch, tree);
+ }
+ branch.childrenLoaded = true;
+ }
+ }
+}
+
+static void BranchChildLoad(FileTreeBranch parent, FileTreeBranch branch, ListBox tree)
+{
+ char path[MAX_LOCATION];
+ parent.GetPath(path);
+ {
+ bool added = false;
+ FileListing listing { path };
+ while(listing.Find())
+ {
+ if(listing.stats.attribs.isDirectory)
+ {
+ FileTreeBranch child = MakeFileTreeBranch(listing.stats, listing.name);
+ AddBranch(child, true, false, parent, tree);
+ added = true;
+ }
+ }
+ if(!added)
+ added = true;
+ }
+ //parent.childrenLoaded = true;
+}
+
+void DeleteBranch(FileTreeBranch branch, ListBox tree)
+{
+ FileTreeBranch child;
+ for(; (child = branch.children.first); )
+ DeleteBranch(child, tree);
+ tree.DeleteRow(branch.row);
+ branch.Delete();
+}
--- /dev/null
+public import "ecere"
+
+import "ExplorerTree"
+import "Panels"
+import "DeleteBox"
+
+class ExplorerSearch : Window
+{
+ hasHorzScroll = false;
+ hasVertScroll = true;
+
+ background = activeBorder;
+
+ //menu = Menu { };
+
+ ExplorerSearchViewTree view;
+
+ SearchThread searchThread { searchPanel = this };
+
+public:
+
+ void OptTree(bool on)
+ {
+ view.results.Clear();
+ view.results.ClearFields();
+ view.results.AddField(DataField { editable = true });
+ if(on)
+ view.results.AddField(view.resultsFieldPath);
+ }
+
+ void SearchStart()
+ {
+ char text[2048];
+
+ searchThread.active = true;
+
+ searchThread.optionSubdirs = options.subdirs.checked;
+ searchThread.optionTree = (options.subdirs.checked && options.tree.checked);
+ searchThread.optionBrowser = (options.subdirs.checked && options.browser.checked);
+ searchThread.optionNameMatchCase = findName.optionMatchCase.checked;
+ searchThread.optionNameMatchWord = findName.optionMatchWord.checked;
+ searchThread.optionContentMatchCase = findTextContent.optionMatchCase.checked;
+ searchThread.optionContentMatchWord = findTextContent.optionMatchWord.checked;
+
+ strcpy(searchThread.location, location.GetText());
+ strcpy(searchThread.nameSearch, findName.GetText());
+ strcpy(searchThread.contentSearch, findTextContent.GetText());
+
+ actions.startStop.text = "Stop Search";
+ actions.clear.disabled = false;
+ view.results.Clear();
+ view.results.hasHeader = !searchThread.optionTree;
+ view.results.treeBranches = searchThread.optionTree;
+ view.browser.Clear();
+ ToggleBrowserDisplay(searchThread.optionBrowser);
+
+ view.browser.text = "Browser";
+ sprintf(text, "Search Results (Searching %s)", location.GetText());
+ view.results.text = text;
+
+ searchThread.Create();
+ }
+
+ bool SearchStop()
+ {
+ if(searchThread.active)
+ {
+ searchThread.terminate = true;
+ app.Unlock();
+ searchThread.Wait();
+ app.Lock();
+ return true;
+ }
+ return false;
+ }
+
+ void SearchUpdateLabel(char * path)
+ {
+ char text[2048];
+ sprintf(text, "Search Results (Searching %s)", path);
+ view.results.text = text;
+ }
+
+ void AddResult(ExplorerFileBranch branch, ExplorerFileBranch addTo)
+ {
+ AddBranch(branch, true, false, addTo, view.results);
+ }
+
+ void SortResults()
+ {
+ //view.results.Sort(resultsNameField, 1);
+ }
+
+ void AddBrowse(ExplorerFileBranch branch, ExplorerFileBranch addTo)
+ {
+ AddBranch(branch, true, false, addTo, view.browser);
+ }
+
+ void SortBrowser()
+ {
+ //view.browser.Sort(browserNameField, 1);
+ }
+
+ void SearchTerminate()
+ {
+ char text[1024];
+
+ if(searchThread.terminate)
+ sprintf(text, "Search Results (%d item(s) found), Search was aborted.", searchThread.matchCount);
+ else
+ sprintf(text, "Search Results (%d item(s) found), Search completed successfuly.", searchThread.matchCount);
+ view.results.text = text;
+ sprintf(text, "Browser (%d item(s) searched)", searchThread.count);
+ view.browser.text = text;
+
+ actions.startStop.text = "Start Search";
+ }
+
+ void ListDirectory(DataRow addTo, char * path)
+ {
+ FileListing listing { path };
+ while(listing.Find())
+ {
+ DataRow row = addTo.AddString(listing.name);
+ row.collapsed = true;
+ if(listing.stats.attribs.isDirectory)
+ ListDirectory(row, listing.path);
+ }
+ }
+
+ void ToggleBrowserDisplay(bool visible)
+ {
+ //view.labelBrowser.visible = visible;
+ view.browser.visible = visible;
+ if(visible)
+ view.results.anchor.bottom = 304;
+ else
+ view.results.anchor.bottom = 4;
+ }
+
+ PanelFileName findName
+ {
+ this, master;
+ anchor = Anchor { left = 4, top = 0, right = 4 };
+ };
+ /*PanelFileSize findSize
+ {
+ this, master;
+ anchor = Anchor { left = 4, top = (int)(findName.position.y + findName.size.h + 4), right = 4 };
+ };*/
+ PanelFileTextContent findTextContent
+ {
+ this, master;
+ anchor = Anchor { left = 4, top = (int)(findName.position.y + findName.size.h + 4), right = 4 };
+ };
+ PanelLocation location
+ {
+ this, master;
+ anchor = Anchor { left = 4, top = (int)(findTextContent.position.y + findTextContent.size.h + 4), right = 4 };
+#ifdef _DEBUG
+ editBox.contents = "D:\\Projects\\Ecere";
+#endif
+ };
+ PanelOptions options
+ {
+ this, master;
+ anchor = Anchor { left = 4, top = (int)(location.position.y + location.size.h + 4), right = 4 };
+ };
+ PanelActions actions
+ {
+ this, master;
+ anchor = Anchor { left = 4, top = (int)(options.position.y + options.size.h + 4), right = 4 };
+ };
+
+ ExplorerSearch()
+ {
+ }
+
+ void OnDestroy()
+ {
+ SearchStop();
+ }
+
+}
+
+class ExplorerSearchView : ExplorerView
+{
+ virtual void AddItem(const FileStats stats, const char * name, bool match);
+}
+
+class ExplorerSearchViewTree : ExplorerSearchView
+{
+
+ DataField resultsFieldPath { "char *" };
+
+ ListBox results
+ {
+ this, master;
+
+ borderStyle = none; // deep
+ hasHorzScroll = true;
+ hasVertScroll = true;
+ fullRowSelect = false;
+ treeBranches = true;
+ collapseControl = true;
+ rootCollapseButton = true;
+ multiSelect = true;
+
+ size = Size { 600, 200 };
+ //anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
+ //anchor = Anchor { left = 8, top = 24, right = 4, bottom = 304 };
+ anchor = Anchor { left = 0, top = 0, right = 0, bottom = 304 };
+ text = "Search Results", hotKey = Key { r, alt = true };
+
+ /*hasHeader = true, moveFields = true, resizable = true, sortable = true;*/
+
+ NotifyKeyHit = CommonNotifyKeyHit;
+ NotifyDoubleClick = Lists_NotifyDoubleClick;
+ };
+ DataField resultsNameField { header = "Name", dataType = "ExplorerFileBranch", width = 304, userData = this };
+ ListBox browser
+ {
+ this, master;
+
+ borderStyle = none; // deep
+ hasHorzScroll = true;
+ hasVertScroll = true;
+ fullRowSelect = false;
+ treeBranches = true;
+ collapseControl = true;
+ rootCollapseButton = true;
+ multiSelect = true;
+
+ size = Size { 624, 268 };
+ anchor = Anchor { left = 8, right = 4, bottom = 4 };
+ text = "Browser", hotKey = Key { e, alt = true };
+
+ /*hasHeader = true, moveFields = true, resizable = true, sortable = true;*/
+
+ NotifyKeyHit = CommonNotifyKeyHit;
+ NotifyDoubleClick = Lists_NotifyDoubleClick;
+ };
+ DataField browserNameField { header = "Name", dataType = "ExplorerFileBranch", width = 304, userData = this }; // editable = true
+
+ bool CommonNotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch)
+ {
+ if((SmartKey)key == del)
+ {
+ //DeleteBox { this, source = listBox }.Modal();
+ /*
+ if(MessageBox { finderWnd, text = "text", contents = "contents", type = yesNo }.Modal() == yes)
+ {
+ OldList selection;
+ Link item;
+
+ listBox.GetMultiSelection(selection);
+
+ for(item = selection.first; item; item = item.next)
+ {
+ char path[MAX_LOCATION];
+ DataRow row = item.data;
+ ExplorerFileBranch branch = (ExplorerFileBranch)row.tag;
+ branch.GetPath(path);
+ if(FileExists(path))
+ DeleteFile(path);
+ if(!FileExists(path))
+ DeleteBranch(branch, listBox);
+ }
+ selection.Free(null);
+ }
+ */
+ }
+ return true;
+ }
+
+ bool Lists_NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
+ {
+ if(listBox.currentRow)
+ {
+ char path[MAX_LOCATION];
+ ExplorerFileBranch branch = (ExplorerFileBranch)listBox.currentRow.tag;
+ //if(listBox != view.results || searchThread.tree)
+ // GetRowPath(listBox.currentRow, path);
+ //else
+ // strcpy(path, *(char **)listBox.currentRow.GetData(resultsFieldPath));
+ branch.GetPath(path);
+ ShellOpen(path);
+ return false;
+ }
+ return true;
+ }
+
+ ExplorerSearchViewTree()
+ {
+ results.AddField(resultsNameField);
+ browser.AddField(browserNameField);
+ }
+
+}
+
--- /dev/null
+/*
+public import "ecere"
+
+static class MsgLine : struct
+{
+ MsgLine prev, next;
+ char * string;
+ int len;
+};
+
+public class NotificationBox : Window
+{
+ background = activeBorder;
+ borderStyle = contour;
+ //hasClose = true;
+ //tabCycle = true;
+
+ AutoDestroyThread autoDestroy { box = this };
+
+public:
+ property char * contents
+ {
+ set
+ {
+ FreeLines();
+ if(value)
+ {
+ int len = strlen(value);
+ int start = 0;
+ int c;
+ for(c = 0; c <= len; c++)
+ {
+ if(c == len || value[c] == '\n')
+ {
+ MsgLine line { };
+ lines.Add(line);
+ if(line)
+ {
+ line.len = c - start;
+ line.string = new char[line.len+1];
+ CopyBytes(line.string, value + start, line.len);
+ line.string[line.len] = '\0';
+ start = c+1;
+ }
+ }
+ }
+ }
+ }
+ };
+ Seconds delay;
+ GuiApplication app;
+ Window reactivate;
+
+private:
+ OldList lines;
+ int totalWidth, totalHeight, lineHeight;
+
+ ~NotificationBox()
+ {
+ FreeLines();
+ }
+
+ */
+ /*
+ bool ButtonActivate(Window control, bool active, Window previous)
+ {
+ control.isDefault = true;
+ return true;
+ }
+ */
+ /*
+
+ bool OnPostCreate()
+ {
+ if(!delay)
+ autoDestroy.delay = 1;
+ else
+ autoDestroy.delay = delay;
+ autoDestroy.app = app;
+ autoDestroy.Create();
+ return true;
+ }
+
+ */
+ /*bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
+ {
+ if(reactivate)
+ reactivate.Activate();
+ return true;
+ }*/
+ /*
+
+ bool OnResizing(int *w, int *h)
+ {
+ *w = Max(*w, Max(totalWidth, 144) + 24);
+
+ *h = Max(*h, Max(totalHeight, 33));// + 40);
+ return true;
+ }
+
+ void OnRedraw(Surface surface)
+ {
+ MsgLine line;
+ //int y = (clientSize.h - 33 - totalHeight) / 2;
+ int y = (clientSize.h - totalHeight) / 2;
+ for(line = lines.first; line; line = line.next)
+ {
+ surface.WriteText((clientSize.w - totalWidth) / 2, y, line.string, line.len);
+ y += lineHeight;
+ }
+ }
+
+ bool OnLoadGraphics()
+ {
+ MsgLine line;
+
+ totalHeight = 0;
+ for(line = lines.first; line; line = line.next)
+ {
+ Size size;
+ if(!line.string[0])
+ display.FontExtent(fontObject, " ", 1, (int *)&size.w, (int *)&size.h);
+ else
+ display.FontExtent(fontObject, line.string, strlen(line.string), (int *)&size.w, (int *)&size.h);
+ if(size.h)
+ lineHeight = size.h;
+ totalWidth = Max(totalWidth, size.w);
+ totalHeight += size.h;
+ }
+ return true;
+ }
+
+ void FreeLines()
+ {
+ MsgLine line;
+ for(line = lines.first; line; line = line.next)
+ delete line.string;
+ lines.Free(null);
+ }
+};
+
+class AutoDestroyThread : Thread
+{
+ GuiApplication app;
+ NotificationBox box;
+ Seconds delay;
+
+ unsigned int Main()
+ {
+ int c;
+ int r = 5;
+ int w, h;
+ Sleep(delay);
+ app.Lock();
+ w = box.size.w;
+ h = box.size.h;
+ app.Unlock();
+ for(c = 0; c < r; c--)
+ {
+ //int vw = w / r;
+ int vh = h / r / 2 - c * h / (r * 2);
+ app.Lock();
+ //box.position.x += vw / 2;
+ box.position.y += vh / 2;
+ //box.size.w -= vw;
+ box.size.h -= vh;
+ box.Update(null);
+ app.Unlock();
+ Sleep(0.5 / r);
+ }
+ app.Lock();
+ box.Destroy(0);
+ app.Unlock();
+ return 0;
+ }
+}
+
+*/
--- /dev/null
+import "Explorer"
+//import "ecere"
+//import "Finder"
+
+class Panel : Label
+{
+ //background = activeBorder;
+ size = { 200, 40 };
+ isGroupBox = true;
+ //background = activeBorder;
+
+ bool OnMoving(int * x, int * y, int w, int h)
+ {
+ //if(((ExplorerWindow)master).userMode)
+ // return false;
+ return true;
+ }
+}
+
+class PanelText : Panel
+{
+ // IDEA: Would it be totally unreasonable for a group box to use client size
+ // to set the actual size considering the size of the border?
+ // Also, to have anchors be relative to the client size?
+ clientSize = { 200, 40 };
+ size = { 200, 64 };
+ //background = activeBorder;
+
+ EditBox editBox
+ {
+ this;
+ //borderStyle = none;
+ size = { 160, 20 };
+ anchor = { left = 8, top = 16, right = 8 };
+ };
+
+ char * GetText()
+ {
+ return editBox.contents;
+ }
+}
+
+class PanelTextMatch : PanelText
+{
+ clientSize = { 200, 40 };
+ size = { 200, 64 };
+
+ Button optionMatchCase
+ {
+ this;
+ //toggle = true, inactive = true;
+ isCheckbox = true;
+ text = "Match Case", hotKey = Key { c, alt = true };
+ //size = { 40, 18 };
+ //anchor = { left = 4, top = 40, right = 0.508f };
+ anchor = { top = 38, right = 8 };
+ };
+ Button optionMatchWord
+ {
+ this;
+ //toggle = true, inactive = true;
+ isCheckbox = true;
+ text = "Match Whole Word", hotKey = Key { w, alt = true };
+ //size = { 40, 18 };
+ position = Point { y = 62 };
+ //anchor = { left = 0.508f, top = 40, right = 4 };
+ anchor = { top = 38, right = 8 };
+ };
+
+ bool OnPostCreate()
+ {
+ optionMatchCase.anchor.right = (int)optionMatchWord.size.w + 8 + 2;
+ return true;
+ }
+
+ /*void OnResize(int width, int height)
+ {
+ optionMatchCase.anchor.right = (int)optionMatchWord.size.w + 8 + 2;
+ }*/
+}
+
+class PanelFileName : PanelTextMatch
+{
+ clientSize = { 200, 40 };
+ size = { 200, 64 };
+ text = "File Name";
+ hotKey = Key { n, alt = true };
+
+#ifdef _DEBUG
+ editBox.contents = "Ecere";
+#endif
+}
+
+class PanelFileSize : Panel
+{
+ clientSize = { 200, 40 };
+ size = { 200, 64 };
+
+ text = "File Size";
+ hotKey = Key { s, alt = true };
+
+ uint compare;
+
+ EditBox editBox
+ {
+ this;
+ //borderStyle = none;
+ contents = "1024";
+ size = { 102, 18 };
+ anchor = { left = 8, top = 16, right = 130 };
+
+ bool NotifyModified(EditBox editBox)
+ {
+ UpdateCompare();
+ return true;
+ }
+ };
+ Button optionGB
+ {
+ this;
+ toggle = true, inactive = true;
+ text = "GB";
+ size = { 30, 18 };
+ anchor = { top = 16, right = 98 };
+ NotifyClicked = optionScale_NotifyClicked;
+ };
+ Button optionMB
+ {
+ this;
+ toggle = true, inactive = true;
+ text = "MB";
+ size = { 30, 18 };
+ anchor = { top = 16, right = 66 };
+ NotifyClicked = optionScale_NotifyClicked;
+ };
+ Button optionKB
+ {
+ this;
+ toggle = true, checked = true, inactive = true;
+ text = "KB";
+ size = { 30, 18 };
+ anchor = { top = 16, right = 34 };
+ NotifyClicked = optionScale_NotifyClicked;
+ };
+ Button optionB
+ {
+ this;
+ toggle = true, inactive = true;
+ text = "B";
+ size = { 30, 18 };
+ anchor = { top = 16, right = 4 };
+ NotifyClicked = optionScale_NotifyClicked;
+ };
+
+ Button optionSmaller
+ {
+ this;
+ toggle = true, inactive = true;
+ text = "Smaller";
+ size = { 74, 18 };
+ anchor = { left = 4, top = 41, right = 0.67f };
+ NotifyClicked = optionCompare_NotifyClicked
+ };
+ Button optionEqual
+ {
+ this;
+ toggle = true, inactive = true;
+ text = "Equal";
+ size = { 74, 18 };
+ anchor = { left = 0.34f, top = 41, right = 0.34f };
+ NotifyClicked = optionCompare_NotifyClicked;
+ };
+ Button optionGreater
+ {
+ this;
+ toggle = true, checked = true, inactive = true;
+ text = "Greater";
+ size = { 74, 18 };
+ anchor = { left = 0.67f, top = 41, right = 4 };
+ NotifyClicked = optionCompare_NotifyClicked;
+ };
+
+ bool optionScale_NotifyClicked(Button button, int x, int y, Modifiers mods)
+ {
+ optionGB.checked = (button == optionGB);
+ optionMB.checked = (button == optionMB);
+ optionKB.checked = (button == optionKB);
+ optionB.checked = (button == optionB);
+ UpdateCompare();
+ return true;
+ }
+
+ bool optionCompare_NotifyClicked(Button button, int x, int y, Modifiers mods)
+ {
+ optionSmaller.checked = (button == optionSmaller);
+ optionEqual.checked = (button == optionEqual);
+ optionGreater.checked = (button == optionGreater);
+ return true;
+ }
+
+ bool Match(uint size)
+ {
+ if(optionSmaller.checked)
+ return size < compare;
+ else if(optionEqual.checked)
+ return size = compare;
+ else if(optionGreater.checked)
+ return size > compare;
+ else
+ return false;
+ }
+
+ void UpdateCompare()
+ {
+ if(optionGB.checked)
+ compare = atoi(editBox.contents) * 1024 * 1024 * 1024;
+ else if(optionMB.checked)
+ compare = atoi(editBox.contents) * 1024 * 1024;
+ else if(optionKB.checked)
+ compare = atoi(editBox.contents) * 1024;
+ else if(optionB.checked)
+ compare = atoi(editBox.contents);
+ }
+
+}
+
+class PanelFileTextContent : PanelTextMatch
+{
+ clientSize = { 200, 40 };
+ size = { 200, 64 };
+ text = "Text Content";
+ hotKey = Key { x, alt = true };
+}
+
+class PanelLocation : Panel
+{
+ clientSize = { 200, 40 };
+ size = { 200, 44 };
+ text = "Location";
+ hotKey = Key { l, alt = true };
+
+ FileDialog fileDialog
+ {
+ master, master;
+ type = selectDir;
+ text = "Select Search Location...";
+ };
+
+ EditBox editBox
+ {
+ this;
+ //borderStyle = none;
+ contents = "/";
+ size = { 160, 20 };
+ anchor = { left = 8, top = 16, right = 2 + 24 + 8 };
+ };
+
+ ToolButton browse
+ {
+ this;
+ anchor = { top = 14, right = 8 };
+ toolId = ExplorerToolId::browse;
+
+ bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+ {
+ fileDialog.currentDirectory = editBox.contents;
+ if(fileDialog.Modal() == ok)
+ editBox.contents = fileDialog.filePath;
+ return true;
+ }
+ };
+
+ /*Button buttonBrowse
+ {
+ this;
+ text = "Browse", hotKey = Key { b, alt = true };
+ size = { 160, 29 };
+ anchor = { left = 8, top = 41, right = 8 };
+
+ };*/
+
+ char * GetText()
+ {
+ return editBox.contents;
+ }
+}
+
+class PanelOptions : Panel
+{
+ clientSize = { 200, 60 };
+ size = { 200, 80 };
+ text = "Options";
+ hotKey = Key { o, alt = true };
+
+ Button subdirs
+ {
+ this;
+ toggle = true, checked = true;
+ text = "Search Sub Directories", hotKey = Key { d, alt = true };
+ size = { 160, 18 };
+ anchor = { left = 8, top = 16, right = 8 };
+
+ bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+ {
+ if(button.checked)
+ {
+ tree.disabled = false;
+ browser.disabled = false;
+ }
+ else
+ {
+ // I need a way to show this unchecked while keeping it original checked value
+ tree.disabled = true;
+ browser.disabled = true;
+ }
+ return true;
+ }
+ };
+ Button tree
+ {
+ this;
+ toggle = true, checked = true, inactive = true;
+ text = "Display Results With Tree", hotKey = Key { t, alt = true };
+ size = { 160, 18 };
+ anchor = { left = 8, top = 40, right = 8 };
+
+ bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+ {
+ ExplorerSearch search = (ExplorerSearch)parent;
+ search.OptTree(button.checked);
+ return true;
+ }
+ };
+ Button browser
+ {
+ this;
+ toggle = true, checked = true, inactive = true;
+ text = "Show Browser", hotKey = Key { h, alt = true };
+ size = { 160, 18 };
+ anchor = { left = 8, top = 60, right = 8 };
+ };
+}
+
+class PanelActions : Panel
+{
+ clientSize = { 200, 38 };
+ size = { 200, 48 };
+ text = "Actions";
+ hotKey = Key { o, alt = true };
+
+ Button startStop
+ {
+ this;
+ isDefault = true;
+ text = "Start Search", hotKey = Key { s, alt = true };
+ size = { 80, 26 };
+ anchor = { top = 16, right = 92 };
+
+ bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+ {
+ ExplorerSearch search = (ExplorerSearch)parent;
+ //--//if(!finderWnd.SearchStop())
+ search.SearchStart();
+ return true;
+ }
+ };
+ Button clear
+ {
+ this;
+ disabled = true;
+ text = "Clear Results", hotKey = Key { c, alt = true };
+ size = { 80, 26 };
+ anchor = { top = 16, right = 8 };
+
+ bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+ {
+ ExplorerSearch search = (ExplorerSearch)parent;
+ search.SearchStop();
+ search.view.results.Clear();
+ search.view.browser.Clear();
+ button.disabled = true;
+ return true;
+ }
+ };
+}
+
--- /dev/null
+import "ExplorerTree"
+import "Finder"
+
+class NumberLink : struct
+{
+ NumberLink prev, next;
+ int num;
+};
+
+struct SearchStackFrame
+{
+ int tag;
+ char path[MAX_LOCATION];
+ FileListing listing;
+
+ bool branched;
+ //DataRow result;
+ //DataRow browse;
+ ExplorerFileBranch result;
+ ExplorerFileBranch browse;
+};
+
+class SearchThread : Thread
+{
+ bool active, terminate, hasNameSearch, hasSizeSearch, hasContentSearch, listLines;
+ int count, matchCount;
+ char location[MAX_LOCATION], nameSearch[1024], contentSearch[1024];
+ bool optionTree, optionBrowser, optionSubdirs;
+ bool optionNameMatchCase, optionNameMatchWord;
+ bool optionContentMatchCase, optionContentMatchWord;
+ OldList lines;
+ //DataField resultsNameField;
+ //DataField browserNameField;
+
+ ExplorerSearch searchPanel;
+
+ SearchThread()
+ {
+ active = false;
+ terminate = false;
+ }
+
+ bool SearchFileContent(String path)
+ {
+ bool match = false;
+ File file = FileOpen(path, read);
+ if(file)
+ {
+ //
+ // char line[65536];
+ // char * find = null;
+ // for( ; !find && file.GetLine(line, 65536) ; )
+ // find = SearchString(line, 0, contentSearch, optionContentMatchCase, optionContentMatchWord);
+ // // find = strstr(line, contentSearch);
+ //
+
+ uint readCount = 16383;
+ char * find = null;
+ char buffer[16384];
+ int seekBack = 0 - strlen(contentSearch) - 2;
+ if(listLines)
+ {
+ uint line = 1;
+ while(readCount == 16383)
+ {
+ uint start = 0, len = 0;
+ readCount = file.Read(buffer, 1, 16383);
+ buffer[readCount] = '\0';
+ for( ; start < readCount; start += len ? len : 1)
+ {
+ if( (len = strlen(&buffer[start])) )
+ {
+ char * newLine = buffer;
+ uint bstart;
+ find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord);
+
+ // todo add a maximum line length possibility as param
+ for(bstart = start;
+ bstart < readCount && newLine && (!find || newLine < find);
+ bstart += (newLine - &buffer[bstart]) / sizeof(char))
+ {
+ newLine = strstr(&buffer[bstart], "\n");
+ newLine++;
+ if(bstart + (newLine - &buffer[bstart]) / sizeof(char) < readCount && newLine && (!find || newLine < find))
+ line++;
+ }
+
+ if(find)
+ {
+ len = (find - &buffer[start]) / sizeof(char) + strlen(contentSearch);
+ match = true;
+ if(!lines.first || ((NumberLink)lines.last).num != line)
+ lines.Add(NumberLink { num = line });
+ }
+
+ }
+ }
+ file.Seek(seekBack, current);
+ }
+ }
+ else
+ {
+ for( ; !find && readCount == 16383; )
+ {
+ uint start = 0, len = 0;
+ readCount = file.Read(buffer, 1, 16383);
+ buffer[readCount] = '\0';
+ for( ; !find && start < readCount; start += len + 1)
+ if( (len = strlen(&buffer[start])) )
+ find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord);
+ file.Seek(seekBack, current);
+ }
+ match = (bool)find;
+ }
+ delete file;
+ }
+ return match;
+ }
+
+ // I wonder if this is optimized at the c level to be compiled inline
+ // and to use in-place in-stack memory for both the return value and the parameters
+ // if not, c should be more optimized...
+ // would the const have any impact on optimization?
+ unsigned int Main()
+ {
+ bool match;
+ int frame, stackTop = 0, treeTop = 0;
+ double lastTime = GetTime();
+ SearchStackFrame stack[1024];
+ //to be used for content replace... EditBox edit { multiLine = true, textHorzScroll = true, textVertScroll = true, maxLineSize = 65536 };
+
+ ExplorerFileBranch fileTreeBranch;
+ // This won't give drive attribs for c: or c:\ and other drives as well
+ // \\Nateus\data\ is not remote, etc...
+ // How to?
+ FileStats stats;
+
+ terminate = false;
+ count = 0;
+ matchCount = 0;
+
+ hasNameSearch = (strlen(nameSearch) != 0);
+ hasSizeSearch = false; // this is temporary
+ hasContentSearch = (strlen(contentSearch) != 0);
+
+ listLines = true;
+ lines = OldList { };
+
+ //SearchDir(location);
+
+ FileGetStats(location, stats);
+
+ strcpy(stack[0].path, location);
+ stack[0].listing = FileListing { stack[0].path }; // there should be a sorted = true/false
+ // Binary Search sorting...
+ if(optionTree)
+ stack[0].branched = false;
+ if(optionBrowser)
+ {
+ app.Lock();
+ {
+ //stack[0].browse = searchPanel.AddBrowserRow();
+ //fileTreeBranch = MakeFileBranch(attribs, stack[0].path);
+ //stack[0].browse.SetData(browserNameField, fileTreeBranch);
+ //stack[0].browse.SetData(typeField, null);
+ //stack[0].browse.SetData(sizeField, null);
+
+ stack[0].browse = MakeFileBranch(stats, stack[0].path);
+ searchPanel.AddBrowse(stack[0].browse, null);
+ }
+ app.Unlock();
+ }
+
+ for(frame = 0; frame >= 0 && !terminate; )
+ {
+ if(stack[frame].listing.Find())
+ {
+ count++;
+
+ //match = (strcmp(stack[frame].listing.name, nameSearch) == 0);
+ //match = (stack[frame].listing.name[0] == nameSearch[0]);
+ //match = (bool)strstr(stack[frame].listing.name, nameSearch);
+
+ if(hasNameSearch)
+ match = (bool)SearchString(stack[frame].listing.name, 0, nameSearch, optionNameMatchCase, optionNameMatchWord);
+ else
+ match = true;
+
+ if(match && hasContentSearch && !stack[frame].listing.stats.attribs.isDirectory)
+ if(!SearchFileContent(stack[frame].listing.path))
+ match = false;
+
+ if(match)
+ {
+ matchCount++;
+ if(optionTree)
+ {
+ for(frame = treeTop; frame <= stackTop; frame++)
+ {
+ if(!stack[frame].branched)
+ {
+ app.Lock();
+ if(frame)
+ {
+ stack[frame].result = MakeFileBranch(stack[frame - 1].listing.stats, stack[frame - 1].listing.name);
+ searchPanel.AddResult(stack[frame].result, stack[frame - 1].result);
+ stack[frame].result.row.collapsed = false;
+ }
+ else
+ {
+ stack[0].result = MakeFileBranch(stats, stack[0].path);
+ searchPanel.AddResult(stack[0].result, null);
+ stack[0].result.row.collapsed = false;
+ }
+ stack[frame].branched = true;
+ app.Unlock();
+ }
+ }
+ treeTop = stackTop;
+ frame--;
+ }
+ }
+ if(optionSubdirs && stack[frame].listing.stats.attribs.isDirectory)
+ {
+ app.Lock();
+ {
+ double thisTime = GetTime();
+ if(thisTime - lastTime > 0.25)
+ {
+ searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);
+ lastTime = thisTime;
+ }
+ }
+ //searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);
+ frame++;
+ if(optionBrowser)
+ {
+ stack[frame].browse = MakeFileBranch(stack[stackTop].listing.stats, stack[stackTop].listing.name);
+ searchPanel.AddBrowse(stack[frame].browse, stack[stackTop].browse);
+
+ if(frame)
+ stack[frame].browse.row.collapsed = true;
+ //if(frame == 1)
+ //searchPanel.SortBrowser(); // this can be very bad for performance in some situations
+ // there should be a way to sort the nodes as they are added
+ // BinarySearch sorting implementation in listBox's Sort?
+ }
+ app.Unlock();
+ strcpy(stack[frame].path, stack[stackTop].listing.path);
+ stack[frame].listing = FileListing { stack[frame].path };
+ if(optionTree)
+ stack[frame].branched = false;
+ if(match)
+ {
+ app.Lock();
+ if(optionTree)
+ {
+ stack[frame].result = MakeFileBranch(stack[stackTop].listing.stats, stack[stackTop].listing.name);
+ searchPanel.AddResult(stack[frame].result, stack[stackTop].result);
+ stack[frame].result.row.collapsed = false;
+ //searchPanel.SortResults(); // this can be very bad for performance in some situations
+ // there should be a way to sort the nodes as they are added
+ // BinarySearch sorting implementation in listBox's Sort?
+ stack[frame].branched = true;
+ }
+ else
+ {
+ //searchPanel.SearchAddResultsItem(stack[stackTop].listing.name, stack[stackTop].listing.path);
+ }
+ app.Unlock();
+ }
+ stackTop++;
+ }
+ else
+ {
+ app.Lock();
+ if(optionBrowser)
+ {
+ ExplorerFileBranch item;
+ item = MakeFileBranch(stack[frame].listing.stats, stack[frame].listing.name);
+ searchPanel.AddBrowse(item, stack[frame].browse);
+ //if(frame == 1)
+ //searchPanel.SortBrowser(); // this can be very bad for performance in some situations
+ // there should be a way to sort the nodes as they are added
+ // BinarySearch sorting implementation in listBox's Sort?
+ }
+ if(match)
+ {
+ if(optionTree)
+ {
+ ExplorerFileBranch item;
+ item = MakeFileBranch(stack[frame].listing.stats, stack[frame].listing.name);
+ searchPanel.AddResult(item, stack[frame].result);
+ item.row.collapsed = false;
+ //searchPanel.SortResults(); // this can be very bad for performance in some situations
+ // there should be a way to sort the nodes as they are added
+ // BinarySearch sorting implementation in listBox's Sort?
+
+ if(listLines && lines.first)
+ {
+ NumberLink lin = lines.first;
+ char temp[MAX_F_STRING];
+ sprintf(temp, "lines %d", lin.num);
+ for(lin = lin.next; lin && strlen(temp) < MAX_F_STRING; lin = lin.next)
+ strcatf(temp, ", %d", lin.num);
+ fileTreeBranch = ExplorerFileBranch { name = CopyString(temp), type = lineNumbers };
+ searchPanel.AddResult(fileTreeBranch, item);
+ //row.AddRow().SetData(resultsNameField, fileTreeBranch);
+ lines.Free(null);
+ }
+ }
+ else
+ ;//searchPanel.SearchAddResultsItem(stack[frame].listing.name, stack[frame].listing.path);
+ }
+ app.Unlock();
+ }
+ }
+ else
+ {
+ if(optionTree && stack[frame].branched && frame == treeTop)
+ {
+ stack[frame].branched = false;
+ treeTop--;
+ }
+ frame--;
+ stackTop--;
+ }
+ }
+ if(terminate)
+ for( ; frame >= 0 ; frame--)
+ stack[frame].listing.Stop();
+
+ app.Lock();
+ if(optionTree)
+ searchPanel.SortResults();
+ if(optionBrowser)
+ searchPanel.SortBrowser();
+ app.Unlock();
+
+ active = false;
+
+ searchPanel.SearchTerminate();
+ return 0;
+ }
+}
+
+
--- /dev/null
+import "ecere"
+//import "Finder"
+
+#define BORDER 2
+#define TOP 2
+#define BOTTOM 2
+#define CORNER (BORDER * 2)
+#define CAPTION 12
+#define DEAD_BORDER 2
+#define MIN_WIDTH 60
+#define MIN_HEIGHT 3
+#define BUTTON_OFFSET 0
+#define NAME_OFFSET 0
+#define NAME_OFFSETX 4
+
+#define SB_WIDTH 16
+#define SB_HEIGHT 16
+
+#define MENU_HEIGHT 25
+#define STATUS_HEIGHT 18
+
+#define TEXT_COLOR skinForeground
+#define TEXT_INACTIVE darkGray
+
+define skinBackground = Color { r = 40, g = 40, b = 40 };
+define skinForeground = white;
+define skinTextForeground = lightGray;
+define evenRowBackground = Color { 80, 70, 60 };
+define selectionColor = steelBlue;
+
+ColorKey skinGradient[3] =
+{
+ { Color { 40,40,40 }, 0.0f },
+ { darkGray, 0.5f },
+ { Color { 40,40,40 }, 1.0f },
+};
+
+/*
+define skinBackground = white; //Color { 255, 255, 255 };
+define skinForeground = black;
+define skinTextForeground = black;
+define evenRowBackground = lavender;
+define selectionColor = cornflowerBlue;
+
+ColorKey skinGradient[2] =
+{
+ { lightGray, 0.0f }
+ { white, 1.0f },
+};
+*/
+
+class AcovelSkin_Window : Window
+{
+ void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving)
+ {
+ bool isNormal = (state == normal || state == maximized);
+ int top = 0, border = 0, bottom = 0;
+ if(state == minimized)
+ top = border = bottom = DEAD_BORDER;
+ else if(((BorderBits)borderStyle).sizable)
+ {
+ top = isNormal ? TOP : 0;
+ border = isNormal ? BORDER : 0;
+ bottom = BOTTOM;
+ }
+ else if(((BorderBits)borderStyle).fixed)
+ {
+ top = 2; //DEAD_BORDER;
+ border = DEAD_BORDER;
+ bottom = DEAD_BORDER;
+ }
+ else if(((BorderBits)borderStyle).contour)
+ {
+ top = 1;
+ border = 1;
+ bottom = 1;
+ }
+
+ if(((BorderBits)borderStyle).deep || ((BorderBits)borderStyle).bevel)
+ {
+ int deepTop = 0, deepBottom = 0, deepBorder = 0;
+ if(((BorderBits)borderStyle).contour)
+ {
+ deepBorder = border;
+ deepTop = (((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar)) ? (top + CAPTION) : top;
+ deepBottom = (((BorderBits)borderStyle).sizable && isNormal) ? bottom : border;
+ }
+
+ surface.Bevel(((BorderBits)borderStyle).bevel ? false : true, deepBorder, deepTop,
+ size.w - deepBorder - deepBorder, size.h - deepBottom - deepTop);
+ }
+
+ if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
+ {
+ /*
+ if(state != maximized || !((BorderBits)borderStyle).sizable)
+ {
+ // Frame for ES_CAPTION windows
+ surface.Bevel(false, 0, 0, size.w, size.h);
+ surface.SetForeground(activeBorder);
+ surface.Rectangle(2, 2, size.w-3, size.h-3);
+
+ // Resizeable frame is 1 pixel thicker
+ if(((BorderBits)borderStyle).sizable && isNormal)
+ surface.Rectangle(3, 3, size.w - 4, size.h - 4);
+ }
+
+ // Caption
+ if(active)
+ surface.Gradient(gradient, sizeof(gradient) / sizeof(ColorKey), GRADIENT_SMOOTHNESS, GRADIENT_DIRECTION,
+ border, top, size.w - border - 1, top + CAPTION - 2);
+ else
+ surface.Gradient(gradientInactive, sizeof(gradientInactive) / sizeof(ColorKey),
+ GRADIENT_SMOOTHNESS, GRADIENT_DIRECTION,
+ border, top, size.w - border - 1, top + CAPTION - 2);
+
+ surface.SetForeground(activeBorder);
+ if(state != minimized)
+ surface.HLine(border, size.w-border-1, top + CAPTION-1);
+ */
+
+ surface.SetForeground(skinBackground);
+ surface.Rectangle(0,0, size.w-1, size.h-1);
+ surface.SetForeground(active ? TEXT_COLOR : TEXT_INACTIVE /*skinForeground*/);
+ surface.Rectangle(1,1, size.w-2, size.h-2);
+ surface.SetBackground(skinBackground);
+ surface.Area(2, 2, size.w-3, CAPTION + 2);
+
+ // surface.TextFont(captionFont);
+ // surface.WriteText(4,2, name, strlen(name));
+
+ surface.SetForeground((active ? TEXT_COLOR : TEXT_INACTIVE));
+ surface.TextOpacity(false);
+ surface.TextFont(captionFont);
+ if(name)
+ {
+ int buttonsSize = border +
+ ((hasMaximize || hasMinimize) ? 52 : 18);
+ surface.WriteTextDots(left, border + NAME_OFFSETX, top + NAME_OFFSET,
+ size.w - (buttonsSize + border + 4), name, strlen(name));
+ }
+ }
+ if(((BorderBits)borderStyle).contour && !((BorderBits)borderStyle).fixed)
+ {
+ surface.SetForeground(skinForeground /*black*/);
+ surface.Rectangle(0, 0, size.w - 1, size.h - 1);
+ }
+
+ if(state != minimized && hasHorzScroll && hasVertScroll)
+ {
+ if(sbh && sbh.visible && sbv && sbv.visible)
+ {
+ surface.SetBackground(activeBorder);
+ surface.Area(
+ clientStart.x + clientSize.w,
+ clientStart.y + clientSize.h,
+ clientStart.x + clientSize.w + SB_WIDTH - 1,
+ clientStart.y + clientSize.h + SB_HEIGHT - 1);
+ }
+ }
+ }
+
+ void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h)
+ {
+ *w = *h = 0;
+ if((((BorderBits)borderStyle).deep || ((BorderBits)borderStyle).bevel) && state != minimized)
+ {
+ *w += 4;
+ *h += 4;
+ }
+ if(((BorderBits)borderStyle).sizable && (state == normal || state == maximized))
+ {
+ *w += 2 * BORDER;
+ *h += TOP + BOTTOM;
+ }
+ if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
+ {
+ *h += CAPTION;
+ if(!((BorderBits)borderStyle).sizable || state == minimized)
+ {
+ *h += 2*DEAD_BORDER;
+ *w += 2*DEAD_BORDER;
+ }
+ }
+ if(((BorderBits)borderStyle).contour && !((BorderBits)borderStyle).fixed)
+ {
+ *w += 2;
+ *h += 2;
+ }
+ if(hasMenuBar && state != minimized)
+ {
+ *h += MENU_HEIGHT;
+ }
+ if(statusBar && state != minimized)
+ {
+ *h += STATUS_HEIGHT;
+ }
+ }
+
+ bool IsMouseMoving(int x, int y, int w, int h)
+ {
+ BorderBits style = (BorderBits)borderStyle; // TOFIX: borderStyle.fixed doesn't work
+ if(style.fixed)
+ {
+ bool resizeX, resizeY, resizeEndX, resizeEndY;
+ if(!IsMouseResizing(x, y, w, h, &resizeX, &resizeY, &resizeEndX, &resizeEndY))
+ return true;
+ }
+ return false;
+ }
+
+ bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
+ {
+ bool result = false;
+
+ *resizeX = *resizeY = *resizeEndX = *resizeEndY = false;
+
+ if(((BorderBits)borderStyle).sizable && (state == normal))
+ {
+ // TopLeft Corner
+ if(Box { 0, 0,CORNER-1, TOP-1 }.IsPointInside({x, y}))
+ result = *resizeX = *resizeY = true;
+ // TopRight Corner
+ if(Box { w-CORNER-1, 0, w-1, TOP-1 }.IsPointInside({x, y}))
+ result = *resizeEndX = *resizeY = true;
+ // BottomLeft Corner
+ if(Box { 0, h-BOTTOM-1, CORNER-1, h-1 }.IsPointInside({x, y}))
+ result = *resizeX = *resizeEndY = true;
+ // BottomRight Corner
+ if(Box { w-CORNER-1, h-BOTTOM-1, w-1, h-1 }.IsPointInside({x, y}))
+ result = *resizeEndX = *resizeEndY = true;
+ // Left Border
+ if(Box { 0,TOP, BORDER, h-BOTTOM-1 }.IsPointInside({x, y}))
+ result = *resizeX = true;
+ // Right Border
+ if(Box { w-BORDER-1, TOP, w-1, h-BOTTOM-1 }.IsPointInside({x, y}))
+ result = *resizeEndX = true;
+ // Top Border
+ if(Box { CORNER, 0, w-CORNER-1, TOP-1 }.IsPointInside({x, y}))
+ result = *resizeY = true;
+ // Bottom Border
+ if(Box { CORNER, h-BOTTOM-1, w-CORNER-1, h-1 }.IsPointInside({x, y}))
+ result = *resizeEndY = true;
+ }
+ return result;
+ }
+
+ void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh)
+ {
+ bool isNormal = (state == normal || state == maximized);
+ if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
+ {
+ *mw = MIN_WIDTH;
+ *mh = MIN_HEIGHT;
+ }
+ else
+ *mw = *mh = 0;
+ /*
+ if(((BorderBits)borderStyle).sizable && isNormal)
+ *mw += 2*CORNER;
+ // GetDecorationsSize(window, mw, mh);
+ */
+
+ if(hasVertScroll)
+ *mw += SB_WIDTH;
+ if(hasHorzScroll)
+ *mh += SB_HEIGHT;
+ if(hasVertScroll && hasHorzScroll)
+ {
+ *mw += 2 * SB_WIDTH + SB_WIDTH;
+ *mh += 2 * SB_HEIGHT + SB_HEIGHT;
+ /*
+ if(((BorderBits)borderStyle).sizable && isNormal)
+ *mw -= 2*CORNER;
+ */
+ }
+ }
+
+ void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
+ {
+ bool isNormal = (state == normal || state == maximized);
+ MinMaxValue aw = 0, ah = 0;
+
+ *x = *y = 0;
+
+ GetDecorationsSize(&aw, &ah);
+
+ // Compute client area start
+ if(((BorderBits)borderStyle).deep || ((BorderBits)borderStyle).bevel)
+ {
+ *x += 2;
+ *y += 2;
+ }
+
+ if(((BorderBits)borderStyle).sizable && isNormal)
+ {
+ *x += BORDER;
+ *y += TOP;
+ }
+
+ if(hasMenuBar)
+ {
+ *y += MENU_HEIGHT;
+ }
+
+ if(((BorderBits)borderStyle).fixed && (state != maximized || !parent.menuBar))
+ {
+ *y += CAPTION;
+ if(!((BorderBits)borderStyle).sizable || state == minimized)
+ {
+ *y += DEAD_BORDER;
+ *x += DEAD_BORDER;
+ }
+ }
+
+ if(((BorderBits)borderStyle).contour && !((BorderBits)borderStyle).fixed)
+ {
+ *x += 1;
+ *y += 1;
+ }
+
+ // Reduce client area
+ *cw = *w - aw;
+ *ch = *h - ah;
+
+ *cw = Max(*cw, 0);
+ *ch = Max(*ch, 0);
+ }
+
+ void UpdateNonClient()
+ {
+ bool isNormal = (state == normal || state == maximized);
+ int top = 0, border = 0;
+ int insideBorder;
+ if(state == minimized)
+ top = border = DEAD_BORDER;
+ else if(((BorderBits)borderStyle).sizable)
+ {
+ if(state == maximized && parent.menuBar)
+ {
+ top = 2;
+ border = 2;
+ }
+ else
+ {
+ top = isNormal ? TOP : 0;
+ border = isNormal ? BORDER : 0;
+ }
+ }
+ else if(((BorderBits)borderStyle).fixed)
+ {
+ top = 2;
+ border = 2;
+ }
+ else if(((BorderBits)borderStyle).contour)
+ {
+ top = 1;
+ border = 1;
+ }
+ insideBorder = border;
+ if(((BorderBits)borderStyle).deep)
+ insideBorder += 2;
+
+ if(menuBar)
+ {
+ if(state == minimized)
+ menuBar.visible = false;
+ else
+ menuBar.visible = true;
+ menuBar.Move(clientStart.x, clientStart.y - MENU_HEIGHT, size.w - insideBorder * 2, MENU_HEIGHT);
+ }
+ if(statusBar)
+ {
+ if(state == minimized)
+ statusBar.visible = false;
+ else
+ {
+ statusBar.visible = true;
+ statusBar.anchor = { left = clientStart.x, bottom = border };
+ statusBar.size.w = size.w - insideBorder * 2;
+ }
+ }
+
+ if(minimizeButton)
+ {
+ minimizeButton.anchor = { right = ((maximizeButton && !maximizeButton.disabled) ? 49 : 24) + border, top = top + BUTTON_OFFSET };
+ minimizeButton.size = { 20, 10 };
+ minimizeButton.foreground = skinForeground;
+ minimizeButton.background = skinBackground;
+ minimizeButton.bevel = false;
+ minimizeButton.OnRedraw = Minimize_OnRedraw;
+ minimizeButton.visible = true;
+ }
+ if(maximizeButton && !maximizeButton.disabled)
+ {
+ maximizeButton.anchor = { right = 24 + border, top = top + BUTTON_OFFSET };
+ maximizeButton.size = { 20, 10 };
+ maximizeButton.bevel = false;
+ maximizeButton.foreground = skinForeground;
+ maximizeButton.background = skinBackground;
+ maximizeButton.OnRedraw = Maximize_OnRedraw;
+ maximizeButton.visible = true;
+ }
+ if(closeButton)
+ {
+ closeButton.anchor = { right = -1 + border, top = top + BUTTON_OFFSET };
+ closeButton.size = { 20, 10 };
+ closeButton.bevel = false;
+ closeButton.foreground = skinForeground;
+ closeButton.background = skinBackground;
+ closeButton.OnRedraw = Close_OnRedraw;
+ closeButton.visible = true;
+ }
+ }
+
+ void OnApplyGraphics()
+ {
+ background = skinBackground;
+ foreground = skinForeground;
+ }
+}
+
+static void Button::SmallButton_OnRedraw(Surface surface)
+{
+ surface.SetForeground(parent.active ? TEXT_COLOR : TEXT_INACTIVE);
+ surface.VLine(0, clientSize.h-2, 0);
+ surface.VLine(0, clientSize.h-2, clientSize.w-1);
+ surface.HLine(1,clientSize.w-2, clientSize.h-1);
+}
+
+static void Button::Minimize_OnRedraw(Surface surface)
+{
+ SmallButton_OnRedraw(this, surface);
+ surface.DrawLine( 5, 3, 14, 3);
+ surface.DrawLine( 5, 4, 14, 4);
+}
+
+static void Button::Maximize_OnRedraw(Surface surface)
+{
+ SmallButton_OnRedraw(this, surface);
+ surface.Rectangle( 5, 2, 14, 7);
+ surface.DrawLine( 5, 3, 14, 4);
+}
+
+static void Button::Close_OnRedraw(Surface surface)
+{
+ SmallButton_OnRedraw(this, surface);
+ surface.DrawLine( 7, 2, 12, 7);
+ surface.DrawLine( 8, 2, 13, 7);
+ surface.DrawLine( 12, 2, 7, 7);
+ surface.DrawLine( 13, 2, 8, 7);
+}
+
+class AcovelSkin_StatusBar : StatusBar
+{
+ void OnApplyGraphics()
+ {
+ background = skinBackground;
+ foreground = skinForeground;
+ }
+}
+
+class AcovelSkin_FileDialog : FileDialog
+{
+ void OnApplyGraphics()
+ {
+ Window child;
+ background = skinBackground;
+ foreground = skinForeground;
+ for(child = firstChild; child; child = child.next)
+ {
+ if(!child.opacity)
+ child.foreground = skinForeground;
+ }
+ }
+}
+
+#define PUREVTBL(c) ((int (**)())*(void **)((byte *)class(c).data + 4))
+
+extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnApplyGraphics;
+extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw;
+
+static void Dummy()
+{
+ Window a;
+ a.OnApplyGraphics();
+ a.OnRedraw(null);
+}
+
+class AcovelSkin_Button : Button
+{
+ void OnApplyGraphics()
+ {
+ //background = skinBackground;
+ background = Color { (int)70 * 6/10, (int)130* 6/10, (int)180* 6/10 };
+ foreground = skinForeground;
+ }
+
+ void OnRedraw(Surface surface)
+ {
+ int isDefault = (int)this.isDefault;
+ PUREVTBL(Button)[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw](this, surface);
+ if(bevel || (bevelOver && (buttonState == down || buttonState == over || checked)))
+ {
+ Color c = steelBlue;
+ if(buttonState == down || checked)
+ {
+ surface.SetForeground(selectionColor);
+ surface.HLine(isDefault + 0, clientSize.w-2-isDefault, 0);
+ surface.VLine(isDefault + 1, clientSize.h-2-isDefault, 0);
+ surface.SetForeground(Color { Min((int)c.r * 16/10, 255), Min((int)c.g * 16/10, 255), Min((int)c.b * 16/10,255) });
+ surface.HLine(isDefault + 0, clientSize.w-1-isDefault, clientSize.h-1-isDefault);
+ surface.VLine(isDefault + 0, clientSize.h-2-isDefault, clientSize.w-1-isDefault);
+ }
+ else
+ {
+ surface.SetForeground(Color { Min((int)c.r * 16/10, 255), Min((int)c.g * 16/10, 255), Min((int)c.b * 16/10,255) });
+ surface.HLine(0 + isDefault, clientSize.w-2 - isDefault, isDefault);
+ surface.VLine(1 + isDefault, clientSize.h-2 - isDefault, isDefault);
+
+
+ surface.SetForeground(selectionColor);
+ surface.HLine(1 + isDefault, clientSize.w-2 - isDefault, clientSize.h-2 - isDefault);
+ surface.VLine(1 + isDefault, clientSize.h-3 - isDefault, clientSize.w-2 - isDefault);
+
+ if(bevel)
+ {
+ //surface.SetForeground(skinForeground);
+ surface.SetForeground(Color { c.r * 4/10, c.g * 4/10, c.b * 4/10 });
+ surface.HLine( isDefault, clientSize.w-1 - isDefault, clientSize.h-1 - isDefault);
+ surface.VLine( isDefault, clientSize.h-2 - isDefault, clientSize.w-1 - isDefault);
+ }
+ }
+ }
+ if(isDefault)
+ {
+ surface.SetForeground(skinForeground);
+ surface.Rectangle(0,0,clientSize.w-1,clientSize.h-1);
+ }
+ if(!(bevelOver) && !isRemote)
+ {
+ if(active)
+ {
+ int x1,y1,x2,y2;
+ int offset = (buttonState == down && this.offset) ? 1 : 0;
+ surface.SetForeground(skinForeground);
+ surface.LineStipple(0x5555);
+
+ #define CAPTION_DISTANCE 18
+ if((isRadio || isCheckbox) && text)
+ {
+ x1 = /*clientSize.h + */CAPTION_DISTANCE;
+ y1 = 0;
+ x2 = clientSize.w-4;
+ y2 = clientSize.h-4;
+ }
+ else
+ {
+ x1 = 3+offset;
+ y1 = 3+offset;
+ x2 = clientSize.w - 5+offset;
+ y2 = clientSize.h - 5+offset;
+
+ if(isRadio || isCheckbox)
+ {
+ x1-=3;
+ y1-=3;
+ x2+=1;
+ y2+=1;
+ }
+ }
+ if((x2 - x1) & 1) x2++;
+ if((y2 - y1) & 1) y2++;
+
+ surface.Rectangle(x1, y1, x2, y2);
+ surface.LineStipple(0);
+ }
+ }
+ }
+}
+
+class AcovelSkin_ScrollBar : ScrollBar
+{
+ void OnApplyGraphics()
+ {
+ PUREVTBL(ScrollBar)[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnApplyGraphics](this);
+
+ background = { skinBackground.r * 9 / 6, skinBackground.g * 9 / 6, skinBackground.b * 9 / 6 };
+
+ upBtn.background = Color { 70 * 6/10, 130* 6/10, 180* 6/10 }; //skinBackground;
+ upBtn.bitmap = { "<:ecere>elements/arrow-up.png", monochrome = true };
+ downBtn.background = Color { 70 * 6/10, 130* 6/10, 180* 6/10 }; //skinBackground;
+ downBtn.bitmap = { "<:ecere>elements/arrow-down.png", monochrome = true };
+ thumb.background = Color { 70 * 6/10, 130* 6/10, 180* 6/10 }; //skinBackground;
+ }
+}
+
+class AcovelSkin_DropBox : DropBox
+{
+ void OnApplyGraphics()
+ {
+ PUREVTBL(DropBox)[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnApplyGraphics](this);
+ button.bitmap = { "<:ecere>elements/arrow-down.png", monochrome = true };
+ background = skinBackground;
+ foreground = skinForeground;
+ this.selectionColor = ::selectionColor;
+ }
+}
+
+class AcovelSkin_ListBox : ListBox
+{
+ void OnApplyGraphics()
+ {
+ PUREVTBL(ListBox)[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnApplyGraphics](this);
+ background = skinBackground;
+ foreground = skinForeground;
+ this.selectionColor = ::selectionColor;
+ }
+}
+
+class AcovelSkin : Skin
+{
+ class_property(name) = "Acovel";
+ class_property(selectionColor) = (Color)selectionColor;
+ class_property(disabledBackColor) = (Color)Color{ 0,0,0 };
+ class_property(disabledFrontColor) = (Color)Color{ 128,128,128 };
+
+ FontResource ::SystemFont()
+ {
+ return { faceName = "Tahoma", size = 8.25f };
+ }
+
+ FontResource ::CaptionFont()
+ {
+ return { faceName = "Verdana", size = 6.5f };
+ }
+
+ char * ::CursorsBitmaps(uint id, int *hotSpotX, int *hotSpotY, byte ** paletteShades)
+ {
+ return null;
+ }
+
+ BitmapResource ::GetBitmap(int id)
+ {
+ return null;
+ }
+
+ int ::VerticalSBW()
+ {
+ return 16;
+ }
+
+ int ::HorizontalSBH()
+ {
+ return 16;
+ }
+}
--- /dev/null
+import "ecere"
+
+class SplitWindow : Window
+{
+ bool sliding;
+ int startPos, startX;
+ background = activeBorder, borderStyle = bevel;
+ anchor = { top = -2, bottom = -2 }, stayOnTop = true, inactive = true;
+ size = { w = 6 };
+ cursor = ((GuiApplication)__thisModule).GetCursor(sizeWE);
+
+ Window leftPane, rightPane;
+ double scaleSplit;
+ int split;
+ bool scale;
+
+ property double scaleSplit
+ {
+ set
+ {
+ scaleSplit = value;
+ property::split = (int)(parent.clientSize.w * (value) + 0.5);
+ scale = true;
+ }
+ }
+ property int split
+ {
+ set
+ {
+ int w = size.w;
+ int pw = parent.clientSize.w;
+ int x = value;
+
+ split = value;
+
+ if(leftPane && !rightPane)
+ leftPane.anchor.right = 0;
+ else if(rightPane && !leftPane)
+ rightPane.anchor.left = 0;
+ else
+ {
+ if(leftPane)
+ leftPane.anchor.right = pw - x;
+ if(rightPane)
+ rightPane.anchor.left = x + w / 2;
+ }
+ anchor.left = x;
+
+ scale = false;
+ }
+ }
+
+ void OnResize(int width, int height)
+ {
+ //if(visible)
+ {
+ if(scale)
+ property::scaleSplit = scaleSplit;
+ else
+ property::split = split;
+ }
+ }
+
+ bool OnLeftButtonDown(int x, int y, Modifiers mods)
+ {
+ sliding = true;
+ startPos = x + absPosition.x;
+ startX = position.x;
+
+ Capture();
+
+ return true;
+ }
+
+ bool OnMouseLeave(Modifiers mods)
+ {
+ parent.cursor = null;
+ return true;
+ }
+ bool OnMouseMove(int x, int y, Modifiers mods)
+ {
+ parent.cursor = cursor;
+ if(sliding)
+ {
+ bool oldScale = scale;
+ x += absPosition.x;
+ x -= startPos;
+ x += startX;
+ x = Max(x, 20);
+ x = Min(x, parent.clientSize.w - 20);
+
+ property::split = x;
+ scale = oldScale;
+ }
+ return true;
+ }
+
+ bool OnLeftButtonUp(int x, int y, Modifiers mods)
+ {
+ if(sliding)
+ {
+ ReleaseCapture();
+ parent.cursor = null;
+ sliding = false;
+ }
+ return true;
+ }
+}
+
--- /dev/null
+public import "ecere"
+
+import "ArrayUtilities"
+
+private:
+
+define array = ((BasicArrayImpl)this).a;
+
+class BasicArrayImpl
+{
+ uint _size;
+ Class type;
+ byte * a;
+};
+
+public class BasicArray
+{
+ uint _size;
+
+ ~BasicArray()
+ {
+ delete array;
+ }
+
+public:
+ Class type;
+ property uint size
+ {
+ set
+ {
+ if(value != _size)
+ {
+ if(array)
+ {
+ if(value)
+ array = renew array byte[value * sizeoftype];
+ else
+ delete array;
+ }
+ else if(value)
+ array = new byte[value * sizeoftype];
+ _size = value;
+ }
+ }
+ get { return _size; }
+ }
+ property void * data
+ {
+ set
+ {
+ memcpy(array, value, _size * sizeoftype);
+ }
+ }
+ void Append(int n)
+ {
+ size += n;
+ }
+ void Insert(uint position, int n)
+ {
+ Append(n);
+ if(position < _size - 1)
+ MoveBytes(array + (position + n) * sizeoftype, array + position * sizeoftype, (_size - position - n) * sizeoftype);
+ }
+ void Trim(int n)
+ {
+ size -= n;
+ }
+ void Remove(uint position, int n)
+ {
+ if(position + n - 1 < _size - 1)
+ MoveBytes(array + position * sizeoftype, array + (position + n) * sizeoftype, (_size - position - n) * sizeoftype);
+ Trim(n);
+ }
+};
+
+public class IntBasicArray : BasicArray
+{
+ type = class(int);
+public:
+ int * const _;
+ uint * Add(int item)
+ {
+ uint pos = _size;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ uint * AddBefore(uint position, int item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}
+
+public class UintBasicArray : BasicArray
+{
+ type = class(uint);
+public:
+ uint * const _;
+ uint * Add(uint item)
+ {
+ uint pos = _size;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ uint * AddBefore(uint position, uint item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}
+
+public class StringBasicArray : BasicArray
+{
+ type = class(String);
+public:
+ String * const _;
+ String * Add(String item)
+ {
+ uint pos = _size;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ String * AddBefore(uint position, String item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}
--- /dev/null
+public import "ecere"
+
+import "ArrayFactoredGrowth"
+
+private:
+
+public import "ecere"
+
+import "ArrayUtilities"
+
+private:
+
+public struct BIloc
+{
+ bool valid;
+ uint offset;
+ uint pos;
+
+ String ToString()
+ {
+ String result = new char[30 + 6 + 11 + 11];
+ sprintf(result, "BIloc { valid=%d, offset=%u, pos=%u }\n", valid, offset, pos);
+ return result;
+ }
+};
+
+public class BinaryIndex : Array
+{
+ type = class(uint);
+ BinaryIndex()
+ {
+ threshold = 8;
+ }
+public:
+ uint * const _;
+ uint threshold;
+ void * client;
+
+ int (*Compare)(void * client, uint offset, typed_object data);
+
+ BIloc Find(typed_object data)
+ {
+ BIloc result { };
+ if(_count && data._class)
+ {
+ uint lo = 0, hi = _count - 1;
+ for( ; hi - lo >= threshold; )
+ {
+ uint tri = (hi - lo) / 3;
+ uint i = lo + tri;
+ if(Compare(client, _[i], data) > 0)
+ hi = i;
+ else
+ {
+ i = hi - tri;
+ if(Compare(client, _[i], data) < 0)
+ lo = i;
+ else
+ lo += tri, hi -= tri;
+ }
+ }
+ if(Compare(client, _[lo], data) <= 0)
+ {
+ if(Compare(client, _[hi], data) >= 0)
+ {
+ uint i;
+ for(i = lo + 1; Compare(client, _[i], data) <= 0; i++);
+ result.pos = i;
+ if(Compare(client, _[i], data) == 0)
+ result.valid = true, result.offset = _[i];
+ }
+ else
+ {
+ if(Compare(client, _[hi], data) <= 0)
+ result.pos = hi + 1;
+ else
+ result.valid = true, result.pos = hi, result.offset = _[hi];
+ }
+ }
+ else
+ {
+ result.pos = lo;
+ if(Compare(client, _[lo], data) == 0)
+ result.valid = true, result.offset = _[lo];
+ }
+ }
+ return result;
+ }
+
+ //void OnSerialize(IOChannel channel)
+ //void OnUnserialize(IOChannel channel)
+}
+
+public class StringBIArray : Array
+{
+ // can simply implement multiple compare modes and allow nice switching using enum for method names
+ type = class(String);
+public:
+ String * const _;
+ private BinaryIndex index { client = this, Compare = (void *)Compare };
+ int Compare(uint offset, typed_object data)
+ {
+ return strcmp(_[offset], (String)data);
+ }
+ BIloc Add(String item)
+ {
+ BIloc result = index.Find(item);
+ if(!result.valid)
+ {
+ result.offset = _count;
+ Append(1);
+ _[result.offset] = item;
+ index.Insert(result.pos, 1);
+ }
+ return result;
+ }
+ BIloc Remove(String item)
+ {
+
+ }
+}
+
--- /dev/null
+public import "ecere"
+
+import "ArrayUtilities"
+
+private:
+
+define array = ((BinarySortedArrayImpl)this).a;
+
+public struct BSloc
+{
+ bool valid;
+ uint pos;
+ //void * item;
+
+ String ToString()
+ {
+ String result = new char[30 + 6 + 11];
+ sprintf(result, "BSloc { valid=%d, pos=%u }\n", valid, pos);
+ return result;
+ }
+};
+
+class BinarySortedArrayImpl
+{
+ uint _size;
+ uint _count;
+ uint _factor;
+ uint _threshold;
+ Class type;
+ void ** a;
+};
+
+// do another class that uses a compare method or modify to use the compare method if it was provided
+public class ArrayBinarySorted
+{
+ uint _size;
+ uint _count;
+ uint _factor;
+ uint _threshold;
+
+ ~ArrayBinarySorted()
+ {
+ delete array;
+ }
+
+public:
+ Class type;
+ property uint count
+ {
+ set
+ {
+ if(value != _count)
+ {
+ int newsize = (value / _factor + 1) * _factor;
+ if(newsize != _size)
+ size = value ? newsize : 0;
+ _count = value;
+ }
+ }
+ get { return _count; }
+ }
+ property uint size
+ {
+ set
+ {
+ if(value != _size)
+ {
+ if(array)
+ {
+ if(value)
+ array = renew array void * [value * sizeof(void *)];
+ else
+ delete array;
+ }
+ else if(value)
+ array = new void * [value * sizeof(void *)];
+ _size = value;
+ }
+ }
+ get { return _size; }
+ }
+ property uint growingFactor { set { _factor = value; } get { return _factor; } }
+ property void * data
+ {
+ set
+ {
+ memcpy(array, value, _size * sizeoftype);
+ }
+ }
+ void Append(int n)
+ {
+ count += n;
+ }
+ void Insert(uint position, int n)
+ {
+ Append(n);
+ if(position < _count - 1)
+ MoveBytes(array + (position + n) * sizeoftype, array + position * sizeoftype, (_count - position - n) * sizeoftype);
+ }
+ void Trim(int n)
+ {
+ count -= n;
+ }
+ void Remove(uint position, int n)
+ {
+ if(position + n - 1 < _count - 1)
+ MoveBytes(array + position * sizeoftype, array + (position + n) * sizeoftype, (_count - position - n) * sizeoftype);
+ Trim(n);
+ }
+ BSloc Find(void * item)
+ {
+ BSloc result { };
+ if(_count && item)
+ {
+ uint lo = 0, hi = _count - 1;
+ for( ; hi - lo >= _threshold; )
+ {
+ uint tri = (hi - lo) / 3;
+ uint i = lo + tri;
+ //if(Compare(client, _[i], item) > 0)
+ if(array[i] > item)
+ hi = i;
+ else
+ {
+ i = hi - tri;
+ if(array[i] < item)
+ lo = i;
+ else
+ lo += tri, hi -= tri;
+ }
+ }
+ if(array[lo] <= item)
+ {
+ if(array[hi] >= item)
+ {
+ uint i;
+ for(i = lo + 1; array[i] <= item; i++);
+ //result.oldpos = i;
+ if(array[i] == item)
+ result.valid = true, result.pos = i;
+ }
+ else
+ {
+ if(array[hi] <= item)
+ ;//result.oldpos = hi + 1;
+ else
+ result.valid = true/*, result.oldpos = hi*/, result.pos = hi;
+ }
+ }
+ else
+ {
+ //result.oldpos = lo;
+ if(array[lo] == item)
+ result.valid = true, result.pos = lo;
+ }
+ }
+ return result;
+ }
+
+};
+
+public class StringBSArray : ArrayBinarySorted
+{
+ type = class(String);
+public:
+ String * const _;
+ BSloc Add(String item)
+ {
+ BSloc result = Find(item);
+ if(!result.valid)
+ {
+ Insert(result.pos, 1);
+ _[result.pos] = item;
+ }
+ return result;
+ }
+ BSloc Remove(String item)
+ {
+
+ }
+}
+
--- /dev/null
+public import "ecere"
+
+import "ArrayUtilities"
+
+private:
+
+define array = ((ArrayImpl)this).a;
+
+class ArrayImpl
+{
+ uint _size;
+ uint _count;
+ uint _factor;
+ Class type;
+ byte * a;
+};
+
+public class RedjArray
+{
+ uint _size;
+ uint _count;
+ uint _factor;
+
+ ~RedjArray()
+ {
+ delete array;
+ }
+
+ //virtual void FreeItem(void *);
+
+public:
+ Class type;
+ property uint count
+ {
+ set
+ {
+ if(value != _count)
+ {
+ int newsize = (value / _factor + 1) * _factor;
+ if(newsize != _size)
+ size = value ? newsize : 0;
+ _count = value;
+ }
+ }
+ get { return _count; }
+ }
+ property uint size
+ {
+ set
+ {
+ if(value != _size)
+ {
+ if(array)
+ {
+ if(value)
+ array = renew array byte[value * sizeoftype];
+ else
+ delete array;
+ }
+ else if(value)
+ array = new byte[value * sizeoftype];
+ _size = value;
+ }
+ }
+ get { return _size; }
+ }
+ property uint growingFactor { set { _factor = value; } get { return _factor; } }
+ property void * data
+ {
+ set
+ {
+ memcpy(array, value, _size * sizeoftype);
+ }
+ }
+ void Append(int n)
+ {
+ count += n;
+ }
+ void Insert(uint position, int n)
+ {
+ Append(n);
+ if(position < _count - 1)
+ MoveBytes(array + (position + n) * sizeoftype, array + position * sizeoftype, (_count - position - n) * sizeoftype);
+ }
+ void Trim(int n)
+ {
+ count -= n;
+ }
+ void Remove(uint position, int n)
+ {
+ if(position + n - 1 < _count - 1)
+ MoveBytes(array + position * sizeoftype, array + (position + n) * sizeoftype, (_count - position - n) * sizeoftype);
+ Trim(n);
+ }
+};
+
+public class IntArray : RedjArray
+{
+ type = class(int);
+public:
+ int * const _;
+ uint * Add(int item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ uint * AddBefore(uint position, int item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}
+
+public class UintArray : RedjArray
+{
+ type = class(uint);
+public:
+ uint * const _;
+ uint * Add(uint item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ uint * AddBefore(uint position, uint item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}
+
+public class StringArray : RedjArray
+{
+ type = class(String);
+public:
+ String * const _;
+ String * Add(String item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ String * AddBefore(uint position, String item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+ void Clear()
+ {
+ int c;
+ for(c = 0; c < _count; c++)
+ delete _[c];
+ }
+}
--- /dev/null
+//#define ARRAY ((IncrementArrayImpl)this).array
+//
+//public import "ecere"
+//
+//default:
+//extern int __ecereVMethodID_class_OnFree;
+//
+//private:
+//
+//class IncrementArrayImpl
+//{
+// uint count;
+// uint size;
+// uint increment;
+// uint divider;
+// Class type;
+// byte * array;
+//};
+//
+//default:
+//extern int __ecereVMethodID_class_OnFree;
+//
+// ~Array()
+// {
+// // what's up with that?
+// //int c;
+// //void ** array = (void **)((ArrayImpl)this).array;
+// //if(type.type == normalClass || type.type == noHeadClass)
+// {
+// //for(c = 0; c<size; c++)
+// //type._vTbl[__ecereVMethodID_class_OnFree](type, array[c]);
+// }
+// // TODO: Call OnFree for structClass
+// delete ARRAY;
+// }
+//
+// // the following after the renew in Array's size property
+// if(value > size)
+// memset(array + size * GetTypeSize(), 0, (value - size) * GetTypeSize());
+//
+// // the following after the MoveBytes in Array's Remove function
+// FillBytes(incarray + count, 0, GetTypeSize()); // why set to 0 and is it even correct code
+//
+
+/*
+class DerivedArray : Array
+{
+ uint dummy;
+
+}
+class IntDerivedArray : DerivedArray
+{
+ type = class(int);
+ offset = offsetof(_);
+public:
+ int * const _;
+}
+*/
+
+/*
+#define ARRAY ((IndexedIncrementArrayImpl)this).array
+
+public import "ecere"
+
+default:
+extern int __ecereVMethodID_class_OnFree;
+
+private:
+
+public class IndexedIncrementArray : public IncrementArray
+{
+ UintIncrementArray index { };
+
+public:
+ property uint count
+ {
+ set
+ {
+ if(value != _count)
+ {
+ if((value / _increment + 1) * _increment != _size)
+ size = value ? (value / _increment + 1) * _increment : 0;
+ index.count = _count;
+ _count = value;
+ }
+ }
+ get { return _count; }
+ }
+ property uint size
+ {
+ set
+ {
+ if(value != _size)
+ {
+ if(ARRAY)
+ {
+ ARRAY = renew ARRAY byte[value * GetTypeSize()];
+ if(value > _size)
+ // this is initializing to 0, right?, do I want that?
+ // why memset instead of FillBytes?
+ memset(ARRAY + _size * GetTypeSize(), 0, (value - _size) * GetTypeSize());
+ }
+ else if(value)
+ ARRAY = new byte[value * GetTypeSize()];
+ index.size = _size;
+ _size = value;
+ }
+ }
+ get { return _size; }
+ }
+ property uint increment { set { _increment = value; } get { return _increment; } }
+ property void * data
+ {
+ set
+ {
+ memcpy(ARRAY, value, _size * GetTypeSize());
+ }
+ }
+ void Append(int n)
+ {
+ count += n;
+ }
+ void Insert(uint position, int n)
+ {
+ Append(n);
+ if(position < _count - 1)
+ MoveBytes(ARRAY + position + n, ARRAY + position, (_count - position - n) * GetTypeSize());
+ }
+ void Trim(int n)
+ {
+ count -= n;
+ }
+ void Remove(uint position, int n)
+ {
+ if(position + n - 1 < _count - 1)
+ MoveBytes(ARRAY + position, ARRAY + position + n, (_count - position - n) * GetTypeSize());
+ //FillBytes(ARRAY + _count, 0, GetTypeSize()); // why set to 0 and is it even correct code
+ Trim(n);
+ }
+};
+
+class IntIndexedIncrementArray : IndexedIncrementArray
+{
+ type = class(int);
+public:
+ int * const _;
+}
+
+class UintIndexedIncrementArray : IndexedIncrementArray
+{
+ type = class(uint);
+public:
+ uint * const _;
+
+ uint * Add(int item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ uint * AddBefore(uint position, int item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}
+
+class StringIndexedIncrementArray : IndexedIncrementArray
+{
+ type = class(String);
+public:
+ String * const _;
+
+ String * Add(String item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ String * AddBefore(uint position, String item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+
+}
+*/
+
+/*
+class UIntBIArray : IncArray
+{
+ type = class(uint);
+public:
+ uint * const _;
+ uint * Add(uint item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ uint * AddBefore(uint position, uint item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}
+*/
+
+/*
+class UintSortArray : IncArray
+{
+ type = class(uint);
+public:
+ uint * const _;
+ uint * Add(uint item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ return &_[pos];
+ }
+ uint * AddBefore(uint position, uint item)
+ {
+ Insert(position, 1);
+ _[position] = item;
+ return &_[position];
+ }
+}
+
+public class SortArray : IncArray
+{
+ UintIncArray index;
+
+
+}
+
+define array = ((SortArrayImpl)this).a;
+
+class SortArrayImpl
+{
+ uint _size;
+ uint _count;
+ uint _increment;
+ Class type;
+ byte * a;
+};
+
+public class SortArray
+{
+ uint _size;
+ uint _count;
+ uint _increment;
+
+ ~SortArray()
+ {
+ delete array;
+ }
+
+public:
+ Class type;
+ property uint count
+ {
+ set
+ {
+ if(value != _count)
+ {
+ int newsize = (value / _increment + 1) * _increment;
+ if(newsize != _size)
+ size = value ? newsize : 0;
+ _count = value;
+ }
+ }
+ get { return _count; }
+ }
+ property uint size
+ {
+ set
+ {
+ if(value != _size)
+ {
+ if(array)
+ {
+ if(value)
+ array = renew array byte[value * sizeoftype];
+ else
+ delete array;
+ }
+ else if(value)
+ array = new byte[value * sizeoftype];
+ _size = value;
+ }
+ }
+ get { return _size; }
+ }
+ property uint increment { set { _increment = value; } get { return _increment; } }
+ property void * data
+ {
+ set
+ {
+ memcpy(array, value, _size * sizeoftype);
+ }
+ }
+ void Append(int n)
+ {
+ count += n;
+ }
+ void Insert(uint position, int n)
+ {
+ Append(n);
+ if(position < _count - 1)
+ MoveBytes(array + (position + n) * sizeoftype, array + position * sizeoftype, (_count - position - n) * sizeoftype);
+ }
+ void Trim(int n)
+ {
+ count -= n;
+ }
+ void Remove(uint position, int n)
+ {
+ if(position + n - 1 < _count - 1)
+ MoveBytes(array + position * sizeoftype, array + (position + n) * sizeoftype, (_count - position - n) * sizeoftype);
+ Trim(n);
+ }
+};
+*/
+
+ /*int CompareInt(uint a, uint b)
+ {
+ return (a > b) ? 1 : ((a < b) ? - 1 : 0);
+ }*/
+
+ /*int CompareString(char * a, char * b)
+ {
+ return (a && b) ? Compare(a, b) : -1;
+ }*/
+
+ //void ::FreeString(char * string)
+
--- /dev/null
+public import "ecere"
+
--- /dev/null
+public import "ecere"
+
+private:
+
+// would be nice not to have to do this
+define sizeoftype = GetTypeSize(type);
+int GetTypeSize(Class type)
+{
+ return type.typeSize;
+}
--- /dev/null
+public import "ecere"
+
+import "ArrayFactoredGrowth"
+
+private:
+
+public class Stack : Array
+{
+}
+
+public class IntStack : Stack
+{
+ type = class(int);
+public:
+ int * const _;
+ void Push(int item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ }
+ int Pop()
+ {
+ int item = _[_count - 1];
+ Trim(1);
+ return item;
+ }
+}
+
+class UintStack : Stack
+{
+ type = class(uint);
+public:
+ uint * const _;
+ void Push(uint item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ }
+ uint Pop()
+ {
+ uint item = _[_count - 1];
+ Trim(1);
+ return item;
+ }
+}
+
+class StringStack : Stack
+{
+ type = class(String);
+public:
+ String * const _;
+ void Push(String item)
+ {
+ uint pos = _count;
+ Append(1);
+ _[pos] = item;
+ }
+ String Pop()
+ {
+ String item = _[_count - 1];
+ Trim(1);
+ return item;
+ }
+}
--- /dev/null
+public import "ecere"
+
+public class TimerTemp
+{
+ bool active;
+
+ Time count;
+ Time from;
+
+ void Start()
+ {
+ if(!active)
+ {
+ active = true;
+ from = GetTime();
+ }
+ }
+
+ void Stop()
+ {
+ if(active)
+ {
+ active = false;
+ count += GetTime() - from;
+ }
+ }
+
+ void Reset()
+ {
+ count = 0;
+ if(active)
+ from = GetTime();
+ }
+}
+
+/*
+public class Delay : Seconds
+{
+
+private:
+
+ Time from;
+
+public:
+
+ property bool elapsed
+ {
+ get
+ {
+ Time now = GetTime();
+ if(!from || now - from > (Time)this)
+ {
+ from = now;
+ return true;
+ }
+ return false;
+ }
+ }
+}
+*/
+
+public class TimeGate
+{
+
+private:
+
+ Time from;
+
+public:
+
+ Time delay;
+
+ /*
+ property bool
+ {
+ get
+ {
+ if(!from || GetTime() - from > delay)
+ {
+ from = GetTime();
+ return true;
+ }
+ return false;
+ }
+ }
+ */
+
+ property bool elapsed
+ {
+ get
+ {
+ Time now = GetTime();
+ if(!from || now - from > delay)
+ {
+ from = now;
+ return true;
+ }
+ return false;
+ }
+ }
+}
+
--- /dev/null
+ÿþW
+
+
+
+
+
+