ide/CodeEditor: fixed escape not closing membersList on X11
[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 editBox.syntaxHighlighting && !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 == ctrlSpace)
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             bool result = true;
1501             if(editor.paramsShown)
1502             {
1503                if(key == escape)
1504                   result = false;
1505                editor.paramsList.Destroy(0);
1506                editor.paramsShown = false;
1507             }
1508             if(editor.membersListShown)
1509             {
1510                if(key == escape)
1511                   result = false;
1512                editor.membersList.Destroy(0);
1513                editor.membersListShown = false;
1514             }
1515
1516             FreeType(editor.functionType);
1517             editor.functionType = null;
1518
1519             FreeType(editor.instanceType);
1520             editor.instanceType = null;
1521
1522             editor.paramsID = -1;
1523
1524             return result;
1525          }
1526          else 
1527             return editor.editBox.OnKeyDown(key, ch);
1528          return false;
1529       }
1530
1531       /*bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
1532       {
1533          CodeEditor editor = (CodeEditor)master;
1534          Window rw = previous ? previous.rootWindow : null;
1535          if(!active && rw != editor.paramsList)
1536          {
1537             Destroy(0);
1538             editor.membersListShown = false;
1539          }
1540          return ListBox::OnActivate(active, previous, goOnWithActivation, direct);
1541       }*/
1542
1543       bool OnKeyHit(Key key, unichar ch)
1544       {
1545          CodeEditor editor = (CodeEditor) master;
1546
1547          switch(key)
1548          {
1549             case enter: case tab:
1550             {
1551                DataRow row = currentRow;
1552                if(row && row.selected)
1553                {
1554                   char * string = row.string;
1555
1556                   editor.editBox.GoToPosition(editor.membersLine, editor.membersLoc.start.line, editor.membersLoc.start.charPos);
1557                   editor.editBox.Delete(
1558                      editor.membersLine, editor.membersLoc.start.line, editor.membersLoc.start.charPos,
1559                      editor.membersLine, editor.membersLoc.end.line, editor.membersLoc.end.charPos);
1560                   editor.editBox.PutS(string);
1561
1562                   Destroy(0);
1563                   editor.membersListShown = false;
1564                }
1565                else
1566                   editor.editBox.OnKeyHit(key, ch);
1567                break;
1568             }
1569             case down:
1570             case up:
1571             case pageDown:
1572             case pageUp:
1573             case home:
1574             case end:
1575             {
1576                return ListBox::OnKeyHit(key, ch);
1577             }
1578             default:
1579             {
1580                /*
1581                bool result;
1582                // If before . or after
1583                //listBox.Destroy(true);
1584                result = editor.editBox.OnKeyHit(key, ch);
1585                return result;
1586                */
1587                return true;
1588             }
1589          }
1590
1591          return false;
1592       }
1593    };
1594
1595    Window paramsList
1596    {
1597       master = this, 
1598       interim = true,
1599       clickThrough = true,
1600       autoCreate = false,
1601       borderStyle = contour,
1602       cursor = null,
1603       background = { 255,255,225 },
1604       
1605       OnKeyDown = membersList.OnKeyDown;
1606
1607       /*bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
1608       {
1609          CodeEditor editor = (CodeEditor)master;
1610          Window rw = previous ? previous.rootWindow : null;
1611          if(!active && previous != editor.editBox && rw != editor.membersList)
1612          {
1613             Destroy(0);
1614             editor.paramsShown = false;
1615          }
1616          return Window::OnActivate(active, previous, goOnWithActivation, direct);
1617       }*/
1618
1619       bool OnKeyHit(Key key, unichar ch)
1620       {
1621          CodeEditor editor = (CodeEditor)master;
1622
1623          if(!editor.membersListShown || editor.membersList.OnKeyHit(key, ch))
1624          {
1625             /*
1626             bool result = true; editor.editBox.OnKeyHit(key, ch);
1627             return (!created) ? false : result;
1628             */
1629             return true;
1630          }
1631          return false;
1632       }
1633
1634       void OnRedraw(Surface surface)
1635       {
1636          CodeEditor editor = (CodeEditor) master;
1637          Type type = editor.functionType ? editor.functionType : editor.instanceType;
1638          Type param;
1639          Type methodType = null;
1640
1641          char string[1024];
1642
1643          int functionW, nameW = 0;
1644          int totalW = 0;
1645          int spaceW, spaceH, commaW, commaWB, parW;
1646          int availW = 1024;
1647          int maxW = 0, lineW = 0;
1648          int realW = 0;
1649          int height = 0;
1650          int x = 2, y = 2;
1651          int id = 0;
1652
1653          Font font = editor.normalFont.font;
1654          Font boldFont = editor.boldFont.font;
1655          Display display = this.display;
1656
1657          if(!type) { return; };
1658
1659          if(type.kind == TypeKind::methodType) { methodType = type; type = type.method.dataType; }
1660
1661          display.FontExtent(boldFont, " ", 1, &spaceW, &spaceH);
1662          display.FontExtent(font, ", ", 2, &commaW, null);
1663          display.FontExtent(boldFont, ", ", 2, &commaWB, null);
1664          display.FontExtent(font, ")", 1, &parW, null);
1665
1666          string[0] = 0;
1667          if(editor.functionType)
1668          {
1669             PrintType(type.returnType, string, true, true);
1670             display.FontExtent(font, string, strlen(string), &functionW, null);
1671             if(type.name)
1672                display.FontExtent(font, type.name, strlen(type.name), &nameW, null);
1673             totalW = nameW + functionW + 2 * parW;
1674          }
1675          else
1676          {
1677             PrintType(type, string, (type.kind == functionType) ? true : false, true); // true);
1678             display.FontExtent(boldFont, string, strlen(string), &functionW, null);
1679             if(instanceName && type.kind != functionType)
1680                display.FontExtent(boldFont, instanceName, strlen(instanceName), &nameW, null);
1681             totalW = functionW + nameW;
1682             surface.TextFont(boldFont);
1683          }   
1684
1685          surface.WriteText(x, y, string, strlen(string));
1686          x += functionW + spaceW;
1687
1688          if(editor.functionType)
1689          {
1690             if(type.name)
1691                surface.WriteText(x, y, type.name, strlen(type.name));
1692             x += nameW;
1693             surface.WriteText(x, y, "(", 1);
1694             x += parW;
1695
1696             if(methodType && !methodType.staticMethod && methodType.methodClass)
1697             {
1698                int tw = 0, width;
1699
1700                if(id == editor.paramsID)
1701                   surface.TextFont(boldFont);
1702                
1703                if(methodType.methodClass)
1704                   surface.TextExtent(methodType.methodClass.name, strlen(methodType.methodClass.name), &tw, null);
1705
1706                width = tw;
1707
1708                if(type.params.first && (((Type)type.params.first).kind != voidType || type.params.count > 1))
1709                   width += ((id == editor.paramsID) ? commaWB : commaW);
1710
1711                if(!height)
1712                   maxW = lineW;
1713
1714                if(lineW && ((height && lineW + width > maxW) || (totalW + lineW + width + 20 > availW)))
1715                {
1716                   height += spaceH;
1717                   lineW = 0;
1718
1719                   x = 2 + nameW + spaceW + functionW + parW;
1720                   y += spaceH;
1721
1722                }
1723                if(methodType.methodClass)
1724                   surface.WriteText(x, y, methodType.methodClass.name, strlen(methodType.methodClass.name));
1725
1726                x += tw;
1727                if(type.params.first && (((Type)type.params.first).kind != voidType || type.params.count > 1))
1728                {
1729                   surface.WriteText(x, y, ",", 1);
1730                   x += ((id ==  editor.paramsID) ? commaWB : commaW);
1731                }      
1732
1733                lineW += width;
1734
1735                if(lineW > realW)
1736                   realW = lineW;
1737
1738                if(id == editor.paramsID)
1739                   surface.TextFont(font);
1740                id ++;
1741             }
1742
1743             if(!methodType || (methodType.staticMethod || !methodType.methodClass) || !type.params.first || ((Type)type.params.first).kind != voidType || type.params.count > 1)
1744             {
1745                for(param = type.params.first; param; param = param.next)
1746                {
1747                   char paramString[1024];
1748                   int tw, width;
1749
1750                   if(id == editor.paramsID || (param.kind == ellipsisType && id < editor.paramsID && editor.paramsID != -1))
1751                      surface.TextFont(boldFont);
1752
1753                   paramString[0] = 0;
1754                   PrintType(param, paramString, true, true);
1755                   surface.TextExtent(paramString, strlen(paramString), &tw, null);
1756                   width = tw;
1757                   if(param.next) width += ((id ==  editor.paramsID) ? commaWB : commaW);
1758
1759                   if(!height)
1760                      maxW = lineW;
1761
1762                   if(lineW && ((height && lineW + width > maxW) || (totalW + lineW + width + 20 > availW)))
1763                   {
1764                      height += spaceH;
1765                      lineW = 0;
1766
1767                      x = 2 + nameW + spaceW + functionW + parW;
1768                      y += spaceH;
1769
1770                   }
1771                   surface.WriteText(x, y, paramString, strlen(paramString));
1772                   x += tw;
1773                   if(param.next)
1774                   {
1775                      surface.WriteText(x, y, ",", 1);
1776                      x += ((id ==  editor.paramsID) ? commaWB : commaW);
1777                   }      
1778
1779                   lineW += width;
1780
1781                   if(lineW > realW)
1782                      realW = lineW;
1783
1784                   if(id == editor.paramsID || (param.kind == ellipsisType && id < editor.paramsID && editor.paramsID != -1))
1785                      surface.TextFont(font);
1786                   id ++;
1787                }
1788             }
1789
1790             surface.WriteText(x, y, ")", 1);
1791          }
1792          else if(instanceName && type.kind != functionType)
1793          {
1794             surface.WriteText(x, y, instanceName, strlen(instanceName));
1795          }
1796       }
1797
1798       bool OnResizing(int * w, int * h)
1799       {
1800          CodeEditor editor = (CodeEditor) master;
1801          Type type = editor.functionType ? editor.functionType : editor.instanceType;
1802          Type param;
1803          Type methodType = null;
1804
1805          char string[1024];
1806
1807          int functionW = 0, nameW = 0;
1808          int totalW = 0;
1809          int spaceW, spaceH, commaW, commaWB, parW;
1810          int availW = 1024;
1811          int maxW = 0, lineW = 0;
1812          int realW = 0;
1813          int height = 0;
1814          int id = 0;
1815
1816          Font font = editor.normalFont.font;
1817          Font boldFont = editor.boldFont.font;
1818          Display display = this.display;
1819
1820          if(type.kind == TypeKind::methodType)
1821          {
1822             methodType = type;
1823             ProcessMethodType(type.method);
1824             type = type.method.dataType;
1825          }
1826
1827          display.FontExtent(boldFont, " ", 1, &spaceW, &spaceH);
1828          display.FontExtent(font, ", ", 2, &commaW, null);
1829          display.FontExtent(boldFont, ", ", 2, &commaWB, null);
1830          display.FontExtent(font, ")", 1, &parW, null);
1831
1832          string[0] = 0;
1833          if(editor.functionType && type)
1834          {
1835             PrintType(type.returnType, string, true, true);
1836             display.FontExtent(font, string, strlen(string), &functionW, null);
1837             if(type.name)
1838                display.FontExtent(font, type.name, strlen(type.name), &nameW, null);
1839             totalW = nameW + spaceW + functionW + 2 * parW;
1840          }
1841          else if(type)
1842          {
1843             PrintType(type, string, false, true); // /*true);
1844             display.FontExtent(boldFont, string, strlen(string), &functionW, null);
1845             if(instanceName && type.kind != functionType)
1846                display.FontExtent(boldFont, instanceName, strlen(instanceName), &nameW, null);
1847             totalW = functionW + nameW + spaceW;
1848          }
1849             
1850          if(editor.functionType)
1851          {
1852             if(methodType)
1853             {
1854                int width = 0;
1855
1856                if(methodType.methodClass)
1857                   display.FontExtent((id == editor.paramsID) ? boldFont : font, methodType.methodClass.name, strlen(methodType.methodClass.name), &width, null);
1858                if(type.params.first && (((Type)type.params.first).kind != voidType || type.params.count > 1))
1859                   width += ((id == editor.paramsID) ? commaWB : commaW);
1860
1861                if(!height)
1862                   maxW = lineW;
1863
1864                if(lineW && ((height && lineW + width > maxW) || (totalW + lineW + width + 20 > availW)))
1865                {
1866                   height += spaceH;
1867                   lineW = 0;
1868                }
1869
1870                lineW += width;
1871
1872                if(lineW > realW)
1873                   realW = lineW;
1874
1875                id++;
1876             }
1877             if(!methodType || methodType.staticMethod || !type.params.first || ((Type)type.params.first).kind != voidType || type.params.count > 1)
1878             {
1879                for(param = type.params.first; param; param = param.next)
1880                {
1881                   char paramString[1024];
1882                   int width = 0;
1883
1884                   paramString[0] = 0;
1885                   PrintType(param, paramString, true, true);
1886                   display.FontExtent((id == editor.paramsID || param.kind == ellipsisType) ? boldFont : font, paramString, strlen(paramString), &width, null);
1887                   if(param.next) 
1888                      width += ((id == editor.paramsID) ? commaWB : commaW);
1889
1890                   if(!height)
1891                      maxW = lineW;
1892
1893                   if(lineW && ((height && lineW + width > maxW) || (totalW + lineW + width + 20 > availW)))
1894                   {
1895                      height += spaceH;
1896                      lineW = 0;
1897                   }
1898
1899                   lineW += width;
1900
1901                   if(lineW > realW)
1902                      realW = lineW;
1903
1904                   id++;
1905                }
1906             }
1907          }
1908          height += spaceH;
1909
1910          *w = realW + totalW + 4;
1911          *h = height + 4;
1912          return true;
1913       }
1914    };
1915
1916    Menu fileMenu { menu, $"File", f };  // MenuPlacement?
1917    MenuItem { fileMenu, $"Save", s, Key { s, ctrl = true }, NotifySelect = MenuFileSave };
1918    MenuItem { fileMenu, $"Save As...", a, NotifySelect = MenuFileSaveAs };
1919
1920    Menu debugMenu { menu, $"Debug", d };  // MenuPlacement?
1921    MenuItem debugRunToCursor
1922    {
1923       debugMenu, $"Run To Cursor", c, Key { f10, ctrl = true };
1924       bool NotifySelect(MenuItem selection, Modifiers mods)
1925       {
1926          ProjectView projectView = ide.projectView;
1927          if(!projectView.buildInProgress)
1928          {
1929             int line = editBox.lineNumber + 1;
1930             if(projectView)
1931             {
1932                CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1933                ProjectConfig config = projectView.project.config;
1934                int bitDepth = ide.workspace.bitDepth;
1935                bool useValgrind = ide.workspace.useValgrind;
1936                ide.debugger.RunToCursor(compiler, config, bitDepth, useValgrind, fileName, line, false, false);
1937                delete compiler;
1938             }
1939          }
1940          return true;
1941       }
1942    };
1943    MenuItem debugSkipRunToCursor
1944    {
1945       debugMenu, $"Run To Cursor Skipping Breakpoints", u, Key { f10, ctrl = true, shift = true };
1946       bool NotifySelect(MenuItem selection, Modifiers mods)
1947       {
1948          ProjectView projectView = ide.projectView;
1949          int line = editBox.lineNumber + 1;
1950          if(projectView)
1951          {
1952             CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1953             ProjectConfig config = projectView.project.config;
1954             int bitDepth = ide.workspace.bitDepth;
1955             bool useValgrind = ide.workspace.useValgrind;
1956             ide.debugger.RunToCursor(compiler, config, bitDepth, useValgrind, fileName, line, true, false);
1957             delete compiler;
1958          }
1959          return true;
1960       }
1961    };
1962    MenuItem debugSkipRunToCursorAtSameLevel
1963    {
1964       debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", u, Key { f10, alt = true };
1965       bool NotifySelect(MenuItem selection, Modifiers mods)
1966       {
1967          ProjectView projectView = ide.projectView;
1968          int line = editBox.lineNumber + 1;
1969          if(projectView)
1970          {
1971             CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1972             ProjectConfig config = projectView.project.config;
1973             int bitDepth = ide.workspace.bitDepth;
1974             bool useValgrind = ide.workspace.useValgrind;
1975             ide.debugger.RunToCursor(compiler, config, bitDepth, useValgrind, fileName, line, true, true);
1976             delete compiler;
1977          }
1978          return true;
1979       }
1980    };
1981    MenuDivider { debugMenu };
1982    MenuItem debugToggleBreakpoint
1983    {
1984       debugMenu, $"Toggle Breakpoint", t, f9;
1985       bool NotifySelect(MenuItem selection, Modifiers mods)
1986       {
1987          ProjectView projectView = ide.projectView;
1988          if(projectView && fileName)
1989          {
1990             int line = editBox.lineNumber + 1;
1991             char name[MAX_LOCATION];
1992             Project prj = null;
1993             // TOFIX: This only looks at the filename...
1994             GetLastDirectory(fileName, name);
1995             if(ide && ide.workspace)
1996             {
1997                for(p : ide.workspace.projects)
1998                {
1999                   if(p.topNode.Find(name, false))
2000                   {
2001                      prj = p;
2002                      break;
2003                   }
2004                }
2005                if(!prj)
2006                {
2007                   for(p : ide.workspace.projects)
2008                   {
2009                      if(IsPathInsideOf(fileName, p.topNode.path))
2010                      {
2011                         prj = p;
2012                         break;
2013                      }
2014                   }
2015                }
2016             }
2017             ide.debugger.ToggleBreakpoint(fileName, line, prj);
2018             Update(null);
2019          }
2020          return true;
2021       }
2022    };
2023
2024    bool debugClosing;
2025    int lastLine;
2026
2027    //MenuItem viewDesignerItem, viewProperties, viewMethods;
2028
2029    bool OnCreate(void)
2030    {
2031       designer.parent = parent;
2032       designer.Create();
2033
2034       toolBox = ((IDEWorkSpace)master).toolBox;
2035       incref toolBox;
2036       // Debugger bug here: value of toolBox appears as 0
2037
2038       sheet = ((IDEWorkSpace)master).sheet;
2039       incref sheet;
2040       return true;
2041    }
2042
2043    bool OnClose(bool parentClosing)
2044    {
2045       if(!parentClosing)
2046       {
2047          if(ide.workspace && fileName)
2048             ide.workspace.UpdateOpenedFileInfo(fileName, closed);
2049          if(inUseDebug && !debugClosing)
2050          {
2051             debugClosing = true;
2052             closing = false;
2053             if(CloseConfirmation(false))
2054             {
2055                visible = false;
2056                OnFileModified({ modified = true }, null);
2057             }
2058             debugClosing = false;
2059             return false;
2060          }
2061          if(designer && !designer.closing)
2062          {
2063             if(designer.visible)
2064             {
2065                visible = false;
2066                return false;
2067             }
2068             /*else
2069             {
2070                //Window formEditor = designer;
2071                //formEditor.Destroy(0);
2072             }*/
2073          }
2074          ide.AdjustFileMenus();
2075       }
2076       return true;
2077    }
2078
2079    void OnDestroy(void)
2080    {
2081       ObjectInfo oClass, next;
2082       Class windowClass = eSystem_FindClass(this.privateModule, "ecere::gui::Window");
2083
2084       FreeType(this.functionType);
2085       FreeType(this.instanceType);
2086
2087       if(designer)
2088       {
2089          designer.Reset();
2090          designer.codeEditor = null;
2091          designer.Destroy(0);
2092          delete designer;
2093       }
2094
2095       for(oClass = (classes).first, next = oClass ? oClass.next : null; oClass; oClass = next, next = next ? (next.next) : null)
2096       {
2097          ObjectInfo object, next;
2098          
2099          for(object = oClass.instances.first; object; object = next)
2100          {
2101             next = object.next;
2102             if(object.instance)
2103             {
2104                Designer::DestroyObject(object.instance);
2105                delete object.instance;
2106             }
2107             sheet.DeleteObject(object);
2108             delete object.name;
2109             oClass.instances.Delete(object);
2110          }
2111          if(oClass.instance)
2112          {
2113             Designer::DestroyObject(oClass.instance);
2114             delete oClass.instance;
2115          }
2116          sheet.DeleteObject(oClass);
2117          delete oClass.name;
2118          classes.Delete(oClass);
2119       }
2120
2121       if(windowClass && windowClass.data)
2122          UnapplySkin(windowClass);
2123
2124       FreeParser();
2125
2126       if(sheet.codeEditor == this)
2127       {
2128          sheet.codeEditor = null;
2129          toolBox.codeEditor = null;
2130       }
2131       delete sheet;
2132       delete toolBox;
2133
2134       {
2135          ProjectView projectView = ide.projectView;
2136          if(projectView)
2137          {
2138             ProjectNode node = projectView.GetNodeFromWindow(this, null, false);
2139             if(node && node.modified)
2140             {
2141                node.modified = false;
2142                projectView.Update(null);
2143             }
2144          }
2145       }
2146    }
2147
2148    bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool directActivation)
2149    {
2150       // 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
2151       /*
2152       if(directActivation)
2153          ide.RepositionWindows(false);    // Moved this up before as resizing causes NotifyCaretMove to be called on all editors
2154       */
2155       if(active && directActivation)
2156       {
2157          AdjustDebugMenus(ide.areDebugMenusUnavailable, ide.isBreakpointTogglingUnavailable, ide.isDebuggerExecuting);
2158          if(openedFileInfo)
2159             openedFileInfo.Activate();
2160          if(designer)
2161          {
2162             int line, charPos;
2163             Location * loc = null;
2164             UpdateFormCode(); // To ensure update when modifying properties...
2165
2166             // Got to the right spot in code so we don't lose our form selection...
2167             if(selected)
2168             {
2169                if(selected.instCode)
2170                   loc = &selected.instCode.loc;
2171                else if(selected.classDefinition)
2172                   loc = &selected.classDefinition.loc;
2173             }
2174             line = editBox.lineNumber + 1;
2175             charPos = editBox.charPos + 1;
2176             if(fixCaret)
2177             {
2178                fixCaret = false;
2179
2180                if(selected && !loc->Inside(line, charPos))
2181                {
2182                   editBox.GoToPosition(null, loc->start.line - 1, loc->start.charPos - 1);
2183                   line = editBox.lineNumber + 1;
2184                   charPos = editBox.charPos + 1;
2185                }
2186                else if(selected && selected.classDefinition)
2187                {
2188                   ObjectInfo object;
2189                   for(object = selected.instances.first; object; object = object.next)
2190                   {
2191                      if(object.instCode)
2192                      {
2193                         if(object.instCode.loc.Inside(line, charPos))
2194                            break;
2195                      }
2196                   }
2197                   if(object)
2198                   {
2199                      editBox.GoToPosition(null, loc->start.line - 1, loc->start.charPos - 1);
2200                      line = editBox.lineNumber + 1;
2201                      charPos = editBox.charPos + 1;
2202                   }
2203                }
2204             }
2205
2206             ProcessCaretMove(editBox, line, charPos);
2207          }
2208       }
2209       if(!active)
2210       {
2211          if(membersListShown)
2212          {
2213             membersList.Destroy(0);
2214             membersListShown = false;
2215          }
2216          if(paramsShown)
2217          {
2218             paramsList.Destroy(0);
2219             paramsShown = false;
2220             FreeType(functionType);
2221             FreeType(instanceType);
2222
2223             functionType = null;
2224             instanceType = null;
2225             paramsID = -1;
2226          }
2227       }
2228       return true;
2229    }
2230
2231    bool OnSaveFile(char * fileName)
2232    {
2233       File f;
2234       if(designer)
2235       {
2236          UpdateFormCode();
2237       }
2238       f = FileOpen(fileName, write);
2239       if(f)
2240       {
2241          if(!ide.projectView)
2242             ide.ChangeFileDialogsDirectory(codeEditorFileDialog.currentDirectory, true);
2243          if(designer)
2244          {
2245             if(!this.fileName)
2246                this.fileName = fileName;  // Put this here because the form designer will check for it...
2247             designer.fileName = fileName;
2248             designer.modifiedDocument = false;
2249          }
2250          editBox.Save(f, false);
2251          modifiedDocument = false;
2252          
2253          delete(f);
2254          return true;
2255       }
2256       return false;
2257    }
2258
2259    bool OnFileModified(FileChange fileChange, char * param)
2260    {
2261       bool reload = false;
2262       if(visible == false && inUseDebug == true)
2263          reload = true;
2264       else
2265       {
2266          char message[2048];
2267
2268          sprintf(message, $"The document %s was modified by another application.\n"
2269             "Would you like to reload it and lose your changes?", fileName);
2270          if(MessageBox { type = yesNo, master = /*parent = */parent, text = $"Document has been modified",
2271             contents = message }.Modal() == yes)
2272             reload = true;
2273       }
2274
2275       if(reload)
2276       {
2277          File f = FileOpen(fileName, read);
2278          if(f)
2279          {
2280             int lineNumber, charPos, len;
2281             Point scroll;
2282
2283             loadingFile = true;
2284             updatingCode = true;
2285             lineNumber = editBox.lineNumber;
2286             charPos = editBox.charPos;
2287             scroll = editBox.scroll;
2288             editBox.Clear();
2289             editBox.Load(f);
2290             lineNumber = lineNumber < editBox.numLines ? lineNumber : editBox.numLines - 1;
2291             len = strlen(editBox.line.text);
2292             editBox.GoToLineNum(lineNumber);
2293             editBox.GoToPosition(editBox.line, lineNumber, charPos <= len ? charPos - 1 : (len ? len - 1 : 0));
2294             editBox.scroll = scroll;
2295             updatingCode = false;
2296             loadingFile = false;
2297
2298             codeModified = true;
2299             if(designer)
2300             {
2301                UpdateFormCode();
2302                designer.modifiedDocument = false;
2303             }
2304             modifiedDocument = false;
2305
2306             delete(f);
2307          }
2308       }
2309       return true;
2310    }
2311
2312    void OnRedraw(Surface surface)
2313    {
2314       // Line Numbers
2315       surface.SetBackground(marginColor);
2316       surface.Area(0, 0, editBox.anchor.left.distance, clientSize.h - 1);
2317       if(ideSettings.showLineNumbers)
2318       {
2319          int currentLineNumber;
2320          int i;
2321          char lineText[256];
2322          int spaceH;
2323
2324          surface.textOpacity = false;
2325          surface.font = font.font;
2326          surface.TextExtent(" ", 1, null, &spaceH);
2327          currentLineNumber = editBox.scroll.y / spaceH + 1;
2328
2329          surface.SetForeground(lineNumbersColor);
2330          for(i = 0; i < editBox.clientSize.h - 4; i += spaceH)
2331          {
2332             // Highlight current line
2333             if(editBox.lineNumber == currentLineNumber - 1)
2334             {
2335                surface.SetBackground(selectedMarginColor);
2336                surface.Area(0, i, editBox.anchor.left.distance, i+spaceH-1);
2337                surface.SetBackground(marginColor);
2338             }
2339             sprintf(lineText,"%5u ", currentLineNumber % 100000);
2340             if(currentLineNumber <= editBox.numLines)
2341                surface.WriteText(editBox.syntaxHighlighting * 20, i+1,lineText,6);
2342             
2343             currentLineNumber++;
2344          }
2345       }
2346
2347       if(editBox.syntaxHighlighting && fileName && ide.projectView)
2348       {
2349          bool error, bpOnCursor, bpOnTopFrame, breakpointEnabled[128];
2350          int lineCursor, lineTopFrame, breakpointLines[128];
2351          int count, i, lineH, boxH, scrollY; //, firstLine; firstLine = editBox.firstLine;
2352          Debugger debugger = ide.debugger;
2353          BitmapResource bmpRes;
2354
2355          boxH = clientSize.h;
2356          scrollY = editBox.scroll.y;
2357          displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
2358
2359          bpOnCursor = bpOnTopFrame = false;
2360          count = debugger.GetMarginIconsLineNumbers(fileName, breakpointLines, breakpointEnabled, 128, &error, &lineCursor, &lineTopFrame);
2361          if(count)
2362          {
2363             for(i = 0; i < count; i++)
2364             {
2365                if(breakpointLines[i] == lineCursor || breakpointLines[i] == lineTopFrame)
2366                {
2367                   bmpRes = breakpointEnabled[i] ? ide.bmpBpHalf : ide.bmpBpHalfDisabled;
2368                   if(breakpointLines[i] == lineCursor)
2369                      bpOnCursor = true;
2370                   if(breakpointLines[i] == lineTopFrame)
2371                      bpOnTopFrame = true;
2372                }
2373                else
2374                   bmpRes = breakpointEnabled[i] ? ide.bmpBp : ide.bmpBpDisabled;
2375                
2376                DrawLineMarginIcon(surface, bmpRes, breakpointLines[i], lineH, scrollY, boxH);
2377             }
2378          }
2379          DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
2380          bmpRes = bpOnTopFrame ? (error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf) : (error ? ide.bmpTopFrameError : ide.bmpTopFrame);
2381          DrawLineMarginIcon(surface, bmpRes, lineTopFrame, lineH, scrollY, boxH);
2382       }
2383       if(editBox.anchor.left.distance)
2384       {
2385          if(editBox.horzScroll && editBox.horzScroll.visible)
2386          {
2387             surface.SetBackground(control);
2388             surface.Area(0, editBox.clientSize.h, editBox.anchor.left.distance, clientSize.h - 1);
2389          }
2390       }
2391    }
2392
2393    void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
2394    {
2395       int lineY;
2396       if(line)
2397       {
2398          lineY = (line - 1) * lineH;
2399          if(lineY + lineH > scrollY && lineY /*+ lineH*/ < scrollY + boxH)
2400          {
2401             Bitmap bitmap = resource.bitmap;
2402             if(bitmap)
2403                surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
2404          }
2405       }
2406    }
2407
2408    watch(fileName)
2409    {
2410       char ext[MAX_EXTENSION];
2411       char * fileName = property::fileName;
2412
2413       if(SearchString(fileName, 0, "Makefile", false, true))
2414          editBox.useTab = true;
2415       designer.fileName = fileName;
2416
2417       if(fileName)
2418       {
2419          GetExtension(fileName, ext);
2420
2421          if(!strcmpi(ext, "ec") || !strcmpi(ext, "eh") || !strcmpi(ext, "c") || !strcmpi(ext, "h") || !strcmpi(ext, "cpp") ||
2422                !strcmpi(ext, "hpp") || !strcmpi(ext, "cxx") || !strcmpi(ext, "hxx") || !strcmpi(ext, "cc") || !strcmpi(ext, "hh") ||
2423                !strcmpi(ext, "m") || !strcmpi(ext, "mm") || !strcmpi(ext, "cs") || !strcmpi(ext, "java") || !strcmpi(ext, "y") || !strcmpi(ext, "l"))
2424             editBox.syntaxHighlighting = true;
2425          else
2426             editBox.syntaxHighlighting = false;
2427
2428          if(parsing && !strcmpi(ext, "ec"))
2429          {
2430             codeModified = true;
2431             EnsureUpToDate();
2432          }
2433
2434          {
2435             int spaceW;
2436             display.FontExtent(font.font, " ", 1, &spaceW, null);
2437             editBox.anchor = Anchor
2438             {
2439                left = (editBox.syntaxHighlighting ? 20 : 0) + (ideSettings.showLineNumbers ? (6 * spaceW) : 0),
2440                right = 0, top = 0, bottom = 0
2441             };
2442          }
2443       }
2444    };
2445
2446    bool OnPostCreate()
2447    {
2448       int spaceW;
2449       display.FontExtent(font.font, " ", 1, &spaceW, null);
2450       editBox.anchor = Anchor
2451       {
2452          left = (editBox.syntaxHighlighting ? 20 : 0) + (ideSettings.showLineNumbers ? (6 * spaceW) : 0),
2453          right = 0, top = 0, bottom = 0
2454       };
2455       return true;
2456    }
2457
2458    bool LoadFile(char * filePath)
2459    {
2460       File f = FileOpen(filePath, read);
2461       if(f)
2462       {
2463          // Added this here... 
2464          fileName = filePath;
2465          loadingFile = true;
2466          updatingCode = true;
2467          editBox.Load(f);
2468          updatingCode = false;
2469          loadingFile = false;
2470          Create();
2471
2472          delete(f);
2473          return true;
2474       }
2475       return false;
2476    }
2477
2478    void AdjustDebugMenus(bool unavailable, bool bpNoToggle, bool executing)
2479    {
2480       debugRunToCursor.disabled                = unavailable || executing;
2481       debugSkipRunToCursor.disabled            = unavailable || executing;
2482       debugSkipRunToCursorAtSameLevel.disabled = unavailable || executing;
2483       debugToggleBreakpoint.disabled           = bpNoToggle;
2484    }
2485
2486    CodeEditor()
2487    {
2488       CodeObjectType c;
2489       ProjectView projectView = ide.projectView;
2490
2491       /*if(fileName)
2492          designer.fileName = fileName;
2493       else
2494       */
2495       if(designer)
2496       {
2497          char title[1024];
2498          sprintf(title, $"Untitled %d", documentID);
2499          // designer.fileName = CopyString(title);
2500          designer.fileName = title;
2501       }
2502
2503       AdjustDebugMenus(ide.areDebugMenusUnavailable, ide.isBreakpointTogglingUnavailable, ide.isDebuggerExecuting);
2504
2505       for(c = 0; c < CodeObjectType::enumSize; c++)
2506          icons[c] = BitmapResource { iconNames[c], window = this };
2507
2508       codeModified = true;
2509       inUseDebug = false;
2510       return true;
2511    }
2512
2513    ~CodeEditor()
2514    {
2515
2516    }
2517
2518    void ModifyCode()
2519    {
2520       selected.modified = true;
2521       selected.oClass.modified = true;
2522
2523       designer.modifiedDocument = true;
2524       modifiedDocument = true;
2525       formModified = true;
2526    }
2527
2528    /****************************************************************************
2529                                  PARSING
2530    ****************************************************************************/
2531    void FreeParser()
2532    {
2533       if(ast != null)
2534       {
2535          FreeASTTree(ast);
2536          ast = null;
2537       }
2538       this.defines.Free(FreeModuleDefine);
2539       this.imports.Free(FreeModuleImport);   // Moved this after FreeAST because Debug printing causes ModuleImports to be created
2540
2541       FreeExcludedSymbols(this.excludedSymbols);
2542       FreeContext(this.globalContext);
2543       FreeIncludeFiles();
2544       FreeGlobalData(&this.globalData);
2545       FindCtx_Terminate();
2546       FindParams_Terminate();
2547
2548       if(GetGlobalContext() == globalContext)
2549       {
2550          SetGlobalData(null);
2551          SetGlobalContext(null);
2552          SetExcludedSymbols(null);
2553          SetTopContext(null);
2554          SetCurrentContext(null);
2555          SetDefines(null);
2556          SetImports(null);
2557          SetPrivateModule(null);
2558       }
2559
2560       if(this.privateModule)
2561       {
2562          FreeTypeData(this.privateModule);
2563          delete this.privateModule;
2564          this.privateModule = null;
2565       }
2566    }
2567
2568    void ParseCode()
2569    {
2570       static bool reentrant = false;
2571       External external;
2572       File editFile;
2573       EditLine l1, l2;
2574       int x1,x2,y1,y2;
2575       char * selectedClassName = null, * selectedName = null;
2576       int selectedPos = 0;
2577       Designer backDesigner;
2578       char oldWorkDir[MAX_LOCATION];
2579       char mainModuleName[MAX_FILENAME] = "";
2580       char * fileName;
2581       ImportedModule module;
2582       char extension[MAX_EXTENSION];
2583       PathBackup pathBackup { };
2584 #ifdef _TIMINGS
2585       Time parseCodeStart = GetTime();
2586       Time startTime, startFindClass;
2587
2588       findClassTotalTime = 0;
2589       checkTypeTotalTime = 0;
2590       externalImportTotalTime = 0;
2591       findClassIgnoreNSTotalTime = 0;
2592       findSymbolTotalTime = 0;
2593       //ResetClassFindTime();
2594 #endif
2595       Project project;
2596
2597       // 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)
2598       if(reentrant) return;
2599       reentrant = true;
2600
2601       updatingCode++;
2602
2603       if(selected)
2604       {
2605          selectedClassName = CopyString(oClass.name);
2606          if(selected != oClass)
2607          {
2608             ObjectInfo object = this.selected;
2609             selectedName = CopyString(object.name);
2610             if(!selectedName)
2611             {
2612                ObjectInfo check;
2613                for(check = this.oClass.instances.first; check; check = check.next)
2614                {
2615                   if(check == object)
2616                      break;
2617                   selectedPos++;
2618                }
2619             }
2620          }
2621          else 
2622             selectedPos = -1;
2623       }
2624
2625       editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
2626
2627       FindCtx_Terminate();
2628       FindParams_Terminate();
2629
2630       SetGlobalData(&globalData);
2631       SetGlobalContext(globalContext);
2632       SetExcludedSymbols(&excludedSymbols);
2633       SetTopContext(globalContext);
2634       SetCurrentContext(globalContext);
2635       SetDefines(&defines);
2636       SetImports(&imports);
2637       SetCurrentNameSpace(null);
2638
2639       /*
2640       sprintf(command, "C:\\Program Files\\Microsoft Visual Studio\\VC98\\Bin\\cl "
2641          "/nologo /D \"MSC\" /D \"WIN32\" /D \"NDEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" "
2642          "/I \"C:\\Program Files\\Microsoft Visual Studio\\VC98\\Include\" "
2643          "/I T:\\ecere\\include /E %s", argv[1]);
2644       */
2645
2646       /*
2647       ChangeWorkingDir("e:\\ec");
2648       sprintf(command, "gcc -x c -E -");
2649       fileInput = DualPipeOpen({ output = true, input = true }, command);
2650       SetFileInput(fileInput);
2651       {
2652          for(;;)
2653          {
2654             byte buffer[8192];
2655             uint count = editFile.Read(buffer, 1, sizeof(buffer));
2656             if(count)
2657                fileInput.Write(buffer, 1, count);
2658             else
2659                break;
2660          }
2661          delete editFile;
2662          fileInput.CloseOutput();
2663       }
2664       */
2665
2666       // TOCHECK: COULDN'T WE CALL FreeParser here?
2667       // Clear everything
2668       FreeType(this.functionType);
2669       FreeType(this.instanceType);
2670       this.functionType = null;
2671       this.instanceType = null;
2672
2673       // Select nothing
2674       sheet.SelectObject(null);
2675
2676       designer.Reset();
2677
2678       selected = null;
2679
2680       // We don't want the designer to be notified of selection when deleting rows...
2681       backDesigner = designer;
2682       designer = null;
2683
2684       if(this.oClass)
2685       {
2686          ObjectInfo _class, next;
2687          
2688          for(_class = classes.first; _class; _class = next)
2689          {
2690             ObjectInfo object;
2691
2692             next = _class.next;
2693             
2694             for(;object = _class.instances.first;)
2695             {
2696                if(object.instance)
2697                {
2698                   Designer::DestroyObject(object.instance);
2699                   delete object.instance;
2700                }
2701                sheet.DeleteObject(object);
2702                delete object.name;
2703                _class.instances.Delete(object);
2704             }
2705             if(_class.instance)
2706             {
2707                Designer::DestroyObject(_class.instance);
2708                delete _class.instance;
2709             }
2710             sheet.DeleteObject(_class);
2711             delete _class.name;
2712             classes.Delete(_class);
2713          }
2714          this.oClass = null;
2715       }
2716
2717       {
2718          Class windowClass = eSystem_FindClass(this.privateModule, "ecere::gui::Window");
2719          if(windowClass && windowClass.data)
2720             UnapplySkin(windowClass);
2721       }
2722
2723       designer = backDesigner;
2724
2725       SetEchoOn(true);
2726       fileInput = editFile = EditBoxStream { editBox = editBox };
2727       SetFileInput(fileInput);
2728
2729       if(ast)
2730       {
2731          FreeASTTree(ast);
2732          ast = null;
2733          //SetAST(null);
2734       }
2735       defines.Free(FreeModuleDefine);
2736       imports.Free(FreeModuleImport);
2737
2738       FreeContext(this.globalContext);
2739       FreeExcludedSymbols(this.excludedSymbols);
2740
2741       FreeIncludeFiles();
2742       FreeGlobalData(&this.globalData);
2743
2744       if(this.privateModule)
2745       {
2746          FreeTypeData(this.privateModule);
2747          delete this.privateModule;
2748       }
2749
2750 #ifdef _TIMINGS
2751       startTime = GetTime();
2752       printf("Cleaning up took %.3f seconds\n", startTime - parseCodeStart);
2753
2754       printf("classes.count: %d\n", globalContext.classes.count);
2755 #endif
2756
2757       if(ide.workspace)
2758       {
2759          CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2760          SetTargetBits(ide.workspace.bitDepth ? ide.workspace.bitDepth : GetHostBits());
2761          delete compiler;
2762       }
2763       this.privateModule = __ecere_COM_Initialize(false | ((GetTargetBits() == sizeof(uintptr) *8) ? 0 : GetTargetBits() == 64 ? 2 : 4), 1, null);
2764
2765       SetPrivateModule(privateModule);
2766
2767       {
2768          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint"), type = ProcessTypeString("unsigned int", false) });
2769          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint64"), type = ProcessTypeString("unsigned int64", false) });
2770          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint32"), type = ProcessTypeString("unsigned int", false) });
2771          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint16"), type = ProcessTypeString("unsigned short", false) });
2772          globalContext.types.Add((BTNode)Symbol { string = CopyString("byte"), type = ProcessTypeString("unsigned char", false) });
2773       }
2774
2775       fileName = this.fileName;
2776       project = null;
2777       if(ide.workspace && ide.workspace.projects && fileName)
2778       {
2779          for(p : ide.workspace.projects)
2780          {
2781             char path[MAX_LOCATION];
2782             ProjectNode pn;
2783             MakePathRelative(fileName, p.topNode.path, path);
2784             MakeSlashPath(path);
2785
2786             pn = p.topNode.FindWithPath(path, false);
2787             if(pn)
2788             {
2789                project = p;
2790                break;
2791             }
2792          }
2793       }
2794       if(!project)
2795          project = ide.project;
2796          
2797       GetWorkingDir(oldWorkDir, MAX_LOCATION);
2798       if(project)
2799          ChangeWorkingDir(project.topNode.path);
2800
2801       SetSomeSourceFileStack(fileName ? fileName : "", 0); //strcpy(sourceFileStack[0], fileName ? fileName : "");
2802
2803       GetLastDirectory(fileName, mainModuleName);
2804       GetExtension(mainModuleName, extension);
2805
2806       SetBuildingEcereCom(false);
2807       SetBuildingEcereComModule(false);
2808
2809       // TODO: Get symbolsDir from project settings instead...
2810       if(ide.projectView)
2811       {
2812          CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2813          ProjectConfig config = project.config;
2814          int bitDepth = ide.workspace.bitDepth;
2815          DirExpression objDir = project.GetObjDir(compiler, config, bitDepth);
2816          SetSymbolsDir(objDir.dir);
2817          ide.SetPath(true, compiler, config, bitDepth);
2818
2819          delete objDir;
2820          delete compiler;
2821          // SetIncludeDirs(ide.projectView.project.config.includeDirs);
2822          // SetSysIncludeDirs(ide.ideSettings.systemDirs[includes]);
2823       }
2824       else
2825       {
2826          switch(GetRuntimePlatform())
2827          {
2828             case win32: SetSymbolsDir("obj/debug.win32"); break;
2829             case tux:   SetSymbolsDir("obj/debug.linux"); break;
2830             case apple: SetSymbolsDir("obj/debug.apple"); break;
2831          }         
2832          SetIncludeDirs(null);
2833          SetSysIncludeDirs(null);
2834       }
2835
2836       {
2837          if(ide.projectView && ide.projectView.IsModuleInProject(this.fileName))
2838          {
2839             // TODO FIX for configless project
2840             if(ide.project.config && ide.project.config.options && ide.project.config.options.preprocessorDefinitions)
2841             {
2842                for(item : ide.project.config.options.preprocessorDefinitions)
2843                {
2844                   if(!strcmp(item, "BUILDING_ECERE_COM"))
2845                   {
2846                      SetBuildingEcereCom(true);
2847                      break;
2848                   }
2849                }
2850             }
2851          }
2852          
2853          if(!(strcmpi(mainModuleName, "instance.ec") && strcmpi(mainModuleName, "BinaryTree.ec") &&
2854             strcmpi(mainModuleName, "dataTypes.ec") && strcmpi(mainModuleName, "OldList.ec") &&
2855             strcmpi(mainModuleName, "String.ec") && strcmpi(mainModuleName, "BTNode.ec") &&
2856             strcmpi(mainModuleName, "Array.ec") && strcmpi(mainModuleName, "AVLTree.ec") &&
2857             strcmpi(mainModuleName, "BuiltInContainer.ec") && strcmpi(mainModuleName, "Container.ec") &&
2858             strcmpi(mainModuleName, "CustomAVLTree.ec") && strcmpi(mainModuleName, "LinkList.ec") &&
2859             strcmpi(mainModuleName, "List.ec") && strcmpi(mainModuleName, "Map.ec") &&
2860             strcmpi(mainModuleName, "Mutex.ec")))
2861          {
2862             SetBuildingEcereComModule(true);
2863          }
2864
2865          // Predeclare all classes
2866          {
2867             char symFile[MAX_FILENAME];
2868             char symLocation[MAX_LOCATION];
2869             ImportedModule module, next;
2870
2871             GetLastDirectory(fileName, symFile);
2872             ChangeExtension(symFile, "sym", symFile);
2873
2874             strcpy(symLocation, GetSymbolsDir());
2875             PathCat(symLocation, symFile);
2876             
2877             // if(!GetEcereImported() && !GetBuildingEcereCom())
2878             if(!strcmp(extension, "ec") || !strcmp(extension, "eh"))
2879             {
2880 #ifdef _TIMINGS
2881                startTime = GetTime();
2882 #endif
2883                eModule_LoadStrict(privateModule, "ecereCOM", privateAccess);
2884 #ifdef _TIMINGS
2885                printf("Loading ecereCOM took %.3f seconds\n", GetTime() - startTime);
2886 #endif
2887             }
2888
2889 #ifdef _TIMINGS
2890             startTime = GetTime();
2891 #endif
2892             // LoadSymbols(symLocation, normalImport, true);
2893             LoadSymbols(symLocation, preDeclImport, false);
2894 #ifdef _TIMINGS
2895             printf("Loading symbols took %.3f seconds\n", GetTime() - startTime);
2896 #endif
2897
2898             for(module = defines.first; module; module = next)
2899             {
2900                next = module.next;
2901                if(module.type == moduleDefinition && strcmpi(module.name, mainModuleName))
2902                {
2903                   delete module.name;
2904                   defines.Delete(module);
2905                }
2906             }
2907          }
2908       }
2909       if(!strcmp(extension, "ec") || !strcmp(extension, "eh"))
2910       {
2911          SetDefaultDeclMode(privateAccess);
2912          SetDeclMode(privateAccess);
2913       }
2914       else
2915       {
2916          SetDefaultDeclMode(defaultAccess);
2917          SetDeclMode(defaultAccess);
2918       }
2919
2920       StripExtension(mainModuleName);
2921       module = ImportedModule { name = CopyString(mainModuleName), type = moduleDefinition };
2922       defines.AddName(module);
2923
2924    #ifdef _DEBUG
2925       // SetYydebug(true);
2926    #endif
2927       resetScanner();
2928
2929 #ifdef _TIMINGS
2930       startTime = GetTime();
2931       startFindClass = checkTypeTotalTime;
2932 #endif
2933       ParseEc();
2934 #ifdef _TIMINGS
2935       printf("ParseEc took %.3f seconds, out of which %.3f seconds were in CheckType\n", GetTime() - startTime, checkTypeTotalTime - startFindClass);
2936 #endif
2937       CheckDataRedefinitions();
2938       SetYydebug(false);
2939
2940       SetIncludeDirs(null);
2941       SetSysIncludeDirs(null);
2942       
2943       delete editFile;
2944       fileInput = null;
2945       SetFileInput(null);
2946
2947       if(GetAST())
2948       {
2949          ast = GetAST();
2950          
2951 #ifdef _TIMINGS
2952          startTime = GetTime();
2953 #endif
2954          PrePreProcessClassDefinitions();
2955          ComputeModuleClasses(privateModule);
2956          PreProcessClassDefinitions();
2957          ProcessClassDefinitions();
2958 #ifdef _TIMINGS
2959          printf("Initial Passes took %.3f seconds\n", GetTime() - startTime);
2960          startTime = GetTime();
2961 #endif
2962
2963          ComputeDataTypes();
2964 #ifdef _TIMINGS
2965          printf("ComputeDataTypes took %.3f seconds\n", GetTime() - startTime);
2966          startTime = GetTime();
2967 #endif
2968          ProcessInstantiations();
2969 #ifdef _TIMINGS
2970          printf("ProcessInstantiations took %.3f seconds\n", GetTime() - startTime);
2971 #endif
2972
2973          if(!strcmp(extension, "ec") || !strcmp(extension, "eh"))
2974          {
2975             Class windowClass = eSystem_FindClass(this.privateModule, "ecere::gui::Window");
2976             if(!windowClass || windowClass.internalDecl)
2977             {
2978 #ifdef _TIMINGS
2979                startTime = GetTime();
2980 #endif
2981                // *** COMMENTED THIS OUT DUE TO ecereCOM issues
2982                // eModule_Load(this.privateModule.application.allModules.first ? this.privateModule.application.allModules.first : this.privateModule, "ecere", privateAccess);
2983                eModule_Load(this.privateModule, "ecere", privateAccess);
2984 #ifdef _TIMINGS
2985                printf("Loading ecere.dll took %.3f seconds\n", GetTime() - startTime);
2986 #endif
2987             }
2988             windowClass = eSystem_FindClass(this.privateModule, "ecere::gui::Window");
2989
2990             if(windowClass && windowClass.data)
2991                ApplySkin(windowClass, app.currentSkin.name, null);
2992          }
2993
2994 #ifdef _TIMINGS
2995          startTime = GetTime();
2996 #endif
2997          for(external = ast->first; external; external = external.next)
2998          {
2999             if(external.type == classExternal)
3000             {
3001                ClassDefinition _class = external._class;
3002                if(_class.baseSpecs && _class.baseSpecs->first && ((Specifier)_class.baseSpecs->first).type == nameSpecifier ) // classSpecifier
3003                {
3004                   Class regClass = eSystem_FindClass(this.privateModule, ((Specifier)_class.baseSpecs->first).name);
3005                   if(regClass)
3006                   {
3007                      if(eClass_GetDesigner(regClass) && !GetBuildingEcereComModule())
3008                      {
3009                         Instance instance = eInstance_New(regClass);
3010                         ObjectInfo classObject 
3011                         {
3012                            name = CopyString(_class._class.name);
3013                            instance = instance;
3014                            classDefinition = _class;
3015                            oClass = classObject;
3016                         };
3017                         Symbol symbol;
3018                         classes.Add(classObject);
3019
3020                         incref instance;
3021
3022                         // Moved this at bottom so that the file dialog doesn't show up in eCom
3023                         designer.CreateObject(instance, classObject, true, null);
3024                         sheet.AddObject(classObject, classObject.name ? classObject.name : _class._class.name, typeClass, false);
3025
3026                         if(_class.definitions)
3027                         {
3028                            ClassDef def;
3029                            ObjectInfo object;
3030                            for(def = _class.definitions->first; def; def = def.next)
3031                            {
3032                               switch(def.type)
3033                               {
3034                                  case defaultPropertiesClassDef:
3035                                  {
3036                                     MemberInit propDef;
3037                                     for(propDef = def.defProperties->first; propDef; propDef = propDef.next)
3038                                     {
3039                                        Identifier id = propDef.identifiers->first;
3040                                        if(id)
3041                                        {
3042                                           Property prop = eClass_FindProperty(regClass, id.string, this.privateModule);
3043                                           if(prop)
3044                                           {
3045                                              Class propertyClass = prop.dataTypeClass;
3046                                              if(!propertyClass)
3047                                                 propertyClass = prop.dataTypeClass = eSystem_FindClass(this.privateModule, prop.dataTypeString);
3048                                              if(prop.compiled && prop.Set && prop.Get && propertyClass && propDef.initializer && propDef.initializer.type == expInitializer && propDef.initializer.exp)
3049                                              {
3050                                                 FreeType(propDef.initializer.exp.destType);
3051                                                 propDef.initializer.exp.destType = MkClassType(propertyClass.name);
3052                                                 ProcessExpressionType(propDef.initializer.exp);
3053                                              
3054                                                 if(propertyClass.type == structClass || propertyClass.type == noHeadClass || propertyClass.type == normalClass)
3055                                                 {
3056                                                    Expression computed = CopyExpression(propDef.initializer.exp);
3057                                                    ComputeExpression(computed);
3058
3059                                                    if(computed.isConstant && computed.type == instanceExp && !id.next)
3060                                                    {
3061                                                       if(prop.Set)
3062                                                       {
3063                                                          if(computed.instance._class && computed.instance._class.symbol &&
3064                                                             computed.instance._class.symbol.registered && 
3065                                                             eClass_IsDerived(computed.instance._class.symbol.registered, propertyClass))
3066                                                          {
3067                                                             ((void (*)(void *, void *))(void *)prop.Set)(instance, computed.instance.data);
3068
3069                                                             // This was saved in the control and shouldn't be freed by FreeExpression...
3070                                                             if(propertyClass.type == normalClass)
3071                                                                computed.instance.data = null;
3072                                                          }
3073                                                       }
3074                                                    }
3075                                                    // MOVED THIS UP NOW THAT char * IS A NORMAL CLASS
3076                                                    else if(computed.type == stringExp && propertyClass.dataTypeString && strstr(propertyClass.dataTypeString, "char *"))
3077                                                    {
3078                                                       String temp = new char[strlen(computed.string)+1];
3079                                                       ReadString(temp, computed.string);
3080                                                       ((void (*)(void *, void *))(void *)prop.Set)(instance, temp);
3081                                                       delete temp;
3082                                                    }
3083                                                    else
3084                                                       propDef.variable = true;
3085                                                    
3086                                                    FreeExpression(computed);
3087                                                 }
3088                                                 else
3089                                                 {
3090                                                    Expression computed = CopyExpression(propDef.initializer.exp);
3091                                                    ComputeExpression(computed);
3092                                                    if(computed.isConstant)
3093                                                    {
3094                                                       //if(computed.type == memberExp) computed = computed.member.exp;
3095
3096                                                       if(computed.type == constantExp)
3097                                                       {
3098                                                          Operand value = GetOperand(computed);
3099                                                          DataValue valueData;
3100                                                          valueData.i64 = value.i64;
3101                                                          SetProperty(prop, instance, valueData);
3102                                                       }
3103                                                       else if(computed.type == stringExp && propertyClass.dataTypeString && strstr(propertyClass.dataTypeString, "char *"))
3104                                                       {
3105                                                          String temp = new char[strlen(computed.string)+1];
3106                                                          ReadString(temp, computed.string);
3107                                                          ((void (*)(void *, void *))(void *)prop.Set)(instance, temp);
3108                                                          delete temp;
3109                                                       }
3110                                                    }
3111                                                    else
3112                                                       propDef.variable = true;
3113
3114                                                    FreeExpression(computed);
3115                                                 }
3116                                              }
3117                                              else
3118                                                 propDef.variable = true;
3119                                           }
3120                                           else
3121                                           {
3122                                              Method method = eClass_FindMethod(regClass, id.string, this.privateModule);
3123                                              if(method && method.type == virtualMethod && propDef.initializer && propDef.initializer.type == expInitializer && 
3124                                                 propDef.initializer.exp && propDef.initializer.exp.type == identifierExp)
3125                                              {
3126                                                 ClassDef def;
3127                                                 // Maintain a list in FunctionDefinition of who is attached to it
3128                                                 for(def = _class.definitions->first; def; def = def.next)
3129                                                 {
3130                                                    if(def.type == functionClassDef)
3131                                                    {
3132                                                       ClassFunction function = def.function;
3133                                                       if(!strcmp(function.declarator.symbol.string, propDef.initializer.exp.identifier.string))
3134                                                       {
3135                                                          function.attached.Add(OldLink { data = method });
3136                                                       }
3137                                                    }
3138                                                 }
3139                                              }                                          
3140                                           }
3141                                        }
3142                                     }
3143                                     break;
3144                                  }
3145                                  case declarationClassDef:
3146                                  {
3147                                     Declaration decl = def.decl;
3148                                     switch(decl.type)
3149                                     {
3150                                        case instDeclaration:
3151                                        {
3152                                           Instantiation inst = decl.inst;
3153                                           Class instClass = eSystem_FindClass(this.privateModule, inst._class.name);
3154                                           if(instClass && eClass_GetDesigner(instClass))
3155                                           {
3156                                              Instance control = eInstance_New(instClass);
3157                                              incref control;
3158
3159                                              object = ObjectInfo
3160                                              {
3161                                                 oClass = classObject;
3162                                                 instance = control;
3163                                                 instCode = inst;
3164                                              };
3165                                              classObject.instances.Add(object);
3166                                              if(inst.exp)
3167                                                 // TOCHECK: Why is this needed now?
3168                                                 object.name = CopyString((inst.exp.type == memberExp) ? inst.exp.member.member.string : inst.exp.identifier.string);
3169                                              def.object = object;
3170
3171                                              // if(object.name) { symbol = eList_Add(&curContext.symbols, sizeof(Symbol)); symbol.string = object.name; symbol.type = MkClassType(instClass.name); }
3172
3173                                              designer.CreateObject(control, object, false, classObject.instance);
3174                                              sheet.AddObject(object, object.name ? object.name : inst._class.name, typeData, false);
3175                                           }
3176                                           break;
3177                                        }
3178                                     }
3179                                     break;
3180                                  }
3181                               }
3182                            }
3183
3184                            // Second pass, process instantiation members
3185                            object = null;
3186                            for(def = _class.definitions->first; def; def = def.next)
3187                            {
3188                               switch(def.type)
3189                               {
3190                                  case declarationClassDef:
3191                                  {
3192                                     Declaration decl = def.decl;
3193                                     switch(decl.type)
3194                                     {
3195                                        case instDeclaration:
3196                                        {
3197                                           Instantiation inst = decl.inst;
3198                                           Class instClass = eSystem_FindClass(this.privateModule, inst._class.name);
3199                                           if(instClass && eClass_GetDesigner(instClass))
3200                                           {
3201                                              Instance control;
3202                                              object = object ? object.next : classObject.instances.first;
3203                                              control = object.instance;                                             
3204                                              
3205                                              if(inst.members)
3206                                              {
3207                                                 MembersInit members;
3208                                                 for(members = inst.members->first; members; members = members.next)
3209                                                 {
3210                                                    switch(members.type)
3211                                                    {
3212                                                       case dataMembersInit:
3213                                                       {
3214                                                          if(members.dataMembers)
3215                                                          {
3216                                                             MemberInit member;
3217                                                             DataMember curMember = null;
3218                                                             Class curClass = null;
3219                                                             DataMember subMemberStack[256];
3220                                                             int subMemberStackPos = 0;
3221
3222                                                             for(member = members.dataMembers->first; member; member = member.next)
3223                                                             {
3224                                                                bool found = false;
3225                                                                Identifier ident = member.identifiers ? member.identifiers->first : null;
3226                                                                if(ident)
3227                                                                {
3228                                                                   DataMember _subMemberStack[256];
3229                                                                   int _subMemberStackPos = 0;
3230                                                                   DataMember thisMember = (DataMember)eClass_FindDataMember(instClass, ident.string, privateModule, _subMemberStack, &_subMemberStackPos);
3231
3232                                                                   if(!thisMember)
3233                                                                   {
3234                                                                      thisMember = (DataMember)eClass_FindProperty(instClass, ident.string, privateModule);
3235                                                                   }
3236                                                                   if(thisMember && thisMember.memberAccess == publicAccess)
3237                                                                   {
3238                                                                      curMember = thisMember;
3239                                                                      curClass = curMember._class;
3240                                                                      memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
3241                                                                      subMemberStackPos = _subMemberStackPos;
3242                                                                      found = true;
3243                                                                   }
3244                                                                }
3245                                                                else
3246                                                                {
3247                                                                   eClass_FindNextMember(instClass, &curClass, (DataMember *)&curMember, subMemberStack, &subMemberStackPos);
3248                                                                   if(curMember) found = true;
3249                                                                }
3250                                                                if(found && curMember.isProperty)
3251                                                                {
3252                                                                   Property prop = (Property) curMember;
3253                                                                   Class propertyClass = prop.dataTypeClass;
3254                                                                   if(!propertyClass)
3255                                                                      propertyClass = prop.dataTypeClass = eSystem_FindClass(this.privateModule, prop.dataTypeString);
3256
3257                                                                   if(prop.compiled && prop.Set && prop.Get && propertyClass && member.initializer && member.initializer.type == expInitializer && member.initializer.exp)
3258                                                                   {
3259                                                                      FreeType(member.initializer.exp.destType);
3260                                                                      member.initializer.exp.destType = MkClassType(propertyClass.name);
3261                                                                      if(propertyClass)
3262                                                                      {
3263                                                                         ProcessExpressionType(member.initializer.exp);
3264                                        
3265                                                                         if(propertyClass.type == structClass || propertyClass.type == normalClass || propertyClass.type == noHeadClass)
3266                                                                         {
3267                                                                            Expression computed;
3268 #ifdef _DEBUG
3269                                                                            /*char debugExpString[4096];
3270                                                                            debugExpString[0] = '\0';
3271                                                                            PrintExpression(member.initializer.exp, debugExpString);*/
3272 #endif
3273                                                                            computed = CopyExpression(member.initializer.exp);
3274                                                                            if(computed)
3275                                                                            {
3276                                                                               ComputeExpression(computed);
3277                                                                               
3278                                                                               if(computed.type == instanceExp && computed.isConstant && computed.isConstant)
3279                                                                               {
3280                                                                                  if(computed.instance.data)
3281                                                                                  {
3282                                                                                     if(computed.instance._class && computed.instance._class.symbol &&
3283                                                                                        computed.instance._class.symbol.registered && 
3284                                                                                        eClass_IsDerived(computed.instance._class.symbol.registered, propertyClass))
3285                                                                                     {
3286                                                                                        ((void (*)(void *, void *))(void *)prop.Set)(control, computed.instance.data);
3287
3288                                                                                        // This was saved in the control and shouldn't be freed by FreeExpression...
3289                                                                                        if(propertyClass.type == normalClass)
3290                                                                                           computed.instance.data = null;
3291                                                                                     }
3292                                                                                  }
3293                                                                               }
3294                                                                               else if(computed.type == identifierExp)
3295                                                                               {
3296                                                                                  member.variable = true;
3297
3298                                                                                  if(eClass_GetDesigner(propertyClass))
3299                                                                                  //if(prop.Set)
3300                                                                                  {
3301                                                                                     char * name = computed.identifier.string;
3302                                                                                     if(!strcmp(name, "this"))
3303                                                                                     {
3304                                                                                        if(prop.Set)
3305                                                                                           ((void (*)(void *, void *))(void *)prop.Set)(control, instance);
3306                                                                                        member.variable = false;
3307                                                                                     }
3308                                                                                     else
3309                                                                                     {
3310                                                                                        ObjectInfo check;
3311                                                                                        for(check = classObject.instances.first; check; check = check.next)
3312                                                                                           if(check.name && !strcmp(name, check.name))
3313                                                                                           {
3314                                                                                              if(prop.Set)
3315                                                                                                 ((void (*)(void *, void *))(void *)prop.Set)(control, check.instance);
3316                                                                                              member.variable = false;
3317                                                                                              break;
3318                                                                                           }
3319                                                                                     }
3320                                                                                  }
3321                                                                               }
3322                                                                               else if(computed.type == memberExp)
3323                                                                               {
3324                                                                                  member.variable = true;
3325                                                                                  if(computed.member.exp.type == identifierExp)
3326                                                                                  {
3327                                                                                     char * name = computed.member.exp.identifier.string;
3328                                                                                     if(!strcmp(name, "this"))
3329                                                                                     {
3330                                                                                        char * name = computed.member.member.string;
3331                                                                                        {
3332                                                                                           ObjectInfo check;
3333                                                                                           for(check = classObject.instances.first; check; check = check.next)
3334                                                                                              if(check.name && !strcmp(name, check.name))
3335                                                                                              {
3336                                                                                                 if(prop.Set)
3337                                                                                                    ((void (*)(void *, void *))(void *)prop.Set)(control, check.instance);
3338                                                                                                 member.variable = false;
3339                                                                                                 break;
3340                                                                                              }
3341                                                                                        }
3342                                                                                     }
3343                                                                                     else
3344                                                                                     {
3345                                                                                        ObjectInfo check;
3346                                                                                        for(check = classObject.instances.first; check; check = check.next)
3347                                                                                        {
3348                                                                                           if(check.name && !strcmp(name, check.name))
3349                                                                                           {
3350                                                                                              Property getProperty = eClass_FindProperty(check.instance._class, computed.member.member.string, this.privateModule);
3351                                                                                              if(getProperty)
3352                                                                                              {
3353                                                                                                 DataValue value { };
3354                                                                                                 GetProperty(getProperty, check.instance, &value);
3355                                                                                                 SetProperty(prop, control, value);
3356                                                                                                 member.variable = false;
3357                                                                                              }
3358                                                                                              break;
3359                                                                                           }
3360                                                                                        }
3361                                                                                     }
3362                                                                                  }
3363                                                                               }
3364                                                                               // MOVED THIS UP NOW THAT char * IS A NORMAL CLASS
3365                                                                               else if(computed.isConstant && computed.type == stringExp && propertyClass.dataTypeString && strstr(propertyClass.dataTypeString, "char *"))
3366                                                                               {
3367                                                                                  String temp = new char[strlen(computed.string)+1];
3368                                                                                  ReadString(temp, computed.string);
3369                                                                                  ((void (*)(void *, void *))(void *)prop.Set)(control, temp);
3370                                                                                  delete temp;
3371                                                                               }
3372                                                                               else
3373                                                                                  member.variable = true;
3374
3375                                                                               FreeExpression(computed);
3376                                                                            }
3377                                                                         }
3378                                                                         else
3379                                                                         {
3380                                                                            Expression computed = CopyExpression(member.initializer.exp);
3381                                                                            if(computed)
3382                                                                            {
3383                                                                               ComputeExpression(computed);
3384                                                                               if(computed.isConstant)
3385                                                                               {
3386                                                                                  if(computed.type == constantExp && (!propertyClass.dataTypeString || strcmp(propertyClass.dataTypeString, "char *"))) //(strcmp(propertyClass.name, "char *") && (strcmp(propertyClass.name, "String"))))
3387                                                                                  {
3388                                                                                     if(!strcmp(propertyClass.dataTypeString, "float"))
3389                                                                                        ((void (*)(void *, float))(void *)prop.Set)(control, (float)strtod(computed.constant, null));
3390                                                                                     else if(!strcmp(propertyClass.dataTypeString, "double"))
3391                                                                                        ((void (*)(void *, double))(void *)prop.Set)(control, strtod(computed.constant, null));
3392                                                                                     else
3393                                                                                        ((void (*)(void *, int))(void *)prop.Set)(control, strtol(computed.constant, null, 0));
3394                                                                                  }
3395                                                                                  else if(computed.type == stringExp  && propertyClass.dataTypeString && strstr(propertyClass.dataTypeString, "char *"))
3396                                                                                  {
3397                                                                                     String temp = new char[strlen(computed.string)+1];
3398                                                                                     ReadString(temp, computed.string);
3399                                                                                     ((void (*)(void *, void *))(void *)prop.Set)(control, temp);
3400                                                                                     delete temp;
3401                                                                                  }
3402                                                                               }
3403                                                                               else
3404                                                                                  member.variable = true;
3405
3406                                                                               FreeExpression(computed);
3407                                                                            }
3408                                                                         }
3409                                                                      }
3410                                                                   }
3411                                                                   else
3412                                                                      member.variable = true;
3413                                                                }
3414                                                                else if(ident && member.initializer && member.initializer.type == expInitializer && member.initializer.exp && 
3415                                                                   member.initializer.exp.type == memberExp) // identifierExp
3416                                                                {
3417                                                                   Method method = eClass_FindMethod(instClass, ident.string, this.privateModule);
3418                                                                   if(method && method.type == virtualMethod)
3419                                                                   {
3420                                                                      ClassDef def;
3421                                                                      // Maintain a list in FunctionDefinition of who is attached to it
3422                                                                      for(def = _class.definitions->first; def; def = def.next)
3423                                                                      {
3424                                                                         if(def.type == functionClassDef)
3425                                                                         {
3426                                                                            ClassFunction function = def.function;
3427                                                                            Identifier id = (member.initializer.exp.type == memberExp) ? member.initializer.exp.member.member : member.initializer.exp.identifier;
3428                                                                            if(function.declarator && !strcmp(function.declarator.symbol.string, id.string))
3429                                                                            {
3430                                                                               function.attached.Add(OldLink { data = method });
3431                                                                               // Reference this particular instance?
3432                                                                            }
3433                                                                         }
3434                                                                      }
3435                                                                   }
3436                                                                }
3437                                                                id++;
3438                                                             }
3439                                                          }
3440                                                          break;
3441                                                       }
3442                                                    }
3443                                                 }                                          
3444                                              }
3445
3446                                              designer.PostCreateObject(object.instance, object, false, classObject.instance);
3447                                              break;
3448                                           }
3449                                        }
3450                                        break;
3451                                     }
3452                                  }
3453                               }
3454                            }
3455                         }
3456
3457                         //designer.CreateObject(instance, classObject, true, null);
3458                         //sheet.AddObject(classObject, classObject.name ? classObject.name : _class._class.name, classType, false);
3459
3460                         designer.PostCreateObject(instance, classObject, true, null);
3461
3462                         //instance.state = Hidden;
3463                         //instance.Create();
3464                         //instance.SetState(Normal, true, 0);
3465                      }
3466                   }
3467                }
3468             }
3469          }
3470
3471          SetAST(null);
3472 #ifdef _TIMINGS
3473          printf("Class/Instance Processing took %.3f seconds\n", GetTime() - startTime);
3474 #endif
3475       }
3476
3477       // Restore Selection
3478       if(selectedClassName)
3479       {
3480          ObjectInfo oClass;
3481          for(oClass = classes.first; oClass; oClass = oClass.next)
3482          {
3483             if(!strcmp(oClass.name, selectedClassName))
3484             {
3485                this.oClass = oClass;
3486                break;
3487             }
3488          }
3489          delete selectedClassName;
3490       }
3491       if(this.oClass)
3492       {
3493          if(selectedName)
3494          {
3495             ObjectInfo check;
3496             int pos = 0;
3497          
3498             for(check = this.oClass.instances.first; check; check = check.next)
3499             {
3500                if(check.name && !strcmp(check.name, selectedName))
3501                {
3502                   this.selected = check;
3503                   break;
3504                }
3505             }
3506             if(!check)
3507             {
3508                if(this.oClass.instances.first)
3509                   this.selected = this.oClass.instances.first;
3510                else
3511                   this.selected = this.oClass;
3512             }
3513          }
3514          else if(selectedPos == -1 || !this.oClass.instances.count)
3515             this.selected = this.oClass;
3516          else
3517          {
3518             ObjectInfo check;
3519             int pos = 0;
3520
3521             if(selectedPos > this.oClass.instances.count)
3522                selectedPos = 0;
3523             for(check = this.oClass.instances.first; check; check = check.next)
3524             {
3525                if(selectedPos == pos++)
3526                {
3527                   this.selected = check;
3528                   break;
3529                }
3530             }
3531          }
3532       }
3533       else
3534       {
3535          this.oClass = classes.first;
3536          this.selected = (this.oClass && this.oClass.instances.first) ? this.oClass.instances.first : this.oClass;
3537       }
3538       delete selectedName;
3539       SetSymbolsDir(null);
3540
3541       if(sheet.codeEditor == this)
3542          sheet.SelectObject(selected);
3543       Update(null);
3544
3545       codeModified = false;
3546
3547       // TESTING THIS TO NOT GET EMPTY PARAMETERS
3548       if(paramsShown)
3549       {
3550          InvokeParameters(false, false, false);
3551       }
3552
3553       editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
3554
3555       reentrant = false;
3556
3557       updatingCode--;
3558
3559       ChangeWorkingDir(oldWorkDir);
3560 #ifdef _TIMINGS
3561       printf("Total FindClass time is %.3f seconds, out of which %.3f is in Ignore NS\n\n", findClassTotalTime, findClassIgnoreNSTotalTime);
3562       printf("Total CheckType time is %.3f seconds\n\n", checkTypeTotalTime);
3563       printf("Total MkExternalImport time is %.3f seconds\n\n", externalImportTotalTime);
3564       printf("Total FindSymbol time is %.3f seconds\n\n", findSymbolTotalTime);
3565       // printf("Total Class Members Find time is %.3f seconds\n\n", GetClassFindTime());
3566       
3567       printf("Whole ParseCode function took %.3f seconds\n\n", GetTime() - parseCodeStart);
3568 #endif
3569       if(inUseDebug && ide.projectView)
3570          ide.debugger.EvaluateWatches();
3571
3572       delete pathBackup;
3573    }
3574
3575    void UpdateInstanceCodeClass(Class _class, ObjectInfo object, EditBoxStream f, Instance test, bool * prev, bool * lastIsMethod, DataMember * curMember, Class * curClass)
3576    {
3577       Property propIt;
3578       Window control = (Window)object.instance;
3579       ObjectInfo classObject = object.oClass;
3580
3581       if(_class.base && _class.base.type != systemClass) UpdateInstanceCodeClass(_class.base, object, f, test, prev, lastIsMethod, curMember, curClass);
3582
3583       if(!strcmp(_class.name, "DesignerBase")) return;
3584
3585       for(propIt = _class.membersAndProperties.first; propIt; propIt = propIt.next)
3586       {
3587          Property prop = eClass_FindProperty(object.instance._class, propIt.name, privateModule);
3588          if(prop && prop.isProperty && !prop.conversion && eClass_FindProperty(object.instance._class, prop.name, privateModule))
3589          {
3590             if(prop.Set && prop.Get && prop.dataTypeString && strcmp(prop.name, "name") && !Code_IsPropertyDisabled(object, prop.name) &&
3591                prop.compiled && (!prop.IsSet || prop.IsSet(control)))
3592             {
3593                Class dataType = prop.dataTypeClass;
3594                if(!dataType)
3595                   dataType = prop.dataTypeClass = eSystem_FindClass(this.privateModule, prop.dataTypeString);
3596          
3597                if(dataType)
3598                {
3599                   if(dataType.type == structClass)
3600                   {
3601                      void * dataForm = new0 byte[dataType.structSize];
3602                      void * dataTest = new0 byte[dataType.structSize];
3603                
3604                      ((void (*)(void *, void *))(void *)prop.Get)(control, dataForm);
3605                      ((void (*)(void *, void *))(void *)prop.Get)(test, dataTest);
3606                
3607                      if((prop.IsSet && !prop.IsSet(test)) || ((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
3608                      {
3609                         char tempString[1024] = "";
3610                         char * string = "";
3611                         bool needClass = true;
3612                         if(*prev)
3613                            f.Printf(", ");
3614                   
3615                         ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
3616                   
3617                         string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
3618                         
3619                         eClass_FindNextMember(_class, curClass, curMember, null, null);
3620                         if(*curMember != (DataMember)prop)
3621                            f.Printf("%s = ", prop.name);
3622
3623                         *curMember = (DataMember)prop;
3624                         *curClass = curMember->_class;
3625
3626                         if(needClass)
3627                            f.Printf("%c %s %c", /*dataType.name, */OpenBracket, string, CloseBracket);
3628                         else
3629                            f.Printf("%s", string);
3630                         *prev = true;
3631                      }
3632
3633                      delete dataForm;
3634                      delete dataTest;
3635                   }
3636                   else if(dataType.type == normalClass || dataType.type == noHeadClass)
3637                   {
3638                      void * dataForm, * dataTest;
3639                
3640                      dataForm = ((void *(*)(void *))(void *)prop.Get)(control);
3641                      dataTest = ((void *(*)(void *))(void *)prop.Get)(test);
3642                
3643                      if((prop.IsSet && !prop.IsSet(test)) || ((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
3644                      {
3645                         char tempString[1024] = "";
3646                         char * string = "";
3647                         if(*prev)
3648                            f.Printf(", ");
3649                   
3650                         ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
3651                   
3652                         eClass_FindNextMember(_class, curClass, curMember, null, null);
3653                         if(*curMember != (DataMember)prop)
3654                            f.Printf("%s = ", prop.name);
3655                         *curMember = (DataMember)prop;
3656                         *curClass = curMember->_class;
3657
3658                         if(eClass_GetDesigner(dataType))
3659                         {
3660                            if(eClass_IsDerived(classObject.instance._class, dataType) && classObject.instance == dataForm)
3661                            //if(!strcmp(classObject.instance._class.name, dataType.name) && classObject.instance == dataForm)
3662                               f.Printf("this", prop.name);
3663                            else
3664                            {
3665                               //ObjectInfo classObject;
3666                               //for(classObject = classes.first; classObject; classObject = classObject.next)
3667                               {
3668                                  ObjectInfo object;
3669
3670                                  for(object = classObject.instances.first; object; object = object.next)
3671                                  {
3672                                     if(!object.deleted && eClass_IsDerived(object.instance._class, dataType) && object.instance == dataForm && object.name)
3673                                     {
3674                                        f.Printf("%s", object.name);
3675                                        break;
3676                                     }
3677                                  }
3678
3679                                  if(!object)
3680                                  {
3681                                     bool needClass = true;
3682                                     string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
3683                                     f.Printf("%s", string);
3684                                  }
3685                               }
3686                            }
3687                         }
3688                         else
3689                         {
3690                            bool needClass = true;
3691                            string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
3692
3693                            if(!strcmp(dataType.dataTypeString, "char *"))
3694                            {
3695                               f.Printf("\"");
3696                               OutputString(f, string);
3697                               f.Puts("\"");
3698                            }
3699                            else if(needClass)
3700                               f.Printf("%c %s %c", /*dataType.name, */OpenBracket, string, CloseBracket);
3701                            else
3702                               f.Printf("%s", string);
3703                         }
3704                         *prev = true;
3705                         *lastIsMethod = false;
3706                      }
3707                   }
3708                   else
3709                   {
3710                      DataValue dataForm, dataTest;
3711                
3712                      GetProperty(prop, control, &dataForm);
3713                      GetProperty(prop, test, &dataTest);
3714                
3715                      if((prop.IsSet && !prop.IsSet(test)) || ((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, &dataForm, &dataTest))
3716                      {
3717                         char * string;
3718                         char tempString[1024] = "";
3719                         SetProperty(prop, test, dataForm);
3720                   
3721                         if(dataType.type != bitClass)
3722                         {
3723                            bool needClass = true;
3724
3725                            if(dataType.type == enumClass)
3726                            {
3727                               NamedLink value;
3728                               Class enumClass = eSystem_FindClass(privateModule, "enum");
3729                               EnumClassData e = ACCESS_CLASSDATA(dataType, enumClass);
3730
3731                               for(value = e.values.first; value; value = value.next)
3732                               {
3733                                  if((int)value.data == dataForm.i)
3734                                  {
3735                                     string = value.name;
3736                                     break;
3737                                  }
3738                               }
3739                            }
3740                            else
3741                               string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, &dataForm, tempString, null, &needClass);
3742                      
3743                            if(string && string[0])
3744                            {
3745                               if(*prev)
3746                                  f.Printf(", ");
3747
3748                               eClass_FindNextMember(_class, curClass, curMember, null, null);
3749                               if(*curMember != (DataMember)prop)
3750                                  f.Printf("%s = ", prop.name);
3751                               *curMember = (DataMember)prop;
3752                               *curClass = curMember->_class;
3753
3754                               if(!strcmp(dataType.dataTypeString, "float") && strchr(string, '.'))
3755                                  f.Printf("%sf", string);
3756                               else
3757                                  f.Printf("%s", string);
3758                               *prev = true;
3759                            }
3760                         }
3761                         else if(dataType.type == bitClass)
3762                         {
3763                            bool needClass = true;
3764
3765                            if(*prev) f.Printf(", ");
3766
3767                            eClass_FindNextMember(_class, curClass, curMember, null, null);
3768                            if(*curMember != (DataMember)prop)
3769                               f.Printf("%s = ", prop.name);
3770                            *curMember = (DataMember)prop;
3771                            *curClass = curMember->_class;
3772
3773                            string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, &dataForm.ui, tempString, null, &needClass);
3774                            if(needClass)
3775                               f.Printf("%c %s %c", /*dataType.name, */OpenBracket, string, CloseBracket);
3776                            else
3777                               f.Printf("%s", string);
3778                            *prev = true;
3779                            *lastIsMethod = false;
3780                         }
3781                      }
3782                   }
3783                }
3784             }
3785          }
3786       }
3787    }
3788
3789    int UpdateInstanceCode(EditBoxStream f, int position, Class regClass, ObjectInfo object, bool * firstObject, char ** text, int * textSize, int movedFuncIdLen, int movedFuncIdPos)
3790    {
3791       Instantiation inst = object.instCode;
3792       Window control = (Window)object.instance;
3793       bool prev = false;
3794       bool methodPresent = false;
3795       Class _class;
3796       bool lastIsMethod = true;
3797       ObjectInfo classObject = object.oClass;
3798       
3799       if(inst)
3800       {
3801          if(object.deleted)
3802          {
3803             // Instance removed, delete it
3804             DeleteJunkBefore(f, inst.loc.start.pos, &position);
3805
3806             f.DeleteBytes(inst.loc.end.pos - inst.loc.start.pos + 1);
3807             position = inst.loc.end.pos + 1;
3808          }
3809          else
3810          {
3811             bool multiLine = false;
3812
3813             // Change the name
3814             // Check if it's an unnamed instance
3815             if(inst.exp)
3816             {
3817                f.Seek(inst.nameLoc.start.pos - position, current);
3818                f.DeleteBytes(inst.nameLoc.end.pos - inst.nameLoc.start.pos);
3819                position = inst.nameLoc.end.pos;
3820                if(object.name)
3821                   f.Printf(object.name);
3822                else
3823                {
3824                   char ch = 0;
3825                   f.Getc(&ch);
3826                   if(isspace(ch) && ch != '\n')
3827                   {
3828                      f.Seek(-1, current);
3829                      f.DeleteBytes(1);
3830                      position ++;
3831                   }
3832                }
3833             }
3834             else
3835             {
3836                int pos = inst.loc.start.pos; // + strlen(inst._class.name);
3837                char ch;
3838                f.Seek(pos - position, current);
3839                while(f.Getc(&ch))
3840                {  
3841                   if(isspace(ch))
3842                   {
3843                      f.Seek(-1, current);
3844                      break;
3845                   }
3846                   pos++;
3847                }
3848
3849                if(object.name)
3850                {
3851                   f.Puts(" ");
3852                   f.Puts(object.name);
3853                }
3854                position = pos;
3855             }
3856
3857             if((this.methodAction == actionAddMethod || this.moveAttached) && this.selected == object)
3858                methodPresent = true;
3859
3860             for(;;)
3861             {
3862                char ch = 0;
3863                if(!f.Getc(&ch))
3864                   break;
3865                position++;
3866                if(ch == OpenBracket)
3867                   break;
3868                if(ch == '\n')
3869                   multiLine = true;
3870             }
3871
3872             // TODO: Simplify this?
3873             if(methodPresent)
3874             {
3875                if(!multiLine)
3876                {
3877                   int count = 0;
3878                   int toDelete = 0;
3879                   int toAdd = 0;
3880
3881                   f.Seek(-1, current);
3882                   f.Puts("\n   ");
3883                   f.Seek(1, current);
3884                   //f.Puts("\n");
3885
3886                   // Fix indentation
3887                   for(;;)
3888                   {
3889                      char ch = 0;
3890                      if(!f.Getc(&ch))
3891                         break;
3892                      position++;
3893                      if(ch == '\n') { toDelete = count; count = 0; }
3894                      else if(isspace(ch)) count++;
3895                      else
3896                      {
3897                         f.Seek(-1, current);
3898                         position--;
3899                         if(count > 6)
3900                         {
3901                            toDelete += count - 6; 
3902                            count = 6;
3903                         }
3904                         else 
3905                            toAdd = 6 - count;
3906                         break;                              
3907                      }
3908                   }
3909                   if(toDelete)
3910                   {
3911                      f.Seek(-toDelete-count, current);
3912                      f.DeleteBytes(toDelete);
3913                      f.Seek(count, current);
3914                   }
3915                   if(toAdd)
3916                   {
3917                      int c;
3918                      for(c = 0; c<toAdd; c++)
3919                         f.Putc(' ');
3920                   }
3921                }
3922             }
3923             else
3924                methodPresent = multiLine;
3925
3926             if(!prev)
3927                f.Printf(methodPresent ? "\n      " : " ");
3928
3929          }
3930       }
3931       else 
3932       {
3933          // Instance not there, create a brand new one
3934          DeleteJunkBefore(f, position, &position);
3935          f.Printf(*firstObject ? "\n\n" : "\n");
3936          *firstObject = false;
3937
3938          if((this.methodAction == actionAddMethod || this.moveAttached) && this.selected == object)
3939             methodPresent = true;
3940
3941          if(methodPresent)
3942          {
3943             if(object.name)
3944                f.Printf("   %s %s\n   %c\n      ", control._class.name, object.name, OpenBracket);
3945             else
3946                f.Printf("   %s\n   %c\n      ", control._class.name, OpenBracket);
3947          }
3948          else
3949          {
3950             if(object.name)
3951                f.Printf("   %s %s %c ", control._class.name, object.name, OpenBracket);
3952             else
3953                f.Printf("   %s %c ", control._class.name, OpenBracket);
3954          }
3955       }
3956
3957       if(!object.deleted)
3958       {
3959          Instance test = eInstance_New(control._class);
3960          DataMember curMember = null;
3961          Class curClass = null;
3962          incref test;
3963
3964          UpdateInstanceCodeClass(control._class, object, f, test, &prev, &lastIsMethod, &curMember, &curClass);
3965
3966          delete test;
3967
3968          // Attach Method here
3969          if((this.methodAction == actionAttachMethod || this.methodAction == actionReattachMethod) && !this.moveAttached && this.selected == object)
3970          {
3971             if(prev) f.Printf(", ");
3972             f.Printf("%s = %s", this.method.name, function.declarator.symbol.string);
3973             prev = true;
3974          }
3975       }
3976
3977       if(inst && !object.deleted)
3978       {
3979          MembersInit members;
3980          Class instClass = eSystem_FindClass(this.privateModule, inst._class.name);
3981
3982          DeleteJunkBefore(f, position, &position);
3983          
3984          // Instance already there, clear out the properties
3985          for(members = inst.members->first; members; members = members.next)
3986          {
3987             if(members.type == dataMembersInit)
3988             {
3989                MemberInit member;
3990
3991                if(members.dataMembers)
3992                {
3993                   bool keptMember = false;
3994                   MemberInit lastKept = null;
3995
3996                   for(member = members.dataMembers->first; member; member = member.next)
3997                   {
3998                      Identifier ident = member.identifiers ? member.identifiers->first : null;
3999                      bool deleted = false;
4000
4001                      // For now delete if it's not a method
4002                      if(!member.variable) // && ident)
4003                      {
4004                         if(!ident || !ident.next)
4005                         {
4006                            Property prop = ident ? eClass_FindProperty(instClass, ident.string, this.privateModule) : null;
4007                            if(!ident || prop)
4008                            {
4009                               f.Seek(member.loc.start.pos - position, current);
4010                               f.DeleteBytes(member.loc.end.pos - member.loc.start.pos);
4011                               position = member.loc.end.pos;
4012                               deleted = true;
4013                            }
4014                            else
4015                            {
4016                               Method method = eClass_FindMethod(instClass, ident.string, this.privateModule);
4017                               if(method && method.type == virtualMethod && member.initializer && member.initializer.type == expInitializer && member.initializer.exp && 
4018                                  member.initializer.exp.type == memberExp /*ExpIdentifier*/)
4019                               {
4020                                  if(((this.methodAction == actionDetachMethod || this.methodAction == actionReattachMethod) && this.method == method && this.selected == object) ||
4021                                     (this.methodAction == actionDeleteMethod && !strcmp(function.declarator.symbol.string, member.initializer.exp.identifier.string)))
4022                                  {
4023                                     f.Seek(member.loc.start.pos - position, current);
4024                                     f.DeleteBytes(member.loc.end.pos - member.loc.start.pos);
4025                                     position = member.loc.end.pos;
4026                                     deleted = true;
4027                                  }
4028                               }                                          
4029                            }
4030                         }
4031                      }
4032                      if(!deleted)
4033                      {
4034                         keptMember = true;
4035                         lastKept = member;
4036
4037                         //f.Seek(member.loc.start.pos - position, current);
4038                         //position = member.loc.start.pos;
4039                         DeleteJunkBefore(f, member.loc.start.pos, &position);
4040                         if(prev) f.Printf(", "); 
4041                         else if(keptMember) f.Printf(" ");
4042                         prev = false;
4043                      }
4044                   } 
4045                
4046                   if(!keptMember || !members.next)
4047                   {
4048                      char ch = 0;
4049                      int count = 0;
4050
4051                      if(keptMember && lastKept != members.dataMembers->last)
4052                      {
4053                         // Delete the comma
4054                         char ch;
4055                         int count = 0;
4056                         f.Seek(-1, current);
4057                         for(;f.Getc(&ch);)
4058                         {
4059                            if(ch == ',')
4060                            {
4061                               count++;
4062                               f.Seek(-1, current);
4063                               break;
4064                            }
4065                            else if(!isspace(ch))
4066                               break;
4067                            f.Seek(-2, current);
4068                            count++;
4069                         }
4070
4071                         if(ch == ',')
4072                            f.DeleteBytes(count);
4073                      }
4074
4075                      f.Seek(members.loc.end.pos - position, current);
4076                      f.Getc(&ch);
4077             
4078                      if(ch == ';')
4079                      {
4080                         f.Seek(-1, current);
4081                         f.DeleteBytes(1);
4082                         position = members.loc.end.pos + 1;
4083                      }
4084                      else
4085                      {
4086                         f.Seek(-1, current);
4087                         position = members.loc.end.pos;
4088                      }
4089
4090                      if(keptMember)
4091                      {
4092                         prev = true;
4093                         lastIsMethod = false;
4094                      }
4095                   }
4096                   else
4097                   {
4098                      DeleteJunkBefore(f, position, &position);
4099                      f.Printf(" ");
4100
4101                      if(lastKept != members.dataMembers->last)
4102                      {
4103                         // Delete the comma
4104                         char ch;
4105                         int count = 0;
4106                         f.Seek(-1, current);
4107                         for(;f.Getc(&ch);)
4108                         {
4109                            if(ch == ',')
4110                            {
4111                               count++;
4112                               f.Seek(-1, current);
4113                               break;
4114                            }
4115                            else if(!isspace(ch))
4116                               break;
4117                            f.Seek(-2, current);
4118                            count++;
4119                         }
4120
4121                         if(ch == ',')
4122                            f.DeleteBytes(count);
4123                      }
4124                      else
4125                      {
4126                         f.Seek(members.loc.end.pos - position, current);
4127                         position = members.loc.end.pos;
4128                      }
4129                      /*
4130                      prev = false;
4131                      lastIsMethod = true;
4132                      */
4133                      prev = true;
4134                      lastIsMethod = false;
4135                      
4136                   }
4137                }
4138                else
4139                {
4140                   f.Seek(members.loc.end.pos - position, current);
4141                   position = members.loc.end.pos;
4142                   prev = false;
4143                   lastIsMethod = true;
4144                }
4145             }
4146             else if(members.type == methodMembersInit)
4147             {
4148                if(this.methodAction == actionDeleteMethod && members.function == function);
4149                else
4150                   methodPresent = true;
4151
4152                // Delete instance method here
4153                if((this.methodAction == actionDeleteMethod || (this.methodAction == actionDetachMethod && this.moveAttached)) && 
4154                   members.function == function)
4155                {
4156                   if(this.moveAttached && !*text)
4157                      GetLocText(editBox, f, position, &function.loc, text, textSize, Max((int)strlen(this.methodName) - movedFuncIdLen,0), 0);
4158
4159                   DeleteJunkBefore(f, members.loc.start.pos, &position);
4160                   f.DeleteBytes(members.loc.end.pos - members.loc.start.pos + 1);
4161                   position = members.loc.end.pos + 1;
4162                   f.Printf("\n");
4163                }
4164                else
4165                {
4166                   DeleteJunkBefore(f, position, &position);
4167                   if(!lastIsMethod)
4168                      f.Printf(";");
4169
4170                   DeleteJunkBefore(f, members.loc.start.pos, &position);
4171                   lastIsMethod = true;
4172                   f.Printf("\n\n      ");               
4173                }
4174
4175                f.Seek(members.loc.end.pos - position, current);
4176                position = members.loc.end.pos;
4177             }
4178             DeleteJunkBefore(f, position, &position);
4179          }
4180       }
4181
4182       if(!object.deleted)
4183       {
4184          if(!methodPresent)
4185             f.Printf(" ");
4186
4187          if((this.methodAction == actionAddMethod || (this.moveAttached && (this.methodAction == actionAttachMethod || this.methodAction == actionReattachMethod))) && this.selected == object)
4188          {
4189             Method method = this.method;
4190             DeleteJunkBefore(f, position, &position);
4191             if(!lastIsMethod)
4192                f.Printf(";");
4193
4194             f.Printf("\n");
4195
4196             if(!method.dataType)
4197                method.dataType = ProcessTypeString(method.dataTypeString, false);
4198
4199             {
4200                Type dataType = method.dataType;
4201                Type returnType = dataType.returnType;
4202                Type param;
4203
4204                if(this.moveAttached)
4205                {
4206                   // Move function here:
4207                   int newLen = strlen(method.name);
4208
4209                   f.Printf("\n   ");
4210
4211                   if(!*text)
4212                      GetLocText(editBox, f, position, &function.loc, text, textSize, Max(newLen - movedFuncIdLen, 0), 3);
4213
4214                   // First change name of function
4215                   memmove(*text + movedFuncIdPos + newLen, *text + movedFuncIdPos + movedFuncIdLen, *textSize - movedFuncIdPos - movedFuncIdLen + 1);
4216                   *textSize += newLen - movedFuncIdLen;
4217                   memcpy(*text + movedFuncIdPos, method.name, newLen);
4218                                           
4219                   // Second, tab right
4220                   {
4221                      int c;
4222                      for(c = 0; (*text)[c]; )
4223                      {
4224                         int i;
4225                         for(i = c; (*text)[i] && (*text)[i] != '\n'; i++);
4226                         if(i != c)
4227                         {
4228                            memmove((*text)+c+3, (*text)+c, *textSize+1-c);
4229                            (*text)[c] = (*text)[c+1] = (*text)[c+2] = ' ';
4230                            c += 3;
4231                            *textSize += 3;
4232                         }
4233                         for(; (*text)[c] && (*text)[c] != '\n'; c++);
4234                         if((*text)[c]) c++;
4235                      }
4236                   }
4237
4238                   f.Puts((*text));
4239                   f.Printf("\n");
4240                }
4241                else
4242                {
4243                   Class moduleClass = eSystem_FindClass(this.privateModule, "Module");
4244
4245                   // ADDING METHOD HERE
4246                   f.Printf("\n      ");
4247                   OutputType(f, returnType, false);
4248             
4249                   f.Printf(" ");
4250                   if(dataType.thisClass)
4251                   {
4252                      if(!eClass_IsDerived(regClass, dataType.thisClass.registered) && !dataType.classObjectType)     // Just fixed this... was backwards.
4253                      {
4254                         if(dataType.thisClass.shortName)
4255                            f.Printf(dataType.thisClass.shortName);
4256                         else
4257                            f.Printf(dataType.thisClass.string);
4258                         f.Printf("::");
4259                      }
4260                   }
4261                   f.Printf(method.name);
4262                   f.Printf("(");
4263                   for(param = dataType.params.first; param; param = param.next)
4264                   {
4265                      OutputType(f, param, true);
4266                      if(param.next)
4267                         f.Printf(", ");
4268                   }
4269                   f.Printf(")\n");                  
4270                   f.Printf("      %c\n\n", OpenBracket);
4271
4272                   if(control._class._vTbl[method.vid] == moduleClass._vTbl[__ecereVMethodID___ecereNameSpace__ecere__com__Module_OnLoad]) // Temp Check for DefaultFunction
4273                   {
4274                      if(returnType.kind == classType && !strcmp(returnType._class.string, "bool"))
4275                         f.Printf("         return true;\n");
4276                      else if(returnType.kind != voidType)
4277                         f.Printf("         return 0;\n");
4278                   }
4279                   else
4280                   {
4281                      f.Printf("         ");
4282                      if(returnType.kind != voidType)
4283                         f.Printf("return ");
4284                      f.Printf("%s::%s(", control._class.name, method.name);
4285                      for(param = dataType.params.first; param; param = param.next)
4286                      {
4287                         if(param.prev) f.Printf(", ");
4288                         if(param.kind != voidType)
4289                            f.Printf(param.name);
4290                      }
4291                      f.Printf(");\n");
4292                   }
4293                   f.Printf("      %c\n", CloseBracket);
4294                }
4295             }
4296          }
4297       }
4298
4299       if(!object.instCode)
4300       {
4301          if(methodPresent)
4302             f.Printf("   %c;\n", CloseBracket);
4303          else
4304             f.Printf("%c;\n", CloseBracket);
4305       }
4306       else if(!object.deleted)
4307       {
4308          // Turn this into a multiline instance when adding a method
4309          DeleteJunkBefore(f, inst.loc.end.pos-1, &position);
4310
4311          f.Printf(methodPresent ? "\n   " : " ");
4312
4313          f.Seek(inst.loc.end.pos + 1 - position, current);
4314          position = inst.loc.end.pos + 1;
4315       }
4316       return position;
4317    }
4318
4319    void OutputClassProperties(Class _class, ObjectInfo classObject, EditBoxStream f, Instance test)
4320    {
4321       Property propIt;
4322       Class regClass = eSystem_FindClass(privateModule, classObject.name);
4323      
4324       if(_class.base && _class.base.type != systemClass) OutputClassProperties(_class.base, classObject, f, test);
4325       
4326       for(propIt = _class.membersAndProperties.first; propIt; propIt = propIt.next)
4327       {
4328          Property prop = eClass_FindProperty(selected.instance._class, propIt.name, privateModule);
4329          if(prop && prop.isProperty && !prop.conversion)
4330          {
4331             if(prop.Set && prop.Get && prop.dataTypeString && strcmp(prop.name, "name") && !Code_IsPropertyDisabled(classObject, prop.name) && 
4332                (!prop.IsSet || prop.IsSet(classObject.instance)))
4333             {
4334                Class dataType = prop.dataTypeClass;
4335                char tempString[1024] = "";
4336                char * string;
4337                bool specify = false;
4338                DataMember member;
4339
4340                member = eClass_FindDataMember(regClass, prop.name, privateModule, null, null);
4341                if(member && member._class == regClass)
4342                   specify = true;
4343
4344                if(!dataType)
4345                   dataType = prop.dataTypeClass = eSystem_FindClass(this.privateModule, prop.dataTypeString);
4346             
4347                if(dataType && dataType.type == structClass)
4348                {
4349                   void * dataForm = new0 byte[dataType.structSize];
4350                   void * dataTest = new0 byte[dataType.structSize];
4351                
4352                   ((void (*)(void *, void *))(void *)prop.Get)(classObject.instance, dataForm);
4353                   ((void (*)(void *, void *))(void *)prop.Get)(test, dataTest);
4354
4355                   if(((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
4356                   {
4357                      bool needClass = true;
4358                      
4359                      string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
4360                      ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
4361                      if(needClass)
4362                         f.Printf("\n   %s%s = %c %s %c;", specify ? "property::" : "", prop.name, /*dataType.name, */OpenBracket, string, CloseBracket);
4363                      else
4364                         f.Printf("\n   %s%s = %s;", specify ? "property::" : "", prop.name, string);
4365                   }
4366                   delete dataForm;
4367                   delete dataTest;
4368                }
4369                else if(dataType && (dataType.type == normalClass || dataType.type == noHeadClass))
4370                {
4371                   void * dataForm, * dataTest;
4372                
4373                   dataForm = ((void *(*)(void *))(void *)prop.Get)(classObject.instance);
4374                   dataTest = ((void *(*)(void *))(void *)prop.Get)(test);
4375                
4376                   if(((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, dataForm, dataTest))
4377                   {
4378                      char tempString[1024] = "";
4379                      char * string;
4380                      ((void (*)(void *, void *))(void *)prop.Set)(test, dataForm);
4381                   
4382                      if(eClass_IsDerived(classObject.instance._class, dataType) && classObject.instance == dataForm)
4383                      {
4384                         // Shouldn't go here ...
4385                         f.Printf("\n   %s%s = this;", specify ? "property::" : "", prop.name);
4386                      }
4387                      else
4388                      {
4389                         bool needClass = true;
4390
4391                         string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, dataForm, tempString, null, &needClass);
4392
4393                         if(!strcmp(dataType.dataTypeString, "char *"))
4394                         {
4395                            f.Printf("\n   %s%s = \"", specify ? "property::" : "", prop.name);
4396                            OutputString(f, string);
4397                            f.Puts("\";");
4398                         }
4399                         else if(needClass)
4400                            f.Printf("\n   %s%s = %c %s %c;", specify ? "property::" : "", prop.name, /*dataType.name, */OpenBracket, string, CloseBracket);
4401                         else
4402                            f.Printf("\n   %s%s = %s;", specify ? "property::" : "", prop.name, string);
4403                      }
4404                   }
4405                }
4406                else if(dataType)
4407                {
4408                   DataValue dataForm, dataTest;
4409                
4410                   GetProperty(prop, classObject.instance, &dataForm);
4411                   GetProperty(prop, test, &dataTest);
4412                
4413                   if(((int (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCompare])(dataType, &dataForm, &dataTest))
4414                   {
4415                      SetProperty(prop, test, dataForm);
4416                      if(dataType.type == bitClass)
4417                      {
4418                         bool needClass = true;
4419                         string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, &dataForm, tempString, null, &needClass);
4420                         if(needClass)
4421                            f.Printf("\n   %s%s = %c %s %c;", specify ? "property::" : "", prop.name, /*dataType.name, */OpenBracket, string, CloseBracket);
4422                         else if(string[0])
4423                            f.Printf("\n   %s%s = %s;", specify ? "property::" : "", prop.name, string);
4424                      }
4425                      else
4426                      {
4427                         bool needClass = true;
4428                         if(dataType.type == enumClass)
4429                         {
4430                            NamedLink value;
4431                            Class enumClass = eSystem_FindClass(privateModule, "enum");
4432                            EnumClassData e = ACCESS_CLASSDATA(dataType, enumClass);
4433
4434                            for(value = e.values.first; value; value = value.next)
4435                            {
4436                               if((int)value.data == dataForm.i)
4437                               {
4438                                  string = value.name;
4439                                  break;
4440                               }
4441                            }
4442                         }
4443                         else
4444                            string = ((char * (*)(void *, void *, void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, &dataForm, tempString, null, &needClass);
4445                         if(!strcmp(dataType.dataTypeString, "float") && strchr(string, '.'))
4446                            f.Printf("\n   %s%s = %sf;", specify ? "property::" : "", prop.name, string);
4447                         else if(string[0])
4448                            f.Printf("\n   %s%s = %s;", specify ? "property::" : "", prop.name, string);
4449                      }
4450                   }                                          
4451                }
4452             }
4453          }
4454       }
4455    }
4456
4457    void UpdateFormCode()
4458    {
4459       if(!this) return;
4460       if(!parsing) return;
4461
4462       updatingCode++;
4463       if(codeModified)
4464       {
4465          ParseCode();
4466       }
4467       else if(formModified)
4468       {
4469          EditBoxStream f { editBox = editBox };
4470          int position = 0;
4471          char * text = null;
4472          int textSize;
4473          Identifier movedFuncId; 
4474          int movedFuncIdLen = 0, movedFuncIdPos = 0;
4475          ObjectInfo classObject;
4476
4477            updatingCode++;
4478
4479          if(moveAttached)
4480          {
4481             movedFuncId = GetDeclId(function.declarator);
4482             movedFuncIdLen = movedFuncId.loc.end.pos - movedFuncId.loc.start.pos;
4483             movedFuncIdPos = movedFuncId.loc.start.pos - function.loc.start.pos;
4484          }
4485
4486          for(classObject = classes.first; classObject; classObject = classObject.next)
4487          {
4488             Class _class;
4489             ClassDefinition classDef = classObject.classDefinition;
4490             Class regClass = eSystem_FindClass(this.privateModule, ((Specifier)classDef.baseSpecs->first).name);
4491             Instance test;
4492             ClassDef def;
4493             bool firstObject = true;
4494             ObjectInfo object = classObject.instances.first;
4495             bool lastIsDecl = false;
4496
4497             if(!classObject.modified) continue;
4498
4499             test = eInstance_New(regClass);
4500             incref test;
4501
4502             // Put it in the same desktop window...
4503             designer.PrepareTestObject(test);
4504             
4505             //f.Printf("class %s : %s\n", classObject.name, classObject.oClass.name);
4506             //f.Printf("%c\n\n", OpenBracket);
4507
4508             // Change the _class name
4509             f.Seek(classDef.nameLoc.start.pos - position, current);
4510             f.DeleteBytes(classDef.nameLoc.end.pos - classDef.nameLoc.start.pos);
4511             f.Printf(classObject.name);
4512             position = classDef.nameLoc.end.pos;
4513
4514             {
4515                // Go to block start, delete all until no white space, put \n
4516                char ch;
4517                int count = 0;
4518                int back = 0;
4519                f.Seek(classDef.blockStart.end.pos - position, current);
4520                position = classDef.blockStart.end.pos;
4521                
4522                for(; f.Getc(&ch); count++)
4523                {
4524                   if(!isspace(ch))
4525                   {
4526                      f.Seek(-1, current);
4527                      break;
4528                   }
4529                
4530                   if(ch == '\n')
4531                      back = 0;
4532                   else
4533                      back++;
4534                }
4535             
4536                f.Seek(-count, current);
4537             
4538                f.DeleteBytes(count-back);
4539                //f.Printf("\n");
4540                position += count-back;
4541             }
4542
4543             // Output properties
4544             OutputClassProperties(classObject.instance._class, classObject, f, test);
4545
4546             for(def = classDef.definitions->first; def; def = def.next)
4547             {
4548                switch(def.type)
4549                {
4550                   case defaultPropertiesClassDef:
4551                   {
4552                      bool keptMember = false;
4553                      MemberInit propDef;
4554                      MemberInit lastKept = null;
4555                      
4556                      lastIsDecl = false;
4557                      DeleteJunkBefore(f, def.loc.start.pos, &position);
4558                      f.Printf("\n   ");
4559
4560                      for(propDef = def.defProperties->first; propDef; propDef = propDef.next)
4561                      {
4562                         Identifier ident = propDef.identifiers->first;
4563                         bool deleted = false;
4564
4565                         // For now delete if it's a prop
4566                         if(!propDef.variable && ident)
4567                         {
4568                            if(!ident.next)
4569                            {
4570                               Property prop = eClass_FindProperty(regClass, ident.string, this.privateModule);
4571                               if(prop)
4572                               {
4573                                  f.Seek(propDef.loc.start.pos - position, current);
4574                                  f.DeleteBytes(propDef.loc.end.pos - propDef.loc.start.pos);
4575                                  position = propDef.loc.end.pos;
4576                                  deleted = true;
4577                               }
4578                               else
4579                               {
4580                                  Method method = eClass_FindMethod(regClass, ident.string, this.privateModule);
4581                                  if(method && method.type == virtualMethod && propDef.initializer && propDef.initializer.type == expInitializer && propDef.initializer.exp && propDef.initializer.exp.type == identifierExp)
4582                                  {
4583                                     if(((methodAction == actionDetachMethod || methodAction == actionReattachMethod) && method == this.method && selected == classObject) ||
4584                                        (methodAction == actionDeleteMethod && !strcmp(function.declarator.symbol.string, propDef.initializer.exp.identifier.string)))
4585                                     {
4586                                        f.Seek(propDef.loc.start.pos - position, current);
4587                                        f.DeleteBytes(propDef.loc.end.pos - propDef.loc.start.pos);
4588                                        position = propDef.loc.end.pos;
4589                                        deleted = true;
4590                                     }
4591                                  }                                          
4592                               }
4593                            }
4594                         }
4595                         if(!deleted)
4596                         {
4597                            keptMember = true;
4598                            lastKept = propDef;
4599                         }
4600                      }
4601                   
4602                      if(!keptMember)
4603                      {
4604                         char ch = 0;
4605                         int count = 0;
4606                         f.Seek(def.loc.end.pos - position - 1, current);
4607                         f.Getc(&ch);
4608                         
4609                         if(ch == ';')
4610                         {
4611                            f.Seek(-1, current);
4612                            f.DeleteBytes(1);
4613                         }
4614                         position = def.loc.end.pos;
4615                      }
4616                      else
4617                      {
4618                         if(lastKept != def.defProperties->last)
4619                         {
4620                            char ch;
4621                            int count = 0;
4622                            
4623                            f.Seek(-1, current);
4624                            for(;f.Getc(&ch);)
4625                            {
4626                               if(ch == ',')
4627                               {
4628                                  count++;
4629                                  f.Seek(-1, current);
4630                                  break;
4631                               }
4632                               else if(!isspace(ch))
4633                                  break;
4634                               f.Seek(-2, current);
4635                               count++;
4636                            }
4637
4638                            if(ch == ',')
4639                               f.DeleteBytes(count);
4640                         }
4641                         else
4642                         {
4643                            f.Seek(def.loc.end.pos - position, current);
4644                            position = def.loc.end.pos;
4645                         }                
4646                      }
4647                      break;
4648                   }
4649                   case declarationClassDef:
4650                   {
4651                      Declaration decl = def.decl;
4652
4653                      if(decl.type == instDeclaration)
4654                      {
4655                         if(def.object/* && ((ObjectInfo)def.object).modified*/)
4656                         {
4657                            while(def.object && object != def.object)
4658                            {
4659                               if(object /*&& ((ObjectInfo)def.object).modified*/)
4660                                  position = UpdateInstanceCode(f, position, regClass, object, &firstObject, &text, &textSize, movedFuncIdLen, movedFuncIdPos);
4661                               object = object.next;
4662                            }
4663
4664                            DeleteJunkBefore(f, def.loc.start.pos, &position);
4665                            f.Printf(firstObject ? "\n\n   " : "\n   ");
4666                            firstObject = false;
4667
4668                            if(def.object && ((ObjectInfo)def.object).modified)
4669                               position = UpdateInstanceCode(f, position, regClass, def.object, &firstObject, &text, &textSize, movedFuncIdLen, movedFuncIdPos);
4670
4671                            object = object ? object.next : null;
4672                         }
4673                         else
4674                         {
4675                            DeleteJunkBefore(f, def.loc.start.pos, &position);
4676                            f.Printf(firstObject ? "\n\n   " : "\n   ");
4677                            firstObject = false;
4678                         }
4679                         lastIsDecl = false;
4680                      }
4681                      else
4682                      {
4683                         DeleteJunkBefore(f, def.loc.start.pos, &position);
4684                         f.Printf(lastIsDecl ? "\n   " : "\n\n   ");
4685                         lastIsDecl = true;
4686                      }
4687                      break;
4688                   }
4689                   case functionClassDef:
4690                   {
4691                      // TESTING IF THIS IS GOOD ENOUGH FOR GENERATED FUNCTION...
4692                      if(!def.function.body) continue;
4693
4694                      lastIsDecl = false;
4695
4696                      DeleteJunkBefore(f, def.loc.start.pos, &position);
4697                      f.Printf("\n\n   ");
4698
4699                      // Delete _class methods
4700                      if((methodAction == actionDeleteMethod || (moveAttached && selected != classObject)) && 
4701                         def.function == function)
4702                      {
4703                         char ch;
4704                         int count = 0;
4705
4706                         if(moveAttached && !text)
4707                         {
4708                            GetLocText(editBox, f, position, &function.loc, &text, &textSize, Max((int)strlen(methodName) - movedFuncIdLen,0), 3);
4709                         }
4710
4711                         f.Seek(def.loc.end.pos - position, current);
4712                         for(; f.Getc(&ch); count++)
4713                         {
4714                            if(!isspace(ch))
4715                            {
4716                               f.Seek(-1, current);
4717                               break;
4718                            }
4719                         }
4720                         f.Seek(def.loc.start.pos - def.loc.end.pos - count, current);
4721
4722                         f.DeleteBytes(def.loc.end.pos - def.loc.start.pos + count);
4723                         position = def.loc.end.pos + count;
4724                      }
4725
4726                      // In case of detaching methods in the _class, simply rename the method
4727                      if(methodAction == actionDetachMethod && moveAttached && selected == classObject && function == def.function)
4728                      {
4729                         f.Seek(function.loc.start.pos + movedFuncIdPos - position, current);
4730                         f.DeleteBytes(movedFuncIdLen);
4731                         f.Puts(methodName);
4732                         position = function.loc.start.pos + movedFuncIdPos + movedFuncIdLen;
4733                      }
4734
4735                      if((methodAction == actionAttachMethod || methodAction == actionReattachMethod) && selected == classObject && moveAttached && 
4736                         function == def.function)
4737                      {
4738                         // In case of attaching methods in the _class, simply rename the method
4739                         f.Seek(function.loc.start.pos + movedFuncIdPos - position, current);
4740                         position = function.loc.start.pos + movedFuncIdPos;
4741                         f.DeleteBytes(movedFuncIdLen);
4742                         if(method.dataType.thisClass)
4743                            f.Printf("%s::", method.dataType.thisClass.string);
4744                         f.Puts(method.name);
4745                         position += movedFuncIdLen;
4746                      }
4747                      break;
4748                   }
4749                   default:
4750                      DeleteJunkBefore(f, def.loc.start.pos, &position);
4751                      if(def.type == memberAccessClassDef)
4752                      {
4753                         f.Printf("\n\n");
4754                         firstObject = false;
4755                         lastIsDecl = true;
4756                      }
4757                      else           
4758                      {
4759                         f.Printf("\n   ");
4760                         lastIsDecl = false;
4761                      }
4762                }
4763
4764                f.Seek(def.loc.end.pos - position, current);
4765                position = def.loc.end.pos;
4766             }
4767
4768             // Output attached methods
4769             if((methodAction == actionAttachMethod || methodAction == actionReattachMethod) && selected == classObject && !moveAttached)
4770             {
4771                DeleteJunkBefore(f, position, &position);
4772                f.Printf("\n   %s = %s;\n", method.name, function.declarator.symbol.string);
4773             }
4774             
4775             // ********** INSTANCES ***************
4776             for(; object; object = object.next)
4777             {
4778                if(!object.instCode)
4779                {
4780                   position = UpdateInstanceCode(f, position, regClass, object, &firstObject, &text, &textSize, movedFuncIdLen, movedFuncIdPos);
4781                }
4782             }
4783
4784             DeleteJunkBefore(f, position, &position);
4785
4786             // ****************** METHODS ***********************
4787             if(methodAction == actionDetachMethod && moveAttached && classObject == oClass)
4788             {
4789                // If detaching an instance method
4790                if(selected != classObject)
4791                {
4792                   int newLen = strlen(methodName);
4793
4794                   if(!text)
4795                      GetLocText(editBox, f, position, &function.loc, &text, &textSize, Max(newLen - movedFuncIdLen,0), 0);
4796                   // Tab selection left
4797                   {
4798                      int c;
4799                      for(c = 0; text[c]; )
4800                      {
4801                         int start = c, i;
4802                         for(i = 0; i<3 && text[c] == ' '; i++, c++);
4803                         memmove(text+start, text+start+i, textSize+1-start-i);
4804                         textSize -= i;
4805                         c -= i;
4806                         for(; text[c] && text[c] != '\n'; c++);
4807                         if(text[c]) c++;
4808                      }
4809                   }
4810
4811                   // Rename function
4812                   memmove(text + movedFuncIdPos + newLen, text + movedFuncIdPos + movedFuncIdLen, textSize - movedFuncIdPos - movedFuncIdLen + 1);
4813                   textSize += newLen - movedFuncIdLen;
4814                   memcpy(text + movedFuncIdPos, methodName, newLen);
4815
4816                   f.Printf("\n\n   ");
4817                   f.Puts(text);
4818                }
4819             }
4820
4821             if(methodAction == actionAddMethod && selected == classObject)
4822             {
4823                Method method = this.method;
4824
4825                if(!method.dataType)
4826                   method.dataType = ProcessTypeString(method.dataTypeString, false);
4827
4828                // ADDING METHOD HERE
4829                {
4830                   Type dataType = method.dataType;
4831                   Type returnType = dataType.returnType;
4832                   Type param;
4833                   Class moduleClass = eSystem_FindClass(this.privateModule, "Module");
4834
4835                   f.Printf("\n\n");
4836                   f.Printf("   ");
4837                   OutputType(f, returnType, false);
4838                
4839                   f.Printf(" ");
4840                   if(dataType.thisClass && !dataType.classObjectType)
4841                   {
4842                      if(dataType.thisClass.shortName)
4843                         f.Printf(dataType.thisClass.shortName);
4844                      else
4845                         f.Printf(dataType.thisClass.string);
4846                      f.Printf("::");
4847                   }
4848                   f.Printf(method.name);
4849                   f.Printf("(");
4850                   for(param = dataType.params.first; param; param = param.next)
4851                   {
4852                      OutputType(f, param, true);
4853                      if(param.next)
4854                         f.Printf(", ");
4855                   }
4856                   f.Printf(")\n");                  
4857                   f.Printf("   %c\n\n", OpenBracket);
4858
4859                   if(test._class._vTbl[method.vid] == moduleClass._vTbl[__ecereVMethodID___ecereNameSpace__ecere__com__Module_OnLoad]) // Temp Check for DefaultFunction
4860                   {
4861                      if(returnType && returnType.kind == classType && !strcmp(returnType._class.string, "bool"))
4862                         f.Printf("      return true;\n");
4863                      else if(returnType && returnType.kind != voidType)
4864                         f.Printf("      return 0;\n");
4865                   }
4866                   else
4867                   {
4868                      f.Printf("      ");
4869                      if(returnType.kind != voidType)
4870                         f.Printf("return ");
4871                      {
4872                         char * name = ((Specifier)classDef.baseSpecs->first).name;
4873                         Symbol _class = FindClass(name);
4874                         f.Printf("%s::%s(", (_class && _class.registered) ? _class.registered.name : name, method.name);
4875                      }
4876                      for(param = dataType.params.first; param; param = param.next)
4877                      {
4878                         if(param.prev) f.Printf(", ");
4879                         if(param.kind != voidType)
4880                            f.Printf(param.name);
4881                      }
4882                      f.Printf(");\n");
4883                   }
4884
4885                   f.Printf("   %c", CloseBracket);
4886                }
4887             }
4888
4889             DeleteJunkBefore(f, classDef.loc.end.pos-1, &position);
4890             f.Printf("\n");
4891
4892             delete test;
4893          }
4894
4895          updatingCode--;
4896          delete f;
4897
4898          ParseCode();
4899          delete text;
4900
4901          // TOFIX: Patch for a glitch where clicking at the end of the view seems one line off. No idea what could be going on?
4902          editBox.OnVScroll(setRange, editBox.scroll.y, 0);
4903       }
4904
4905       updatingCode--;
4906       codeModified = false;
4907       formModified = false;
4908       methodAction = 0;
4909       moveAttached = false;
4910       function = null;
4911       method = null;
4912    }
4913
4914    int FindMethod(char * methodName /*Method method*/, ClassFunction*functionPtr, Location propLoc)
4915    {
4916       int found = 0;
4917       ClassFunction function = null;
4918       if(methodName)
4919       {
4920          ObjectInfo object = this.selected;
4921          
4922          if(object && object == this.oClass)
4923          {
4924             ClassDefinition classDef = object.oClass.classDefinition;
4925             ClassDef def;
4926             if(classDef && classDef.definitions)
4927             {
4928                for(def = classDef.definitions->first; def; def = def.next)
4929                {
4930                   if(def.type == functionClassDef && def.function.declarator)
4931                   {
4932                      if(!strcmp(def.function.declarator.symbol.string, methodName))
4933                      {
4934                         function = def.function;
4935                         found = 1;
4936                         break;
4937                      }
4938                   }
4939                   else if(def.type == defaultPropertiesClassDef)
4940                   {
4941                      MemberInit propDef;
4942
4943                      for(propDef = def.defProperties->first; propDef; propDef = propDef.next)
4944                      {
4945                         Identifier ident = propDef.identifiers ? propDef.identifiers->first : null;
4946                         if(ident && !ident.next)
4947                         {
4948                            if(!strcmp(ident.string, methodName) && propDef.initializer && propDef.initializer.type == expInitializer && propDef.initializer.exp && propDef.initializer.exp.type == identifierExp)
4949                            {
4950                               found = 2;
4951                               if(propLoc != null)
4952                                  propLoc = propDef.loc;
4953                               if(functionPtr)
4954                               {
4955                                  ClassDefinition classDef = object.oClass.classDefinition;
4956                                  ClassDef def;
4957                                  if(classDef.definitions)
4958                                  {
4959                                     for(def = classDef.definitions->first; def; def = def.next)
4960                                     {
4961                                        if(def.type == functionClassDef)
4962                                        {
4963                                           if(!strcmp(def.function.declarator.symbol.string, propDef.initializer.exp.identifier.string))
4964                                           {
4965                                              function = def.function;
4966                                              break;
4967                                           }
4968                                        }
4969                                     }
4970                                     if(function) break;
4971                                  }
4972                               }
4973                               else
4974                                  break;
4975                            }
4976                         }
4977                      }
4978                   }
4979                }
4980             }
4981          }
4982          else if(object)
4983          {
4984             Instantiation inst = object.instCode;
4985
4986             // Check here to see if the method already exists, no need to call ModifyCode in that case
4987             if(inst && inst.members)
4988             {
4989                MembersInit members;
4990                for(members = inst.members->first; members; members = members.next)
4991                {
4992                   switch(members.type)
4993                   {
4994                      case dataMembersInit:
4995                      {
4996                         if(members.dataMembers)
4997                         {
4998                            MemberInit member;
4999                            for(member = members.dataMembers->first; member; member = member.next)
5000                            {
5001                               Identifier ident = member.identifiers ? member.identifiers->first : null;
5002                               if(ident && !ident.next)
5003                               {
5004                                  if(!strcmp(ident.string, methodName) && member.initializer && member.initializer.type == expInitializer && member.initializer.exp && member.initializer.exp.type == memberExp /*ExpIdentifier*/)
5005                                  {
5006                                     found = 2;
5007                                     if(propLoc != null)
5008                                        propLoc = member.loc;
5009                                     if(functionPtr)
5010                                     {
5011                                        ClassDefinition classDef = object.oClass.classDefinition;
5012                                        ClassDef def;
5013                                        if(classDef.definitions)
5014                                        {
5015                                           for(def = classDef.definitions->first; def; def = def.next)
5016                                           {
5017                                              if(def.type == functionClassDef)
5018                                              {
5019                                                 if(def.function.declarator && !strcmp(def.function.declarator.symbol.string, member.initializer.exp.identifier.string))
5020                                                 {
5021                                                    function = def.function;
5022                                                    break;
5023                                                 }
5024                                              }
5025                                           }
5026                                           if(function) break;
5027                                        }
5028                                        if(!function)
5029                                        {
5030                                           // TODO: Fix memory leak
5031                                           function = ClassFunction
5032                                           {
5033                                              declarator = Declarator { symbol = Symbol { string = CopyString(member.initializer.exp.member.member ? member.initializer.exp.member.member.string : "") } }
5034                                           };
5035                                        }
5036                                     }
5037                                     else
5038                                        break;
5039                                  }
5040                               }
5041                            }
5042                         }
5043                         break;
5044                      }
5045                      case methodMembersInit:
5046                      {
5047                         if(members.function.declarator && !strcmp(members.function.declarator.symbol.string, methodName))
5048                         {
5049                            function = members.function;
5050                            found = 1;
5051                         }
5052                         break;
5053                      }
5054                   }
5055                   if(function)
5056                      break;
5057                }
5058             }
5059          }
5060       }
5061       if(functionPtr) *functionPtr = function;
5062       return found;
5063    }
5064
5065    void GoToMethod(char * methodName /*Method method*/)
5066    {
5067       if(methodName)
5068       {
5069          ObjectInfo object = selected;
5070          EditBoxStream f { editBox = editBox };
5071          ClassFunction function = null;
5072          bool atChar = false;
5073          int indent = 6;
5074          EditLine l1, l2;
5075          int y1,y2, x1, x2;
5076          Location propLoc = { {0,0,-1} };
5077
5078          // GO TO THE METHOD
5079          if(FindMethod(methodName, &function, &propLoc) == 1 && object != this.oClass) indent = 9;
5080          if(function && function.body)
5081          {
5082             bool lfCount = 0;
5083             f.Seek(function.body.loc.start.pos+1, current);
5084             for(;;)
5085             {
5086                char ch;
5087                if(!f.Getc(&ch))
5088                   break;
5089                if(ch == '\n')
5090                {
5091                   if(lfCount)
5092                   {
5093                      f.Seek(-1, current);
5094                      break;
5095                   }
5096                   lfCount++;
5097                }
5098                else if(!isspace(ch))
5099                {
5100                   f.Seek(-1, current);
5101                   atChar = true;
5102                   break;
5103                }
5104             }
5105          }
5106          else if(propLoc.start.pos > -1)
5107          {
5108             f.Seek(propLoc.start.pos, current);
5109             atChar = true;
5110          }
5111          editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
5112          delete f;
5113          if(function || propLoc.start.pos > -1)
5114          {
5115             editBox.SetSelPos(l1, y1, atChar ? x1 : indent, l2, y2, atChar ? x2 : indent);
5116             editBox.CenterOnCursor();
5117             SetState(normal, false, 0);
5118             Activate();
5119
5120             if(function && function.declarator && function.declarator.symbol && !function.declarator.symbol.type)
5121             {
5122                FreeClassFunction(function);
5123             }
5124          }
5125       }
5126    }
5127
5128    void FindCompatibleMethods(Method method, OldList compatible)
5129    {
5130       ClassDefinition classDef = this.oClass.classDefinition;
5131       if(classDef && classDef.definitions)
5132       {
5133          Class regClass { };
5134          Class baseClass = eSystem_FindClass(this.privateModule, ((Specifier)classDef.baseSpecs->first).name);
5135          ClassDef def;
5136          Class _class;
5137          Symbol classSym { };
5138          Symbol selectedClass;
5139          if(this.selected == this.oClass)
5140             selectedClass = classSym;
5141          else
5142             selectedClass = FindClass(this.selected.instance._class.name);
5143
5144          regClass.name = classDef._class.name;
5145          regClass.base = eSystem_FindClass(this.privateModule, ((Specifier)classDef.baseSpecs->first).name);
5146          for(def = classDef.definitions->first; def; def = def.next)
5147          {
5148             if(def.type == functionClassDef && def.function.declarator)
5149             {
5150                Method vMethod = eClass_FindMethod(baseClass, def.function.declarator.symbol.string, this.privateModule);
5151                if(!vMethod)
5152                   vMethod = eClass_FindMethod(this.selected.instance._class, def.function.declarator.symbol.string, this.privateModule);
5153                if(!vMethod)
5154                {
5155                   Type type = def.function.declarator.symbol.type;
5156                   if(CheckCompatibleMethod(method, type, regClass, this.selected == this.oClass, FindClass(this.selected.instance._class.name)))
5157                   {
5158                      compatible.Add(OldLink { data = def.function });
5159                   }
5160                }
5161             }
5162          }
5163
5164          if(this.oClass && this.oClass.instance)
5165          {
5166             classSym.registered = regClass;
5167             //classSym.registered = this.oClass.oClass;
5168
5169             for(_class = regClass.base; _class; _class = _class.base)
5170             {
5171                Method testMethod;
5172                for(testMethod = (Method)_class.methods.first; testMethod; testMethod = (Method)((BTNode)testMethod).next)
5173                {
5174                   // TODO: Understand why these functions popup in attach list
5175                   if(testMethod.type != virtualMethod /*&& testMethod.function != Window_OnGetString && testMethod.function != Window_OnGetDataFromString*/)
5176                   {
5177                      if(!testMethod.dataType)
5178                         testMethod.dataType = ProcessTypeString(testMethod.dataTypeString, false);
5179                         
5180                      //if(CheckCompatibleMethod(method, testMethod.dataType, &regClass, false, selectedClass)) // this.selected == this.oClass, selectedClass))
5181                      if(CheckCompatibleMethod(method, testMethod.dataType, this.oClass.instance._class, false, selectedClass)) // this.selected == this.oClass, selectedClass))
5182                      //if(CheckCompatibleMethod(method, testMethod.dataType, &regClass, this.selected == this.oClass, FindClass(this.oClass.oClass.name)))
5183                      {
5184                         // TODO: Fix memory leak, Figure out if it should be ClassFunction or FunctionDefinition
5185                         // ClassFunction function { };
5186                         FunctionDefinition function { };
5187
5188                         function.declarator = Declarator { };
5189                         function.declarator.symbol = Symbol { string = CopyString(testMethod.name) };
5190                         excludedSymbols.Add(function.declarator.symbol);
5191
5192                         compatible.Add(OldLink { data = function });
5193                      }
5194                   }
5195                }
5196             }
5197          }
5198          delete regClass;
5199          delete classSym;
5200       }
5201    }
5202
5203    void AddMethod(Method method)
5204    {
5205       if(method)
5206       {
5207          char methodName[1024];
5208          strcpy(methodName, method.name);
5209          if(!FindMethod(methodName, null, null))
5210          {
5211             methodAction = actionAddMethod;
5212             this.method = method;
5213             ModifyCode();
5214          }
5215          UpdateFormCode();         
5216          GoToMethod(methodName);
5217       }
5218    }
5219
5220    void DeleteMethod(ClassFunction function)
5221    {
5222       if(function)
5223       {
5224          methodAction = actionDeleteMethod;
5225          this.function = function;
5226          ModifyCode();
5227          UpdateFormCode(); 
5228
5229          Update(null);
5230       }
5231    }
5232
5233    void AttachMethod(Method method, ClassFunction function)
5234    {
5235       if(function)
5236       {
5237          // If it's an instance we'll ask if we want to move it inside...
5238          if(!function.attached.count && function.body)
5239          {
5240             // Find the function in the _class to check if it's a virtual function
5241             Class regClass = eSystem_FindClass(this.privateModule, ((Specifier)this.oClass.classDefinition.baseSpecs->first).name);
5242             Method method = eClass_FindMethod(regClass, function.declarator.symbol.string, this.privateModule);
5243             /*    LATER we'll need to check for public/virtual properties etc, for now only checked if virtual in base _class
5244             ClassDef def;
5245             for(def = this.classDefinition.first; def; def = def.next)
5246             {
5247                if(def.type == functionClassDef)
5248                {
5249                   if(def.function == function)
5250                      break;
5251                }
5252             }
5253             */
5254             if(!method || method.type != virtualMethod)
5255             {
5256                char title[1024];
5257                sprintf(title, $"Attach %s", function.declarator.symbol.string);
5258                if(MessageBox { type = yesNo, master = parent, text = title, contents = $"Method is unused. Move method inside instance?"}.Modal() == yes)
5259                {
5260                   moveAttached = true;
5261                }
5262             }
5263          }
5264
5265          methodAction = actionAttachMethod;
5266          this.method = method;
5267          this.function = function;
5268          ModifyCode();
5269          UpdateFormCode(); 
5270          Update(null);
5271       }
5272    }
5273
5274    void ReAttachMethod(Method method, ClassFunction function)
5275    {
5276       if(function)
5277       {
5278          // If it's an instance we'll ask if we want to move it inside...
5279          if(!function.attached.count && function.body)
5280          {
5281             // Find the function in the _class to check if it's a virtual function
5282             Class regClass = eSystem_FindClass(this.privateModule, ((Specifier)this.oClass.classDefinition.baseSpecs->first).name);
5283             Method method = eClass_FindMethod(regClass, function.declarator.symbol.string, this.privateModule);
5284             /*    LATER we'll need to check for public/virtual properties etc, for now only checked if virtual in base _class
5285             ClassDef def;
5286             for(def = this.classDefinition.first; def; def = def.next)
5287             {
5288                if(def.type == functionClassDef)
5289                {
5290                   if(def.function == function)
5291                      break;
5292                }
5293             }
5294             */
5295             if(!method || method.type != virtualMethod)
5296             {
5297                char title[1024];
5298                sprintf(title, $"Attach %s", function.declarator.symbol.string);
5299                if(MessageBox { type = yesNo, master = parent, text = title, 
5300                   contents = $"Method is unused. Move method inside instance?" }.Modal() == yes)
5301                {
5302                   moveAttached = true;
5303                }
5304             }
5305          }
5306
5307          methodAction = actionReattachMethod;
5308          this.method = method;
5309          this.function = function;
5310          ModifyCode();
5311          UpdateFormCode(); 
5312          Update(null);
5313       }
5314    }
5315
5316    void DetachMethod(Method method, ClassFunction function, int type)
5317    {
5318       bool result = true;
5319
5320       if(type == 1)
5321       {
5322          Window dialog
5323          {
5324             hasClose = true, borderStyle = sizable, minClientSize = { 300, 55 }, 
5325             master = sheet, text = $"Name detached method", background = formColor
5326          };
5327          Button cancelButton
5328          {
5329             dialog, anchor = { horz = 45, top = 30 }, size = { 80 }, text = $"Cancel", hotKey = escape,
5330             id = DialogResult::cancel, NotifyClicked = ButtonCloseDialog
5331          };
5332          Button okButton
5333          {
5334             dialog, anchor = { horz = -45, top = 30 }, size = { 80 }, text = $"OK", isDefault = true,
5335             id = DialogResult::ok, NotifyClicked = ButtonCloseDialog
5336          };
5337          EditBox nameBox
5338          {
5339             dialog, anchor = { left = 5, right = 5, top = 5 }
5340          };
5341          sprintf(methodName, "%s_%s", selected.name, method.name);
5342          nameBox.contents = methodName;
5343          incref nameBox;
5344          result = dialog.Modal() == ok;
5345          strcpy(methodName, nameBox.contents);
5346          delete nameBox;
5347       }
5348       if(result)
5349       {
5350          // If the method is not attached, move it outside
5351          if(type == 1)
5352          {
5353             // Add this class to the methodName
5354             char name[1024] = "";
5355
5356             if(this.selected != this.oClass && !method.dataType.thisClass)
5357             {
5358                strcat(name, this.selected.instance._class.name);
5359                strcat(name, "::");
5360                strcat(name, this.methodName);
5361                strcpy(this.methodName, name);
5362             }
5363             else if(method.dataType.thisClass && (this.selected == this.oClass || !eClass_IsDerived(this.oClass.instance._class, method.dataType.thisClass.registered)))
5364             {
5365                strcat(name, method.dataType.thisClass.string);
5366                strcat(name, "::");
5367                strcat(name, this.methodName);
5368                strcpy(this.methodName, name);
5369             }
5370             
5371             this.moveAttached = true;
5372          }
5373
5374          this.methodAction = actionDetachMethod;
5375          this.method = method;
5376          this.function = function;
5377          ModifyCode();
5378          UpdateFormCode(); 
5379          Update(null);
5380       }
5381    }
5382
5383    void AddObject(Instance instance, ObjectInfo * object)
5384    {
5385       int id;
5386       incref instance;
5387       //*object = _class.instances.Add(sizeof(ObjectInfo));
5388       *object = ObjectInfo { };
5389       oClass.instances.Insert((selected.oClass == selected) ? null : selected, *object);
5390       (*object).oClass = oClass;
5391       (*object).instance = instance;
5392       for(id = 1;; id++)
5393       {
5394          char name[1024];
5395          ObjectInfo check;
5396          sprintf(name, "%c%s%d", tolower(instance._class.name[0]), instance._class.name+1, id);
5397
5398          // if(strcmp(name, this.oClass.instance.name)) 
5399          
5400          {
5401             for(check = oClass.instances.first; check; check = check.next)
5402                if(!check.deleted && check.name && !strcmp(name, check.name)) 
5403                   break;
5404             if(!check)
5405             {
5406                (*object).name = CopyString(name);
5407                break;
5408             }
5409          }
5410       }            
5411       toolBox.controlClass = null;
5412
5413       ModifyCode();
5414
5415       //sheet.AddObject(*object, (*object).name, TypeData, true);
5416
5417       selected = *object;
5418    }
5419
5420    void EnsureUpToDate()
5421    {
5422       if(sheet && codeModified && parsing)
5423          ParseCode();
5424    }
5425
5426    void SelectObject(ObjectInfo object)
5427    {
5428       selected = object;
5429       oClass = object ? object.oClass : null;
5430       if(designer)
5431          designer.SelectObject(object, object ? object.instance : null);
5432    }
5433
5434    void SelectObjectFromDesigner(ObjectInfo object)
5435    {
5436       selected = object;
5437       sheet.SelectObject(object);
5438    }
5439
5440    void EnumerateObjects(Sheet sheet)
5441    {
5442       ObjectInfo oClass;
5443
5444       for(oClass = classes.first; oClass; oClass = oClass.next)
5445       {
5446          if(oClass.instance)
5447          {
5448             ObjectInfo object;
5449
5450             sheet.AddObject(oClass, oClass.name ? oClass.name : oClass.instance._class.name, typeClass, false);
5451             for(object = oClass.instances.first; object; object = object.next)
5452                sheet.AddObject(object, object.name ? object.name : object.instance._class.name, typeData, false);
5453          }
5454       }
5455       sheet.SelectObject(selected);
5456    }
5457
5458    void AddControl()
5459    {
5460       designer.AddObject();
5461    }
5462
5463    void DeleteObject(ObjectInfo object)
5464    {
5465       delete object.instance;
5466       object.deleted = true;
5467       object.modified = true;
5468       object.oClass.modified = true;
5469
5470       if(selected == object)
5471       {
5472          bool looped = false;
5473          ObjectInfo select = object;
5474
5475          for(;;)
5476          {            
5477             select = select.prev;
5478             if(!select) 
5479             {
5480                if(looped) break;
5481                select = object.oClass.instances.last;
5482                if(!select) break;
5483                looped = true;
5484             }
5485             if(!select.deleted)
5486                break;
5487          }
5488          sheet.SelectObject(select ? select : oClass);
5489       }
5490
5491       if(!object.instCode && object.oClass != object)
5492       {
5493          delete object.name;
5494          oClass.instances.Delete(object);
5495       }
5496
5497       if(sheet.codeEditor == this)
5498          sheet.DeleteObject(object);
5499    }
5500
5501    void RenameObject(ObjectInfo object, char * name)
5502    {
5503       bool valid = false;
5504
5505       // Validate the name:
5506       if(object != oClass && (!name || !name[0])) valid = true;   // What's this one again?
5507       else if(name[0] && (isalpha(name[0]) || name[0] == '_'))
5508       {
5509          int c;
5510          for(c = 0; name[c]; c++)
5511             if(!isalnum(name[c]) && name[c] != '_' && name[c] != '_')
5512                break;
5513          if(!name[c])
5514             valid = true;
5515       }
5516       if(valid)
5517       {
5518          delete object.name;
5519          object.name = (name && name[0]) ? CopyString(name) : null;
5520
5521          sheet.RenameObject(object, object.name ? object.name : object.instance._class.name);
5522       }
5523    }
5524
5525    void DesignerModifiedObject()
5526    {
5527       sheet.ListProperties(false);
5528       sheet.Update(null);
5529    }
5530
5531    void ListSubMembers(Type member)
5532    {
5533       Type subMember;
5534
5535       for(subMember = member.members.first; subMember; subMember = subMember.next)
5536       {
5537          if(subMember.name)
5538          {
5539             DataRow row = membersList.AddString(subMember.name);
5540             row.icon = icons[typeData];
5541          }
5542          else
5543          {
5544             ListSubMembers(subMember);
5545          }
5546       }
5547    }
5548
5549    void ListSubDataMembers(DataMember member, bool isPrivate)
5550    {
5551       DataMember subMember;
5552       for(subMember = member.members.first; subMember; subMember = subMember.next)
5553       {
5554          if((subMember.memberAccess == publicAccess && !isPrivate) || subMember._class.module == privateModule)
5555          {
5556             if(subMember.name)
5557             {
5558                DataRow row = membersList.AddString(subMember.name);
5559                BitmapResource bitmap = null;
5560                if(!subMember.dataType)
5561                   subMember.dataType = ProcessTypeString(subMember.dataTypeString, false);
5562             
5563                if(subMember.dataType && subMember.dataType.kind == classType && subMember.dataType._class)
5564                {
5565                   char * bitmapName = (char *)eClass_GetProperty(subMember.dataType._class.registered, "icon");
5566                   if(bitmapName)
5567                   {
5568                      bitmap = { bitmapName };
5569                      membersList.AddResource(bitmap);
5570                   }
5571                }
5572                row.icon = bitmap ? bitmap : icons[(subMember.memberAccess == publicAccess && !isPrivate) ? typeData : typeDataPrivate];
5573             }
5574             else
5575             {
5576                ListSubDataMembers(subMember, isPrivate || member.memberAccess == privateAccess);
5577             }
5578          }
5579       }
5580    }
5581
5582    void ListClassMembers(Class whatClass, bool methodsOnly)
5583    {
5584       Class _class;
5585       Class baseClass = eSystem_FindClass(this.privateModule, "class");
5586       bool isPrivate = false;
5587
5588       for(_class = whatClass; _class && _class.type != systemClass; _class = _class.base)
5589       {
5590          Method method, methodIt;
5591          DataMember member;
5592          DataMember memberIt;
5593
5594          for(methodIt = (Method)_class.methods.first; methodIt; methodIt = (Method)((BTNode)methodIt).next)
5595          {
5596             method = eClass_FindMethod(whatClass, methodIt.name, privateModule);
5597             if(methodIt.memberAccess == privateAccess && method && method.memberAccess == publicAccess)
5598                method = methodIt;
5599             if(method && method._class.type != systemClass && !eClass_FindMethod(baseClass, method.name, this.privateModule))
5600             {
5601                if(method.memberAccess == publicAccess || method._class.module == privateModule)
5602                {
5603                   DataRow row = membersList.FindString(method.name);
5604                   if(!row)
5605                   {
5606                      row = membersList.AddString(method.name);
5607
5608                      if(!method.dataType)
5609                         method.dataType = ProcessTypeString(method.dataTypeString, false);
5610
5611                      row.icon = icons[(method.type == virtualMethod && method.dataType && method.dataType.thisClass) ? typeEvent : ((method.memberAccess == publicAccess && !isPrivate) ? typeMethod : typeMethodPrivate)];
5612                   }
5613                }
5614             }
5615          }
5616
5617          if(!methodsOnly)
5618          {
5619             for(memberIt = _class.membersAndProperties.first; memberIt; memberIt = memberIt.next)
5620             {
5621                if(memberIt.name)
5622                {
5623                   if(memberIt.isProperty)
5624                   {
5625                      member = (DataMember)eClass_FindProperty(whatClass, memberIt.name, privateModule);
5626                      if(!member)
5627                         member = eClass_FindDataMember(whatClass, memberIt.name, privateModule, null, null);
5628                   }
5629                   else
5630                   {
5631                      member = eClass_FindDataMember(whatClass, memberIt.name, privateModule, null, null);
5632                      if(!member)
5633                         member = (DataMember)eClass_FindProperty(whatClass, memberIt.name, privateModule);
5634                   }
5635
5636                   if(memberIt.memberAccess == privateAccess && member && member.memberAccess == publicAccess)
5637                      member = memberIt;
5638                }
5639                else
5640                   member = memberIt;
5641
5642                if(member && (member.memberAccess == publicAccess || member._class.module == privateModule))
5643                {
5644                   if(member.isProperty)
5645                   {
5646                      Property prop = (Property) member;
5647                      if(!membersList.FindString(prop.name))
5648                      {
5649                         DataRow row = membersList.AddString(prop.name);
5650                         row.icon = icons[(member.memberAccess == publicAccess && !isPrivate) ? typeProperty : typePropertyPrivate];
5651                      }
5652                   }
5653                   else if(member.name && !membersList.FindString(member.name))
5654                   {
5655                      DataRow row = membersList.AddString(member.name);
5656                
5657                      BitmapResource bitmap = null;
5658                      if(!member.dataType)
5659                         member.dataType = ProcessTypeString(member.dataTypeString, false);
5660                
5661                      if(member.dataType && member.dataType.kind == classType && member.dataType._class)
5662                      {
5663                         char * bitmapName = (char *)eClass_GetProperty(member.dataType._class.registered, "icon");
5664                         if(bitmapName)
5665                         {
5666                            bitmap = { bitmapName };
5667                            membersList.AddResource(bitmap);
5668                         }
5669                      }
5670                      row.icon = bitmap ? bitmap : icons[(member.memberAccess == publicAccess && !isPrivate) ? typeData : typeDataPrivate];
5671                   }
5672                   else
5673                      ListSubDataMembers(member, member.memberAccess == privateAccess);
5674                }
5675             }
5676          }
5677          if(_class.inheritanceAccess == privateAccess)
5678          {
5679             isPrivate = true;
5680             if(_class.module != privateModule) break;
5681          }
5682       }
5683    }
5684
5685    void ListClassMembersMatch(Class whatClass, Type methodType)
5686    {
5687       Class _class;
5688       Class baseClass = eSystem_FindClass(this.privateModule, "class");
5689       bool isPrivate = false;
5690
5691       for(_class = whatClass; _class && _class.type != systemClass; _class = _class.base)
5692       {
5693          Method method;
5694          Property prop;
5695          DataMember member;
5696
5697          for(method = (Method)_class.methods.first; method; method = (Method)((BTNode)method).next)
5698          {
5699             if(method.memberAccess == publicAccess || method._class.module == privateModule)
5700             {
5701                if(method._class.type != systemClass && !eClass_FindMethod(baseClass, method.name, this.privateModule))
5702                {
5703                   if(!method.dataType)
5704                      method.dataType = ProcessTypeString(method.dataTypeString, false);
5705
5706                   if(MatchTypes(method.dataType, methodType, null, whatClass, /*null, */whatClass, false, true, false, false))
5707                   {
5708                      DataRow row = membersList.FindString(method.name);
5709                      if(!row)
5710                      {
5711                         row = membersList.AddString(method.name);
5712                         row.icon = icons[(method.type == virtualMethod && method.dataType.thisClass) ? typeEvent : ((method.memberAccess == publicAccess && !isPrivate) ? typeMethod : typeMethodPrivate)];
5713                      }
5714                   }
5715                }
5716             }
5717          }
5718          if(_class.inheritanceAccess == privateAccess)
5719          {
5720             isPrivate = true;
5721             if(_class.module != privateModule) break;
5722          }
5723       }
5724    }
5725
5726    void ListClassPropertiesAndVirtual(Class whatClass, String curString)
5727    {
5728       Class _class;
5729       bool isPrivate = false;
5730       for(_class = whatClass; _class /*&& _class.type != systemClass*/; _class = _class.base)
5731       {
5732          Method method;
5733          Property prop;
5734          DataMember member;
5735
5736          for(method = (Method)_class.methods.first; method; method = (Method)((BTNode)method).next)
5737          {
5738             if(method.type == virtualMethod)
5739             {
5740                if(method.memberAccess == publicAccess || method._class.module == privateModule)
5741                {
5742                   DataRow row = membersList.FindString(method.name);
5743                   if(!row)
5744                   {
5745                      row = membersList.AddString(method.name);
5746
5747                      if(!method.dataType)
5748                         method.dataType = ProcessTypeString(method.dataTypeString, false);
5749
5750                      row.icon = icons[method.dataType.thisClass ? typeEvent : ((method.memberAccess == publicAccess && !isPrivate) ? typeMethod : typeMethodPrivate)];
5751                   }
5752                }
5753             }
5754          }
5755
5756          for(member = _class.membersAndProperties.first; member; member = member.next)
5757          {
5758             if(member.memberAccess == publicAccess || member._class.module == privateModule)
5759             {
5760                if(member.isProperty)
5761                {
5762                   Property prop = (Property)member;
5763                   {
5764                      DataRow row = membersList.AddString(prop.name);
5765                      row.icon = icons[(member.memberAccess == publicAccess && !isPrivate) ? typeProperty : typePropertyPrivate];
5766                   }
5767                }
5768                else if(member.name && (!curString || strcmp(curString, member.name)))
5769                {
5770                   DataRow row = membersList.AddString(member.name);
5771                
5772                   BitmapResource bitmap = null;
5773                   if(!member.dataType)
5774                      member.dataType = ProcessTypeString(member.dataTypeString, false);
5775                
5776                   if(member.dataType && member.dataType.kind == classType && member.dataType._class)
5777                   {
5778                      char * bitmapName = (char *)eClass_GetProperty(member.dataType._class.registered, "icon");
5779                      if(bitmapName)
5780                      {
5781                         bitmap = { bitmapName };
5782                         membersList.AddResource(bitmap);
5783                      }
5784                   }
5785                   row.icon = bitmap ? bitmap : icons[(member.memberAccess == publicAccess && !isPrivate) ? typeData : typeDataPrivate];
5786                }
5787                else
5788                   ListSubDataMembers(member, member.memberAccess == privateAccess || isPrivate);
5789             }
5790          }
5791          if(_class.inheritanceAccess == privateAccess)
5792          {
5793             isPrivate = true;
5794             if(_class.module != privateModule) break;
5795          }
5796       }
5797    }
5798
5799    void ListMembers(Type type)
5800    {
5801       if(type && (type.kind == classType || type.kind == structType || type.kind == unionType))
5802       {
5803          Class _class;
5804          
5805          if(type.kind == classType)
5806          {
5807             if(type._class)
5808                ListClassMembers(type._class.registered, false);
5809          }
5810          else
5811          {
5812             Type member;
5813             for(member = type.members.first; member; member = member.next)
5814             {
5815                if(member.name)
5816                {
5817                   DataRow row = membersList.AddString(member.name);
5818                   row.icon = icons[typeData];
5819                }
5820                else if(member.kind == structType || member.kind == unionType)
5821                   ListSubMembers(member);
5822             }
5823          }
5824       }
5825    }
5826
5827    void ListModule(Module mainModule, int recurse, bool listClasses)
5828    {
5829       Module module;
5830       ListNameSpace(mainModule.application.systemNameSpace, 1, listClasses);
5831       ListNameSpace(mainModule.application.privateNameSpace, 1, listClasses);
5832       ListNameSpace(mainModule.application.publicNameSpace, 1, listClasses);
5833       for(module = mainModule.application.allModules.first; module; module = module.next)
5834       {
5835          if(ModuleVisibility(mainModule, module))
5836             ListNameSpace(module.publicNameSpace, recurse, listClasses);
5837       }
5838    }
5839
5840    void ListNameSpace(NameSpace nameSpace, int recurse, bool listClasses)
5841    {
5842       NameSpace * ns;
5843       BTNamedLink link;
5844
5845       if(listClasses)
5846       {
5847          for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
5848          {
5849             Class _class = link.data;
5850             if(_class.type != systemClass && !_class.templateClass)  // Omit templatized classes
5851             {
5852                DataRow row = membersList.AddString(_class.name);
5853                row.icon = (_class.type == unitClass || _class.type == enumClass) ? icons[typeDataType] : icons[typeClass];
5854             }
5855          }
5856       }
5857
5858       for(link = (BTNamedLink)nameSpace.defines.first; link; link = (BTNamedLink)((BTNode)link).next )
5859       {
5860          DefinedExpression definedExp = link.data;
5861          DataRow row = membersList.AddString(link /*definedExp*/.name);
5862          row.icon = icons[typeData];
5863       }
5864
5865       for(link = (BTNamedLink)nameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
5866       {
5867          GlobalFunction function = link.data;
5868          DataRow row = membersList.AddString(link /*function*/.name);
5869          row.icon = icons[typeMethod];
5870       }
5871
5872
5873       for(ns = (NameSpace *)nameSpace.nameSpaces.first; ns; ns = (NameSpace *)((BTNode)ns).next)
5874       {
5875          if(recurse != 2 && listClasses)
5876          {
5877             if(!membersList.FindString(ns->name))
5878             {
5879                DataRow row = membersList.AddString(ns->name);
5880                row.icon = icons[typeNameSpace];
5881             }
5882          }
5883
5884          if(recurse)
5885             ListNameSpace(ns, 2, listClasses);
5886       }
5887    }
5888
5889    void ListEnumValues(Class _class)
5890    {
5891       List<Class> classes { };
5892       for(; _class && _class.type == enumClass; _class = _class.base)
5893          classes.Insert(null, _class);
5894       for(_class : classes)
5895       {
5896          EnumClassData enumeration = (EnumClassData)_class.data;
5897          NamedLink item;
5898          for(item = enumeration.values.first; item; item = item.next)
5899          {
5900             DataRow row = membersList.AddString(item.name);
5901             row.icon = icons[typeEnumValue];
5902          }
5903       }
5904       delete classes;
5905    }
5906
5907    bool ListEnumsModule(Module mainModule, Type dest)
5908    {
5909       bool result = false;
5910       Module module;
5911       result |= ListEnums(mainModule.application.systemNameSpace, dest);
5912       result |= ListEnums(mainModule.application.privateNameSpace, dest);
5913       result |= ListEnums(mainModule.application.publicNameSpace, dest);
5914       for(module = mainModule.application.allModules.first; module; module = module.next)
5915       {
5916          if(ModuleVisibility(mainModule, module))
5917             result |= ListEnums(module.publicNameSpace, dest);
5918       }
5919       return result;
5920    }
5921
5922    void ListNameSpaceByString(Module mainModule, char * string)
5923    {
5924       NameSpace * nameSpace;
5925       Module module;
5926       nameSpace = FindNameSpace(mainModule.application.systemNameSpace, string);
5927       if(nameSpace) ListNameSpace(nameSpace, 0, true);
5928       nameSpace = FindNameSpace(mainModule.application.privateNameSpace, string);
5929       if(nameSpace) ListNameSpace(nameSpace, 0, true);
5930       nameSpace = FindNameSpace(mainModule.application.publicNameSpace, string);
5931       if(nameSpace) ListNameSpace(nameSpace, 0, true);
5932       for(module = mainModule.application.allModules.first; module; module = module.next)
5933       {
5934          if(ModuleVisibility(mainModule, module))
5935          {
5936             nameSpace = FindNameSpace(module.publicNameSpace, string);
5937             if(nameSpace) ListNameSpace(nameSpace, 0, true);
5938          }
5939       }
5940    }
5941
5942    bool ListEnums(NameSpace nameSpace, Type dest)
5943    {
5944       BTNamedLink link;
5945       bool result = false;
5946
5947       for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
5948       {
5949          Class _class = link.data;
5950          if(_class.type == enumClass && (dest.kind != classType || ((!dest._class || !dest._class.registered || (dest._class.registered != _class && strcmp(dest._class.registered.dataTypeString, "char *"))) && !dest.classObjectType)) &&
5951             dest.kind != pointerType && dest.kind != ellipsisType)
5952          {
5953             OldList conversions { };
5954             Type type { };
5955             type.kind = classType;
5956             type._class = FindClass(_class.name);
5957             if(MatchTypes(type, dest, &conversions, null, null, true, false, false, false))
5958             {
5959                ListEnumValues(_class);
5960                result = true;
5961             }
5962             conversions.Free(null);
5963             delete type;
5964          }
5965       }
5966       for(nameSpace = (NameSpace *)nameSpace.nameSpaces.first; nameSpace != null; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
5967       {
5968          result |= ListEnums(nameSpace, dest);
5969       }
5970       return result;
5971    }
5972
5973    NameSpace * FindNameSpace(NameSpace nameSpace, char * name)
5974    {
5975       int start = 0, c;
5976       char ch;
5977       for(c = 0; (ch = name[c]); c++)
5978       {
5979          if(ch == '.' || (ch == ':' && name[c+1] == ':'))
5980          {
5981             NameSpace * newSpace;
5982             char * spaceName = new char[c - start + 1];
5983             memcpy(spaceName, name + start, c - start);
5984             spaceName[c-start] = '\0';
5985             newSpace = (NameSpace *)nameSpace.nameSpaces.FindString(spaceName);
5986             delete spaceName;
5987             if(!newSpace)
5988                return null;
5989             nameSpace = newSpace;
5990             if(ch == ':') c++;
5991             start = c+1;
5992          }
5993       }
5994       if(c - start)
5995       {
5996          // name + start;
5997       }
5998       return (NameSpace *)nameSpace;
5999    }
6000
6001    void ListSymbols(Expression exp, bool enumOnly, char * string, Identifier realIdentifier)
6002    {
6003       bool listedEnums = false;
6004       Type destType = (exp && exp.destType && !exp.destType.truth) ? exp.destType : null;
6005       bool listClasses = true;
6006
6007       if(exp && (exp.type == identifierExp || exp.type == memberExp))
6008       {
6009          // TOCHECK: This memberExp check wasn't here... Some stuff isn't quite done
6010          Identifier id = (exp.type == memberExp) ? exp.member.member : exp.identifier;
6011          char * colons = id ? RSearchString(id.string, "::", strlen(id.string), true, false) : null;
6012
6013          if(exp.type == identifierExp)
6014             id = realIdentifier;
6015
6016          if(id && id._class && !id._class.name)
6017          {
6018             listClasses = false;
6019             SetThisClass(null);
6020          }
6021          else if(id && id._class && id._class.name)
6022          {
6023             if(id.classSym)
6024             {
6025                Class _class = id.classSym.registered;
6026                if(_class && _class.type == enumClass)
6027                {
6028                   ListEnumValues(_class);
6029                }
6030                else
6031                   ListClassMembers(id.classSym.registered, true);
6032                return;
6033             }
6034             return;
6035          }
6036          else if(id && colons)
6037          {
6038             ListNameSpaceByString(this.privateModule, id.string);
6039             return;
6040          }
6041       }
6042
6043       if(this.privateModule && destType && (destType.kind != pointerType || destType.type.kind != voidType) && destType.kind != ellipsisType)
6044       {
6045          listedEnums = ListEnumsModule(this.privateModule, destType);
6046       }
6047
6048       if(destType && destType.kind == classType && destType._class.registered && destType._class.registered.type == enumClass)
6049       {
6050          ListEnumValues(destType._class.registered);
6051
6052          if(insideClass)
6053             ListClassPropertiesAndVirtual(insideClass, null);
6054
6055          listedEnums = true;
6056       }
6057       else if(destType && destType.kind == enumType)
6058       {
6059          NamedLink value;
6060
6061          for(value = destType.members.first; value; value = value.next)
6062          {
6063             DataRow row = membersList.AddString(value.name);
6064             row.icon = icons[typeEnumValue];
6065          }
6066
6067          if(insideClass)
6068             ListClassPropertiesAndVirtual(insideClass, null);
6069
6070          listedEnums = true;
6071       }
6072       else if(insideClass && !enumOnly)
6073       {
6074          ListClassPropertiesAndVirtual(insideClass, string);
6075       }
6076
6077       if(listedEnums && string && string[0])
6078       {
6079          DataRow row = membersList.FindSubString(string);
6080          if(!row)
6081             listedEnums = false;      
6082       }
6083       
6084       if(!insideClass && exp && exp.destType && exp.destType.kind == functionType && GetThisClass())
6085       {
6086          ListClassMembersMatch(GetThisClass(), exp.destType);
6087       }
6088       else if(!insideClass && !enumOnly && !listedEnums)
6089       {
6090          Context ctx;
6091          Symbol symbol = null;
6092          {
6093             if(GetThisClass())
6094             { 
6095                ListClassMembers(GetThisClass(), false);
6096             }
6097
6098             for(ctx = listClasses ? GetCurrentContext() : GetTopContext(); ctx != GetTopContext().parent && !symbol; ctx = ctx.parent)
6099             {
6100                for(symbol = (Symbol)ctx.symbols.first; symbol; symbol = (Symbol)((BTNode)symbol).next)
6101                {
6102                   // Don't list enum values?
6103                   //if(symbol.type.kind != TypeEnum)
6104                   DataRow row = membersList.FindString(symbol.string);
6105                   if(!row)
6106                   {
6107                      if(GetBuildingEcereComModule() && symbol.type && symbol.type.kind == functionType && eSystem_FindFunction(privateModule, symbol.string))
6108                         continue;
6109                      row = membersList.AddString(symbol.string);
6110                      if(symbol.type && symbol.type.kind == functionType)
6111                         row.icon = icons[typeMethod];
6112                      else if(symbol.type && symbol.type.kind == enumType)
6113                      {
6114                         row.icon = icons[typeEnumValue];
6115                      }
6116                      else 
6117                      {
6118                         BitmapResource bitmap = null;
6119                         if(symbol.type && symbol.type.kind == classType && symbol.type._class && symbol.type._class)
6120                         {
6121                            char * bitmapName = (char *)eClass_GetProperty(symbol.type._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                if(listClasses)
6134                {
6135                   for(symbol = (Symbol)ctx.types.first; symbol; symbol = (Symbol)((BTNode)symbol).next)
6136                   {
6137                      DataRow row = membersList.FindString(symbol.string);
6138                      if(!row)
6139                      {
6140                         row = membersList.AddString(symbol.string);
6141                         if(symbol.type.kind == functionType)
6142                            row.icon = icons[typeMethod];
6143                         else if(symbol.type.kind == classType && (!symbol.type._class.registered || (symbol.type._class.registered.type != unitClass && symbol.type._class.registered.type != enumClass)))
6144                         {
6145                            row.icon = icons[typeClass];
6146                         }
6147                         else
6148                         {
6149                            row.icon = icons[typeDataType];
6150                         }
6151                      }
6152                   }
6153                }
6154             }
6155
6156             ListModule(this.privateModule, 1, listClasses);
6157             // TODO: Implement this with name space
6158             /*
6159             {
6160                GlobalData data;
6161                for(data = globalData.first; data; data = data.next)
6162                {
6163                   DataRow row = membersList.FindString(data.name);
6164                   if(!data.dataType)
6165                      data.dataType = ProcessTypeString(data.dataTypeString, false);
6166                   if(!row)
6167                   {
6168                      row = membersList.AddString(data.name);
6169
6170                      if(data.dataType && data.dataType.kind == TypeEnum)
6171                      {
6172                         row.icon = icons[typeEnumValue];
6173                      }
6174                      else 
6175                      {
6176                         BitmapResource bitmap = null;
6177                         if(data.dataType && data.dataType.kind == classType && data.dataType._class && data.dataType._class)
6178                         {
6179                            char * bitmapName = (char *)eClass_GetProperty(data.dataType._class.registered, "icon");
6180                            if(bitmapName)
6181                            {
6182                               bitmap = { bitmapName };
6183                               membersList.AddResource(bitmap);
6184                            }
6185                         }
6186                         row.icon = bitmap ? bitmap : icons[typeData];
6187                      }
6188                   }
6189                }
6190             }
6191             */
6192
6193             {
6194                DataRow row = membersList.AddString("Min");
6195                row.icon = icons[typeMethod];
6196
6197                row = membersList.AddString("Max");
6198                row.icon = icons[typeMethod];
6199
6200                row = membersList.AddString("Abs");
6201                row.icon = icons[typeMethod];
6202
6203                row = membersList.AddString("Sgn");
6204                row.icon = icons[typeMethod];
6205             }
6206          }
6207       }
6208    }
6209
6210    void OverrideVirtualFunction(ClassFunction function, Method method, Class _class, bool isInstance, bool extraIndent)
6211    {
6212       EditBoxStream f { editBox = editBox };
6213       uint position = 0;
6214       EditLine l1, l2;
6215       int x1,y1,x2,y2;
6216
6217       updatingCode = true;
6218
6219       if(!method.dataType)
6220          method.dataType = ProcessTypeString(method.dataTypeString, false);
6221
6222       DeleteJunkBefore(f, function.loc.start.pos, &position);
6223       f.DeleteBytes(function.loc.end.pos - function.loc.start.pos - 1);
6224
6225       // ADDING METHOD HERE
6226       {
6227          Type dataType = method.dataType;
6228          Type returnType = dataType.returnType;
6229          Type param;
6230          Class moduleClass = eSystem_FindClass(this.privateModule, "Module");
6231
6232          if(insideDef.prev)
6233              f.Printf("\n\n");
6234          else
6235             f.Printf("\n");
6236          if(extraIndent) f.Printf("   ");
6237          f.Printf("   ");
6238          OutputType(f, returnType, false);
6239
6240          f.Printf(" ");
6241          
6242          if(dataType.thisClass && !dataType.classObjectType && (!isInstance || !insideClass || !eClass_IsDerived(insideClass, dataType.thisClass.registered)))
6243          {
6244             if(dataType.thisClass.shortName)
6245                f.Printf(dataType.thisClass.shortName);
6246             else
6247                f.Printf(dataType.thisClass.string);
6248             f.Printf("::");
6249          }
6250          f.Printf(method.name);
6251          f.Printf("(");
6252          for(param = dataType.params.first; param; param = param.next)
6253          {
6254             // Decided not to write void...
6255             if(param.kind != voidType)
6256             {
6257                OutputType(f, param, true);
6258                if(param.next)
6259                   f.Printf(", ");
6260             }
6261          }
6262          f.Printf(")\n");                  
6263          if(extraIndent) f.Printf("   ");
6264          f.Printf("   %c\n", OpenBracket);
6265
6266          editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6267
6268          f.Printf("\n");
6269
6270          if(!_class || 
6271             (
6272                (isInstance ? _class : _class.base)._vTbl[method.vid] == moduleClass._vTbl[__ecereVMethodID___ecereNameSpace__ecere__com__Module_OnLoad] ||
6273                (isInstance ? _class : _class.base)._vTbl[method.vid] == DummyMethod)) // Temp Check for DefaultFunction
6274          {
6275             if(returnType && returnType.kind == classType && !strcmp(returnType._class.string, "bool"))
6276             {
6277                if(extraIndent) f.Printf("   ");
6278                f.Printf("      return true;\n");
6279             }
6280             else if(returnType && returnType.kind != voidType)
6281             {
6282                if(extraIndent) f.Printf("   ");
6283                f.Printf("      return 0;\n");
6284             }
6285          }
6286          else
6287          {
6288             if(extraIndent) f.Printf("   ");
6289             f.Printf("      ");
6290             if(returnType.kind != voidType)
6291                f.Printf("return ");
6292             f.Printf("%s::%s(", isInstance ? _class.name : _class.base.name, method.name);
6293             for(param = dataType.params.first; param; param = param.next)
6294             {
6295                if(param.prev) f.Printf(", ");
6296                if(param.kind != voidType)
6297                   f.Printf(param.name);
6298             }
6299             f.Printf(");\n");
6300          }
6301       }
6302
6303       if(extraIndent) f.Printf("   ");
6304       f.Printf("   %c", CloseBracket);
6305       // f.Printf("\n");
6306
6307       delete f;
6308
6309       if(extraIndent) { x1 += 3; x2 += 3; }
6310       editBox.SetSelPos(l1, y1, x1 + 6, l2, y2, x2 + 6);
6311
6312       this.updatingCode = false;
6313
6314    }
6315
6316    // Return false if we overrided a function and don't want to run params listing
6317    bool InvokeAutoComplete(bool enumOnly, int pointer, bool caretMove)
6318    {
6319       bool didOverride = false;
6320       EditLine line = editBox.line;
6321       char * text = line.text;
6322       int lineNum, charPos;
6323       Expression exp = null;
6324       EditLine l1, l2;
6325       int x1,y1, x2,y2;
6326       //Identifier id = null;
6327       Expression memberExp = null;
6328       Identifier realIdentifier = null;
6329
6330       if(!parsing) return true;
6331       if(!privateModule) return !didOverride;
6332
6333       insideFunction = null;
6334
6335       charPos = editBox.charPos + 1;
6336       if(!membersListShown)
6337       {
6338          EnsureUpToDate();
6339       }
6340
6341       editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6342       { 
6343          EditBoxStream f { editBox = editBox };
6344
6345          updatingCode = true;
6346          editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
6347          for(;;)
6348          {
6349             char ch;
6350             if(!f.Seek(-1, current))
6351                break;
6352             f.Getc(&ch);
6353             if(!isspace(ch)) break;
6354             f.Seek(-1, current);
6355          }
6356          editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6357
6358          lineNum = editBox.lineNumber + 1;
6359          charPos = editBox.charPos + 1;
6360          delete f;
6361          updatingCode = false;
6362       }
6363
6364       if(!membersListShown)
6365       {
6366          memberExp = FindExpTree(ast, lineNum, charPos);
6367          if(memberExp && (memberExp.type == TypeKind::memberExp || memberExp.type == pointerExp) && !memberExp.addedThis)
6368          {
6369          }
6370          else if(!pointer)
6371          {
6372             editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6373             { 
6374                EditBoxStream f { editBox = editBox };
6375                char ch = 0;
6376
6377                updatingCode = true;
6378
6379                editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
6380
6381                f.Getc(&ch);
6382                if(ch == '}' || ch == ',' || ch == ')')
6383                {
6384                   f.Seek(-1, current);
6385                   ch = ' ';
6386                }
6387                if(isspace(ch))
6388                {
6389                   for(;;)
6390                   {
6391                      char ch;
6392                      if(!f.Seek(-1, current))
6393                         break;
6394                      f.Getc(&ch);
6395                      if(!isspace(ch)) break;
6396                      f.Seek(-1, current);
6397                   }
6398                }
6399                else
6400                   f.Seek(-1, current);
6401
6402                editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6403
6404                lineNum = editBox.lineNumber + 1;
6405                charPos = editBox.charPos + 1;
6406                delete f;
6407                updatingCode = false;
6408             }
6409
6410             realIdentifier = FindCtxTree(ast, lineNum, charPos);
6411             exp = ctxInsideExp;
6412          }
6413       }
6414
6415       editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6416       lineNum = editBox.lineNumber + 1;
6417       charPos = editBox.charPos/* + 1*/;
6418
6419       {
6420          int rowCount;
6421          char tempString[1024];
6422          char * string = null;
6423          CodePosition idStart, idEnd;
6424
6425          if(membersListShown)
6426          {
6427             char * buffer = membersLine.text;
6428             int c;
6429             bool firstChar = true;
6430             int len = 0;
6431             string = tempString;
6432
6433             for(c = membersLoc.start.charPos; c<membersLoc.end.charPos; c++)
6434             {
6435                bool isSpace = (buffer[c] == ' ' || buffer[c] == '\t');
6436                if(!isSpace) firstChar = false;
6437                if(!firstChar)
6438                   string[len++] = buffer[c];
6439             }
6440             string[len] = 0;
6441          }
6442          else //if(realIdentifier)//if(id)
6443          {
6444             /*
6445             char * buffer = id.string;
6446             int c;
6447             bool firstChar = true;
6448             int len = 0;
6449             string = tempString;
6450             for(c = 0; c<= charPos - id.loc.start.charPos; c++)
6451             {
6452                bool isSpace = (buffer[c] == ' ' || buffer[c] == '\t');
6453                if(!isSpace) firstChar = false;
6454                if(!firstChar)
6455                   string[len++] = buffer[c];
6456             }
6457             string[len] = 0;
6458             */
6459             int x, y;
6460             int len = 0;
6461             EditLine editLine = editBox.line;
6462             bool firstChar = true;
6463             bool done = false;
6464
6465             string = tempString;
6466             for(y = lineNum-1; y >= 0; y--)
6467             {
6468                char * buffer = editLine.text;
6469                int lineCount = editLine.count;
6470                for(x = (y == lineNum-1) ? (Min(charPos, lineCount) - 1 ): lineCount-1; x >= 0; x--)
6471                {
6472                   bool isSpace = (buffer[x] == ' ' || buffer[x] == '\t');
6473                   if(!isSpace)
6474                   {
6475                      if(firstChar)
6476                      {
6477                         idEnd.charPos = x + 2;
6478                         idEnd.line = y + 1;
6479                      }
6480                      firstChar = false;
6481                   }
6482                   // TESTING THIS CODE HERE FOR NOT CONSIDERING bool when doing ctrl-space past it
6483                   else if(firstChar)
6484                   {
6485                      idEnd.charPos = x + 2;
6486                      idEnd.line = y + 1;
6487                      done = true;
6488                      break;
6489                   }
6490                   if(!firstChar)
6491                   {
6492                      if(!isalnum(buffer[x]) && buffer[x] != '_')
6493                      {
6494                         x++;
6495                         done = true;
6496                         break;
6497                      }
6498                      memmove(string+1, string, len++);
6499                      string[0] = buffer[x];
6500                   }
6501                }
6502
6503                //if(done || firstChar)
6504                if(done || !firstChar)
6505                   break;
6506                editLine = editLine.prev;
6507             }
6508             string[len] = 0;
6509             if(!strcmp(string, "case"))
6510             {
6511                idEnd.charPos += 4;
6512                x+=4;
6513                string[0] = '\0';
6514             }
6515             else if(!strcmp(string, "return"))
6516             {
6517                idEnd.charPos += 6;
6518                x+=6;
6519                string[0] = '\0';
6520             }
6521             else if(!strcmp(string, "delete"))
6522             {
6523                idEnd.charPos += 6;
6524                x+=6;
6525                string[0] = '\0';
6526             }
6527             else if(!strcmp(string, "new"))
6528             {
6529                idEnd.charPos += 3;
6530                x+=3;
6531                string[0] = '\0';
6532             }
6533             else if(!strcmp(string, "renew"))
6534             {
6535                idEnd.charPos +=5;
6536                x+=5;
6537                string[0] = '\0';
6538             }
6539             if(x < 0) x = 0;
6540
6541             idStart.charPos = x + 1;
6542             idStart.line = y + 1;
6543          }
6544
6545          if(!membersListShown)
6546          {
6547             membersList.Clear();
6548             if(memberExp && (memberExp.type == ExpressionType::memberExp || memberExp.type == pointerExp) && !memberExp.addedThis)
6549             {
6550                Type type = memberExp.member.exp.expType;
6551                if(pointer == 2 && type)
6552                {
6553                   if(type.kind == pointerType || type.kind == arrayType)
6554                      type = type.type;
6555                   /*else
6556                      type = null;*/
6557                }
6558                ListMembers(type);
6559             }
6560             else if(!pointer)
6561             {
6562                ListSymbols(exp, enumOnly, string, realIdentifier);
6563             }
6564             membersList.Sort(null, 1);
6565          }
6566
6567          if(insideFunction)
6568          {
6569             // Virtual function override
6570             Identifier id = GetDeclId(insideFunction.declarator);
6571             char * string = id ? id.string : null;
6572
6573             Method method = eClass_FindMethod(GetThisClass(), string, this.privateModule);
6574             if(method)
6575             {
6576                if(method.type != virtualMethod || (!insideInstance && method._class == GetThisClass()))
6577                   insideFunction = null;
6578                else
6579                {
6580                   OverrideVirtualFunction(insideFunction, method, GetThisClass(), insideInstance, insideInstance && insideClass);
6581                   didOverride = true;
6582                }
6583             }
6584          }
6585          if(!didOverride) //insideFunction)
6586          {
6587             rowCount = membersList.rowCount;
6588             if(rowCount)
6589             {
6590                DataRow row = string ? membersList.FindSubString(string) : null;
6591                if(row && !membersList.FindSubStringAfter(row, string) && !caretMove)
6592                {
6593                   char * newString = row.string;
6594                   if(!membersListShown)
6595                   {
6596                      membersLoc.start.line = idStart.line-1;
6597                      membersLoc.start.charPos = idStart.charPos-1;
6598                      //membersLoc.end = membersLoc.start;
6599                       membersLoc.end.charPos = idEnd.charPos-1;
6600                       membersLoc.end.line = idEnd.line-1;
6601                      //membersLoc.end.charPos = idStart.charPos + strlen(string)-1; //end.charPos-1;
6602                      //membersLoc.end.charPos = idStart.charPos + strlen(string)-1; //end.charPos-1;
6603                      membersLine = line;
6604                   }
6605                   else
6606                   {
6607                      membersList.Destroy(0);
6608                      membersListShown = false;
6609                   }
6610
6611                   editBox.GoToPosition(membersLine, membersLoc.start.line, membersLoc.start.charPos);
6612                   editBox.Delete(
6613                      line, membersLoc.start.line, membersLoc.start.charPos,
6614                      line, membersLoc.end.line, membersLoc.end.charPos);
6615                   editBox.PutS(newString);
6616                }
6617                else
6618                {
6619                   if(!row)
6620                   {
6621                      row = membersList.FindSubStringi(string);
6622                      if(row)
6623                         membersList.currentRow = row;
6624                      membersList.currentRow.selected = false;
6625                   }
6626                   else
6627                      membersList.currentRow = row;
6628
6629                   if(!membersListShown)
6630                   {
6631                      Point caret;
6632
6633                      // TESTING THESE ADDITIONS TO THE IF SO THAT CARET ISNT MOVED IF NOT ON TOP OF A WORD
6634                      if(string && string[0] && lineNum == idStart.line && charPos >= idStart.charPos-1 && charPos <= idEnd.charPos-1)
6635                         editBox.SetSelPos(l1, y1, idStart.charPos-1, l2, y2, idStart.charPos-1);
6636                      editBox.GetCaretPosition(caret);
6637                      editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
6638                
6639                      membersList.master = this;
6640
6641                      caret.y += editBox.GetCaretSize();
6642                      caret.x -= 20;
6643                      membersList.Create();
6644
6645                      {
6646                         int x = caret.x + editBox.absPosition.x - app.desktop.absPosition.x - editBox.scroll.x;
6647                         int y = caret.y + editBox.absPosition.y - app.desktop.absPosition.y - editBox.scroll.y;
6648                         Window parent = membersList.parent;
6649
6650                         if(!paramsAbove && (paramsShown || y + membersList.size.h > parent.clientSize.h))
6651                         {
6652                            y -= editBox.GetCaretSize() + membersList.size.h;
6653                            membersAbove = true;
6654                         }
6655                         else
6656                            membersAbove = false;
6657
6658                         membersList.position = { x, y };
6659                      }
6660
6661                      membersLine = l1;
6662                      membersLoc.start.line = lineNum - 1;
6663
6664                      if(string && string[0])
6665                      {
6666                         membersLoc.start.charPos = idStart.charPos-1;
6667                         membersLoc.end = membersLoc.start;
6668                         //membersLoc.end.charPos = id.loc.end.charPos-1;
6669                         membersLoc.end.charPos = idStart.charPos + strlen(string)-1; //end.charPos-1;
6670                      }
6671                      else
6672                      {
6673                         membersLoc.start.charPos = charPos;
6674                         membersLoc.end = membersLoc.start;
6675                         membersLoc.end.charPos = charPos;
6676                      }
6677                      membersListShown = true;
6678
6679                      // Hack to keep caret shown
6680                      editBox.GetCaretPosition(caret);
6681                      editBox.SetCaret(caret.x, caret.y, editBox.GetCaretSize());
6682                   }
6683                   if(row)
6684                      membersList.SetScrollPosition(0, row.index * membersList.rowHeight);
6685                }            
6686             }
6687          }
6688       }
6689
6690       SetCurrentContext(globalContext);
6691       SetThisClass(null);
6692
6693       return !didOverride;
6694    }
6695
6696    void InvokeParameters(bool exact, bool reposition, bool caretMove)
6697    {
6698       EditLine line = editBox.line;
6699       char * text = line.text;
6700       int lineNum, charPos;
6701       Expression exp = null;
6702       EditLine l1, l2;
6703       int x1,y1, x2,y2;
6704
6705       if(!parsing) return;
6706
6707       charPos = editBox.charPos + 1;
6708       EnsureUpToDate();
6709
6710       editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6711       { 
6712          EditBoxStream f { editBox = editBox };
6713          char ch;
6714
6715          updatingCode = true;
6716          editBox.SetSelPos(l1, y1, x1, l2, y2, x2);
6717
6718          f.Getc(&ch);
6719          if(ch == '}' || ch == ',' || ch == ')')
6720          {
6721             f.Seek(-1, current);
6722             ch = ' ';
6723          }
6724          if(isspace(ch))
6725          {
6726             for(;;)
6727             {
6728                char ch;
6729                if(!f.Seek(-1, current))
6730                   break;
6731                f.Getc(&ch);
6732                if(!isspace(ch)) break;
6733                f.Seek(-1, current);
6734             }
6735          }
6736          else
6737             f.Seek(-1, current);
6738
6739          editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6740
6741          lineNum = editBox.lineNumber + 1;
6742          charPos = editBox.charPos + 1;
6743          delete f;
6744          updatingCode = false;
6745       }
6746       
6747       charPos = Min(charPos, l1.count + 1);
6748       if(!caretMove)
6749          FindParamsTree(ast, lineNum, charPos);
6750
6751       // Not sure about this == ExpCall... paramsInsideExp doesn't seem to necessarily be a ExpCall
6752       if(exact && ((::functionType && paramsInsideExp.type == callExp && paramsInsideExp.call.exp.loc.end.charPos != charPos-1) /*|| instanceType*/))
6753       {
6754          ::functionType = null;
6755          ::instanceType = null;
6756       }
6757
6758       //if((::functionType || ::instanceType) && (!paramsShown || insideExp != functionExp || ::paramsID != this.paramsID))
6759       if((::functionType || ::instanceType) && (!paramsShown || true /*paramsInsideExp.destType != functionExp.destType */|| ::paramsID != this.paramsID))
6760       {
6761
6762          int x, y;
6763          Window parent = paramsList.parent;
6764
6765          if(this.functionType != ::functionType || this.instanceType != ::instanceType)
6766             reposition = false;
6767
6768          if(!this.paramsShown || reposition || paramsInsideExp != functionExp || ::instanceType) // Added instanceType here, otherwise instance popups never reposition... 
6769                                                                                                           // ( Dummy exp: always ends up with same memory)
6770          {
6771             editBox.GetSelPos(&l1, &y1, &x1, &l2, &y2, &x2, false);
6772             editBox.GetCaretPosition(paramsPosition);
6773             this.paramsPosition.y += editBox.GetCaretSize();
6774          }
6775
6776          FreeType(this.functionType);
6777          FreeType(this.instanceType);
6778
6779          this.functionType = ::functionType;
6780          this.instanceType = ::instanceType;
6781
6782          if(this.functionType) this.functionType.refCount++;
6783          if(this.instanceType) this.instanceType.refCount++;
6784
6785          this.paramsID = ::paramsID;
6786          functionExp = paramsInsideExp;
6787
6788          paramsList.master = this;
6789
6790          paramsList.Create();
6791
6792          x = paramsPosition.x + editBox.absPosition.x - app.desktop.absPosition.x - editBox.scroll.x;
6793          y = paramsPosition.y + editBox.absPosition.y - app.desktop.absPosition.y - editBox.scroll.y;
6794
6795          if(!this.membersAbove && ( this.membersListShown || y + paramsList.size.h > parent.clientSize.h) )
6796          {
6797             y -= editBox.GetCaretSize() + paramsList.clientSize.h;
6798             paramsAbove = true;
6799          }
6800          else
6801             paramsAbove = false;
6802          if(x + paramsList.size.w > parent.clientSize.w)
6803          {
6804             x = parent.clientSize.w - paramsList.size.w;
6805             if(x < 0) x = 0;
6806          }
6807
6808          paramsList.position = { x, y };
6809
6810          // Hack to keep caret shown
6811          {
6812             Point caret;
6813             editBox.GetCaretPosition(caret);
6814             editBox.SetCaret(caret.x, caret.y, editBox.GetCaretSize());
6815          }
6816
6817          this.paramsShown = true;
6818       }
6819       else if((!::functionType && !::instanceType) || reposition)
6820       {
6821          paramsList.Destroy(0);
6822          paramsShown = false;
6823
6824          FreeType(this.functionType);
6825          FreeType(this.instanceType);
6826          this.functionType = null;
6827          this.instanceType = null;
6828          this.paramsID = -1;
6829       }
6830
6831       SetCurrentContext(globalContext);
6832       SetThisClass(null);
6833    }
6834
6835    bool ViewDesigner()
6836    {
6837       if(designer)
6838       {
6839          designer.visible = true;
6840          designer.Activate();
6841       }
6842       return true;
6843    }
6844 };
6845
6846 CodeEditor NewCodeEditor(Window parent, WindowState state, bool modified)
6847 {
6848    CodeEditor document { state = state, parent = parent, modifiedDocument = modified };
6849    document.Create();
6850    return document;
6851 }