X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7474e2cb62228a7921ff3a0595019c03efe40be3..c616c2e834192db06bbef18b9404824f563e335f:/src/msw/tbar95.cpp?ds=sidebyside diff --git a/src/msw/tbar95.cpp b/src/msw/tbar95.cpp index f03cfbd04b..1b69f1db05 100644 --- a/src/msw/tbar95.cpp +++ b/src/msw/tbar95.cpp @@ -17,10 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "tbar95.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -39,10 +35,11 @@ #include "wx/control.h" #endif -#if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE && (!defined(_WIN32_WCE) || (_WIN32_WCE >= 400 && !defined(__POCKETPC__) && !defined(__SMARTPHONE__))) +#if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE && !defined(__SMARTPHONE__) #include "wx/toolbar.h" #include "wx/sysopt.h" +#include "wx/image.h" #include "wx/msw/private.h" @@ -92,9 +89,6 @@ // these values correspond to those used by comctl32.dll #define DEFAULTBITMAPX 16 #define DEFAULTBITMAPY 15 -#define DEFAULTBUTTONX 24 -#define DEFAULTBUTTONY 24 -#define DEFAULTBARHEIGHT 27 // ---------------------------------------------------------------------------- // wxWin macros @@ -213,6 +207,7 @@ wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control) void wxToolBar::Init() { m_hBitmap = 0; + m_disabledImgList = NULL; m_nButtons = 0; @@ -243,25 +238,17 @@ bool wxToolBar::Create(wxWindow *parent, SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - // workaround for flat toolbar on Windows XP classic style + // workaround for flat toolbar on Windows XP classic style: we have to set + // the style after creating the control; doing it at creation time doesn't work #if wxUSE_UXTHEME if ( style & wxTB_FLAT ) { - wxUxThemeEngine *p = wxUxThemeEngine::Get(); - if ( !p || !p->IsThemeActive() ) - { - DWORD dwToolbarStyle; - - dwToolbarStyle = (DWORD)::SendMessage(GetHwnd(), TB_GETSTYLE, 0, 0L ); + LRESULT style = ::SendMessage(GetHwnd(), TB_GETSTYLE, 0, 0L); - if ((dwToolbarStyle & TBSTYLE_FLAT) == 0) - { - dwToolbarStyle |= TBSTYLE_FLAT; - ::SendMessage(GetHwnd(), TB_SETSTYLE, 0, (LPARAM)dwToolbarStyle ); - } - } + if ( !(style & TBSTYLE_FLAT) ) + ::SendMessage(GetHwnd(), TB_SETSTYLE, 0, style | TBSTYLE_FLAT); } -#endif +#endif // wxUSE_UXTHEME return true; } @@ -310,8 +297,8 @@ void wxToolBar::Recreate() ::SetParent(GetHwndOf(win), GetHwnd()); } - // only destroy the old toolbar now -- after all the children had been - // reparented + // only destroy the old toolbar now -- + // after all the children had been reparented ::DestroyWindow(hwndOld); // it is for the old bitmap control and can't be used with the new one @@ -321,8 +308,13 @@ void wxToolBar::Recreate() m_hBitmap = 0; } + if ( m_disabledImgList ) + { + delete m_disabledImgList; + m_disabledImgList = NULL; + } + Realize(); - UpdateSize(); } wxToolBar::~wxToolBar() @@ -331,14 +323,12 @@ wxToolBar::~wxToolBar() // 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(); - } if ( m_hBitmap ) - { ::DeleteObject((HBITMAP) m_hBitmap); - } + + delete m_disabledImgList; } wxSize wxToolBar::DoGetBestSize() const @@ -368,6 +358,8 @@ wxSize wxToolBar::DoGetBestSize() const sizeBest.y = size.cy; } + CacheBestSize(sizeBest); + return sizeBest; } @@ -380,28 +372,24 @@ WXDWORD wxToolBar::MSWGetStyle(long style, WXDWORD *exstyle) const (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle ); - // always include this one, it never hurts and setting it later only if we - // do have tooltips wouldn't work + // always include this one, it never hurts and setting it later + // only if we do have tooltips wouldn't work msStyle |= TBSTYLE_TOOLTIPS; if ( style & (wxTB_FLAT | wxTB_HORZ_LAYOUT) ) { // static as it doesn't change during the program lifetime - static int s_verComCtl = wxTheApp->GetComCtl32Version(); + static int s_verComCtl = wxApp::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 ) - { msStyle |= TBSTYLE_FLAT | TBSTYLE_TRANSPARENT; - } if ( s_verComCtl >= 470 && style & wxTB_HORZ_LAYOUT ) - { msStyle |= TBSTYLE_LIST; - } } if ( style & wxTB_NODIVIDER ) @@ -452,9 +440,7 @@ bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool) } if ( tool2->IsControl() ) - { pos += ((wxToolBarTool *)tool2)->GetSeparatorsCount() - 1; - } } // now determine the number of buttons to delete and the area taken by them @@ -472,7 +458,6 @@ bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool) if ( tool->IsControl() ) { nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount(); - width *= nButtonsToDelete; } @@ -505,32 +490,70 @@ bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool) } InvalidateBestSize(); + return true; } +void wxToolBar::CreateDisabledImageList() +{ + if (m_disabledImgList != NULL) + { + delete m_disabledImgList; + m_disabledImgList = NULL; + } + + // as we can't use disabled image list with older versions of comctl32.dll, + // don't even bother creating it + if ( wxTheApp->GetComCtl32Version() >= 470 ) + { + // search for the first disabled button img in the toolbar, if any + for ( wxToolBarToolsList::compatibility_iterator + node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + wxToolBarToolBase *tool = node->GetData(); + wxBitmap bmpDisabled = tool->GetDisabledBitmap(); + if ( bmpDisabled.Ok() ) + { + m_disabledImgList = new wxImageList + ( + m_defaultWidth, + m_defaultHeight, + bmpDisabled.GetMask() != NULL, + GetToolsCount() + ); + break; + } + } + + // we don't have any disabled bitmaps + } +} + bool wxToolBar::Realize() { const size_t nTools = GetToolsCount(); if ( nTools == 0 ) - { // nothing to do return true; - } const bool isVertical = HasFlag(wxTB_VERTICAL); bool doRemap, doRemapBg, doTransparent; - if (wxSystemOptions::GetOptionInt(wxT("msw.remap")) == 2) + doRemapBg = doRemap = doTransparent = false; + +#ifndef __WXWINCE__ + int remapValue = (-1); + const wxChar *remapOptionStr = wxT("msw.remap"); + if (wxSystemOptions::HasOption( remapOptionStr )) + remapValue = wxSystemOptions::GetOptionInt( remapOptionStr ); + + doTransparent = (remapValue == 2); + if (!doTransparent) { - doRemapBg = doRemap = false; - doTransparent = true; - } - else - { doRemap = !wxSystemOptions::HasOption(wxT("msw.remap")) - || wxSystemOptions::GetOptionInt(wxT("msw.remap")) == 1; + doRemap = (remapValue != 0); doRemapBg = !doRemap; - doTransparent = false; } +#endif // delete all old buttons, if any for ( size_t pos = 0; pos < m_nButtons; pos++ ) @@ -563,22 +586,29 @@ bool wxToolBar::Realize() sizeBmp.x = m_defaultWidth; sizeBmp.y = m_defaultHeight; - const wxCoord totalBitmapWidth = m_defaultWidth * nTools, + const wxCoord totalBitmapWidth = m_defaultWidth * + wx_truncate_cast(wxCoord, nTools), totalBitmapHeight = m_defaultHeight; - // Create a bitmap and copy all the tool bitmaps to it + // Create a bitmap and copy all the tool bitmaps into it wxMemoryDC dcAllButtons; wxBitmap bitmap(totalBitmapWidth, totalBitmapHeight); dcAllButtons.SelectObject(bitmap); + +#ifndef __WXWINCE__ if (doTransparent) dcAllButtons.SetBackground(*wxTRANSPARENT_BRUSH); else - dcAllButtons.SetBackground(*wxLIGHT_GREY_BRUSH); + dcAllButtons.SetBackground(wxBrush(GetBackgroundColour())); +#else + dcAllButtons.SetBackground(wxBrush(wxColour(192,192,192))); +#endif dcAllButtons.Clear(); m_hBitmap = bitmap.GetHBITMAP(); HBITMAP hBitmap = (HBITMAP)m_hBitmap; +#ifndef __WXWINCE__ if (doRemapBg) { dcAllButtons.SelectObject(wxNullBitmap); @@ -590,6 +620,7 @@ bool wxToolBar::Realize() dcAllButtons.SelectObject(bitmap); } +#endif // !__WXWINCE__ // the button position wxCoord x = 0; @@ -597,24 +628,70 @@ bool wxToolBar::Realize() // the number of buttons (not separators) int nButtons = 0; + CreateDisabledImageList(); for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) { wxToolBarToolBase *tool = node->GetData(); if ( tool->IsButton() ) { const wxBitmap& bmp = tool->GetNormalBitmap(); + + const int w = bmp.GetWidth(); + const int h = bmp.GetHeight(); + if ( bmp.Ok() ) { - int xOffset = wxMax(0, (m_defaultWidth - bmp.GetWidth())/2); - int yOffset = wxMax(0, (m_defaultHeight - bmp.GetHeight())/2); + int xOffset = wxMax(0, (m_defaultWidth - w)/2); + int yOffset = wxMax(0, (m_defaultHeight - h)/2); + // notice the last parameter: do use mask - dcAllButtons.DrawBitmap(bmp, x+xOffset, yOffset, true); + dcAllButtons.DrawBitmap(bmp, x + xOffset, yOffset, true); } else { wxFAIL_MSG( _T("invalid tool button bitmap") ); } + // also deal with disabled bitmap if we want to use them + if ( m_disabledImgList ) + { + wxBitmap bmpDisabled = tool->GetDisabledBitmap(); +#if wxUSE_IMAGE + if ( !bmpDisabled.Ok() ) + { + // no disabled bitmap specified but we still need to + // fill the space in the image list with something, so + // we grey out the normal bitmap + wxImage imgGreyed; + wxCreateGreyedImage(bmp.ConvertToImage(), imgGreyed); + + if (doRemap) + { + // we need to have light grey background colour for + // MapBitmap() to work correctly + for ( int y = 0; y < h; y++ ) + { + for ( int x = 0; x < w; x++ ) + { + if ( imgGreyed.IsTransparent(x, y) ) + imgGreyed.SetRGB(x, y, + wxLIGHT_GREY->Red(), + wxLIGHT_GREY->Green(), + wxLIGHT_GREY->Blue()); + } + } + } + + bmpDisabled = wxBitmap(imgGreyed); + } +#endif // wxUSE_IMAGE + + if (doRemap) + MapBitmap(bmpDisabled.GetHBITMAP(), w, h); + + m_disabledImgList->Add(bmpDisabled); + } + // still inc width and number of buttons because otherwise the // subsequent buttons will all be shifted which is rather confusing // (and like this you'd see immediately which bitmap was bad) @@ -640,7 +717,7 @@ bool wxToolBar::Realize() if ( oldToolBarBitmap ) { #ifdef TB_REPLACEBITMAP - if ( wxTheApp->GetComCtl32Version() >= 400 ) + if ( wxApp::GetComCtl32Version() >= 400 ) { TBREPLACEBITMAP replaceBitmap; replaceBitmap.hInstOld = NULL; @@ -682,6 +759,19 @@ bool wxToolBar::Realize() wxFAIL_MSG(wxT("Could not add bitmap to toolbar")); } } + + if ( m_disabledImgList ) + { + HIMAGELIST oldImageList = (HIMAGELIST) + ::SendMessage(GetHwnd(), + TB_SETDISABLEDIMAGELIST, + 0, + (LPARAM)GetHimagelistOf(m_disabledImgList)); + + // delete previous image list if any + if ( oldImageList ) + ::DeleteObject( oldImageList ); + } } // don't call SetToolBitmapSize() as we don't want to change the values of @@ -709,12 +799,11 @@ bool wxToolBar::Realize() // don't add separators to the vertical toolbar with old comctl32.dll // versions as they didn't handle this properly if ( isVertical && tool->IsSeparator() && - wxTheApp->GetComCtl32Version() <= 472 ) + wxApp::GetComCtl32Version() <= 472 ) { continue; } - TBBUTTON& button = buttons[i]; wxZeroMemory(button); @@ -739,9 +828,7 @@ bool wxToolBar::Realize() { const wxString& label = tool->GetLabel(); if ( !label.empty() ) - { button.iString = (int)label.c_str(); - } } button.idCommand = tool->GetId(); @@ -763,7 +850,29 @@ bool wxToolBar::Realize() // radio items button.fsState |= TBSTATE_CHECKED; - tool->Toggle(true); + if (tool->Toggle(true)) + { + DoToggleTool(tool, true); + } + } + else if (tool->IsToggled()) + { + wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious(); + int prevIndex = i - 1; + while ( nodePrev ) + { + TBBUTTON& prevButton = buttons[prevIndex]; + wxToolBarToolBase *tool = nodePrev->GetData(); + if ( !tool->IsButton() || tool->GetKind() != wxITEM_RADIO ) + break; + + if ( tool->Toggle(false) ) + DoToggleTool(tool, false); + + prevButton.fsState = TBSTATE_ENABLED; + nodePrev = nodePrev->GetPrevious(); + prevIndex--; + } } isRadio = true; @@ -773,12 +882,14 @@ bool wxToolBar::Realize() button.fsStyle = TBSTYLE_CHECK; break; + case wxITEM_NORMAL: + button.fsStyle = TBSTYLE_BUTTON; + break; + default: wxFAIL_MSG( _T("unexpected toolbar button kind") ); - // fall through - - case wxITEM_NORMAL: button.fsStyle = TBSTYLE_BUTTON; + break; } bitmapId++; @@ -832,7 +943,6 @@ bool wxToolBar::Realize() } wxControl *control = tool->GetControl(); - wxSize size = control->GetSize(); // the position of the leftmost controls corner @@ -842,7 +952,7 @@ bool wxToolBar::Realize() #ifdef TB_SETBUTTONINFO // available in headers, now check whether it is available now // (during run-time) - if ( wxTheApp->GetComCtl32Version() >= 471 ) + if ( wxApp::GetComCtl32Version() >= 471 ) { // set the (underlying) separators width to be that of the // control @@ -908,7 +1018,7 @@ bool wxToolBar::Realize() left = 0; top = y; - y += height + 2*GetMargins().y; + y += height + 2 * GetMargins().y; } else // horizontal toolbar { @@ -928,21 +1038,20 @@ bool wxToolBar::Realize() if ( !isVertical ) { if ( m_maxRows == 0 ) - { // if not set yet, only one row SetRows(1); - } } else if ( m_nButtons > 0 ) // vertical non empty toolbar { if ( m_maxRows == 0 ) - { // if not set yet, have one column SetRows(m_nButtons); - } } InvalidateBestSize(); + SetBestFittingSize(); + UpdateSize(); + return true; } @@ -963,8 +1072,8 @@ bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id) 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 seem to - // happen at all, and is handled otherwise + // ignore the event when a radio button is released, as this doesn't + // seem to happen at all, and is handled otherwise if ( tool->GetKind() == wxITEM_RADIO && !toggled ) return true; @@ -979,7 +1088,7 @@ bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id) // revert back tool->Toggle(!toggled); - ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0)); + ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(!toggled, 0)); } return true; @@ -1012,6 +1121,8 @@ bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl), return HandleTooltipNotify(code, lParam, tool->GetShortHelp()); #else + wxUnusedVar(lParam); + return false; #endif } @@ -1054,7 +1165,7 @@ wxSize wxToolBar::GetToolSize() const #if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \ && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) \ && !defined (__DIGITALMARS__) - if ( wxTheApp->GetComCtl32Version() >= 470 ) + if ( wxApp::GetComCtl32Version() >= 470 ) { DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0); @@ -1074,7 +1185,7 @@ wxToolBarToolBase *GetItemSkippingDummySpacers(const wxToolBarToolsList& tools, { wxToolBarToolsList::compatibility_iterator current = tools.GetFirst(); - for ( ; current != 0; current = current->GetNext() ) + for ( ; current ; current = current->GetNext() ) { if ( index == 0 ) return current->GetData(); @@ -1097,22 +1208,22 @@ wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const pt.x = x; pt.y = y; int index = (int)::SendMessage(GetHwnd(), TB_HITTEST, 0, (LPARAM)&pt); + // MBN: when the point ( x, y ) is close to the toolbar border // 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; - } - // if comctl32 version < 4.71 wxToolBar95 adds dummy spacers -#if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 ) - if ( wxTheApp->GetComCtl32Version() >= 471 ) + // when TB_SETBUTTONINFO is available (both during compile- and run-time), + // we don't use the dummy separators hack +#ifdef TB_SETBUTTONINFO + if ( wxApp::GetComCtl32Version() >= 471 ) { return m_tools.Item((size_t)index)->GetData(); } else -#endif +#endif // TB_SETBUTTONINFO { return GetItemSkippingDummySpacers( m_tools, (size_t) index ); } @@ -1120,13 +1231,17 @@ wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const void wxToolBar::UpdateSize() { - // the toolbar size changed - ::SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0); + // In case Realize is called after the initial display (IOW the programmer + // may have rebuilt the toolbar) give the frame the option of resizing the + // 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. - // we must also refresh the frame after the toolbar size (possibly) changed wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); - if ( frame ) + if ( frame && frame->GetToolBar() == this ) { + // the toolbar size changed + ::SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0); frame->SendSizeEvent(); } } @@ -1237,7 +1352,7 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event) event.Skip(); return; } - + // notice that this 'dumb' implementation may cause flicker for some of the // controls in which case they should intercept wxEraseEvent and process it // themselves somehow @@ -1309,10 +1424,10 @@ bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam) bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam) { - // erase any dummy separators which we used for aligning the controls if - // any here + // erase any dummy separators which were used + // for aligning the controls if any here - // first of all, do we have any controls at all? + // first of all, are there any controls at all? wxToolBarToolsList::compatibility_iterator node; for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) { @@ -1321,10 +1436,8 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam) } if ( !node ) - { // no controls, nothing to erase return false; - } // prepare the DC on which we'll be drawing wxClientDC dc(this); @@ -1333,10 +1446,8 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam) RECT r; if ( !::GetUpdateRect(GetHwnd(), &r, FALSE) ) - { // nothing to redraw anyhow return false; - } wxRect rectUpdate; wxCopyRECTToRect(r, rectUpdate); @@ -1414,14 +1525,14 @@ void wxToolBar::HandleMouseMove(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam) wxToolBarToolBase* tool = FindToolForPosition( x, y ); // cursor left current tool - if( tool != m_pInTool && !tool ) + if ( tool != m_pInTool && !tool ) { m_pInTool = 0; OnMouseEnter( -1 ); } // cursor entered a tool - if( tool != m_pInTool && tool ) + if ( tool != m_pInTool && tool ) { m_pInTool = tool; OnMouseEnter( tool->GetId() ); @@ -1432,20 +1543,25 @@ WXLRESULT 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 + // wxControl::MSWWindowProc (HandleMouseMove just calls OnMouseEnter) HandleMouseMove(wParam, lParam); break; + case WM_SIZE: + if ( HandleSize(wParam, lParam) ) + return 0; + break; + +#ifndef __WXWINCE__ case WM_PAINT: if ( HandlePaint(wParam, lParam) ) return 0; +#endif + + default: + break; } return wxControl::MSWWindowProc(nMsg, wParam, lParam); @@ -1561,5 +1677,5 @@ WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height) #endif // 0 } -#endif // wxUSE_TOOLBAR && Win95 +#endif // wxUSE_TOOLBAR