1 /////////////////////////////////////////////////////////////////////////////
4 // Author: David Webster
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
21 #include "wx/dialog.h"
22 #include "wx/settings.h"
23 #include "wx/dcclient.h"
26 #include "wx/os2/private.h"
27 #include "wx/statusbr.h"
28 #include "wx/toolbar.h"
29 #include "wx/menuitem.h"
32 extern wxWindowList wxModelessWindows
;
33 extern wxList WXDLLEXPORT wxPendingDelete
;
34 extern wxChar wxFrameClassName
[];
35 extern wxMenu
*wxCurrentPopupMenu
;
37 #if !USE_SHARED_LIBRARY
38 BEGIN_EVENT_TABLE(wxFrame
, wxWindow
)
39 EVT_SIZE(wxFrame::OnSize
)
40 EVT_ACTIVATE(wxFrame::OnActivate
)
41 EVT_MENU_HIGHLIGHT_ALL(wxFrame::OnMenuHighlight
)
42 EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged
)
43 EVT_IDLE(wxFrame::OnIdle
)
44 EVT_CLOSE(wxFrame::OnCloseWindow
)
47 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxWindow
)
50 bool wxFrame::m_useNativeStatusBar
= FALSE
;
54 m_frameToolBar
= NULL
;
55 m_frameMenuBar
= NULL
;
56 m_frameStatusBar
= NULL
;
61 bool wxFrame::Create( wxWindow
*parent
63 ,const wxString
& title
75 m_windowStyle
= style
;
76 m_frameMenuBar
= NULL
;
77 m_frameToolBar
= NULL
;
78 m_frameStatusBar
= NULL
;
80 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
86 m_windowId
= (int)NewControlId();
88 if (parent
) parent
->AddChild(this);
97 if ((m_windowStyle
& wxFRAME_FLOAT_ON_PARENT
) == 0)
101 wxTopLevelWindows
.Append(this);
103 OS2Create(m_windowId
, parent
, wxFrameClassName
, this, title
,
104 x
, y
, width
, height
, style
);
106 wxModelessWindows
.Append(this);
112 m_isBeingDeleted
= TRUE
;
113 wxTopLevelWindows
.DeleteObject(this);
115 if (m_frameStatusBar
)
116 delete m_frameStatusBar
;
118 delete m_frameMenuBar
;
120 if (wxTheApp
&& (wxTopLevelWindows
.Number() == 0))
122 wxTheApp
->SetTopWindow(NULL
);
124 if (wxTheApp
->GetExitOnFrameDelete())
126 // TODO: PostQuitMessage(0);
131 wxModelessWindows
.DeleteObject(this);
133 // For some reason, wxWindows can activate another task altogether
134 // when a frame is destroyed after a modal dialog has been invoked.
135 // Try to bring the parent to the top.
136 // MT:Only do this if this frame is currently the active window, else weird
137 // things start to happen
138 if ( wxGetActiveWindow() == this )
139 if (GetParent() && GetParent()->GetHWND())
140 // TODO: OS/2 PM version
141 // ::BringWindowToTop((HWND) GetParent()->GetHWND());
145 // Get size *available for subwindows* i.e. excluding menu bar, toolbar etc.
146 void wxFrame::DoGetClientSize(int *x
, int *y
) const
149 //TODO: ::GetClientRect(GetHwnd(), &rect);
151 if ( GetStatusBar() )
153 int statusX
, statusY
;
154 GetStatusBar()->GetClientSize(&statusX
, &statusY
);
155 // TODO: OS/2's rect rect.bottom -= statusY;
158 wxPoint
pt(GetClientAreaOrigin());
170 // Set the client size (i.e. leave the calculation of borders etc.
172 void wxFrame::DoSetClientSize(int width
, int height
)
174 HWND hWnd
= GetHwnd();
177 // TODO: ::GetClientRect(hWnd, &rect);
180 //TODO: ::GetWindowRect(hWnd, &rect2);
182 // Find the difference between the entire window (title bar and all)
183 // and the client area; add this to the new client size to move the
186 int actual_width = rect2.right - rect2.left - rect.right + width;
187 int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
189 if ( GetStatusBar() )
191 int statusX
, statusY
;
192 GetStatusBar()->GetClientSize(&statusX
, &statusY
);
193 // actual_height += statusY;
196 wxPoint pt(GetClientAreaOrigin());
197 actual_width += pt.y;
198 actual_height += pt.x;
202 point.x = rect2.left;
205 MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE);
207 wxSizeEvent
event(wxSize(width
, height
), m_windowId
);
208 event
.SetEventObject( this );
209 GetEventHandler()->ProcessEvent(event
);
212 void wxFrame::DoGetSize(int *width
, int *height
) const
215 // TODO: ::GetWindowRect(GetHwnd(), &rect);
216 // *width = rect.right - rect.left;
217 // *height = rect.bottom - rect.top;
220 void wxFrame::DoGetPosition(int *x
, int *y
) const
223 // TODO: ::GetWindowRect(GetHwnd(), &rect);
225 // point.x = rect.left;
226 // point.y = rect.top;
232 bool wxFrame::Show(bool show
)
243 // Try to highlight the correct window (the parent)
247 hWndParent
= (HWND
) GetParent()->GetHWND();
249 // TODO: ::BringWindowToTop(hWndParent);
250 cshow
= (int)show
; // just to have something here, remove
254 // TODO: ::ShowWindow(GetHwnd(), (BOOL)cshow);
257 // TODO: ::BringWindowToTop(GetHwnd());
259 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, m_windowId
);
260 event
.SetEventObject( this );
261 GetEventHandler()->ProcessEvent(event
);
266 void wxFrame::Iconize(bool iconize
)
277 ShowWindow(GetHwnd(), (BOOL)cshow);
279 m_iconized
= iconize
;
282 // Equivalent to maximize/restore in Windows
283 void wxFrame::Maximize(bool maximize
)
292 ShowWindow(GetHwnd(), cshow);
297 bool wxFrame::IsIconized() const
299 // TODO: ((wxFrame *)this)->m_iconized = (::IsIconic(GetHwnd()) != 0);
304 bool wxFrame::IsMaximized() const
306 //TODO: return (::IsZoomed(GetHwnd()) != 0) ;
307 return FALSE
; // remove
310 void wxFrame::SetIcon(const wxIcon
& icon
)
316 wxStatusBar
*wxFrame::OnCreateStatusBar(int number
, long style
, wxWindowID id
,
317 const wxString
& name
)
319 wxStatusBar
*statusBar
= NULL
;
321 statusBar
= new wxStatusBar(this, id
, wxPoint(0, 0), wxSize(100, 20),
324 // Set the height according to the font and the border size
325 wxClientDC
dc(statusBar
);
326 dc
.SetFont(statusBar
->GetFont());
329 dc
.GetTextExtent("X", &x
, &y
);
331 int height
= (int)( (y
* 1.1) + 2* statusBar
->GetBorderY());
332 statusBar
->SetSize(-1, -1, 100, height
);
333 statusBar
->SetFieldsCount(number
);
337 wxStatusBar
* wxFrame::CreateStatusBar(int number
, long style
, wxWindowID id
,
338 const wxString
& name
)
340 // VZ: calling CreateStatusBar twice is an error - why anyone would do it?
341 wxCHECK_MSG( m_frameStatusBar
== NULL
, FALSE
,
342 T("recreating status bar in wxFrame") );
344 m_frameStatusBar
= OnCreateStatusBar(number
, style
, id
,
346 if ( m_frameStatusBar
)
349 return m_frameStatusBar
;
355 void wxFrame::SetStatusText(const wxString
& text
, int number
)
357 wxCHECK_RET( m_frameStatusBar
!= NULL
, T("no statusbar to set text for") );
359 m_frameStatusBar
->SetStatusText(text
, number
);
362 void wxFrame::SetStatusWidths(int n
, const int widths_field
[])
364 wxCHECK_RET( m_frameStatusBar
!= NULL
, T("no statusbar to set widths for") );
366 m_frameStatusBar
->SetStatusWidths(n
, widths_field
);
370 void wxFrame::PositionStatusBar()
372 // native status bar positions itself
373 if (m_frameStatusBar
)
376 GetClientSize(&w
, &h
);
378 m_frameStatusBar
->GetSize(&sw
, &sh
);
380 // Since we wish the status bar to be directly under the client area,
381 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
382 m_frameStatusBar
->SetSize(0, h
, w
, sh
);
385 #endif // wxUSE_STATUSBAR
387 void wxFrame::DetachMenuBar()
391 // Fix this in wxMenuBar m_frameMenuBar->Detach();
392 m_frameMenuBar
= NULL
;
396 void wxFrame::SetMenuBar(wxMenuBar
*menu_bar
)
404 // Fix this in wxMenuBar wxCHECK_RET( !menu_bar->GetFrame(), T("this menubar is already attached") );
407 delete m_frameMenuBar
;
409 // Fix this in wxMenuBar m_hMenu = menu_bar->Create();
414 InternalSetMenuBar();
416 m_frameMenuBar
= menu_bar
;
417 // Fix this in wxMenuBar menu_bar->Attach(this);
420 void wxFrame::InternalSetMenuBar()
423 /* if ( !::SetMenu(GetHwnd(), (HMENU)m_hMenu) )
425 wxLogLastError("SetMenu");
430 // Responds to colour changes, and passes event on to children.
431 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
433 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
436 if ( m_frameStatusBar
)
438 wxSysColourChangedEvent event2
;
439 event2
.SetEventObject( m_frameStatusBar
);
440 m_frameStatusBar
->GetEventHandler()->ProcessEvent(event2
);
443 // Propagate the event to the non-top-level children
444 wxWindow::OnSysColourChanged(event
);
452 bool wxFrame::OS2Create(int id
, wxWindow
*parent
, const wxChar
*wclass
, wxWindow
*wx_win
, const wxChar
*title
,
453 int x
, int y
, int width
, int height
, long style
)
456 m_defaultIcon
= (WXHICON
) (wxSTD_FRAME_ICON
? wxSTD_FRAME_ICON
: wxDEFAULT_FRAME_ICON
);
458 // If child windows aren't properly drawn initially, WS_CLIPCHILDREN
459 // could be the culprit. But without it, you can get a lot of flicker.
463 if ((style & wxCAPTION) == wxCAPTION)
464 msflags = WS_OVERLAPPED;
468 if (style & wxMINIMIZE_BOX)
469 msflags |= WS_MINIMIZEBOX;
470 if (style & wxMAXIMIZE_BOX)
471 msflags |= WS_MAXIMIZEBOX;
472 if (style & wxTHICK_FRAME)
473 msflags |= WS_THICKFRAME;
474 if (style & wxSYSTEM_MENU)
475 msflags |= WS_SYSMENU;
476 if ((style & wxMINIMIZE) || (style & wxICONIZE))
477 msflags |= WS_MINIMIZE;
478 if (style & wxMAXIMIZE)
479 msflags |= WS_MAXIMIZE;
480 if (style & wxCAPTION)
481 msflags |= WS_CAPTION;
482 if (style & wxCLIP_CHILDREN)
483 msflags |= WS_CLIPCHILDREN;
485 // Keep this in wxFrame because it saves recoding this function
488 if (style & wxTINY_CAPTION_VERT)
489 msflags |= IBS_VERTCAPTION;
490 if (style & wxTINY_CAPTION_HORIZ)
491 msflags |= IBS_HORZCAPTION;
493 if (style & wxTINY_CAPTION_VERT)
494 msflags |= WS_CAPTION;
495 if (style & wxTINY_CAPTION_HORIZ)
496 msflags |= WS_CAPTION;
498 if ((style & wxTHICK_FRAME) == 0)
499 msflags |= WS_BORDER;
501 WXDWORD extendedStyle = MakeExtendedStyle(style);
503 #if !defined(__WIN16__) && !defined(__SC__)
504 if (style & wxFRAME_TOOL_WINDOW)
505 extendedStyle |= WS_EX_TOOLWINDOW;
508 if (style & wxSTAY_ON_TOP)
509 extendedStyle |= WS_EX_TOPMOST;
512 if ( !wxWindow::OS2Create(id, parent, wclass, wx_win, title, x, y, width, height,
513 msflags, NULL, extendedStyle) )
516 // Seems to be necessary if we use WS_POPUP
517 // style instead of WS_OVERLAPPED
518 if (width > -1 && height > -1)
519 ::PostMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED, MAKELPARAM(width, height));
524 // Default resizing behaviour - if only ONE subwindow, resize to client
526 void wxFrame::OnSize(wxSizeEvent
& event
)
528 // if we're using constraints - do use them
529 #if wxUSE_CONSTRAINTS
530 if ( GetAutoLayout() )
537 // do we have _exactly_ one child?
538 wxWindow
*child
= NULL
;
539 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
541 node
= node
->GetNext() )
543 wxWindow
*win
= node
->GetData();
544 if ( !win
->IsTopLevel()
546 && (win
!= GetStatusBar())
547 #endif // wxUSE_STATUSBAR
549 && (win
!= GetToolBar())
550 #endif // wxUSE_TOOLBAR
554 return; // it's our second subwindow - nothing to do
560 // we have exactly one child - set it's size to fill the whole frame
561 int clientW
, clientH
;
562 GetClientSize(&clientW
, &clientH
);
567 child
->SetSize(x
, y
, clientW
, clientH
);
571 // Default activation behaviour - set the focus for the first child
573 void wxFrame::OnActivate(wxActivateEvent
& event
)
575 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
577 node
= node
->GetNext() )
579 // FIXME all this is totally bogus - we need to do the same as wxPanel,
580 // but how to do it without duplicating the code?
583 wxWindow
*child
= node
->GetData();
585 if ( !child
->IsTopLevel()
587 && !wxDynamicCast(child
, wxToolBar
)
588 #endif // wxUSE_TOOLBAR
590 && !wxDynamicCast(child
, wxStatusBar
)
591 #endif // wxUSE_STATUSBAR
600 // The default implementation for the close window event.
601 void wxFrame::OnCloseWindow(wxCloseEvent
& event
)
606 // Destroy the window (delayed, if a managed window)
607 bool wxFrame::Destroy()
609 if (!wxPendingDelete
.Member(this))
610 wxPendingDelete
.Append(this);
614 // Default menu selection behaviour - display a help string
615 void wxFrame::OnMenuHighlight(wxMenuEvent
& event
)
620 int menuId
= event
.GetMenuId();
623 wxMenuBar
*menuBar
= GetMenuBar();
624 // Fix this in wxMenuBar
626 if (menuBar && menuBar->FindItem(menuId))
628 help = menuBar->GetHelpString(menuId);
633 // set status text even if the string is empty - this will at
634 // least remove the string from the item which was previously
640 wxMenuBar
*wxFrame::GetMenuBar() const
642 return m_frameMenuBar
;
645 bool wxFrame::ProcessCommand(int id
)
647 wxMenuBar
*bar
= GetMenuBar() ;
651 wxMenuItem
*item
= bar
->FindItemForId(id
);
653 if ( item
&& item
->IsCheckable() )
655 bar
->Check(id
, !bar
->IsChecked(id
)) ;
658 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
659 commandEvent
.SetInt( id
);
660 commandEvent
.SetEventObject( this );
662 return GetEventHandler()->ProcessEvent(commandEvent
);
665 // Checks if there is a toolbar, and returns the first free client position
666 wxPoint
wxFrame::GetClientAreaOrigin() const
672 GetToolBar()->GetSize(& w
, & h
);
674 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL
)
686 void wxFrame::ScreenToClient(int *x
, int *y
) const
688 wxWindow::ScreenToClient(x
, y
);
690 // We may be faking the client origin.
691 // So a window that's really at (0, 30) may appear
692 // (to wxWin apps) to be at (0, 0).
693 wxPoint
pt(GetClientAreaOrigin());
698 void wxFrame::ClientToScreen(int *x
, int *y
) const
700 // We may be faking the client origin.
701 // So a window that's really at (0, 30) may appear
702 // (to wxWin apps) to be at (0, 0).
703 wxPoint
pt1(GetClientAreaOrigin());
707 wxWindow::ClientToScreen(x
, y
);
711 wxToolBar
* wxFrame::CreateToolBar(long style
, wxWindowID id
, const wxString
& name
)
713 wxCHECK_MSG( m_frameToolBar
== NULL
, FALSE
,
714 T("recreating toolbar in wxFrame") );
716 wxToolBar
* toolBar
= OnCreateToolBar(style
, id
, name
);
729 wxToolBar
* wxFrame::OnCreateToolBar(long style
, wxWindowID id
, const wxString
& name
)
731 return new wxToolBar(this, id
, wxDefaultPosition
, wxDefaultSize
, style
, name
);
734 void wxFrame::PositionToolBar()
737 // TODO: ::GetClientRect(GetHwnd(), &rect);
739 if ( GetStatusBar() )
741 int statusX
, statusY
;
742 GetStatusBar()->GetClientSize(&statusX
, &statusY
);
743 // TODO: rect.bottom -= statusY;
749 GetToolBar()->GetSize(& tw
, & th
);
751 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL
)
753 // Use the 'real' MSW position
754 GetToolBar()->SetSize(0, 0, tw
, rect
.yBottom
, wxSIZE_NO_ADJUSTMENTS
);
758 // Use the 'real' MSW position
759 GetToolBar()->SetSize(0, 0, rect
.xRight
, th
, wxSIZE_NO_ADJUSTMENTS
);
763 #endif // wxUSE_TOOLBAR
765 // propagate our state change to all child frames: this allows us to emulate X
766 // Windows behaviour where child frames float independently of the parent one
767 // on the desktop, but are iconized/restored with it
768 void wxFrame::IconizeChildFrames(bool bIconize
)
770 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
772 node
= node
->GetNext() )
774 wxWindow
*win
= node
->GetData();
776 if ( win
->IsKindOf(CLASSINFO(wxFrame
)) )
778 ((wxFrame
*)win
)->Iconize(bIconize
);
784 // make the window modal (all other windows unresponsive)
785 void wxFrame::MakeModal(bool modal
)
788 wxEnableTopLevelWindows(FALSE
);
789 Enable(TRUE
); // keep this window enabled
792 wxEnableTopLevelWindows(TRUE
);
797 // ===========================================================================
798 // message processing
799 // ===========================================================================
801 // ---------------------------------------------------------------------------
803 // ---------------------------------------------------------------------------
805 bool wxFrame::OS2TranslateMessage(WXMSG
* pMsg
)
807 // TODO: if ( wxWindow::OS2TranslateMessage(pMsg) )
810 // try the menu bar accels
811 wxMenuBar
*menuBar
= GetMenuBar();
815 // TODO: const wxAcceleratorTable& acceleratorTable = menuBar->GetAccelTable();
816 // return acceleratorTable.Translate(this, pMsg);
820 // ---------------------------------------------------------------------------
821 // our private (non virtual) message handlers
822 // ---------------------------------------------------------------------------
824 bool wxFrame::HandlePaint()
828 // if ( GetUpdateRect(GetHwnd(), &rect, FALSE) )
832 // HICON hIcon = m_icon.Ok() ? GetHiconOf(m_icon)
833 // : (HICON)m_defaultIcon;
835 // Hold a pointer to the dc so long as the OnPaint() message
836 // is being processed
839 // HDC hdc = ::BeginPaint(GetHwnd(), &ps);
840 // // Erase background before painting or we get white background
841 // OS2DefWindowProc(WM_ICONERASEBKGND, (WORD)(LONG)ps.hdc, 0L);
846 // TODO: ::GetClientRect(GetHwnd(), &rect);
848 // FIXME: why hardcoded?
849 // static const int icon_width = 32;
850 // static const int icon_height = 32;
852 // int icon_x = (int)((rect.right - icon_width)/2);
853 // int icon_y = (int)((rect.bottom - icon_height)/2);
855 // TODO: ::DrawIcon(hdc, icon_x, icon_y, hIcon);
858 // TODO: ::EndPaint(GetHwnd(), &ps);
864 // return wxWindow::HandlePaint();
869 // // nothing to paint - processed
875 bool wxFrame::HandleSize(int x
, int y
, WXUINT id
)
877 bool processed
= FALSE
;
882 // only do it it if we were iconized before, otherwise resizing the
883 // parent frame has a curious side effect of bringing it under it's
888 // restore all child frames too
889 IconizeChildFrames(FALSE);
898 // iconize all child frames too
899 IconizeChildFrames(TRUE);
910 wxSizeEvent
event(wxSize(x
, y
), m_windowId
);
911 event
.SetEventObject( this );
912 processed
= GetEventHandler()->ProcessEvent(event
);
918 bool wxFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND control
)
922 // In case it's e.g. a toolbar.
923 wxWindow
*win
= wxFindWinFromHandle(control
);
925 // TODO: return win->OS2Command(cmd, id);
929 // handle here commands from menus and accelerators
930 if ( cmd
== 0 || cmd
== 1 )
932 if ( wxCurrentPopupMenu
)
934 wxMenu
*popupMenu
= wxCurrentPopupMenu
;
935 wxCurrentPopupMenu
= NULL
;
937 // return popupMenu->OS2Command(cmd, id);
941 if ( ProcessCommand(id
) )
950 bool wxFrame::HandleMenuSelect(WXWORD nItem
, WXWORD flags
, WXHMENU hMenu
)
953 if ( flags
== 0xFFFF && hMenu
== 0 )
955 // menu was removed from screen
959 else if ( !(flags & MF_POPUP) && !(flags & MF_SEPARATOR) )
966 // don't give hints for separators (doesn't make sense) nor for the
967 // items opening popup menus (they don't have them anyhow)
971 wxMenuEvent
event(wxEVT_MENU_HIGHLIGHT
, item
);
972 event
.SetEventObject( this );
974 return GetEventHandler()->ProcessEvent(event
);
977 // ---------------------------------------------------------------------------
978 // the window proc for wxFrame
979 // ---------------------------------------------------------------------------
981 MRESULT
wxFrame::OS2WindowProc(HWND hwnd
, WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
984 bool processed
= FALSE
;
991 // if we can't close, tell the system that we processed the
992 // message - otherwise it would close us
993 processed = !Close();
1000 UnpackCommand((WXWPARAM)wParam, (WXLPARAM)lParam,
1003 processed = HandleCommand(id, cmd, (WXHWND)hwnd);
1011 UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu);
1013 processed = HandleMenuSelect(item, flags, hmenu);
1018 processed = HandlePaint();
1021 case WM_QUERYDRAGICON:
1023 HICON hIcon = m_icon.Ok() ? GetHiconOf(m_icon)
1024 : (HICON)(m_defaultIcon);
1026 processed = rc != 0;
1031 processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
1036 rc
= wxWindow::OS2WindowProc(hwnd
, message
, wParam
, lParam
);