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