9d15c9e0e4bfcbd41a67f5bd1529a5d27e408487
[sdk] / ecere / src / gui / FormDesigner.ec
1 namespace gui;
2
3 import "Window"
4
5 define GridSnap = 8;
6
7 class FormDesigner : ClassDesignerBase
8 {
9    opacity = 0;
10    //background = Blue;
11    drawBehind = true;
12    inactive = true;
13    stayOnTop = true;
14    // clickThrough = true;
15
16    Window selected;
17    Window form;
18    Window moved;
19    int xClicked, yClicked;
20    int resizeX, resizeY;
21    int wBefore, hBefore;
22    int xBefore, yBefore;
23    Window parentBefore;
24    bool onBorder;
25
26    // CLASS EDITOR METHODS
27    void SelectObject(ObjectInfo object, Window control)
28    {
29       if((object && form != object.oClass.instance) || !object)
30       {
31          if(form)
32             form.visible = false;
33
34          form = (Window)(object ? object.oClass.instance : null);
35
36          if(form)
37             form.visible = true;
38       }
39       
40       selected = control;
41       Update(null);
42       //activeDesigner.Update(null);
43    }
44
45    void ::CreateObject(DesignerBase designer, Window instance, ObjectInfo object, bool isClass, Window _class)
46    {
47       instance.object = object;
48       instance.formDesigner = true;
49       LockControls(instance, instance);
50       if(isClass)
51       {
52          // TESTING THIS IN POST... instance.visible = false;
53          instance.parent = designer;
54          instance.OnRedraw = DrawGrid;
55          //instance.OnLeftButtonUp = ecere::OnLeftButtonUp;
56          //instance.OnLeftButtonDown = ecere::OnLeftButtonDown;
57          //instance.OnLeftDoubleClick = ecere::OnLeftDoubleClick;
58          instance.OnSysKeyDown = ecere::gui::OnKeyDown;
59          //instance.Create();
60       }
61       else
62       {
63          // instance.parent = _class;
64       }   
65    }
66
67    void ::PostCreateObject(Window instance, ObjectInfo object, bool isClass, Window _class)
68    {
69       if(instance.displayDriver && !strcmp(instance.displayDriver, "LFB")) return;
70       instance.setVisible = instance.visible;
71       if(isClass)
72       {
73          instance.visible = false;
74          instance.Create();
75       }
76       else if(instance.parent == guiApp.desktop)   // TOCHECK: Verify if there's 2 guiApp/desktop's to be worried about
77          instance.autoCreate = false;
78       else
79          instance.visible = true;
80    }
81
82    void ::DroppedObject(Window instance, ObjectInfo object, bool isClass, Window _class)
83    {
84       instance.parent = _class;
85       instance.text = object.name;
86       instance.Create();
87    }
88
89    void AddObject()
90    {
91       if(form)
92       {
93          OnLeftButtonUp(
94             selected.absPosition.x - absPosition.x - clientStart.x + selected.clientStart.x + GridSnap,
95             selected.absPosition.y - absPosition.y - clientStart.y + selected.clientStart.y + GridSnap, 0);
96          Activate();
97       }
98    }
99
100    void ::ListClasses(DesignerBase designer, Class _class)
101    {
102       OldLink link;
103       if(eClass_GetProperty(_class, "icon"))
104          designer.AddToolBoxClass(_class);
105       /*
106       for(link = _class.derivatives.first; link; link = link.next)
107          designer.AddToolBoxClass(link.data);
108       */
109    }
110
111    void ListToolBoxClasses(DesignerBase designer)
112    {
113       OldLink link;
114       Class commonControlClass = eSystem_FindClass(_class.module, "CommonControl");
115       for(link = commonControlClass.derivatives.first; link; link = link.next)
116       {
117          ListSubClasses(designer, link.data);
118       }
119    }
120
121    void ::ListSubClasses(DesignerBase designer, Class c)
122    {
123       OldLink link;
124       ListClasses(designer, c);
125       for(link = c.derivatives.first; link; link = link.next)
126          ListSubClasses(designer, link.data);
127    }
128
129    void ::PrepareTestObject(DesignerBase designer, Window test)
130    {
131       test.parent = designer;
132    }
133
134    void ::DestroyObject(Window window)
135    {
136       // Better way to safeguard this? Still needed?
137       // if(eInstance_FindMethod(window, "Destroy"))
138          window.Destroy(0);
139    }
140
141    void Reset()
142    {
143       form = null;
144       FreeMouseRange();
145       moved = null;
146       selected = null;
147    }
148
149    void ::FixProperty(Property prop, Window object)
150    {
151       FormDesigner designer = (FormDesigner)activeDesigner.classDesigner;
152       
153       if(!strcmp(prop.name, "parent"))
154       {
155          if(object.parent == guiApp.desktop)
156             object.parent = designer.form;
157
158          if(object.parent == designer.form)
159          {  
160             ObjectInfo previous = object.object;
161             while((previous = previous.prev) && ((Window)previous.instance).parent != designer.form);
162             if(previous)
163                object.parent.children.Move(object, (Window)previous.instance);
164          }
165       }
166       
167       if(!strcmp(prop.name, "master") && !object.master)
168          object.master = designer.form;
169
170       if(!strcmp(prop.name, "visible"))
171       {
172          object.setVisible = !object.style.hidden;
173          object.visible = true;
174       }
175    }
176
177    void ::CreateNew(EditBox editBox, Size clientSize, char * name, char * inherit)
178    {
179       int w = 640, h = 480;
180       if(clientSize.w - 40 -200 < w)
181       {
182          w = (clientSize.w - 40 - 200);
183          w -= w % GridSnap;
184          h = h * w / 640;
185          h -= h % GridSnap;
186          w = Max(w, 304);
187          h = Max(h, 304);
188       }
189
190       editBox.Home();
191       editBox.Printf("import \"ecere\"\n\n");
192       editBox.Printf("class %s : %s\n", name, inherit);
193       editBox.Printf("{\n");
194       
195       editBox.Printf("   text = \"%s\";\n", name);
196       //editBox.Printf("   background = Color { 212, 208, 200 };\n");
197       
198       editBox.Printf("   background = activeBorder;\n");
199       editBox.Printf("   borderStyle = sizable;\n");
200       editBox.Printf("   hasMaximize = true;\n");
201       editBox.Printf("   hasMinimize = true;\n");
202       editBox.Printf("   hasClose = true;\n");
203       //editBox.Printf("   position = { 20, 20 };\n");
204       editBox.Printf("   size = { %d, %d };\n", w, h);
205       
206       
207       //editBox.Printf("   Button ok { parent = this, position = { 100, 100 }, size = { 80, 20 } };\n");
208
209       //editBox.Printf("\n   Button ok\n   {\n      parent = this;\n\n      bool NotifyClicked()\n      {\n      }\n   };\n");
210       editBox.Printf("}\n");
211
212       /*
213       editBox.Printf("class %s : %s\n", "SecondForm", inherit);
214       editBox.Printf("{\n");
215       editBox.Printf("   text = \"%s\";\n", "SecondForm");
216       editBox.Printf("   background = Color { 100, 90, 120 };\n");
217       editBox.Printf("   borderStyle = sizable;\n");
218       editBox.Printf("   hasMaximize = true;\n");
219       editBox.Printf("   hasMinimize = true;\n");
220       editBox.Printf("   hasClose = true;\n");
221       editBox.Printf("   position = { 20, 20 };\n");
222       editBox.Printf("   size = { %d, %d };\n", 320, 200);
223       editBox.Printf("   Button ok { parent = this, text = \"OK\", position = { A_RIGHT|10, A_RIGHT|10 }, size = { 80, 20 } };\n");
224       editBox.Printf("}\n");
225       */
226    }
227
228    // WINDOW METHODS
229    void OnRedraw(Surface surface)
230    {
231       DrawSelection(master, surface);
232    }
233
234    bool OnMouseMove(int x, int y, Modifiers mods)
235    {
236       if(mods.isSideEffect)
237          return true;
238
239       if(x >= 0 && y >=0 && x < clientSize.w && y < clientSize.h)
240       {
241          // Capture();
242          if(moved)
243          {
244             Window parent = FindWindow(form, master, moved, x,y, true, null, null);
245             Window curParent = moved.parent;
246
247             int dx = x - xClicked;
248             int dy = y - yClicked;
249
250             if(resizeX || resizeY)
251                parent = curParent;
252             if(!parent)
253                parent = (moved == form) ? master : form;
254             {
255                int w = moved.size.w;
256                int h = moved.size.h;
257                Box box;
258                Anchor anchor = moved.anchor;
259                
260                x = xBefore + parentBefore.absPosition.x - curParent.absPosition.x + parentBefore.clientStart.x - curParent.clientStart.x;
261                y = yBefore + parentBefore.absPosition.y - curParent.absPosition.y + parentBefore.clientStart.y - curParent.clientStart.y;
262
263                box.left = moved.absPosition.x - absPosition.x - clientStart.x;
264                box.top  = moved.absPosition.y - absPosition.y - clientStart.y;
265                box.right = box.left + moved.size.w - 1;
266                box.bottom= box.top  + moved.size.h - 1;
267
268                dx -= dx % GridSnap;
269                dy -= dy % GridSnap;
270
271                if(resizeX || resizeY)
272                {
273                   w = wBefore;
274                   h = hBefore;
275                   if(resizeX < 0)
276                   {
277                      x += dx;
278                      w -= dx;
279                   }
280                   else if(resizeX > 0)
281                   {
282                      w += dx;            
283                   }
284             
285                   if(resizeY < 0)
286                   {
287                      y += dy;
288                      h -= dy;
289                   }
290                   else if(resizeY > 0)
291                   {
292                      h += dy;
293                   }
294                   if(resizeX) 
295                   {
296                      w = Max(w, GridSnap);
297                      moved.size.w = w;
298                   }
299                   if(resizeY) 
300                   {
301                      h = Max(h, GridSnap);
302                      moved.size.h = h;
303                   }
304                   if(resizeX < 0) x -= x % GridSnap;
305                   if(resizeY < 0) y -= y % GridSnap;
306                }
307                else
308                {
309                   x += dx;
310                   y += dy;
311                   if(parent != curParent)
312                   {
313                      Window master = moved.master;
314
315                      x += curParent.absPosition.x - parent.absPosition.x + curParent.clientStart.x - parent.clientStart.x;
316                      y += curParent.absPosition.y - parent.absPosition.y + curParent.clientStart.y - parent.clientStart.y;
317
318                      moved.parent = parent;
319                      if(parent == form)
320                      {  
321                         ObjectInfo previous = moved.object;
322                         while((previous = previous.prev) && ((Window)previous.instance).parent != form);
323                         if(previous)
324                            moved.parent.children.Move(moved, (Window)previous.instance);
325                      }
326                      if(master == form)
327                         moved.master = master;
328                   }
329                   x -= x % GridSnap;
330                   y -= y % GridSnap;
331                }
332                
333                activeDesigner.ModifyCode();
334
335                moved.Move(x, y, w, h);
336
337                if(resizeX < 0 || resizeY < 0)
338                {
339                   if(resizeX < 0)
340                   {
341                      w = moved.size.w;
342                      x = Min(x, xBefore + wBefore - w);
343                   }
344                   if(resizeY < 0)
345                   {
346                      h = moved.size.h;
347                      y = Min(y, yBefore + hBefore - h);
348                   }
349                   moved.Move(x, y, w, h);
350                }
351
352                {
353                   int vpw, vph;
354                   
355                   // Fix Anchor
356                   x = moved.position.x;
357                   y = moved.position.y;
358                   w = moved.size.w;
359                   h = moved.size.h;
360
361                   vpw = parent.clientSize.w;
362                   vph = parent.clientSize.h;
363                   if(moved.nonClient)
364                   {
365                      vpw = parent.size.w;
366                      vph = parent.size.h;
367                   }
368                   else if(moved.style.fixed) // TOFIX: moved.borderStyle.fixed
369                   {
370                      if(!moved.dontScrollHorz && parent.scrollArea.w) vpw = parent.scrollArea.w;
371                      if(!moved.dontScrollVert && parent.scrollArea.h) vph = parent.scrollArea.h;
372                   }
373
374                   if(anchor.left.type == offset) anchor.left.distance = x;
375                   else if(anchor.left.type == relative) anchor.left.percent = (float)x / vpw;
376                   if(anchor.top.type == offset) anchor.top.distance = y;
377                   else if(anchor.top.type == relative) anchor.top.percent = (float)y / vph;
378                   if(anchor.right.type == offset) anchor.right.distance = vpw - (x + w);
379                   //else if(anchor.right.type == relative) anchor.right.percent = (float) (x + w) / vpw;
380                   else if(anchor.right.type == relative) anchor.right.percent = (float) (vpw - (x + w)) / vpw;
381                   if(anchor.bottom.type == offset) anchor.bottom.distance = vph - (y + h);
382                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (y + h) / vph;
383                   else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (vph - (y + h)) / vph;
384
385                   if(!anchor.left.type && !anchor.right.type)
386                   {
387                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
388                      //anchor.horz.type = anchor.horz.distance ? offset : 0;
389                   }
390                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
391                   if(!anchor.top.type && !anchor.bottom.type) 
392                   {
393                      anchor.vert.distance = (y + h / 2) - (vph / 2);
394                      //anchor.vert.type = anchor.vert.distance ? offset : 0;
395                   }
396                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
397
398                   moved.anchor = anchor;
399                }
400
401                x = moved.position.x;
402                y = moved.position.y;
403                w = moved.size.w;
404                h = moved.size.h;
405
406                box.left = Min(box.left, moved.absPosition.x - absPosition.x - clientStart.x);
407                box.top  = Min(box.top, moved.absPosition.y - absPosition.y - clientStart.y);
408                box.right = Max(box.right, moved.absPosition.x - absPosition.x - clientStart.x + moved.size.w - 1);
409                box.bottom= Max(box.bottom, moved.absPosition.y - absPosition.y - clientStart.y + moved.size.h - 1);
410
411                box.left -= 7;
412                box.top -= 7;
413                box.right += 7;
414                box.bottom += 7;
415          
416                Update(box);
417                //activeDesigner.Update(box);
418
419                activeDesigner.UpdateProperties();
420             }
421          }
422       }
423       /*else
424          ReleaseCapture();*/
425       return true;
426    }
427
428    bool OnMouseOver(int x, int y, Modifiers mods)
429    {
430       x += absPosition.x - activeDesigner.absPosition.x + clientStart.x - activeDesigner.clientStart.x;
431       y += absPosition.y - activeDesigner.absPosition.y + clientStart.y - activeDesigner.clientStart.y;
432
433       if(x >= 0 && y >=0 && x < activeDesigner.clientSize.w && y < activeDesigner.clientSize.h)
434       {
435          if(activeDesigner.isDragging && !mods.isSideEffect)
436             activeDesigner.Activate();
437
438          // Capture();
439       }
440       return true;
441    }
442
443    bool OnMouseLeave(Modifiers mods)
444    {
445       // activeDesigner.classDesigner.ReleaseCapture();
446       return true;
447    }
448
449    bool OnLeftButtonDown(int x, int y, Modifiers mods)
450    {
451       char * objectClass = activeDesigner.objectClass;
452
453       if(!objectClass && selected)
454       {
455          Window control = FindWindow(form, master, null, x, y, false, null, null);
456          bool onBorder = false;
457          Window parent = selected.parent;
458          //if(control && (parent == control || parent == control.parent))
459          {
460             int cx = selected.absPosition.x - absPosition.x - clientStart.x;
461             int cy = selected.absPosition.y - absPosition.y - clientStart.y;
462             int cw = selected.size.w;
463             int ch = selected.size.h;
464
465             onBorder = true;
466
467             // Top Row
468             if(x >= cx - 7 && x < cx + cw + 6 && y >= cy - 7 && y < cy)
469             {
470                // Top Left
471                if(x >= cx - 7 && x < cx)
472                {
473                   resizeX = -1;
474                   resizeY = -1;
475                }
476                // Top Center
477                else if(x >= cx + cw/2 - 3 && x < cx + cw/2 + 3)
478                {
479                   resizeX = 0;
480                   resizeY = -1;
481                }
482                // Top Right
483                else if(x >= cx + cw && x < cx + cw + 6)
484                {
485                   resizeX = 1;
486                   resizeY = -1;
487                }
488             }
489             // Bottom row
490             else if(x >= cx - 7 && x < cx + cw + 6 && y >= cy + ch && y < cy + ch + 6)
491             {
492                // Bottom Left
493                if(x >= cx - 7 && x < cx && y >= cy + ch && y < cy + ch + 6)
494                {
495                   resizeX = -1;
496                   resizeY = 1;
497                }
498                // Bottom Center
499                else if(x >= cx + cw/2 - 3 && x < cx + cw/2 + 3 && y >= cy + ch && y < cy + ch + 6)
500                {
501                   resizeX = 0;
502                   resizeY = 1;
503                }
504                // Bottom Right
505                else if(x >= cx + cw && x < cx + cw + 6 && y >= cy + ch && y < cy + ch + 6)
506                {
507                   resizeX = 1;
508                   resizeY = 1;
509                }
510             }
511             // Left Border
512             else if(x >= cx - 7 && x < cx && y >= cy - 7 && y < cy + ch + 6)
513             {
514                // Middle Left
515                if(y >= cy + ch/2 - 3 && y < cy + ch/2 + 3)
516                {
517                   resizeX = -1;
518                   resizeY = 0;
519                }
520             }
521             // Right border
522             else if(x >= cx + cw && x < cx + cw + 6 && y >= cy - 7 && y < cy + ch + 6)
523             {
524                // Middle Right
525                if(y >= cy + ch / 2 - 3 && y < cy + ch/2 + 3)
526                {
527                   resizeX = 1;
528                   resizeY = 0;
529                }
530             }
531             else
532                onBorder = false;
533          }
534          if(onBorder)
535          {
536             control = selected;
537          }
538
539          if(control)
540          {
541             Window parent = control.parent;
542
543             if(parent.nonClient)
544                ((control == form) ? (Window)this : form).SetMouseRangeToWindow();
545             else
546                ((control == form) ? (Window)this : form).SetMouseRangeToClient();
547             
548             xClicked = x;
549             yClicked = y;
550
551             if(selected != control)
552                activeDesigner.SelectObjectFromDesigner(control.object);
553
554             Update(null);
555             //activeDesigner.Update(null);
556
557             moved = control;
558             xBefore = control.position.x;
559             yBefore = control.position.y;
560             parentBefore = control.parent;
561             this.onBorder = onBorder;
562             wBefore = control.size.w;
563             hBefore = control.size.h;
564          }
565       }
566       return true;
567    }
568
569    bool OnLeftButtonUp(int x, int y, Modifiers mods)
570    {
571       if(moved)
572       {
573          moved = null;
574          resizeX = resizeY = 0;
575          FreeMouseRange();
576       }
577       else
578       {
579          char * objectClass = activeDesigner.objectClass;
580          if(objectClass)
581          {
582             Window parent = FindWindow(form, activeDesigner, null, x, y, true, &x, &y);
583             if(parent)
584             {
585                ObjectInfo object;
586                Window control = (Window)eInstance_New(eSystem_FindClass(form._class.module, objectClass));
587
588                activeDesigner.CodeAddObject(control, &object);
589
590                while(!parent.name) 
591                {
592                   x += parent.position.x + parent.clientStart.x;
593                   y += parent.position.y + parent.clientStart.y;
594                   parent = parent.parent;
595                }
596
597                control.object = object;
598
599                control.parent = parent;
600                control.master = form;
601
602                x -= x % GridSnap;
603                y -= y % GridSnap;
604
605                control.position.x = x;
606                control.position.y = y;
607                control.text = object.name;
608
609                LockControls(control, control);
610
611                control.Create();
612                if(parent == form)
613                {  
614                   ObjectInfo previous = control.object;
615                   while((previous = previous.prev) && ((Window)previous.instance).parent != form);
616                   if(previous)
617                      control.parent.children.Move(control, (Window)previous.instance);
618                }
619
620                activeDesigner.SheetAddObject(object);
621
622                //selected = control;
623                //activeDesigner.Update(null);
624                Update(null);
625             }
626          }
627       }
628       return true;
629    }
630
631    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
632    {
633       Window control = FindWindow(form, activeDesigner, null, x, y, false, &x, &y);
634       if(control && selected == control)
635       {
636          activeDesigner.AddDefaultMethod(control, form);
637          return false; // Prevent OnLeftButtonDown to be sent to the activated code editor
638       }
639       return true;
640    }
641
642    void ::LockControls(Window window, Window control)
643    {
644       Window child;
645
646       if(window == control)
647       {
648          ObjectInfo object = window.object;
649          window.OnDestroy = ecere::gui::OnDestroy;
650          window.OnSysKeyDown = ecere::gui::OnSysKey;
651          window.OnSysKeyHit = ecere::gui::OnSysKey;
652          window.OnSysKeyUp = ecere::gui::OnSysKey;
653             
654          if(object != object.oClass)
655          {
656             window.OnActivate = Control_OnActivate;
657             window.OnClose = null;
658          }
659       }
660
661       window.control = control;
662       for(child = window.firstChild; child; child = child.next)
663       {
664          LockControls(child, control);
665       }
666    }
667
668    void DrawSelection(Window window, Surface surface)
669    {
670       Window result = null, control;
671       for(control = window.lastChild; control; control = control.prev)
672       {
673          if(selected == control)
674          {
675             Window parent = selected.parent;
676             int x;
677             int y;
678             int w = selected.size.w;
679             int h = selected.size.h;
680
681             x = selected.absPosition.x - absPosition.x - clientStart.x;
682             y = selected.absPosition.y - absPosition.y - clientStart.y;
683
684             surface.SetBackground(Color {170, 170, 170});
685             surface.Area(x - 7, y - 7, x + w - 1 + 7, y-1);
686             surface.Area(x - 7, y + h, x + w - 1 + 7, y + h - 1 + 7);
687             surface.Area(x - 7, y - 7, x - 1, y + h - 1 + 7);
688             surface.Area(x + w, y - 7 , x + w - 1 + 7, y + h - 1 + 7);
689
690             surface.SetBackground(white);
691
692             surface.Area(x - 6, y - 6, x-1, y-1);
693             surface.Area(x + w/2 - 2, y - 6, x + w/2 + 2, y - 1);
694             surface.Area(x + w + 1, y - 6, x + w-1 + 6, y-1);
695
696             surface.Area(x - 6, y + h + 1, x-1, y + h - 1 + 6);
697             surface.Area(x + w/2 - 2, y + h + 1, x + w/2 + 2, y + h - 1 + 6);
698             surface.Area(x + w + 1, y + h + 1, x + w-1 + 6, y + h - 1 + 6);
699
700             surface.Area(x - 6, y + h/2 - 2, x-1, y + h /2 + 2);
701             surface.Area(x + w, y + h/2 - 2, x + w-1 + 6, y + h /2 + 2);
702
703             surface.SetForeground(black);
704
705             surface.Rectangle(x - 7, y - 7, x-1, y-1);
706             surface.Rectangle(x + w/2 - 3, y - 7, x + w/2 + 3, y - 1);
707             surface.Rectangle(x + w, y - 7, x + w-1 + 7, y-1);
708
709             surface.Rectangle(x - 7, y + h, x-1, y + h - 1 + 7);
710             surface.Rectangle(x + w/2 - 3, y + h, x + w/2 + 3, y + h - 1 + 7);
711             surface.Rectangle(x + w, y + h, x + w-1 + 7, y + h - 1 + 7);
712
713             surface.Rectangle(x - 7, y + h/2 - 3, x-1, y + h /2 + 3);
714             surface.Rectangle(x + w, y + h/2 - 3, x + w-1 + 7, y + h /2 + 3);
715          }
716          DrawSelection(control, surface);
717       }
718    }
719 }
720
721 static bool Control_OnActivate(Window window, bool active, Window previous, bool * goOn, bool direct)
722 {
723    if(active)
724    {
725       *goOn = true;
726       return false;
727    }
728    return true;
729 }
730
731 static Window GetWindow(Window window, int x, int y, int * rx, int * ry)
732 {
733    Window result = null, control;
734    for(control = window.lastChild; control; control = control.prev)
735    {
736       int cx = control.position.x;
737       int cy = control.position.y;
738       int cw = control.size.w;
739       int ch = control.size.h;
740
741       if(x >= cx && x < cx + cw && y >= cy && y < cy + ch)
742       {
743          x -= control.position.x + control.clientStart.x;
744          y -= control.position.y + control.clientStart.y;
745          result = GetWindow(control, x, y, rx, ry);
746          if(!result)
747          {
748             *rx = x;
749             *ry = y;
750             result = control;
751          }
752          break;
753       }
754    }
755    return result;
756 }
757
758 static Window FindWindow(Window form, Window window, Window moved, int x, int y, bool asParent, int * dx, int * dy)
759 {
760    Window result = null, control;
761    for(control = window.lastChild; control; control = control.prev)
762    {
763       if(control != moved && control.control == control && (!asParent || control.name))
764       {
765          if(!form || control == form)
766          {
767             int cx = control.position.x - (asParent ? 0 : 7);
768             int cy = control.position.y - (asParent ? 0 : 7);
769             int cw = control.size.w + (asParent ? 0 : 14);
770             int ch = control.size.h + (asParent ? 0 : 14);
771
772             int sx = x - (control.position.x + control.clientStart.x);
773             int sy = y - (control.position.y + control.clientStart.y);
774             if((sx >= 0 && sy >= 0 && sx < control.clientSize.w && sy < control.clientSize.h) ||
775                !(x >= cx && x < cx + cw && y >= cy && y < cy + ch))
776                result = FindWindow(null, control, moved, sx, sy, asParent, dx, dy);
777             if(result)
778                break;
779             else if(x >= cx && x < cx + cw && y >= cy && y < cy + ch)
780             {
781                if(dx) *dx = sx;
782                if(dy) *dy = sy;
783                result = control;
784                break;
785             }
786          }
787       }
788    }
789    return result;
790 }
791
792 static void OnDestroy(Window window)
793 {
794    FormDesigner designer = activeDesigner ? (FormDesigner)activeDesigner.classDesigner : null;
795
796    if(designer && designer.form)
797       activeDesigner.DeleteObject(window.object);
798 }
799
800 static bool OnSysKey(Window window, Key key, unichar ch)
801 {
802    return false;
803 }
804
805 static void DrawGrid(Window window, Surface surface)
806 {
807    int x, y;
808    int w = window.clientSize.w;
809    int h = window.clientSize.h;
810    Color background = window.background;
811    if(!surface) return;
812
813    if(background.r > 128 || background.g > 128)
814       surface.SetForeground(black);
815    else
816       surface.SetForeground(white);
817
818    for(y = GridSnap; y < h; y += GridSnap)
819       for(x = GridSnap; x < w; x += GridSnap)
820          surface.PutPixel(x, y);
821 }
822
823 static bool OnKeyDown(Window window, Key key, unichar ch)
824 {
825    FormDesigner designer = (FormDesigner)activeDesigner.classDesigner;
826    if(key == del)
827    {
828       if(designer.selected && designer.selected != designer.form)
829       {
830          bool confirmation = activeDesigner.ObjectContainsCode(designer.selected.object);
831
832          if(confirmation)
833             confirmation = MessageBox { type = okCancel, master = window.master, text = "Deleting control with code", contents = "Control contains code. Delete anyways?" }.Modal() != ok;
834
835          // Confirmation if control contains other controls
836          if(!confirmation)
837          {
838             Window child = designer.selected.firstChild;
839             for( ; child; child = child.next)
840             {
841                if(child.control == child)
842                {
843                   confirmation = true;
844                   break;
845                }
846             }
847
848             if(confirmation)
849                confirmation = MessageBox { type = okCancel, master = window.master, text = "Deleting control with children", contents = "Control contains other controls. Delete control and children?"}.Modal() != ok;
850          }
851
852          if(!confirmation)
853          {
854             activeDesigner.ModifyCode();
855          
856             designer.selected.Destroy(0);
857             //activeDesigner.Update(null);
858             designer.Update(null);
859          }
860       }
861    }
862    return false;
863 }