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