sdk: const correctness
[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       //((void (*)(void *, void *, void *))(void *)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                ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, ((void **)data)[0]);
47             ((void **)data)[0] = newData;
48          }
49          else
50          {
51             // Free old data first
52             ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
53             ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCopy])(type, data, newData);
54          }
55       }
56       if(created)
57          NotifyChanged(master, this, closingDropDown);
58       //editor.Activate();
59    }
60
61    bool SaveData()      // TODO: Clear this up, along with Saving DataBox
62    {
63       if(editor && ((bool (*)(void *, void *, Window, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSaveEdit])(type, data, editor, null))
64       {
65          Refresh();
66          NotifyChanged(master, this, 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(DataBox dataBox, bool closingDropDown);
94    virtual void OnConfigure(Window editor);
95
96 private:
97    bool inAutoSize;
98
99    watch(background)     { if(editor) editor.background = background; };
100    watch(foreground)     { if(editor) editor.foreground = foreground; };
101    //watch(selectionColor) { if(editor) editor.selectionColor = selectionColor; };
102    //watch(selectionText)  { if(editor) editor.selectionText = selectionText; };
103    watch(opacity)        { if(editor) editor.opacity = opacity; };
104
105    bool OnPostCreate()
106    {
107       // 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.
108       // ( A tweak for enum classes is in typeEdit.ec, as the base class editor invokes it )
109       if(type/* && (!readOnly || (autoSize && type._vTbl[__ecereVMethodID_class_OnEdit] == class(Instance)._vTbl[__ecereVMethodID_class_OnEdit]))*/ &&
110          (type.type == normalClass || type.type == noHeadClass || data))
111       {
112          // IMPORTANT FIX: If keepEditor is true, we were passing editor rather than the editor's current master
113          editor = ((Window (*)(void *, void *, DataBox, void *, int, int, int, int, void*))(void *)type._vTbl[__ecereVMethodID_class_OnEdit])(type,
114             (type.type == normalClass || type.type == noHeadClass) ? (data ? (*(void **)data) : null) : data,
115             this, (keepEditor && editor) ? editor.master : this, 0, 0, clientSize.w, clientSize.h, fieldData);// null);
116          if(editor && readOnly && !eClass_IsDerived(editor._class, class(EditBox)) &&
117                !(autoSize && type._vTbl[__ecereVMethodID_class_OnEdit] == class(Instance)._vTbl[__ecereVMethodID_class_OnEdit]))
118          {
119             editor.Destroy(0);
120             editor = null;
121             return true;
122          }
123          if(editor)
124          {
125             // editor.anchor = { 0, 0, 0, 0 };
126             editor.background = background;
127             editor.foreground = foreground;
128             editor.opacity = opacity;
129             if(eClass_IsDerived(editor._class, class(EditBox)))
130             {
131                ((EditBox)editor).readOnly = readOnly;
132                ((EditBox)editor).autoSize = autoSize;
133                ((EditBox)editor).clickThrough = true;
134             }
135             else if(eClass_IsDerived(editor._class, class(Button)) && autoSize)
136                size = editor.size;
137          }
138          else
139          {
140             // TODO: Should returning 0 from OnPostCreate cancel creation?
141             Destroy(0);
142             return false;
143          }
144       }
145       return true;
146    }
147
148    void OnRedraw(Surface surface)
149    {
150       if(type && (!editor || !editor.created || editor.anchor.left)) // ColorDropBox lets part of the DataBox show
151       {
152          char tempString[1024];
153          if(type._vTbl[__ecereVMethodID_class_OnDisplay] == class(Instance)._vTbl[__ecereVMethodID_class_OnDisplay])
154          {
155             if(needUpdate)
156             {
157                const String s;
158                if(type.type == noHeadClass || type.type == normalClass)
159                   s = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, *(void **)this.data, tempString, fieldData, null);
160                else
161                   s = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, this.data, tempString, fieldData, null);
162                delete stringValue;
163                stringValue = CopyString(s);
164                needUpdate = false;
165             }
166             ((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);
167          }
168          else
169          {
170             if(type.type == noHeadClass || type.type == normalClass)
171                ((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);
172             else
173                ((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);
174          }
175       }
176    }
177
178    void OnDestroy()
179    {
180       editor = null;
181       CommonControl::OnDestroy();
182    }
183
184    void OnPosition(int x, int y, int width, int height)
185    {
186       if(editor)
187          editor.OnPosition(editor.position.x, editor.position.y, editor.size.w, editor.size.h);
188    }
189
190    bool OnKeyHit(Key key, unichar ch)
191    {
192       return editor ? editor.OnKeyHit(key, ch) : true;
193    }
194
195    bool OnKeyDown(Key key, unichar ch)
196    {
197       if((SmartKey)key == enter)
198       {
199          SaveData();
200          return false;
201       }
202       else if((SmartKey)key == escape)
203       {
204          Refresh();
205          return true;
206       }
207       return editor ? editor.OnKeyDown(key, ch) : true;
208    }
209
210    void OnChildResized(Window child, int x, int y, int w, int h)
211    {
212       if(!inAutoSize && autoSize == true)
213       {
214          inAutoSize = true;
215          clientSize = { w, h };
216          inAutoSize = false;
217       }
218    }
219 };
220
221 public class SavingDataBox : DataBox
222 {
223    class_property(icon) = "<:ecere>controls/dataBox.png";
224    borderStyle = deep;
225    bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
226    {
227       if(!active && editor && !editor.modalSlave)
228       {
229          if(!SaveData())
230             Refresh();
231       }
232       return true;
233    }
234
235    bool OnKeyDown(Key key, unichar ch)
236    {
237       if((SmartKey)key == enter)
238       {
239          if(!SaveData())
240             // Force Refresh on Enter if SaveData didn't do it
241             Refresh();
242          return true;
243       }
244       return DataBox::OnKeyDown(key, ch);
245    }
246
247    bool OnResizing(int * w, int * h)
248    {
249       if(!*w || !*h)
250       {
251          int spaceH;
252          display.FontExtent(fontObject, " ", 1, null, &spaceH);
253          if(!*h)
254             *h = spaceH + 2;
255          if(!*w)
256             *w = spaceH * 80 / 14;
257       }
258       return true;
259    }
260 }