old explorer: native decorations
[ede] / explorer / src / Explorer.ec
1 public import "ecere"
2 import "SplitWindow"
3
4 import "ExplorerTree" // meant to be called ExplorerTools
5 import "Finder"
6 import "Search"       // meant to be called ExplorerSearch
7 import "Panels"
8
9 /*
10 #ifdef __WIN32__
11 #include <direct.h>
12 #else
13 #include <unistd.h>
14 #endif
15 */
16
17 enum ExplorerToolId
18 {
19    none,
20    newWindow, goBack, goForward, goUp, goHome,
21    browse,
22    panelTree, panelSearch,
23    addressBar,
24    refreshView,
25    viewList, viewDetails, viewIcons, viewCards, viewShowcase, viewCustom,
26    previewPictures
27 };
28
29 static char * toolIconNames[] = 
30 {
31    "<:ecere>emblems/unreadable.png",     /* none */
32
33    "<:ecere>actions/windowNew.png",            /* newWindow */
34    "<:ecere>actions/goPrevious.png",           /* goBack */
35    "<:ecere>actions/goNext.png",               /* goForward */
36    "<:ecere>actions/goUp.png",                 /* goUp */
37    "<:ecere>actions/goHome.png",               /* goHome */
38
39    ":browse.png",                                           /* browse */
40
41    ":panel-tree.png",                                       /* panelTree */
42    "<:ecere>actions/editFind.png",             /* panelSearch */
43
44    "<:ecere>emblems/unreadable.png",     /* addressBar */
45
46    "<:ecere>actions/viewRefresh.png",          /* refreshView */
47
48    ":view-list.png",                                        /* viewList */
49    ":view-details.png",                                     /* viewDetails */
50    ":view-icons.png",                                       /* viewIcons */
51    ":view-cards.png",                                       /* viewCards */
52    ":view-showcase-right.png",                              /* viewShowcase */
53    ":view-custom.png",                                      /* viewCustom */
54    
55    "<:ecere>mimetypes/image.png",     /* previewPictures */
56    
57    ""
58 };
59
60 class ToolButton : Button
61 {
62    size = Size { 24, 24 };
63
64    property int toolId
65    {
66       set
67       {
68          bitmap = BitmapResource { fileName = toolIconNames[value], alphaBlend = true };
69          id = value;
70       }
71    }
72
73    bool TestToolBar::NotifyClicked(ToolButton button, int x, int y, Modifiers mods)
74    {
75       NotifyToolClick(this.parent, this, button.id);
76       return true;
77    }
78 }
79
80 class ToggleToolButton : ToolButton
81 {
82    toggle = true;
83    size = Size { 24, 24 };
84    
85    bool TestToolBar::NotifyClicked(ToggleToolButton button, int x, int y, Modifiers mods)
86    {
87       NotifyToolClick(this.parent, this, button.id);
88       return true;
89    }
90 }
91
92 class GroupToggleToolButton : ToolButton
93 {
94    toggle = true;
95    size = Size { 24, 24 };
96    GroupToggleToolButton * selected;
97    bool TestToolBar::NotifyClicked(GroupToggleToolButton button, int x, int y, Modifiers mods)
98    {
99       bool configured = (bool)button.selected;
100       bool preselection = (configured && (*button.selected));
101       bool reclick = preselection ? (*button.selected == button) : false;
102       if(configured && preselection && !reclick)
103       {
104          (*button.selected).checked = false;
105          *button.selected = button;
106       }
107       NotifyToolClick(this.parent, this, button.id);
108       return true;
109    }
110 }
111
112 class OptionToolButton : ToolButton
113 {
114    toggle = true;
115    size = Size { 24, 24 };
116    OptionToolButton * selected;
117    bool TestToolBar::NotifyClicked(OptionToolButton button, int x, int y, Modifiers mods)
118    {
119       bool configured = (bool)button.selected;
120       bool preselection = (configured && (*button.selected));
121       bool reclick = preselection ? (*button.selected == button) : false;
122       if(configured && !preselection)
123          *button.selected = button;
124       else if(configured && !reclick)
125       {
126          (*button.selected).checked = false;
127          *button.selected = button;
128       }
129       button.checked = true;
130       if(!reclick)
131          NotifyToolClick(this.parent, this, button.id);
132       return true;
133    }
134 }
135
136 class TestToolBar : Window
137 {
138    int xL, xR;
139
140    borderStyle = bevel;
141    inactive = true;
142    background = activeBorder;
143    size = Size { h = 32 };
144    anchor = Anchor { left = 0, top = 0, right = 0 };
145
146    virtual void Window::NotifyToolClick(TestToolBar toolBar, int id);
147
148    xL = 0;
149
150    ToolButton newWindow { this, anchor = { left = (xL += 20) }, toolId = ExplorerToolId::newWindow };
151
152    ToolButton goBack    { this, anchor = { left = (xL += 46) }, toolId = ExplorerToolId::goBack };
153    ToolButton goForward { this, anchor = { left = (xL += 26) }, toolId = ExplorerToolId::goForward };
154    ToolButton goUp      { this, anchor = { left = (xL += 30) }, toolId = ExplorerToolId::goUp };
155    ToolButton goHome    { this, anchor = { left = (xL += 30) }, toolId = ExplorerToolId::goHome };
156
157    GroupToggleToolButton panelTree   { this, anchor = { left = (xL += 46) }, toolId = ExplorerToolId::panelTree, selected = &selectedPanel, checked = true };
158    GroupToggleToolButton panelSearch { this, anchor = { left = (xL += 26) }, toolId = ExplorerToolId::panelSearch, selected = &selectedPanel };
159    GroupToggleToolButton selectedPanel;
160    selectedPanel = panelTree;
161
162    xR = 0;
163
164    OptionToolButton viewList     { this, anchor = { right = (xR += 20) }, toolId = ExplorerToolId::viewList, selected = &selectedView, checked = true };
165    OptionToolButton viewDetails  { this, anchor = { right = (xR += 26) }, toolId = ExplorerToolId::viewDetails, selected = &selectedView };
166    OptionToolButton viewIcons    { this, anchor = { right = (xR += 26) }, toolId = ExplorerToolId::viewIcons, selected = &selectedView };
167    OptionToolButton viewTiles    { this, anchor = { right = (xR += 26) }, toolId = ExplorerToolId::viewCards, selected = &selectedView };
168    OptionToolButton viewShowcase { this, anchor = { right = (xR += 26) }, toolId = ExplorerToolId::viewShowcase, selected = &selectedView };
169    OptionToolButton selectedView;
170    selectedView = viewList;
171
172    ToggleToolButton previewPictures { this, anchor = { right = (xR += 46) }, toolId = ExplorerToolId::previewPictures };
173
174    ToolButton refreshView { this, anchor = { right = (xR += 46) }, toolId = ExplorerToolId::refreshView };
175
176    EditBox addressBar
177    {
178       this, master;
179       size = { w = 250 }, anchor = { left = (xL += 30), right = (xR += 30) }, id = ExplorerToolId::addressBar;
180    };
181
182    /*DropBox tileSet
183    {
184       this,
185       anchor = { left = (xPos += 88) };
186       inactive = true;
187
188       bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
189       {
190          return true;
191       }
192    };*/
193
194    TestToolBar()
195    {
196       /*tileSet.AddString("Forest").tag = 0;
197       tileSet.AddString("Winter").tag = 0;
198       tileSet.AddString("Wasteland").tag = 0;*/
199    }
200 };
201
202 class ExplorerWindow : Window
203 {
204    text = "Ecere Explorer";
205    background = activeBorder;
206    borderStyle = sizable;
207    hasMaximize = true;
208    hasMinimize = true;
209    hasClose = true;
210    hasMenuBar = true;
211    tabCycle = true;
212    size = Size { 888, 840 };
213    nativeDecorations = true;
214
215    bool userMode;
216    bool clipboard;
217
218    int treeSplit;
219    int searchSplit;
220    
221    ExplorerToolId lastViewId;
222
223    menu = Menu { };
224    
225    Menu fileMenu { menu, "File", f };
226    Menu windowMenu { menu, "Window", w };
227       MenuItem newWindow
228       {
229          windowMenu, "New Window", n;
230          
231          bool NotifySelect(MenuItem selection, Modifiers mods)
232          {
233             ExplorerWindow { }.Create();
234             return true;
235          }
236       };
237
238    TestToolBar toolBar
239    {
240       this;
241
242       void NotifyToolClick(TestToolBar toolBar, int id)
243       {
244          ExplorerToolId toolId = (ExplorerToolId)id;
245          switch(toolId)
246          {
247             case none:
248                break;
249             case newWindow:
250                ExplorerWindow { }.Create();
251                break;
252             case goBack:
253             case goForward:
254                break;
255             case goUp:
256             {
257                ExplorerFileBranch branch = tree.branch;
258                if(branch && branch.parent)
259                   tree.Select(branch.parent);
260                break;
261             }
262             case panelTree:
263                if(tree.visible)
264                {
265                   split.leftPane = null;
266                   split.visible = false;
267                   tree.visible = false;
268                   treeSplit = split.split;
269                   split.OnResize(split.size.w, split.size.h);
270                }
271                else
272                {
273                   if(search.visible)
274                   {
275                      search.visible = false;
276                      searchSplit = split.split;
277                   }
278                   tree.visible = true;
279                   split.leftPane = tree;
280                   split.visible = true;
281                   split.split = treeSplit;
282                   split.OnResize(split.size.w, split.size.h);
283                   SwitchViews(lastViewId);
284                }
285                break;
286             case panelSearch:
287                if(search.visible)
288                {
289                   split.leftPane = null;
290                   split.visible = false;
291                   search.visible = false;
292                   searchSplit = split.split;
293                   split.OnResize(split.size.w, split.size.h);
294                   SwitchViews(lastViewId);
295                }
296                else
297                {
298                   if(tree.visible)
299                   {
300                      tree.visible = false;
301                      treeSplit = split.split;
302                   }
303                   search.visible = true;
304                   split.leftPane = search;
305                   split.visible = true;
306                   split.split = searchSplit;
307
308                   view = ExplorerSearchViewTree { viewHolder, this };
309                   view.previewPictures = toolBar.previewPictures.checked;
310                   view.anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
311                   view.NotifyItemOpen = ViewNotifyItemOpen;
312                   view.Create();
313                   search.view = (ExplorerSearchViewTree)view;
314
315                   split.OnResize(split.size.w, split.size.h);
316                }
317                break;
318             case refreshView:
319                if(view)
320                   view.Refresh();
321                break;
322             case previewPictures:
323                if(view)
324                   view.previewPictures = toolBar.previewPictures.checked;
325                break;
326             case viewList:
327             case viewDetails:
328             case viewIcons:
329             case viewCards:
330             case viewShowcase:
331                SwitchViews(toolId);
332                break;
333          }
334       }
335    };
336
337    void SwitchViews(ExplorerToolId viewId)
338    {
339       ExplorerFileBranch branch = tree.branch;
340       view.Destroy(0);
341       switch(viewId)
342       {
343          case viewList:     view = ExplorerViewList     { parent = viewHolder, master = this }; break;
344          case viewDetails:  view = ExplorerViewDetails  { parent = viewHolder, master = this }; break;
345          case viewIcons:    view = ExplorerViewIcons    { parent = viewHolder, master = this }; break;
346          case viewCards:    view = ExplorerViewCards    { parent = viewHolder, master = this }; break;
347          case viewShowcase: view = ExplorerViewShowcase { parent = viewHolder, master = this }; break;
348       }
349       view.tabCycle = true;
350       view.previewPictures = toolBar.previewPictures.checked;
351       view.anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
352       view.NotifyItemOpen = ViewNotifyItemOpen;
353       view.Create();
354       view.Load(branch);
355       lastViewId = viewId;
356    }
357
358    Window deep
359    {
360       this;
361       borderStyle = deep;
362       tabCycle = true;
363       anchor = Anchor { left = 0, top = 34, right = 0, bottom = 0 };
364    };
365
366    ExplorerTree tree
367    {
368       deep, this;
369       //visible = false;
370       tabCycle = true;
371       size = Size { 624, 268 };
372       anchor = Anchor { left = 0, top = 0, bottom = 0 };
373       text = "Browser", hotKey = Key { e, alt = true };
374       NotifyBranchSelect = TreeNotifyBranchSelect;
375    };
376    
377    ExplorerView view;
378
379    ExplorerSearch search
380    {
381       deep, this;
382       visible = false;
383       tabCycle = true;
384       size = Size { 624, 268 };
385       anchor = Anchor { left = 0, top = 0, bottom = 0 };
386    };
387
388    ExplorerViewSearch results;
389
390    bool TreeNotifyBranchSelect(ExplorerTree tree, ExplorerFileBranch branch)
391    {
392       if(branch)
393       {
394          char path[MAX_LOCATION];
395          branch.GetPath(path);
396          toolBar.addressBar.contents = path;
397          view.Load(branch);
398       }
399       return true;
400    }
401    
402    bool ViewNotifyItemOpen(ExplorerView view, ExplorerFileItem item)
403    {
404       ExplorerFileBranch branch = tree.branch;
405       if(item && branch)
406       {
407          if(item.type.isFolderType)
408          {
409             ExplorerFileBranch child;
410             
411             if(!branch.loaded || !branch.childrenLoaded)
412                BranchLoad(branch, tree.tree);
413
414             for(child = branch.children.first; child; child = child.next)
415                if(!strcmp(child.name, item.name))
416                   break;
417             
418             if(child)
419             {
420                if(branch.row.collapsed)
421                   child.row.collapsed = true;
422                child.EnsureVisible(false);
423                tree.Select(child);
424             }
425          }
426          else
427          {
428             char path[MAX_LOCATION];
429             branch.GetPath(path);
430             PathCat(path, item.name);
431             ShellOpen(path);
432          }
433       }
434    }
435
436    Window viewHolder
437    {
438       parent = deep, master = this;
439       tabCycle = true;
440       anchor = Anchor { top = 0, bottom = 0, right = 0 };
441    };
442
443    SplitWindow split
444    {
445       deep, this;
446       leftPane = tree, rightPane = viewHolder;
447       split = 300;
448    };
449
450    void GoToLocation(char * location)
451    {
452       int c;
453       char * temp;
454       char step[MAX_LOCATION];
455       
456       StringArray steps { growingFactor = 4 };
457       ExplorerFileBranch last = null;
458       
459       temp = CopyString(location);
460       while(strlen(temp))
461       {
462          GetLastDirectory(temp, step);
463          StripLastDirectory(temp, temp);
464          steps.Add(CopyString(step));
465       }
466       
467       for(c = steps._count - 1; c >= 0; c--)
468       {
469          last = tree.Find(steps._[c], last);
470          if(!last)
471             break;
472          tree.Select(last);
473       }
474       
475       delete temp;
476       delete steps;
477    }
478
479    void SearchLocation(char * location)
480    {
481       GoToLocation(location);
482       search.location.editBox.contents = location;
483    }
484
485    bool OnPostCreate()
486    {
487       userMode = true;
488       return true;
489    }
490
491    ExplorerWindow()
492    {
493       userMode = false;
494
495       treeSplit = 300;
496       searchSplit = 200;
497
498       view = ExplorerViewList
499       {
500          parent = viewHolder, master = this;
501          tabCycle = true;
502          previewPictures = toolBar.previewPictures.checked;
503          anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
504          NotifyItemOpen = ViewNotifyItemOpen;
505       };
506       lastViewId = viewList;
507       
508       tree.Load();
509       view.Load(tree.root);
510    }
511
512    void InitTree()
513    {
514    }
515
516    void InitSearch()
517    {
518    }
519 }
520
521 class ExplorerApp : GuiApplication
522 {
523    //skin = "Acovel";
524
525    bool Init()
526    {
527       QuickPathTool goPath { };
528       QuickPathTool searchPath { };
529       char * findWhat = null;
530       SetLoggingMode(debug, null);
531       if(argc > 1)
532       {
533          if(!strcmpi(argv[1], "go") && argc > 2)
534             goPath = argv[2];
535          else if(!strcmpi(argv[1], "find") && argc > 2)
536          {
537             char * unquoted;
538             if(argv[2][0] == '\"')
539                StripQuotes(argv[2], unquoted);
540             else
541                unquoted = argv[2];
542             findWhat = CopyString(unquoted);
543             if(argc > 3)
544             {
545                if(!strcmpi(argv[3], "in") && argc > 4)
546                   searchPath = argv[4];
547                else
548                   searchPath = ""; // this should make it current dir
549             }
550             else
551                searchPath = ""; // same
552          } 
553          else if(!strcmpi(argv[1], "search") && argc > 2)
554             searchPath = argv[2];
555          else if(!strcmpi(argv[1], "image") && argc > 2)
556             ;
557          else if(!strcmpi(argv[1], "slides") && argc > 2)
558             ;
559          else
560             goPath = argv[1];
561       }
562       else
563          goPath = "";
564       if(goPath)
565       {
566          ExplorerWindow explorerWnd { };
567          explorerWnd.Create();
568          explorerWnd.GoToLocation(goPath);
569       }
570       else if(searchPath)
571       {
572          ExplorerWindow explorerWnd { };
573          explorerWnd.Create();
574          explorerWnd.SearchLocation(searchPath);
575       }
576       return true;
577    }
578 }
579
580 struct QuickPathTool
581 {
582    char path[MAX_LOCATION];
583
584    property char * 
585    {
586       set
587       {
588          char * unquoted;
589          GetWorkingDir(path, MAX_LOCATION);
590          if(value[0] == '\"')
591             StripQuotes(value, unquoted);
592          else
593             unquoted = value;
594          PathCat(path, unquoted);
595          if(!FileExists(path))
596          {
597             // this incomplete functionality is not quite at it's place in this class
598             int len;
599             char * original = CopyString(path);
600             while((len = strlen(path)))
601             {
602                StripLastDirectory(path, path);
603                if(FileExists(path))
604                {
605                   // TODO: message location does not exist, 
606                   //       this higher location exists though
607                   //       go there?
608                   break;
609                }
610             }
611             if(!len)
612             {
613                // TODO: message location does not exist, 
614                //       unable to select alternate location
615             }
616             path[0] = '\0';
617             delete original;
618          }
619       }
620       get { return path[0] ? path : null; }
621    }
622    property bool { get { return (bool)path[0]; } }
623 };
624
625 define app = ((ExplorerApp)__thisModule);