eb690c357346f4d565071809d44ed97c94a6e34e
[ede] / explorer / src / ExplorerWindow.ec
1 import "Explorer"
2 //import "IconBag"
3 //import "ToolBar"
4 import "SearchBox"
5
6 #ifdef _DEBUG
7    define title = "Ecere Explorer (Debug)";
8 #else
9    define title = "Ecere Explorer";
10 #endif
11
12 /*
13 define backgroundColor = Color { 30, 40, 50 }; //Color { 20, 20, 60 };
14 define foregroundColor = lightGray; //white;
15 define selectionColor = lightYellow;
16 define selectionText = Color { 20, 30, 40 };
17 define toolBarBackgroundColor = backgroundColor;//white; //Color { 240, 240, 250 };
18 define toolBarForegroundColor = foregroundColor;//white; //Color { 240, 240, 250 };
19 */
20 define backgroundColor = Color { 155, 170, 160 };
21 //define backgroundColor = Color { 250, 250, 255 };
22 //define backgroundColor = beige;//white; //Color { 128, 145, 175 }; //200, 224, 224 }; //lightGray;
23 define foregroundColor = Color { 45, 45, 45 };//black;
24 define selectionColor = Color { 80, 140, 110 };//app.currentSkin.selectionColor;
25 define selectionText = black;//app.currentSkin.selectionText;
26 define toolBarBackgroundColor = Color { 170, 187, 176 }; //backgroundColor;//white; //Color { 240, 240, 250 };
27 define toolBarForegroundColor = foregroundColor;//white; //Color { 240, 240, 250 };
28
29 enum ExplorerToolId
30 {
31    none,
32    newWindow, goBack, goForward, goUp, goHome,
33    newFile, newFolder,
34    browse,
35    panelTree, panelSearch,
36    addressBar,
37    refresh,
38    viewList, viewDetails, viewIcons, viewCards, viewShowcase, viewTree, viewCustom,
39    previewPictures,
40
41    searchInFileName,
42    inFileNameMatchCase,
43    inFileNameMatchWord,
44    searchInFileContent,
45    inFileContentMatchCase,
46    inFileContentMatchWord,
47    searchInSubDirs,
48    searchStart,
49    searchStop,
50
51    hasHeader
52 };
53
54 enum Icon
55 {
56    missing,
57    newWindow, goBack, goForward, goUp, goHome, newFile, newFolder,
58    browse,
59    panelTree, panelSearch,
60    addressBar,
61    refresh,
62    viewList, viewDetails, viewIcons, viewCards, viewShowcase, viewTree, viewCustom,
63    previewPictures,
64    searchInFileName, inFileNameMatchCase, inFileNameMatchWord,
65    searchInFileContent, inFileContentMatchCase, inFileContentMatchWord,
66    searchInSubDirs, searchStart, searchStop,
67    hasHeader
68 };
69 static const char * iconNames[Icon::enumSize] =
70 {
71    "<:ecere>emblems/unreadable.png",         /* missing */
72
73    "<:ecere>actions/windowNew.png",          /* newWindow */
74    "<:ecere>actions/goPrevious.png",         /* goBack */
75    "<:ecere>actions/goNext.png",             /* goForward */
76    "<:ecere>actions/goUp.png",               /* goUp */
77    "<:ecere>actions/goHome.png",             /* goHome */
78    "<:ecere>mimeTypes/file.png",             /* newFile */
79    "<:ecere>actions/folderNew.png",          /* newFolder */
80
81    ":browse.png",                            /* browse */
82
83    ":panel-tree.png",                        /* panelTree */
84    "<:ecere>actions/editFind.png",           /* panelSearch */
85
86    "",                                       /* addressBar */
87
88    "<:ecere>actions/viewRefresh.png",        /* refresh */
89
90    ":view-list.png",                         /* viewList */
91    ":view-details.png",                      /* viewDetails */
92    ":view-icons.png",                        /* viewIcons */
93    ":view-cards.png",                        /* viewCards */
94    ":view-showcase-right.png",               /* viewShowcase */
95    ":panel-tree.png",                        /* viewTree */
96    ":view-custom.png",                       /* viewCustom */
97
98    "<:ecere>mimeTypes/image.png",            /* previewPictures */
99
100    "",                                       /* searchInFileName */
101    "<:ecere>emblems/unreadable.png",         /* inFileNameMatchCase */
102    "<:ecere>emblems/unreadable.png",         /* inFileNameMatchWord */
103    "",                                       /* searchInFileContent */
104    "<:ecere>emblems/unreadable.png",         /* inFileContentMatchCase */
105    "<:ecere>emblems/unreadable.png",         /* inFileContentMatchWord */
106    ":browse.png",                            /* searchInSubDirs */
107    "<:ecere>actions/editFind.png",           /* searchStart */
108    "<:ecere>emblems/unreadable.png",         /* searchStop */
109    "<:ecere>emblems/unreadable.png"          /* hasHeader */
110 };
111
112 class IconToolButton : ToolButton
113 {
114    //inactive = true;
115    //bitmapAlignment = left;
116
117    property Icon icon
118    {
119       set
120       {
121          bitmap = BitmapResource { fileName = iconNames[value], alphaBlend = true };
122          //id = value;
123       }
124    }
125 }
126
127 class ToggleIconToolButton : IconToolButton
128 {
129    toggle = true;
130 }
131
132
133 class ExplorerWindow : Window
134 {
135    text = title;
136    background = backgroundColor;
137    borderStyle = sizable;
138    hasMaximize = true;
139    hasMinimize = true;
140    hasClose = true;
141    hasMenuBar = true;
142    //tabCycle = true;
143    size = { 840, 480 };
144    minClientSize = { 600, 300 };
145    nativeDecorations = true;
146    tabCycle = true;
147    icon = { ":explorerIcon.png" };
148
149    /*
150    bool userMode;
151    bool clipboard;
152
153    int treeSplit;
154    int searchSplit;
155
156    ExplorerToolId lastViewId;
157 */
158
159    bool treeInitialized;
160    int historyIndex;
161    Array<HistoryItem> history { };
162
163
164    menu = Menu { };
165
166    Menu fileMenu { menu, "File", f };
167    Menu windowMenu { menu, "Window", w };
168       MenuItem itemNewWindow { windowMenu, "New Window", n, NotifySelect = NewWindow_NotifySelect };
169
170    bool NewWindow_NotifySelect(MenuItem selection, Modifiers mods)
171    {
172       //ExplorerWindow { }.Create();
173       ExplorerWindow w { };//.Create();
174       w.location = location;
175       w.view.autoLoad = true;
176       w.Create();
177       w.Activate(); // tocheck: not working?
178       return true;
179    }
180
181 #if 0
182    IconBag<ExplorerToolId> iconBag
183    {
184       //window = guiApp.desktop;
185       window = this;
186       alphaBlend = true;
187       iconNames =
188       [
189       ];
190    };
191 #endif
192
193    Stacker stack
194    {
195       this;
196       gap = 0;
197       direction = vertical;
198       background = backgroundColor;
199       opacity = 0.0f;
200       tabCycle = true;
201
202       flipper = panels;
203       flipSpring = true;
204
205       anchor = { left = 0, top = 0, right = 0, bottom = 0 };
206       //moveable = false;
207    };
208
209    ToolBar/*<ExplorerToolId>*/ toolBar
210    {
211       stack, this;
212       size = { h = 32 };
213       //moveable = false;
214       borderStyle = none;
215       background = toolBarBackgroundColor;
216       tabCycle = true;
217
218       //iconBag = iconBag;
219       inactive = false;
220
221       flipper = addressBar;
222       flipSpring = true;
223
224 #if 0
225       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
226       {
227          bool noViewActivation = false;
228          ExplorerToolId id = (ExplorerToolId)button.id;
229          switch(id)
230          {
231             case none:
232                break;
233             case newWindow:
234             {
235                noViewActivation = true;
236                NewWindow_NotifySelect(null, 0);
237                break;
238             }
239             case goBack:
240             case goForward:
241                historyIndex += id == goBack ? -1 : 1;
242                GoToHistoryIndex(/*false, false, */false);
243                break;
244             case goHome:
245             {
246                char * home = getenv("HOME");
247                if(home && home[0] && FileExists(home).isDirectory)
248                   location = home;//GoTo(home, false, false);
249                break;
250             }
251             case goUp:
252             {
253                char * path = view.path;
254                char * newPath = new char[strlen(path)+1];
255                StripLastDirectory(path, newPath);
256                if(!newPath[0])
257                {
258                   newPath[0] = '/';
259                   newPath[1] = 0;
260                }
261                location = newPath;//GoTo(newPath, false, false);
262                delete newPath;
263                break;
264             }
265             case newFile:
266                NewFile(view, null, 0);
267                break;
268             case newFolder:
269                NewFolder(view, null, 0);
270                break;
271             case panelTree:
272                SearchStop();
273                //ToggleSearchMode(false);
274                tree.visible = button.checked;
275                split.visible = button.checked;
276                if(button.checked)
277                {
278                   split.rightPane = view;
279                   view.anchor = { top = 0, bottom = 0, right = 0 };
280                   location = addressBar.path;//GoTo(addressBar.path, false, false);
281                   ReadyTree();
282                }
283                else
284                {
285                   split.rightPane = null;
286                   view.anchor = { left = 2, top = 0, bottom = 0, right = 0 };
287                }
288                //search.visible = !button.checked;
289                break;
290             case panelSearch:
291                ToggleSearchMode(button.checked);
292
293                //tree.visible = false; //!button.checked;
294                //split.visible = false; //!button.checked;
295                if(button.checked)
296                {
297                   /*split.rightPane = view;
298                   view.anchor = { top = 0, bottom = 0, right = 0 };*/
299                   //split.rightPane = null;
300                   //view.anchor = { left = 2, top = 0, bottom = 0, right = 0 };
301
302                   //SearchStart();
303                   searchInFileName.Activate();
304                }
305                else
306                {
307                   //split.rightPane = null;
308                   //view.anchor = { left = 2, top = 0, bottom = 0, right = 0 };
309
310                   location = addressBar.path;//GoTo(addressBar.path, false, false);
311                }
312                break;
313             case refresh:
314                Refresh();
315                break;
316             case previewPictures:
317                view.previewPictures = button.checked;
318                view.Refresh();
319                break;
320             case viewList:
321                view.details = false;
322                view.treeBranches = false;
323                view.Refresh();
324                break;
325             case viewDetails:
326                view.details = true;
327                view.treeBranches = false;
328                view.Refresh();
329                break;
330             case viewIcons:
331             case viewCards:
332                //SwitchViews(toolId);
333                view.details = false;
334                view.treeBranches = false;
335                view.Refresh();
336                break;
337             case viewShowcase:
338                view.preview = button.checked;
339                view.Refresh();
340                break;
341             case viewTree:
342                view.treeBranches = button.checked;
343                view.Refresh();
344                break;
345             case hasHeader:
346                view.hasHeader ^= true;
347                break;
348          }
349          if(!noViewActivation)
350             view.Activate();
351          return true;
352       }
353 #endif
354    };
355
356    Window { toolBar, size = { w = 8 }, inactive = true };
357    IconToolButton goBack { toolBar, this, icon = goBack, hotKey = { left, alt = true }, toolTip = "Back", disabled = true;
358       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
359       {
360          historyIndex += -1;
361          GoToHistoryIndex(/*false, false, */false);
362          view.Activate();
363          return true;
364       }
365    };
366    Window { toolBar, size = { w = 2 }, inactive = true };
367    IconToolButton goForward { toolBar, this, icon = goForward, hotKey = { right, alt = true }, toolTip = "Forward", disabled = true;
368       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
369       {
370          historyIndex += 1;
371          GoToHistoryIndex(/*false, false, */false);
372          view.Activate();
373          return true;
374       }
375    };
376    Window { toolBar, size = { w = 2 }, inactive = true };
377    IconToolButton refresh { toolBar, this, icon = refresh, hotKey = { r, ctrl = true }, toolTip = "Refresh";
378       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
379       {
380          Refresh();
381          view.Activate();
382          return true;
383       }
384    };
385    Window { toolBar, size = { w = 2 }, inactive = true };
386    IconToolButton goHome { toolBar, this, icon = goHome, hotKey = { h, ctrl = true }, toolTip = "Go Home";
387       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
388       {
389          char * home = getenv("HOME");
390          if(home && home[0] && FileExists(home).isDirectory)
391             location = home;//GoTo(home, false, false);
392          view.Activate();
393          return true;
394       }
395    };
396    Window { toolBar, size = { w = 8 }, inactive = true };
397    PathBox addressBar
398    {
399       toolBar, this;
400       size = { 300, 22 };//, icon = addressBar;
401       typeExpected = directory;
402       borderStyle = deep;
403       background = toolBarBackgroundColor;
404       foreground = toolBarForegroundColor;
405       selectionColor = selectionColor;
406       selectionText = selectionText;
407       toolTip = "Location";
408
409       bool OnKeyDown(Key key, unichar ch)
410       {
411          if((SmartKey)key == enter)
412          {
413             // how to make enter effect a modification
414             // how to implement in PathBox
415          }
416          return true;
417       }
418
419       bool NotifyModified(PathBox pathBox)
420       {
421          location = pathBox.path;//GoTo(pathBox.path, false, false);
422          return true;
423       }
424    };
425    //FlipStacker { toolBar, spring = previous };
426    Window { toolBar, size = { w = 8 }, inactive = true };
427    IconToolButton newFile { toolBar, this, icon = newFile, hotKey = { l, ctrl = true }, toolTip = "Create New File";
428       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
429       {
430          NewFile(view, null, 0);
431          view.Activate();
432          return true;
433       }
434    };
435    Window { toolBar, size = { w = 2 }, inactive = true };
436    IconToolButton newFolder { toolBar, this, icon = newFolder, hotKey = { d, ctrl = true }, toolTip = "Create New Folder";
437       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
438       {
439          NewFolder(view, null, 0);
440          view.Activate();
441          return true;
442       }
443    };
444    Window { toolBar, size = { w = 8 }, inactive = true };
445    IconToolButton goUp { toolBar, this, icon = goUp, hotKey = { up, alt = true }, toolTip = "Go to Parent Folder";
446       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
447       {
448          const char * path = view.path;
449          char * newPath = new char[strlen(path)+1];
450          StripLastDirectory(path, newPath);
451          if(!newPath[0])
452          {
453             newPath[0] = '/';
454             newPath[1] = 0;
455          }
456          location = newPath;//GoTo(newPath, false, false);
457          delete newPath;
458          view.Activate();
459          return true;
460       }
461    };
462    Window { toolBar, size = { w = 8 }, inactive = true };
463    //GroupToggleIconToolButton selectedPanel;
464    ToggleIconToolButton panelTree   { toolBar, this, icon = panelTree/*, selected = &selectedPanel*//*, checked = true*/, toolTip = "Toggle Tree Panel";
465       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
466       {
467          SearchStop();
468          //ToggleSearchMode(false);
469          tree.visible = button.checked;
470          split.visible = button.checked;
471          if(button.checked)
472          {
473             split.rightPane = view;
474             view.anchor = { top = 0, bottom = 0, right = 0 };
475             location = addressBar.path;//GoTo(addressBar.path, false, false);
476             ReadyTree();
477          }
478          else
479          {
480             split.rightPane = null;
481             view.anchor = { left = 2, top = 0, bottom = 0, right = 0 };
482          }
483          //search.visible = !button.checked;
484          view.Activate();
485          return true;
486       }
487    };
488    ToggleIconToolButton panelSearch { toolBar, this, icon = panelSearch, hotKey = { f, ctrl = true }/*, selected = &selectedPanel*/, toolTip = "Toggle Search";
489       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
490       {
491          ToggleSearchMode(button.checked);
492
493          //tree.visible = false; //!button.checked;
494          //split.visible = false; //!button.checked;
495          if(button.checked)
496          {
497             /*split.rightPane = view;
498             view.anchor = { top = 0, bottom = 0, right = 0 };*/
499             //split.rightPane = null;
500             //view.anchor = { left = 2, top = 0, bottom = 0, right = 0 };
501
502             //SearchStart();
503             searchInFileName.Activate();
504          }
505          else
506          {
507             //split.rightPane = null;
508             //view.anchor = { left = 2, top = 0, bottom = 0, right = 0 };
509
510             location = addressBar.path;//GoTo(addressBar.path, false, false);
511          }
512          view.Activate();
513          return true;
514       }
515    };
516    //selectedPanel = panelTree;
517    Window { toolBar, size = { w = 8 }, inactive = true };
518    /*OptionIconToolButton selectedView;
519    OptionIconToolButton viewList     { toolBar, this, icon = viewList, selected = &selectedView, checked = true };
520    OptionIconToolButton viewDetails  { toolBar, this, icon = viewDetails, selected = &selectedView };
521    OptionIconToolButton viewIcons    { toolBar, this, icon = viewIcons, selected = &selectedView };
522    OptionIconToolButton viewTiles    { toolBar, this, icon = viewCards, selected = &selectedView };
523    OptionIconToolButton viewShowcase { toolBar, this, icon = viewShowcase, selected = &selectedView };
524    OptionIconToolButton viewTree     { toolBar, this, icon = viewTree, selected = &selectedView };
525    selectedView = viewList;*/
526    //ToggleIconToolButton viewList     { toolBar, this, icon = viewList, checked = true };
527       /*case viewList:
528          view.details = false;
529          view.treeBranches = false;
530          view.Refresh();
531          break;*/
532    ToggleIconToolButton viewDetails  { toolBar, this, icon = viewDetails, toolTip = "Toggle Listing Details";
533       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
534       {
535          view.details = button.checked;
536          view.treeBranches = false;
537          view.Refresh();
538          view.Activate();
539          return true;
540       }
541    };
542       /*case viewCards:
543          //SwitchViews(toolId);
544          view.details = false;
545          view.treeBranches = false;
546          view.Refresh();
547          break;*/
548    //ToggleIconToolButton viewIcons    { toolBar, this, icon = viewIcons };
549    //ToggleIconToolButton viewTiles    { toolBar, this, icon = viewCards };
550    ToggleIconToolButton viewShowcase { toolBar, this, icon = viewShowcase, toolTip = "Toggle Showcase";
551       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
552       {
553          view.preview = button.checked;
554          view.Refresh();
555          view.Activate();
556          return true;
557       }
558    };
559    ToggleIconToolButton viewTree     { toolBar, this, icon = viewTree, hotKey = { t, ctrl = true }, toolTip = "Toggle Tree Listing";
560       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
561       {
562          view.treeBranches = button.checked;
563          view.Refresh();
564          view.Activate();
565          return true;
566       }
567    };
568    Window { toolBar, size = { w = 8 }, inactive = true };
569    ToggleIconToolButton previewPictures { toolBar, this, icon = previewPictures, toolTip = "Toggle Picture Preview";
570       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
571       {
572          view.previewPictures = button.checked;
573          view.Refresh();
574          view.Activate();
575          return true;
576       }
577    };
578
579    Window { toolBar, size = { w = 8 }, inactive = true };
580    ToggleIconToolButton hasHeader { toolBar, this, icon = hasHeader, toolTip = "Toggle Listing Header";
581       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
582       {
583          view.hasHeader ^= true;
584          view.Activate();
585          return true;
586       }
587    };
588    Window { toolBar, size = { w = 8 }, inactive = true };
589    IconToolButton newWindow { toolBar, this, icon = newWindow, hotKey = { w, ctrl = true }, toolTip = "Open New Window";
590       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
591       {
592          NewWindow_NotifySelect(null, 0);
593          return true;
594       }
595    };
596    Window { toolBar, size = { w = 8 }, inactive = true };
597
598
599 #if 0
600    /*void OnDestroy()
601    {
602       iconBag.window = null;
603       delete iconBag;
604    }*/
605
606    bool OnLoadGraphics()
607    {
608       iconBag.Load();
609       return true;
610    }
611
612    void OnUnloadGraphics()
613    {
614       iconBag.Unload();
615    }
616 #endif
617
618    Stacker panels
619    {
620       stack, this;
621       gap = 0;
622       direction = horizontal;
623       opacity = 0.0f;
624       tabCycle = true;
625
626       anchor.left = 0;
627       //anchor.bottom = 0;
628       anchor.right = 0;
629
630       //size = { h = 400 };
631    };
632
633    //FlipStacker flipStack { stack, spring = previous };
634
635    //Window searchSpace { stack, size = { h = 32 }, background = toolBarBackgroundColor, inactive = true, opacity = 0.0f };
636
637    ToolBar/*<ExplorerToolId>*/ searchBar
638    {
639       stack, this;
640       size = { h = 32 };
641       visible = false;
642       //moveable = false;
643       borderStyle = none;
644       background = toolBarBackgroundColor;
645       tabCycle = true;
646       //iconBag = iconBag;
647       inactive = false;
648
649       flipper = searchInFileContent;
650       flipSpring = true;
651
652 #if 0
653       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
654       {
655          ExplorerToolId id = (ExplorerToolId)button.id;
656          switch(id)
657          {
658             case none:
659                break;
660             case searchStart:
661                SearchStart();
662                break;
663             case searchStop:
664                SearchStop();
665                break;
666          }
667          view.Activate();
668          return true;
669       }
670 #endif
671    };
672
673    Window { searchBar, size = { w = 8 }, inactive = true };
674    //Label { searchBar, this, labeledWindow = searchInFileName};
675    //Window { searchBar, size = { w = 2 }, inactive = true };
676    SearchBox searchInFileName
677    {
678       searchBar, this;
679       size = { 200, 22 };//, icon = searchInFileName;
680       borderStyle = deep;
681       background = toolBarBackgroundColor;
682       foreground = toolBarForegroundColor;
683       selectionColor = selectionColor;
684       selectionText = selectionText;
685       //text = "File Name:";
686       caption = "Search File Names";
687       toolTip = "Search File Names";
688
689       bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
690       {
691          if((SmartKey)key == enter)
692             SearchStart();
693          return true;
694       }
695
696       /*bool NotifyActivate(Window window, bool active, Window previous)
697       {
698          if(active)
699          {
700             toolBar.focusHolder = window;
701          }
702          return true;
703       }*/
704    };
705    Window { searchBar, size = { w = 2 }, inactive = true };
706 #ifndef __WIN32__
707    ToggleIconToolButton inFileNameMatchCase { searchBar, this, icon = inFileNameMatchCase, toolTip = "Toggle Match Case";
708       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
709       {
710          return true;
711       }
712    };
713 #endif
714    ToggleIconToolButton inFileNameMatchWord { searchBar, this, icon = inFileNameMatchWord, toolTip = "Toggle Match Whole Word";
715       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
716       {
717          return true;
718       }
719    };
720    Window { searchBar, size = { w = 8 }, inactive = true };
721    //Label { searchBar, this, labeledWindow = searchInFileContent};
722    //Window { searchBar, size = { w = 2 }, inactive = true };
723    SearchBox searchInFileContent
724    {
725       searchBar, this;
726       size = { 200, 22 };//, icon = searchInFileContent;
727       borderStyle = deep;
728       background = toolBarBackgroundColor;
729       foreground = toolBarForegroundColor;
730       selectionColor = selectionColor;
731       selectionText = selectionText;
732       //text = "File Content:";
733       caption = "Search File Contents";
734       toolTip = "Search File Contents";
735
736       bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
737       {
738          if((SmartKey)key == enter)
739             SearchStart();
740          return true;
741       }
742
743       /*bool NotifyActivate(Window window, bool active, Window previous)
744       {
745          if(active)
746             toolBar.focusHolder = window;
747          return true;
748       }*/
749    };
750    //FlipStacker { searchBar, spring = previous };
751    ToggleIconToolButton inFileContentMatchCase { searchBar, this, icon = inFileContentMatchCase, toolTip = "Toggle Match Case";
752       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
753       {
754          return true;
755       }
756    };
757    ToggleIconToolButton inFileContentMatchWord { searchBar, this, icon = inFileContentMatchWord, toolTip = "Toggle Match Whole Word";
758       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
759       {
760          return true;
761       }
762    };
763    Window { searchBar, size = { w = 8 }, inactive = true };
764    ToggleIconToolButton searchInSubDirs { searchBar, this, icon = searchInSubDirs, checked = true, toolTip = "Toggle Include Subfolders";
765       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
766       {
767          return true;
768       }
769    };
770    Window { searchBar, size = { w = 8 }, inactive = true };
771    IconToolButton searchStart { searchBar, this, icon = searchStart, hotKey = { s, ctrl = true }, toolTip = "Start Search";
772       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
773       {
774          SearchStart();
775          view.Activate();
776          return true;
777       }
778    };
779    Window { searchBar, size = { w = 8 }, inactive = true };
780    IconToolButton searchStop { searchBar, this, icon = searchStop, hotKey = { escape }, disabled = true, toolTip = "Stop Search";
781       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
782       {
783          SearchStop();
784          view.Activate();
785          return true;
786       }
787    };
788    Window { searchBar, size = { w = 8 }, inactive = true };
789
790
791
792    //Window { searchBar, size = { h = 1 } };
793
794    /*SearchPanel searchPanel
795    {
796       panels, this;
797    };*/
798
799    /*Window hack
800    {
801       panels, this;
802       anchor.top = 0;
803       anchor.bottom = 0;
804       anchor.right = 0;
805       borderStyle = none;
806       background = backgroundColor;
807    };*/
808
809    /*Tree*/FileSystemBox tree//;
810    {
811       panels, this;
812       size = { w = 240 };
813       borderStyle = none;
814       background = backgroundColor;
815       foreground = foregroundColor;
816       selectionColor = selectionColor;
817       selectionText = selectionText;
818       visible = false;
819       anchor.top = 0;
820       anchor.bottom = 0;
821       //anchor = { left = 0, top = 0, bottom = 0 };
822
823       treeBranches = true;
824       foldersOnly = true;
825       autoLoad = false;
826
827       bool NotifyNodeSelect(FileSystemBox box, FileSystemBoxSelection selection)
828       {
829          if(treeInitialized)
830          {
831             FileSystemNode node = selection.node;
832             if(node)
833             {
834                char p[MAX_LOCATION];
835                node.GetPath(p);
836                location = node.path;//GoTo(node.path, false, true);
837             }
838          }
839          return true;
840       }
841
842       /*bool NotifyActivate(Window window, bool active, Window previous)
843       {
844          if(active)
845             toolBar.focusHolder = window;
846          return true;
847       }*/
848    };
849
850    PaneSplitter split
851    {
852       panels, this;
853       visible = false;
854       leftPane = tree;//, rightPane = view;
855       split = 300;
856    };
857
858    //FileSystemCache testCache;
859    FileSystemBox view
860    {
861       panels, this;
862       borderStyle = none;
863       background = backgroundColor;
864       foreground = foregroundColor;
865       selectionColor = selectionColor;
866       selectionText = selectionText;
867       anchor.top = 0;
868       anchor.bottom = 0;
869       anchor.right = 0;
870       //anchor = { left = 2, top = 0, bottom = 0, right = 0 };
871
872       locationBox = addressBar;
873       navigateFolders = true;
874       multiSelect = true;
875       autoLoad = false;
876
877       //iteratorClass = class(FileSystemCacheIterator);
878       //iteratorClass = class(FileSystemIterator);
879
880       bool NotifyIteratorInit(FileSystemBox box, FileSystemIterator fileSystemIterator)
881       {
882          //((FileSystemCacheIterator)fileSystemIterator).cache = testCache;
883          //((FileSystemIterator)fileSystemIterator)
884          return true;
885       }
886
887       bool NotifyNodeOpen(FileSystemBox box, FileSystemBoxSelection selection)
888       {
889          FileSystemNode node = selection.node;
890          if(node)
891          {
892             if(node.type.isFile)
893             {
894                char path[MAX_LOCATION];
895             //#ifndef __WIN32__
896             //   char command[MAX_LOCATION];
897             //   node.GetPath(path);
898             //   /*_FileType t = node.type;
899             //   if(t == ewsFile || t == epjFile ||
900             //         t == ecFile || t == ehFile ||
901             //         t == cppFile || t == hppFile ||
902             //         t == cFile || t == hFile ||
903             //         t == textFile || t == webFile)*/
904             //      sprintf(command, "gnome-open \"%s\"", path);
905             //   /*else
906             //      sprintf(command, "%s", path);*/
907             //   Execute(command);
908             //#else
909                node.GetPath(path);
910                ShellOpen(path);
911             //#endif
912             }
913             else if(node.type.isFolder)
914                location = node.path;//GoTo(node.path, true, false);
915          }
916          UpdateHistoryItem(selection);
917          return true;
918       }
919
920       bool NotifyNodeSelect(FileSystemBox box, FileSystemBoxSelection selection)
921       {
922          if(!comparedLocations)
923             UpdateHistoryItem(selection);
924          return true;
925       }
926
927       bool NotifyNodeMenu(FileSystemBox box, Menu menu, FileSystemBoxSelection selection)
928       {
929          char * text;
930          char * itemString;
931          FileSystemNode node = selection.node;
932
933          //PrintLn(node.name);
934          if(box.selection.nodes.count == 1)
935             itemString = CopyString(node.name);
936          else
937             itemString = PrintString(box.selection.nodes.count, " items");
938          text = PrintString("Open ", itemString);
939          MenuItem { menu, text, o, disabled = false;
940             NotifySelect = FileSystemBox::MenuOpen
941             /*bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
942             {
943                for(node : this.selection.nodes)
944                {
945                   // todo: somehow bring MenuOpen / OpenNode behavior ourside
946                }
947                return true;
948             }*/
949          };
950          //delete text;
951          if(node.type == folder)
952          {
953             text = PrintString("Open ", itemString, " in another window");
954             MenuItem { menu, text, w, disabled = false;
955                bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
956                {
957                   for(node : this.selection.nodes)
958                   {
959                      ExplorerWindow ew { /*location = this.selection.node.path*/ };//.Create();
960                      ew.Create();
961                      ew.location = /*this.selection.*/node.path;
962                   }
963                   return true;
964                }
965             };
966             //delete text;
967             MenuDivider { menu };
968             text = PrintString("Open ", itemString, " in shell");
969             MenuItem { menu, text, w, disabled = false;
970                bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
971                {
972                   for(node : this.selection.nodes)
973                   {
974                      if(node.stats.attribs)
975                         ShellOpen(/*this.selection.*/node.path);
976                   }
977                   return true;
978                }
979             };
980             //delete text;
981             MenuDivider { menu };
982             MenuItem { menu, "Create File", w, NotifySelect = NewFile, disabled = false };
983             MenuItem { menu, "Create Folder", w, NotifySelect = NewFolder, disabled = false };
984          }
985          if(panelSearch.checked)
986          {
987             MenuDivider { menu };
988             MenuItem { menu, "Open Containing Folder", f, NotifySelect = FileSystemBox::MenuOpen, disabled = false;
989                bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
990                {
991                   char path[MAX_LOCATION];
992                   StripLastDirectory(this.selection.node.path, path);
993                   this.path = path;
994                   return true;
995                }
996             };
997             MenuItem { menu, "Open Containing Folder in another window", r, NotifySelect = FileSystemBox::MenuOpen, disabled = false;
998                bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
999                {
1000                   char path[MAX_LOCATION];
1001                   ExplorerWindow ew { /*location = this.selection.node.path*/ };//.Create();
1002                   ew.Create();
1003                   StripLastDirectory(this.selection.node.path, path);
1004                   ew.location = path;
1005                   return true;
1006                }
1007             };
1008             delete itemString;
1009          }
1010          if(node.isListItem/* && TODO: unless node is at root location*/)
1011          {
1012             MenuDivider { menu };
1013             MenuItem { menu, "Replace by Parent\tCtrl+R", r, NotifySelect = FileSystemBox::MenuReplaceListItemByContainingDir, disabled = false };
1014          }
1015          else if(box.mode == list)
1016          {
1017             MenuDivider { menu };
1018             MenuItem { menu, "Replace List Item\tCtrl+R", r, NotifySelect = FileSystemBox::MenuReplaceListItemByChild, disabled = false };
1019          }
1020          MenuDivider { menu };
1021          MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false };
1022          MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false };
1023          MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /*!clipboard*/ };
1024          MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false };
1025          //MenuDivider { menu };
1026          return true;
1027       }
1028
1029       /*bool NotifyActivate(Window window, bool active, Window previous)
1030       {
1031          if(active)
1032             toolBar.focusHolder = window;
1033          return true;
1034       }*/
1035    };
1036
1037    FileSystemSearch searchThread
1038    {
1039       owner = this, fsb = view, tree = tree/*, searchPanel = this*/;
1040
1041       /*bool ExplorerWindow::NotifyUpdateSearchLocation(FileSystemSearch search, char * location)
1042       {
1043          char string[MAX_LOCATION + 2048];
1044          sprintf(string, "%s (Searching %s)", title, location);
1045          PrintLn(string); //view.results.text = string;
1046          text = string;
1047          return true;
1048       }*/
1049
1050       bool ExplorerWindow::NotifySearchTerminated(FileSystemSearch search)
1051       {
1052          searchStop.disabled = true;
1053          return true;
1054       }
1055    };
1056
1057    void ToggleSearchMode(bool inSearch)
1058    {
1059       SearchStop();
1060       //search.visible = inSearch;
1061       //panelSearch.checked = inSearch; // <------ this is toggling panelSearch even though it shouldn't
1062       //searchSpace.visible = !inSearch;
1063       searchBar.visible = inSearch;
1064       history[historyIndex].inSearch = inSearch;
1065       view.pathColumn = inSearch;
1066       /*if(inSearch)
1067          searchThread.InitResults();*/
1068       if(inSearch && /*(*/searchInFileName.contents[0]/* || searchInFileContents.contents[0])*/)
1069          SearchStart();
1070    }
1071
1072    void ReadyTree()
1073    {
1074       if(tree.visible)
1075       {
1076          if(!treeInitialized)
1077          {
1078             tree.path = "/"; // this should be available as a parameter
1079             treeInitialized = true;
1080          }
1081          tree.SelectLocation(view.path);
1082       }
1083    }
1084
1085    void Refresh()
1086    {
1087       if(searchBar.visible)
1088          SearchStart();
1089       else
1090       {
1091          if(tree.visible)
1092             tree.Refresh();
1093          view.Refresh();
1094       }
1095    }
1096
1097    //void NewFile()
1098    bool FileSystemBox::NewFile(MenuItem selection, Modifiers mods)
1099    {
1100       if(master._class == class(ExplorerWindow))
1101       {
1102          ExplorerWindow ew = (ExplorerWindow)master;
1103          if(CreateNewFileDialog { /*master = */ew/*, parent = parent*/, currentDirectory = selection ? ew.view.selection.node.path : ew.view.path }.Modal() == ok )
1104             ew.Refresh();
1105       }
1106       return true;
1107    }
1108
1109    //void NewFolder()
1110    bool FileSystemBox::NewFolder(MenuItem selection, Modifiers mods)
1111    {
1112       if(master._class == class(ExplorerWindow))
1113       {
1114          ExplorerWindow ew = (ExplorerWindow)master;
1115          if(CreateDirectoryDialog { /*master = */ew/*, parent = parent*/, currentDirectory = selection ? ew.view.selection.node.path : ew.view.path }.Modal() == ok )
1116             ew.Refresh();
1117       }
1118       return true;
1119    }
1120
1121    //void GoTo(char * location/*, bool viewIsAtLocation, bool treeIsAtLocation*/)
1122    property const char * location
1123    {
1124       set
1125       {
1126          HistoryItem item = null;
1127          if(!history.count || fstrcmp(history[historyIndex].path, value))
1128          {
1129             int c;
1130             for(c = 0; c < history.count; c++)
1131                if(!fstrcmp(history[c].path, value))
1132                   break;
1133             if(c == history.count)
1134             {
1135                item = { path = CopyString(value) };
1136                if(history.count)
1137                {
1138                   while(historyIndex < history.count-1)
1139                   {
1140                      delete history[history.count-1].path;
1141                      history.count--;
1142                   }
1143                }
1144                history.Add(item);
1145                historyIndex = history.count-1;
1146             }
1147             else
1148                historyIndex = c;
1149          }
1150          GoToHistoryIndex(/*viewIsAtLocation, treeIsAtLocation, */item != null);
1151       }
1152       get { return view.path; }
1153    }
1154
1155    property Array<String> comparedLocations
1156    {
1157       set
1158       {
1159          // dd
1160          view.comparedPaths = value;
1161       }
1162       get
1163       {
1164          return view.comparedPaths;
1165       }
1166    }
1167
1168    void GoToHistoryIndex(/*bool viewIsAtLocation, bool treeIsAtLocation, */bool updateHistoryItem)
1169    {
1170       bool viewIsAtLocation;
1171       bool treeIsAtLocation;
1172       HistoryItem item = history[historyIndex];
1173
1174       goBack.disabled = historyIndex == 0;
1175       goForward.disabled = historyIndex == history.count-1;
1176       goUp.disabled = !fstrcmp(item.path, "/");
1177
1178       viewIsAtLocation = !fstrcmp(item.path, tree.path);
1179       treeIsAtLocation = !fstrcmp(item.path, view.path);
1180
1181       if(!viewIsAtLocation)
1182       {
1183          if(item.inSearch != panelSearch.checked)
1184          {
1185             ToggleSearchMode(item.inSearch);
1186             if(item.inSearch)
1187                SearchStart();
1188          }
1189          if(!item.inSearch)
1190          /*{
1191             //SearchStart();
1192          }
1193          else*/
1194          {
1195             if(fstrcmp(view.path, item.path))
1196                view.path = item.path;
1197             item.holdRecordingSelection = true;
1198             view.SelectMultipleByPath(item.selection);
1199          }
1200       }
1201       if(tree.visible && !treeIsAtLocation)
1202          tree.SelectLocation(item.path);
1203
1204       if(updateHistoryItem)
1205          UpdateHistoryItem(view.selection);
1206    }
1207
1208    void UpdateHistoryItem(FileSystemBoxSelection selection)
1209    {
1210       if(history.count > historyIndex)   // TODO: Review why this would happen...
1211       {
1212          HistoryItem item = history[historyIndex];
1213
1214          if(!item.holdRecordingSelection)
1215          {
1216             if(selection.node || (selection.nodes && selection.nodes.count))
1217             {
1218                item.selection.Free();
1219                if(selection.nodes.count)
1220                {
1221                   for(node : selection.nodes)
1222                      item.selection.Add(CopyString(node.path));
1223                }
1224                else if(selection.node)
1225                   item.selection.Add(CopyString(selection.node.path));
1226             }
1227          }
1228          else
1229             item.holdRecordingSelection = false;
1230       }
1231    }
1232
1233    void SearchStart()
1234    {
1235       SearchStop();
1236       searchThread.active = true;
1237
1238       searchThread.optionSubdirs = searchInSubDirs.checked == true;
1239       searchThread.optionTree = view.treeBranches; //(options.subdirs.checked && options.tree.checked);
1240       searchThread.optionBrowser = tree.visible; //(options.subdirs.checked && options.browser.checked);
1241 #ifndef __WIN32__
1242       searchThread.optionNameMatchCase = inFileNameMatchCase.checked;
1243 #else
1244       searchThread.optionNameMatchCase = false;
1245 #endif
1246       searchThread.optionNameMatchWord = inFileNameMatchWord.checked;
1247       searchThread.optionContentMatchCase = inFileContentMatchCase.checked;
1248       searchThread.optionContentMatchWord = inFileContentMatchWord.checked;
1249
1250       strcpy(searchThread.location, view.path);
1251       strcpy(searchThread.nameSearch, searchInFileName.contents);
1252       strcpy(searchThread.contentSearch, searchInFileContent.contents);
1253
1254       //actions.startStop.text = "Stop Search";
1255       //actions.clear.disabled = false;
1256       //view.results.Clear();
1257       //view.results.hasHeader = !searchThread.optionTree;
1258       //view.results.treeBranches = searchThread.optionTree;
1259       //view.browser.Clear();
1260       //ToggleBrowserDisplay(searchThread.optionBrowser);
1261
1262       //view.browser.text = "Browser";
1263       /*{
1264          char string[MAX_LOCATION + 2048];
1265          sprintf(string, "%s (Searching %s)", title, view.path);
1266          //PrintLn(string); //view.results.text = string;
1267          text = string;
1268       }*/
1269       searchThread.InitResults();
1270       searchThread.Create();
1271       searchStop.disabled = false;
1272       //Update(null);
1273    }
1274
1275    bool SearchStop()
1276    {
1277       if(searchThread.active)
1278       {
1279          searchThread.terminate = true;
1280          //searchStop.disabled = true;
1281          app.Unlock();
1282             searchThread.Wait();
1283          app.Lock();
1284          return true;
1285       }
1286       return false;
1287    }
1288
1289    /*ExplorerSearch search
1290    {
1291       deep, this;
1292       visible = false;
1293       tabCycle = true;
1294       size = Size { 624, 268 };
1295       anchor = Anchor { left = 0, top = 0, bottom = 0 };
1296    };
1297
1298    ExplorerViewSearch results;*/
1299
1300    /*Window viewHolder
1301    {
1302       parent = deep, master = this;
1303       tabCycle = true;
1304       anchor = Anchor { top = 0, bottom = 0, right = 0 };
1305    };*/
1306
1307    // Preview / Showcase
1308    /*PreviewArea previewArea
1309    {
1310       panels, this;
1311    };*/
1312
1313    //FlipStacker flipPanels { panels, spring = previous };
1314
1315    /*bool TreeNotifyBranchSelect(ExplorerTree tree, ExplorerFileBranch branch)
1316    {
1317       if(branch)
1318       {
1319          char path[MAX_LOCATION];
1320          branch.GetPath(path);
1321          toolBar.addressBar.contents = path;
1322          view.Load(branch);
1323       }
1324       return true;
1325    }*/
1326
1327    /*bool ViewNotifyItemOpen(ExplorerView view, ExplorerFileItem item)
1328    {
1329       ExplorerFileBranch branch = tree.branch;
1330       if(item && branch)
1331       {
1332          if(item.type.isFolderType)
1333          {
1334             ExplorerFileBranch child;
1335
1336             if(!branch.loaded || !branch.childrenLoaded)
1337                BranchLoad(branch, tree.tree);
1338
1339             for(child = branch.children.first; child; child = child.next)
1340                if(!strcmp(child.name, item.name))
1341                   break;
1342
1343             if(child)
1344             {
1345                if(branch.row.collapsed)
1346                   child.row.collapsed = true;
1347                child.EnsureVisible(false);
1348                tree.Select(child);
1349             }
1350          }
1351          else
1352          {
1353             char path[MAX_LOCATION];
1354             branch.GetPath(path);
1355             PathCat(path, item.name);
1356             ShellOpen(path);
1357          }
1358       }
1359    }*/
1360
1361    /*void SwitchViews(ExplorerToolId viewId)
1362    {
1363       ExplorerFileBranch branch = tree.branch;
1364       view.Destroy(0);
1365       switch(viewId)
1366       {
1367          case viewList:     view = ExplorerViewList     { parent = viewHolder, master = this }; break;
1368          case viewDetails:  view = ExplorerViewDetails  { parent = viewHolder, master = this }; break;
1369          case viewIcons:    view = ExplorerViewIcons    { parent = viewHolder, master = this }; break;
1370          case viewCards:    view = ExplorerViewCards    { parent = viewHolder, master = this }; break;
1371          case viewShowcase: view = ExplorerViewShowcase { parent = viewHolder, master = this }; break;
1372       }
1373       view.tabCycle = true;
1374       view.previewPictures = toolBar.previewPictures.checked;
1375       view.anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
1376       view.NotifyItemOpen = ViewNotifyItemOpen;
1377       view.Create();
1378       view.Load(branch);
1379       lastViewId = viewId;
1380    }*/
1381
1382    /*void SearchLocation(char * location)
1383    {
1384       location = location;//GoTo(location);
1385       search.location.editBox.contents = location;
1386    }*/
1387
1388    bool OnPostCreate()
1389    {
1390       //userMode = true;
1391       addressBar.path = view.path;
1392       ReadyTree();
1393       view.Refresh();
1394       return true;
1395    }
1396
1397    bool OnClose(bool parentClosing)
1398    {
1399       SearchStop();
1400       return true;
1401    }
1402
1403    /*ExplorerWindow()
1404    {
1405       userMode = false;
1406
1407       treeSplit = 300;
1408       searchSplit = 200;
1409
1410       view = ExplorerViewList
1411       {
1412          parent = viewHolder, master = this;
1413          tabCycle = true;
1414          previewPictures = toolBar.previewPictures.checked;
1415          anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
1416          NotifyItemOpen = ViewNotifyItemOpen;
1417       };
1418       lastViewId = viewList;
1419
1420       tree.Load();
1421       view.Load(tree.root);
1422    }*/
1423
1424    /*void InitTree()
1425    {
1426    }*/
1427
1428    /*void InitSearch()
1429    {
1430    }*/
1431 }
1432
1433 //class TreeFileSystemBox : FileSystemBox { }
1434
1435 class HistoryItem
1436 {
1437    char * path;
1438    bool holdRecordingSelection;
1439    bool inSearch;
1440    Array<String> selection { };
1441
1442    ~HistoryItem()
1443    {
1444       delete path;
1445    }
1446 }