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
// -----------------------------------------------------------------------------
void SetItemSelectedImage(const wxTreeItemId& item, int image)
{ SetItemImage(item, image, wxTreeItemIcon_Selected); }
- // implementation
+ // implementation only from now on
// callbacks
void OnPaint( wxPaintEvent &event );
void OnMouse( wxMouseEvent &event );
void OnIdle( wxIdleEvent &event );
- // implementation
+ // implementation helpers
void SendDeleteEvent(wxGenericTreeItem *itemBeingDeleted);
- // Draw Special Information
- void DrawBorder(wxTreeItemId& item);
- void DrawLine(wxTreeItemId& item, bool below);
+ void DrawBorder(const wxTreeItemId& item);
+ void DrawLine(const wxTreeItemId& item, bool below);
protected:
friend class wxGenericTreeItem;
wxBrush *m_hilightBrush;
wxImageList *m_imageListNormal,
*m_imageListState;
+
int m_dragCount;
wxPoint m_dragStart;
+ bool m_isDragging; // true between BEGIN/END drag events
+ wxGenericTreeItem *m_dropTarget;
+
wxTimer *m_renameTimer;
bool m_renameAccept;
wxString m_renameRes;
bool TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select);
void UnselectAllChildren( wxGenericTreeItem *item );
+ void DrawDropEffect(wxGenericTreeItem *item);
+
private:
DECLARE_EVENT_TABLE()
DECLARE_DYNAMIC_CLASS(wxTreeCtrl)
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
{
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
m_accept = accept;
m_owner = owner;
(*m_accept) = FALSE;
- (*m_res) = "";
+ (*m_res) = wxEmptyString;
m_startValue = value;
}
m_owner->OnRenameAccept();
}
-#define PIXELS_PER_UNIT 10
// -----------------------------------------------------------------------------
// wxTreeEvent
// -----------------------------------------------------------------------------
{
if ((point.y > m_y) && (point.y < m_y + theTree->GetLineHeight(this)))
{
- if (point.y<m_y+theTree->GetLineHeight(this)/2)
+ if (point.y < m_y+theTree->GetLineHeight(this)/2 )
flags |= wxTREE_HITTEST_ONITEMUPPERPART;
else
flags |= wxTREE_HITTEST_ONITEMLOWERPART;
m_imageListState = (wxImageList *) NULL;
m_dragCount = 0;
+ m_isDragging = FALSE;
+ m_dropTarget = (wxGenericTreeItem *)NULL;
m_renameTimer = new wxTreeRenameTimer( this );
}
}
-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);
}
// -----------------------------------------------------------------------------
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;
+
+ 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;
+
+ ReleaseMouse();
+
+ SetCursor(wxCURSOR_DEFAULT);
+
+ 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 );
+ }
+ }
}
}