ide/Designer/Sheet: (#676) Multi-line editing of EditBox contents in property sheet
[sdk] / ecere / src / gui / typeEdit.ec
1 namespace gui;
2
3 import "Window"
4
5 static define ROWOFFSET = 1;
6
7 class Enumeration : struct
8 {
9    OldList values;
10    int largest;
11 };
12
13 static void UnusedFunction()
14 {
15    int a;
16    a.OnGetString(0,0,0);
17    a.OnFree();
18    a.OnCopy(null);
19    a.OnCompare(null);
20    a.OnSaveEdit(null,0);
21    a.OnEdit(null,null,0,0,0,0,0);
22    a.OnDisplay(null,0,0,0,0,0,0);
23    a.OnGetDataFromString(null);
24 }
25
26 default:
27 extern int __ecereVMethodID_class_OnEdit;
28 extern int __ecereVMethodID_class_OnDisplay;
29 extern int __ecereVMethodID_class_OnGetString;
30 extern int __ecereVMethodID_class_OnGetDataFromString;
31 extern int __ecereVMethodID_class_OnFree;
32 extern int __ecereVMethodID_class_OnCompare;
33 extern int __ecereVMethodID_class_OnCopy;
34 extern int __ecereVMethodID_class_OnSaveEdit;
35 private:
36
37 /*static */Window Enum_OnEdit(Class _class, int * data, Window window, Window master,
38                           int x, int y, int w, int h, void * userData)
39 {
40    Enumeration enumeration = _class.data;
41    NamedLink item;
42    DropBox dropBox
43    {
44       window, master = master,
45       borderStyle = 0, //position = { x, y }, size = { w, h },
46       modifyVirtualArea = false, activeStipple = false;
47       anchor = { 0, 0, 0, 0 };
48
49       bool DataBox::NotifySelect(DropBox control, DataRow row, Modifiers mods)
50       {
51          SetData(row.GetData(null), mods.closingDropDown);
52          return true;
53       }
54
55       bool DataBox::NotifyClose(DropBox dropBox)
56       {
57          //dropBox.Deactivate();
58          return true;
59       }
60    };
61    // Read only DataBoxes don't really need the edition, but it will be invoked if autoSize is on because the base class OnEdit check succeeded and chained here,
62    // and it's thinking the editor is going to be an EditBox. We return an editor so the DataBox goes on with life.
63    if(!((DataBox)window).readOnly)
64    {
65       dropBox.AddField({ dataType = _class, userData = userData });
66       dropBox.Create();
67
68       for(item = enumeration.values.first; item; item = item.next)
69       {
70          DataRow row = dropBox.AddRow();
71          row.SetData(null, (uint)item.data); //name);
72          if(data && (int)item.data == *data)
73             dropBox.currentRow = row;
74       }
75    }
76    else
77       dropBox.autoCreate = false;
78    return dropBox;
79 }
80
81
82 static void OnDisplay(Class _class, void * data, Surface surface, int x, int y, int width, void * fieldData, Alignment alignment, DataDisplayFlags displayFlags)
83 {
84    static char tempString[16384];
85    char * string;
86    int len;
87    bool needClass = false;
88    int w, h;
89
90    tempString[0] = '\0';
91    string = ((char * (*)(void *, void *, void *, void *, void *))(void *)_class._vTbl[__ecereVMethodID_class_OnGetString])(_class, data, tempString, fieldData, &needClass);
92    len = string ? strlen(string) : 0;
93
94    //surface.TextOpacity(false);
95
96    if(!(displayFlags.fullRow) || (displayFlags.header && displayFlags.current))
97    {
98       surface.TextExtent(string, len, &w, &h);
99       h = Max(h, 16);
100    }
101
102    // Draw the selection background
103    if(!(displayFlags.fullRow) && (displayFlags.selected) && displayFlags.firstField)
104       surface.Area(x - 3, y, x + w + 1, y + h - 1);
105
106    if(string)
107    //surface.WriteTextDots(alignment, x, y + 2, width, string, len);
108    surface.WriteTextDots(alignment, x, y + ROWOFFSET, width, string, len);
109
110    if(!guiApp.textMode)
111    {
112       // Draw the current row stipple
113       if(displayFlags.current && !(displayFlags.fullRow) && displayFlags.firstField)
114       {
115          if(displayFlags.active)
116          {
117             surface.LineStipple(0x5555);
118             if(displayFlags.selected)
119                surface.SetForeground(0xFFFFFF80);
120             else
121                surface.SetForeground(black);
122          }
123          else
124             surface.SetForeground(SELECTION_COLOR);
125          surface.Rectangle(x - 3, y, x + w + 1, y + h - 1);
126          surface.LineStipple(0);
127       }
128    }
129    if((displayFlags.header) && (displayFlags.current) && (displayFlags.fullRow || displayFlags.firstField))
130    {
131       surface.LineStipple(0xAAAA);
132       surface.SetForeground(black);
133       surface.Rectangle(x-2, y+1, x+w+1, y + h - 1);
134       surface.LineStipple(0);
135    }
136 }
137
138 static bool class_OnSaveEdit(Class _class, void ** data, Window editControl, void * object)
139 {
140    if(_class.type == enumClass)
141    {
142       DropBox dropBox = (DropBox)editControl;
143       return dropBox.Save();
144    }
145    else
146    {
147       bool changed = false;
148       EditBox editBox = (EditBox)editControl;
149       if(editBox.modifiedDocument && (!_class.noExpansion || _class._vTbl[__ecereVMethodID_class_OnGetDataFromString] != (void *)Instance::OnGetDataFromString))
150       {
151          if(_class.type == normalClass || _class.type == noHeadClass)
152          {
153             ((void (*)(void *, void *))(void *)_class._vTbl[__ecereVMethodID_class_OnFree])(_class, *data);
154             changed = ((bool (*)(void *, void *, const char *))(void *)_class._vTbl[__ecereVMethodID_class_OnGetDataFromString])(_class, data, editBox.line.text);
155          }
156          else
157          {
158             ((void (*)(void *, void *))(void *)_class._vTbl[__ecereVMethodID_class_OnFree])(_class, data);
159             changed = ((bool (*)(void *, void *, const char *))(void *)_class._vTbl[__ecereVMethodID_class_OnGetDataFromString])(_class, data, editBox.line.text);
160          }
161          //changed = true;
162       }
163       return changed;
164    }
165 }
166
167 static Window OnEdit(Class _class, void * data, Window window, Window master,
168                      int x, int y, int w, int h, void * fieldData)
169 {
170    if(_class.type == enumClass)
171       return Enum_OnEdit(_class, data, window, master, x, y, w, h, fieldData);
172    else
173    {
174       char tempString[MAX_F_STRING] = "";
175       // Don't show the editbox right away so that the text is highlighted by default
176       char * string = "";
177       EditBox editBox
178       {
179          window, master = master, visible = false, //position = { x, y },
180          borderStyle = 0,
181          modifyVirtualArea = false, //sizeAnchor = { { w, h }, isClientH = true };
182          autoSize = (eClass_IsDerived(window._class, class(DataBox)) ? ((DataBox)window).autoSize : false);
183
184          void DataBox::NotifyUpdate(EditBox editBox)
185          {
186             Modified();
187             modifiedDocument = true;
188          }
189
190          bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
191          {
192             opacity = (active && !readOnly) ? 1.0f : parent.opacity;
193             return EditBox::OnActivate(active, previous, goOnWithActivation, direct);
194          }
195       };
196       if(!editBox.autoSize)
197          editBox.anchor = { 0, 0, 0, 0 };
198       else
199          editBox.anchor = { 0, 0 };
200
201       if(data)
202       {
203          bool needClass = false;
204          char * result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)_class._vTbl[__ecereVMethodID_class_OnGetString])(_class, data, tempString, fieldData, &needClass);
205          if(result)
206             string = result;
207       }
208 /*#ifdef _DEBUG
209       PrintLn(window._class.name);
210       if(editBox.autoSize)
211          PrintLn("typeEdit::OnEdit -- editBox.autoSize == true");
212 #endif*/
213       editBox.contents = string;
214       editBox.visible = true;
215       editBox.Create();
216       if(!window.active)
217       {
218          // editBox.contents = string;
219          editBox.Deselect();
220          editBox.Home();
221       }
222       return editBox;
223    }
224
225 }
226
227 public class MultiLineString : String
228 {
229    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
230    {
231       // Don't show the editbox right away so that the text is highlighted by default
232       char * string = "";
233       EditBox editBox
234       {
235          dataBox, visible = false,
236          borderStyle = 0,
237          hasHorzScroll = true, hasVertScroll = true,
238          modifyVirtualArea = false,
239          autoSize = dataBox.autoSize;
240          anchor = { 0, 0, 0, 0 };
241          multiLine = true;
242
243          void DataBox::NotifyUpdate(EditBox editBox)
244          {
245             Modified();
246             modifiedDocument = true;
247          }
248
249          bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
250          {
251             opacity = active ? 1.0f : parent.opacity;
252             return true;
253          }
254       };
255       editBox.contents = this;
256       editBox.visible = true;
257
258       editBox.Create();
259       if(!dataBox.active)
260          editBox.contents = this;
261       return editBox;
262    }
263
264    bool OnSaveEdit(Window window, void * object)
265    {
266       bool changed = false;
267       EditBox editBox = (EditBox)window;
268       if(editBox.modifiedDocument)
269       {
270          EditLine line;
271          int size = 0;
272          char * string;
273
274          delete this;
275
276          for(line = editBox.firstLine; line; line = line.next)
277             size += line.count+1;
278          this = string = new char[size+1];
279          size = 0;
280          for(line = editBox.firstLine; line; line = line.next)
281          {
282             memcpy(string + size, line.text, line.count);
283             size += line.count;
284             if(line.next)
285             {
286                string[size] = '\n';
287                size++;
288             }
289          }
290          string[size] = '\0';
291
292          changed = true;
293       }
294       return changed;
295    }
296 };
297
298 __on_register_module()
299 {
300    Class baseClass = eSystem_FindClass(module, "class");
301    eClass_AddMethod(baseClass, "OnDisplay", null, OnDisplay, publicAccess);
302    eClass_AddMethod(baseClass, "OnEdit", null, OnEdit, publicAccess);
303    eClass_AddMethod(baseClass, "OnSaveEdit", null, class_OnSaveEdit, publicAccess);
304 }