sdk: Fixed many warnings and related problems
[sdk] / ide / src / project / ProjectView.ec
index a4e4f1a..2d9f2a4 100644 (file)
@@ -7,7 +7,7 @@ class ImportFolderFSI : NormalFileSystemIterator
    ProjectView projectView;
    Array<ProjectNode> stack { };
 
-   bool OnFolder(char * folderPath)
+   bool OnFolder(const char * folderPath)
    {
       char name[MAX_LOCATION];
       ProjectNode parentNode = stack.lastIterator.data;
@@ -20,70 +20,54 @@ class ImportFolderFSI : NormalFileSystemIterator
       return true;
    }
 
-   void OutFolder(char * folderPath, bool isRoot)
+   void OutFolder(const char * folderPath, bool isRoot)
    {
       stack.lastIterator.Remove(); //stack.Remove();
    }
 
-   bool OnFile(char * filePath)
+   bool OnFile(const char * filePath)
    {
       ProjectNode parentNode = stack.lastIterator.data;
-      projectView.AddFile(parentNode, filePath, parentNode.isInResources, false);
+      if(!projectView.AddFile(parentNode, filePath, parentNode.isInResources, false))
+      {
+         char * msg = PrintString($"This file can't be imported due to a conflict.\n\n", filePath,
+               "\n\nThis occurs with identical file paths and with conflicting file names.\n");
+         MessageBox { master = ide, type = ok, text = "Import File Conflict", contents = msg }.Modal();
+         delete msg;
+      }
       return true;
    }
 }
 
-static FileFilter fileFilters[] =
-{
-   { 
-      "EC/C/C++ Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)",
-      "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx"
-   },
-   {
-      "EC/C/C++ Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)",
-      "ec, eh, c, cpp, cc, cxx"
-   },
-   {
-      "Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)",
-      "eh, h, hpp, hh, hxx"
-   },
-   { "All files", null }
-};
-
-static FileFilter resourceFilters[] =
-{
-   {
-      "Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png,*.gif)",
-      "jpg, jpeg, bmp, pcx, png, gif"
-   },
-   {
-      "3D Studio Model Files (*.3ds)",
-      "3ds"
-   },
-   { "All files", null }
-};
-
-static FileType fileTypes[] =
-{
-   { "Based on extension", null },
-   { "Text",               "txt" },
-   { "Image",              "jpg" },
-   { "3D Studio Model",    "3ds" }
-};
-
-static FileFilter projectFilters[] =
-{
-   { "Project Files (*.epj)", ProjectExtension },
-   { "Workspace Files (*.ews)", WorkspaceExtension }
-};
-
-static FileType projectTypes[] =
-{
-   { "ECERE Project", ProjectExtension },
-   { "ECERE Workspace", WorkspaceExtension }
-};
-
-static char * iconNames[] = 
+static Array<FileFilter> fileFilters
+{ [
+   { $"eC/C/C++ Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
+   { $"eC/C/C++ Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, eh, c, cpp, cc, cxx" },
+   { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
+   { $"All files", null }
+] };
+
+static Array<FileFilter> resourceFilters
+{ [
+   { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
+   { $"3D Studio Model Files (*.3ds)", "3ds" },
+   { $"Translations (*.mo)", "mo" },
+   { $"All files", null }
+] };
+
+static Array<FileFilter> projectFilters
+{ [
+   { $"Project Files (*.epj)", ProjectExtension },
+   { $"Workspace Files (*.ews)", WorkspaceExtension }
+] };
+
+static Array<FileType> projectTypes
+{ [
+   { $"Ecere IDE Project", ProjectExtension },
+   { $"Ecere IDE Workspace", WorkspaceExtension }
+] };
+
+static const char * iconNames[] =
 {
    "<:ecere>mimeTypes/file.png",                   /*genFile*/
    "<:ecere>mimeTypes/textEcereWorkspace.png",     /*ewsFile*/
@@ -92,6 +76,7 @@ static char * iconNames[] =
    "<:ecere>status/folderOpen.png",                /*openFolder*/
    "<:ecere>mimeTypes/textEcereSource.png",        /*ecFile*/
    "<:ecere>mimeTypes/textEcereHeader.png",        /*ehFile*/
+   "<:ecere>mimeTypes/textCSource.png",            /*sFile*/ // TODO: change sFile icon to differentiate from cFile icon
    "<:ecere>mimeTypes/textCSource.png",            /*cFile*/
    "<:ecere>mimeTypes/textCHeader.png",            /*hFile*/
    "<:ecere>mimeTypes/textC++Source.png",          /*cppFile*/
@@ -103,12 +88,14 @@ static char * iconNames[] =
    "<:ecere>mimeTypes/package.png",                /*archiveFile*/
    "<:ecere>mimeTypes/packageSoftware.png",        /*packageFile*/
    "<:ecere>mimeTypes/packageOpticalDisc.png",     /*opticalMediaImageFile*/
-   "<:ecere>mimeTypes/file.png"                    /*mFile*/ //TODO: create icon for mfile
+   "<:ecere>mimeTypes/file.png",                   /*mFile*/ //TODO: create icon for .m file
+   "<:ecere>mimeTypes/file.png"                    /*mmFile*/ //TODO: create icon for .mm file
 };
 
 enum PrepareMakefileMethod { normal, force, forceExists };
 
-enum BuildType { build, rebuild, relink, run, start, restart };
+enum CleanType { clean, realClean, cleanTarget };
+enum BuildType { build, rebuild, relink, run, start, restart, clean, install };
 enum BuildState
 {
    none, buildingMainProject, buildingSecondaryProject, compilingFile;
@@ -129,10 +116,10 @@ class ProjectView : Window
    size = { 300 };
    anchor = Anchor { left = 0, top = 0, bottom = 0 };
    menu = Menu { };
-   
+
    //hasMinimize = true;
    saveDialog = projectFileDialog;
-   
+
    DataRow resourceRow;
    BuildState buildInProgress;
    BitmapResource icons[NodeIcons];
@@ -158,60 +145,46 @@ class ProjectView : Window
             resourceFileDialog.currentDirectory = workspace.workspaceDir;
             for(prj : workspace.projects)
                AddNode(prj.topNode, null);
-            ide.statusBar.text = "Generating Makefile & Dependencies...";
+            ide.statusBar.text = $"Generating Makefile & Dependencies...";
             app.UpdateDisplay();
             for(prj : workspace.projects)
                prj.ModifiedAllConfigs(true, false, false, false);
-            ide.statusBar.text = "Initializing Debugger"; app.UpdateDisplay();
+            ide.statusBar.text = $"Initializing Debugger"; app.UpdateDisplay();
             ide.statusBar.text = null;
             app.UpdateDisplay();
          }
       }
       get { return workspace; }
    }
-   
-   /*property Project project
-   {
-      set
-      {
-         if(project)
-         {
-            DeleteNode(project.topNode);
-            project.Free();
-         }
-         project = value;
-         if(project)
-         {
-            AddNode(project.topNode, null);
-            fileDialog.currentDirectory = project.topNode.path;
-            resourceFileDialog.currentDirectory = project.topNode.path;
-
-            // Make sure this is done already...
-            {
-               char filePath[MAX_LOCATION];
-               strcpy(filePath, project.topNode.path);
-               PathCat(filePath, project.topNode.name);
-               strcat(filePath, ".epj");
-               fileName = filePath;
-            }
-
-            ide.statusBar.text = "Generating Makefile & Dependencies...";
-            app.UpdateDisplay();
-            // REDJ set makefile generation flag so generation occurs only when compiling instead of generating on the spot
-            project.config.makingModified = true;
-            ide.statusBar.text = "Initializing Debugger";
-            ide.statusBar.text = null;
-            app.UpdateDisplay();
-         }
-      }
-      get { return project; }
-   }*/
 
    bool drawingInProjectSettingsDialog;
    bool drawingInProjectSettingsDialogHeader;
    ProjectSettings projectSettingsDialog;
 
    bool stopBuild;
+   PopupMenu popupMenu;
+
+   ProjectView()
+   {
+      NodeIcons c;
+      for(c = 0; c < NodeIcons::enumSize; c++)
+      {
+         icons[c] = BitmapResource { iconNames[c], alphaBlend = true };
+         AddResource(icons[c]);
+      }
+      fileList.AddField(DataField { dataType = class(ProjectNode), freeData = false, userData = this });
+   }
+
+   ~ProjectView()
+   {
+      DebugStop();
+      ide.DestroyTemporaryProjectDir();
+      if(project)
+      {
+         workspace.Free();
+         delete workspace;
+      }
+   }
 
    ListBox fileList
    {
@@ -229,11 +202,11 @@ class ProjectView : Window
          if(!active) Update(null);
          return ListBox::OnActivate(active, previous, goOnWithActivation, direct);
       }
-      
+
       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
       {
-         OpenSelectedNodes();
-         return true;
+         // Prevent the double click from reactivating the project view (returns false if we opened something)
+         return !OpenSelectedNodes(mods.ctrl && mods.shift);
       }
 
       bool NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods)
@@ -241,111 +214,160 @@ class ProjectView : Window
          DataRow row = listBox.currentRow;
          if(row)
          {
+            bool showDebuggingMenuItems = mods.ctrl && mods.shift;
+            bool showInstallMenuItem = mods.ctrl && mods.shift;
             ProjectNode node = (ProjectNode)row.tag;
+#ifdef IDE_SHOW_INSTALL_MENU_BUTTON
+            showInstallMenuItem = true;
+#endif
             if(node.type == NodeTypes::project || node.type == resources || node.type == file || node.type == folder)
             {
-               bool buildMenuUnavailable = buildInProgress;
-               PopupMenu popupMenu;
-               Menu popupContent { };
-               
+               bool na = buildInProgress; // N/A - buildMenuUnavailable
+               Menu pop { };
+
                if(node.type == NodeTypes::project)
                {
-                  //if(node == ((Project)workspace.projects.first).topNode)
+                  MenuItem mi;
+                                                                                                                                             mi = ide.projectBuildItem;
+                  MenuItem { pop, $"Build"              , b, f7     , NotifySelect = ProjectBuild      , bitmap = mi.bitmap }.disabled = na; mi = ide.projectLinkItem;
+                  MenuItem { pop, $"Relink"             , l         , NotifySelect = ProjectLink       , bitmap = mi.bitmap }.disabled = na; mi = ide.projectRebuildItem;
+                  MenuItem { pop, $"Rebuild"            , r, shiftF7, NotifySelect = ProjectRebuild    , bitmap = mi.bitmap }.disabled = na; mi = ide.projectCleanTargetItem;
+                  MenuItem { pop, $"Clean Target"       , g         , NotifySelect = ProjectCleanTarget, bitmap = mi.bitmap }.disabled = na; mi = ide.projectCleanItem;
+                  MenuItem { pop, $"Clean"              , c         , NotifySelect = ProjectClean      , bitmap = mi.bitmap }.disabled = na; mi = ide.projectRealCleanItem;
+                  MenuItem { pop, $"Real Clean"                     , NotifySelect = ProjectRealClean  , bitmap = mi.bitmap }.disabled = na; mi = ide.projectRegenerateItem;
+                  MenuItem { pop, $"Regenerate Makefile", m         , NotifySelect = ProjectRegenerate , bitmap = mi.bitmap }.disabled = na;
+                  if(showInstallMenuItem)
+                  {
+                     mi = ide.projectInstallItem;
+                     MenuItem { pop, $"Install"            , t         , NotifySelect = ProjectInstall    , bitmap = mi.bitmap }.disabled = na;
+                  }
+                  if(showDebuggingMenuItems && node.ContainsFilesWithExtension("ec", node.project.config))
                   {
-                     MenuItem { popupContent, "Build", b, NotifySelect = ProjectBuild }.disabled = buildMenuUnavailable;
-                     MenuItem { popupContent, "Relink", l, NotifySelect = ProjectLink }.disabled = buildMenuUnavailable;
-                     MenuItem { popupContent, "Rebuild", r, NotifySelect = ProjectRebuild }.disabled = buildMenuUnavailable;
-                     MenuItem { popupContent, "Clean", c, NotifySelect = ProjectClean }.disabled = buildMenuUnavailable;
-                     MenuItem { popupContent, "Regenerate Makefile", m, NotifySelect = ProjectRegenerate }.disabled = buildMenuUnavailable;
-                     MenuDivider { popupContent };
+                     MenuDivider { pop };
+                     MenuItem { pop, $"Debug Generate Symbols", l, NotifySelect = FileDebugGenerateSymbols }.disabled = na;
+                     MenuItem { pop, $"Debug Precompile", l, NotifySelect = FileDebugPrecompile }.disabled = na;
+                     MenuItem { pop, $"Debug Compile", l, NotifySelect = FileDebugCompile }.disabled = na;
                   }
-                  MenuItem { popupContent, "New File...", l, Key { l, ctrl = true }, NotifySelect = ProjectNewFile };
-                  MenuItem { popupContent, "New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
-                  MenuItem { popupContent, "Import Folder...", i, NotifySelect = ProjectImportFolder };
-                  MenuItem { popupContent, "Add Files to Project...", f, NotifySelect = ProjectAddFiles };
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Add New Form...", o, NotifySelect = ProjectAddNewForm };
-                  // MenuItem { popupContent, "Add New Behavior Graph...", g, NotifySelect = ProjectAddNewGraph };
-                  MenuDivider { popupContent };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"New File...", l, Key { l, ctrl = true }, NotifySelect = ProjectNewFile };
+                  MenuItem { pop, $"New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
+                  MenuItem { pop, $"Import Folder...", i, NotifySelect = ProjectImportFolder };
+                  MenuItem { pop, $"Add Files to Project...", f, NotifySelect = ProjectAddFiles };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Add New Form...", o, NotifySelect = ProjectAddNewForm };
+                  // MenuItem { pop, "Add New Behavior Graph...", g, NotifySelect = ProjectAddNewGraph };
+                  MenuDivider { pop };
                   if(node != ((Project)workspace.projects.first).topNode)
                   {
-                     MenuItem { popupContent, "Remove project from workspace", r, NotifySelect = ProjectRemove }.disabled = buildMenuUnavailable;
-                     MenuDivider { popupContent };
+                     MenuItem { pop, $"Remove project from workspace", r, NotifySelect = ProjectRemove }.disabled = na;
+                     MenuDivider { pop };
                   }
-                  MenuItem { popupContent, "Active Configuration...", s, Key { f5, alt = true } , NotifySelect = MenuConfig };
-                  MenuItem { popupContent, "Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Browse Folder", w, NotifySelect = MenuBrowseFolder };
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Save", v, Key { s, ctrl = true }, NotifySelect = ProjectSave }.disabled = !node.modified;
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Properties...", p, Key { enter, alt = true }, NotifySelect = FileProperties };
+                  MenuItem { pop, $"Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Browse Folder", w, NotifySelect = MenuBrowseFolder };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Save", v, Key { s, ctrl = true }, NotifySelect = ProjectSave }.disabled = !node.modified;
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Properties...", p, Key { enter, alt = true }, NotifySelect = FileProperties };
                }
                else if(node.type == resources)
                {
-                  MenuItem { popupContent, "New File...", l, Key { l, ctrl = true }, NotifySelect = ProjectNewFile };
-                  MenuItem { popupContent, "New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
-                  MenuItem { popupContent, "Add Resources to Project...", f, NotifySelect = ResourcesAddFiles };
-                  MenuItem { popupContent, "Browse Folder", w, NotifySelect = MenuBrowseFolder };
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
-                  MenuItem { popupContent, "Properties...", p, Key { enter, alt = true }, NotifySelect = FileProperties };
+                  MenuItem { pop, $"New File...", l, Key { l, ctrl = true }, NotifySelect = ProjectNewFile };
+                  MenuItem { pop, $"New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
+                  MenuItem { pop, $"Import Folder...", i, NotifySelect = ProjectImportFolder };
+                  MenuItem { pop, $"Add Resources to Project...", f, NotifySelect = ResourcesAddFiles };
+                  MenuItem { pop, $"Browse Folder", w, NotifySelect = MenuBrowseFolder };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
+                  MenuItem { pop, $"Properties...", p, Key { enter, alt = true }, NotifySelect = FileProperties };
                }
                else if(node.type == file)
                {
-                  MenuItem { popupContent, "Open", o, NotifySelect = FileOpenFile };
-                  MenuItem { popupContent, "Compile", c, Key { f7, ctrl = true}, NotifySelect = FileCompile }.disabled = buildMenuUnavailable;
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Remove", r, NotifySelect = FileRemoveFile };
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Browse Folder", w, NotifySelect = MenuBrowseFolder };
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
-                  MenuItem { popupContent, "Properties..", p, Key { enter, alt = true }, NotifySelect = FileProperties };
+                  MenuItem { pop, $"Open", o, NotifySelect = FileOpenFile };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Clean", l, NotifySelect = FileClean, bitmap = ide.projectCleanItem.bitmap }.disabled = na;
+                  MenuItem { pop, $"Compile", c, Key { f7, ctrl = true}, NotifySelect = FileCompile, bitmap = ide.projectBuildItem.bitmap }.disabled = na;
+                  if(showDebuggingMenuItems)
+                  {
+                     char extension[MAX_EXTENSION];
+                     GetExtension(node.name, extension);
+                     if(!strcmpi(extension, "ec"))
+                     {
+                        MenuDivider { pop };
+                        MenuItem { pop, $"Debug Precompile", l, NotifySelect = FileDebugPrecompile }.disabled = na;
+                        MenuItem { pop, $"Debug Compile", l, NotifySelect = FileDebugCompile }.disabled = na;
+                     }
+                  }
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Remove", r, NotifySelect = FileRemoveFile };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Browse Folder", w, NotifySelect = MenuBrowseFolder };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
+                  MenuItem { pop, $"Properties..", p, Key { enter, alt = true }, NotifySelect = FileProperties };
                }
                else if(node.type == folder)
                {
                   bool isInResources = node.isInResources;
 
-                  MenuItem { popupContent, "New File...", l, Key { l, ctrl = true }, NotifySelect = ProjectNewFile };
-                  MenuItem { popupContent, "New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
-                  MenuItem { popupContent, "Import Folder...", i, NotifySelect = ProjectImportFolder };
+                  MenuItem { pop, $"New File...", l, Key { l, ctrl = true }, NotifySelect = ProjectNewFile };
+                  MenuItem { pop, $"New Folder...", n, Key { f, ctrl = true }, NotifySelect = ProjectNewFolder };
+                  MenuItem { pop, $"Import Folder...", i, NotifySelect = ProjectImportFolder };
                   if(isInResources)
                   {
-                     MenuItem { popupContent, "Add Resources to Folder...", f, NotifySelect = ResourcesAddFiles };
+                     MenuItem { pop, $"Add Resources to Folder...", f, NotifySelect = ResourcesAddFiles };
                   }
                   else
                   {
-                     MenuItem { popupContent, "Add Files to Folder...", f, NotifySelect = ProjectAddFiles };
+                     MenuItem { pop, $"Add Files to Folder...", f, NotifySelect = ProjectAddFiles };
                   }
                   if(!isInResources)
                   {
-                     MenuDivider { popupContent };
-                     MenuItem { popupContent, "Add New Form...", o, NotifySelect = ProjectAddNewForm };
-                     MenuItem { popupContent, "Add New Behavior Graph...", g, NotifySelect = ProjectAddNewGraph };
+                     MenuDivider { pop };
+                     MenuItem { pop, $"Add New Form...", o, NotifySelect = ProjectAddNewForm };
+                     // MenuItem { pop, $"Add New Behavior Graph...", g, NotifySelect = ProjectAddNewGraph };
                   }
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Remove", r, NotifySelect = FileRemoveFile };
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Browse Folder", w, NotifySelect = MenuBrowseFolder };
-                  MenuDivider { popupContent };
-                  MenuItem { popupContent, "Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
-                  MenuItem { popupContent, "Properties...", p, Key { enter, alt = true }, NotifySelect = FileProperties };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Clean", l, NotifySelect = FileClean, bitmap = ide.projectCleanItem.bitmap }.disabled = na;
+                  MenuItem { pop, $"Compile", c, Key { f7, ctrl = true}, NotifySelect = FileCompile, bitmap = ide.projectBuildItem.bitmap }.disabled = na;
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Remove", r, NotifySelect = FileRemoveFile };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Browse Folder", w, NotifySelect = MenuBrowseFolder };
+                  MenuDivider { pop };
+                  MenuItem { pop, $"Settings...", s, Key { f7, alt = true } , NotifySelect = MenuSettings };
+                  MenuItem { pop, $"Properties...", p, Key { enter, alt = true }, NotifySelect = FileProperties };
                }
 
-               popupMenu = 
+               popupMenu =
                {
-                  master = this, menu = popupContent;
+                  master = this, menu = pop;
                   position = {
-                     x + clientStart.x + absPosition.x - app.desktop.position.x, 
+                     x + clientStart.x + absPosition.x - app.desktop.position.x,
                      y + clientStart.y + absPosition.y - app.desktop.position.y };
+
+                  void NotifyDestroyed(Window window, DialogResult result)
+                  {
+                     popupMenu = null;
+                  }
                };
                popupMenu.Create();
+               ide.AdjustPopupBuildMenus();
             }
          }
          return true;
       }
 
+      bool NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch)
+      {
+         if(key == altUp || key == altDown)
+         {
+            SelectNextProject(key == altUp);
+            return false;
+         }
+         return true;
+      }
+
       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
       {
          if(row)
@@ -355,7 +377,7 @@ class ProjectView : Window
             {
                case altEnter: case Key { keyPadEnter, alt = true }:
                {
-                  NodeProperties { parent = parent, master = this, 
+                  NodeProperties { parent = parent, master = this,
                      position = { position.x + 100, position.y + 100 }, node = node }.Create();
                   return false;
                }
@@ -404,7 +426,9 @@ class ProjectView : Window
                   }
                   break;
                }
-               case Key { space, shift = true }:
+               case Key { space, false, true }:
+               case Key { space, true, true }:
+               case Key { space, true }:
                case space:
                {
                   if(node.type == NodeTypes::project)
@@ -418,7 +442,7 @@ class ProjectView : Window
                            break;
                         }
                      }
-                     prj.RotateActiveConfig(!key.shift);
+                     prj.RotateActiveConfig(!key.shift, key.ctrl);
                      if(prj == project)
                         ide.AdjustMenus();
                      return false;
@@ -429,9 +453,11 @@ class ProjectView : Window
          }
          switch(key)
          {
-            case enter: case keyPadEnter:  OpenSelectedNodes();   break;
-            case del:                      RemoveSelectedNodes(); break;
-            case escape:                      
+            case Key { enter, true, true }:        OpenSelectedNodes(true);   break;
+            case Key { keyPadEnter, true, true }:  OpenSelectedNodes(true);   break;
+            case enter: case keyPadEnter:          OpenSelectedNodes(false);  break;
+            case del:                              RemoveSelectedNodes();     break;
+            case escape:
             {
                Window activeClient = ide.activeClient;
                if(activeClient)
@@ -453,25 +479,23 @@ class ProjectView : Window
       }
    };
 
-   FileDialog importFileDialog { autoCreate = false, type = selectDir, text = "Import Folder" };
+   FileDialog importFileDialog { autoCreate = false, type = selectDir, text = $"Import Folder" };
    FileDialog projectFileDialog
    {
-      autoCreate = false, filters = projectFilters, sizeFilters = sizeof(projectFilters);
-      types = projectTypes, sizeTypes = sizeof(projectTypes);
+      autoCreate = false, filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
+      types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType);
    };
    FileDialog fileDialog
    {
-      autoCreate = false, mayNotExist = true, filters = fileFilters, sizeFilters = sizeof(fileFilters);
-      types = fileTypes, sizeTypes = sizeof(fileTypes);
+      autoCreate = false, mayNotExist = true, filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
    };
    FileDialog resourceFileDialog
    {
-      autoCreate = false, mayNotExist = true, filters = resourceFilters, sizeFilters = sizeof(resourceFilters);
-      types = fileTypes, sizeTypes = sizeof(fileTypes);
+      autoCreate = false, mayNotExist = true, filters = resourceFilters.array, sizeFilters = resourceFilters.count * sizeof(FileFilter);
    };
 
-   Menu fileMenu { menu, "File", f };
-   MenuItem { fileMenu, "Save", s, Key { s, ctrl = true }, NotifySelect = MenuFileSave };
+   Menu fileMenu { menu, $"File", f };
+   MenuItem { fileMenu, $"Save", s, Key { s, ctrl = true }, NotifySelect = MenuFileSave };
    // MenuItem { fileMenu, "Save As...", a, NotifySelect = MenuFileSaveAs };
 
    bool OnClose(bool parentClosing)
@@ -483,6 +507,35 @@ class ProjectView : Window
       }
       if(buildInProgress)
          return false;
+
+      if(modifiedDocument)
+      {
+         DialogResult dialogRes;
+         char msg[2048];
+         bool first = true;
+         strcpy(msg, $"You have modified projects.\nSave changes to ");
+         for(p : ide.workspace.projects)
+         {
+            if(p.topNode.modified)
+            {
+               if(!first) strcat(msg, ", ");
+               strcat(msg, p.name);
+               first = false;
+            }
+         }
+         strcat(msg, "?");
+
+         dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = msg }.Modal();
+
+         if(dialogRes == yes)
+         {
+            // TOFIX: Precomp error if brackets are taken out
+            return (DialogResult)MenuFileSave(null, 0) != cancel;
+         }
+         else if(dialogRes == cancel)
+            return false;
+         modifiedDocument = false;
+      }
       return true;
    }
 
@@ -498,17 +551,19 @@ class ProjectView : Window
       ide.watchesView.Clear();
       ide.threadsView.Clear();
       ide.breakpointsView.Clear();
-      ide.outputView.ShowClearSelectTab(find); // why this? 
+      ide.outputView.ShowClearSelectTab(find); // why this?
    }
 
-   bool OnSaveFile(char * fileName)
+   bool OnSaveFile(const char * fileName)
    {
       for(prj : ide.workspace.projects)
       {
-         if(prj.topNode.modified && prj.Save(prj.filePath))
+         if(prj.topNode.modified)
          {
-            // ProjectUpdateMakefileForAllConfigs(prj, true, true);
-            prj.topNode.modified = false;
+            prj.StopMonitoring();
+            if(prj.Save(prj.filePath))
+               prj.topNode.modified = false;
+            prj.StartMonitoring();
          }
       }
       modifiedDocument = false;
@@ -516,584 +571,660 @@ class ProjectView : Window
       return true;
    }
 
-   bool IsModuleInProject(char * filePath)
+   bool IsModuleInProject(const char * filePath)
    {
       char moduleName[MAX_FILENAME]; //, modulePath[MAX_LOCATION];
       GetLastDirectory(filePath, moduleName);
       return project.topNode.Find(moduleName, false) != null;
    }
 
-   bool GetRelativePath(char * filePath, char * relativePath)
+   ProjectNode GetNodeForCompilationFromWindow(Window document, bool nonExcludedFirst, bool * isExcluded, bool * isCObject)
    {
-      /*ProjectNode node;
-      char moduleName[MAX_FILENAME]; //, modulePath[MAX_LOCATION];
-      GetLastDirectory(filePath, moduleName);
-      
-      // try with workspace dir first?
-      if((node = project.topNode.Find(moduleName, false)))
+      ProjectNode node = null;
+      if(nonExcludedFirst)
+         node = GetNodeFromWindow(document, null, false, false, isExcluded);
+      if(!node)
+         node = GetNodeFromWindow(document, null, true, false, isExcluded);
+      if(!node && nonExcludedFirst)
       {
-         strcpy(relativePath, node.path);
-         PathCatSlash(relativePath, node.name);
-         return true;
+         node = GetNodeFromWindow(document, null, false, true, isExcluded);
+         if(isCObject && node) *isCObject = true;
+      }
+      if(!node)
+      {
+         node = GetNodeFromWindow(document, null, true, true, isExcluded);
+         if(isCObject && node) *isCObject = true;
       }
-      // WARNING: On failure, relative path is uninitialized
-      return false;   */
-      return project.GetRelativePath(filePath, relativePath);
+      return node;
    }
 
-   ProjectNode GetNodeFromWindow(Window document, Project project)
+   ProjectNode GetNodeFromWindow(Window document, Project project, bool allNodes, bool isCObject, bool * isNodeExcluded)
    {
+      ProjectNode node = null;
       if(document.fileName)
       {
+         bool excluded;
          char winFileName[MAX_LOCATION];
          char * documentFileName = GetSlashPathBuffer(winFileName, document.fileName);
-         for(p : ide.workspace.projects)
+         Project prj;
+         ProjectNode n;
+         if(isCObject)
          {
-            Project prj = project ? project : p;
-            ProjectNode node;
-            char moduleName[MAX_FILENAME], modulePath[MAX_LOCATION];
-            GetLastDirectory(document.fileName, moduleName);
-
-            if((node = prj.topNode.Find(moduleName, false)))
+            char name[MAX_FILENAME];
+            GetLastDirectory(documentFileName, name);
+            ChangeExtension(name, "ec", name);
+            for(p : ide.workspace.projects)
+            {
+               prj = project ? project : p;
+               if((n = prj.topNode.Find(name, false)))
+               {
+                  if(allNodes || !(excluded = n.GetIsExcluded(prj.config)))
+                  {
+                     node = n;
+                     break;
+                  }
+               }
+               if(project) break;
+            }
+         }
+         else
+         {
+            for(p : ide.workspace.projects)
             {
-               strcpy(modulePath, prj.topNode.path);
-               PathCatSlash(modulePath, node.path);
-               PathCatSlash(modulePath, node.name);
-               if(!fstrcmp(documentFileName, modulePath))
+               prj = project ? project : p;
+               if((n = prj.topNode.FindByFullPath(documentFileName, false)))
                {
-                  return node;
+                  if(allNodes || !(excluded = n.GetIsExcluded(prj.config)))
+                  {
+                     node = n;
+                     break;
+                  }
                }
+               if(project) break;
             }
-            if(project) break;
          }
+         if(node && isNodeExcluded)
+            *isNodeExcluded = excluded;
       }
-      return null;
+      return node;
    }
 
-   void Compile(ProjectNode node)
+   //                          ((( UTILITY FUNCTIONS )))
+   //
+   //  ************************************************************************
+   //  *** These methods below are part of a sequence of events, and as     ***
+   //  *** such they must be passed the current compiler and project config ***
+   //  ************************************************************************
+   bool DisplayCompiler(CompilerConfig compiler, bool cleanLog)
    {
-      char fileName[MAX_LOCATION];
-      char extension[MAX_EXTENSION];
-      Window document;
-      Project prj = node.project;
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
-      DirExpression objDir = prj.objDir;
-
-      strcpy(fileName, prj.topNode.path);
-      PathCatSlash(fileName, objDir.dir);
-      PathCatSlash(fileName, node.name);
-      StripExtension(fileName);
-      strcat(fileName, ".o");
-      if(FileExists(fileName))
-         DeleteFile(fileName);
-
-      GetExtension(node.name, extension);
-      if(!strcmp(extension, "ec"))
-      {
-         // Delete generated C file
-         strcpy(fileName, prj.topNode.path);
-         PathCat(fileName, objDir.dir);
-         PathCat(fileName, node.name);
-         StripExtension(fileName);
-         strcat(fileName, ".c");
-         if(FileExists(fileName))
-            DeleteFile(fileName);
-
-         // Delete symbol file
-         strcpy(fileName, prj.topNode.path);
-         PathCat(fileName, node.path);
-         PathCat(fileName, node.name);
-         StripExtension(fileName);
-         strcat(fileName, ".sym");
-         if(FileExists(fileName))
-            DeleteFile(fileName);
-      }
+      ide.outputView.buildBox.Logf($"%s Compiler\n", compiler ? compiler.name : $"{problem with compiler selection}");
+      return true;
+   }
 
-      stopBuild = false;
+   bool ProjectPrepareForToolchain(Project project, PrepareMakefileMethod method, bool cleanLog, bool displayCompiler,
+      CompilerConfig compiler, ProjectConfig config)
+   {
+      ShowOutputBuildLog(cleanLog);
 
-      // Check if we have to save
-      strcpy(fileName, prj.topNode.path);
-      PathCatSlash(fileName, node.path);
-      PathCatSlash(fileName, node.name);
-      for(document = ide.firstChild; document; document = document.next)
+      if(displayCompiler)
+         DisplayCompiler(compiler, false);
+
+      ProjectPrepareCompiler(project, compiler, false);
+      ProjectPrepareMakefile(project, method, compiler, config);
+      return true;
+   }
+
+   bool ProjectPrepareCompiler(Project project, CompilerConfig compiler, bool silent)
+   {
+      if((!project.GenerateCrossPlatformMk(app.includeFile) ||
+            !project.GenerateCompilerCf(compiler, project.topNode.ContainsFilesWithExtension("ec", project.config))) && !silent)
+         ide.outputView.buildBox.Logf($"Error generating compiler configuration (Is the project/config directory writable?)\n");
+      return true;
+   }
+
+   // Note: Compiler is only passed in to for VisualStudio support
+   bool ProjectPrepareMakefile(Project project, PrepareMakefileMethod method, CompilerConfig compiler, ProjectConfig config)
+   {
+      if(compiler.type.isVC)
       {
-         if(document.modifiedDocument)
+         // I'm guessing we'll want to support generating VS files on Linux as well...
+         ide.statusBar.text = $"Generating Visual Studio Solution...";
+         app.UpdateDisplay();
+         //GenerateVSSolutionFile(project, compiler);
+         ide.statusBar.text = $"Generating Visual Studio Project...";
+         app.UpdateDisplay();
+         //GenerateVCProjectFile(project, compiler, bitDepth);
+         ide.statusBar.text = null;
+         app.UpdateDisplay();
+         return true;
+      }
+      else
+      {
+         char makefilePath[MAX_LOCATION];
+         char makefileName[MAX_LOCATION];
+         bool exists;
+         LogBox logBox = ide.outputView.buildBox;
+
+         strcpy(makefilePath, project.topNode.path);
+         project.CatMakeFileName(makefileName, config);
+         PathCatSlash(makefilePath, makefileName);
+
+         exists = FileExists(makefilePath);
+         if(method == force ||
+           (method == forceExists && exists) ||
+           (method == normal && (!exists || (config && config.makingModified))))
          {
-            char documentFileName[MAX_LOCATION];
-            if(!fstrcmp(GetSlashPathBuffer(documentFileName, document.fileName), fileName))
-               if(!document.MenuFileSave(null, 0))
-                  return;
+            const char * reason;
+            const char * action;
+            ide.statusBar.text = $"Generating Makefile & Dependencies..."; // Dependencies?
+            app.UpdateDisplay();
+
+            if((method == normal && !exists) || (method == force && !exists))
+               action = $"Generating ";
+            else if(method == force)
+               action = $"Regenerating ";
+            else if(method == normal || method == forceExists)
+               action = $"Updating ";
+            else
+               action = "";
+            if(!exists)
+               reason = $"Makefile doesn't exist. ";
+            else if(project.topNode.modified)
+               reason = $"Project has been modified. ";
+            else
+               reason = "";
+
+            //logBox.Logf("%s\n", makefileName);
+            logBox.Logf($"%s - %s%smakefile for %s config...\n", makefileName, reason, action, GetConfigName(config));
+
+            if(!project.GenerateMakefile(null, false, null, config))
+               ide.outputView.buildBox.Logf($"Error generating makefile (Is the project directory writable?)\n");
+
+            ide.statusBar.text = null;
+            app.UpdateDisplay();
+            return true;
          }
       }
+      return false;
+   }
 
-      if(ProjectPrepareForToolchain(prj, normal, true, true))
+   bool BuildInterrim(Project prj, BuildType buildType, CompilerConfig compiler, ProjectConfig config, int bitDepth, bool justPrint)
+   {
+      if(ProjectPrepareForToolchain(prj, normal, true, true, compiler, config))
       {
-         if(!node.isExcluded)
-         {
-            buildInProgress = compilingFile;
-            ide.AdjustBuildMenus();
+         ide.outputView.buildBox.Logf($"Building project %s using the %s configuration...\n", prj.name, GetConfigName(config));
+         return Build(prj, buildType, compiler, config, bitDepth, justPrint);
+      }
+      return false;
+   }
 
-            //ide.outputView.ShowClearSelectTab(build);
-            // this stuff doesn't even appear
-            //ide.outputView.buildBox.Logf("%s Compiler\n", compiler.name);
-            if(prj.config)
-               ide.outputView.buildBox.Logf("Compiling single file %s in project %s using the %s configuration...\n", node.name, prj.name, prj.config.name);
-            else
-               ide.outputView.buildBox.Logf("Compiling single file %s in project %s...\n", node.name, prj.name);
+   bool DebugStopForMake(Project prj, BuildType buildType, CompilerConfig compiler, ProjectConfig config)
+   {
+      bool result = false;
+      // TOFIX: DebugStop is being abused and backfiring on us.
+      //        It's supposed to be the 'Debug/Stop' item, not unloading executable or anything else
 
-            prj.Compile(node);
-            buildInProgress = none;
-            ide.AdjustBuildMenus();
+      //        configIsInDebugSession seems to be used for two OPPOSITE things:
+      //        If we're debugging another config, we need to unload the executable!
+      //        In building, we want to stop if we're debugging the 'same' executable
+      if(buildType != run) ///* && prj == project*/ && prj.configIsInDebugSession)
+      {
+         if(buildType == start || buildType == restart)
+         {
+            if(ide.debugger && ide.debugger.isPrepared)
+               result = DebugStop();
          }
          else
-            ide.outputView.buildBox.Logf("File %s is excluded from current build configuration.\n", node.name);
+         {
+            if(ide.project == prj && ide.debugger && ide.debugger.prjConfig == config && ide.debugger.isPrepared)
+               result = DebugStop();
+         }
       }
-      delete objDir;
-      delete compiler;
+      app.ProcessInput(true);
+      ShowOutputBuildLog(false);
+      return result;
    }
 
-   void GoToError(const char * line)
+   bool Build(Project prj, BuildType buildType, CompilerConfig compiler, ProjectConfig config, int bitDepth, bool justPrint)
    {
-      char * colon;
-      
-      while(isspace(*line)) line++;
-      colon = strstr(line, ":");
+      bool result = true;
+      Window document;
 
+      stopBuild = false;
+      for(document = master.firstChild; document; document = document.next)
       {
-         int lineNumber = 0;
-         int col = 1;
-         bool lookForLineNumber = true;
-
-         // deal with linking error
-         if(colon && colon[1] == ' ')
+         if(document.modifiedDocument)
          {
-            colon = strstr(colon + 1, ":");
-            if(colon && !colon[1])
-            {
-               colon = strstr(line, ":");
-               lookForLineNumber = false;
-            }
-            else if(colon && !isdigit(colon[1]))
+            ProjectNode node = GetNodeFromWindow(document, prj, true, false, null);
+            if(node && !document.MenuFileSave(null, 0))
             {
-               line = colon + 1;
-               colon = strstr(line, ":");
+               result = false;
+               break;
             }
          }
-         // Don't be mistaken by the drive letter colon
-         if(colon && (colon[1] == '/' || colon[1] == '\\'))
-            colon = strstr(colon + 1, ":");
-         if(colon && lookForLineNumber)
+      }
+      if(result)
+      {
+         DirExpression targetDir = prj.GetTargetDir(compiler, config, bitDepth);
+
+         DebugStopForMake(prj, buildType, compiler, config);
+
+         // TODO: Disabled until problems fixed... is it fixed?
+         if(buildType == rebuild || (config && config.compilingModified))
+            prj.Clean(compiler, config, bitDepth, clean, justPrint);
+         else
          {
-            char * comma;
-            // MSVS Errors
-            char * par = RSearchString(line, "(", colon - line, true, false);
-            if(par && strstr(par, ")"))
-               colon = par;
-            else if((colon+1)[0] == ' ')
+            if(buildType == relink || (config && config.linkingModified))
+               prj.Clean(compiler, config, bitDepth, cleanTarget, false);
+            if(config && config.symbolGenModified)
             {
-               // NOTE: This is the same thing as saying 'colon = line'
-               for( ; colon != line; colon--)
-                  /*if(*colon == '(')
-                     break*/;
+               DirExpression objDir = prj.GetObjDir(compiler, config, bitDepth);
+               char fileName[MAX_LOCATION];
+               char moduleName[MAX_FILENAME];
+               strcpy(fileName, prj.topNode.path);
+               PathCatSlash(fileName, objDir.dir);
+               ReplaceSpaces(moduleName, prj.moduleName);
+               strcat(moduleName, ".main.ec");
+               PathCatSlash(fileName, moduleName);
+               if(FileExists(fileName))
+                  DeleteFile(fileName);
+               ChangeExtension(fileName, "c", fileName);
+               if(FileExists(fileName))
+                  DeleteFile(fileName);
+               ChangeExtension(fileName, "o", fileName);
+               if(FileExists(fileName))
+                  DeleteFile(fileName);
+
+               delete objDir;
             }
-            lineNumber = atoi(colon + 1);
-            /*
-            comma = strchr(colon, ',');
-            if(comma)
-               col = atoi(comma+1);
-            */
-            comma = strchr(colon+1, ':');
-            if(comma)
-               col = atoi(comma+1);
          }
-         
+         buildInProgress = prj == project ? buildingMainProject : buildingSecondaryProject;
+         ide.AdjustBuildMenus();
+         ide.AdjustDebugMenus();
+
+         result = prj.Build(buildType, null, compiler, config, bitDepth, justPrint, normal);
+
+         if(config)
          {
-            char moduleName[MAX_LOCATION], filePath[MAX_LOCATION];
-            char * bracket;
-            if(colon)
-            {
-               // Cut module name
-               strncpy(moduleName, line, colon - line);
-               moduleName[colon - line] = '\0';
-            }
-            else
-               strcpy(moduleName, line);
+            config.compilingModified = false;
+            if(!stopBuild)
+               config.linkingModified = false;
 
-            // Remove stuff in brackets
-            /*
-            bracket = strstr(moduleName, "(");
-            if(bracket) *bracket = '\0';
-            */
-            MakeSlashPath(moduleName);
-
-            if(!colon)
-            {
-               // Check if it's one of our modules
-               ProjectNode node = project.topNode.Find(moduleName, false);
-               if(node)
-               {
-                  strcpy(moduleName, node.path);
-                  PathCatSlash(moduleName, node.name);
-               }
-               else
-                  moduleName[0] = '\0';
-            }
-            if(moduleName[0])
-            {
-               CodeEditor codeEditor;
-               strcpy(filePath, project.topNode.path);
-               PathCatSlash(filePath, moduleName);
-      
-               codeEditor = (CodeEditor)ide.OpenFile(filePath, normal, true, null, no, normal);
-               if(!codeEditor)
-               {
-                  char name[MAX_LOCATION];
-                  // TOFIX: Improve on this, don't use only filename, make a function
-                  if(ide && ide.workspace)
-                  {
-                     for(prj : ide.workspace.projects)
-                     {
-                        if(prj.topNode.FindWithPath(moduleName, false))
-                        {
-                           strcpy(filePath, prj.topNode.path);
-                           PathCatSlash(filePath, moduleName);
-                           codeEditor = (CodeEditor)ide.OpenFile(filePath, normal, true, null, no, normal);
-                           if(codeEditor)
-                              break;
-                        }
-                     }
-                  }
-               }
-               if(codeEditor && lineNumber)
-               {
-                  EditBox editBox = codeEditor.editBox;
-                  editBox.GoToLineNum(lineNumber - 1);
-                  editBox.GoToPosition(editBox.line, lineNumber - 1, col ? (col - 1) : 0);
-               }
-            }
+            config.symbolGenModified = false;
          }
-      }
-   }
-
-   bool OpenNode(ProjectNode node)
-   {
-      char filePath[MAX_LOCATION];
-      node.GetFullFilePath(filePath);
-      return ide.OpenFile(filePath, normal, true/*false Why was it opening hidden?*/, null, something, normal) ? true : false;
-   }
-
-   void AddNode(ProjectNode node, DataRow addTo)
-   {
-      DataRow row = addTo ? addTo.AddRow() : fileList.AddRow();
-
-      row.tag = (int)node;
-      node.row = row;
-
-      if(node.type == resources)
-         resourceRow = row;
-
-      row.SetData(null, node);
-
-      if(node.files && node.files.first && node.parent && 
-            !(!node.parent.parent && 
-               (!strcmpi(node.name, "notes") || !strcmpi(node.name, "sources") || 
-                  !strcmpi(node.name, "src") || !strcmpi(node.name, "tools"))))
-         row.collapsed = true;
-      else if(node.type == folder)
-         node.icon = openFolder;
-
-      if(node.files)
-      {
-         for(child : node.files)
-            AddNode(child, row);
-      }
-   }
+         buildInProgress = none;
+         ide.AdjustBuildMenus();
+         ide.AdjustDebugMenus();
 
-   void DeleteNode(ProjectNode projectNode)
-   {
-      if(projectNode.files)
-      {
-         ProjectNode child;
-         while(child = projectNode.files.first)
-            DeleteNode(child);
-      }
-      fileList.DeleteRow(projectNode.row);
-      projectNode.Delete();
-   }
+         ide.workspace.modified = true;
 
-   ProjectView()
-   {
-      NodeIcons c;
-      for(c = 0; c < NodeIcons::enumSize; c++)
-      {
-         icons[c] = BitmapResource { iconNames[c], alphaBlend = true };
-         AddResource(icons[c]);
+         delete targetDir;
       }
-      fileList.AddField(DataField { dataType = class(ProjectNode), freeData = false, userData = this });
+      return result;
    }
 
-   ~ProjectView()
-   {
-      DebugStop();
-      ide.DestroyTemporaryProjectDir();
-      if(project)
-      {
-         workspace.Free();
-         delete workspace;
-      }
-   }
+   //                          ((( USER ACTIONS )))
+   //
+   //  ************************************************************************
+   //  *** Methods below should atomically start a process, and as such     ***
+   //  *** they can query compiler and config directly from ide and project ***
+   //  *** but ONLY ONCE!!!                                                 ***
+   //  ************************************************************************
 
-   bool ProjectSave(MenuItem selection, Modifiers mods)
+   bool ProjectBuild(MenuItem selection, Modifiers mods)
    {
-      DataRow row = fileList.currentRow;
-      ProjectNode node = row ? (ProjectNode)row.tag : null;
-      Project prj = node ? node.project : null;
-      if(prj)
+      if(buildInProgress == none)
       {
-         if(prj.Save(prj.filePath))
+         Project prj = project;
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         int bitDepth = ide.workspace.bitDepth;
+         ProjectConfig config;
+         if(selection || !ide.activeClient)
          {
-            // ProjectUpdateMakefileForAllConfigs(prj, true, true);
-            prj.topNode.modified = false;
-            prj = null;
-            for(p : ide.workspace.projects)
-            {
-               if(p.topNode.modified)
-               { 
-                  prj = p;
-                  break;
-               }
-            }
-            if(!prj)
-               modifiedDocument = false;
-            Update(null);
+            DataRow row = fileList.currentRow;
+            ProjectNode node = row ? (ProjectNode)row.tag : null;
+            if(node) prj = node.project;
+         }
+         else
+         {
+            ProjectNode node = GetNodeForCompilationFromWindow(ide.activeClient, true, null, null);
+            if(node)
+               prj = node.project;
+         }
+         config = prj.config;
+         if(/*prj != project || */!prj.GetConfigIsInDebugSession(config) || !ide.DontTerminateDebugSession($"Project Build"))
+         {
+            BuildInterrim(prj, build, compiler, config, bitDepth, mods.ctrl && mods.shift);
          }
+         delete compiler;
       }
+      else
+         stopBuild = true;
       return true;
    }
 
-   bool ShowOutputBuildLog(bool cleanLog)
+   bool ProjectInstall(MenuItem selection, Modifiers mods)
    {
-      OutputView output = ide.outputView;
-      if(cleanLog)
-         output.ShowClearSelectTab(build);
+      Project prj = project;
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      int bitDepth = ide.workspace.bitDepth;
+      ProjectConfig config;
+      if(selection || !ide.activeClient)
+      {
+         DataRow row = fileList.currentRow;
+         ProjectNode node = row ? (ProjectNode)row.tag : null;
+         if(node) prj = node.project;
+      }
       else
       {
-         output.SelectTab(build);
-         output.Show();
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, true, false, null);
+         if(node)
+            prj = node.project;
       }
-   }
-
-   bool DisplayCompiler(bool cleanLog)
-   {
-      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
-      LogBox logBox = ide.outputView.buildBox;
-      ShowOutputBuildLog(cleanLog);
-      logBox.Logf("%s Compiler\n", compiler ? compiler.name : "{problem with compiler selection}");
-      delete compiler;
-   }
-
-   bool ProjectUpdateMakefileForAllConfigs(Project project, bool cleanLog, bool displayCompiler)
-   {
-      ProjectConfig currentConfig = project.config;
-      ShowOutputBuildLog(cleanLog);
-
-      if(displayCompiler)
-         DisplayCompiler(false);
-      
-      for(config : project.configurations)
+      config = prj.config;
+      if(!prj.GetConfigIsInDebugSession(config) ||
+            (!ide.DontTerminateDebugSession($"Project Install") && DebugStopForMake(prj, relink, compiler, config)))
       {
-         project.config = config;
-         ProjectPrepareMakefile(project, forceExists, false, false);
+         BuildInterrim(prj, build, compiler, config, bitDepth, mods.ctrl && mods.shift);
+         if(ProjectPrepareForToolchain(prj, normal, false, false, compiler, config))
+         {
+            ide.outputView.buildBox.Logf($"\nInstalling project %s using the %s configuration...\n", prj.name, GetConfigName(config));
+            Build(prj, install, compiler, config, bitDepth, mods.ctrl && mods.shift);
+         }
       }
-
-      project.config = currentConfig;
-
-      ide.Update(null);
-   }
-
-   bool ProjectPrepareForToolchain(Project project, PrepareMakefileMethod method, bool cleanLog, bool displayCompiler)
-   {
-      bool isReady = true;
-      char message[MAX_F_STRING];
-      LogBox logBox = ide.outputView.buildBox;
-
-      ShowOutputBuildLog(cleanLog);
-
-      if(displayCompiler)
-         DisplayCompiler(false);
-
-      ProjectPrepareMakefile(project, method, false, false);
+      delete compiler;
       return true;
    }
 
-   bool ProjectPrepareMakefile(Project project, PrepareMakefileMethod method, bool cleanLog, bool displayCompiler)
-   {
-      char makefilePath[MAX_LOCATION];
-      char makefileName[MAX_LOCATION];
-      bool exists;
-      LogBox logBox = ide.outputView.buildBox;
-      
-      ShowOutputBuildLog(cleanLog);
-
-      if(displayCompiler)
-         DisplayCompiler(false);
-
-      strcpy(makefilePath, project.topNode.path);
-      project.CatMakeFileName(makefileName);
-      PathCatSlash(makefilePath, makefileName);
-
-      exists = FileExists(makefilePath);
-      if((method == normal && (!exists || project.config.makingModified/*|| project.topNode.modified*/)) ||
-            (method == forceExists && exists) || 
-            method == force) // || project.config.makingModified || makefileDirty
-      {
-         char * reason;
-         char * action;
-         ide.statusBar.text = "Generating Makefile & Dependencies..."; // Dependencies?
-         app.UpdateDisplay();
-         
-         if((method == normal && !exists) || (method == force && !exists))
-            action = "Generating ";
-         else if(method == force)
-            action = "Regenerating ";
-         else if(method == normal || method == forceExists)
-            action = "Updating ";
-         else
-            action = "";
-         if(!exists)
-            reason = "Makefile doesn't exist. ";
-         else if(project.topNode.modified)
-            reason = "Project has been modified. ";
-         else
-            reason = "";
-
-         //logBox.Logf("%s\n", makefileName);
-         logBox.Logf("%s - %s%smakefile for %s config...\n", makefileName, reason, action, project.configName);
-         project.GenerateMakefile(null, false, null);
-
-         ide.statusBar.text = null;
-         app.UpdateDisplay();
-         return true;
-      }
-      return false;
-   }
-   
-   bool ProjectBuild(MenuItem selection, Modifiers mods)
+   bool ProjectLink(MenuItem selection, Modifiers mods)
    {
       Project prj = project;
-      if(selection || !ide.activeClient || activeClient == this)
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      int bitDepth = ide.workspace.bitDepth;
+      ProjectConfig config;
+      if(selection || !ide.activeClient)
       {
          DataRow row = fileList.currentRow;
          ProjectNode node = row ? (ProjectNode)row.tag : null;
          if(node) prj = node.project;
       }
-      // Added this code here until dependencies work:
-      else //if(ide.activeClient)
+      else
       {
-         ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, true, false, null);
          if(node)
             prj = node.project;
       }
-      if(/*prj != project || */!prj.configIsInDebugSession || !ide.DontTerminateDebugSession("Project Build"))
-         BuildInterrim(prj, build);
-      return true;
-   }
-
-   bool BuildInterrim(Project prj, BuildType buildType)
-   {
-      if(ProjectPrepareForToolchain(prj, normal, true, true))
+      config = prj.config;
+      if(!prj.GetConfigIsInDebugSession(config) ||
+            (!ide.DontTerminateDebugSession($"Project Link") && DebugStopForMake(prj, relink, compiler, config)))
       {
-         ide.outputView.buildBox.Logf("Building project %s using the %s configuration...\n", prj.name, prj.configName);
-         return Build(prj, buildType);
+         if(ProjectPrepareForToolchain(prj, normal, true, true, compiler, config))
+         {
+            ide.outputView.buildBox.Logf($"Relinking project %s using the %s configuration...\n", prj.name, GetConfigName(config));
+            if(config)
+               config.linkingModified = true;
+            Build(prj, relink, compiler, config, bitDepth, mods.ctrl && mods.shift);
+         }
       }
-      return false;
+      delete compiler;
+      return true;
    }
 
-   bool ProjectLink(MenuItem selection, Modifiers mods)
+   bool ProjectRebuild(MenuItem selection, Modifiers mods)
    {
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      int bitDepth = ide.workspace.bitDepth;
       Project prj = project;
-      if(selection || !ide.activeClient || activeClient == this)
+      ProjectConfig config;
+      if(selection || !ide.activeClient)
       {
          DataRow row = fileList.currentRow;
          ProjectNode node = row ? (ProjectNode)row.tag : null;
          if(node) prj = node.project;
       }
-      // Added this code here until dependencies work:
-      else //if(ide.activeClient)
+      else
       {
-         ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, true, false, null);
          if(node)
             prj = node.project;
       }
-      if(ProjectPrepareForToolchain(prj, normal, true, true))
+      config = prj.config;
+      if(!prj.GetConfigIsInDebugSession(config) ||
+            (!ide.DontTerminateDebugSession($"Project Rebuild") && DebugStopForMake(prj, rebuild, compiler, config)))
       {
-         ide.outputView.buildBox.Logf("Relinking project %s using the %s configuration...\n", prj.name, prj.configName);
-         if(prj.config)
-            prj.config.linkingModified = true;
-         Build(prj, relink);
+         if(ProjectPrepareForToolchain(prj, normal, true, true, compiler, config))
+         {
+            ide.outputView.buildBox.Logf($"Rebuilding project %s using the %s configuration...\n", prj.name, GetConfigName(config));
+            /*if(config)
+            {
+               config.compilingModified = true;
+               config.makingModified = true;
+            }*/ // -- should this still be used depite the new solution of BuildType?
+            Build(prj, rebuild, compiler, config, bitDepth, mods.ctrl && mods.shift);
+         }
       }
+      delete compiler;
       return true;
    }
 
-   bool ProjectRebuild(MenuItem selection, Modifiers mods)
+   bool ProjectCleanTarget(MenuItem selection, Modifiers mods)
    {
-      Project prj = GetSelectedProject((bool)selection);
-      if(ProjectPrepareForToolchain(prj, normal, true, true))
-      {
-         ide.outputView.buildBox.Logf("Rebuilding project %s using the %s configuration...\n", prj.name, prj.configName);
-         /*if(prj.config)
-         {
-            prj.config.compilingModified = true;
-            prj.config.makingModified = true;
-         }*/ // -- should this still be used depite the new solution of BuildType?
-         Build(prj, rebuild);
-      }
+      CleanProject($"Project Clean Target", $"Cleaning project %s target using the %s configuration...\n", selection, cleanTarget, mods.ctrl && mods.shift);
       return true;
    }
 
    bool ProjectClean(MenuItem selection, Modifiers mods)
    {
-      Project prj = GetSelectedProject((bool)selection);
-      if(ProjectPrepareForToolchain(prj, normal, true, true))
+      CleanProject($"Project Clean", $"Cleaning project %s using the %s configuration...\n", selection, clean, mods.ctrl && mods.shift);
+      return true;
+   }
+
+   bool ProjectRealClean(MenuItem selection, Modifiers mods)
+   {
+      CleanProject($"Project Real Clean", $"Removing intermediate objects directory for project %s using the %s configuration...\n", selection, realClean, mods.ctrl && mods.shift);
+      return true;
+   }
+
+   void CleanProject(const char * terminateDebugSessionMessage, const char * cleaningMessageLogFormat, MenuItem selection, CleanType cleanType, bool justPrint)
+   {
+      Project prj = project;
+      Array<Project> projects { };
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      int bitDepth = ide.workspace.bitDepth;
+      if(selection)
       {
-         ide.outputView.buildBox.Logf("Cleaning project %s using the %s configuration...\n", prj.name, prj.configName);
-         
-         buildInProgress = prj == project ? buildingMainProject : buildingSecondaryProject;
-         ide.AdjustBuildMenus();
+         OldLink item;
+         OldList selectedRows;
+         fileList.GetMultiSelection(selectedRows);
+         for(item = selectedRows.first; item; item = item.next)
+         {
+            DataRow row = item.data;
+            ProjectNode node = (ProjectNode)row.tag;
+            if(node.type == project)
+               projects.Add(node.project);
+         }
+         selectedRows.Free(null);
+      }
+      if(selection || !ide.activeClient)
+      {
+         DataRow row = fileList.currentRow;
+         ProjectNode node = row ? (ProjectNode)row.tag : null;
+         if(node) prj = node.project;
+         if(projects.count == 0)
+            projects.Add(prj);
+      }
+      else
+      {
+         // TODO: a file can belong to more than one project, ask which one to clean
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, true, false, null);
+         if(node) prj = node.project;
+         if(projects.count == 0)
+            projects.Add(prj);
+      }
+      for(prj : projects)
+      {
+         ProjectConfig config = prj.config;
+         if(!prj.GetConfigIsInDebugSession(config) ||
+               (!ide.DontTerminateDebugSession(terminateDebugSessionMessage) && DebugStopForMake(prj, clean, compiler, config)))
+         {
+            if(ProjectPrepareForToolchain(prj, normal, true, true, compiler, config))
+            {
+               ide.outputView.buildBox.Logf(cleaningMessageLogFormat, prj.name, GetConfigName(config));
 
-         prj.Clean();
-         buildInProgress = none;
-         ide.AdjustBuildMenus();
+               buildInProgress = prj == project ? buildingMainProject : buildingSecondaryProject;
+               ide.AdjustBuildMenus();
+               ide.AdjustDebugMenus();
+
+               prj.Clean(compiler, config, bitDepth, cleanType, justPrint);
+               buildInProgress = none;
+               ide.AdjustBuildMenus();
+               ide.AdjustDebugMenus();
+            }
+         }
       }
-      return true;
+      delete compiler;
+      delete projects;
    }
 
    bool ProjectRegenerate(MenuItem selection, Modifiers mods)
    {
       Project prj = project;
-      if(selection || !ide.activeClient || activeClient == this)
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      ShowOutputBuildLog(true);
+      if(selection || !ide.activeClient)
       {
          DataRow row = fileList.currentRow;
          ProjectNode node = row ? (ProjectNode)row.tag : null;
          if(node)
             prj = node.project;
       }
-      // Added this code here until dependencies work:
-      else //if(ide.activeClient)
+      else
       {
-         ProjectNode node = GetNodeFromWindow(ide.activeClient, null);
+         ProjectNode node = GetNodeFromWindow(ide.activeClient, null, true, false, null);
          if(node)
             prj = node.project;
       }
 
-      ProjectPrepareMakefile(prj, force, true, true);
+      DisplayCompiler(compiler, false);
+      ProjectPrepareCompiler(project, compiler, false);
+      ProjectPrepareMakefile(prj, force, compiler, prj.config);
+      delete compiler;
       return true;
    }
 
-   bool ProjectNewFile(MenuItem selection, Modifiers mods)
+   bool Compile(Project project, List<ProjectNode> nodes, bool justPrint, SingleFileCompileMode mode)
    {
-      DataRow row = fileList.currentRow;
-      if(row)
+      bool result = true;
+      Window document;
+      ProjectConfig config = project.config;
+
+      stopBuild = false;
+
+      for(document = ide.firstChild; document; document = document.next)
+      {
+         if(document.modifiedDocument)
+         {
+            ProjectNode n = GetNodeFromWindow(document, project, true, mode == cObject ? true : false, null);
+            for(node : nodes)
+            {
+               if(n && n.IsInNode(node) && !document.MenuFileSave(null, 0))
+               {
+                  ide.outputView.buildBox.Logf($"Unable to save %s file.\n", node.name);
+                  result = false;
+                  break;
+               }
+            }
+         }
+      }
+
+      if(result)
+      {
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         int bitDepth = ide.workspace.bitDepth;
+         result = false;
+         if(ProjectPrepareForToolchain(project, normal, true, true, compiler, config))
+         {
+            if(config)
+               ide.outputView.buildBox.Logf($"%s specific file(s) in project %s using the %s configuration...\n",
+                     (mode == normal || mode == cObject) ? $"Compiling" : $"Debug compiling", project.name, config.name);
+            else
+               ide.outputView.buildBox.Logf($"%s specific file(s) in project %s...\n",
+                     (mode == normal || mode == cObject) ? $"Compiling" : $"Debug compiling", project.name);
+
+            buildInProgress = compilingFile;
+            ide.AdjustBuildMenus();
+            result = project.Compile(nodes, compiler, config, bitDepth, justPrint, mode);
+            buildInProgress = none;
+            ide.AdjustBuildMenus();
+         }
+         delete compiler;
+      }
+      return result;
+   }
+
+   bool Clean(Project project, List<ProjectNode> nodes, bool justPrint)
+   {
+      bool result = true;
+      Window document;
+      ProjectConfig config = project.config;
+
+      stopBuild = false;
+
+      for(document = ide.firstChild; document; document = document.next)
+      {
+         if(document.modifiedDocument)
+         {
+            ProjectNode n = GetNodeFromWindow(document, project, true, false, null);
+            for(node : nodes)
+            {
+               if(n && n.IsInNode(node) && !document.MenuFileSave(null, 0))
+               {
+                  ide.outputView.buildBox.Logf($"Unable to save %s file.\n", node.name);
+                  result = false;
+                  break;
+               }
+            }
+         }
+      }
+
+      if(result)
+      {
+         CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+         int bitDepth = ide.workspace.bitDepth;
+         result = false;
+         if(ProjectPrepareForToolchain(project, normal, true, true, compiler, config))
+         {
+            Map<String, NameCollisionInfo> namesInfo { };
+            project.topNode.GenMakefileGetNameCollisionInfo(namesInfo, config);
+            for(node : nodes)
+            {
+               if(node.GetIsExcluded(config))
+                  ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
+               else
+               {
+                  if(config)
+                     ide.outputView.buildBox.Logf($"Deleting intermediate objects for %s %s in project %s using the %s configuration...\n",
+                           node.type == file ? $"single file" : $"folder", node.name, project.name, config.name);
+                  else
+                     ide.outputView.buildBox.Logf($"Deleting intermediate objects for %s %s in project %s...\n",
+                           node.type == file ? $"single file" : $"folder", node.name, project.name);
+
+                  node.DeleteIntermediateFiles(compiler, config, bitDepth, namesInfo, false);
+                  result = true;
+               }
+            }
+            namesInfo.Free();
+            delete namesInfo;
+         }
+         delete compiler;
+      }
+      return result;
+   }
+
+   bool ProjectNewFile(MenuItem selection, Modifiers mods)
+   {
+      DataRow row = fileList.currentRow;
+      if(row)
       {
          char fileName[1024];
          char filePath[MAX_LOCATION];
@@ -1102,8 +1233,8 @@ class ProjectView : Window
          parentNode.GetFileSysMatchingPath(filePath);
          MakePathRelative(filePath, parentNode.project.topNode.path, filePath);
          for(n = parentNode; n && n != parentNode.project.resNode; n = n.parent);
-         sprintf(fileName, "Untitled %d", documentID);
-         fileNode = AddFile(parentNode, fileName, (bool)n, true);
+         sprintf(fileName, $"Untitled %d", documentID);
+         fileNode = AddFile(parentNode, fileName, n != null, true);
          fileNode.path = CopyUnixPath(filePath);
          if(fileNode)
          {
@@ -1158,6 +1289,7 @@ class ProjectView : Window
    {
       CodeEditor codeEditor = CreateNew("Form", "form", "Window", null);
       codeEditor.EnsureUpToDate();
+      ide.RepositionWindows(false);
       return true;
    }
 
@@ -1181,308 +1313,679 @@ class ProjectView : Window
       return true;
    }
 
-   bool MenuConfig(MenuItem selection, Modifiers mods)
+   bool ProjectUpdateMakefileForAllConfigs(Project project)
+   {
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+
+      // This call really does not belong here:
+      ide.UpdateToolBarActiveConfigs(false);
+      for(config : project.configurations)
+         ProjectPrepareMakefile(project, forceExists, compiler, config);
+
+      ide.Update(null);
+      delete compiler;
+      return true;
+   }
+
+   bool MenuSettings(MenuItem selection, Modifiers mods)
+   {
+      ProjectNode node = GetSelectedNode(true);
+      Project prj = node ? node.project : project;
+      projectSettingsDialog = ProjectSettings { master = parent, project = prj, projectNode = node };
+      incref projectSettingsDialog;
+      projectSettingsDialog.Modal();
+      delete projectSettingsDialog;
+      ide.UpdateToolBarActiveConfigs(false);
+      Update(null);
+      ide.AdjustMenus();
+      return true;
+   }
+
+   bool FileProperties(MenuItem selection, Modifiers mods)
+   {
+      DataRow row = fileList.currentRow;
+      if(row)
+      {
+         ProjectNode node = (ProjectNode)row.tag;
+         NodeProperties { parent = parent, master = this, node = node,
+               position = { position.x + 100, position.y + 100 } }.Create();
+      }
+      return true;
+   }
+
+   bool FileOpenFile(MenuItem selection, Modifiers mods)
+   {
+      OpenSelectedNodes(mods.ctrl && mods.shift);
+      return true;
+   }
+
+   bool FileRemoveFile(MenuItem selection, Modifiers mods)
+   {
+      RemoveSelectedNodes();
+      return true;
+   }
+
+   bool FileCompile(MenuItem selection, Modifiers mods)
+   {
+      OldLink item;
+      OldList selectedRows;
+      Project project = null;
+      List<ProjectNode> nodes { };
+      fileList.GetMultiSelection(selectedRows);
+      for(item = selectedRows.first; item; item = item.next)
+      {
+         DataRow row = item.data;
+         ProjectNode node = (ProjectNode)row.tag;
+         if(!project)
+            project = node.project;
+         else if(node.project != project)
+         {
+            project = null;
+            break;
+         }
+         nodes.Add(node);
+      }
+      selectedRows.Free(null);
+      if(project)
+         Compile(project, nodes, mods.ctrl && mods.shift, normal);
+      else
+         ide.outputView.buildBox.Logf($"Please select files from a single project.\n");
+      delete nodes;
+      return true;
+   }
+
+   bool FileClean(MenuItem selection, Modifiers mods)
+   {
+      OldLink item;
+      OldList selectedRows;
+      Project project = null;
+      List<ProjectNode> nodes { };
+      fileList.GetMultiSelection(selectedRows);
+      for(item = selectedRows.first; item; item = item.next)
+      {
+         DataRow row = item.data;
+         ProjectNode node = (ProjectNode)row.tag;
+         if(!project)
+            project = node.project;
+         else if(node.project != project)
+         {
+            project = null;
+            break;
+         }
+         nodes.Add(node);
+      }
+      selectedRows.Free(null);
+      if(project)
+         Clean(project, nodes, mods.ctrl && mods.shift);
+      else
+         ide.outputView.buildBox.Logf($"Please select files from a single project.\n");
+      delete nodes;
+      return true;
+   }
+
+   bool FileDebugPrecompile(MenuItem selection, Modifiers mods)
+   {
+      DataRow row = fileList.currentRow;
+      ProjectNode node = row ? (ProjectNode)row.tag : null;
+      if(node)
+      {
+         List<ProjectNode> nodes { };
+         nodes.Add(node);
+         if(node.type == project)
+            ProjectBuild(selection, mods);
+         ide.Update(null);
+         if(!stopBuild)
+            Compile(node.project, nodes, mods.ctrl && mods.shift, debugPrecompile);
+         delete nodes;
+      }
+      return true;
+   }
+
+   bool FileDebugCompile(MenuItem selection, Modifiers mods)
+   {
+      DataRow row = fileList.currentRow;
+      ProjectNode node = row ? (ProjectNode)row.tag : null;
+      if(node)
+      {
+         List<ProjectNode> nodes { };
+         nodes.Add(node);
+         if(node.type == project)
+            ProjectBuild(selection, mods);
+         else
+            Compile(node.project, nodes, mods.ctrl && mods.shift, normal);
+         if(!stopBuild)
+            Compile(node.project, nodes, mods.ctrl && mods.shift, debugCompile);
+         delete nodes;
+      }
+      return true;
+   }
+
+   bool FileDebugGenerateSymbols(MenuItem selection, Modifiers mods)
+   {
+      DataRow row = fileList.currentRow;
+      ProjectNode node = row ? (ProjectNode)row.tag : null;
+      if(node)
+      {
+         List<ProjectNode> nodes { };
+         nodes.Add(node);
+         if(node.type == project)
+            ProjectBuild(selection, mods);
+         else
+            Compile(node.project, nodes, mods.ctrl && mods.shift, normal);
+         if(!stopBuild)
+            Compile(node.project, nodes, mods.ctrl && mods.shift, debugGenerateSymbols);
+         delete nodes;
+      }
+      return true;
+   }
+
+   Project GetSelectedProject(bool useSelection)
+   {
+      Project prj = project;
+      if(useSelection)
+      {
+         DataRow row = fileList.currentRow;
+         ProjectNode node = row ? (ProjectNode)row.tag : null;
+         if(node)
+            prj = node.project;
+      }
+      return prj;
+   }
+
+   void SelectNextProject(bool backwards)
+   {
+      DataRow row = fileList.currentRow;
+      DataRow currentRow = row;
+      ProjectNode node = (ProjectNode)row.tag;
+      if(node.type != project)
+         row = node.project.topNode.row;
+      else if(backwards)
+         row = row.previous ? row.previous : fileList.lastRow;
+      if(!backwards)
+         row = row.next ? row.next : fileList.firstRow;
+      if(row && row != currentRow)
+      {
+         fileList.SelectRow(row);
+         fileList.currentRow = row;
+      }
+   }
+
+   ProjectNode GetSelectedNode(bool useSelection)
+   {
+      ProjectNode node = null;
+      if(useSelection)
+      {
+         DataRow row = fileList.currentRow;
+         if(row)
+            node = (ProjectNode)row.tag;
+      }
+      return node;
+   }
+
+   bool MenuBrowseFolder(MenuItem selection, Modifiers mods)
+   {
+      char folder[MAX_LOCATION];
+      Project prj;
+      ProjectNode node = GetSelectedNode(true);
+      if(!node)
+         node = project.topNode;
+      prj = node.project;
+
+      strcpy(folder, prj.topNode.path);
+      if(node != prj.topNode)
+         PathCatSlash(folder, node.path);
+      ShellOpen(folder);
+      return true;
+   }
+
+   bool Run(MenuItem selection, Modifiers mods)
    {
-      if(ProjectActiveConfig { parent = parent.parent, master = parent, project = project }.Modal() == ok)
-         ide.AdjustMenus();
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      ProjectConfig config = project.config;
+      int bitDepth = ide.workspace.bitDepth;
+      String args = new char[maxPathLen];
+      args[0] = '\0';
+      if(ide.workspace.commandLineArgs)
+         //ide.debugger.GetCommandLineArgs(args);
+         strcpy(args, ide.workspace.commandLineArgs);
+      if(ide.debugger.isActive)
+         project.Run(args, compiler, config, bitDepth);
+      /*else if(config.targetType == sharedLibrary || config.targetType == staticLibrary)
+         MessageBox { master = ide, type = ok, text = "Run", contents = "Shared and static libraries cannot be run like executables." }.Modal();*/
+      else if(BuildInterrim(project, run, compiler, config, bitDepth, false))
+         project.Run(args, compiler, config, bitDepth);
+      delete args;
+      delete compiler;
       return true;
    }
 
-   bool MenuCompiler(MenuItem selection, Modifiers mods)
+   bool DebugStart()
+   {
+      bool result = false;
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      ProjectConfig config = project.config;
+      int bitDepth = ide.workspace.bitDepth;
+      bool useValgrind = ide.workspace.useValgrind;
+      TargetTypes targetType = project.GetTargetType(config);
+      if(targetType == sharedLibrary || targetType == staticLibrary)
+         MessageBox { master = ide, type = ok, text = $"Run", contents = $"Shared and static libraries cannot be run like executables." }.Modal();
+      else if(project.GetCompress(config))
+         MessageBox { master = ide, text = $"Starting Debug", contents = $"Debugging compressed applications is not supported\n" }.Modal();
+      else if(project.GetDebug(config) ||
+         MessageBox { master = ide, type = okCancel, text = $"Starting Debug", contents = $"Attempting to debug non-debug configuration\nProceed anyways?" }.Modal() == ok)
+      {
+         if(/*!IsProjectModified() ||*/ BuildInterrim(project, start, compiler, config, bitDepth, false))
+         {
+            if(compiler.type.isVC)
+            {
+               //bool result = false;
+               char oldwd[MAX_LOCATION];
+               PathBackup pathBackup { };
+               char command[MAX_LOCATION];
+
+               ide.SetPath(false, compiler, config, bitDepth);
+
+               GetWorkingDir(oldwd, sizeof(oldwd));
+               ChangeWorkingDir(project.topNode.path);
+
+               sprintf(command, "%s /useenv %s.sln /projectconfig \"%s|Win32\" /command \"%s\"" , "devenv", project.name, config.name, "Debug.Start");
+               Execute(command);
+               ChangeWorkingDir(oldwd);
+
+               delete pathBackup;
+            }
+            else
+            {
+               ide.debugger.Start(compiler, config, bitDepth, useValgrind);
+               result = true;
+            }
+         }
+      }
+      delete compiler;
+      return result;
+   }
+
+   void GoToError(const char * line, const bool noParsing)
+   {
+      char * colon;
+
+      while(isspace(*line)) line++;
+      colon = strstr(line, ":");
+
+      {
+         int lineNumber = 0;
+         int col = 1;
+         bool lookForLineNumber = true;
+
+         // deal with linking error
+         if(colon && colon[1] == ' ')
+         {
+            colon = strstr(colon + 1, ":");
+            if(colon && !colon[1])
+            {
+               colon = strstr(line, ":");
+               lookForLineNumber = false;
+            }
+            else if(colon && !isdigit(colon[1]))
+            {
+               line = colon + 1;
+               colon = strstr(line, ":");
+            }
+         }
+         // Don't be mistaken by the drive letter colon
+         if(colon && (colon[1] == '/' || colon[1] == '\\'))
+            colon = strstr(colon + 1, ":");
+         if(colon && lookForLineNumber)
+         {
+            char * comma;
+#if 0 // MSVS Errors -- todo fix this later
+            char * par = RSearchString(line, "(", colon - line, true, false);
+            if(par && strstr(par, ")"))
+               colon = par;
+            else if((colon+1)[0] == ' ')
+            {
+               // NOTE: This is the same thing as saying 'colon = line'
+               for( ; colon != line; colon--)
+                  /*if(*colon == '(')
+                     break*/;
+            }
+#endif
+            lineNumber = atoi(colon + 1);
+            /*
+            comma = strchr(colon, ',');
+            if(comma)
+               col = atoi(comma+1);
+            */
+            comma = strchr(colon+1, ':');
+            if(comma)
+               col = atoi(comma+1);
+         }
+
+         {
+            char moduleName[MAX_LOCATION], filePath[MAX_LOCATION] = "";
+            char ext[MAX_EXTENSION] = "";
+            ProjectNode node = null;
+            if(colon)
+            {
+               const char * inFileIncludedFrom = strstr(line, stringInFileIncludedFrom);
+               const char * from = strstr(line, "from ");
+               const char * start = inFileIncludedFrom ? inFileIncludedFrom + strlen(stringInFileIncludedFrom) : from ? from + strlen("from ") : line;
+               int len;
+               if(colon < start)
+                  start = line;
+               len = Min((int)(colon - start), MAX_LOCATION-1);
+               // Cut module name
+               strncpy(moduleName, start, len);
+               moduleName[len] = '\0';
+            }
+            else
+               strcpy(moduleName, line);
+
+            if(!colon)
+            {
+               char * msg;
+               if((msg = strstr(moduleName, " - ")))
+               {
+                  bool found = false;
+                  msg[0] = '\0';
+                  for(prj : ide.workspace.projects)
+                  {
+                     strcpy(filePath, prj.topNode.path);
+                     PathCatSlash(filePath, moduleName);
+                     if(FileExists(filePath).isFile)
+                     {
+                        found = true;
+                        break;
+                     }
+                  }
+                  if(!found)
+                  {
+                     msg[0] = ' ';
+                     filePath[0] = '\0';
+                  }
+               }
+               else if((msg = strstr(moduleName, "...")) && (colon = strchr(moduleName, ' ')) && (++colon)[0])
+               {
+                  bool found = false;
+                  msg[0] = '\0';
+                  for(prj : ide.workspace.projects)
+                  {
+                     if((node = prj.resNode.Find(colon, true)))
+                     {
+                        strcpy(filePath, prj.topNode.path);
+                        PathCatSlash(filePath, node.path);
+                        PathCatSlash(filePath, node.name);
+
+                        found = true;
+                        break;
+                     }
+                  }
+                  if(!found)
+                  {
+                     msg[0] = '.';
+                     filePath[0] = '\0';
+                  }
+               }
+               colon = null;
+            }
+            // Remove stuff in brackets
+            /*
+            bracket = strstr(moduleName, "(");
+            if(bracket) *bracket = '\0';
+            */
+            MakeSlashPath(moduleName);
+            GetExtension(moduleName, ext);
+
+            if(!colon && !filePath[0])
+            {
+               // Check if it's one of our modules
+               node = project.topNode.Find(moduleName, false);
+               if(node)
+               {
+                  strcpy(filePath, node.path);
+                  PathCatSlash(filePath, node.name);
+               }
+               else
+               {
+                  char ext[MAX_EXTENSION];
+                  GetExtension(moduleName, ext);
+                  {
+                     DotMain dotMain = DotMain::FromFileName(moduleName);
+                     IntermediateFileType type = IntermediateFileType::FromExtension(ext);
+                     ProjectConfig config = null;
+                     if(type)
+                     {
+                        for(prj : ide.workspace.projects; prj.lastBuildConfigName)
+                        {
+                           if((config = prj.GetConfig(prj.lastBuildConfigName)))
+                              node = prj.FindNodeByObjectFileName(moduleName, type, dotMain, config);
+                           if(node)
+                              break;
+                        }
+                     }
+                     if(node)
+                     {
+                        char name[MAX_FILENAME];
+                        Project project = node.project;
+                        CompilerConfig compiler = ideSettings.GetCompilerConfig(project.lastBuildCompilerName);
+                        if(compiler)
+                        {
+                           int bitDepth = ide.workspace.bitDepth;
+                           DirExpression objDir = project.GetObjDir(compiler, config, bitDepth);
+                           strcpy(filePath, project.topNode.path);
+                           PathCatSlash(filePath, objDir.dir);
+                           node.GetObjectFileName(name, project.configsNameCollisions[config ? config.name : ""], type, dotMain);
+                           PathCatSlash(filePath, name);
+                           delete objDir;
+                        }
+                        delete compiler;
+                     }
+                  }
+               }
+               if(!node)
+                  filePath[0] = '\0';
+            }
+            if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "lib") ||
+                  !strcmp(ext, "dll") || !strcmp(ext, "exe") || !strcmp(ext, "mo"))
+               moduleName[0] = 0;    // Avoid opening binary files
+            if(moduleName[0])
+            {
+               CodeEditor codeEditor;
+               if(!filePath[0])
+               {
+                  strcpy(filePath, project.topNode.path);
+                  PathCatSlash(filePath, moduleName);
+               }
+
+               codeEditor = (CodeEditor)ide.OpenFile(filePath, false, true, null, no, normal, noParsing);
+               if(!codeEditor && !strcmp(ext, "c"))
+               {
+                  char ecName[MAX_LOCATION];
+                  ChangeExtension(filePath, "ec", ecName);
+                  codeEditor = (CodeEditor)ide.OpenFile(ecName, false, true, null, no, normal, noParsing);
+               }
+               if(!codeEditor)
+               {
+                  char path[MAX_LOCATION];
+                  // TOFIX: Improve on this, don't use only filename, make a function
+                  if(ide && ide.workspace)
+                  {
+                     for(prj : ide.workspace.projects)
+                     {
+                        ProjectNode node;
+                        MakePathRelative(filePath, prj.topNode.path, path);
+
+                        if((node = prj.topNode.FindWithPath(path, false)))
+                        {
+                           strcpy(filePath, prj.topNode.path);
+                           PathCatSlash(filePath, node.path);
+                           PathCatSlash(filePath, node.name);
+                           codeEditor = (CodeEditor)ide.OpenFile(filePath, false, true, null, no, normal, noParsing);
+                           if(codeEditor)
+                              break;
+                        }
+                     }
+                     if(!codeEditor && (strchr(moduleName, '/') || strchr(moduleName, '\\')))
+                     {
+                        for(prj : ide.workspace.projects)
+                        {
+                           ProjectNode node;
+                           if((node = prj.topNode.FindWithPath(moduleName, false)))
+                           {
+                              strcpy(filePath, prj.topNode.path);
+                              PathCatSlash(filePath, node.path);
+                              PathCatSlash(filePath, node.name);
+                              codeEditor = (CodeEditor)ide.OpenFile(filePath, false, true, null, no, normal, noParsing);
+                              if(codeEditor)
+                                 break;
+                           }
+                        }
+                     }
+                     if(!codeEditor)
+                     {
+                        GetLastDirectory(moduleName, moduleName);
+                        for(prj : ide.workspace.projects)
+                        {
+                           ProjectNode node;
+                           if((node = prj.topNode.Find(moduleName, false)))
+                           {
+                              strcpy(filePath, prj.topNode.path);
+                              PathCatSlash(filePath, node.path);
+                              PathCatSlash(filePath, node.name);
+                              codeEditor = (CodeEditor)ide.OpenFile(filePath, false, true, null, no, normal, noParsing);
+                              if(codeEditor)
+                                 break;
+                           }
+                        }
+                     }
+                  }
+               }
+               if(codeEditor && lineNumber)
+               {
+                  EditBox editBox = codeEditor.editBox;
+                  if(editBox.GoToLineNum(lineNumber - 1))
+                     editBox.GoToPosition(editBox.line, lineNumber - 1, col ? (col - 1) : 0);
+               }
+            }
+         }
+      }
+   }
+
+   bool OpenNode(ProjectNode node, bool noParsing)
    {
-      ActiveCompilerDialog compilerDialog
-      {
-         parent = parent.parent, master = parent;
-         ideSettings = ideSettings, workspaceActiveCompiler = ide.workspace.compiler;
-      };
-      incref compilerDialog;
-      if(compilerDialog.Modal() == ok && strcmp(compilerDialog.workspaceActiveCompiler, ide.workspace.compiler))
+      char filePath[MAX_LOCATION];
+      char ext[MAX_EXTENSION];
+      node.GetFullFilePath(filePath);
+      GetExtension(filePath, ext);
+      if(binaryDocExt.Find(ext))
       {
-         ide.workspace.compiler = compilerDialog.workspaceActiveCompiler;
-         for(prj : ide.workspace.projects)
-            ide.projectView.ProjectUpdateMakefileForAllConfigs(prj, true, true);
+         ShellOpen(filePath);
+         return true;
       }
-      delete compilerDialog;
-      return true;
+      else
+         return ide.OpenFile(filePath, false, true/*false Why was it opening hidden?*/, null, something, normal, noParsing) ? true : false;
    }
 
-   bool MenuSettings(MenuItem selection, Modifiers mods)
+   void AddNode(ProjectNode node, DataRow addTo)
    {
-      ProjectNode node = GetSelectedNode(true);
-      Project prj = node ? node.project : project;
-      projectSettingsDialog = ProjectSettings { parent = parent.parent, master = parent, project = prj, projectNode = node };
-      projectSettingsDialog.Modal();
+      DataRow row = addTo ? addTo.AddRow() : fileList.AddRow();
 
-      Update(null);
-      ide.AdjustMenus();
-      return true;
-   }
+      row.tag = (int64)node;
+      node.row = row;
 
-   bool FileProperties(MenuItem selection, Modifiers mods)
-   {
-      DataRow row = fileList.currentRow;
-      if(row)
-      {
-         ProjectNode node = (ProjectNode)row.tag;
-         NodeProperties { parent = parent, master = this, node = node, 
-               position = { position.x + 100, position.y + 100 } }.Create();
-      }
-      return true;
-   }
+      if(node.type == resources)
+         resourceRow = row;
 
-   bool FileOpenFile(MenuItem selection, Modifiers mods)
-   {
-      OpenSelectedNodes();
-      return true;
-   }
+      row.SetData(null, node);
 
-   bool FileRemoveFile(MenuItem selection, Modifiers mods)
-   {
-      RemoveSelectedNodes();
-      return true;
-   }
+      if(node.files && node.files.first && node.parent &&
+            !(!node.parent.parent &&
+               (!strcmpi(node.name, "notes") || !strcmpi(node.name, "sources") ||
+                  !strcmpi(node.name, "src") || !strcmpi(node.name, "tools"))))
+         row.collapsed = true;
+      else if(node.type == folder)
+         node.icon = openFolder;
 
-   bool FileCompile(MenuItem selection, Modifiers mods)
-   {
-      DataRow row = fileList.currentRow;
-      if(row)
+      if(node.files)
       {
-         ProjectNode node = (ProjectNode)row.tag;
-         Compile(node);
+         for(child : node.files)
+            AddNode(child, row);
       }
-      return true;
    }
 
-   /*bool IsProjectModified()
+   void DeleteNode(ProjectNode projectNode)
    {
-      Window document;
-
-      for(document = master.firstChild; document; document = document.next)
+      if(projectNode.files)
       {
-         if(document.modifiedDocument)
-            if(GetNodeFromWindow(document), project)
-               return true;
+         ProjectNode child;
+         while((child = projectNode.files.first))
+            DeleteNode(child);
       }
-      return false;
+      fileList.DeleteRow(projectNode.row);
+      projectNode.Delete();
    }
-   */
 
-   bool Build(Project prj, BuildType buildType)
+   bool ProjectSave(MenuItem selection, Modifiers mods)
    {
-      bool result = true;
-      Window document;
-
-      stopBuild = false;
-      for(document = master.firstChild; document; document = document.next)
-      {
-         if(document.modifiedDocument)
-         {
-            ProjectNode node = GetNodeFromWindow(document, prj);
-            if(node && !document.MenuFileSave(null, 0))
-            {
-               result = false;
-               break;
-            }
-         }
-      }
-      if(result)
+      DataRow row = fileList.currentRow;
+      ProjectNode node = row ? (ProjectNode)row.tag : null;
+      Project prj = node ? node.project : null;
+      if(prj)
       {
-         DirExpression targetDir = prj.targetDir;
-
-         // TOFIX: DebugStop is being abused and backfiring on us.
-         //        It's supposed to be the 'Debug/Stop' item, not unloading executable or anything else
-
-         //        configIsInDebugSession seems to be used for two OPPOSITE things:
-         //        If we're debugging another config, we need to unload the executable!
-         //        In building, we want to stop if we're debugging the 'same' executable
-         if(buildType != run) ///* && prj == project*/ && prj.configIsInDebugSession)
+         prj.StopMonitoring();
+         if(prj.Save(prj.filePath))
          {
-            if(buildType == start || buildType == restart)
-            {
-               if(ide.debugger && ide.debugger.isPrepared)
-               {
-                  DebugStop();
-               }
-            }
-            else
+            Project modPrj = null;
+            prj.topNode.modified = false;
+            for(p : ide.workspace.projects)
             {
-               if(ide.project == prj && ide.debugger && ide.debugger.prjConfig == prj.config && ide.debugger.isPrepared)
+               if(p.topNode.modified)
                {
-                  DebugStop();
+                  modPrj = p;
+                  break;
                }
             }
+            if(!modPrj)
+               modifiedDocument = false;
+            Update(null);
          }
-         
-         // TODO: Disabled until problems fixed... is it fixed?
-         if(buildType == rebuild || (prj.config && prj.config.compilingModified))
-            prj.Clean();
-         else
-         {
-            if(buildType == relink || (prj.config && prj.config.linkingModified))
-            {
-               char target[MAX_LOCATION];
-
-               strcpy(target, prj.topNode.path);
-               PathCat(target, targetDir.dir);
-               prj.CatTargetFileName(target);
-               if(FileExists(target))
-                  DeleteFile(target);
-            }
-            if(prj.config && prj.config.symbolGenModified)
-            {
-               DirExpression objDir = prj.objDir;
-               char fileName[MAX_LOCATION];
-               char moduleName[MAX_FILENAME];
-               strcpy(fileName, prj.topNode.path);
-               PathCatSlash(fileName, objDir.dir);
-               strcpy(moduleName, prj.moduleName);
-               strcat(moduleName, ".main.ec");
-               PathCatSlash(fileName, moduleName);
-               if(FileExists(fileName))
-                  DeleteFile(fileName);
-               ChangeExtension(fileName, "c", fileName);
-               if(FileExists(fileName))
-                  DeleteFile(fileName);
-               ChangeExtension(fileName, "o", fileName);
-               if(FileExists(fileName))
-                  DeleteFile(fileName);
-
-               delete objDir;
-            }
-         }
-         buildInProgress = prj == project ? buildingMainProject : buildingSecondaryProject;
-         ide.AdjustBuildMenus();
-         ide.AdjustDebugMenus();
-
-         result = prj.Build(buildType == run, null);
-
-         if(prj.config)
-         {
-            prj.config.compilingModified = false;
-            if(!ide.ShouldStopBuild())
-               prj.config.linkingModified = false;
-
-            prj.config.symbolGenModified = false;
-         }
-         buildInProgress = none;
-         ide.AdjustBuildMenus();
-         ide.AdjustDebugMenus();
-
-         ide.workspace.modified = true;
-
-         delete targetDir;
+         prj.StartMonitoring();
       }
-      return result;
+      return true;
    }
 
-   Project GetSelectedProject(bool useSelection)
-   {
-      Project prj = project;
-      if(useSelection)
-      {
-         DataRow row = fileList.currentRow;
-         ProjectNode node = row ? (ProjectNode)row.tag : null;
-         if(node)
-            prj = node.project;
-      }
-      return prj;
-   }
-   
-   ProjectNode GetSelectedNode(bool useSelection)
+   bool ShowOutputBuildLog(bool cleanLog)
    {
-      ProjectNode node = null;
-      if(useSelection)
+      OutputView output = ide.outputView;
+      if(cleanLog)
+         output.ShowClearSelectTab(build);
+      else
       {
-         DataRow row = fileList.currentRow;
-         if(row)
-            node = (ProjectNode)row.tag;
+         output.SelectTab(build);
+         output.Show();
       }
-      return node;
-   }
-
-   bool MenuBrowseFolder(MenuItem selection, Modifiers mods)
-   {
-      char folder[MAX_LOCATION];
-      Project prj;
-      ProjectNode node = GetSelectedNode(true);
-      if(!node)
-         node = project.topNode;
-      prj = node.project;
-
-      strcpy(folder, prj.topNode.path);
-      if(node != prj.topNode)
-         PathCatSlash(folder, node.path);
-      ShellOpen(folder);
-   }
-
-   bool Run(MenuItem selection, Modifiers mods)
-   {
-      char args[MAX_LOCATION * 64];
-      args[0] = '\0';
-      if(ide.workspace.commandLineArgs)
-         //ide.debugger.GetCommandLineArgs(args);
-         strcpy(args, ide.workspace.commandLineArgs);
-      if(ide.debugger.isActive)
-         project.Run(args);
-      /*else if(project.config.targetType == sharedLibrary || project.config.targetType == staticLibrary)
-         MessageBox { master = ide, type = ok, text = "Run", contents = "Shared and static libraries cannot be run like executables." }.Modal();*/
-      else if(BuildInterrim(project, run))
-         project.Run(args);
       return true;
    }
 
-   bool DebugStart()
-   {
-      bool result = false;
-      if(project.targetType == sharedLibrary || project.targetType == staticLibrary)
-         MessageBox { master = ide, type = ok, text = "Run", contents = "Shared and static libraries cannot be run like executables." }.Modal();
-      else if(project.compress)
-         MessageBox { master = ide, text = "Starting Debug", contents = "Debugging compressed applications is not supported\n" }.Modal();
-      else if(project.debug ||
-         MessageBox { master = ide, type = okCancel, text = "Starting Debug", contents = "Attempting to debug non-debug configuration\nProceed anyways?" }.Modal() == ok)
-      {
-         if(/*!IsProjectModified() ||*/ BuildInterrim(project, start))
-         {
-            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
-            if(compiler.type.isVC)
-            {
-               //bool result = false;
-               char oldwd[MAX_LOCATION];
-               char oldPath[MAX_LOCATION * 65];
-               char command[MAX_LOCATION];
-
-               GetEnvironment("PATH", oldPath, sizeof(oldPath));
-               ide.SetPath(false); //true
-               
-               GetWorkingDir(oldwd, sizeof(oldwd));
-               ChangeWorkingDir(project.topNode.path);
-
-               sprintf(command, "%s /useenv %s.sln /projectconfig \"%s|Win32\" /command \"%s\"" , "devenv", project.name, project.config.name, "Debug.Start");
-               //ide.outputView.buildBox.Logf("command: %s\n", command);
-               Execute(command);
-               ChangeWorkingDir(oldwd);
-               SetEnvironment("PATH", oldPath);
-            }
-            else
-            {
-               ide.debugger.Start();
-               result = true;
-            }
-
-            delete compiler;
-         }
-      }
-      return result;      
-   }
-
    bool DebugRestart()
    {
-      if(/*!IsProjectModified() ||*/ BuildInterrim(project, restart))
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      ProjectConfig config = project.config;
+      int bitDepth = ide.workspace.bitDepth;
+      bool useValgrind = ide.workspace.useValgrind;
+
+      bool result = false;
+      if(/*!IsProjectModified() ||*/ BuildInterrim(project, restart, compiler, config, bitDepth, false))
       {
-         ide.debugger.Restart();
-         return true;
+         // For Restart, compiler and config will only be used if for
+         // whatever reason (if at all possible) the Debugger is in a
+         // 'terminated' or 'none' state
+         ide.debugger.Restart(compiler, config, bitDepth, useValgrind);
+         result = true;
       }
-      return false;
+
+      delete compiler;
+      return result;
    }
 
    bool DebugResume()
@@ -1505,15 +2008,42 @@ class ProjectView : Window
 
    bool DebugStepInto()
    {
-      if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start)))
-         ide.debugger.StepInto();
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      ProjectConfig config = project.config;
+      int bitDepth = ide.workspace.bitDepth;
+      bool useValgrind = ide.workspace.useValgrind;
+
+      if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start, compiler, config, bitDepth, false)))
+         ide.debugger.StepInto(compiler, config, bitDepth, useValgrind);
+      delete compiler;
       return true;
    }
 
    bool DebugStepOver(bool skip)
    {
-      if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start)))
-         ide.debugger.StepOver(skip);
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      ProjectConfig config = project.config;
+      int bitDepth = ide.workspace.bitDepth;
+      bool useValgrind = ide.workspace.useValgrind;
+
+      if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start, compiler, config, bitDepth, false)))
+         ide.debugger.StepOver(compiler, config, bitDepth, useValgrind, skip);
+
+      delete compiler;
+      return true;
+   }
+
+   bool DebugStepUntil(bool skip)
+   {
+      CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
+      ProjectConfig config = project.config;
+      int bitDepth = ide.workspace.bitDepth;
+      bool useValgrind = ide.workspace.useValgrind;
+
+      if((ide.debugger.isActive) || (!buildInProgress && BuildInterrim(project, start, compiler, config, bitDepth, false)))
+         ide.debugger.StepUntil(compiler, config, bitDepth, useValgrind, skip);
+
+      delete compiler;
       return true;
    }
 
@@ -1527,11 +2057,28 @@ class ProjectView : Window
    {
       if(toNode)
       {
-         //bool isFolder = toNode.type == folder;
-         //bool isRes = toNode.isInResources;
-         
+         char path[MAX_LOCATION];
+         char currentDir[MAX_LOCATION];
+         ProjectNode node = toNode;
          FileDialog fileDialog = importFileDialog;
          fileDialog.master = parent;
+         while(node)
+         {
+            node.GetFullFilePath(path);
+            while(path[0])
+            {
+               StripLastDirectory(path, path);
+               if(FileExists(path).isDirectory) break;
+            }
+            if(path[0] || node == toNode.project.topNode)
+               node = null;
+            else
+               node = toNode.project.topNode;
+         }
+         MakeSystemPath(path);
+         StripLastDirectory(path, currentDir);
+         fileDialog.currentDirectory = currentDir[0] ? currentDir : path;
+         fileDialog.filePath = path;
          if(fileDialog.Modal() == ok)
          {
             ImportFolderFSI fsi { projectView = this };
@@ -1556,7 +2103,7 @@ class ProjectView : Window
                break;
             after = node;
          }
-         
+
          if(name && name[0])
             folderNode = parentNode.Add(prj, name, after, folder, folder, true);
          else
@@ -1580,11 +2127,11 @@ class ProjectView : Window
             }
             Update(null);
             folderNode.row = parentNode.row.AddRowAfter(after ? after.row : null);
-            folderNode.row.tag = (int)folderNode;
-               
+            folderNode.row.tag = (int64)folderNode;
+
             folderNode.row.SetData(null, folderNode);
             fileList.currentRow = folderNode.row;
-            
+
             if(showProperties)
             {
                nodeProperties = NodeProperties
@@ -1604,7 +2151,7 @@ class ProjectView : Window
    {
       FileDialog fileDialog = (!resources) ? this.fileDialog : resourceFileDialog;
       fileDialog.type = multiOpen;
-      fileDialog.text = !resources ? "Add Files to Project" : "Add Resources to Project";
+      fileDialog.text = !resources ? $"Add Files to Project" : $"Add Resources to Project";
       fileDialog.master = parent;
 
       if(fileDialog.Modal() == ok)
@@ -1614,13 +2161,13 @@ class ProjectView : Window
          ProjectNode parentNode = (ProjectNode)row.tag;
          bool addFailed = false;
          int numSelections = fileDialog.numSelections;
-         char ** multiFilePaths = fileDialog.multiFilePaths;
+         const char * const * multiFilePaths = fileDialog.multiFilePaths;
 
          Array<String> nameConflictFiles { };
 
          for(c = 0; c < numSelections; c++)
          {
-            char * filePath = multiFilePaths[c];
+            const char * filePath = multiFilePaths[c];
             FileAttribs exists = FileExists(filePath);
             bool addThisFile = true;
 
@@ -1628,8 +2175,8 @@ class ProjectView : Window
                addThisFile = false;
             else if(!exists)
             {
-               if(MessageBox { master = ide, type = yesNo, text = filePath, 
-                     contents = "File doesn't exist. Create?" }.Modal() == yes)
+               if(MessageBox { master = ide, type = yesNo, text = filePath,
+                     contents = $"File doesn't exist. Create?" }.Modal() == yes)
                {
                   File f = FileOpen(filePath, write);
                   if(f)
@@ -1639,8 +2186,8 @@ class ProjectView : Window
                   }
                   else
                   {
-                     MessageBox { master = ide, type = ok, text = filePath, 
-                           contents = "Couldn't create file."}.Modal();
+                     MessageBox { master = ide, type = ok, text = filePath,
+                           contents = $"Couldn't create file."}.Modal();
                      addThisFile = false;
                   }
                }
@@ -1658,10 +2205,10 @@ class ProjectView : Window
          if(addFailed)
          {
             int len = 0;
-            char * part1 = "The following file";
-            char * opt1 = " was ";
-            char * opt2 = "s were ";
-            char * part2 = "not added because of identical file name conflict within the project.\n\n";
+            const char * part1 = $"The following file";
+            const char * opt1 = $" was ";
+            const char * opt2 = $"s were ";
+            const char * part2 = $"not added because of identical file name conflict within the project.\n\n";
             char * message;
             len += strlen(part1);
             len += strlen(part2);
@@ -1677,7 +2224,7 @@ class ProjectView : Window
                strcat(message, s);
                strcat(message, "\n");
             }
-            MessageBox { master = ide, type = ok, text = "Name Conflict", 
+            MessageBox { master = ide, type = ok, text = $"Name Conflict",
                   contents = message }.Modal();
             delete message;
          }
@@ -1686,7 +2233,7 @@ class ProjectView : Window
       }
    }
 
-   ProjectNode AddFile(ProjectNode parentNode, char * filePath, bool resources, bool isTemporary)
+   ProjectNode AddFile(ProjectNode parentNode, const char * filePath, bool resources, bool isTemporary)
    {
       ProjectNode result = null;
       ProjectNode after = null;
@@ -1709,13 +2256,13 @@ class ProjectView : Window
          }
          Update(null);
          result.row = parentNode.row.AddRowAfter(after ? after.row : null);
-         result.row.tag = (int)result;
+         result.row.tag = (int64)result;
          result.row.SetData(null, result);
       }
       return result;
    }
 
-   CodeEditor CreateNew(char * upper, char * lower, char * base, char * className)
+   CodeEditor CreateNew(const char * upper, const char * lower, const char * base, char * className)
    {
       CodeEditor codeEditor = null;
       ProjectNode projectNode;
@@ -1751,8 +2298,8 @@ class ProjectView : Window
          Update(null);
          project.ModifiedAllConfigs(true, false, false, true);
          projectNode.row = parentNode.row.AddRowAfter(after ? after.row : null);
-         projectNode.row.tag =(int)projectNode;
-            
+         projectNode.row.tag =(int64)projectNode;
+
          projectNode.row.SetData(null, projectNode);
          fileList.currentRow = projectNode.row;
 
@@ -1767,7 +2314,7 @@ class ProjectView : Window
             subclass(ClassDesignerBase) designerClass = eClass_GetDesigner(baseClass);
             if(designerClass)
             {
-               codeEditor = (CodeEditor)ide.OpenFile(filePath, normal, false, null, whatever, normal);
+               codeEditor = (CodeEditor)ide.OpenFile(filePath, false, false, null, whatever, normal, false);
                strcpy(name, projectNode.name);
                sprintf(name, "%s%d", upper, c);
                if(className)
@@ -1783,20 +2330,24 @@ class ProjectView : Window
          }
          else // TODO: fix no symbols generated when ommiting {} for following else
          {
-            codeEditor = (CodeEditor)ide.OpenFile(filePath, normal, false, null, whatever, normal);
+            codeEditor = (CodeEditor)ide.OpenFile(filePath, false, false, null, whatever, normal, false);
          }
+         ide.sheet.visible = true;
+         ide.sheet.Activate();
          if(codeEditor)
          {
             codeEditor.ViewDesigner();
             codeEditor.codeModified = true;
          }
       }
-      visible = false;
-      return codeEditor;   
+      //visible = false;
+      return codeEditor;
    }
 
-   void OpenSelectedNodes()
+   // Returns true if we opened something
+   bool OpenSelectedNodes(bool noParsing)
    {
+      bool result = false;
       OldList selection;
       OldLink item;
 
@@ -1806,16 +2357,21 @@ class ProjectView : Window
          DataRow row = item.data;
          ProjectNode node = (ProjectNode)row.tag;
          if(node.type == file)
-            OpenNode(node);
+         {
+            OpenNode(node, noParsing);
+            result = true;
+         }
       }
       selection.Free(null);
+      ide.RepositionWindows(false);
+      return result;
    }
 
    void RemoveSelectedNodes()
    {
       OldList selection;
       OldLink item, next;
-      
+
       fileList.GetMultiSelection(selection);
 
       // Remove children of parents we're deleting
@@ -1863,9 +2419,9 @@ class ProjectView : Window
          else if(node.type == folder)
          {
             char message[1024];
-            sprintf(message, "Are you sure you want to remove the folder \"%s\"\n"
+            sprintf(message, $"Are you sure you want to remove the folder \"%s\"\n"
                   "and all of its contents from the project?", node.name);
-            if(MessageBox { master = ide, type = yesNo, text = "Delete Folder", contents = message }.Modal() == yes)
+            if(MessageBox { master = ide, type = yesNo, text = $"Delete Folder", contents = message }.Modal() == yes)
             {
                Project prj = node.project;
                if(node.containsFile)
@@ -1887,8 +2443,8 @@ class ProjectView : Window
                   break;
                }
             }
-            sprintf(message, "Are you sure you want to remove the \"%s\" project\n" "from this workspace?", node.name);
-            if(MessageBox { master = ide, type = yesNo, text = "Remove Project", contents = message }.Modal() == yes)
+            sprintf(message, $"Are you sure you want to remove the \"%s\" project\n" "from this workspace?", node.name);
+            if(MessageBox { master = ide, type = yesNo, text = $"Remove Project", contents = message }.Modal() == yes)
             {
                // THIS GOES FIRST!
                DeleteNode(node);