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