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
;
55 m_frameToolBar
= NULL
;
57 m_frameMenuBar
= NULL
;
58 m_frameStatusBar
= NULL
;
63 bool wxFrame::Create( wxWindow
*parent
65 ,const wxString
& title
77 m_windowStyle
= style
;
78 m_frameMenuBar
= NULL
;
80 m_frameToolBar
= NULL
;
82 m_frameStatusBar
= NULL
;
84 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
90 m_windowId
= (int)NewControlId();
92 if (parent
) parent
->AddChild(this);
101 if ((m_windowStyle
& wxFRAME_FLOAT_ON_PARENT
) == 0)
105 wxTopLevelWindows
.Append(this);
107 OS2Create(m_windowId
, parent
, wxFrameClassName
, this, title
,
108 x
, y
, width
, height
, style
);
110 wxModelessWindows
.Append(this);
116 m_isBeingDeleted
= TRUE
;
117 wxTopLevelWindows
.DeleteObject(this);
119 if (m_frameStatusBar
)
120 delete m_frameStatusBar
;
122 delete m_frameMenuBar
;
124 if (wxTheApp
&& (wxTopLevelWindows
.Number() == 0))
126 wxTheApp
->SetTopWindow(NULL
);
128 if (wxTheApp
->GetExitOnFrameDelete())
130 // TODO: PostQuitMessage(0);
135 wxModelessWindows
.DeleteObject(this);
137 // For some reason, wxWindows can activate another task altogether
138 // when a frame is destroyed after a modal dialog has been invoked.
139 // Try to bring the parent to the top.
140 // MT:Only do this if this frame is currently the active window, else weird
141 // things start to happen
142 if ( wxGetActiveWindow() == this )
143 if (GetParent() && GetParent()->GetHWND())
144 // TODO: OS/2 PM version
145 // ::BringWindowToTop((HWND) GetParent()->GetHWND());
149 // Get size *available for subwindows* i.e. excluding menu bar, toolbar etc.
150 void wxFrame::DoGetClientSize(int *x
, int *y
) const
153 //TODO: ::GetClientRect(GetHwnd(), &rect);
155 if ( GetStatusBar() )
157 int statusX
, statusY
;
158 GetStatusBar()->GetClientSize(&statusX
, &statusY
);
159 // TODO: OS/2's rect rect.bottom -= statusY;
162 wxPoint
pt(GetClientAreaOrigin());
174 // Set the client size (i.e. leave the calculation of borders etc.
176 void wxFrame::DoSetClientSize(int width
, int height
)
178 HWND hWnd
= GetHwnd();
181 // TODO: ::GetClientRect(hWnd, &rect);
184 //TODO: ::GetWindowRect(hWnd, &rect2);
186 // Find the difference between the entire window (title bar and all)
187 // and the client area; add this to the new client size to move the
190 int actual_width = rect2.right - rect2.left - rect.right + width;
191 int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
193 if ( GetStatusBar() )
195 int statusX
, statusY
;
196 GetStatusBar()->GetClientSize(&statusX
, &statusY
);
197 // actual_height += statusY;
200 wxPoint pt(GetClientAreaOrigin());
201 actual_width += pt.y;
202 actual_height += pt.x;
206 point.x = rect2.left;
209 MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE);
211 wxSizeEvent
event(wxSize(width
, height
), m_windowId
);
212 event
.SetEventObject( this );
213 GetEventHandler()->ProcessEvent(event
);
216 void wxFrame::DoGetSize(int *width
, int *height
) const
219 // TODO: ::GetWindowRect(GetHwnd(), &rect);
220 // *width = rect.right - rect.left;
221 // *height = rect.bottom - rect.top;
224 void wxFrame::DoGetPosition(int *x
, int *y
) const
227 // TODO: ::GetWindowRect(GetHwnd(), &rect);
229 // point.x = rect.left;
230 // point.y = rect.top;
236 bool wxFrame::Show(bool show
)
247 // Try to highlight the correct window (the parent)
251 hWndParent
= (HWND
) GetParent()->GetHWND();
253 // TODO: ::BringWindowToTop(hWndParent);
254 cshow
= (int)show
; // just to have something here, remove
258 // TODO: ::ShowWindow(GetHwnd(), (BOOL)cshow);
261 // TODO: ::BringWindowToTop(GetHwnd());
263 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, m_windowId
);
264 event
.SetEventObject( this );
265 GetEventHandler()->ProcessEvent(event
);
270 void wxFrame::Iconize(bool iconize
)
281 ShowWindow(GetHwnd(), (BOOL)cshow);
283 m_iconized
= iconize
;
286 // Equivalent to maximize/restore in Windows
287 void wxFrame::Maximize(bool maximize
)
296 ShowWindow(GetHwnd(), cshow);
301 bool wxFrame::IsIconized() const
303 // TODO: ((wxFrame *)this)->m_iconized = (::IsIconic(GetHwnd()) != 0);
308 bool wxFrame::IsMaximized() const
310 //TODO: return (::IsZoomed(GetHwnd()) != 0) ;
311 return FALSE
; // remove
314 void wxFrame::SetIcon(const wxIcon
& icon
)
320 wxStatusBar
*wxFrame::OnCreateStatusBar(int number
, long style
, wxWindowID id
,
321 const wxString
& name
)
323 wxStatusBar
*statusBar
= NULL
;
325 statusBar
= new wxStatusBar(this, id
, wxPoint(0, 0), wxSize(100, 20),
328 // Set the height according to the font and the border size
329 wxClientDC
dc(statusBar
);
330 dc
.SetFont(statusBar
->GetFont());
333 dc
.GetTextExtent("X", &x
, &y
);
335 int height
= (int)( (y
* 1.1) + 2* statusBar
->GetBorderY());
336 statusBar
->SetSize(-1, -1, 100, height
);
337 statusBar
->SetFieldsCount(number
);
341 wxStatusBar
* wxFrame::CreateStatusBar(int number
, long style
, wxWindowID id
,
342 const wxString
& name
)
344 // VZ: calling CreateStatusBar twice is an error - why anyone would do it?
345 wxCHECK_MSG( m_frameStatusBar
== NULL
, FALSE
,
346 wxT("recreating status bar in wxFrame") );
348 m_frameStatusBar
= OnCreateStatusBar(number
, style
, id
,
350 if ( m_frameStatusBar
)
353 return m_frameStatusBar
;
359 void wxFrame::SetStatusText(const wxString
& text
, int number
)
361 wxCHECK_RET( m_frameStatusBar
!= NULL
, wxT("no statusbar to set text for") );
363 m_frameStatusBar
->SetStatusText(text
, number
);
366 void wxFrame::SetStatusWidths(int n
, const int widths_field
[])
368 wxCHECK_RET( m_frameStatusBar
!= NULL
, wxT("no statusbar to set widths for") );
370 m_frameStatusBar
->SetStatusWidths(n
, widths_field
);
374 void wxFrame::PositionStatusBar()
376 // native status bar positions itself
377 if (m_frameStatusBar
)
380 GetClientSize(&w
, &h
);
382 m_frameStatusBar
->GetSize(&sw
, &sh
);
384 // Since we wish the status bar to be directly under the client area,
385 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
386 m_frameStatusBar
->SetSize(0, h
, w
, sh
);
389 #endif // wxUSE_STATUSBAR
391 void wxFrame::DetachMenuBar()
395 // Fix this in wxMenuBar m_frameMenuBar->Detach();
396 m_frameMenuBar
= NULL
;
400 void wxFrame::SetMenuBar(wxMenuBar
*menu_bar
)
408 // Fix this in wxMenuBar wxCHECK_RET( !menu_bar->GetFrame(), wxT("this menubar is already attached") );
411 delete m_frameMenuBar
;
413 // Fix this in wxMenuBar m_hMenu = menu_bar->Create();
418 InternalSetMenuBar();
420 m_frameMenuBar
= menu_bar
;
421 // Fix this in wxMenuBar menu_bar->Attach(this);
424 void wxFrame::InternalSetMenuBar()
427 /* if ( !::SetMenu(GetHwnd(), (HMENU)m_hMenu) )
429 wxLogLastError("SetMenu");
434 // Responds to colour changes, and passes event on to children.
435 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
437 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
440 if ( m_frameStatusBar
)
442 wxSysColourChangedEvent event2
;
443 event2
.SetEventObject( m_frameStatusBar
);
444 m_frameStatusBar
->GetEventHandler()->ProcessEvent(event2
);
447 // Propagate the event to the non-top-level children
448 wxWindow::OnSysColourChanged(event
);
456 bool wxFrame::OS2Create(int id
, wxWindow
*parent
, const wxChar
*wclass
, wxWindow
*wx_win
, const wxChar
*title
,
457 int x
, int y
, int width
, int height
, long style
)
460 m_defaultIcon
= (WXHICON
) (wxSTD_FRAME_ICON
? wxSTD_FRAME_ICON
: wxDEFAULT_FRAME_ICON
);
462 // If child windows aren't properly drawn initially, WS_CLIPCHILDREN
463 // could be the culprit. But without it, you can get a lot of flicker.
467 if ((style & wxCAPTION) == wxCAPTION)
468 msflags = WS_OVERLAPPED;
472 if (style & wxMINIMIZE_BOX)
473 msflags |= WS_MINIMIZEBOX;
474 if (style & wxMAXIMIZE_BOX)
475 msflags |= WS_MAXIMIZEBOX;
476 if (style & wxTHICK_FRAME)
477 msflags |= WS_THICKFRAME;
478 if (style & wxSYSTEM_MENU)
479 msflags |= WS_SYSMENU;
480 if ((style & wxMINIMIZE) || (style & wxICONIZE))
481 msflags |= WS_MINIMIZE;
482 if (style & wxMAXIMIZE)
483 msflags |= WS_MAXIMIZE;
484 if (style & wxCAPTION)
485 msflags |= WS_CAPTION;
486 if (style & wxCLIP_CHILDREN)
487 msflags |= WS_CLIPCHILDREN;
489 // Keep this in wxFrame because it saves recoding this function
492 if (style & wxTINY_CAPTION_VERT)
493 msflags |= IBS_VERTCAPTION;
494 if (style & wxTINY_CAPTION_HORIZ)
495 msflags |= IBS_HORZCAPTION;
497 if (style & wxTINY_CAPTION_VERT)
498 msflags |= WS_CAPTION;
499 if (style & wxTINY_CAPTION_HORIZ)
500 msflags |= WS_CAPTION;
502 if ((style & wxTHICK_FRAME) == 0)
503 msflags |= WS_BORDER;
505 WXDWORD extendedStyle = MakeExtendedStyle(style);
507 #if !defined(__WIN16__) && !defined(__SC__)
508 if (style & wxFRAME_TOOL_WINDOW)
509 extendedStyle |= WS_EX_TOOLWINDOW;
512 if (style & wxSTAY_ON_TOP)
513 extendedStyle |= WS_EX_TOPMOST;
516 if ( !wxWindow::OS2Create(id, parent, wclass, wx_win, title, x, y, width, height,
517 msflags, NULL, extendedStyle) )
520 // Seems to be necessary if we use WS_POPUP
521 // style instead of WS_OVERLAPPED
522 if (width > -1 && height > -1)
523 ::PostMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED, MAKELPARAM(width, height));
528 // Default resizing behaviour - if only ONE subwindow, resize to client
530 void wxFrame::OnSize(wxSizeEvent
& event
)
532 // if we're using constraints - do use them
533 #if wxUSE_CONSTRAINTS
534 if ( GetAutoLayout() )
541 // do we have _exactly_ one child?
542 wxWindow
*child
= NULL
;
543 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
545 node
= node
->GetNext() )
547 wxWindow
*win
= node
->GetData();
548 if ( !win
->IsTopLevel()
550 && (win
!= GetStatusBar())
551 #endif // wxUSE_STATUSBAR
553 && (win
!= GetToolBar())
554 #endif // wxUSE_TOOLBAR
558 return; // it's our second subwindow - nothing to do
564 // we have exactly one child - set it's size to fill the whole frame
565 int clientW
, clientH
;
566 GetClientSize(&clientW
, &clientH
);
571 child
->SetSize(x
, y
, clientW
, clientH
);
575 // Default activation behaviour - set the focus for the first child
577 void wxFrame::OnActivate(wxActivateEvent
& event
)
579 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
581 node
= node
->GetNext() )
583 // FIXME all this is totally bogus - we need to do the same as wxPanel,
584 // but how to do it without duplicating the code?
587 wxWindow
*child
= node
->GetData();
589 if ( !child
->IsTopLevel()
591 && !wxDynamicCast(child
, wxToolBar
)
592 #endif // wxUSE_TOOLBAR
594 && !wxDynamicCast(child
, wxStatusBar
)
595 #endif // wxUSE_STATUSBAR
604 // The default implementation for the close window event.
605 void wxFrame::OnCloseWindow(wxCloseEvent
& event
)
610 // Destroy the window (delayed, if a managed window)
611 bool wxFrame::Destroy()
613 if (!wxPendingDelete
.Member(this))
614 wxPendingDelete
.Append(this);
618 // Default menu selection behaviour - display a help string
619 void wxFrame::OnMenuHighlight(wxMenuEvent
& event
)
624 int menuId
= event
.GetMenuId();
627 wxMenuBar
*menuBar
= GetMenuBar();
628 // Fix this in wxMenuBar
630 if (menuBar && menuBar->FindItem(menuId))
632 help = menuBar->GetHelpString(menuId);
637 // set status text even if the string is empty - this will at
638 // least remove the string from the item which was previously
644 wxMenuBar
*wxFrame::GetMenuBar() const
646 return m_frameMenuBar
;
649 bool wxFrame::ProcessCommand(int id
)
651 wxMenuBar
*bar
= GetMenuBar() ;
655 wxMenuItem
*item
= bar
->FindItemForId(id
);
657 if ( item
&& item
->IsCheckable() )
659 bar
->Check(id
, !bar
->IsChecked(id
)) ;
662 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
663 commandEvent
.SetInt( id
);
664 commandEvent
.SetEventObject( this );
666 return GetEventHandler()->ProcessEvent(commandEvent
);
669 // Checks if there is a toolbar, and returns the first free client position
670 wxPoint
wxFrame::GetClientAreaOrigin() const
677 GetToolBar()->GetSize(& w
, & h
);
679 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL
)
692 void wxFrame::DoScreenToClient(int *x
, int *y
) const
694 wxWindow::ScreenToClient(x
, y
);
696 // We may be faking the client origin.
697 // So a window that's really at (0, 30) may appear
698 // (to wxWin apps) to be at (0, 0).
699 wxPoint
pt(GetClientAreaOrigin());
704 void wxFrame::DoClientToScreen(int *x
, int *y
) const
706 // We may be faking the client origin.
707 // So a window that's really at (0, 30) may appear
708 // (to wxWin apps) to be at (0, 0).
709 wxPoint
pt1(GetClientAreaOrigin());
713 wxWindow::DoClientToScreen(x
, y
);
717 wxToolBar
* wxFrame::CreateToolBar(long style
, wxWindowID id
, const wxString
& name
)
719 wxCHECK_MSG( m_frameToolBar
== NULL
, FALSE
,
720 wxT("recreating toolbar in wxFrame") );
722 wxToolBar
* toolBar
= OnCreateToolBar(style
, id
, name
);
735 wxToolBar
* wxFrame::OnCreateToolBar(long style
, wxWindowID id
, const wxString
& name
)
737 return new wxToolBar(this, id
, wxDefaultPosition
, wxDefaultSize
, style
, name
);
740 void wxFrame::PositionToolBar()
743 // TODO: ::GetClientRect(GetHwnd(), &rect);
745 if ( GetStatusBar() )
747 int statusX
, statusY
;
748 GetStatusBar()->GetClientSize(&statusX
, &statusY
);
749 // TODO: rect.bottom -= statusY;
755 GetToolBar()->GetSize(& tw
, & th
);
757 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL
)
759 // Use the 'real' MSW position
760 GetToolBar()->SetSize(0, 0, tw
, rect
.yBottom
, wxSIZE_NO_ADJUSTMENTS
);
764 // Use the 'real' MSW position
765 GetToolBar()->SetSize(0, 0, rect
.xRight
, th
, wxSIZE_NO_ADJUSTMENTS
);
769 #endif // wxUSE_TOOLBAR
771 // propagate our state change to all child frames: this allows us to emulate X
772 // Windows behaviour where child frames float independently of the parent one
773 // on the desktop, but are iconized/restored with it
774 void wxFrame::IconizeChildFrames(bool bIconize
)
776 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
778 node
= node
->GetNext() )
780 wxWindow
*win
= node
->GetData();
782 if ( win
->IsKindOf(CLASSINFO(wxFrame
)) )
784 ((wxFrame
*)win
)->Iconize(bIconize
);
790 // make the window modal (all other windows unresponsive)
791 void wxFrame::MakeModal(bool modal
)
794 wxEnableTopLevelWindows(FALSE
);
795 Enable(TRUE
); // keep this window enabled
798 wxEnableTopLevelWindows(TRUE
);
803 // ===========================================================================
804 // message processing
805 // ===========================================================================
807 // ---------------------------------------------------------------------------
809 // ---------------------------------------------------------------------------
811 bool wxFrame::OS2TranslateMessage(WXMSG
* pMsg
)
813 // TODO: if ( wxWindow::OS2TranslateMessage(pMsg) )
816 // try the menu bar accels
817 wxMenuBar
*menuBar
= GetMenuBar();
821 // TODO: const wxAcceleratorTable& acceleratorTable = menuBar->GetAccelTable();
822 // return acceleratorTable.Translate(this, pMsg);
826 // ---------------------------------------------------------------------------
827 // our private (non virtual) message handlers
828 // ---------------------------------------------------------------------------
830 bool wxFrame::HandlePaint()
834 // if ( GetUpdateRect(GetHwnd(), &rect, FALSE) )
838 // HICON hIcon = m_icon.Ok() ? GetHiconOf(m_icon)
839 // : (HICON)m_defaultIcon;
841 // Hold a pointer to the dc so long as the OnPaint() message
842 // is being processed
845 // HDC hdc = ::BeginPaint(GetHwnd(), &ps);
846 // // Erase background before painting or we get white background
847 // OS2DefWindowProc(WM_ICONERASEBKGND, (WORD)(LONG)ps.hdc, 0L);
852 // TODO: ::GetClientRect(GetHwnd(), &rect);
854 // FIXME: why hardcoded?
855 // static const int icon_width = 32;
856 // static const int icon_height = 32;
858 // int icon_x = (int)((rect.right - icon_width)/2);
859 // int icon_y = (int)((rect.bottom - icon_height)/2);
861 // TODO: ::DrawIcon(hdc, icon_x, icon_y, hIcon);
864 // TODO: ::EndPaint(GetHwnd(), &ps);
870 // return wxWindow::HandlePaint();
875 // // nothing to paint - processed
881 bool wxFrame::HandleSize(int x
, int y
, WXUINT id
)
883 bool processed
= FALSE
;
888 // only do it it if we were iconized before, otherwise resizing the
889 // parent frame has a curious side effect of bringing it under it's
894 // restore all child frames too
895 IconizeChildFrames(FALSE);
904 // iconize all child frames too
905 IconizeChildFrames(TRUE);
918 wxSizeEvent
event(wxSize(x
, y
), m_windowId
);
919 event
.SetEventObject( this );
920 processed
= GetEventHandler()->ProcessEvent(event
);
926 bool wxFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND control
)
930 // In case it's e.g. a toolbar.
931 wxWindow
*win
= wxFindWinFromHandle(control
);
933 // TODO: return win->OS2Command(cmd, id);
937 // handle here commands from menus and accelerators
938 if ( cmd
== 0 || cmd
== 1 )
940 if ( wxCurrentPopupMenu
)
942 wxMenu
*popupMenu
= wxCurrentPopupMenu
;
943 wxCurrentPopupMenu
= NULL
;
945 // return popupMenu->OS2Command(cmd, id);
949 if ( ProcessCommand(id
) )
958 bool wxFrame::HandleMenuSelect(WXWORD nItem
, WXWORD flags
, WXHMENU hMenu
)
961 if ( flags
== 0xFFFF && hMenu
== 0 )
963 // menu was removed from screen
967 else if ( !(flags & MF_POPUP) && !(flags & MF_SEPARATOR) )
974 // don't give hints for separators (doesn't make sense) nor for the
975 // items opening popup menus (they don't have them anyhow)
979 wxMenuEvent
event(wxEVT_MENU_HIGHLIGHT
, item
);
980 event
.SetEventObject( this );
982 return GetEventHandler()->ProcessEvent(event
);
985 // ---------------------------------------------------------------------------
986 // the window proc for wxFrame
987 // ---------------------------------------------------------------------------
989 MRESULT
wxFrame::OS2WindowProc(HWND hwnd
, WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
992 bool processed
= FALSE
;
999 // if we can't close, tell the system that we processed the
1000 // message - otherwise it would close us
1001 processed = !Close();
1008 UnpackCommand((WXWPARAM)wParam, (WXLPARAM)lParam,
1011 processed = HandleCommand(id, cmd, (WXHWND)hwnd);
1019 UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu);
1021 processed = HandleMenuSelect(item, flags, hmenu);
1026 processed = HandlePaint();
1029 case WM_QUERYDRAGICON:
1031 HICON hIcon = m_icon.Ok() ? GetHiconOf(m_icon)
1032 : (HICON)(m_defaultIcon);
1034 processed = rc != 0;
1039 processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
1044 rc
= wxWindow::OS2WindowProc(hwnd
, message
, wParam
, lParam
);