From ddec1cfe7674fc97b59db1fae712107c596e6444 Mon Sep 17 00:00:00 2001 From: Jerome St-Louis Date: Tue, 17 May 2011 00:44:03 -0400 Subject: [PATCH] Initial Git commit --- explorer/Explorer.epj | 80 ++ explorer/res/browse.png | Bin 0 -> 593 bytes explorer/res/panel-tree.png | Bin 0 -> 261 bytes explorer/res/view-cards.png | Bin 0 -> 293 bytes explorer/res/view-details.png | Bin 0 -> 279 bytes explorer/res/view-icons.png | Bin 0 -> 372 bytes explorer/res/view-list.png | Bin 0 -> 239 bytes explorer/res/view-showcase-right.png | Bin 0 -> 537 bytes explorer/src/DeleteBox.ec | 139 +++ explorer/src/Explorer.ec | 624 ++++++++++ explorer/src/ExplorerTree.ec | 1527 ++++++++++++++++++++++++ explorer/src/ExplorerWindow.ec | 58 + explorer/src/FileListItem.ec | 108 ++ explorer/src/FileTreeBranch.ec | 365 ++++++ explorer/src/Finder.ec | 300 +++++ explorer/src/NotificationBox.ec | 178 +++ explorer/src/Panels.ec | 386 ++++++ explorer/src/Search.ec | 347 ++++++ explorer/src/Skin.ec | 657 ++++++++++ explorer/src/SplitWindow.ec | 109 ++ explorer/src/Structures/ArrayBasic.ec | 134 +++ explorer/src/Structures/ArrayBinaryIndexed.ec | 122 ++ explorer/src/Structures/ArrayBinarySorted.ec | 182 +++ explorer/src/Structures/ArrayFactoredGrowth.ec | 161 +++ explorer/src/Structures/ArrayNotes.ec | 343 ++++++ explorer/src/Structures/ArrayTypes.ec | 2 + explorer/src/Structures/ArrayUtilities.ec | 10 + explorer/src/Structures/Stack.ec | 66 + explorer/src/Structures/Temp.ec | 102 ++ explorer/tools/FinderMenuCommand.reg | 7 + 30 files changed, 6007 insertions(+) create mode 100644 explorer/Explorer.epj create mode 100644 explorer/res/browse.png create mode 100644 explorer/res/panel-tree.png create mode 100644 explorer/res/view-cards.png create mode 100644 explorer/res/view-details.png create mode 100644 explorer/res/view-icons.png create mode 100644 explorer/res/view-list.png create mode 100644 explorer/res/view-showcase-right.png create mode 100644 explorer/src/DeleteBox.ec create mode 100644 explorer/src/Explorer.ec create mode 100644 explorer/src/ExplorerTree.ec create mode 100644 explorer/src/ExplorerWindow.ec create mode 100644 explorer/src/FileListItem.ec create mode 100644 explorer/src/FileTreeBranch.ec create mode 100644 explorer/src/Finder.ec create mode 100644 explorer/src/NotificationBox.ec create mode 100644 explorer/src/Panels.ec create mode 100644 explorer/src/Search.ec create mode 100644 explorer/src/Skin.ec create mode 100644 explorer/src/SplitWindow.ec create mode 100644 explorer/src/Structures/ArrayBasic.ec create mode 100644 explorer/src/Structures/ArrayBinaryIndexed.ec create mode 100644 explorer/src/Structures/ArrayBinarySorted.ec create mode 100644 explorer/src/Structures/ArrayFactoredGrowth.ec create mode 100644 explorer/src/Structures/ArrayNotes.ec create mode 100644 explorer/src/Structures/ArrayTypes.ec create mode 100644 explorer/src/Structures/ArrayUtilities.ec create mode 100644 explorer/src/Structures/Stack.ec create mode 100644 explorer/src/Structures/Temp.ec create mode 100644 explorer/tools/FinderMenuCommand.reg diff --git a/explorer/Explorer.epj b/explorer/Explorer.epj new file mode 100644 index 0000000..df6b66d --- /dev/null +++ b/explorer/Explorer.epj @@ -0,0 +1,80 @@ +{ + "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 diff --git a/explorer/res/browse.png b/explorer/res/browse.png new file mode 100644 index 0000000000000000000000000000000000000000..f22798915f02ecb32493106d5405febe0e8365f9 GIT binary patch literal 593 zcmV-X0Px#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vGh)&Kwv)&Y=jd7JN2bPDNB8b~7$9Fmkdbk^le!gGod|R5(v#3=I!9l#q}x zVn74Ge*FTA{QCLp==^yLZ=lP=`MLSo$>+|U!-|g`JDQxFnwSiaFE2M+8{o;H0d zP7E{vWC$|0KykszlP8mxEn7wqFJHbqdButqV1wWWq-UlkgIthUH7nU9bqPt>Eq6`` z1IPf73qYEW-FTh6@6rpRFi0&(57+>Z3qYK8#~&y6Y`j4f2B`%b5T6(ec7atf%YPUK z8A6B;HvkkMAQyl%9K632YzWK%e0&rGsNw=r!k}~Awd7@o9zenXKm^fU>#rww02Q~czM9;y;&O7;l1s_O3(hC!%{`YqW9J=&0iZC5D4U%;d-vVs zf_dkX3+6%;<;^*loD0M`v(F`G&pw-+HS1h*=FGFn89+Q`+iipaD_5^f?gZKfQj|Rl zr0^_6;f%A%X*13wrvmBJ>1UEtrkzPno_Z#E)~!lvI6;>1s;*b zK=o%pn6Zg}(Jr7Mdx@v7EBiG@ZaxOxwUfJIfI<=_t`Q}{`DrEPiAAXl0g0J;C3=3Y zAqr*2dWHr?n^Y$O)f9NTIEGmGZ=HOR4``|D&;R{=7q4CNP0RTxU}+uLx#G(~VF}X{ zUng&7>X|4X9pI7lwphGk#{00TGar>KR^51&HGI8P_Toa$mLt19zW68LaxGqF$6XI= zhr2rqC#e5;dcZDN&CA*$|Ix976BYiLobYDu%)8;XDK<6$Xg7nWtDnm{r-UW|v!lvI6;>1s;*b zK=r3VnDK%)%Tb^pdx@v7EBiG@ZaxOxwUfJIfI<=_t`Q}{`DrEPiAAXl0g0J;C3=3Y zAqr*2dWHr?n^Y$O)lBeoaSXBWPyX}&zdf_a0Z9W!CKKfdxfBM0W|PS+j#US4CCpmL zRPgHl{{R2)*Z%$g|K98W|Ige0`CtG3>;M1P=l=d*|8C;{|JCJ=IxMeU%^M~hyVd*u z|8u?LNemmM9zXm0pZ}1A-hrnfGkOhrZ}2Rz5O`?VC^v!SM?$T^*$E1&ybB~8f}|Q) jA7ofLs61`-WoKaP+yDN^n-9%Ew=sCS`njxgN@xNArV4SK literal 0 HcmV?d00001 diff --git a/explorer/res/view-details.png b/explorer/res/view-details.png new file mode 100644 index 0000000000000000000000000000000000000000..0a52090f0b615ac89fcd8cc382c9dc5e5bcc7a75 GIT binary patch literal 279 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b zK=o%qm@&Y^Ar2_WUgGKN%6^TJn~yAywdF`1h%74J(*-FMJ@&CaHBQ z)YxLttsDD|Uid0zO)xb2>#(p!^3jwko|v~eQ~$1Cd@!zDp?z}Tukhzukq6{^f|phc TSvxZVUBlq%>gTe~DWM4fsk&iA literal 0 HcmV?d00001 diff --git a/explorer/res/view-icons.png b/explorer/res/view-icons.png new file mode 100644 index 0000000000000000000000000000000000000000..334c5189ce21ecda21452d36cc0ad61fc2ee9f20 GIT binary patch literal 372 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b zK=r3VnDK%)%Tb^pdx@v7EBiG@ZaxOxwUfJIfI<=_t`Q}{`DrEPiAAXl0g0J;C3=3Y zAqr*2dWHr?n^Y$O)!g@VaSXBWUm9e{#bhY(#V+eTdrgD<2gatkHzMNFm2YsGm0iEd zQP$M^^o7dJy}s|haY#gX7)`!;_MHhsTINf&xzdbkg&p(j{5;4$~#UlIISwSpD#Q-by!>)zLD2lOg~ Mr>mdKI;Vst0Om!GS^xk5 literal 0 HcmV?d00001 diff --git a/explorer/res/view-list.png b/explorer/res/view-list.png new file mode 100644 index 0000000000000000000000000000000000000000..43dddab2478a0bfbb664173b7b7828faf0244b3c GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b zK=o%pn6Zg}(Jr7Mdx@v7EBiG@ZaxOxwUfJIfI<=_t`Q}{`DrEPiAAXl0g0J;C3=3Y zAqr*2dWHr?n^Y$O)kJx^IEGmGC;$2X-=5i(A%#JR&1fT2im679$XSQ!4Re|s7rG^x zvcw8Z=XQ9+!h0ag`i$$27{_Yy2cPXN*xG$`Cd}vS;A0LbIyRl7&CTk7WWbI&{kpOf bayS@D^Y+KBs1Mr;w1vUb)z4*}Q$iB}x93Kj literal 0 HcmV?d00001 diff --git a/explorer/res/view-showcase-right.png b/explorer/res/view-showcase-right.png new file mode 100644 index 0000000000000000000000000000000000000000..721e70555128696769bfeef17574d06be9e30a6d GIT binary patch literal 537 zcmV+!0_OdRP)q}KZ6a{eoNApY6 zhmfEs2qQ6qA}R_Zj6_K*#a^1Jsfmx&)D$)CVVa5dFfGfX#G-!9QSbG1xYB80pP4hW z*V=3E*^`gFFxEetBY$&_@5PQ2et{rz%v$uH+>4)Q)>*dN4(M$E<_6o8o72n}_6KC4E5P;=9Tpi%%FpZD5sX_b( zPPcNtgR%!)>F4?o4P&%Eq5DOO8eHn8@*%YWSU*Zj0Cr8%Kf~x;id(1&dDe~4JVD2E z`d%^;fKT5tvy?(X(>U$V=$&SGmWek^FEYQ(($^F<=$YbC0FJ+A>OFHGS^UDvDr-Me zC>Wb(a)H?oEUfV98>>III_969_$uW2?la2)_ +#else +#include +#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); diff --git a/explorer/src/ExplorerTree.ec b/explorer/src/ExplorerTree.ec new file mode 100644 index 0000000..d3993bb --- /dev/null +++ b/explorer/src/ExplorerTree.ec @@ -0,0 +1,1527 @@ +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(); +} + diff --git a/explorer/src/ExplorerWindow.ec b/explorer/src/ExplorerWindow.ec new file mode 100644 index 0000000..5a5b37f --- /dev/null +++ b/explorer/src/ExplorerWindow.ec @@ -0,0 +1,58 @@ +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]); + } + } +} + diff --git a/explorer/src/FileListItem.ec b/explorer/src/FileListItem.ec new file mode 100644 index 0000000..7a354c2 --- /dev/null +++ b/explorer/src/FileListItem.ec @@ -0,0 +1,108 @@ +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; +} + diff --git a/explorer/src/FileTreeBranch.ec b/explorer/src/FileTreeBranch.ec new file mode 100644 index 0000000..3c2ef27 --- /dev/null +++ b/explorer/src/FileTreeBranch.ec @@ -0,0 +1,365 @@ +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(); +} diff --git a/explorer/src/Finder.ec b/explorer/src/Finder.ec new file mode 100644 index 0000000..c65367f --- /dev/null +++ b/explorer/src/Finder.ec @@ -0,0 +1,300 @@ +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); + } + +} + diff --git a/explorer/src/NotificationBox.ec b/explorer/src/NotificationBox.ec new file mode 100644 index 0000000..47d3339 --- /dev/null +++ b/explorer/src/NotificationBox.ec @@ -0,0 +1,178 @@ +/* +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; + } +} + +*/ diff --git a/explorer/src/Panels.ec b/explorer/src/Panels.ec new file mode 100644 index 0000000..9e5df0e --- /dev/null +++ b/explorer/src/Panels.ec @@ -0,0 +1,386 @@ +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; + } + }; +} + diff --git a/explorer/src/Search.ec b/explorer/src/Search.ec new file mode 100644 index 0000000..df805b0 --- /dev/null +++ b/explorer/src/Search.ec @@ -0,0 +1,347 @@ +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; + } +} + + diff --git a/explorer/src/Skin.ec b/explorer/src/Skin.ec new file mode 100644 index 0000000..fe5ba20 --- /dev/null +++ b/explorer/src/Skin.ec @@ -0,0 +1,657 @@ +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; + } +} diff --git a/explorer/src/SplitWindow.ec b/explorer/src/SplitWindow.ec new file mode 100644 index 0000000..b625e03 --- /dev/null +++ b/explorer/src/SplitWindow.ec @@ -0,0 +1,109 @@ +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; + } +} + diff --git a/explorer/src/Structures/ArrayBasic.ec b/explorer/src/Structures/ArrayBasic.ec new file mode 100644 index 0000000..1ea0cff --- /dev/null +++ b/explorer/src/Structures/ArrayBasic.ec @@ -0,0 +1,134 @@ +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]; + } +} diff --git a/explorer/src/Structures/ArrayBinaryIndexed.ec b/explorer/src/Structures/ArrayBinaryIndexed.ec new file mode 100644 index 0000000..443b9ce --- /dev/null +++ b/explorer/src/Structures/ArrayBinaryIndexed.ec @@ -0,0 +1,122 @@ +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) + { + + } +} + diff --git a/explorer/src/Structures/ArrayBinarySorted.ec b/explorer/src/Structures/ArrayBinarySorted.ec new file mode 100644 index 0000000..38c325e --- /dev/null +++ b/explorer/src/Structures/ArrayBinarySorted.ec @@ -0,0 +1,182 @@ +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) + { + + } +} + diff --git a/explorer/src/Structures/ArrayFactoredGrowth.ec b/explorer/src/Structures/ArrayFactoredGrowth.ec new file mode 100644 index 0000000..2386ded --- /dev/null +++ b/explorer/src/Structures/ArrayFactoredGrowth.ec @@ -0,0 +1,161 @@ +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]; + } +} diff --git a/explorer/src/Structures/ArrayNotes.ec b/explorer/src/Structures/ArrayNotes.ec new file mode 100644 index 0000000..ad727c1 --- /dev/null +++ b/explorer/src/Structures/ArrayNotes.ec @@ -0,0 +1,343 @@ +//#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) +// 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) + diff --git a/explorer/src/Structures/ArrayTypes.ec b/explorer/src/Structures/ArrayTypes.ec new file mode 100644 index 0000000..12be979 --- /dev/null +++ b/explorer/src/Structures/ArrayTypes.ec @@ -0,0 +1,2 @@ +public import "ecere" + diff --git a/explorer/src/Structures/ArrayUtilities.ec b/explorer/src/Structures/ArrayUtilities.ec new file mode 100644 index 0000000..bb305a4 --- /dev/null +++ b/explorer/src/Structures/ArrayUtilities.ec @@ -0,0 +1,10 @@ +public import "ecere" + +private: + +// would be nice not to have to do this +define sizeoftype = GetTypeSize(type); +int GetTypeSize(Class type) +{ + return type.typeSize; +} diff --git a/explorer/src/Structures/Stack.ec b/explorer/src/Structures/Stack.ec new file mode 100644 index 0000000..779ac36 --- /dev/null +++ b/explorer/src/Structures/Stack.ec @@ -0,0 +1,66 @@ +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; + } +} diff --git a/explorer/src/Structures/Temp.ec b/explorer/src/Structures/Temp.ec new file mode 100644 index 0000000..c9b600f --- /dev/null +++ b/explorer/src/Structures/Temp.ec @@ -0,0 +1,102 @@ +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; + } + } +} + diff --git a/explorer/tools/FinderMenuCommand.reg b/explorer/tools/FinderMenuCommand.reg new file mode 100644 index 0000000..0d73995 --- /dev/null +++ b/explorer/tools/FinderMenuCommand.reg @@ -0,0 +1,7 @@ +ÿþW + + + + + + -- 1.8.3.1