added dnd support to generic wxTreeCtrl

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6146 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-02-18 22:12:58 +00:00
parent c4c829aeab
commit 3dbeaa523d
3 changed files with 228 additions and 135 deletions

View File

@@ -96,49 +96,6 @@ protected:
wxTreeItemId m_pItem; wxTreeItemId m_pItem;
}; };
//-----------------------------------------------------------------------------
// wxTreeRenameTimer (internal)
//-----------------------------------------------------------------------------
class WXDLLEXPORT wxTreeRenameTimer: public wxTimer
{
private:
wxTreeCtrl *m_owner;
public:
wxTreeRenameTimer( wxTreeCtrl *owner );
void Notify();
};
//-----------------------------------------------------------------------------
// wxTreeTextCtrl (internal)
//-----------------------------------------------------------------------------
class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
{
DECLARE_DYNAMIC_CLASS(wxTreeTextCtrl);
private:
bool *m_accept;
wxString *m_res;
wxTreeCtrl *m_owner;
wxString m_startValue;
public:
wxTreeTextCtrl(void) {};
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 );
DECLARE_EVENT_TABLE()
};
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// wxTreeCtrl - the tree control // wxTreeCtrl - the tree control
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -405,7 +362,7 @@ public:
void SetItemSelectedImage(const wxTreeItemId& item, int image) void SetItemSelectedImage(const wxTreeItemId& item, int image)
{ SetItemImage(item, image, wxTreeItemIcon_Selected); } { SetItemImage(item, image, wxTreeItemIcon_Selected); }
// implementation // implementation only from now on
// callbacks // callbacks
void OnPaint( wxPaintEvent &event ); void OnPaint( wxPaintEvent &event );
@@ -415,12 +372,11 @@ public:
void OnMouse( wxMouseEvent &event ); void OnMouse( wxMouseEvent &event );
void OnIdle( wxIdleEvent &event ); void OnIdle( wxIdleEvent &event );
// implementation // implementation helpers
void SendDeleteEvent(wxGenericTreeItem *itemBeingDeleted); void SendDeleteEvent(wxGenericTreeItem *itemBeingDeleted);
// Draw Special Information void DrawBorder(const wxTreeItemId& item);
void DrawBorder(wxTreeItemId& item); void DrawLine(const wxTreeItemId& item, bool below);
void DrawLine(wxTreeItemId& item, bool below);
protected: protected:
friend class wxGenericTreeItem; friend class wxGenericTreeItem;
@@ -442,8 +398,12 @@ protected:
wxBrush *m_hilightBrush; wxBrush *m_hilightBrush;
wxImageList *m_imageListNormal, wxImageList *m_imageListNormal,
*m_imageListState; *m_imageListState;
int m_dragCount; int m_dragCount;
wxPoint m_dragStart; wxPoint m_dragStart;
bool m_isDragging; // true between BEGIN/END drag events
wxGenericTreeItem *m_dropTarget;
wxTimer *m_renameTimer; wxTimer *m_renameTimer;
bool m_renameAccept; bool m_renameAccept;
wxString m_renameRes; wxString m_renameRes;
@@ -479,6 +439,8 @@ protected:
bool TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select); bool TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select);
void UnselectAllChildren( wxGenericTreeItem *item ); void UnselectAllChildren( wxGenericTreeItem *item );
void DrawDropEffect(wxGenericTreeItem *item);
private: private:
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
DECLARE_DYNAMIC_CLASS(wxTreeCtrl) DECLARE_DYNAMIC_CLASS(wxTreeCtrl)

View File

@@ -149,7 +149,7 @@ MyFrame::MyFrame(const wxString& title, int x, int y, int w, int h)
file_menu->Append(TreeTest_About, "&About..."); file_menu->Append(TreeTest_About, "&About...");
file_menu->AppendSeparator(); file_menu->AppendSeparator();
file_menu->Append(TreeTest_Quit, "E&xit"); file_menu->Append(TreeTest_Quit, "E&xit\tAlt-X");
tree_menu->Append(TreeTest_Recreate, "&Recreate the tree"); tree_menu->Append(TreeTest_Recreate, "&Recreate the tree");
tree_menu->Append(TreeTest_CollapseAndReset, "C&ollapse and reset"); tree_menu->Append(TreeTest_CollapseAndReset, "C&ollapse and reset");
@@ -200,9 +200,6 @@ MyFrame::MyFrame(const wxString& title, int x, int y, int w, int h)
wxDefaultPosition, wxDefaultSize, wxDefaultPosition, wxDefaultSize,
wxTR_HAS_BUTTONS | wxTR_HAS_BUTTONS |
wxTR_EDIT_LABELS | wxTR_EDIT_LABELS |
#ifndef NO_MULTIPLE_SELECTION
wxTR_MULTIPLE |
#endif
#ifndef NO_VARIABLE_HEIGHT #ifndef NO_VARIABLE_HEIGHT
wxTR_HAS_VARIABLE_ROW_HEIGHT | wxTR_HAS_VARIABLE_ROW_HEIGHT |
#endif #endif
@@ -622,9 +619,10 @@ void MyTreeCtrl::DoToggleIcon(const wxTreeItemId& item)
// avoid repetition // avoid repetition
#define TREE_EVENT_HANDLER(name) \ #define TREE_EVENT_HANDLER(name) \
void MyTreeCtrl::name(wxTreeEvent& WXUNUSED(event)) \ void MyTreeCtrl::name(wxTreeEvent& event) \
{ \ { \
wxLogMessage(#name); \ wxLogMessage(#name); \
event.Skip(); \
} }
TREE_EVENT_HANDLER(OnBeginRDrag) TREE_EVENT_HANDLER(OnBeginRDrag)
@@ -636,6 +634,7 @@ TREE_EVENT_HANDLER(OnItemExpanding)
TREE_EVENT_HANDLER(OnItemCollapsed) TREE_EVENT_HANDLER(OnItemCollapsed)
TREE_EVENT_HANDLER(OnSelChanged) TREE_EVENT_HANDLER(OnSelChanged)
TREE_EVENT_HANDLER(OnSelChanging) TREE_EVENT_HANDLER(OnSelChanging)
TREE_EVENT_HANDLER(OnTreeKeyDown)
#undef TREE_EVENT_HANDLER #undef TREE_EVENT_HANDLER
@@ -688,7 +687,7 @@ void MyTreeCtrl::OnEndDrag(wxTreeEvent& event)
// //
// Finally, we only copy one item here but we might copy the entire tree if // Finally, we only copy one item here but we might copy the entire tree if
// we were dragging a folder. // we were dragging a folder.
AppendItem(itemDst, text); AppendItem(itemDst, text, TreeCtrlIcon_File);
} }
void MyTreeCtrl::OnBeginLabelEdit(wxTreeEvent& event) void MyTreeCtrl::OnBeginLabelEdit(wxTreeEvent& event)
@@ -732,11 +731,6 @@ void MyTreeCtrl::OnItemCollapsing(wxTreeEvent& event)
} }
} }
void MyTreeCtrl::OnTreeKeyDown(wxTreeEvent&WXUNUSED(event))
{
wxLogMessage("OnTreeKeyDown");
}
void MyTreeCtrl::OnItemActivated(wxTreeEvent&WXUNUSED(event)) void MyTreeCtrl::OnItemActivated(wxTreeEvent&WXUNUSED(event))
{ {
// show some info about this item // show some info about this item

View File

@@ -53,10 +53,54 @@ WX_DEFINE_OBJARRAY(wxArrayTreeItemIds);
static const int NO_IMAGE = -1; static const int NO_IMAGE = -1;
#define PIXELS_PER_UNIT 10
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// private classes // 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 // a tree item
class WXDLLEXPORT wxGenericTreeItem class WXDLLEXPORT wxGenericTreeItem
{ {
@@ -242,7 +286,7 @@ wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent,
m_accept = accept; m_accept = accept;
m_owner = owner; m_owner = owner;
(*m_accept) = FALSE; (*m_accept) = FALSE;
(*m_res) = ""; (*m_res) = wxEmptyString;
m_startValue = value; m_startValue = value;
} }
@@ -283,7 +327,6 @@ void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
m_owner->OnRenameAccept(); m_owner->OnRenameAccept();
} }
#define PIXELS_PER_UNIT 10
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// wxTreeEvent // wxTreeEvent
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -563,6 +606,8 @@ void wxTreeCtrl::Init()
m_imageListState = (wxImageList *) NULL; m_imageListState = (wxImageList *) NULL;
m_dragCount = 0; m_dragCount = 0;
m_isDragging = FALSE;
m_dropTarget = (wxGenericTreeItem *)NULL;
m_renameTimer = new wxTreeRenameTimer( this ); m_renameTimer = new wxTreeRenameTimer( this );
@@ -1663,28 +1708,51 @@ 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 )
{
wxGenericTreeItem *i=item.m_pItem; if ( item->HasPlus() )
{
wxClientDC dc(this); // it's a folder, indicate it by a border
PrepareDC( dc ); DrawBorder(item);
dc.SetLogicalFunction(wxINVERT); }
else
int w,h,x; {
ViewStart(&x,&h); // we only need x // draw a line under the drop target because the item will be
GetClientSize(&w,&h); // we only need w // dropped there
DrawLine(item, TRUE /* below */);
h=GetLineHeight(i)+1;
// 2 white column at border
dc.DrawRectangle( PIXELS_PER_UNIT*x+2, i->GetY()-1, w-6, h);
} }
void wxTreeCtrl::DrawLine(wxTreeItemId &item, bool below) SetCursor(wxCURSOR_BULLSEYE);
}
else
{ {
if (!item) return; // 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 = i->GetWidth() + 2;
int h = GetLineHeight(i) + 2;
dc.DrawRectangle( i->GetX() - 1, i->GetY() - 1, w, h);
}
void wxTreeCtrl::DrawLine(const wxTreeItemId &item, bool below)
{
wxCHECK_RET( item.IsOk(), _T("invalid item in wxTreeCtrl::DrawLine") );
wxGenericTreeItem *i = item.m_pItem; wxGenericTreeItem *i = item.m_pItem;
@@ -1692,13 +1760,14 @@ void wxTreeCtrl::DrawLine(wxTreeItemId &item, bool below)
PrepareDC( dc ); PrepareDC( dc );
dc.SetLogicalFunction(wxINVERT); dc.SetLogicalFunction(wxINVERT);
int w,h,y; int x = i->GetX(),
GetSize(&w,&h); y = i->GetY();
if ( below )
{
y += GetLineHeight(i) - 1;
}
if (below) y=i->GetY()+GetLineHeight(i)-1; dc.DrawLine( x, y, x + i->GetWidth(), y);
else y=i->GetY();
dc.DrawLine( 0, y, w, y);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -2018,10 +2087,22 @@ void wxTreeCtrl::OnRenameAccept()
void wxTreeCtrl::OnMouse( wxMouseEvent &event ) void wxTreeCtrl::OnMouse( wxMouseEvent &event )
{ {
if ( !(event.LeftUp() || event.RightDown() || event.LeftDClick() || event.Dragging()) ) return;
if ( !m_anchor ) 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); wxClientDC dc(this);
PrepareDC(dc); PrepareDC(dc);
wxCoord x = dc.DeviceToLogicalX( event.GetX() ); wxCoord x = dc.DeviceToLogicalX( event.GetX() );
@@ -2029,50 +2110,104 @@ void wxTreeCtrl::OnMouse( wxMouseEvent &event )
int flags = 0; int flags = 0;
wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), this, flags); wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), this, flags);
bool onButton = flags & wxTREE_HITTEST_ONITEMBUTTON; bool onButton = flags & wxTREE_HITTEST_ONITEMBUTTON;
if (event.Dragging()) if ( event.Dragging() && !m_isDragging )
{ {
if (m_dragCount == 0) if (m_dragCount == 0)
m_dragStart = wxPoint(x,y); m_dragStart = wxPoint(x,y);
m_dragCount++; 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; wxEventType command = event.RightIsDown()
if (event.RightIsDown()) command = wxEVT_COMMAND_TREE_BEGIN_RDRAG; ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
: wxEVT_COMMAND_TREE_BEGIN_DRAG;
wxTreeEvent nevent( command, GetId() ); wxTreeEvent nevent( command, GetId() );
nevent.m_item = m_current; nevent.m_item = m_current;
nevent.SetEventObject(this); 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;
CaptureMouse();
}
}
else if ( event.Moving() )
{
if ( item != m_dropTarget )
{
// unhighlight the previous drop target
DrawDropEffect(m_dropTarget);
m_dropTarget = item;
// highlight the current drop target if any
DrawDropEffect(m_dropTarget);
wxYield();
}
}
else if ( (event.LeftUp() || event.RightUp()) && m_isDragging )
{
// erase the highlighting
DrawDropEffect(m_dropTarget);
// generate the drag end event
wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, GetId());
event.m_item = item;
event.m_pointDrag = wxPoint(x, y);
event.SetEventObject(this);
(void)GetEventHandler()->ProcessEvent(event);
m_isDragging = FALSE;
m_dropTarget = (wxGenericTreeItem *)NULL;
ReleaseMouse();
SetCursor(wxCURSOR_DEFAULT);
wxYield();
} }
else else
{ {
// here we process only the messages which happen on tree items
m_dragCount = 0; m_dragCount = 0;
}
if (item == NULL) return; /* we hit the blank area */ if (item == NULL) return; /* we hit the blank area */
if (event.RightDown()) { if ( event.RightDown() )
{
wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId()); wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId());
nevent.m_item = item; nevent.m_item = item;
nevent.m_code = 0; nevent.m_code = 0;
nevent.SetEventObject(this); nevent.SetEventObject(this);
GetEventHandler()->ProcessEvent(nevent); GetEventHandler()->ProcessEvent(nevent);
return;
} }
else if ( event.LeftUp() && (item == m_current) &&
if (event.LeftUp() && (item == m_current) &&
(flags & wxTREE_HITTEST_ONITEMLABEL) && (flags & wxTREE_HITTEST_ONITEMLABEL) &&
HasFlag(wxTR_EDIT_LABELS) ) HasFlag(wxTR_EDIT_LABELS) )
{ {
m_renameTimer->Start( 100, TRUE ); m_renameTimer->Start( 100, TRUE );
return;
} }
else
{
// how should the selection work for this event? // how should the selection work for this event?
bool is_multiple, extended_select, unselect_others; bool is_multiple, extended_select, unselect_others;
EventFlagsToSelType(GetWindowStyleFlag(), EventFlagsToSelType(GetWindowStyleFlag(),
@@ -2091,11 +2226,13 @@ void wxTreeCtrl::OnMouse( wxMouseEvent &event )
if ( event.LeftDClick() ) if ( event.LeftDClick() )
{ {
wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() ); wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
event.m_item = item; nevent.m_item = item;
event.m_code = 0; nevent.m_code = 0;
event.SetEventObject( this ); nevent.SetEventObject( this );
GetEventHandler()->ProcessEvent( event ); GetEventHandler()->ProcessEvent( nevent );
}
}
} }
} }