]> git.saurik.com Git - wxWidgets.git/blob - src/msw/mdi.cpp
fix for scrolling in checklistboxes (Win32 only)
[wxWidgets.git] / src / msw / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mdi.cpp
3 // Purpose: MDI classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "mdi.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/setup.h"
25 #include "wx/frame.h"
26 #include "wx/menu.h"
27 #include "wx/app.h"
28 #include "wx/utils.h"
29 #include "wx/dialog.h"
30 #include "wx/statusbr.h"
31 #include "wx/settings.h"
32 #endif
33
34 #include "wx/mdi.h"
35 #include "wx/msw/private.h"
36
37 #if wxUSE_NATIVE_STATUSBAR
38 #include <wx/msw/statbr95.h>
39 #endif
40
41 #include <string.h>
42
43 extern wxList wxModelessWindows;
44 extern wxMenu *wxCurrentPopupMenu;
45
46 #define IDM_WINDOWTILE 4001
47 #define IDM_WINDOWCASCADE 4002
48 #define IDM_WINDOWICONS 4003
49 #define IDM_WINDOWNEXT 4004
50 // This range gives a maximum of 500
51 // MDI children. Should be enough :-)
52 #define wxFIRST_MDI_CHILD 4100
53 #define wxLAST_MDI_CHILD 4600
54
55 // Status border dimensions
56 #define wxTHICK_LINE_BORDER 3
57 #define wxTHICK_LINE_WIDTH 1
58
59 extern char wxMDIFrameClassName[];
60 extern char wxMDIChildFrameClassName[];
61 extern wxWindow *wxWndHook;
62
63 #if !USE_SHARED_LIBRARY
64 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
65 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
66 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
67
68 BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
69 EVT_SIZE(wxMDIParentFrame::OnSize)
70 EVT_ACTIVATE(wxMDIParentFrame::OnActivate)
71 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
72 END_EVENT_TABLE()
73
74 BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow)
75 EVT_SCROLL(wxMDIClientWindow::OnScroll)
76 END_EVENT_TABLE()
77
78 #endif
79
80 wxMDIParentFrame::wxMDIParentFrame(void)
81 {
82 m_clientWindow = NULL;
83 m_currentChild = NULL;
84 m_windowMenu = 0;
85 m_parentFrameActive = TRUE;
86 }
87
88 bool wxMDIParentFrame::Create(wxWindow *parent,
89 wxWindowID id,
90 const wxString& title,
91 const wxPoint& pos,
92 const wxSize& size,
93 long style,
94 const wxString& name)
95 {
96 m_defaultIcon = (WXHICON) (wxSTD_MDIPARENTFRAME_ICON ? wxSTD_MDIPARENTFRAME_ICON : wxDEFAULT_MDIPARENTFRAME_ICON);
97
98 m_clientWindow = NULL;
99 m_currentChild = NULL;
100 m_windowMenu = 0;
101 m_parentFrameActive = TRUE;
102
103 if (!parent)
104 wxTopLevelWindows.Append(this);
105
106 SetName(name);
107 m_windowStyle = style;
108
109 if (parent) parent->AddChild(this);
110
111 if ( id > -1 )
112 m_windowId = id;
113 else
114 m_windowId = (int)NewControlId();
115
116 int x = pos.x;
117 int y = pos.y;
118 int width = size.x;
119 int height = size.y;
120
121 m_windowMenu = (WXHMENU) ::LoadMenu(wxGetInstance(), "wxWindowMenu");
122
123 DWORD msflags = WS_OVERLAPPED ;
124 if (style & wxMINIMIZE_BOX)
125 msflags |= WS_MINIMIZEBOX;
126 if (style & wxMAXIMIZE_BOX)
127 msflags |= WS_MAXIMIZEBOX;
128 if (style & wxTHICK_FRAME)
129 msflags |= WS_THICKFRAME;
130 if (style & wxSYSTEM_MENU)
131 msflags |= WS_SYSMENU;
132 if ((style & wxMINIMIZE) || (style & wxICONIZE))
133 msflags |= WS_MINIMIZE;
134 if (style & wxMAXIMIZE)
135 msflags |= WS_MAXIMIZE;
136 if (style & wxCAPTION)
137 msflags |= WS_CAPTION;
138
139 // Adding WS_CLIPCHILDREN causes children not to be properly
140 // drawn when first displaying them.
141 // if (style & wxCLIP_CHILDREN)
142 // msflags |= WS_CLIPCHILDREN;
143
144 wxWindow::MSWCreate(m_windowId, parent, wxMDIFrameClassName, this, title, x, y, width, height,
145 msflags);
146
147 wxModelessWindows.Append(this);
148
149 return TRUE;
150 }
151
152 wxMDIParentFrame::~wxMDIParentFrame(void)
153 {
154 DestroyChildren();
155
156 DestroyMenu((HMENU) m_windowMenu); // Destroy dummy "Window" menu
157 m_windowMenu = 0;
158
159 if (m_clientWindow->MSWGetOldWndProc())
160 m_clientWindow->UnsubclassWin();
161
162 m_clientWindow->m_hWnd = 0;
163 delete m_clientWindow;
164 }
165
166 // Get size *available for subwindows* i.e. excluding menu bar.
167 void wxMDIParentFrame::GetClientSize(int *x, int *y) const
168 {
169 RECT rect;
170 ::GetClientRect((HWND) GetHWND(), &rect);
171
172 int cwidth = rect.right;
173 int cheight = rect.bottom;
174
175 if ( GetStatusBar() )
176 {
177 int sw, sh;
178 GetStatusBar()->GetSize(&sw, &sh);
179 cheight -= sh;
180 }
181
182 wxPoint pt(GetClientAreaOrigin());
183 cheight -= pt.y;
184 cwidth -= pt.x;
185
186 *x = cwidth;
187 *y = cheight;
188 }
189
190 void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar)
191 {
192 if (!menu_bar)
193 {
194 m_frameMenuBar = NULL;
195 return;
196 }
197
198 if (menu_bar->m_menuBarFrame)
199 return;
200
201 int i;
202 HMENU menu = CreateMenu();
203
204 for (i = 0; i < menu_bar->m_menuCount; i ++)
205 {
206 HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu;
207 //
208 // After looking Bounds Checker result, it seems that all
209 // menus must be individually destroyed. So, don't reset m_hMenu,
210 // to allow ~wxMenu to do the job.
211 //
212 menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup;
213 // Uncommenting for the moment... JACS
214 menu_bar->m_menus[i]->m_hMenu = (WXHMENU) NULL;
215 AppendMenu(menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]);
216 }
217
218 menu_bar->m_hMenu = (WXHMENU)menu;
219 if (m_frameMenuBar)
220 delete m_frameMenuBar;
221
222 this->m_hMenu = (WXHMENU) menu;
223
224 // MDI parent-specific code follows
225
226 HMENU subMenu = GetSubMenu((HMENU) m_windowMenu, 0);
227
228 // Try to insert Window menu in front of Help, otherwise append it.
229 int N = GetMenuItemCount(menu);
230 bool success = FALSE;
231 for (i = 0; i < N; i++)
232 {
233 char buf[100];
234 int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION);
235 if ((chars > 0) && (strcmp(buf, "&Help") == 0 ||
236 strcmp(buf, "Help") == 0))
237 {
238 success = TRUE;
239 InsertMenu(menu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
240 (UINT)subMenu, "&Window");
241 break;
242 }
243 }
244 if (!success)
245 AppendMenu(menu, MF_POPUP,
246 (UINT)subMenu,
247 "&Window");
248 m_parentFrameActive = TRUE;
249 #ifdef __WIN32__
250 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDISETMENU,
251 (WPARAM)menu,
252 (LPARAM)subMenu);
253 #else
254 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
255 MAKELPARAM(menu, subMenu));
256 #endif
257 DrawMenuBar((HWND) GetHWND());
258
259 m_frameMenuBar = menu_bar;
260 menu_bar->m_menuBarFrame = this;
261 }
262
263 void wxMDIParentFrame::OnSize(wxSizeEvent& event)
264 {
265 #if wxUSE_CONSTRAINTS
266 if (GetAutoLayout())
267 Layout();
268 #endif
269 int x = 0;
270 int y = 0;
271 int width, height;
272 GetClientSize(&width, &height);
273
274 if ( GetClientWindow() )
275 GetClientWindow()->SetSize(x, y, width, height);
276
277 /* Already done in MSWOnSize
278 // forward WM_SIZE to status bar control
279 #if wxUSE_NATIVE_STATUSBAR
280 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
281 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
282 #endif
283 */
284
285 }
286
287 void wxMDIParentFrame::OnActivate(wxActivateEvent& event)
288 {
289 // Do nothing
290 }
291
292 // Returns the active MDI child window
293 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild(void) const
294 {
295 // HWND hWnd = (HWND)LOWORD(SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L));
296 HWND hWnd = (HWND)SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L);
297 if (hWnd == 0)
298 return NULL;
299 else
300 return (wxMDIChildFrame *)wxFindWinFromHandle((WXHWND) hWnd);
301 }
302
303 // Create the client window class (don't Create the window,
304 // just return a new class)
305 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient(void)
306 {
307 return new wxMDIClientWindow ;
308 }
309
310 // Responds to colour changes, and passes event on to children.
311 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
312 {
313 if ( m_clientWindow )
314 {
315 m_clientWindow->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
316 m_clientWindow->Refresh();
317 }
318 /*
319 if ( m_frameToolBar )
320 {
321 wxSysColourChangedEvent event2;
322 event2.eventObject = m_frameToolBar;
323 m_frameToolBar->GetEventHandler()->ProcessEvent(event2);
324 }
325 */
326
327 // Propagate the event to the non-top-level children
328 wxFrame::OnSysColourChanged(event);
329 }
330
331 // MDI operations
332 void wxMDIParentFrame::Cascade(void)
333 {
334 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDICASCADE, 0, 0);
335 }
336
337 void wxMDIParentFrame::Tile(void)
338 {
339 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDITILE, MDITILE_HORIZONTAL, 0);
340 }
341
342 void wxMDIParentFrame::ArrangeIcons(void)
343 {
344 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIICONARRANGE, 0, 0);
345 }
346
347 void wxMDIParentFrame::ActivateNext(void)
348 {
349 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 0);
350 }
351
352 void wxMDIParentFrame::ActivatePrevious(void)
353 {
354 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 1);
355 }
356
357
358 /*
359 // Returns a style for the client window - usually 0
360 // or, for example, wxHSCROLL | wxVSCROLL
361 long wxMDIParentFrame::GetClientStyle(void) const
362 {
363 return wxHSCROLL | wxVSCROLL ;
364 }
365 */
366
367 bool wxMDIParentFrame::MSWOnDestroy(void)
368 {
369 return FALSE;
370 }
371
372 void wxMDIParentFrame::MSWOnCreate(WXLPCREATESTRUCT WXUNUSED(cs))
373 {
374 m_clientWindow = OnCreateClient();
375 // Uses own style for client style
376 m_clientWindow->CreateClient(this, GetWindowStyleFlag());
377 }
378
379 void wxMDIParentFrame::MSWOnSize(int x, int y, WXUINT id)
380 {
381 switch (id)
382 {
383 case SIZEFULLSCREEN:
384 case SIZENORMAL:
385 m_iconized = FALSE;
386 break;
387 case SIZEICONIC:
388 m_iconized = TRUE;
389 break;
390 }
391
392 if (!m_iconized)
393 {
394 // forward WM_SIZE to status bar control
395 #if wxUSE_NATIVE_STATUSBAR
396 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
397 {
398 wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId());
399 event.SetEventObject( m_frameStatusBar );
400
401 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
402 }
403 #endif
404
405 PositionStatusBar();
406 PositionToolBar();
407
408 wxSizeEvent event(wxSize(x, y), m_windowId);
409 event.SetEventObject( this );
410 if (!GetEventHandler()->ProcessEvent(event))
411 Default();
412 }
413 }
414
415 bool wxMDIParentFrame::MSWOnActivate(int state, bool minimized, WXHWND activate)
416 {
417 wxWindow::MSWOnActivate(state, minimized, activate);
418
419 // If this window is an MDI parent, we must also send an OnActivate message
420 // to the current child.
421 if ((m_currentChild != NULL) && ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE)))
422 {
423 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_currentChild->GetId());
424 event.SetEventObject( m_currentChild );
425 m_currentChild->GetEventHandler()->ProcessEvent(event);
426 }
427 return 0;
428 }
429
430 bool wxMDIParentFrame::MSWOnCommand(WXWORD id, WXWORD cmd, WXHWND control)
431 {
432 // if (cmd == 0) // Why did I do this test?
433 {
434 // In case it's e.g. a toolbar.
435 wxWindow *win = wxFindWinFromHandle(control);
436 if (win)
437 return win->MSWCommand(cmd, id);
438
439 /*
440 if (wxCurrentPopupMenu)
441 {
442 wxMenu *popupMenu = wxCurrentPopupMenu;
443 wxCurrentPopupMenu = NULL;
444 if (!popupMenu->MSWCommand(cmd, id))
445 return TRUE;
446 }
447 */
448
449 switch (id)
450 {
451 case IDM_WINDOWCASCADE:
452 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDICASCADE, MDITILE_SKIPDISABLED, 0);
453 return TRUE;
454 case IDM_WINDOWTILE:
455 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDITILE, MDITILE_HORIZONTAL, 0);
456 return TRUE;
457 case IDM_WINDOWICONS:
458 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIICONARRANGE, 0, 0);
459 return TRUE;
460 case IDM_WINDOWNEXT:
461 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 0);
462 return TRUE;
463 default:
464 break;
465 }
466 if (id >= 0xF000)
467 {
468 return FALSE; // Get WndProc to call default proc
469 }
470
471 if (m_parentFrameActive && (id < wxFIRST_MDI_CHILD || id > wxLAST_MDI_CHILD))
472 {
473 ProcessCommand(id);
474 return TRUE;
475 }
476 else if (m_currentChild && (id < wxFIRST_MDI_CHILD || id > wxLAST_MDI_CHILD))
477 {
478 return m_currentChild->MSWOnCommand(id, cmd, control);
479 }
480 }
481 if (id >= wxFIRST_MDI_CHILD && id <= wxLAST_MDI_CHILD)
482 {
483 wxNode* node = GetChildren().First();
484 while (node)
485 {
486 wxWindow* child = (wxWindow*) node->Data();
487 if (child->GetHWND())
488 {
489 #ifdef __WIN32__
490 long childId = GetWindowLong((HWND) child->GetHWND(), GWL_ID);
491 #else
492 long childId = GetWindowWord((HWND) child->GetHWND(), GWW_ID);
493 #endif
494 if (childId == id)
495 {
496 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) child->GetHWND(), 0);
497 return TRUE;
498 }
499 }
500 node = node->Next();
501 }
502 /*
503 wxWindow* child = FindItem(id);
504 if (child)
505 {
506 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) child->GetHWND(), 0);
507 return TRUE;
508 }
509 */
510 }
511
512 return FALSE;
513 }
514
515 void wxMDIParentFrame::MSWOnMenuHighlight(WXWORD nItem, WXWORD nFlags, WXHMENU hSysMenu)
516 {
517 if (m_parentFrameActive)
518 {
519 if (nFlags == 0xFFFF && hSysMenu == (WXHMENU) NULL)
520 {
521 wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, -1);
522 event.SetEventObject( this );
523 GetEventHandler()->ProcessEvent(event);
524 }
525 else if (nFlags != MF_SEPARATOR)
526 {
527 wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, nItem);
528 event.SetEventObject( this );
529 GetEventHandler()->ProcessEvent(event);
530 }
531 }
532 else if (m_currentChild)
533 {
534 m_currentChild->MSWOnMenuHighlight(nItem, nFlags, hSysMenu);
535 }
536 }
537
538 long wxMDIParentFrame::MSWDefWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
539 {
540 WXHWND clientWnd;
541 if ( GetClientWindow() )
542 clientWnd = GetClientWindow()->GetHWND();
543 else
544 clientWnd = 0;
545
546 return DefFrameProc((HWND) GetHWND(), (HWND) clientWnd, message, wParam, lParam);
547 }
548
549 bool wxMDIParentFrame::MSWProcessMessage(WXMSG* msg)
550 {
551 if ((m_currentChild != (wxWindow *)NULL) && (m_currentChild->GetHWND() != (WXHWND) NULL) && m_currentChild->MSWProcessMessage(msg))
552 return TRUE;
553
554 return FALSE;
555 }
556
557 bool wxMDIParentFrame::MSWTranslateMessage(WXMSG* msg)
558 {
559 MSG *pMsg = (MSG *)msg;
560
561 if ((m_currentChild != (wxWindow *)NULL) && (m_currentChild->GetHWND() != (WXHWND) NULL) && m_currentChild->MSWTranslateMessage(msg))
562 return TRUE;
563
564 if (m_acceleratorTable.Ok() &&
565 ::TranslateAccelerator((HWND) GetHWND(), (HACCEL) m_acceleratorTable.GetHACCEL(), pMsg))
566 return TRUE;
567
568 if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN)
569 {
570 if (::TranslateMDISysAccel((HWND) GetClientWindow()->GetHWND(), pMsg))
571 return TRUE;
572 }
573
574 return FALSE;
575 }
576
577
578 bool wxMDIParentFrame::MSWOnEraseBkgnd(WXHDC WXUNUSED(pDC))
579 {
580 return TRUE;
581 }
582
583 extern wxWindow *wxWndHook;
584 extern wxList *wxWinHandleList;
585
586 wxMDIChildFrame::wxMDIChildFrame(void)
587 {
588 // m_active = FALSE;
589 }
590
591 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
592 wxWindowID id,
593 const wxString& title,
594 const wxPoint& pos,
595 const wxSize& size,
596 long style,
597 const wxString& name)
598 {
599 m_defaultIcon = (WXHICON) (wxSTD_MDICHILDFRAME_ICON ? wxSTD_MDICHILDFRAME_ICON : wxDEFAULT_MDICHILDFRAME_ICON);
600
601 SetName(name);
602
603 if ( id > -1 )
604 m_windowId = id;
605 else
606 m_windowId = (int)NewControlId();
607
608 if (parent) parent->AddChild(this);
609
610 wxWndHook = this;
611
612 int x = pos.x;
613 int y = pos.y;
614 int width = size.x;
615 int height = size.y;
616
617 MDICREATESTRUCT mcs;
618
619 mcs.szClass = wxMDIChildFrameClassName;
620 mcs.szTitle = title;
621 mcs.hOwner = wxGetInstance();
622 if (x > -1) mcs.x = x;
623 else mcs.x = CW_USEDEFAULT;
624
625 if (y > -1) mcs.y = y;
626 else mcs.y = CW_USEDEFAULT;
627
628 if (width > -1) mcs.cx = width;
629 else mcs.cx = CW_USEDEFAULT;
630
631 if (height > -1) mcs.cy = height;
632 else mcs.cy = CW_USEDEFAULT;
633
634 DWORD msflags = WS_OVERLAPPED | WS_CLIPCHILDREN ;
635 if (style & wxMINIMIZE_BOX)
636 msflags |= WS_MINIMIZEBOX;
637 if (style & wxMAXIMIZE_BOX)
638 msflags |= WS_MAXIMIZEBOX;
639 if (style & wxTHICK_FRAME)
640 msflags |= WS_THICKFRAME;
641 if (style & wxSYSTEM_MENU)
642 msflags |= WS_SYSMENU;
643 if ((style & wxMINIMIZE) || (style & wxICONIZE))
644 msflags |= WS_MINIMIZE;
645 if (style & wxMAXIMIZE)
646 msflags |= WS_MAXIMIZE;
647 if (style & wxCAPTION)
648 msflags |= WS_CAPTION;
649
650 mcs.style = msflags;
651
652 mcs.lParam = 0;
653
654 DWORD Return = SendMessage((HWND) parent->GetClientWindow()->GetHWND(),
655 WM_MDICREATE, 0, (LONG)(LPSTR)&mcs);
656
657 //handle = (HWND)LOWORD(Return);
658 // Must be the DWORRD for WIN32. And in 16 bits, HIWORD=0 (says Microsoft)
659 m_hWnd = (WXHWND)Return;
660
661 // This gets reassigned so can't be stored
662 // m_windowId = GetWindowLong((HWND) m_hWnd, GWL_ID);
663
664 wxWndHook = NULL;
665 wxWinHandleList->Append((long)GetHWND(), this);
666
667 SetWindowLong((HWND) GetHWND(), 0, (long)this);
668
669 wxModelessWindows.Append(this);
670 return TRUE;
671 }
672
673 wxMDIChildFrame::~wxMDIChildFrame(void)
674 {
675 MSWDestroyWindow();
676
677 ResetWindowStyle(NULL);
678 }
679
680 // Set the client size (i.e. leave the calculation of borders etc.
681 // to wxWindows)
682 void wxMDIChildFrame::SetClientSize(int width, int height)
683 {
684 HWND hWnd = (HWND) GetHWND();
685
686 RECT rect;
687 ::GetClientRect(hWnd, &rect);
688
689 RECT rect2;
690 GetWindowRect(hWnd, &rect2);
691
692 // Find the difference between the entire window (title bar and all)
693 // and the client area; add this to the new client size to move the
694 // window
695 int actual_width = rect2.right - rect2.left - rect.right + width;
696 int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
697
698 if (GetStatusBar())
699 {
700 int sx, sy;
701 GetStatusBar()->GetSize(&sx, &sy);
702 actual_height += sy;
703 }
704
705 POINT point;
706 point.x = rect2.left;
707 point.y = rect2.top;
708
709 // If there's an MDI parent, must subtract the parent's top left corner
710 // since MoveWindow moves relative to the parent
711 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
712 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
713
714 MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE);
715
716 wxSizeEvent event(wxSize(width, height), m_windowId);
717 event.SetEventObject( this );
718 GetEventHandler()->ProcessEvent(event);
719 }
720
721 void wxMDIChildFrame::GetPosition(int *x, int *y) const
722 {
723 RECT rect;
724 GetWindowRect((HWND) GetHWND(), &rect);
725 POINT point;
726 point.x = rect.left;
727 point.y = rect.top;
728
729 // Since we now have the absolute screen coords,
730 // if there's a parent we must subtract its top left corner
731 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
732 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
733
734 *x = point.x;
735 *y = point.y;
736 }
737
738 void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar)
739 {
740 if (!menu_bar)
741 {
742 m_frameMenuBar = NULL;
743 return;
744 }
745
746 if (menu_bar->m_menuBarFrame)
747 return;
748
749 int i;
750 HMENU menu = CreateMenu();
751
752 for (i = 0; i < menu_bar->m_menuCount; i ++)
753 {
754 HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu;
755 //
756 // After looking Bounds Checker result, it seems that all
757 // menus must be individually destroyed. So, don't reset m_hMenu,
758 // to allow ~wxMenu to do the job.
759 //
760 menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup;
761 // Uncommenting for the moment... JACS
762 menu_bar->m_menus[i]->m_hMenu = 0;
763 ::AppendMenu((HMENU) menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]);
764 }
765
766 menu_bar->m_hMenu = (WXHMENU)menu;
767 if (m_frameMenuBar)
768 delete m_frameMenuBar;
769
770 this->m_hMenu = (WXHMENU) menu;
771
772 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
773
774 parent->m_parentFrameActive = FALSE;
775 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
776
777 // Try to insert Window menu in front of Help, otherwise append it.
778 int N = GetMenuItemCount(menu);
779 bool success = FALSE;
780 for (i = 0; i < N; i++)
781 {
782 char buf[100];
783 int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION);
784 if ((chars > 0) && (strcmp(buf, "&Help") == 0 ||
785 strcmp(buf, "Help") == 0))
786 {
787 success = TRUE;
788 InsertMenu(menu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
789 (UINT)subMenu, "&Window");
790 break;
791 }
792 }
793 if (!success)
794 AppendMenu(menu, MF_POPUP,
795 (UINT)subMenu,
796 "&Window");
797 #ifdef __WIN32__
798 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
799 (WPARAM)menu,
800 (LPARAM)subMenu);
801 #else
802 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
803 MAKELPARAM(menu, subMenu));
804 #endif
805
806 DrawMenuBar((HWND) parent->GetHWND());
807 m_frameMenuBar = menu_bar;
808 menu_bar->m_menuBarFrame = this;
809 }
810
811 // MDI operations
812 void wxMDIChildFrame::Maximize(void)
813 {
814 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
815 if ( parent && parent->GetClientWindow() )
816 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIMAXIMIZE, (WPARAM) (HWND) GetHWND(), 0);
817 }
818
819 void wxMDIChildFrame::Restore(void)
820 {
821 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
822 if ( parent && parent->GetClientWindow() )
823 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIRESTORE, (WPARAM) (HWND) GetHWND(), 0);
824 }
825
826 void wxMDIChildFrame::Activate(void)
827 {
828 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
829 if ( parent && parent->GetClientWindow() )
830 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) GetHWND(), 0);
831 }
832
833 static HWND invalidHandle = 0;
834 void wxMDIChildFrame::MSWOnSize(int x, int y, WXUINT id)
835 {
836 if (!GetHWND()) return;
837
838 if (invalidHandle == (HWND) GetHWND())
839 {
840 return;
841 }
842
843 (void)MSWDefWindowProc(m_lastMsg, m_lastWParam, m_lastLParam);
844
845 switch (id)
846 {
847 case SIZEFULLSCREEN:
848 case SIZENORMAL:
849 m_iconized = FALSE;
850 break;
851 case SIZEICONIC:
852 m_iconized = TRUE;
853 break;
854 }
855
856 if (!m_iconized)
857 {
858 // forward WM_SIZE to status bar control
859 #if wxUSE_NATIVE_STATUSBAR
860 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
861 {
862 wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId());
863 event.SetEventObject( m_frameStatusBar );
864
865 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
866 }
867 #endif
868
869 PositionStatusBar();
870 PositionToolBar();
871
872 wxWindow::MSWOnSize(x, y, id);
873 }
874 }
875
876 bool wxMDIChildFrame::MSWOnCommand(WXWORD id, WXWORD cmd, WXHWND control)
877 {
878 // if ((cmd == 0) && GetHWND())
879 if (GetHWND())
880 {
881 // In case it's e.g. a toolbar.
882 wxWindow *win = wxFindWinFromHandle(control);
883 if (win)
884 return win->MSWCommand(cmd, id);
885
886 if (wxCurrentPopupMenu)
887 {
888 wxMenu *popupMenu = wxCurrentPopupMenu;
889 wxCurrentPopupMenu = NULL;
890 if (popupMenu->MSWCommand(cmd, id))
891 return TRUE;
892 }
893
894 if (GetMenuBar() && GetMenuBar()->FindItemForId(id))
895 {
896 ProcessCommand(id);
897 return TRUE;
898 }
899 else
900 return FALSE;
901 return TRUE;
902 }
903 else
904 return FALSE;
905 }
906
907 long wxMDIChildFrame::MSWDefWindowProc(WXUINT message, WXUINT wParam, WXLPARAM lParam)
908 {
909 if (GetHWND())
910 return DefMDIChildProc((HWND) GetHWND(), (UINT) message, (WPARAM) wParam, (LPARAM) lParam);
911 else return 0;
912 }
913
914 bool wxMDIChildFrame::MSWProcessMessage(WXMSG *msg)
915 {
916 return FALSE;
917 }
918
919 bool wxMDIChildFrame::MSWTranslateMessage(WXMSG* msg)
920 {
921 MSG *pMsg = (MSG *)msg;
922 if (m_acceleratorTable.Ok())
923 {
924 wxFrame *parent = (wxFrame *)GetParent();
925 HWND parent_hwnd = (HWND) parent->GetHWND();
926 return (::TranslateAccelerator(parent_hwnd, (HACCEL) m_acceleratorTable.GetHACCEL(), pMsg) != 0);
927 }
928
929 return FALSE;
930 }
931
932 long wxMDIChildFrame::MSWOnMDIActivate(long activate, WXHWND WXUNUSED(one), WXHWND WXUNUSED(two))
933 {
934 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
935 HMENU parent_menu = (HMENU) parent->GetWinMenu();
936 HMENU child_menu = (HMENU) GetWinMenu();
937
938 if (activate)
939 {
940 // m_active = TRUE;
941 parent->m_currentChild = this;
942 if (child_menu)
943 {
944 parent->m_parentFrameActive = FALSE;
945 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
946 #ifdef __WIN32__
947 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
948 (WPARAM)child_menu,
949 (LPARAM)subMenu);
950 #else
951 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
952 MAKELONG(child_menu, subMenu));
953 #endif
954
955 ::DrawMenuBar((HWND) parent->GetHWND());
956 }
957 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_windowId);
958 event.SetEventObject( this );
959 GetEventHandler()->ProcessEvent(event);
960 }
961 else
962 {
963 if (parent->m_currentChild == this)
964 parent->m_currentChild = NULL;
965
966 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, m_windowId);
967 event.SetEventObject( this );
968 GetEventHandler()->ProcessEvent(event);
969
970 // m_active = FALSE;
971 if (parent_menu)
972 {
973 parent->m_parentFrameActive = TRUE;
974 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
975 #ifdef __WIN32__
976 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
977 (WPARAM)parent_menu,
978 (LPARAM)subMenu);
979 #else
980 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
981 MAKELONG(parent_menu, subMenu));
982 #endif
983
984 ::DrawMenuBar((HWND) parent->GetHWND());
985 }
986 }
987 bool flag = (activate != 0);
988 wxActivateEvent event(wxEVT_ACTIVATE, flag, m_windowId);
989 event.SetEventObject( this );
990 GetEventHandler()->ProcessEvent(event);
991 return 0;
992 }
993
994 void wxMDIChildFrame::MSWDestroyWindow(void)
995 {
996 MSWDetachWindowMenu();
997 invalidHandle = (HWND) GetHWND();
998
999 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
1000
1001 // Must make sure this handle is invalidated (set to NULL)
1002 // since all sorts of things could happen after the
1003 // child client is destroyed, but before the wxFrame is
1004 // destroyed.
1005
1006 HWND oldHandle = (HWND)GetHWND();
1007 #ifdef __WIN32__
1008 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (WPARAM)oldHandle, (LPARAM)0);
1009 #else
1010 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (HWND)oldHandle, 0);
1011 #endif
1012 invalidHandle = 0;
1013
1014 if (m_hMenu)
1015 {
1016 ::DestroyMenu((HMENU) m_hMenu);
1017 m_hMenu = 0;
1018 }
1019 m_hWnd = 0;
1020 }
1021
1022 // Change the client window's extended style so we don't
1023 // get a client edge style when a child is maximised (a double
1024 // border looks silly.)
1025 bool wxMDIChildFrame::ResetWindowStyle(void *vrect)
1026 {
1027 #if defined(__WIN95__)
1028 RECT *rect = (RECT *)vrect;
1029 wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
1030 wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild();
1031 if (!pChild || (pChild == this))
1032 {
1033 DWORD dwStyle = ::GetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE);
1034 DWORD dwThisStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE);
1035 DWORD dwNewStyle = dwStyle;
1036 if (pChild != NULL && (dwThisStyle & WS_MAXIMIZE))
1037 dwNewStyle &= ~(WS_EX_CLIENTEDGE);
1038 else
1039 dwNewStyle |= WS_EX_CLIENTEDGE;
1040
1041 if (dwStyle != dwNewStyle)
1042 {
1043 ::RedrawWindow((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
1044 ::SetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE, dwNewStyle);
1045 ::SetWindowPos((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, 0, 0, 0, 0,
1046 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS);
1047 if (rect)
1048 ::GetClientRect((HWND) pFrameWnd->GetClientWindow()->GetHWND(), rect);
1049 return TRUE;
1050 }
1051 }
1052 return FALSE;
1053 #else
1054 return FALSE;
1055 #endif
1056 }
1057
1058 void wxMDIChildFrame::MSWOnWindowPosChanging(void *pos)
1059 {
1060 WINDOWPOS *lpPos = (WINDOWPOS *)pos;
1061 #if defined(__WIN95__)
1062 if (!(lpPos->flags & SWP_NOSIZE))
1063 {
1064 RECT rectClient;
1065 DWORD dwExStyle = ::GetWindowLong((HWND) GetHWND(), GWL_EXSTYLE);
1066 DWORD dwStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE);
1067 if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE))
1068 {
1069 ::AdjustWindowRectEx(&rectClient, dwStyle, FALSE, dwExStyle);
1070 lpPos->x = rectClient.left;
1071 lpPos->y = rectClient.top;
1072 lpPos->cx = rectClient.right - rectClient.left;
1073 lpPos->cy = rectClient.bottom - rectClient.top;
1074 }
1075 wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
1076 if (pFrameWnd && pFrameWnd->GetToolBar())
1077 {
1078 pFrameWnd->GetToolBar()->Refresh();
1079 }
1080 }
1081 #endif
1082 Default();
1083 }
1084
1085 // Client window
1086 wxMDIClientWindow::wxMDIClientWindow(void)
1087 {
1088 m_scrollX = 0;
1089 m_scrollY = 0;
1090 }
1091
1092 wxMDIClientWindow::~wxMDIClientWindow(void)
1093 {
1094 }
1095
1096 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
1097 {
1098 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE);
1099
1100 CLIENTCREATESTRUCT ccs;
1101 m_windowStyle = style;
1102 m_windowParent = parent;
1103
1104 ccs.hWindowMenu = (HMENU) parent->GetWindowMenu();
1105 ccs.idFirstChild = wxFIRST_MDI_CHILD;
1106
1107 DWORD msStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN ;
1108 if ( parent->GetWindowStyleFlag() & wxHSCROLL )
1109 msStyle |= WS_HSCROLL;
1110 if ( parent->GetWindowStyleFlag() & wxVSCROLL )
1111 msStyle |= WS_VSCROLL ;
1112
1113 #if defined(__WIN95__)
1114 DWORD exStyle = WS_EX_CLIENTEDGE;
1115 #else
1116 DWORD exStyle = 0;
1117 #endif
1118
1119 wxWndHook = this;
1120 m_hWnd = (WXHWND) ::CreateWindowEx(exStyle, "mdiclient", NULL,
1121 msStyle, 0, 0, 0, 0, (HWND) parent->GetHWND(), NULL,
1122 wxGetInstance(), (LPSTR)(LPCLIENTCREATESTRUCT)&ccs);
1123 SubclassWin(m_hWnd);
1124 wxWndHook = NULL;
1125
1126 return (m_hWnd != 0) ;
1127 }
1128
1129 // Window procedure: here for debugging purposes
1130 long wxMDIClientWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1131 {
1132 return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
1133 // return MSWDefWindowProc(nMsg, wParam, lParam);
1134 }
1135
1136 long wxMDIClientWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1137 {
1138 if ( MSWGetOldWndProc() != 0)
1139 return ::CallWindowProc(CASTWNDPROC MSWGetOldWndProc(), (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
1140 else
1141 return ::DefWindowProc((HWND) m_hWnd, (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
1142 }
1143
1144 // Explicitly call default scroll behaviour
1145 void wxMDIClientWindow::OnScroll(wxScrollEvent& event)
1146 {
1147 // Note: for client windows, the scroll position is not set in
1148 // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what
1149 // scroll position we're at.
1150 // This makes it hard to paint patterns or bitmaps in the background,
1151 // and have the client area scrollable as well.
1152
1153 if ( event.GetOrientation() == wxHORIZONTAL )
1154 m_scrollX = event.GetPosition(); // Always returns zero!
1155 else
1156 m_scrollY = event.GetPosition(); // Always returns zero!
1157
1158 Default();
1159 }
1160
1161 // Should hand the message to the default proc
1162 long wxMDIClientWindow::MSWOnMDIActivate(long bActivate, WXHWND, WXHWND)
1163 {
1164 return Default();
1165 }
1166