ecere:gui/gfx:drivers/cocoa: Partial native Cocoa drivers implementation for Mac...
[sdk] / ide / src / project / ProjectNode.ec
index 4193c46..0a1a1a2 100644 (file)
@@ -46,59 +46,72 @@ enum NodeIcons
 
    NodeIcons ::SelectFileIcon(char * filePath)
    {
-      char extension[MAX_EXTENSION];
-      GetExtension(filePath, extension);
-      if(!strcmpi(extension, WorkspaceExtension))
-         return ewsFile;
-      else if(!strcmpi(extension, ProjectExtension))
-         return epjFile;
-      else if(!strcmpi(extension, "ec"))
-         return ecFile;
-      else if(!strcmpi(extension, "eh"))
-         return ehFile;
-      else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
-            !strcmpi(extension, "cxx"))
-         return cppFile;
-      else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") ||
-            !strcmpi(extension, "hxx"))
-         return hppFile;
-      else if(!strcmpi(extension, "c"))
-         return cFile;
-      else if(!strcmpi(extension, "h"))
-         return hFile;
-      else if(!strcmpi(extension, "m"))
-         return mFile;
-      else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
-            !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
-         return textFile;
-      else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
-            !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
-            !strcmpi(extension, "js"))
-         return webFile;
-      else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
-            !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
-            !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
-            !strcmpi(extension, "ico"))
-         return pictureFile;
-      else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
-            !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
-         return soundFile;
-      else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
-            !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
-            !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
-            !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
-            !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
-            !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
-         return archiveFile;
-      else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
-            !strcmpi(extension, "rpm"))
-         return packageFile;
-      else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
-            !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
-            !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
-            !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
-         return opticalMediaImageFile;
-      return genFile;
+      NodeIcons icon;
+      if(filePath && filePath[0])
+      {
+         char extension[MAX_EXTENSION];
+         GetExtension(filePath, extension);
+         if(strlen(extension))
+         {
+            if(!strcmpi(extension, WorkspaceExtension))
+               icon = ewsFile;
+            else if(!strcmpi(extension, ProjectExtension))
+               icon = epjFile;
+            else if(!strcmpi(extension, "ec"))
+               icon = ecFile;
+            else if(!strcmpi(extension, "eh"))
+               icon = ehFile;
+            else if(!strcmpi(extension, "cpp") || !strcmpi(extension, "cc") ||
+                  !strcmpi(extension, "cxx"))
+               icon = cppFile;
+            else if(!strcmpi(extension, "hpp") || !strcmpi(extension, "hh") ||
+                  !strcmpi(extension, "hxx"))
+               icon = hppFile;
+            else if(!strcmpi(extension, "c"))
+               icon = cFile;
+            else if(!strcmpi(extension, "h"))
+               icon = hFile;
+            else if(!strcmpi(extension, "m"))
+               icon = mFile;
+            else if(!strcmpi(extension, "txt") || !strcmpi(extension, "text") ||
+                  !strcmpi(extension, "nfo") || !strcmpi(extension, "info"))
+               icon = textFile;
+            else if(!strcmpi(extension, "htm") || !strcmpi(extension, "html") ||
+                  !strcmpi(extension, "css") || !strcmpi(extension, "php") ||
+                  !strcmpi(extension, "js"))
+               icon = webFile;
+            else if(!strcmpi(extension, "bmp") || !strcmpi(extension, "pcx") ||
+                  !strcmpi(extension, "jpg") || !strcmpi(extension, "jpeg") ||
+                  !strcmpi(extension, "gif") || !strcmpi(extension, "png") ||
+                  !strcmpi(extension, "ico"))
+               icon = pictureFile;
+            else if(!strcmpi(extension, "wav") || !strcmpi(extension, "mp3") ||
+                  !strcmpi(extension, "ogg") || !strcmpi(extension, "snd"))
+               icon = soundFile;
+            else if(!strcmpi(extension, "ear") || !strcmpi(extension, "7z") ||
+                  !strcmpi(extension, "rar") || !strcmpi(extension, "zip") ||
+                  !strcmpi(extension, "gz") || !strcmpi(extension, "bz2") ||
+                  !strcmpi(extension, "tar") || !strcmpi(extension, "arj") ||
+                  !strcmpi(extension, "lza") || !strcmpi(extension, "lzh") ||
+                  !strcmpi(extension, "cpio") || !strcmpi(extension, "z"))
+               icon = archiveFile;
+            else if(!strcmpi(extension, "cab") || !strcmpi(extension, "deb") ||
+                  !strcmpi(extension, "rpm"))
+               icon = packageFile;
+            else if(!strcmpi(extension, "iso") || !strcmpi(extension, "mds") ||
+                  !strcmpi(extension, "cue") || !strcmpi(extension, "bin") ||
+                  !strcmpi(extension, "ccd") || !strcmpi(extension, "bwt") ||
+                  !strcmpi(extension, "cdi") || !strcmpi(extension, "nrg"))
+               icon = opticalMediaImageFile;
+            else
+               icon = genFile;
+         }
+         else
+            icon = genFile;
+      }
+      else
+         icon = genFile; // tocheck: error icon?
+      return icon;
    }
 
    NodeIcons ::SelectNodeIcon(NodeTypes type)
@@ -232,9 +245,108 @@ public:
    };
 
    LinkList<ProjectNode> files;
-   ProjectOptions options;
-   Array<PlatformOptions> platforms;
-   List<ProjectConfig> configurations;
+   property ProjectOptions options
+   {
+      get { return project ? project.options : options; }
+      set { if(project) project.options = value; else options = value; }
+      isset { ProjectOptions options = project ? project.options : this.options; return options && !options.isEmpty; }
+   }
+   property Array<PlatformOptions> platforms
+   {
+      get { return project ? project.platforms : platforms; }
+      set
+      {
+         if(project) { project.platforms = value; }
+         else
+         {
+            if(platforms) { platforms.Free(); delete platforms; }
+            if(value)
+            {
+               List<PlatformOptions> empty { };
+               Iterator<PlatformOptions> it { value };
+               platforms = value;
+               for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
+               for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
+               delete empty;
+            }
+         }
+      }
+      isset
+      {
+         Array<PlatformOptions> platforms = project ? project.platforms : this.platforms;
+         if(platforms)
+         {
+            for(p : platforms)
+            {
+               if(p.options && !p.options.isEmpty)
+                  return true;
+            }
+         }
+         return false;
+      }
+   }
+   property List<ProjectConfig> configurations
+   {
+      get { return project ? project.configurations : configurations; }
+      set
+      {
+         if(project) { project.configurations = value; }
+         else
+         {
+            if(configurations) { configurations.Free(); delete configurations; }
+            if(value)
+            {
+               List<ProjectConfig> empty { };
+               Iterator<ProjectConfig> it { value };
+               configurations = value;
+               for(c : configurations)
+               {
+                  bool somethingSet = c.options && !c.options.isEmpty;
+                  // TODO: Implement isset keyword
+                  if(!somethingSet && c.platforms && c.platforms.count)
+                  {
+                     for(p : c.platforms)
+                     {
+                        if(p.options && !p.options.isEmpty)
+                        {
+                           somethingSet = true;
+                           break;
+                        }
+                     }
+                  }
+                  if(!somethingSet)
+                     empty.Add(c);
+               }
+               for(c : empty; it.Find(c)) configurations.Delete(it.pointer);
+               delete empty;
+            }
+         }
+      }
+      isset
+      {
+         if(!parent) return true;
+         if(configurations)
+         {
+            for(c : configurations)
+            {
+               bool somethingSet = c.options && !c.options.isEmpty;
+               if(!somethingSet && c.platforms && c.platforms.count)
+               {
+                  for(p : c.platforms)
+                  {
+                     if(p.options && !p.options.isEmpty)
+                     {
+                        somethingSet = true;
+                        break;
+                     }
+                  }
+               }
+               return somethingSet;
+            }
+         }
+         return false;
+      }
+   }
 
    property ProjectConfig config
    {
@@ -242,10 +354,6 @@ public:
       {
          Project prj;
          ProjectConfig result = null;
-         /*if(configurations)
-            printf("test\n");
-         if(prj)
-            printf("test\n");*/
          if(configurations && (prj = property::project) && prj.config)
          {
             const char * projectConfigName = prj.config.name;
@@ -265,10 +373,10 @@ public:
    ProjectConfig GetMatchingNodeConfig(ProjectConfig config)
    {
       ProjectConfig nodeConfig = null;
-      if(configurations)
+      if(property::configurations)
       {
          const char * configName = config.name;
-         for(cfg : configurations)
+         for(cfg : property::configurations)
          {
             if(!strcmpi(cfg.name, configName))
             {
@@ -285,7 +393,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          SetBool memoryGuard = localMemoryGuard;
          String defaultNameSpace = localDefaultNameSpace;
          SetBool strictNameSpaces = localStrictNameSpaces;
@@ -304,7 +412,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          SetBool memoryGuard = localMemoryGuard;
          if(!memoryGuard)
          {
@@ -319,7 +427,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          String defaultNameSpace = localDefaultNameSpace;
          if(!defaultNameSpace)
          {
@@ -334,7 +442,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          SetBool strictNameSpaces = localStrictNameSpaces;
          if(!strictNameSpaces)
          {
@@ -349,7 +457,7 @@ public:
       get
       {
          ProjectConfig config = this.config;
-         ProjectOptions options = this.options;
+         ProjectOptions options = property::options;
          SetBool noLineNumbers = localNoLineNumbers;
          if(!noLineNumbers)
          {
@@ -360,6 +468,61 @@ public:
       }
    }
 
+   property ProjectNode root { get { ProjectNode n; for(n = this; n.parent; n = n.parent); return n; } }
+
+   property bool containsFile
+   {
+      get
+      {
+         bool result;
+         if(files)
+         {
+            for(child : files)
+            {
+               if(child.type == file ||
+                     ((child.type == folder || child.type == folderOpen) && child.containsFile))
+               {
+                  result = true;
+                  break;
+               }
+            }
+         }
+         else
+            result = false;
+         return result;
+      }
+   }
+
+   char * GetFullFilePath(char * buffer)
+   {
+      if(buffer)
+      {
+         strcpy(buffer, root.path);
+         PathCatSlash(buffer, path);
+         PathCatSlash(buffer, name);
+      }
+      return buffer;
+   }
+
+   char * GetFileSysMatchingPath(char * buffer)
+   {
+      if(buffer)
+      {
+         ProjectNode n, root = this.root;
+         for(n = this; n && (n.type == folder || n.type == project); n = n.parent)
+         {
+            strcpy(buffer, root.path);
+            if(n != root)
+               PathCatSlash(buffer, n.path);
+            if(FileExists(buffer).isDirectory)
+               break;
+         }
+         if(!(n && (n.type == folder || n.type == project)))
+            buffer[0] = '\0';
+      }
+      return buffer;
+   }
+
    void CollectPerFileAndDirOptions(ProjectConfig projectConfig, Array<String> perFilePreprocessorDefs, Array<DirPath> perFileIncludeDirs)
    {
       ProjectNode node = null;
@@ -374,9 +537,10 @@ public:
       // TODO: Check how to fix duplication of following options when configuration is made per-config-per-file
       while((node = nodeStack.lastIterator.data))
       {
-         if(node.options && node.options.preprocessorDefinitions)
+         ProjectOptions nodeOptions = node.property::options;
+         if(nodeOptions && nodeOptions.preprocessorDefinitions)
          {
-            for(def : node.options.preprocessorDefinitions)
+            for(def : nodeOptions.preprocessorDefinitions)
                perFilePreprocessorDefs.Add(CopyString(def));
          }
          if(config && config.options && config.options.preprocessorDefinitions)
@@ -384,9 +548,9 @@ public:
             for(def : config.options.preprocessorDefinitions)
                perFilePreprocessorDefs.Add(CopyString(def));
          }
-         if(node.options && node.options.includeDirs)
+         if(nodeOptions && nodeOptions.includeDirs)
          {
-            for(dir : node.options.includeDirs)
+            for(dir : nodeOptions.includeDirs)
                perFileIncludeDirs.Add(CopySystemPath(dir));
          }
          if(config && config.options && config.options.includeDirs)
@@ -400,6 +564,9 @@ public:
    }
 
 private:
+   ProjectOptions options;
+   Array<PlatformOptions> platforms;
+   List<ProjectConfig> configurations;
    ProjectNodeType nodeType;
    ProjectNode parent;
    char * name;
@@ -437,9 +604,9 @@ private:
       {
          for(f : files; (f.configurations || f.files)) { f.RenameConfig(oldName, newName); }
       }
-      if(configurations)
+      if(property::configurations)
       {
-         for(c : configurations; !strcmp(c.name, oldName))
+         for(c : property::configurations; !strcmp(c.name, oldName))
          {
             delete c.name;
             c.name = CopyString(newName);
@@ -453,9 +620,9 @@ private:
       {
          for(f : files; (f.configurations || f.files)) { f.DeleteConfig(configToDelete); }
       }
-      if(configurations)
+      if(property::configurations)
       {
-         Iterator<ProjectConfig> c { configurations };
+         Iterator<ProjectConfig> c { property::configurations };
          while(c.Next())
          {
             ProjectConfig config = c.data;
@@ -466,10 +633,8 @@ private:
                break;
             }
          }
-         if(!configurations.count)
-         {
-            delete configurations;
-         }
+         if(!property::configurations.count)
+            property::configurations = null;
       }
    }
 
@@ -482,20 +647,20 @@ private:
          backupNode.files = { };
          for(f : files) backupNode.files.Add(f.Backup());
       }
-      if(options)
-         backupNode.options = options.Copy();
+      if(property::options)
+         backupNode.options = property::options.Copy();
 
-      if(platforms)
+      if(property::platforms)
       {
          backupNode.platforms = { };
-         for(p : platforms)
+         for(p : property::platforms)
             backupNode.platforms.Add(p.Copy());
       }
 
-      if(configurations)
+      if(property::configurations)
       {
          backupNode.configurations = { };
-         for(c : configurations)
+         for(c : property::configurations)
             backupNode.configurations.Add(c.Copy());
       }
       return backupNode;
@@ -513,28 +678,19 @@ private:
          }
       }
 
-      delete options;
-      if(platforms)
-      {
-         platforms.Free();
-         delete platforms;
-      }
-      if(configurations)
-      {
-         configurations.Free();
-         delete configurations;
-      }
-
-      options = backupNode.options ? backupNode.options.Copy() : null;
+      property::options = backupNode.options ? backupNode.options.Copy() : null;
       if(backupNode.platforms)
       {
-         platforms = { };
+         Array<PlatformOptions> platforms { };
+         property::platforms = platforms;
+
          for(p : backupNode.platforms)
             platforms.Add(p.Copy());
       }
       if(backupNode.configurations)
       {
-         configurations = { };
+         List<ProjectConfig> configurations { };
+         property::configurations = configurations;
          for(c : backupNode.configurations)
             configurations.Add(c.Copy());
       }
@@ -595,7 +751,7 @@ private:
       if(!needClass)
       {
          // TOCHECK: Called from JSON writer
-         if(nodeType == file && !options && !configurations && !platforms && name)
+         if(nodeType == file && !property::options && !property::configurations && !property::platforms && name)
          {
             strcpy(tempString, "\"");
             strcat(tempString, property::fileName);
@@ -617,14 +773,15 @@ private:
          files.Free();
          delete files;
       }
-      delete options;
+      if(!project)
+         delete options;
 
-      if(platforms)
+      if(!project && platforms)
       {
          platforms.Free();
          delete platforms;
       };
-      if(configurations)
+      if(!project && configurations)
       {
          configurations.Free();
          delete configurations;
@@ -650,95 +807,167 @@ private:
       }
    }
 
-   property TwoStrings platformSpecificExclusionFu
+   property TwoStrings platformSpecificFu
    {
       get
       {
-         // TODO: Proper folder exclusion fix: collect platform names across parents and then build exclusion expression
-         //       Find solution to excluding a drivers folder for all platforms and overriting that exclusion on children files/folders
-         TwoStrings result { };
-         int nestingCount = 0, c, len;
-         Platform platform;
-         ProjectConfig config = property::config;
-         Map<String, bool> platformNames { };
-         if(platforms)
-         {
-            for(p : platforms)
-               if(p.options.excludeFromBuild == true)
-                  platformNames[p.name] = true;
-         }
-         if(config && config.platforms)
+         TwoStrings result { a = CopyString(""), b = CopyString("") };
+         // note: unknown platform is for common
+         Map<Platform, SetBool> exclusionInfo { };
+         MapNode<Platform, SetBool> mn;
+         char * exp, * var;
+         int len;
+         SetBool common;
+
+         CollectExclusionInfo(exclusionInfo);
+         common = exclusionInfo[unknown];
          {
-            for(p : config.platforms)
-               if(p.options.excludeFromBuild == true)
-                  platformNames[p.name] = true;
+            Map<Platform, SetBool> cleaned { };
+            SetBool opposite = common == true ? false : true;
+            for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
+            {
+               if(mn.key == unknown || mn.value == opposite)
+                 cleaned[mn.key] = mn.value;
+            }
+            delete exclusionInfo;
+            exclusionInfo = cleaned;
          }
-         if(platformNames.count)
+
+         if(exclusionInfo.count > 1)
          {
-            len = 0;
-            result.a = new char[1];
-            result.a[0] = '\0';
-            for(s : platformNames)
+            if(exclusionInfo.count > 2)
             {
-               for(platform = (Platform)1; platform < Platform::enumSize; platform++)
-                  if(!strcmpi(&s, platform))
-                     break;
-               if(platform < Platform::enumSize)
+               exp = result.a;
+               len = strlen(exp) + strlen("$(if $(or ");
+               exp = renew exp char[len+1];
+               strcat(exp, "$(if $(or ");
+               result.a = exp;
+
+               for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
                {
-                  const char * opening = "$(if $(";
-                  const char * close = "),,";
-                  char * t = PlatformToMakefileVariable(platform);
-                  nestingCount++;
-                  len += strlen(t) + strlen(opening) + strlen(close);
-                  result.a = renew result.a char[len + 1];
-                  strcat(result.a, opening);
-                  strcat(result.a, t);
-                  strcat(result.a, close);
+                  if(mn.key != unknown)
+                  {
+                     char * comma = mn.next ? "," : "";
+
+                     var = PlatformToMakefileVariable(mn.key);
+
+                     exp = result.a;
+                     len = strlen(exp) + strlen("$(") + strlen(var) + strlen(")") + strlen(comma);
+                     exp = renew exp char[len+1];
+                     strcat(exp, "$(");
+                     strcat(exp, var);
+                     strcat(exp, ")");
+                     strcat(exp, comma);
+                     result.a = exp;
+                  }
                }
+
+               exp = result.a;
+               len = strlen(exp) + strlen("),");
+               exp = renew exp char[len+1];
+            }
+            else
+            {
+               if(exclusionInfo.root.minimum.key != unknown)
+                  var = PlatformToMakefileVariable(exclusionInfo.root.minimum.key);
+               else
+                  var = PlatformToMakefileVariable(exclusionInfo.root.minimum.next.key);
+
+               exp = result.a;
+               len = strlen(exp) + strlen("$(if $(") + strlen(var) + strlen("),");
+               exp = renew exp char[len+1];
+               strcat(exp, "$(if $(");
+               strcat(exp, var);
             }
-            result.b = new char[nestingCount + 1];
-            for(c = 0; c < nestingCount; c++)
-               result.b[c] = ')';
-            result.b[nestingCount] = '\0';
+
+            strcat(exp, "),");
+            result.a = exp;
+
+            exp = common == true ? result.b : result.a;
+            len = strlen(exp) + strlen(",");
+            exp = renew exp char[len+1];
+            strcat(exp, ",");
+            if(common == true) result.b = exp; else result.a = exp;
+
+            exp = result.b;
+            len = strlen(exp) + strlen(")");
+            exp = renew exp char[len+1];
+            strcat(exp, ")");
+            result.b = exp;
          }
+         delete exclusionInfo;
+         
+         return result;
+      }
+   }
+
+   property bool isExcluded
+   {
+      get
+      {
+         bool result;
+         // note: unknown platform is for common
+         Map<Platform, SetBool> exclusionInfo { };
+         CollectExclusionInfo(exclusionInfo);
+         if(exclusionInfo.count == 0)
+            result = false;
+         else if(exclusionInfo.count == 1)
+            result = exclusionInfo.root.minimum.value == true;
          else
          {
-            result.a = CopyString("");
-            result.b = CopyString("");
-         }
-         delete platformNames;
-         if(parent)
-         {
-            TwoStrings parentResult = parent.platformSpecificExclusionFu;
-            if(parentResult.a && parentResult.a[0])
+            SetBool check = exclusionInfo.root.minimum.value;
+            MapNode<Platform, SetBool> mn;
+            for(mn = exclusionInfo.root.minimum; mn; mn = mn.next)
             {
-               len = strlen(result.a) + strlen(parentResult.a);
-               result.a = renew result.a char[len + 1];
-               strcat(result.a, parentResult.a);
-               len = strlen(result.b) + strlen(parentResult.b);
-               result.b = renew result.b char[len + 1];
-               strcat(result.b, parentResult.b);
+               if(check != mn.value)
+                  break;
             }
-            delete parentResult;
+            if(!mn) // all are same
+               result = check == true;
+            else
+               result = false;
          }
+         delete exclusionInfo;
          return result;
+
       }
    }
 
-   property bool isExcluded
+   void CollectExclusionInfo(Map<Platform, SetBool> output)
    {
-      get
+      // note: unknown platform is for common
+      Platform platform;
+      ProjectConfig config = property::config;
+      ProjectOptions options = property::options;
+      Array<PlatformOptions> platforms = property::platforms;
+      List<ProjectConfig> configurations = property::configurations;
+
+      if(parent)
+         parent.CollectExclusionInfo(output);
+      else
+         output[unknown] = unset;
+
+      if(options && options.excludeFromBuild)
+         output[unknown] = options.excludeFromBuild;
+      
+      if(config && config.options && config.options.excludeFromBuild)
+         output[unknown] = config.options.excludeFromBuild;
+
+      if(platforms)
       {
-         // THIS IS THE GENERIC (ALL PLATFORMS) EXCLUDED FROM BUILD
-         // TODO: We can also have platform specific exclusion...
-         ProjectConfig config = property::config;
-         if(config && config.options && config.options.excludeFromBuild)
-            return config.options.excludeFromBuild == true;            
-         if(options && options.excludeFromBuild)
-            return options.excludeFromBuild == true;
-         if(parent)
-            return parent.isExcluded;
-         return false;
+         for(p : platforms)
+         {
+            if(p.options.excludeFromBuild && (platform = p.name))
+               output[platform] = p.options.excludeFromBuild;
+         }
+      }
+      if(config && config.platforms)
+      {
+         for(p : config.platforms)
+         {
+            if(p.options.excludeFromBuild && (platform = p.name))
+               output[platform] = p.options.excludeFromBuild;
+         }
       }
    }
 
@@ -831,13 +1060,73 @@ private:
       return result;
    }
 
+   ProjectNode FindSameNameConflict(char * name, bool includeResources, Map<Platform, SetBool> exclusionInfo)
+   {
+      ProjectNode result = null;
+      Map<Platform, SetBool> compareExclusion { };
+      SetBool common, commonComp;
+      SetBool actual, actualComp;
+      if(files)
+      {
+         for(child : files)
+         {
+            if(includeResources || child.type != resources)
+            {
+               if(child.type != folder && child.name && !strcmpi(child.name, name))
+               {
+                  child.CollectExclusionInfo(compareExclusion);
+                  common = exclusionInfo[unknown];
+                  commonComp = compareExclusion[unknown];
+                  if(exclusionInfo.count == 1 && compareExclusion.count == 1)
+                  {
+                     if(!(common == true || commonComp == true))
+                     {
+                        result = child;
+                        break;
+                     }
+                  }
+                  else
+                  {
+                     Platform platform;
+                     for(platform = (Platform)1; platform < Platform::enumSize; platform++)
+                     {
+                        actual = common;
+                        actualComp = commonComp;
+                        if(exclusionInfo[platform] != unset)
+                           actual = exclusionInfo[platform];
+                        if(compareExclusion[platform] != unset)
+                           actualComp = compareExclusion[platform];
+                        if(!(actual == true || actualComp == true))
+                        {
+                           result = child;
+                           break;
+                        }
+                     }
+                     if(result) break;
+                  }
+                  compareExclusion.Free();
+                  break;
+               }
+               result = child.FindSameNameConflict(name, includeResources, exclusionInfo);
+               if(result) break;
+            }
+         }
+         compareExclusion.Free();
+      }
+      delete compareExclusion;
+      return result;
+   }
+
    ProjectNode Add(Project project, char * filePath, ProjectNode after, NodeTypes type, NodeIcons icon, bool checkIfExists)
    {
       ProjectNode node = null;
       char temp[MAX_LOCATION];
+      Map<Platform, SetBool> exclusionInfo { };
 
       GetLastDirectory(filePath, temp);
-      if(!checkIfExists || !project.topNode.Find(temp, false))
+      //if(!checkIfExists || !project.topNode.Find(temp, false))
+      CollectExclusionInfo(exclusionInfo);
+      if(!checkIfExists || !project.topNode.FindSameNameConflict(temp, false, exclusionInfo))
       {
          // Do the check for folder in the same parent or resource files only here
          if(type == folder || !checkIfExists)
@@ -857,9 +1146,12 @@ private:
          }
          if(type != folder)
          {
-            StripLastDirectory(filePath, temp);
-            MakePathRelative(temp, project.topNode.path, temp);
-            node.path = CopyUnixPath(temp);
+            if(filePath)
+            {
+               StripLastDirectory(filePath, temp);
+               MakePathRelative(temp, project.topNode.path, temp);
+               node.path = CopyUnixPath(temp);
+            }
             node.nodeType = file;
          }
          else
@@ -870,6 +1162,7 @@ private:
          }
          files.Insert(after, node);
       }
+      delete exclusionInfo;
       return node;
    }
 
@@ -960,9 +1253,9 @@ private:
             {
                surface.LineStipple(0x5555);
                if(displayFlags.selected)
-                  surface.SetForeground(0xFFFFFF80);
+                  surface.SetForeground(projectView.fileList.stippleColor);
                else
-                  surface.SetForeground(black);
+                  surface.SetForeground(projectView.fileList.foreground);
             }
             else
             {
@@ -1006,13 +1299,14 @@ private:
 
       while((node = nodeStack.lastIterator.data))
       {
+         ProjectOptions nodeOptions = node.property::options;
          ProjectConfig config = node.config;
-         if(node.options && node.options.preprocessorDefinitions)
-            OutputListOption(f, "D", node.options.preprocessorDefinitions, inPlace, false);
+         if(nodeOptions && nodeOptions.preprocessorDefinitions)
+            OutputListOption(f, "D", nodeOptions.preprocessorDefinitions, inPlace, false);
          if(config && config.options && config.options.preprocessorDefinitions)
             OutputListOption(f, "D", config.options.preprocessorDefinitions, inPlace, false);
-         if(node.options && node.options.includeDirs)
-            OutputListOption(f, "I", node.options.includeDirs, inPlace, true);
+         if(nodeOptions && nodeOptions.includeDirs)
+            OutputListOption(f, "I", nodeOptions.includeDirs, inPlace, true);
          if(config && config.options && config.options.includeDirs)
             OutputListOption(f, "I", config.options.includeDirs, inPlace, true);
 
@@ -1070,8 +1364,7 @@ private:
       if(type == file)
       {
          char s[2048];
-         // TOCHECK: Does this take care of parent folder platform specific exclusions?
-         TwoStrings ts = platformSpecificExclusionFu;
+         TwoStrings ts = platformSpecificFu;
          char moduleName[MAX_FILENAME];
          char extension[MAX_EXTENSION];
          GetExtension(name, extension);
@@ -1265,7 +1558,11 @@ private:
                modulePath, moduleName, extension, moduleName);
             */
 
-            f.Printf("\t$(ECP) $(CECFLAGS)");
+            f.Printf("\t$(ECP)");
+            // Give priority to file flags
+            GenFileFlags(f, project);
+
+            f.Printf(" $(CECFLAGS)");
             if(ecflags)
             {
                if(memoryGuard)
@@ -1281,7 +1578,7 @@ private:
             else
                f.Printf(" $(ECFLAGS)");
             f.Printf(" $(CFLAGS)");
-            GenFileFlags(f, project);
+
             f.Printf(" -c %s%s.%s -o $(OBJ)%s.sym\n\n",
                modulePath, moduleName, extension, moduleName);
          }
@@ -1409,6 +1706,8 @@ private:
          */
 
             f.Printf("\t$(ECC)");
+            // Give priority to file flags
+            GenFileFlags(f, project);
             if(ecflags)
             {
                f.Printf("%s $(CECFLAGS)", noLineNumbers ? " -nolinenumbers" : "");
@@ -1425,7 +1724,7 @@ private:
             else
                f.Printf(" $(CECFLAGS) $(ECFLAGS)");
             f.Printf(" $(CFLAGS) $(FVISIBILITY)");
-            GenFileFlags(f, project);
+
             f.Printf(" -c %s%s.%s -o $(OBJ)%s.c -symbols $(OBJ)\n\n",
                modulePath, moduleName, extension, moduleName);
          }
@@ -1460,9 +1759,9 @@ private:
          /*if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
                !strcmpi(extension, "ec") || !strcmpi(extension, "cc") ||
                !strcmpi(extension, "cxx"))*/
-         if((!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
-               !strcmpi(extension, "cc") || !strcmpi(extension, "cxx")) ||
-               !strcmpi(extension, "ec"))
+         if(!strcmpi(extension, "c") || !strcmpi(extension, "cpp") ||
+               !strcmpi(extension, "cc") || !strcmpi(extension, "cxx") ||
+               !strcmpi(extension, "m") || !strcmpi(extension, "ec"))
          {
             DualPipe dep;
             char command[2048];
@@ -1564,8 +1863,12 @@ private:
                }
 #endif
             }
-            f.Printf("\t$(CC) $(CFLAGS)");
+            f.Printf("\t$(CC)");
+            // Give priority to file flags
             GenFileFlags(f, project);
+
+            f.Printf(" $(CFLAGS)");
+
             if(!strcmpi(extension, "ec"))
                f.Printf(" $(FVISIBILITY) -c $(OBJ)%s.c -o $(OBJ)%s.o\n\n", moduleName, moduleName);
             else
@@ -1600,7 +1903,7 @@ private:
          for(c = 0; c < files.count; c++)
          {
             ProjectNode child = files[c];
-            TwoStrings ts = child.platformSpecificExclusionFu;
+            TwoStrings ts = child.platformSpecificFu;
             if(count > 0 && ts)
                prev = true;
             if(child.type == file && !child.isExcluded && !(count > 0 && ts))