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