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