X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6cedba093a6d87371ca67534b1b9165fe3d45fbc..8dd4f53663d62aba88bf9c65e292fe25a6bb96aa:/src/generic/treectrl.cpp diff --git a/src/generic/treectrl.cpp b/src/generic/treectrl.cpp index a438ee6aaa..dc7160f294 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 @@ -242,7 +286,7 @@ wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent, m_accept = accept; m_owner = owner; (*m_accept) = FALSE; - (*m_res) = ""; + (*m_res) = wxEmptyString; m_startValue = value; } @@ -283,7 +327,6 @@ void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) m_owner->OnRenameAccept(); } -#define PIXELS_PER_UNIT 10 // ----------------------------------------------------------------------------- // wxTreeEvent // ----------------------------------------------------------------------------- @@ -430,7 +473,7 @@ wxGenericTreeItem *wxGenericTreeItem::HitTest( const wxPoint& point, { if ((point.y > m_y) && (point.y < m_y + theTree->GetLineHeight(this))) { - if (point.yGetLineHeight(this)/2) + if (point.y < m_y+theTree->GetLineHeight(this)/2 ) flags |= wxTREE_HITTEST_ONITEMUPPERPART; else flags |= wxTREE_HITTEST_ONITEMLOWERPART; @@ -563,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 ); @@ -1663,42 +1709,66 @@ void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int & } } -void wxTreeCtrl::DrawBorder(wxTreeItemId &item) +void wxTreeCtrl::DrawDropEffect(wxGenericTreeItem *item) { - if (!item) return; + 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 */); + } - wxGenericTreeItem *i=item.m_pItem; + SetCursor(wxCURSOR_BULLSEYE); + } + else + { + // can't drop here + SetCursor(wxCURSOR_NO_ENTRY); + } +} + +void wxTreeCtrl::DrawBorder(const wxTreeItemId &item) +{ + wxCHECK_RET( item.IsOk(), _T("invalid item in wxTreeCtrl::DrawLine") ); + + 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); } // ----------------------------------------------------------------------------- @@ -2018,84 +2088,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); 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); - // 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); + // 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); - SelectItem(item, unselect_others, extended_select); + (void)GetEventHandler()->ProcessEvent(event); - if (event.LeftDClick()) + m_isDragging = FALSE; + m_dropTarget = (wxGenericTreeItem *)NULL; + + 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 ); + } + } } }