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