cleaned all trailing white space from source files.
[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.caption = 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 = 632, h = 438;
180       if(clientSize.w - 40 -200 < w)
181       {
182          w = (clientSize.w - 40 - 200);
183          w -= w % GridSnap;
184          h = h * w / 632;
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("   caption = \"%s\";\n", name);
196       //editBox.Printf("   background = Color { 212, 208, 200 };\n");
197
198       editBox.Printf("   background = formColor;\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("   clientSize = { %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("   caption = \"%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, caption = \"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;
587                Class c = eSystem_FindClass(form._class.module, objectClass);
588                if(!c)
589                   c = eSystem_FindClass(form._class.module.application, objectClass);
590                if(c)
591                {
592                   control = (Window)eInstance_New(c);
593
594                   activeDesigner.CodeAddObject(control, &object);
595
596                   while(!parent.name)
597                   {
598                      x += parent.position.x + parent.clientStart.x;
599                      y += parent.position.y + parent.clientStart.y;
600                      parent = parent.parent;
601                   }
602
603                   control.object = object;
604
605                   control.parent = parent;
606                   control.master = form;
607
608                   x -= x % GridSnap;
609                   y -= y % GridSnap;
610
611                   control.position.x = x;
612                   control.position.y = y;
613                   control.caption = object.name;
614
615                   LockControls(control, control);
616
617                   control.Create();
618                   if(parent == form)
619                   {
620                      ObjectInfo previous = control.object;
621                      while((previous = previous.prev) && ((Window)previous.instance).parent != form);
622                      if(previous)
623                         control.parent.children.Move(control, (Window)previous.instance);
624                   }
625
626                   activeDesigner.SheetAddObject(object);
627
628                   //selected = control;
629                   //activeDesigner.Update(null);
630                   Update(null);
631                }
632             }
633          }
634       }
635       return true;
636    }
637
638    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
639    {
640       Window control = FindWindow(form, activeDesigner, null, x, y, false, &x, &y);
641       if(control && selected == control)
642       {
643          activeDesigner.AddDefaultMethod(control, form);
644          return false; // Prevent OnLeftButtonDown to be sent to the activated code editor
645       }
646       return true;
647    }
648
649    void ::LockControls(Window window, Window control)
650    {
651       Window child;
652
653       if(window == control)
654       {
655          ObjectInfo object = window.object;
656          window.OnDestroy = ecere::gui::OnDestroy;
657          window.OnSysKeyDown = ecere::gui::OnSysKey;
658          window.OnSysKeyHit = ecere::gui::OnSysKey;
659          window.OnSysKeyUp = ecere::gui::OnSysKey;
660
661          if(object != object.oClass)
662          {
663             window.OnActivate = Control_OnActivate;
664             window.OnClose = null;
665          }
666       }
667
668       window.control = control;
669       for(child = window.firstChild; child; child = child.next)
670       {
671          LockControls(child, control);
672       }
673    }
674
675    void DrawSelection(Window window, Surface surface)
676    {
677       Window result = null, control;
678       for(control = window.lastChild; control; control = control.prev)
679       {
680          if(selected == control)
681          {
682             Window parent = selected.parent;
683             int x;
684             int y;
685             int w = selected.size.w;
686             int h = selected.size.h;
687
688             x = selected.absPosition.x - absPosition.x - clientStart.x;
689             y = selected.absPosition.y - absPosition.y - clientStart.y;
690
691             surface.SetBackground(Color {170, 170, 170});
692             surface.Area(x - 7, y - 7, x + w - 1 + 7, y-1);
693             surface.Area(x - 7, y + h, x + w - 1 + 7, y + h - 1 + 7);
694             surface.Area(x - 7, y - 7, x - 1, y + h - 1 + 7);
695             surface.Area(x + w, y - 7 , x + w - 1 + 7, y + h - 1 + 7);
696
697             surface.SetBackground(white);
698
699             surface.Area(x - 6, y - 6, x-1, y-1);
700             surface.Area(x + w/2 - 2, y - 6, x + w/2 + 2, y - 1);
701             surface.Area(x + w + 1, y - 6, x + w-1 + 6, y-1);
702
703             surface.Area(x - 6, y + h + 1, x-1, y + h - 1 + 6);
704             surface.Area(x + w/2 - 2, y + h + 1, x + w/2 + 2, y + h - 1 + 6);
705             surface.Area(x + w + 1, y + h + 1, x + w-1 + 6, y + h - 1 + 6);
706
707             surface.Area(x - 6, y + h/2 - 2, x-1, y + h /2 + 2);
708             surface.Area(x + w, y + h/2 - 2, x + w-1 + 6, y + h /2 + 2);
709
710             surface.SetForeground(black);
711
712             surface.Rectangle(x - 7, y - 7, x-1, y-1);
713             surface.Rectangle(x + w/2 - 3, y - 7, x + w/2 + 3, y - 1);
714             surface.Rectangle(x + w, y - 7, x + w-1 + 7, y-1);
715
716             surface.Rectangle(x - 7, y + h, x-1, y + h - 1 + 7);
717             surface.Rectangle(x + w/2 - 3, y + h, x + w/2 + 3, y + h - 1 + 7);
718             surface.Rectangle(x + w, y + h, x + w-1 + 7, y + h - 1 + 7);
719
720             surface.Rectangle(x - 7, y + h/2 - 3, x-1, y + h /2 + 3);
721             surface.Rectangle(x + w, y + h/2 - 3, x + w-1 + 7, y + h /2 + 3);
722          }
723          DrawSelection(control, surface);
724       }
725    }
726 }
727
728 static bool Control_OnActivate(Window window, bool active, Window previous, bool * goOn, bool direct)
729 {
730    if(active)
731    {
732       *goOn = true;
733       return false;
734    }
735    return true;
736 }
737
738 static Window GetWindow(Window window, int x, int y, int * rx, int * ry)
739 {
740    Window result = null, control;
741    for(control = window.lastChild; control; control = control.prev)
742    {
743       int cx = control.position.x;
744       int cy = control.position.y;
745       int cw = control.size.w;
746       int ch = control.size.h;
747
748       if(x >= cx && x < cx + cw && y >= cy && y < cy + ch)
749       {
750          x -= control.position.x + control.clientStart.x;
751          y -= control.position.y + control.clientStart.y;
752          result = GetWindow(control, x, y, rx, ry);
753          if(!result)
754          {
755             *rx = x;
756             *ry = y;
757             result = control;
758          }
759          break;
760       }
761    }
762    return result;
763 }
764
765 static Window FindWindow(Window form, Window window, Window moved, int x, int y, bool asParent, int * dx, int * dy)
766 {
767    Window result = null, control;
768    for(control = window.lastChild; control; control = control.prev)
769    {
770       if(control != moved && control.control == control && (!asParent || control.name))
771       {
772          if(!form || control == form)
773          {
774             int cx = control.position.x - (asParent ? 0 : 7);
775             int cy = control.position.y - (asParent ? 0 : 7);
776             int cw = control.size.w + (asParent ? 0 : 14);
777             int ch = control.size.h + (asParent ? 0 : 14);
778
779             int sx = x - (control.position.x + control.clientStart.x);
780             int sy = y - (control.position.y + control.clientStart.y);
781             if((sx >= 0 && sy >= 0 && sx < control.clientSize.w && sy < control.clientSize.h) ||
782                !(x >= cx && x < cx + cw && y >= cy && y < cy + ch))
783                result = FindWindow(null, control, moved, sx, sy, asParent, dx, dy);
784             if(result)
785                break;
786             else if(x >= cx && x < cx + cw && y >= cy && y < cy + ch)
787             {
788                if(dx) *dx = sx;
789                if(dy) *dy = sy;
790                result = control;
791                break;
792             }
793          }
794       }
795    }
796    return result;
797 }
798
799 static void OnDestroy(Window window)
800 {
801    FormDesigner designer = activeDesigner ? (FormDesigner)activeDesigner.classDesigner : null;
802
803    if(designer && designer.form)
804       activeDesigner.DeleteObject(window.object);
805 }
806
807 static bool OnSysKey(Window window, Key key, unichar ch)
808 {
809    return false;
810 }
811
812 static void DrawGrid(Window window, Surface surface)
813 {
814    int x, y;
815    int w = window.clientSize.w;
816    int h = window.clientSize.h;
817    Color background = window.background;
818    if(!surface) return;
819
820    if(background.r > 128 || background.g > 128)
821       surface.SetForeground(black);
822    else
823       surface.SetForeground(white);
824
825    for(y = GridSnap; y < h; y += GridSnap)
826       for(x = GridSnap; x < w; x += GridSnap)
827          surface.PutPixel(x, y);
828 }
829
830 static bool OnKeyDown(Window window, Key key, unichar ch)
831 {
832    FormDesigner designer = (FormDesigner)activeDesigner.classDesigner;
833    if(key == del)
834    {
835       if(designer.selected && designer.selected != designer.form)
836       {
837          bool confirmation = activeDesigner.ObjectContainsCode(designer.selected.object);
838
839          if(confirmation)
840             confirmation = MessageBox { type = okCancel, master = window.master, caption = $"Deleting control with code", contents = $"Control contains code. Delete anyways?" }.Modal() != ok;
841
842          // Confirmation if control contains other controls
843          if(!confirmation)
844          {
845             Window child = designer.selected.firstChild;
846             for( ; child; child = child.next)
847             {
848                if(child.control == child)
849                {
850                   confirmation = true;
851                   break;
852                }
853             }
854
855             if(confirmation)
856                confirmation = MessageBox { type = okCancel, master = window.master, caption = $"Deleting control with children", contents = $"Control contains other controls. Delete control and children?"}.Modal() != ok;
857          }
858
859          if(!confirmation)
860          {
861             activeDesigner.ModifyCode();
862
863             designer.selected.Destroy(0);
864             //activeDesigner.Update(null);
865             designer.Update(null);
866          }
867       }
868    }
869    return false;
870 }