ide; fixed both ways: in a main project, if target is set to Shared Library, can...
[sdk] / ide / src / designer / CodeEditor.ec
1 import "ide"
2
3 // *** Color Schemes ***
4
5 // *** The Old Color Scheme that was causing me auras and ophtalmic migraines -- Uncomment at your own risk! ***
6 /*
7 FontResource panelFont { $"Courier New", 10 };
8 FontResource codeFont { $"Courier New", 10 };
9 Color selectionColor = Color { 10, 36, 106 };
10 Color selectionText = white;
11 Color viewsBackground = white;
12 Color viewsText = black;
13 Color outputBackground = white;
14 Color outputText = black;
15 Color projectViewBackground = white;
16 Color projectViewText = black;
17 Color codeEditorBG = white;
18 Color codeEditorFG = black;
19 Color marginColor = Color {230, 230, 230};
20 Color selectedMarginColor = Color {200, 200, 200};
21 Color lineNumbersColor = Color {60, 60, 60};
22 SyntaxColorScheme colorScheme
23 {
24    keywordColors = [ blue, blue ];
25    commentColor = dimGray;
26    charLiteralColor = crimson;
27    stringLiteralColor = crimson;
28    preprocessorColor = green;
29    numberColor = teal;
30 };
31 */
32
33 // The new nice dark scheme -- so peaceful on my brain
34
35 FontResource panelFont { $"Courier New", 10 };
36 FontResource codeFont { $"Courier New", 10 };
37 /*
38 FontResource panelFont { $"Consolas", 12 };
39 FontResource codeFont { $"Consolas", 12 };
40 */
41 Color selectionColor = lightYellow;
42 Color selectionText = Color { 30, 40, 50 };
43 Color viewsBackground = Color { 30, 40, 50 };
44 Color viewsText = lightGray;
45 Color outputBackground = black;
46 Color outputText = lime;
47 Color projectViewBackground = Color { 30, 40, 50 };
48 Color projectViewText = lightGray;
49 Color codeEditorBG = black;
50 Color codeEditorFG = ivory;
51 Color marginColor = Color {24, 24, 24};
52 Color selectedMarginColor = Color {64, 64, 64};
53 Color lineNumbersColor = Color {160, 160, 160};
54 SyntaxColorScheme colorScheme
55 {
56    keywordColors = [ skyBlue, skyBlue ];
57    commentColor = Color { 125, 125, 125 };
58    charLiteralColor = Color { 245, 50, 245 };
59    stringLiteralColor = Color { 245, 50, 245 };
60    preprocessorColor = { 120, 220, 140 };
61    numberColor = Color {   0, 192, 192 };
62 };
63
64 // *********************
65
66 import "findCtx"
67 import "findExp"
68 import "findParams"
69
70 // UNTIL IMPLEMENTED IN GRAMMAR
71 #define ACCESS_CLASSDATA(_class, baseClass) \
72    (_class ? ((void *)(((char *)_class.data) + baseClass.offsetClass)) : null)
73
74 #ifdef ECERE_STATIC
75 extern int __attribute__((__stdcall__)) __ecereDll_Load_ecere(struct __ecereNameSpace__ecere__com__Instance * module);
76 extern int __attribute__((__stdcall__)) __ecereDll_Unload_ecere(struct __ecereNameSpace__ecere__com__Instance * module);
77 #endif
78
79 static Array<FileFilter> fileFilters
80 { [
81    { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
82    { $"Header Files for C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
83    { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
84    { $"Text files (*.txt)", "txt" },
85    { $"All files", null }
86 ] };
87
88 static Array<FileType> fileTypes
89 { [
90    { $"eC Source Code", "ec", whenNoneGiven },
91    { $"Text Files", "txt", never }
92 ] };
93
94 static char * iconNames[] = 
95 {
96    "<:ecere>constructs/class.png",
97    "<:ecere>constructs/data.png",
98    "<:ecere>constructs/method.png",
99    "<:ecere>constructs/event.png",
100    "<:ecere>constructs/property.png",
101    "<:ecere>constructs/namespace.png",
102    "<:ecere>constructs/dataType.png",
103    "<:ecere>constructs/enumValue.png",
104    "<:ecere>constructs/dataPrivate.png",
105    "<:ecere>constructs/methodPrivate.png",
106    "<:ecere>constructs/propertyPrivate.png"
107 };
108
109 enum SheetType { methods, properties };
110
111 extern int __ecereVMethodID_class_OnEdit;
112 extern int __ecereVMethodID_class_OnDisplay;
113 extern int __ecereVMethodID_class_OnGetString;
114 extern int __ecereVMethodID_class_OnFree;
115 extern int __ecereVMethodID_class_OnCompare;
116 extern int __ecereVMethodID_class_OnCopy;
117 extern int __ecereVMethodID_class_OnSaveEdit;
118 extern int __ecereVMethodID___ecereNameSpace__ecere__com__Module_OnLoad;
119
120 class EditFileDialog : FileDialog
121 {
122    bool OnCreate()
123    {
124       if(!ide.projectView && ideSettings.ideFileDialogLocation)
125          currentDirectory = ideSettings.ideFileDialogLocation;
126       return FileDialog::OnCreate();
127    }
128 }
129
130 EditFileDialog codeEditorFileDialog
131 {
132    type = multiOpen, text = $"Open",
133    types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType);
134    filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter)
135 };
136
137 EditFileDialog codeEditorFormFileDialog
138 {
139    type = open, text = $"Open Project",
140    types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType),
141    filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter)
142 };
143
144 define OpenBracket = '{';
145 define CloseBracket = '}';
146
147 enum MethodAction
148 {
149    actionAddMethod = 1, 
150    actionDeleteMethod = 2, 
151    actionDetachMethod = 3, 
152    actionAttachMethod = 4, 
153    actionReattachMethod = 5
154 };
155
156 //extern StatusField pos, ovr, caps, num;
157 //extern Class thisClass;
158
159 File output;
160
161 File fileInput;
162
163 bool parseError = false;
164
165 int returnCode;
166
167 Class insideClass;
168 Expression ctxInsideExp;
169 Expression paramsInsideExp;
170 ClassFunction insideFunction;
171 ClassDef insideDef;
172 Type instanceType;
173 char * instanceName;
174 Type functionType;
175 int paramsID;
176 bool insideInstance;
177
178 /****************************************************************************
179                               GENERATING
180 ****************************************************************************/
181
182 static void OutputString(File f, char * string)
183 {
184    int c;
185    for(c = 0; string[c]; c++)
186    {
187       if(string[c] == '\"')
188          f.Puts("\\\"");
189       else if(string[c] == '\\')
190          f.Puts("\\\\");
191       else
192          f.Putc(string[c]);
193    }                              
194 }
195
196 void OutputType(File f, Type type, bool outputName)
197 {
198    if(type)
199    {
200       switch(type.kind)
201       {
202          case voidType:
203             f.Printf("void");
204             break;
205          case charType:
206             if(!type.isSigned) f.Printf("unsigned ");
207             f.Printf("char");
208             break;
209          case shortType:
210             if(!type.isSigned) f.Printf("unsigned ");
211             f.Printf("short");
212             break;
213          case intType:
214             if(!type.isSigned) f.Printf("unsigned ");
215             f.Printf("int");
216             break;
217          case int64Type:
218             if(!type.isSigned) f.Printf("unsigned ");
219             f.Printf("__int64");
220             break;
221          case longType:
222             if(!type.isSigned) f.Printf("unsigned ");
223             f.Printf("long");
224             break;
225          case floatType:
226             f.Printf("float");
227             break;
228          case doubleType:
229             f.Printf("double");
230             break;
231          case classType:
232          {
233             if(type._class && !strcmp(type._class.string, "class"))
234             {
235                switch(type.classObjectType)
236                {
237                   case anyObject:
238                      f.Printf("any_object");
239                      break;
240                   default:
241                      f.Printf("typed_object");
242                      break;
243                }
244                if(type.byReference)
245                   f.Printf(" &");
246             }
247             else
248                // ADD CODE TO DECIDE WHETHER TO OUTPUT FULLY QUAlIFIED OR NOT:
249                f.Printf(type._class.shortName ? type._class.shortName : type._class.string);
250             break;
251          }
252          case structType:
253             break;
254          case unionType:
255             break;
256          case functionType:
257             break;
258          case arrayType:
259             OutputType(f, type.type, false);
260             break;
261          case pointerType:
262             OutputType(f, type.type, false);
263             f.Printf(" *");
264             break;
265          case ellipsisType:
266             f.Printf("...");
267             break;
268          case enumType:
269             break;
270          case methodType:
271             break;
272       }
273       if(outputName)
274       {
275          if(type.name)
276          {
277             f.Printf(" ");
278             f.Printf(type.name);
279          }
280       }
281       if(type.kind == arrayType)
282       {
283          f.Printf("[");
284          f.Printf("%d", type.arraySize);
285          f.Printf("]");
286       }
287    }
288 }
289
290 void DeleteJunkBefore(EditBoxStream f, int pos, int * position)
291 {
292    char ch;
293    int before = 0;
294    
295    if(position)
296       f.Seek(pos - *position, current);
297                                                       
298    // Try to delete spaces and \n before...
299    f.Seek(-1, current);
300    for(;f.Getc(&ch);)
301    {
302       if(!isspace(ch))
303          break;
304       /*else if(ch == '\n')
305       {
306          // Look for // comments on the line before
307          EditBox editBox = f.editBox;
308          EditLine line = editBox.line;
309          char * text;
310          char last = 0;
311          int c;
312          bool quoted = false;
313          line = line.prev;
314          text = line.text;
315          for(c = 0; text[c]; c++)
316          {
317             if(text[c] == '"')
318             {
319                quoted ^= true;
320                last = 0;
321             }
322             else if(!quoted)
323             {
324                if(text[c] == '/' && last == '/')
325                   break;
326                last = text[c];
327             }
328          }
329          if(text[c])
330             break;
331       }*/
332       before++;
333       f.Seek(-2, current);
334    }
335
336    f.DeleteBytes(before);
337    if(position)
338       *position = pos;
339 }
340
341 void GetLocText(EditBox editBox, File f, int position, Location loc, char ** text, int * size, int pad, int linePad)
342 {
343    EditLine l1, l2;
344    int y1,x1, y2,x2;
345
346    editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
347
348    // Cut & Paste function
349    
350    {
351       EditLine l1, l2;
352       int y1,x1,y2,x2;
353
354       f.Seek(loc.start.pos - position, current);
355       l1 = editBox.line;
356       x1 = editBox.charPos;
357       y1 = editBox.lineNumber;
358       f.Seek(loc.end.pos - loc.start.pos, current);
359       l2 = editBox.line;
360       x2 = editBox.charPos;
361       y2 = editBox.lineNumber;
362       editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
363
364       *size = editBox.SelSize();
365       *text = new char[*size+1 + (y2-y1+1) * linePad + pad]; // Add pad for tabs and new name
366       editBox.GetSel(*text, false);
367    }
368    
369    editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
370    f.Printf(""); // Make the stream point to where the editbox is
371 }
372
373 void Code_FixProperty(Property prop, Instance object)
374 {
375    Designer::FixProperty(prop, object);
376 }
377
378 bool Code_IsPropertyModified(Instance test, ObjectInfo selected, Property prop)
379 {
380    bool result = false;
381    if(prop.dataTypeString && (!prop.IsSet || prop.IsSet(selected.instance)))
382    {
383       Class dataType = prop.dataTypeClass;
384
385       if(!dataType)
386          dataType = prop.dataTypeClass = eSystem_FindClass(test._class.module, prop.dataTypeString);
387
388       if(dataType && dataType._vTbl && dataType.type == structClass)
389       {
390          void * dataForm = new0 byte[dataType.structSize];
391          void * dataTest = new0 byte[dataType.structSize];
392    
393          ((void (*)(void *, void *))(void *)prop.Get)(selected.instance, dataForm);
394          ((void (*)(void *, void *))(void *)prop.Get)(test, dataTest);
395
396          if((prop.IsSet && !prop.IsSet(test)) || ((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
397          {
398             ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
399             result = true;
400          }
401          delete dataForm;
402          delete dataTest;
403       }
404       else if(dataType && dataType._vTbl && (dataType.type == normalClass || dataType.type == noHeadClass))
405       {
406          void * dataForm, * dataTest;
407    
408          dataForm = ((void *(*)(void *))(void *)prop.Get)(selected.instance);
409          dataTest = ((void *(*)(void *))(void *)prop.Get)(test);
410    
411          if((prop.IsSet && !prop.IsSet(test)) || ((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
412          {
413             ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
414             result = true;
415          }
416       }
417       else if(dataType && dataType._vTbl)
418       {
419          DataValue dataForm, dataTest;
420    
421          GetProperty(prop, selected.instance, &dataForm);
422          GetProperty(prop, test, &dataTest);
423    
424          if((prop.IsSet && !prop.IsSet(test)) || ((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, &dataForm, &dataTest))
425          {
426             SetProperty(prop, test, dataForm);
427
428             // In case setting on test unset on real instance (e.g. isDefault)
429             if(strcmp(prop.name, "name"))
430             {
431                GetProperty(prop, selected.instance, &dataTest);
432                if(((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, &dataForm, &dataTest))
433                   SetProperty(prop, selected.instance, dataForm);
434             }
435             result = true;
436          }                                          
437       }
438    }
439    return result;
440 }
441
442 bool Code_IsPropertyDisabled(ObjectInfo selected, char * name)
443 {
444    bool disabled = false;
445    if(selected.oClass == selected)
446    {
447       ClassDef def;                  
448       if(selected.classDefinition)
449       {
450          for(def = selected.classDefinition.definitions->first; def; def = def.next)
451          {
452             if(def.type == defaultPropertiesClassDef)
453             {
454                MemberInit prop;
455                for(prop = def.defProperties->first; prop; prop = prop.next)
456                {
457                   if(prop.identifiers && prop.identifiers->first)
458                   {
459                      Identifier id = prop.identifiers->first;
460                      if(prop.variable && !strcmp(id.string, name))
461                      {
462                         disabled = true;
463                         break;
464                      }
465                   }
466                }
467             }
468             if(disabled) break;
469          }
470       }
471    }
472    else if(selected.instCode)
473    {
474       MembersInit members;
475       if(selected.instCode.members)
476       {
477          for(members = selected.instCode.members->first; members; members = members.next)
478          {
479             if(members.type == dataMembersInit && members.dataMembers)
480             {
481                MemberInit prop;
482                for(prop = members.dataMembers->first; prop; prop = prop.next)
483                {
484                   if(prop.identifiers && prop.identifiers->first)
485                   {
486                      Identifier id = prop.identifiers->first;
487                      if(prop.variable && !strcmp(id.string, name))
488                      {
489                         disabled = true;
490                         break;
491                      }
492                   }
493                }
494             }
495             if(disabled) break;
496          }
497       }
498    }
499    return disabled;
500 }
501
502 static bool CheckCompatibleMethod(Method method, Type type, Class regClass, bool isForm, Symbol selectedClass)
503 {
504    bool result = false;   
505    bool reset = false;
506    if(!method.dataType)
507       method.dataType = ProcessTypeString(method.dataTypeString, false);
508    if(!method.dataType.thisClass && !isForm)
509    {
510       reset = true;
511       method.dataType.thisClass = selectedClass;
512    }
513    //result = MatchTypes(method.dataType, type, null, regClass, regClass, false);
514    result = MatchTypes(type, method.dataType, null, regClass, regClass, false, true, true, false);
515    if(reset)
516       method.dataType.thisClass = null;
517    return result;
518 }
519
520 bool Code_IsFunctionEmpty(ClassFunction function, Method method, ObjectInfo object)
521 {
522    bool confirmation = true;
523    Statement body = function.body;
524    // Check if it contains any code
525    if((!body.compound.declarations || !body.compound.declarations->count) && (!body.compound.statements || body.compound.statements->count <= 1))
526    {
527       Class moduleClass = eSystem_FindClass(object.instance._class.module, "Module");
528       Statement stmt = body.compound.statements ? body.compound.statements->first : null;
529       Type dataType = method.dataType;
530       Type returnType = dataType.returnType;
531       Expression exp = null;
532
533       if(!method.dataType)
534          method.dataType = ProcessTypeString(method.dataTypeString, false);
535
536       confirmation = false;
537      
538       // Check if default function should be calling base class:
539       if(object.instance._class._vTbl[method.vid] == moduleClass._vTbl[__ecereVMethodID___ecereNameSpace__ecere__com__Module_OnLoad]) // Temp Check for DefaultFunction
540       {
541          if(returnType.kind != voidType)
542          {
543             if(!stmt || stmt.type != returnStmt || !stmt.expressions || stmt.expressions->count != 1)
544                confirmation = true;
545             else
546             {
547                exp = stmt.expressions->first;
548                if(returnType.kind == classType && !strcmp(returnType._class.string, "bool"))
549                {
550                   if( (exp.type != identifierExp || strcmp(exp.identifier.string, "true")) &&
551                       (exp.type != constantExp || strcmp(exp.constant, "1")))
552                      confirmation = true;
553                }
554                else
555                {
556                   if(exp.type != constantExp || strcmp(exp.constant, "0"))
557                      confirmation = true;
558                }
559             }
560          }
561          else
562          {
563             if(stmt)
564                confirmation = true;        
565          }
566       }
567       else
568       {
569          if(stmt)
570          {
571             if(returnType.kind != voidType)
572             {
573                if(stmt.type == returnStmt && stmt.expressions && stmt.expressions->count == 1)
574                   exp = stmt.expressions->first;
575             }
576             else if(stmt.type == expressionStmt && stmt.expressions && stmt.expressions->count == 1)
577                exp = stmt.expressions->first;
578          }
579
580          if(!exp || exp.type != callExp || exp.call.exp.type != identifierExp)
581             confirmation = true;        
582          else
583          {
584             Identifier id = exp.call.exp.identifier;
585             Class base = object.instance._class;
586             if(!id._class || (id._class.name && !strcmp(id._class.name, base.name)) || strcmp(id.string, method.name))
587                confirmation = true;
588             else
589             {
590                Expression arg = exp.call.arguments ? exp.call.arguments->first : null;
591                if(!arg || arg.type != identifierExp || strcmp("this", arg.identifier.string))
592                   confirmation = true;
593                else
594                {
595                   Type param;
596                   arg = arg.next;
597                   for(param = dataType.params.first; param; param = param.next)
598                   {
599                      if(!arg || arg.type != identifierExp || strcmp(param.name, arg.identifier.string))
600                      {
601                         confirmation = true;
602                         break;
603                      }
604                      arg = arg ?arg.next : null;
605                   }
606                }
607             }                  
608          }
609       }
610    }
611    return !confirmation;
612 }
613
614 class CodeEditor : Window
615 {
616    background = marginColor;
617    borderStyle = sizableDeep;
618    hasMaximize = true;
619    hasMinimize = true;
620    hasClose = true;
621    isDocument = true;
622    isActiveClient = true;
623    anchor = Anchor { left = 300, right = 150, top = 0, bottom = 0 };
624    menu = Menu { };
625    
626    // eWindow_SetX(A_CASCADE); eWindow_SetY(A_CASCADE); 
627    // eWindow_SetWidth(A_RELATIVE|80); eWindow_SetHeight(A_RELATIVE|80);
628
629    SheetType sheetSelected;
630    ToolBox toolBox;
631    Sheet sheet;
632
633    OldList * ast;
634    Context globalContext { };
635    OldList excludedSymbols { offset = (uint)&((Symbol)0).left };
636
637    OldList defines;
638    OldList imports;
639
640    OldList classes;
641    bool codeModified;
642    bool formModified;
643    
644    ObjectInfo selected;
645    ObjectInfo oClass;
646
647    // Methods Editing:
648    MethodAction methodAction;
649    Method method;
650    ClassFunction function;
651    bool moveAttached;
652    char methodName[1024];
653
654    bool updatingCode;
655    bool loadingFile;
656    bool fixCaret;
657    bool membersListShown;
658    bool membersAbove;
659    Location membersLoc;
660    EditLine membersLine;
661
662    Type functionType, instanceType;
663    int paramsID;
664    bool paramsShown;
665    bool paramsAbove;
666    Point paramsPosition;
667    Expression functionExp;
668    bool expectingMove;
669
670    BitmapResource icons[CodeObjectType];
671    
672    FontResource boldFont { $"Tahoma", 8.25f, bold = true, window = this };
673    FontResource normalFont { $"Tahoma", 8.25f, window = this };
674
675    Module privateModule;
676    NameSpace globalData;
677    bool skipModified;
678    bool inUseDebug;
679    OpenedFileInfo openedFileInfo;
680
681    FontResource font { codeFont.faceName, codeFont.size };
682    saveDialog = codeEditorFileDialog;
683
684    Designer designer { codeEditor = this, visible = false, saveDialog = codeEditorFormFileDialog };
685
686    bool noParsing;
687
688    property bool parsing { get { return !noParsing && !ide.noParsing; } };
689
690    void ProcessCaretMove(EditBox editBox, int line, int charPos)
691    {
692       char temp[512];
693       ObjectInfo classItem;
694
695       // OnActivateClient is called after OnActivate
696       if(!updatingCode)
697       {
698          sprintf(temp, $"Ln %d, Col %d", line, editBox.column + 1);
699          ide.pos.text = temp;
700       }
701       if(sheet.codeEditor != this) return;
702       
703       if(!updatingCode)
704       {
705          for(classItem = classes.first; classItem; classItem = classItem.next)
706          {
707             ClassDefinition classDef = classItem.classDefinition;
708             if(classDef && classDef.loc.Inside(line, charPos))
709                break;
710          }
711
712          if(classItem)
713          {
714             ObjectInfo object;
715             for(object = classItem.instances.first; object; object = object.next)
716             {
717                if(object.instCode)
718                {
719                   if(object.instCode.loc.Inside(line, charPos))
720                      break;
721                }
722             }
723             if(object)
724                sheet.SelectObject(object);
725             else
726                sheet.SelectObject(classItem);
727             Update(null);
728          }
729          //else
730          {
731             //sheet.SelectObject(null);
732             //Update(null);
733          }
734
735          sprintf(temp, $"Ln %d, Col %d", line, editBox.column + 1);
736          ide.pos.text = temp;
737
738          if(expectingMove)
739             expectingMove = false;
740          else
741          {
742             if(membersListShown)
743             {
744                bool hide = false;
745                if(line-1 != membersLoc.start.line)
746                   hide = true;
747                else
748                {
749                   char * buffer = membersLine.text;
750                   int c;
751
752                   if(charPos - 1 < membersLoc.start.charPos)
753                      hide = true;
754                   else if(charPos - 1 > membersLoc.end.charPos)
755                   {
756                      char * buffer = membersLine.text;
757                      //if(membersList.currentRow)
758                      //   hide = true;
759                      //else
760                      {
761                         for(c = membersLoc.start.charPos; c<=charPos && buffer[c]; c++)
762                            if(buffer[c] != ' ' && buffer[c] != '\t')
763                               break;
764                         if(c < charPos && buffer[c])
765                            hide = true;
766                      }
767                   }
768                }
769                if(hide)
770                {
771                   membersList.Destroy(0);
772                   membersListShown = false;
773                }
774             }
775             {
776                bool back = codeModified;
777                codeModified = false;
778                if(paramsShown)
779                   InvokeParameters(false, false, false);
780                /*if(membersListShown)
781                   InvokeAutoComplete(false, 0, true);*/
782                codeModified = back;
783             }
784          }
785       }
786    }
787
788    watch(modifiedDocument)
789    {
790       ProjectView projectView = ide.projectView;
791       if(projectView)
792       {
793          ProjectNode node = projectView.GetNodeFromWindow(this, null, false);
794          if(node)
795          {
796             node.modified = modifiedDocument;
797             projectView.Update(null);
798          }
799       }
800    };
801
802
803    EditBox editBox
804    {
805       textVertScroll = true, multiLine = true, /*lineNumbers = ideSettings.showLineNumbers,*/
806       freeCaret = ideSettings.useFreeCaret, caretFollowsScrolling = ideSettings.caretFollowsScrolling, 
807       tabKey = true, smartHome = true;
808       tabSelection = true, /*maxLineSize = 65536, */parent = this, hasHorzScroll = true, hasVertScroll = true;
809       selectionColor = selectionColor, selectionText = selectionText,
810       background = codeEditorBG, foreground = codeEditorFG, syntaxColorScheme = colorScheme,
811       font = font, borderStyle = none;
812       anchor = Anchor { left = 0, right = 0, top = 0, bottom = 0 };
813
814       bool OnMouseOver(int x, int y, Modifiers mods)
815       {
816          CodeEditor editor = (CodeEditor)master;
817          if(editor.designer && editor.designer.isDragging && !mods.isSideEffect)
818             Activate();
819          return true;
820       }
821
822       void NotifyCaretMove(EditBox editBox, int line, int charPos)
823       {
824          // Update Line Numbers
825          int spaceH;
826          int oldLine = lastLine;
827          display.FontExtent(font.font, " ", 1, null, &spaceH);
828          {
829             Box box { 0, (Min(oldLine,oldLine)-1) * spaceH - editBox.scroll.y, editBox.anchor.left.distance, (Max(oldLine, oldLine))*spaceH-1 - editBox.scroll.y };
830             Update(box);
831          }
832          {
833             Box box { 0, (Min(line,line)-1) * spaceH - editBox.scroll.y, editBox.anchor.left.distance, (Max(line, line))*spaceH-1 - editBox.scroll.y };
834             Update(box);
835          }
836          lastLine = line;
837
838          if(ide.activeClient == this)
839             ProcessCaretMove(editBox, line, charPos);
840          if(openedFileInfo)
841             openedFileInfo.CaretMove(line, charPos);
842       }
843
844       void NotifyOvrToggle(EditBox editBox, bool overwrite)
845       {
846          ide.ovr.color = overwrite ? black : Color { 128, 128, 128 };
847       }
848
849       void NotifyUpdate(EditBox editBox)
850       {
851          if(designer)
852          {
853             if(!skipModified)
854             {
855                codeModified = true;
856                designer.modifiedDocument = true;
857             }
858          }
859          modifiedDocument = true;
860       }
861
862       bool NotifyUnsetModified(EditBox editBox)
863       {
864          modifiedDocument = false;
865          return true;
866       }
867
868       bool NotifyCharsAdded(EditBox editBox, BufferLocation before, BufferLocation after, bool pasteOperation)
869       {
870          if(!loadingFile && after.y != before.y)
871          {
872             ProjectView projectView = ide.projectView;
873             if(projectView && fileName)
874             {
875                int c;
876                // HOW WE MIGHT WANT TO DO IT:
877                char * text = before.line.text;
878                for(c = before.x-1; c>= 0; c--)
879                   if(!isspace(text[c]))
880                      break;
881                ide.debugger.MoveIcons(fileName, before.y + (((!pasteOperation && c > -1) || !after.line.count) ? 1 : 0), after.y - before.y, false);
882
883                // HOW VISUAL STUDIO DOES IT:
884                /*
885                char * text = after.line.text;
886                for(c = after.line.count-1; c>= 0; c--)
887                   if(!isspace(text[c]))
888                      break;
889                ide.debugger.MoveIcons(fileName, before.y + ((c < 0) ? 1 : 0), after.y - before.y, false);
890                */
891             }
892             Update({ 0, 0, editBox.position.x, clientSize.h });
893          }
894
895          if(!updatingCode)
896          {
897             ObjectInfo oClass;
898
899             for(oClass = classes.first; oClass; oClass = oClass.next)
900             {
901                ObjectInfo object;
902                for(object = oClass.instances.first; object; object = object.next)
903                {
904                   if(object.instCode)
905                   {
906                      object.instCode.loc.start.AdjustAdd(before, after);
907                      object.instCode.loc.end.AdjustAdd(before, after);
908                   }
909                }
910                if(oClass.instCode)
911                {
912                   oClass.classDefinition.loc.start.AdjustAdd(before, after);
913                   oClass.classDefinition.loc.end.AdjustAdd(before, after);
914                }
915             }
916
917             if(!pasteOperation)
918             {
919                expectingMove = true;
920                if(membersListShown)
921                {
922                   bool hide = false;
923                   if(before.y != after.y)
924                      hide = true;
925                   else
926                   {
927                      char * buffer = membersLine.text;
928                      int c;
929                      bool firstChar = true;
930                      bool addedChar = false;
931                      char string[1024];
932                      int len = 0;
933
934                      DataRow row;
935
936                      membersLoc.end.charPos += after.x - Max(membersLoc.start.charPos, before.x);
937
938                      for(c = membersLoc.start.charPos; c<membersLoc.end.charPos && len < sizeof(string)-1; c++)
939                      {
940                         bool isSpace = (buffer[c] == ' ' || buffer[c] == '\t');
941                         if(!isalnum(buffer[c]) && buffer[c] != '_' && (!isSpace || !firstChar)) //|| membersList.currentRow
942                         {
943                            hide = true;
944                            break;
945                         }
946                         if(!isSpace) 
947                            firstChar = false;
948                         else if(firstChar)
949                         {
950                            membersLoc.start.charPos++;
951                            addedChar = true;
952                         }
953
954                         if(!firstChar)
955                            string[len++] = buffer[c];
956                      }
957                      if(firstChar)
958                      {
959                         row = membersList.currentRow;
960                         if(row && row.selected)
961                         {
962                            hide = true;
963                            if(addedChar)
964                               membersLoc.start.charPos--;
965                         }
966                      }
967
968                      string[len] = 0;
969
970                      if(!hide)
971                      {
972                         row = membersList.FindSubString(string);
973                         if(row)
974                            membersList.currentRow = row;
975                         else
976                         {
977                            row = membersList.FindSubStringi(string);
978                            if(row)
979                               membersList.currentRow = row;
980                            membersList.currentRow.selected = false;
981                         }
982                         if(row)
983                            membersList.SetScrollPosition(0, (row.index) * membersList.rowHeight);
984                      }
985                      else
986                      {
987                         row = membersList.currentRow;
988                      }
989
990                      // Accept current string if hiding typing char
991                      if(hide && row && row.selected)
992                      {
993                         char * string = row.string;
994                         int len = strlen(string);
995                         membersLoc.end.charPos -= after.x - before.x;
996                         editBox.GoToPosition(membersLine, membersLoc.start.line, membersLoc.start.charPos);
997                         editBox.Delete(membersLine, membersLoc.start.line, membersLoc.start.charPos,
998                                        membersLine, membersLoc.end.line, membersLoc.end.charPos);
999                         editBox.PutS(string);
1000                         editBox.GoToPosition(membersLine, membersLoc.start.line, membersLoc.start.charPos + len + 1 /*after.x - before.x*/);
1001
1002                         after.x += membersLoc.start.charPos + len - before.x;
1003                         before.x = membersLoc.start.charPos + len;
1004                      }
1005                   }
1006                   if(hide)
1007                   {
1008                      membersList.Destroy(0);
1009                      membersListShown = false;
1010                   }
1011                }
1012                if(/*after.x - before.x == 1 && */after.y == before.y && !membersListShown)
1013                {
1014                   EditLine line = editBox.line;
1015                   char * text = line.text;
1016                   char ch = text[after.x-1];
1017                   if(ch == '.' || (ch == '>' && after.x-1 > 0 && text[after.x-1-1] == '-') || (ch == ':' && after.x-1 > 0 && text[after.x-1-1] == ':'))
1018                   {
1019
1020                      /*
1021                      // Can we call invoke auto complete here instead?
1022
1023
1024                      int line, charPos;
1025                      Expression exp;
1026                      void * l1, * l2;
1027                      int x1,y1, x2,y2;
1028                      int oldCharPos;
1029                      Point caret;
1030
1031                      // Force caret update already...
1032                      editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
1033                      editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
1034
1035                      editBox.GetCaretPosition(&caret);
1036
1037                      
1038
1039                      // Go back in the buffer until no space before
1040                      //yydebug = true;
1041                      codeModified = true;
1042                      EnsureUpToDate();
1043                      SetYydebug(false);
1044                      { 
1045                         EditBoxStream f { editBox = editBox };
1046                         oldCharPos = x1;
1047                         x1--;
1048                         x2--;
1049                         if(text[after.x-1] == '>')
1050                         {
1051                            x1--;
1052                            x2--;
1053                         }
1054
1055                         editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
1056                         for(;;)
1057                         {
1058                            char ch;
1059                            if(!f.Seek(-1, current))
1060                               break;
1061                            f.Getc(&ch);
1062                            if(!isspace(ch)) break;
1063                            f.Seek(-1, current);
1064                         }
1065                         editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
1066
1067                         line = editBox.lineNumber + 1;
1068                         charPos = editBox.charPos + 1;
1069                         delete f;
1070                      }
1071
1072                      exp = FindExpTree(ast, line, charPos);
1073
1074                      if(exp)
1075                      {
1076                         Type type = exp.expType;
1077
1078                         if(type && text[after.x-1] != '.')
1079                         {
1080                            if(type.kind == TypePointer || type.kind == TypeArray)
1081                               type = type.type;
1082                            else
1083                               type = null;
1084                         }
1085
1086                         membersList.Clear();
1087                         ListMembers(type);
1088
1089                         if(membersList.rowCount)
1090                         {
1091                            membersList.Sort(null, 1);
1092                            membersList.master = this;
1093
1094                            caret.y += editBox.GetCaretSize();
1095                            caret.x -= 20;
1096
1097                            membersList.Create();
1098
1099                            {
1100                               int x = caret.x + editBox.GetAbsX() - app.desktop.GetAbsX() - editBox.GetScrollX();
1101                               int y = caret.y + editBox.GetAbsY() - app.desktop.GetAbsY() - editBox.GetScrollY();
1102                               Window parent = membersList.parent;
1103
1104                               if(!paramsAbove && (paramsShown || y + membersList.GetHeight() > parent.GetClientHeight()))
1105                               {
1106                                  y -= editBox.GetCaretSize() + membersList.GetHeight();
1107                                  membersAbove = true;
1108                               }
1109                               else
1110                                  membersAbove = false;
1111
1112                               membersList.position = { x, y };
1113                            }
1114          
1115                            membersLine = l1;
1116                            membersLoc.start.line = line - 1;
1117                            membersLoc.start.charPos = oldCharPos;
1118                            membersLoc.end = membersLoc.start;
1119                            membersListShown = true;
1120                         }
1121                      }
1122
1123                      SetThisClass(null);
1124                      SetCurrentContext(globalContext);
1125                      */
1126                      codeModified = true;
1127                      skipModified = true;
1128                      if(text[after.x-1] == ':')
1129                         InvokeAutoComplete(false, 0, false);
1130                      else if(text[after.x-1] == '.')
1131                         InvokeAutoComplete(false, 1, false);
1132                      else if(text[after.x-1] == '>')
1133                         InvokeAutoComplete(false, 2, false);
1134                      skipModified = false;
1135                   }
1136                   else if(ch == '(' || ch == OpenBracket || ch == ',' || ch == '='  || ch == '?'  || ch == ':')
1137                   {
1138                      codeModified = true;
1139                      skipModified = true;
1140
1141                      if(InvokeAutoComplete(true, 0, false))
1142                      {
1143                         if(ch == '(' || ch == OpenBracket)
1144                            InvokeParameters(true, true, false);
1145                         else
1146                            InvokeParameters(this.functionType ? false : true, false, false);
1147                      }
1148
1149                      // InvokeAutoComplete(true, 0, false);
1150                      skipModified = false;
1151                   }
1152                   else if(ch == ')' || ch == '}' || ch == ';')
1153                   {
1154                      codeModified = true;               
1155                      skipModified = true;
1156                      if(paramsShown)
1157                         InvokeParameters(false, true, false);
1158                      skipModified = false;
1159                   }
1160                   else 
1161                   {
1162                      bool back = codeModified;
1163                      codeModified = false;
1164                      if(paramsShown)
1165                         InvokeParameters(false, false, true);
1166                      if(membersListShown)
1167                         InvokeAutoComplete(false, 0, true);
1168                      codeModified = back;
1169                   }
1170                }
1171                else
1172                {
1173                   bool back = codeModified;
1174                   codeModified = false;
1175
1176                   if(paramsShown)
1177                      InvokeParameters(false, false, true);
1178                   /*if(membersListShown)
1179                      InvokeAutoComplete(false, 0, true);*/
1180
1181                   codeModified = back;
1182                }
1183             }
1184          }
1185          return true;
1186       }
1187
1188       bool NotifyCharsDeleted(EditBox editBox, BufferLocation before, BufferLocation after, bool pasteOperation)
1189       {
1190          if(!loadingFile && after.y != before.y)
1191          {
1192             ProjectView projectView = ide.projectView;
1193             if(projectView && fileName)
1194                ide.debugger.MoveIcons(fileName, before.y + 1, before.y - after.y, before.x == 0);
1195             Update({ 0, 0, editBox.position.x, clientSize.h });
1196          }
1197
1198          if(!updatingCode)
1199          {
1200             ObjectInfo oClass;
1201
1202             for(oClass = classes.first; oClass; oClass = oClass.next)
1203             {
1204                ObjectInfo object;
1205                Location * loc;
1206                for(object = oClass.instances.first; object; object = object.next)
1207                {
1208                   if(object.instCode)
1209                   {
1210                      loc = &object.instCode.loc;
1211
1212                      if((before.y+1 < loc->start.line || (before.y+1 == loc->start.line && before.x+1 <= loc->start.charPos)) && 
1213                         (after.y+1 > loc->end.line    || (after.y+1 == loc->end.line && after.x+1 >= loc->end.charPos)))
1214                      {
1215                         object.instCode = null;
1216                      }
1217                      else
1218                      {
1219                         loc->start.AdjustDelete(before, after);
1220                         loc->end.AdjustDelete(before, after);
1221                      }
1222                   }
1223                }
1224                if(oClass.classDefinition)
1225                {
1226                   loc = &oClass.classDefinition.loc;
1227                   if((before.y+1 < loc->start.line || (before.y+1 == loc->start.line && before.x+1 <= loc->start.charPos)) && 
1228                      (after.y+1 > loc->end.line    || (after.y+1 == loc->end.line && after.x+1 >= loc->end.charPos)))
1229                   {
1230                      oClass.classDefinition = null;
1231                   }
1232                   else
1233                   {
1234                      loc->start.AdjustDelete(before, after);
1235                      loc->end.AdjustDelete(before, after);
1236                   }
1237                }
1238             }
1239
1240             if(membersListShown)
1241             {
1242                bool hide = false;
1243                if(pasteOperation || before.y != after.y)
1244                   hide = true;
1245                else
1246                {
1247                   char * buffer = membersLine.text;
1248                   int c;
1249                   bool firstChar = true;
1250                   char string[1024];
1251                   int len = 0;
1252
1253                   if(before.x >= membersLoc.start.charPos)
1254                   {
1255                      for(c = membersLoc.start.charPos; c<before.x && len < sizeof(string)-1; c++)
1256                      {
1257                         bool isSpace = (buffer[c] == ' ' || buffer[c] == '\t');
1258                         if(!isalnum(buffer[c]) && buffer[c] != '_' && (!isSpace || !firstChar))
1259                         {
1260                            hide = true;
1261                            break;
1262                         }
1263                         if(!isSpace) firstChar = false;
1264
1265                         if(!firstChar)
1266                            string[len++] = buffer[c];
1267                      }
1268                   }
1269                   else
1270                   {
1271                      // If deleting spaces before...
1272                      for(c = before.x; c<membersLoc.start.charPos; c++)
1273                      {
1274                         bool isSpace = (buffer[c] == ' ' || buffer[c] == '\t');
1275                         if(!isSpace)
1276                         {
1277                            hide = true;
1278                            break;
1279                         }
1280                      }
1281                      if(!hide)
1282                         membersLoc.start.charPos = before.x;
1283                   }
1284
1285                   if(membersLoc.end.charPos >= after.x)
1286                   {
1287                      for(c = after.x; c<membersLoc.end.charPos && len < sizeof(string)-1; c++)
1288                      {
1289                         bool isSpace = (buffer[c] == ' ' || buffer[c] == '\t');
1290                         if(!isalnum(buffer[c]) && buffer[c] != '_' && (!isSpace || !firstChar))
1291                         {
1292                            hide = true;
1293                            break;
1294                         }
1295                         if(!isSpace) firstChar = false;
1296
1297                         if(!firstChar)
1298                            string[len++] = buffer[c];
1299                      }
1300                   }
1301                   else
1302                      hide = true;
1303
1304                   string[len] = '\0';
1305
1306                   membersLoc.end.charPos -= after.x - before.x;
1307                   if(!hide)
1308                   {
1309                      DataRow row;
1310                      row = membersList.FindSubString(string);
1311                      if(!row)
1312                      {
1313                         row = membersList.FindSubStringi(string);
1314                         if(row)
1315                            membersList.currentRow = row;
1316                         membersList.currentRow.selected = false;
1317                      }
1318                      else
1319                         membersList.currentRow = row;
1320                      if(row)
1321                         membersList.SetScrollPosition(0, row.index * membersList.rowHeight);
1322                   }
1323                }
1324                if(hide)
1325                {
1326                   membersList.Destroy(0);
1327                   membersListShown = false;
1328                }
1329
1330                /*
1331                if(paramsShown)
1332                {
1333                   InvokeParameters(false, false);
1334                }
1335                */
1336             }
1337          }
1338          return true;
1339       }
1340
1341       bool NotifyDropped(EditBox editBox, int x, int y)
1342       {
1343          char * controlClass = toolBox.controlClass;
1344          if(controlClass && controlClass[0])
1345          {
1346             Instance control;
1347             ObjectInfo object;
1348             ObjectInfo classObject;
1349
1350             //editBox.NotifyCaretMove(this, editBox, y, x);
1351             editBox.GoToLineNum(y);
1352             editBox.GoToPosition(editBox.line, y, x);
1353
1354             classObject = selected ? selected.oClass : null;
1355
1356             if((!selected || selected == classObject) && classObject && classObject.instances.first)
1357                selected = classObject.instances.last;
1358
1359             UpdateFormCode();
1360             control = eInstance_New(eSystem_FindClass(privateModule, controlClass));
1361             if(control)
1362             {
1363                AddObject(control, &object);
1364
1365                designer.CreateObject(control, object, false, classObject.instance);
1366                // designer.PostCreateObject(control, object, false, classObject.instance);
1367                designer.DroppedObject(control, object, false, classObject.instance);
1368
1369                sheet.AddObject(object, object.name, typeData /* className*/, true);
1370                
1371                UpdateFormCode();
1372                //codeModified = true;
1373                EnsureUpToDate();
1374             }
1375          }
1376          return true;
1377       }
1378
1379       bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
1380       {
1381          if(key == Key { space, ctrl = true })
1382          {
1383             membersList.Destroy(0);
1384             membersListShown = false;
1385             InvokeAutoComplete(false, 0, false);
1386             return false;
1387          }
1388          else if(key == Key { space, ctrl = true, shift = true })
1389             InvokeParameters(false, true, false);
1390          else if(key == escape)
1391             ide.RepositionWindows(true);
1392          else if(key == ctrlF7)
1393          {
1394             if(ide.projectView)
1395             {
1396                ProjectNode node = ide.projectView.GetNodeFromWindow(this, null, false);
1397                if(!node)
1398                   node = ide.projectView.GetNodeFromWindow(this, null, true);
1399                if(!node)
1400                {
1401                   char * s;
1402                   s = PrintString($"The ", fileName, $" file is not part of any project.\n", 
1403                      $"It can't be compiled.");
1404                   MessageBox { type = ok, /*parent = ide, */master = ide, text = $"File not in project error", contents = s }.Modal();
1405                   delete s;
1406                   return false;
1407                }
1408             }
1409          }
1410          return true;
1411       }
1412
1413       bool OnKeyDown(Key key, unichar ch)
1414       {
1415          CodeEditor editor = (CodeEditor)master;
1416          if(key == escape /*|| key == leftAlt || key == rightAlt || (key.ctrl && key.code != left && key.code != right && key.code != leftShift && key.code != rightShift && key.code !=  space)*/)
1417          {
1418             if(editor.membersListShown)
1419             {
1420                editor.membersList.Destroy(0);
1421                editor.membersListShown = false;
1422                return false;
1423             }
1424             if(editor.paramsShown)
1425             {
1426                editor.paramsList.Destroy(0);
1427                editor.paramsShown = false;
1428                FreeType(editor.functionType);
1429                FreeType(editor.instanceType);
1430
1431                editor.functionType = null;
1432                editor.instanceType = null;
1433                editor.paramsID = -1;
1434                return false;
1435             }
1436          }
1437          return EditBox::OnKeyDown(key, ch);
1438       }
1439
1440       void OnVScroll(ScrollBarAction action, int position, Key key)
1441       {
1442          if(anchor.left.distance)
1443          {
1444             Box box { 0, 0, anchor.left.distance-1, parent.clientSize.h - 1 };
1445             parent.Update(box);
1446          }
1447          EditBox::OnVScroll(action, position, key);
1448          {
1449             CodeEditor ce = (CodeEditor)parent;
1450             if(ce.openedFileInfo)
1451                ce.openedFileInfo.ScrollChange({ scroll.x, position });
1452          }
1453       }
1454
1455       void OnHScroll(ScrollBarAction action, int position, Key key)
1456       {
1457          EditBox::OnHScroll(action, position, key);
1458          {
1459             CodeEditor ce = (CodeEditor)parent;
1460             if(ce.openedFileInfo)
1461                ce.openedFileInfo.ScrollChange({ position, scroll.y });
1462          }
1463       }
1464    };
1465    ListBox membersList
1466    {
1467       master = this,
1468       fullRowSelect = false,
1469       interim = true,
1470       autoCreate = false,
1471       borderStyle = bevel;
1472       // size = { 200, 400 };
1473
1474       bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
1475       {
1476          DataRow row = listBox.currentRow;
1477          if(row)
1478          {
1479             char * string = row.string;
1480
1481             editBox.GoToPosition(membersLine, membersLoc.start.line, membersLoc.start.charPos);
1482             editBox.Delete(
1483                membersLine, membersLoc.start.line, membersLoc.start.charPos,
1484                membersLine, membersLoc.end.line, membersLoc.end.charPos);
1485             editBox.PutS(string);
1486
1487             listBox.Destroy(0);
1488             membersListShown = false;
1489          }
1490          return true;
1491       }
1492
1493       bool OnKeyDown(Key key, unichar ch)
1494       {
1495          CodeEditor editor = (CodeEditor) master;
1496          if(key == escape || key == leftAlt || key == rightAlt || 
1497             (key.ctrl && key.code != left && key.code != right && 
1498              key.code != leftShift && key.code != rightShift && key.code != space))
1499          {
1500             if(editor.paramsShown)
1501                editor.paramsList.Destroy(0);
1502             if(editor.membersListShown)
1503                editor.membersList.Destroy(0);
1504
1505             editor.paramsShown = false;
1506             FreeType(editor.functionType);
1507             FreeType(editor.instanceType);
1508
1509             editor.functionType = null;
1510             editor.instanceType = null;
1511             editor.paramsID = -1;
1512
1513             editor.membersListShown = false;
1514             return true;
1515          }
1516          else 
1517             return editor.editBox.OnKeyDown(key, ch);
1518          return false;
1519       }
1520
1521       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
1522       {
1523          CodeEditor editor = (CodeEditor)master;
1524          if(!active)
1525          {
1526             Destroy(0);
1527             editor.membersListShown = false;
1528          }
1529          return ListBox::OnActivate(active, previous, goOnWithActivation, direct);
1530       }
1531
1532       bool OnKeyHit(Key key, unichar ch)
1533       {
1534          CodeEditor editor = (CodeEditor) master;
1535
1536          switch(key)
1537          {
1538             case enter: case tab:
1539             {
1540                DataRow row = currentRow;
1541                if(row && row.selected)
1542                {
1543                   char * string = row.string;
1544
1545                   editor.editBox.GoToPosition(editor.membersLine, editor.membersLoc.start.line, editor.membersLoc.start.charPos);
1546                   editor.editBox.Delete(
1547                      editor.membersLine, editor.membersLoc.start.line, editor.membersLoc.start.charPos,
1548                      editor.membersLine, editor.membersLoc.end.line, editor.membersLoc.end.charPos);
1549                   editor.editBox.PutS(string);
1550
1551                   Destroy(0);
1552                   editor.membersListShown = false;
1553                }
1554                else
1555                   editor.editBox.OnKeyHit(key, ch);
1556                break;
1557             }
1558             case down:
1559             case up:
1560             case pageDown:
1561             case pageUp:
1562             case home:
1563             case end:
1564             {
1565                return ListBox::OnKeyHit(key, ch);
1566             }
1567             default:
1568             {
1569                /*
1570                bool result;
1571                // If before . or after
1572                //listBox.Destroy(true);
1573                result = editor.editBox.OnKeyHit(key, ch);
1574                return result;
1575                */
1576                return true;
1577             }
1578          }
1579
1580          return false;
1581       }
1582    };
1583
1584    Window paramsList
1585    {
1586       master = this, 
1587       interim = true,
1588       clickThrough = true,
1589       autoCreate = false,
1590       borderStyle = contour,
1591       cursor = null,
1592       background = { 255,255,225 },
1593       
1594       OnKeyDown = membersList.OnKeyDown;
1595
1596       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
1597       {
1598          CodeEditor editor = (CodeEditor)master;
1599          if(!active)
1600          {
1601             Destroy(0);
1602             editor.membersListShown = false;
1603          }
1604          return Window::OnActivate(active, previous, goOnWithActivation, direct);
1605       }
1606
1607       bool OnKeyHit(Key key, unichar ch)
1608       {
1609          CodeEditor editor = (CodeEditor)master;
1610
1611          if(!editor.membersListShown || editor.membersList.OnKeyHit(key, ch))
1612          {
1613             /*
1614             bool result = true; editor.editBox.OnKeyHit(key, ch);
1615             return (!created) ? false : result;
1616             */
1617             return true;
1618          }
1619          return false;
1620       }
1621
1622       void OnRedraw(Surface surface)
1623       {
1624          CodeEditor editor = (CodeEditor) master;
1625          Type type = editor.functionType ? editor.functionType : editor.instanceType;
1626          Type param;
1627          Type methodType = null;
1628
1629          char string[1024];
1630
1631          int functionW, nameW = 0;
1632          int totalW = 0;
1633          int spaceW, spaceH, commaW, commaWB, parW;
1634          int availW = 1024;
1635          int maxW = 0, lineW = 0;
1636          int realW = 0;
1637          int height = 0;
1638          int x = 2, y = 2;
1639          int id = 0;
1640
1641          Font font = editor.normalFont.font;
1642          Font boldFont = editor.boldFont.font;
1643          Display display = this.display;
1644
1645          if(!type) { return; };
1646
1647          if(type.kind == TypeKind::methodType) { methodType = type; type = type.method.dataType; }
1648
1649          display.FontExtent(boldFont, " ", 1, &spaceW, &spaceH);
1650          display.FontExtent(font, ", ", 2, &commaW, null);
1651          display.FontExtent(boldFont, ", ", 2, &commaWB, null);
1652          display.FontExtent(font, ")", 1, &parW, null);
1653
1654          string[0] = 0;
1655          if(editor.functionType)
1656          {
1657             PrintType(type.returnType, string, true, true);
1658             display.FontExtent(font, string, strlen(string), &functionW, null);
1659             if(type.name)
1660                display.FontExtent(font, type.name, strlen(type.name), &nameW, null);
1661             totalW = nameW + functionW + 2 * parW;
1662          }
1663          else
1664          {
1665             PrintType(type, string, (type.kind == functionType) ? true : false, true); // true);
1666             display.FontExtent(boldFont, string, strlen(string), &functionW, null);
1667             if(instanceName && type.kind != functionType)
1668                display.FontExtent(boldFont, instanceName, strlen(instanceName), &nameW, null);
1669             totalW = functionW + nameW;
1670             surface.TextFont(boldFont);
1671          }   
1672
1673          surface.WriteText(x, y, string, strlen(string));
1674          x += functionW + spaceW;
1675
1676          if(editor.functionType)
1677          {
1678             if(type.name)
1679                surface.WriteText(x, y, type.name, strlen(type.name));
1680             x += nameW;
1681             surface.WriteText(x, y, "(", 1);
1682             x += parW;
1683
1684             if(methodType && !methodType.staticMethod && methodType.methodClass)
1685             {
1686                int tw = 0, width;
1687
1688                if(id == editor.paramsID)
1689                   surface.TextFont(boldFont);
1690                
1691                if(methodType.methodClass)
1692                   surface.TextExtent(methodType.methodClass.name, strlen(methodType.methodClass.name), &tw, null);
1693
1694                width = tw;
1695
1696                if(type.params.first && (((Type)type.params.first).kind != voidType || type.params.count > 1))
1697                   width += ((id == editor.paramsID) ? commaWB : commaW);
1698
1699                if(!height)
1700                   maxW = lineW;
1701
1702                if(lineW && ((height && lineW + width > maxW) || (totalW + lineW + width + 20 > availW)))
1703                {
1704                   height += spaceH;
1705                   lineW = 0;
1706
1707                   x = 2 + nameW + spaceW + functionW + parW;
1708                   y += spaceH;
1709
1710                }
1711                if(methodType.methodClass)
1712                   surface.WriteText(x, y, methodType.methodClass.name, strlen(methodType.methodClass.name));
1713
1714                x += tw;
1715                if(type.params.first && (((Type)type.params.first).kind != voidType || type.params.count > 1))
1716                {
1717                   surface.WriteText(x, y, ",", 1);
1718                   x += ((id ==  editor.paramsID) ? commaWB : commaW);
1719                }      
1720
1721                lineW += width;
1722
1723                if(lineW > realW)
1724                   realW = lineW;
1725
1726                if(id == editor.paramsID)
1727                   surface.TextFont(font);
1728                id ++;
1729             }
1730
1731             if(!methodType || (methodType.staticMethod || !methodType.methodClass) || !type.params.first || ((Type)type.params.first).kind != voidType || type.params.count > 1)
1732             {
1733                for(param = type.params.first; param; param = param.next)
1734                {
1735                   char paramString[1024];
1736                   int tw, width;
1737
1738                   if(id == editor.paramsID || (param.kind == ellipsisType && id < editor.paramsID && editor.paramsID != -1))
1739                      surface.TextFont(boldFont);
1740
1741                   paramString[0] = 0;
1742                   PrintType(param, paramString, true, true);
1743                   surface.TextExtent(paramString, strlen(paramString), &tw, null);
1744                   width = tw;
1745                   if(param.next) width += ((id ==  editor.paramsID) ? commaWB : commaW);
1746
1747                   if(!height)
1748                      maxW = lineW;
1749
1750                   if(lineW && ((height && lineW + width > maxW) || (totalW + lineW + width + 20 > availW)))
1751                   {
1752                      height += spaceH;
1753                      lineW = 0;
1754
1755                      x = 2 + nameW + spaceW + functionW + parW;
1756                      y += spaceH;
1757
1758                   }
1759                   surface.WriteText(x, y, paramString, strlen(paramString));
1760                   x += tw;
1761                   if(param.next)
1762                   {
1763                      surface.WriteText(x, y, ",", 1);
1764                      x += ((id ==  editor.paramsID) ? commaWB : commaW);
1765                   }      
1766
1767                   lineW += width;
1768
1769                   if(lineW > realW)
1770                      realW = lineW;
1771
1772                   if(id == editor.paramsID || (param.kind == ellipsisType && id < editor.paramsID && editor.paramsID != -1))
1773                      surface.TextFont(font);
1774                   id ++;
1775                }
1776             }
1777
1778             surface.WriteText(x, y, ")", 1);
1779          }
1780          else if(instanceName && type.kind != functionType)
1781          {
1782             surface.WriteText(x, y, instanceName, strlen(instanceName));
1783          }
1784       }
1785
1786       bool OnResizing(int * w, int * h)
1787       {
1788          CodeEditor editor = (CodeEditor) master;
1789          Type type = editor.functionType ? editor.functionType : editor.instanceType;
1790          Type param;
1791          Type methodType = null;
1792
1793          char string[1024];
1794
1795          int functionW = 0, nameW = 0;
1796          int totalW = 0;
1797          int spaceW, spaceH, commaW, commaWB, parW;
1798          int availW = 1024;
1799          int maxW = 0, lineW = 0;
1800          int realW = 0;
1801          int height = 0;
1802          int id = 0;
1803
1804          Font font = editor.normalFont.font;
1805          Font boldFont = editor.boldFont.font;
1806          Display display = this.display;
1807
1808          if(type.kind == TypeKind::methodType)
1809          {
1810             methodType = type;
1811             ProcessMethodType(type.method);
1812             type = type.method.dataType;
1813          }
1814
1815          display.FontExtent(boldFont, " ", 1, &spaceW, &spaceH);
1816          display.FontExtent(font, ", ", 2, &commaW, null);
1817          display.FontExtent(boldFont, ", ", 2, &commaWB, null);
1818          display.FontExtent(font, ")", 1, &parW, null);
1819
1820          string[0] = 0;
1821          if(editor.functionType && type)
1822          {
1823             PrintType(type.returnType, string, true, true);
1824             display.FontExtent(font, string, strlen(string), &functionW, null);
1825             if(type.name)
1826                display.FontExtent(font, type.name, strlen(type.name), &nameW, null);
1827             totalW = nameW + spaceW + functionW + 2 * parW;
1828          }
1829          else if(type)
1830          {
1831             PrintType(type, string, false, true); // /*true);
1832             display.FontExtent(boldFont, string, strlen(string), &functionW, null);
1833             if(instanceName && type.kind != functionType)
1834                display.FontExtent(boldFont, instanceName, strlen(instanceName), &nameW, null);
1835             totalW = functionW + nameW + spaceW;
1836          }
1837             
1838          if(editor.functionType)
1839          {
1840             if(methodType)
1841             {
1842                int width = 0;
1843
1844                if(methodType.methodClass)
1845                   display.FontExtent((id == editor.paramsID) ? boldFont : font, methodType.methodClass.name, strlen(methodType.methodClass.name), &width, null);
1846                if(type.params.first && (((Type)type.params.first).kind != voidType || type.params.count > 1))
1847                   width += ((id == editor.paramsID) ? commaWB : commaW);
1848
1849                if(!height)
1850                   maxW = lineW;
1851
1852                if(lineW && ((height && lineW + width > maxW) || (totalW + lineW + width + 20 > availW)))
1853                {
1854                   height += spaceH;
1855                   lineW = 0;
1856                }
1857
1858                lineW += width;
1859
1860                if(lineW > realW)
1861                   realW = lineW;
1862
1863                id++;
1864             }
1865             if(!methodType || methodType.staticMethod || !type.params.first || ((Type)type.params.first).kind != voidType || type.params.count > 1)
1866             {
1867                for(param = type.params.first; param; param = param.next)
1868                {
1869                   char paramString[1024];
1870                   int width = 0;
1871
1872                   paramString[0] = 0;
1873                   PrintType(param, paramString, true, true);
1874                   display.FontExtent((id == editor.paramsID || param.kind == ellipsisType) ? boldFont : font, paramString, strlen(paramString), &width, null);
1875                   if(param.next) 
1876                      width += ((id == editor.paramsID) ? commaWB : commaW);
1877
1878                   if(!height)
1879                      maxW = lineW;
1880
1881                   if(lineW && ((height && lineW + width > maxW) || (totalW + lineW + width + 20 > availW)))
1882                   {
1883                      height += spaceH;
1884                      lineW = 0;
1885                   }
1886
1887                   lineW += width;
1888
1889                   if(lineW > realW)
1890                      realW = lineW;
1891
1892                   id++;
1893                }
1894             }
1895          }
1896          height += spaceH;
1897
1898          *w = realW + totalW + 4;
1899          *h = height + 4;
1900          return true;
1901       }
1902    };
1903
1904    Menu fileMenu { menu, $"File", f };  // MenuPlacement?
1905    MenuItem { fileMenu, $"Save", s, Key { s, ctrl = true }, NotifySelect = MenuFileSave };
1906    MenuItem { fileMenu, $"Save As...", a, NotifySelect = MenuFileSaveAs };
1907
1908    Menu debugMenu { menu, $"Debug", d };  // MenuPlacement?
1909    MenuItem debugRunToCursor
1910    {
1911       debugMenu, $"Run To Cursor", c, Key { f10, ctrl = true };
1912       bool NotifySelect(MenuItem selection, Modifiers mods)
1913       {
1914          ProjectView projectView = ide.projectView;
1915          if(!projectView.buildInProgress)
1916          {
1917             int line = editBox.lineNumber + 1;
1918             if(projectView)
1919             {
1920                CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1921                ProjectConfig config = projectView.project.config;
1922                int bitDepth = ide.workspace.bitDepth;
1923                ide.debugger.RunToCursor(compiler, config, bitDepth, fileName, line, false);
1924                delete compiler;
1925             }
1926          }
1927          return true;
1928       }
1929    };
1930    MenuItem debugSkipRunToCursor
1931    {
1932       debugMenu, $"Run To Cursor Skipping Breakpoints", u, Key { f10, ctrl = true, shift = true };
1933       bool NotifySelect(MenuItem selection, Modifiers mods)
1934       {
1935          ProjectView projectView = ide.projectView;
1936          int line = editBox.lineNumber + 1;
1937          if(projectView)
1938          {
1939             CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1940             ProjectConfig config = projectView.project.config;
1941             int bitDepth = ide.workspace.bitDepth;
1942             ide.debugger.RunToCursor(compiler, config, bitDepth, fileName, line, true);
1943             delete compiler;
1944          }
1945          return true;
1946       }
1947    };
1948    MenuDivider { debugMenu };
1949    MenuItem debugToggleBreakpoint
1950    {
1951       debugMenu, $"Toggle Breakpoint", t, f9;
1952       bool NotifySelect(MenuItem selection, Modifiers mods)
1953       {
1954          ProjectView projectView = ide.projectView;
1955          if(projectView && fileName)
1956          {
1957             int line = editBox.lineNumber + 1;
1958             char name[MAX_LOCATION];
1959             Project prj = null;
1960             // TOFIX: This only looks at the filename...
1961             GetLastDirectory(fileName, name);
1962             if(ide && ide.workspace)
1963             {
1964                for(p : ide.workspace.projects)
1965                {
1966                   if(p.topNode.Find(name, false))
1967                   {
1968                      prj = p;
1969                      break;
1970                   }
1971                }
1972                if(!prj)
1973                {
1974                   for(p : ide.workspace.projects)
1975                   {
1976                      if(IsPathInsideOf(fileName, p.topNode.path))
1977                      {
1978                         prj = p;
1979                         break;
1980                      }
1981                   }
1982                }
1983             }
1984             ide.debugger.ToggleBreakpoint(fileName, line, prj);
1985             Update(null);
1986          }
1987          return true;
1988       }
1989    };
1990
1991    bool debugClosing;
1992    int lastLine;
1993
1994    //MenuItem viewDesignerItem, viewProperties, viewMethods;
1995
1996    bool OnCreate(void)
1997    {
1998       designer.parent = parent;
1999       designer.Create();
2000
2001       toolBox = ((IDEWorkSpace)master).toolBox;
2002       incref toolBox;
2003       // Debugger bug here: value of toolBox appears as 0
2004
2005       sheet = ((IDEWorkSpace)master).sheet;
2006       incref sheet;
2007       return true;
2008    }
2009
2010    bool OnClose(bool parentClosing)
2011    {
2012       if(!parentClosing)
2013       {
2014          if(ide.workspace && fileName)
2015             ide.workspace.UpdateOpenedFileInfo(fileName, closed);
2016          if(inUseDebug && !debugClosing)
2017          {
2018             debugClosing = true;
2019             closing = false;
2020             if(CloseConfirmation(false))
2021             {
2022                visible = false;
2023                OnFileModified({ modified = true }, null);
2024             }
2025             debugClosing = false;
2026             return false;
2027          }
2028          if(designer && !designer.closing)
2029          {
2030             if(designer.visible)
2031             {
2032                visible = false;
2033                return false;
2034             }
2035             /*else
2036             {
2037                //Window formEditor = designer;
2038                //formEditor.Destroy(0);
2039             }*/
2040          }
2041          ide.AdjustFileMenus();
2042       }
2043       return true;
2044    }
2045
2046    void OnDestroy(void)
2047    {
2048       ObjectInfo oClass, next;
2049       Class windowClass = eSystem_FindClass(this.privateModule, "ecere::gui::Window");
2050
2051       FreeType(this.functionType);
2052       FreeType(this.instanceType);
2053
2054       if(designer)
2055       {
2056          designer.Reset();
2057          designer.codeEditor = null;
2058          designer.Destroy(0);
2059          delete designer;
2060       }
2061
2062       for(oClass = (classes).first, next = oClass ? oClass.next : null; oClass; oClass = next, next = next ? (next.next) : null)
2063       {
2064          ObjectInfo object, next;
2065          
2066          for(object = oClass.instances.first; object; object = next)
2067          {
2068             next = object.next;
2069             if(object.instance)
2070             {
2071                Designer::DestroyObject(object.instance);
2072                delete object.instance;
2073             }
2074             sheet.DeleteObject(object);
2075             delete object.name;
2076             oClass.instances.Delete(object);
2077          }
2078          if(oClass.instance)
2079          {
2080             Designer::DestroyObject(oClass.instance);
2081             delete oClass.instance;
2082          }
2083          sheet.DeleteObject(oClass);
2084          delete oClass.name;
2085          classes.Delete(oClass);
2086       }
2087
2088       if(windowClass && windowClass.data)
2089          UnapplySkin(windowClass);
2090
2091       FreeParser();
2092
2093       if(sheet.codeEditor == this)
2094       {
2095          sheet.codeEditor = null;
2096          toolBox.codeEditor = null;
2097       }
2098       delete sheet;
2099       delete toolBox;
2100
2101       {
2102          ProjectView projectView = ide.projectView;
2103          if(projectView)
2104          {
2105             ProjectNode node = projectView.GetNodeFromWindow(this, null, false);
2106             if(node && node.modified)
2107             {
2108                node.modified = false;
2109                projectView.Update(null);
2110             }
2111          }
2112       }
2113    }
2114
2115    bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool directActivation)
2116    {
2117       // WHY WAS THIS HERE? I think this was here because once you move a window in the ide it's hard to reposition it correctly
2118       /*
2119       if(directActivation)
2120          ide.RepositionWindows(false);    // Moved this up before as resizing causes NotifyCaretMove to be called on all editors
2121       */
2122       if(active && directActivation)
2123       {
2124          AdjustDebugMenus(ide.areDebugMenusUnavailable, ide.isBreakpointTogglingUnavailable, ide.isDebuggerExecuting);
2125          if(openedFileInfo)
2126             openedFileInfo.Activate();
2127          if(designer)
2128          {
2129             int line, charPos;
2130             Location * loc = null;
2131             UpdateFormCode(); // To ensure update when modifying properties...
2132
2133             // Got to the right spot in code so we don't lose our form selection...
2134             if(selected)
2135             {
2136                if(selected.instCode)
2137                   loc = &selected.instCode.loc;
2138                else if(selected.classDefinition)
2139                   loc = &selected.classDefinition.loc;
2140             }
2141             line = editBox.lineNumber + 1;
2142             charPos = editBox.charPos + 1;
2143             if(fixCaret)
2144             {
2145                fixCaret = false;
2146
2147                if(selected && !loc->Inside(line, charPos))
2148                {
2149                   editBox.GoToPosition(null, loc->start.line - 1, loc->start.charPos - 1);
2150                   line = editBox.lineNumber + 1;
2151                   charPos = editBox.charPos + 1;
2152                }
2153                else if(selected && selected.classDefinition)
2154                {
2155                   ObjectInfo object;
2156                   for(object = selected.instances.first; object; object = object.next)
2157                   {
2158                      if(object.instCode)
2159                      {
2160                         if(object.instCode.loc.Inside(line, charPos))
2161                            break;
2162                      }
2163                   }
2164                   if(object)
2165                   {
2166                      editBox.GoToPosition(null, loc->start.line - 1, loc->start.charPos - 1);
2167                      line = editBox.lineNumber + 1;
2168                      charPos = editBox.charPos + 1;
2169                   }
2170                }
2171             }
2172
2173             ProcessCaretMove(editBox, line, charPos);
2174          }
2175       }
2176       return true;
2177    }
2178
2179    bool OnSaveFile(char * fileName)
2180    {
2181       File f;
2182       if(designer)
2183       {
2184          UpdateFormCode();
2185       }
2186       f = FileOpen(fileName, write);
2187       if(f)
2188       {
2189          if(!ide.projectView)
2190             ide.ChangeFileDialogsDirectory(codeEditorFileDialog.currentDirectory, true);
2191          if(designer)
2192          {
2193             if(!this.fileName)
2194                this.fileName = fileName;  // Put this here because the form designer will check for it...
2195             designer.fileName = fileName;
2196             designer.modifiedDocument = false;
2197          }
2198          editBox.Save(f, false);
2199          modifiedDocument = false;
2200          
2201          delete(f);
2202          return true;
2203       }
2204       return false;
2205    }
2206
2207    bool OnFileModified(FileChange fileChange, char * param)
2208    {
2209       bool reload = false;
2210       if(visible == false && inUseDebug == true)
2211          reload = true;
2212       else
2213       {
2214          char message[2048];
2215
2216          sprintf(message, $"The document %s was modified by another application.\n"
2217             "Would you like to reload it and lose your changes?", fileName);
2218          if(MessageBox { type = yesNo, master = /*parent = */parent, text = $"Document has been modified",
2219             contents = message }.Modal() == yes)
2220             reload = true;
2221       }
2222
2223       if(reload)
2224       {
2225          File f = FileOpen(fileName, read);
2226          if(f)
2227          {
2228             int lineNumber, charPos, len;
2229             Point scroll;
2230
2231             loadingFile = true;
2232             updatingCode = true;
2233             lineNumber = editBox.lineNumber;
2234             charPos = editBox.charPos;
2235             scroll = editBox.scroll;
2236             editBox.Clear();
2237             editBox.Load(f);
2238             lineNumber = lineNumber < editBox.numLines ? lineNumber : editBox.numLines - 1;
2239             len = strlen(editBox.line.text);
2240             editBox.GoToLineNum(lineNumber);
2241             editBox.GoToPosition(editBox.line, lineNumber, charPos <= len ? charPos - 1 : (len ? len - 1 : 0));
2242             editBox.scroll = scroll;
2243             updatingCode = false;
2244             loadingFile = false;
2245
2246             codeModified = true;
2247             if(designer)
2248             {
2249                UpdateFormCode();
2250                designer.modifiedDocument = false;
2251             }
2252             modifiedDocument = false;
2253
2254             delete(f);
2255          }
2256       }
2257       return true;
2258    }
2259
2260    void OnRedraw(Surface surface)
2261    {
2262       // Line Numbers
2263       surface.SetBackground(marginColor);
2264       surface.Area(0, 0, editBox.anchor.left.distance, clientSize.h - 1);
2265       if(ideSettings.showLineNumbers)
2266       {
2267          int currentLineNumber;
2268          int i;
2269          char lineText[256];
2270          int spaceH;
2271
2272          surface.textOpacity = false;
2273          surface.font = font.font;
2274          surface.TextExtent(" ", 1, null, &spaceH);
2275          currentLineNumber = editBox.scroll.y / spaceH + 1;
2276
2277          surface.SetForeground(lineNumbersColor);
2278          for(i = 0; i < editBox.clientSize.h - 4; i += spaceH)
2279          {
2280             // Highlight current line
2281             if(editBox.lineNumber == currentLineNumber - 1)
2282             {
2283                surface.SetBackground(selectedMarginColor);
2284                surface.Area(0, i, editBox.anchor.left.distance, i+spaceH-1);
2285                surface.SetBackground(marginColor);
2286             }
2287             sprintf(lineText,"%5u ", currentLineNumber % 100000);
2288             if(currentLineNumber <= editBox.numLines)
2289                surface.WriteText(editBox.syntaxHighlighting * 20, i+1,lineText,6);
2290             
2291             currentLineNumber++;
2292          }
2293       }
2294
2295       if(editBox.syntaxHighlighting && fileName && ide.projectView)
2296       {
2297          bool error, bpOnCursor, bpOnTopFrame, breakpointEnabled[128];
2298          int lineCursor, lineTopFrame, breakpointLines[128];
2299          int count, i, lineH, boxH, scrollY; //, firstLine; firstLine = editBox.firstLine;
2300          Debugger debugger = ide.debugger;
2301          BitmapResource bmpRes;
2302
2303          boxH = clientSize.h;
2304          scrollY = editBox.scroll.y;
2305          displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
2306
2307          bpOnCursor = bpOnTopFrame = false;
2308          count = debugger.GetMarginIconsLineNumbers(fileName, breakpointLines, breakpointEnabled, 128, &error, &lineCursor, &lineTopFrame);
2309          if(count)
2310          {
2311             for(i = 0; i < count; i++)
2312             {
2313                if(breakpointLines[i] == lineCursor || breakpointLines[i] == lineTopFrame)
2314                {
2315                   bmpRes = breakpointEnabled[i] ? ide.bmpBpHalf : ide.bmpBpHalfDisabled;
2316                   if(breakpointLines[i] == lineCursor)
2317                      bpOnCursor = true;
2318                   if(breakpointLines[i] == lineTopFrame)
2319                      bpOnTopFrame = true;
2320                }
2321                else
2322                   bmpRes = breakpointEnabled[i] ? ide.bmpBp : ide.bmpBpDisabled;
2323                
2324                DrawLineMarginIcon(surface, bmpRes, breakpointLines[i], lineH, scrollY, boxH);
2325             }
2326          }
2327          DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
2328          bmpRes = bpOnTopFrame ? (error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf) : (error ? ide.bmpTopFrameError : ide.bmpTopFrame);
2329          DrawLineMarginIcon(surface, bmpRes, lineTopFrame, lineH, scrollY, boxH);
2330       }
2331       if(editBox.anchor.left.distance)
2332       {
2333          if(editBox.horzScroll && editBox.horzScroll.visible)
2334          {
2335             surface.SetBackground(control);
2336             surface.Area(0, editBox.clientSize.h, editBox.anchor.left.distance, clientSize.h - 1);
2337          }
2338       }
2339    }
2340
2341    void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
2342    {
2343       int lineY;
2344       if(line)
2345       {
2346          lineY = (line - 1) * lineH;
2347          if(lineY + lineH > scrollY && lineY /*+ lineH*/ < scrollY + boxH)
2348          {
2349             Bitmap bitmap = resource.bitmap;
2350             if(bitmap)
2351                surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
2352          }
2353       }
2354    }
2355
2356    watch(fileName)
2357    {
2358       char ext[MAX_EXTENSION];
2359       char * fileName = property::fileName;
2360
2361       if(SearchString(fileName, 0, "Makefile", false, true))
2362          editBox.useTab = true;
2363       designer.fileName = fileName;
2364
2365       if(fileName)
2366       {
2367          GetExtension(fileName, ext);
2368          if(parsing && !strcmpi(ext, "ec"))
2369          {
2370             codeModified = true;
2371             EnsureUpToDate();
2372          }
2373
2374          if(!strcmpi(ext, "ec") || !strcmpi(ext, "c") || !strcmpi(ext, "cc") || !strcmpi(ext, "cpp") || !strcmpi(ext, "eh") || !strcmpi(ext, "hh") || !strcmpi(ext, "hpp") || !strcmpi(ext, "h") || !strcmpi(ext, "hxx") || !strcmpi(ext, "cxx"))
2375             editBox.syntaxHighlighting = true;
2376          else
2377             editBox.syntaxHighlighting = false;
2378          {
2379             int spaceW;
2380             display.FontExtent(font.font, " ", 1, &spaceW, null);
2381             editBox.anchor = Anchor
2382             {
2383                left = (editBox.syntaxHighlighting ? 20 : 0) + (ideSettings.showLineNumbers ? (6 * spaceW) : 0),
2384                right = 0, top = 0, bottom = 0
2385             };
2386          }
2387       }
2388    };
2389
2390    bool OnPostCreate()
2391    {
2392       int spaceW;
2393       display.FontExtent(font.font, " ", 1, &spaceW, null);
2394       editBox.anchor = Anchor
2395       {
2396          left = (editBox.syntaxHighlighting ? 20 : 0) + (ideSettings.showLineNumbers ? (6 * spaceW) : 0),
2397          right = 0, top = 0, bottom = 0
2398       };
2399       return true;
2400    }
2401
2402    bool LoadFile(char * filePath)
2403    {
2404       File f = FileOpen(filePath, read);
2405       if(f)
2406       {
2407          // Added this here... 
2408          fileName = filePath;
2409          loadingFile = true;
2410          updatingCode = true;
2411          editBox.Load(f);
2412          updatingCode = false;
2413          loadingFile = false;
2414          Create();
2415
2416          delete(f);
2417          return true;
2418       }
2419       return false;
2420    }
2421
2422    void AdjustDebugMenus(bool unavailable, bool bpNoToggle, bool executing)
2423    {
2424       debugRunToCursor.disabled                = unavailable || executing;
2425       debugSkipRunToCursor.disabled            = unavailable || executing;
2426       debugToggleBreakpoint.disabled           = bpNoToggle;
2427    }
2428
2429    CodeEditor()
2430    {
2431       CodeObjectType c;
2432       ProjectView projectView = ide.projectView;
2433
2434       /*if(fileName)
2435          designer.fileName = fileName;
2436       else
2437       */
2438       if(designer)
2439       {
2440          char title[1024];
2441          sprintf(title, $"Untitled %d", documentID);
2442          // designer.fileName = CopyString(title);
2443          designer.fileName = title;
2444       }
2445
2446       AdjustDebugMenus(ide.areDebugMenusUnavailable, ide.isBreakpointTogglingUnavailable, ide.isDebuggerExecuting);
2447
2448       for(c = 0; c < CodeObjectType::enumSize; c++)
2449          icons[c] = BitmapResource { iconNames[c], window = this };
2450
2451       codeModified = true;
2452       inUseDebug = false;
2453       return true;
2454    }
2455
2456    ~CodeEditor()
2457    {
2458
2459    }
2460
2461    void ModifyCode()
2462    {
2463       selected.modified = true;
2464       selected.oClass.modified = true;
2465
2466       designer.modifiedDocument = true;
2467       modifiedDocument = true;
2468       formModified = true;
2469    }
2470
2471    /****************************************************************************
2472                                  PARSING
2473    ****************************************************************************/
2474    void FreeParser()
2475    {
2476       if(ast != null)
2477       {
2478          FreeASTTree(ast);
2479          ast = null;
2480       }
2481       this.defines.Free(FreeModuleDefine);
2482       this.imports.Free(FreeModuleImport);   // Moved this after FreeAST because Debug printing causes ModuleImports to be created
2483
2484       FreeExcludedSymbols(this.excludedSymbols);
2485       FreeContext(this.globalContext);
2486       FreeIncludeFiles();
2487       FreeGlobalData(&this.globalData);
2488       FindCtx_Terminate();
2489       FindParams_Terminate();
2490
2491       if(GetGlobalContext() == globalContext)
2492       {
2493          SetGlobalData(null);
2494          SetGlobalContext(null);
2495          SetExcludedSymbols(null);
2496          SetTopContext(null);
2497          SetCurrentContext(null);
2498          SetDefines(null);
2499          SetImports(null);
2500          SetPrivateModule(null);
2501       }
2502
2503       if(this.privateModule)
2504       {
2505          FreeTypeData(this.privateModule);
2506          delete this.privateModule;
2507          this.privateModule = null;
2508       }
2509    }
2510
2511    void ParseCode()
2512    {
2513       static bool reentrant = false;
2514       External external;
2515       File editFile;
2516       EditLine l1, l2;
2517       int x1,x2,y1,y2;
2518       char * selectedClassName = null, * selectedName = null;
2519       int selectedPos = 0;
2520       Designer backDesigner;
2521       char oldWorkDir[MAX_LOCATION];
2522       char mainModuleName[MAX_FILENAME] = "";
2523       char * fileName;
2524       ImportedModule module;
2525       char extension[MAX_EXTENSION];
2526       PathBackup pathBackup { };
2527 #ifdef _TIMINGS
2528       Time parseCodeStart = GetTime();
2529       Time startTime, startFindClass;
2530
2531       findClassTotalTime = 0;
2532       checkTypeTotalTime = 0;
2533       externalImportTotalTime = 0;
2534       findClassIgnoreNSTotalTime = 0;
2535       findSymbolTotalTime = 0;
2536       //ResetClassFindTime();
2537 #endif
2538       Project project;
2539
2540       // This temporarily fixes issue with 2 overrides in release mode with VC6 (only happens with both ecere.dll and ide.exe compiled in release mode)
2541       if(reentrant) return;
2542       reentrant = true;
2543
2544       updatingCode++;
2545
2546       if(selected)
2547       {
2548          selectedClassName = CopyString(oClass.name);
2549          if(selected != oClass)
2550          {
2551             ObjectInfo object = this.selected;
2552             selectedName = CopyString(object.name);
2553             if(!selectedName)
2554             {
2555                ObjectInfo check;
2556                for(check = this.oClass.instances.first; check; check = check.next)
2557                {
2558                   if(check == object)
2559                      break;
2560                   selectedPos++;
2561                }
2562             }
2563          }
2564          else 
2565             selectedPos = -1;
2566       }
2567
2568       editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
2569
2570       FindCtx_Terminate();
2571       FindParams_Terminate();
2572
2573       SetGlobalData(&globalData);
2574       SetGlobalContext(globalContext);
2575       SetExcludedSymbols(&excludedSymbols);
2576       SetTopContext(globalContext);
2577       SetCurrentContext(globalContext);
2578       SetDefines(&defines);
2579       SetImports(&imports);
2580       SetCurrentNameSpace(null);
2581
2582       /*
2583       sprintf(command, "C:\\Program Files\\Microsoft Visual Studio\\VC98\\Bin\\cl "
2584          "/nologo /D \"MSC\" /D \"WIN32\" /D \"NDEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" "
2585          "/I \"C:\\Program Files\\Microsoft Visual Studio\\VC98\\Include\" "
2586          "/I T:\\ecere\\include /E %s", argv[1]);
2587       */
2588
2589       /*
2590       ChangeWorkingDir("e:\\ec");
2591       sprintf(command, "gcc -x c -E -");
2592       fileInput = DualPipeOpen({ output = true, input = true }, command);
2593       SetFileInput(fileInput);
2594       {
2595          for(;;)
2596          {
2597             byte buffer[8192];
2598             uint count = editFile.Read(buffer, 1, sizeof(buffer));
2599             if(count)
2600                fileInput.Write(buffer, 1, count);
2601             else
2602                break;
2603          }
2604          delete editFile;
2605          fileInput.CloseOutput();
2606       }
2607       */
2608
2609       // TOCHECK: COULDN'T WE CALL FreeParser here?
2610       // Clear everything
2611       FreeType(this.functionType);
2612       FreeType(this.instanceType);
2613       this.functionType = null;
2614       this.instanceType = null;
2615
2616       // Select nothing
2617       sheet.SelectObject(null);
2618
2619       designer.Reset();
2620
2621       selected = null;
2622
2623       // We don't want the designer to be notified of selection when deleting rows...
2624       backDesigner = designer;
2625       designer = null;
2626
2627       if(this.oClass)
2628       {
2629          ObjectInfo _class, next;
2630          
2631          for(_class = classes.first; _class; _class = next)
2632          {
2633             ObjectInfo object;
2634
2635             next = _class.next;
2636             
2637             for(;object = _class.instances.first;)
2638             {
2639                if(object.instance)
2640                {
2641                   Designer::DestroyObject(object.instance);
2642                   delete object.instance;
2643                }
2644                sheet.DeleteObject(object);
2645                delete object.name;
2646                _class.instances.Delete(object);
2647             }
2648             if(_class.instance)
2649             {
2650                Designer::DestroyObject(_class.instance);
2651                delete _class.instance;
2652             }
2653             sheet.DeleteObject(_class);
2654             delete _class.name;
2655             classes.Delete(_class);
2656          }
2657          this.oClass = null;
2658       }
2659
2660       {
2661          Class windowClass = eSystem_FindClass(this.privateModule, "ecere::gui::Window");
2662          if(windowClass && windowClass.data)
2663             UnapplySkin(windowClass);
2664       }
2665
2666       designer = backDesigner;
2667
2668       SetEchoOn(true);
2669       fileInput = editFile = EditBoxStream { editBox = editBox };
2670       SetFileInput(fileInput);
2671
2672       if(ast)
2673       {
2674          FreeASTTree(ast);
2675          ast = null;
2676          //SetAST(null);
2677       }
2678       defines.Free(FreeModuleDefine);
2679       imports.Free(FreeModuleImport);
2680
2681       FreeContext(this.globalContext);
2682       FreeExcludedSymbols(this.excludedSymbols);
2683
2684       FreeIncludeFiles();
2685       FreeGlobalData(&this.globalData);
2686
2687       if(this.privateModule)
2688       {
2689          FreeTypeData(this.privateModule);
2690          delete this.privateModule;
2691       }
2692
2693 #ifdef _TIMINGS
2694       startTime = GetTime();
2695       printf("Cleaning up took %.3f seconds\n", startTime - parseCodeStart);
2696
2697       printf("classes.count: %d\n", globalContext.classes.count);
2698 #endif
2699
2700       if(ide.workspace)
2701       {
2702          CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2703          SetTargetBits(ide.workspace.bitDepth ? ide.workspace.bitDepth : GetHostBits());
2704          delete compiler;
2705       }
2706       this.privateModule = __ecere_COM_Initialize(false | ((GetTargetBits() == sizeof(uintptr) *8) ? 0 : GetTargetBits() == 64 ? 2 : 4), 1, null);
2707
2708       SetPrivateModule(privateModule);
2709
2710       {
2711          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint"), type = ProcessTypeString("unsigned int", false) });
2712          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint64"), type = ProcessTypeString("unsigned int64", false) });
2713          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint32"), type = ProcessTypeString("unsigned int", false) });
2714          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint16"), type = ProcessTypeString("unsigned short", false) });
2715          globalContext.types.Add((BTNode)Symbol { string = CopyString("byte"), type = ProcessTypeString("unsigned char", false) });
2716       }
2717
2718       fileName = this.fileName;
2719       project = null;
2720       if(ide.workspace && ide.workspace.projects && fileName)
2721       {
2722          for(p : ide.workspace.projects)
2723          {
2724             char path[MAX_LOCATION];
2725             ProjectNode pn;
2726             MakePathRelative(fileName, p.topNode.path, path);
2727             MakeSlashPath(path);
2728
2729             pn = p.topNode.FindWithPath(path, false);
2730             if(pn)
2731             {
2732                project = p;
2733                break;
2734             }
2735          }
2736       }
2737       if(!project)
2738          project = ide.project;
2739          
2740       GetWorkingDir(oldWorkDir, MAX_LOCATION);
2741       if(project)
2742          ChangeWorkingDir(project.topNode.path);
2743
2744       SetSomeSourceFileStack(fileName ? fileName : "", 0); //strcpy(sourceFileStack[0], fileName ? fileName : "");
2745
2746       GetLastDirectory(fileName, mainModuleName);
2747       GetExtension(mainModuleName, extension);
2748
2749       SetBuildingEcereCom(false);
2750       SetBuildingEcereComModule(false);
2751
2752       // TODO: Get symbolsDir from project settings instead...
2753       if(ide.projectView)
2754       {
2755          CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2756          ProjectConfig config = project.config;
2757          int bitDepth = ide.workspace.bitDepth;
2758          DirExpression objDir = project.GetObjDir(compiler, config, bitDepth);
2759          SetSymbolsDir(objDir.dir);
2760          ide.SetPath(true, compiler, config, bitDepth);
2761
2762          delete objDir;
2763          delete compiler;
2764          // SetIncludeDirs(ide.projectView.project.config.includeDirs);
2765          // SetSysIncludeDirs(ide.ideSettings.systemDirs[includes]);
2766       }
2767       else
2768       {
2769          switch(GetRuntimePlatform())
2770          {
2771             case win32: SetSymbolsDir("obj/debug.win32"); break;
2772             case tux:   SetSymbolsDir("obj/debug.linux"); break;
2773             case apple: SetSymbolsDir("obj/debug.apple"); break;
2774          }         
2775          SetIncludeDirs(null);
2776          SetSysIncludeDirs(null);
2777       }
2778
2779       {
2780          if(ide.projectView && ide.projectView.IsModuleInProject(this.fileName))
2781          {
2782             // TODO FIX for configless project
2783             if(ide.project.config && ide.project.config.options && ide.project.config.options.preprocessorDefinitions)
2784             {
2785                for(item : ide.project.config.options.preprocessorDefinitions)
2786                {
2787                   if(!strcmp(item, "BUILDING_ECERE_COM"))
2788                   {
2789                      SetBuildingEcereCom(true);
2790                      break;
2791                   }
2792                }
2793             }
2794          }
2795          
2796          if(!(strcmpi(mainModuleName, "instance.ec") && strcmpi(mainModuleName, "BinaryTree.ec") &&
2797             strcmpi(mainModuleName, "dataTypes.ec") && strcmpi(mainModuleName, "OldList.ec") &&
2798             strcmpi(mainModuleName, "String.ec") && strcmpi(mainModuleName, "BTNode.ec") &&
2799             strcmpi(mainModuleName, "Array.ec") && strcmpi(mainModuleName, "AVLTree.ec") &&
2800             strcmpi(mainModuleName, "BuiltInContainer.ec") && strcmpi(mainModuleName, "Container.ec") &&
2801             strcmpi(mainModuleName, "CustomAVLTree.ec") && strcmpi(mainModuleName, "LinkList.ec") &&
2802             strcmpi(mainModuleName, "List.ec") && strcmpi(mainModuleName, "Map.ec") &&
2803             strcmpi(mainModuleName, "Mutex.ec")))
2804          {
2805             SetBuildingEcereComModule(true);
2806          }
2807
2808          // Predeclare all classes
2809          {
2810             char symFile[MAX_FILENAME];
2811             char symLocation[MAX_LOCATION];
2812             ImportedModule module, next;
2813
2814             GetLastDirectory(fileName, symFile);
2815             ChangeExtension(symFile, "sym", symFile);
2816
2817             strcpy(symLocation, GetSymbolsDir());
2818             PathCat(symLocation, symFile);
2819             
2820             // if(!GetEcereImported() && !GetBuildingEcereCom())
2821             if(!strcmp(extension, "ec") || !strcmp(extension, "eh"))
2822             {
2823 #ifdef _TIMINGS
2824                startTime = GetTime();
2825 #endif
2826                eModule_LoadStrict(privateModule, "ecereCOM", privateAccess);
2827 #ifdef _TIMINGS
2828                printf("Loading ecereCOM took %.3f seconds\n", GetTime() - startTime);
2829 #endif
2830             }
2831
2832 #ifdef _TIMINGS
2833             startTime = GetTime();
2834 #endif
2835             // LoadSymbols(symLocation, normalImport, true);
2836             LoadSymbols(symLocation, preDeclImport, false);
2837 #ifdef _TIMINGS
2838             printf("Loading symbols took %.3f seconds\n", GetTime() - startTime);
2839 #endif
2840
2841             for(module = defines.first; module; module = next)
2842             {
2843                next = module.next;
2844                if(module.type == moduleDefinition && strcmpi(module.name, mainModuleName))
2845                {
2846                   delete module.name;
2847                   defines.Delete(module);
2848                }
2849             }
2850          }
2851       }
2852       if(!strcmp(extension, "ec") || !strcmp(extension, "eh"))
2853       {
2854          SetDefaultDeclMode(privateAccess);
2855          SetDeclMode(privateAccess);
2856       }
2857       else
2858       {
2859          SetDefaultDeclMode(defaultAccess);
2860          SetDeclMode(defaultAccess);
2861       }
2862
2863       StripExtension(mainModuleName);
2864       module = ImportedModule { name = CopyString(mainModuleName), type = moduleDefinition };
2865       defines.AddName(module);
2866
2867    #ifdef _DEBUG
2868       // SetYydebug(true);
2869    #endif
2870       resetScanner();
2871
2872 #ifdef _TIMINGS
2873       startTime = GetTime();
2874       startFindClass = checkTypeTotalTime;
2875 #endif
2876       ParseEc();
2877 #ifdef _TIMINGS
2878       printf("ParseEc took %.3f seconds, out of which %.3f seconds were in CheckType\n", GetTime() - startTime, checkTypeTotalTime - startFindClass);
2879 #endif
2880       CheckDataRedefinitions();
2881       SetYydebug(false);
2882
2883       SetIncludeDirs(null);
2884       SetSysIncludeDirs(null);
2885       
2886       delete editFile;
2887       fileInput = null;
2888       SetFileInput(null);
2889
2890       if(GetAST())
2891       {
2892          ast = GetAST();
2893          
2894 #ifdef _TIMINGS
2895          startTime = GetTime();
2896 #endif
2897          PrePreProcessClassDefinitions();
2898          ComputeModuleClasses(privateModule);
2899          PreProcessClassDefinitions();
2900          ProcessClassDefinitions();
2901 #ifdef _TIMINGS
2902          printf("Initial Passes took %.3f seconds\n", GetTime() - startTime);
2903          startTime = GetTime();
2904 #endif
2905
2906          ComputeDataTypes();
2907 #ifdef _TIMINGS
2908          printf("ComputeDataTypes took %.3f seconds\n", GetTime() - startTime);
2909          startTime = GetTime();
2910 #endif
2911          ProcessInstantiations();
2912 #ifdef _TIMINGS
2913          printf("ProcessInstantiations took %.3f seconds\n", GetTime() - startTime);
2914 #endif
2915
2916          if(!strcmp(extension, "ec") || !strcmp(extension, "eh"))
2917          {
2918             Class windowClass = eSystem_FindClass(this.privateModule, "ecere::gui::Window");
2919             if(!windowClass || windowClass.internalDecl)
2920             {
2921 #ifdef _TIMINGS
2922                startTime = GetTime();
2923 #endif
2924                // *** COMMENTED THIS OUT DUE TO ecereCOM issues
2925                // eModule_Load(this.privateModule.application.allModules.first ? this.privateModule.application.allModules.first : this.privateModule, "ecere", privateAccess);
2926                eModule_Load(this.privateModule, "ecere", privateAccess);
2927 #ifdef _TIMINGS
2928                printf("Loading ecere.dll took %.3f seconds\n", GetTime() - startTime);
2929 #endif
2930             }
2931             windowClass = eSystem_FindClass(this.privateModule, "ecere::gui::Window");
2932
2933             if(windowClass && windowClass.data)
2934                ApplySkin(windowClass, app.currentSkin.name, null);
2935          }
2936
2937 #ifdef _TIMINGS
2938          startTime = GetTime();
2939 #endif
2940          for(external = ast->first; external; external = external.next)
2941          {
2942             if(external.type == classExternal)
2943             {
2944                ClassDefinition _class = external._class;
2945                if(_class.baseSpecs && _class.baseSpecs->first && ((Specifier)_class.baseSpecs->first).type == nameSpecifier ) // classSpecifier
2946                {
2947                   Class regClass = eSystem_FindClass(this.privateModule, ((Specifier)_class.baseSpecs->first).name);
2948                   if(regClass)
2949                   {
2950                      if(eClass_GetDesigner(regClass) && !GetBuildingEcereComModule())
2951                      {
2952                         Instance instance = eInstance_New(regClass);
2953                         ObjectInfo classObject 
2954                         {
2955                            name = CopyString(_class._class.name);
2956                            instance = instance;
2957                            classDefinition = _class;
2958                            oClass = classObject;
2959                         };
2960                         Symbol symbol;
2961                         classes.Add(classObject);
2962
2963                         incref instance;
2964
2965                         // Moved this at bottom so that the file dialog doesn't show up in eCom
2966                         designer.CreateObject(instance, classObject, true, null);
2967                         sheet.AddObject(classObject, classObject.name ? classObject.name : _class._class.name, typeClass, false);
2968
2969                         if(_class.definitions)
2970                         {
2971                            ClassDef def;
2972                            ObjectInfo object;
2973                            for(def = _class.definitions->first; def; def = def.next)
2974                            {
2975                               switch(def.type)
2976                               {
2977                                  case defaultPropertiesClassDef:
2978                                  {
2979                                     MemberInit propDef;
2980                                     for(propDef = def.defProperties->first; propDef; propDef = propDef.next)
2981                                     {
2982                                        Identifier id = propDef.identifiers->first;
2983                                        if(id)
2984                                        {
2985                                           Property prop = eClass_FindProperty(regClass, id.string, this.privateModule);
2986                                           if(prop)
2987                                           {
2988                                              Class propertyClass = prop.dataTypeClass;
2989                                              if(!propertyClass)
2990                                                 propertyClass = prop.dataTypeClass = eSystem_FindClass(this.privateModule, prop.dataTypeString);
2991                                              if(prop.compiled && prop.Set && prop.Get && propertyClass && propDef.initializer && propDef.initializer.type == expInitializer && propDef.initializer.exp)
2992                                              {
2993                                                 FreeType(propDef.initializer.exp.destType);
2994                                                 propDef.initializer.exp.destType = MkClassType(propertyClass.name);
2995                                                 ProcessExpressionType(propDef.initializer.exp);
2996                                              
2997                                                 if(propertyClass.type == structClass || propertyClass.type == noHeadClass || propertyClass.type == normalClass)
2998                                                 {
2999                                                    Expression computed = CopyExpression(propDef.initializer.exp);
3000                                                    ComputeExpression(computed);
3001
3002                                                    if(computed.isConstant && computed.type == instanceExp && !id.next)
3003                                                    {
3004                                                       if(prop.Set)
3005                                                       {
3006                                                          if(computed.instance._class && computed.instance._class.symbol &&
3007                                                             computed.instance._class.symbol.registered && 
3008                                                             eClass_IsDerived(computed.instance._class.symbol.registered, propertyClass))
3009                                                          {
3010                                                             ((void (*)(void *, void *))(void *)prop.Set)(instance, computed.instance.data);
3011
3012                                                             // This was saved in the control and shouldn't be freed by FreeExpression...
3013                                                             if(propertyClass.type == normalClass)
3014                                                                computed.instance.data = null;
3015                                                          }
3016                                                       }
3017                                                    }
3018                                                    // MOVED THIS UP NOW THAT char * IS A NORMAL CLASS
3019                                                    else if(computed.type == stringExp && propertyClass.dataTypeString && strstr(propertyClass.dataTypeString, "char *"))
3020                                                    {
3021                                                       String temp = new char[strlen(computed.string)+1];
3022                                                       ReadString(temp, computed.string);
3023                                                       ((void (*)(void *, void *))(void *)prop.Set)(instance, temp);
3024                                                       delete temp;
3025                                                    }
3026                                                    else
3027                                                       propDef.variable = true;
3028                                                    
3029                                                    FreeExpression(computed);
3030                                                 }
3031                                                 else
3032                                                 {
3033                                                    Expression computed = CopyExpression(propDef.initializer.exp);
3034                                                    ComputeExpression(computed);
3035                                                    if(computed.isConstant)
3036                                                    {
3037                                                       //if(computed.type == memberExp) computed = computed.member.exp;
3038
3039                                                       if(computed.type == constantExp)
3040                                                       {
3041                                                          Operand value = GetOperand(computed);
3042                                                          DataValue valueData;
3043                                                          valueData.i64 = value.i64;
3044                                                          SetProperty(prop, instance, valueData);
3045                                                       }
3046                                                       else if(computed.type == stringExp && propertyClass.dataTypeString && strstr(propertyClass.dataTypeString, "char *"))
3047                                                       {
3048                                                          String temp = new char[strlen(computed.string)+1];
3049                                                          ReadString(temp, computed.string);
3050                                                          ((void (*)(void *, void *))(void *)prop.Set)(instance, temp);
3051                                                          delete temp;
3052                                                       }
3053                                                    }
3054                                                    else
3055                                                       propDef.variable = true;
3056
3057                                                    FreeExpression(computed);
3058                                                 }
3059                                              }
3060                                              else
3061                                                 propDef.variable = true;
3062                                           }
3063                                           else
3064                                           {
3065                                              Method method = eClass_FindMethod(regClass, id.string, this.privateModule);
3066                                              if(method && method.type == virtualMethod && propDef.initializer && propDef.initializer.type == expInitializer && 
3067                                                 propDef.initializer.exp && propDef.initializer.exp.type == identifierExp)
3068                                              {
3069                                                 ClassDef def;
3070                                                 // Maintain a list in FunctionDefinition of who is attached to it
3071                                                 for(def = _class.definitions->first; def; def = def.next)
3072                                                 {
3073                                                    if(def.type == functionClassDef)
3074                                                    {
3075                                                       ClassFunction function = def.function;
3076                                                       if(!strcmp(function.declarator.symbol.string, propDef.initializer.exp.identifier.string))
3077                                                       {
3078                                                          function.attached.Add(OldLink { data = method });
3079                                                       }
3080                                                    }
3081                                                 }
3082                                              }                                          
3083                                           }
3084                                        }
3085                                     }
3086                                     break;
3087                                  }
3088                                  case declarationClassDef:
3089                                  {
3090                                     Declaration decl = def.decl;
3091                                     switch(decl.type)
3092                                     {
3093                                        case instDeclaration:
3094                                        {
3095                                           Instantiation inst = decl.inst;
3096                                           Class instClass = eSystem_FindClass(this.privateModule, inst._class.name);
3097                                           if(instClass && eClass_GetDesigner(instClass))
3098                                           {
3099                                              Instance control = eInstance_New(instClass);
3100                                              incref control;
3101
3102                                              object = ObjectInfo
3103                                              {
3104                                                 oClass = classObject;
3105                                                 instance = control;
3106                                                 instCode = inst;
3107                                              };
3108                                              classObject.instances.Add(object);
3109                                              if(inst.exp)
3110                                                 // TOCHECK: Why is this needed now?
3111                                                 object.name = CopyString((inst.exp.type == memberExp) ? inst.exp.member.member.string : inst.exp.identifier.string);
3112                                              def.object = object;
3113
3114                                              // if(object.name) { symbol = eList_Add(&curContext.symbols, sizeof(Symbol)); symbol.string = object.name; symbol.type = MkClassType(instClass.name); }
3115
3116                                              designer.CreateObject(control, object, false, classObject.instance);
3117                                              sheet.AddObject(object, object.name ? object.name : inst._class.name, typeData, false);
3118                                           }
3119                                           break;
3120                                        }
3121                                     }
3122                                     break;
3123                                  }
3124                               }
3125                            }
3126
3127                            // Second pass, process instantiation members
3128                            object = null;
3129                            for(def = _class.definitions->first; def; def = def.next)
3130                            {
3131                               switch(def.type)
3132                               {
3133                                  case declarationClassDef:
3134                                  {
3135                                     Declaration decl = def.decl;
3136                                     switch(decl.type)
3137                                     {
3138                                        case instDeclaration:
3139                                        {
3140                                           Instantiation inst = decl.inst;
3141                                           Class instClass = eSystem_FindClass(this.privateModule, inst._class.name);
3142                                           if(instClass && eClass_GetDesigner(instClass))
3143                                           {
3144                                              Instance control;
3145                                              object = object ? object.next : classObject.instances.first;
3146                                              control = object.instance;                                             
3147                                              
3148                                              if(inst.members)
3149                                              {
3150                                                 MembersInit members;
3151                                                 for(members = inst.members->first; members; members = members.next)
3152                                                 {
3153                                                    switch(members.type)
3154                                                    {
3155                                                       case dataMembersInit:
3156                                                       {
3157                                                          if(members.dataMembers)
3158                                                          {
3159                                                             MemberInit member;
3160                                                             DataMember curMember = null;
3161                                                             Class curClass = null;
3162                                                             DataMember subMemberStack[256];
3163                                                             int subMemberStackPos = 0;
3164
3165                                                             for(member = members.dataMembers->first; member; member = member.next)
3166                                                             {
3167                                                                bool found = false;
3168                                                                Identifier ident = member.identifiers ? member.identifiers->first : null;
3169                                                                if(ident)
3170                                                                {
3171                                                                   DataMember _subMemberStack[256];
3172                                                                   int _subMemberStackPos = 0;
3173                                                                   DataMember thisMember = (DataMember)eClass_FindDataMember(instClass, ident.string, privateModule, _subMemberStack, &_subMemberStackPos);
3174
3175                                                                   if(!thisMember)
3176                                                                   {
3177                                                                      thisMember = (DataMember)eClass_FindProperty(instClass, ident.string, privateModule);
3178                                                                   }
3179                                                                   if(thisMember && thisMember.memberAccess == publicAccess)
3180                                                                   {
3181                                                                      curMember = thisMember;
3182                                                                      curClass = curMember._class;
3183                                                                      memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
3184                                                                      subMemberStackPos = _subMemberStackPos;
3185                                                                      found = true;
3186                                                                   }
3187                                                                }
3188                                                                else
3189                                                                {
3190                                                                   eClass_FindNextMember(instClass, &curClass, (DataMember *)&curMember, subMemberStack, &subMemberStackPos);
3191                                                                   if(curMember) found = true;
3192                                                                }
3193                                                                if(found && curMember.isProperty)
3194                                                                {
3195                                                                   Property prop = (Property) curMember;
3196                                                                   Class propertyClass = prop.dataTypeClass;
3197                                                                   if(!propertyClass)
3198                                                                      propertyClass = prop.dataTypeClass = eSystem_FindClass(this.privateModule, prop.dataTypeString);
3199
3200                                                                   if(prop.compiled && prop.Set && prop.Get && propertyClass && member.initializer && member.initializer.type == expInitializer && member.initializer.exp)
3201                                                                   {
3202                                                                      FreeType(member.initializer.exp.destType);
3203                                                                      member.initializer.exp.destType = MkClassType(propertyClass.name);
3204                                                                      if(propertyClass)
3205                                                                      {
3206                                                                         ProcessExpressionType(member.initializer.exp);
3207                                        
3208                                                                         if(propertyClass.type == structClass || propertyClass.type == normalClass || propertyClass.type == noHeadClass)
3209                                                                         {
3210                                                                            Expression computed;
3211 #ifdef _DEBUG
3212                                                                            /*char debugExpString[4096];
3213                                                                            debugExpString[0] = '\0';
3214                                                                            PrintExpression(member.initializer.exp, debugExpString);*/
3215 #endif
3216                                                                            computed = CopyExpression(member.initializer.exp);
3217                                                                            if(computed)
3218                                                                            {
3219                                                                               ComputeExpression(computed);
3220                                                                               
3221                                                                               if(computed.type == instanceExp && computed.isConstant && computed.isConstant)
3222                                                                               {
3223                                                                                  if(computed.instance.data)
3224                                                                                  {
3225                                                                                     if(computed.instance._class && computed.instance._class.symbol &&
3226                                                                                        computed.instance._class.symbol.registered && 
3227                                                                                        eClass_IsDerived(computed.instance._class.symbol.registered, propertyClass))
3228                                                                                     {
3229                                                                                        ((void (*)(void *, void *))(void *)prop.Set)(control, computed.instance.data);
3230
3231                                                                                        // This was saved in the control and shouldn't be freed by FreeExpression...
3232                                                                                        if(propertyClass.type == normalClass)
3233                                                                                           computed.instance.data = null;
3234                                                                                     }
3235                                                                                  }
3236                                                                               }
3237                                                                               else if(computed.type == identifierExp)
3238                                                                               {
3239                                                                                  member.variable = true;
3240
3241                                                                                  if(eClass_GetDesigner(propertyClass))
3242                                                                                  //if(prop.Set)
3243                                                                                  {
3244                                                                                     char * name = computed.identifier.string;
3245                                                                                     if(!strcmp(name, "this"))
3246                                                                                     {
3247                                                                                        if(prop.Set)
3248                                                                                           ((void (*)(void *, void *))(void *)prop.Set)(control, instance);
3249                                                                                        member.variable = false;
3250                                                                                     }
3251                                                                                     else
3252                                                                                     {
3253                                                                                        ObjectInfo check;
3254                                                                                        for(check = classObject.instances.first; check; check = check.next)
3255                                                                                           if(check.name && !strcmp(name, check.name))
3256                                                                                           {
3257                                                                                              if(prop.Set)
3258                                                                                                 ((void (*)(void *, void *))(void *)prop.Set)(control, check.instance);
3259                                                                                              member.variable = false;
3260                                                                                              break;
3261                                                                                           }
3262                                                                                     }
3263                                                                                  }
3264                                                                               }
3265                                                                               else if(computed.type == memberExp)
3266                                                                               {
3267                                                                                  member.variable = true;
3268                                                                                  if(computed.member.exp.type == identifierExp)
3269                                                                                  {
3270                                                                                     char * name = computed.member.exp.identifier.string;
3271                                                                                     if(!strcmp(name, "this"))
3272                                                                                     {
3273                                                                                        char * name = computed.member.member.string;
3274                                                                                        {
3275                                                                                           ObjectInfo check;
3276                                                                                           for(check = classObject.instances.first; check; check = check.next)
3277                                                                                              if(check.name && !strcmp(name, check.name))
3278                                                                                              {
3279                                                                                                 if(prop.Set)
3280                                                                                                    ((void (*)(void *, void *))(void *)prop.Set)(control, check.instance);
3281                                                                                                 member.variable = false;
3282                                                                                                 break;
3283                                                                                              }
3284                                                                                        }
3285                                                                                     }
3286                                                                                     else
3287                                                                                     {
3288                                                                                        ObjectInfo check;
3289                                                                                        for(check = classObject.instances.first; check; check = check.next)
3290                                                                                        {
3291                                                                                           if(check.name && !strcmp(name, check.name))
3292                                                                                           {
3293                                                                                              Property getProperty = eClass_FindProperty(check.instance._class, computed.member.member.string, this.privateModule);
3294                                                                                              if(getProperty)
3295                                                                                              {
3296                                                                                                 DataValue value { };
3297                                                                                                 GetProperty(getProperty, check.instance, &value);
3298                                                                                                 SetProperty(prop, control, value);
3299                                                                                                 member.variable = false;
3300                                                                                              }
3301                                                                                              break;
3302                                                                                           }
3303                                                                                        }
3304                                                                                     }
3305                                                                                  }
3306                                                                               }
3307                                                                               // MOVED THIS UP NOW THAT char * IS A NORMAL CLASS
3308                                                                               else if(computed.isConstant && computed.type == stringExp && propertyClass.dataTypeString && strstr(propertyClass.dataTypeString, "char *"))
3309                                                                               {
3310                                                                                  String temp = new char[strlen(computed.string)+1];
3311                                                                                  ReadString(temp, computed.string);
3312                                                                                  ((void (*)(void *, void *))(void *)prop.Set)(control, temp);
3313                                                                                  delete temp;
3314                                                                               }
3315                                                                               else
3316                                                                                  member.variable = true;
3317
3318                                                                               FreeExpression(computed);
3319                                                                            }
3320                                                                         }
3321                                                                         else
3322                                                                         {
3323                                                                            Expression computed = CopyExpression(member.initializer.exp);
3324                                                                            if(computed)
3325                                                                            {
3326                                                                               ComputeExpression(computed);
3327                                                                               if(computed.isConstant)
3328                                                                               {
3329                                                                                  if(computed.type == constantExp && (!propertyClass.dataTypeString || strcmp(propertyClass.dataTypeString, "char *"))) //(strcmp(propertyClass.name, "char *") && (strcmp(propertyClass.name, "String"))))
3330                                                                                  {
3331                                                                                     if(!strcmp(propertyClass.dataTypeString, "float"))
3332                                                                                        ((void (*)(void *, float))(void *)prop.Set)(control, (float)strtod(computed.constant, null));
3333                                                                                     else if(!strcmp(propertyClass.dataTypeString, "double"))
3334                                                                                        ((void (*)(void *, double))(void *)prop.Set)(control, strtod(computed.constant, null));
3335                                                                                     else
3336                                                                                        ((void (*)(void *, int))(void *)prop.Set)(control, strtol(computed.constant, null, 0));
3337                                                                                  }
3338                                                                                  else if(computed.type == stringExp  && propertyClass.dataTypeString && strstr(propertyClass.dataTypeString, "char *"))
3339                                                                                  {
3340                                                                                     String temp = new char[strlen(computed.string)+1];
3341                                                                                     ReadString(temp, computed.string);
3342                                                                                     ((void (*)(void *, void *))(void *)prop.Set)(control, temp);
3343                                                                                     delete temp;
3344                                                                                  }
3345                                                                               }
3346                                                                               else
3347                                                                                  member.variable = true;
3348
3349                                                                               FreeExpression(computed);
3350                                                                            }
3351                                                                         }
3352                                                                      }
3353                                                                   }
3354                                                                   else
3355                                                                      member.variable = true;
3356                                                                }
3357                                                                else if(ident && member.initializer && member.initializer.type == expInitializer && member.initializer.exp && 
3358                                                                   member.initializer.exp.type == memberExp) // identifierExp
3359                                                                {
3360                                                                   Method method = eClass_FindMethod(instClass, ident.string, this.privateModule);
3361                                                                   if(method && method.type == virtualMethod)
3362                                                                   {
3363                                                                      ClassDef def;
3364                                                                      // Maintain a list in FunctionDefinition of who is attached to it
3365                                                                      for(def = _class.definitions->first; def; def = def.next)
3366                                                                      {
3367                                                                         if(def.type == functionClassDef)
3368                                                                         {
3369                                                                            ClassFunction function = def.function;
3370                                                                            Identifier id = (member.initializer.exp.type == memberExp) ? member.initializer.exp.member.member : member.initializer.exp.identifier;
3371                                                                            if(function.declarator && !strcmp(function.declarator.symbol.string, id.string))
3372                                                                            {
3373                                                                               function.attached.Add(OldLink { data = method });
3374                                                                               // Reference this particular instance?
3375                                                                            }
3376                                                                         }
3377                                                                      }
3378                                                                   }
3379                                                                }
3380                                                                id++;
3381                                                             }
3382                                                          }
3383                                                          break;
3384                                                       }
3385                                                    }
3386                                                 }                                          
3387                                              }
3388
3389                                              designer.PostCreateObject(object.instance, object, false, classObject.instance);
3390                                              break;
3391                                           }
3392                                        }
3393                                        break;
3394                                     }
3395                                  }
3396                               }
3397                            }
3398                         }
3399
3400                         //designer.CreateObject(instance, classObject, true, null);
3401                         //sheet.AddObject(classObject, classObject.name ? classObject.name : _class._class.name, classType, false);
3402
3403                         designer.PostCreateObject(instance, classObject, true, null);
3404
3405                         //instance.state = Hidden;
3406                         //instance.Create();
3407                         //instance.SetState(Normal, true, 0);
3408                      }
3409                   }
3410                }
3411             }
3412          }
3413
3414          SetAST(null);
3415 #ifdef _TIMINGS
3416          printf("Class/Instance Processing took %.3f seconds\n", GetTime() - startTime);
3417 #endif
3418       }
3419
3420       // Restore Selection
3421       if(selectedClassName)
3422       {
3423          ObjectInfo oClass;
3424          for(oClass = classes.first; oClass; oClass = oClass.next)
3425          {
3426             if(!strcmp(oClass.name, selectedClassName))
3427             {
3428                this.oClass = oClass;
3429                break;
3430             }
3431          }
3432          delete selectedClassName;
3433       }
3434       if(this.oClass)
3435       {
3436          if(selectedName)
3437          {
3438             ObjectInfo check;
3439             int pos = 0;
3440          
3441             for(check = this.oClass.instances.first; check; check = check.next)
3442             {
3443                if(check.name && !strcmp(check.name, selectedName))
3444                {
3445                   this.selected = check;
3446                   break;
3447                }
3448             }
3449             if(!check)
3450             {
3451                if(this.oClass.instances.first)
3452                   this.selected = this.oClass.instances.first;
3453                else
3454                   this.selected = this.oClass;
3455             }
3456          }
3457          else if(selectedPos == -1 || !this.oClass.instances.count)
3458             this.selected = this.oClass;
3459          else
3460          {
3461             ObjectInfo check;
3462             int pos = 0;
3463
3464             if(selectedPos > this.oClass.instances.count)
3465                selectedPos = 0;
3466             for(check = this.oClass.instances.first; check; check = check.next)
3467             {
3468                if(selectedPos == pos++)
3469                {
3470                   this.selected = check;
3471                   break;
3472                }
3473             }
3474          }
3475       }
3476       else
3477       {
3478          this.oClass = classes.first;
3479          this.selected = (this.oClass && this.oClass.instances.first) ? this.oClass.instances.first : this.oClass;
3480       }
3481       delete selectedName;
3482       SetSymbolsDir(null);
3483
3484       if(sheet.codeEditor == this)
3485          sheet.SelectObject(selected);
3486       Update(null);
3487
3488       codeModified = false;
3489
3490       // TESTING THIS TO NOT GET EMPTY PARAMETERS
3491       if(paramsShown)
3492       {
3493          InvokeParameters(false, false, false);
3494       }
3495
3496       editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
3497
3498       reentrant = false;
3499
3500       updatingCode--;
3501
3502       ChangeWorkingDir(oldWorkDir);
3503 #ifdef _TIMINGS
3504       printf("Total FindClass time is %.3f seconds, out of which %.3f is in Ignore NS\n\n", findClassTotalTime, findClassIgnoreNSTotalTime);
3505       printf("Total CheckType time is %.3f seconds\n\n", checkTypeTotalTime);
3506       printf("Total MkExternalImport time is %.3f seconds\n\n", externalImportTotalTime);
3507       printf("Total FindSymbol time is %.3f seconds\n\n", findSymbolTotalTime);
3508       // printf("Total Class Members Find time is %.3f seconds\n\n", GetClassFindTime());
3509       
3510       printf("Whole ParseCode function took %.3f seconds\n\n", GetTime() - parseCodeStart);
3511 #endif
3512       if(inUseDebug && ide.projectView)
3513          ide.debugger.EvaluateWatches();
3514
3515       delete pathBackup;
3516    }
3517
3518    void UpdateInstanceCodeClass(Class _class, ObjectInfo object, EditBoxStream f, Instance test, bool * prev, bool * lastIsMethod, DataMember * curMember, Class * curClass)
3519    {
3520       Property propIt;
3521       Window control = (Window)object.instance;
3522       ObjectInfo classObject = object.oClass;
3523
3524       if(_class.base && _class.base.type != systemClass) UpdateInstanceCodeClass(_class.base, object, f, test, prev, lastIsMethod, curMember, curClass);
3525
3526       if(!strcmp(_class.name, "DesignerBase")) return;
3527
3528       for(propIt = _class.membersAndProperties.first; propIt; propIt = propIt.next)
3529       {
3530          Property prop = eClass_FindProperty(object.instance._class, propIt.name, privateModule);
3531          if(prop && prop.isProperty && !prop.conversion && eClass_FindProperty(object.instance._class, prop.name, privateModule))
3532          {
3533             if(prop.Set && prop.Get && prop.dataTypeString && strcmp(prop.name, "name") && !Code_IsPropertyDisabled(object, prop.name) &&
3534                prop.compiled && (!prop.IsSet || prop.IsSet(control)))
3535             {
3536                Class dataType = prop.dataTypeClass;
3537                if(!dataType)
3538                   dataType = prop.dataTypeClass = eSystem_FindClass(this.privateModule, prop.dataTypeString);
3539          
3540                if(dataType)
3541                {
3542                   if(dataType.type == structClass)
3543                   {
3544                      void * dataForm = new0 byte[dataType.structSize];
3545                      void * dataTest = new0 byte[dataType.structSize];
3546                
3547                      ((void (*)(void *, void *))(void *)prop.Get)(control, dataForm);
3548                      ((void (*)(void *, void *))(void *)prop.Get)(test, dataTest);
3549                
3550                      if((prop.IsSet && !prop.IsSet(test)) || ((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
3551                      {
3552                         char tempString[1024] = "";
3553                         char * string = "";
3554                         bool needClass = true;
3555                         if(*prev)
3556                            f.Printf(", ");
3557                   
3558                         ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
3559                   
3560                         string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
3561                         
3562                         eClass_FindNextMember(_class, curClass, curMember, null, null);
3563                         if(*curMember != (DataMember)prop)
3564                            f.Printf("%s = ", prop.name);
3565
3566                         *curMember = (DataMember)prop;
3567                         *curClass = curMember->_class;
3568
3569                         if(needClass)
3570                            f.Printf("%c %s %c", /*dataType.name, */OpenBracket, string, CloseBracket);
3571                         else
3572                            f.Printf("%s", string);
3573                         *prev = true;
3574                      }
3575
3576                      delete dataForm;
3577                      delete dataTest;
3578                   }
3579                   else if(dataType.type == normalClass || dataType.type == noHeadClass)
3580                   {
3581                      void * dataForm, * dataTest;
3582                
3583                      dataForm = ((void *(*)(void *))(void *)prop.Get)(control);
3584                      dataTest = ((void *(*)(void *))(void *)prop.Get)(test);
3585                
3586                      if((prop.IsSet && !prop.IsSet(test)) || ((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
3587                      {
3588                         char tempString[1024] = "";
3589                         char * string = "";
3590                         if(*prev)
3591                            f.Printf(", ");
3592                   
3593                         ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
3594                   
3595                         eClass_FindNextMember(_class, curClass, curMember, null, null);
3596                         if(*curMember != (DataMember)prop)
3597                            f.Printf("%s = ", prop.name);
3598                         *curMember = (DataMember)prop;
3599                         *curClass = curMember->_class;
3600
3601                         if(eClass_GetDesigner(dataType))
3602                         {
3603                            if(eClass_IsDerived(classObject.instance._class, dataType) && classObject.instance == dataForm)
3604                            //if(!strcmp(classObject.instance._class.name, dataType.name) && classObject.instance == dataForm)
3605                               f.Printf("this", prop.name);
3606                            else
3607                            {
3608                               //ObjectInfo classObject;
3609                               //for(classObject = classes.first; classObject; classObject = classObject.next)
3610                               {
3611                                  ObjectInfo object;
3612
3613                                  for(object = classObject.instances.first; object; object = object.next)
3614                                  {
3615                                     if(!object.deleted && eClass_IsDerived(object.instance._class, dataType) && object.instance == dataForm && object.name)
3616                                     {
3617                                        f.Printf("%s", object.name);
3618                                        break;
3619                                     }
3620                                  }
3621
3622                                  if(!object)
3623                                  {
3624                                     bool needClass = true;
3625                                     string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
3626                                     f.Printf("%s", string);
3627                                  }
3628                               }
3629                            }
3630                         }
3631                         else
3632                         {
3633                            bool needClass = true;
3634                            string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
3635
3636                            if(!strcmp(dataType.dataTypeString, "char *"))
3637                            {
3638                               f.Printf("\"");
3639                               OutputString(f, string);
3640                               f.Puts("\"");
3641                            }
3642                            else if(needClass)
3643                               f.Printf("%c %s %c", /*dataType.name, */OpenBracket, string, CloseBracket);
3644                            else
3645                               f.Printf("%s", string);
3646                         }
3647                         *prev = true;
3648                         *lastIsMethod = false;
3649                      }
3650                   }
3651                   else
3652                   {
3653                      DataValue dataForm, dataTest;
3654                
3655                      GetProperty(prop, control, &dataForm);
3656                      GetProperty(prop, test, &dataTest);
3657                
3658                      if((prop.IsSet && !prop.IsSet(test)) || ((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, &dataForm, &dataTest))
3659                      {
3660                         char * string;
3661                         char tempString[1024] = "";
3662                         SetProperty(prop, test, dataForm);
3663                   
3664                         if(dataType.type != bitClass)
3665                         {
3666                            bool needClass = true;
3667
3668                            if(dataType.type == enumClass)
3669                            {
3670                               NamedLink value;
3671                               Class enumClass = eSystem_FindClass(privateModule, "enum");
3672                               EnumClassData e = ACCESS_CLASSDATA(dataType, enumClass);
3673
3674                               for(value = e.values.first; value; value = value.next)
3675                               {
3676                                  if((int)value.data == dataForm.i)
3677                                  {
3678                                     string = value.name;
3679                                     break;
3680                                  }
3681                               }
3682                            }
3683                            else
3684                               string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, &dataForm, tempString, null, &needClass);
3685                      
3686                            if(string && string[0])
3687                            {
3688                               if(*prev)
3689                                  f.Printf(", ");
3690
3691                               eClass_FindNextMember(_class, curClass, curMember, null, null);
3692                               if(*curMember != (DataMember)prop)
3693                                  f.Printf("%s = ", prop.name);
3694                               *curMember = (DataMember)prop;
3695                               *curClass = curMember->_class;
3696
3697                               if(!strcmp(dataType.dataTypeString, "float") && strchr(string, '.'))
3698                                  f.Printf("%sf", string);
3699                               else
3700                                  f.Printf("%s", string);
3701                               *prev = true;
3702                            }
3703                         }
3704                         else if(dataType.type == bitClass)
3705                         {
3706                            bool needClass = true;
3707
3708                            if(*prev) f.Printf(", ");
3709
3710                            eClass_FindNextMember(_class, curClass, curMember, null, null);
3711                            if(*curMember != (DataMember)prop)
3712                               f.Printf("%s = ", prop.name);
3713                            *curMember = (DataMember)prop;
3714                            *curClass = curMember->_class;
3715
3716                            string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, &dataForm.ui, tempString, null, &needClass);
3717                            if(needClass)
3718                               f.Printf("%c %s %c", /*dataType.name, */OpenBracket, string, CloseBracket);
3719                            else
3720                               f.Printf("%s", string);
3721                            *prev = true;
3722                            *lastIsMethod = false;
3723                         }
3724                      }
3725                   }
3726                }
3727             }
3728          }
3729       }
3730    }
3731
3732    int UpdateInstanceCode(EditBoxStream f, int position, Class regClass, ObjectInfo object, bool * firstObject, char ** text, int * textSize, int movedFuncIdLen, int movedFuncIdPos)
3733    {
3734       Instantiation inst = object.instCode;
3735       Window control = (Window)object.instance;
3736       bool prev = false;
3737       bool methodPresent = false;
3738       Class _class;
3739       bool lastIsMethod = true;
3740       ObjectInfo classObject = object.oClass;
3741       
3742       if(inst)
3743       {
3744          if(object.deleted)
3745          {
3746             // Instance removed, delete it
3747             DeleteJunkBefore(f, inst.loc.start.pos, &position);
3748
3749             f.DeleteBytes(inst.loc.end.pos - inst.loc.start.pos + 1);
3750             position = inst.loc.end.pos + 1;
3751          }
3752          else
3753          {
3754             bool multiLine = false;
3755
3756             // Change the name
3757             // Check if it's an unnamed instance
3758             if(inst.exp)
3759             {
3760                f.Seek(inst.nameLoc.start.pos - position, current);
3761                f.DeleteBytes(inst.nameLoc.end.pos - inst.nameLoc.start.pos);
3762                position = inst.nameLoc.end.pos;
3763                if(object.name)
3764                   f.Printf(object.name);
3765                else
3766                {
3767                   char ch = 0;
3768                   f.Getc(&ch);
3769                   if(isspace(ch) && ch != '\n')
3770                   {
3771                      f.Seek(-1, current);
3772                      f.DeleteBytes(1);
3773                      position ++;
3774                   }
3775                }
3776             }
3777             else
3778             {
3779                int pos = inst.loc.start.pos; // + strlen(inst._class.name);
3780                char ch;
3781                f.Seek(pos - position, current);
3782                while(f.Getc(&ch))
3783                {  
3784                   if(isspace(ch))
3785                   {
3786                      f.Seek(-1, current);
3787                      break;
3788                   }
3789                   pos++;
3790                }
3791
3792                if(object.name)
3793                {
3794                   f.Puts(" ");
3795                   f.Puts(object.name);
3796                }
3797                position = pos;
3798             }
3799
3800             if((this.methodAction == actionAddMethod || this.moveAttached) && this.selected == object)
3801                methodPresent = true;
3802
3803             for(;;)
3804             {
3805                char ch = 0;
3806                if(!f.Getc(&ch))
3807                   break;
3808                position++;
3809                if(ch == OpenBracket)
3810                   break;
3811                if(ch == '\n')
3812                   multiLine = true;
3813             }
3814
3815             // TODO: Simplify this?
3816             if(methodPresent)
3817             {
3818                if(!multiLine)
3819                {
3820                   int count = 0;
3821                   int toDelete = 0;
3822                   int toAdd = 0;
3823
3824                   f.Seek(-1, current);
3825                   f.Puts("\n   ");
3826                   f.Seek(1, current);
3827                   //f.Puts("\n");
3828
3829                   // Fix indentation
3830                   for(;;)
3831                   {
3832                      char ch = 0;
3833                      if(!f.Getc(&ch))
3834                         break;
3835                      position++;
3836                      if(ch == '\n') { toDelete = count; count = 0; }
3837                      else if(isspace(ch)) count++;
3838                      else
3839                      {
3840                         f.Seek(-1, current);
3841                         position--;
3842                         if(count > 6)
3843                         {
3844                            toDelete += count - 6; 
3845                            count = 6;
3846                         }
3847                         else 
3848                            toAdd = 6 - count;
3849                         break;                              
3850                      }
3851                   }
3852                   if(toDelete)
3853                   {
3854                      f.Seek(-toDelete-count, current);
3855                      f.DeleteBytes(toDelete);
3856                      f.Seek(count, current);
3857                   }
3858                   if(toAdd)
3859                   {
3860                      int c;
3861                      for(c = 0; c<toAdd; c++)
3862                         f.Putc(' ');
3863                   }
3864                }
3865             }
3866             else
3867                methodPresent = multiLine;
3868
3869             if(!prev)
3870                f.Printf(methodPresent ? "\n      " : " ");
3871
3872          }
3873       }
3874       else 
3875       {
3876          // Instance not there, create a brand new one
3877          DeleteJunkBefore(f, position, &position);
3878          f.Printf(*firstObject ? "\n\n" : "\n");
3879          *firstObject = false;
3880
3881          if((this.methodAction == actionAddMethod || this.moveAttached) && this.selected == object)
3882             methodPresent = true;
3883
3884          if(methodPresent)
3885          {
3886             if(object.name)
3887                f.Printf("   %s %s\n   %c\n      ", control._class.name, object.name, OpenBracket);
3888             else
3889                f.Printf("   %s\n   %c\n      ", control._class.name, OpenBracket);
3890          }
3891          else
3892          {
3893             if(object.name)
3894                f.Printf("   %s %s %c ", control._class.name, object.name, OpenBracket);
3895             else
3896                f.Printf("   %s %c ", control._class.name, OpenBracket);
3897          }
3898       }
3899
3900       if(!object.deleted)
3901       {
3902          Instance test = eInstance_New(control._class);
3903          DataMember curMember = null;
3904          Class curClass = null;
3905          incref test;
3906
3907          UpdateInstanceCodeClass(control._class, object, f, test, &prev, &lastIsMethod, &curMember, &curClass);
3908
3909          delete test;
3910
3911          // Attach Method here
3912          if((this.methodAction == actionAttachMethod || this.methodAction == actionReattachMethod) && !this.moveAttached && this.selected == object)
3913          {
3914             if(prev) f.Printf(", ");
3915             f.Printf("%s = %s", this.method.name, function.declarator.symbol.string);
3916             prev = true;
3917          }
3918       }
3919
3920       if(inst && !object.deleted)
3921       {
3922          MembersInit members;
3923          Class instClass = eSystem_FindClass(this.privateModule, inst._class.name);
3924
3925          DeleteJunkBefore(f, position, &position);
3926          
3927          // Instance already there, clear out the properties
3928          for(members = inst.members->first; members; members = members.next)
3929          {
3930             if(members.type == dataMembersInit)
3931             {
3932                MemberInit member;
3933
3934                if(members.dataMembers)
3935                {
3936                   bool keptMember = false;
3937                   MemberInit lastKept = null;
3938
3939                   for(member = members.dataMembers->first; member; member = member.next)
3940                   {
3941                      Identifier ident = member.identifiers ? member.identifiers->first : null;
3942                      bool deleted = false;
3943
3944                      // For now delete if it's not a method
3945                      if(!member.variable) // && ident)
3946                      {
3947                         if(!ident || !ident.next)
3948                         {
3949                            Property prop = ident ? eClass_FindProperty(instClass, ident.string, this.privateModule) : null;
3950                            if(!ident || prop)
3951                            {
3952                               f.Seek(member.loc.start.pos - position, current);
3953                               f.DeleteBytes(member.loc.end.pos - member.loc.start.pos);
3954                               position = member.loc.end.pos;
3955                               deleted = true;
3956                            }
3957                            else
3958                            {
3959                               Method method = eClass_FindMethod(instClass, ident.string, this.privateModule);
3960                               if(method && method.type == virtualMethod && member.initializer && member.initializer.type == expInitializer && member.initializer.exp && 
3961                                  member.initializer.exp.type == memberExp /*ExpIdentifier*/)
3962                               {
3963                                  if(((this.methodAction == actionDetachMethod || this.methodAction == actionReattachMethod) && this.method == method && this.selected == object) ||
3964                                     (this.methodAction == actionDeleteMethod && !strcmp(function.declarator.symbol.string, member.initializer.exp.identifier.string)))
3965                                  {
3966                                     f.Seek(member.loc.start.pos - position, current);
3967                                     f.DeleteBytes(member.loc.end.pos - member.loc.start.pos);
3968                                     position = member.loc.end.pos;
3969                                     deleted = true;
3970                                  }
3971                               }                                          
3972                            }
3973                         }
3974                      }
3975                      if(!deleted)
3976                      {
3977                         keptMember = true;
3978                         lastKept = member;
3979
3980                         //f.Seek(member.loc.start.pos - position, current);
3981                         //position = member.loc.start.pos;
3982                         DeleteJunkBefore(f, member.loc.start.pos, &position);
3983                         if(prev) f.Printf(", "); 
3984                         else if(keptMember) f.Printf(" ");
3985                         prev = false;
3986                      }
3987                   } 
3988                
3989                   if(!keptMember || !members.next)
3990                   {
3991                      char ch = 0;
3992                      int count = 0;
3993
3994                      if(keptMember && lastKept != members.dataMembers->last)
3995                      {
3996                         // Delete the comma
3997                         char ch;
3998                         int count = 0;
3999                         f.Seek(-1, current);
4000                         for(;f.Getc(&ch);)
4001                         {
4002                            if(ch == ',')
4003                            {
4004                               count++;
4005                               f.Seek(-1, current);
4006                               break;
4007                            }
4008                            else if(!isspace(ch))
4009                               break;
4010                            f.Seek(-2, current);
4011                            count++;
4012                         }
4013
4014                         if(ch == ',')
4015                            f.DeleteBytes(count);
4016                      }
4017
4018                      f.Seek(members.loc.end.pos - position, current);
4019                      f.Getc(&ch);
4020             
4021                      if(ch == ';')
4022                      {
4023                         f.Seek(-1, current);
4024                         f.DeleteBytes(1);
4025                         position = members.loc.end.pos + 1;
4026                      }
4027                      else
4028                      {
4029                         f.Seek(-1, current);
4030                         position = members.loc.end.pos;
4031                      }
4032
4033                      if(keptMember)
4034                      {
4035                         prev = true;
4036                         lastIsMethod = false;
4037                      }
4038                   }
4039                   else
4040                   {
4041                      DeleteJunkBefore(f, position, &position);
4042                      f.Printf(" ");
4043
4044                      if(lastKept != members.dataMembers->last)
4045                      {
4046                         // Delete the comma
4047                         char ch;
4048                         int count = 0;
4049                         f.Seek(-1, current);
4050                         for(;f.Getc(&ch);)
4051                         {
4052                            if(ch == ',')
4053                            {
4054                               count++;
4055                               f.Seek(-1, current);
4056                               break;
4057                            }
4058                            else if(!isspace(ch))
4059                               break;
4060                            f.Seek(-2, current);
4061                            count++;
4062                         }
4063
4064                         if(ch == ',')
4065                            f.DeleteBytes(count);
4066                      }
4067                      else
4068                      {
4069                         f.Seek(members.loc.end.pos - position, current);
4070                         position = members.loc.end.pos;
4071                      }
4072                      /*
4073                      prev = false;
4074                      lastIsMethod = true;
4075                      */
4076                      prev = true;
4077                      lastIsMethod = false;
4078                      
4079                   }
4080                }
4081                else
4082                {
4083                   f.Seek(members.loc.end.pos - position, current);
4084                   position = members.loc.end.pos;
4085                   prev = false;
4086                   lastIsMethod = true;
4087                }
4088             }
4089             else if(members.type == methodMembersInit)
4090             {
4091                if(this.methodAction == actionDeleteMethod && members.function == function);
4092                else
4093                   methodPresent = true;
4094
4095                // Delete instance method here
4096                if((this.methodAction == actionDeleteMethod || (this.methodAction == actionDetachMethod && this.moveAttached)) && 
4097                   members.function == function)
4098                {
4099                   if(this.moveAttached && !*text)
4100                      GetLocText(editBox, f, position, &function.loc, text, textSize, Max((int)strlen(this.methodName) - movedFuncIdLen,0), 0);
4101
4102                   DeleteJunkBefore(f, members.loc.start.pos, &position);
4103                   f.DeleteBytes(members.loc.end.pos - members.loc.start.pos + 1);
4104                   position = members.loc.end.pos + 1;
4105                   f.Printf("\n");
4106                }
4107                else
4108                {
4109                   DeleteJunkBefore(f, position, &position);
4110                   if(!lastIsMethod)
4111                      f.Printf(";");
4112
4113                   DeleteJunkBefore(f, members.loc.start.pos, &position);
4114                   lastIsMethod = true;
4115                   f.Printf("\n\n      ");               
4116                }
4117
4118                f.Seek(members.loc.end.pos - position, current);
4119                position = members.loc.end.pos;
4120             }
4121             DeleteJunkBefore(f, position, &position);
4122          }
4123       }
4124
4125       if(!object.deleted)
4126       {
4127          if(!methodPresent)
4128             f.Printf(" ");
4129
4130          if((this.methodAction == actionAddMethod || (this.moveAttached && (this.methodAction == actionAttachMethod || this.methodAction == actionReattachMethod))) && this.selected == object)
4131          {
4132             Method method = this.method;
4133             DeleteJunkBefore(f, position, &position);
4134             if(!lastIsMethod)
4135                f.Printf(";");
4136
4137             f.Printf("\n");
4138
4139             if(!method.dataType)
4140                method.dataType = ProcessTypeString(method.dataTypeString, false);
4141
4142             {
4143                Type dataType = method.dataType;
4144                Type returnType = dataType.returnType;
4145                Type param;
4146
4147                if(this.moveAttached)
4148                {
4149                   // Move function here:
4150                   int newLen = strlen(method.name);
4151
4152                   f.Printf("\n   ");
4153
4154                   if(!*text)
4155                      GetLocText(editBox, f, position, &function.loc, text, textSize, Max(newLen - movedFuncIdLen, 0), 3);
4156
4157                   // First change name of function
4158                   memmove(*text + movedFuncIdPos + newLen, *text + movedFuncIdPos + movedFuncIdLen, *textSize - movedFuncIdPos - movedFuncIdLen + 1);
4159                   *textSize += newLen - movedFuncIdLen;
4160                   memcpy(*text + movedFuncIdPos, method.name, newLen);
4161                                           
4162                   // Second, tab right
4163                   {
4164                      int c;
4165                      for(c = 0; (*text)[c]; )
4166                      {
4167                         int i;
4168                         for(i = c; (*text)[i] && (*text)[i] != '\n'; i++);
4169                         if(i != c)
4170                         {
4171                            memmove((*text)+c+3, (*text)+c, *textSize+1-c);
4172                            (*text)[c] = (*text)[c+1] = (*text)[c+2] = ' ';
4173                            c += 3;
4174                            *textSize += 3;
4175                         }
4176                         for(; (*text)[c] && (*text)[c] != '\n'; c++);
4177                         if((*text)[c]) c++;
4178                      }
4179                   }
4180
4181                   f.Puts((*text));
4182                   f.Printf("\n");
4183                }
4184                else
4185                {
4186                   Class moduleClass = eSystem_FindClass(this.privateModule, "Module");
4187
4188                   // ADDING METHOD HERE
4189                   f.Printf("\n      ");
4190                   OutputType(f, returnType, false);
4191             
4192                   f.Printf(" ");
4193                   if(dataType.thisClass)
4194                   {
4195                      if(!eClass_IsDerived(regClass, dataType.thisClass.registered) && !dataType.classObjectType)     // Just fixed this... was backwards.
4196                      {
4197                         if(dataType.thisClass.shortName)
4198                            f.Printf(dataType.thisClass.shortName);
4199                         else
4200                            f.Printf(dataType.thisClass.string);
4201                         f.Printf("::");
4202                      }
4203                   }
4204                   f.Printf(method.name);
4205                   f.Printf("(");
4206                   for(param = dataType.params.first; param; param = param.next)
4207                   {
4208                      OutputType(f, param, true);
4209                      if(param.next)
4210                         f.Printf(", ");
4211                   }
4212                   f.Printf(")\n");                  
4213                   f.Printf("      %c\n\n", OpenBracket);
4214
4215                   if(control._class._vTbl[method.vid] == moduleClass._vTbl[__ecereVMethodID___ecereNameSpace__ecere__com__Module_OnLoad]) // Temp Check for DefaultFunction
4216                   {
4217                      if(returnType.kind == classType && !strcmp(returnType._class.string, "bool"))
4218                         f.Printf("         return true;\n");
4219                      else if(returnType.kind != voidType)
4220                         f.Printf("         return 0;\n");
4221                   }
4222                   else
4223                   {
4224                      f.Printf("         ");
4225                      if(returnType.kind != voidType)
4226                         f.Printf("return ");
4227                      f.Printf("%s::%s(", control._class.name, method.name);
4228                      for(param = dataType.params.first; param; param = param.next)
4229                      {
4230                         if(param.prev) f.Printf(", ");
4231                         if(param.kind != voidType)
4232                            f.Printf(param.name);
4233                      }
4234                      f.Printf(");\n");
4235                   }
4236                   f.Printf("      %c\n", CloseBracket);
4237                }
4238             }
4239          }
4240       }
4241
4242       if(!object.instCode)
4243       {
4244          if(methodPresent)
4245             f.Printf("   %c;\n", CloseBracket);
4246          else
4247             f.Printf("%c;\n", CloseBracket);
4248       }
4249       else if(!object.deleted)
4250       {
4251          // Turn this into a multiline instance when adding a method
4252          DeleteJunkBefore(f, inst.loc.end.pos-1, &position);
4253
4254          f.Printf(methodPresent ? "\n   " : " ");
4255
4256          f.Seek(inst.loc.end.pos + 1 - position, current);
4257          position = inst.loc.end.pos + 1;
4258       }
4259       return position;
4260    }
4261
4262    void OutputClassProperties(Class _class, ObjectInfo classObject, EditBoxStream f, Instance test)
4263    {
4264       Property propIt;
4265       Class regClass = eSystem_FindClass(privateModule, classObject.name);
4266      
4267       if(_class.base && _class.base.type != systemClass) OutputClassProperties(_class.base, classObject, f, test);
4268       
4269       for(propIt = _class.membersAndProperties.first; propIt; propIt = propIt.next)
4270       {
4271          Property prop = eClass_FindProperty(selected.instance._class, propIt.name, privateModule);
4272          if(prop && prop.isProperty && !prop.conversion)
4273          {
4274             if(prop.Set && prop.Get && prop.dataTypeString && strcmp(prop.name, "name") && !Code_IsPropertyDisabled(classObject, prop.name) && 
4275                (!prop.IsSet || prop.IsSet(classObject.instance)))
4276             {
4277                Class dataType = prop.dataTypeClass;
4278                char tempString[1024] = "";
4279                char * string;
4280                bool specify = false;
4281                DataMember member;
4282
4283                member = eClass_FindDataMember(regClass, prop.name, privateModule, null, null);
4284                if(member && member._class == regClass)
4285                   specify = true;
4286
4287                if(!dataType)
4288                   dataType = prop.dataTypeClass = eSystem_FindClass(this.privateModule, prop.dataTypeString);
4289             
4290                if(dataType && dataType.type == structClass)
4291                {
4292                   void * dataForm = new0 byte[dataType.structSize];
4293                   void * dataTest = new0 byte[dataType.structSize];
4294                
4295                   ((void (*)(void *, void *))(void *)prop.Get)(classObject.instance, dataForm);
4296                   ((void (*)(void *, void *))(void *)prop.Get)(test, dataTest);
4297
4298                   if(((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
4299                   {
4300                      bool needClass = true;
4301                      
4302                      string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
4303                      ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
4304                      if(needClass)
4305                         f.Printf("\n   %s%s = %c %s %c;", specify ? "property::" : "", prop.name, /*dataType.name, */OpenBracket, string, CloseBracket);
4306                      else
4307                         f.Printf("\n   %s%s = %s;", specify ? "property::" : "", prop.name, string);
4308                   }
4309                   delete dataForm;
4310                   delete dataTest;
4311                }
4312                else if(dataType && (dataType.type == normalClass || dataType.type == noHeadClass))
4313                {
4314                   void * dataForm, * dataTest;
4315                
4316                   dataForm = ((void *(*)(void *))(void *)prop.Get)(classObject.instance);
4317                   dataTest = ((void *(*)(void *))(void *)prop.Get)(test);
4318                
4319                   if(((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
4320                   {
4321                      char tempString[1024] = "";
4322                      char * string;
4323                      ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
4324                   
4325                      if(eClass_IsDerived(classObject.instance._class, dataType) && classObject.instance == dataForm)
4326                      {
4327                         // Shouldn't go here ...
4328                         f.Printf("\n   %s%s = this;", specify ? "property::" : "", prop.name);
4329                      }
4330                      else
4331                      {
4332                         bool needClass = true;
4333
4334                         string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
4335
4336                         if(!strcmp(dataType.dataTypeString, "char *"))
4337                         {
4338                            f.Printf("\n   %s%s = \"", specify ? "property::" : "", prop.name);
4339                            OutputString(f, string);
4340                            f.Puts("\";");
4341                         }
4342                         else if(needClass)
4343                            f.Printf("\n   %s%s = %c %s %c;", specify ? "property::" : "", prop.name, /*dataType.name, */OpenBracket, string, CloseBracket);
4344                         else
4345                            f.Printf("\n   %s%s = %s;", specify ? "property::" : "", prop.name, string);
4346                      }
4347                   }
4348                }
4349                else if(dataType)
4350                {
4351                   DataValue dataForm, dataTest;
4352                
4353                   GetProperty(prop, classObject.instance, &dataForm);
4354                   GetProperty(prop, test, &dataTest);
4355                
4356                   if(((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, &dataForm, &dataTest))
4357                   {
4358                      SetProperty(prop, test, dataForm);
4359                      if(dataType.type == bitClass)
4360                      {
4361                         bool needClass = true;
4362                         string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, &dataForm, tempString, null, &needClass);
4363                         if(needClass)
4364                            f.Printf("\n   %s%s = %c %s %c;", specify ? "property::" : "", prop.name, /*dataType.name, */OpenBracket, string, CloseBracket);
4365                         else if(string[0])
4366                            f.Printf("\n   %s%s = %s;", specify ? "property::" : "", prop.name, string);
4367                      }
4368                      else
4369                      {
4370                         bool needClass = true;
4371                         if(dataType.type == enumClass)
4372                         {
4373                            NamedLink value;
4374                            Class enumClass = eSystem_FindClass(privateModule, "enum");
4375                            EnumClassData e = ACCESS_CLASSDATA(dataType, enumClass);
4376
4377                            for(value = e.values.first; value; value = value.next)
4378                            {
4379                               if((int)value.data == dataForm.i)
4380                               {
4381                                  string = value.name;
4382                                  break;
4383                               }
4384                            }
4385                         }
4386                         else
4387                            string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, &dataForm, tempString, null, &needClass);
4388                         if(!strcmp(dataType.dataTypeString, "float") && strchr(string, '.'))
4389                            f.Printf("\n   %s%s = %sf;", specify ? "property::" : "", prop.name, string);
4390                         else if(string[0])
4391                            f.Printf("\n   %s%s = %s;", specify ? "property::" : "", prop.name, string);
4392                      }
4393                   }                                          
4394                }
4395             }
4396          }
4397       }
4398    }
4399
4400    void UpdateFormCode()
4401    {
4402       if(!this) return;
4403       if(!parsing) return;
4404          
4405       updatingCode++;
4406       if(codeModified)
4407       {
4408          ParseCode();
4409       }
4410       else if(formModified)
4411       {
4412          EditBoxStream f { editBox = editBox };
4413          int position = 0;
4414          char * text = null;
4415          int textSize;
4416          Identifier movedFuncId; 
4417          int movedFuncIdLen = 0, movedFuncIdPos = 0;
4418          ObjectInfo classObject;
4419
4420            updatingCode++;
4421
4422          if(moveAttached)
4423          {
4424             movedFuncId = GetDeclId(function.declarator);
4425             movedFuncIdLen = movedFuncId.loc.end.pos - movedFuncId.loc.start.pos;
4426             movedFuncIdPos = movedFuncId.loc.start.pos - function.loc.start.pos;
4427          }
4428
4429          for(classObject = classes.first; classObject; classObject = classObject.next)
4430          {
4431             Class _class;
4432             ClassDefinition classDef = classObject.classDefinition;
4433             Class regClass = eSystem_FindClass(this.privateModule, ((Specifier)classDef.baseSpecs->first).name);
4434             Instance test;
4435             ClassDef def;
4436             bool firstObject = true;
4437             ObjectInfo object = classObject.instances.first;
4438             bool lastIsDecl = false;
4439
4440             if(!classObject.modified) continue;
4441
4442             test = eInstance_New(regClass);
4443             incref test;
4444
4445             // Put it in the same desktop window...
4446             designer.PrepareTestObject(test);
4447             
4448             //f.Printf("class %s : %s\n", classObject.name, classObject.oClass.name);
4449             //f.Printf("%c\n\n", OpenBracket);
4450
4451             // Change the _class name
4452             f.Seek(classDef.nameLoc.start.pos - position, current);
4453             f.DeleteBytes(classDef.nameLoc.end.pos - classDef.nameLoc.start.pos);
4454             f.Printf(classObject.name);
4455             position = classDef.nameLoc.end.pos;
4456
4457             {
4458                // Go to block start, delete all until no white space, put \n
4459                char ch;
4460                int count = 0;
4461                int back = 0;
4462                f.Seek(classDef.blockStart.end.pos - position, current);
4463                position = classDef.blockStart.end.pos;
4464                
4465                for(; f.Getc(&ch); count++)
4466                {
4467                   if(!isspace(ch))
4468                   {
4469                      f.Seek(-1, current);
4470                      break;
4471                   }
4472                
4473                   if(ch == '\n')
4474                      back = 0;
4475                   else
4476                      back++;
4477                }
4478             
4479                f.Seek(-count, current);
4480             
4481                f.DeleteBytes(count-back);
4482                //f.Printf("\n");
4483                position += count-back;
4484             }
4485
4486             // Output properties
4487             OutputClassProperties(classObject.instance._class, classObject, f, test);
4488
4489             for(def = classDef.definitions->first; def; def = def.next)
4490             {
4491                switch(def.type)
4492                {
4493                   case defaultPropertiesClassDef:
4494                   {
4495                      bool keptMember = false;
4496                      MemberInit propDef;
4497                      MemberInit lastKept = null;
4498                      
4499                      lastIsDecl = false;
4500                      DeleteJunkBefore(f, def.loc.start.pos, &position);
4501                      f.Printf("\n   ");
4502
4503                      for(propDef = def.defProperties->first; propDef; propDef = propDef.next)
4504                      {
4505                         Identifier ident = propDef.identifiers->first;
4506                         bool deleted = false;
4507
4508                         // For now delete if it's a prop
4509                         if(!propDef.variable && ident)
4510                         {
4511                            if(!ident.next)
4512                            {
4513                               Property prop = eClass_FindProperty(regClass, ident.string, this.privateModule);
4514                               if(prop)
4515                               {
4516                                  f.Seek(propDef.loc.start.pos - position, current);
4517                                  f.DeleteBytes(propDef.loc.end.pos - propDef.loc.start.pos);
4518                                  position = propDef.loc.end.pos;
4519                                  deleted = true;
4520                               }
4521                               else
4522                               {
4523                                  Method method = eClass_FindMethod(regClass, ident.string, this.privateModule);
4524                                  if(method && method.type == virtualMethod && propDef.initializer && propDef.initializer.type == expInitializer && propDef.initializer.exp && propDef.initializer.exp.type == identifierExp)
4525                                  {
4526                                     if(((methodAction == actionDetachMethod || methodAction == actionReattachMethod) && method == this.method && selected == classObject) ||
4527                                        (methodAction == actionDeleteMethod && !strcmp(function.declarator.symbol.string, propDef.initializer.exp.identifier.string)))
4528                                     {
4529                                        f.Seek(propDef.loc.start.pos - position, current);
4530                                        f.DeleteBytes(propDef.loc.end.pos - propDef.loc.start.pos);
4531                                        position = propDef.loc.end.pos;
4532                                        deleted = true;
4533                                     }
4534                                  }                                          
4535                               }
4536                            }
4537                         }
4538                         if(!deleted)
4539                         {
4540                            keptMember = true;
4541                            lastKept = propDef;
4542                         }
4543                      }
4544                   
4545                      if(!keptMember)
4546                      {
4547                         char ch = 0;
4548                         int count = 0;
4549                         f.Seek(def.loc.end.pos - position - 1, current);
4550                         f.Getc(&ch);
4551                         
4552                         if(ch == ';')
4553                         {
4554                            f.Seek(-1, current);
4555                            f.DeleteBytes(1);
4556                         }
4557                         position = def.loc.end.pos;
4558                      }
4559                      else
4560                      {
4561                         if(lastKept != def.defProperties->last)
4562                         {
4563                            char ch;
4564                            int count = 0;
4565                            
4566                            f.Seek(-1, current);
4567                            for(;f.Getc(&ch);)
4568                            {
4569                               if(ch == ',')
4570                               {
4571                                  count++;
4572                                  f.Seek(-1, current);
4573                                  break;
4574                               }
4575                               else if(!isspace(ch))
4576                                  break;
4577                               f.Seek(-2, current);
4578                               count++;
4579                            }
4580
4581                            if(ch == ',')
4582                               f.DeleteBytes(count);
4583                         }
4584                         else
4585                         {
4586                            f.Seek(def.loc.end.pos - position, current);
4587                            position = def.loc.end.pos;
4588                         }                
4589                      }
4590                      break;
4591                   }
4592                   case declarationClassDef:
4593                   {
4594                      Declaration decl = def.decl;
4595
4596                      if(decl.type == instDeclaration)
4597                      {
4598                         if(def.object/* && ((ObjectInfo)def.object).modified*/)
4599                         {
4600                            while(def.object && object != def.object)
4601                            {
4602                               if(object /*&& ((ObjectInfo)def.object).modified*/)
4603                                  position = UpdateInstanceCode(f, position, regClass, object, &firstObject, &text, &textSize, movedFuncIdLen, movedFuncIdPos);
4604                               object = object.next;
4605                            }
4606
4607                            DeleteJunkBefore(f, def.loc.start.pos, &position);
4608                            f.Printf(firstObject ? "\n\n   " : "\n   ");
4609                            firstObject = false;
4610
4611                            if(def.object && ((ObjectInfo)def.object).modified)
4612                               position = UpdateInstanceCode(f, position, regClass, def.object, &firstObject, &text, &textSize, movedFuncIdLen, movedFuncIdPos);
4613
4614                            object = object ? object.next : null;
4615                         }
4616                         else
4617                         {
4618                            DeleteJunkBefore(f, def.loc.start.pos, &position);
4619                            f.Printf(firstObject ? "\n\n   " : "\n   ");
4620                            firstObject = false;
4621                         }
4622                         lastIsDecl = false;
4623                      }
4624                      else
4625                      {
4626                         DeleteJunkBefore(f, def.loc.start.pos, &position);
4627                         f.Printf(lastIsDecl ? "\n   " : "\n\n   ");
4628                         lastIsDecl = true;
4629                      }
4630                      break;
4631                   }
4632                   case functionClassDef:
4633                   {
4634                      // TESTING IF THIS IS GOOD ENOUGH FOR GENERATED FUNCTION...
4635                      if(!def.function.body) continue;
4636
4637                      lastIsDecl = false;
4638
4639                      DeleteJunkBefore(f, def.loc.start.pos, &position);
4640                      f.Printf("\n\n   ");
4641
4642                      // Delete _class methods
4643                      if((methodAction == actionDeleteMethod || (moveAttached && selected != classObject)) && 
4644                         def.function == function)
4645                      {
4646                         char ch;
4647                         int count = 0;
4648
4649                         if(moveAttached && !text)
4650                         {
4651                            GetLocText(editBox, f, position, &function.loc, &text, &textSize, Max((int)strlen(methodName) - movedFuncIdLen,0), 3);
4652                         }
4653
4654                         f.Seek(def.loc.end.pos - position, current);
4655                         for(; f.Getc(&ch); count++)
4656                         {
4657                            if(!isspace(ch))
4658                            {
4659                               f.Seek(-1, current);
4660                               break;
4661                            }
4662                         }
4663                         f.Seek(def.loc.start.pos - def.loc.end.pos - count, current);
4664
4665                         f.DeleteBytes(def.loc.end.pos - def.loc.start.pos + count);
4666                         position = def.loc.end.pos + count;
4667                      }
4668
4669                      // In case of detaching methods in the _class, simply rename the method
4670                      if(methodAction == actionDetachMethod && moveAttached && selected == classObject && function == def.function)
4671                      {
4672                         f.Seek(function.loc.start.pos + movedFuncIdPos - position, current);
4673                         f.DeleteBytes(movedFuncIdLen);
4674                         f.Puts(methodName);
4675                         position = function.loc.start.pos + movedFuncIdPos + movedFuncIdLen;
4676                      }
4677
4678                      if((methodAction == actionAttachMethod || methodAction == actionReattachMethod) && selected == classObject && moveAttached && 
4679                         function == def.function)
4680                      {
4681                         // In case of attaching methods in the _class, simply rename the method
4682                         f.Seek(function.loc.start.pos + movedFuncIdPos - position, current);
4683                         position = function.loc.start.pos + movedFuncIdPos;
4684                         f.DeleteBytes(movedFuncIdLen);
4685                         if(method.dataType.thisClass)
4686                            f.Printf("%s::", method.dataType.thisClass.string);
4687                         f.Puts(method.name);
4688                         position += movedFuncIdLen;
4689                      }
4690                      break;
4691                   }
4692                   default:
4693                      DeleteJunkBefore(f, def.loc.start.pos, &position);
4694                      if(def.type == memberAccessClassDef)
4695                      {
4696                         f.Printf("\n\n");
4697                         firstObject = false;
4698                         lastIsDecl = true;
4699                      }
4700                      else           
4701                      {
4702                         f.Printf("\n   ");
4703                         lastIsDecl = false;
4704                      }
4705                }
4706
4707                f.Seek(def.loc.end.pos - position, current);
4708                position = def.loc.end.pos;
4709             }
4710
4711             // Output attached methods
4712             if((methodAction == actionAttachMethod || methodAction == actionReattachMethod) && selected == classObject && !moveAttached)
4713             {
4714                DeleteJunkBefore(f, position, &position);
4715                f.Printf("\n   %s = %s;\n", method.name, function.declarator.symbol.string);
4716             }
4717             
4718             // ********** INSTANCES ***************
4719             for(; object; object = object.next)
4720             {
4721                if(!object.instCode)
4722                {
4723                   position = UpdateInstanceCode(f, position, regClass, object, &firstObject, &text, &textSize, movedFuncIdLen, movedFuncIdPos);
4724                }
4725             }
4726
4727             DeleteJunkBefore(f, position, &position);
4728
4729             // ****************** METHODS ***********************
4730             if(methodAction == actionDetachMethod && moveAttached && classObject == oClass)
4731             {
4732                // If detaching an instance method
4733                if(selected != classObject)
4734                {
4735                   int newLen = strlen(methodName);
4736
4737                   if(!text)
4738                      GetLocText(editBox, f, position, &function.loc, &text, &textSize, Max(newLen - movedFuncIdLen,0), 0);
4739                   // Tab selection left
4740                   {
4741                      int c;
4742                      for(c = 0; text[c]; )
4743                      {
4744                         int start = c, i;
4745                         for(i = 0; i<3 && text[c] == ' '; i++, c++);
4746                         memmove(text+start, text+start+i, textSize+1-start-i);
4747                         textSize -= i;
4748                         c -= i;
4749                         for(; text[c] && text[c] != '\n'; c++);
4750                         if(text[c]) c++;
4751                      }
4752                   }
4753
4754                   // Rename function
4755                   memmove(text + movedFuncIdPos + newLen, text + movedFuncIdPos + movedFuncIdLen, textSize - movedFuncIdPos - movedFuncIdLen + 1);
4756                   textSize += newLen - movedFuncIdLen;
4757                   memcpy(text + movedFuncIdPos, methodName, newLen);
4758
4759                   f.Printf("\n\n   ");
4760                   f.Puts(text);
4761                }
4762             }
4763
4764             if(methodAction == actionAddMethod && selected == classObject)
4765             {
4766                Method method = this.method;
4767
4768                if(!method.dataType)
4769                   method.dataType = ProcessTypeString(method.dataTypeString, false);
4770
4771                // ADDING METHOD HERE
4772                {
4773                   Type dataType = method.dataType;
4774                   Type returnType = dataType.returnType;
4775                   Type param;
4776                   Class moduleClass = eSystem_FindClass(this.privateModule, "Module");
4777
4778                   f.Printf("\n\n");
4779                   f.Printf("   ");
4780                   OutputType(f, returnType, false);
4781                
4782                   f.Printf(" ");
4783                   if(dataType.thisClass && !dataType.classObjectType)
4784                   {
4785                      if(dataType.thisClass.shortName)
4786                         f.Printf(dataType.thisClass.shortName);
4787                      else
4788                         f.Printf(dataType.thisClass.string);
4789                      f.Printf("::");
4790                   }
4791                   f.Printf(method.name);
4792                   f.Printf("(");
4793                   for(param = dataType.params.first; param; param = param.next)
4794                   {
4795                      OutputType(f, param, true);
4796                      if(param.next)
4797                         f.Printf(", ");
4798                   }
4799                   f.Printf(")\n");                  
4800                   f.Printf("   %c\n\n", OpenBracket);
4801
4802                   if(test._class._vTbl[method.vid] == moduleClass._vTbl[__ecereVMethodID___ecereNameSpace__ecere__com__Module_OnLoad]) // Temp Check for DefaultFunction
4803                   {
4804                      if(returnType && returnType.kind == classType && !strcmp(returnType._class.string, "bool"))
4805                         f.Printf("      return true;\n");
4806                      else if(returnType && returnType.kind != voidType)
4807                         f.Printf("      return 0;\n");
4808                   }
4809                   else
4810                   {
4811                      f.Printf("      ");
4812                      if(returnType.kind != voidType)
4813                         f.Printf("return ");
4814                      {
4815                         char * name = ((Specifier)classDef.baseSpecs->first).name;
4816                         Symbol _class = FindClass(name);
4817                         f.Printf("%s::%s(", (_class && _class.registered) ? _class.registered.name : name, method.name);
4818                      }
4819                      for(param = dataType.params.first; param; param = param.next)
4820                      {
4821                         if(param.prev) f.Printf(", ");
4822                         if(param.kind != voidType)
4823                            f.Printf(param.name);
4824                      }
4825                      f.Printf(");\n");
4826                   }
4827
4828                   f.Printf("   %c", CloseBracket);
4829                }
4830             }
4831
4832             DeleteJunkBefore(f, classDef.loc.end.pos-1, &position);
4833             f.Printf("\n");
4834
4835             delete test;
4836          }
4837
4838          updatingCode--;
4839          delete f;
4840
4841          ParseCode();
4842          delete text;
4843
4844          // TOFIX: Patch for a glitch where clicking at the end of the view seems one line off. No idea what could be going on?
4845          editBox.OnVScroll(setRange, editBox.scroll.y, 0);
4846       }
4847
4848       updatingCode--;
4849       codeModified = false;
4850       formModified = false;
4851       methodAction = 0;
4852       moveAttached = false;
4853       function = null;
4854       method = null;
4855    }
4856
4857    int FindMethod(char * methodName /*Method method*/, ClassFunction*functionPtr, Location propLoc)
4858    {
4859       int found = 0;
4860       ClassFunction function = null;
4861       if(methodName)
4862       {
4863          ObjectInfo object = this.selected;
4864          
4865          if(object && object == this.oClass)
4866          {
4867             ClassDefinition classDef = object.oClass.classDefinition;
4868             ClassDef def;
4869             if(classDef && classDef.definitions)
4870             {
4871                for(def = classDef.definitions->first; def; def = def.next)
4872                {
4873                   if(def.type == functionClassDef && def.function.declarator)
4874                   {
4875                      if(!strcmp(def.function.declarator.symbol.string, methodName))
4876                      {
4877                         function = def.function;
4878                         found = 1;
4879                         break;
4880                      }
4881                   }
4882                   else if(def.type == defaultPropertiesClassDef)
4883                   {
4884                      MemberInit propDef;
4885
4886                      for(propDef = def.defProperties->first; propDef; propDef = propDef.next)
4887                      {
4888                         Identifier ident = propDef.identifiers ? propDef.identifiers->first : null;
4889                         if(ident && !ident.next)
4890                         {
4891                            if(!strcmp(ident.string, methodName) && propDef.initializer && propDef.initializer.type == expInitializer && propDef.initializer.exp && propDef.initializer.exp.type == identifierExp)
4892                            {
4893                               found = 2;
4894                               if(propLoc != null)
4895                                  propLoc = propDef.loc;
4896                               if(functionPtr)
4897                               {
4898                                  ClassDefinition classDef = object.oClass.classDefinition;
4899                                  ClassDef def;
4900                                  if(classDef.definitions)
4901                                  {
4902                                     for(def = classDef.definitions->first; def; def = def.next)
4903                                     {
4904                                        if(def.type == functionClassDef)
4905                                        {
4906                                           if(!strcmp(def.function.declarator.symbol.string, propDef.initializer.exp.identifier.string))
4907                                           {
4908                                              function = def.function;
4909                                              break;
4910                                           }
4911                                        }
4912                                     }
4913                                     if(function) break;
4914                                  }
4915                               }
4916                               else
4917                                  break;
4918                            }
4919                         }
4920                      }
4921                   }
4922                }
4923             }
4924          }
4925          else if(object)
4926          {
4927             Instantiation inst = object.instCode;
4928
4929             // Check here to see if the method already exists, no need to call ModifyCode in that case
4930             if(inst && inst.members)
4931             {
4932                MembersInit members;
4933                for(members = inst.members->first; members; members = members.next)
4934                {
4935                   switch(members.type)
4936                   {
4937                      case dataMembersInit:
4938                      {
4939                         if(members.dataMembers)
4940                         {
4941                            MemberInit member;
4942                            for(member = members.dataMembers->first; member; member = member.next)
4943                            {
4944                               Identifier ident = member.identifiers ? member.identifiers->first : null;
4945                               if(ident && !ident.next)
4946                               {
4947                                  if(!strcmp(ident.string, methodName) && member.initializer && member.initializer.type == expInitializer && member.initializer.exp && member.initializer.exp.type == memberExp /*ExpIdentifier*/)
4948                                  {
4949                                     found = 2;
4950                                     if(propLoc != null)
4951                                        propLoc = member.loc;
4952                                     if(functionPtr)
4953                                     {
4954                                        ClassDefinition classDef = object.oClass.classDefinition;
4955                                        ClassDef def;
4956                                        if(classDef.definitions)
4957                                        {
4958                                           for(def = classDef.definitions->first; def; def = def.next)
4959                                           {
4960                                              if(def.type == functionClassDef)
4961                                              {
4962                                                 if(def.function.declarator && !strcmp(def.function.declarator.symbol.string, member.initializer.exp.identifier.string))
4963                                                 {
4964                                                    function = def.function;
4965                                                    break;
4966                                                 }
4967                                              }
4968                                           }
4969                                           if(function) break;
4970                                        }
4971                                        if(!function)
4972                                        {
4973                                           // TODO: Fix memory leak
4974                                           function = ClassFunction
4975                                           {
4976                                              declarator = Declarator { symbol = Symbol { string = CopyString(member.initializer.exp.member.member ? member.initializer.exp.member.member.string : "") } }
4977                                           };
4978                                        }
4979                                     }
4980                                     else
4981                                        break;
4982                                  }
4983                               }
4984                            }
4985                         }
4986                         break;
4987                      }
4988                      case methodMembersInit:
4989                      {
4990                         if(members.function.declarator && !strcmp(members.function.declarator.symbol.string, methodName))
4991                         {
4992                            function = members.function;
4993                            found = 1;
4994                         }
4995                         break;
4996                      }
4997                   }
4998                   if(function)
4999                      break;
5000                }
5001             }
5002          }
5003       }
5004       if(functionPtr) *functionPtr = function;
5005       return found;
5006    }
5007
5008    void GoToMethod(char * methodName /*Method method*/)
5009    {
5010       if(methodName)
5011       {
5012          ObjectInfo object = selected;
5013          EditBoxStream f { editBox = editBox };
5014          ClassFunction function = null;
5015          bool atChar = false;
5016          int indent = 6;
5017          EditLine l1, l2;
5018          int y1,y2, x1, x2;
5019          Location propLoc = { {0,0,-1} };
5020
5021          // GO TO THE METHOD
5022          if(FindMethod(methodName, &function, &propLoc) == 1 && object != this.oClass) indent = 9;
5023          if(function && function.body)
5024          {
5025             bool lfCount = 0;
5026             f.Seek(function.body.loc.start.pos+1, current);
5027             for(;;)
5028             {
5029                char ch;
5030                if(!f.Getc(&ch))
5031                   break;
5032                if(ch == '\n')
5033                {
5034                   if(lfCount)
5035                   {
5036                      f.Seek(-1, current);
5037                      break;
5038                   }
5039                   lfCount++;
5040                }
5041                else if(!isspace(ch))
5042                {
5043                   f.Seek(-1, current);
5044                   atChar = true;
5045                   break;
5046                }
5047             }
5048          }
5049          else if(propLoc.start.pos > -1)
5050          {
5051             f.Seek(propLoc.start.pos, current);
5052             atChar = true;
5053          }
5054          editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
5055          delete f;
5056          if(function || propLoc.start.pos > -1)
5057          {
5058             editBox.SetSelPos(l1, y1, atChar ? x1 : indent, l2, y2, atChar ? x2 : indent);
5059             editBox.CenterOnCursor();
5060             SetState(normal, false, 0);
5061             Activate();
5062
5063             if(function && function.declarator && function.declarator.symbol && !function.declarator.symbol.type)
5064             {
5065                FreeClassFunction(function);
5066             }
5067          }
5068       }
5069    }
5070
5071    void FindCompatibleMethods(Method method, OldList compatible)
5072    {
5073       ClassDefinition classDef = this.oClass.classDefinition;
5074       if(classDef && classDef.definitions)
5075       {
5076          Class regClass { };
5077          Class baseClass = eSystem_FindClass(this.privateModule, ((Specifier)classDef.baseSpecs->first).name);
5078          ClassDef def;
5079          Class _class;
5080          Symbol classSym { };
5081          Symbol selectedClass;
5082          if(this.selected == this.oClass)
5083             selectedClass = classSym;
5084          else
5085             selectedClass = FindClass(this.selected.instance._class.name);
5086
5087          regClass.name = classDef._class.name;
5088          regClass.base = eSystem_FindClass(this.privateModule, ((Specifier)classDef.baseSpecs->first).name);
5089          for(def = classDef.definitions->first; def; def = def.next)
5090          {
5091             if(def.type == functionClassDef && def.function.declarator)
5092             {
5093                Method vMethod = eClass_FindMethod(baseClass, def.function.declarator.symbol.string, this.privateModule);
5094                if(!vMethod)
5095                   vMethod = eClass_FindMethod(this.selected.instance._class, def.function.declarator.symbol.string, this.privateModule);
5096                if(!vMethod)
5097                {
5098                   Type type = def.function.declarator.symbol.type;
5099                   if(CheckCompatibleMethod(method, type, regClass, this.selected == this.oClass, FindClass(this.selected.instance._class.name)))
5100                   {
5101                      compatible.Add(OldLink { data = def.function });
5102                   }
5103                }
5104             }
5105          }
5106
5107          if(this.oClass && this.oClass.instance)
5108          {
5109             classSym.registered = regClass;
5110             //classSym.registered = this.oClass.oClass;
5111
5112             for(_class = regClass.base; _class; _class = _class.base)
5113             {
5114                Method testMethod;
5115                for(testMethod = (Method)_class.methods.first; testMethod; testMethod = (Method)((BTNode)testMethod).next)
5116                {
5117                   // TODO: Understand why these functions popup in attach list
5118                   if(testMethod.type != virtualMethod /*&& testMethod.function != Window_OnGetString && testMethod.function != Window_OnGetDataFromString*/)
5119                   {
5120                      if(!testMethod.dataType)
5121                         testMethod.dataType = ProcessTypeString(testMethod.dataTypeString, false);
5122                         
5123                      //if(CheckCompatibleMethod(method, testMethod.dataType, &regClass, false, selectedClass)) // this.selected == this.oClass, selectedClass))
5124                      if(CheckCompatibleMethod(method, testMethod.dataType, this.oClass.instance._class, false, selectedClass)) // this.selected == this.oClass, selectedClass))
5125                      //if(CheckCompatibleMethod(method, testMethod.dataType, &regClass, this.selected == this.oClass, FindClass(this.oClass.oClass.name)))
5126                      {
5127                         // TODO: Fix memory leak, Figure out if it should be ClassFunction or FunctionDefinition
5128                         // ClassFunction function { };
5129                         FunctionDefinition function { };
5130
5131                         function.declarator = Declarator { };
5132                         function.declarator.symbol = Symbol { string = CopyString(testMethod.name) };
5133                         excludedSymbols.Add(function.declarator.symbol);
5134
5135                         compatible.Add(OldLink { data = function });
5136                      }
5137                   }
5138                }
5139             }
5140          }
5141          delete regClass;
5142          delete classSym;
5143       }
5144    }
5145
5146    void AddMethod(Method method)
5147    {
5148       if(method)
5149       {
5150          char methodName[1024];
5151          strcpy(methodName, method.name);
5152          if(!FindMethod(methodName, null, null))
5153          {
5154             methodAction = actionAddMethod;
5155             this.method = method;
5156             ModifyCode();
5157          }
5158          UpdateFormCode();         
5159          GoToMethod(methodName);
5160       }
5161    }
5162
5163    void DeleteMethod(ClassFunction function)
5164    {
5165       if(function)
5166       {
5167          methodAction = actionDeleteMethod;
5168          this.function = function;
5169          ModifyCode();
5170          UpdateFormCode(); 
5171
5172          Update(null);
5173       }
5174    }
5175
5176    void AttachMethod(Method method, ClassFunction function)
5177    {
5178       if(function)
5179       {
5180          // If it's an instance we'll ask if we want to move it inside...
5181          if(!function.attached.count && function.body)
5182          {
5183             // Find the function in the _class to check if it's a virtual function
5184             Class regClass = eSystem_FindClass(this.privateModule, ((Specifier)this.oClass.classDefinition.baseSpecs->first).name);
5185             Method method = eClass_FindMethod(regClass, function.declarator.symbol.string, this.privateModule);
5186             /*    LATER we'll need to check for public/virtual properties etc, for now only checked if virtual in base _class
5187             ClassDef def;
5188             for(def = this.classDefinition.first; def; def = def.next)
5189             {
5190                if(def.type == functionClassDef)
5191                {
5192                   if(def.function == function)
5193                      break;
5194                }
5195             }
5196             */
5197             if(!method || method.type != virtualMethod)
5198             {
5199                char title[1024];
5200                sprintf(title, $"Attach %s", function.declarator.symbol.string);
5201                if(MessageBox { type = yesNo, master = parent, text = title, contents = $"Method is unused. Move method inside instance?"}.Modal() == yes)
5202                {
5203                   moveAttached = true;
5204                }
5205             }
5206          }
5207
5208          methodAction = actionAttachMethod;
5209          this.method = method;
5210          this.function = function;
5211          ModifyCode();
5212          UpdateFormCode(); 
5213          Update(null);
5214       }
5215    }
5216
5217    void ReAttachMethod(Method method, ClassFunction function)
5218    {
5219       if(function)
5220       {
5221          // If it's an instance we'll ask if we want to move it inside...
5222          if(!function.attached.count && function.body)
5223          {
5224             // Find the function in the _class to check if it's a virtual function
5225             Class regClass = eSystem_FindClass(this.privateModule, ((Specifier)this.oClass.classDefinition.baseSpecs->first).name);
5226             Method method = eClass_FindMethod(regClass, function.declarator.symbol.string, this.privateModule);
5227             /*    LATER we'll need to check for public/virtual properties etc, for now only checked if virtual in base _class
5228             ClassDef def;
5229             for(def = this.classDefinition.first; def; def = def.next)
5230             {
5231                if(def.type == functionClassDef)
5232                {
5233                   if(def.function == function)
5234                      break;
5235                }
5236             }
5237             */
5238             if(!method || method.type != virtualMethod)
5239             {
5240                char title[1024];
5241                sprintf(title, $"Attach %s", function.declarator.symbol.string);
5242                if(MessageBox { type = yesNo, master = parent, text = title, 
5243                   contents = $"Method is unused. Move method inside instance?" }.Modal() == yes)
5244                {
5245                   moveAttached = true;
5246                }
5247             }
5248          }
5249
5250          methodAction = actionReattachMethod;
5251          this.method = method;
5252          this.function = function;
5253          ModifyCode();
5254          UpdateFormCode(); 
5255          Update(null);
5256       }
5257    }
5258
5259    void DetachMethod(Method method, ClassFunction function, int type)
5260    {
5261       bool result = true;
5262
5263       if(type == 1)
5264       {
5265          Window dialog
5266          {
5267             hasClose = true, borderStyle = sizable, minClientSize = { 300, 55 }, 
5268             master = sheet, text = $"Name detached method", background = formColor
5269          };
5270          Button cancelButton
5271          {
5272             dialog, anchor = { horz = 45, top = 30 }, size = { 80 }, text = $"Cancel", hotKey = escape,
5273             id = DialogResult::cancel, NotifyClicked = ButtonCloseDialog
5274          };
5275          Button okButton
5276          {
5277             dialog, anchor = { horz = -45, top = 30 }, size = { 80 }, text = $"OK", isDefault = true,
5278             id = DialogResult::ok, NotifyClicked = ButtonCloseDialog
5279          };
5280          EditBox nameBox
5281          {
5282             dialog, anchor = { left = 5, right = 5, top = 5 }
5283          };
5284          sprintf(methodName, "%s_%s", selected.name, method.name);
5285          nameBox.contents = methodName;
5286          incref nameBox;
5287          result = dialog.Modal() == ok;
5288          strcpy(methodName, nameBox.contents);
5289          delete nameBox;
5290       }
5291       if(result)
5292       {
5293          // If the method is not attached, move it outside
5294          if(type == 1)
5295          {
5296             // Add this class to the methodName
5297             char name[1024] = "";
5298
5299             if(this.selected != this.oClass && !method.dataType.thisClass)
5300             {
5301                strcat(name, this.selected.instance._class.name);
5302                strcat(name, "::");
5303                strcat(name, this.methodName);
5304                strcpy(this.methodName, name);
5305             }
5306             else if(method.dataType.thisClass && (this.selected == this.oClass || !eClass_IsDerived(this.oClass.instance._class, method.dataType.thisClass.registered)))
5307             {
5308                strcat(name, method.dataType.thisClass.string);
5309                strcat(name, "::");
5310                strcat(name, this.methodName);
5311                strcpy(this.methodName, name);
5312             }
5313             
5314             this.moveAttached = true;
5315          }
5316
5317          this.methodAction = actionDetachMethod;
5318          this.method = method;
5319          this.function = function;
5320          ModifyCode();
5321          UpdateFormCode(); 
5322          Update(null);
5323       }
5324    }
5325
5326    void AddObject(Instance instance, ObjectInfo * object)
5327    {
5328       int id;
5329       incref instance;
5330       //*object = _class.instances.Add(sizeof(ObjectInfo));
5331       *object = ObjectInfo { };
5332       oClass.instances.Insert((selected.oClass == selected) ? null : selected, *object);
5333       (*object).oClass = oClass;
5334       (*object).instance = instance;
5335       for(id = 1;; id++)
5336       {
5337          char name[1024];
5338          ObjectInfo check;
5339          sprintf(name, "%c%s%d", tolower(instance._class.name[0]), instance._class.name+1, id);
5340
5341          // if(strcmp(name, this.oClass.instance.name)) 
5342          
5343          {
5344             for(check = oClass.instances.first; check; check = check.next)
5345                if(!check.deleted && check.name && !strcmp(name, check.name)) 
5346                   break;
5347             if(!check)
5348             {
5349                (*object).name = CopyString(name);
5350                break;
5351             }
5352          }
5353       }            
5354       toolBox.controlClass = null;
5355
5356       ModifyCode();
5357
5358       //sheet.AddObject(*object, (*object).name, TypeData, true);
5359
5360       selected = *object;
5361    }
5362
5363    void EnsureUpToDate()
5364    {
5365       if(sheet && codeModified && parsing)
5366          ParseCode();
5367    }
5368
5369    void SelectObject(ObjectInfo object)
5370    {
5371       selected = object;
5372       oClass = object ? object.oClass : null;
5373       if(designer)
5374          designer.SelectObject(object, object ? object.instance : null);
5375    }
5376
5377    void SelectObjectFromDesigner(ObjectInfo object)
5378    {
5379       selected = object;
5380       sheet.SelectObject(object);
5381    }
5382
5383    void EnumerateObjects(Sheet sheet)
5384    {
5385       ObjectInfo oClass;
5386
5387       for(oClass = classes.first; oClass; oClass = oClass.next)
5388       {
5389          if(oClass.instance)
5390          {
5391             ObjectInfo object;
5392
5393             sheet.AddObject(oClass, oClass.name ? oClass.name : oClass.instance._class.name, typeClass, false);
5394             for(object = oClass.instances.first; object; object = object.next)
5395                sheet.AddObject(object, object.name ? object.name : object.instance._class.name, typeData, false);
5396          }
5397       }
5398       sheet.SelectObject(selected);
5399    }
5400
5401    void AddControl()
5402    {
5403       designer.AddObject();
5404    }
5405
5406    void DeleteObject(ObjectInfo object)
5407    {
5408       delete object.instance;
5409       object.deleted = true;
5410       object.modified = true;
5411       object.oClass.modified = true;
5412
5413       if(selected == object)
5414       {
5415          bool looped = false;
5416          ObjectInfo select = object;
5417
5418          for(;;)
5419          {            
5420             select = select.prev;
5421             if(!select) 
5422             {
5423                if(looped) break;
5424                select = object.oClass.instances.last;
5425                if(!select) break;
5426                looped = true;
5427             }
5428             if(!select.deleted)
5429                break;
5430          }
5431          sheet.SelectObject(select ? select : oClass);
5432       }
5433
5434       if(!object.instCode && object.oClass != object)
5435       {
5436          delete object.name;
5437          oClass.instances.Delete(object);
5438       }
5439
5440       if(sheet.codeEditor == this)
5441          sheet.DeleteObject(object);
5442    }
5443
5444    void RenameObject(ObjectInfo object, char * name)
5445    {
5446       bool valid = false;
5447
5448       // Validate the name:
5449       if(object != oClass && (!name || !name[0])) valid = true;   // What's this one again?
5450       else if(name[0] && (isalpha(name[0]) || name[0] == '_'))
5451       {
5452          int c;
5453          for(c = 0; name[c]; c++)
5454             if(!isalnum(name[c]) && name[c] != '_' && name[c] != '_')
5455                break;
5456          if(!name[c])
5457             valid = true;
5458       }
5459       if(valid)
5460       {
5461          delete object.name;
5462          object.name = (name && name[0]) ? CopyString(name) : null;
5463
5464          sheet.RenameObject(object, object.name ? object.name : object.instance._class.name);
5465       }
5466    }
5467
5468    void DesignerModifiedObject()
5469    {
5470       sheet.ListProperties(false);
5471       sheet.Update(null);
5472    }
5473
5474    void ListSubMembers(Type member)
5475    {
5476       Type subMember;
5477
5478       for(subMember = member.members.first; subMember; subMember = subMember.next)
5479       {
5480          if(subMember.name)
5481          {
5482             DataRow row = membersList.AddString(subMember.name);
5483             row.icon = icons[typeData];
5484          }
5485          else
5486          {
5487             ListSubMembers(subMember);
5488          }
5489       }
5490    }
5491
5492    void ListSubDataMembers(DataMember member, bool isPrivate)
5493    {
5494       DataMember subMember;
5495       for(subMember = member.members.first; subMember; subMember = subMember.next)
5496       {
5497          if((subMember.memberAccess == publicAccess && !isPrivate) || subMember._class.module == privateModule)
5498          {
5499             if(subMember.name)
5500             {
5501                DataRow row = membersList.AddString(subMember.name);
5502                BitmapResource bitmap = null;
5503                if(!subMember.dataType)
5504                   subMember.dataType = ProcessTypeString(subMember.dataTypeString, false);
5505             
5506                if(subMember.dataType && subMember.dataType.kind == classType && subMember.dataType._class)
5507                {
5508                   char * bitmapName = (char *)eClass_GetProperty(subMember.dataType._class.registered, "icon");
5509                   if(bitmapName)
5510                   {
5511                      bitmap = { bitmapName };
5512                      membersList.AddResource(bitmap);
5513                   }
5514                }
5515                row.icon = bitmap ? bitmap : icons[(subMember.memberAccess == publicAccess && !isPrivate) ? typeData : typeDataPrivate];
5516             }
5517             else
5518             {
5519                ListSubDataMembers(subMember, isPrivate || member.memberAccess == privateAccess);
5520             }
5521          }
5522       }
5523    }
5524
5525    void ListClassMembers(Class whatClass, bool methodsOnly)
5526    {
5527       Class _class;
5528       Class baseClass = eSystem_FindClass(this.privateModule, "class");
5529       bool isPrivate = false;
5530
5531       for(_class = whatClass; _class && _class.type != systemClass; _class = _class.base)
5532       {
5533          Method method, methodIt;
5534          DataMember member;
5535          DataMember memberIt;
5536
5537          for(methodIt = (Method)_class.methods.first; methodIt; methodIt = (Method)((BTNode)methodIt).next)
5538          {
5539             method = eClass_FindMethod(whatClass, methodIt.name, privateModule);
5540             if(methodIt.memberAccess == privateAccess && method && method.memberAccess == publicAccess)
5541                method = methodIt;
5542             if(method && method._class.type != systemClass && !eClass_FindMethod(baseClass, method.name, this.privateModule))
5543             {
5544                if(method.memberAccess == publicAccess || method._class.module == privateModule)
5545                {
5546                   DataRow row = membersList.FindString(method.name);
5547                   if(!row)
5548                   {
5549                      row = membersList.AddString(method.name);
5550
5551                      if(!method.dataType)
5552                         method.dataType = ProcessTypeString(method.dataTypeString, false);
5553
5554                      row.icon = icons[(method.type == virtualMethod && method.dataType && method.dataType.thisClass) ? typeEvent : ((method.memberAccess == publicAccess && !isPrivate) ? typeMethod : typeMethodPrivate)];
5555                   }
5556                }
5557             }
5558          }
5559
5560          if(!methodsOnly)
5561          {
5562             for(memberIt = _class.membersAndProperties.first; memberIt; memberIt = memberIt.next)
5563             {
5564                if(memberIt.name)
5565                {
5566                   if(memberIt.isProperty)
5567                   {
5568                      member = (DataMember)eClass_FindProperty(whatClass, memberIt.name, privateModule);
5569                      if(!member)
5570                         member = eClass_FindDataMember(whatClass, memberIt.name, privateModule, null, null);
5571                   }
5572                   else
5573                   {
5574                      member = eClass_FindDataMember(whatClass, memberIt.name, privateModule, null, null);
5575                      if(!member)
5576                         member = (DataMember)eClass_FindProperty(whatClass, memberIt.name, privateModule);
5577                   }
5578
5579                   if(memberIt.memberAccess == privateAccess && member && member.memberAccess == publicAccess)
5580                      member = memberIt;
5581                }
5582                else
5583                   member = memberIt;
5584
5585                if(member && (member.memberAccess == publicAccess || member._class.module == privateModule))
5586                {
5587                   if(member.isProperty)
5588                   {
5589                      Property prop = (Property) member;
5590                      if(!membersList.FindString(prop.name))
5591                      {
5592                         DataRow row = membersList.AddString(prop.name);
5593                         row.icon = icons[(member.memberAccess == publicAccess && !isPrivate) ? typeProperty : typePropertyPrivate];
5594                      }
5595                   }
5596                   else if(member.name && !membersList.FindString(member.name))
5597                   {
5598                      DataRow row = membersList.AddString(member.name);
5599                
5600                      BitmapResource bitmap = null;
5601                      if(!member.dataType)
5602                         member.dataType = ProcessTypeString(member.dataTypeString, false);
5603                
5604                      if(member.dataType && member.dataType.kind == classType && member.dataType._class)
5605                      {
5606                         char * bitmapName = (char *)eClass_GetProperty(member.dataType._class.registered, "icon");
5607                         if(bitmapName)
5608                         {
5609                            bitmap = { bitmapName };
5610                            membersList.AddResource(bitmap);
5611                         }
5612                      }
5613                      row.icon = bitmap ? bitmap : icons[(member.memberAccess == publicAccess && !isPrivate) ? typeData : typeDataPrivate];
5614                   }
5615                   else
5616                      ListSubDataMembers(member, member.memberAccess == privateAccess);
5617                }
5618             }
5619          }
5620          if(_class.inheritanceAccess == privateAccess)
5621          {
5622             isPrivate = true;
5623             if(_class.module != privateModule) break;
5624          }
5625       }
5626    }
5627
5628    void ListClassMembersMatch(Class whatClass, Type methodType)
5629    {
5630       Class _class;
5631       Class baseClass = eSystem_FindClass(this.privateModule, "class");
5632       bool isPrivate = false;
5633
5634       for(_class = whatClass; _class && _class.type != systemClass; _class = _class.base)
5635       {
5636          Method method;
5637          Property prop;
5638          DataMember member;
5639
5640          for(method = (Method)_class.methods.first; method; method = (Method)((BTNode)method).next)
5641          {
5642             if(method.memberAccess == publicAccess || method._class.module == privateModule)
5643             {
5644                if(method._class.type != systemClass && !eClass_FindMethod(baseClass, method.name, this.privateModule))
5645                {
5646                   if(!method.dataType)
5647                      method.dataType = ProcessTypeString(method.dataTypeString, false);
5648
5649                   if(MatchTypes(method.dataType, methodType, null, whatClass, /*null, */whatClass, false, true, false, false))
5650                   {
5651                      DataRow row = membersList.FindString(method.name);
5652                      if(!row)
5653                      {
5654                         row = membersList.AddString(method.name);
5655                         row.icon = icons[(method.type == virtualMethod && method.dataType.thisClass) ? typeEvent : ((method.memberAccess == publicAccess && !isPrivate) ? typeMethod : typeMethodPrivate)];
5656                      }
5657                   }
5658                }
5659             }
5660          }
5661          if(_class.inheritanceAccess == privateAccess)
5662          {
5663             isPrivate = true;
5664             if(_class.module != privateModule) break;
5665          }
5666       }
5667    }
5668
5669    void ListClassPropertiesAndVirtual(Class whatClass, String curString)
5670    {
5671       Class _class;
5672       bool isPrivate = false;
5673       for(_class = whatClass; _class /*&& _class.type != systemClass*/; _class = _class.base)
5674       {
5675          Method method;
5676          Property prop;
5677          DataMember member;
5678
5679          for(method = (Method)_class.methods.first; method; method = (Method)((BTNode)method).next)
5680          {
5681             if(method.type == virtualMethod)
5682             {
5683                if(method.memberAccess == publicAccess || method._class.module == privateModule)
5684                {
5685                   DataRow row = membersList.FindString(method.name);
5686                   if(!row)
5687                   {
5688                      row = membersList.AddString(method.name);
5689
5690                      if(!method.dataType)
5691                         method.dataType = ProcessTypeString(method.dataTypeString, false);
5692
5693                      row.icon = icons[method.dataType.thisClass ? typeEvent : ((method.memberAccess == publicAccess && !isPrivate) ? typeMethod : typeMethodPrivate)];
5694                   }
5695                }
5696             }
5697          }
5698
5699          for(member = _class.membersAndProperties.first; member; member = member.next)
5700          {
5701             if(member.memberAccess == publicAccess || member._class.module == privateModule)
5702             {
5703                if(member.isProperty)
5704                {
5705                   Property prop = (Property)member;
5706                   {
5707                      DataRow row = membersList.AddString(prop.name);
5708                      row.icon = icons[(member.memberAccess == publicAccess && !isPrivate) ? typeProperty : typePropertyPrivate];
5709                   }
5710                }
5711                else if(member.name && (!curString || strcmp(curString, member.name)))
5712                {
5713                   DataRow row = membersList.AddString(member.name);
5714                
5715                   BitmapResource bitmap = null;
5716                   if(!member.dataType)
5717                      member.dataType = ProcessTypeString(member.dataTypeString, false);
5718                
5719                   if(member.dataType && member.dataType.kind == classType && member.dataType._class)
5720                   {
5721                      char * bitmapName = (char *)eClass_GetProperty(member.dataType._class.registered, "icon");
5722                      if(bitmapName)
5723                      {
5724                         bitmap = { bitmapName };
5725                         membersList.AddResource(bitmap);
5726                      }
5727                   }
5728                   row.icon = bitmap ? bitmap : icons[(member.memberAccess == publicAccess && !isPrivate) ? typeData : typeDataPrivate];
5729                }
5730                else
5731                   ListSubDataMembers(member, member.memberAccess == privateAccess || isPrivate);
5732             }
5733          }
5734          if(_class.inheritanceAccess == privateAccess)
5735          {
5736             isPrivate = true;
5737             if(_class.module != privateModule) break;
5738          }
5739       }
5740    }
5741
5742    void ListMembers(Type type)
5743    {
5744       if(type && (type.kind == classType || type.kind == structType || type.kind == unionType))
5745       {
5746          Class _class;
5747          
5748          if(type.kind == classType)
5749          {
5750             if(type._class)
5751                ListClassMembers(type._class.registered, false);
5752          }
5753          else
5754          {
5755             Type member;
5756             for(member = type.members.first; member; member = member.next)
5757             {
5758                if(member.name)
5759                {
5760                   DataRow row = membersList.AddString(member.name);
5761                   row.icon = icons[typeData];
5762                }
5763                else if(member.kind == structType || member.kind == unionType)
5764                   ListSubMembers(member);
5765             }
5766          }
5767       }
5768    }
5769
5770    void ListModule(Module mainModule, int recurse, bool listClasses)
5771    {
5772       Module module;
5773       ListNameSpace(mainModule.application.systemNameSpace, 1, listClasses);
5774       ListNameSpace(mainModule.application.privateNameSpace, 1, listClasses);
5775       ListNameSpace(mainModule.application.publicNameSpace, 1, listClasses);
5776       for(module = mainModule.application.allModules.first; module; module = module.next)
5777       {
5778          if(ModuleVisibility(mainModule, module))
5779             ListNameSpace(module.publicNameSpace, recurse, listClasses);
5780       }
5781    }
5782
5783    void ListNameSpace(NameSpace nameSpace, int recurse, bool listClasses)
5784    {
5785       NameSpace * ns;
5786       BTNamedLink link;
5787
5788       if(listClasses)
5789       {
5790          for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
5791          {
5792             Class _class = link.data;
5793             if(_class.type != systemClass)
5794             {
5795                DataRow row = membersList.AddString(_class.name);
5796                row.icon = (_class.type == unitClass || _class.type == enumClass) ? icons[typeDataType] : icons[typeClass];
5797             }
5798          }
5799       }
5800
5801       for(link = (BTNamedLink)nameSpace.defines.first; link; link = (BTNamedLink)((BTNode)link).next )
5802       {
5803          DefinedExpression definedExp = link.data;
5804          DataRow row = membersList.AddString(link /*definedExp*/.name);
5805          row.icon = icons[typeData];
5806       }
5807
5808       for(link = (BTNamedLink)nameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
5809       {
5810          GlobalFunction function = link.data;
5811          DataRow row = membersList.AddString(link /*function*/.name);
5812          row.icon = icons[typeMethod];
5813       }
5814
5815
5816       for(ns = (NameSpace *)nameSpace.nameSpaces.first; ns; ns = (NameSpace *)((BTNode)ns).next)
5817       {
5818          if(recurse != 2 && listClasses)
5819          {
5820             if(!membersList.FindString(ns->name))
5821             {
5822                DataRow row = membersList.AddString(ns->name);
5823                row.icon = icons[typeNameSpace];
5824             }
5825          }
5826
5827          if(recurse)
5828             ListNameSpace(ns, 2, listClasses);
5829       }
5830    }
5831
5832    void ListEnumValues(Class _class)
5833    {
5834       List<Class> classes { };
5835       for(; _class && _class.type == enumClass; _class = _class.base)
5836          classes.Insert(null, _class);
5837       for(_class : classes)
5838       {
5839          EnumClassData enumeration = (EnumClassData)_class.data;
5840          NamedLink item;
5841          for(item = enumeration.values.first; item; item = item.next)
5842          {
5843             DataRow row = membersList.AddString(item.name);
5844             row.icon = icons[typeEnumValue];
5845          }
5846       }
5847       delete classes;
5848    }
5849
5850    bool ListEnumsModule(Module mainModule, Type dest)
5851    {
5852       bool result = false;
5853       Module module;
5854       result |= ListEnums(mainModule.application.systemNameSpace, dest);
5855       result |= ListEnums(mainModule.application.privateNameSpace, dest);
5856       result |= ListEnums(mainModule.application.publicNameSpace, dest);
5857       for(module = mainModule.application.allModules.first; module; module = module.next)
5858       {
5859          if(ModuleVisibility(mainModule, module))
5860             result |= ListEnums(module.publicNameSpace, dest);
5861       }
5862       return result;
5863    }
5864
5865    void ListNameSpaceByString(Module mainModule, char * string)
5866    {
5867       NameSpace * nameSpace;
5868       Module module;
5869       nameSpace = FindNameSpace(mainModule.application.systemNameSpace, string);
5870       if(nameSpace) ListNameSpace(nameSpace, 0, true);
5871       nameSpace = FindNameSpace(mainModule.application.privateNameSpace, string);
5872       if(nameSpace) ListNameSpace(nameSpace, 0, true);
5873       nameSpace = FindNameSpace(mainModule.application.publicNameSpace, string);
5874       if(nameSpace) ListNameSpace(nameSpace, 0, true);
5875       for(module = mainModule.application.allModules.first; module; module = module.next)
5876       {
5877          if(ModuleVisibility(mainModule, module))
5878          {
5879             nameSpace = FindNameSpace(module.publicNameSpace, string);
5880             if(nameSpace) ListNameSpace(nameSpace, 0, true);
5881          }
5882       }
5883    }
5884
5885    bool ListEnums(NameSpace nameSpace, Type dest)
5886    {
5887       BTNamedLink link;
5888       bool result = false;
5889
5890       for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
5891       {
5892          Class _class = link.data;
5893          if(_class.type == enumClass && (dest.kind != classType || !dest._class || dest._class.registered != _class))
5894          {
5895             OldList conversions { };
5896             Type type { };
5897             type.kind = classType;
5898             type._class = FindClass(_class.name);
5899             if(MatchTypes(type, dest, &conversions, null, null, true, false, false, false))
5900             {
5901                ListEnumValues(_class);
5902                result = true;
5903             }
5904             conversions.Free(null);
5905             delete type;
5906          }
5907       }
5908       for(nameSpace = (NameSpace *)nameSpace.nameSpaces.first; nameSpace != null; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
5909       {
5910          result |= ListEnums(nameSpace, dest);
5911       }
5912       return result;
5913    }
5914
5915    NameSpace * FindNameSpace(NameSpace nameSpace, char * name)
5916    {
5917       int start = 0, c;
5918       char ch;
5919       for(c = 0; (ch = name[c]); c++)
5920       {
5921          if(ch == '.' || (ch == ':' && name[c+1] == ':'))
5922          {
5923             NameSpace * newSpace;
5924             char * spaceName = new char[c - start + 1];
5925             memcpy(spaceName, name + start, c - start);
5926             spaceName[c-start] = '\0';
5927             newSpace = (NameSpace *)nameSpace.nameSpaces.FindString(spaceName);
5928             delete spaceName;
5929             if(!newSpace)
5930                return null;
5931             nameSpace = newSpace;
5932             if(ch == ':') c++;
5933             start = c+1;
5934          }
5935       }
5936       if(c - start)
5937       {
5938          // name + start;
5939       }
5940       return (NameSpace *)nameSpace;
5941    }
5942
5943    void ListSymbols(Expression exp, bool enumOnly, char * string, Identifier realIdentifier)
5944    {
5945       bool listedEnums = false;
5946       Type destType = (exp && exp.destType && !exp.destType.truth) ? exp.destType : null;
5947       bool listClasses = true;
5948
5949       if(exp && (exp.type == identifierExp || exp.type == memberExp))
5950       {
5951          // TOCHECK: This memberExp check wasn't here... Some stuff isn't quite done
5952          Identifier id = (exp.type == memberExp) ? exp.member.member : exp.identifier;
5953          char * colons = id ? RSearchString(id.string, "::", strlen(id.string), true, false) : null;
5954
5955          if(exp.type == identifierExp)
5956             id = realIdentifier;
5957
5958          if(id && id._class && !id._class.name)
5959          {
5960             listClasses = false;
5961             SetThisClass(null);
5962          }
5963          else if(id && id._class && id._class.name)
5964          {
5965             if(id.classSym)
5966             {
5967                Class _class = id.classSym.registered;
5968                if(_class && _class.type == enumClass)
5969                {
5970                   ListEnumValues(_class);
5971                }
5972                else
5973                   ListClassMembers(id.classSym.registered, true);
5974                return;
5975             }
5976             return;
5977          }
5978          else if(id && colons)
5979          {
5980             ListNameSpaceByString(this.privateModule, id.string);
5981             return;
5982          }
5983       }
5984
5985       if(this.privateModule && destType && (destType.kind != pointerType || destType.type.kind != voidType) && destType.kind != ellipsisType)
5986       {
5987          listedEnums = ListEnumsModule(this.privateModule, destType);
5988       }
5989
5990       if(destType && destType.kind == classType && destType._class.registered && destType._class.registered.type == enumClass)
5991       {
5992          ListEnumValues(destType._class.registered);
5993
5994          if(insideClass)
5995             ListClassPropertiesAndVirtual(insideClass, null);
5996
5997          listedEnums = true;
5998       }
5999       else if(destType && destType.kind == enumType)
6000       {
6001          NamedLink value;
6002
6003          for(value = destType.members.first; value; value = value.next)
6004          {
6005             DataRow row = membersList.AddString(value.name);
6006             row.icon = icons[typeEnumValue];
6007          }
6008
6009          if(insideClass)
6010             ListClassPropertiesAndVirtual(insideClass, null);
6011
6012          listedEnums = true;
6013       }
6014       else if(insideClass && !enumOnly)
6015       {
6016          ListClassPropertiesAndVirtual(insideClass, string);
6017       }
6018
6019       if(listedEnums && string && string[0])
6020       {
6021          DataRow row = membersList.FindSubString(string);
6022          if(!row)
6023             listedEnums = false;      
6024       }
6025       
6026       if(!insideClass && exp && exp.destType && exp.destType.kind == functionType && GetThisClass())
6027       {
6028          ListClassMembersMatch(GetThisClass(), exp.destType);
6029       }
6030       else if(!insideClass && !enumOnly && !listedEnums)
6031       {
6032          Context ctx;
6033          Symbol symbol = null;
6034          {
6035             if(GetThisClass())
6036             { 
6037                ListClassMembers(GetThisClass(), false);
6038             }
6039
6040             for(ctx = listClasses ? GetCurrentContext() : GetTopContext(); ctx != GetTopContext().parent && !symbol; ctx = ctx.parent)
6041             {
6042                for(symbol = (Symbol)ctx.symbols.first; symbol; symbol = (Symbol)((BTNode)symbol).next)
6043                {
6044                   // Don't list enum values?
6045                   //if(symbol.type.kind != TypeEnum)
6046                   DataRow row = membersList.FindString(symbol.string);
6047                   if(!row)
6048                   {
6049                      if(GetBuildingEcereComModule() && symbol.type && symbol.type.kind == functionType && eSystem_FindFunction(privateModule, symbol.string))
6050                         continue;
6051                      row = membersList.AddString(symbol.string);
6052                      if(symbol.type && symbol.type.kind == functionType)
6053                         row.icon = icons[typeMethod];
6054                      else if(symbol.type && symbol.type.kind == enumType)
6055                      {
6056                         row.icon = icons[typeEnumValue];
6057                      }
6058                      else 
6059                      {
6060                         BitmapResource bitmap = null;
6061                         if(symbol.type && symbol.type.kind == classType && symbol.type._class && symbol.type._class)
6062                         {
6063                            char * bitmapName = (char *)eClass_GetProperty(symbol.type._class.registered, "icon");
6064                            if(bitmapName)
6065                            {
6066                               bitmap = { bitmapName };
6067                               membersList.AddResource(bitmap);
6068                            }
6069                         }
6070                         row.icon = bitmap ? bitmap : icons[typeData];
6071                      }
6072                   }
6073                }
6074
6075                if(listClasses)
6076                {
6077                   for(symbol = (Symbol)ctx.types.first; symbol; symbol = (Symbol)((BTNode)symbol).next)
6078                   {
6079                      DataRow row = membersList.FindString(symbol.string);
6080                      if(!row)
6081                      {
6082                         row = membersList.AddString(symbol.string);
6083                         if(symbol.type.kind == functionType)
6084                            row.icon = icons[typeMethod];
6085                         else if(symbol.type.kind == classType && (!symbol.type._class.registered || (symbol.type._class.registered.type != unitClass && symbol.type._class.registered.type != enumClass)))
6086                         {
6087                            row.icon = icons[typeClass];
6088                         }
6089                         else
6090                         {
6091                            row.icon = icons[typeDataType];
6092                         }
6093                      }
6094                   }
6095                }
6096             }
6097
6098             ListModule(this.privateModule, 1, listClasses);
6099             // TODO: Implement this with name space
6100             /*
6101             {
6102                GlobalData data;
6103                for(data = globalData.first; data; data = data.next)
6104                {
6105                   DataRow row = membersList.FindString(data.name);
6106                   if(!data.dataType)
6107                      data.dataType = ProcessTypeString(data.dataTypeString, false);
6108                   if(!row)
6109                   {
6110                      row = membersList.AddString(data.name);
6111
6112                      if(data.dataType && data.dataType.kind == TypeEnum)
6113                      {
6114                         row.icon = icons[typeEnumValue];
6115                      }
6116                      else 
6117                      {
6118                         BitmapResource bitmap = null;
6119                         if(data.dataType && data.dataType.kind == classType && data.dataType._class && data.dataType._class)
6120                         {
6121                            char * bitmapName = (char *)eClass_GetProperty(data.dataType._class.registered, "icon");
6122                            if(bitmapName)
6123                            {
6124                               bitmap = { bitmapName };
6125                               membersList.AddResource(bitmap);
6126                            }
6127                         }
6128                         row.icon = bitmap ? bitmap : icons[typeData];
6129                      }
6130                   }
6131                }
6132             }
6133             */
6134
6135             {
6136                DataRow row = membersList.AddString("Min");
6137                row.icon = icons[typeMethod];
6138
6139                row = membersList.AddString("Max");
6140                row.icon = icons[typeMethod];
6141
6142                row = membersList.AddString("Abs");
6143                row.icon = icons[typeMethod];
6144
6145                row = membersList.AddString("Sgn");
6146                row.icon = icons[typeMethod];
6147             }
6148          }
6149       }
6150    }
6151
6152    void OverrideVirtualFunction(ClassFunction function, Method method, Class _class, bool isInstance, bool extraIndent)
6153    {
6154       EditBoxStream f { editBox = editBox };
6155       uint position = 0;
6156       EditLine l1, l2;
6157       int x1,y1,x2,y2;
6158
6159       updatingCode = true;
6160
6161       if(!method.dataType)
6162          method.dataType = ProcessTypeString(method.dataTypeString, false);
6163
6164       DeleteJunkBefore(f, function.loc.start.pos, &position);
6165       f.DeleteBytes(function.loc.end.pos - function.loc.start.pos - 1);
6166
6167       // ADDING METHOD HERE
6168       {
6169          Type dataType = method.dataType;
6170          Type returnType = dataType.returnType;
6171          Type param;
6172          Class moduleClass = eSystem_FindClass(this.privateModule, "Module");
6173
6174          if(insideDef.prev)
6175              f.Printf("\n\n");
6176          else
6177             f.Printf("\n");
6178          if(extraIndent) f.Printf("   ");
6179          f.Printf("   ");
6180          OutputType(f, returnType, false);
6181
6182          f.Printf(" ");
6183          
6184          if(dataType.thisClass && !dataType.classObjectType && (!isInstance || !insideClass || !eClass_IsDerived(insideClass, dataType.thisClass.registered)))
6185          {
6186             if(dataType.thisClass.shortName)
6187                f.Printf(dataType.thisClass.shortName);
6188             else
6189                f.Printf(dataType.thisClass.string);
6190             f.Printf("::");
6191          }
6192          f.Printf(method.name);
6193          f.Printf("(");
6194          for(param = dataType.params.first; param; param = param.next)
6195          {
6196             // Decided not to write void...
6197             if(param.kind != voidType)
6198             {
6199                OutputType(f, param, true);
6200                if(param.next)
6201                   f.Printf(", ");
6202             }
6203          }
6204          f.Printf(")\n");                  
6205          if(extraIndent) f.Printf("   ");
6206          f.Printf("   %c\n", OpenBracket);
6207
6208          editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6209
6210          f.Printf("\n");
6211
6212          if(!_class || 
6213             (
6214                (isInstance ? _class : _class.base)._vTbl[method.vid] == moduleClass._vTbl[__ecereVMethodID___ecereNameSpace__ecere__com__Module_OnLoad] ||
6215                (isInstance ? _class : _class.base)._vTbl[method.vid] == DummyMethod)) // Temp Check for DefaultFunction
6216          {
6217             if(returnType && returnType.kind == classType && !strcmp(returnType._class.string, "bool"))
6218             {
6219                if(extraIndent) f.Printf("   ");
6220                f.Printf("      return true;\n");
6221             }
6222             else if(returnType && returnType.kind != voidType)
6223             {
6224                if(extraIndent) f.Printf("   ");
6225                f.Printf("      return 0;\n");
6226             }
6227          }
6228          else
6229          {
6230             if(extraIndent) f.Printf("   ");
6231             f.Printf("      ");
6232             if(returnType.kind != voidType)
6233                f.Printf("return ");
6234             f.Printf("%s::%s(", isInstance ? _class.name : _class.base.name, method.name);
6235             for(param = dataType.params.first; param; param = param.next)
6236             {
6237                if(param.prev) f.Printf(", ");
6238                if(param.kind != voidType)
6239                   f.Printf(param.name);
6240             }
6241             f.Printf(");\n");
6242          }
6243       }
6244
6245       if(extraIndent) f.Printf("   ");
6246       f.Printf("   %c", CloseBracket);
6247       // f.Printf("\n");
6248
6249       delete f;
6250
6251       if(extraIndent) { x1 += 3; x2 += 3; }
6252       editBox.SetSelPos(l1, y1, x1 + 6, l2, y2, x2 + 6);
6253
6254       this.updatingCode = false;
6255
6256    }
6257
6258    // Return false if we overrided a function and don't want to run params listing
6259    bool InvokeAutoComplete(bool enumOnly, int pointer, bool caretMove)
6260    {
6261       bool didOverride = false;
6262       EditLine line = editBox.line;
6263       char * text = line.text;
6264       int lineNum, charPos;
6265       Expression exp = null;
6266       EditLine l1, l2;
6267       int x1,y1, x2,y2;
6268       //Identifier id = null;
6269       Expression memberExp = null;
6270       Identifier realIdentifier = null;
6271
6272       if(!parsing) return true;
6273       if(!privateModule) return !didOverride;
6274
6275       insideFunction = null;
6276
6277       charPos = editBox.charPos + 1;
6278       if(!membersListShown)
6279       {
6280          EnsureUpToDate();
6281       }
6282
6283       editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6284       { 
6285          EditBoxStream f { editBox = editBox };
6286
6287          updatingCode = true;
6288          editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
6289          for(;;)
6290          {
6291             char ch;
6292             if(!f.Seek(-1, current))
6293                break;
6294             f.Getc(&ch);
6295             if(!isspace(ch)) break;
6296             f.Seek(-1, current);
6297          }
6298          editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6299
6300          lineNum = editBox.lineNumber + 1;
6301          charPos = editBox.charPos + 1;
6302          delete f;
6303          updatingCode = false;
6304       }
6305
6306       if(!membersListShown)
6307       {
6308          memberExp = FindExpTree(ast, lineNum, charPos);
6309          if(memberExp && (memberExp.type == TypeKind::memberExp || memberExp.type == pointerExp) && !memberExp.addedThis)
6310          {
6311          }
6312          else if(!pointer)
6313          {
6314             editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6315             { 
6316                EditBoxStream f { editBox = editBox };
6317                char ch = 0;
6318
6319                updatingCode = true;
6320
6321                editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
6322
6323                f.Getc(&ch);
6324                if(ch == '}' || ch == ',' || ch == ')')
6325                {
6326                   f.Seek(-1, current);
6327                   ch = ' ';
6328                }
6329                if(isspace(ch))
6330                {
6331                   for(;;)
6332                   {
6333                      char ch;
6334                      if(!f.Seek(-1, current))
6335                         break;
6336                      f.Getc(&ch);
6337                      if(!isspace(ch)) break;
6338                      f.Seek(-1, current);
6339                   }
6340                }
6341                else
6342                   f.Seek(-1, current);
6343
6344                editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6345
6346                lineNum = editBox.lineNumber + 1;
6347                charPos = editBox.charPos + 1;
6348                delete f;
6349                updatingCode = false;
6350             }
6351
6352             realIdentifier = FindCtxTree(ast, lineNum, charPos);
6353             exp = ctxInsideExp;
6354          }
6355       }
6356
6357       editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6358       lineNum = editBox.lineNumber + 1;
6359       charPos = editBox.charPos/* + 1*/;
6360
6361       {
6362          int rowCount;
6363          char tempString[1024];
6364          char * string = null;
6365          CodePosition idStart, idEnd;
6366
6367          if(membersListShown)
6368          {
6369             char * buffer = membersLine.text;
6370             int c;
6371             bool firstChar = true;
6372             int len = 0;
6373             string = tempString;
6374
6375             for(c = membersLoc.start.charPos; c<membersLoc.end.charPos; c++)
6376             {
6377                bool isSpace = (buffer[c] == ' ' || buffer[c] == '\t');
6378                if(!isSpace) firstChar = false;
6379                if(!firstChar)
6380                   string[len++] = buffer[c];
6381             }
6382             string[len] = 0;
6383          }
6384          else //if(realIdentifier)//if(id)
6385          {
6386             /*
6387             char * buffer = id.string;
6388             int c;
6389             bool firstChar = true;
6390             int len = 0;
6391             string = tempString;
6392             for(c = 0; c<= charPos - id.loc.start.charPos; c++)
6393             {
6394                bool isSpace = (buffer[c] == ' ' || buffer[c] == '\t');
6395                if(!isSpace) firstChar = false;
6396                if(!firstChar)
6397                   string[len++] = buffer[c];
6398             }
6399             string[len] = 0;
6400             */
6401             int x, y;
6402             int len = 0;
6403             EditLine editLine = editBox.line;
6404             bool firstChar = true;
6405             bool done = false;
6406
6407             string = tempString;
6408             for(y = lineNum-1; y >= 0; y--)
6409             {
6410                char * buffer = editLine.text;
6411                int lineCount = editLine.count;
6412                for(x = (y == lineNum-1) ? (Min(charPos, lineCount) - 1 ): lineCount-1; x >= 0; x--)
6413                {
6414                   bool isSpace = (buffer[x] == ' ' || buffer[x] == '\t');
6415                   if(!isSpace)
6416                   {
6417                      if(firstChar)
6418                      {
6419                         idEnd.charPos = x + 2;
6420                         idEnd.line = y + 1;
6421                      }
6422                      firstChar = false;
6423                   }
6424                   // TESTING THIS CODE HERE FOR NOT CONSIDERING bool when doing ctrl-space past it
6425                   else if(firstChar)
6426                   {
6427                      idEnd.charPos = x + 2;
6428                      idEnd.line = y + 1;
6429                      done = true;
6430                      break;
6431                   }
6432                   if(!firstChar)
6433                   {
6434                      if(!isalnum(buffer[x]) && buffer[x] != '_')
6435                      {
6436                         x++;
6437                         done = true;
6438                         break;
6439                      }
6440                      memmove(string+1, string, len++);
6441                      string[0] = buffer[x];
6442                   }
6443                }
6444
6445                //if(done || firstChar)
6446                if(done || !firstChar)
6447                   break;
6448                editLine = editLine.prev;
6449             }
6450             string[len] = 0;
6451             if(!strcmp(string, "case"))
6452             {
6453                idEnd.charPos += 4;
6454                x+=4;
6455                string[0] = '\0';
6456             }
6457             else if(!strcmp(string, "return"))
6458             {
6459                idEnd.charPos += 6;
6460                x+=6;
6461                string[0] = '\0';
6462             }
6463             else if(!strcmp(string, "delete"))
6464             {
6465                idEnd.charPos += 6;
6466                x+=6;
6467                string[0] = '\0';
6468             }
6469             else if(!strcmp(string, "new"))
6470             {
6471                idEnd.charPos += 3;
6472                x+=3;
6473                string[0] = '\0';
6474             }
6475             else if(!strcmp(string, "renew"))
6476             {
6477                idEnd.charPos +=5;
6478                x+=5;
6479                string[0] = '\0';
6480             }
6481             if(x < 0) x = 0;
6482
6483             idStart.charPos = x + 1;
6484             idStart.line = y + 1;
6485          }
6486
6487          if(!membersListShown)
6488          {
6489             membersList.Clear();
6490             if(memberExp && (memberExp.type == ExpressionType::memberExp || memberExp.type == pointerExp) && !memberExp.addedThis)
6491             {
6492                Type type = memberExp.member.exp.expType;
6493                if(pointer == 2 && type)
6494                {
6495                   if(type.kind == pointerType || type.kind == arrayType)
6496                      type = type.type;
6497                   /*else
6498                      type = null;*/
6499                }
6500                ListMembers(type);
6501             }
6502             else if(!pointer)
6503             {
6504                ListSymbols(exp, enumOnly, string, realIdentifier);
6505             }
6506             membersList.Sort(null, 1);
6507          }
6508
6509          if(insideFunction)
6510          {
6511             // Virtual function override
6512             Identifier id = GetDeclId(insideFunction.declarator);
6513             char * string = id ? id.string : null;
6514
6515             Method method = eClass_FindMethod(GetThisClass(), string, this.privateModule);
6516             if(method)
6517             {
6518                if(method.type != virtualMethod || (!insideInstance && method._class == GetThisClass()))
6519                   insideFunction = null;
6520                else
6521                {
6522                   OverrideVirtualFunction(insideFunction, method, GetThisClass(), insideInstance, insideInstance && insideClass);
6523                   didOverride = true;
6524                }
6525             }
6526          }
6527          if(!didOverride) //insideFunction)
6528          {
6529             rowCount = membersList.rowCount;
6530             if(rowCount)
6531             {
6532                DataRow row = string ? membersList.FindSubString(string) : null;
6533                if(row && !membersList.FindSubStringAfter(row, string) && !caretMove)
6534                {
6535                   char * newString = row.string;
6536                   if(!membersListShown)
6537                   {
6538                      membersLoc.start.line = idStart.line-1;
6539                      membersLoc.start.charPos = idStart.charPos-1;
6540                      //membersLoc.end = membersLoc.start;
6541                       membersLoc.end.charPos = idEnd.charPos-1;
6542                       membersLoc.end.line = idEnd.line-1;
6543                      //membersLoc.end.charPos = idStart.charPos + strlen(string)-1; //end.charPos-1;
6544                      //membersLoc.end.charPos = idStart.charPos + strlen(string)-1; //end.charPos-1;
6545                      membersLine = line;
6546                   }
6547                   else
6548                   {
6549                      membersList.Destroy(0);
6550                      membersListShown = false;
6551                   }
6552
6553                   editBox.GoToPosition(membersLine, membersLoc.start.line, membersLoc.start.charPos);
6554                   editBox.Delete(
6555                      line, membersLoc.start.line, membersLoc.start.charPos,
6556                      line, membersLoc.end.line, membersLoc.end.charPos);
6557                   editBox.PutS(newString);
6558                }
6559                else
6560                {
6561                   if(!row)
6562                   {
6563                      row = membersList.FindSubStringi(string);
6564                      if(row)
6565                         membersList.currentRow = row;
6566                      membersList.currentRow.selected = false;
6567                   }
6568                   else
6569                      membersList.currentRow = row;
6570
6571                   if(!membersListShown)
6572                   {
6573                      Point caret;
6574
6575                      // TESTING THESE ADDITIONS TO THE IF SO THAT CARET ISNT MOVED IF NOT ON TOP OF A WORD
6576                      if(string && string[0] && lineNum == idStart.line && charPos >= idStart.charPos-1 && charPos <= idEnd.charPos-1)
6577                         editBox.SetSelPos(l1, y1, idStart.charPos-1, l2, y2, idStart.charPos-1);
6578                      editBox.GetCaretPosition(caret);
6579                      editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
6580                
6581                      membersList.master = this;
6582
6583                      caret.y += editBox.GetCaretSize();
6584                      caret.x -= 20;
6585                      membersList.Create();
6586
6587                      {
6588                         int x = caret.x + editBox.absPosition.x - app.desktop.absPosition.x - editBox.scroll.x;
6589                         int y = caret.y + editBox.absPosition.y - app.desktop.absPosition.y - editBox.scroll.y;
6590                         Window parent = membersList.parent;
6591
6592                         if(!paramsAbove && (paramsShown || y + membersList.size.h > parent.clientSize.h))
6593                         {
6594                            y -= editBox.GetCaretSize() + membersList.size.h;
6595                            membersAbove = true;
6596                         }
6597                         else
6598                            membersAbove = false;
6599
6600                         membersList.position = { x, y };
6601                      }
6602
6603                      membersLine = l1;
6604                      membersLoc.start.line = lineNum - 1;
6605
6606                      if(string && string[0])
6607                      {
6608                         membersLoc.start.charPos = idStart.charPos-1;
6609                         membersLoc.end = membersLoc.start;
6610                         //membersLoc.end.charPos = id.loc.end.charPos-1;
6611                         membersLoc.end.charPos = idStart.charPos + strlen(string)-1; //end.charPos-1;
6612                      }
6613                      else
6614                      {
6615                         membersLoc.start.charPos = charPos;
6616                         membersLoc.end = membersLoc.start;
6617                         membersLoc.end.charPos = charPos;
6618                      }
6619                      membersListShown = true;
6620
6621                      // Hack to keep caret shown
6622                      editBox.GetCaretPosition(caret);
6623                      editBox.SetCaret(caret.x, caret.y, editBox.GetCaretSize());
6624                   }
6625                   if(row)
6626                      membersList.SetScrollPosition(0, row.index * membersList.rowHeight);
6627                }            
6628             }
6629          }
6630       }
6631
6632       SetCurrentContext(globalContext);
6633       SetThisClass(null);
6634
6635       return !didOverride;
6636    }
6637
6638    void InvokeParameters(bool exact, bool reposition, bool caretMove)
6639    {
6640       EditLine line = editBox.line;
6641       char * text = line.text;
6642       int lineNum, charPos;
6643       Expression exp = null;
6644       EditLine l1, l2;
6645       int x1,y1, x2,y2;
6646
6647       if(!parsing) return;
6648
6649       charPos = editBox.charPos + 1;
6650       EnsureUpToDate();
6651
6652       editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6653       { 
6654          EditBoxStream f { editBox = editBox };
6655          char ch;
6656
6657          updatingCode = true;
6658          editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
6659
6660          f.Getc(&ch);
6661          if(ch == '}' || ch == ',' || ch == ')')
6662          {
6663             f.Seek(-1, current);
6664             ch = ' ';
6665          }
6666          if(isspace(ch))
6667          {
6668             for(;;)
6669             {
6670                char ch;
6671                if(!f.Seek(-1, current))
6672                   break;
6673                f.Getc(&ch);
6674                if(!isspace(ch)) break;
6675                f.Seek(-1, current);
6676             }
6677          }
6678          else
6679             f.Seek(-1, current);
6680
6681          editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6682
6683          lineNum = editBox.lineNumber + 1;
6684          charPos = editBox.charPos + 1;
6685          delete f;
6686          updatingCode = false;
6687       }
6688       
6689       charPos = Min(charPos, l1.count + 1);
6690       if(!caretMove)
6691          FindParamsTree(ast, lineNum, charPos);
6692
6693       // Not sure about this == ExpCall... paramsInsideExp doesn't seem to necessarily be a ExpCall
6694       if(exact && ((::functionType && paramsInsideExp.type == callExp && paramsInsideExp.call.exp.loc.end.charPos != charPos-1) /*|| instanceType*/))
6695       {
6696          ::functionType = null;
6697          ::instanceType = null;
6698       }
6699
6700       //if((::functionType || ::instanceType) && (!paramsShown || insideExp != functionExp || ::paramsID != this.paramsID))
6701       if((::functionType || ::instanceType) && (!paramsShown || true /*paramsInsideExp.destType != functionExp.destType */|| ::paramsID != this.paramsID))
6702       {
6703
6704          int x, y;
6705          Window parent = paramsList.parent;
6706
6707          if(this.functionType != ::functionType || this.instanceType != ::instanceType)
6708             reposition = false;
6709
6710          if(!this.paramsShown || reposition || paramsInsideExp != functionExp || ::instanceType) // Added instanceType here, otherwise instance popups never reposition... 
6711                                                                                                           // ( Dummy exp: always ends up with same memory)
6712          {
6713             editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6714             editBox.GetCaretPosition(paramsPosition);
6715             this.paramsPosition.y += editBox.GetCaretSize();
6716          }
6717
6718          FreeType(this.functionType);
6719          FreeType(this.instanceType);
6720
6721          this.functionType = ::functionType;
6722          this.instanceType = ::instanceType;
6723
6724          if(this.functionType) this.functionType.refCount++;
6725          if(this.instanceType) this.instanceType.refCount++;
6726
6727          this.paramsID = ::paramsID;
6728          functionExp = paramsInsideExp;
6729
6730          paramsList.master = this;
6731
6732          paramsList.Create();
6733
6734          x = paramsPosition.x + editBox.absPosition.x - app.desktop.absPosition.x - editBox.scroll.x;
6735          y = paramsPosition.y + editBox.absPosition.y - app.desktop.absPosition.y - editBox.scroll.y;
6736
6737          if(!this.membersAbove && ( this.membersListShown || y + paramsList.size.h > parent.clientSize.h) )
6738          {
6739             y -= editBox.GetCaretSize() + paramsList.clientSize.h;
6740             paramsAbove = true;
6741          }
6742          else
6743             paramsAbove = false;
6744          if(x + paramsList.size.w > parent.clientSize.w)
6745          {
6746             x = parent.clientSize.w - paramsList.size.w;
6747             if(x < 0) x = 0;
6748          }
6749
6750          paramsList.position = { x, y };
6751
6752          // Hack to keep caret shown
6753          {
6754             Point caret;
6755             editBox.GetCaretPosition(caret);
6756             editBox.SetCaret(caret.x, caret.y, editBox.GetCaretSize());
6757          }
6758
6759          this.paramsShown = true;
6760       }
6761       else if((!::functionType && !::instanceType) || reposition)
6762       {
6763          paramsList.Destroy(0);
6764          paramsShown = false;
6765
6766          FreeType(this.functionType);
6767          FreeType(this.instanceType);
6768          this.functionType = null;
6769          this.instanceType = null;
6770          this.paramsID = -1;
6771       }
6772
6773       SetCurrentContext(globalContext);
6774       SetThisClass(null);
6775    }
6776
6777    bool ViewDesigner()
6778    {
6779       if(designer)
6780       {
6781          designer.visible = true;
6782          designer.Activate();
6783       }
6784       return true;
6785    }
6786 };
6787
6788 CodeEditor NewCodeEditor(Window parent, WindowState state, bool modified)
6789 {
6790    CodeEditor document { state = state, parent = parent, modifiedDocument = modified };
6791    document.Create();
6792    return document;
6793 }