X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/90c1530adf4014047991d04edf1f097808a88027..2d956b58023a4955313a1c1531bc70a0deb0b831:/src/msw/tbar95.cpp?ds=sidebyside diff --git a/src/msw/tbar95.cpp b/src/msw/tbar95.cpp index 758426c5a5..7c6515ff12 100644 --- a/src/msw/tbar95.cpp +++ b/src/msw/tbar95.cpp @@ -36,6 +36,7 @@ #include "wx/settings.h" #include "wx/bitmap.h" #include "wx/dcmemory.h" + #include "wx/control.h" #endif #if wxUSE_TOOLBAR && defined(__WIN95__) && wxUSE_TOOLBAR_NATIVE @@ -94,9 +95,15 @@ #ifndef TBSTYLE_FLAT #define TBSTYLE_LIST 0x1000 #define TBSTYLE_FLAT 0x0800 +#endif + +#ifndef TBSTYLE_TRANSPARENT #define TBSTYLE_TRANSPARENT 0x8000 #endif - // use TBSTYLE_TRANSPARENT if you use TBSTYLE_FLAT + +#ifndef TBSTYLE_TOOLTIPS + #define TBSTYLE_TOOLTIPS 0x0100 +#endif // Messages #ifndef TB_GETSTYLE @@ -135,14 +142,15 @@ class wxToolBarTool : public wxToolBarToolBase public: wxToolBarTool(wxToolBar *tbar, int id, - const wxBitmap& bitmap1, - const wxBitmap& bitmap2, - bool toggle, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, wxObject *clientData, - const wxString& shortHelpString, - const wxString& longHelpString) - : wxToolBarToolBase(tbar, id, bitmap1, bitmap2, toggle, - clientData, shortHelpString, longHelpString) + const wxString& shortHelp, + const wxString& longHelp) + : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind, + clientData, shortHelp, longHelp) { m_nSepCount = 0; } @@ -153,6 +161,19 @@ public: m_nSepCount = 1; } + virtual void SetLabel(const wxString& label) + { + if ( label == m_label ) + return; + + wxToolBarToolBase::SetLabel(label); + + // we need to update the label shown in the toolbar because it has a + // pointer to the internal buffer of the old label + // + // TODO: use TB_SETBUTTONINFO + } + // set/get the number of separators which we use to cover the space used by // a control in the toolbar void SetSeparatorsCount(size_t count) { m_nSepCount = count; } @@ -172,15 +193,16 @@ private: // ---------------------------------------------------------------------------- wxToolBarToolBase *wxToolBar::CreateTool(int id, - const wxBitmap& bitmap1, - const wxBitmap& bitmap2, - bool toggle, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, wxObject *clientData, - const wxString& shortHelpString, - const wxString& longHelpString) + const wxString& shortHelp, + const wxString& longHelp) { - return new wxToolBarTool(this, id, bitmap1, bitmap2, toggle, - clientData, shortHelpString, longHelpString); + return new wxToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind, + clientData, shortHelp, longHelp); } wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control) @@ -221,20 +243,29 @@ bool wxToolBar::Create(wxWindow *parent, return FALSE; // prepare flags - DWORD msflags = 0; // WS_VISIBLE | WS_CHILD always included + DWORD msflags = TBSTYLE_TOOLTIPS; // WS_VISIBLE | WS_CHILD always included if ( style & wxCLIP_SIBLINGS ) msflags |= WS_CLIPSIBLINGS; -#ifdef TBSTYLE_TOOLTIPS - msflags |= TBSTYLE_TOOLTIPS; -#endif - - if (style & wxTB_FLAT) + if ( style & wxTB_FLAT ) { - if (wxTheApp->GetComCtl32Version() > 400) - msflags |= TBSTYLE_FLAT; + // static as it doesn't change during the program lifetime + static int s_verComCtl = wxTheApp->GetComCtl32Version(); + + // comctl32.dll 4.00 doesn't support the flat toolbars and using this + // style with 6.00 (part of Windows XP) leads to the toolbar with + // incorrect background colour - and not using it still results in the + // correct (flat) toolbar, so don't use it there + if ( s_verComCtl > 400 && s_verComCtl < 600 ) + { + msflags |= TBSTYLE_FLAT | TBSTYLE_TRANSPARENT; + } } + if (style & wxTB_NODIVIDER) + msflags |= CCS_NODIVIDER; + if (style & wxTB_NOALIGN) + msflags |= CCS_NOPARENTALIGN; // MSW-specific initialisation if ( !wxControl::MSWCreateControl(TOOLBARCLASSNAME, msflags) ) @@ -244,9 +275,7 @@ bool wxToolBar::Create(wxWindow *parent, ::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); // set up the colors and fonts - wxRGBToColour(m_backgroundColour, GetSysColor(COLOR_BTNFACE)); - m_foregroundColour = *wxBLACK; - + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR)); SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); // position it @@ -438,12 +467,12 @@ bool wxToolBar::Realize() wxToolBarToolBase *tool = node->GetData(); if ( tool->IsButton() ) { - const wxBitmap& bmp = tool->GetBitmap1(); + const wxBitmap& bmp = tool->GetNormalBitmap(); if ( bmp.Ok() ) { #if USE_BITMAP_MASKS // notice the last parameter: do use mask - dcAllButtons.DrawBitmap(tool->GetBitmap1(), x, 0, TRUE); + dcAllButtons.DrawBitmap(bmp, x, 0, TRUE); #else // !USE_BITMAP_MASKS HBITMAP hbmp = GetHbitmapOf(bmp); HBITMAP oldBitmap2 = (HBITMAP)::SelectObject(memoryDC2, hbmp); @@ -531,7 +560,6 @@ bool wxToolBar::Realize() wxLogDebug(wxT("TB_DELETEBUTTON failed")); } } - } if ( addBitmap ) // no old bitmap or we can't replace it @@ -554,6 +582,7 @@ bool wxToolBar::Realize() // this array will hold the indices of all controls in the toolbar wxArrayInt controlIds; + bool lastWasRadio = FALSE; int i = 0; for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) { @@ -567,6 +596,7 @@ bool wxToolBar::Realize() wxZeroMemory(button); + bool isRadio = FALSE; switch ( tool->GetStyle() ) { case wxTOOL_STYLE_CONTROL: @@ -580,6 +610,12 @@ bool wxToolBar::Realize() case wxTOOL_STYLE_BUTTON: button.iBitmap = bitmapId; + + if ( HasFlag(wxTB_TEXT) && !tool->GetLabel().empty() ) + { + button.iString = (int)tool->GetLabel().c_str(); + } + button.idCommand = tool->GetId(); if ( tool->IsEnabled() ) @@ -587,18 +623,46 @@ bool wxToolBar::Realize() if ( tool->IsToggled() ) button.fsState |= TBSTATE_CHECKED; - button.fsStyle = tool->CanBeToggled() ? TBSTYLE_CHECK - : TBSTYLE_BUTTON; + switch ( tool->GetKind() ) + { + case wxITEM_RADIO: + button.fsStyle = TBSTYLE_CHECKGROUP; + + if ( !lastWasRadio ) + { + // the first item in the radio group is checked by + // default to be consistent with wxGTK and the menu + // radio items + button.fsState |= TBSTATE_CHECKED; + + tool->Toggle(TRUE); + } + + isRadio = TRUE; + break; + + case wxITEM_CHECK: + button.fsStyle = TBSTYLE_CHECK; + break; + + default: + wxFAIL_MSG( _T("unexpected toolbar button kind") ); + // fall through + + case wxITEM_NORMAL: + button.fsStyle = TBSTYLE_BUTTON; + } bitmapId++; break; } + lastWasRadio = isRadio; + i++; } - if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS, - (WPARAM)i, (LPARAM)buttons) ) + if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS, (WPARAM)i, (LPARAM)buttons) ) { wxLogLastError(wxT("TB_ADDBUTTONS")); } @@ -771,15 +835,20 @@ bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id) bool toggled = tool->IsToggled(); - // OnLeftClick() can veto the button state change - for buttons which may - // be toggled only, of couse - if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() ) + // avoid sending the event when a radio button is released, this is not + // interesting + if ( !tool->CanBeToggled() || tool->GetKind() != wxITEM_RADIO || toggled ) { - // revert back - toggled = !toggled; - tool->SetToggle(toggled); + // OnLeftClick() can veto the button state change - for buttons which + // may be toggled only, of couse + if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() ) + { + // revert back + toggled = !toggled; + tool->SetToggle(toggled); - ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0)); + ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0)); + } } return TRUE; @@ -970,6 +1039,67 @@ void wxToolBar::UpdateSize() } } +// ---------------------------------------------------------------------------- +// toolbar styles +// --------------------------------------------------------------------------- + +void wxToolBar::SetWindowStyleFlag(long style) +{ + // there doesn't seem to be any reasonably simple way to prevent the + // toolbar from showing the icons so for now we don't honour wxTB_NOICONS + if ( (style & wxTB_TEXT) != (GetWindowStyle() & wxTB_TEXT) ) + { + // update the strings of all toolbar buttons + // + // NB: we can only do it using TB_SETBUTTONINFO which is available + // in comctl32.dll >= 4.71 only +#if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 ) + if ( wxTheApp->GetComCtl32Version() >= 471 ) + { + // set the (underlying) separators width to be that of the + // control + TBBUTTONINFO tbbi; + tbbi.cbSize = sizeof(tbbi); + tbbi.dwMask = TBIF_TEXT; + if ( !(style & wxTB_TEXT) ) + { + // don't show the text - remove the labels + tbbi.pszText = NULL; + } + + for ( wxToolBarToolsList::Node *node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + wxToolBarToolBase *tool = node->GetData(); + if ( !tool->IsButton() ) + { + continue; + } + + if ( style & wxTB_TEXT ) + { + // cast is harmless + tbbi.pszText = (wxChar *)tool->GetLabel().c_str(); + } + + if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO, + tool->GetId(), (LPARAM)&tbbi) ) + { + // the id is probably invalid? + wxLogLastError(wxT("TB_SETBUTTONINFO")); + } + } + + UpdateSize(); + Refresh(); + } +#endif // comctl32.dll 4.71 + } + + wxToolBarBase::SetWindowStyleFlag(style); +} + // ---------------------------------------------------------------------------- // tool state // ---------------------------------------------------------------------------- @@ -1030,69 +1160,191 @@ void wxToolBar::OnMouseEvent(wxMouseEvent& event) } } -long wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +bool wxToolBar::HandleSize(WXWPARAM wParam, WXLPARAM lParam) { - if ( nMsg == WM_SIZE ) + // calculate our minor dimenstion ourselves - we're confusing the standard + // logic (TB_AUTOSIZE) with our horizontal toolbars and other hacks + RECT r; + if ( ::SendMessage(GetHwnd(), TB_GETITEMRECT, 0, (LPARAM)&r) ) { - // calculate our minor dimenstion ourselves - we're confusing the - // standard logic (TB_AUTOSIZE) with our horizontal toolbars and other - // hacks - RECT r; - if ( ::SendMessage(GetHwnd(), TB_GETITEMRECT, 0, (LPARAM)&r) ) - { - int w, h; + int w, h; - if ( GetWindowStyle() & wxTB_VERTICAL ) + if ( GetWindowStyle() & wxTB_VERTICAL ) + { + w = r.right - r.left; + if ( m_maxRows ) { - w = r.right - r.left; - if ( m_maxRows ) - { - w *= (m_nButtons + m_maxRows - 1)/m_maxRows; - } - h = HIWORD(lParam); + w *= (m_nButtons + m_maxRows - 1)/m_maxRows; } + h = HIWORD(lParam); + } + else + { + w = LOWORD(lParam); + if (HasFlag( wxTB_FLAT )) + h = r.bottom - r.top - 3; else - { - w = LOWORD(lParam); h = r.bottom - r.top; - if ( m_maxRows ) - { - h += 6; // FIXME: this is the separator line height... - h *= m_maxRows; - } - } - - if ( MAKELPARAM(w, h) != lParam ) + if ( m_maxRows ) { - // size really changed - SetSize(w, h); + // FIXME: 6 is hardcoded separator line height... + //h += 6; + if (HasFlag(wxTB_NODIVIDER)) + h += 3; + else + h += 6; + h *= m_maxRows; } + } - // message processed - return 0; + if ( MAKELPARAM(w, h) != lParam ) + { + // size really changed + SetSize(w, h); } + + // message processed + return TRUE; } - else if ( nMsg == WM_MOUSEMOVE ) + + return FALSE; +} + +bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam) +{ + // erase any dummy separators which we used for aligning the controls if + // any here + + // first of all, do we have any controls at all? + wxToolBarToolsList::Node *node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) { - wxCoord x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam); - wxToolBarToolBase* tool = FindToolForPosition( x, y ); + if ( node->GetData()->IsControl() ) + break; + } - // cursor left current tool - if( tool != m_pInTool && !tool ) - { - m_pInTool = 0; - OnMouseEnter( -1 ); - } + if ( !node ) + { + // no controls, nothing to erase + return FALSE; + } - // cursor entered a tool - if( tool != m_pInTool && tool ) + // prepare the DC on which we'll be drawing + wxClientDC dc(this); + dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID)); + dc.SetPen(*wxTRANSPARENT_PEN); + + RECT r; + if ( !GetUpdateRect(GetHwnd(), &r, FALSE) ) + { + // nothing to redraw anyhow + return FALSE; + } + + wxRect rectUpdate; + wxCopyRECTToRect(r, rectUpdate); + + dc.SetClippingRegion(rectUpdate); + + // draw the toolbar tools, separators &c normally + wxControl::MSWWindowProc(WM_PAINT, wParam, lParam); + + // for each control in the toolbar find all the separators intersecting it + // and erase them + // + // NB: this is really the only way to do it as we don't know if a separator + // corresponds to a control (i.e. is a dummy one) or a real one + // otherwise + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + wxToolBarToolBase *tool = node->GetData(); + if ( tool->IsControl() ) { - m_pInTool = tool; - OnMouseEnter( tool->GetId() ); + // get the control rect in our client coords + wxControl *control = tool->GetControl(); + wxRect rectCtrl = control->GetRect(); + + // iterate over all buttons + TBBUTTON tbb; + int count = ::SendMessage(GetHwnd(), TB_BUTTONCOUNT, 0, 0); + for ( int n = 0; n < count; n++ ) + { + // is it a separator? + if ( !::SendMessage(GetHwnd(), TB_GETBUTTON, + n, (LPARAM)&tbb) ) + { + wxLogDebug(_T("TB_GETBUTTON failed?")); + + continue; + } + + if ( tbb.fsStyle != TBSTYLE_SEP ) + continue; + + // get the bounding rect of the separator + RECT r; + if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, + n, (LPARAM)&r) ) + { + wxLogDebug(_T("TB_GETITEMRECT failed?")); + + continue; + } + + // does it intersect the control? + wxRect rectItem; + wxCopyRECTToRect(r, rectItem); + if ( rectCtrl.Intersects(rectItem) ) + { + // yes, do erase it! + dc.DrawRectangle(rectItem); + } + } } + } + + return TRUE; +} + +void wxToolBar::HandleMouseMove(WXWPARAM wParam, WXLPARAM lParam) +{ + wxCoord x = GET_X_LPARAM(lParam), + y = GET_Y_LPARAM(lParam); + wxToolBarToolBase* tool = FindToolForPosition( x, y ); + + // cursor left current tool + if( tool != m_pInTool && !tool ) + { + m_pInTool = 0; + OnMouseEnter( -1 ); + } + + // cursor entered a tool + if( tool != m_pInTool && tool ) + { + m_pInTool = tool; + OnMouseEnter( tool->GetId() ); + } +} + +long wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + switch ( nMsg ) + { + case WM_SIZE: + if ( HandleSize(wParam, lParam) ) + return 0; + break; + + case WM_MOUSEMOVE: + // we don't handle mouse moves, so always pass the message to + // wxControl::MSWWindowProc + HandleMouseMove(wParam, lParam); + break; - // we don't handle mouse moves, so fall through - // to wxControl::MSWWindowProc + case WM_PAINT: + if ( HandlePaint(wParam, lParam) ) + return 0; } return wxControl::MSWWindowProc(nMsg, wParam, lParam);