compiler/libec; ecere; ide: Safer default virtual method calls
[sdk] / ecere / src / gui / controls / DataBox.ec
index 5dc721e..7d3932f 100644 (file)
@@ -24,37 +24,47 @@ public:
    Window editor;
    bool readOnly;
    bool keepEditor;
+   bool autoSize;
+   bool needUpdate;
+   String stringValue;
+   needUpdate = true;
 
-   virtual void SetData(any_object newData, bool closingDropDown)
+   ~DataBox()
    {
-      //type._vTbl[__ecereVMethodID_class_OnCopy](type, data, newData);
+      delete stringValue;
+   }
 
+   virtual void SetData(any_object newData, bool closingDropDown)
+   {
+      //((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCopy])(type, data, newData);
+      needUpdate = true;
       if(type)
       {
          if(type.type == normalClass || type.type == noHeadClass)
          {
             if(((void **)data)[0])
-               type._vTbl[__ecereVMethodID_class_OnFree](type, ((void **)data)[0]);
+               ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, ((void **)data)[0]);
             ((void **)data)[0] = newData;
          }
          else
          {
             // Free old data first
-            type._vTbl[__ecereVMethodID_class_OnFree](type, data);
-            type._vTbl[__ecereVMethodID_class_OnCopy](type, data, newData);
+            ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
+            ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCopy])(type, data, newData);
          }
       }
       if(created)
-         NotifyChanged(master, closingDropDown);
+         NotifyChanged(master, this, closingDropDown);
       //editor.Activate();
    }
 
    bool SaveData()      // TODO: Clear this up, along with Saving DataBox
    {
-      if(editor && type._vTbl[__ecereVMethodID_class_OnSaveEdit](type, data, editor, null))
+      bool (* onSaveEdit)(void *, void *, Window, void *) = (void *)type._vTbl[__ecereVMethodID_class_OnSaveEdit];
+      if(editor && (!onSaveEdit || onSaveEdit(type, data, editor, null)))
       {
          Refresh();
-         NotifyChanged(master, false);
+         NotifyChanged(master, this, false);
          // Refresh();
          return true;
       }
@@ -68,6 +78,7 @@ public:
 
    void Refresh()
    {
+      needUpdate = true;
       if(created)
       {
          if(!keepEditor)
@@ -80,25 +91,51 @@ public:
    }
 
    virtual bool Window::NotifyModified();
-   virtual bool Window::NotifyChanged(bool closingDropDown);
+   virtual bool Window::NotifyChanged(DataBox dataBox, bool closingDropDown);
    virtual void OnConfigure(Window editor);
 
 private:
+   bool inAutoSize;
+
+   watch(background)     { if(editor) editor.background = background; };
+   watch(foreground)     { if(editor) editor.foreground = foreground; };
+   //watch(selectionColor) { if(editor) editor.selectionColor = selectionColor; };
+   //watch(selectionText)  { if(editor) editor.selectionText = selectionText; };
+   watch(opacity)        { if(editor) editor.opacity = opacity; };
 
    bool OnPostCreate()
    {
-      if(type && !readOnly && (type.type == normalClass || type.type == noHeadClass || data))
+      // Right now for read-only DataBoxes the only reason we'd want to create an editor is for autoSize purposes, when using the default EditBox editor that supports it.
+      // ( A tweak for enum classes is in typeEdit.ec, as the base class editor invokes it )
+      if(type/* && (!readOnly || (autoSize && type._vTbl[__ecereVMethodID_class_OnEdit] == class(Instance)._vTbl[__ecereVMethodID_class_OnEdit]))*/ &&
+         (type.type == normalClass || type.type == noHeadClass || data))
       {
          // IMPORTANT FIX: If keepEditor is true, we were passing editor rather than the editor's current master
-         editor = (Window)type._vTbl[__ecereVMethodID_class_OnEdit](type, 
-            (type.type == normalClass || type.type == noHeadClass) ? (data ? (*(void **)data) : null) : data, 
+         editor = ((Window (*)(void *, void *, DataBox, void *, int, int, int, int, void*))(void *)type._vTbl[__ecereVMethodID_class_OnEdit])(type,
+            (type.type == normalClass || type.type == noHeadClass) ? (data ? (*(void **)data) : null) : data,
             this, (keepEditor && editor) ? editor.master : this, 0, 0, clientSize.w, clientSize.h, fieldData);// null);
+         if(editor && readOnly && !eClass_IsDerived(editor._class, class(EditBox)) &&
+               !(autoSize && type._vTbl[__ecereVMethodID_class_OnEdit] == class(Instance)._vTbl[__ecereVMethodID_class_OnEdit]))
+         {
+            editor.Destroy(0);
+            editor = null;
+            return true;
+         }
          if(editor)
          {
             // editor.anchor = { 0, 0, 0, 0 };
             editor.background = background;
             editor.foreground = foreground;
             editor.opacity = opacity;
+            if(eClass_IsDerived(editor._class, class(EditBox)))
+            {
+               ((EditBox)editor).readOnly = readOnly;
+               if(autoSize)
+                  ((EditBox)editor).autoSize = autoSize;
+               ((EditBox)editor).clickThrough = true;
+            }
+            else if(eClass_IsDerived(editor._class, class(Button)) && autoSize)
+               size = editor.size;
          }
          else
          {
@@ -112,19 +149,38 @@ private:
 
    void OnRedraw(Surface surface)
    {
-      if(type)
+      if(type && data && (!editor || !editor.created || editor.anchor.left)) // ColorDropBox lets part of the DataBox show
       {
-         //type._vTbl[__ecereVMethodID_class_OnDisplay](type, this.data, surface, 3, 2, clientSize.w, null, type.defaultAlignment, 0);
-         if(type.type == noHeadClass || type.type == normalClass)
-            type._vTbl[__ecereVMethodID_class_OnDisplay](type, *(void **)this.data, surface, 3, 1, clientSize.w, fieldData, type.defaultAlignment, 0);
+         char tempString[1024];
+         if(type._vTbl[__ecereVMethodID_class_OnDisplay] == class(Instance)._vTbl[__ecereVMethodID_class_OnDisplay])
+         {
+            if(needUpdate)
+            {
+               const String s;
+               if(type.type == noHeadClass || type.type == normalClass)
+                  s = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, *(void **)this.data, tempString, fieldData, null);
+               else
+                  s = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, this.data, tempString, fieldData, null);
+               delete stringValue;
+               stringValue = CopyString(s);
+               needUpdate = false;
+            }
+            ((void (*)(void *, void *, void *, int, int, int, void *, uint, uint))(void *)class(String)._vTbl[__ecereVMethodID_class_OnDisplay])(class(String), stringValue, surface, 3, 1, clientSize.w, fieldData, type.defaultAlignment, 0);
+         }
          else
-            type._vTbl[__ecereVMethodID_class_OnDisplay](type, this.data, surface, 3, 1, clientSize.w, fieldData, type.defaultAlignment, 0);
+         {
+            if(type.type == noHeadClass || type.type == normalClass)
+               ((void (*)(void *, void *, void *, int, int, int, void *, uint, uint))(void *)type._vTbl[__ecereVMethodID_class_OnDisplay])(type, *(void **)this.data, surface, 3, 1, clientSize.w, fieldData, type.defaultAlignment, 0);
+            else
+               ((void (*)(void *, void *, void *, int, int, int, void *, uint, uint))(void *)type._vTbl[__ecereVMethodID_class_OnDisplay])(type, this.data, surface, 3, 1, clientSize.w, fieldData, type.defaultAlignment, 0);
+         }
       }
    }
 
    void OnDestroy()
    {
       editor = null;
+      CommonControl::OnDestroy();
    }
 
    void OnPosition(int x, int y, int width, int height)
@@ -152,6 +208,16 @@ private:
       }
       return editor ? editor.OnKeyDown(key, ch) : true;
    }
+
+   void OnChildResized(Window child, int x, int y, int w, int h)
+   {
+      if(!inAutoSize && autoSize == true)
+      {
+         inAutoSize = true;
+         clientSize = { w, h };
+         inAutoSize = false;
+      }
+   }
 };
 
 public class SavingDataBox : DataBox
@@ -172,9 +238,25 @@ public class SavingDataBox : DataBox
    {
       if((SmartKey)key == enter)
       {
-         SaveData();
+         if(!SaveData())
+            // Force Refresh on Enter if SaveData didn't do it
+            Refresh();
          return true;
       }
       return DataBox::OnKeyDown(key, ch);
    }
+
+   bool OnResizing(int * w, int * h)
+   {
+      if(!*w || !*h)
+      {
+         int spaceH;
+         display.FontExtent(fontObject, " ", 1, null, &spaceH);
+         if(!*h)
+            *h = spaceH + 2;
+         if(!*w)
+            *w = spaceH * 80 / 14;
+      }
+      return true;
+   }
 }