// Modified by:
// Created: 04/01/98
// RCS-ID: $Id$
-// Copyright: (c) Julian Smart and Markus Holzem
-// Licence: wxWindows license
+// Copyright: (c) Julian Smart
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
#include "wx/msw/private.h"
-#ifndef __TWIN32__
-
-#if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__TWIN32__)) && !defined(__CYGWIN10__))
+#if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__))
#include <commctrl.h>
#else
#include "wx/msw/gnuwin32/extra.h"
#endif
-#endif // __TWIN32__
+#include "wx/msw/missing.h"
-#include "wx/msw/dib.h"
#include "wx/app.h" // for GetComCtl32Version
#if defined(__MWERKS__) && defined(__WXMSW__)
long style,
const wxString& name)
{
- // toolbars never have border, giving one to them results in broken
- // appearance
- style &= ~wxBORDER_MASK;
- style |= wxBORDER_NONE;
-
// common initialisation
if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
return FALSE;
- // prepare flags
- DWORD msflags = TBSTYLE_TOOLTIPS; // WS_VISIBLE | WS_CHILD always included
-
- if ( style & wxCLIP_SIBLINGS )
- msflags |= WS_CLIPSIBLINGS;
+ // MSW-specific initialisation
+ if ( !MSWCreateToolbar(pos, size) )
+ return FALSE;
- if ( style & wxTB_FLAT )
- {
- // static as it doesn't change during the program lifetime
- static int s_verComCtl = wxTheApp->GetComCtl32Version();
+ // set up the colors and fonts
+ SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR));
+ SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
- // 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;
+ return TRUE;
+}
- // MSW-specific initialisation
- if ( !wxControl::MSWCreateControl(TOOLBARCLASSNAME, msflags) )
+bool wxToolBar::MSWCreateToolbar(const wxPoint& pos, const wxSize& size)
+{
+ if ( !MSWCreateControl(TOOLBARCLASSNAME, wxEmptyString, pos, size) )
return FALSE;
// toolbar-specific post initialisation
::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
- // set up the colors and fonts
- SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR));
- SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
+ return TRUE;
+}
+
+void wxToolBar::Recreate()
+{
+ const HWND hwndOld = GetHwnd();
+ if ( !hwndOld )
+ {
+ // we haven't been created yet, no need to recreate
+ return;
+ }
+
+ // get the position and size before unsubclassing the old toolbar
+ const wxPoint pos = GetPosition();
+ const wxSize size = GetSize();
- // position it
- int x = pos.x;
- int y = pos.y;
- int width = size.x;
- int height = size.y;
+ UnsubclassWin();
- if (width <= 0)
- width = 100;
- if (height <= 0)
- height = m_defaultHeight;
- if (x < 0)
- x = 0;
- if (y < 0)
- y = 0;
+ if ( !MSWCreateToolbar(pos, size) )
+ {
+ // what can we do?
+ wxFAIL_MSG( _T("recreating the toolbar failed") );
- SetSize(x, y, width, height);
+ return;
+ }
- return TRUE;
+ // reparent all our children under the new toolbar
+ for ( wxWindowList::compatibility_iterator node = m_children.GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxWindow *win = node->GetData();
+ if ( !win->IsTopLevel() )
+ ::SetParent(GetHwndOf(win), GetHwnd());
+ }
+
+ // 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
+ if ( m_hBitmap )
+ {
+ ::DeleteObject((HBITMAP) m_hBitmap);
+ m_hBitmap = 0;
+ }
+
+ Realize();
+ UpdateSize();
}
wxToolBar::~wxToolBar()
}
}
+wxSize wxToolBar::DoGetBestSize() const
+{
+ wxSize sizeBest = GetToolSize();
+ sizeBest.x *= GetToolsCount();
+
+ // reverse horz and vertical components if necessary
+ return HasFlag(wxTB_VERTICAL) ? wxSize(sizeBest.y, sizeBest.x) : sizeBest;
+}
+
+WXDWORD wxToolBar::MSWGetStyle(long style, WXDWORD *exstyle) const
+{
+ // toolbars never have border, giving one to them results in broken
+ // appearance
+ WXDWORD msStyle = wxControl::MSWGetStyle
+ (
+ (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
+ 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();
+
+ // 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 )
+ msStyle |= CCS_NODIVIDER;
+
+ if ( style & wxTB_NOALIGN )
+ msStyle |= CCS_NOPARENTALIGN;
+
+ if ( style & wxTB_VERTICAL )
+ msStyle |= CCS_VERT;
+
+ return msStyle;
+}
+
// ----------------------------------------------------------------------------
// adding/removing tools
// ----------------------------------------------------------------------------
-bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos),
- wxToolBarToolBase *tool)
+bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
{
// nothing special to do here - we really create the toolbar buttons in
// Realize() later
// first determine the position of the first button to delete: it may be
// different from pos if we use several separators to cover the space used
// by a control
- wxToolBarToolsList::Node *node;
+ wxToolBarToolsList::compatibility_iterator node;
for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
{
wxToolBarToolBase *tool2 = node->GetData();
bool wxToolBar::Realize()
{
- size_t nTools = GetToolsCount();
+ const size_t nTools = GetToolsCount();
if ( nTools == 0 )
{
// nothing to do
return TRUE;
}
- bool isVertical = (GetWindowStyle() & wxTB_VERTICAL) != 0;
+ const bool isVertical = HasFlag(wxTB_VERTICAL);
+
+ // delete all old buttons, if any
+ for ( size_t pos = 0; pos < m_nButtons; pos++ )
+ {
+ if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
+ {
+ wxLogDebug(wxT("TB_DELETEBUTTON failed"));
+ }
+ }
// First, add the bitmap: we use one bitmap for all toolbar buttons
// ----------------------------------------------------------------
- // if we already have a bitmap, we'll replace the existing one - otherwise
- // we'll install a new one
- HBITMAP oldToolBarBitmap = (HBITMAP)m_hBitmap;
+ 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 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;
- int totalBitmapWidth = (int)(m_defaultWidth * nTools);
- int totalBitmapHeight = (int)m_defaultHeight;
+ const wxCoord totalBitmapWidth = m_defaultWidth * nTools,
+ totalBitmapHeight = m_defaultHeight;
- // Create a bitmap and copy all the tool bitmaps to it
+ // Create a bitmap and copy all the tool bitmaps to it
#if USE_BITMAP_MASKS
- wxMemoryDC dcAllButtons;
- wxBitmap bitmap(totalBitmapWidth, totalBitmapHeight);
- dcAllButtons.SelectObject(bitmap);
- dcAllButtons.SetBackground(*wxLIGHT_GREY_BRUSH);
- dcAllButtons.Clear();
-
- m_hBitmap = bitmap.GetHBITMAP();
- HBITMAP hBitmap = (HBITMAP)m_hBitmap;
+ wxMemoryDC dcAllButtons;
+ wxBitmap bitmap(totalBitmapWidth, totalBitmapHeight);
+ dcAllButtons.SelectObject(bitmap);
+ dcAllButtons.SetBackground(*wxLIGHT_GREY_BRUSH);
+ dcAllButtons.Clear();
+
+ m_hBitmap = bitmap.GetHBITMAP();
+ HBITMAP hBitmap = (HBITMAP)m_hBitmap;
#else // !USE_BITMAP_MASKS
- HBITMAP hBitmap = ::CreateCompatibleBitmap(ScreenHDC(),
- totalBitmapWidth,
- totalBitmapHeight);
- if ( !hBitmap )
- {
- wxLogLastError(_T("CreateCompatibleBitmap"));
+ HBITMAP hBitmap = ::CreateCompatibleBitmap(ScreenHDC(),
+ totalBitmapWidth,
+ totalBitmapHeight);
+ if ( !hBitmap )
+ {
+ wxLogLastError(_T("CreateCompatibleBitmap"));
- return FALSE;
- }
+ return FALSE;
+ }
- m_hBitmap = (WXHBITMAP)hBitmap;
+ m_hBitmap = (WXHBITMAP)hBitmap;
- HDC memoryDC = ::CreateCompatibleDC(NULL);
- HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, hBitmap);
+ MemoryHDC memoryDC;
+ SelectInHDC hdcSelector(memoryDC, hBitmap);
- HDC memoryDC2 = ::CreateCompatibleDC(NULL);
+ MemoryHDC memoryDC2;
#endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
- // the button position
- wxCoord x = 0;
+ // the button position
+ wxCoord x = 0;
- // the number of buttons (not separators)
- int nButtons = 0;
+ // the number of buttons (not separators)
+ int nButtons = 0;
- wxToolBarToolsList::Node *node = m_tools.GetFirst();
- while ( node )
- {
- wxToolBarToolBase *tool = node->GetData();
- if ( tool->IsButton() )
+ for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
{
- const wxBitmap& bmp = tool->GetNormalBitmap();
- if ( bmp.Ok() )
+ wxToolBarToolBase *tool = node->GetData();
+ if ( tool->IsButton() )
{
+ const wxBitmap& bmp = tool->GetNormalBitmap();
+ if ( bmp.Ok() )
+ {
#if USE_BITMAP_MASKS
- // notice the last parameter: do use mask
- dcAllButtons.DrawBitmap(bmp, x, 0, TRUE);
+ // notice the last parameter: do use mask
+ dcAllButtons.DrawBitmap(bmp, x, 0, TRUE);
#else // !USE_BITMAP_MASKS
- HBITMAP hbmp = GetHbitmapOf(bmp);
- HBITMAP oldBitmap2 = (HBITMAP)::SelectObject(memoryDC2, hbmp);
- if ( !BitBlt(memoryDC, x, 0, m_defaultWidth, m_defaultHeight,
- memoryDC2, 0, 0, SRCCOPY) )
+ SelectInHDC hdcSelector2(memoryDC2, GetHbitmapOf(bmp));
+ if ( !BitBlt(memoryDC,
+ x, 0, m_defaultWidth, m_defaultHeight,
+ memoryDC2,
+ 0, 0, SRCCOPY) )
+ {
+ wxLogLastError(wxT("BitBlt"));
+ }
+#endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
+ }
+ else
{
- wxLogLastError(wxT("BitBlt"));
+ wxFAIL_MSG( _T("invalid tool button bitmap") );
}
- ::SelectObject(memoryDC2, oldBitmap2);
-#endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
+ // 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)
+ x += m_defaultWidth;
+ nButtons++;
}
- else
- {
- wxFAIL_MSG( _T("invalid tool button bitmap") );
- }
-
- // 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)
- x += m_defaultWidth;
- nButtons++;
}
- node = node->GetNext();
- }
-
#if USE_BITMAP_MASKS
- dcAllButtons.SelectObject(wxNullBitmap);
+ dcAllButtons.SelectObject(wxNullBitmap);
- // don't delete this HBITMAP!
- bitmap.SetHBITMAP(0);
-#else // !USE_BITMAP_MASKS
- ::SelectObject(memoryDC, oldBitmap);
- ::DeleteDC(memoryDC);
- ::DeleteDC(memoryDC2);
+ // don't delete this HBITMAP!
+ bitmap.SetHBITMAP(0);
#endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
- // Map to system colours
- hBitmap = (HBITMAP)MapBitmap((WXHBITMAP) hBitmap,
- totalBitmapWidth, totalBitmapHeight);
+ // Map to system colours
+ hBitmap = (HBITMAP)MapBitmap((WXHBITMAP) hBitmap,
+ totalBitmapWidth, totalBitmapHeight);
- int bitmapId = 0;
+ bool addBitmap = TRUE;
- bool addBitmap = TRUE;
-
- if ( oldToolBarBitmap )
- {
-#ifdef TB_REPLACEBITMAP
- if ( wxTheApp->GetComCtl32Version() >= 400 )
+ if ( oldToolBarBitmap )
{
- TBREPLACEBITMAP replaceBitmap;
- replaceBitmap.hInstOld = NULL;
- replaceBitmap.hInstNew = NULL;
- replaceBitmap.nIDOld = (UINT) oldToolBarBitmap;
- replaceBitmap.nIDNew = (UINT) hBitmap;
- replaceBitmap.nButtons = nButtons;
- if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP,
- 0, (LPARAM) &replaceBitmap) )
+#ifdef TB_REPLACEBITMAP
+ if ( wxTheApp->GetComCtl32Version() >= 400 )
{
- wxFAIL_MSG(wxT("Could not replace the old bitmap"));
- }
+ TBREPLACEBITMAP replaceBitmap;
+ replaceBitmap.hInstOld = NULL;
+ replaceBitmap.hInstNew = NULL;
+ replaceBitmap.nIDOld = (UINT) oldToolBarBitmap;
+ replaceBitmap.nIDNew = (UINT) hBitmap;
+ replaceBitmap.nButtons = nButtons;
+ if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP,
+ 0, (LPARAM) &replaceBitmap) )
+ {
+ wxFAIL_MSG(wxT("Could not replace the old bitmap"));
+ }
- ::DeleteObject(oldToolBarBitmap);
+ ::DeleteObject(oldToolBarBitmap);
- // already done
- addBitmap = FALSE;
- }
- else
+ // already done
+ addBitmap = FALSE;
+ }
+ else
#endif // TB_REPLACEBITMAP
- {
- // we can't replace the old bitmap, so we will add another one
- // (awfully inefficient, but what else to do?) and shift the bitmap
- // indices accordingly
- addBitmap = TRUE;
+ {
+ // we can't replace the old bitmap, so we will add another one
+ // (awfully inefficient, but what else to do?) and shift the bitmap
+ // indices accordingly
+ addBitmap = TRUE;
- bitmapId = m_nButtons;
+ bitmapId = m_nButtons;
+ }
}
- // Now delete all the buttons
- for ( size_t pos = 0; pos < m_nButtons; pos++ )
+ if ( addBitmap ) // no old bitmap or we can't replace it
{
- if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
+ TBADDBITMAP addBitmap;
+ addBitmap.hInst = 0;
+ addBitmap.nID = (UINT) hBitmap;
+ if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP,
+ (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 )
{
- wxLogDebug(wxT("TB_DELETEBUTTON failed"));
+ wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
}
}
}
- if ( addBitmap ) // no old bitmap or we can't replace it
+ // 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)) )
{
- TBADDBITMAP addBitmap;
- addBitmap.hInst = 0;
- addBitmap.nID = (UINT) hBitmap;
- if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP,
- (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 )
- {
- wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
- }
+ wxLogLastError(_T("TB_SETBITMAPSIZE"));
}
// Next add the buttons and separators
{
wxToolBarToolBase *tool = node->GetData();
- // don't add separators to the vertical toolbar - looks ugly
- if ( isVertical && tool->IsSeparator() )
+ // 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 )
+ {
continue;
+ }
+
TBBUTTON& button = buttons[i];
break;
case wxTOOL_STYLE_BUTTON:
- button.iBitmap = bitmapId;
+ if ( !HasFlag(wxTB_NOICONS) )
+ button.iBitmap = bitmapId;
- if ( HasFlag(wxTB_TEXT) && !tool->GetLabel().empty() )
+ if ( HasFlag(wxTB_TEXT) )
{
- button.iString = (int)tool->GetLabel().c_str();
+ const wxString& label = tool->GetLabel();
+ if ( !label.empty() )
+ {
+ button.iString = (int)label.c_str();
+ }
}
button.idCommand = tool->GetId();
wxToolBarToolBase *GetItemSkippingDummySpacers(const wxToolBarToolsList& tools,
size_t index )
{
- wxToolBarToolsList::Node* current = tools.GetFirst();
+ wxToolBarToolsList::compatibility_iterator current = tools.GetFirst();
for ( ; current != 0; current = current->GetNext() )
{
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;
- }
+ // the style bits whose changes force us to recreate the toolbar
+ static const long MASK_NEEDS_RECREATE = wxTB_TEXT | wxTB_NOICONS;
- if ( style & wxTB_TEXT )
- {
- // cast is harmless
- tbbi.pszText = (wxChar *)tool->GetLabel().c_str();
- }
+ const long styleOld = GetWindowStyle();
- if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO,
- tool->GetId(), (LPARAM)&tbbi) )
- {
- // the id is probably invalid?
- wxLogLastError(wxT("TB_SETBUTTONINFO"));
- }
- }
+ wxToolBarBase::SetWindowStyleFlag(style);
- UpdateSize();
- Refresh();
- }
-#endif // comctl32.dll 4.71
+ // don't recreate an empty toolbar: not only this is unnecessary, but it is
+ // also fatal as we'd then try to recreate the toolbar when it's just being
+ // created
+ if ( GetToolsCount() &&
+ (style & MASK_NEEDS_RECREATE) != (styleOld & MASK_NEEDS_RECREATE) )
+ {
+ // to remove the text labels, simply re-realizing the toolbar is enough
+ // but I don't know of any way to add the text to an existing toolbar
+ // other than by recreating it entirely
+ Recreate();
}
-
- wxToolBarBase::SetWindowStyleFlag(style);
}
// ----------------------------------------------------------------------------
bool wxToolBar::HandleSize(WXWPARAM wParam, WXLPARAM lParam)
{
- // calculate our minor dimenstion ourselves - we're confusing the standard
+ // calculate our minor dimension 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) )
h = r.bottom - r.top;
if ( m_maxRows )
{
- // FIXME: 6 is hardcoded separator line height...
- //h += 6;
- if (HasFlag(wxTB_NODIVIDER))
- h += 3;
- else
- h += 6;
+ // FIXME: hardcoded separator line height...
+ h += HasFlag(wxTB_NODIVIDER) ? 4 : 6;
h *= m_maxRows;
}
}
// any here
// first of all, do we have any controls at all?
- wxToolBarToolsList::Node *node;
+ wxToolBarToolsList::compatibility_iterator node;
for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
{
if ( node->GetData()->IsControl() )