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