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