Initial git commit -- Transition from CodeGuard repository
[sdk] / ide / src / designer / Sheet.ec
1 import "ide"
2
3 import "CodeObject"
4
5 static void UnusedFunction()
6 {
7    int a;
8    Module b;
9    a.OnGetString(0,0,0);
10    a.OnFree();
11    a.OnCopy(null);
12    a.OnCompare(null);
13    a.OnSaveEdit(null,0);
14    a.OnEdit(null,null,0,0,0,0,0);
15    a.OnDisplay(null,0,0,0,0,0,0);
16    b.OnLoad();
17 }
18
19 extern int __ecereVMethodID_class_OnEdit;
20 extern int __ecereVMethodID_class_OnDisplay;
21 extern int __ecereVMethodID_class_OnGetString;
22 extern int __ecereVMethodID_class_OnFree;
23 extern int __ecereVMethodID_class_OnCompare;
24 extern int __ecereVMethodID_class_OnCopy;
25 extern int __ecereVMethodID_class_OnSaveEdit;
26
27 //#define SHOW_METHODS
28
29
30 // *** THESE METHODS SHOULD BE IMPROVED UPON AND USED TO SET PROPERTIES FROM NOW ON ***
31 //     (Other locations where this will be useful: JSON (DataValue version?), CodeEditor, ...)
32 // This takes in a value according to the any_object rules
33
34 void SetPropValue(Property prop, void * object, any_object value)
35 {
36    Class type = prop.dataTypeClass;
37    if(!type)
38       type = prop.dataTypeClass = eSystem_FindClass(prop._class.module, prop.dataTypeString);
39
40    if(type.type == normalClass || type.type == noHeadClass || type.type == structClass)
41    {
42       prop.Set(object, value);
43    }
44    // TOFIX: How to swiftly handle classes with base data type?
45    else if(type == class(double) || !strcmp(type.dataTypeString, "double"))
46    {
47       ((void (*)(void *, double))(void *)prop.Set)(object, *(double *)value);
48    }
49    else if(type == class(float) || !strcmp(type.dataTypeString, "float"))
50    {
51       ((void (*)(void *, float))(void *)prop.Set)(object, *(float *)value);
52    }
53    else if(type.typeSize == sizeof(int64))// || !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64"))
54    {
55       ((void (*)(void *, int64))(void *)prop.Set)(object, *(int64 *)value);
56    }
57    else if(type.typeSize == sizeof(int))// || !strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint"))
58    {
59       ((void (*)(void *, int))(void *)prop.Set)(object, *(int *)value);
60    }
61    else if(type.typeSize == sizeof(short int)) // || !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||  !strcmp(type.dataTypeString, "int16"))
62    {
63       ((void (*)(void *, short))(void *)prop.Set)(object, *(short *)value);
64    }
65    else if(type.typeSize == sizeof(byte))// || !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
66    {
67       ((void (*)(void *, byte))(void *)prop.Set)(object, *(byte *)value);
68    }
69    else
70    {
71       ((void (*)(void *, void *))(void *)prop.Set)(object, value);
72    }
73 }
74
75 any_object GetPropValue(Property prop, Instance object)
76 {
77    if(object)
78    {
79       Class type = prop.dataTypeClass;
80       if(!type)
81       {
82          type = prop.dataTypeClass = eSystem_FindClass(prop._class.module, prop.dataTypeString);
83       }
84
85       if(type.type == normalClass || type.type == noHeadClass || type.type == structClass)
86       {
87          return ((void*(*)())(void *)prop.Get)(object);
88       }
89       // TOFIX: How to swiftly handle classes with base data type?
90       else if(type == class(double) || !strcmp(type.dataTypeString, "double"))
91       {
92          double d = ((double(*)())(void *)prop.Get)(object);
93          return d;
94       }
95       else if(type == class(float) || !strcmp(type.dataTypeString, "float"))
96       {
97          float f =((float(*)())(void *)prop.Get)(object);
98          return f;
99       }
100       else if(type.typeSize == sizeof(int64))// || !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64"))
101       {
102          return ((int64(*)())(void *)prop.Get)(object);
103       }
104       else if(type.typeSize == sizeof(int))// || !strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint"))
105       {
106          return ((int(*)())(void *)prop.Get)(object);
107       }
108       else if(type.typeSize == sizeof(short int)) // || !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||  !strcmp(type.dataTypeString, "int16"))
109       {
110          return ((short(*)())(void *)prop.Get)(object);
111       }
112       else if(type.typeSize == sizeof(byte))// || !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
113       {
114          return ((byte(*)())(void *)prop.Get)(object);
115       }
116       else
117       {
118          return prop.Get(object);
119       }
120    }
121    else
122       return 0;
123 }
124
125 void CopyProperty(Property prop, Instance dest, Instance src)
126 {
127    Class type = prop.dataTypeClass;
128    if(!type)
129       type = prop.dataTypeClass = eSystem_FindClass(prop._class.module, prop.dataTypeString);
130
131    if(type.type == structClass)
132    {
133       void * propData = new0 byte[type.structSize];
134       prop.Get(src, propData);
135       prop.Set(dest, propData);
136       delete propData;
137    }
138    else if(type.type == normalClass || type.type == noHeadClass)
139    {
140       // TOCHECK: Why was there a return here?
141       /*return */prop.Set(dest, ((void*(*)())(void *)prop.Get)(src));
142    }
143    // TOFIX: How to swiftly handle classes with base data type?
144    else if(type == class(double) || !strcmp(type.dataTypeString, "double"))
145    {
146       ((void (*)(void *, double))(void *)prop.Set)(dest, ((double(*)())(void *)prop.Get)(src));
147    }
148    else if(type == class(float) || !strcmp(type.dataTypeString, "float"))
149    {
150       ((void (*)(void *, float))(void *)prop.Set)(dest, ((float(*)())(void *)prop.Get)(src));
151    }
152    else if(type.typeSize == sizeof(int64))// || !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64"))
153    {
154       ((void (*)(void *, int64))(void *)prop.Set)(dest, ((int64(*)())(void *)prop.Get)(src));
155    }
156    else if(type.typeSize == sizeof(int))// || !strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint"))
157    {
158       ((void (*)(void *, int))(void *)prop.Set)(dest, ((int(*)())(void *)prop.Get)(src));
159    }
160    else if(type.typeSize == sizeof(short int)) // || !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||  !strcmp(type.dataTypeString, "int16"))
161    {
162       ((void (*)(void *, short))(void *)prop.Set)(dest, ((short(*)())(void *)prop.Get)(src));
163    }
164    else if(type.typeSize == sizeof(byte))// || !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
165    {
166       ((void (*)(void *, byte))(void *)prop.Set)(dest, ((byte(*)())(void *)prop.Get)(src));
167    }
168    else
169    {
170       prop.Set(dest, prop.Get(src));
171    }
172 }
173
174 void GetProperty(Property prop, Instance object, DataValue value)
175 {
176    if(object)
177    {
178       Class type = prop.dataTypeClass;
179       if(!type)
180       {
181          type = prop.dataTypeClass = eSystem_FindClass(prop._class.module, prop.dataTypeString);
182 #ifdef _DEBUG
183          if(prop._class.module.application == __thisModule &&
184             prop.dataTypeClass.module.application == ((Designer)GetActiveDesigner()).codeEditor.privateModule)
185             printf("Warning");
186 #endif
187       }
188
189       if(type.type == normalClass || type.type == noHeadClass || type.type == structClass)
190       {
191          value.p = ((void*(*)())(void *)prop.Get)(object);
192       }
193       // TOFIX: How to swiftly handle classes with base data type?
194       else if(type == class(double) || !strcmp(type.dataTypeString, "double"))
195       {
196          value.d = ((double(*)())(void *)prop.Get)(object);
197       }
198       else if(type == class(float) || !strcmp(type.dataTypeString, "float"))
199       {
200          value.f = ((float(*)())(void *)prop.Get)(object);
201       }
202       else if(type.typeSize == sizeof(int64))// || !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64"))
203       {
204          value.i64 = ((int64(*)())(void *)prop.Get)(object);
205       }
206       else if(type.typeSize == sizeof(int))// || !strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint"))
207       {
208          value.i = ((int(*)())(void *)prop.Get)(object);
209       }
210       else if(type.typeSize == sizeof(short int)) // || !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||  !strcmp(type.dataTypeString, "int16"))
211       {
212          value.s = ((short(*)())(void *)prop.Get)(object);
213       }
214       else if(type.typeSize == sizeof(byte))// || !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
215       {
216          value.uc = ((byte(*)())(void *)prop.Get)(object);
217       }
218       else
219       {
220          value.i = prop.Get(object);
221       }
222    }
223    else
224       value.i64 = 0;
225 }
226
227 void SetProperty(Property prop, Instance object, DataValue value)
228 {
229    if(object)
230    {
231       Class type = prop.dataTypeClass;
232       if(!type)
233          type = prop.dataTypeClass = eSystem_FindClass(prop._class.module, prop.dataTypeString);
234
235       if(type.type == normalClass || type.type == noHeadClass || type.type == structClass)
236       {
237          prop.Set(object, value);
238       }
239       // TOFIX: How to swiftly handle classes with base data type?
240       else if(type == class(double) || !strcmp(type.dataTypeString, "double"))
241       {
242          ((void (*)(void *, double))(void *)prop.Set)(object, value.d);
243       }
244       else if(type == class(float) || !strcmp(type.dataTypeString, "float"))
245       {
246          ((void (*)(void *, float))(void *)prop.Set)(object, value.f);
247       }
248       else if(type.typeSize == sizeof(int64))// || !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64"))
249       {
250          ((void (*)(void *, int64))(void *)prop.Set)(object, value.i64);
251       }
252       else if(type.typeSize == sizeof(int))// || !strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint"))
253       {
254          ((void (*)(void *, int))(void *)prop.Set)(object, value.i);
255       }
256       else if(type.typeSize == sizeof(short int)) // || !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||  !strcmp(type.dataTypeString, "int16"))
257       {
258          ((void (*)(void *, short))(void *)prop.Set)(object, value.s);
259       }
260       else if(type.typeSize == sizeof(byte))// || !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
261       {
262          ((void (*)(void *, byte))(void *)prop.Set)(object, value.uc);
263       }
264       else
265       {
266          ((void (*)(void *, int))(void *)prop.Set)(object, value.i);
267       }
268    }
269 }
270
271 class Sheet : Window
272 {
273    text = "Sheet";
274    borderStyle = sizable;
275    hasClose = true;
276    //tabCycle = true;
277    size.w = 300;
278    anchor = { left = 0, top = 0, bottom = 0 };
279    background = activeBorder;
280
281    Sheet()
282    {
283       dropBox.AddField(dropField);
284       properties.AddField(propertyName);
285       properties.AddField(propertyValue);
286       methods.AddField(methodName);
287    }
288
289    ~Sheet()
290    {
291       categories.Free(null);
292    }
293
294    DropBox dropBox
295    {
296       this,
297       anchor = { left = 0, top = 0, right = 0 };
298
299       bool NotifySelect(DropBox control, DataRow row, Modifiers keyFlags)
300       {
301          ObjectInfo selected = (ObjectInfo)(row ? row.tag : null);
302          ToolBox toolBox = ((IDE)parent).toolBox;
303
304          if(codeEditor && selected)
305             codeEditor.SelectObject(selected);
306
307          // TODO: Get containing class of object
308          toolBox.selectedClass = selected ? selected.oClass : null;
309
310          object = selected ? selected.instance : null;
311
312          methods.Clear();
313          ListProperties(true);
314
315          {
316             DataRow row;
317             row = methods.currentRow;
318             if(row)
319                strcpy(selectedMethod, ((CodeObject)row.GetData(methodName)).name);
320          }
321
322
323          if(selected && selected.instance && codeEditor)
324          {
325             Class _class;
326             int c = 0;
327             int rowHeight = methods.rowHeight;
328
329             propertyValue.userData = (void *)selected.instance;
330
331             // Fill up the methods
332             {
333                CodeObjectType type;
334                {
335                   for(_class = selected.instance._class; _class && _class.type != systemClass; _class = _class.base)
336                   {
337                      int id;
338                      for(id = _class.base ? _class.base.vTblSize : 0; id<_class.vTblSize; id++)
339                      {
340                         Method method;
341                         for(method = (Method)_class.methods.first; method; method = (Method)((BTNode)method).next)
342                         {
343                            if(method.type == virtualMethod && method.vid == id)
344                            {
345                               if(!method.dataType)
346                                  method.dataType = ProcessTypeString(method.dataTypeString, false);
347
348                               type = method.dataType.thisClass ? typeEvent : typeMethod;
349                               {
350                                  DataRow row = methods.AddRow();
351                                  CodeObject codeObject
352                                  {
353                                     eventsUp = (selected.oClass == selected) ? false : true;
354                                     type = type;
355                                     method = method;
356                                     name = method.name;
357                                     overriden = codeEditor.FindMethod(method.name, &codeObject.function, null);
358                                  };
359                                  if(!codeObject.overriden || codeObject.overriden == 2)
360                                     codeEditor.FindCompatibleMethods(method, codeObject.compatible);
361
362                                  row.SetData(methodName, codeObject);
363
364                                  if(!strcmp(method.name, selectedMethod))
365                                     methods.currentRow = row;
366                               }
367                            }
368                         }
369                      }
370                   }
371                }
372             }
373             methods.Sort(methodName, 1);
374             {
375                DataRow row;
376                for(row = methods.firstRow; row; row = row.next)
377                {
378                   CodeObject codeObject = row.GetData(methodName);
379                   CreateButtons(codeObject, row.index * rowHeight, rowHeight, row);
380                }
381             }
382          }
383          return true;
384       }
385    };
386    DataField dropField { dataType = class(CodeObject) };
387
388    Button propBtn
389    {
390       this, inactive = true, text = "Properties", bevelOver = true, isRadio = true;
391       size.h = 20;
392       anchor = { left = 0, bottom = 3, right = 0.5 };
393       bitmap = null;
394
395       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
396       {
397          text = "Properties";
398          button.font = { "Tahoma", 8.25f, bold = true };
399          methBtn.font = null;
400
401          methods.visible = false;
402          methBtn.Activate();      // Ensure proper cycling (until tab order?)
403          properties.visible = true;
404
405          alphabetical.disabled = false;
406          categorized.disabled = false;
407
408          properties.Activate();
409
410          // ((IDE)master).SheetSelected(Properties);
411          return true;
412       }
413    };
414
415    Button methBtn
416    {
417       this, inactive = true, bevelOver = true;
418       text = "Methods";
419       isRadio = true;
420       bitmap = null;
421       size.h = 20;
422       anchor = { bottom = 3, left = 0.5, right = 0 };
423
424       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
425       {
426          text = "Methods";
427          button.font = { "Tahoma", 8.25f, bold = true };
428          propBtn.font = null;
429
430          properties.visible = false;
431          methBtn.Activate();      // Ensure proper cycling (until tab order?)
432          methods.visible = true;
433
434          alphabetical.disabled = true;
435          categorized.disabled = true;
436
437          methods.Activate();
438                        
439          // ((IDE)master).SheetSelected(Methods);
440          return true;
441       }
442    };
443
444    // Menu
445    menu = Menu { };
446    MenuPlacement editMenu { menu, text = "Edit" };
447    Menu viewMenu { menu, text = "View" };
448
449    // Property Sheet
450    ListBox properties
451    {
452       this, anchor = { left = 0, right = 0, top = 50, bottom = 25 };
453       hasVertScroll = true, alwaysEdit = true, collapseControl = true, resizable = true;
454
455       bool NotifySelect(ListBox control, DataRow row, Modifiers keyFlags)
456       {
457          /*
458          if(row)
459          {
460             strcpy(selectedProp, (char *)row.GetData(propertyName));
461             selectedScroll = properties.scroll.y;
462             selectedScroll -= row.index * properties.rowHeight;
463          }
464          else
465             selectedProp[0] = 0;
466          if(row)
467          {
468             prop = ((PropertyInfo)row.GetData(propertyValue)).prop;
469          }
470          else
471             prop = null;
472          */
473          return true;
474       }
475    };
476
477    DataField propertyName { dataType = class(char *), width = 130 };
478    DataField propertyValue { dataType = class(PropertyInfo), width = 0, editable = true };
479
480    // Method Sheet
481    ListBox methods
482    {
483       this, anchor = { left = 0, right = 0, top = 50, bottom = 25 };
484       hasVertScroll = true;
485       // alwaysEdit = true;
486       // resizable = true;
487
488       bool NotifyDoubleClick(ListBox control, int x, int y, Modifiers mods)
489       {
490          CodeObject object = control.GetData(methodName);
491          if(object)
492             codeEditor.AddMethod(object.method);   
493          return false;
494       }
495
496       bool NotifyRightClick(ListBox control, int x, int y, Modifiers mods)
497       {
498          CodeObject object = control.GetData(methodName);
499          Menu menu { };
500          PopupMenu popupMenu;
501          MenuItem item;
502          if(object.overriden == 0)
503          {
504             MenuItem { menu, "Override", o, enter, bold = true, NotifySelect = OverrideMethodSelected };
505             if(object.compatible.count)
506             {
507                Menu attachMenu { menu, "Attach", a };
508                OldLink compatible;
509                for(compatible = object.compatible.first; compatible; compatible = compatible.next)
510                {
511                   ClassFunction function = compatible.data;
512                   MenuItem { attachMenu, function.declarator.symbol.string, id = (int)function, NotifySelect = AttachMethodSelected };
513                }
514             }
515          }
516          else if(object.overriden == 1)
517          {
518             MenuItem { menu, "Go to", g, enter, bold = true, NotifySelect = GotoMethodSelected };
519             MenuItem { menu, "Detach", d, d, NotifySelect = DetachMethodSelected };
520             MenuItem { menu, "Delete", del, del, NotifySelect = DeleteMethodSelected };
521          }
522          else if(object.overriden == 2)
523          {
524             MenuItem { menu, "Go to", g, enter, bold = true, NotifySelect = GotoMethodSelected };
525             MenuItem { menu, "Detach", d, d, NotifySelect = DetachMethodSelected };
526             if(object.compatible.count > 1)
527             {
528                Menu attachMenu { menu, "Reattach", r };
529                OldLink compatible;
530                for(compatible = object.compatible.first; compatible; compatible = compatible.next)
531                {
532                   ClassFunction function = compatible.data;
533                   if(function != object.function)
534                   {
535                      MenuItem { attachMenu, function.declarator.symbol.string, id = (int)function, NotifySelect = ReattachMethodSelected };
536                   }
537                }
538             }
539          }
540
541          attachMethod = object.method;
542          popupMenu = PopupMenu { menu = menu, master = this, position =
543             {
544                x + control.absPosition.x - app.desktop.absPosition.x,
545                y + control.absPosition.y - app.desktop.absPosition.y
546             } };
547          popupMenu.Create();
548          // popupMenu.Capture();
549          return false;
550       }
551
552       bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
553       {
554          if(row)
555          {
556             CodeObject object = row.GetData(methodName);
557             switch((SmartKey)key)
558             {
559                case enter:
560                   if(!object.overriden)
561                      listBox.NotifyDoubleClick(this, listBox, 0,0, 0);
562                   else
563                      codeEditor.GoToMethod(object.method.name);
564                   break;
565                case del:
566                   if(object.deleteBtn)
567                      object.deleteBtn.NotifyClicked(this, object.deleteBtn, 0,0,0);
568                   else if(object.detachBtn)
569                      object.detachBtn.NotifyClicked(this, object.detachBtn, 0,0,0);
570                   break;
571                case a:
572                   if(object.attachBtn)
573                      object.attachBtn.NotifyPushed(this, object.attachBtn, 0,0,0);
574                   break;
575                case d:
576                   if(object.detachBtn)
577                      object.detachBtn.NotifyClicked(this, object.detachBtn, 0,0,0);
578                   break;
579             }
580          }
581          return true;
582       }
583    };
584
585    DataField methodName { dataType = class(CodeObject) };
586
587 #ifdef SHOW_METHODS
588    methBtn.font = { "Tahoma", 8.25, bold = true };
589    methBtn.checked = true;
590    properties.visible = false;
591    text = "Methods";
592 #else
593    propBtn.font = { "Tahoma", 8.25f, bold = true };
594    propBtn.checked = true;
595    methods.visible = false;
596    text = "Properties";
597 #endif
598
599    Button alphabetical
600    {
601       this, bevelOver = true, inactive = true, position = { 25, 25 }, size = { 24, 24 };
602       bitmap = { "<:ecere>elements/orderAscending.png" };
603       // isRadio = true;
604
605       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
606       {
607          if(!alphabetical.checked)
608          {
609             alphabetical.checked = true;
610             categorized.checked = false;
611
612             ListProperties(true);
613          }
614          return true;
615       }
616    };
617
618    Button categorized
619    {
620       this, bevelOver = true, checked = true, inactive = true, position = { 0, 25 }, size = { 24, 24 };
621       bitmap = { "<:ecere>elements/orderCategorized.png" };
622       // isRadio = true;
623       
624       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
625       {
626          if(!categorized.checked)
627          {
628             categorized.checked = true;
629             alphabetical.checked = false;
630
631             ListProperties(true);
632          }
633          return true;
634       }
635    };
636
637    property CodeEditor codeEditor
638    {
639       set
640       {
641          if(codeEditor != value)
642          {
643             codeEditor = value;
644             // Refill it up
645             dropBox.Clear();
646             dropField.userData = codeEditor;
647             methodName.userData = codeEditor;
648             
649             if(codeEditor)
650                codeEditor.EnumerateObjects(this);
651           }
652       }
653       get
654       {
655          return codeEditor;
656       }
657    }
658
659    property SheetType sheetSelected
660    {
661       set
662       {
663          if(methBtn.checked != (value == SheetType::methods))
664             ToggleSheet();
665       }
666       get
667       {
668          return methBtn.checked ? methods : properties;
669       }
670    }
671
672    bool OnClose(bool parentClosing)
673    {
674       if(!parentClosing)
675       {
676          visible = false;
677          return false;
678       }
679       return true;
680    }
681
682    bool OnKeyDown(Key key, unichar ch)
683    {
684       if(key == shiftTab)
685          dropBox.Activate();
686       else if(key == tab)
687          ToggleSheet();
688       else if(key == escape)
689       {
690          Window activeClient = ide.activeClient;
691          if(activeClient) 
692             activeClient.Activate();
693          else 
694             ide.RepositionWindows(true);
695       }
696       return true;
697    }
698
699    bool OnKeyHit(Key key, unichar ch)
700    {
701       return properties.OnKeyHit(key, ch);
702    }
703
704    bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
705    {
706       if(active && codeEditor)
707          codeEditor.EnsureUpToDate();
708       return true;
709    }
710
711    void ListProperties(bool clear)
712    {
713       DataRow row = dropBox.currentRow;
714       ObjectInfo selected = row ? (ObjectInfo)row.tag : null;
715       
716       //int scroll = 0;
717       bool categorized = this.categorized.checked;
718       bool currentRow = false;
719       char selectedProp[1024];
720
721       if(clear)
722       {
723          Category cat;
724          DataRow row = properties.currentRow;
725          if(row)
726          {
727             DataRow propRow = row;
728             char * propName;
729             while(propRow && propRow.parent && !propRow.parent.isHeader)
730                propRow = row.parent;
731             
732             propName = propRow.GetData(propertyName);
733             strcpy(this.selectedProp, propName);
734             selectedScroll = properties.scroll.y;
735             selectedScroll -= propRow.index * properties.rowHeight;
736          }
737          currentRow = this.selectedProp[0] ? true : false;
738
739          for(cat = categories.first; cat; cat = cat.next)
740          {
741             cat.collapsed = cat.row.collapsed;
742             cat.row = null;
743          }
744
745          // Preserve selected property (PropertySheetSelect will null it)
746          strcpy(selectedProp, this.selectedProp);
747          properties.Clear();
748          strcpy(this.selectedProp, selectedProp);
749       }
750       if(selected && selected.instance && codeEditor)
751       {
752          Instance test = eInstance_New(selected.instance._class);
753          Class _class = null;
754          incref test;
755
756          // Put it in the same desktop window...
757          if(selected.classDefinition)
758             codeEditor.designer.PrepareTestObject(test);
759
760          // Fill up the properties
761          while(_class != selected.instance._class)
762          {
763             BitMember bitMember = null;
764             Class lastClass = _class;
765             Property propIt;
766
767             for(_class = selected.instance._class; _class.base != lastClass && _class.base.type != systemClass && _class.inheritanceAccess != privateAccess; _class = _class.base);
768
769             for(propIt = _class.membersAndProperties.first; propIt; propIt = propIt.next)
770             {
771                if(propIt.isProperty)
772                {
773                   Property prop = eClass_FindProperty(selected.instance._class, propIt.name, GetPrivateModule());
774                   
775                   if(prop && prop.Set && prop.Get && prop.compiled)
776                   {
777                      bool disabled = Code_IsPropertyDisabled(selected, prop.name);
778                      bool bold;
779                      Class dataType = prop.dataTypeClass;
780                      if(!dataType)
781                         dataType = prop.dataTypeClass = eSystem_FindClass(codeEditor.privateModule, prop.dataTypeString);
782
783                      if(!strcmp(_class.name, "DesignerBase"))
784                         disabled = true;
785                      bold = !disabled && Code_IsPropertyModified(test, selected, prop);                           
786
787                      if(dataType)
788                      {
789                         DataRow row;
790                         PropertyInfo info { prop, disabled, bold ? codeEditor.boldFont : codeEditor.normalFont };
791                         char * name = prop.category ? prop.category : "Misc";
792                         Category category = categories.FindName(name, false);
793
794                         // Hide properties like this for now..
795                         if(name && !strcmp(name, "Private")) 
796                            continue;
797
798                         if(!category)
799                         {
800                            category = Category { name = name };
801                            categories.AddName(category);
802                         }
803                         if(!category.row && categorized)
804                         {
805                            PropertyInfo catInfo { null, false, null, name };
806                            category.row = properties.AddRow();
807                            category.row.SetData(propertyName, name );
808                            category.row.SetData(propertyValue, catInfo);
809                            category.row.isHeader = true;
810                            category.row.collapsed = category.collapsed;
811                         }
812
813                         if(clear)
814                         {
815                            row = categorized ? category.row.FindRow((int)prop) : properties.FindRow((int)prop);
816                            if(!row)
817                               row = categorized ? category.row.AddRow() : properties.AddRow();
818                            row.tag = (int)prop;
819                         }
820                         else
821                            row = categorized ? category.row.FindRow((int)prop) : properties.FindRow((int)prop);
822
823                         row.SetData(propertyName, prop.name);
824                         row.SetData(propertyValue, info);
825
826                         if(clear && !strcmp(prop.name, this.selectedProp))
827                            properties.currentRow = row;
828
829                         if(!dataType.noExpansion && (dataType.type == structClass || dataType.type == normalClass || dataType.type == noHeadClass || dataType.type == bitClass))
830                         {
831                            DataMember member;
832                            
833                            if(clear)
834                               row.collapsed = true;
835
836                            for(member = dataType.membersAndProperties.first; member; member = member.next)
837                            {
838                               if(member.isProperty)
839                               {
840                                  Property subProp = (Property)member;
841                                  if(!subProp.conversion && subProp.Get && subProp.Set)
842                                  {
843                                     DataRow subRow;
844                                     PropertyInfo info { prop, disabled, bold ? codeEditor.boldFont : codeEditor.normalFont, null, null, subProp };
845
846                                     if(clear)
847                                     {
848                                        subRow = row.AddRow();
849                                        subRow.tag = (int)subProp;
850                                     }
851                                     else
852                                        subRow = row.FindRow((int)subProp);
853                                     
854                                     subRow.SetData(propertyName, subProp.name);
855                                     subRow.SetData(propertyValue, info);
856                                  }
857                               }
858                               else if(member.name)
859                               {
860                                  DataRow subRow;
861                                  PropertyInfo info { prop, disabled, bold ? codeEditor.boldFont : codeEditor.normalFont, null, member, null };
862                                  if(clear)
863                                  {
864                                     subRow = row.AddRow();
865                                     subRow.tag = (int)member;
866                                  }
867                                  else
868                                     subRow = row.FindRow((int)member);
869
870                                  subRow.SetData(propertyName, member.name);
871                                  subRow.SetData(propertyValue, info);
872                               }
873                               else
874                               {
875                                  DataMember subMember;
876                                  for(subMember = member.members.first; subMember; subMember = subMember.next)
877                                  {
878                                     DataRow subRow;
879                                     PropertyInfo info { prop, disabled, bold ? codeEditor.boldFont : codeEditor.normalFont, null, subMember, null, member.offset };
880                                     if(clear)
881                                     {
882                                        subRow = row.AddRow();
883                                        subRow.tag = (int)subMember;
884                                     }
885                                     else
886                                        subRow = row.FindRow((int)subMember);
887
888                                     subRow.SetData(propertyName, subMember.name);
889                                     subRow.SetData(propertyValue, info);
890                                  }
891                               }
892                            }
893                         }
894                      }
895                   }
896                }
897             }
898          }
899          delete test;
900          // Sort alphabetically for now...
901          if(clear)
902          {
903             // properties.Sort(null, 1);
904             properties.Sort(propertyValue, 1);
905             if(!properties.currentRow)
906             {
907                bool found = false;
908                
909                for(_class = selected.instance._class; _class; _class = _class.base)
910                {
911                   Property prop;
912                   for(prop = _class.membersAndProperties.first; prop; prop = prop.next)
913                   {
914                      if(prop.isProperty && prop.Set && prop.Get && prop.compiled)
915                      {
916                         if(_class.defaultProperty && !strcmp(prop.name, _class.defaultProperty))
917                         {
918                            DataRow row;
919                            char * name = prop.category ? prop.category : "Misc";
920                            Category category = categories.FindName(name, false);
921                            row = category ? (categorized ? category.row.FindRow((int)prop) : properties.FindRow((int)prop)) : null;
922                            properties.currentRow = row;
923                            found = true;
924                            break;                                                                                                                              
925                         }
926                      }
927                   }
928                   if(found) break;
929                }
930                if(!found)
931                   properties.currentRow = properties.firstRow;
932             }
933
934             if(currentRow)
935             {
936                DataRow row = properties.currentRow;
937                properties.scroll.y = selectedScroll + row.index * properties.rowHeight;
938             }
939          }
940       }
941    }
942
943    void AddObject(ObjectInfo object, char * name, CodeObjectType type, bool select)
944    {
945       DataRow after = null;
946       DataRow row;
947       CodeObject codeObject;
948       char * bitmap = null;
949       bool foundClass = false;
950
951       for(row = dropBox.firstRow; row; row = row.next)
952       {
953          CodeObject codeObject = row.GetData(null);
954          if(codeObject.object.oClass == object.oClass)
955             foundClass = true;
956          else if(foundClass)
957             break;
958          after = row;
959       }
960
961       row = (DataRow)dropBox.AddRowAfter(after);
962       
963       row.tag = (int)object;
964
965       codeObject = 
966       {
967          object = object;
968          name = name;
969          type = type;
970          indent = (type == typeClass) ? 0 : 1;
971       };
972
973       if(type != typeClass)
974          bitmap = (char *)eClass_GetProperty(object.instance._class, "icon");
975       if(bitmap)
976       {
977          codeObject.bitmap = { bitmap };
978          AddResource(codeObject.bitmap);
979       }
980       
981       row.SetData(null, codeObject);
982
983       if(select)
984       {
985          this.object = object ? object.instance : null;
986          propertyValue.userData = object ? (void *)object.instance : null;
987          dropBox.SelectRow(row);
988       }
989    }
990
991    void DeleteObject(ObjectInfo object)
992    {
993       DataRow row = dropBox.FindRow((int)object);
994       if(row)
995       {
996          CodeObject codeObject = row.GetData(null);
997      
998          if(codeObject.bitmap)
999             RemoveResource(codeObject.bitmap);
1000          dropBox.DeleteRow(row);
1001       }
1002    }
1003
1004    void SelectObject(ObjectInfo object)
1005    {
1006       if(this)
1007       {
1008          DataRow row = dropBox.FindRow((int)object);
1009          this.object = object ? object.instance : null;
1010          propertyValue.userData = object ? (void *)object.instance : null;
1011          dropBox.SelectRow(row);
1012       }
1013    }
1014
1015    void RenameObject(ObjectInfo object, char * name)
1016    {
1017       DataRow row = dropBox.FindRow((int)object);
1018       CodeObject codeObject = row.GetData(null);
1019       // Isn't this useless? Shouldn't it be after?
1020       codeObject.name = name;
1021       // row.SetData(null, codeObject);  // Is this necessary?
1022    }
1023
1024    void DataBox::EditSetData(void * setValue, bool closingDropDown)
1025    {
1026       ((Sheet)master.master).SetData(setValue, this);
1027    }
1028
1029    void SetData(void * setValue, DataBox dataBox)
1030    {
1031       //PropertyInfo propertyPtr = row.GetData(null);
1032       PropertyInfo propertyPtr = properties.GetData(null);
1033       Property prop = propertyPtr ? propertyPtr.prop : null;
1034       Instance object = this.object;
1035       if(prop)
1036       {   
1037          Class dataType = prop.dataTypeClass;
1038          if(!dataType)
1039             dataType = prop.dataTypeClass = eSystem_FindClass(codeEditor.privateModule, prop.dataTypeString);
1040          if(propertyPtr.subMember)
1041          {
1042             DataMember member = propertyPtr.subMember;
1043             Class subDataType = member.dataTypeClass;
1044             if(!member.dataTypeClass)
1045                subDataType = member.dataTypeClass = eSystem_FindClass(codeEditor.privateModule, member.dataTypeString);
1046             if(subDataType)
1047             {
1048                void * data = null;
1049                if(!subDataType.dataType)
1050                   subDataType.dataType = ProcessTypeString(subDataType.dataTypeString, false);
1051
1052                if(dataType.type == structClass)
1053                {
1054                   data = new0 byte[dataType.structSize];
1055                   prop.Get(object, data);
1056                   // CopyBytes((byte *)data + member.offset + propertyPtr.extraOffset, &setValue, subDataType.size);
1057                   CopyBytes((byte *)data + member.offset + propertyPtr.extraOffset, &setValue, subDataType.dataType.size);
1058                   prop.Set(object, data);
1059                }
1060                else if(dataType.type == normalClass || dataType.type == noHeadClass)
1061                {
1062                }
1063                else
1064                {
1065                   if(dataType.type == bitClass)
1066                   {
1067                      BitMember bitMember = (BitMember) member;
1068                      if(subDataType)
1069                      {
1070                         DataValue value = { 0 };
1071                         value.ui = prop.Get(object);
1072                         value.ui &= ~ (uint)bitMember.mask;
1073                         value.ui |= (uint)setValue << bitMember.pos;
1074                         prop.Set(object, value.ui);
1075                      }
1076                   }
1077                   else
1078                   {
1079                      data = dataType.typeSize ? new0 byte[dataType.typeSize] : null;
1080                      prop.Get(object, data);
1081                      // CopyBytes((byte *)data + member.offset + propertyPtr.extraOffset, &setValue, subDataType.typeSize);
1082                      CopyBytes((byte *)data + member.offset + propertyPtr.extraOffset, &setValue, subDataType.dataType.size);
1083                      // TODO: Support non 32 bit datatypes here
1084                      prop.Set(object, data);
1085                   }
1086                }
1087
1088                if(data) dataType._vTbl[__ecereVMethodID_class_OnFree](dataType,&data);
1089                delete data;
1090             }
1091          }
1092          else if(propertyPtr.subProperty)
1093          {
1094             Property subProperty = propertyPtr.subProperty;
1095             Class subDataType = subProperty.dataTypeClass;
1096             if(!subDataType)
1097                subDataType = subProperty.dataTypeClass = eSystem_FindClass(codeEditor.privateModule, subProperty.dataTypeString);
1098             if(subDataType)
1099             {
1100                void * data = null;
1101
1102                if(dataType.type == structClass)
1103                {
1104                   data = new0 byte[dataType.structSize];
1105                   prop.Get(object, data);
1106                   subProperty.Set(data, (uint)setValue);
1107                   prop.Set(object, data);
1108                }
1109                else if(dataType.type == normalClass || dataType.type == noHeadClass)
1110                {
1111                   Instance current = (Instance)prop.Get(object);
1112                   Instance propObject = eInstance_New(dataType);
1113                   CopyInstanceData(dataType, propObject, current);
1114                   subProperty.Set(propObject, setValue);
1115                   prop.Set(object, propObject);
1116                }
1117                else
1118                {
1119                   data = dataType.typeSize ? new0 byte[dataType.typeSize] : null;
1120                   prop.Get(object, data);
1121                   subProperty.Set(data, setValue);
1122                   // TODO: Support not 32 bit data types here
1123                   prop.Set(object, data);
1124                }
1125
1126                if(data) dataType._vTbl[__ecereVMethodID_class_OnFree](dataType,&data);
1127                delete data;
1128             }
1129          }
1130          else
1131          {
1132             SetPropValue(prop, object, setValue);
1133          }      
1134          Code_FixProperty(propertyPtr.prop, object);
1135
1136          properties.Update(null);
1137          dropBox.Update(null);
1138          codeEditor.designer.Update(null);
1139          codeEditor.Update(null);   // patch for redraw bug if on top
1140
1141          ListProperties(false);
1142
1143          dataBox.editor.font = { propertyPtr.font.faceName, propertyPtr.font.size, propertyPtr.font.bold };
1144          codeEditor.ModifyCode();
1145       }
1146    }
1147
1148    bool SaveEdit(PropertyInfo propertyPtr, Instance object)
1149    {
1150       codeEditor.designer.Update(null);
1151       codeEditor.Update(null);   // patch for redraw bug if on top
1152       properties.Update(null);
1153       dropBox.Update(null);
1154
1155       Code_FixProperty(propertyPtr.prop, object);
1156       ListProperties(false);
1157
1158       codeEditor.ModifyCode();
1159       return true;
1160    }
1161
1162    void ToggleSheet()
1163    {
1164       if(!propBtn.checked)
1165       {
1166          propBtn.checked = true;
1167          propBtn.NotifyClicked(this, propBtn, 0,0,0);
1168       }
1169       else
1170       {
1171          methBtn.checked = true;
1172          methBtn.NotifyClicked(this, methBtn, 0,0,0);
1173       }
1174    }
1175
1176    bool AttachMethodSelected(MenuItem selection, Modifiers mods)
1177    {
1178       ClassFunction function = (ClassFunction)selection.id;
1179       codeEditor.AttachMethod(attachMethod, function);
1180       return true;
1181    }
1182
1183    bool ReattachMethodSelected(MenuItem selection, Modifiers mods)
1184    {
1185       ClassFunction function = (ClassFunction)selection.id;
1186       CodeObject object = methods.GetData(methodName);
1187       codeEditor.ReAttachMethod(attachMethod, function);
1188       return true;
1189    }
1190
1191    bool OverrideMethodSelected(MenuItem selection, Modifiers mods)
1192    {
1193       ClassFunction function = (ClassFunction)selection.id;
1194       CodeObject object = methods.GetData(methodName);
1195       if(object)
1196          codeEditor.AddMethod(object.method);   
1197       return true;
1198    }
1199
1200    bool GotoMethodSelected(MenuItem selection, Modifiers mods)
1201    {
1202       ClassFunction function = (ClassFunction)selection.id;
1203       CodeObject object = methods.GetData(methodName);
1204       if(object)
1205          codeEditor.GoToMethod(object.method.name);
1206       return true;
1207    }
1208
1209    bool DetachMethodSelected(MenuItem selection, Modifiers mods)
1210    {
1211       ClassFunction function = (ClassFunction)selection.id;
1212       CodeObject object = methods.GetData(methodName);
1213       if(object)
1214          codeEditor.DetachMethod(object.method, object.function, object.overriden);
1215       return true;
1216    }
1217
1218    bool DeleteMethodSelected(MenuItem selection, Modifiers mods)
1219    {
1220       ClassFunction function = (ClassFunction)selection.id;
1221       CodeObject object = methods.GetData(methodName);
1222       if(object)
1223          object.deleteBtn.NotifyClicked(this, object.deleteBtn, 0,0,0);
1224       return true;
1225    }
1226
1227    bool AddMethodClicked(Button button, int x, int y, Modifiers mods)
1228    {
1229       DataRow row = (DataRow)button.id;
1230       CodeObject object = row.GetData(methodName);
1231       codeEditor.AddMethod(object.method);   
1232       return true;
1233    }
1234
1235    void CreateButtons(CodeObject codeObject, int y, int h, DataRow row)
1236    {
1237       BitmapResource bitmap;
1238       
1239       if(codeObject.overriden)
1240       {
1241          if(codeObject.overriden == 1)
1242          {
1243             codeObject.deleteBtn = Button
1244             {
1245                methods, master = this,
1246                inactive = true,
1247                bitmap = { ":actions/delete.png", alphaBlend = true },
1248                anchor = { right = 16, top = y },
1249                size = { 16, h },
1250                id = (int)row;
1251
1252                bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1253                {
1254                   CodeObject codeObject = ((DataRow)button.id).GetData(null);
1255                   bool confirmation = !Code_IsFunctionEmpty(codeObject.function, codeObject.method, codeEditor.selected);
1256
1257                   if(confirmation)
1258                   {
1259                      char title[1024];
1260                      sprintf(title, "Delete %s", codeObject.name);
1261                      if(MessageBox
1262                         {
1263                            master = parent, type = okCancel, text = title, 
1264                            contents = "Method still contains code. Are you sure you want to delete it?"
1265                         }.Modal() == ok)
1266                         confirmation = false;
1267                   }
1268
1269                   if(!confirmation && codeObject.function.attached.count)
1270                   {
1271                      char title[1024];
1272                      sprintf(title, "Delete %s", codeObject.name);
1273                      confirmation = true;
1274                      if(MessageBox
1275                         {
1276                            master = parent, type = okCancel, text = title,
1277                            contents = "Other methods are still attached to this method. Are you sure you want to delete it?"
1278                         }.Modal() == ok)
1279                         confirmation = false;
1280                   }
1281
1282                   if(!confirmation)
1283                   {
1284                      codeEditor.DeleteMethod(codeObject.function);
1285                   }
1286                   return false;
1287                }
1288             };
1289             incref codeObject.deleteBtn;
1290             codeObject.deleteBtn.Create();
1291          }
1292
1293          if(codeObject.overriden == 2 || !codeObject.function.attached.count)
1294          {
1295             codeObject.detachBtn = Button 
1296             {
1297                methods,
1298                master = methods.master,
1299                inactive = true,
1300                bitmap = { ":actions/detach.png" },
1301                anchor = { right = 0, top = y },
1302                size = { 16, h },
1303                id = (int)row;
1304
1305                bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1306                {
1307                   DataRow row = (DataRow)button.id;
1308                   CodeObject object = row.GetData(methodName);
1309
1310                   codeEditor.DetachMethod(object.method, object.function, object.overriden);
1311                   return true;
1312                }
1313             };
1314             incref codeObject.detachBtn;
1315             codeObject.detachBtn.Create();
1316          }
1317       }
1318       else
1319       {
1320          if(codeObject.compatible.count)
1321          {
1322             codeObject.attachBtn = Button
1323             {
1324                parent = methods, master = methods.master,
1325                inactive = true,
1326                bitmap = { ":actions/attach.png" },
1327                anchor = { right = 0, top = y },
1328                size = { 16, h },
1329                id = (int)row;
1330
1331                bool NotifyPushed(Button button, int x, int y, Modifiers mods)
1332                {
1333                   // Create menu
1334                   DataRow row = (DataRow)button.id;
1335                   CodeObject object = row.GetData(methodName);
1336                   OldLink compatible;
1337                   PopupMenu popupMenu;
1338
1339                   Menu menu { };
1340                   
1341                   for(compatible = object.compatible.first; compatible; compatible = compatible.next)
1342                   {
1343                      ClassFunction function = compatible.data;
1344                      MenuItem { menu, function.declarator.symbol.string, id = (int)function, NotifySelect = AttachMethodSelected };
1345                   }
1346                   attachMethod = object.method;
1347
1348                   popupMenu = PopupMenu
1349                   { 
1350                      master = this, menu = menu, 
1351                      position =
1352                      {
1353                         button.absPosition.x - app.desktop.position.x,
1354                         button.absPosition.y - app.desktop.position.y + button.size.h
1355                      };
1356                   };
1357                   popupMenu.Create();
1358                   button.ReleaseCapture();
1359                   popupMenu.Capture();
1360                   return false;
1361                }
1362             };
1363             incref codeObject.attachBtn;
1364             codeObject.attachBtn.Create();
1365          }
1366       }
1367    }
1368    Instance object;
1369    Method attachMethod;
1370    char selectedMethod[1024];
1371    CodeEditor codeEditor;
1372    OldList categories;
1373    char selectedProp[1024];
1374    int selectedScroll;
1375 }
1376
1377 static int String_OnCompare(char ** string1, char ** string2)
1378 {
1379    int result = 0;
1380    if(*string1 && *string2)
1381       result = strcmpi(*string1, *string2);
1382    else if(!*string1 && *string2)
1383       result = 1;
1384    else if(*string1 && !*string2)
1385       result = -1;
1386    return result;
1387 }
1388
1389 static void CopyInstanceData(Class dataType, Instance propObject, Instance current)
1390 {
1391    Class _class;
1392    for(_class = dataType; _class && _class.type != systemClass; _class = _class.base)
1393    {
1394       DataMember member;
1395       for(member = _class.membersAndProperties.first; member; member = member.next)
1396       {               
1397          Class memberType = member.dataTypeClass;
1398          if(!memberType)
1399             memberType = member.dataTypeClass = eSystem_FindClass(((Designer)GetActiveDesigner()).codeEditor.privateModule, member.dataTypeString);
1400          if(member.isProperty)
1401          {
1402             Property subProp = (Property) member;
1403             if(subProp.Get && subProp.Set)
1404                CopyProperty(subProp, propObject, current);
1405          }
1406          else
1407          {
1408             if(memberType)
1409                // TOCHECK: I have serious doubts this works in many cases.
1410                memberType._vTbl[__ecereVMethodID_class_OnCopy](memberType, (byte *)propObject + member.offset, (byte *)current + member.offset);
1411             else if(member.memberOffset)
1412                memcpy((byte *)propObject + member.offset, (byte *)current + member.offset, member.memberOffset);
1413          }
1414       }
1415    }
1416 }
1417
1418 class PropertyInfo : struct
1419 {
1420 public:
1421    Property prop;
1422    bool disabled;
1423    FontResource font;
1424    char * categoryName;
1425    DataMember subMember;
1426    Property subProperty;
1427    uint extraOffset;
1428
1429    void OnDisplay(Surface surface, int x, int y, int width, Instance object, Alignment alignment, DataDisplayFlags displayFlags)
1430    {
1431       Property prop = this.prop;
1432
1433       surface.TextFont(font.font);
1434       if(disabled)
1435       {  
1436          surface.SetBackground(Color { 170, 170, 170 });
1437          surface.Area(0,0, x+width-1, y+100);
1438       }
1439       else if(prop && prop.dataTypeString)
1440       {
1441          Class dataType = prop.dataTypeClass;
1442          Module module = ((Designer)GetActiveDesigner()).codeEditor.privateModule;
1443          if(!dataType)
1444             dataType = prop.dataTypeClass = eSystem_FindClass(module, prop.dataTypeString);
1445          
1446          if(dataType && prop.Get)
1447          {
1448             void * dataPtr, * data = null, * subData = null;
1449             DataValue valueData, valueSubData;
1450             uint64 bitValue;
1451             
1452             // Get main prop
1453             if(dataType.type == structClass)
1454             {
1455                data = new0 byte[dataType.structSize];
1456                prop.Get(object, data);
1457                dataPtr = data;
1458             }
1459             else
1460             {
1461                GetProperty(prop, object, &valueData);
1462                if(dataType.type == normalClass)
1463                   dataPtr = valueData.p;
1464                else
1465                   dataPtr = &valueData;
1466             }
1467             
1468             // Get sub prop
1469             if(this.subMember)
1470             {
1471                DataMember member = this.subMember;
1472                Class subDataType = member.dataTypeClass;
1473                if(!subDataType)
1474                   subDataType = member.dataTypeClass = eSystem_FindClass(((Designer)GetActiveDesigner()).codeEditor.privateModule, member.dataTypeString);
1475                if(subDataType)
1476                {
1477                   if(dataType.type == bitClass)
1478                   {
1479                      BitMember bitMember = (BitMember)member;
1480                      bitValue = (valueData.i & bitMember.mask) >> bitMember.pos;
1481                      dataPtr = &bitValue;
1482                   }
1483                   else
1484                      dataPtr = (byte *)dataPtr + member.offset + this.extraOffset;
1485                }
1486                dataType = subDataType;
1487             }
1488             else if(this.subProperty)
1489             {
1490                Property subProperty = this.subProperty;
1491                Class subDataType = subProperty.dataTypeClass;
1492                if(!subDataType)
1493                   subDataType = subProperty.dataTypeClass = eSystem_FindClass(((Designer)GetActiveDesigner()).codeEditor.privateModule, subProperty.dataTypeString);
1494                if(!subProperty.Get) subDataType = null;
1495                if(subDataType)
1496                {
1497                   if(subDataType.type == structClass)
1498                   {
1499                      subData = new0 byte[subDataType.structSize];
1500                      subProperty.Get(dataPtr, subData);
1501                      dataPtr = subData;
1502                   }
1503                   else
1504                   {
1505                      GetProperty(subProperty, dataPtr, &valueSubData);
1506                      if(subDataType.type == normalClass)
1507                         dataPtr = valueSubData.p;
1508                      else
1509                         dataPtr = &valueSubData;
1510                   }
1511                }
1512                dataType = subDataType;
1513             }
1514
1515             if(dataType)
1516                dataType._vTbl[__ecereVMethodID_class_OnDisplay](dataType, dataPtr, surface, x, y, width, null, alignment, displayFlags);
1517
1518             delete data;
1519             delete subData;
1520          }
1521       }
1522    }
1523
1524    Window OnEdit(DataBox dataBox, Window obsolete, int x, int y, int w, int h, void * unused)
1525    {
1526       EditBox editData = null;
1527       Property prop = this.prop;
1528       
1529       dataBox.SetData = Sheet::EditSetData;
1530       if(prop && prop.dataTypeString && !this.disabled)
1531       {
1532          Sheet propertyWindow = (Sheet)dataBox.master.master;
1533          Instance object = propertyWindow.object;
1534          Class dataType = prop.dataTypeClass;
1535          if(!dataType)
1536             dataType = prop.dataTypeClass = eSystem_FindClass(((Designer)GetActiveDesigner()).codeEditor.privateModule, prop.dataTypeString);
1537
1538          if(dataType && prop.Get)
1539          {
1540             void * dataPtr, * data = null, * subData = null;
1541             DataValue valueData, valueSubData;
1542             uint64 bitValue;
1543             
1544             // Get main prop
1545             if(dataType.type == structClass)
1546             {
1547                data = new0 byte[dataType.structSize];
1548                prop.Get(object, data);
1549                dataPtr = data;
1550             }
1551             else
1552             {
1553                GetProperty(prop, object, &valueData);
1554                if(dataType.type == normalClass)
1555                   dataPtr = valueData.p;
1556                else
1557                   dataPtr = &valueData;
1558             }
1559             
1560             // Get sub prop
1561             if(this.subMember)
1562             {
1563                DataMember member = this.subMember;
1564                Class subDataType = member.dataTypeClass;
1565                if(!subDataType)
1566                   subDataType = member.dataTypeClass = eSystem_FindClass(((Designer)GetActiveDesigner()).codeEditor.privateModule, member.dataTypeString);
1567                if(subDataType)
1568                {
1569                   if(dataType.type == bitClass)
1570                   {
1571                      BitMember bitMember = (BitMember)member;
1572                      bitValue = (valueData.i & bitMember.mask) >> bitMember.pos;
1573                      dataPtr = &bitValue;
1574                   }
1575                   else
1576                      dataPtr = (byte *)dataPtr + member.offset + this.extraOffset;
1577                }
1578                dataType = subDataType;
1579             }
1580             else if(this.subProperty)
1581             {
1582                Property subProperty = this.subProperty;
1583                Class subDataType = subProperty.dataTypeClass;
1584                if(!subDataType)
1585                   subDataType = subProperty.dataTypeClass = eSystem_FindClass(((Designer)GetActiveDesigner()).codeEditor.privateModule, subProperty.dataTypeString);
1586                if(!subProperty.Get) subDataType = null;
1587                if(subDataType)
1588                {
1589                   if(subDataType.type == structClass)
1590                   {
1591                      subData = new0 byte[subDataType.structSize];
1592                      subProperty.Get(dataPtr, subData);
1593                      dataPtr = subData;
1594                   }
1595                   else
1596                   {
1597                      GetProperty(subProperty, dataPtr, &valueSubData);
1598                      if(subDataType.type == normalClass)
1599                         dataPtr = valueSubData.p;
1600                      else
1601                         dataPtr = &valueSubData;
1602                   }
1603                }
1604                dataType = subDataType;
1605             }
1606
1607             if(dataType)
1608                editData = (void *)dataType._vTbl[__ecereVMethodID_class_OnEdit](dataType, dataPtr, dataBox, obsolete,  x, y, w, h, object /*unused*/);
1609
1610             delete data;
1611             delete subData;
1612
1613             editData.font = { font.faceName, font.size, font.bold };
1614          }
1615       }
1616       return editData;
1617    }
1618
1619    int OnCompare(PropertyInfo data2)
1620    {
1621       char * category1 = prop ? prop.category : categoryName;
1622       char * category2 = data2.prop ? data2.prop.category : data2.categoryName;
1623       int result;
1624
1625       if(!category1) category1 = "Misc";
1626       if(!category2) category2 = "Misc";
1627       
1628       if(!prop)
1629       {
1630          // result = String::OnCompare((String)category1, (String)category2);
1631          result = String_OnCompare(&category1, &category2);
1632       }
1633       else
1634       //if(!result)
1635       {
1636          if(subMember && !data2.subMember)
1637          {
1638             result = 1;
1639          }
1640          else if(!subMember && data2.subMember)
1641          {
1642             result = 1;
1643          }
1644          else if(subMember && data2.subMember)
1645          {
1646             if(subMember.id < data2.subMember.id)
1647                result = -1;
1648             else if(subMember.id > data2.subMember.id)
1649                result = 1;
1650             else
1651                result = 0;
1652          }
1653          else if(subProperty && !data2.subProperty)
1654          {
1655             result = 1;
1656          }
1657          else if(!subProperty && data2.subProperty)
1658          {
1659             result = 1;
1660          }
1661          else if(subProperty && data2.subProperty)
1662          {
1663             if(subProperty.id < data2.subProperty.id)
1664                result = -1;
1665             else if(subProperty.id > data2.subProperty.id)
1666                result = 1;
1667             else
1668                result = 0;
1669          }
1670          else if(prop && !data2.prop)
1671             result = 1;
1672          else if(!prop && data2.prop)
1673             result = -1;
1674          else
1675             // result = ((String)prop.name).OnCompare(data2.prop.name);
1676             // result = String::OnCompare((String)prop.name, (String)data2.prop.name);
1677             result = String_OnCompare(&prop.name, &data2.prop.name);
1678       }
1679       return result;
1680    }
1681
1682    bool OnSaveEdit(Window editControl, void * unusedData)
1683    {
1684       Property prop = this.prop;
1685       if(prop)
1686       {
1687          Sheet sheet = (Sheet)editControl.master.master.master;
1688          Instance object = sheet.object;
1689          Class mainDataType = prop.dataTypeClass;
1690          Class dataType;
1691          bool result = false;
1692          void * dataPtr, * data = null, * subData = null;
1693          void * propObject = null;
1694          DataValue valueData = { 0 }, valueSubData = { 0 };
1695          uint bitValue;
1696
1697          if(!mainDataType)
1698             mainDataType = prop.dataTypeClass = eSystem_FindClass(((Designer)GetActiveDesigner()).codeEditor.privateModule, prop.dataTypeString);
1699          dataType = mainDataType;
1700          
1701          // Prepare main prop
1702          if(dataType.type == structClass)
1703          {
1704             data = new0 byte[dataType.structSize];
1705             if(this.subMember || this.subProperty)
1706                prop.Get(object, data);
1707             dataPtr = data;
1708             propObject = data;
1709          }
1710          else if(dataType.type == normalClass || dataType.type == noHeadClass)
1711          {
1712             dataPtr = &valueData;
1713             
1714             if(this.subMember || this.subProperty)
1715             {
1716                Class _class;
1717                Instance current = (Instance)prop.Get(object);
1718                propObject = valueData.p = eInstance_New(dataType);
1719                CopyInstanceData(dataType, propObject, current);
1720             }
1721          }
1722          else
1723          {
1724             
1725             if(this.subMember || this.subProperty)
1726                GetProperty(prop, object, &valueData);
1727             
1728             dataPtr = &valueData;
1729             propObject = &valueData;
1730          }
1731          
1732          // Prepare sub prop
1733          if(this.subMember)
1734          {
1735             DataMember member = this.subMember;
1736             Class subDataType = member.dataTypeClass;
1737             if(!subDataType)
1738                subDataType = member.dataTypeClass = eSystem_FindClass(((Designer)GetActiveDesigner()).codeEditor.privateModule, member.dataTypeString);
1739             if(subDataType)
1740             {
1741                if(dataType.type == bitClass)
1742                   dataPtr = &bitValue;
1743                else
1744                   dataPtr = (byte *)dataPtr + member.offset + this.extraOffset;
1745             }
1746             dataType = subDataType;
1747          }
1748          else if(this.subProperty)
1749          {
1750             Property subProperty = this.subProperty;
1751             Class subDataType = subProperty.dataTypeClass;
1752             
1753             if(!subDataType)
1754                subDataType = subProperty.dataTypeClass = 
1755                   eSystem_FindClass(((Designer)GetActiveDesigner()).codeEditor.privateModule, subProperty.dataTypeString);
1756             if(!subProperty.Get) subDataType = null;
1757             if(subDataType)
1758             {
1759                if(subDataType.type == structClass)
1760                {
1761                   subData = new0 byte[subDataType.structSize];
1762                   dataPtr = subData;
1763                }
1764                else
1765                   dataPtr = &valueSubData;
1766             }
1767             dataType = subDataType;
1768          }
1769
1770          if(dataType)
1771          {
1772             if(dataType._vTbl[__ecereVMethodID_class_OnSaveEdit](dataType, dataPtr, editControl, null))
1773             {
1774                if(mainDataType.type == bitClass && this.subMember)
1775                {
1776                   BitMember bitMember = (BitMember)this.subMember;
1777                   valueData.ui &= ~ (uint)bitMember.mask;
1778                   valueData.ui |= bitValue << bitMember.pos;
1779                }
1780                if(this.subProperty)
1781                {
1782                   if(dataType.type == structClass)
1783                      this.subProperty.Set(propObject, subData);
1784                   else if(dataType.type == unitClass || dataType.type == enumClass || dataType.type == bitClass)
1785                   {
1786                      if(!strcmp(dataType.dataTypeString, "float"))
1787                         ((void(*)(void *,float))(void *)this.subProperty.Set)(propObject, valueSubData.f);
1788                      else if(!strcmp(dataType.dataTypeString, "double"))
1789                         ((void(*)(void *,double))(void *)this.subProperty.Set)(propObject, valueSubData.d);
1790                      else if(!strcmp(dataType.dataTypeString, "byte"))
1791                         ((void(*)(void *,byte))(void *)this.subProperty.Set)(propObject, valueSubData.uc);
1792                      else if(!strcmp(dataType.dataTypeString, "uint16"))
1793                         ((void(*)(void *,uint16))(void *)this.subProperty.Set)(propObject, valueSubData.us);
1794                      else 
1795                         this.subProperty.Set(propObject, valueSubData.ui);
1796                   }
1797                   else
1798                      this.subProperty.Set(propObject, valueSubData.ui);
1799                }
1800                if(mainDataType.type == structClass)
1801                   prop.Set(object, data);
1802                else if(mainDataType.type == unitClass || mainDataType.type == enumClass || mainDataType.type == bitClass)
1803                {
1804                   if(!strcmp(mainDataType.dataTypeString, "float"))
1805                      ((void(*)(void *,float))(void *)prop.Set)(object, valueData.f);
1806                   else if(!strcmp(mainDataType.dataTypeString, "double"))
1807                      ((void(*)(void *,double))(void *)prop.Set)(object, valueData.d);
1808                   else if(!strcmp(mainDataType.dataTypeString, "byte"))
1809                      ((void(*)(void *,byte))(void *)prop.Set)(object, valueData.uc);
1810                   else if(!strcmp(mainDataType.dataTypeString, "uint16"))
1811                      ((void(*)(void *,uint16))(void *)prop.Set)(object, valueData.us);
1812                   else
1813                      prop.Set(object, valueData.ui);
1814                }
1815                else
1816                   prop.Set(object, valueData.ui);
1817
1818                result = true;
1819             }
1820             if(data == dataPtr)     dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, &data);
1821             if(subData == dataPtr)  dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, &subData);
1822          }
1823          delete data;
1824          delete subData;
1825
1826          if(result)
1827             return sheet.SaveEdit(this, object);
1828       }
1829       return false;
1830    }
1831 };
1832
1833 class Category : struct
1834 {
1835    Category prev, next;
1836    char * name;
1837    DataRow row;
1838    bool collapsed;
1839 };