X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3c30bbb9faaa517f4fa3a4e896a945f3db82b1b0..713129f9d34e3027d2be46b134d2f4c490ad145f:/src/msw/toolbar.cpp diff --git a/src/msw/toolbar.cpp b/src/msw/toolbar.cpp index 5c4b2c4d5b..ba4638e445 100644 --- a/src/msw/toolbar.cpp +++ b/src/msw/toolbar.cpp @@ -43,8 +43,10 @@ #include "wx/stattext.h" #endif +#include "wx/artprov.h" #include "wx/sysopt.h" #include "wx/dcclient.h" +#include "wx/scopedarray.h" #include "wx/msw/private.h" #include "wx/msw/dc.h" @@ -96,10 +98,6 @@ #define TB_GETMAXSIZE (WM_USER + 83) #endif -// these values correspond to those used by comctl32.dll -#define DEFAULTBITMAPX 16 -#define DEFAULTBITMAPY 15 - // ---------------------------------------------------------------------------- // wxWin macros // ---------------------------------------------------------------------------- @@ -202,7 +200,7 @@ public: wxStaticText* GetStaticText() { wxASSERT_MSG( IsControl(), - _T("only makes sense for embedded control tools") ); + wxT("only makes sense for embedded control tools") ); return m_staticText; } @@ -216,7 +214,7 @@ private: size_t m_nSepCount; wxStaticText *m_staticText; - DECLARE_NO_COPY_CLASS(wxToolBarTool) + wxDECLARE_NO_COPY_CLASS(wxToolBarTool); }; // ---------------------------------------------------------------------------- @@ -284,8 +282,13 @@ void wxToolBar::Init() m_nButtons = 0; - m_defaultWidth = DEFAULTBITMAPX; - m_defaultHeight = DEFAULTBITMAPY; + // even though modern Windows applications typically use 24*24 (or even + // 32*32) size for their bitmaps, the native control itself still uses the + // old 16*15 default size (see TB_SETBITMAPSIZE documentation in MSDN), so + // default to it so that we don't call SetToolBitmapSize() unnecessarily in + // wxToolBarBase::AdjustToolBitmapSize() + m_defaultWidth = 16; + m_defaultHeight = 15; m_pInTool = NULL; } @@ -358,7 +361,7 @@ void wxToolBar::Recreate() if ( !MSWCreateToolbar(pos, size) ) { // what can we do? - wxFAIL_MSG( _T("recreating the toolbar failed") ); + wxFAIL_MSG( wxT("recreating the toolbar failed") ); return; } @@ -397,9 +400,7 @@ wxToolBar::~wxToolBar() { // we must refresh the frame size when the toolbar is deleted but the frame // is not - otherwise toolbar leaves a hole in the place it used to occupy - wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); - if ( frame && !frame->IsBeingDeleted() ) - frame->SendSizeEvent(); + SendSizeEventToParent(); if ( m_hBitmap ) ::DeleteObject((HBITMAP) m_hBitmap); @@ -581,13 +582,15 @@ bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool) wxToolBarTool *tool2 = (wxToolBarTool*)node->GetData(); if ( tool2->IsControl() ) { + wxControl * const control = tool2->GetControl(); + int x; - wxControl *control = tool2->GetControl(); control->GetPosition(&x, NULL); control->Move(x - width, wxDefaultCoord); - wxStaticText* staticText = tool2->GetStaticText(); - staticText->Move(x - width, wxDefaultCoord); + wxStaticText * const staticText = tool2->GetStaticText(); + if ( staticText ) + staticText->Move(x - width, wxDefaultCoord); } } @@ -633,10 +636,10 @@ void wxToolBar::CreateDisabledImageList() bool wxToolBar::Realize() { + if ( !wxToolBarBase::Realize() ) + return false; + const size_t nTools = GetToolsCount(); - if ( nTools == 0 ) - // nothing to do - return true; #ifdef wxREMAP_BUTTON_COLOURS // don't change the values of these constants, they can be set from the @@ -675,22 +678,12 @@ bool wxToolBar::Realize() wxToolBarToolsList::compatibility_iterator node; int bitmapId = 0; - wxSize sizeBmp; - if ( HasFlag(wxTB_NOICONS) ) - { - // no icons, don't leave space for them - sizeBmp.x = - sizeBmp.y = 0; - } - else // do show icons + if ( !HasFlag(wxTB_NOICONS) ) { // if we already have a bitmap, we'll replace the existing one -- // otherwise we'll install a new one HBITMAP oldToolBarBitmap = (HBITMAP)m_hBitmap; - sizeBmp.x = m_defaultWidth; - sizeBmp.y = m_defaultHeight; - const wxCoord totalBitmapWidth = m_defaultWidth * wx_truncate_cast(wxCoord, nTools), totalBitmapHeight = m_defaultHeight; @@ -759,7 +752,7 @@ bool wxToolBar::Realize() } else { - wxFAIL_MSG( _T("invalid tool button bitmap") ); + wxFAIL_MSG( wxT("invalid tool button bitmap") ); } // also deal with disabled bitmap if we want to use them @@ -894,18 +887,11 @@ bool wxToolBar::Realize() } } - // don't call SetToolBitmapSize() as we don't want to change the values of - // m_defaultWidth/Height - if ( !::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, - MAKELONG(sizeBmp.x, sizeBmp.y)) ) - { - wxLogLastError(_T("TB_SETBITMAPSIZE")); - } // Next add the buttons and separators // ----------------------------------- - TBBUTTON *buttons = new TBBUTTON[nTools]; + wxScopedArray buttons(new TBBUTTON[nTools]); // this array will hold the indices of all controls in the toolbar wxArrayInt controlIds; @@ -1011,7 +997,7 @@ bool wxToolBar::Realize() break; default: - wxFAIL_MSG( _T("unexpected toolbar button kind") ); + wxFAIL_MSG( wxT("unexpected toolbar button kind") ); button.fsStyle = TBSTYLE_BUTTON; break; } @@ -1025,12 +1011,11 @@ bool wxToolBar::Realize() i++; } - if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS, (WPARAM)i, (LPARAM)buttons) ) + if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS, i, (LPARAM)buttons.get()) ) { wxLogLastError(wxT("TB_ADDBUTTONS")); } - delete [] buttons; // Deal with the controls finally // ------------------------------ @@ -1218,9 +1203,10 @@ bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id_) bool toggled = false; // just to suppress warnings + LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0); + if ( tool->CanBeToggled() ) { - LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0); toggled = (state & TBSTATE_CHECKED) != 0; // ignore the event when a radio button is released, as this doesn't @@ -1232,9 +1218,38 @@ bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id_) UnToggleRadioGroup(tool); } + // Without the two lines of code below, if the toolbar was repainted during + // OnLeftClick(), then it could end up without the tool bitmap temporarily + // (see http://lists.nongnu.org/archive/html/lmi/2008-10/msg00014.html). + // The Update() call bellow ensures that this won't happen, by repainting + // invalidated areas of the toolbar immediately. + // + // To complicate matters, the tool would be drawn in depressed state (this + // code is called when mouse button is released, not pressed). That's not + // ideal, having the tool pressed for the duration of OnLeftClick() + // provides the user with useful visual clue that the app is busy reacting + // to the event. So we manually put the tool into pressed state, handle the + // event and then finally restore tool's original state. + ::SendMessage(GetHwnd(), TB_SETSTATE, id, MAKELONG(state | TBSTATE_PRESSED, 0)); + Update(); + + bool allowLeftClick = OnLeftClick(id, toggled); + + // Restore the unpressed state. Enabled/toggled state might have been + // changed since so take care of it. + if (tool->IsEnabled()) + state |= TBSTATE_ENABLED; + else + state &= ~TBSTATE_ENABLED; + if (tool->IsToggled()) + state |= TBSTATE_CHECKED; + else + state &= ~TBSTATE_CHECKED; + ::SendMessage(GetHwnd(), TB_SETSTATE, id, MAKELONG(state, 0)); + // OnLeftClick() can veto the button state change - for buttons which // may be toggled only, of couse - if ( !OnLeftClick(id, toggled) && tool->CanBeToggled() ) + if ( !allowLeftClick && tool->CanBeToggled() ) { // revert back tool->Toggle(!toggled); @@ -1262,7 +1277,7 @@ bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl), } const wxToolBarToolBase * const tool = FindById(tbhdr->iItem); - wxCHECK_MSG( tool, false, _T("drop down message for unknown tool") ); + wxCHECK_MSG( tool, false, wxT("drop down message for unknown tool") ); wxMenu * const menu = tool->GetDropdownMenu(); if ( !menu ) @@ -1392,7 +1407,7 @@ wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const // TB_HITTEST returns m_nButtons ( not -1 ) if ( index < 0 || (size_t)index >= m_nButtons ) // it's a separator or there is no tool at all there - return (wxToolBarToolBase *)NULL; + return NULL; // when TB_SETBUTTONINFO is available (both during compile- and run-time), // we don't use the dummy separators hack @@ -1420,11 +1435,7 @@ void wxToolBar::UpdateSize() // toolbar to full width again, but only if the parent is a frame and the // toolbar is managed by the frame. Otherwise assume that some other // layout mechanism is controlling the toolbar size and leave it alone. - wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); - if ( frame && frame->GetToolBar() == this ) - { - frame->SendSizeEvent(); - } + SendSizeEventToParent(); } // ---------------------------------------------------------------------------- @@ -1479,12 +1490,12 @@ void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(tog { // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or // without, so we really need to delete the button and recreate it here - wxFAIL_MSG( _T("not implemented") ); + wxFAIL_MSG( wxT("not implemented") ); } void wxToolBar::SetToolNormalBitmap( int id, const wxBitmap& bitmap ) { - wxToolBarTool* tool = wx_static_cast(wxToolBarTool*, FindById(id)); + wxToolBarTool* tool = static_cast(FindById(id)); if ( tool ) { wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools.")); @@ -1496,7 +1507,7 @@ void wxToolBar::SetToolNormalBitmap( int id, const wxBitmap& bitmap ) void wxToolBar::SetToolDisabledBitmap( int id, const wxBitmap& bitmap ) { - wxToolBarTool* tool = wx_static_cast(wxToolBarTool*, FindById(id)); + wxToolBarTool* tool = static_cast(FindById(id)); if ( tool ) { wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools.")); @@ -1563,7 +1574,7 @@ void wxToolBar::OnMouseEvent(wxMouseEvent& event) void wxToolBar::OnEraseBackground(wxEraseEvent& event) { RECT rect = wxGetClientRect(GetHwnd()); - + wxDC *dc = event.GetDC(); if (!dc) return; wxMSWDCImpl *impl = (wxMSWDCImpl*) dc->GetImpl(); @@ -1589,7 +1600,9 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event) // it can also return S_FALSE which seems to simply say that it // didn't draw anything but no error really occurred if ( FAILED(hr) ) - wxLogApiError(_T("DrawThemeParentBackground(toolbar)"), hr); + { + wxLogApiError(wxT("DrawThemeParentBackground(toolbar)"), hr); + } } } @@ -1612,7 +1625,9 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event) // it can also return S_FALSE which seems to simply say that it // didn't draw anything but no error really occurred if ( FAILED(hr) ) - wxLogApiError(_T("DrawThemeParentBackground(toolbar)"), hr); + { + wxLogApiError(wxT("DrawThemeParentBackground(toolbar)"), hr); + } } } @@ -1642,6 +1657,10 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event) bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam) { + // wait until we have some tools + if ( !GetToolsCount() ) + return false; + // calculate our minor dimension ourselves - we're confusing the standard // logic (TB_AUTOSIZE) with our horizontal toolbars and other hacks const RECT r = wxGetTBItemRect(GetHwnd(), 0); @@ -1684,6 +1703,7 @@ bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam) return true; } +#ifndef __WXWINCE__ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam) { // erase any dummy separators which were used @@ -1753,7 +1773,7 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam) if ( !::SendMessage(GetHwnd(), TB_GETBUTTON, n, (LPARAM)&tbb) ) { - wxLogDebug(_T("TB_GETBUTTON failed?")); + wxLogDebug(wxT("TB_GETBUTTON failed?")); continue; } @@ -1795,14 +1815,14 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam) r.right = clientSize.x; r.top = 0; r.bottom = clientSize.y; - + wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); HRESULT hr = theme->DrawThemeBackground(hTheme, GetHdcOf(*impl), 0, 0, & r, & clipRect); if ( hr == S_OK ) haveRefreshed = true; } } -#endif +#endif // wxUSE_UXTHEME if (!haveRefreshed) dc.DrawRectangle(rectItem); @@ -1827,6 +1847,7 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam) return true; } +#endif // __WXWINCE__ void wxToolBar::HandleMouseMove(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam) { @@ -1859,12 +1880,14 @@ WXLRESULT wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam #ifndef __WXWINCE__ case WM_PAINT: - if ( HandlePaint(wParam, lParam) ) + // refreshing the controls in the toolbar inside a composite window + // results in an endless stream of WM_PAINT messages -- and seems + // to be unnecessary anyhow as everything works just fine without + // any special workarounds in this case + if ( !IsDoubleBuffered() && HandlePaint(wParam, lParam) ) return 0; -#endif - - default: break; +#endif // __WXWINCE__ } return wxControl::MSWWindowProc(nMsg, wParam, lParam); @@ -1882,7 +1905,7 @@ WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height) if ( !hdcMem ) { - wxLogLastError(_T("CreateCompatibleDC")); + wxLogLastError(wxT("CreateCompatibleDC")); return bitmap; } @@ -1891,7 +1914,7 @@ WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height) if ( !bmpInHDC ) { - wxLogLastError(_T("SelectObject")); + wxLogLastError(wxT("SelectObject")); return bitmap; }