ecere/gui: DataBox/Label (Tooltips): Fixes to chain through OnDestroy() so that circu...
[sdk] / ecere / src / gui / controls / DataBox.ec
1 namespace gui::controls;
2
3 import "Window"
4
5 default:
6 extern int __ecereVMethodID_class_OnGetString;
7 extern int __ecereVMethodID_class_OnGetDataFromString;
8 extern int __ecereVMethodID_class_OnCompare;
9 extern int __ecereVMethodID_class_OnSerialize;
10 extern int __ecereVMethodID_class_OnUnserialize;
11 extern int __ecereVMethodID_class_OnFree;
12 extern int __ecereVMethodID_class_OnEdit;
13 extern int __ecereVMethodID_class_OnCopy;
14 extern int __ecereVMethodID_class_OnDisplay;
15 extern int __ecereVMethodID_class_OnSaveEdit;
16 private:
17
18 public class DataBox : CommonControl
19 {
20 public:
21    Class type;
22    void * data;
23    void * fieldData;
24    Window editor;
25    bool readOnly;
26    bool keepEditor;
27    bool autoSize;
28    bool needUpdate;
29    String stringValue;
30    needUpdate = true;
31
32    ~DataBox()
33    {
34       delete stringValue;
35    }
36
37    virtual void SetData(any_object newData, bool closingDropDown)
38    {
39       //type._vTbl[__ecereVMethodID_class_OnCopy](type, data, newData);
40       needUpdate = true;
41       if(type)
42       {
43          if(type.type == normalClass || type.type == noHeadClass)
44          {
45             if(((void **)data)[0])
46                type._vTbl[__ecereVMethodID_class_OnFree](type, ((void **)data)[0]);
47             ((void **)data)[0] = newData;
48          }
49          else
50          {
51             // Free old data first
52             type._vTbl[__ecereVMethodID_class_OnFree](type, data);
53             type._vTbl[__ecereVMethodID_class_OnCopy](type, data, newData);
54          }
55       }
56       if(created)
57          NotifyChanged(master, closingDropDown);
58       //editor.Activate();
59    }
60
61    bool SaveData()      // TODO: Clear this up, along with Saving DataBox
62    {
63       if(editor && type._vTbl[__ecereVMethodID_class_OnSaveEdit](type, data, editor, null))
64       {
65          Refresh();
66          NotifyChanged(master, false);
67          // Refresh();
68          return true;
69       }
70       return false;
71    }
72
73    void Modified()
74    {
75       NotifyModified(master);
76    }
77
78    void Refresh()
79    {
80       needUpdate = true;
81       if(created)
82       {
83          if(!keepEditor)
84          {
85             editor.Destroy(0);
86             editor = null;
87          }
88          OnPostCreate();
89       }
90    }
91
92    virtual bool Window::NotifyModified();
93    virtual bool Window::NotifyChanged(bool closingDropDown);
94    virtual void OnConfigure(Window editor);
95
96 private:
97    bool inAutoSize;
98
99    bool OnPostCreate()
100    {
101       if(type && (!readOnly || (autoSize && type._vTbl[__ecereVMethodID_class_OnEdit] == class(Instance)._vTbl[__ecereVMethodID_class_OnEdit])) &&
102          (type.type == normalClass || type.type == noHeadClass || data))
103       {
104          // IMPORTANT FIX: If keepEditor is true, we were passing editor rather than the editor's current master
105          editor = (Window)type._vTbl[__ecereVMethodID_class_OnEdit](type, 
106             (type.type == normalClass || type.type == noHeadClass) ? (data ? (*(void **)data) : null) : data, 
107             this, (keepEditor && editor) ? editor.master : this, 0, 0, clientSize.w, clientSize.h, fieldData);// null);
108          if(editor)
109          {
110             // editor.anchor = { 0, 0, 0, 0 };
111             editor.background = background;
112             editor.foreground = foreground;
113             editor.opacity = opacity;
114 /*#if _DEBUG
115             if(autoSize)
116                PrintLn("DataBox::OnPostCreate -- autoSize == true");
117 #endif*/
118             if(eClass_IsDerived(editor._class, class(EditBox)))
119             {
120                ((EditBox)editor).readOnly = readOnly;
121                ((EditBox)editor).autoSize = autoSize;
122             }
123          }
124          else
125          {
126             // TODO: Should returning 0 from OnPostCreate cancel creation?
127             Destroy(0);
128             return false;
129          }
130       }
131       return true;
132    }
133
134    void OnRedraw(Surface surface)
135    {
136       if(type && !editor)
137       {
138          char tempString[1024];
139          if(type._vTbl[__ecereVMethodID_class_OnDisplay] == class(Instance)._vTbl[__ecereVMethodID_class_OnDisplay])
140          {
141             if(needUpdate)
142             {
143                String s;
144                if(type.type == noHeadClass || type.type == normalClass)
145                   s = (String)type._vTbl[__ecereVMethodID_class_OnGetString](type, *(void **)this.data, tempString, fieldData, null);
146                else
147                   s = (String)type._vTbl[__ecereVMethodID_class_OnGetString](type, this.data, tempString, fieldData, null);
148                delete stringValue;
149                stringValue = CopyString(s);
150                needUpdate = false;
151             }
152             class(String)._vTbl[__ecereVMethodID_class_OnDisplay](class(String), stringValue, surface, 3, 1, clientSize.w, fieldData, type.defaultAlignment, 0);
153          }
154          else
155          {
156             if(type.type == noHeadClass || type.type == normalClass)
157                type._vTbl[__ecereVMethodID_class_OnDisplay](type, *(void **)this.data, surface, 3, 1, clientSize.w, fieldData, type.defaultAlignment, 0);
158             else
159                type._vTbl[__ecereVMethodID_class_OnDisplay](type, this.data, surface, 3, 1, clientSize.w, fieldData, type.defaultAlignment, 0);
160          }
161       }
162    }
163
164    void OnDestroy()
165    {
166       editor = null;
167       CommonControl::OnDestroy();
168    }
169
170    void OnPosition(int x, int y, int width, int height)
171    {
172       if(editor)
173          editor.OnPosition(editor.position.x, editor.position.y, editor.size.w, editor.size.h);
174    }
175
176    bool OnKeyHit(Key key, unichar ch)
177    {
178       return editor ? editor.OnKeyHit(key, ch) : true;
179    }
180
181    bool OnKeyDown(Key key, unichar ch)
182    {
183       if((SmartKey)key == enter)
184       {
185          SaveData();
186          return false;
187       }
188       else if((SmartKey)key == escape)
189       {
190          Refresh();
191          return true;
192       }
193       return editor ? editor.OnKeyDown(key, ch) : true;
194    }
195
196    void OnChildResized(Window child, int x, int y, int w, int h)
197    {
198       if(!inAutoSize && autoSize == true)
199       {
200          inAutoSize = true;
201          clientSize = { w, h };
202          inAutoSize = false;
203       }
204    }
205 };
206
207 public class SavingDataBox : DataBox
208 {
209    class_property(icon) = "<:ecere>controls/dataBox.png";
210    borderStyle = deep;
211    bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
212    {
213       if(!active && editor && !editor.modalSlave)
214       {
215          if(!SaveData())
216             Refresh();
217       }
218       return true;
219    }
220
221    bool OnKeyDown(Key key, unichar ch)
222    {
223       if((SmartKey)key == enter)
224       {
225          if(!SaveData())
226             // Force Refresh on Enter if SaveData didn't do it
227             Refresh();
228          return true;
229       }
230       return DataBox::OnKeyDown(key, ch);
231    }
232 }