sdk: const correctness
[sdk] / ecere / src / gui / controls / PathBox.ec
index 4f7b525..d724db2 100644 (file)
@@ -3,12 +3,25 @@ import "Window"
 import "Array"
 
 default extern int __ecereVMethodID_class_OnGetDataFromString;
-default static void _workAround()
+default __attribute__((unused)) static void _workAround()
 {
    int a;
    a.OnGetDataFromString(0);
 }
 
+
+/* We need a dynamic cast :) Easy eC compiler introduction contribution! :)
+static define pathBoxDataBox =                        dynamic_cast(pathBox.master);
+static define pathBoxListBox = pathBoxEditorDataBox ? dynamic_cast((pathBoxDataBox).parent) : null;
+static define pathBoxDirsBox = pathBoxEditorListBox ? dynamic_cast((pathBoxListBox).parent) : null;
+*/
+static Class _classDataBox() { return class(DataBox); }
+static Class _classListBox() { return class(ListBox); }                              // Fix #908
+static Class _classDirectoriesBox() { return class(DirectoriesBox); }
+static define pathBoxDataBox =                    eClass_IsDerived(         pathBox.master._class, _classDataBox()        ) ?                 (DataBox)pathBox.master : null;
+static define pathBoxListBox = (pathBoxDataBox && eClass_IsDerived((pathBoxDataBox).parent._class, _classListBox()       )) ?        (ListBox)(pathBoxDataBox).parent : null;
+static define pathBoxDirsBox = (pathBoxListBox && eClass_IsDerived((pathBoxListBox).parent._class, _classDirectoriesBox())) ? (DirectoriesBox)(pathBoxListBox).parent : null;
+
 public class FilePath : String
 {
    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
@@ -17,9 +30,16 @@ public class FilePath : String
       {
          dataBox, borderStyle = 0, anchor = { 0, 0, 0, 0 },
          typeExpected = any;
-         browseDialog = userData ? (FileDialog)userData : { type = open, text = $"Select a file..." };
          path = this;
       };
+      DirectoriesBox dirsBox = pathBoxDirsBox;
+      if(dirsBox)
+         pathBox.browseDialog = dirsBox.browseDialog;
+      // TOCHECK: compiler issues?
+      /*else if(userData && eClass_IsDerived(userData._class, class(FileDialog)))
+         pathBox.browseDialog = (FileDialog)userData;*/
+      else
+         pathBox.browseDialog = { type = open, text = $"Select a file..." };
       pathBox.Create();
       return pathBox;
    }
@@ -29,8 +49,11 @@ public class FilePath : String
       bool changed = false;
       if(pathBox.modifiedDocument)
       {
+         DirectoriesBox dirsBox = pathBoxDirsBox;
+         if(dirsBox)
+            dirsBox.NotifyPathBoxModified(dirsBox.master, dirsBox, pathBox);
          String::OnFree();
-         changed = _class._vTbl[__ecereVMethodID_class_OnGetDataFromString](_class, &this, pathBox.systemPath);
+         changed = ((bool (*)(void *, void *, const char *))(void *)_class._vTbl[__ecereVMethodID_class_OnGetDataFromString])(_class, &this, pathBox.systemPath);
       }
       return changed;
    }
@@ -49,12 +72,34 @@ public class DirPath : FilePath
       {
          dataBox, borderStyle = 0, anchor = { 0, 0, 0, 0 },
          typeExpected = directory;
-         browseDialog = userData ? (FileDialog)userData : { type = selectDir, text = $"Select a folder..." };
          path = this;
       };
+      DirectoriesBox dirsBox = pathBoxDirsBox;
+      if(dirsBox)
+         pathBox.browseDialog = dirsBox.browseDialog;
+      // TOCHECK: compiler issues? (same)
+      /*else if(userData && eClass_IsDerived(userData._class, class(FileDialog)))
+         pathBox.browseDialog = (FileDialog)userData;*/
+      else
+         pathBox.browseDialog = { type = selectDir, text = $"Select a folder..." };
       pathBox.Create();
       return pathBox;
    }
+
+   bool OnSaveEdit(PathBox pathBox, void * object)
+   {
+      bool changed = false;
+      if(pathBox.modifiedDocument)
+      {
+         DirectoriesBox dirsBox = pathBoxDirsBox;
+         if(dirsBox)
+            dirsBox.NotifyPathBoxModified(dirsBox.master, dirsBox, pathBox);
+         String::OnFree();
+         changed = ((bool (*)(void *, void *, const char *))(void *)_class._vTbl[__ecereVMethodID_class_OnGetDataFromString])(_class, &this, pathBox.systemPath);
+      }
+      return changed;
+   }
+
 }
 
 public enum PathTypeExpected { none, any, directory, file };
@@ -64,22 +109,15 @@ public class PathBox : CommonControl
    borderStyle = deep;
    clientSize = { 64, 18 };
 
-   watch(background) { editBox.background = background; };
-   watch(foreground) { editBox.foreground = foreground; };
-   watch(opacity)    { editBox.opacity    = opacity; };
-
-#if defined(__WIN32__)
-   PathBox()
-   {
-      path[0] = '\0';
-   }
-#endif
+   watch(background)     { editBox.background = background; };
+   watch(foreground)     { editBox.foreground = foreground; };
+   watch(selectionColor) { editBox.selectionColor = selectionColor; };
+   watch(selectionText)  { editBox.selectionText = selectionText; };
+   watch(opacity)        { editBox.opacity = opacity; };
 
    PathTypeExpected typeExpected;
    FileDialog browseDialog;
-#if defined(__WIN32__)
    char path[MAX_LOCATION];
-#endif
 
    BitmapResource file { "<:ecere>mimeTypes/file.png", transparent = true, alphaBlend = true };
    BitmapResource brokenFile { "<:ecere>mimeTypes/brokenFile.png", transparent = true, alphaBlend = true };
@@ -108,6 +146,10 @@ public class PathBox : CommonControl
       }
       bool NotifyModified(EditBox editBox)
       {
+         PathBox pathBox = this;
+         DirectoriesBox dirsBox = pathBoxDirsBox;
+         if(dirsBox)
+            dirsBox.NotifyPathBoxModified(dirsBox.master, dirsBox, this);
          return NotifyModified(master, this);
       }
 
@@ -137,62 +179,59 @@ public class PathBox : CommonControl
 
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
+         if(modifiedDocument)
+            NotifyModified(master, this);
+
          if(browseDialog)
          {
-            /* We need a reinterpret cast :) Easy eC compiler introduction contribution! :)
-            DataBox dataBox = reinterpret(master);
-            ListBox lb = dataBox ? reinterpret(dataBox.parent) : null;
-            DirectoriesBox dirBox = lb ? reinterpret(lb.parent) : null;
-            */
-            DataBox dataBox = eClass_IsDerived(master._class, class(DataBox)) ? (DataBox)master : null;
-            ListBox lb = ((dataBox && eClass_IsDerived(dataBox.parent._class, class(ListBox))) ? (ListBox)dataBox.parent : null;
-            DirectoriesBox dirBox = ((lb && eClass_IsDerived(lb.parent._class, class(DirectoriesBox))) ? (DirectoriesBox)lb.parent : null;
-            char * browsePath = CopyString(editBox.contents);
-            char fileName[MAX_LOCATION];
-
-            incref this;
-
-            GetLastDirectory(browsePath, fileName);
-            StripLastDirectory(browsePath, browsePath);
-
-            if(!browsePath[0])
-            {
-               char filePath[MAX_LOCATION];
-               delete browsePath;
-               LocateModule(null, filePath);
-               StripLastDirectory(filePath, filePath);
-               browsePath = CopyString(filePath);
-            }
-
+            char browsePath[MAX_LOCATION];
+            PathBox pathBox = this;
+            DataBox dataBox = pathBoxDataBox;
+            ListBox listBox;
+            DirectoriesBox dirsBox = pathBoxDirsBox;
+            const char * ebContents = editBox.contents;
+            String backFilePath = CopyString(browseDialog.filePath);
+            char * baseBrowsePath = dirsBox ? dirsBox.baseBrowsePath : null;
+
+            browsePath[0] = '\0';
+            strncpy(browsePath, browseDialog.filePath, MAX_LOCATION); browsePath[MAX_LOCATION-1] = '\0';
+            if(baseBrowsePath && baseBrowsePath[0] && ((ebContents && ebContents[0]) || !backFilePath || !backFilePath[0]))
+               PathCat(browsePath, baseBrowsePath);
+            PathCat(browsePath, ebContents);
+            browseDialog.filePath = (ebContents && ebContents[0]) ? browsePath : "";
+            if(pathBox.typeExpected == directory && browsePath[0] && FileExists(browsePath).isDirectory && backFilePath && backFilePath[0])
+               StripLastDirectory(browsePath, browsePath);
             while(browsePath[0] && !FileExists(browsePath).isDirectory)
-            {
-               char temp[MAX_LOCATION];
-               GetLastDirectory(browsePath, temp);
-               PathCat(temp, fileName);
-               strcpy(fileName, temp);
                StripLastDirectory(browsePath, browsePath);
+            if(!browsePath[0])
+            {
+               char path[MAX_LOCATION];
+               LocateModule(null, path);
+               StripLastDirectory(path, path);
+               strncpy(browsePath, path, MAX_LOCATION); browsePath[MAX_LOCATION-1] = '\0';
             }
-            browseDialog.filePath = fileName;
             browseDialog.currentDirectory = browsePath;
-            delete browsePath;
             browseDialog.master = rootWindow;
 
-            // THIS PART WAS MISSING IN THE PathBox/DirectoriesBox INTEGRATION AND WAS CRUCIAL
-            if(dirBox) dirBox.browsing = true;
+            incref this;
+            if(dirsBox) dirsBox.browsing = true;
             if(browseDialog.Modal())
             {
                PathBox pathBox = dataBox ? (PathBox)dataBox.editor : this;
                pathBox.modifiedDocument = true;
                pathBox.property::path = browseDialog.filePath;
+               pathBox.NotifyModified(pathBox.master, this);
                if(dataBox)
                   dataBox.SaveData();
                else
                   pathBox.editBox.SelectAll();
-               if(lb) lb.StopEditing(true);
-               pathBox.NotifyModified(pathBox.master, this);
+               if((listBox = pathBoxListBox))
+                  listBox.StopEditing(true);
             }
-            if(dirBox) dirBox.browsing = false;
-
+            else
+               browseDialog.filePath = backFilePath;
+            delete backFilePath;
+            if(dirsBox) dirsBox.browsing = false;
             delete this;
          }
          return true;
@@ -204,8 +243,12 @@ public class PathBox : CommonControl
       if(typeExpected != none)
       {
          BitmapResource icon = null;
-         FileAttribs exists = FileExists(editBox.contents);
-         
+         char path[MAX_LOCATION];
+         FileAttribs exists { };
+         GetSystemPathBuffer(path, editBox.contents);
+         if(!(path[0] == DIR_SEP && path[1] == DIR_SEP && (!path[2] || !strchr(&path[2], DIR_SEP))))
+            exists = FileExists(path);
+
          switch(typeExpected)
          {
             case any:
@@ -241,6 +284,8 @@ public class PathBox : CommonControl
    }
 
 public:
+   virtual bool Window::NotifyModified(PathBox pathBox);
+
    property PathTypeExpected typeExpected
    {
       set
@@ -257,7 +302,7 @@ public:
             typeExpected = value;
             if(browseDialog && browseDialog.type == open && typeExpected == directory)
                browseDialog.type = selectDir;
-         }         
+         }
       }
    }
 
@@ -283,6 +328,7 @@ public:
          browse.visible = browseDialog ? true : false;
          editBox.anchor.right = browseDialog ? 26 : 1;
       }
+      get { return browseDialog; }
    }
 
    void Home() { editBox.Home(); }
@@ -291,7 +337,7 @@ public:
    void SelectAll() { editBox.SelectAll(); }
    void Deselect() { editBox.Deselect(); }
 
-   property String path
+   property const String path
    {
       set
       {
@@ -309,8 +355,6 @@ public:
 
    property Color selectionColor { set { editBox.selectionColor = value; } get { return editBox.selectionColor; }/* isset { return selectionColor ? true : false; }*/ };
    property Color selectionText  { set { editBox.selectionText = value; } get { return editBox.selectionText; }/* isset { return selectionText ? true : false; }*/ };
-
-   virtual bool Window::NotifyModified(PathBox pathBox);
 }
 
 // DirectoriesBox
@@ -318,18 +362,27 @@ FileDialog browseFileDialog { type = selectDir, text = $"Select directory" };
 
 public class DirectoriesBox : CommonControl
 {
+   FileDialog browseDialog;
+   char * baseBrowsePath;
+
 public:
 
    bool browsing;
 
    opacity = 0;
 
+   virtual bool Window::NotifyModified(DirectoriesBox dirsBox);
+   virtual bool Window::NotifyPathBoxModified(DirectoriesBox dirsBox, PathBox pathBox);
+
    virtual bool OnChangedDir(char ** directory);
    virtual bool OnPrepareBrowseDir(char ** directory);
    virtual bool OnBrowsedDir(char ** directory);
 
-   watch(foreground) { list.foreground = foreground; };
-   watch(background) { list.background = background; };
+   watch(foreground)     { list.foreground = foreground; };
+   watch(background)     { list.background = background; };
+   //watch(selectionColor) { list.selectionColor = selectionColor; };
+   //watch(selectionText)  { list.selectionText = selectionText; };
+   watch(opacity)        { list.opacity = opacity; };
 
    property Array<String> strings
    {
@@ -354,7 +407,7 @@ public:
          DataRow row;
          for(row = list.firstRow; row; row = row.next)
          {
-            String string = row.string;
+            const String string = row.string;
             if(string && string[0])
                array.Add(CopyUnixPath(string));
          }
@@ -362,7 +415,39 @@ public:
       }
    }
 
-   virtual bool Window::NotifyModified(DirectoriesBox dirsBox);
+   property FileDialog browseDialog
+   {
+      set
+      {
+         delete browseDialog;
+         browseDialog = value;
+         if(browseDialog)
+         {
+            incref browseDialog;
+            if(browseDialog.type == open)
+               browseDialog.type = selectDir;
+            if(!strcmp(browseDialog.text, "Select a file...") && text)
+            {
+               char temp[1024] = "Select ";
+               strcat(temp, text);
+               strcat(temp, "...");
+               browseDialog.text = temp;
+            }
+         }
+      }
+      get { return browseDialog; }
+   }
+
+   property String baseBrowsePath
+   {
+      set
+      {
+         delete baseBrowsePath;
+         if(value)
+            baseBrowsePath = CopyString(value);
+      }
+      get { return baseBrowsePath; }
+   }
 
    bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
    {
@@ -411,7 +496,7 @@ public:
          return true;
       }
    };
-   Button up
+   RepButton up
    {
       parent = this, bevelOver = true, inactive = true;
       position = { 315, 0 }, size = { 22, 22 };
@@ -436,7 +521,7 @@ public:
          return true;
       }
    };
-   Button down
+   RepButton down
    {
       parent = this, bevelOver = true, inactive = true;
       position = { 340, 0 }, size = { 22, 22 };
@@ -486,11 +571,7 @@ public:
                listBox.SetData(null, dir);
                listBox.modifiedDocument = true;
                if(listBox.currentRow == listBox.lastRow && listBox.lastRow.string)
-               {
-                  DataRow r = listBox.lastRow;
-                  char * s = r.string;
                   listBox.currentRow = listBox.AddString("");
-               }
             }
             delete dir;
          }
@@ -507,8 +588,27 @@ public:
          return true;
       }
 
+      bool NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch)
+      {
+         // Prioritize row moving Ctrl-Up/Down over scrollbar scrolling
+         if(key == ctrlUp || key == ctrlDown)
+         {
+            Button btn = (key == ctrlUp) ? up : down;
+            btn.OnKeyHit(hotKey, 0);
+            return false;
+         }
+         return true;
+      }
+
       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
       {
+         // Prioritize row moving Ctrl-Up/Down over scrollbar scrolling
+         if(key == ctrlUp || key == ctrlDown)
+         {
+            Button btn = (key == ctrlUp) ? up : down;
+            btn.OnKeyDown(hotKey, 0);
+            return false;
+         }
          if(key == del)
          {
             listBox.StopEditing(true);
@@ -539,12 +639,19 @@ public:
          return true;
       }
    };
-   DataField dirField { dataType = class(DirPath), editable = true, userData = browseFileDialog };
+   DataField dirField { dataType = class(DirPath), editable = true };
 
    DirectoriesBox()
    {
+      incref browseFileDialog;
+      browseDialog = browseFileDialog;
       list.AddField(dirField);
       list.AddString("");
       list.modifiedDocument = false;
    }
+   ~DirectoriesBox()
+   {
+      delete browseDialog;
+      delete baseBrowsePath;
+   }
 }