399fdaf0ab8c81f81bb59af329096062bb70d08c
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / MdiChildContext.cs
1
2 using System;
3 using System.Drawing;
4 using System.Drawing.Drawing2D;
5
6 namespace System.Windows.Forms {
7
8         internal class MdiChildContext {
9
10                 private static readonly int MdiBorderStyle = 0xFFFF;
11                 private static Color titlebar_color;
12
13                 private int BorderWidth = 3;
14 //              private int TitleBarHeight = 26;
15 //              private int ToolTitleBarHeight = 19;
16                 private Size MinTitleBarSize = new Size (115, 25);
17
18                 private Form form;
19                 private MdiClient mdi_container;
20                 private Button close_button;
21                 private Button maximize_button;
22                 private Button minimize_button;
23
24                 // moving windows
25                 private Point start;
26                 private State state;
27                 private FormPos sizing_edge;
28                 private Rectangle virtual_position;
29                 private Rectangle prev_virtual_position;
30                 private Rectangle prev_bounds;
31                 private bool maximized;
32
33                 private enum State {
34                         Idle,
35                         Moving,
36                         Sizing,
37                 }
38
39                 [Flags]
40                 private enum FormPos {
41                         None,
42
43                         TitleBar = 1,
44
45                         Top = 2,
46                         Left = 4,
47                         Right = 8,
48                         Bottom = 16,
49
50                         TopLeft = Top | Left,
51                         TopRight = Top | Right,
52
53                         BottomLeft = Bottom | Left,
54                         BottomRight = Bottom | Right,
55
56                         AnyEdge = Top | Left | Right | Bottom,
57                 }
58
59                 public MdiChildContext (Form form, MdiClient mdi_container)
60                 {
61                         titlebar_color = Color.FromArgb (255, 0, 0, 255);
62                         this.form = form;
63                         this.mdi_container = mdi_container;
64
65                         if (form.FormBorderStyle != FormBorderStyle.None)
66                                 form.InternalBorderStyle = (BorderStyle) MdiBorderStyle;
67                         else
68                                 form.InternalBorderStyle = BorderStyle.None;
69
70                         /*
71                         minimize_button = new Button ();
72                         minimize_button.Bounds = new Rectangle (form.Width - 62,
73                                         -26, 18, 22);
74                         minimize_button.Anchor = AnchorStyles.Top | AnchorStyles.Right;
75                         minimize_button.Paint += new PaintEventHandler (PaintButtonHandler);
76                         minimize_button.Click += new EventHandler (OnMinimizeHandler);
77                         
78                         maximize_button = new Button ();
79                         maximize_button.Bounds = new Rectangle (form.Width - 44,
80                                         BorderWidth + 2, 18, 22);
81                         maximize_button.Anchor = AnchorStyles.Top | AnchorStyles.Right;
82                         maximize_button.Paint += new PaintEventHandler (PaintButtonHandler);
83                         maximize_button.Click += new EventHandler (OnMaximizeHandler);
84                         
85                         close_button = new Button ();
86                         close_button.Bounds = new Rectangle (form.Width - 24,
87                                         BorderWidth + 2, 18, 22);
88                         close_button.Anchor = AnchorStyles.Top | AnchorStyles.Right;
89                         close_button.Paint += new PaintEventHandler (PaintButtonHandler);
90                         close_button.Click += new EventHandler (CloseButtonClicked);
91
92
93                         form.Controls.AddImplicit (close_button);
94                         form.Controls.AddImplicit (maximize_button);
95                         form.Controls.AddImplicit (minimize_button);
96                         */
97                 }
98
99                 public bool HandleMessage (ref Message m)
100                 {
101                         switch ((Msg)m.Msg) {
102
103
104                                 // The mouse handling messages are actually
105                                 // not WM_NC* messages except for the first button and NCMOVEs
106                                 // down because we capture on the form
107
108                         case Msg.WM_MOUSEMOVE:
109                                 return HandleMouseMove (form, ref m);
110
111                         case Msg.WM_LBUTTONUP:
112                                 HandleLButtonUp (ref m);
113                                 break;
114
115                         case Msg.WM_RBUTTONDOWN:
116                         case Msg.WM_LBUTTONDOWN:
117                                 return HandleButtonDown (ref m);
118
119                         case Msg.WM_NCMOUSEMOVE:
120                                 return HandleNCMouseMove (form, ref m);
121
122                         case Msg.WM_NCLBUTTONDOWN:
123                                 return HandleNCLButtonDown (ref m);
124
125                         case Msg.WM_NCPAINT:
126 //                              form.UpdateStyles ();
127                                 PaintWindowDecorations ();
128                                 // Graphics g = XplatUI.GetMenuDC (form.Handle, IntPtr.Zero);
129                                 // g.Clear (Color.Red);
130                                 break;
131                         }
132                         return false;
133                 }
134
135                 public void UpdateBorderStyle (FormBorderStyle border_style)
136                 {
137                         if (border_style != FormBorderStyle.None)
138                                 XplatUI.SetBorderStyle (form.Handle, (FormBorderStyle) MdiBorderStyle);
139                         else
140                                 XplatUI.SetBorderStyle (form.Handle, FormBorderStyle.None);
141                 }
142
143                 private bool HandleButtonDown (ref Message m)
144                 {
145                         form.BringToFront ();
146                         mdi_container.ActiveMdiChild = form;
147                         return false;
148                 }
149
150                 private bool HandleNCLButtonDown (ref Message m)
151                 {
152                         form.BringToFront ();
153                         mdi_container.ActiveMdiChild = form;
154
155                         int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
156                         int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
157
158                         form.PointToClient (ref x, ref y);
159
160                         // Need to adjust because we are in NC land
161                         y += TitleBarHeight;
162                         FormPos pos = FormPosForCoords (x, y);
163
164                         start = new Point (x, y);
165                         virtual_position = form.Bounds;
166
167                         if (pos == FormPos.TitleBar) {
168                                 HandleTitleBarDown (x, y);
169                                 return true;
170                         }
171
172                         /*
173                         if (IsSizable) {
174                                 SetCursorForPos (pos);
175                         
176                                 if ((pos & FormPos.AnyEdge) == 0)
177                                         return false;
178
179                                 state = State.Sizing;
180                                 sizing_edge = pos;
181                                 form.Capture = true;
182                                 return true;
183                         }
184                         */
185
186                         return false;
187                 }
188
189                 private void HandleTitleBarDown (int x, int y)
190                 {
191                         state = State.Moving;                        
192                         form.Capture = true;
193                 }
194
195                 private bool HandleMouseMove (Form form, ref Message m)
196                 {
197                         switch (state) {
198                         case State.Moving:
199                                 HandleWindowMove (m);
200                                 return true;
201                         case State.Sizing:
202                                 HandleSizing (m);
203                                 return true;
204                         }
205
206                         /*
207                         if (IsSizable) {
208                                 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
209                                 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
210                                 FormPos pos = FormPosForCoords (x, y);
211                                 Console.WriteLine ("position:   " + pos);
212                                 SetCursorForPos (pos);
213
214                                 ClearVirtualPosition ();
215                                 state = State.Idle;
216                         }
217                         */
218                         
219                         return false;
220                 }
221
222                 private bool HandleNCMouseMove (Form form, ref Message m)
223                 {
224                         if (IsSizable) {
225                                 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
226                                 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
227                                 FormPos pos = FormPosForCoords (x, y);
228                                 Console.WriteLine ("position:   " + pos);
229                                 SetCursorForPos (pos);
230
231                                 ClearVirtualPosition ();
232                                 state = State.Idle;
233                         }
234
235                         return false;
236                 }
237
238                 private void SetCursorForPos (FormPos pos)
239                 {
240                         switch (pos) {
241                         case FormPos.TopLeft:
242                         case FormPos.BottomRight:
243                                 form.Cursor = Cursors.SizeNWSE;
244                                 break;
245                         case FormPos.TopRight:
246                         case FormPos.BottomLeft:
247                                 form.Cursor = Cursors.SizeNESW;
248                                 break;
249                         case FormPos.Top:
250                         case FormPos.Bottom:
251                                 form.Cursor = Cursors.SizeNS;
252                                 break;
253                         case FormPos.Left:
254                         case FormPos.Right:
255                                 form.Cursor = Cursors.SizeWE;
256                                 break;
257                         default:
258                                 form.Cursor = Cursors.Default;
259                                 break;
260                         }
261                 }
262         
263                 private void HandleWindowMove (Message m)
264                 {
265                         Point move = MouseMove (m);
266
267                         virtual_position.X = form.Left + move.X;
268                         virtual_position.Y = form.Top + move.Y;
269                         virtual_position.Width = form.Width;
270                         virtual_position.Height = form.Height;
271
272                         mdi_container.EnsureScrollBars (virtual_position.Right, virtual_position.Bottom);
273
274                         DrawVirtualPosition ();
275                 }
276
277                 private void HandleSizing (Message m)
278                 {
279                         Point move = MouseMove (m);
280                         Rectangle pos = virtual_position;
281                         int mw = MinTitleBarSize.Width + (BorderWidth * 2);
282                         int mh = MinTitleBarSize.Height + (BorderWidth * 2);
283                         
284                         if ((sizing_edge & FormPos.Top) != 0) {
285                                 int height = form.Height - move.Y;
286                                 if (height <= mh) {
287                                         move.Y += height - mh;
288                                         height = mh;
289                                 }
290                                 pos.Y = form.Top + move.Y;
291                                 pos.Height = height;
292                         } else if ((sizing_edge & FormPos.Bottom) != 0) {
293                                 int height = form.Height + move.Y;
294                                 if (height <= mh)
295                                         move.Y -= height - mh;
296                                 pos.Height = form.Height + move.Y;
297                         }
298
299                         if ((sizing_edge & FormPos.Left) != 0) {
300                                 int width = form.Width - move.X;
301                                 if (width <= mw) {
302                                         move.X += width - mw;
303                                         width = mw;
304                                 }
305                                 pos.X = form.Left + move.X;
306                                 pos.Width = width;
307                         } else if ((sizing_edge & FormPos.Right) != 0) {
308                                 int width = form.Width + move.X;
309                                 if (width <= mw)
310                                         move.X -= width - mw;
311                                 pos.Width = form.Width + move.X;
312                         }
313
314                         UpdateVP (pos);
315                 }
316
317                 private bool IsSizable {
318                         get {
319                                 switch (form.FormBorderStyle) {
320                                 case FormBorderStyle.Sizable:
321                                 case FormBorderStyle.SizableToolWindow:
322                                         return true;
323                                 default:
324                                         return false;
325                                 }
326                         }
327                 }
328
329                 private bool HasBorders {
330                         get {
331                                 return form.FormBorderStyle != FormBorderStyle.None;
332                         }
333                 }
334
335                 private bool IsToolWindow {
336                         get {
337                                 if (form.FormBorderStyle == FormBorderStyle.SizableToolWindow ||
338                                                 form.FormBorderStyle == FormBorderStyle.FixedToolWindow)
339                                         return true;
340                                 return false;
341                         }
342                 }
343
344                 private int TitleBarHeight {
345                         get {
346                                 if (IsToolWindow)
347                                         return 19;
348                                 if (form.FormBorderStyle == FormBorderStyle.None)
349                                         return 0;
350                                 return 26;
351                         }
352                 }
353
354                 private void UpdateVP (Rectangle r)
355                 {
356                         UpdateVP (r.X, r.Y, r.Width, r.Height);
357                 }
358
359                 private void UpdateVP (Point loc, int w, int h)
360                 {
361                         UpdateVP (loc.X, loc.Y, w, h);
362                 }
363
364                 private void UpdateVP (int x, int y, int w, int h)
365                 {
366                         virtual_position.X = x;
367                         virtual_position.Y = y;
368                         virtual_position.Width = w;
369                         virtual_position.Height = h;
370
371                         DrawVirtualPosition ();
372                 }
373
374                 private void HandleLButtonUp (ref Message m)
375                 {
376                         if (state == State.Idle)
377                                 return;
378
379                         ClearVirtualPosition ();
380
381                         form.Capture = false;
382                         form.Bounds = virtual_position;
383                         state = State.Idle;
384                 }
385
386                 private void PaintWindowDecorations ()
387                 {
388                         Graphics dc = XplatUI.GetMenuDC (form.Handle, IntPtr.Zero);
389
390                         if (HasBorders) {
391                                 Rectangle borders = new Rectangle (0, 0, form.Width, form.Height);
392 //                      dc.FillRectangle (new SolidBrush (Color.Black), borders);
393                                 
394 /*                      
395                         dc.DrawRectangle (new Pen (SystemColors.ControlLight, 1), borders);
396                         borders.Inflate (-2, -2);
397                         dc.DrawRectangle (new Pen (SystemColors.ControlDark, 1), borders);
398                         borders.X++;
399                         borders.Width -= 2;
400                         dc.DrawRectangle (new Pen (SystemColors.ControlLight, 1), borders);
401 */
402                         
403                                 ControlPaint.DrawBorder3D (dc, borders, Border3DStyle.Raised);
404
405                                 if (IsSizable) {
406                                         borders.Inflate (-1, -1);
407                                         ControlPaint.DrawFocusRectangle (dc, borders);
408                                 }
409                         }
410
411                         Color color = ThemeEngine.Current.ColorControlDark;
412                         if (form == mdi_container.ActiveMdiChild && !maximized)
413                                 color = titlebar_color;
414
415                         Rectangle tb = new Rectangle (BorderWidth, BorderWidth,
416                                         form.Width - (BorderWidth * 2), TitleBarHeight - 1);
417
418                         dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (color), tb);
419
420                         dc.DrawLine (new Pen (Color.White, 1), BorderWidth,
421                                         TitleBarHeight + BorderWidth, form.Width - BorderWidth,
422                                         TitleBarHeight + BorderWidth);
423
424                         if (!IsToolWindow) {
425                                 tb.X += 18; // Room for the icon and the buttons
426                                 tb.Width = (form.Width - 62) - tb.X;
427                         }
428
429                         if (form.Text != null) {
430                                 StringFormat format = new StringFormat ();
431                                 format.FormatFlags = StringFormatFlags.NoWrap;
432                                 format.Trimming = StringTrimming.EllipsisCharacter;
433                                 format.LineAlignment = StringAlignment.Center;
434                                 dc.DrawString (form.Text, form.Font,
435                                                 ThemeEngine.Current.ResPool.GetSolidBrush (Color.White),
436                                                 tb, format);
437                         }
438
439                         if (!IsToolWindow) {
440                                 if (form.Icon != null) {
441                                         dc.DrawIcon (form.Icon, new Rectangle (BorderWidth + 3,
442                                                                      BorderWidth + 3, 16, 16));
443                                 }
444
445                                 Rectangle r = new Rectangle (form.Width - 62, BorderWidth + 2, 18, 22);
446                                 dc.FillRectangle (SystemBrushes.Control, r);
447                                 ControlPaint.DrawCaptionButton (dc, r, CaptionButton.Minimize, ButtonState.Normal);
448
449                                 r = new Rectangle (form.Width - 44,     BorderWidth + 2, 18, 22);
450                                 dc.FillRectangle (SystemBrushes.Control, r);
451                                 ControlPaint.DrawCaptionButton (dc, r, CaptionButton.Maximize, ButtonState.Normal);
452
453                                 r = new Rectangle (form.Width - 24,     BorderWidth + 2, 18, 22);
454                                 dc.FillRectangle (SystemBrushes.Control, r);
455                                 ControlPaint.DrawCaptionButton (dc, r, CaptionButton.Close, ButtonState.Normal);
456                         } else {
457                                 Rectangle r = new Rectangle (form.Width - BorderWidth - 2 - 13,
458                                                 BorderWidth + 2, 13, 13);
459                                 dc.FillRectangle (SystemBrushes.Control, r);
460                                 ControlPaint.DrawCaptionButton (dc, r, CaptionButton.Close, ButtonState.Normal);
461                                 
462                         }
463                 }
464
465                 private void PaintButtonHandler (object sender, PaintEventArgs pe)
466                 {
467                         if (sender == close_button) {
468                                 ControlPaint.DrawCaptionButton (pe.Graphics,
469                                                 close_button.ClientRectangle,
470                                                 CaptionButton.Close,
471                                                 close_button.ButtonState);
472                         } else if (sender == maximize_button) {
473                                 ControlPaint.DrawCaptionButton (pe.Graphics,
474                                                 maximize_button.ClientRectangle,
475                                                 CaptionButton.Maximize,
476                                                 maximize_button.ButtonState);
477                         } else if (sender == minimize_button) {
478                                 ControlPaint.DrawCaptionButton (pe.Graphics,
479                                                 minimize_button.ClientRectangle,
480                                                 CaptionButton.Minimize,
481                                                 minimize_button.ButtonState);
482                         }
483                 }
484
485                 private void CloseButtonClicked (object sender, EventArgs e)
486                 {
487                         form.Close ();
488                         // form.Close should set visibility to false somewhere
489                         // in it's closing chain but currently does not.
490                         form.Visible = false;
491                 }
492
493                 private void OnMinimizeHandler (object sender, EventArgs e)
494                 {
495                         form.SuspendLayout ();
496                         form.Width = MinTitleBarSize.Width + (BorderWidth * 2);
497                         form.Height = MinTitleBarSize.Height + (BorderWidth * 2);
498                         form.ResumeLayout ();
499                 }
500
501                 private void OnMaximizeHandler (object sender, EventArgs e)
502                 {
503                         if (maximized) {
504                                 form.Bounds = prev_bounds;
505                                 maximized = false;
506                         } else {
507                                 prev_bounds = form.Bounds;
508                                 form.Bounds = form.Parent.Bounds;
509                                 maximized = true;
510                         }
511                 }
512
513                 private Point NewLocation (Message m)
514                 {
515                         int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
516                         int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
517                         int x_move = x - start.X;
518                         int y_move = y - start.Y;
519
520                         return new Point (form.Left + x_move, form.Top + y_move);
521                 }
522
523                 private Point MouseMove (Message m)
524                 {
525                         int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
526                         int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
527                         int x_move = x - start.X;
528                         int y_move = y - start.Y;
529
530                         return new Point (x_move, y_move);
531                 }
532
533                 private void DrawVirtualPosition ()
534                 {
535                         ClearVirtualPosition ();
536
537                         XplatUI.DrawReversibleRectangle (mdi_container.Handle, virtual_position, 2);
538                         prev_virtual_position = virtual_position;
539                 }
540
541                 private void ClearVirtualPosition ()
542                 {
543                         if (prev_virtual_position != Rectangle.Empty)
544                                 XplatUI.DrawReversibleRectangle (mdi_container.Handle,
545                                                 prev_virtual_position, 2);
546                         prev_virtual_position = Rectangle.Empty;
547                 }
548
549                 private FormPos FormPosForCoords (int x, int y)
550                 {
551                         if (y < TitleBarHeight + BorderWidth) {
552
553                                 if (y > BorderWidth && x > BorderWidth &&
554                                                 x < form.Width - BorderWidth)
555                                         return FormPos.TitleBar;
556
557                                 if (x < BorderWidth || (x < 20 && y < BorderWidth))
558                                         return FormPos.TopLeft;
559
560                                 if (x > form.Width - BorderWidth ||
561                                         (x > form.Width - 20 && y < BorderWidth))
562                                         return FormPos.TopRight;
563
564                                 if (y < BorderWidth)
565                                         return FormPos.Top;
566
567                         } else if (y > form.Height - 20) {
568
569                                 if (x < BorderWidth ||
570                                                 (x < 20 && y > form.Height - BorderWidth))
571                                         return FormPos.BottomLeft;
572
573                                 if (x > form.Width - BorderWidth ||
574                                                 (x > form.Width - 20 &&
575                                                  y > form.Height - BorderWidth))
576                                         return FormPos.BottomRight;
577
578                                 if (y > form.Height - BorderWidth)
579                                         return FormPos.Bottom;
580
581
582                         } else if (x < BorderWidth) {
583                                 return FormPos.Left;
584                         } else if (x > form.Width - BorderWidth) {
585                                 return FormPos.Right;
586                         }
587                         
588                         return FormPos.None;
589                 }
590         }
591
592 }
593