2005-10-08 Alexander Olk <alex.olk@googlemail.com>
[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 Color titlebar_color;
11
12                 private int BorderWidth = 3;
13                 private int TitleBarHeight = 25;
14                 private Size MinTitleBarSize = new Size (115, 25);
15                 
16                 private Form form;
17                 private MdiClient mdi_container;
18                 private Button close_button;
19                 private Button maximize_button;
20                 private Button minimize_button;
21                 
22                 // moving windows
23                 private Point start;
24                 private State state;
25                 private FormPos sizing_edge;
26                 private Rectangle virtual_position;
27                 private Rectangle prev_virtual_position;
28                 private Rectangle prev_bounds;
29                 private bool maximized;
30                 
31                 private enum State {
32                         Idle,
33                         Moving,
34                         Sizing,
35                 }
36
37                 [Flags]
38                 private enum FormPos {
39                         None,
40
41                         TitleBar = 1,
42
43                         Top = 2,
44                         Left = 4,
45                         Right = 8,
46                         Bottom = 16,
47
48                         TopLeft = Top | Left,
49                         TopRight = Top | Right,
50
51                         BottomLeft = Bottom | Left,
52                         BottomRight = Bottom | Right,
53
54                         AnyEdge = Top | Left | Right | Bottom,
55                 }
56
57                 public MdiChildContext (Form form)
58                 {
59                         titlebar_color = Color.FromArgb (255, 0, 0, 255);
60                         this.form = form;
61
62                         form.Paint += new PaintEventHandler (PaintWindowDecorations);
63
64                         minimize_button = new Button ();
65                         minimize_button.Bounds = new Rectangle (form.Width - 62,
66                                         BorderWidth + 2, 18, 22);
67                         minimize_button.Anchor = AnchorStyles.Top | AnchorStyles.Right;
68                         minimize_button.Paint += new PaintEventHandler (PaintButtonHandler);
69                         minimize_button.Click += new EventHandler (OnMinimizeHandler);
70                         
71                         maximize_button = new Button ();
72                         maximize_button.Bounds = new Rectangle (form.Width - 44,
73                                         BorderWidth + 2, 18, 22);
74                         maximize_button.Anchor = AnchorStyles.Top | AnchorStyles.Right;
75                         maximize_button.Paint += new PaintEventHandler (PaintButtonHandler);
76                         maximize_button.Click += new EventHandler (OnMaximizeHandler);
77                         
78                         close_button = new Button ();
79                         close_button.Bounds = new Rectangle (form.Width - 24,
80                                         BorderWidth + 2, 18, 22);
81                         close_button.Anchor = AnchorStyles.Top | AnchorStyles.Right;
82                         close_button.Paint += new PaintEventHandler (PaintButtonHandler);
83                         close_button.Click += new EventHandler (CloseButtonClicked);
84
85                         form.Controls.AddImplicit (close_button);
86                         form.Controls.AddImplicit (maximize_button);
87                         form.Controls.AddImplicit (minimize_button);
88
89                         mdi_container = (MdiClient) form.Parent;
90
91                         form.InternalBorderStyle = BorderStyle.FixedSingle;
92                 }
93
94                 public bool HandleMessage (ref Message m)
95                 {
96                         switch ((Msg)m.Msg) {
97
98                         case Msg.WM_LBUTTONDOWN:
99                                 return HandleLButtonDown (form, ref m);
100
101                         case Msg.WM_MOUSEMOVE:
102                                 return HandleMouseMove (form, ref m);
103                                  
104                         case Msg.WM_LBUTTONUP:
105                                 HandleLButtonUp (ref m);
106                                 break;
107                         }
108                         return false;
109                 }
110
111                 
112                 private bool HandleLButtonDown (Form form, ref Message m)
113                 {
114                         form.BringToFront ();
115                         mdi_container.ActiveMdiChild = form;
116
117                         int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
118                         int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
119                         FormPos pos = FormPosForCoords (x, y);
120
121                         start = new Point (x, y);
122                         virtual_position = form.Bounds;
123
124                         if (pos == FormPos.TitleBar) {
125                                 HandleTitleBarDown (x, y);
126                                 return true;
127                         }
128
129                         if (IsSizable) {
130                                 SetCursorForPos (pos);
131                         
132                                 if ((pos & FormPos.AnyEdge) == 0)
133                                         return false;
134
135                                 state = State.Sizing;
136                                 sizing_edge = pos;
137                                 form.Capture = true;
138                                 return true;
139                         }
140
141                         return false;
142                 }
143
144                 private void HandleTitleBarDown (int x, int y)
145                 {
146                         state = State.Moving;                        
147                         form.Capture = true;
148                 }
149
150                 private bool HandleMouseMove (Form form, ref Message m)
151                 {
152                         switch (state) {
153                         case State.Moving:
154                                 HandleWindowMove (m);
155                                 return true;
156                         case State.Sizing:
157                                 HandleSizing (m);
158                                 return true;
159                         }
160
161                         if (IsSizable) {
162                                 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
163                                 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
164                                 FormPos pos = FormPosForCoords (x, y);
165
166                                 SetCursorForPos (pos);
167
168                                 ClearVirtualPosition ();
169                                 state = State.Idle;
170                         }
171
172                         return false;
173                 }
174         
175                 private void SetCursorForPos (FormPos pos)
176                 {
177                         switch (pos) {
178                         case FormPos.TopLeft:
179                         case FormPos.BottomRight:
180                                 form.Cursor = Cursors.SizeNWSE;
181                                 break;
182                         case FormPos.TopRight:
183                         case FormPos.BottomLeft:
184                                 form.Cursor = Cursors.SizeNESW;
185                                 break;
186                         case FormPos.Top:
187                         case FormPos.Bottom:
188                                 form.Cursor = Cursors.SizeNS;
189                                 break;
190                         case FormPos.Left:
191                         case FormPos.Right:
192                                 form.Cursor = Cursors.SizeWE;
193                                 break;
194                         default:
195                                 form.Cursor = Cursors.Default;
196                                 break;
197                         }
198                 }
199         
200                 private void HandleWindowMove (Message m)
201                 {
202                         Point move = MouseMove (m);
203
204                         virtual_position.X = form.Left + move.X;
205                         virtual_position.Y = form.Top + move.Y;
206                         virtual_position.Width = form.Width;
207                         virtual_position.Height = form.Height;
208
209                         DrawVirtualPosition ();
210                 }
211
212                 private void HandleSizing (Message m)
213                 {
214                         Point move = MouseMove (m);
215                         Rectangle pos = virtual_position;
216                         int mw = MinTitleBarSize.Width + (BorderWidth * 2);
217                         int mh = MinTitleBarSize.Height + (BorderWidth * 2);
218                         
219                         if ((sizing_edge & FormPos.Top) != 0) {
220                                 int height = form.Height - move.Y;
221                                 if (height <= mh) {
222                                         move.Y += height - mh;
223                                         height = mh;
224                                 }
225                                 pos.Y = form.Top + move.Y;
226                                 pos.Height = height;
227                         } else if ((sizing_edge & FormPos.Bottom) != 0) {
228                                 int height = form.Height + move.Y;
229                                 if (height <= mh)
230                                         move.Y -= height - mh;
231                                 pos.Height = form.Height + move.Y;
232                         }
233
234                         if ((sizing_edge & FormPos.Left) != 0) {
235                                 int width = form.Width - move.X;
236                                 if (width <= mw) {
237                                         move.X += width - mw;
238                                         width = mw;
239                                 }
240                                 pos.X = form.Left + move.X;
241                                 pos.Width = width;
242                         } else if ((sizing_edge & FormPos.Right) != 0) {
243                                 int width = form.Width + move.X;
244                                 if (width <= mw)
245                                         move.X -= width - mw;
246                                 pos.Width = form.Width + move.X;
247                         }
248
249                         UpdateVP (pos);
250                 }
251
252                 private bool IsSizable {
253                         get {
254                                 switch (form.FormBorderStyle) {
255                                 case FormBorderStyle.Sizable:
256                                 case FormBorderStyle.SizableToolWindow:
257                                         return true;
258                                 default:
259                                         return false;
260                                 }
261                         }
262                 }
263
264                 private void UpdateVP (Rectangle r)
265                 {
266                         UpdateVP (r.X, r.Y, r.Width, r.Height);
267                 }
268
269                 private void UpdateVP (Point loc, int w, int h)
270                 {
271                         UpdateVP (loc.X, loc.Y, w, h);
272                 }
273
274                 private void UpdateVP (int x, int y, int w, int h)
275                 {
276                         virtual_position.X = x;
277                         virtual_position.Y = y;
278                         virtual_position.Width = w;
279                         virtual_position.Height = h;
280
281                         DrawVirtualPosition ();
282                 }
283
284                 private void HandleLButtonUp (ref Message m)
285                 {
286                         if (state == State.Idle)
287                                 return;
288
289                         ClearVirtualPosition ();
290
291                         form.Capture = false;
292                         form.Bounds = virtual_position;
293                         state = State.Idle;
294                 }
295
296                 private void PaintWindowDecorations (object sender, PaintEventArgs pe)
297                 {
298                         Color color = titlebar_color;
299                         if (maximized)
300                                 color = ThemeEngine.Current.ColorControl;
301                         Rectangle tb = new Rectangle (BorderWidth, BorderWidth,
302                                         form.Width - BorderWidth, TitleBarHeight);
303
304                         pe.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (color),
305                                                 BorderWidth, BorderWidth,
306                                                 form.Width - BorderWidth, TitleBarHeight);
307
308                         if (form.Text != null) {
309                                 StringFormat format = new StringFormat ();
310                                 format.LineAlignment = StringAlignment.Center;
311                                 pe.Graphics.DrawString (form.Text, form.Font,
312                                                 ThemeEngine.Current.ResPool.GetSolidBrush (form.ForeColor),
313                                                 tb, format);
314                         }
315
316                         if (form.Icon != null) {
317                                 pe.Graphics.DrawIcon (form.Icon, BorderWidth, BorderWidth);
318                         }
319
320                         /*
321                         Pen bp = new Pen (ThemeEngine.Current.ColorControl,
322                                         BorderWidth);
323
324                         // HACK: kludge the borders around
325                         Rectangle border = form.ClientRectangle;
326                         border.X++;
327                         border.Y++;
328                         border.Width -= 4;
329                         border.Height -= 4;
330                         pe.Graphics.DrawRectangle (bp, border);
331
332                         Border3DStyle style = Border3DStyle.Raised | Border3DStyle.Bump;
333                         border = form.ClientRectangle;
334
335                         if (maximized) {
336                                 style = Border3DStyle.SunkenInner;
337                                 border.Y = TitleBarHeight + BorderWidth * 2;
338                                 border.Height -= TitleBarHeight;
339                         }
340                         
341                         ControlPaint.DrawBorder3D (pe.Graphics, border,
342                                         style,
343                                         Border3DSide.Left | Border3DSide.Right |
344                                         Border3DSide.Top | Border3DSide.Bottom);
345                         */
346                 }
347
348                 private void PaintButtonHandler (object sender, PaintEventArgs pe)
349                 {
350                         if (sender == close_button) {
351                                 ControlPaint.DrawCaptionButton (pe.Graphics,
352                                                 close_button.ClientRectangle,
353                                                 CaptionButton.Close,
354                                                 close_button.ButtonState);
355                         } else if (sender == maximize_button) {
356                                 ControlPaint.DrawCaptionButton (pe.Graphics,
357                                                 maximize_button.ClientRectangle,
358                                                 CaptionButton.Maximize,
359                                                 maximize_button.ButtonState);
360                         } else if (sender == minimize_button) {
361                                 ControlPaint.DrawCaptionButton (pe.Graphics,
362                                                 minimize_button.ClientRectangle,
363                                                 CaptionButton.Minimize,
364                                                 minimize_button.ButtonState);
365                         }
366                 }
367
368                 private void CloseButtonClicked (object sender, EventArgs e)
369                 {
370                         form.Close ();
371                         // form.Close should set visibility to false somewhere
372                         // in it's closing chain but currently does not.
373                         form.Visible = false;
374                 }
375
376                 private void OnMinimizeHandler (object sender, EventArgs e)
377                 {
378                         form.SuspendLayout ();
379                         form.Width = MinTitleBarSize.Width + (BorderWidth * 2);
380                         form.Height = MinTitleBarSize.Height + (BorderWidth * 2);
381                         form.ResumeLayout ();
382                 }
383
384                 private void OnMaximizeHandler (object sender, EventArgs e)
385                 {
386                         if (maximized) {
387                                 form.Bounds = prev_bounds;
388                                 maximized = false;
389                         } else {
390                                 prev_bounds = form.Bounds;
391                                 form.Bounds = form.Parent.Bounds;
392                                 maximized = true;
393                         }
394                 }
395
396                 private Point NewLocation (Message m)
397                 {
398                         int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
399                         int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
400                         int x_move = x - start.X;
401                         int y_move = y - start.Y;
402
403                         return new Point (form.Left + x_move, form.Top + y_move);
404                 }
405
406                 private Point MouseMove (Message m)
407                 {
408                         int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
409                         int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
410                         int x_move = x - start.X;
411                         int y_move = y - start.Y;
412
413                         return new Point (x_move, y_move);
414                 }
415
416                 // For now just use a solid pen as it is 10 billion times
417                 // faster then using the hatch, and what we really need is invert
418                 private void DrawVirtualPosition ()
419                 {
420                         ClearVirtualPosition ();
421
422                         XplatUI.DrawReversibleRectangle (mdi_container.Handle, virtual_position);
423                         prev_virtual_position = virtual_position;
424                 }
425
426                 private void ClearVirtualPosition ()
427                 {
428                         if (prev_virtual_position != Rectangle.Empty)
429                                 XplatUI.DrawReversibleRectangle (mdi_container.Handle,
430                                                 prev_virtual_position);
431                         prev_virtual_position = Rectangle.Empty;
432                 }
433
434                 private FormPos FormPosForCoords (int x, int y)
435                 {
436                         if (y < TitleBarHeight + BorderWidth) {
437
438                                 if (y > BorderWidth && x > BorderWidth &&
439                                                 x < form.Width - BorderWidth)
440                                         return FormPos.TitleBar;
441
442                                 if (x < BorderWidth || (x < 20 && y < BorderWidth))
443                                         return FormPos.TopLeft;
444
445                                 if (x > form.Width - BorderWidth ||
446                                         (x > form.Width - 20 && y < BorderWidth))
447                                         return FormPos.TopRight;
448
449                                 if (y < BorderWidth)
450                                         return FormPos.Top;
451
452                         } else if (y > form.Height - 20) {
453
454                                 if (x < BorderWidth ||
455                                                 (x < 20 && y > form.Height - BorderWidth))
456                                         return FormPos.BottomLeft;
457
458                                 if (x > form.Width - BorderWidth ||
459                                                 (x > form.Width - 20 &&
460                                                  y > form.Height - BorderWidth))
461                                         return FormPos.BottomRight;
462
463                                 if (y > form.Height - BorderWidth)
464                                         return FormPos.Bottom;
465
466
467                         } else if (x < BorderWidth) {
468                                 return FormPos.Left;
469                         } else if (x > form.Width - BorderWidth) {
470                                 return FormPos.Right;
471                         }
472
473                         return FormPos.None;
474                 }
475         }
476
477 }
478