diff --git a/src/msw/toolbar.cpp b/src/msw/toolbar.cpp index a9f9dfb6b3..2cdf24f9b1 100644 --- a/src/msw/toolbar.cpp +++ b/src/msw/toolbar.cpp @@ -165,17 +165,7 @@ public: if ( IsControl() && !m_label.empty() ) { // Create a control to render the control's label. - // It has the same witdh as the control. - wxSize size(control->GetSize().GetWidth(), wxDefaultCoord); - m_staticText = new wxStaticText - ( - m_tbar, - wxID_ANY, - m_label, - wxDefaultPosition, - size, - wxALIGN_CENTRE | wxST_NO_AUTORESIZE - ); + m_staticText = new wxStaticText(m_tbar, wxID_ANY, m_label); } else // no label { @@ -1057,6 +1047,7 @@ bool wxToolBar::Realize() // this array will hold the indices of all controls in the toolbar wxArrayInt controlIds; + int minReqHeight = 0; bool lastWasRadio = false; int i = 0; for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) @@ -1071,16 +1062,11 @@ bool wxToolBar::Realize() switch ( tool->GetStyle() ) { case wxTOOL_STYLE_CONTROL: - if ( wxStaticText *staticText = tool->GetStaticText() ) - { - staticText->Show(AreControlLabelsShown()); - } - - // Set separator width/height to fit the control width/height - // taking into account tool padding value. - // (height is not used but it is set for the sake of consistency). + if ( !IsVertical() ) { const wxSize size = MSWGetFittingtSizeForControl(tool); + if ( minReqHeight < size.y ) + minReqHeight = size.y; button.iBitmap = size.x; } @@ -1197,6 +1183,15 @@ bool wxToolBar::Realize() break; } + if ( IsVertical() ) + { + // MSDN says that TBSTATE_WRAP should be used for all buttons in + // vertical toolbars, so do it even if it doesn't seem to actually + // change anything in practice (including the problem with + // TB_AUTOSIZE mentioned in UpdateSize()). + button.fsState |= TBSTATE_WRAP; + } + lastWasRadio = isRadio; i++; @@ -1208,6 +1203,24 @@ bool wxToolBar::Realize() } + // Make sure the toolbar is tall enough to fit the embedded controls, which + // may be taller than the buttons. + wxSize toolSize = GetToolSize(); + if ( toolSize.y < minReqHeight ) + { + toolSize.y = minReqHeight; + + // Surprisingly, we need to send TB_AUTOSIZE before TB_SETBUTTONSIZE + // and not after it, as might be expected: otherwise, the button size + // remains unchanged (doing TB_AUTOSIZE later doesn't seem to do any + // harm but doesn't change the button size neither). + ::SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0); + + ::SendMessage(GetHwnd(), TB_SETBUTTONSIZE, + 0, MAKELPARAM(toolSize.x, toolSize.y)); + } + + // Adjust controls and stretchable spaces // -------------------------------------- @@ -1243,58 +1256,52 @@ bool wxToolBar::Realize() // good and wxGTK doesn't do it neither (and the code below can't // deal with this case) control->Hide(); + if ( wxStaticText * const staticText = tool->GetStaticText() ) + staticText->Hide(); continue; } control->Show(); - wxStaticText * const staticText = tool->GetStaticText(); - wxSize size = control->GetSize(); - wxSize staticTextSize; - if ( staticText && staticText->IsShown() ) - { - staticTextSize = staticText->GetSize(); - staticTextSize.y += MARGIN_CONTROL_LABEL; - } - - // position the control itself correctly vertically centering it on the - // icon area of the toolbar - int height = r.bottom - r.top - staticTextSize.y; - - int diff = height - size.y; - if ( diff < 0 || !HasFlag(wxTB_TEXT) ) - { - // not enough room for the static text - if ( staticText ) - staticText->Hide(); - - // recalculate height & diff without the staticText control - height = r.bottom - r.top; - diff = height - size.y; - if ( diff < 0 ) - { - // the control is too high, resize to fit - // Actually don't set the size, otherwise we can never fit - // the toolbar around the controls. - // control->SetSize(wxDefaultCoord, height - 2); - - diff = 2; - } - } - else // enough space for both the control and the label - { - if ( staticText ) - staticText->Show(); - } + const wxSize controlSize = control->GetSize(); // Take also into account tool padding value. - control->Move(r.left + m_toolPacking/2, r.top + (diff + 1) / 2); - if ( staticText ) + const int x = r.left + m_toolPacking/2; + const int height = r.bottom - r.top; + + // Greater of control and its label widths. + int totalWidth = controlSize.x; + + // Height of control and its label, if any, including the margin + // between them. + int totalHeight = controlSize.y; + + if ( wxStaticText * const staticText = tool->GetStaticText() ) { - staticText->Move(r.left + m_toolPacking/2 + (size.x - staticTextSize.x)/2, - r.bottom - staticTextSize.y); + const bool shown = AreControlLabelsShown(); + staticText->Show(shown); + + if ( shown ) + { + const wxSize staticTextSize = staticText->GetSize(); + + if ( staticTextSize.x > totalWidth ) + totalWidth = staticTextSize.x; + + // Center the static text horizontally for consistency with the + // button labels and position it below the control vertically. + staticText->Move(x + (totalWidth - staticTextSize.x)/2, + r.top + (height + controlSize.y + - staticTextSize.y + + MARGIN_CONTROL_LABEL)/2); + + totalHeight += staticTextSize.y + MARGIN_CONTROL_LABEL; + } } + control->Move(x + (totalWidth - controlSize.x)/2, + r.top + (height - totalHeight)/2); + m_totalFixedSize += r.right - r.left; } @@ -1638,14 +1645,25 @@ void wxToolBar::SetRows(int nRows) const bool enable = (!IsVertical() && m_maxRows == 1) || (IsVertical() && (size_t)m_maxRows == m_nButtons); - const LPARAM state = MAKELONG(enable ? TBSTATE_ENABLED : TBSTATE_HIDDEN, 0); + LPARAM state = enable ? TBSTATE_ENABLED : TBSTATE_HIDDEN; + + if ( IsVertical() ) + { + // As in Realize(), ensure that TBSTATE_WRAP is used for all the + // tools, including separators, in vertical toolbar, and here it does + // make a difference: without it, the following tools wouldn't be + // visible because they would be on the same row as the separator. + state |= TBSTATE_WRAP; + } + wxToolBarToolsList::compatibility_iterator node; for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) { wxToolBarTool * const tool = (wxToolBarTool*)node->GetData(); if ( tool->IsStretchableSpace() ) { - if ( !::SendMessage(GetHwnd(), TB_SETSTATE, tool->GetId(), state) ) + if ( !::SendMessage(GetHwnd(), TB_SETSTATE, + tool->GetId(), MAKELONG(state, 0)) ) { wxLogLastError(wxT("TB_SETSTATE (stretchable spacer)")); } @@ -1683,6 +1701,40 @@ void wxToolBar::UpdateSize() { wxPoint pos = GetPosition(); ::SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0); + + // TB_AUTOSIZE doesn't seem to work for vertical toolbars which it resizes + // to have the same width as a horizontal toolbar would have, even though + // we do use TBSTATE_WRAP which should make it start a new row after each + // tool. So override its width determination explicitly. + if ( IsVertical() ) + { + // Find the widest tool in the toolbar. + int maxWidth = 0; + + int i = 0; + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext(), ++i ) + { + wxToolBarTool * const tool = (wxToolBarTool*)node->GetData(); + if ( tool->IsSeparator() ) + { + // Somehow, separators get resized to have huge width, which + // probably explains why TB_AUTOSIZE doesn't work correctly for + // us in the first place. Because of this, don't take them into + // account: they can't be wider than any normal button, anyhow. + continue; + } + + const RECT rc = wxGetTBItemRect(GetHwnd(), i); + const int width = rc.right - rc.left; + if ( width > maxWidth ) + maxWidth = width; + } + + SetSize(maxWidth, GetSize().y); + } + if (pos != GetPosition()) Move(pos); @@ -1867,115 +1919,12 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event) #endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK } -bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam) +bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM WXUNUSED(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 - // Find bounding box for all rows. - RECT r; - ::SetRectEmpty(&r); - // Bounding box for single (current) row - RECT rcRow; - ::SetRectEmpty(&rcRow); - int rowPosX = INT_MIN; - wxToolBarToolsList::compatibility_iterator node; - int i = 0; - for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) - { - wxToolBarTool * const - tool = static_cast(node->GetData()); - if ( tool->IsToBeDeleted() ) - continue; - - // Skip hidden buttons - const RECT rcItem = wxGetTBItemRect(GetHwnd(), i); - if ( ::IsRectEmpty(&rcItem) ) - { - i++; - continue; - } - - if ( rcItem.top > rowPosX ) - { - // We have the next row. - rowPosX = rcItem.top; - - // Shift origin to (0, 0) to make it the same as for the total rect. - ::OffsetRect(&rcRow, -rcRow.left, -rcRow.top); - - // And update the bounding box for all rows. - ::UnionRect(&r, &r, &rcRow); - - // Reset the current row bounding box for the next row. - ::SetRectEmpty(&rcRow); - } - - // Separators shouldn't be taken into account as they are sometimes - // reported to have the width of the entire client area by the toolbar. - // And we know that they are not the biggest items in the toolbar in - // any case, so just skip them. - if( !tool->IsSeparator() ) - { - // Update bounding box of current row - ::UnionRect(&rcRow, &rcRow, &rcItem); - } - - i++; - } - - // Take into account the last row rectangle too. - ::OffsetRect(&rcRow, -rcRow.left, -rcRow.top); - ::UnionRect(&r, &r, &rcRow); - - if ( !r.right ) - return false; - - int w, h; - - if ( IsVertical() ) - { - w = r.right - r.left; - h = HIWORD(lParam); - } - else - { - w = LOWORD(lParam); - if (HasFlag( wxTB_FLAT )) - h = r.bottom - r.top - 3; - else - h = r.bottom - r.top; - - // Take control height into account - for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) - { - wxToolBarTool * const - tool = static_cast(node->GetData()); - if (tool->IsControl()) - { - int y = (tool->GetControl()->GetSize().y - 2); // -2 since otherwise control height + 4 (below) is too much - if (y > h) - h = y; - } - } - - if ( m_maxRows ) - { - // FIXME: hardcoded separator line height... - h += HasFlag(wxTB_NODIVIDER) ? 4 : 6; - h *= m_maxRows; - } - } - - if ( MAKELPARAM(w, h) != lParam ) - { - // size really changed - SetSize(w, h); - } - UpdateStretchableSpacersSize(); // message processed