From 39d2f9a7c866338762ca974209219f40d4420af6 Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Fri, 18 Jul 2003 14:12:53 +0000 Subject: [PATCH 1/1] Added WCE toolbar Got menubars working with WCE git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@22085 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/frame.h | 9 - include/wx/msw/menu.h | 14 + include/wx/msw/wince/tbarwce.h | 148 ++++ include/wx/msw/wx.rc | 32 + include/wx/toolbar.h | 2 + samples/minimal/minimal.cpp | 8 +- src/msw/frame.cpp | 58 +- src/msw/menu.cpp | 132 +++- src/msw/settings.cpp | 4 + src/msw/toplevel.cpp | 11 +- src/msw/wince/tbarwce.cpp | 1258 ++++++++++++++++++++++++++++++++ src/msw/window.cpp | 43 +- 12 files changed, 1647 insertions(+), 72 deletions(-) create mode 100644 include/wx/msw/wince/tbarwce.h create mode 100644 src/msw/wince/tbarwce.cpp diff --git a/include/wx/msw/frame.h b/include/wx/msw/frame.h index b90e37d8b0..cc8bd90b35 100644 --- a/include/wx/msw/frame.h +++ b/include/wx/msw/frame.h @@ -102,12 +102,6 @@ public: // current size - this has an effect of refreshing the window layout virtual void SendSizeEvent(); -#ifdef __WXWINCE__ - WXHWND GetCommandBar() { return m_commandBar; } - WXHWND CreateCommandBar() ; - void RemoveCommandBar() ; -#endif - protected: // common part of all ctors void Init(); @@ -155,9 +149,6 @@ private: #if wxUSE_TOOLTIPS WXHWND m_hwndToolTip; #endif // tooltips -#ifdef __WXWINCE__ - WXHWND m_commandBar; -#endif // used by IconizeChildFrames(), see comments there bool m_wasMinimized; diff --git a/include/wx/msw/menu.h b/include/wx/msw/menu.h index e306076348..5d273cd57f 100644 --- a/include/wx/msw/menu.h +++ b/include/wx/msw/menu.h @@ -25,6 +25,10 @@ class WXDLLEXPORT wxFrame; +#if defined(__WXWINCE__) && wxUSE_TOOLBAR +class WXDLLEXPORT wxToolBar; +#endif + // ---------------------------------------------------------------------------- // Menu // ---------------------------------------------------------------------------- @@ -153,6 +157,12 @@ public: virtual void Detach(); virtual void Attach(wxFrame *frame); +#if defined(__WXWINCE__) && wxUSE_TOOLBAR + // Under WinCE, a menubar is owned by the frame's toolbar + void SetToolBar(wxToolBar* toolBar) { m_toolBar = toolBar; } + wxToolBar* GetToolBar() const { return m_toolBar; } +#endif + #if wxUSE_ACCEL // get the accel table for all the menus const wxAcceleratorTable& GetAccelTable() const { return m_accelTable; } @@ -189,6 +199,10 @@ protected: wxAcceleratorTable m_accelTable; #endif // wxUSE_ACCEL +#if defined(__WXWINCE__) && wxUSE_TOOLBAR + wxToolBar* m_toolBar; +#endif + private: DECLARE_DYNAMIC_CLASS(wxMenuBar) }; diff --git a/include/wx/msw/wince/tbarwce.h b/include/wx/msw/wince/tbarwce.h new file mode 100644 index 0000000000..938559aca3 --- /dev/null +++ b/include/wx/msw/wince/tbarwce.h @@ -0,0 +1,148 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/msw/wince/tbarwce.h +// Purpose: Windows CE wxToolBar class +// Author: Julian Smart +// Modified by: +// Created: 2003-07-12 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_BARWCE_H_ +#define _WX_BARWCE_H_ + +#ifdef __GNUG__ + #pragma interface "tbarwce.h" +#endif + +#if wxUSE_TOOLBAR + +#include "wx/dynarray.h" + +class WXDLLEXPORT wxToolBar : public wxToolBarBase +{ +public: + // ctors and dtor + wxToolBar() { Init(); } + + wxToolBar(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxNO_BORDER | wxTB_HORIZONTAL, + const wxString& name = wxToolBarNameStr, + wxMenuBar* menuBar = NULL) + { + Init(); + + Create(parent, id, pos, size, style, name, menuBar); + } + + bool Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxNO_BORDER | wxTB_HORIZONTAL, + const wxString& name = wxToolBarNameStr, + wxMenuBar* menuBar = NULL); + + virtual ~wxToolBar(); + + // override/implement base class virtuals + virtual wxToolBarToolBase *FindToolForPosition(wxCoord x, wxCoord y) const; + + virtual bool Realize(); + + virtual void SetToolBitmapSize(const wxSize& size); + virtual wxSize GetToolSize() const; + + virtual void SetRows(int nRows); + + // implementation only from now on + // ------------------------------- + + virtual void SetWindowStyleFlag(long style); + + virtual bool MSWCommand(WXUINT param, WXWORD id); + virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result); + + void OnMouseEvent(wxMouseEvent& event); + void OnSysColourChanged(wxSysColourChangedEvent& event); + + void SetFocus() {} + + static WXHBITMAP MapBitmap(WXHBITMAP bitmap, int width, int height); + + // Return HMENU for the menu associated with the commandbar + WXHMENU GetHMenu(); + + // Set the wxMenuBar associated with this commandbar + void SetMenuBar(wxMenuBar* menuBar) { m_menuBar = menuBar; } + + // Returns the wxMenuBar associated with this commandbar + wxMenuBar* GetMenuBar() const { return m_menuBar; } + +protected: + // common part of all ctors + void Init(); + + // create the native toolbar control + bool MSWCreateToolbar(const wxPoint& pos, const wxSize& size, wxMenuBar* menuBar); + + // recreate the control completely + void Recreate(); + + // implement base class pure virtuals + virtual bool DoInsertTool(size_t pos, wxToolBarToolBase *tool); + virtual bool DoDeleteTool(size_t pos, wxToolBarToolBase *tool); + + virtual void DoEnableTool(wxToolBarToolBase *tool, bool enable); + virtual void DoToggleTool(wxToolBarToolBase *tool, bool toggle); + virtual void DoSetToggle(wxToolBarToolBase *tool, bool toggle); + + virtual wxToolBarToolBase *CreateTool(int id, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, + wxObject *clientData, + const wxString& shortHelp, + const wxString& longHelp); + virtual wxToolBarToolBase *CreateTool(wxControl *control); + + // override WndProc mainly to process WM_SIZE + virtual long MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); + + // return the appropriate size and flags for the toolbar control + virtual wxSize DoGetBestSize() const; + virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const; + + // handlers for various events + void HandleMouseMove(WXWPARAM wParam, WXLPARAM lParam); + + // should be called whenever the toolbar size changes + void UpdateSize(); + + // the big bitmap containing all bitmaps of the toolbar buttons + WXHBITMAP m_hBitmap; + + // the total number of toolbar elements + size_t m_nButtons; + + // the tool the cursor is in + wxToolBarToolBase *m_pInTool; + + // The menubar associated with this toolbar + wxMenuBar* m_menuBar; + +private: + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(wxToolBar) + DECLARE_NO_COPY_CLASS(wxToolBar) +}; + +#endif // wxUSE_TOOLBAR + +#endif + // _WX_BARWCE_H_ diff --git a/include/wx/msw/wx.rc b/include/wx/msw/wx.rc index e9371c812a..5f27ac35d8 100644 --- a/include/wx/msw/wx.rc +++ b/include/wx/msw/wx.rc @@ -35,6 +35,10 @@ #include #endif +#if defined(_WIN32_WCE) + #include +#endif + ////////////////////////////////////////////////////////////////////////////// // // This is the MDI Window menu @@ -53,6 +57,34 @@ BEGIN END END +#ifdef _WIN32_WCE + +// Dummy menubar/toolbar for WinCE + +5000 RCDATA DISCARDABLE +BEGIN + // Popup menu name + 5000, + // Count of items to put on the menu + 0 +END + +5000 MENU DISCARDABLE +BEGIN + POPUP "Dummy" + BEGIN + MENUITEM "Dummy" 99 + END +END + +STRINGTABLE DISCARDABLE +BEGIN + 5001 "Dummy menu" +END + +#endif + + ////////////////////////////////////////////////////////////////////////////// // // Standard wxWindows Cursors diff --git a/include/wx/toolbar.h b/include/wx/toolbar.h index 11878e4760..c2ba87c44a 100644 --- a/include/wx/toolbar.h +++ b/include/wx/toolbar.h @@ -121,6 +121,8 @@ enum #else // wxUSE_TOOLBAR_NATIVE #if defined(__WXUNIVERSAL__) #include "wx/univ/toolbar.h" + #elif defined(__WXWINCE__) + #include "wx/msw/wince/tbarwce.h" #elif defined(__WXMSW__) && defined(__WIN95__) #include "wx/msw/tbar95.h" #elif defined(__WXMSW__) diff --git a/samples/minimal/minimal.cpp b/samples/minimal/minimal.cpp index 8298169a69..d6ab0abbfe 100644 --- a/samples/minimal/minimal.cpp +++ b/samples/minimal/minimal.cpp @@ -121,7 +121,11 @@ bool MyApp::OnInit() { // create the main application window MyFrame *frame = new MyFrame(_T("Minimal wxWindows App"), - wxPoint(50, 50), wxSize(450, 340)); +#ifdef __WXWINCE__ + wxPoint(0, 0), wxDefaultSize, wxNO_BORDER); +#else + wxPoint(50, 50), wxSize(450, 340)); +#endif // and show it (the frames, unlike simple controls, are not shown when // created initially) @@ -163,7 +167,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, SetMenuBar(menuBar); #endif // wxUSE_MENUS -#if wxUSE_STATUSBAR +#if wxUSE_STATUSBAR && !defined(__WXWINCE__) // create a status bar just for fun (by default with 1 pane only) CreateStatusBar(2); SetStatusText(_T("Welcome to wxWindows!")); diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp index f2dff269be..f17d23dddb 100644 --- a/src/msw/frame.cpp +++ b/src/msw/frame.cpp @@ -106,9 +106,6 @@ void wxFrame::Init() #if wxUSE_TOOLTIPS m_hwndToolTip = 0; #endif -#ifdef __WXWINCE__ - m_commandBar = 0; -#endif // Data to save/restore when calling ShowFullScreen m_fsStatusBarFields = 0; @@ -140,10 +137,6 @@ wxFrame::~wxFrame() { m_isBeingDeleted = TRUE; DeleteAllBars(); -#ifdef __WXWINCE__ - RemoveCommandBar(); -#endif - } // ---------------------------------------------------------------------------- @@ -271,6 +264,7 @@ void wxFrame::AttachMenuBar(wxMenuBar *menubar) } else // set new non NULL menu bar { +#ifndef __WXWINCE__ // Can set a menubar several times. if ( menubar->GetHMenu() ) { @@ -286,7 +280,7 @@ void wxFrame::AttachMenuBar(wxMenuBar *menubar) return; } } - +#endif InternalSetMenuBar(); } } @@ -296,18 +290,14 @@ void wxFrame::InternalSetMenuBar() #ifdef __WXMICROWIN__ // Nothing #elif defined(__WXWINCE__) - - CreateCommandBar() ; - if (m_commandBar) + if (!GetToolBar()) { - if (!CommandBar_InsertMenubarEx((HWND) m_commandBar, NULL, - (LPTSTR) (HMENU) m_hMenu, 0)) - { - wxFAIL_MSG( _T("failed to set menubar") ); - return; - } - CommandBar_DrawMenuBar((HWND) m_commandBar, 0); + wxToolBar* toolBar = new wxToolBar(this, -1, + wxDefaultPosition, wxDefaultSize, + wxBORDER_NONE | wxTB_HORIZONTAL, + wxToolBarNameStr, GetMenuBar()); + SetToolBar(toolBar); } #else if ( !::SetMenu(GetHwnd(), (HMENU)m_hMenu) ) @@ -434,6 +424,11 @@ bool wxFrame::ShowFullScreen(bool show, long style) wxToolBar* wxFrame::CreateToolBar(long style, wxWindowID id, const wxString& name) { +#ifdef __WXWINCE__ + // We may already have a toolbar from calling SetMenuBar. + if (GetToolBar()) + return GetToolBar(); +#endif if ( wxFrameBase::CreateToolBar(style, id, name) ) { PositionToolBar(); @@ -850,30 +845,3 @@ bool wxFrame::HandleInitMenuPopup(WXHMENU hMenu) return GetEventHandler()->ProcessEvent(event); } - -#ifdef __WXWINCE__ -WXHWND wxFrame::CreateCommandBar() -{ - if (m_commandBar) - return m_commandBar; - - m_commandBar = (WXHWND) CommandBar_Create(wxGetInstance(), GetHwnd(), NewControlId()); - if (!m_commandBar) - { - wxFAIL_MSG( _T("failed to create commandbar") ); - return 0; - } - return m_commandBar; -} - -void wxFrame::RemoveCommandBar() -{ - if (m_commandBar) - { - ::DestroyWindow((HWND) m_commandBar); - m_commandBar = NULL; - } -} -#endif - - diff --git a/src/msw/menu.cpp b/src/msw/menu.cpp index f1a7bb4a2c..6bce598d97 100644 --- a/src/msw/menu.cpp +++ b/src/msw/menu.cpp @@ -44,6 +44,20 @@ #include "wx/msw/private.h" +#ifdef __WXWINCE__ +#include +#include +#include +#include +#include +#include + +#ifndef TBSTYLE_NO_DROPDOWN_ARROW +#define TBSTYLE_NO_DROPDOWN_ARROW 0x0080 +#endif + +#endif + // other standard headers #include @@ -260,6 +274,10 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) id = pItem->GetId(); } +#ifdef __WXWINCE__ + wxString strippedString; +#endif + LPCTSTR pData; #if wxUSE_OWNER_DRAWN @@ -274,7 +292,12 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) // menu is just a normal string (passed in data parameter) flags |= MF_STRING; +#ifdef __WXWINCE__ + strippedString = wxStripMenuCodes(pItem->GetText()); + pData = (wxChar*)strippedString.c_str(); +#else pData = (wxChar*)pItem->GetText().c_str(); +#endif } BOOL ok; @@ -558,6 +581,9 @@ void wxMenuBar::Init() { m_eventHandler = this; m_hMenu = 0; +#ifdef __WXWINCE__ + m_toolBar = NULL; +#endif } wxMenuBar::wxMenuBar() @@ -587,6 +613,9 @@ wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[]) wxMenuBar::~wxMenuBar() { + // In Windows CE, the menubar is always associated + // with a toolbar, which destroys the menu implicitly. +#ifndef __WXWINCE__ // we should free Windows resources only if Windows doesn't do it for us // which happens if we're attached to a frame if (m_hMenu && !IsAttached()) @@ -594,6 +623,7 @@ wxMenuBar::~wxMenuBar() ::DestroyMenu((HMENU)m_hMenu); m_hMenu = (WXHMENU)NULL; } +#endif } // --------------------------------------------------------------------------- @@ -604,11 +634,53 @@ void wxMenuBar::Refresh() { wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") ); +#ifdef __WXWINCE__ + if (GetToolBar()) + { + CommandBar_DrawMenuBar((HWND) GetToolBar()->GetHWND(), 0); + } +#else DrawMenuBar(GetHwndOf(GetFrame())); +#endif } WXHMENU wxMenuBar::Create() { +#ifdef __WXWINCE__ + if ( m_hMenu != 0 ) + return m_hMenu; + + if (!GetToolBar()) + return 0; + + HWND hCommandBar = (HWND) GetToolBar()->GetHWND(); + HMENU hMenu = (HMENU)::SendMessage(hCommandBar, SHCMBM_GETMENU, (WPARAM)0, (LPARAM)0); + if (hMenu) + { + TBBUTTON tbButton; + memset(&tbButton, 0, sizeof(TBBUTTON)); + tbButton.iBitmap = I_IMAGENONE; + tbButton.fsState = TBSTATE_ENABLED; + tbButton.fsStyle = TBSTYLE_DROPDOWN | TBSTYLE_NO_DROPDOWN_ARROW | TBSTYLE_AUTOSIZE; + + size_t i; + for (i = 0; i < GetMenuCount(); i++) + { + HMENU hPopupMenu = (HMENU) GetMenu(i)->GetHMenu() ; + tbButton.dwData = (DWORD)hPopupMenu; + wxString label = wxStripMenuCodes(GetLabelTop(i)); + tbButton.iString = (int) label.c_str(); + + tbButton.idCommand = NewControlId(); + if (!::SendMessage(hCommandBar, TB_INSERTBUTTON, i, (LPARAM)&tbButton)) + { + wxLogLastError(wxT("TB_INSERTBUTTON")); + } + } + } + m_hMenu = (WXHMENU) hMenu; + return m_hMenu; +#else if ( m_hMenu != 0 ) return m_hMenu; @@ -634,6 +706,7 @@ WXHMENU wxMenuBar::Create() } return m_hMenu; +#endif } // --------------------------------------------------------------------------- @@ -768,13 +841,34 @@ bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title) if ( IsAttached() ) { +#ifdef __WXWINCE__ + if (!GetToolBar()) + return FALSE; + TBBUTTON tbButton; + memset(&tbButton, 0, sizeof(TBBUTTON)); + tbButton.iBitmap = I_IMAGENONE; + tbButton.fsState = TBSTATE_ENABLED; + tbButton.fsStyle = TBSTYLE_DROPDOWN | TBSTYLE_NO_DROPDOWN_ARROW | TBSTYLE_AUTOSIZE; + + HMENU hPopupMenu = (HMENU) menu->GetHMenu() ; + tbButton.dwData = (DWORD)hPopupMenu; + wxString label = wxStripMenuCodes(title); + tbButton.iString = (int) label.c_str(); + + tbButton.idCommand = NewControlId(); + if (!::SendMessage((HWND) GetToolBar()->GetHWND(), TB_INSERTBUTTON, pos, (LPARAM)&tbButton)) + { + wxLogLastError(wxT("TB_INSERTBUTTON")); + return FALSE; + } +#else if ( !::InsertMenu(GetHmenu(), pos, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT)GetHmenuOf(menu), title) ) { wxLogLastError(wxT("InsertMenu")); } - +#endif #if wxUSE_ACCEL if ( menu->HasAccels() ) { @@ -801,16 +895,39 @@ bool wxMenuBar::Append(wxMenu *menu, const wxString& title) if ( IsAttached() ) { +#ifdef __WXWINCE__ + if (!GetToolBar()) + return FALSE; + TBBUTTON tbButton; + memset(&tbButton, 0, sizeof(TBBUTTON)); + tbButton.iBitmap = I_IMAGENONE; + tbButton.fsState = TBSTATE_ENABLED; + tbButton.fsStyle = TBSTYLE_DROPDOWN | TBSTYLE_NO_DROPDOWN_ARROW | TBSTYLE_AUTOSIZE; + + size_t pos = GetMenuCount(); + HMENU hPopupMenu = (HMENU) menu->GetHMenu() ; + tbButton.dwData = (DWORD)hPopupMenu; + wxString label = wxStripMenuCodes(title); + tbButton.iString = (int) label.c_str(); + + tbButton.idCommand = NewControlId(); + if (!::SendMessage((HWND) GetToolBar()->GetHWND(), TB_INSERTBUTTON, pos, (LPARAM)&tbButton)) + { + wxLogLastError(wxT("TB_INSERTBUTTON")); + return FALSE; + } +#else if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING, (UINT)submenu, title) ) { wxLogLastError(wxT("AppendMenu")); } +#endif #if wxUSE_ACCEL if ( menu->HasAccels() ) { - // need to rebuild accell table + // need to rebuild accelerator table RebuildAccelTable(); } #endif // wxUSE_ACCEL @@ -829,11 +946,20 @@ wxMenu *wxMenuBar::Remove(size_t pos) if ( IsAttached() ) { +#ifdef __WXWINCE__ + if (GetToolBar()) + { + if (!::SendMessage((HWND) GetToolBar()->GetHWND(), TB_DELETEBUTTON, (UINT) pos, (LPARAM) 0)) + { + wxLogLastError(wxT("TB_DELETEBUTTON")); + } + } +#else if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) ) { wxLogLastError(wxT("RemoveMenu")); } - +#endif #if wxUSE_ACCEL if ( menu->HasAccels() ) { diff --git a/src/msw/settings.cpp b/src/msw/settings.cpp index 1c5c52d672..9ba29bc069 100644 --- a/src/msw/settings.cpp +++ b/src/msw/settings.cpp @@ -200,7 +200,11 @@ wxColour wxSystemSettingsNative::GetColour(wxSystemColour index) if ( !hasCol ) { +#ifdef __WXWINCE__ + colSys = ::GetSysColor(index|SYS_COLOR_INDEX_FLAG); +#else colSys = ::GetSysColor(index); +#endif } return wxRGBToColour(colSys); diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index 961cd90c52..6bc345507e 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -156,7 +156,12 @@ WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const if ( style & wxFRAME_TOOL_WINDOW ) msflags |= WS_POPUP; else - msflags |= WS_OVERLAPPED; + { +#ifdef __WXWINCE__ + if (msflags & WS_BORDER) +#endif + msflags |= WS_OVERLAPPED; + } // border and caption styles if ( style & wxRESIZE_BORDER ) @@ -167,13 +172,17 @@ WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const } else if ( !(style & wxBORDER_NONE) ) msflags |= WS_BORDER; +#ifndef __WXWINCE__ else msflags |= WS_POPUP; +#endif if ( style & wxCAPTION ) msflags |= WS_CAPTION; +#ifndef __WXWINCE__ else msflags |= WS_POPUP; +#endif // next translate the individual flags if ( style & wxMINIMIZE_BOX ) diff --git a/src/msw/wince/tbarwce.cpp b/src/msw/wince/tbarwce.cpp new file mode 100644 index 0000000000..554b07da26 --- /dev/null +++ b/src/msw/wince/tbarwce.cpp @@ -0,0 +1,1258 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: msw/wince/tbarwce.cpp +// Purpose: wxToolBar for Windows CE +// Author: Julian Smart +// Modified by: +// Created: 2003-07-12 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "tbarwce.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/frame.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/dynarray.h" + #include "wx/settings.h" + #include "wx/bitmap.h" + #include "wx/dcmemory.h" + #include "wx/control.h" +#endif + +#if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE + +#include "wx/toolbar.h" + +#if !defined(__GNUWIN32__) && !defined(__SALFORDC__) + #include "malloc.h" +#endif + +#include "wx/msw/private.h" +#include +#include +#include +#include +#include +#include + +#include "wx/msw/winundef.h" + +#if defined(__MWERKS__) && defined(__WXMSW__) +// including for max definition doesn't seem +// to work using CodeWarrior 6 Windows. So we define it +// here. (Otherwise we get a undefined identifier 'max' +// later on in this file.) (Added by dimitri@shortcut.nl) +# ifndef max +# define max(a,b) (((a) > (b)) ? (a) : (b)) +# endif + +#endif + +// ---------------------------------------------------------------------------- +// conditional compilation +// ---------------------------------------------------------------------------- + +// wxWindows previously always considered that toolbar buttons have light grey +// (0xc0c0c0) background and so ignored any bitmap masks - however, this +// doesn't work with XPMs which then appear to have black background. To make +// this work, we must respect the bitmap masks - which we do now. This should +// be ok in any case, but to restore 100% compatible with the old version +// behaviour, you can set this to 0. +#define USE_BITMAP_MASKS 1 + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// these standard constants are not always defined in compilers headers + +// Styles +#ifndef TBSTYLE_FLAT + #define TBSTYLE_LIST 0x1000 + #define TBSTYLE_FLAT 0x0800 +#endif + +#ifndef TBSTYLE_TRANSPARENT + #define TBSTYLE_TRANSPARENT 0x8000 +#endif + +#ifndef TBSTYLE_TOOLTIPS + #define TBSTYLE_TOOLTIPS 0x0100 +#endif + +// Messages +#ifndef TB_GETSTYLE + #define TB_SETSTYLE (WM_USER + 56) + #define TB_GETSTYLE (WM_USER + 57) +#endif + +#ifndef TB_HITTEST + #define TB_HITTEST (WM_USER + 69) +#endif + +// 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 +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxToolBarBase) + +BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase) + EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent) + EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged) +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxToolBarTool : public wxToolBarToolBase +{ +public: + wxToolBarTool(wxToolBar *tbar, + int id, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, + wxObject *clientData, + const wxString& shortHelp, + const wxString& longHelp) + : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind, + clientData, shortHelp, longHelp) + { + m_nSepCount = 0; + } + + wxToolBarTool(wxToolBar *tbar, wxControl *control) + : wxToolBarToolBase(tbar, control) + { + 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; } + size_t GetSeparatorsCount() const { return m_nSepCount; } + +private: + size_t m_nSepCount; +}; + + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxToolBarTool +// ---------------------------------------------------------------------------- + +wxToolBarToolBase *wxToolBar::CreateTool(int id, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, + wxObject *clientData, + const wxString& shortHelp, + const wxString& longHelp) +{ + return new wxToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind, + clientData, shortHelp, longHelp); +} + +wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control) +{ + return new wxToolBarTool(this, control); +} + +// ---------------------------------------------------------------------------- +// wxToolBar construction +// ---------------------------------------------------------------------------- + +void wxToolBar::Init() +{ + m_hBitmap = 0; + + m_nButtons = 0; + + m_defaultWidth = DEFAULTBITMAPX; + m_defaultHeight = DEFAULTBITMAPY; + + m_pInTool = 0; + m_menuBar = NULL; +} + +bool wxToolBar::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + wxMenuBar* menuBar) +{ + // common initialisation + if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) ) + return FALSE; + + // MSW-specific initialisation + if ( !MSWCreateToolbar(pos, size, menuBar) ) + return FALSE; + + // set up the colors and fonts + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR)); + SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + + return TRUE; +} + +#ifndef TBSTYLE_NO_DROPDOWN_ARROW +#define TBSTYLE_NO_DROPDOWN_ARROW 0x0080 +#endif + +bool wxToolBar::MSWCreateToolbar(const wxPoint& pos, const wxSize& size, wxMenuBar* menuBar) +{ + SetMenuBar(menuBar); + if (m_menuBar) + m_menuBar->SetToolBar(this); + + // Create the menubar. + SHMENUBARINFO mbi; + + memset (&mbi, 0, sizeof (SHMENUBARINFO)); + mbi.cbSize = sizeof (SHMENUBARINFO); + mbi.hwndParent = (HWND) GetParent()->GetHWND(); + mbi.nToolBarId = 5000; + mbi.nBmpId = 0; + mbi.cBmpImages = 0; + mbi.dwFlags = 0 ; // SHCMBF_EMPTYBAR; + mbi.hInstRes = wxGetInstance(); + + if (!SHCreateMenuBar(&mbi)) + { + wxFAIL_MSG( _T("SHCreateMenuBar failed") ); + return FALSE; + } + + SetHWND((WXHWND) mbi.hwndMB); +/* + if (!::SendMessage((HWND) GetHWND(), TB_DELETEBUTTON, 0, (LPARAM) 0)) + { + wxLogLastError(wxT("TB_DELETEBUTTON")); + } +*/ + // install wxWindows window proc for this window + SubclassWin(m_hWnd); + + if (menuBar) + menuBar->Create(); +#if 0 + { + HMENU hMenu = (HMENU)::SendMessage(mbi.hwndMB, SHCMBM_GETMENU, (WPARAM)0, (LPARAM)0); + if (hMenu) + { + TBBUTTON tbButton; + memset(&tbButton, 0, sizeof(TBBUTTON)); + tbButton.iBitmap = I_IMAGENONE; + tbButton.fsState = TBSTATE_ENABLED; + tbButton.fsStyle = TBSTYLE_DROPDOWN | TBSTYLE_NO_DROPDOWN_ARROW | TBSTYLE_AUTOSIZE; + + size_t i; + for (i = 0; i < menuBar->GetMenuCount(); i++) + { + HMENU hPopupMenu = (HMENU) menuBar->GetMenu(i)->GetHMenu() ; + tbButton.dwData = (DWORD)hPopupMenu; + wxString label = wxStripMenuCodes(menuBar->GetLabelTop(i)); + tbButton.iString = (int) label.c_str(); + + tbButton.idCommand = NewControlId(); + if (!::SendMessage((HWND) GetHWND(), TB_INSERTBUTTON, i, (LPARAM)&tbButton)) + { + wxLogLastError(wxT("TB_INSERTBUTTON")); + } + } + } + } +#endif + +#if 0 + CommandBar_AddToolTips( hwndCB, uNumSmallTips,szSmallTips); + + CommandBar_AddBitmap(hwndCB, HINST_COMMCTRL, IDB_STD_SMALL_COLOR, + 15, 16, 16); + // Add buttons in tbSTDButton to Commandbar + CommandBar_AddButtons(hwndCB, sizeof(tbSTDButton)/sizeof(TBBUTTON), + tbSTDButton); +#endif + return TRUE; +} + +void wxToolBar::Recreate() +{ +#if 0 + 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(); + + UnsubclassWin(); + + if ( !MSWCreateToolbar(pos, size) ) + { + // what can we do? + wxFAIL_MSG( _T("recreating the toolbar failed") ); + + return; + } + + // 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(); +#endif +} + +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(); + } + + if ( m_hBitmap ) + { + ::DeleteObject((HBITMAP) m_hBitmap); + } +} + +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; +} + +// Return HMENU for the menu associated with the commandbar +WXHMENU wxToolBar::GetHMenu() +{ + if (GetHWND()) + { + return (WXHMENU) (HMENU)::SendMessage((HWND) GetHWND(), SHCMBM_GETMENU, (WPARAM)0, (LPARAM)0); + } + else + return 0; +} + + +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) +{ + // nothing special to do here - we really create the toolbar buttons in + // Realize() later + tool->Attach(this); + + return TRUE; +} + +bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool) +{ + // the main difficulty we have here is with the controls in the toolbars: + // as we (sometimes) use several separators to cover up the space used by + // them, the indices are not the same for us and the toolbar + + // 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::compatibility_iterator node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + wxToolBarToolBase *tool2 = node->GetData(); + if ( tool2 == tool ) + { + // let node point to the next node in the list + node = node->GetNext(); + + break; + } + + if ( tool2->IsControl() ) + { + pos += ((wxToolBarTool *)tool2)->GetSeparatorsCount() - 1; + } + } + + // now determine the number of buttons to delete and the area taken by them + size_t nButtonsToDelete = 1; + + // get the size of the button we're going to delete + RECT r; + if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) ) + { + wxLogLastError(_T("TB_GETITEMRECT")); + } + + int width = r.right - r.left; + + if ( tool->IsControl() ) + { + nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount(); + + width *= nButtonsToDelete; + } + + // do delete all buttons + m_nButtons -= nButtonsToDelete; + while ( nButtonsToDelete-- > 0 ) + { + if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) ) + { + wxLogLastError(wxT("TB_DELETEBUTTON")); + + return FALSE; + } + } + + tool->Detach(); + + // and finally reposition all the controls after this button (the toolbar + // takes care of all normal items) + for ( /* node -> first after deleted */ ; node; node = node->GetNext() ) + { + wxToolBarToolBase *tool2 = node->GetData(); + if ( tool2->IsControl() ) + { + int x; + wxControl *control = tool2->GetControl(); + control->GetPosition(&x, NULL); + control->Move(x - width, -1); + } + } + + return TRUE; +} + +bool wxToolBar::Realize() +{ + const size_t nTools = GetToolsCount(); + if ( nTools == 0 ) + { + // nothing to do + return TRUE; + } + + const bool isVertical = HasFlag(wxTB_VERTICAL); + +#if 0 + // 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")); + } + } +#endif + + // add the buttons and separators + // ------------------------------ + + TBBUTTON *buttons = new TBBUTTON[nTools]; + + // this array will hold the indices of all controls in the toolbar + wxArrayInt controlIds; + + bool lastWasRadio = FALSE; + int i = 0; + wxToolBarToolsList::Node* node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + wxToolBarToolBase *tool = node->GetData(); + + TBBUTTON& button = buttons[i]; + + wxZeroMemory(button); + + bool isRadio = FALSE; + switch ( tool->GetStyle() ) + { + case wxTOOL_STYLE_CONTROL: + button.idCommand = tool->GetId(); + // fall through: create just a separator too + + case wxTOOL_STYLE_SEPARATOR: + button.fsState = TBSTATE_ENABLED; + button.fsStyle = TBSTYLE_SEP; + break; + + case wxTOOL_STYLE_BUTTON: + // TODO +#if 0 + if ( !HasFlag(wxTB_NOICONS) ) + button.iBitmap = bitmapId; + + if ( HasFlag(wxTB_TEXT) ) + { + const wxString& label = tool->GetLabel(); + if ( !label.empty() ) + { + button.iString = (int)label.c_str(); + } + } + + button.idCommand = tool->GetId(); + + if ( tool->IsEnabled() ) + button.fsState |= TBSTATE_ENABLED; + if ( tool->IsToggled() ) + button.fsState |= TBSTATE_CHECKED; + + 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++; +#endif + break; + } + + lastWasRadio = isRadio; + + i++; + } + + // Add buttons in tbSTDButton to Commandbar + if (!CommandBar_AddButtons(GetHwnd(), i, buttons)) + { + wxLogLastError(wxT("CommandBar_AddButtons")); + } + + delete [] buttons; + +#if 0 + // Deal with the controls finally + // ------------------------------ + + // adjust the controls size to fit nicely in the toolbar + int y = 0; + size_t index = 0; + for ( node = m_tools.GetFirst(); node; node = node->GetNext(), index++ ) + { + wxToolBarToolBase *tool = node->GetData(); + + // we calculate the running y coord for vertical toolbars so we need to + // get the items size for all items but for the horizontal ones we + // don't need to deal with the non controls + bool isControl = tool->IsControl(); + if ( !isControl && !isVertical ) + continue; + + // note that we use TB_GETITEMRECT and not TB_GETRECT because the + // latter only appeared in v4.70 of comctl32.dll + RECT r; + if ( !SendMessage(GetHwnd(), TB_GETITEMRECT, + index, (LPARAM)(LPRECT)&r) ) + { + wxLogLastError(wxT("TB_GETITEMRECT")); + } + + if ( !isControl ) + { + // can only be control if isVertical + y += r.bottom - r.top; + + continue; + } + + wxControl *control = tool->GetControl(); + + wxSize size = control->GetSize(); + + // the position of the leftmost controls corner + int left = -1; + + // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+ +#if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 ) + // available in headers, now check whether it is available now + // (during run-time) + if ( wxTheApp->GetComCtl32Version() >= 471 ) + { + // set the (underlying) separators width to be that of the + // control + TBBUTTONINFO tbbi; + tbbi.cbSize = sizeof(tbbi); + tbbi.dwMask = TBIF_SIZE; + tbbi.cx = size.x; + if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO, + tool->GetId(), (LPARAM)&tbbi) ) + { + // the id is probably invalid? + wxLogLastError(wxT("TB_SETBUTTONINFO")); + } + } + else +#endif // comctl32.dll 4.71 + // TB_SETBUTTONINFO unavailable + { + // try adding several separators to fit the controls width + int widthSep = r.right - r.left; + left = r.left; + + TBBUTTON tbb; + wxZeroMemory(tbb); + tbb.idCommand = 0; + tbb.fsState = TBSTATE_ENABLED; + tbb.fsStyle = TBSTYLE_SEP; + + size_t nSeparators = size.x / widthSep; + for ( size_t nSep = 0; nSep < nSeparators; nSep++ ) + { + if ( !SendMessage(GetHwnd(), TB_INSERTBUTTON, + index, (LPARAM)&tbb) ) + { + wxLogLastError(wxT("TB_INSERTBUTTON")); + } + + index++; + } + + // remember the number of separators we used - we'd have to + // delete all of them later + ((wxToolBarTool *)tool)->SetSeparatorsCount(nSeparators); + + // adjust the controls width to exactly cover the separators + control->SetSize((nSeparators + 1)*widthSep, -1); + } + + // position the control itself correctly vertically + int height = r.bottom - r.top; + int diff = height - size.y; + if ( diff < 0 ) + { + // the control is too high, resize to fit + control->SetSize(-1, height - 2); + + diff = 2; + } + + int top; + if ( isVertical ) + { + left = 0; + top = y; + + y += height + 2*GetMargins().y; + } + else // horizontal toolbar + { + if ( left == -1 ) + left = r.left; + + top = r.top; + } + + control->Move(left, top + (diff + 1) / 2); + } + + // the max index is the "real" number of buttons - i.e. counting even the + // separators which we added just for aligning the controls + m_nButtons = index; + + 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); + } + } +#endif + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// message handlers +// ---------------------------------------------------------------------------- + +bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id) +{ + wxToolBarToolBase *tool = FindById((int)id); + if ( !tool ) + { + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED); + event.SetEventObject(this); + event.SetId(id); + event.SetInt(id); + + return GetEventHandler()->ProcessEvent(event); + } + + if ( tool->CanBeToggled() ) + { + LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0); + tool->Toggle((state & TBSTATE_CHECKED) != 0); + } + + bool toggled = tool->IsToggled(); + + // avoid sending the event when a radio button is released, this is not + // interesting + if ( !tool->CanBeToggled() || tool->GetKind() != wxITEM_RADIO || 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)); + } + } + + return TRUE; +} + +bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl), + WXLPARAM lParam, + WXLPARAM *WXUNUSED(result)) +{ +#if wxUSE_TOOLTIPS + // First check if this applies to us + NMHDR *hdr = (NMHDR *)lParam; + + // the tooltips control created by the toolbar is sometimes Unicode, even + // in an ANSI application - this seems to be a bug in comctl32.dll v5 + UINT code = hdr->code; + if ( (code != (UINT) TTN_NEEDTEXTA) && (code != (UINT) TTN_NEEDTEXTW) ) + return FALSE; + + HWND toolTipWnd = (HWND)::SendMessage((HWND)GetHWND(), TB_GETTOOLTIPS, 0, 0); + if ( toolTipWnd != hdr->hwndFrom ) + return FALSE; + + LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam; + int id = (int)ttText->hdr.idFrom; + + wxToolBarToolBase *tool = FindById(id); + if ( !tool ) + return FALSE; + + return HandleTooltipNotify(code, lParam, tool->GetShortHelp()); +#else + return FALSE; +#endif +} + +// ---------------------------------------------------------------------------- +// toolbar geometry +// ---------------------------------------------------------------------------- + +void wxToolBar::SetToolBitmapSize(const wxSize& size) +{ + wxToolBarBase::SetToolBitmapSize(size); + + ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, MAKELONG(size.x, size.y)); +} + +void wxToolBar::SetRows(int nRows) +{ + if ( nRows == m_maxRows ) + { + // avoid resizing the frame uselessly + return; + } + + // TRUE in wParam means to create at least as many rows, FALSE - + // at most as many + RECT rect; + ::SendMessage(GetHwnd(), TB_SETROWS, + MAKEWPARAM(nRows, !(GetWindowStyle() & wxTB_VERTICAL)), + (LPARAM) &rect); + + m_maxRows = nRows; + + UpdateSize(); +} + +// The button size is bigger than the bitmap size +wxSize wxToolBar::GetToolSize() const +{ + // TB_GETBUTTONSIZE is supported from version 4.70 +#if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \ + && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) + if ( wxTheApp->GetComCtl32Version() >= 470 ) + { + DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0); + + return wxSize(LOWORD(dw), HIWORD(dw)); + } + else +#endif // comctl32.dll 4.70+ + { + // defaults + return wxSize(m_defaultWidth + 8, m_defaultHeight + 7); + } +} + +static +wxToolBarToolBase *GetItemSkippingDummySpacers(const wxToolBarToolsList& tools, + size_t index ) +{ + wxToolBarToolsList::compatibility_iterator current = tools.GetFirst(); + + for ( ; current != 0; current = current->GetNext() ) + { + if ( index == 0 ) + return current->GetData(); + + wxToolBarTool *tool = (wxToolBarTool *)current->GetData(); + size_t separators = tool->GetSeparatorsCount(); + + // if it is a normal button, sepcount == 0, so skip 1 item (the button) + // otherwise, skip as many items as the separator count, plus the + // control itself + index -= separators ? separators + 1 : 1; + } + + return 0; +} + +wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const +{ + POINT pt; + 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 ) + { + return m_tools.Item((size_t)index)->GetData(); + } + else +#endif + { + return GetItemSkippingDummySpacers( m_tools, (size_t) index ); + } +} + +void wxToolBar::UpdateSize() +{ + // the toolbar size changed + SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0); + + // we must also refresh the frame after the toolbar size (possibly) changed + wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); + if ( frame ) + { + frame->SendSizeEvent(); + } +} + +// ---------------------------------------------------------------------------- +// toolbar styles +// --------------------------------------------------------------------------- + +void wxToolBar::SetWindowStyleFlag(long style) +{ + // the style bits whose changes force us to recreate the toolbar + static const long MASK_NEEDS_RECREATE = wxTB_TEXT | wxTB_NOICONS; + + const long styleOld = GetWindowStyle(); + + wxToolBarBase::SetWindowStyleFlag(style); + + // 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(); + } +} + +// ---------------------------------------------------------------------------- +// tool state +// ---------------------------------------------------------------------------- + +void wxToolBar::DoEnableTool(wxToolBarToolBase *tool, bool enable) +{ + ::SendMessage(GetHwnd(), TB_ENABLEBUTTON, + (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0)); +} + +void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool toggle) +{ + ::SendMessage(GetHwnd(), TB_CHECKBUTTON, + (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0)); +} + +void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle)) +{ + // 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") ); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +// Responds to colour changes, and passes event on to children. +void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent& event) +{ + wxRGBToColour(m_backgroundColour, ::GetSysColor(COLOR_BTNFACE)); + + // Remap the buttons + Realize(); + + // Relayout the toolbar + int nrows = m_maxRows; + m_maxRows = 0; // otherwise SetRows() wouldn't do anything + SetRows(nrows); + + Refresh(); + + // let the event propagate further + event.Skip(); +} + +void wxToolBar::OnMouseEvent(wxMouseEvent& event) +{ + if (event.Leaving() && m_pInTool) + { + OnMouseEnter( -1 ); + event.Skip(); + return; + } + + if (event.RightDown()) + { + // For now, we don't have an id. Later we could + // try finding the tool. + OnRightClick((int)-1, event.GetX(), event.GetY()); + } + else + { + event.Skip(); + } +} + +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) +{ +#if 0 + 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; + } +#endif + return wxControl::MSWWindowProc(nMsg, wParam, lParam); +} + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height) +{ + MemoryHDC hdcMem; + + if ( !hdcMem ) + { + wxLogLastError(_T("CreateCompatibleDC")); + + return bitmap; + } + + SelectInHDC bmpInHDC(hdcMem, (HBITMAP)bitmap); + + if ( !bmpInHDC ) + { + wxLogLastError(_T("SelectObject")); + + return bitmap; + } + + wxCOLORMAP *cmap = wxGetStdColourMap(); + + for ( int i = 0; i < width; i++ ) + { + for ( int j = 0; j < height; j++ ) + { + COLORREF pixel = ::GetPixel(hdcMem, i, j); + + for ( size_t k = 0; k < wxSTD_COL_MAX; k++ ) + { + COLORREF col = cmap[k].from; + if ( abs(GetRValue(pixel) - GetRValue(col)) < 10 && + abs(GetGValue(pixel) - GetGValue(col)) < 10 && + abs(GetBValue(pixel) - GetBValue(col)) < 10 ) + { + ::SetPixel(hdcMem, i, j, cmap[k].to); + break; + } + } + } + } + + return bitmap; + + // VZ: I leave here my attempts to map the bitmap to the system colours + // faster by using BitBlt() even though it's broken currently - but + // maybe someone else can finish it? It should be faster than iterating + // over all pixels... +#if 0 + MemoryHDC hdcMask, hdcDst; + if ( !hdcMask || !hdcDst ) + { + wxLogLastError(_T("CreateCompatibleDC")); + + return bitmap; + } + + // create the target bitmap + HBITMAP hbmpDst = ::CreateCompatibleBitmap(hdcDst, width, height); + if ( !hbmpDst ) + { + wxLogLastError(_T("CreateCompatibleBitmap")); + + return bitmap; + } + + // create the monochrome mask bitmap + HBITMAP hbmpMask = ::CreateBitmap(width, height, 1, 1, 0); + if ( !hbmpMask ) + { + wxLogLastError(_T("CreateBitmap(mono)")); + + ::DeleteObject(hbmpDst); + + return bitmap; + } + + SelectInHDC bmpInDst(hdcDst, hbmpDst), + bmpInMask(hdcMask, hbmpMask); + + // for each colour: + for ( n = 0; n < NUM_OF_MAPPED_COLOURS; n++ ) + { + // create the mask for this colour + ::SetBkColor(hdcMem, ColorMap[n].from); + ::BitBlt(hdcMask, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY); + + // replace this colour with the target one in the dst bitmap + HBRUSH hbr = ::CreateSolidBrush(ColorMap[n].to); + HGDIOBJ hbrOld = ::SelectObject(hdcDst, hbr); + + ::MaskBlt(hdcDst, 0, 0, width, height, + hdcMem, 0, 0, + hbmpMask, 0, 0, + MAKEROP4(PATCOPY, SRCCOPY)); + + (void)::SelectObject(hdcDst, hbrOld); + ::DeleteObject(hbr); + } + + ::DeleteObject((HBITMAP)bitmap); + + return (WXHBITMAP)hbmpDst; +#endif // 0 +} + +#endif // wxUSE_TOOLBAR && Win95 + diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 78e16bb4d2..51243e6392 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -2978,18 +2978,37 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, // do create the window wxWindowCreationHook hook(this); - m_hWnd = (WXHWND)::CreateWindowEx - ( - extendedStyle, - className, - title ? title : wxEmptyString, - style, - x, y, w, h, - (HWND)MSWGetParent(), - (HMENU)controlId, - wxGetInstance(), - NULL // no extra data - ); +#ifdef __WXWINCE__ + if (extendedStyle == 0) + { + m_hWnd = (WXHWND)::CreateWindow + ( + className, + title ? title : wxEmptyString, + style, + x, y, w, h, + (HWND)MSWGetParent(), + (HMENU)controlId, + wxGetInstance(), + NULL // no extra data + ); + } + else +#endif + { + m_hWnd = (WXHWND)::CreateWindowEx + ( + extendedStyle, + className, + title ? title : wxEmptyString, + style, + x, y, w, h, + (HWND)MSWGetParent(), + (HMENU)controlId, + wxGetInstance(), + NULL // no extra data + ); + } if ( !m_hWnd ) { -- 2.45.2