]> git.saurik.com Git - wxWidgets.git/blame - src/common/treebase.cpp
Fix horizontal mouse wheel scrolling in wxGTK.
[wxWidgets.git] / src / common / treebase.cpp
CommitLineData
484523cf 1/////////////////////////////////////////////////////////////////////////////
80fdcdb9 2// Name: src/common/treebase.cpp
484523cf
JS
3// Purpose: Base wxTreeCtrl classes
4// Author: Julian Smart
5// Created: 01/02/97
6// Modified:
484523cf 7// Copyright: (c) 1998 Robert Roebling, Julian Smart et al
65571936 8// Licence: wxWindows licence
484523cf
JS
9/////////////////////////////////////////////////////////////////////////////
10
11// =============================================================================
12// declarations
13// =============================================================================
14
15// -----------------------------------------------------------------------------
16// headers
17// -----------------------------------------------------------------------------
18
484523cf
JS
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
1e6feb95 23 #pragma hdrstop
484523cf
JS
24#endif
25
1e6feb95
VZ
26#if wxUSE_TREECTRL
27
8cee4a30 28#include "wx/treectrl.h"
42e53e77 29#include "wx/imaglist.h"
ed2ec17c 30
f313deaa
PC
31extern WXDLLEXPORT_DATA(const char) wxTreeCtrlNameStr[] = "treeCtrl";
32
ed2ec17c
GT
33// ----------------------------------------------------------------------------
34// events
35// ----------------------------------------------------------------------------
36
ce7fe42e
VZ
37wxDEFINE_EVENT( wxEVT_TREE_BEGIN_DRAG, wxTreeEvent );
38wxDEFINE_EVENT( wxEVT_TREE_BEGIN_RDRAG, wxTreeEvent );
39wxDEFINE_EVENT( wxEVT_TREE_BEGIN_LABEL_EDIT, wxTreeEvent );
40wxDEFINE_EVENT( wxEVT_TREE_END_LABEL_EDIT, wxTreeEvent );
41wxDEFINE_EVENT( wxEVT_TREE_DELETE_ITEM, wxTreeEvent );
42wxDEFINE_EVENT( wxEVT_TREE_GET_INFO, wxTreeEvent );
43wxDEFINE_EVENT( wxEVT_TREE_SET_INFO, wxTreeEvent );
44wxDEFINE_EVENT( wxEVT_TREE_ITEM_EXPANDED, wxTreeEvent );
45wxDEFINE_EVENT( wxEVT_TREE_ITEM_EXPANDING, wxTreeEvent );
46wxDEFINE_EVENT( wxEVT_TREE_ITEM_COLLAPSED, wxTreeEvent );
47wxDEFINE_EVENT( wxEVT_TREE_ITEM_COLLAPSING, wxTreeEvent );
48wxDEFINE_EVENT( wxEVT_TREE_SEL_CHANGED, wxTreeEvent );
49wxDEFINE_EVENT( wxEVT_TREE_SEL_CHANGING, wxTreeEvent );
50wxDEFINE_EVENT( wxEVT_TREE_KEY_DOWN, wxTreeEvent );
51wxDEFINE_EVENT( wxEVT_TREE_ITEM_ACTIVATED, wxTreeEvent );
52wxDEFINE_EVENT( wxEVT_TREE_ITEM_RIGHT_CLICK, wxTreeEvent );
53wxDEFINE_EVENT( wxEVT_TREE_ITEM_MIDDLE_CLICK, wxTreeEvent );
54wxDEFINE_EVENT( wxEVT_TREE_END_DRAG, wxTreeEvent );
55wxDEFINE_EVENT( wxEVT_TREE_STATE_IMAGE_CLICK, wxTreeEvent );
56wxDEFINE_EVENT( wxEVT_TREE_ITEM_GETTOOLTIP, wxTreeEvent );
57wxDEFINE_EVENT( wxEVT_TREE_ITEM_MENU, wxTreeEvent );
ed2ec17c 58
28953245
SC
59// ----------------------------------------------------------------------------
60// XTI
61// ----------------------------------------------------------------------------
62
63wxDEFINE_FLAGS( wxTreeCtrlStyle )
64wxBEGIN_FLAGS( wxTreeCtrlStyle )
65// new style border flags, we put them first to
66// use them for streaming out
67wxFLAGS_MEMBER(wxBORDER_SIMPLE)
68wxFLAGS_MEMBER(wxBORDER_SUNKEN)
69wxFLAGS_MEMBER(wxBORDER_DOUBLE)
70wxFLAGS_MEMBER(wxBORDER_RAISED)
71wxFLAGS_MEMBER(wxBORDER_STATIC)
72wxFLAGS_MEMBER(wxBORDER_NONE)
73
74// old style border flags
75wxFLAGS_MEMBER(wxSIMPLE_BORDER)
76wxFLAGS_MEMBER(wxSUNKEN_BORDER)
77wxFLAGS_MEMBER(wxDOUBLE_BORDER)
78wxFLAGS_MEMBER(wxRAISED_BORDER)
79wxFLAGS_MEMBER(wxSTATIC_BORDER)
80wxFLAGS_MEMBER(wxBORDER)
81
82// standard window styles
83wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
84wxFLAGS_MEMBER(wxCLIP_CHILDREN)
85wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
86wxFLAGS_MEMBER(wxWANTS_CHARS)
87wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
88wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
89wxFLAGS_MEMBER(wxVSCROLL)
90wxFLAGS_MEMBER(wxHSCROLL)
91
92wxFLAGS_MEMBER(wxTR_EDIT_LABELS)
93wxFLAGS_MEMBER(wxTR_NO_BUTTONS)
94wxFLAGS_MEMBER(wxTR_HAS_BUTTONS)
95wxFLAGS_MEMBER(wxTR_TWIST_BUTTONS)
96wxFLAGS_MEMBER(wxTR_NO_LINES)
97wxFLAGS_MEMBER(wxTR_FULL_ROW_HIGHLIGHT)
98wxFLAGS_MEMBER(wxTR_LINES_AT_ROOT)
99wxFLAGS_MEMBER(wxTR_HIDE_ROOT)
100wxFLAGS_MEMBER(wxTR_ROW_LINES)
101wxFLAGS_MEMBER(wxTR_HAS_VARIABLE_ROW_HEIGHT)
102wxFLAGS_MEMBER(wxTR_SINGLE)
103wxFLAGS_MEMBER(wxTR_MULTIPLE)
104#if WXWIN_COMPATIBILITY_2_8
105wxFLAGS_MEMBER(wxTR_EXTENDED)
106#endif
107wxFLAGS_MEMBER(wxTR_DEFAULT_STYLE)
108wxEND_FLAGS( wxTreeCtrlStyle )
109
110wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxTreeCtrl, wxControl, "wx/treectrl.h")
111
112wxBEGIN_PROPERTIES_TABLE(wxTreeCtrl)
ce7fe42e
VZ
113wxEVENT_PROPERTY( TextUpdated, wxEVT_TEXT, wxCommandEvent )
114wxEVENT_RANGE_PROPERTY( TreeEvent, wxEVT_TREE_BEGIN_DRAG, \
115 wxEVT_TREE_STATE_IMAGE_CLICK, wxTreeEvent )
28953245
SC
116
117wxPROPERTY_FLAGS( WindowStyle, wxTreeCtrlStyle, long, SetWindowStyleFlag, \
118 GetWindowStyleFlag, wxEMPTY_PARAMETER_VALUE, 0 /*flags*/, \
119 wxT("Helpstring"), wxT("group")) // style
120wxEND_PROPERTIES_TABLE()
121
122wxEMPTY_HANDLERS_TABLE(wxTreeCtrl)
123
124wxCONSTRUCTOR_5( wxTreeCtrl, wxWindow*, Parent, wxWindowID, Id, \
125 wxPoint, Position, wxSize, Size, long, WindowStyle )
126
484523cf
JS
127// ----------------------------------------------------------------------------
128// Tree event
129// ----------------------------------------------------------------------------
130
e47859da 131IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
b8fbf1a0 132
09f277d6
VZ
133wxTreeEvent::wxTreeEvent(wxEventType commandType,
134 wxTreeCtrlBase *tree,
135 const wxTreeItemId& item)
136 : wxNotifyEvent(commandType, tree->GetId()),
137 m_item(item)
484523cf 138{
cb719f2e 139 m_editCancelled = false;
09f277d6
VZ
140
141 SetEventObject(tree);
142
143 if ( item.IsOk() )
144 SetClientObject(tree->GetItemData(item));
484523cf
JS
145}
146
49b6ebb7
RD
147wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
148 : wxNotifyEvent(commandType, id)
149{
150 m_itemOld = 0l;
151 m_editCancelled = false;
152}
153
0cd936a4
WS
154wxTreeEvent::wxTreeEvent(const wxTreeEvent & event)
155 : wxNotifyEvent(event)
156{
157 m_evtKey = event.m_evtKey;
158 m_item = event.m_item;
159 m_itemOld = event.m_itemOld;
160 m_pointDrag = event.m_pointDrag;
161 m_label = event.m_label;
162 m_editCancelled = event.m_editCancelled;
163}
164
8cee4a30
VZ
165// ----------------------------------------------------------------------------
166// wxTreeCtrlBase
167// ----------------------------------------------------------------------------
168
4e4841b0
VZ
169wxTreeCtrlBase::wxTreeCtrlBase()
170{
171 m_imageListNormal =
172 m_imageListState = NULL;
173 m_ownsImageListNormal =
174 m_ownsImageListState = false;
175
176 // arbitrary default
177 m_spacing = 18;
178
179 // quick DoGetBestSize calculation
180 m_quickBestSize = true;
64ac3db8
VZ
181
182 Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(wxTreeCtrlBase::OnCharHook));
4e4841b0
VZ
183}
184
8cee4a30
VZ
185wxTreeCtrlBase::~wxTreeCtrlBase()
186{
187 if (m_ownsImageListNormal)
188 delete m_imageListNormal;
189 if (m_ownsImageListState)
190 delete m_imageListState;
191}
192
03966fcb
RR
193void wxTreeCtrlBase::SetItemState(const wxTreeItemId& item, int state)
194{
195 if ( state == wxTREE_ITEMSTATE_NEXT )
196 {
4754ab16
RR
197 int current = GetItemState(item);
198 if ( current == wxTREE_ITEMSTATE_NONE )
199 return;
200 state = current + 1;
03966fcb
RR
201 if ( m_imageListState && state >= m_imageListState->GetImageCount() )
202 state = 0;
203 }
204 else if ( state == wxTREE_ITEMSTATE_PREV )
205 {
4754ab16
RR
206 int current = GetItemState(item);
207 if ( current == wxTREE_ITEMSTATE_NONE )
208 return;
209 state = current - 1;
03966fcb
RR
210 if ( state == -1 )
211 state = m_imageListState ? m_imageListState->GetImageCount() - 1 : 0;
212 }
213 // else: wxTREE_ITEMSTATE_NONE depending on platform
214
215 DoSetItemState(item, state);
216}
217
fbf8436c
VZ
218static void
219wxGetBestTreeSize(const wxTreeCtrlBase* treeCtrl, wxTreeItemId id, wxSize& size)
7c384067
JS
220{
221 wxRect rect;
70934138 222
fbf8436c 223 if ( treeCtrl->GetBoundingRect(id, rect, true /* just the item */) )
7c384067 224 {
9e7642ae 225 // Translate to logical position so we get the full extent
9766efc3 226#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
9e7642ae
JS
227 rect.x += treeCtrl->GetScrollPos(wxHORIZONTAL);
228 rect.y += treeCtrl->GetScrollPos(wxVERTICAL);
9766efc3 229#endif
9e7642ae 230
fbf8436c 231 size.IncTo(wxSize(rect.GetRight(), rect.GetBottom()));
7c384067
JS
232 }
233
234 wxTreeItemIdValue cookie;
235 for ( wxTreeItemId item = treeCtrl->GetFirstChild(id, cookie);
236 item.IsOk();
3e748fca 237 item = treeCtrl->GetNextChild(id, cookie) )
7c384067
JS
238 {
239 wxGetBestTreeSize(treeCtrl, item, size);
240 }
241}
242
8cee4a30
VZ
243wxSize wxTreeCtrlBase::DoGetBestSize() const
244{
245 wxSize size;
246
247 // this doesn't really compute the total bounding rectangle of all items
248 // but a not too bad guess of it which has the advantage of not having to
249 // examine all (potentially hundreds or thousands) items in the control
70934138 250
7c384067 251 if (GetQuickBestSize())
8cee4a30 252 {
7c384067
JS
253 for ( wxTreeItemId item = GetRootItem();
254 item.IsOk();
255 item = GetLastChild(item) )
8cee4a30 256 {
7c384067
JS
257 wxRect rect;
258
259 // last parameter is "true" to get only the dimensions of the text
260 // label, we don't want to get the entire item width as it's determined
261 // by the current size
262 if ( GetBoundingRect(item, rect, true) )
263 {
264 if ( size.x < rect.x + rect.width )
265 size.x = rect.x + rect.width;
266 if ( size.y < rect.y + rect.height )
267 size.y = rect.y + rect.height;
268 }
8cee4a30
VZ
269 }
270 }
fbf8436c
VZ
271 else // use precise, if potentially slow, size computation method
272 {
273 // iterate over all items recursively
16f32ee7
VZ
274 wxTreeItemId idRoot = GetRootItem();
275 if ( idRoot.IsOk() )
276 wxGetBestTreeSize(this, idRoot, size);
fbf8436c
VZ
277 }
278
8cee4a30
VZ
279 // need some minimal size even for empty tree
280 if ( !size.x || !size.y )
281 size = wxControl::DoGetBestSize();
b24069f2 282 else
54a4121a
VZ
283 {
284 // Add border size
285 size += GetWindowBorderSize();
286
b24069f2 287 CacheBestSize(size);
54a4121a 288 }
8cee4a30
VZ
289
290 return size;
291}
292
70934138
VZ
293void wxTreeCtrlBase::ExpandAll()
294{
9248adc8
VZ
295 if ( IsEmpty() )
296 return;
297
70934138
VZ
298 ExpandAllChildren(GetRootItem());
299}
300
301void wxTreeCtrlBase::ExpandAllChildren(const wxTreeItemId& item)
302{
624f89c2 303 Freeze();
70934138
VZ
304 // expand this item first, this might result in its children being added on
305 // the fly
e660f922
VZ
306 if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) )
307 Expand(item);
308 //else: expanding hidden root item is unsupported and unnecessary
70934138
VZ
309
310 // then (recursively) expand all the children
311 wxTreeItemIdValue cookie;
312 for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
313 idCurr.IsOk();
314 idCurr = GetNextChild(item, cookie) )
315 {
316 ExpandAllChildren(idCurr);
317 }
624f89c2 318 Thaw();
70934138
VZ
319}
320
9248adc8
VZ
321void wxTreeCtrlBase::CollapseAll()
322{
323 if ( IsEmpty() )
324 return;
325
326 CollapseAllChildren(GetRootItem());
327}
328
329void wxTreeCtrlBase::CollapseAllChildren(const wxTreeItemId& item)
330{
624f89c2 331 Freeze();
9248adc8
VZ
332 // first (recursively) collapse all the children
333 wxTreeItemIdValue cookie;
334 for ( wxTreeItemId idCurr = GetFirstChild(item, cookie);
335 idCurr.IsOk();
336 idCurr = GetNextChild(item, cookie) )
337 {
338 CollapseAllChildren(idCurr);
339 }
340
06f1b704
VZ
341 // then collapse this element too unless it's the hidden root which can't
342 // be collapsed
343 if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) )
344 Collapse(item);
624f89c2 345 Thaw();
9248adc8
VZ
346}
347
348bool wxTreeCtrlBase::IsEmpty() const
349{
350 return !GetRootItem().IsOk();
351}
352
64ac3db8
VZ
353void wxTreeCtrlBase::OnCharHook(wxKeyEvent& event)
354{
355 if ( GetEditControl() )
356 {
357 bool discardChanges = false;
358 switch ( event.GetKeyCode() )
359 {
360 case WXK_ESCAPE:
361 discardChanges = true;
362 // fall through
363
364 case WXK_RETURN:
2e3407de 365 EndEditLabel(GetFocusedItem(), discardChanges);
64ac3db8
VZ
366
367 // Do not call Skip() below.
368 return;
369 }
370 }
371
372 event.Skip();
373}
374
1e6feb95 375#endif // wxUSE_TREECTRL