X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/406005d21b612ca71c2066db8f9d4873ab8cd51a..77611ad4da9df336a0805508276a81b8f4437107:/src/generic/treectrl.cpp diff --git a/src/generic/treectrl.cpp b/src/generic/treectrl.cpp index 5055888bc7..9a43e04af0 100644 --- a/src/generic/treectrl.cpp +++ b/src/generic/treectrl.cpp @@ -53,10 +53,54 @@ WX_DEFINE_OBJARRAY(wxArrayTreeItemIds); static const int NO_IMAGE = -1; +#define PIXELS_PER_UNIT 10 + // ----------------------------------------------------------------------------- // private classes // ----------------------------------------------------------------------------- +// timer used for enabling in-place edit +class WXDLLEXPORT wxTreeRenameTimer: public wxTimer +{ +public: + wxTreeRenameTimer( wxTreeCtrl *owner ); + + void Notify(); + +private: + wxTreeCtrl *m_owner; +}; + +// control used for in-place edit +class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl +{ +public: + wxTreeTextCtrl() { } + wxTreeTextCtrl( wxWindow *parent, + const wxWindowID id, + bool *accept, + wxString *res, + wxTreeCtrl *owner, + const wxString &value = wxEmptyString, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + int style = 0, + const wxValidator& validator = wxDefaultValidator, + const wxString &name = wxTextCtrlNameStr ); + + void OnChar( wxKeyEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + +private: + bool *m_accept; + wxString *m_res; + wxTreeCtrl *m_owner; + wxString m_startValue; + + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(wxTreeTextCtrl); +}; + // a tree item class WXDLLEXPORT wxGenericTreeItem { @@ -76,7 +120,7 @@ public: const wxString& GetText() const { return m_text; } int GetImage(wxTreeItemIcon which = wxTreeItemIcon_Normal) const - { return m_images[which]; } + { return m_images[which]; } wxTreeItemData *GetData() const { return m_data; } // returns the current image for the item (depending on its @@ -167,8 +211,8 @@ private: // children but has a [+] button int m_isBold :1; // render the label in bold font - int m_x, m_y; - long m_height, m_width; + wxCoord m_x, m_y; + wxCoord m_height, m_width; int m_xCross, m_yCross; int m_level; @@ -182,6 +226,23 @@ private: // implementation // ============================================================================= +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// translate the key or mouse event flags to the type of selection we're +// dealing with +static void EventFlagsToSelType(long style, + bool shiftDown, + bool ctrlDown, + bool &is_multiple, + bool &extended_select, + bool &unselect_others) +{ + is_multiple = (style & wxTR_MULTIPLE) != 0; + extended_select = shiftDown && is_multiple; + unselect_others = !(extended_select || (ctrlDown && is_multiple)); +} // ----------------------------------------------------------------------------- // wxTreeRenameTimer (internal) @@ -208,19 +269,24 @@ BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl) EVT_KILL_FOCUS (wxTreeTextCtrl::OnKillFocus) END_EVENT_TABLE() -wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent, const wxWindowID id, - bool *accept, wxString *res, wxTreeCtrl *owner, - const wxString &value, const wxPoint &pos, const wxSize &size, -#if wxUSE_VALIDATORS - int style, const wxValidator& validator, const wxString &name ) : -#endif - wxTextCtrl( parent, id, value, pos, size, style, validator, name ) +wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent, + const wxWindowID id, + bool *accept, + wxString *res, + wxTreeCtrl *owner, + const wxString &value, + const wxPoint &pos, + const wxSize &size, + int style, + const wxValidator& validator, + const wxString &name ) + : wxTextCtrl( parent, id, value, pos, size, style, validator, name ) { m_res = res; m_accept = accept; m_owner = owner; (*m_accept) = FALSE; - (*m_res) = ""; + (*m_res) = wxEmptyString; m_startValue = value; } @@ -230,14 +296,23 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) { (*m_accept) = TRUE; (*m_res) = GetValue(); - m_owner->SetFocus(); + + if (!wxPendingDelete.Member(this)) + wxPendingDelete.Append(this); + + if ((*m_accept) && ((*m_res) != m_startValue)) + m_owner->OnRenameAccept(); + return; } if (event.m_keyCode == WXK_ESCAPE) { (*m_accept) = FALSE; (*m_res) = ""; - m_owner->SetFocus(); + + if (!wxPendingDelete.Member(this)) + wxPendingDelete.Append(this); + return; } event.Skip(); @@ -245,15 +320,13 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) { - if (wxPendingDelete.Member(this)) return; - - wxPendingDelete.Append(this); + if (!wxPendingDelete.Member(this)) + wxPendingDelete.Append(this); if ((*m_accept) && ((*m_res) != m_startValue)) m_owner->OnRenameAccept(); } -#define PIXELS_PER_UNIT 10 // ----------------------------------------------------------------------------- // wxTreeEvent // ----------------------------------------------------------------------------- @@ -297,7 +370,7 @@ wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent, m_parent = parent; m_attr = (wxTreeItemAttr *)NULL; - + // We don't know the height here yet. m_width = 0; m_height = 0; @@ -363,7 +436,7 @@ size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const return count; size_t total = count; - for ( size_t n = 0; n < count; ++n ) + for (size_t n = 0; n < count; ++n) { total += m_children[n]->GetChildrenCount(); } @@ -398,62 +471,63 @@ wxGenericTreeItem *wxGenericTreeItem::HitTest( const wxPoint& point, const wxTreeCtrl *theTree, int &flags) { - if ((point.y > m_y) && (point.y < m_y + theTree->GetLineHeight(this))) - { - if (point.yGetLineHeight(this)/2) - flags |= wxTREE_HITTEST_ONITEMUPPERPART; - else - flags |= wxTREE_HITTEST_ONITEMLOWERPART; - - // 5 is the size of the plus sign - if ((point.x > m_xCross-5) && (point.x < m_xCross+5) && - (point.y > m_yCross-5) && (point.y < m_yCross+5) && - (IsExpanded() || HasPlus())) + if ((point.y > m_y) && (point.y < m_y + theTree->GetLineHeight(this))) { - flags|=wxTREE_HITTEST_ONITEMBUTTON; - return this; - } + if (point.y < m_y+theTree->GetLineHeight(this)/2 ) + flags |= wxTREE_HITTEST_ONITEMUPPERPART; + else + flags |= wxTREE_HITTEST_ONITEMLOWERPART; - if ((point.x >= m_x) && (point.x <= m_x+m_width)) - { - int image_w = -1; - int image_h; + // 5 is the size of the plus sign + if ((point.x > m_xCross-5) && (point.x < m_xCross+5) && + (point.y > m_yCross-5) && (point.y < m_yCross+5) && + (IsExpanded() || HasPlus())) + { + flags|=wxTREE_HITTEST_ONITEMBUTTON; + return this; + } - // assuming every image (normal and selected ) has the same size ! - if ( (GetImage() != NO_IMAGE) && theTree->m_imageListNormal ) - theTree->m_imageListNormal->GetSize(GetImage(), image_w, image_h); + if ((point.x >= m_x) && (point.x <= m_x+m_width)) + { + int image_w = -1; + int image_h; - if ((image_w != -1) && (point.x <= m_x + image_w + 1)) - flags |= wxTREE_HITTEST_ONITEMICON; - else - flags |= wxTREE_HITTEST_ONITEMLABEL; + // assuming every image (normal and selected ) has the same size ! + if ( (GetImage() != NO_IMAGE) && theTree->m_imageListNormal ) + theTree->m_imageListNormal->GetSize(GetImage(), image_w, image_h); - return this; - } + if ((image_w != -1) && (point.x <= m_x + image_w + 1)) + flags |= wxTREE_HITTEST_ONITEMICON; + else + flags |= wxTREE_HITTEST_ONITEMLABEL; - if (point.x < m_x) - flags |= wxTREE_HITTEST_ONITEMINDENT; - if (point.x > m_x+m_width) - flags |= wxTREE_HITTEST_ONITEMRIGHT; + return this; + } - return this; - } - else - { - if (!m_isCollapsed) + if (point.x < m_x) + flags |= wxTREE_HITTEST_ONITEMINDENT; + if (point.x > m_x+m_width) + flags |= wxTREE_HITTEST_ONITEMRIGHT; + + return this; + } + else { - size_t count = m_children.Count(); - for ( size_t n = 0; n < count; n++ ) - { - wxGenericTreeItem *res = m_children[n]->HitTest( point, theTree, flags ); - if ( res != NULL ) - return res; - } + if (!m_isCollapsed) + { + size_t count = m_children.Count(); + for ( size_t n = 0; n < count; n++ ) + { + wxGenericTreeItem *res = m_children[n]->HitTest( point, theTree, flags ); + if ( res != NULL ) + return res; + } + } } - } - flags|=wxTREE_HITTEST_NOWHERE; - return NULL; + flags|=wxTREE_HITTEST_NOWHERE; + + return (wxGenericTreeItem*) NULL; } int wxGenericTreeItem::GetCurrentImage() const @@ -532,6 +606,9 @@ void wxTreeCtrl::Init() m_imageListState = (wxImageList *) NULL; m_dragCount = 0; + m_isDragging = FALSE; + m_dropTarget = + m_oldSelection = (wxGenericTreeItem *)NULL; m_renameTimer = new wxTreeRenameTimer( this ); @@ -546,10 +623,8 @@ void wxTreeCtrl::Init() bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, -#if wxUSE_VALIDATORS - const wxValidator &validator, -#endif - const wxString& name ) + const wxValidator &validator, + const wxString& name ) { Init(); @@ -559,7 +634,7 @@ bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id, SetValidator( validator ); #endif - SetBackgroundColour( *wxWHITE ); + SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) ); // m_dottedPen = wxPen( "grey", 0, wxDOT ); too slow under XFree86 m_dottedPen = wxPen( "grey", 0, 0 ); @@ -581,28 +656,26 @@ wxTreeCtrl::~wxTreeCtrl() size_t wxTreeCtrl::GetCount() const { - return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount(); + return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount(); } void wxTreeCtrl::SetIndent(unsigned int indent) { - m_indent = indent; - m_dirty = TRUE; - Refresh(); + m_indent = indent; + m_dirty = TRUE; } void wxTreeCtrl::SetSpacing(unsigned int spacing) { - m_spacing = spacing; - m_dirty = TRUE; - Refresh(); + m_spacing = spacing; + m_dirty = TRUE; } size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively) { - wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") ); - return item.m_pItem->GetChildrenCount(recursively); + return item.m_pItem->GetChildrenCount(recursively); } // ----------------------------------------------------------------------------- @@ -611,35 +684,35 @@ size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively) wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const { - wxCHECK_MSG( item.IsOk(), wxT(""), wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), wxT(""), wxT("invalid tree item") ); - return item.m_pItem->GetText(); + return item.m_pItem->GetText(); } int wxTreeCtrl::GetItemImage(const wxTreeItemId& item, wxTreeItemIcon which) const { - wxCHECK_MSG( item.IsOk(), -1, wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), -1, wxT("invalid tree item") ); - return item.m_pItem->GetImage(which); + return item.m_pItem->GetImage(which); } wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const { - wxCHECK_MSG( item.IsOk(), NULL, wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), NULL, wxT("invalid tree item") ); - return item.m_pItem->GetData(); + return item.m_pItem->GetData(); } void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text) { - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - wxClientDC dc(this); - wxGenericTreeItem *pItem = item.m_pItem; - pItem->SetText(text); - CalculateSize(pItem, dc); - RefreshLine(pItem); + wxClientDC dc(this); + wxGenericTreeItem *pItem = item.m_pItem; + pItem->SetText(text); + CalculateSize(pItem, dc); + RefreshLine(pItem); } void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, @@ -658,18 +731,18 @@ void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) { - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - item.m_pItem->SetData(data); + item.m_pItem->SetData(data); } void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has) { - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - wxGenericTreeItem *pItem = item.m_pItem; - pItem->SetHasPlus(has); - RefreshLine(pItem); + wxGenericTreeItem *pItem = item.m_pItem; + pItem->SetHasPlus(has); + RefreshLine(pItem); } void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold) @@ -720,37 +793,37 @@ void wxTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font) bool wxTreeCtrl::IsVisible(const wxTreeItemId& WXUNUSED(item)) const { - wxFAIL_MSG(wxT("not implemented")); + wxFAIL_MSG(wxT("not implemented")); - return TRUE; + return TRUE; } bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const { - wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); - return !item.m_pItem->GetChildren().IsEmpty(); + return !item.m_pItem->GetChildren().IsEmpty(); } bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const { - wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); - return item.m_pItem->IsExpanded(); + return item.m_pItem->IsExpanded(); } bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const { - wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); - return item.m_pItem->IsSelected(); + return item.m_pItem->IsSelected(); } bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const { - wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); - return item.m_pItem->IsBold(); + return item.m_pItem->IsBold(); } // ----------------------------------------------------------------------------- @@ -779,7 +852,7 @@ wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) co wxArrayGenericTreeItems& children = item.m_pItem->GetChildren(); if ( (size_t)cookie < children.Count() ) { - return children.Item(cookie++); + return children.Item((size_t)cookie++); } else { @@ -911,7 +984,7 @@ wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text, if (!HasFlag(wxTR_MULTIPLE)) { m_current = m_key_current = m_anchor; - m_current->SetHilight( TRUE ); + m_current->SetHilight( TRUE ); } Refresh(); @@ -925,7 +998,7 @@ wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent, int image, int selImage, wxTreeItemData *data) { - return DoInsertItem(parent, 0u, text, image, selImage, data); + return DoInsertItem(parent, 0u, text, image, selImage, data); } wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId, @@ -934,17 +1007,34 @@ wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId, int image, int selImage, wxTreeItemData *data) { - wxGenericTreeItem *parent = parentId.m_pItem; - if ( !parent ) - { - // should we give a warning here? - return AddRoot(text, image, selImage, data); - } + wxGenericTreeItem *parent = parentId.m_pItem; + if ( !parent ) + { + // should we give a warning here? + return AddRoot(text, image, selImage, data); + } + + int index = parent->GetChildren().Index(idPrevious.m_pItem); + wxASSERT_MSG( index != wxNOT_FOUND, + wxT("previous item in wxTreeCtrl::InsertItem() is not a sibling") ); + + return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data); +} + +wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId, + size_t before, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) +{ + wxGenericTreeItem *parent = parentId.m_pItem; + if ( !parent ) + { + // should we give a warning here? + return AddRoot(text, image, selImage, data); + } - int index = parent->GetChildren().Index(idPrevious.m_pItem); - wxASSERT_MSG( index != wxNOT_FOUND, - wxT("previous item in wxTreeCtrl::InsertItem() is not a sibling") ); - return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data); + return DoInsertItem(parentId, before, text, image, selImage, data); } wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parentId, @@ -952,23 +1042,23 @@ wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parentId, int image, int selImage, wxTreeItemData *data) { - wxGenericTreeItem *parent = parentId.m_pItem; - if ( !parent ) - { - // should we give a warning here? - return AddRoot(text, image, selImage, data); - } + wxGenericTreeItem *parent = parentId.m_pItem; + if ( !parent ) + { + // should we give a warning here? + return AddRoot(text, image, selImage, data); + } - return DoInsertItem(parent, parent->GetChildren().Count(), text, - image, selImage, data); + return DoInsertItem( parent, parent->GetChildren().Count(), text, + image, selImage, data); } void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item) { - wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() ); - event.m_item = item; - event.SetEventObject( this ); - ProcessEvent( event ); + wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() ); + event.m_item = item; + event.SetEventObject( this ); + ProcessEvent( event ); } void wxTreeCtrl::DeleteChildren(const wxTreeItemId& itemId) @@ -1011,65 +1101,65 @@ void wxTreeCtrl::DeleteAllItems() void wxTreeCtrl::Expand(const wxTreeItemId& itemId) { - wxGenericTreeItem *item = itemId.m_pItem; + wxGenericTreeItem *item = itemId.m_pItem; - if ( !item->HasPlus() ) - return; + if ( !item->HasPlus() ) + return; - if ( item->IsExpanded() ) - return; + if ( item->IsExpanded() ) + return; - wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() ); - event.m_item = item; - event.SetEventObject( this ); + wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() ); + event.m_item = item; + event.SetEventObject( this ); // if ( ProcessEvent( event ) && event.m_code ) TODO: Was this a typo ? - if ( ProcessEvent( event ) && !event.IsAllowed() ) - { - // cancelled by program - return; - } + if ( ProcessEvent( event ) && !event.IsAllowed() ) + { + // cancelled by program + return; + } - item->Expand(); - CalculatePositions(); + item->Expand(); + CalculatePositions(); - RefreshSubtree(item); + RefreshSubtree(item); - event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED); - ProcessEvent( event ); + event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED); + ProcessEvent( event ); } void wxTreeCtrl::Collapse(const wxTreeItemId& itemId) { - wxGenericTreeItem *item = itemId.m_pItem; + wxGenericTreeItem *item = itemId.m_pItem; - if ( !item->IsExpanded() ) - return; + if ( !item->IsExpanded() ) + return; - wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() ); - event.m_item = item; - event.SetEventObject( this ); - if ( ProcessEvent( event ) && !event.IsAllowed() ) - { - // cancelled by program - return; - } + wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() ); + event.m_item = item; + event.SetEventObject( this ); + if ( ProcessEvent( event ) && !event.IsAllowed() ) + { + // cancelled by program + return; + } - item->Collapse(); + item->Collapse(); - wxArrayGenericTreeItems& children = item->GetChildren(); - size_t count = children.Count(); - for ( size_t n = 0; n < count; n++ ) - { - Collapse(children[n]); - } + wxArrayGenericTreeItems& children = item->GetChildren(); + size_t count = children.Count(); + for ( size_t n = 0; n < count; n++ ) + { + Collapse(children[n]); + } - CalculatePositions(); + CalculatePositions(); - RefreshSubtree(item); + RefreshSubtree(item); - event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED); - ProcessEvent( event ); + event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED); + ProcessEvent( event ); } void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item) @@ -1152,7 +1242,7 @@ bool wxTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxGenericT crt_item->SetHilight(select); RefreshLine(crt_item); - if (crt_item==last_item) + if (crt_item==last_item) return TRUE; if (crt_item->HasChildren()) @@ -1161,9 +1251,9 @@ bool wxTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxGenericT size_t count = children.Count(); for ( size_t n = 0; n < count; ++n ) { - if (TagAllChildrenUntilLast(children[n], last_item, select)) + if (TagAllChildrenUntilLast(children[n], last_item, select)) return TRUE; - } + } } return FALSE; @@ -1171,27 +1261,27 @@ bool wxTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxGenericT void wxTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeItem *item2) { - // item2 is not necessary after item1 - wxGenericTreeItem *first=NULL, *last=NULL; + // item2 is not necessary after item1 + wxGenericTreeItem *first=NULL, *last=NULL; - // choice first' and 'last' between item1 and item2 - if (item1->GetY()GetY()) - { - first=item1; - last=item2; - } - else - { - first=item2; - last=item1; - } + // choice first' and 'last' between item1 and item2 + if (item1->GetY()GetY()) + { + first=item1; + last=item2; + } + else + { + first=item2; + last=item1; + } - bool select = m_current->IsSelected(); + bool select = m_current->IsSelected(); - if ( TagAllChildrenUntilLast(first,last,select) ) - return; + if ( TagAllChildrenUntilLast(first,last,select) ) + return; - TagNextChildren(first,last,select); + TagNextChildren(first,last,select); } void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId, @@ -1404,28 +1494,29 @@ wxImageList *wxTreeCtrl::GetStateImageList() const void wxTreeCtrl::SetImageList(wxImageList *imageList) { - m_imageListNormal = imageList; - - // Calculate a m_lineHeight value from the image sizes. - // May be toggle off. Then wxTreeCtrl will spread when - // necessary (which might look ugly). -#if 1 - wxClientDC dc(this); - m_lineHeight = (int)(dc.GetCharHeight() + 4); - int - width = 0, - height = 0, - n = m_imageListNormal->GetImageCount(); - for(int i = 0; i < n ; i++) - { - m_imageListNormal->GetSize(i, width, height); - if(height > m_lineHeight) m_lineHeight = height; - } - - if (m_lineHeight<40) m_lineHeight+=2; // at least 4 pixels (odd such that a line can be drawn in between) - else m_lineHeight+=m_lineHeight/10; // otherwise 10% extra spacing + m_imageListNormal = imageList; -#endif + if ( !m_imageListNormal ) + return; + + // Calculate a m_lineHeight value from the image sizes. + // May be toggle off. Then wxTreeCtrl will spread when + // necessary (which might look ugly). + wxClientDC dc(this); + m_lineHeight = (int)(dc.GetCharHeight() + 4); + int width = 0, height = 0, + n = m_imageListNormal->GetImageCount(); + + for (int i = 0; i < n ; i++) + { + m_imageListNormal->GetSize(i, width, height); + if (height > m_lineHeight) m_lineHeight = height; + } + + if (m_lineHeight < 40) + m_lineHeight += 2; // at least 2 pixels + else + m_lineHeight += m_lineHeight/10; // otherwise 10% extra spacing } void wxTreeCtrl::SetStateImageList(wxImageList *imageList) @@ -1481,12 +1572,31 @@ void wxTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) int image = item->GetCurrentImage(); if ( image != NO_IMAGE ) { - m_imageListNormal->GetSize( image, image_w, image_h ); - image_w += 4; + if ( m_imageListNormal ) + { + m_imageListNormal->GetSize( image, image_w, image_h ); + image_w += 4; + } + else + { + image = NO_IMAGE; + } } int total_h = GetLineHeight(item); + if (item->IsSelected()) + dc.SetBrush(*m_hilightBrush); + else + { + wxColour colBg; + if ( attr && attr->HasBackgroundColour() ) + colBg = attr->GetBackgroundColour(); + else + colBg = m_backgroundColour; + dc.SetBrush(wxBrush(colBg, wxSOLID)); + } + dc.DrawRectangle( item->GetX()-2, item->GetY(), item->GetWidth()+2, total_h ); if ( image != NO_IMAGE ) @@ -1499,11 +1609,8 @@ void wxTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) dc.DestroyClippingRegion(); } - bool hasBgCol = attr && attr->HasBackgroundColour(); - dc.SetBackgroundMode(hasBgCol ? wxSOLID : wxTRANSPARENT); - if ( hasBgCol ) - dc.SetTextBackground(attr->GetBackgroundColour()); - dc.DrawText( item->GetText(), image_w + item->GetX(), item->GetY() + dc.SetBackgroundMode(wxTRANSPARENT); + dc.DrawText( item->GetText(), image_w + item->GetX(), (wxCoord)item->GetY() + ((total_h > text_h) ? (total_h - text_h)/2 : 0)); // restore normal font @@ -1552,15 +1659,12 @@ void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int & } wxPen *pen = wxTRANSPARENT_PEN; - wxBrush *brush; // FIXME is this really needed? wxColour colText; if ( item->IsSelected() ) { colText = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT ); - brush = m_hilightBrush; - if ( m_hasFocus ) pen = wxBLACK_PEN; @@ -1572,14 +1676,11 @@ void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int & colText = attr->GetTextColour(); else colText = *wxBLACK; - - brush = wxWHITE_BRUSH; } // prepare to draw dc.SetTextForeground(colText); dc.SetPen(*pen); - dc.SetBrush(*brush); // draw PaintItem(item, dc); @@ -1616,42 +1717,66 @@ void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int & } } -void wxTreeCtrl::DrawBorder(wxTreeItemId &item) +void wxTreeCtrl::DrawDropEffect(wxGenericTreeItem *item) +{ + if ( item ) + { + if ( item->HasPlus() ) + { + // it's a folder, indicate it by a border + DrawBorder(item); + } + else + { + // draw a line under the drop target because the item will be + // dropped there + DrawLine(item, TRUE /* below */); + } + + SetCursor(wxCURSOR_BULLSEYE); + } + else + { + // can't drop here + SetCursor(wxCURSOR_NO_ENTRY); + } +} + +void wxTreeCtrl::DrawBorder(const wxTreeItemId &item) { - if (!item) return; + wxCHECK_RET( item.IsOk(), _T("invalid item in wxTreeCtrl::DrawLine") ); - wxGenericTreeItem *i=item.m_pItem; + wxGenericTreeItem *i = item.m_pItem; wxClientDC dc(this); PrepareDC( dc ); dc.SetLogicalFunction(wxINVERT); + dc.SetBrush(*wxTRANSPARENT_BRUSH); - int w,h,x; - ViewStart(&x,&h); // we only need x - GetClientSize(&w,&h); // we only need w + int w = i->GetWidth() + 2; + int h = GetLineHeight(i) + 2; - h=GetLineHeight(i)+1; - // 2 white column at border - dc.DrawRectangle( PIXELS_PER_UNIT*x+2, i->GetY()-1, w-6, h); + dc.DrawRectangle( i->GetX() - 1, i->GetY() - 1, w, h); } -void wxTreeCtrl::DrawLine(wxTreeItemId &item, bool below) +void wxTreeCtrl::DrawLine(const wxTreeItemId &item, bool below) { - if (!item) return; + wxCHECK_RET( item.IsOk(), _T("invalid item in wxTreeCtrl::DrawLine") ); - wxGenericTreeItem *i=item.m_pItem; + wxGenericTreeItem *i = item.m_pItem; wxClientDC dc(this); PrepareDC( dc ); dc.SetLogicalFunction(wxINVERT); - int w,h,y; - GetSize(&w,&h); - - if (below) y=i->GetY()+GetLineHeight(i)-1; - else y=i->GetY(); + int x = i->GetX(), + y = i->GetY(); + if ( below ) + { + y += GetLineHeight(i) - 1; + } - dc.DrawLine( 0, y, w, y); + dc.DrawLine( x, y, x + i->GetWidth(), y); } // ----------------------------------------------------------------------------- @@ -1694,7 +1819,7 @@ void wxTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) void wxTreeCtrl::OnChar( wxKeyEvent &event ) { wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() ); - te.m_code = event.KeyCode(); + te.m_code = (int)event.KeyCode(); te.SetEventObject( this ); GetEventHandler()->ProcessEvent( te ); @@ -1704,10 +1829,23 @@ void wxTreeCtrl::OnChar( wxKeyEvent &event ) return; } - bool is_multiple=(GetWindowStyleFlag() & wxTR_MULTIPLE); - bool extended_select=(event.ShiftDown() && is_multiple); - bool unselect_others=!(extended_select || (event.ControlDown() && is_multiple)); - + // how should the selection work for this event? + bool is_multiple, extended_select, unselect_others; + EventFlagsToSelType(GetWindowStyleFlag(), + event.ShiftDown(), + event.ControlDown(), + is_multiple, extended_select, unselect_others); + + // + : Expand + // - : Collaspe + // * : Toggle Expand/Collapse + // ' ' | return : activate + // up : go up (not last children!) + // down : go down + // left : go to parent + // right : open if parent and go next + // home : go to root + // end : go to last item without opening parents switch (event.KeyCode()) { case '+': @@ -1886,8 +2024,8 @@ wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& flags) wxClientDC dc(this); PrepareDC(dc); - long x = dc.DeviceToLogicalX( (long)point.x ); - long y = dc.DeviceToLogicalY( (long)point.y ); + wxCoord x = dc.DeviceToLogicalX( point.x ); + wxCoord y = dc.DeviceToLogicalY( point.y ); int w, h; GetSize(&w, &h); @@ -1932,8 +2070,15 @@ void wxTreeCtrl::Edit( const wxTreeItemId& item ) int image = m_currentEdit->GetCurrentImage(); if ( image != NO_IMAGE ) { - m_imageListNormal->GetSize( image, image_w, image_h ); - image_w += 4; + if ( m_imageListNormal ) + { + m_imageListNormal->GetSize( image, image_w, image_h ); + image_w += 4; + } + else + { + wxFAIL_MSG(_T("you must create an image list to use images!")); + } } x += image_w; w -= image_w + 4; // I don't know why +4 is needed @@ -1968,81 +2113,175 @@ void wxTreeCtrl::OnRenameAccept() void wxTreeCtrl::OnMouse( wxMouseEvent &event ) { - if ( !(event.LeftUp() || event.RightDown() || event.LeftDClick() || event.Dragging()) ) return; - if ( !m_anchor ) return; + // we process left mouse up event (enables in-place edit), right down + // (pass to the user code), left dbl click (activate item) and + // dragging/moving events for items drag-and-drop + if ( !(event.LeftUp() || + event.RightDown() || + event.LeftDClick() || + event.Dragging() || + ((event.Moving() || event.RightUp()) && m_isDragging)) ) + { + event.Skip(); + + return; + } + wxClientDC dc(this); PrepareDC(dc); - long x = dc.DeviceToLogicalX( (long)event.GetX() ); - long y = dc.DeviceToLogicalY( (long)event.GetY() ); + wxCoord x = dc.DeviceToLogicalX( event.GetX() ); + wxCoord y = dc.DeviceToLogicalY( event.GetY() ); - int flags=0; + int flags = 0; wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), this, flags); + bool onButton = flags & wxTREE_HITTEST_ONITEMBUTTON; - if (event.Dragging()) + if ( event.Dragging() && !m_isDragging ) { if (m_dragCount == 0) m_dragStart = wxPoint(x,y); m_dragCount++; - if (m_dragCount != 3) return; + if (m_dragCount != 3) + { + // wait until user drags a bit further... + return; + } - int command = wxEVT_COMMAND_TREE_BEGIN_DRAG; - if (event.RightIsDown()) command = wxEVT_COMMAND_TREE_BEGIN_RDRAG; + wxEventType command = event.RightIsDown() + ? wxEVT_COMMAND_TREE_BEGIN_RDRAG + : wxEVT_COMMAND_TREE_BEGIN_DRAG; wxTreeEvent nevent( command, GetId() ); nevent.m_item = m_current; nevent.SetEventObject(this); - GetEventHandler()->ProcessEvent(nevent); - return; + + // by default the dragging is not supported, the user code must + // explicitly allow the event for it to take place + nevent.Veto(); + + if ( GetEventHandler()->ProcessEvent(nevent) && nevent.IsAllowed() ) + { + // we're going to drag this item + m_isDragging = TRUE; + + // remember the old cursor because we will change it while + // dragging + m_oldCursor = m_cursor; + + // in a single selection control, hide the selection temporarily + if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE) ) + { + m_oldSelection = GetSelection().m_pItem; + + if ( m_oldSelection ) + { + m_oldSelection->SetHilight(FALSE); + RefreshLine(m_oldSelection); + } + } + + CaptureMouse(); + } } - else + else if ( event.Moving() ) { - m_dragCount = 0; - } + if ( item != m_dropTarget ) + { + // unhighlight the previous drop target + DrawDropEffect(m_dropTarget); - if (item == NULL) return; /* we hit the blank area */ + m_dropTarget = item; - if (event.RightDown()) { - wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK,GetId()); - nevent.m_item=item; - nevent.m_code=0; - nevent.SetEventObject(this); - GetEventHandler()->ProcessEvent(nevent); - return; - } + // highlight the current drop target if any + DrawDropEffect(m_dropTarget); - if (event.LeftUp() && (item == m_current) && - (flags & wxTREE_HITTEST_ONITEMLABEL) && - HasFlag(wxTR_EDIT_LABELS) ) - { - m_renameTimer->Start( 100, TRUE ); - return; + wxYield(); + } } + else if ( (event.LeftUp() || event.RightUp()) && m_isDragging ) + { + // erase the highlighting + DrawDropEffect(m_dropTarget); - bool is_multiple=(GetWindowStyleFlag() & wxTR_MULTIPLE); - bool extended_select=(event.ShiftDown() && is_multiple); - bool unselect_others=!(extended_select || (event.ControlDown() && is_multiple)); + // generate the drag end event + wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, GetId()); - if (onButton) - { - Toggle( item ); - if (is_multiple) - return; - } + event.m_item = item; + event.m_pointDrag = wxPoint(x, y); + event.SetEventObject(this); + + (void)GetEventHandler()->ProcessEvent(event); - SelectItem(item, unselect_others, extended_select); + m_isDragging = FALSE; + m_dropTarget = (wxGenericTreeItem *)NULL; - if (event.LeftDClick()) + if ( m_oldSelection ) + { + m_oldSelection->SetHilight(TRUE); + RefreshLine(m_oldSelection); + m_oldSelection = (wxGenericTreeItem *)NULL; + } + + ReleaseMouse(); + + SetCursor(m_oldCursor); + + wxYield(); + } + else { - wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() ); - event.m_item = item; - event.m_code = 0; - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent( event ); + // here we process only the messages which happen on tree items + + m_dragCount = 0; + + if (item == NULL) return; /* we hit the blank area */ + + if ( event.RightDown() ) + { + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId()); + nevent.m_item = item; + nevent.m_code = 0; + nevent.SetEventObject(this); + GetEventHandler()->ProcessEvent(nevent); + } + else if ( event.LeftUp() && (item == m_current) && + (flags & wxTREE_HITTEST_ONITEMLABEL) && + HasFlag(wxTR_EDIT_LABELS) ) + { + m_renameTimer->Start( 100, TRUE ); + } + else + { + // how should the selection work for this event? + bool is_multiple, extended_select, unselect_others; + EventFlagsToSelType(GetWindowStyleFlag(), + event.ShiftDown(), + event.ControlDown(), + is_multiple, extended_select, unselect_others); + + if ( onButton ) + { + Toggle( item ); + if ( is_multiple ) + return; + } + + SelectItem(item, unselect_others, extended_select); + + if ( event.LeftDClick() ) + { + wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() ); + nevent.m_item = item; + nevent.m_code = 0; + nevent.SetEventObject( this ); + GetEventHandler()->ProcessEvent( nevent ); + } + } } } @@ -2063,8 +2302,8 @@ void wxTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) ) void wxTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc ) { - long text_w = 0; - long text_h = 0; + wxCoord text_w = 0; + wxCoord text_h = 0; if (item->IsBold()) dc.SetFont(m_boldFont); @@ -2080,17 +2319,23 @@ void wxTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc ) int image = item->GetCurrentImage(); if ( image != NO_IMAGE ) { - m_imageListNormal->GetSize( image, image_w, image_h ); - image_w += 4; + if ( m_imageListNormal ) + { + m_imageListNormal->GetSize( image, image_w, image_h ); + image_w += 4; + } } int total_h = (image_h > text_h) ? image_h : text_h; - if (total_h<40) total_h+=2; // at least 4 pixels - else total_h+=total_h/10; // otherwise 10% extra spacing + if (total_h < 40) + total_h += 2; // at least 2 pixels + else + total_h += total_h/10; // otherwise 10% extra spacing item->SetHeight(total_h); - if (total_h>m_lineHeight) m_lineHeight=total_h; + if (total_h>m_lineHeight) + m_lineHeight=total_h; item->SetWidth(image_w+text_w+2); } @@ -2118,7 +2363,7 @@ void wxTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, i wxArrayGenericTreeItems& children = item->GetChildren(); size_t n, count = children.Count(); for (n = 0; n < count; ++n ) - CalculateLevel( children[n], dc, level+1, y ); // recurse + CalculateLevel( children[n], dc, level+1, y ); // recurse } void wxTreeCtrl::CalculatePositions() @@ -2140,6 +2385,8 @@ void wxTreeCtrl::CalculatePositions() void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem *item) { + if (m_dirty) return; + wxClientDC dc(this); PrepareDC(dc); @@ -2160,6 +2407,8 @@ void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem *item) void wxTreeCtrl::RefreshLine( wxGenericTreeItem *item ) { + if (m_dirty) return; + wxClientDC dc(this); PrepareDC( dc );