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