From d4597e138eff53fccbcb41259e8cb7ab2db3bab9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 8 Dec 2001 23:13:27 +0000 Subject: [PATCH] fixed bugs with setting the client size when the difference between the total and client size changes as the result (e.g. because the scrollbars [dis]appear or the menu bar [un]wraps git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@12934 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/toplevel.h | 1 + include/wx/toplevel.h | 10 ++--- src/common/framecmn.cpp | 9 ++-- src/msw/frame.cpp | 83 ++++++++++++++++++------------------ src/msw/toplevel.cpp | 39 +++++++---------- src/msw/window.cpp | 89 +++++++++++++++++++++++++-------------- 6 files changed, 125 insertions(+), 106 deletions(-) diff --git a/include/wx/msw/toplevel.h b/include/wx/msw/toplevel.h index 66c81cfb45..f6a42ff4b7 100644 --- a/include/wx/msw/toplevel.h +++ b/include/wx/msw/toplevel.h @@ -90,6 +90,7 @@ protected: // implement the geometry-related methods for a top level window virtual void DoSetClientSize(int width, int height); + virtual void DoGetClientSize(int *width, int *height) const; // get the MSW window flags corresponding to wxWindows ones // diff --git a/include/wx/toplevel.h b/include/wx/toplevel.h index 9eb6f10f0c..64a1c964a0 100644 --- a/include/wx/toplevel.h +++ b/include/wx/toplevel.h @@ -47,9 +47,9 @@ enum wxFULLSCREEN_NOSTATUSBAR = 0x0004, wxFULLSCREEN_NOBORDER = 0x0008, wxFULLSCREEN_NOCAPTION = 0x0010, - - wxFULLSCREEN_ALL = wxFULLSCREEN_NOMENUBAR | wxFULLSCREEN_NOTOOLBAR | - wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER | + + wxFULLSCREEN_ALL = wxFULLSCREEN_NOMENUBAR | wxFULLSCREEN_NOTOOLBAR | + wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION }; @@ -105,7 +105,7 @@ public: // maximize the window to cover entire screen virtual bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL) = 0; - + // return TRUE if the frame is in fullscreen mode virtual bool IsFullScreen() const = 0; @@ -122,7 +122,7 @@ public: bool Iconized() const { return IsIconized(); } #endif // WXWIN_COMPATIBILITY_2 - + #ifdef __WXUNIVERSAL__ // move/resize the frame interactively, i.e. let the user do it virtual void InteractiveMove(int flags = wxINTERACTIVE_MOVE); diff --git a/src/common/framecmn.cpp b/src/common/framecmn.cpp index fc7b2f413a..7b067ddf0d 100644 --- a/src/common/framecmn.cpp +++ b/src/common/framecmn.cpp @@ -148,12 +148,13 @@ wxPoint wxFrameBase::GetClientAreaOrigin() const wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin(); #if wxUSE_TOOLBAR - if ( GetToolBar() && GetToolBar()->IsShown() ) + wxToolBar *toolbar = GetToolBar(); + if ( toolbar && toolbar->IsShown() ) { int w, h; - GetToolBar()->GetSize(& w, & h); + toolbar->GetSize(&w, &h); - if ( GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL ) + if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL ) { pt.x += w; } @@ -186,7 +187,7 @@ bool wxFrameBase::ProcessCommand(int id) { if (!item->IsEnabled()) return TRUE; - + if (item->IsCheckable()) { item->Toggle(); diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp index d15747b1ea..814f3bd254 100644 --- a/src/msw/frame.cpp +++ b/src/msw/frame.cpp @@ -142,30 +142,9 @@ wxFrame::~wxFrame() DeleteAllBars(); } -// Get size *available for subwindows* i.e. excluding menu bar, toolbar etc. -void wxFrame::DoGetClientSize(int *x, int *y) const -{ - RECT rect; - ::GetClientRect(GetHwnd(), &rect); - -#if wxUSE_STATUSBAR - if ( GetStatusBar() && GetStatusBar()->IsShown() ) - { - int statusX, statusY; - GetStatusBar()->GetClientSize(&statusX, &statusY); - rect.bottom -= statusY; - } -#endif // wxUSE_STATUSBAR - - wxPoint pt(GetClientAreaOrigin()); - rect.bottom -= pt.y; - rect.right -= pt.x; - - if ( x ) - *x = rect.right; - if ( y ) - *y = rect.bottom; -} +// ---------------------------------------------------------------------------- +// wxFrame client size calculations +// ---------------------------------------------------------------------------- void wxFrame::DoSetClientSize(int width, int height) { @@ -181,6 +160,24 @@ void wxFrame::DoSetClientSize(int width, int height) wxTopLevelWindow::DoSetClientSize(width, height); } +// Get size *available for subwindows* i.e. excluding menu bar, toolbar etc. +void wxFrame::DoGetClientSize(int *x, int *y) const +{ + wxTopLevelWindow::DoGetClientSize(x, y); + +#if wxUSE_STATUSBAR + // adjust client area height to take the status bar into account + if ( y ) + { + wxStatusBar *statbar = GetStatusBar(); + if ( statbar && statbar->IsShown() ) + { + *y -= statbar->GetClientSize().y; + } + } +#endif // wxUSE_STATUSBAR +} + // ---------------------------------------------------------------------------- // wxFrame: various geometry-related functions // ---------------------------------------------------------------------------- @@ -234,7 +231,7 @@ wxStatusBar *wxFrame::OnCreateStatusBar(int number, void wxFrame::PositionStatusBar() { - if ( !m_frameStatusBar ) + if ( !m_frameStatusBar || !m_frameStatusBar->IsShown() ) return; int w, h; @@ -459,36 +456,40 @@ wxToolBar* wxFrame::CreateToolBar(long style, wxWindowID id, const wxString& nam void wxFrame::PositionToolBar() { - RECT rect; - ::GetClientRect(GetHwnd(), &rect); + wxToolBar *toolbar = GetToolBar(); + if ( toolbar && toolbar->IsShown() ) + { + // don't call our (or even wxTopLevelWindow) version because we want + // the real (full) client area size, not excluding the tool/status bar + int width, height; + wxWindow::DoGetClientSize(&width, &height); #if wxUSE_STATUSBAR - if ( GetStatusBar() ) - { - int statusX, statusY; - GetStatusBar()->GetClientSize(&statusX, &statusY); - rect.bottom -= statusY; - } + wxStatusBar *statbar = GetStatusBar(); + if ( statbar && statbar->IsShown() ) + { + height -= statbar->GetClientSize().y; + } #endif // wxUSE_STATUSBAR - if ( GetToolBar() && GetToolBar()->IsShown() ) - { int tw, th; - GetToolBar()->GetSize(&tw, &th); + toolbar->GetSize(&tw, &th); - if ( GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL ) + if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL ) { - th = rect.bottom; + th = height; } else { - tw = rect.right; + tw = width; } - // Use the 'real' MSW position here - GetToolBar()->SetSize(0, 0, tw, th, wxSIZE_NO_ADJUSTMENTS); + // use the 'real' MSW position here, don't offset relativly to the + // client area origin + toolbar->SetSize(0, 0, tw, th, wxSIZE_NO_ADJUSTMENTS); } } + #endif // wxUSE_TOOLBAR // ---------------------------------------------------------------------------- diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index a7b917f9f1..9aacc56017 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -387,39 +387,30 @@ wxTopLevelWindowMSW::~wxTopLevelWindowMSW() } // ---------------------------------------------------------------------------- -// wxTopLevelWindowMSW geometry +// wxTopLevelWindowMSW client size // ---------------------------------------------------------------------------- void wxTopLevelWindowMSW::DoSetClientSize(int width, int height) { - HWND hWnd = GetHwnd(); - - RECT rectClient; - ::GetClientRect(hWnd, &rectClient); - - RECT rectTotal; - ::GetWindowRect(hWnd, &rectTotal); - - // Find the difference between the entire window (title bar and all) - // and the client area; add this to the new client size to move the - // window - width += rectTotal.right - rectTotal.left - rectClient.right; - height += rectTotal.bottom - rectTotal.top - rectClient.bottom; - - // note that calling GetClientAreaOrigin() takes the toolbar into account + // call GetClientAreaOrigin() to take the toolbar into account wxPoint pt = GetClientAreaOrigin(); width += pt.x; height += pt.y; - if ( !::MoveWindow(hWnd, rectTotal.left, rectTotal.top, - width, height, TRUE /* redraw */) ) - { - wxLogLastError(_T("MoveWindow")); - } + wxWindow::DoSetClientSize(width, height); +} - wxSizeEvent event(wxSize(width, height), m_windowId); - event.SetEventObject(this); - (void)GetEventHandler()->ProcessEvent(event); +void wxTopLevelWindowMSW::DoGetClientSize(int *x, int *y) const +{ + wxWindow::DoGetClientSize(x, y); + + wxPoint pt = GetClientAreaOrigin(); + + if ( x ) + *x -= pt.x; + + if ( y ) + *y -= pt.y; } // ---------------------------------------------------------------------------- diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 2979f857d5..dd98fe4c43 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1493,40 +1493,65 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) void wxWindowMSW::DoSetClientSize(int width, int height) { - wxWindow *parent = GetParent(); - HWND hWnd = GetHwnd(); - HWND hParentWnd = (HWND) 0; - if ( parent ) - hParentWnd = (HWND) parent->GetHWND(); - - RECT rect; - ::GetClientRect(hWnd, &rect); - - RECT rect2; - GetWindowRect(hWnd, &rect2); - - // Find the difference between the entire window (title bar and all) - // and the client area; add this to the new client size to move the - // window - int actual_width = rect2.right - rect2.left - rect.right + width; - int actual_height = rect2.bottom - rect2.top - rect.bottom + height; - - // If there's a parent, must subtract the parent's top left corner - // since MoveWindow moves relative to the parent - - POINT point; - point.x = rect2.left; - point.y = rect2.top; - if ( parent ) + // setting the client size is less obvious than it it could have been + // because in the result of changing the total size the window scrollbar + // may [dis]appear and/or its menubar may [un]wrap and so the client size + // will not be correct as the difference between the total and client size + // changes - so we keep changing it until we get it right + // + // normally this loop shouldn't take more than 2 iterations (usually 1 but + // if scrollbars [dis]appear as the result of the first call, then 2) but + // just to be on the safe side we check for it instead of making it an + // "infinite" loop (i.e. leaving break inside as the only way to get out) + for ( int i = 0; i < 3; i++ ) { - ::ScreenToClient(hParentWnd, &point); + RECT rectClient; + ::GetClientRect(GetHwnd(), &rectClient); + + // if the size is already ok, stop here (rectClient.left = top = 0) + if ( rectClient.right == width && rectClient.bottom == height ) + { + break; + } + + if ( i == 2 ) + { + // how did it happen? maybe OnSize() handler does something really + // strange in this class? + wxFAIL_MSG( _T("logic error in DoSetClientSize") ); + + break; + } + + int widthClient = width, + heightClient = height; + + // Find the difference between the entire window (title bar and all) + // and the client area; add this to the new client size to move the + // window + RECT rectWin; + ::GetWindowRect(GetHwnd(), &rectWin); + + widthClient += rectWin.right - rectWin.left - rectClient.right; + heightClient += rectWin.bottom - rectWin.top - rectClient.bottom; + + POINT point; + point.x = rectWin.left; + point.y = rectWin.top; + + // MoveWindow positions the child windows relative to the parent, so + // adjust if necessary + if ( !IsTopLevel() ) + { + wxWindow *parent = GetParent(); + if ( parent ) + { + ::ScreenToClient(GetHwndOf(parent), &point); + } + } + + DoMoveWindow(point.x, point.y, widthClient, heightClient); } - - DoMoveWindow(point.x, point.y, actual_width, actual_height); - - wxSizeEvent event(wxSize(width, height), m_windowId); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); } // For implementation purposes - sometimes decorations make the client area