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