X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0e93516996cf2bd0a6023b548c95fc32789fa4a7..56bd6aaca9d758663e202816e1861ee8674526e7:/src/msw/treectrl.cpp diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 7f8403c58f..c8973fd6b2 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -29,6 +29,9 @@ #include "wx/msw/private.h" +// Set this to 1 to be _absolutely_ sure that repainting will work for all comctl32.dll versions +#define wxUSE_COMCTL32_SAFELY 0 + // Mingw32 is a bit mental even though this is done in winundef #ifdef GetFirstChild #undef GetFirstChild @@ -43,9 +46,8 @@ #include "wx/log.h" #include "wx/dynarray.h" #include "wx/imaglist.h" -#include "wx/treectrl.h" #include "wx/settings.h" - +#include "wx/msw/treectrl.h" #include "wx/msw/dragimag.h" #ifdef __GNUWIN32_OLD__ @@ -86,6 +88,7 @@ // looks quite ugly. #define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0 + // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- @@ -112,7 +115,7 @@ static bool IsItemSelected(HWND hwndTV, HTREEITEM hItem) if ( !TreeView_GetItem(hwndTV, &tvi) ) { - wxLogLastError("TreeView_GetItem"); + wxLogLastError(wxT("TreeView_GetItem")); } return (tvi.state & TVIS_SELECTED) != 0; @@ -128,7 +131,7 @@ static void SelectItem(HWND hwndTV, HTREEITEM hItem, bool select = TRUE) if ( TreeView_SetItem(hwndTV, &tvi) == -1 ) { - wxLogLastError("TreeView_SetItem"); + wxLogLastError(wxT("TreeView_SetItem")); } } @@ -446,7 +449,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl) // ---------------------------------------------------------------------------- // handy table for sending events -static const wxEventType g_events[2][2] = +static wxEventType g_events[2][2] = { { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING }, { wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxEVT_COMMAND_TREE_ITEM_EXPANDING } @@ -495,11 +498,19 @@ void wxTreeCtrl::Init() { m_imageListNormal = NULL; m_imageListState = NULL; + m_ownsImageListNormal = m_ownsImageListState = FALSE; m_textCtrl = NULL; m_hasAnyAttr = FALSE; m_dragImage = NULL; - m_htSelStart = 0; + + // Initialize static array of events, because with the new event system, + // they may not be initialized yet. + + g_events[0][0] = wxEVT_COMMAND_TREE_ITEM_COLLAPSED; + g_events[0][1] = wxEVT_COMMAND_TREE_ITEM_COLLAPSING; + g_events[1][0] = wxEVT_COMMAND_TREE_ITEM_EXPANDED; + g_events[1][1] = wxEVT_COMMAND_TREE_ITEM_EXPANDING; } bool wxTreeCtrl::Create(wxWindow *parent, @@ -516,8 +527,10 @@ bool wxTreeCtrl::Create(wxWindow *parent, return FALSE; DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | - TVS_HASLINES | TVS_SHOWSELALWAYS; + TVS_SHOWSELALWAYS /* | WS_CLIPSIBLINGS */; + if ((m_windowStyle & wxTR_NO_LINES) == 0) + wstyle |= TVS_HASLINES; if ( m_windowStyle & wxTR_HAS_BUTTONS ) wstyle |= TVS_HASBUTTONS; @@ -545,8 +558,23 @@ bool wxTreeCtrl::Create(wxWindow *parent, if ( !MSWCreateControl(WC_TREEVIEW, wstyle) ) return FALSE; +#if wxUSE_COMCTL32_SAFELY + wxWindow::SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); + wxWindow::SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); +#elif 1 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); +#else + // This works around a bug in the Windows tree control whereby for some versions + // of comctrl32, setting any colour actually draws the background in black. + // This will initialise the background to the system colour. + // THIS FIX NOW REVERTED since it caused problems on _other_ systems. + // Assume the user has an updated comctl32.dll. + ::SendMessage(GetHwnd(), TVM_SETBKCOLOR, 0,-1); + wxWindow::SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); + SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); +#endif + // VZ: this is some experimental code which may be used to get the // TVS_CHECKBOXES style functionality for comctl32.dll < 4.71. @@ -622,6 +650,9 @@ wxTreeCtrl::~wxTreeCtrl() // delete user data to prevent memory leaks DeleteAllItems(); + + if (m_ownsImageListNormal) delete m_imageListNormal; + if (m_ownsImageListState) delete m_imageListState; } // ---------------------------------------------------------------------------- @@ -634,7 +665,7 @@ bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const { if ( !TreeView_GetItem(GetHwnd(), tvItem) ) { - wxLogLastError("TreeView_GetItem"); + wxLogLastError(wxT("TreeView_GetItem")); return FALSE; } @@ -646,7 +677,7 @@ void wxTreeCtrl::DoSetItem(wxTreeViewItem* tvItem) { if ( TreeView_SetItem(GetHwnd(), tvItem) == -1 ) { - wxLogLastError("TreeView_SetItem"); + wxLogLastError(wxT("TreeView_SetItem")); } } @@ -685,12 +716,28 @@ void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which) void wxTreeCtrl::SetImageList(wxImageList *imageList) { + if (m_ownsImageListNormal) delete m_imageListNormal; SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL); + m_ownsImageListNormal = FALSE; } void wxTreeCtrl::SetStateImageList(wxImageList *imageList) { + if (m_ownsImageListState) delete m_imageListState; SetAnyImageList(m_imageListState = imageList, TVSIL_STATE); + m_ownsImageListState = FALSE; +} + +void wxTreeCtrl::AssignImageList(wxImageList *imageList) +{ + SetImageList(imageList); + m_ownsImageListNormal = TRUE; +} + +void wxTreeCtrl::AssignStateImageList(wxImageList *imageList) +{ + SetStateImageList(imageList); + m_ownsImageListState = TRUE; } size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, @@ -707,20 +754,24 @@ size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool wxTreeCtrl::SetBackgroundColour(const wxColour &colour) { +#if !wxUSE_COMCTL32_SAFELY if ( !wxWindowBase::SetBackgroundColour(colour) ) return FALSE; SendMessage(GetHwnd(), TVM_SETBKCOLOR, 0, colour.GetPixel()); +#endif return TRUE; } bool wxTreeCtrl::SetForegroundColour(const wxColour &colour) { +#if !wxUSE_COMCTL32_SAFELY if ( !wxWindowBase::SetForegroundColour(colour) ) return FALSE; SendMessage(GetHwnd(), TVM_SETTEXTCOLOR, 0, colour.GetPixel()); +#endif return TRUE; } @@ -908,6 +959,12 @@ wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) { + // first, associate this piece of data with this item + if ( data ) + { + data->SetId(item); + } + wxTreeViewItem tvItem(item, TVIF_PARAM); if ( HasIndirectData(item) ) @@ -1079,7 +1136,7 @@ wxTreeItemId wxTreeCtrl::GetRootItem() const wxTreeItemId wxTreeCtrl::GetSelection() const { - wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (WXHTREEITEM)0, + wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (long)(WXHTREEITEM)0, wxT("this only works with single selection controls") ); return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(GetHwnd())); @@ -1142,16 +1199,14 @@ wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const { - wxASSERT_MSG( IsVisible(item), wxT("The item you call GetNextVisible() " - "for must be visible itself!")); + wxASSERT_MSG( IsVisible(item), wxT("The item you call GetNextVisible() for must be visible itself!")); return wxTreeItemId((WXHTREEITEM) TreeView_GetNextVisible(GetHwnd(), HITEM(item))); } wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const { - wxASSERT_MSG( IsVisible(item), wxT("The item you call GetPrevVisible() " - "for must be visible itself!")); + wxASSERT_MSG( IsVisible(item), wxT("The item you call GetPrevVisible() for must be visible itself!")); return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(GetHwnd(), HITEM(item))); } @@ -1219,6 +1274,11 @@ wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent, mask |= TVIF_TEXT; tvIns.item.pszText = (wxChar *)text.c_str(); // cast is ok } + else + { + tvIns.item.pszText = NULL; + tvIns.item.cchTextMax = 0; + } if ( image != -1 ) { @@ -1249,7 +1309,7 @@ wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent, HTREEITEM id = (HTREEITEM) TreeView_InsertItem(GetHwnd(), &tvIns); if ( id == 0 ) { - wxLogLastError("TreeView_InsertItem"); + wxLogLastError(wxT("TreeView_InsertItem")); } if ( data != NULL ) @@ -1275,7 +1335,7 @@ wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text, int image, int selectedImage, wxTreeItemData *data) { - return DoInsertItem(wxTreeItemId((WXHTREEITEM) 0), (WXHTREEITEM) 0, + return DoInsertItem(wxTreeItemId((long) (WXHTREEITEM) 0), (long)(WXHTREEITEM) 0, text, image, selectedImage, data); } @@ -1334,7 +1394,7 @@ void wxTreeCtrl::Delete(const wxTreeItemId& item) { if ( !TreeView_DeleteItem(GetHwnd(), HITEM(item)) ) { - wxLogLastError("TreeView_DeleteItem"); + wxLogLastError(wxT("TreeView_DeleteItem")); } } @@ -1357,7 +1417,7 @@ void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item) { if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM)children[n]) ) { - wxLogLastError("TreeView_DeleteItem"); + wxLogLastError(wxT("TreeView_DeleteItem")); } } } @@ -1366,7 +1426,7 @@ void wxTreeCtrl::DeleteAllItems() { if ( !TreeView_DeleteAllItems(GetHwnd()) ) { - wxLogLastError("TreeView_DeleteAllItems"); + wxLogLastError(wxT("TreeView_DeleteAllItems")); } } @@ -1440,7 +1500,7 @@ void wxTreeCtrl::Unselect() wxT("doesn't make sense, may be you want UnselectAll()?") ); // just remove the selection - SelectItem(wxTreeItemId((WXHTREEITEM) 0)); + SelectItem(wxTreeItemId((long) (WXHTREEITEM) 0)); } void wxTreeCtrl::UnselectAll() @@ -1491,7 +1551,7 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item) { if ( !TreeView_SelectItem(GetHwnd(), HITEM(item)) ) { - wxLogLastError("TreeView_SelectItem"); + wxLogLastError(wxT("TreeView_SelectItem")); } else { @@ -1513,7 +1573,7 @@ void wxTreeCtrl::ScrollTo(const wxTreeItemId& item) { if ( !TreeView_SelectSetFirstVisible(GetHwnd(), HITEM(item)) ) { - wxLogLastError("TreeView_SelectSetFirstVisible"); + wxLogLastError(wxT("TreeView_SelectSetFirstVisible")); } } @@ -1544,6 +1604,14 @@ void wxTreeCtrl::DeleteTextCtrl() { if ( m_textCtrl ) { + // the HWND corresponding to this control is deleted by the tree + // control itself and we don't know when exactly this happens, so check + // if the window still exists before calling UnsubclassWin() + if ( !::IsWindow(GetHwndOf(m_textCtrl)) ) + { + m_textCtrl->SetHWND(0); + } + m_textCtrl->UnsubclassWin(); m_textCtrl->SetHWND(0); delete m_textCtrl; @@ -1915,25 +1983,6 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) switch ( hdr->code ) { - case NM_RCLICK: - { - if ( wxControl::MSWOnNotify(idCtrl, lParam, result) ) - return TRUE; - - TV_HITTESTINFO tvhti; - ::GetCursorPos(&(tvhti.pt)); - ::ScreenToClient(GetHwnd(),&(tvhti.pt)); - if ( TreeView_HitTest(GetHwnd(),&tvhti) ) - { - if( tvhti.flags & TVHT_ONITEM ) - { - event.m_item = (WXHTREEITEM) tvhti.hItem; - eventType = wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK; - } - } - } - break; - case TVN_BEGINDRAG: eventType = wxEVT_COMMAND_TREE_BEGIN_DRAG; // fall through @@ -2029,8 +2078,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; default: - wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND " - "message"), tv->action); + wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND message"), tv->action); } bool ing = ((int)hdr->code == TVN_ITEMEXPANDING); @@ -2082,7 +2130,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) } break; -#if defined(_WIN32_IE) && _WIN32_IE >= 0x300 +#if defined(_WIN32_IE) && _WIN32_IE >= 0x300 && !wxUSE_COMCTL32_SAFELY case NM_CUSTOMDRAW: { LPNMTVCUSTOMDRAW lptvcd = (LPNMTVCUSTOMDRAW)lParam; @@ -2179,6 +2227,30 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; #endif // _WIN32_IE >= 0x300 + case NM_DBLCLK: + case NM_RCLICK: + { + TV_HITTESTINFO tvhti; + ::GetCursorPos(&tvhti.pt); + ::ScreenToClient(GetHwnd(), &tvhti.pt); + if ( TreeView_HitTest(GetHwnd(), &tvhti) ) + { + if ( tvhti.flags & TVHT_ONITEM ) + { + event.m_item = (WXHTREEITEM) tvhti.hItem; + eventType = (int)hdr->code == NM_DBLCLK + ? wxEVT_COMMAND_TREE_ITEM_ACTIVATED + : wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK; + + event.m_pointDrag.x = tvhti.pt.x; + event.m_pointDrag.y = tvhti.pt.y; + } + + break; + } + } + // fall through + default: return wxControl::MSWOnNotify(idCtrl, lParam, result); } @@ -2191,6 +2263,14 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // post processing switch ( hdr->code ) { + case NM_DBLCLK: + // we translate NM_DBLCLK into ACTIVATED event, so don't interpret + // the return code of this event handler as the return value for + // NM_DBLCLK - otherwise, double clicking the item to toggle its + // expanded status would never work + *result = FALSE; + break; + case TVN_BEGINDRAG: case TVN_BEGINRDRAG: if ( event.IsAllowed() ) @@ -2221,6 +2301,11 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) delete data; // can't be NULL here m_itemsWithIndirectData.Remove(item); +#if 0 + int iIndex = m_itemsWithIndirectData.Index(item); + wxASSERT( iIndex != wxNOT_FOUND) ; + m_itemsWithIndirectData.wxBaseArray::RemoveAt((size_t)iIndex); +#endif } else { @@ -2238,8 +2323,12 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; case TVN_ENDLABELEDIT: - // return TRUE to set the label to the new string + // return TRUE to set the label to the new string: note that we + // also must pretend that we did process the message or it is going + // to be passed to DefWindowProc() which will happily return FALSE + // cancelling the label change *result = event.IsAllowed(); + processed = TRUE; // ensure that we don't have the text ctrl which is going to be // deleted any more @@ -2290,18 +2379,5 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) return processed; } -// ---------------------------------------------------------------------------- -// Tree event -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent) - -wxTreeEvent::wxTreeEvent(wxEventType commandType, int id) - : wxNotifyEvent(commandType, id) -{ - m_code = 0; - m_itemOld = 0; -} - #endif // __WIN95__