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