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