Finally really correct background erasing for wxMSW wxToolBar.

Do use TBSTYLE_FLAT and TBSTYLE_TRANSPARENT (the former actually implies the
latter) for MSW toolbar as it is the only way to avoid the flicker of toolbar
buttons. These styles were disabled before because of lack of understanding
about how they worked: with them, the toolbar supposes that its parent takes
care of erasing its background but wx didn't do this (in fact wxFrame did
accidentally erase toolbar background because of the use of Win32 client
rectangle, including tool/status bars, instead of wx client rectangle,
excluding them, in wxWindowMSW::DoEraseBackground(), but it didn't do it
correctly).

Now we allow hooking WM_ERASEBKGND events processing in a parent window by a
child one and use this to handle toolbar background erasing in toolbar itself.
We still prevent the native toolbar from drawing dummy separators and always
erase the area occupied by them ourselves and thus avoid the flicker entirely.

The only remaining flicker in the toolbar sample is that of embedded
wxStaticText control. It does appear with correctly transparent background and
bitmaps with alpha channel also (still) are drawn correctly in wxStaticBitmaps
embedded in the toolbar.

Finally, we still use solid background brush for toolbar but we can easily use
a themed background if really desired, there is just a single function to
change to do it (MSWGetToolbarBgBrush()).

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62971 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2009-12-22 15:37:43 +00:00
parent 4b601a59b5
commit bec9bf3e20
4 changed files with 252 additions and 48 deletions

View File

@@ -173,13 +173,16 @@
extern wxMenu *wxCurrentPopupMenu;
#endif
namespace
{
// true if we had already created the std colour map, used by
// wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT)
static bool gs_hasStdCmap = false;
bool gs_hasStdCmap = false;
// last mouse event information we need to filter out the duplicates
#if wxUSE_MOUSEEVENT_HACK
static struct MouseEventInfoDummy
struct MouseEventInfoDummy
{
// mouse position (in screen coordinates)
wxPoint pos;
@@ -194,14 +197,29 @@ WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler,
wxIntegerHash, wxIntegerEqual,
MSWMessageHandlers);
static MSWMessageHandlers gs_messageHandlers;
MSWMessageHandlers gs_messageHandlers;
// hash containing all our windows, it uses HWND keys and wxWindow* values
WX_DECLARE_HASH_MAP(HWND, wxWindow *,
wxPointerHash, wxPointerEqual,
WindowHandles);
static WindowHandles gs_windowHandles;
WindowHandles gs_windowHandles;
#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
// temporary override for WM_ERASEBKGND processing: we don't store this in
// wxWindow itself as we don't need it during most of the time so don't
// increase the size of all window objects unnecessarily
WX_DECLARE_HASH_MAP(wxWindow *, wxWindow *,
wxPointerHash, wxPointerEqual,
EraseBgHooks);
EraseBgHooks gs_eraseBgHooks;
#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
} // anonymous namespace
// ---------------------------------------------------------------------------
// private functions
@@ -3269,7 +3287,17 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
break;
case WM_ERASEBKGND:
processed = HandleEraseBkgnd((WXHDC)wParam);
{
#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
// check if an override was configured for this window
EraseBgHooks::const_iterator it = gs_eraseBgHooks.find(this);
if ( it != gs_eraseBgHooks.end() )
processed = it->second->MSWEraseBgHook((WXHDC)wParam);
else
#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
processed = HandleEraseBkgnd((WXHDC)wParam);
}
if ( processed )
{
// we processed the message, i.e. erased the background
@@ -4867,13 +4895,47 @@ bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
return true;
}
#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
bool wxWindowMSW::MSWHasEraseBgHook() const
{
return gs_eraseBgHooks.find(this) != gs_eraseBgHooks.end();
}
void wxWindowMSW::MSWSetEraseBgHook(wxWindow *child)
{
if ( child )
{
if ( !gs_eraseBgHooks.insert(
EraseBgHooks::value_type(this, child)).second )
{
wxFAIL_MSG( wxT("Setting erase background hook twice?") );
}
}
else // reset the hook
{
if ( gs_eraseBgHooks.erase(this) != 1 )
{
wxFAIL_MSG( wxT("Resetting erase background which was not set?") );
}
}
}
#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
{
HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
if ( !hbr )
return false;
wxFillRect(GetHwnd(), (HDC)hDC, hbr);
// erase just the client area of the window, this is important for the
// frames to avoid drawing over the toolbar part of the window (you might
// think using WS_CLIPCHILDREN would prevent this from happening, but it
// clearly doesn't)
RECT rc;
wxCopyRectToRECT(GetClientRect(), rc);
::FillRect((HDC)hDC, &rc, hbr);
return true;
}