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