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