From eba99da4c0563e6508761272a1e1f1b791d0af6b Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Wed, 30 Mar 2005 15:30:06 +0000 Subject: [PATCH] Applied patch [ 1166587 ] [wxMSW] Removes all flicker from wxStaticBox By Jamie Gadd git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@33178 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 24 ++++--- include/wx/msw/radiobox.h | 2 + include/wx/msw/statbox.h | 4 ++ src/msw/radiobox.cpp | 61 ++++++++++++++-- src/msw/statbox.cpp | 142 ++++++++++++++++++++++++++++++++++++-- 5 files changed, 208 insertions(+), 25 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index c90f3bec94..35563a220a 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -13,8 +13,8 @@ All: - Added wxTempFileOutputStream by Stas Sergeev. - Fixed wxDateTime::SetToWeekDayInSameWeek(Sun, Monday_First). - Added WXK_SPECIAL keycodes for special hardware buttons. -- Fixed bug with wxFile::Seek(-1, wxFromCurrent) -- Added wxString/C array constructors to wxArrayString +- Fixed bug with wxFile::Seek(-1, wxFromCurrent). +- Added wxString/C array constructors to wxArrayString. All (GUI): @@ -26,29 +26,31 @@ All (GUI): - Restored ability to set a custom splitter sash size with SetSashSize. - Fixed wxScrolledWindow sizer behaviour so that the virtual size isn't used to set the window size. -- Added wxTE_BESTWRAP (based on patch by Mart Raudsepp) +- Added wxTE_BESTWRAP (based on patch by Mart Raudsepp). - wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED is now only sent once at the end of - splitter dragging and not after each CHANGING event (Jacobo Vilella Vilahur) + splitter dragging and not after each CHANGING event (Jacobo Vilella Vilahur). Unix: -- Fixed build on Linux/AMD64 +- Fixed build on Linux/AMD64. wxMSW: -- Added "orient" parameter to wxMDIParentFrame::Tile() -- wxTextCtrl with wxTE_RICH2 style now uses RichEdit 4.1 if available -- fix handling Alt-key events in wxComboBox (reported by Joakim Roubert) -- wxWindow::Refresh() refreshes the window children as well +- Added "orient" parameter to wxMDIParentFrame::Tile(). +- wxTextCtrl with wxTE_RICH2 style now uses RichEdit 4.1 if available. +- fix handling Alt-key events in wxComboBox (reported by Joakim Roubert). +- wxWindow::Refresh() refreshes the window children as well. +- Improved static box and radio box refresh and background colour + handling (Jamie Gadd). wxGTK: -- Improved wxSystemSettings::GetMetric() to work better with X11. (Mart Raudsepp) +- Improved wxSystemSettings::GetMetric() to work better with X11 (Mart Raudsepp). - Corrected wxListBox selection handling. - Corrected default button size handling for different themes. - Corrected splitter sash size and look for different themes. - Fixed keyboard input for dead-keys. -- Added support for more wrapping styles (Mart Raudsepp) +- Added support for more wrapping styles (Mart Raudsepp). wxMac: diff --git a/include/wx/msw/radiobox.h b/include/wx/msw/radiobox.h index 2658783a36..7607e04a40 100644 --- a/include/wx/msw/radiobox.h +++ b/include/wx/msw/radiobox.h @@ -144,6 +144,8 @@ protected: int sizeFlags = wxSIZE_AUTO); virtual wxSize DoGetBestSize() const; + virtual WXHRGN MSWCalculateClippingRegion(); + virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); // the buttons we contain wxSubwindows *m_radioButtons; diff --git a/include/wx/msw/statbox.h b/include/wx/msw/statbox.h index 1f89b27e53..e222abbeb1 100644 --- a/include/wx/msw/statbox.h +++ b/include/wx/msw/statbox.h @@ -48,8 +48,12 @@ protected: virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const; virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); + virtual WXHRGN MSWCalculateClippingRegion(); + virtual void MSWClipBoxRegion(HRGN hrgn, const RECT *rc); + void OnPaint(wxPaintEvent& event); DECLARE_DYNAMIC_CLASS_NO_COPY(wxStaticBox) + DECLARE_EVENT_TABLE() }; #endif // _WX_MSW_STATBOX_H_ diff --git a/src/msw/radiobox.cpp b/src/msw/radiobox.cpp index d34034c6b1..a6df181a1a 100644 --- a/src/msw/radiobox.cpp +++ b/src/msw/radiobox.cpp @@ -165,9 +165,6 @@ bool wxRadioBox::Create(wxWindow *parent, wxUnusedVar(val); #endif // wxUSE_VALIDATORS/!wxUSE_VALIDATORS - // and now create the buttons - HWND hwndParent = GetHwndOf(parent); - m_radioButtons = new wxSubwindows(n); m_radioWidth = new int[n]; m_radioHeight = new int[n]; @@ -186,7 +183,7 @@ bool wxRadioBox::Create(wxWindow *parent, choices[i], styleBtn, 0, 0, 0, 0, // will be set in SetSize() - hwndParent, + GetHwnd(), (HMENU)newId, wxGetInstance(), NULL); @@ -209,7 +206,7 @@ bool wxRadioBox::Create(wxWindow *parent, (void)::CreateWindow(_T("BUTTON"), wxEmptyString, WS_GROUP | BS_AUTORADIOBUTTON | WS_CHILD, - 0, 0, 0, 0, hwndParent, + 0, 0, 0, 0, GetHwnd(), (HMENU)NewControlId(), wxGetInstance(), NULL); m_radioButtons->SetFont(GetFont()); @@ -515,8 +512,8 @@ void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags) if (y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) yy = currentY; - int y_offset = yy; - int x_offset = xx; + int y_offset = 0; + int x_offset = 0; int cx1, cy1; wxGetCharSize(m_hWnd, &cx1, &cy1, GetFont()); @@ -819,5 +816,55 @@ LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd, return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, message, wParam, lParam); } +WXHRGN wxRadioBox::MSWCalculateClippingRegion() +{ + RECT rc; + ::GetWindowRect(GetHwnd(), &rc); + HRGN hrgn = ::CreateRectRgn(rc.left, rc.top, rc.right + 1, rc.bottom + 1); + + size_t count = GetCount(); + for ( size_t i = 0; i < count; ++i ) + { + ::GetWindowRect((*m_radioButtons)[i], &rc); + HRGN hrgnchild = ::CreateRectRgnIndirect(&rc); + ::CombineRgn(hrgn, hrgn, hrgnchild, RGN_DIFF); + ::DeleteObject(hrgnchild); + } + + ::GetWindowRect(GetHwnd(), &rc); + ::OffsetRgn(hrgn, -rc.left, -rc.top); + + return hrgn; +} + +WXLRESULT wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ +#ifndef __WXWINCE__ + if ( nMsg == WM_PRINTCLIENT ) + { + // first check to see if a parent window knows how to paint us better + for ( wxWindow *win = GetParent(); win; win = win->GetParent() ) + if ( win->MSWPrintChild(this, wParam, lParam) ) + return true; + + // nope, so lets do it ourselves + RECT rc; + WXHBRUSH hbr = DoMSWControlColor((HDC)wParam, wxNullColour); + if ( !hbr ) + { + wxBrush *brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID); + hbr = (WXHBRUSH)brush->GetResourceHandle(); + } + + ::GetClientRect(GetHwnd(), &rc); + ::FillRect((HDC)wParam, &rc, (HBRUSH)hbr); + + return true; + } +#endif + // __WXWINCE__ + + return wxStaticBox::MSWWindowProc(nMsg, wParam, lParam); +} #endif // wxUSE_RADIOBOX diff --git a/src/msw/statbox.cpp b/src/msw/statbox.cpp index cd21abe857..6e2254b850 100644 --- a/src/msw/statbox.cpp +++ b/src/msw/statbox.cpp @@ -38,15 +38,10 @@ #include "wx/statbox.h" #include "wx/notebook.h" #include "wx/sysopt.h" +#include "wx/image.h" #include "wx/msw/private.h" -// under CE this style is not defined but we don't need to make static boxes -// transparent there neither -#ifndef WS_EX_TRANSPARENT - #define WS_EX_TRANSPARENT 0 -#endif - // ---------------------------------------------------------------------------- // wxWin macros // ---------------------------------------------------------------------------- @@ -103,6 +98,10 @@ wxCONSTRUCTOR_6( wxStaticBox , wxWindow* , Parent , wxWindowID , Id , wxString , IMPLEMENT_DYNAMIC_CLASS(wxStaticBox, wxControl) #endif +BEGIN_EVENT_TABLE(wxStaticBox, wxControl) + EVT_PAINT(wxStaticBox::OnPaint) +END_EVENT_TABLE() + // ============================================================================ // implementation // ============================================================================ @@ -132,8 +131,12 @@ WXDWORD wxStaticBox::MSWGetStyle(long style, WXDWORD *exstyle) const { long styleWin = wxStaticBoxBase::MSWGetStyle(style, exstyle); + // no need for it anymore, must be removed for wxRadioBox child + // buttons to be able to repaint themselves + styleWin &= ~WS_CLIPCHILDREN; + if ( exstyle ) - *exstyle = WS_EX_TRANSPARENT; + *exstyle = 0; return styleWin | BS_GROUPBOX; } @@ -194,5 +197,130 @@ void wxStaticBox::GetBordersForSizer(int *borderTop, int *borderOther) const #endif // !wxDIALOG_UNIT_COMPATIBILITY } +// rc must be in client coords! +void wxStaticBox::MSWClipBoxRegion(HRGN hrgn, const RECT *rc) +{ + HRGN hrgnchild; + + // top + hrgnchild = ::CreateRectRgn(0, 0, rc->right, 14); + ::CombineRgn(hrgn, hrgn, hrgnchild, RGN_DIFF); + ::DeleteObject(hrgnchild); + + // bottom + hrgnchild = ::CreateRectRgn(0, rc->bottom - 7, rc->right, rc->bottom); + ::CombineRgn(hrgn, hrgn, hrgnchild, RGN_DIFF); + ::DeleteObject(hrgnchild); + + // left + hrgnchild = ::CreateRectRgn(0, 0, 7, rc->bottom); + ::CombineRgn(hrgn, hrgn, hrgnchild, RGN_DIFF); + ::DeleteObject(hrgnchild); + + // right + hrgnchild = ::CreateRectRgn(rc->right - 7, 0, rc->right, rc->bottom); + ::CombineRgn(hrgn, hrgn, hrgnchild, RGN_DIFF); + ::DeleteObject(hrgnchild); +} + +WXHRGN wxStaticBox::MSWCalculateClippingRegion() +{ + RECT rc; + ::GetWindowRect(GetHwnd(), &rc); + HRGN hrgn = ::CreateRectRgn(rc.left, rc.top, rc.right + 1, rc.bottom + 1); + + wxWindowList::compatibility_iterator node = GetParent()->GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + + // can't just test for (this != child) here since if a wxStaticBox + // overlaps another wxStaticBox then neither are drawn. The overlapping + // region will flicker but we shouldn't have overlapping windows anyway. + if ( !child->IsKindOf(CLASSINFO(wxStaticBox)) ) + { + ::GetWindowRect(GetHwndOf(child), &rc); + if ( RectInRegion(hrgn, &rc) ) + { + // need to remove WS_CLIPSIBLINGS from all sibling windows + // that are within this staticbox if set + LONG style = ::GetWindowLong(GetHwndOf(child), GWL_STYLE); + if ( style & WS_CLIPSIBLINGS ) + { + style &= ~WS_CLIPSIBLINGS; + ::SetWindowLong(GetHwndOf(child), GWL_STYLE, style); + + // MSDN: "If you have changed certain window data using + // SetWindowLong, you must call SetWindowPos to have the + // changes take effect." + ::SetWindowPos(GetHwndOf(child), NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | + SWP_FRAMECHANGED); + } + + HRGN hrgnchild = ::CreateRectRgnIndirect(&rc); + ::CombineRgn(hrgn, hrgn, hrgnchild, RGN_DIFF); + ::DeleteObject(hrgnchild); + } + } + + node = node->GetNext(); + } + ::GetWindowRect(GetHwnd(), &rc); + ::OffsetRgn(hrgn, -rc.left, -rc.top); + + return hrgn; +} + +void wxStaticBox::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + RECT rc; + ::GetClientRect(GetHwnd(), &rc); + + // paint the actual box + wxMemoryDC memdc; + wxBitmap bitmap(rc.right, rc.bottom); + memdc.SelectObject(bitmap); + + // get bg brush + WXHBRUSH hbr = DoMSWControlColor(GetHdcOf(memdc), wxNullColour); + if ( !hbr ) + { + wxBrush *brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID); + hbr = (WXHBRUSH)brush->GetResourceHandle(); + } + + // draw solid box, but only blit the good bits + ::FillRect(GetHdcOf(memdc), &rc, (HBRUSH)hbr); + MSWDefWindowProc(WM_PAINT, (WPARAM)GetHdcOf(memdc), 0); + + // top + dc.Blit(7, 0, rc.right - 7, 14, &memdc, 7, 0); + // bottom + dc.Blit(7, rc.bottom - 7, rc.right - 7, rc.bottom, &memdc, 7, rc.bottom - 7); + // left + dc.Blit(0, 0, 7, rc.bottom, &memdc, 0, 0); + // right + dc.Blit(rc.right - 7, 0, rc.right, rc.bottom, &memdc, rc.right - 7, 0); + + // paint the inner + HRGN hrgn = (HRGN)MSWCalculateClippingRegion(); + // now remove the box itself + MSWClipBoxRegion(hrgn, &rc); + + hbr = DoMSWControlColor(GetHdcOf(dc), wxNullColour); + if ( !hbr ) + { + wxBrush *brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID); + hbr = (WXHBRUSH)brush->GetResourceHandle(); + } + + ::SelectClipRgn(GetHdcOf(dc), hrgn); + ::FillRect(GetHdcOf(dc), &rc, (HBRUSH)hbr); + ::SelectClipRgn(GetHdcOf(dc), NULL); + ::DeleteObject(hrgn); +} + #endif // wxUSE_STATBOX -- 2.47.2