code dump. unfortunate lack of commits. rick click menu on files/folders. comparative...
[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 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          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 = true;
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       }
885
886       bool NotifyNodeOpen(FileSystemBox box, FileSystemBoxSelection selection)
887       {
888          FileSystemNode node = selection.node;
889          if(node)
890          {
891             if(node.type.isFile)
892             {
893                char path[MAX_LOCATION];
894             //#ifndef __WIN32__
895             //   char command[MAX_LOCATION];
896             //   node.GetPath(path);
897             //   /*_FileType t = node.type;
898             //   if(t == ewsFile || t == epjFile ||
899             //         t == ecFile || t == ehFile ||
900             //         t == cppFile || t == hppFile ||
901             //         t == cFile || t == hFile ||
902             //         t == textFile || t == webFile)*/
903             //      sprintf(command, "gnome-open \"%s\"", path);
904             //   /*else
905             //      sprintf(command, "%s", path);*/
906             //   Execute(command);
907             //#else
908                node.GetPath(path);
909                ShellOpen(path);
910             //#endif
911             }
912             else if(node.type.isFolder)
913                location = node.path;//GoTo(node.path, true, false);
914          }
915          UpdateHistoryItem(selection);
916          return true;
917       }
918
919       bool NotifyNodeSelect(FileSystemBox box, FileSystemBoxSelection selection)
920       {
921          if(!comparedLocations)
922             UpdateHistoryItem(selection);
923          return true;
924       }
925
926       bool NotifyNodeMenu(FileSystemBox box, Menu menu, FileSystemBoxSelection selection)
927       {
928          char * text;
929          char * itemString;
930          FileSystemNode node = selection.node;
931
932          //PrintLn(node.name);
933          if(box.selection.nodes.count == 1)
934             itemString = node.name;
935          else
936             itemString = PrintString(box.selection.nodes.count, " items");
937          text = PrintString("Open ", itemString);
938          MenuItem { menu, text, o, disabled = false;
939             NotifySelect = FileSystemBox::MenuOpen
940             /*bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
941             {
942                for(node : this.selection.nodes)
943                {
944                   // todo: somehow bring MenuOpen / OpenNode behavior ourside
945                }
946                return true;
947             }*/
948          };
949          //delete text;
950          if(node.type == folder)
951          {
952             text = PrintString("Open ", itemString, " in another window");
953             MenuItem { menu, text, w, disabled = false;
954                bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
955                {
956                   for(node : this.selection.nodes)
957                   {
958                      ExplorerWindow ew { /*location = this.selection.node.path*/ };//.Create();
959                      ew.Create();
960                      ew.location = /*this.selection.*/node.path;
961                   }
962                   return true;
963                }
964             };
965             //delete text;
966             MenuDivider { menu };
967             text = PrintString("Open ", itemString, " in shell");
968             MenuItem { menu, text, w, disabled = false;
969                bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
970                {
971                   for(node : this.selection.nodes)
972                   {
973                      if(node.stats.attribs)
974                         ShellOpen(/*this.selection.*/node.path);
975                   }
976                   return true;
977                }
978             };
979             //delete text;
980             MenuDivider { menu };
981             MenuItem { menu, "Create File", w, NotifySelect = NewFile, disabled = false };
982             MenuItem { menu, "Create Folder", w, NotifySelect = NewFolder, disabled = false };
983          }
984          if(panelSearch.checked)
985          {
986             MenuDivider { menu };
987             MenuItem { menu, "Open Containing Folder", f, NotifySelect = FileSystemBox::MenuOpen, disabled = false;
988                bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
989                {
990                   char path[MAX_LOCATION];
991                   StripLastDirectory(this.selection.node.path, path);
992                   this.path = path;
993                   return true;
994                }
995             };
996             MenuItem { menu, "Open Containing Folder in another window", r, NotifySelect = FileSystemBox::MenuOpen, disabled = false;
997                bool FileSystemBox::NotifySelect(MenuItem selection, Modifiers mods)
998                {
999                   char path[MAX_LOCATION];
1000                   ExplorerWindow ew { /*location = this.selection.node.path*/ };//.Create();
1001                   ew.Create();
1002                   StripLastDirectory(this.selection.node.path, path);
1003                   ew.location = path;
1004                   return true;
1005                }
1006             };
1007             delete itemString;
1008          }
1009          if(node.isListItem/* && TODO: unless node is at root location*/)
1010          {
1011             MenuDivider { menu };
1012             MenuItem { menu, "Replace by Parent\tCtrl+R", r, NotifySelect = FileSystemBox::MenuReplaceListItemByContainingDir, disabled = false };
1013          }
1014          else if(box.mode == list)
1015          {
1016             MenuDivider { menu };
1017             MenuItem { menu, "Replace List Item\tCtrl+R", r, NotifySelect = FileSystemBox::MenuReplaceListItemByChild, disabled = false };
1018          }
1019          MenuDivider { menu };
1020          MenuItem { menu, "Cut\tCtrl+X", t, NotifySelect = null, disabled = false };
1021          MenuItem { menu, "Copy\tCtrl+C", c, NotifySelect = null, disabled = false };
1022          MenuItem { menu, "Paste\tCtrl+V", p, NotifySelect = null, disabled = false /*!clipboard*/ };
1023          MenuItem { menu, "Delete\tDel", d, NotifySelect = null, disabled = false };
1024          //MenuDivider { menu };
1025          return true;
1026       }
1027
1028       /*bool NotifyActivate(Window window, bool active, Window previous)
1029       {
1030          if(active)
1031             toolBar.focusHolder = window;
1032          return true;
1033       }*/
1034    };
1035
1036    FileSystemSearch searchThread
1037    {
1038       owner = this, fsb = view, tree = tree/*, searchPanel = this*/;
1039
1040       /*bool ExplorerWindow::NotifyUpdateSearchLocation(FileSystemSearch search, char * location)
1041       {
1042          char string[MAX_LOCATION + 2048];
1043          sprintf(string, "%s (Searching %s)", title, location);
1044          PrintLn(string); //view.results.text = string;
1045          text = string;
1046          return true;
1047       }*/
1048
1049       bool ExplorerWindow::NotifySearchTerminated(FileSystemSearch search)
1050       {
1051          searchStop.disabled = true;
1052          return true;
1053       }
1054    };
1055
1056    void ToggleSearchMode(bool inSearch)
1057    {
1058       SearchStop();
1059       //search.visible = inSearch;
1060       //panelSearch.checked = inSearch; // <------ this is toggling panelSearch even though it shouldn't
1061       //searchSpace.visible = !inSearch;
1062       searchBar.visible = inSearch;
1063       history[historyIndex].inSearch = inSearch;
1064       view.pathColumn = inSearch;
1065       /*if(inSearch)
1066          searchThread.InitResults();*/
1067       if(inSearch && /*(*/searchInFileName.contents[0]/* || searchInFileContents.contents[0])*/)
1068          SearchStart();
1069    }
1070
1071    void ReadyTree()
1072    {
1073       if(tree.visible)
1074       {
1075          if(!treeInitialized)
1076          {
1077             tree.path = "/"; // this should be available as a parameter
1078             treeInitialized = true;
1079          }
1080          tree.SelectLocation(view.path);
1081       }
1082    }
1083
1084    void Refresh()
1085    {
1086       if(searchBar.visible)
1087          SearchStart();
1088       else
1089       {
1090          if(tree.visible)
1091             tree.Refresh();
1092          view.Refresh();
1093       }
1094    }
1095
1096    //void NewFile()
1097    bool FileSystemBox::NewFile(MenuItem selection, Modifiers mods)
1098    {
1099       if(master._class == class(ExplorerWindow))
1100       {
1101          ExplorerWindow ew = (ExplorerWindow)master;
1102          if(CreateNewFileDialog { /*master = */ew/*, parent = parent*/, currentDirectory = selection ? ew.view.selection.node.path : ew.view.path }.Modal() == ok )
1103             ew.Refresh();
1104       }
1105    }
1106
1107    //void NewFolder()
1108    bool FileSystemBox::NewFolder(MenuItem selection, Modifiers mods)
1109    {
1110       if(master._class == class(ExplorerWindow))
1111       {
1112          ExplorerWindow ew = (ExplorerWindow)master;
1113          if(CreateDirectoryDialog { /*master = */ew/*, parent = parent*/, currentDirectory = selection ? ew.view.selection.node.path : ew.view.path }.Modal() == ok )
1114             ew.Refresh();
1115       }
1116    }
1117
1118    //void GoTo(char * location/*, bool viewIsAtLocation, bool treeIsAtLocation*/)
1119    property char * location
1120    {
1121       set
1122       {
1123          HistoryItem item = null;
1124          if(!history.count || fstrcmp(history[historyIndex].path, value))
1125          {
1126             int c;
1127             for(c = 0; c < history.count; c++)
1128                if(!fstrcmp(history[c].path, value))
1129                   break;
1130             if(c == history.count)
1131             {
1132                item = { path = CopyString(value) };
1133                if(history.count)
1134                {
1135                   while(historyIndex < history.count-1)
1136                   {
1137                      delete history[history.count-1].path;
1138                      history.count--;
1139                   }
1140                }
1141                history.Add(item);
1142                historyIndex = history.count-1;
1143             }
1144             else
1145                historyIndex = c;
1146          }
1147          GoToHistoryIndex(/*viewIsAtLocation, treeIsAtLocation, */item != null);
1148       }
1149       get { return view.path; }
1150    }
1151
1152    property Array<String> comparedLocations
1153    {
1154       set
1155       {
1156          // dd
1157          view.comparedPaths = value;
1158       }
1159       get
1160       {
1161          return view.comparedPaths;
1162       }
1163    }
1164
1165    void GoToHistoryIndex(/*bool viewIsAtLocation, bool treeIsAtLocation, */bool updateHistoryItem)
1166    {
1167       bool viewIsAtLocation;
1168       bool treeIsAtLocation;
1169       HistoryItem item = history[historyIndex];
1170
1171       goBack.disabled = historyIndex == 0;
1172       goForward.disabled = historyIndex == history.count-1;
1173       goUp.disabled = !fstrcmp(item.path, "/");
1174
1175       viewIsAtLocation = !fstrcmp(item.path, tree.path);
1176       treeIsAtLocation = !fstrcmp(item.path, view.path);
1177
1178       if(!viewIsAtLocation)
1179       {
1180          if(item.inSearch != panelSearch.checked)
1181          {
1182             ToggleSearchMode(item.inSearch);
1183             if(item.inSearch)
1184                SearchStart();
1185          }
1186          if(!item.inSearch)
1187          /*{
1188             //SearchStart();
1189          }
1190          else*/
1191          {
1192             if(fstrcmp(view.path, item.path))
1193                view.path = item.path;
1194             item.holdRecordingSelection = true;
1195             view.SelectMultipleByPath(item.selection);
1196          }
1197       }
1198       if(tree.visible && !treeIsAtLocation)
1199          tree.SelectLocation(item.path);
1200
1201       if(updateHistoryItem)
1202          UpdateHistoryItem(view.selection);
1203    }
1204
1205    void UpdateHistoryItem(FileSystemBoxSelection selection)
1206    {
1207       HistoryItem item = history[historyIndex];
1208
1209       if(!item.holdRecordingSelection)
1210       {
1211          if(selection.node || (selection.nodes && selection.nodes.count))
1212          {
1213             item.selection.Free();
1214             if(selection.nodes.count)
1215             {
1216                for(node : selection.nodes)
1217                   item.selection.Add(CopyString(node.path));
1218             }
1219             else if(selection.node)
1220                item.selection.Add(CopyString(selection.node.path));
1221          }
1222       }
1223       else
1224          item.holdRecordingSelection = false;
1225    }
1226
1227    void SearchStart()
1228    {
1229       SearchStop();
1230       searchThread.active = true;
1231
1232       searchThread.optionSubdirs = searchInSubDirs.checked == true;
1233       searchThread.optionTree = view.treeBranches; //(options.subdirs.checked && options.tree.checked);
1234       searchThread.optionBrowser = tree.visible; //(options.subdirs.checked && options.browser.checked);
1235 #ifndef __WIN32__
1236       searchThread.optionNameMatchCase = inFileNameMatchCase.checked;
1237 #else
1238       searchThread.optionNameMatchCase = false;
1239 #endif
1240       searchThread.optionNameMatchWord = inFileNameMatchWord.checked;
1241       searchThread.optionContentMatchCase = inFileContentMatchCase.checked;
1242       searchThread.optionContentMatchWord = inFileContentMatchWord.checked;
1243
1244       strcpy(searchThread.location, view.path);
1245       strcpy(searchThread.nameSearch, searchInFileName.contents);
1246       strcpy(searchThread.contentSearch, searchInFileContent.contents);
1247
1248       //actions.startStop.text = "Stop Search";
1249       //actions.clear.disabled = false;
1250       //view.results.Clear();
1251       //view.results.hasHeader = !searchThread.optionTree;
1252       //view.results.treeBranches = searchThread.optionTree;
1253       //view.browser.Clear();
1254       //ToggleBrowserDisplay(searchThread.optionBrowser);
1255
1256       //view.browser.text = "Browser";
1257       /*{
1258          char string[MAX_LOCATION + 2048];
1259          sprintf(string, "%s (Searching %s)", title, view.path);
1260          //PrintLn(string); //view.results.text = string;
1261          text = string;
1262       }*/
1263       searchThread.InitResults();
1264       searchThread.Create();
1265       searchStop.disabled = false;
1266       //Update(null);
1267    }
1268
1269    bool SearchStop()
1270    {
1271       if(searchThread.active)
1272       {
1273          searchThread.terminate = true;
1274          //searchStop.disabled = true;
1275          app.Unlock();
1276             searchThread.Wait();
1277          app.Lock();
1278          return true;
1279       }
1280       return false;
1281    }
1282
1283    /*ExplorerSearch search
1284    {
1285       deep, this;
1286       visible = false;
1287       tabCycle = true;
1288       size = Size { 624, 268 };
1289       anchor = Anchor { left = 0, top = 0, bottom = 0 };
1290    };
1291
1292    ExplorerViewSearch results;*/
1293
1294    /*Window viewHolder
1295    {
1296       parent = deep, master = this;
1297       tabCycle = true;
1298       anchor = Anchor { top = 0, bottom = 0, right = 0 };
1299    };*/
1300
1301    // Preview / Showcase
1302    /*PreviewArea previewArea
1303    {
1304       panels, this;
1305    };*/
1306
1307    //FlipStacker flipPanels { panels, spring = previous };
1308
1309    /*bool TreeNotifyBranchSelect(ExplorerTree tree, ExplorerFileBranch branch)
1310    {
1311       if(branch)
1312       {
1313          char path[MAX_LOCATION];
1314          branch.GetPath(path);
1315          toolBar.addressBar.contents = path;
1316          view.Load(branch);
1317       }
1318       return true;
1319    }*/
1320    
1321    /*bool ViewNotifyItemOpen(ExplorerView view, ExplorerFileItem item)
1322    {
1323       ExplorerFileBranch branch = tree.branch;
1324       if(item && branch)
1325       {
1326          if(item.type.isFolderType)
1327          {
1328             ExplorerFileBranch child;
1329             
1330             if(!branch.loaded || !branch.childrenLoaded)
1331                BranchLoad(branch, tree.tree);
1332
1333             for(child = branch.children.first; child; child = child.next)
1334                if(!strcmp(child.name, item.name))
1335                   break;
1336             
1337             if(child)
1338             {
1339                if(branch.row.collapsed)
1340                   child.row.collapsed = true;
1341                child.EnsureVisible(false);
1342                tree.Select(child);
1343             }
1344          }
1345          else
1346          {
1347             char path[MAX_LOCATION];
1348             branch.GetPath(path);
1349             PathCat(path, item.name);
1350             ShellOpen(path);
1351          }
1352       }
1353    }*/
1354
1355    /*void SwitchViews(ExplorerToolId viewId)
1356    {
1357       ExplorerFileBranch branch = tree.branch;
1358       view.Destroy(0);
1359       switch(viewId)
1360       {
1361          case viewList:     view = ExplorerViewList     { parent = viewHolder, master = this }; break;
1362          case viewDetails:  view = ExplorerViewDetails  { parent = viewHolder, master = this }; break;
1363          case viewIcons:    view = ExplorerViewIcons    { parent = viewHolder, master = this }; break;
1364          case viewCards:    view = ExplorerViewCards    { parent = viewHolder, master = this }; break;
1365          case viewShowcase: view = ExplorerViewShowcase { parent = viewHolder, master = this }; break;
1366       }
1367       view.tabCycle = true;
1368       view.previewPictures = toolBar.previewPictures.checked;
1369       view.anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
1370       view.NotifyItemOpen = ViewNotifyItemOpen;
1371       view.Create();
1372       view.Load(branch);
1373       lastViewId = viewId;
1374    }*/
1375
1376    /*void SearchLocation(char * location)
1377    {
1378       location = location;//GoTo(location);
1379       search.location.editBox.contents = location;
1380    }*/
1381
1382    bool OnPostCreate()
1383    {
1384       //userMode = true;
1385       addressBar.path = view.path;
1386       ReadyTree();
1387       return true;
1388    }
1389
1390    bool OnClose(bool parentClosing)
1391    {
1392       SearchStop();
1393       return true;
1394    }
1395
1396    /*ExplorerWindow()
1397    {
1398       userMode = false;
1399
1400       treeSplit = 300;
1401       searchSplit = 200;
1402
1403       view = ExplorerViewList
1404       {
1405          parent = viewHolder, master = this;
1406          tabCycle = true;
1407          previewPictures = toolBar.previewPictures.checked;
1408          anchor = Anchor { left = 0, top = 0, bottom = 0, right = 0 };
1409          NotifyItemOpen = ViewNotifyItemOpen;
1410       };
1411       lastViewId = viewList;
1412       
1413       tree.Load();
1414       view.Load(tree.root);
1415    }*/
1416
1417    /*void InitTree()
1418    {
1419    }*/
1420
1421    /*void InitSearch()
1422    {
1423    }*/
1424 }
1425
1426 //class TreeFileSystemBox : FileSystemBox { }
1427
1428 class HistoryItem
1429 {
1430    char * path;
1431    bool holdRecordingSelection;
1432    bool inSearch;
1433    Array<String> selection { };
1434
1435    ~HistoryItem()
1436    {
1437       delete path;
1438    }
1439 }