From: Julian Smart Date: Sun, 8 Feb 2004 13:02:01 +0000 (+0000) Subject: Added wxTreeListCtrl: patch [ 883529 ] wxTreeListCltr X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/c360bf5bebfe57a93a5714ec386ef9175c02c821 Added wxTreeListCtrl: patch [ 883529 ] wxTreeListCltr Otto Wyss git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@25621 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/contrib/build/gizmos/gizmos.bkl b/contrib/build/gizmos/gizmos.bkl index 90752612bd..6ab57b2c54 100644 --- a/contrib/build/gizmos/gizmos.bkl +++ b/contrib/build/gizmos/gizmos.bkl @@ -12,6 +12,7 @@ multicell.cpp splittree.cpp statpict.cpp + @@ -23,6 +24,7 @@ wx/gizmos/splittree.h wx/gizmos/statpict.h wx/gizmos/gizmos.h + diff --git a/contrib/docs/latex/gizmos/classes.tex b/contrib/docs/latex/gizmos/classes.tex index 20edd1e691..0052d13573 100644 --- a/contrib/docs/latex/gizmos/classes.tex +++ b/contrib/docs/latex/gizmos/classes.tex @@ -17,3 +17,5 @@ \input splitterscrolledwindow.tex \input thinsplitterwindow.tex \input treecompanionwindow.tex +% Uncomment this when treelistctrl.text has been debugged +%\input treelistctrl.tex diff --git a/contrib/docs/latex/gizmos/treelistctrl.tex b/contrib/docs/latex/gizmos/treelistctrl.tex new file mode 100644 index 0000000000..0f9d736cbc --- /dev/null +++ b/contrib/docs/latex/gizmos/treelistctrl.tex @@ -0,0 +1,1080 @@ +\section{\class{wxTreeListCtrl}}\label{wxtreelistctrl} + +A tree list control presents information as a hierarchy, with items that may be expanded +to show further items. Items in a tree list control are referenced by wxTreeItemId handles, +which may be tested for validity by calling wxTreeItemId::IsOk. + +To intercept events from a tree list control, use the event table macros described in \helpref{wxTreeEvent}{wxtreeevent}. + +\wxheading{Derived from} + +\helpref{wxControl}{wxcontrol}\\ +wxListCtrl\\ +wxTreeCtrl\\ +\helpref{wxWindow}{wxwindow}\\ +\helpref{wxEvtHandler}{wxevthandler}\\ +\helpref{wxObject}{wxobject} + +\wxheading{Include files} + + + +\wxheading{Window styles} + +\twocolwidtha{5cm} +\begin{twocollist}\itemsep=0pt +\twocolitem{\windowstyle{wxTR\_EDIT\_LABELS}}{Use this style +if you wish the user to be able to edit labels in the tree list control.} +\twocolitem{\windowstyle{wxTR\_NO\_BUTTONS}}{For convenience +to document that no buttons are to be drawn.} +\twocolitem{\windowstyle{wxTR\_HAS\_BUTTONS}}{Use this style +to show + and - buttons to the left of parent items.} +\twocolitem{\windowstyle{wxTR\_TWIST\_BUTTONS}}{Use this style +to show Mac-style twister buttons to the left of parent items. +If both wxTR\_HAS\_BUTTONS and wxTR\_TWIST\_BUTTONS are given, +twister buttons are generated. Generic only.} +\twocolitem{\windowstyle{wxTR\_NO\_LINES}}{Use this style +to hide vertical level connectors.} +\twocolitem{\windowstyle{wxTR\_FULL\_ROW\_HIGHLIGHT}}{Use this style to have the background +colour and the selection highlight extend over the entire horizontal +row of the tree list control window. (This flag is ignored under Windows unless you +specify wxTR\_NO\_LINES as well.) } +\twocolitem{\windowstyle{wxTR\_LINES\_AT\_ROOT}}{Use this style +to show lines between root nodes. +Only applicable if wxTR\_HIDE\_ROOT is set and wxTR\_NO\_LINES is not set.} +\twocolitem{\windowstyle{wxTR\_HIDE\_ROOT}}{Use this style +to suppress the display of the root node, +effectively causing the first-level nodes +to appear as a series of root nodes.} +\twocolitem{\windowstyle{wxTR\_ROW\_LINES}}{Use this style +to draw a contrasting border between displayed rows.} +\twocolitem{\windowstyle{wxTR\_HAS\_VARIABLE\_ROW\_HEIGHT}}{Use this style +to cause row heights to be just big enough to fit the content. +If not set, all rows use the largest row height. +The default is that this flag is unset. +Generic only.} +\twocolitem{\windowstyle{wxTR\_SINGLE}}{For convenience +to document that only one item may be selected at a time. +Selecting another item causes the current selection, if any, +to be deselected. This is the default.} +\twocolitem{\windowstyle{wxTR\_MULTIPLE}}{Use this style +to allow a range of items to be selected. +If a second range is selected, the current range, if any, is deselected.} +\twocolitem{\windowstyle{wxTR\_EXTENDED}}{Use this style +to allow disjoint items to be selected. (Only partially implemented; may not work in all cases.)} +\twocolitem{\windowstyle{wxTR\_DEFAULT\_STYLE}}{The set of flags that are +closest to the defaults for the native control for a particular toolkit.} +\end{twocollist} + +See also \helpref{window styles overview}{windowstyles}. + +\wxheading{Event handling} + +To process input from a tree list control, use these event handler macros to direct input to member +functions that take a \helpref{wxTreeEvent}{wxtreeevent} argument. + +\twocolwidtha{7cm} +\begin{twocollist}\itemsep=0pt +\twocolitem{{\bf EVT\_TREE\_BEGIN\_DRAG(id, func)}}{Begin dragging with the left mouse button.} +\twocolitem{{\bf EVT\_TREE\_BEGIN\_RDRAG(id, func)}}{Begin dragging with the right mouse button.} +\twocolitem{{\bf EVT\_TREE\_BEGIN\_LABEL\_EDIT(id, func)}}{Begin editing a label. This can be prevented by calling \helpref{Veto()}{wxnotifyeventveto}.} +\twocolitem{{\bf EVT\_TREE\_END\_LABEL\_EDIT(id, func)}}{Finish editing a label. This can be prevented by calling \helpref{Veto()}{wxnotifyeventveto}.} +\twocolitem{{\bf EVT\_TREE\_DELETE\_ITEM(id, func)}}{Delete an item.} +\twocolitem{{\bf EVT\_TREE\_GET\_INFO(id, func)}}{Request information from the application.} +\twocolitem{{\bf EVT\_TREE\_SET\_INFO(id, func)}}{Information is being supplied.} +\twocolitem{{\bf EVT\_TREE\_ITEM\_ACTIVATED(id, func)}}{The item has been activated, i.e. chosen by double clicking it with mouse or from keyboard} +\twocolitem{{\bf EVT\_TREE\_ITEM\_COLLAPSED(id, func)}}{The item has been collapsed.} +\twocolitem{{\bf EVT\_TREE\_ITEM\_COLLAPSING(id, func)}}{The item is being collapsed. This can be prevented by calling \helpref{Veto()}{wxnotifyeventveto}.} +\twocolitem{{\bf EVT\_TREE\_ITEM\_EXPANDED(id, func)}}{The item has been expanded.} +\twocolitem{{\bf EVT\_TREE\_ITEM\_EXPANDING(id, func)}}{The item is being expanded. This can be prevented by calling \helpref{Veto()}{wxnotifyeventveto}.} +\twocolitem{{\bf EVT\_TREE\_SEL\_CHANGED(id, func)}}{Selection has changed.} +\twocolitem{{\bf EVT\_TREE\_SEL\_CHANGING(id, func)}}{Selection is changing. This can be prevented by calling \helpref{Veto()}{wxnotifyeventveto}.} +\twocolitem{{\bf EVT\_TREE\_KEY\_DOWN(id, func)}}{A key has been pressed.} +\end{twocollist} + +\wxheading{See also} + +wxTreeItemData, wxListBox, wxListCtrl,\rtfsp +wxImageList, wxTreeEvent + +\wxheading{Win32 notes} + +wxTreeListCtrl class uses the standard common treeview control under Win32 +implemented in the system library {\tt comctl32.dll}. Some versions of this +library are known to have bugs with handling the tree list control colours: the +usual symptom is that the expanded items leave black (or otherwise incorrectly +coloured) background behind them, especially for the controls using non +default background colour. The recommended solution is to upgrade the {\tt comctl32.dll} +to a newer version: see +\urlref{http://www.microsoft.com/msdownload/ieplatform/ie/comctrlx86.asp}{http://www.microsoft.com/msdownload/ieplatform/ie/comctrlx86.asp}. + +\latexignore{\rtfignore{\wxheading{Members (tree specific}}} + +\membersection{wxTreeListCtrl::wxTreeListCtrl}\label{wxtreelistctrlconstr} + +\func{}{wxTreeListCtrl}{\void} + +Default constructor. + +\func{}{wxTreeListCtrl}{\param{wxWindow*}{ parent}, \param{wxWindowID}{ id = -1},\rtfsp +\param{const wxPoint\&}{ pos = wxDefaultPosition}, \param{const wxSize\&}{ size = wxDefaultSize},\rtfsp +\param{long}{ style = wxTR\_DEFAULT\_STYLE}, \param{const wxValidator\& }{validator = wxDefaultValidator}, \param{const wxString\& }{name = ``treelistctrl"}} + +Constructor, creating and showing a tree list control. + +\wxheading{Parameters} + +\docparam{parent}{Parent window. Must not be NULL.} + +\docparam{id}{Window identifier. A value of -1 indicates a default value.} + +\docparam{pos}{Window position.} + +\docparam{size}{Window size. If the default size (-1, -1) is specified then the window is sized +appropriately.} + +\docparam{style}{Window style. See \helpref{wxTreeListCtrl}{wxtreelistctrl}.} + +\docparam{validator}{Window validator.} + +\docparam{name}{Window name.} + +\wxheading{See also} + +\helpref{wxTreeListCtrl::Create}{wxtreelistctrlcreate}, \helpref{wxValidator}{wxvalidator} + +\membersection{wxTreeListCtrl::\destruct{wxTreeListCtrl}} + +\func{void}{\destruct{wxTreeListCtrl}}{\void} + +Destructor, destroying the list control. + +\membersection{wxTreeListCtrl::AddRoot}\label{wxtreelistctrladdroot} + +\func{wxTreeItemId}{AddRoot}{\param{const wxString\&}{ text}, + \param{int}{ image = -1}, \param{int}{ selImage = -1}, \param{wxTreeItemData*}{ data = NULL}} + +Adds the root node to the tree, returning the new item. + +The {\it image} and {\it selImage} parameters are an index within +the normal image list specifying the image to use for unselected and +selected items, respectively. +If {\it image} > -1 and {\it selImage} is -1, the same image is used for +both selected and unselected items. + +\membersection{wxTreeListCtrl::AppendItem}\label{wxtreelistctrlappenditem} + +\func{wxTreeItemId}{AppendItem}{\param{const wxTreeItemId\& }{parent}, \param{const wxString\&}{ text}, + \param{int}{ image = -1}, \param{int}{ selImage = -1}, \param{wxTreeItemData*}{ data = NULL}} + +Appends an item to the end of the branch identified by {\it parent}, return a new item id. + +The {\it image} and {\it selImage} parameters are an index within +the normal image list specifying the image to use for unselected and +selected items, respectively. +If {\it image} > -1 and {\it selImage} is -1, the same image is used for +both selected and unselected items. + +\membersection{wxTreeListCtrl::AssignButtonsImageList}\label{wxtreelistctrlassignbuttonsimagelist} + +\func{void}{AssignButtonsImageList}{\param{wxImageList*}{ imageList}} + +Sets the buttons image list. The button images assigned with this method will +be automatically deleted by wxTreeListCtrl as appropriate +(i.e. it takes ownership of the list). + +Setting or assigning the button image list enables the display of image buttons. +Once enabled, the only way to disable the display of button images is to set +the button image list to NULL. + +This function is only available in the generic version. + +See also \helpref{SetButtonsImageList}{wxtreelistctrlsetbuttonsimagelist}. + +\membersection{wxTreeListCtrl::AssignImageList}\label{wxtreelistctrlassignimagelist} + +\func{void}{AssignImageList}{\param{wxImageList*}{ imageList}} + +Sets the normal image list. Image list assigned with this method will +be automatically deleted by wxTreeListCtrl as appropriate +(i.e. it takes ownership of the list). + +See also \helpref{SetImageList}{wxtreelistctrlsetimagelist}. + +\membersection{wxTreeListCtrl::AssignStateImageList}\label{wxtreelistctrlassignstateimagelist} + +\func{void}{AssignStateImageList}{\param{wxImageList*}{ imageList}} + +Sets the state image list. Image list assigned with this method will +be automatically deleted by wxTreeListCtrl as appropriate +(i.e. it takes ownership of the list). + +See also \helpref{SetStateImageList}{wxtreelistctrlsetstateimagelist}. + + +\membersection{wxTreeListCtrl::Collapse}\label{wxtreelistctrlcollapse} + +\func{void}{Collapse}{\param{const wxTreeItemId\&}{ item}} + +Collapses the given item. + +\membersection{wxTreeListCtrl::CollapseAndReset}\label{wxtreelistctrlcollapseandreset} + +\func{void}{CollapseAndReset}{\param{const wxTreeItemId\&}{ item}} + +Collapses the given item and removes all children. + +\membersection{wxTreeListCtrl::Create}\label{wxtreelistctrlcreate} + +\func{bool}{wxTreeListCtrl}{\param{wxWindow*}{ parent}, \param{wxWindowID}{ id = -1},\rtfsp +\param{const wxPoint\&}{ pos = wxDefaultPosition}, \param{const wxSize\&}{ size = wxDefaultSize},\rtfsp +\param{long}{ style = wxTR\_DEFAULT\_STYLE}, \param{const wxValidator\& }{validator = wxDefaultValidator}, \param{const wxString\& }{name = ``listCtrl"}} + +Creates the tree list control. See \helpref{wxTreeListCtrl::wxTreeListCtrl}{wxtreelistctrlconstr} for further details. + +\membersection{wxTreeListCtrl::Delete}\label{wxtreelistctrldelete} + +\func{void}{Delete}{\param{const wxTreeItemId\&}{ item}} + +Deletes the specified item. A {\tt EVT\_TREE\_DELETE\_ITEM} event will be +generated. + +This function may cause a subsequent call to GetNextChild to fail. + +\membersection{wxTreeListCtrl::DeleteAllItems}\label{wxtreelistctrldeleteallitems} + +\func{void}{DeleteAllItems}{\void} + +Deletes all the items in the control. Note that this will {\bf not} generate +any events unlike \helpref{Delete}{wxtreelistctrldelete} method. + +\membersection{wxTreeListCtrl::DeleteChildren}\label{wxtreelistctrldeletechildren} + +\func{void}{DeleteChildren}{\param{const wxTreeItemId\& }{item}} + +Deletes all children of the given item (but not the item itself). Note that +this will {\bf not} generate any events unlike +\helpref{Delete}{wxtreelistctrldelete} method. + +If you have called \helpref{wxTreeListCtrl::SetItemHasChildren}{wxtreelistctrlsetitemhaschildren}, you +may need to call it again since {\it DeleteChildren} does not automatically +clear the setting. + +\membersection{wxTreeListCtrl::Edit}\label{wxtreelistctrledit} + +\func{void}{Edit}{\param{const wxTreeItemId\&}{ item}} + +The same as \helpref{EditLabel}{wxtreelistctrleditlabel}. + +\membersection{wxTreeListCtrl::EditLabel}\label{wxtreelistctrleditlabel} + +\func{void}{EditLabel}{\param{const wxTreeItemId\&}{ item}} + +Starts editing the label of the given item. This function generates a +EVT\_TREE\_BEGIN\_LABEL\_EDIT event which can be vetoed so that no +text control will appear for in-place editing. + +If the user changed the label, i.e. s/he does not press ESC or leave +the text control without changes, a EVT\_TREE\_END\_LABEL\_EDIT event +will be sent which can be vetoed as well. + +\wxheading{See also} + +\helpref{wxTreeEvent}{wxtreeevent} + +\membersection{wxTreeListCtrl::EnsureVisible}\label{wxtreelistctrlensurevisible} + +\func{void}{EnsureVisible}{\param{const wxTreeItemId\&}{ item}} + +Scrolls and/or expands items to ensure that the given item is visible. + +\membersection{wxTreeListCtrl::Expand}\label{wxtreelistctrlexpand} + +\func{void}{Expand}{\param{const wxTreeItemId\&}{ item}} + +Expands the given item. + +\membersection{wxTreeListCtrl::ExpandAll}\label{wxtreelistctrlexpandall} + +\func{void}{ExpandAll}{\param{const wxTreeItemId\&}{ item}} + +Expands the given item and all subitems recursively. + +\membersection{wxTreeListCtrl::GetBoundingRect}\label{wxtreelistctrlgetitemrect} + +\constfunc{bool}{GetBoundingRect}{\param{const wxTreeItemId\&}{ item}, \param{wxRect\& }{rect}, \param{bool }{textOnly = FALSE}} + +Retrieves the rectangle bounding the {\it item}. If {\it textOnly} is TRUE, +only the rectangle around the item's label will be returned, otherwise the +item's image is also taken into account. + +The return value is TRUE if the rectangle was successfully retrieved or FALSE +if it was not (in this case {\it rect} is not changed) - for example, if the +item is currently invisible. + +\pythonnote{The wxPython version of this method requires only the +{\tt item} and {\tt textOnly} parameters. The return value is either a +{\tt wxRect} object or {\tt None}.} + +\perlnote{In wxPerl this method only takes the parameters {\tt item} and + {\tt textOnly}, and returns a Wx::Rect ( or undef ).} + +\membersection{wxTreeListCtrl::GetButtonsImageList}\label{wxtreelistctrlgetbuttonsimagelist} + +\constfunc{wxImageList*}{GetButtonsImageList}{\void} + +Returns the buttons image list (from which application-defined button images are taken). + +This function is only available in the generic version. + +\membersection{wxTreeListCtrl::GetChildrenCount}\label{wxtreelistctrlgetchildrencount} + +\constfunc{size\_t}{GetChildrenCount}{\param{const wxTreeItemId\&}{ item}, \param{bool}{ recursively = TRUE}} + +Returns the number of items in the branch. If {\it recursively} is TRUE, returns the total number +of descendants, otherwise only one level of children is counted. + +\membersection{wxTreeListCtrl::GetCount}\label{wxtreelistctrlgetcount} + +\constfunc{int}{GetCount}{\void} + +Returns the number of items in the control. + +\membersection{wxTreeListCtrl::GetFirstChild}\label{wxtreelistctrlgetfirstchild} + +\constfunc{wxTreeItemId}{GetFirstChild}{\param{const wxTreeItemId\&}{ item}, \param{long\& }{cookie}} + +Returns the first child; call \helpref{wxTreeListCtrl::GetNextChild}{wxtreelistctrlgetnextchild} for the next child. + +For this enumeration function you must pass in a `cookie' parameter +which is opaque for the application but is necessary for the library +to make these functions reentrant (i.e. allow more than one +enumeration on one and the same object simultaneously). The cookie passed to +GetFirstChild and GetNextChild should be the same variable. + +Returns an invalid tree item if there are no further children. + +\wxheading{See also} + +\membersection{wxTreeListCtrl::GetHeaderWindow}\label{wxtreelistctrlgetheaderwindow} + +\constfunc{wxTreeListHeaderWindow*}{GetHeaderWindow}{\void} + +Returns the pointer to the header window. + +\membersection{wxTreeListCtrl::GetMainWindow}\label{wxtreelistctrlgetmainwindow} + +\constfunc{wxTreeListMainWindow*}{GetMainWindow}{\void} + +Returns the pointer to the main window. + +\helpref{wxTreeListCtrl::GetNextChild}{wxtreelistctrlgetnextchild}, +\helpref{wxTreeListCtrl::GetNextSibling}{wxtreelistctrlgetnextsibling} + +\pythonnote{In wxPython the returned wxTreeItemId and the new cookie +value are both returned as a tuple containing the two values.} + +\perlnote{In wxPerl this method only takes the {\tt item} parameter, and + returns a 2-element list {\tt ( item, cookie )}.} + +\membersection{wxTreeListCtrl::GetFirstVisibleItem}\label{wxtreelistctrlgetfirstvisibleitem} + +\constfunc{wxTreeItemId}{GetFirstVisibleItem}{\void} + +Returns the first visible item. + +\membersection{wxTreeListCtrl::GetImageList}\label{wxtreelistctrlgetimagelist} + +\constfunc{wxImageList*}{GetImageList}{\void} + +Returns the normal image list. + +\membersection{wxTreeListCtrl::GetIndent}\label{wxtreelistctrlgetindent} + +\constfunc{int}{GetIndent}{\void} + +Returns the current tree list control indentation. + +\membersection{wxTreeListCtrl::GetItemBackgroundColour}\label{wxtreelistctrlgetitembackgroundcolour} + +\constfunc{wxColour}{GetItemBackgroundColour}{\param{const wxTreeItemId\&}{ item}} + +Returns the background colour of the item. + +\membersection{wxTreeListCtrl::GetItemData}\label{wxtreelistctrlgetitemdata} + +\constfunc{wxTreeItemData*}{GetItemData}{\param{const wxTreeItemId\&}{ item}} + +Returns the tree item data associated with the item. + +\wxheading{See also} + +\helpref{wxTreeItemData}{wxtreeitemdata} + +\pythonnote{wxPython provides the following shortcut method: + +\indented{2cm}{\begin{twocollist}\itemsep=0pt +\twocolitem{{\bf GetPyData(item)}}{Returns the Python Object +associated with the wxTreeItemData for the given item Id.} +\end{twocollist}} +} + +\perlnote{wxPerl provides the following shortcut method: +\indented{2cm}{ +\begin{twocollist}\itemsep=0pt +\twocolitem{{\bf GetPlData( item )}}{Returns the Perl data +associated with the Wx::TreeItemData ( it is just the same as +tree->GetItemData( item )->GetData(); ).} +\end{twocollist}} +} + +\membersection{wxTreeListCtrl::GetItemFont}\label{wxtreelistctrlgetitemfont} + +\constfunc{wxFont}{GetItemFont}{\param{const wxTreeItemId\&}{ item}} + +Returns the font of the item label. + +\membersection{wxTreeListCtrl::GetItemImage}\label{wxtreelistctrlgetitemimage} + +\constfunc{int}{GetItemImage}{\param{const wxTreeItemId\&}{ item}, + \param{wxTreeItemIcon}{ which = wxTreeItemIcon_Normal}} + +Gets the specified item image of the main column. + +\constfunc{int}{GetItemImage}{\param{const wxTreeItemId\&}{ item}, \param{size_t}{ column}, + \param{wxTreeItemIcon}{ which = wxTreeItemIcon_Normal}} + +Gets the specified item image of the entered column. + +The value of {\it which} may be: + +\begin{itemize}\itemsep=0pt +\item{wxTreeItemIcon\_Normal} to get the normal item image +\item{wxTreeItemIcon\_Selected} to get the selected item image (i.e. the image +which is shown when the item is currently selected) +\item{wxTreeItemIcon\_Expanded} to get the expanded image (this only +makes sense for items which have children - then this image is shown when the +item is expanded and the normal image is shown when it is collapsed) +\item{wxTreeItemIcon\_SelectedExpanded} to get the selected expanded image +(which is shown when an expanded item is currently selected) +\end{itemize} + +\membersection{wxTreeListCtrl::GetItemText}\label{wxtreelistctrlgetitemtext} + +\constfunc{wxString}{GetItemText}{\param{const wxTreeItemId\&}{ item}} + +Returns the item text of the main column. + +\constfunc{wxString}{GetItemText}{\param{const wxTreeItemId\&}{ item}, \param{size_t}{ column}} + +Returns the item text of the entered column. + +\membersection{wxTreeListCtrl::GetItemTextColour}\label{wxtreelistctrlgetitemtextcolour} + +\constfunc{wxColour}{GetItemTextColour}{\param{const wxTreeItemId\&}{ item}} + +Returns the colour of the item label. + +\membersection{wxTreeListCtrl::GetLastChild}\label{wxtreelistctrlgetlastchild} + +\constfunc{wxTreeItemId}{GetLastChild}{\param{const wxTreeItemId\&}{ item}} + +Returns the last child of the item (or an invalid tree item if this item has no children). + +\wxheading{See also} + +\helpref{GetFirstChild}{wxtreelistctrlgetfirstchild}, +\helpref{wxTreeListCtrl::GetNextSibling}{wxtreelistctrlgetnextsibling}, +\helpref{GetLastChild}{wxtreelistctrlgetlastchild} + +\membersection{wxTreeListCtrl::GetLineSpacing}\label{wxtreelistctrlgetlinespacing} + +\constfunc{int}{GetLineSpacing}{\void} + +Returns the space above and below the text on each line. + +\membersection{wxTreeListCtrl::GetNextChild}\label{wxtreelistctrlgetnextchild} + +\constfunc{wxTreeItemId}{GetNextChild}{\param{const wxTreeItemId\&}{ item}, \param{long\& }{cookie}} + +Returns the next child; call \helpref{wxTreeListCtrl::GetFirstChild}{wxtreelistctrlgetfirstchild} for the first child. + +For this enumeration function you must pass in a `cookie' parameter +which is opaque for the application but is necessary for the library +to make these functions reentrant (i.e. allow more than one +enumeration on one and the same object simultaneously). The cookie passed to +GetFirstChild and GetNextChild should be the same. + +Returns an invalid tree item if there are no further children. + +\wxheading{See also} + +\helpref{wxTreeListCtrl::GetFirstChild}{wxtreelistctrlgetfirstchild} + +\pythonnote{In wxPython the returned wxTreeItemId and the new cookie +value are both returned as a tuple containing the two values.} + +\perlnote{In wxPerl this method returns a 2-element list + {\tt ( item, cookie )}, instead of modifying its parameters.} + +\membersection{wxTreeListCtrl::GetNextSibling}\label{wxtreelistctrlgetnextsibling} + +\constfunc{wxTreeItemId}{GetNextSibling}{\param{const wxTreeItemId\&}{ item}} + +Returns the next sibling of the specified item; call \helpref{wxTreeListCtrl::GetPrevSibling}{wxtreelistctrlgetprevsibling} for the previous sibling. + +Returns an invalid tree item if there are no further siblings. + +\wxheading{See also} + +\helpref{wxTreeListCtrl::GetPrevSibling}{wxtreelistctrlgetprevsibling} + +\membersection{wxTreeListCtrl::GetNextVisible}\label{wxtreelistctrlgetnextvisible} + +\constfunc{wxTreeItemId}{GetNextVisible}{\param{const wxTreeItemId\&}{ item}} + +Returns the next visible item. + +\membersection{wxTreeListCtrl::GetItemParent}\label{wxtreelistctrlgetitemparent} + +\constfunc{wxTreeItemId}{GetItemParent}{\param{const wxTreeItemId\&}{ item}} + +Returns the item's parent. + +\membersection{wxTreeListCtrl::GetPrevSibling}\label{wxtreelistctrlgetprevsibling} + +\constfunc{wxTreeItemId}{GetPrevSibling}{\param{const wxTreeItemId\&}{ item}} + +Returns the previous sibling of the specified item; call \helpref{wxTreeListCtrl::GetNextSibling}{wxtreelistctrlgetnextsibling} for the next sibling. + +Returns an invalid tree item if there are no further children. + +\wxheading{See also} + +\helpref{wxTreeListCtrl::GetNextSibling}{wxtreelistctrlgetnextsibling} + +\membersection{wxTreeListCtrl::GetPrevVisible}\label{wxtreelistctrlgetprevvisible} + +\constfunc{wxTreeItemId}{GetPrevVisible}{\param{const wxTreeItemId\&}{ item}} + +Returns the previous visible item. + +\membersection{wxTreeListCtrl::GetRootItem}\label{wxtreelistctrlgetrootitem} + +\constfunc{wxTreeItemId}{GetRootItem}{\void} + +Returns the root item for the tree list control. + +\membersection{wxTreeListCtrl::GetSelection}\label{wxtreelistctrlgetselection} + +\constfunc{wxTreeItemId}{GetSelection}{\void} + +Returns the selection, or an invalid item if there is no selection. +This function only works with the controls without wxTR\_MULTIPLE style, use +\helpref{GetSelections}{wxtreelistctrlgetselections} for the controls which do have +this style. + +\membersection{wxTreeListCtrl::GetSelections}\label{wxtreelistctrlgetselections} + +\constfunc{size\_t}{GetSelections}{\param{wxArrayTreeItemIds\& }{selection}} + +Fills the array of tree items passed in with the currently selected items. This +function can be called only if the control has the wxTR\_MULTIPLE style. + +Returns the number of selected items. + +\pythonnote{The wxPython version of this method accepts no parameters +and returns a Python list of {\tt wxTreeItemId}s.} + +\perlnote{In wxPerl this method takes no parameters and returns a list of + {\tt Wx::TreeItemId}s.} + +\membersection{wxTreeListCtrl::GetStateImageList}\label{wxtreelistctrlgetstateimagelist} + +\constfunc{wxImageList*}{GetStateImageList}{\void} + +Returns the state image list (from which application-defined state images are taken). + +\membersection{wxTreeListCtrl::GetWindowStyle}\label{wxtreelistctrlgetwindowstyle} + +\constfunc{long}{GetWindowStyle}{\void} + +??? + +\membersection{wxTreeListCtrl::GetWindowStyleFlag}\label{wxtreelistctrlgetwindowstyleflag} + +\constfunc{long}{GetWindowStyleFlag}{\void} + +??? + +\membersection{wxTreeListCtrl::HitTest}\label{wxtreelistctrlhittest} + +\func{wxTreeItemId}{HitTest}{\param{const wxPoint\& }{point}} + +\func{wxTreeItemId}{HitTest}{\param{const wxPoint\& }{point}, \param{int\& }{flags}} + +\func{wxTreeItemId}{HitTest}{\param{const wxPoint\& }{point}, \param{int\& }{flags}, + \param{int\& }{column}} + +Calculates which (if any) item is under the given point, returning the tree item +id at this point plus extra information {\it flags}. {\it flags} is a bitlist of the following: + +\twocolwidtha{5cm} +\begin{twocollist}\itemsep=0pt +\twocolitem{wxTREE\_HITTEST\_ABOVE}{Above the client area.} +\twocolitem{wxTREE\_HITTEST\_BELOW}{Below the client area.} +\twocolitem{wxTREE\_HITTEST\_NOWHERE}{In the client area but below the last item.} +\twocolitem{wxTREE\_HITTEST\_ONITEMBUTTON}{On the button associated with an item.} +\twocolitem{wxTREE\_HITTEST\_ONITEMICON}{On the bitmap associated with an item.} +\twocolitem{wxTREE\_HITTEST\_ONITEMINDENT}{In the indentation associated with an item.} +\twocolitem{wxTREE\_HITTEST\_ONITEMLABEL}{On the label (string) associated with an item.} +\twocolitem{wxTREE\_HITTEST\_ONITEMRIGHT}{In the area to the right of an item.} +\twocolitem{wxTREE\_HITTEST\_ONITEMSTATEICON}{On the state icon for a tree view item that is in a user-defined state.} +\twocolitem{wxTREE\_HITTEST\_TOLEFT}{To the right of the client area.} +\twocolitem{wxTREE\_HITTEST\_TORIGHT}{To the left of the client area.} +\end{twocollist} + +\pythonnote{in wxPython both the wxTreeItemId and the flags are +returned as a tuple.} + +\perlnote{In wxPerl this method only takes the {\tt point} parameter + and returns a 2-element list {\tt ( item, flags )}.} + +\membersection{wxTreeListCtrl::InsertItem}\label{wxtreelistctrlinsertitem} + +\func{wxTreeItemId}{InsertItem}{\param{const wxTreeItemId\& }{parent}, \param{const wxTreeItemId\& }{previous}, \param{const wxString\&}{ text}, + \param{int}{ image = -1}, \param{int}{ selImage = -1}, \param{wxTreeItemData*}{ data = NULL}} + +\func{wxTreeItemId}{InsertItem}{\param{const wxTreeItemId\& }{parent}, \param{size\_t}{ before}, \param{const wxString\&}{ text}, + \param{int}{ image = -1}, \param{int}{ selImage = -1}, \param{wxTreeItemData*}{ data = NULL}} + +Inserts an item after a given one ({\it previous}) or before one identified by its position ({\it before}). +{\it before} must be less than the number of children. + +The {\it image} and {\it selImage} parameters are an index within +the normal image list specifying the image to use for unselected and +selected items, respectively. +If {\it image} > -1 and {\it selImage} is -1, the same image is used for +both selected and unselected items. + +\pythonnote{The second form of this method is called +{\tt InsertItemBefore} in wxPython.} + +\membersection{wxTreeListCtrl::IsBold}\label{wxtreelistctrlisbold} + +\constfunc{bool}{IsBold}{\param{const wxTreeItemId\& }{item}} + +Returns TRUE if the given item is in bold state. + +See also: \helpref{SetItemBold}{wxtreelistctrlsetitembold} + +\membersection{wxTreeListCtrl::IsExpanded}\label{wxtreelistctrlisexpanded} + +\constfunc{bool}{IsExpanded}{\param{const wxTreeItemId\&}{ item}} + +Returns TRUE if the item is expanded (only makes sense if it has children). + +\membersection{wxTreeListCtrl::IsSelected}\label{wxtreelistctrlisselected} + +\constfunc{bool}{IsSelected}{\param{const wxTreeItemId\&}{ item}} + +Returns TRUE if the item is selected. + +\membersection{wxTreeListCtrl::IsVisible}\label{wxtreelistctrlisvisible} + +\constfunc{bool}{IsVisible}{\param{const wxTreeItemId\&}{ item}} + +Returns TRUE if the item is visible (it might be outside the view, or not expanded). + +\membersection{wxTreeListCtrl::HasChildren}\label{wxtreelistctrlhaschildren} + +\constfunc{bool}{HasChildren}{\param{const wxTreeItemId\&}{ item}} + +Returns TRUE if the item has children.??? + +\membersection{wxTreeListCtrl::ItemHasChildren}\label{wxtreelistctrlitemhaschildren} + +\constfunc{bool}{ItemHasChildren}{\param{const wxTreeItemId\&}{ item}} + +Returns TRUE if the item has children. + +\membersection{wxTreeListCtrl::OnCompareItems}\label{wxtreelistctrloncompareitems} + +\func{int}{OnCompareItems}{\param{const wxTreeItemId\& }{item1}, \param{const wxTreeItemId\& }{item2}} + +Override this function in the derived class to change the sort order of the +items in the tree list control. The function should return a negative, zero or +positive value if the first item is less than, equal to or greater than the +second one. + +The base class version compares items alphabetically. + +See also: \helpref{SortChildren}{wxtreelistctrlsortchildren} + +\membersection{wxTreeListCtrl::PrependItem}\label{wxtreelistctrlprependitem} + +\func{wxTreeItemId}{PrependItem}{\param{const wxTreeItemId\& }{parent}, \param{const wxString\&}{ text}, + \param{int}{ image = -1}, \param{int}{ selImage = -1}, \param{wxTreeItemData*}{ data = NULL}} + +Appends an item as the first child of {\it parent}, return a new item id. + +The {\it image} and {\it selImage} parameters are an index within +the normal image list specifying the image to use for unselected and +selected items, respectively. +If {\it image} > -1 and {\it selImage} is -1, the same image is used for +both selected and unselected items. + +\membersection{wxTreeListCtrl::Refresh}\label{wxtreelistctrlrefresh} + +\func{bool}{Refresh}{\param{bool}{ erase=TRUE}, \param{wxRect*}{ rect=NULL}} + +Description??? + +Parameter??? + +\membersection{wxTreeListCtrl::SetBackgroundColour}\label{wxtreelistctrlsetbackgroundcolour} + +\func{void}{SetBackgroundColour}{\param{const wxColour\&}{ colour}} + +??? + +\membersection{wxTreeListCtrl::SetFocus}\label{wxtreelistctrlsetfocus} + +\func{void}{SetFocus}{\void} + +??? + +\membersection{wxTreeListCtrl::SetFont}\label{wxtreelistctrlsetfont} + +\func{void}{SetFont}{\param{const wxFont\&}{ font}} + +??? + +\membersection{wxTreeListCtrl::SetForegroundColour}\label{wxtreelistctrlsetforegroundcolour} + +\func{void}{SetForegroundColour}{\param{const wxColour\&}{ colour}} + +??? + +\membersection{wxTreeListCtrl::SetWindowStyle}\label{wxtreelistctrlsetwindowstyle} + +\func{void}{SetWindowStyle}{\param{const long}{ styles}} + +??? + +\membersection{wxTreeListCtrl::ScrollTo}\label{wxtreelistctrlscrollto} + +\func{void}{ScrollTo}{\param{const wxTreeItemId\&}{ item}} + +Scrolls the specified item into view. + +\membersection{wxTreeListCtrl::SelectItem}\label{wxtreelistctrlselectitem} + +\func{bool}{SelectItem}{\param{const wxTreeItemId\&}{ item}, \param{bool}{ unselect_others=TRUE}, + \param{bool}{ extended_select=FALSE}} + +Selects the given item. + +Parameter??? + +\membersection{wxTreeListCtrl::SetButtonsImageList}\label{wxtreelistctrlsetbuttonsimagelist} + +\func{void}{SetButtonsImageList}{\param{wxImageList*}{ imageList}} + +Sets the buttons image list (from which application-defined button images are taken). +The button images assigned with this method will +{\bf not} be deleted by wxTreeListCtrl's destructor, you must delete it yourself. + +Setting or assigning the button image list enables the display of image buttons. +Once enabled, the only way to disable the display of button images is to set +the button image list to NULL. + +This function is only available in the generic version. + +See also \helpref{AssignButtonsImageList}{wxtreelistctrlassignbuttonsimagelist}. + +\membersection{wxTreeListCtrl::SetImageList}\label{wxtreelistctrlsetimagelist} + +\func{void}{SetImageList}{\param{wxImageList*}{ imageList}} + +Sets the normal image list. Image list assigned with this method will +{\bf not} be deleted by wxTreeListCtrl's destructor, you must delete it yourself. + +See also \helpref{AssignImageList}{wxtreelistctrlassignimagelist}. + +\membersection{wxTreeListCtrl::SetIndent}\label{wxtreelistctrlsetindent} + +\func{void}{SetIndent}{\param{int}{ indent}} + +Sets the indentation for the tree list control. + +\membersection{wxTreeListCtrl::SetItemBackgroundColour}\label{wxtreelistctrlsetitembackgroundcolour} + +\func{void}{SetItemBackgroundColour}{\param{const wxTreeItemId\&}{ item}, \param{const wxColour\& }{colour}} + +Sets the colour of the item's background. + +\membersection{wxTreeListCtrl::SetItemBold}\label{wxtreelistctrlsetitembold} + +\func{void}{SetItemBold}{\param{const wxTreeItemId\& }{item}, \param{bool}{ bold = TRUE}} + +Makes item appear in bold font if {\it bold} parameter is TRUE or resets it to +the normal state. + +See also: \helpref{IsBold}{wxtreelistctrlisbold} + +\membersection{wxTreeListCtrl::SetItemData}\label{wxtreelistctrlsetitemdata} + +\func{void}{SetItemData}{\param{const wxTreeItemId\&}{ item}, \param{wxTreeItemData* }{data}} + +Sets the item client data. + +\pythonnote{wxPython provides the following shortcut method:\par +\indented{2cm}{\begin{twocollist}\itemsep=0pt +\twocolitem{{\bf SetPyData(item, obj)}}{Associate the given Python +Object with the wxTreeItemData for the given item Id.} +\end{twocollist}} +} + +\perlnote{wxPerl provides the following shortcut method: +\indented{2cm}{ +\begin{twocollist}\itemsep=0pt +\twocolitem{{\bf SetPlData( item, data )}}{Sets the Perl data +associated with the Wx::TreeItemData ( it is just the same as +tree->GetItemData( item )->SetData( data ); ).} +\end{twocollist}} +} + +\membersection{wxTreeListCtrl::SetItemFont}\label{wxtreelistctrlsetitemfont} + +\func{void}{SetItemFont}{\param{const wxTreeItemId\&}{ item}, \param{const wxFont\& }{font}} + +Sets the item's font. All items in the tree should have the same height to avoid +text clipping, so the fonts height should be the same for all of them, +although font attributes may vary. + +\wxheading{See also} + +\helpref{SetItemBold}{wxtreelistctrlsetitembold} + +\membersection{wxTreeListCtrl::SetItemHasChildren}\label{wxtreelistctrlsetitemhaschildren} + +\func{void}{SetItemHasChildren}{\param{const wxTreeItemId\&}{ item}, \param{bool}{ has = TRUE}} + +Force appearance of the button next to the item. This is useful to +allow the user to expand the items which don't have any children now, +but instead adding them only when needed, thus minimizing memory +usage and loading time. + +\membersection{wxTreeListCtrl::SetItemImage}\label{wxtreelistctrlsetitemimage} + +\func{void}{SetItemImage}{\param{const wxTreeItemId\&}{ item}, \param{int}{ image}, + \param{wxTreeItemIcon}{ which = wxTreeItemIcon_Normal}} + +Sets the specified item image of the main column. See \helpref{GetItemImage}{wxtreelistctrlgetitemimage} +for the description of the {\it which} parameter. + +\func{void}{SetItemImage}{\param{const wxTreeItemId\&}{ item}, \param{size_t}{ column}, \param{int}{ image}, + \param{wxTreeItemIcon}{ which = wxTreeItemIcon_Normal}} + +Sets the specified item image of the entered column. See \helpref{GetItemImage}{wxtreelistctrlgetitemimage} +for the description of the {\it which} parameter. + +\membersection{wxTreeListCtrl::SetItemText}\label{wxtreelistctrlsetitemtext} + +\func{void}{SetItemText}{\param{const wxTreeItemId\&}{ item}, \param{const wxString\&}{ text}} + +Sets the item text of the main column. + +\func{void}{SetItemText}{\param{const wxTreeItemId\&}{ item}, \param{size_t}{ column}, \param{const wxString\&}{ text}} + +Sets the item text of the entered column. + +\membersection{wxTreeListCtrl::SetItemTextColour}\label{wxtreelistctrlsetitemtextcolour} + +\func{void}{SetItemTextColour}{\param{const wxTreeItemId\&}{ item}, \param{const wxColour\&}{ colour}} + +Sets the colour of the item's text. + +\membersection{wxTreeListCtrl::SetLineSpacing}\label{wxtreelistctrlsetindent} + +\func{void}{SetLineSpacing}{\param{unsigned int}{ spacing}} + +Sets the space above and below the text on each line. + +\membersection{wxTreeListCtrl::SetStateImageList}\label{wxtreelistctrlsetstateimagelist} + +\func{void}{SetStateImageList}{\param{wxImageList*}{ imageList}} + +Sets the state image list (from which application-defined state images are taken). +Image list assigned with this method will +{\bf not} be deleted by wxTreeListCtrl's destructor, you must delete it yourself. + +See also \helpref{AssignStateImageList}{wxtreelistctrlassignstateimagelist}. + +\func{void}{SetWindowStyle}{\param{long}{styles}} + +Sets the mode flags associated with the display of the tree list control. +The new mode takes effect immediately. +(Generic only; MSW ignores changes.) + +\membersection{wxTreeListCtrl::SortChildren}\label{wxtreelistctrlsortchildren} + +\func{void}{SortChildren}{\param{const wxTreeItemId\&}{ item}} + +Sorts the children of the given item using +\helpref{OnCompareItems}{wxtreelistctrloncompareitems} method of wxTreeListCtrl. You +should override that method to change the sort order (the default is ascending +case-sensitive alphabetical order). + +\wxheading{See also} + +wxTreeItemData, \helpref{OnCompareItems}{wxtreelistctrloncompareitems} + +\membersection{wxTreeListCtrl::Toggle}\label{wxtreelistctrltoggle} + +\func{void}{Toggle}{\param{const wxTreeItemId\&}{ item}} + +Toggles the given item between collapsed and expanded states. + +\membersection{wxTreeListCtrl::Unselect}\label{wxtreelistctrlunselect} + +\func{void}{Unselect}{\void} + +Removes the selection from the currently selected item (if any). + +\membersection{wxTreeListCtrl::UnselectAll}\label{wxtreelistctrlunselectall} + +\func{void}{UnselectAll}{\void} + +This function either behaves the same as \helpref{Unselect}{wxtreelistctrlunselect} +if the control doesn't have wxTR\_MULTIPLE style, or removes the selection from +all items if it does have this style. + +\latexignore{\rtfignore{\wxheading{Members (column specific}}} + +\membersection{wxTreeListCtrl::AddColumn}\label{wxtreelistctrladdcolumn} + +\func{void}{AddColumn}{\param{const wxString\&}{ text}} + +\func{void}{AddColumn}{\param{const wxString\&}{ text}, \param{size_t}{ width}, \param{wxTreeListColumnAlign}{ alignment = wxTL_ALIGN_LEFT}} + +\func{void}{AddColumn}{\param{const wxTreeListColumnInfo\&}{ col}} + +Adds a column. + +\membersection{wxTreeListCtrl::GetColumn}\label{wxtreelistctrlgetcolumn} + +\func{wxTreeListColumnInfo\&}{GetColumn}{\param{size_t}{ column}} + +\constfunc{wxTreeListColumnInfo\&}{GetColumn}{\param{size_t}{ column}} + +Returns the infos of the columns. + +\membersection{wxTreeListCtrl::GetColumnAlignment}\label{wxtreelistctrlgetcolumnalignment} + +\constfunc{wxTreeListColumnAlign}{GetColumnAlignment}{\param{size_t}{ column}} + +Returns the alignment of the columns. + +\membersection{wxTreeListCtrl::GetColumnCount}\label{wxtreelistctrlgetcolumncount} + +\constfunc{size_t}{GetColumnCount}{\void} + +Returns the number of columns. + +\membersection{wxTreeListCtrl::GetColumnImage}\label{wxtreelistctrlgetcolumnimage} + +\constfunc{int}{GetColumnImage}{\param{size_t}{ column}} + +Returns the image of the columns. + +\membersection{wxTreeListCtrl::GetColumnText}\label{wxtreelistctrlgetcolumntext} + +\constfunc{wxString}{GetColumnText}{\param{size_t}{ column}} + +Returns the text of the columns. + +\membersection{wxTreeListCtrl::GetColumnWidth}\label{wxtreelistctrlgetcolumnwidth} + +\constfunc{size_t}{GetColumnWidth}{\param{size_t}{ column}} + +Returns the width of the columns. + +\membersection{wxTreeListCtrl::GetMainColumn}\label{wxtreelistctrlgetmaincolumn} + +\constfunc{size_t}{GetMainColumn}{\void} + +Returns the number of the main column. + +\membersection{wxTreeListCtrl::InsertColumn}\label{wxtreelistctrlinsertcolumn} + +\func{void}{InsertColumn}{\param{size_t}{ before}, \param{const wxString\&}{ text}} + +\func{void}{InsertColumn}{\param{size_t}{ before}, \param{const wxString\&}{ text}, \param{size_t}{ width}, + \param{wxTreeListColumnAlign}{ alignment = wxTL_ALIGN_LEFT}} + +Inserts a column before(???) the entered column. + +\membersection{wxTreeListCtrl::IsColumnShown}\label{wxtreelistctrliscolumnshown} + +\constfunc{bool}{IsColumnShown}{\param{size_t}{ column}} + +Returns if the columns is shown. + +\membersection{wxTreeListCtrl::RemoveColumn}\label{wxtreelistctrlremovecolumn} + +\func{void}{RemoveColumn}{\param{size_t}{ column}} + +Removes the entered column. + +\membersection{wxTreeListCtrl::SetColumn}\label{wxtreelistctrlsetcolumn} + +\func{void}{SetColumn}{\param{size_t}{ column}, \param{const wxTreeListColumnInfo\&}{ info}} + +Sets the infos of the column. + +\membersection{wxTreeListCtrl::SetColumnAlignment}\label{wxtreelistctrlsetcolumnalignment} + +\func{void}{SetColumnAlignment}{\param{size_t}{ column}, \param{const wxTreeListColumnAlign}{ align}} + +Sets the alignment of the column. + +\membersection{wxTreeListCtrl::SetColumnImage}\label{wxtreelistctrlsetcolumnimage} + +\func{void}{SetColumnImage}{\param{size_t}{ column}, \param{int}{ image}} + +Sets the image of the column. + +\membersection{wxTreeListCtrl::SetColumnText}\label{wxtreelistctrlsetcolumntext} + +\func{void}{SetColumnText}{\param{size_t}{ column}, \param{const wxString\&}{ text}} + +Sets the text of the column. + +\membersection{wxTreeListCtrl::SetColumnWidth}\label{wxtreelistctrlsetcolumnwidth} + +\func{void}{SetColumnWidth}{\param{size_t}{ column}, \param{size_t}{ width}} + +Sets the width of the column. + +\membersection{wxTreeListCtrl::SetMainColumn}\label{wxtreelistctrlsetmaincolumn} + +\func{void}{SetMainColumn}{\param{size_t}{ column}} + +Set the main column. + +\membersection{wxTreeListCtrl::ShowColumn}\label{wxtreelistctrlshowcolumn} + +\func{void}{ShowColumn}{\param{size_t}{ column}, \param{bool}{ shown}} + +Shows/hides the column. + +\latexignore{\rtfignore{\wxheading{Members (item specific}}} + +\membersection{wxTreeListCtrl::GetItemBold}\label{wxtreelistctrlgetitembold} + +\constfunc{bool}{GetItemBold}{\param{const wxTreeItemId\&}{ item}} + +Returns the item bold status. + diff --git a/contrib/include/wx/gizmos/treelistctrl.h b/contrib/include/wx/gizmos/treelistctrl.h new file mode 100644 index 0000000000..8b89663a85 --- /dev/null +++ b/contrib/include/wx/gizmos/treelistctrl.h @@ -0,0 +1,515 @@ +// -*- C++ -*- ////////////////////////////////////////////////////////////// +// Name: treelistctrl.h (derived by wx/treectrlg.h) +// Purpose: wxTreeListCtrl class +// Author: Robert Roebling +// Modified by: Alberto Griggio, 2002 +// Created: 01/02/97 +// RCS-ID: $Id$ +// Copyright: (c) Robert Roebling, Julian Smart, Alberto Griggio, +// Vadim Zeitlin, Otto Wyss +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + + +#ifndef TREELISTCTRL_H +#define TREELISTCTRL_H + +#if defined(__GNUG__) && !defined(__APPLE__) + #pragma interface "treelistctrl.h" +#endif + +#include +#include +#include +#include // for wxListEvent + +#ifdef GIZMOISDLL +#define GIZMODLLEXPORT WXDLLEXPORT +#else +#define GIZMODLLEXPORT +#endif + + +class GIZMODLLEXPORT wxTreeListItem; +class GIZMODLLEXPORT wxTreeListHeaderWindow; +class GIZMODLLEXPORT wxTreeListMainWindow; + +//----------------------------------------------------------------------------- +// wxTreeListColumnAttrs +//----------------------------------------------------------------------------- + +enum wxTreeListColumnAlign { + wxTL_ALIGN_LEFT, + wxTL_ALIGN_RIGHT, + wxTL_ALIGN_CENTER +}; + + +class GIZMODLLEXPORT wxTreeListColumnInfo: public wxObject { +public: + enum { DEFAULT_COL_WIDTH = 100 }; + + wxTreeListColumnInfo(const wxString &text = wxT(""), + int image = -1, + size_t width = DEFAULT_COL_WIDTH, + bool shown = true, + wxTreeListColumnAlign alignment = wxTL_ALIGN_LEFT) + { + m_image = image; + m_selected_image = -1; + m_text = text; + m_width = width; + m_shown = shown; + m_alignment = alignment; + } + + wxTreeListColumnInfo(const wxTreeListColumnInfo& other) + { + m_image = other.m_image; + m_selected_image = other.m_selected_image; + m_text = other.m_text; + m_width = other.m_width; + m_shown = other.m_shown; + m_alignment = other.m_alignment; + } + + ~wxTreeListColumnInfo() {} + + // getters + bool GetShown() const { return m_shown; } + wxTreeListColumnAlign GetAlignment() const { return m_alignment; } + wxString GetText() const { return m_text; } + int GetImage() const { return m_image; } + int GetSelectedImage() const { return m_selected_image; } + size_t GetWidth() const { return m_width; } + + // setters + wxTreeListColumnInfo& SetShown(bool shown) + { m_shown = shown; return *this; } + + wxTreeListColumnInfo& SetAlignment(wxTreeListColumnAlign alignment) + { m_alignment = alignment; return *this; } + + wxTreeListColumnInfo& SetText(const wxString& text) + { m_text = text; return *this; } + + wxTreeListColumnInfo& SetImage(int image) + { m_image = image; return *this; } + + wxTreeListColumnInfo& SetSelectedImage(int image) + { m_selected_image = image; return *this; } + + wxTreeListColumnInfo& SetWidth(size_t with) + { m_width = with; return *this; } + +private: + bool m_shown; + wxTreeListColumnAlign m_alignment; + wxString m_text; + int m_image; + int m_selected_image; + size_t m_width; +}; + +//---------------------------------------------------------------------------- +// wxTreeListCtrl - the multicolumn tree control +//---------------------------------------------------------------------------- + +// additional flag for HitTest +const int wxTREE_HITTEST_ONITEMCOLUMN = 0x2000; +extern GIZMODLLEXPORT const wxChar* wxTreeListCtrlNameStr; + + +class GIZMODLLEXPORT wxTreeListCtrl : public wxControl +{ +public: + // creation + // -------- + wxTreeListCtrl() {} + + wxTreeListCtrl(wxWindow *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTR_DEFAULT_STYLE, + const wxValidator &validator = wxDefaultValidator, + const wxString& name = wxTreeListCtrlNameStr ) + : m_header_win(0), m_main_win(0) + { + Create(parent, id, pos, size, style, validator, name); + } + + virtual ~wxTreeListCtrl() {} + + bool Create(wxWindow *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTR_DEFAULT_STYLE, + const wxValidator &validator = wxDefaultValidator, + const wxString& name = wxTreeListCtrlNameStr ); + + void Refresh(bool erase=TRUE, const wxRect* rect=NULL); + void SetFocus(); + // accessors + // --------- + + // get the total number of items in the control + size_t GetCount() const; + + // indent is the number of pixels the children are indented relative to + // the parents position. SetIndent() also redraws the control + // immediately. + unsigned int GetIndent() const; + void SetIndent(unsigned int indent); + + // line spacing is the space above and below the text on each line + unsigned int GetLineSpacing() const; + void SetLineSpacing(unsigned int spacing); + + // image list: these functions allow to associate an image list with + // the control and retrieve it. Note that when assigned with + // SetImageList, the control does _not_ delete + // the associated image list when it's deleted in order to allow image + // lists to be shared between different controls. If you use + // AssignImageList, the control _does_ delete the image list. + // + // The normal image list is for the icons which correspond to the + // normal tree item state (whether it is selected or not). + // Additionally, the application might choose to show a state icon + // which corresponds to an app-defined item state (for example, + // checked/unchecked) which are taken from the state image list. + wxImageList *GetImageList() const; + wxImageList *GetStateImageList() const; + wxImageList *GetButtonsImageList() const; + + void SetImageList(wxImageList *imageList); + void SetStateImageList(wxImageList *imageList); + void SetButtonsImageList(wxImageList *imageList); + void AssignImageList(wxImageList *imageList); + void AssignStateImageList(wxImageList *imageList); + void AssignButtonsImageList(wxImageList *imageList); + + + // Functions to work with tree list ctrl columns + + // adds a column + void AddColumn(const wxString& text) + { AddColumn(wxTreeListColumnInfo(text)); } + void AddColumn(const wxString& text, + size_t width, + wxTreeListColumnAlign alignment = wxTL_ALIGN_LEFT) + { AddColumn(wxTreeListColumnInfo(text, + -1, + width, + true, + alignment)); } + void AddColumn(const wxTreeListColumnInfo& col); + + // inserts a column before the given one + void InsertColumn(size_t before, const wxString& text) + { InsertColumn(before, wxTreeListColumnInfo(text)); } + void InsertColumn(size_t before, const wxTreeListColumnInfo& col); + + // deletes the given column - does not delete the corresponding column + // of each item + void RemoveColumn(size_t column); + + // returns the number of columns in the ctrl + size_t GetColumnCount() const; + + void SetColumnWidth(size_t column, size_t width); + int GetColumnWidth(size_t column) const; + + // tells which column is the "main" one, i.e. the "threaded" one + void SetMainColumn(size_t column); + size_t GetMainColumn() const; + + void SetColumnText(size_t column, const wxString& text); + wxString GetColumnText(size_t column) const; + + void SetColumn(size_t column, const wxTreeListColumnInfo& info); + wxTreeListColumnInfo& GetColumn(size_t column); + const wxTreeListColumnInfo& GetColumn(size_t column) const; + + // other column-related methods + void SetColumnAlignment(size_t column, wxTreeListColumnAlign align); + wxTreeListColumnAlign GetColumnAlignment(size_t column) const; + + void SetColumnImage(size_t column, int image); + int GetColumnImage(size_t column) const; + + void ShowColumn(size_t column, bool shown); + bool IsColumnShown(size_t column) const; + + // Functions to work with tree list ctrl items. + + // accessors + // --------- + + // retrieve item's label (of the main column) + wxString GetItemText(const wxTreeItemId& item) const + { return GetItemText(item, GetMainColumn()); } + // retrieves item's label of the given column + wxString GetItemText(const wxTreeItemId& item, size_t column) const; + + // get one of the images associated with the item (normal by default) + int GetItemImage(const wxTreeItemId& item, + wxTreeItemIcon which = wxTreeItemIcon_Normal) const + { return GetItemImage(item, GetMainColumn(), which); } + int GetItemImage(const wxTreeItemId& item, size_t column, + wxTreeItemIcon which = wxTreeItemIcon_Normal) const; + + // get the data associated with the item + wxTreeItemData *GetItemData(const wxTreeItemId& item) const; + + bool GetItemBold(const wxTreeItemId& item) const; + wxColour GetItemTextColour(const wxTreeItemId& item) const; + wxColour GetItemBackgroundColour(const wxTreeItemId& item) const; + wxFont GetItemFont(const wxTreeItemId& item) const; + + // modifiers + // --------- + + // set item's label + void SetItemText(const wxTreeItemId& item, const wxString& text) + { SetItemText(item, GetMainColumn(), text); } + void SetItemText(const wxTreeItemId& item, size_t column, + const wxString& text); + + // get one of the images associated with the item (normal by default) + void SetItemImage(const wxTreeItemId& item, int image, + wxTreeItemIcon which = wxTreeItemIcon_Normal) + { SetItemImage(item, GetMainColumn(), image, which); } + // the which parameter is ignored for all columns but the main one + void SetItemImage(const wxTreeItemId& item, size_t column, int image, + wxTreeItemIcon which = wxTreeItemIcon_Normal); + + // associate some data with the item + void SetItemData(const wxTreeItemId& item, wxTreeItemData *data); + + // force appearance of [+] button near the item. This is useful to + // allow the user to expand the items which don't have any children now + // - but instead add them only when needed, thus minimizing memory + // usage and loading time. + void SetItemHasChildren(const wxTreeItemId& item, bool has = TRUE); + + // the item will be shown in bold + void SetItemBold(const wxTreeItemId& item, bool bold = TRUE); + + // set the item's text colour + void SetItemTextColour(const wxTreeItemId& item, const wxColour& colour); + + // set the item's background colour + void SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& colour); + + // set the item's font (should be of the same height for all items) + void SetItemFont(const wxTreeItemId& item, const wxFont& font); + + // set the window font + virtual bool SetFont( const wxFont &font ); + + // set the styles. + void SetWindowStyle(const long styles); + long GetWindowStyle() const; + long GetWindowStyleFlag() const { return GetWindowStyle(); } + + // item status inquiries + // --------------------- + + // is the item visible (it might be outside the view or not expanded)? + bool IsVisible(const wxTreeItemId& item) const; + // does the item has any children? + bool HasChildren(const wxTreeItemId& item) const + { return ItemHasChildren(item); } + bool ItemHasChildren(const wxTreeItemId& item) const; + // is the item expanded (only makes sense if HasChildren())? + bool IsExpanded(const wxTreeItemId& item) const; + // is this item currently selected (the same as has focus)? + bool IsSelected(const wxTreeItemId& item) const; + // is item text in bold font? + bool IsBold(const wxTreeItemId& item) const; + // does the layout include space for a button? + + // number of children + // ------------------ + + // if 'recursively' is FALSE, only immediate children count, otherwise + // the returned number is the number of all items in this branch + size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = TRUE); + + // navigation + // ---------- + + // wxTreeItemId.IsOk() will return FALSE if there is no such item + + // get the root tree item + wxTreeItemId GetRootItem() const; + + // get the item currently selected (may return NULL if no selection) + wxTreeItemId GetSelection() const; + + // get the items currently selected, return the number of such item + size_t GetSelections(wxArrayTreeItemIds&) const; + + // get the parent of this item (may return NULL if root) + wxTreeItemId GetItemParent(const wxTreeItemId& item) const; + + // for this enumeration function you must pass in a "cookie" parameter + // which is opaque for the application but is necessary for the library + // to make these functions reentrant (i.e. allow more than one + // enumeration on one and the same object simultaneously). Of course, + // the "cookie" passed to GetFirstChild() and GetNextChild() should be + // the same! + + // get the first child of this item + wxTreeItemId GetFirstChild(const wxTreeItemId& item, long& cookie) const; + // get the next child + wxTreeItemId GetNextChild(const wxTreeItemId& item, long& cookie) const; + // get the last child of this item - this method doesn't use cookies + wxTreeItemId GetLastChild(const wxTreeItemId& item) const; + + // get the next sibling of this item + wxTreeItemId GetNextSibling(const wxTreeItemId& item) const; + // get the previous sibling + wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const; + + // get first visible item + wxTreeItemId GetFirstVisibleItem() const; + // get the next visible item: item must be visible itself! + // see IsVisible() and wxTreeCtrl::GetFirstVisibleItem() + wxTreeItemId GetNextVisible(const wxTreeItemId& item) const; + // get the previous visible item: item must be visible itself! + wxTreeItemId GetPrevVisible(const wxTreeItemId& item) const; + + // Only for internal use right now, but should probably be public + wxTreeItemId GetNext(const wxTreeItemId& item) const; + + // operations + // ---------- + + // add the root node to the tree + wxTreeItemId AddRoot(const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item in as the first child of the parent + wxTreeItemId PrependItem(const wxTreeItemId& parent, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item after a given one + wxTreeItemId InsertItem(const wxTreeItemId& parent, + const wxTreeItemId& idPrevious, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item before the one with the given index + wxTreeItemId InsertItem(const wxTreeItemId& parent, + size_t index, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item in as the last child of the parent + wxTreeItemId AppendItem(const wxTreeItemId& parent, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // delete this item and associated data if any + void Delete(const wxTreeItemId& item); + // delete all children (but don't delete the item itself) + // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events + void DeleteChildren(const wxTreeItemId& item); + // delete all items from the tree + // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events + void DeleteAllItems(); + + // expand this item + void Expand(const wxTreeItemId& item); + // expand this item and all subitems recursively + void ExpandAll(const wxTreeItemId& item); + // collapse the item without removing its children + void Collapse(const wxTreeItemId& item); + // collapse the item and remove all children + void CollapseAndReset(const wxTreeItemId& item); + // toggles the current state + void Toggle(const wxTreeItemId& item); + + // remove the selection from currently selected item (if any) + void Unselect(); + void UnselectAll(); + // select this item + void SelectItem(const wxTreeItemId& item, bool unselect_others=TRUE, + bool extended_select=FALSE); + // make sure this item is visible (expanding the parent item and/or + // scrolling to this item if necessary) + void EnsureVisible(const wxTreeItemId& item); + // scroll to this item (but don't expand its parent) + void ScrollTo(const wxTreeItemId& item); + //void AdjustMyScrollbars(); + + // The first function is more portable (because easier to implement + // on other platforms), but the second one returns some extra info. + wxTreeItemId HitTest(const wxPoint& point) + { int dummy; return HitTest(point, dummy); } + wxTreeItemId HitTest(const wxPoint& point, int& flags) + { int col; return HitTest(point, flags, col); } + wxTreeItemId HitTest(const wxPoint& point, int& flags, int& column); + + // get the bounding rectangle of the item (or of its label only) + bool GetBoundingRect(const wxTreeItemId& item, + wxRect& rect, + bool textOnly = FALSE) const; + + // Start editing the item label: this (temporarily) replaces the item + // with a one line edit control. The item will be selected if it hadn't + // been before. + void EditLabel( const wxTreeItemId& item ) { Edit( item ); } + void Edit( const wxTreeItemId& item ); + + // sorting + // this function is called to compare 2 items and should return -1, 0 + // or +1 if the first item is less than, equal to or greater than the + // second one. The base class version performs alphabetic comparaison + // of item labels (GetText) + virtual int OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2); + // sort the children of this item using OnCompareItems + // + // NB: this function is not reentrant and not MT-safe (FIXME)! + void SortChildren(const wxTreeItemId& item); + + // overridden base class virtuals + virtual bool SetBackgroundColour(const wxColour& colour); + virtual bool SetForegroundColour(const wxColour& colour); + + + wxTreeListHeaderWindow* GetHeaderWindow() const + { return m_header_win; } + + wxTreeListMainWindow* GetMainWindow() const + { return m_main_win; } + +protected: + // header window, responsible for column visualization and manipulation + wxTreeListHeaderWindow* m_header_win; + // main window, the "true" tree ctrl + wxTreeListMainWindow* m_main_win; + +// // the common part of all ctors +// void Init(); + + void OnSize(wxSizeEvent& event); + + +private: + size_t fill_column; + + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(wxTreeListCtrl) +}; + +#endif // TREELISTCTRL_H + diff --git a/contrib/src/gizmos/treelistctrl.cpp b/contrib/src/gizmos/treelistctrl.cpp new file mode 100644 index 0000000000..bee20336b4 --- /dev/null +++ b/contrib/src/gizmos/treelistctrl.cpp @@ -0,0 +1,4804 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: treelistctrl.cpp (derived by treectlg.h) +// Purpose: multi column tree control implementation +// Author: Robert Roebling +// Created: 01/02/97 +// Modified: Alberto Griggio, 2002 +// 22/10/98 - almost total rewrite, simpler interface (VZ) +// Id: $Id$ +// Copyright: (c) Robert Roebling, Julian Smart, Alberto Griggio, +// Vadim Zeitlin, Otto Wyss +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +#if defined(__GNUG__) && !defined(__APPLE__) + #pragma implementation "treelistctrl.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wx/gizmos/treelistctrl.h" +//#include "treelistctrl.h" + + +#ifdef __WXGTK__ + #include + #include +#endif + +// --------------------------------------------------------------------------- +// array types +// --------------------------------------------------------------------------- + +class wxTreeListItem; + +WX_DEFINE_ARRAY(wxTreeListItem *, wxArrayTreeListItems); + +#include +WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo); +#include +WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo); + +#if !wxCHECK_VERSION(2, 3, 3) +WX_DEFINE_ARRAY(short, wxArrayShort); +#endif + + +// -------------------------------------------------------------------------- +// constants +// -------------------------------------------------------------------------- + +static const int NO_IMAGE = -1; + +const int LINEHEIGHT = 10; +const int PIXELS_PER_UNIT = 10; +const int LINEATROOT = 5; +const int MARGIN = 2; +const int MININDENT = 10; +const int BTNWIDTH = 11; +const int BTNHEIGHT = 11; + +const wxChar* wxTreeListCtrlNameStr = wxT("treelistctrl"); + +static wxTreeListColumnInfo wxInvalidTreeListColumnInfo; + + +// --------------------------------------------------------------------------- +// private classes +// --------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// wxTreeListHeaderWindow (internal) +//----------------------------------------------------------------------------- + +class wxTreeListHeaderWindow : public wxWindow +{ +protected: + wxTreeListMainWindow *m_owner; + wxCursor *m_currentCursor; + wxCursor *m_resizeCursor; + bool m_isDragging; + + // column being resized + int m_column; + + // divider line position in logical (unscrolled) coords + int m_currentX; + + // minimal position beyond which the divider line can't be dragged in + // logical coords + int m_minX; + + wxArrayTreeListColumnInfo m_columns; + + // total width of the columns + int m_total_col_width; + + +public: + wxTreeListHeaderWindow(); + + wxTreeListHeaderWindow( wxWindow *win, + wxWindowID id, + wxTreeListMainWindow *owner, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + long style = 0, + const wxString &name = wxT("wxtreelistctrlcolumntitles") ); + + virtual ~wxTreeListHeaderWindow(); + + void DoDrawRect( wxDC *dc, int x, int y, int w, int h ); + void DrawCurrent(); + void AdjustDC(wxDC& dc); + + void OnPaint( wxPaintEvent &event ); + void OnMouse( wxMouseEvent &event ); + void OnSetFocus( wxFocusEvent &event ); + + + // columns manipulation + + size_t GetColumnCount() const { return m_columns.GetCount(); } + + void AddColumn(const wxTreeListColumnInfo& col); + + void InsertColumn(size_t before, const wxTreeListColumnInfo& col); + + void RemoveColumn(size_t column); + + void SetColumn(size_t column, const wxTreeListColumnInfo& info); + const wxTreeListColumnInfo& GetColumn(size_t column) const + { + wxCHECK_MSG(column < GetColumnCount(), wxInvalidTreeListColumnInfo, wxT("Invalid column")); + return m_columns[column]; + } + wxTreeListColumnInfo& GetColumn(size_t column) + { + wxCHECK_MSG(column < GetColumnCount(), wxInvalidTreeListColumnInfo, wxT("Invalid column")); + return m_columns[column]; + } + + void SetColumnWidth(size_t column, size_t width); + + void SetColumnText(size_t column, const wxString& text) + { + wxCHECK_RET(column < GetColumnCount(), wxT("Invalid column")); + m_columns[column].SetText(text); + } + + void SetColumnShown(size_t column, bool shown) + { + wxCHECK_RET(column < GetColumnCount(), wxT("Invalid column")); + m_columns[column].SetShown(shown); + } + + wxString GetColumnText(size_t column) const + { + wxCHECK_MSG(column < GetColumnCount(), wxEmptyString, wxT("Invalid column")); + return m_columns[column].GetText(); + } + + int GetColumnWidth(size_t column) const + { + wxCHECK_MSG(column < GetColumnCount(), -1, wxT("Invalid column")); + return m_columns[column].GetWidth(); + } + + int GetWidth() const { return m_total_col_width; } + + int GetColumnShown(size_t column) const + { + wxCHECK_MSG(column < GetColumnCount(), -1, wxT("Invalid column")); + return m_columns[column].GetShown(); + } + + // needs refresh + bool m_dirty; + +private: + // common part of all ctors + void Init(); + + void SendListEvent(wxEventType type, wxPoint pos); + + DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow) + DECLARE_EVENT_TABLE() +}; + + +// this is the "true" control +class wxTreeListMainWindow: public wxScrolledWindow +{ +public: + // creation + // -------- + wxTreeListMainWindow() { Init(); } + + wxTreeListMainWindow(wxTreeListCtrl *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTR_DEFAULT_STYLE, + const wxValidator &validator = wxDefaultValidator, + const wxString& name = wxT("wxtreelistmainwindow")) + { + Init(); + Create(parent, id, pos, size, style, validator, name); + } + + virtual ~wxTreeListMainWindow(); + + bool Create(wxTreeListCtrl *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTR_DEFAULT_STYLE, + const wxValidator &validator = wxDefaultValidator, + const wxString& name = wxT("wxtreelistctrl")); + + // accessors + // --------- + + // get the total number of items in the control + size_t GetCount() const; + + // indent is the number of pixels the children are indented relative to + // the parents position. SetIndent() also redraws the control + // immediately. + unsigned int GetIndent() const { return m_indent; } + void SetIndent(unsigned int indent); + + // see wxTreeListCtrl for the meaning + unsigned int GetLineSpacing() const { return m_linespacing; } + void SetLineSpacing(unsigned int spacing); + + // image list: these functions allow to associate an image list with + // the control and retrieve it. Note that when assigned with + // SetImageList, the control does _not_ delete + // the associated image list when it's deleted in order to allow image + // lists to be shared between different controls. If you use + // AssignImageList, the control _does_ delete the image list. + // + // The normal image list is for the icons which correspond to the + // normal tree item state (whether it is selected or not). + // Additionally, the application might choose to show a state icon + // which corresponds to an app-defined item state (for example, + // checked/unchecked) which are taken from the state image list. + wxImageList *GetImageList() const; + wxImageList *GetStateImageList() const; + wxImageList *GetButtonsImageList() const; + + void SetImageList(wxImageList *imageList); + void SetStateImageList(wxImageList *imageList); + void SetButtonsImageList(wxImageList *imageList); + void AssignImageList(wxImageList *imageList); + void AssignStateImageList(wxImageList *imageList); + void AssignButtonsImageList(wxImageList *imageList); + + // Functions to work with tree ctrl items. + + // accessors + // --------- + + // retrieve item's label + wxString GetItemText(const wxTreeItemId& item) const + { return GetItemText(item, GetMainColumn()); } + // get one of the images associated with the item (normal by default) + int GetItemImage(const wxTreeItemId& item, + wxTreeItemIcon which = wxTreeItemIcon_Normal) const + { return GetItemImage(item, GetMainColumn(), which); } + + // get the data associated with the item + wxTreeItemData *GetItemData(const wxTreeItemId& item) const; + + bool GetItemBold(const wxTreeItemId& item) const; + wxColour GetItemTextColour(const wxTreeItemId& item) const; + wxColour GetItemBackgroundColour(const wxTreeItemId& item) const; + wxFont GetItemFont(const wxTreeItemId& item) const; + + // modifiers + // --------- + + // set item's label + void SetItemText(const wxTreeItemId& item, const wxString& text) + { SetItemText(item, GetMainColumn(), text); } + + // get one of the images associated with the item (normal by default) + void SetItemImage(const wxTreeItemId& item, int image, + wxTreeItemIcon which = wxTreeItemIcon_Normal) + { SetItemImage(item, GetMainColumn(), image, which); } + + // associate some data with the item + void SetItemData(const wxTreeItemId& item, wxTreeItemData *data); + + // force appearance of [+] button near the item. This is useful to + // allow the user to expand the items which don't have any children now + // - but instead add them only when needed, thus minimizing memory + // usage and loading time. + void SetItemHasChildren(const wxTreeItemId& item, bool has = TRUE); + + // the item will be shown in bold + void SetItemBold(const wxTreeItemId& item, bool bold = TRUE); + + // set the item's text colour + void SetItemTextColour(const wxTreeItemId& item, const wxColour& colour); + + // set the item's background colour + void SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& colour); + + // set the item's font (should be of the same height for all items) + void SetItemFont(const wxTreeItemId& item, const wxFont& font); + + // set the window font + virtual bool SetFont( const wxFont &font ); + + // set the styles. No need to specify a GetWindowStyle here since + // the base wxWindow member function will do it for us + void SetWindowStyle(const long styles); + + // item status inquiries + // --------------------- + + // is the item visible (it might be outside the view or not expanded)? + bool IsVisible(const wxTreeItemId& item) const; + // does the item has any children? + bool HasChildren(const wxTreeItemId& item) const + { return ItemHasChildren(item); } + bool ItemHasChildren(const wxTreeItemId& item) const; + // is the item expanded (only makes sense if HasChildren())? + bool IsExpanded(const wxTreeItemId& item) const; + // is this item currently selected (the same as has focus)? + bool IsSelected(const wxTreeItemId& item) const; + // is item text in bold font? + bool IsBold(const wxTreeItemId& item) const; + // does the layout include space for a button? + + // number of children + // ------------------ + + // if 'recursively' is FALSE, only immediate children count, otherwise + // the returned number is the number of all items in this branch + size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = TRUE); + + // navigation + // ---------- + + // wxTreeItemId.IsOk() will return FALSE if there is no such item + + // get the root tree item + wxTreeItemId GetRootItem() const { return m_anchor; } + + // get the item currently selected (may return NULL if no selection) + wxTreeItemId GetSelection() const { return m_current; } + + // get the items currently selected, return the number of such item + size_t GetSelections(wxArrayTreeItemIds&) const; + + // get the parent of this item (may return NULL if root) + wxTreeItemId GetItemParent(const wxTreeItemId& item) const; + + // for this enumeration function you must pass in a "cookie" parameter + // which is opaque for the application but is necessary for the library + // to make these functions reentrant (i.e. allow more than one + // enumeration on one and the same object simultaneously). Of course, + // the "cookie" passed to GetFirstChild() and GetNextChild() should be + // the same! + + // get the first child of this item + wxTreeItemId GetFirstChild(const wxTreeItemId& item, long& cookie) const; + // get the next child + wxTreeItemId GetNextChild(const wxTreeItemId& item, long& cookie) const; + // get the last child of this item - this method doesn't use cookies + wxTreeItemId GetLastChild(const wxTreeItemId& item) const; + + // get the next sibling of this item + wxTreeItemId GetNextSibling(const wxTreeItemId& item) const; + // get the previous sibling + wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const; + + // get first visible item + wxTreeItemId GetFirstVisibleItem() const; + // get the next visible item: item must be visible itself! + // see IsVisible() and wxTreeCtrl::GetFirstVisibleItem() + wxTreeItemId GetNextVisible(const wxTreeItemId& item) const; + // get the previous visible item: item must be visible itself! + wxTreeItemId GetPrevVisible(const wxTreeItemId& item) const; + + // Only for internal use right now, but should probably be public + wxTreeItemId GetNext(const wxTreeItemId& item) const; + + // operations + // ---------- + + // add the root node to the tree + wxTreeItemId AddRoot(const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item in as the first child of the parent + wxTreeItemId PrependItem(const wxTreeItemId& parent, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item after a given one + wxTreeItemId InsertItem(const wxTreeItemId& parent, + const wxTreeItemId& idPrevious, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item before the one with the given index + wxTreeItemId InsertItem(const wxTreeItemId& parent, + size_t index, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item in as the last child of the parent + wxTreeItemId AppendItem(const wxTreeItemId& parent, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // delete this item and associated data if any + void Delete(const wxTreeItemId& item); + // delete all children (but don't delete the item itself) + // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events + void DeleteChildren(const wxTreeItemId& item); + // delete all items from the tree + // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events + void DeleteAllItems(); + + // expand this item + void Expand(const wxTreeItemId& item); + // expand this item and all subitems recursively + void ExpandAll(const wxTreeItemId& item); + // collapse the item without removing its children + void Collapse(const wxTreeItemId& item); + // collapse the item and remove all children + void CollapseAndReset(const wxTreeItemId& item); + // toggles the current state + void Toggle(const wxTreeItemId& item); + + // remove the selection from currently selected item (if any) + void Unselect(); + void UnselectAll(); + // select this item + void SelectItem(const wxTreeItemId& item, bool unselect_others=TRUE, + bool extended_select=FALSE); + // make sure this item is visible (expanding the parent item and/or + // scrolling to this item if necessary) + void EnsureVisible(const wxTreeItemId& item); + // scroll to this item (but don't expand its parent) + void ScrollTo(const wxTreeItemId& item); + void AdjustMyScrollbars(); + + // The first function is more portable (because easier to implement + // on other platforms), but the second one returns some extra info. + wxTreeItemId HitTest(const wxPoint& point) + { int dummy; return HitTest(point, dummy); } + wxTreeItemId HitTest(const wxPoint& point, int& flags) + { int col; return HitTest(point, flags, col); } + // ALB + wxTreeItemId HitTest(const wxPoint& point, int& flags, int& column); + + + // get the bounding rectangle of the item (or of its label only) + bool GetBoundingRect(const wxTreeItemId& item, + wxRect& rect, + bool textOnly = FALSE) const; + + // Start editing the item label: this (temporarily) replaces the item + // with a one line edit control. The item will be selected if it hadn't + // been before. + void EditLabel( const wxTreeItemId& item ) { Edit( item ); } + void Edit( const wxTreeItemId& item ); + + // sorting + // this function is called to compare 2 items and should return -1, 0 + // or +1 if the first item is less than, equal to or greater than the + // second one. The base class version performs alphabetic comparaison + // of item labels (GetText) + virtual int OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2); + // sort the children of this item using OnCompareItems + // + // NB: this function is not reentrant and not MT-safe (FIXME)! + void SortChildren(const wxTreeItemId& item); + + // deprecated functions: use Set/GetItemImage directly + // get the selected item image + int GetItemSelectedImage(const wxTreeItemId& item) const + { return GetItemImage(item, wxTreeItemIcon_Selected); } + // set the selected item image + void SetItemSelectedImage(const wxTreeItemId& item, int image) + { SetItemImage(item, image, wxTreeItemIcon_Selected); } + + // implementation only from now on + + // overridden base class virtuals + virtual bool SetBackgroundColour(const wxColour& colour); + virtual bool SetForegroundColour(const wxColour& colour); + + // callbacks + void OnPaint( wxPaintEvent &event ); + void OnSetFocus( wxFocusEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + void OnChar( wxKeyEvent &event ); + void OnMouse( wxMouseEvent &event ); + void OnIdle( wxIdleEvent &event ); + void OnSize(wxSizeEvent& event); // ALB + void OnScroll(wxScrollWinEvent& event); // ALB + + // implementation helpers + void SendDeleteEvent(wxTreeListItem *itemBeingDeleted); + + void DrawBorder(const wxTreeItemId& item); + void DrawLine(const wxTreeItemId& item, bool below); + + size_t GetColumnCount() const + { return m_owner->GetHeaderWindow()->GetColumnCount(); } + + void SetMainColumn(size_t column) + { + if(column < GetColumnCount()) + m_main_column = column; + } + size_t GetMainColumn() const { return m_main_column; } + + void SetItemText(const wxTreeItemId& item, size_t column, + const wxString& text); + wxString GetItemText(const wxTreeItemId& item, size_t column) const; + + void SetItemImage(const wxTreeItemId& item, size_t column, int image, + wxTreeItemIcon which = wxTreeItemIcon_Normal); + int GetItemImage(const wxTreeItemId& item, size_t column, + wxTreeItemIcon which = wxTreeItemIcon_Normal) const; +protected: + wxTreeListCtrl* m_owner; // ALB + + size_t m_main_column; // ALB + + friend class wxTreeListItem; + friend class wxTreeListRenameTimer; + friend class wxTreeListTextCtrl; + + wxFont m_normalFont; + wxFont m_boldFont; + + wxTreeListItem *m_anchor; + wxTreeListItem *m_current, *m_key_current, *m_currentEdit; + int m_btnWidth, m_btnWidth2; + int m_btnHeight, m_btnHeight2; + int m_imgWidth, m_imgWidth2; + int m_imgHeight, m_imgHeight2; + unsigned short m_indent; + int m_lineHeight; + unsigned short m_linespacing; + wxPen m_dottedPen; + wxBrush *m_hilightBrush, + *m_hilightUnfocusedBrush; + bool m_hasFocus; +public: + bool m_dirty; +protected: + bool m_ownsImageListNormal, + m_ownsImageListState, + m_ownsImageListButtons; + bool m_isDragging; // true between BEGIN/END drag events + bool m_renameAccept; + bool m_lastOnSame; // last click on the same item as prev + wxImageList *m_imageListNormal, + *m_imageListState, + *m_imageListButtons; + + int m_dragCount; + wxPoint m_dragStart; + wxTreeListItem *m_dropTarget; + wxCursor m_oldCursor; // cursor is changed while dragging + wxTreeListItem *m_oldSelection; + + wxTimer *m_renameTimer; + wxString m_renameRes; + + // the common part of all ctors + void Init(); + + // misc helpers + wxTreeItemId DoInsertItem(const wxTreeItemId& parent, + size_t previous, + const wxString& text, + int image, int selectedImage, + wxTreeItemData *data); + bool HasButtons(void) const + { return (m_imageListButtons != NULL) || + HasFlag (wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); } + +protected: + void CalculateLineHeight(); + int GetLineHeight(wxTreeListItem *item) const; + void PaintLevel( wxTreeListItem *item, wxDC& dc, int level, int &y, + int x_colstart); + void PaintItem( wxTreeListItem *item, wxDC& dc); + + void CalculateLevel( wxTreeListItem *item, wxDC &dc, int level, int &y, + int x_colstart); + void CalculatePositions(); + void CalculateSize( wxTreeListItem *item, wxDC &dc ); + + void RefreshSubtree( wxTreeListItem *item ); + void RefreshLine( wxTreeListItem *item ); + + // redraw all selected items + void RefreshSelected(); + + // RefreshSelected() recursive helper + void RefreshSelectedUnder(wxTreeListItem *item); + + void OnRenameTimer(); + void OnRenameAccept(); + + void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const; + void SelectItemRange( wxTreeListItem *item1, wxTreeListItem *item2 ); + bool TagAllChildrenUntilLast(wxTreeListItem *crt_item, + wxTreeListItem *last_item, bool select); + bool TagNextChildren(wxTreeListItem *crt_item, wxTreeListItem *last_item, + bool select); + void UnselectAllChildren( wxTreeListItem *item ); + + void DrawDropEffect(wxTreeListItem *item); + +private: + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow) +}; + + +// timer used for enabling in-place edit +class wxTreeListRenameTimer: public wxTimer +{ +public: + wxTreeListRenameTimer( wxTreeListMainWindow *owner ); + + void Notify(); + +private: + wxTreeListMainWindow *m_owner; +}; + +// control used for in-place edit +class wxTreeListTextCtrl: public wxTextCtrl +{ +public: + wxTreeListTextCtrl( wxWindow *parent, + const wxWindowID id, + bool *accept, + wxString *res, + wxTreeListMainWindow *owner, + const wxString &value = wxEmptyString, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + int style = wxSIMPLE_BORDER, + const wxValidator& validator = wxDefaultValidator, + const wxString &name = wxTextCtrlNameStr ); + + void OnChar( wxKeyEvent &event ); + void OnKeyUp( wxKeyEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + +private: + bool *m_accept; + wxString *m_res; + wxTreeListMainWindow *m_owner; + wxString m_startValue; + bool m_finished; + + DECLARE_EVENT_TABLE() +}; + +// a tree item +class wxTreeListItem +{ +public: + // ctors & dtor + wxTreeListItem() { m_data = NULL; } + wxTreeListItem( wxTreeListMainWindow *owner, + wxTreeListItem *parent, + const wxArrayString& text, + int image, + int selImage, + wxTreeItemData *data ); + + ~wxTreeListItem(); + + // trivial accessors + wxArrayTreeListItems& GetChildren() { return m_children; } + + const wxString GetText() const + { + if(m_text.GetCount() > 0) return m_text[0]; + return wxEmptyString; + } + const wxString GetText(size_t col) const + { + if(m_text.GetCount() > col) return m_text[col]; + return wxEmptyString; + } + int GetImage(wxTreeItemIcon which = wxTreeItemIcon_Normal) const + { return m_images[which]; } + int GetImage(size_t col, wxTreeItemIcon which=wxTreeItemIcon_Normal) const + { + if(col == m_owner->GetMainColumn()) return m_images[which]; + if(col < m_col_images.GetCount()) return m_col_images[col]; + return NO_IMAGE; + } + wxTreeItemData *GetData() const { return m_data; } + + // returns the current image for the item (depending on its + // selected/expanded/whatever state) + int GetCurrentImage() const; + + void SetText( const wxString &text ); + void SetText(size_t col, const wxString& text) // ALB + { + if(col < m_text.GetCount()) + m_text[col] = text; + else if(col < m_owner->GetColumnCount()) { + int howmany = m_owner->GetColumnCount(); + for(int i = m_text.GetCount(); i < howmany; ++i) + m_text.Add(wxEmptyString); + m_text[col] = text; + } + } + void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; } + void SetImage(size_t col, int image, wxTreeItemIcon which) + { + if(col == m_owner->GetMainColumn()) m_images[which] = image; + else if(col < m_col_images.GetCount()) + m_col_images[col] = image; + else if(col < m_owner->GetColumnCount()) { + int howmany = m_owner->GetColumnCount(); + for(int i = m_col_images.GetCount(); i < howmany; ++i) + m_col_images.Add(NO_IMAGE); + m_col_images[col] = image; + } + } + + void SetData(wxTreeItemData *data) { m_data = data; } + + void SetHasPlus(bool has = TRUE) { m_hasPlus = has; } + + void SetBold(bool bold) { m_isBold = bold; } + + int GetX() const { return m_x; } + int GetY() const { return m_y; } + + void SetX(int x) { m_x = x; } + void SetY(int y) { m_y = y; } + + int GetHeight() const { return m_height; } + int GetWidth() const { return m_width; } + + void SetHeight(int h) { m_height = h; } + void SetWidth(int w) { m_width = w; } + + wxTreeListItem *GetItemParent() const { return m_parent; } + + // operations + // deletes all children notifying the treectrl about it if !NULL + // pointer given + void DeleteChildren(wxTreeListMainWindow *tree = NULL); + + // get count of all children (and grand children if 'recursively') + size_t GetChildrenCount(bool recursively = TRUE) const; + + void Insert(wxTreeListItem *child, size_t index) + { m_children.Insert(child, index); } + + void GetSize( int &x, int &y, const wxTreeListMainWindow* ); + + // return the item at given position (or NULL if no item), onButton is + // TRUE if the point belongs to the item's button, otherwise it lies + // on the button's label + wxTreeListItem *HitTest( const wxPoint& point, + const wxTreeListMainWindow *, + int &flags, + int level ); + wxTreeListItem *HitTest( const wxPoint& point, + const wxTreeListMainWindow *, + int &flags, int& column /*ALB*/, + int level ); + + void Expand() { m_isCollapsed = FALSE; } + void Collapse() { m_isCollapsed = TRUE; } + + void SetHilight( bool set = TRUE ) { m_hasHilight = set; } + + // status inquiries + bool HasChildren() const { return !m_children.IsEmpty(); } + bool IsSelected() const { return m_hasHilight != 0; } + bool IsExpanded() const { return !m_isCollapsed; } + bool HasPlus() const { return m_hasPlus || HasChildren(); } + bool IsBold() const { return m_isBold != 0; } + + // attributes + // get them - may be NULL + wxTreeItemAttr *GetAttributes() const { return m_attr; } + // get them ensuring that the pointer is not NULL + wxTreeItemAttr& Attr() + { + if ( !m_attr ) + { + m_attr = new wxTreeItemAttr; + m_ownsAttr = TRUE; + } + return *m_attr; + } + // set them + void SetAttributes(wxTreeItemAttr *attr) + { + if ( m_ownsAttr ) delete m_attr; + m_attr = attr; + m_ownsAttr = FALSE; + } + // set them and delete when done + void AssignAttributes(wxTreeItemAttr *attr) + { + SetAttributes(attr); + m_ownsAttr = TRUE; + } + +private: + wxTreeListMainWindow *m_owner; // control the item belongs to + + // since there can be very many of these, we save size by chosing + // the smallest representation for the elements and by ordering + // the members to avoid padding. + wxArrayString m_text; // labels to be rendered for item + + wxTreeItemData *m_data; // user-provided data + + wxArrayTreeListItems m_children; // list of children + wxTreeListItem *m_parent; // parent of this item + + wxTreeItemAttr *m_attr; // attributes??? + + // tree ctrl images for the normal, selected, expanded and + // expanded+selected states + short m_images[wxTreeItemIcon_Max]; + wxArrayShort m_col_images; // images for the various columns (!= main) + + wxCoord m_x; // (virtual) offset from top + wxCoord m_y; // (virtual) offset from left + short m_width; // width of this item + unsigned char m_height; // height of this item + + // use bitfields to save size + int m_isCollapsed :1; + int m_hasHilight :1; // same as focused + int m_hasPlus :1; // used for item which doesn't have + // children but has a [+] button + int m_isBold :1; // render the label in bold font + int m_ownsAttr :1; // delete attribute when done +}; + +// =========================================================================== +// 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)); +} + +// --------------------------------------------------------------------------- +// wxTreeListRenameTimer (internal) +// --------------------------------------------------------------------------- + +wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow *owner ) +{ + m_owner = owner; +} + +void wxTreeListRenameTimer::Notify() +{ + m_owner->OnRenameTimer(); +} + +//----------------------------------------------------------------------------- +// wxTreeListTextCtrl (internal) +//----------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTreeListTextCtrl,wxTextCtrl) + EVT_CHAR (wxTreeListTextCtrl::OnChar) + EVT_KEY_UP (wxTreeListTextCtrl::OnKeyUp) + EVT_KILL_FOCUS (wxTreeListTextCtrl::OnKillFocus) +END_EVENT_TABLE() + +wxTreeListTextCtrl::wxTreeListTextCtrl( wxWindow *parent, + const wxWindowID id, + bool *accept, + wxString *res, + wxTreeListMainWindow *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) = wxEmptyString; + m_startValue = value; + m_finished = FALSE; +} + +void wxTreeListTextCtrl::OnChar( wxKeyEvent &event ) +{ + if (event.m_keyCode == WXK_RETURN) + { + (*m_accept) = TRUE; + (*m_res) = GetValue(); + + if ((*m_res) != m_startValue) + m_owner->OnRenameAccept(); + + if (!wxPendingDelete.Member(this)) + wxPendingDelete.Append(this); + + m_finished = TRUE; + m_owner->SetFocus(); // This doesn't work. TODO. + + return; + } + if (event.m_keyCode == WXK_ESCAPE) + { + (*m_accept) = FALSE; + (*m_res) = wxEmptyString; + + if (!wxPendingDelete.Member(this)) + wxPendingDelete.Append(this); + + m_finished = TRUE; + m_owner->SetFocus(); // This doesn't work. TODO. + + return; + } + event.Skip(); +} + +void wxTreeListTextCtrl::OnKeyUp( wxKeyEvent &event ) +{ + if (m_finished) + { + event.Skip(); + return; + } + + // auto-grow the textctrl: + wxSize parentSize = m_owner->GetSize(); + wxPoint myPos = GetPosition(); + wxSize mySize = GetSize(); + int sx, sy; + GetTextExtent(GetValue() + _T("M"), &sx, &sy); + if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x; + if (mySize.x > sx) sx = mySize.x; + SetSize(sx, -1); + + event.Skip(); +} + +void wxTreeListTextCtrl::OnKillFocus( wxFocusEvent &event ) +{ + if (m_finished) + { + event.Skip(); + return; + } + + if (!wxPendingDelete.Member(this)) + wxPendingDelete.Append(this); + + (*m_accept) = TRUE; + (*m_res) = GetValue(); + + if ((*m_res) != m_startValue) + m_owner->OnRenameAccept(); +} + +//----------------------------------------------------------------------------- +// wxTreeListHeaderWindow +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow,wxWindow); + +BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow) + EVT_PAINT (wxTreeListHeaderWindow::OnPaint) + EVT_MOUSE_EVENTS (wxTreeListHeaderWindow::OnMouse) + EVT_SET_FOCUS (wxTreeListHeaderWindow::OnSetFocus) +END_EVENT_TABLE() + +void wxTreeListHeaderWindow::Init() +{ + m_currentCursor = (wxCursor *) NULL; + m_isDragging = FALSE; + m_dirty = FALSE; + m_total_col_width = 0; +} + +wxTreeListHeaderWindow::wxTreeListHeaderWindow() +{ + Init(); + + m_owner = (wxTreeListMainWindow *) NULL; + m_resizeCursor = (wxCursor *) NULL; +} + +wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow *win, + wxWindowID id, + wxTreeListMainWindow *owner, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString &name ) + : wxWindow( win, id, pos, size, style, name ) +{ + Init(); + + m_owner = owner; + m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE); + + SetBackgroundColour(wxSystemSettings::GetSystemColour( + wxSYS_COLOUR_BTNFACE)); +} + +wxTreeListHeaderWindow::~wxTreeListHeaderWindow() +{ + delete m_resizeCursor; +} + +void wxTreeListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h ) +{ +#ifdef __WXGTK__ + GtkStateType state = m_parent->IsEnabled() ? GTK_STATE_NORMAL + : GTK_STATE_INSENSITIVE; + + x = dc->XLOG2DEV( x ); + + gtk_paint_box (m_wxwindow->style, GTK_PIZZA(m_wxwindow)->bin_window, + state, GTK_SHADOW_OUT, + (GdkRectangle*) NULL, m_wxwindow, "button", + x-1, y-1, w+2, h+2); +#elif defined( __WXMAC__ ) + const int m_corner = 1; + + dc->SetBrush( *wxTRANSPARENT_BRUSH ); + + dc->SetPen( wxPen(wxSystemSettings::GetSystemColour( + wxSYS_COLOUR_BTNSHADOW), 1, wxSOLID)); + dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer) + dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer) + + wxPen pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID ); + + dc->SetPen( pen ); + dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner) + dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner) + + dc->SetPen( *wxWHITE_PEN ); + dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer) + dc->DrawRectangle( x, y, 1, h ); // left (outer) + dc->DrawLine( x, y+h-1, x+1, y+h-1 ); + dc->DrawLine( x+w-1, y, x+w-1, y+1 ); +#else // !GTK, !Mac + const int m_corner = 1; + + dc->SetBrush( *wxTRANSPARENT_BRUSH ); + + dc->SetPen( *wxBLACK_PEN ); + dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer) + dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer) + + wxPen pen(wxSystemSettings::GetSystemColour( + wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID); + + dc->SetPen( pen ); + dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner) + dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner) + + dc->SetPen( *wxWHITE_PEN ); + dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer) + dc->DrawRectangle( x, y, 1, h ); // left (outer) + dc->DrawLine( x, y+h-1, x+1, y+h-1 ); + dc->DrawLine( x+w-1, y, x+w-1, y+1 ); +#endif +} + +// shift the DC origin to match the position of the main window horz +// scrollbar: this allows us to always use logical coords +void wxTreeListHeaderWindow::AdjustDC(wxDC& dc) +{ + int xpix; + m_owner->GetScrollPixelsPerUnit( &xpix, NULL ); + + int x; + m_owner->GetViewStart( &x, NULL ); + + // account for the horz scrollbar offset + dc.SetDeviceOrigin( -x * xpix, 0 ); +} + +void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) +{ + static const int HEADER_OFFSET_X = 1, HEADER_OFFSET_Y = 1; +#ifdef __WXGTK__ + wxClientDC dc( this ); +#else + wxPaintDC dc( this ); +#endif + + PrepareDC( dc ); + AdjustDC( dc ); + + dc.BeginDrawing(); + + dc.SetFont( GetFont() ); + + // width and height of the entire header window + int w, h; + GetClientSize( &w, &h ); + m_owner->CalcUnscrolledPosition(w, 0, &w, NULL); + + dc.SetBackgroundMode(wxTRANSPARENT); + + // do *not* use the listctrl colour for headers - one day we will have a + // function to set it separately + //dc.SetTextForeground( *wxBLACK ); + dc.SetTextForeground(wxSystemSettings:: + GetSystemColour( wxSYS_COLOUR_WINDOWTEXT )); + + int x = HEADER_OFFSET_X; + + int numColumns = GetColumnCount(); + for ( int i = 0; i < numColumns && x < w; i++ ) + { + wxTreeListColumnInfo& column = GetColumn(i); + int wCol = column.GetWidth(); + + // the width of the rect to draw: make it smaller to fit entirely + // inside the column rect + int cw = wCol - 2; + + dc.SetPen( *wxWHITE_PEN ); + + DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 ); + + // if we have an image, draw it on the right of the label + int image = column.GetImage(); //item.m_image; + int ix = -2, iy = 0; + wxImageList* imageList = m_owner->GetImageList(); + if(image != -1) { + if(imageList) { + imageList->GetSize(image, ix, iy); + } + //else: ignore the column image + } + + // extra margins around the text label + static const int EXTRA_WIDTH = 3; + static const int EXTRA_HEIGHT = 4; + + int text_width = 0; + int text_x = x; + int image_offset = cw - ix - 1; + + switch(column.GetAlignment()) { + case wxTL_ALIGN_LEFT: + text_x += EXTRA_WIDTH; + cw -= ix + 2; + break; + case wxTL_ALIGN_RIGHT: + dc.GetTextExtent(column.GetText(), &text_width, NULL); + text_x += cw - text_width - EXTRA_WIDTH; + image_offset = 0; + break; + case wxTL_ALIGN_CENTER: + dc.GetTextExtent(column.GetText(), &text_width, NULL); + text_x += (cw - text_width)/2 + ix + 2; + image_offset = (cw - text_width - ix - 2)/2; + break; + } + + // draw the image + if(image != -1 && imageList) { + imageList->Draw(image, dc, x + image_offset/*cw - ix - 1*/, + HEADER_OFFSET_Y + (h - 4 - iy)/2, + wxIMAGELIST_DRAW_TRANSPARENT); + } + + // draw the text clipping it so that it doesn't overwrite the column + // boundary + wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 ); + + dc.DrawText( column.GetText(), + text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT ); + + x += wCol; + } + + int more_w = m_owner->GetSize().x - x; + if (more_w > 0) + { + DoDrawRect( &dc, x, HEADER_OFFSET_Y, more_w, h-2 ); + } + + + dc.EndDrawing(); +} + +void wxTreeListHeaderWindow::DrawCurrent() +{ + int x1 = m_currentX; + int y1 = 0; + ClientToScreen( &x1, &y1 ); + + int x2 = m_currentX-1; +#ifdef __WXMSW__ + ++x2; // but why ? +#endif + int y2 = 0; + m_owner->GetClientSize( NULL, &y2 ); + m_owner->ClientToScreen( &x2, &y2 ); + + wxScreenDC dc; + dc.SetLogicalFunction( wxINVERT ); + dc.SetPen( wxPen( *wxBLACK, 2, wxSOLID ) ); + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + + AdjustDC(dc); + + dc.DrawLine( x1, y1, x2, y2 ); + + dc.SetLogicalFunction( wxCOPY ); + + dc.SetPen( wxNullPen ); + dc.SetBrush( wxNullBrush ); +} + +void wxTreeListHeaderWindow::OnMouse( wxMouseEvent &event ) +{ + // we want to work with logical coords + int x; + m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL); + int y = event.GetY(); + + if (m_isDragging) + { + SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING, + event.GetPosition()); + + // we don't draw the line beyond our window, but we allow dragging it + // there + int w = 0; + GetClientSize( &w, NULL ); + m_owner->CalcUnscrolledPosition(w, 0, &w, NULL); + w -= 6; + + // erase the line if it was drawn + if ( m_currentX < w ) + DrawCurrent(); + + if (event.ButtonUp()) + { + ReleaseMouse(); + m_isDragging = FALSE; + m_dirty = TRUE; + SetColumnWidth( m_column, m_currentX - m_minX ); + Refresh(); + SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG, + event.GetPosition()); + } + else + { + if (x > m_minX + 7) + m_currentX = x; + else + m_currentX = m_minX + 7; + + // draw in the new location + if ( m_currentX < w ) + DrawCurrent(); + } + } + else // not dragging + { + m_minX = 0; + bool hit_border = FALSE; + + // end of the current column + int xpos = 0; + + // find the column where this event occured + int countCol = GetColumnCount(); + for (int col = 0; col < countCol; col++) + { + if (!GetColumnShown (col)) continue; + xpos += GetColumnWidth (col); + m_column = col; + + if ( (abs(x-xpos) < 3) && (y < 22) ) + { + // near the column border + hit_border = TRUE; + break; + } + + if ( x < xpos ) + { + // inside the column + break; + } + + m_minX = xpos; + } + + if (event.LeftDown() || event.RightUp()) + { + if (hit_border && event.LeftDown()) + { + m_isDragging = TRUE; + m_currentX = x; + DrawCurrent(); + CaptureMouse(); + SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, + event.GetPosition()); + } + else // click on a column + { + SendListEvent( event.LeftDown() + ? wxEVT_COMMAND_LIST_COL_CLICK + : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK, + event.GetPosition()); + } + } + else if (event.Moving()) + { + bool setCursor; + if (hit_border) + { + setCursor = m_currentCursor == wxSTANDARD_CURSOR; + m_currentCursor = m_resizeCursor; + } + else + { + setCursor = m_currentCursor != wxSTANDARD_CURSOR; + m_currentCursor = wxSTANDARD_CURSOR; + } + + if ( setCursor ) + SetCursor(*m_currentCursor); + } + } +} + +void wxTreeListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) +{ + m_owner->SetFocus(); +} + +void wxTreeListHeaderWindow::SendListEvent(wxEventType type, wxPoint pos) +{ + wxWindow *parent = GetParent(); + wxListEvent le( type, parent->GetId() ); + le.SetEventObject( parent ); + le.m_pointDrag = pos; + + // the position should be relative to the parent window, not + // this one for compatibility with MSW and common sense: the + // user code doesn't know anything at all about this header + // window, so why should it get positions relative to it? + le.m_pointDrag.y -= GetSize().y; + + le.m_col = m_column; + parent->GetEventHandler()->ProcessEvent( le ); +} + +inline +void wxTreeListHeaderWindow::AddColumn(const wxTreeListColumnInfo& col) +{ + m_columns.Add(col); + m_total_col_width += col.GetWidth(); + //m_owner->GetHeaderWindow()->Refresh(); + //m_dirty = TRUE; + m_owner->AdjustMyScrollbars(); + m_owner->m_dirty = TRUE; + Refresh(); +} + +inline +void wxTreeListHeaderWindow::SetColumnWidth(size_t column, size_t width) +{ + if(column < GetColumnCount()) { + m_total_col_width -= m_columns[column].GetWidth(); + m_columns[column].SetWidth(width); + m_total_col_width += width; + m_owner->AdjustMyScrollbars(); + m_owner->m_dirty = TRUE; + //m_dirty = TRUE; + Refresh(); + } +} + + +inline +void wxTreeListHeaderWindow::InsertColumn(size_t before, + const wxTreeListColumnInfo& col) +{ + wxCHECK_RET(before < GetColumnCount(), wxT("Invalid column index")); + m_columns.Insert(col, before); + m_total_col_width += col.GetWidth(); + //m_dirty = TRUE; + //m_owner->GetHeaderWindow()->Refresh(); + m_owner->AdjustMyScrollbars(); + m_owner->m_dirty = TRUE; + Refresh(); +} + +inline +void wxTreeListHeaderWindow::RemoveColumn(size_t column) +{ + wxCHECK_RET(column < GetColumnCount(), wxT("Invalid column")); + m_total_col_width -= m_columns[column].GetWidth(); + m_columns.RemoveAt(column); + //m_dirty = TRUE; + m_owner->AdjustMyScrollbars(); + m_owner->m_dirty = TRUE; + Refresh(); +} + +inline +void wxTreeListHeaderWindow::SetColumn(size_t column, + const wxTreeListColumnInfo& info) +{ + wxCHECK_RET(column < GetColumnCount(), wxT("Invalid column")); + size_t w = m_columns[column].GetWidth(); + m_columns[column] = info; + //m_owner->GetHeaderWindow()->Refresh(); + //m_dirty = TRUE; + if(w != info.GetWidth()) { + m_total_col_width += info.GetWidth() - w; + m_owner->AdjustMyScrollbars(); + m_owner->m_dirty = TRUE; + } + Refresh(); +} + +// --------------------------------------------------------------------------- +// wxTreeListItem +// --------------------------------------------------------------------------- + +wxTreeListItem::wxTreeListItem(wxTreeListMainWindow *owner, + wxTreeListItem *parent, + const wxArrayString& text, + int image, int selImage, + wxTreeItemData *data) + : m_text(text) +{ + m_images[wxTreeItemIcon_Normal] = image; + m_images[wxTreeItemIcon_Selected] = selImage; + m_images[wxTreeItemIcon_Expanded] = NO_IMAGE; + m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE; + + m_data = data; + m_x = m_y = 0; + + m_isCollapsed = TRUE; + m_hasHilight = FALSE; + m_hasPlus = FALSE; + m_isBold = FALSE; + + m_owner = owner; + + m_parent = parent; + + m_attr = (wxTreeItemAttr *)NULL; + m_ownsAttr = FALSE; + + // We don't know the height here yet. + m_width = 0; + m_height = 0; +} + +wxTreeListItem::~wxTreeListItem() +{ + delete m_data; + + if (m_ownsAttr) delete m_attr; + + wxASSERT_MSG( m_children.IsEmpty(), + wxT("please call DeleteChildren() before deleting the item") ); +} + +void wxTreeListItem::DeleteChildren(wxTreeListMainWindow *tree) +{ + size_t count = m_children.Count(); + for ( size_t n = 0; n < count; n++ ) + { + wxTreeListItem *child = m_children[n]; + if (tree) + tree->SendDeleteEvent(child); + + child->DeleteChildren(tree); + delete child; + } + + m_children.Empty(); +} + +void wxTreeListItem::SetText( const wxString &text ) +{ + if(m_text.GetCount() > 0) m_text[0] = text; + else { + m_text.Add(text); + } +} + +size_t wxTreeListItem::GetChildrenCount(bool recursively) const +{ + size_t count = m_children.Count(); + if ( !recursively ) + return count; + + size_t total = count; + for (size_t n = 0; n < count; ++n) + { + total += m_children[n]->GetChildrenCount(); + } + + return total; +} + +void wxTreeListItem::GetSize( int &x, int &y, + const wxTreeListMainWindow *theButton ) +{ + int bottomY=m_y+theButton->GetLineHeight(this); + if ( y < bottomY ) y = bottomY; + int width = m_x + m_width; + if ( x < width ) x = width; + + if (IsExpanded()) + { + size_t count = m_children.Count(); + for ( size_t n = 0; n < count; ++n ) + { + m_children[n]->GetSize( x, y, theButton ); + } + } +} + +wxTreeListItem *wxTreeListItem::HitTest(const wxPoint& point, + const wxTreeListMainWindow *theCtrl, + int &flags, + int level) +{ + // for a hidden root node, don't evaluate it, but do evaluate children + if (!(theCtrl->HasFlag(wxTR_HIDE_ROOT) && (level == 0))) + { + // evaluate the item + int h = theCtrl->GetLineHeight(this); + if ((point.y > m_y) && (point.y < m_y + h)) + { + // check for above/below middle + int y_mid = m_y + h/2; + if (point.y < y_mid ) + flags |= wxTREE_HITTEST_ONITEMUPPERPART; + else + flags |= wxTREE_HITTEST_ONITEMLOWERPART; + + // check for button hit + if (HasPlus() && theCtrl->HasButtons()) { + int bntX = m_x - theCtrl->GetIndent() - theCtrl->m_btnWidth2; + int bntY = y_mid - theCtrl->m_btnHeight2; + if ((point.x > bntX) && (point.x < (bntX + theCtrl->m_btnWidth)) && + (point.y > bntY) && (point.y < (bntY + theCtrl->m_btnHeight))) { + flags |= wxTREE_HITTEST_ONITEMBUTTON; + return this; + } + } + + // check for image hit + int imgX = m_x - theCtrl->m_imgWidth2; + int imgY = y_mid - theCtrl->m_imgHeight2; + if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) && + (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) { + flags |= wxTREE_HITTEST_ONITEMICON; + return this; + } + + // check for label hit + int lblX = m_x - theCtrl->m_imgWidth2 + theCtrl->m_imgWidth + MARGIN; + if ((point.x >= lblX) && (point.x <= (m_x + m_width)) && + (point.y >= m_y) && (point.y <= (m_y + h))) { + flags |= wxTREE_HITTEST_ONITEMLABEL; + return this; + } + + // else check for indent + if (point.x < m_x) { + flags |= wxTREE_HITTEST_ONITEMINDENT; + return this; + } + + // else check for item right??? + if (point.x > m_x + m_width) { + flags |= wxTREE_HITTEST_ONITEMRIGHT; + return this; + } + + } + + // if children are expanded, fall through to evaluate them + if (m_isCollapsed) return (wxTreeListItem*) NULL; + } + + // evaluate children + size_t count = m_children.Count(); + for ( size_t n = 0; n < count; n++ ) + { + wxTreeListItem *res = m_children[n]->HitTest(point, theCtrl, + flags, level + 1); + if ( res != NULL ) + return res; + } + + return (wxTreeListItem*) NULL; +} + +// ALB +wxTreeListItem *wxTreeListItem::HitTest(const wxPoint& point, + const wxTreeListMainWindow *theCtrl, + int &flags, int& column, int level) +{ + column = theCtrl->GetMainColumn(); //-1; + + wxTreeListItem* res = HitTest(point, theCtrl, flags, level); + if(!res) { + column = -1; + return res; + } + + wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow(); + if (point.x >= header_win->GetWidth()) + column = -1; + else if(flags & wxTREE_HITTEST_ONITEMINDENT) { + int x = 0; + for(size_t i = 0; i < theCtrl->GetMainColumn(); ++i) { + if (!header_win->GetColumnShown(i)) continue; + int w = header_win->GetColumnWidth(i); + if(point.x >= x && point.x < x+w) { + flags ^= wxTREE_HITTEST_ONITEMINDENT; + flags |= wxTREE_HITTEST_ONITEMCOLUMN; + column = i; + return res; + } + } + } + else if(flags & wxTREE_HITTEST_ONITEMRIGHT) { + int x = 0; + size_t i; + for(i = 0; i < theCtrl->GetMainColumn()+1; ++i) { + if (!header_win->GetColumnShown(i)) continue; + x += header_win->GetColumnWidth(i); + } + for(i = theCtrl->GetMainColumn()+1; i < theCtrl->GetColumnCount(); ++i) { + if (!header_win->GetColumnShown(i)) continue; + int w = header_win->GetColumnWidth(i); + if(point.x >= x && point.x < x+w) { + flags ^= wxTREE_HITTEST_ONITEMRIGHT; + flags |= wxTREE_HITTEST_ONITEMCOLUMN; + column = i; + return res; + } + } + } + + return res; +} + + +int wxTreeListItem::GetCurrentImage() const +{ + int image = NO_IMAGE; + if ( IsExpanded() ) + { + if ( IsSelected() ) + { + image = GetImage(wxTreeItemIcon_SelectedExpanded); + } + + if ( image == NO_IMAGE ) + { + // we usually fall back to the normal item, but try just the + // expanded one (and not selected) first in this case + image = GetImage(wxTreeItemIcon_Expanded); + } + } + else // not expanded + { + if ( IsSelected() ) + image = GetImage(wxTreeItemIcon_Selected); + } + + // maybe it doesn't have the specific image we want, + // try the default one instead + if ( image == NO_IMAGE ) image = GetImage(); + + return image; +} + +// --------------------------------------------------------------------------- +// wxTreeListMainWindow implementation +// --------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow) + +BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow) + EVT_PAINT (wxTreeListMainWindow::OnPaint) + EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse) + EVT_CHAR (wxTreeListMainWindow::OnChar) + EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus) + EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus) + EVT_IDLE (wxTreeListMainWindow::OnIdle) + //EVT_SIZE (wxTreeListMainWindow::OnSize) + EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll) +END_EVENT_TABLE() + + +// --------------------------------------------------------------------------- +// construction/destruction +// --------------------------------------------------------------------------- + +void wxTreeListMainWindow::Init() +{ + m_current = m_key_current = m_anchor = (wxTreeListItem *) NULL; + m_hasFocus = FALSE; + m_dirty = FALSE; + + m_lineHeight = LINEHEIGHT; + m_indent = MININDENT; // min. indent + m_linespacing = 4; + + m_hilightBrush = new wxBrush + ( + wxSystemSettings::GetSystemColour + ( + wxSYS_COLOUR_HIGHLIGHT + ), + wxSOLID + ); + + m_hilightUnfocusedBrush = new wxBrush + ( + wxSystemSettings::GetSystemColour + ( + wxSYS_COLOUR_BTNSHADOW + ), + wxSOLID + ); + + m_imageListNormal = m_imageListButtons = + m_imageListState = (wxImageList *) NULL; + m_ownsImageListNormal = m_ownsImageListButtons = + m_ownsImageListState = FALSE; + + m_dragCount = 0; + m_isDragging = FALSE; + m_dropTarget = m_oldSelection = (wxTreeListItem *)NULL; + + m_renameTimer = new wxTreeListRenameTimer( this ); + m_lastOnSame = FALSE; + + m_normalFont = wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ); + m_boldFont = wxFont( m_normalFont.GetPointSize(), + m_normalFont.GetFamily(), + m_normalFont.GetStyle(), + wxBOLD, + m_normalFont.GetUnderlined()); +} + + +static const int HEADER_HEIGHT = 23; + +bool wxTreeListMainWindow::Create(wxTreeListCtrl *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator &validator, + const wxString& name ) +{ +#ifdef __WXMAC__ + int major,minor; + wxGetOsVersion( &major, &minor ); + + if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS; + if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS; + style &= ~wxTR_LINES_AT_ROOT; + style |= wxTR_NO_LINES; + if (major < 10) + style |= wxTR_ROW_LINES; +#endif + + wxScrolledWindow::Create( parent, id, pos, size, + style|wxHSCROLL|wxVSCROLL, name ); + +#if wxUSE_VALIDATORS + SetValidator( validator ); +#endif + + SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) ); + +#ifdef __WXMSW__ + { + int i, j; + wxBitmap bmp(8, 8); + wxMemoryDC bdc; + bdc.SelectObject(bmp); + bdc.SetPen(*wxGREY_PEN); + bdc.DrawRectangle(-1, -1, 10, 10); + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + if (!((i + j) & 1)) { + bdc.DrawPoint(i, j); + } + } + } + + m_dottedPen = wxPen(bmp, 1); + } +#else + //m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86 + m_dottedPen = wxPen( wxT("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK! +#endif + + // ALB + m_owner = parent; + m_main_column = 0; + + return TRUE; +} + +wxTreeListMainWindow::~wxTreeListMainWindow() +{ + delete m_hilightBrush; + delete m_hilightUnfocusedBrush; + + DeleteAllItems(); + + delete m_renameTimer; + if (m_ownsImageListNormal) delete m_imageListNormal; + if (m_ownsImageListState) delete m_imageListState; + if (m_ownsImageListButtons) delete m_imageListButtons; +} + + + +//----------------------------------------------------------------------------- +// accessors +//----------------------------------------------------------------------------- + +inline +size_t wxTreeListMainWindow::GetCount() const +{ + return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount(); +} + +inline +void wxTreeListMainWindow::SetIndent(unsigned int indent) +{ + m_indent = indent; + m_dirty = TRUE; +} + +inline +void wxTreeListMainWindow::SetLineSpacing(unsigned int spacing) +{ + m_linespacing = spacing; + m_dirty = TRUE; + CalculateLineHeight(); +} + +inline +size_t wxTreeListMainWindow::GetChildrenCount(const wxTreeItemId& item, + bool recursively) +{ + wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") ); + + return ((wxTreeListItem*) item.m_pItem)->GetChildrenCount(recursively); +} + +void wxTreeListMainWindow::SetWindowStyle(const long styles) +{ + // right now, just sets the styles. Eventually, we may + // want to update the inherited styles, but right now + // none of the parents has updatable styles + m_windowStyle = styles; + m_dirty = TRUE; +} + +//----------------------------------------------------------------------------- +// functions to work with tree items +//----------------------------------------------------------------------------- + +inline +int wxTreeListMainWindow::GetItemImage(const wxTreeItemId& item, size_t column, + wxTreeItemIcon which) const +{ + wxCHECK_MSG( item.IsOk(), -1, wxT("invalid tree item") ); + + return ((wxTreeListItem*) item.m_pItem)->GetImage(column, which); +} + +inline +wxTreeItemData *wxTreeListMainWindow::GetItemData(const wxTreeItemId& item) + const +{ + wxCHECK_MSG( item.IsOk(), NULL, wxT("invalid tree item") ); + + return ((wxTreeListItem*) item.m_pItem)->GetData(); +} + +inline +bool wxTreeListMainWindow::GetItemBold(const wxTreeItemId& item) const +{ + wxCHECK_MSG(item.IsOk(), FALSE, wxT("invalid tree item")); + return ((wxTreeListItem *)item.m_pItem)->IsBold(); +} + +inline +wxColour wxTreeListMainWindow::GetItemTextColour(const wxTreeItemId& item) + const +{ + wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); + + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + return pItem->Attr().GetTextColour(); +} + +inline +wxColour wxTreeListMainWindow::GetItemBackgroundColour( + const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); + + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + return pItem->Attr().GetBackgroundColour(); +} + +inline +wxFont wxTreeListMainWindow::GetItemFont(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxNullFont, wxT("invalid tree item") ); + + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + return pItem->Attr().GetFont(); +} + + + +inline +void wxTreeListMainWindow::SetItemImage(const wxTreeItemId& item, + size_t column, + int image, wxTreeItemIcon which) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->SetImage(column, image, which); + + wxClientDC dc(this); + CalculateSize(pItem, dc); + RefreshLine(pItem); +} + +inline +void wxTreeListMainWindow::SetItemData(const wxTreeItemId& item, + wxTreeItemData *data) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + ((wxTreeListItem*) item.m_pItem)->SetData(data); +} + +inline +void wxTreeListMainWindow::SetItemHasChildren(const wxTreeItemId& item, + bool has) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->SetHasPlus(has); + RefreshLine(pItem); +} + +inline +void wxTreeListMainWindow::SetItemBold(const wxTreeItemId& item, bool bold) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + // avoid redrawing the tree if no real change + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + if ( pItem->IsBold() != bold ) + { + pItem->SetBold(bold); + RefreshLine(pItem); + } +} + +inline +void wxTreeListMainWindow::SetItemTextColour(const wxTreeItemId& item, + const wxColour& col) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->Attr().SetTextColour(col); + RefreshLine(pItem); +} + +inline +void wxTreeListMainWindow::SetItemBackgroundColour(const wxTreeItemId& item, + const wxColour& col) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->Attr().SetBackgroundColour(col); + RefreshLine(pItem); +} + +inline +void wxTreeListMainWindow::SetItemFont(const wxTreeItemId& item, + const wxFont& font) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->Attr().SetFont(font); + RefreshLine(pItem); +} + +inline +bool wxTreeListMainWindow::SetFont( const wxFont &font ) +{ + wxScrolledWindow::SetFont(font); + + m_normalFont = font ; + m_boldFont = wxFont( m_normalFont.GetPointSize(), + m_normalFont.GetFamily(), + m_normalFont.GetStyle(), + wxBOLD, + m_normalFont.GetUnderlined()); + + return TRUE; +} + + +// ---------------------------------------------------------------------------- +// item status inquiries +// ---------------------------------------------------------------------------- + +inline +bool wxTreeListMainWindow::IsVisible(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); + + // An item is only visible if it's not a descendant of a collapsed item + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + wxTreeListItem* parent = pItem->GetItemParent(); + while (parent) + { + if (!parent->IsExpanded()) + return FALSE; + parent = parent->GetItemParent(); + } + + int startX, startY; + GetViewStart(& startX, & startY); + + wxSize clientSize = GetClientSize(); + + wxRect rect; + if (!GetBoundingRect(item, rect)) + return FALSE; + if (rect.GetWidth() == 0 || rect.GetHeight() == 0) + return FALSE; + if (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) + return FALSE; + if (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x) + return FALSE; + + return TRUE; +} + +inline +bool wxTreeListMainWindow::ItemHasChildren(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); + + // consider that the item does have children if it has the "+" button: it + // might not have them (if it had never been expanded yet) but then it + // could have them as well and it's better to err on this side rather than + // disabling some operations which are restricted to the items with + // children for an item which does have them + return ((wxTreeListItem*) item.m_pItem)->HasPlus(); +} + +inline +bool wxTreeListMainWindow::IsExpanded(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); + + return ((wxTreeListItem*) item.m_pItem)->IsExpanded(); +} + +inline +bool wxTreeListMainWindow::IsSelected(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); + + return ((wxTreeListItem*) item.m_pItem)->IsSelected(); +} + +inline +bool wxTreeListMainWindow::IsBold(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); + + return ((wxTreeListItem*) item.m_pItem)->IsBold(); +} + +// ---------------------------------------------------------------------------- +// navigation +// ---------------------------------------------------------------------------- + +inline +wxTreeItemId wxTreeListMainWindow::GetItemParent(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + return ((wxTreeListItem*) item.m_pItem)->GetItemParent(); +} + +inline +wxTreeItemId wxTreeListMainWindow::GetFirstChild(const wxTreeItemId& item, + long& cookie) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + cookie = 0; + return GetNextChild(item, cookie); +} + +inline +wxTreeItemId wxTreeListMainWindow::GetNextChild(const wxTreeItemId& item, + long& cookie) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxArrayTreeListItems& children = ((wxTreeListItem*) + item.m_pItem)->GetChildren(); + if ( (size_t)cookie < children.Count() ) + { + return children.Item((size_t)cookie++); + } + else + { + // there are no more of them + return wxTreeItemId(); + } +} + +inline +wxTreeItemId wxTreeListMainWindow::GetLastChild(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren(); + return (children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last())); +} + +inline +wxTreeItemId wxTreeListMainWindow::GetNextSibling(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxTreeListItem *i = (wxTreeListItem*) item.m_pItem; + wxTreeListItem *parent = i->GetItemParent(); + if ( parent == NULL ) + { + // root item doesn't have any siblings + return wxTreeItemId(); + } + + wxArrayTreeListItems& siblings = parent->GetChildren(); + int index = siblings.Index(i); + wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? + + size_t n = (size_t)(index + 1); + return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]); +} + +inline +wxTreeItemId wxTreeListMainWindow::GetPrevSibling(const wxTreeItemId& item) + const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxTreeListItem *i = (wxTreeListItem*) item.m_pItem; + wxTreeListItem *parent = i->GetItemParent(); + if ( parent == NULL ) + { + // root item doesn't have any siblings + return wxTreeItemId(); + } + + wxArrayTreeListItems& siblings = parent->GetChildren(); + int index = siblings.Index(i); + wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? + + return index == 0 ? wxTreeItemId() + : wxTreeItemId(siblings[(size_t)(index - 1)]); +} + +// Only for internal use right now, but should probably be public +wxTreeItemId wxTreeListMainWindow::GetNext(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxTreeListItem *i = (wxTreeListItem*) item.m_pItem; + + // First see if there are any children. + wxArrayTreeListItems& children = i->GetChildren(); + if (children.GetCount() > 0) + { + return children.Item(0); + } + else + { + // Try a sibling of this or ancestor instead + wxTreeItemId p = item; + wxTreeItemId toFind; + do + { + toFind = GetNextSibling(p); + p = GetItemParent(p); + } while (p.IsOk() && !toFind.IsOk()); + return toFind; + } +} + +inline +wxTreeItemId wxTreeListMainWindow::GetFirstVisibleItem() const +{ + wxTreeItemId id = GetRootItem(); + if (!id.IsOk()) + return id; + + do + { + if (IsVisible(id)) + return id; + id = GetNext(id); + } while (id.IsOk()); + + return wxTreeItemId(); +} + +inline +wxTreeItemId wxTreeListMainWindow::GetNextVisible(const wxTreeItemId& item) + const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxTreeItemId id = item; + if (id.IsOk()) + { + while (id = GetNext(id), id.IsOk()) + { + if (IsVisible(id)) + return id; + } + } + return wxTreeItemId(); +} + +inline +wxTreeItemId wxTreeListMainWindow::GetPrevVisible(const wxTreeItemId& item) + const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxFAIL_MSG(wxT("not implemented")); + + return wxTreeItemId(); +} + +// ---------------------------------------------------------------------------- +// operations +// ---------------------------------------------------------------------------- + +wxTreeItemId wxTreeListMainWindow::DoInsertItem(const wxTreeItemId& parentId, + size_t previous, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) +{ + wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem; + if ( !parent ) + { + // should we give a warning here? + return AddRoot(text, image, selImage, data); + } + + m_dirty = TRUE; // do this first so stuff below doesn't cause flicker + + // ALB + wxArrayString arr; + arr.Alloc(GetColumnCount()); + for(size_t i = 0; i < GetColumnCount(); ++i) { + arr.Add(wxEmptyString); + } + arr[m_main_column] = text; + wxTreeListItem *item = + new wxTreeListItem( this, parent, arr, image, selImage, data ); + + if ( data != NULL ) + { + data->SetId((long)item); + } + + parent->Insert( item, previous ); + + return item; +} + +wxTreeItemId wxTreeListMainWindow::AddRoot(const wxString& text, + int image, int selImage, + wxTreeItemData *data) +{ + wxCHECK_MSG(!m_anchor, wxTreeItemId(), wxT("tree can have only one root")); + wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), wxT("Add column(s) before adding the root item")); + + m_dirty = TRUE; // do this first so stuff below doesn't cause flicker + + // ALB + wxArrayString arr; + arr.Alloc(GetColumnCount()); + for(size_t i = 0; i < GetColumnCount(); ++i) { + arr.Add(wxEmptyString); + } + arr[m_main_column] = text; + m_anchor = new wxTreeListItem( this, (wxTreeListItem *)NULL, arr, + image, selImage, data); +#if 0 + if (HasFlag(wxTR_HIDE_ROOT)) + { + // if root is hidden, make sure we can navigate + // into children + m_anchor->SetHasPlus(); + Expand(m_anchor); + } +#endif + if ( data != NULL ) + { + data->SetId((long)m_anchor); + } + + if (!HasFlag(wxTR_MULTIPLE)) + { + m_current = m_key_current = m_anchor; + m_current->SetHilight( TRUE ); + } + + return m_anchor; +} + +inline +wxTreeItemId wxTreeListMainWindow::PrependItem(const wxTreeItemId& parent, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) +{ + return DoInsertItem(parent, 0u, text, image, selImage, data); +} + +inline +wxTreeItemId wxTreeListMainWindow::InsertItem(const wxTreeItemId& parentId, + const wxTreeItemId& idPrevious, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) +{ + wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem; + if ( !parent ) + { + // should we give a warning here? + return AddRoot(text, image, selImage, data); + } + + int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem); + wxASSERT_MSG( index != wxNOT_FOUND, + wxT("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") ); + + return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data); +} + +inline +wxTreeItemId wxTreeListMainWindow::InsertItem(const wxTreeItemId& parentId, + size_t before, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) +{ + wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem; + if ( !parent ) + { + // should we give a warning here? + return AddRoot(text, image, selImage, data); + } + + return DoInsertItem(parentId, before, text, image, selImage, data); +} + +inline +wxTreeItemId wxTreeListMainWindow::AppendItem(const wxTreeItemId& parentId, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) +{ + wxTreeListItem *parent = (wxTreeListItem*) 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); +} + +void wxTreeListMainWindow::SendDeleteEvent(wxTreeListItem *item) +{ + wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, m_owner->GetId() ); + event.SetItem((long) item); + event.SetEventObject( /*this*/m_owner ); + m_owner->ProcessEvent( event ); +} + +inline +void wxTreeListMainWindow::DeleteChildren(const wxTreeItemId& itemId) +{ + m_dirty = TRUE; // do this first so stuff below doesn't cause flicker + + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + item->DeleteChildren(this); +} + +inline +void wxTreeListMainWindow::Delete(const wxTreeItemId& itemId) +{ + m_dirty = TRUE; // do this first so stuff below doesn't cause flicker + + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + + // don't stay with invalid m_key_current or we will crash in + // the next call to OnChar() + bool changeKeyCurrent = FALSE; + wxTreeListItem *itemKey = m_key_current; + while ( itemKey ) + { + if ( itemKey == item ) + { + // m_key_current is a descendant of the item being deleted + changeKeyCurrent = TRUE; + break; + } + itemKey = itemKey->GetItemParent(); + } + + wxTreeListItem *parent = item->GetItemParent(); + if ( parent ) + { + parent->GetChildren().Remove( item ); // remove by value + } + + if ( changeKeyCurrent ) + { + // may be NULL or not + m_key_current = parent; + } + + item->DeleteChildren(this); + SendDeleteEvent(item); + delete item; +} + +inline +void wxTreeListMainWindow::DeleteAllItems() +{ + if ( m_anchor ) + { + m_dirty = TRUE; + + m_anchor->DeleteChildren(this); + delete m_anchor; + + m_anchor = NULL; + } +} + +void wxTreeListMainWindow::Expand(const wxTreeItemId& itemId) +{ + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + + wxCHECK_RET( item, _T("invalid item in wxTreeListMainWindow::Expand") ); + + if ( !item->HasPlus() ) + return; + + if ( item->IsExpanded() ) + return; + + wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, m_owner->GetId() ); + event.SetItem( (long) item ); + event.SetEventObject( /*this*/m_owner ); + + if ( m_owner->ProcessEvent( event ) && !event.IsAllowed() ) + { + // cancelled by program + return; + } + + item->Expand(); + CalculatePositions(); + + RefreshSubtree(item); + + event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED); + ProcessEvent( event ); +} + +void wxTreeListMainWindow::ExpandAll(const wxTreeItemId& item) +{ + Expand(item); + if ( IsExpanded(item) ) + { + long cookie; + wxTreeItemId child = GetFirstChild(item, cookie); + while ( child.IsOk() ) + { + ExpandAll(child); + + child = GetNextChild(item, cookie); + } + } +} + +void wxTreeListMainWindow::Collapse(const wxTreeItemId& itemId) +{ + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + + if ( !item->IsExpanded() ) + return; + + wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, m_owner->GetId() ); + event.SetItem( (long) item ); + event.SetEventObject( /*this*/m_owner ); + if ( m_owner->ProcessEvent( event ) && !event.IsAllowed() ) + { + // cancelled by program + return; + } + + item->Collapse(); + +#if 0 // TODO why should items be collapsed recursively? + wxArrayTreeListItems& children = item->GetChildren(); + size_t count = children.Count(); + for ( size_t n = 0; n < count; n++ ) + { + Collapse(children[n]); + } +#endif + + CalculatePositions(); + + RefreshSubtree(item); + + event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED); + ProcessEvent( event ); +} + +void wxTreeListMainWindow::CollapseAndReset(const wxTreeItemId& item) +{ + Collapse(item); + DeleteChildren(item); +} + +void wxTreeListMainWindow::Toggle(const wxTreeItemId& itemId) +{ + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + + if (item->IsExpanded()) + Collapse(itemId); + else + Expand(itemId); +} + +void wxTreeListMainWindow::Unselect() +{ + if (m_current) + { + m_current->SetHilight( FALSE ); + RefreshLine( m_current ); + } +} + +void wxTreeListMainWindow::UnselectAllChildren(wxTreeListItem *item) +{ + if (item->IsSelected()) + { + item->SetHilight(FALSE); + RefreshLine(item); + } + + if (item->HasChildren()) + { + wxArrayTreeListItems& children = item->GetChildren(); + size_t count = children.Count(); + for ( size_t n = 0; n < count; ++n ) + { + UnselectAllChildren(children[n]); + } + } +} + +void wxTreeListMainWindow::UnselectAll() +{ + UnselectAllChildren((wxTreeListItem*) GetRootItem().m_pItem); +} + +// Recursive function ! +// To stop we must have crt_itemGetItemParent(); + + if (parent == NULL) // This is root item + return TagAllChildrenUntilLast(crt_item, last_item, select); + + wxArrayTreeListItems& children = parent->GetChildren(); + int index = children.Index(crt_item); + wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? + + size_t count = children.Count(); + for (size_t n=(size_t)(index+1); nSetHilight(select); + RefreshLine(crt_item); + + if (crt_item==last_item) + return TRUE; + + if (crt_item->HasChildren()) + { + wxArrayTreeListItems& children = crt_item->GetChildren(); + size_t count = children.Count(); + for ( size_t n = 0; n < count; ++n ) + { + if (TagAllChildrenUntilLast(children[n], last_item, select)) + return TRUE; + } + } + + return FALSE; +} + +void wxTreeListMainWindow::SelectItemRange(wxTreeListItem *item1, wxTreeListItem *item2) +{ + // item2 is not necessary after item1 + wxTreeListItem *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; + } + + bool select = m_current->IsSelected(); + + if ( TagAllChildrenUntilLast(first,last,select) ) + return; + + TagNextChildren(first,last,select); +} + +void wxTreeListMainWindow::SelectItem(const wxTreeItemId& itemId, + bool unselect_others, + bool extended_select) +{ + wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") ); + + bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE); + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + + //wxCHECK_RET( ( (!unselect_others) && is_single), + // wxT("this is a single selection tree") ); + + // to keep going anyhow !!! + if (is_single) + { + if (item->IsSelected()) + return; // nothing to do + unselect_others = TRUE; + extended_select = FALSE; + } + else if ( unselect_others && item->IsSelected() ) + { + // selection change if there is more than one item currently selected + wxArrayTreeItemIds selected_items; + if ( GetSelections(selected_items) == 1 ) + return; + } + + wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() ); + event.SetItem( (long) item ); + event.SetOldItem( (long) m_current ); + event.SetEventObject( /*this*/m_owner ); + // TODO : Here we don't send any selection mode yet ! + + if(m_owner->GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed()) + return; + + wxTreeItemId parent = GetItemParent( itemId ); + while (parent.IsOk()) + { + if (!IsExpanded(parent)) + Expand( parent ); + + parent = GetItemParent( parent ); + } + + EnsureVisible( itemId ); + + // ctrl press + if (unselect_others) + { + if (is_single) Unselect(); // to speed up thing + else UnselectAll(); + } + + // shift press + if (extended_select) + { + if ( !m_current ) + { + m_current = m_key_current = (wxTreeListItem*) GetRootItem().m_pItem; + } + + // don't change the mark (m_current) + SelectItemRange(m_current, item); + } + else + { + bool select=TRUE; // the default + + // Check if we need to toggle hilight (ctrl mode) + if (!unselect_others) + select=!item->IsSelected(); + + m_current = m_key_current = item; + m_current->SetHilight(select); + RefreshLine( m_current ); + } + + event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED); + GetEventHandler()->ProcessEvent( event ); +} + +void wxTreeListMainWindow::FillArray(wxTreeListItem *item, + wxArrayTreeItemIds &array) const +{ + if ( item->IsSelected() ) + array.Add(wxTreeItemId(item)); + + if ( item->HasChildren() ) + { + wxArrayTreeListItems& children = item->GetChildren(); + size_t count = children.GetCount(); + for ( size_t n = 0; n < count; ++n ) + FillArray(children[n], array); + } +} + +size_t wxTreeListMainWindow::GetSelections(wxArrayTreeItemIds &array) const +{ + array.Empty(); + wxTreeItemId idRoot = GetRootItem(); + if ( idRoot.IsOk() ) + { + FillArray((wxTreeListItem*) idRoot.m_pItem, array); + } + //else: the tree is empty, so no selections + + return array.Count(); +} + +void wxTreeListMainWindow::EnsureVisible(const wxTreeItemId& item) +{ + if (!item.IsOk()) return; + + wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem; + + // first expand all parent branches + wxTreeListItem *parent = gitem->GetItemParent(); + while ( parent ) + { + Expand(parent); + parent = parent->GetItemParent(); + } + + //if (parent) CalculatePositions(); + + ScrollTo(item); +} + +void wxTreeListMainWindow::ScrollTo(const wxTreeItemId &item) +{ + if (!item.IsOk()) return; + + // We have to call this here because the label in + // question might just have been added and no screen + // update taken place. + if (m_dirty) wxYieldIfNeeded(); + + wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem; + + // now scroll to the item + int item_y = gitem->GetY(); + + int start_x = 0; + int start_y = 0; + GetViewStart( &start_x, &start_y ); + start_y *= PIXELS_PER_UNIT; + + int client_h = 0; + int client_w = 0; + GetClientSize( &client_w, &client_h ); + + if (item_y < start_y+3) + { + // going down + int x = 0; + int y = 0; + m_anchor->GetSize( x, y, this ); + x = m_owner->GetHeaderWindow()->GetWidth(); //m_total_col_width; // ALB + y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + //x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + int x_pos = GetScrollPos( wxHORIZONTAL ); + // Item should appear at top + SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, item_y/PIXELS_PER_UNIT ); + } + else if (item_y+GetLineHeight(gitem) > start_y+client_h) + { + // going up + int x = 0; + int y = 0; + m_anchor->GetSize( x, y, this ); + y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + //x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + x = m_owner->GetHeaderWindow()->GetWidth(); //m_total_col_width; // ALB + item_y += PIXELS_PER_UNIT+2; + int x_pos = GetScrollPos( wxHORIZONTAL ); + // Item should appear at bottom + SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT ); + } +} + +// FIXME: tree sorting functions are not reentrant and not MT-safe! +static wxTreeListMainWindow *s_treeBeingSorted = NULL; + +static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1, + wxTreeListItem **item2) +{ + wxCHECK_MSG( s_treeBeingSorted, 0, wxT("bug in wxTreeListMainWindow::SortChildren()") ); + + return s_treeBeingSorted->OnCompareItems(*item1, *item2); +} + +int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2) +{ + // ALB: delegate to m_owner, to let the user overrride the comparison + //return wxStrcmp(GetItemText(item1), GetItemText(item2)); + return m_owner->OnCompareItems(item1, item2); +} + +void wxTreeListMainWindow::SortChildren(const wxTreeItemId& itemId) +{ + wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") ); + + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + + wxCHECK_RET( !s_treeBeingSorted, + wxT("wxTreeListMainWindow::SortChildren is not reentrant") ); + + wxArrayTreeListItems& children = item->GetChildren(); + if ( children.Count() > 1 ) + { + m_dirty = TRUE; + + s_treeBeingSorted = this; + children.Sort(tree_ctrl_compare_func); + s_treeBeingSorted = NULL; + } + //else: don't make the tree dirty as nothing changed +} + +inline +wxImageList *wxTreeListMainWindow::GetImageList() const +{ + return m_imageListNormal; +} + +inline +wxImageList *wxTreeListMainWindow::GetButtonsImageList() const +{ + return m_imageListButtons; +} + +inline +wxImageList *wxTreeListMainWindow::GetStateImageList() const +{ + return m_imageListState; +} + +void wxTreeListMainWindow::CalculateLineHeight() +{ + wxClientDC dc(this); + dc.SetFont( m_normalFont ); + m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing); + + if ( m_imageListNormal ) + { + // Calculate a m_lineHeight value from the normal Image sizes. + // May be toggle off. Then wxTreeListMainWindow will spread when + // necessary (which might look ugly). + int n = m_imageListNormal->GetImageCount(); + for (int i = 0; i < n ; i++) + { + int width = 0, height = 0; + m_imageListNormal->GetSize(i, width, height); + if (height > m_lineHeight) m_lineHeight = height + m_linespacing; + } + } + + if (m_imageListButtons) + { + // Calculate a m_lineHeight value from the Button image sizes. + // May be toggle off. Then wxTreeListMainWindow will spread when + // necessary (which might look ugly). + int n = m_imageListButtons->GetImageCount(); + for (int i = 0; i < n ; i++) + { + int width = 0, height = 0; + m_imageListButtons->GetSize(i, width, height); + if (height > m_lineHeight) m_lineHeight = height + m_linespacing; + } + } + +/*? FIXME: Don't get what this code is for... Adding a line space is already done!!! + if (m_lineHeight < 30) + m_lineHeight += 2; // at least 2 pixels + else + m_lineHeight += m_lineHeight/10; // otherwise 10% extra spacing +?*/ +} + +inline +void wxTreeListMainWindow::SetImageList(wxImageList *imageList) +{ + if (m_ownsImageListNormal) delete m_imageListNormal; + m_imageListNormal = imageList; + m_ownsImageListNormal = FALSE; + m_dirty = TRUE; + CalculateLineHeight(); +} + +inline +void wxTreeListMainWindow::SetStateImageList(wxImageList *imageList) +{ + if (m_ownsImageListState) delete m_imageListState; + m_imageListState = imageList; + m_ownsImageListState = FALSE; +} + +inline +void wxTreeListMainWindow::SetButtonsImageList(wxImageList *imageList) +{ + if (m_ownsImageListButtons) delete m_imageListButtons; + m_imageListButtons = imageList; + m_ownsImageListButtons = FALSE; + m_dirty = TRUE; + CalculateLineHeight(); +} + +inline +void wxTreeListMainWindow::AssignImageList(wxImageList *imageList) +{ + SetImageList(imageList); + m_ownsImageListNormal = TRUE; +} + +inline +void wxTreeListMainWindow::AssignStateImageList(wxImageList *imageList) +{ + SetStateImageList(imageList); + m_ownsImageListState = TRUE; +} + +inline +void wxTreeListMainWindow::AssignButtonsImageList(wxImageList *imageList) +{ + SetButtonsImageList(imageList); + m_ownsImageListButtons = TRUE; +} + +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +void wxTreeListMainWindow::AdjustMyScrollbars() +{ + if (m_anchor) + { + int x = 0, y = 0; + m_anchor->GetSize( x, y, this ); + y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + //x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + int x_pos = GetScrollPos( wxHORIZONTAL ); + int y_pos = GetScrollPos( wxVERTICAL ); + x = m_owner->GetHeaderWindow()->GetWidth() + 2; + if(x < GetClientSize().GetWidth()) x_pos = 0; + //m_total_col_width + 2; // ALB + SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, + y/PIXELS_PER_UNIT, x_pos, y_pos ); + } + else + { + SetScrollbars( 0, 0, 0, 0 ); + } +} + +int wxTreeListMainWindow::GetLineHeight(wxTreeListItem *item) const +{ + if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) + return item->GetHeight(); + else + return m_lineHeight; +} + +void wxTreeListMainWindow::PaintItem(wxTreeListItem *item, wxDC& dc) +{ + // TODO implement "state" icon on items + + wxTreeItemAttr *attr = item->GetAttributes(); + if ( attr && attr->HasFont() ) + dc.SetFont(attr->GetFont()); + else if (item->IsBold()) + dc.SetFont(m_boldFont); + + long text_w = 0, text_h = 0; + + dc.GetTextExtent( item->GetText(GetMainColumn()), &text_w, &text_h ); + + int total_h = GetLineHeight(item); + + if ( item->IsSelected() ) + { + dc.SetBrush(*(m_hasFocus ? m_hilightBrush : m_hilightUnfocusedBrush)); + int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0; + dc.DrawRectangle (0, item->GetY() + offset, + m_owner->GetHeaderWindow()->GetWidth(), total_h-offset); + } +#if 0 // this code is probably not needed + else + { + wxColour colBg; + if ( attr && attr->HasBackgroundColour() ) + colBg = attr->GetBackgroundColour(); + else + colBg = m_backgroundColour; + dc.SetBrush(wxBrush(colBg, wxTRANSPARENT)); + } +#endif + + dc.SetBackgroundMode(wxTRANSPARENT); + int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0; + int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0; + int x_colstart = 0; + for ( size_t i = 0; i < GetColumnCount(); ++i ) { + if (!m_owner->GetHeaderWindow()->GetColumnShown(i)) continue; + int colwidth = m_owner->GetHeaderWindow()->GetColumnWidth(i); + int image; + int image_x = x_colstart + MARGIN; + int image_w = 0; + if(i == GetMainColumn()) { + image = item->GetCurrentImage(); + image_x = item->GetX() - m_imgWidth2; + image_w = m_imgWidth + MARGIN; + } + else + { + image = item->GetImage(i); + if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN; + } + + // honor text alignment + wxString text = item->GetText(i); + switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) { + case wxTL_ALIGN_LEFT: + // already left aligned + break; + case wxTL_ALIGN_RIGHT: + dc.GetTextExtent(text, &text_w, NULL); + image_x = x_colstart + colwidth - (image_w + text_w + MARGIN); + break; + case wxTL_ALIGN_CENTER: + dc.GetTextExtent(text, &text_w, NULL); + int w = colwidth - image_w - text_w; + image_x = x_colstart + (w > 0)? w: 0; + break; + } + int text_x = image_x + image_w; + + wxDCClipper clipper (dc, x_colstart, item->GetY(), colwidth, total_h); + if (image != NO_IMAGE) + { + int image_y = item->GetY() + img_extraH; + m_imageListNormal->Draw ( image, dc, image_x, image_y, + wxIMAGELIST_DRAW_TRANSPARENT ); + } + int text_y = item->GetY() + text_extraH; + dc.DrawText ( text, (wxCoord)text_x, (wxCoord)text_y ); + + x_colstart += colwidth; + } + + // restore normal font + dc.SetFont( m_normalFont ); +} + +// Now y stands for the top of the item, whereas it used to stand for middle ! +void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc, + int level, int &y, int x_colstart ) +{ + // Handle hide root (only level 0) + if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) { + // always expand hidden root + wxArrayTreeListItems& children = item->GetChildren(); + int n; + for (n = 0; n < (int)children.Count(); n++) { + PaintLevel (children[n], dc, 1, y, x_colstart); + } + // end after expanding root + return; + } + + // calculate position of vertical lines + int x = x_colstart + MARGIN; // start of column + if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root + if (HasButtons()) x += m_btnWidth2; // space for buttons etc. + if (!HasFlag(wxTR_HIDE_ROOT)) x += m_indent; // indent root as well + x += m_indent * level; // indent according to level + + // handle column text + item->SetX (x); + item->SetY (y); + + int h = GetLineHeight(item); + int y_top = y; + int y_mid = y_top + (h/2); + y += h; + + int exposed_x = dc.LogicalToDeviceX(0); + int exposed_y = dc.LogicalToDeviceY(y_top); + + if (IsExposed(exposed_x, exposed_y, 10000, h)) // 10000 = very much + { + if (HasFlag(wxTR_ROW_LINES)) + { + //dc.DestroyClippingRegion(); + int total_width = m_owner->GetHeaderWindow()->GetWidth(); + // if the background colour is white, choose a + // contrasting color for the lines + dc.SetPen (*((GetBackgroundColour() == *wxWHITE)? + wxMEDIUM_GREY_PEN : wxWHITE_PEN)); + dc.DrawLine(0, y_top, total_width, y_top); + dc.DrawLine(0, y, total_width, y); + } + + // restore DC objects + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(m_dottedPen); + dc.SetTextForeground(*wxBLACK); + + if (((level == 0) || ((level == 1) && HasFlag(wxTR_HIDE_ROOT))) && + HasFlag(wxTR_LINES_AT_ROOT) && !HasFlag(wxTR_NO_LINES)) { + int rootPos = x_colstart + MARGIN; + dc.DrawLine (rootPos, y_mid, rootPos+LINEATROOT, y_mid); + } + + size_t clip_width = m_owner->GetHeaderWindow()-> + GetColumn(m_main_column).GetWidth(); + //m_columns[m_main_column].GetWidth(); + + if (item->HasPlus() && HasButtons()) // should the item show a button? + { + if (!HasFlag(wxTR_NO_LINES)) { + int lineOffset = m_indent - m_btnWidth2; + dc.DrawLine(x-lineOffset, y_mid, x-m_imgWidth2, y_mid); + } + + // clip to the column width + wxDCClipper clipper(dc, x_colstart, y_top, clip_width, 10000); + + if (m_imageListButtons != NULL) + { + // draw the image button here + int image = wxTreeItemIcon_Normal; + if (item->IsExpanded()) image = wxTreeItemIcon_Expanded; + if (item->IsSelected()) + image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal; + int xx = x + m_btnWidth2; + int yy = y_mid - m_btnHeight2; + dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight); + m_imageListButtons->Draw(image, dc, xx, yy, + wxIMAGELIST_DRAW_TRANSPARENT); + dc.DestroyClippingRegion(); + } + else if (HasFlag(wxTR_TWIST_BUTTONS)) + { + // draw the twisty button here + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*m_hilightBrush); + + wxPoint button[3]; + + if (item->IsExpanded()) + { + button[0].x = (x-m_indent) - m_btnWidth2; + button[0].y = y_mid - (m_btnHeight/3-1); + button[1].x = button[0].x + m_btnWidth; + button[1].y = button[0].y; + button[2].x = x; + button[2].y = y_mid + (m_btnHeight/3); + } + else + { + button[0].x = (x-m_indent) - (m_btnWidth/3-1); + button[0].y = y_mid-m_btnHeight2; + button[1].x = button[0].x; + button[1].y = button[0].y + m_btnHeight; + button[2].x = button[0].x + (m_btnWidth/3); + button[2].y = y_mid; + } + dc.DrawPolygon(3, button); + + dc.SetPen(m_dottedPen); + } + else // if (HasFlag(wxTR_HAS_BUTTONS)) + { + // draw the plus sign here + dc.SetPen(*wxGREY_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + int xpos = x - m_indent; + dc.DrawRectangle (xpos-m_btnWidth2, y_mid-m_btnHeight2, + m_btnWidth, m_btnHeight); + dc.SetPen(*wxBLACK_PEN); + dc.DrawLine (xpos-(m_btnWidth2-3), y_mid, + xpos+(m_btnWidth2-2), y_mid); + if (!item->IsExpanded()) + dc.DrawLine (xpos, y_mid-(m_btnHeight2-2), + xpos, y_mid+(m_btnHeight2-1)); + dc.SetPen(m_dottedPen); + } + } + else if (!HasFlag(wxTR_NO_LINES)) // no button; maybe a line? + { + // clip to the column width + wxDCClipper clipper(dc, x_colstart, y_top, clip_width, 10000); + + // draw the horizontal line here + if (!(level == 0) && !((level == 1) && HasFlag(wxTR_HIDE_ROOT))) { + dc.DrawLine(x-m_indent, y_mid, x-m_imgWidth2, y_mid); + } + } + + wxPen *pen = +#ifndef __WXMAC__ + // don't draw rect outline if we already have the + // background color under Mac + (item->IsSelected() && m_hasFocus) ? wxBLACK_PEN : +#endif // !__WXMAC__ + wxTRANSPARENT_PEN; + + wxColour colText; + if ( item->IsSelected() ) + { + colText = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + } + else + { + wxTreeItemAttr *attr = item->GetAttributes(); + if (attr && attr->HasTextColour()) + colText = attr->GetTextColour(); + else + //colText = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT); + colText = GetForegroundColour(); + } + + // prepare to draw + dc.SetTextForeground(colText); + dc.SetPen(*pen); + + // draw + PaintItem(item, dc); + } + + // restore DC objects + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(m_dottedPen); + dc.SetTextForeground(*wxBLACK); + + if (item->IsExpanded()) + { + wxArrayTreeListItems& children = item->GetChildren(); + + // clip to the column width + size_t clip_width = m_owner->GetHeaderWindow()-> + GetColumn(m_main_column).GetWidth(); + wxDCClipper clipper(dc, x_colstart, y_top, clip_width, 10000); + + // process lower levels + int oldY = y_mid + m_imgHeight2; + int y2; + int n; + for (n = 0; n < (int)children.Count(); n++) { + + if (!HasFlag(wxTR_NO_LINES)) + { + // draw line down to last child + if (children[n]->HasPlus() && HasButtons()) { + y2 = y + h/2 - m_btnHeight2; + dc.DrawLine(x, oldY, x, y2); + oldY = y2 + m_btnHeight; + }else{ + y2 = y + h/2; + dc.DrawLine(x, oldY, x, y2); + oldY = y2; + } + } + + PaintLevel (children[n], dc, level+1, y, x_colstart); + } + } +} + +void wxTreeListMainWindow::DrawDropEffect(wxTreeListItem *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 wxTreeListMainWindow::DrawBorder(const wxTreeItemId &item) +{ + wxCHECK_RET( item.IsOk(), _T("invalid item in wxTreeListMainWindow::DrawLine") ); + + wxTreeListItem *i = (wxTreeListItem*) 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 wxTreeListMainWindow::DrawLine(const wxTreeItemId &item, bool below) +{ + wxCHECK_RET( item.IsOk(), _T("invalid item in wxTreeListMainWindow::DrawLine") ); + + wxTreeListItem *i = (wxTreeListItem*) item.m_pItem; + + wxClientDC dc(this); + PrepareDC( dc ); + dc.SetLogicalFunction(wxINVERT); + + int x = i->GetX(), + y = i->GetY(); + if ( below ) + { + y += GetLineHeight(i) - 1; + } + + dc.DrawLine( x, y, x + i->GetWidth(), y); +} + +// ---------------------------------------------------------------------------- +// wxWindows callbacks +// ---------------------------------------------------------------------------- + +void wxTreeListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) +{ + wxPaintDC dc(this); + + PrepareDC( dc ); + + if(!GetColumnCount()) return; // ALB + + if ( !m_anchor) + return; + + // calculate button size + m_btnWidth = 0, m_btnWidth2 = 0; + m_btnHeight = 0, m_btnHeight2 = 0; + if (m_imageListButtons) { + m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight); + }else if (HasButtons()) { + m_btnWidth = BTNWIDTH; + m_btnHeight = BTNHEIGHT; + } + m_btnWidth2 = m_btnWidth/2; + m_btnHeight2 = m_btnHeight/2; + + // calculate image size + m_imgWidth = 0, m_imgWidth2 = 0; + m_imgHeight = 0, m_imgHeight2 = 0; + if (m_imageListNormal) { + m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight); + m_imgWidth += 4; //? ToDo: Why + 4? + } + m_imgWidth2 = m_imgWidth/2; + m_imgHeight2 = m_imgHeight/2; + + // calculate indent size + int btnIndent = HasButtons()? m_btnWidth + LINEATROOT: 0; + m_indent = wxMax (MININDENT, wxMax (m_imgWidth, btnIndent)) + MARGIN; + + // set default values + dc.SetFont( m_normalFont ); + dc.SetPen( m_dottedPen ); + + // this is now done dynamically + //if(GetImageList() == NULL) + // m_lineHeight = (int)(dc.GetCharHeight() + 4); + + // calculate column start and paint + int x_colstart = 0; + int i = 0; + for (i = 0; i < (int)GetMainColumn(); ++i) { + if (!m_owner->GetHeaderWindow()->GetColumnShown(i)) continue; + x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth (i); + } + int y = 0; + PaintLevel ( m_anchor, dc, 0, y, x_colstart ); +} + +void wxTreeListMainWindow::OnSetFocus( wxFocusEvent &event ) +{ + m_hasFocus = TRUE; + + RefreshSelected(); + + event.Skip(); +} + +void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event ) +{ + m_hasFocus = FALSE; + + RefreshSelected(); + + event.Skip(); +} + +void wxTreeListMainWindow::OnChar( wxKeyEvent &event ) +{ + wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, m_owner->GetId() ); + te.SetKeyEvent( event ); + te.SetEventObject( /*this*/m_owner ); + if ( m_owner->GetEventHandler()->ProcessEvent( te ) ) + { + // intercepted by the user code + return; + } + + if ( (m_current == 0) || (m_key_current == 0) ) + { + event.Skip(); + return; + } + + // 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 (not on Win32) + // - : Collaspe (not on Win32) + // * : Expand all/Collapse all + // ' ' | return : activate + // up : go up (not last children!) + // down : go down + // left : go to parent (or collapse on Win32) + // right : open if parent and go next (or expand on Win32) + // home : go to root + // end : go to last item without opening parents + switch (event.KeyCode()) + { +#ifndef __WXMSW__ // mimic the standard win32 tree ctrl + case '+': + case WXK_ADD: + if (m_current->HasPlus() && !IsExpanded(m_current)) + { + Expand(m_current); + } + break; +#endif // __WXMSW__ + + case '*': + case WXK_MULTIPLY: + if ( !IsExpanded(m_current) ) + { + // expand all + ExpandAll(m_current); + break; + } + //else: fall through to Collapse() it + +#ifndef __WXMSW__ // mimic the standard wxTreeCtrl behaviour + case '-': + case WXK_SUBTRACT: + if (IsExpanded(m_current)) + { + Collapse(m_current); + } + break; +#endif // __WXMSW__ + + case ' ': + case WXK_RETURN: + { + wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, + m_owner->GetId() ); + event.SetItem( (long) m_current); + event.SetEventObject( /*this*/m_owner ); + m_owner->GetEventHandler()->ProcessEvent( event ); + } + break; + + // up goes to the previous sibling or to the last + // of its children if it's expanded + case WXK_UP: + { + wxTreeItemId prev = GetPrevSibling( m_key_current ); + if (!prev) + { + prev = GetItemParent( m_key_current ); + if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) + { + break; // don't go to root if it is hidden + } + if (prev) + { + long cookie = 0; + wxTreeItemId current = m_key_current; + // TODO: Huh? If we get here, we'd better be the first child of our parent. How else could it be? + if (current == GetFirstChild( prev, cookie )) + { + // otherwise we return to where we came from + SelectItem( prev, unselect_others, extended_select ); + m_key_current= (wxTreeListItem*) prev.m_pItem; + EnsureVisible( prev ); + break; + } + } + } + if (prev) + { + while ( IsExpanded(prev) && HasChildren(prev) ) + { + wxTreeItemId child = GetLastChild(prev); + if ( child ) + { + prev = child; + } + } + + SelectItem( prev, unselect_others, extended_select ); + m_key_current=(wxTreeListItem*) prev.m_pItem; + EnsureVisible( prev ); + } + } + break; + + // left arrow goes to the parent + case WXK_LEFT: +#if defined(__WXMSW__) // mimic the standard win32 tree ctrl + if (IsExpanded(m_current)) + { + Collapse(m_current); + } + else +#endif // __WXMSW__ + { + wxTreeItemId prev = GetItemParent( m_current ); + if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) + { + // don't go to root if it is hidden + prev = GetPrevSibling( m_current ); + } + if (prev) + { + EnsureVisible( prev ); + SelectItem( prev, unselect_others, extended_select ); + } + } + break; + + case WXK_RIGHT: +#if defined(__WXMSW__) // mimic the standard win32 tree ctrl + if (m_current->HasPlus() && !IsExpanded(m_current)) + { + Expand(m_current); + break; + } +#endif // __WXMSW__ + + // this works the same as the down arrow except that we + // also expand the item if it wasn't expanded yet + Expand(m_current); + // fall through + + case WXK_DOWN: + { + if (IsExpanded(m_key_current) && HasChildren(m_key_current)) + { + long cookie = 0; + wxTreeItemId child = GetFirstChild( m_key_current, cookie ); + SelectItem( child, unselect_others, extended_select ); + m_key_current=(wxTreeListItem*) child.m_pItem; + EnsureVisible( child ); + } + else + { + wxTreeItemId next = GetNextSibling( m_key_current ); + if (!next) + { + wxTreeItemId current = m_key_current; + while (current && !next) + { + current = GetItemParent( current ); + if (current) next = GetNextSibling( current ); + } + } + if (next) + { + SelectItem( next, unselect_others, extended_select ); + m_key_current=(wxTreeListItem*) next.m_pItem; + EnsureVisible( next ); + } + } + } + break; + + // selects the last visible tree item + case WXK_END: + { + wxTreeItemId last = GetRootItem(); + + while ( last.IsOk() && IsExpanded(last) ) + { + wxTreeItemId lastChild = GetLastChild(last); + + // it may happen if the item was expanded but then all of + // its children have been deleted - so IsExpanded() returned + // TRUE, but GetLastChild() returned invalid item + if ( !lastChild ) + break; + + last = lastChild; + } + + if ( last.IsOk() ) + { + EnsureVisible( last ); + SelectItem( last, unselect_others, extended_select ); + } + } + break; + + // selects the root item + case WXK_HOME: + { + wxTreeItemId prev = GetRootItem(); + if (!prev) break; + if (HasFlag(wxTR_HIDE_ROOT)) + { + long dummy; + prev = GetFirstChild(prev, dummy); + if (!prev) break; + } + EnsureVisible( prev ); + SelectItem( prev, unselect_others, extended_select ); + } + break; + + default: + event.Skip(); + } +} + +wxTreeItemId wxTreeListMainWindow::HitTest(const wxPoint& point, int& flags, + int& column) +{ + // JACS: removed wxYieldIfNeeded() because it can cause the window + // to be deleted from under us if a close window event is pending + + int w, h; + GetSize(&w, &h); + flags=0; + column = -1; + if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT; + if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT; + if (point.y<0) flags |= wxTREE_HITTEST_ABOVE; + if (point.y>h) flags |= wxTREE_HITTEST_BELOW; + if (flags) return wxTreeItemId(); + + if (m_anchor == NULL) + { + flags = wxTREE_HITTEST_NOWHERE; + return wxTreeItemId(); + } + + wxClientDC dc(this); + PrepareDC(dc); + wxCoord x = dc.DeviceToLogicalX( point.x ); + wxCoord y = dc.DeviceToLogicalY( point.y ); + wxTreeListItem *hit = m_anchor->HitTest(wxPoint(x, y), this, flags, + column, 0); + if (hit == NULL) + { + flags = wxTREE_HITTEST_NOWHERE; + return wxTreeItemId(); + } + return hit; +} + +// get the bounding rectangle of the item (or of its label only) +bool wxTreeListMainWindow::GetBoundingRect(const wxTreeItemId& item, + wxRect& rect, + bool WXUNUSED(textOnly)) const +{ + wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") ); + + wxTreeListItem *i = (wxTreeListItem*) item.m_pItem; + + int startX, startY; + GetViewStart(& startX, & startY); + + rect.x = i->GetX() - startX*PIXELS_PER_UNIT; + rect.y = i->GetY() - startY*PIXELS_PER_UNIT; + rect.width = i->GetWidth(); + //rect.height = i->GetHeight(); + rect.height = GetLineHeight(i); + + return TRUE; +} + +/* **** */ + +void wxTreeListMainWindow::Edit( const wxTreeItemId& item ) +{ + if (!item.IsOk()) return; + + m_currentEdit = (wxTreeListItem*) item.m_pItem; + + wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, m_owner->GetId() ); + te.SetItem( (long) m_currentEdit); + te.SetEventObject( /*this*/m_owner ); + m_owner->GetEventHandler()->ProcessEvent( te ); + + if (!te.IsAllowed()) return; + + // We have to call this here because the label in + // question might just have been added and no screen + // update taken place. + if (m_dirty) wxYieldIfNeeded(); + + wxString s = m_currentEdit->GetText(/*ALB*/m_main_column); + int x = m_currentEdit->GetX(); + int y = m_currentEdit->GetY(); + int w = m_currentEdit->GetWidth(); + int h = m_currentEdit->GetHeight(); + + int image = m_currentEdit->GetCurrentImage(); + x += m_imgWidth; + w -= m_imgWidth + 4; // I don't know why +4 is needed + + wxClientDC dc(this); + PrepareDC( dc ); + x = dc.LogicalToDeviceX( x ); + y = dc.LogicalToDeviceY( y ); + + wxTreeListTextCtrl *text = new wxTreeListTextCtrl(this, -1, + &m_renameAccept, + &m_renameRes, + this, + s, + wxPoint(x-4,y-4), + wxSize(w+11,h+8)); + text->SetFocus(); +} + +void wxTreeListMainWindow::OnRenameTimer() +{ + Edit( m_current ); +} + +void wxTreeListMainWindow::OnRenameAccept() +{ + // TODO if the validator fails this causes a crash + wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, m_owner->GetId() ); + le.SetItem( (long) m_currentEdit ); + le.SetEventObject( /*this*/m_owner ); + le.SetLabel( m_renameRes ); + m_owner->GetEventHandler()->ProcessEvent( le ); + + if (!le.IsAllowed()) return; + + SetItemText( m_currentEdit, m_renameRes ); +} + +void wxTreeListMainWindow::OnMouse( wxMouseEvent &event ) +{ + 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.LeftDown() || + event.LeftUp() || + event.RightDown() || + event.LeftDClick() || + event.Dragging() || + ((event.Moving() || event.RightUp()) && m_isDragging)) ) + { + event.Skip(); + return; + } + + if ( event.LeftDown() ) + SetFocus(); + + wxClientDC dc(this); + PrepareDC(dc); + wxCoord x = dc.DeviceToLogicalX( event.GetX() ); + wxCoord y = dc.DeviceToLogicalY( event.GetY() ); + + int flags = 0; + wxTreeListItem *item = m_anchor->HitTest(wxPoint(x,y), this, flags, 0); + + if ( event.Dragging() && !m_isDragging ) + { + if (m_dragCount == 0) + m_dragStart = wxPoint(x,y); + + m_dragCount++; + + if (m_dragCount != 3) + { + // wait until user drags a bit further... + return; + } + + wxEventType command = event.RightIsDown() + ? wxEVT_COMMAND_TREE_BEGIN_RDRAG + : wxEVT_COMMAND_TREE_BEGIN_DRAG; + + wxTreeEvent nevent( command,/*ALB*/ m_owner->GetId() ); + nevent.SetItem( (long) m_current); + nevent.SetEventObject(/*this*/m_owner); // ALB + + // by default the dragging is not supported, the user code must + // explicitly allow the event for it to take place + nevent.Veto(); + + if ( m_owner->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 = (wxTreeListItem*) GetSelection().m_pItem; + + if ( m_oldSelection ) + { + m_oldSelection->SetHilight(FALSE); + RefreshLine(m_oldSelection); + } + } + + 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); + + wxYieldIfNeeded(); + } + } + else if ( (event.LeftUp() || event.RightUp()) && m_isDragging ) + { + // erase the highlighting + DrawDropEffect(m_dropTarget); + + if ( m_oldSelection ) + { + m_oldSelection->SetHilight(TRUE); + RefreshLine(m_oldSelection); + m_oldSelection = (wxTreeListItem *)NULL; + } + + // generate the drag end event + wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG,/*ALB*/m_owner->GetId()); + + event.SetItem( (long) item ); + event.SetPoint( wxPoint(x, y) ); + event.SetEventObject(/*this*/m_owner); + + (void)m_owner->GetEventHandler()->ProcessEvent(event); + + m_isDragging = FALSE; + m_dropTarget = (wxTreeListItem *)NULL; + + ReleaseMouse(); + + SetCursor(m_oldCursor); + + wxYieldIfNeeded(); + } + else + { + // 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() ) + { + SetFocus(); + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, + m_owner->GetId()); + nevent.SetItem( (long) item ); + int nx, ny; + CalcScrolledPosition(x, y, &nx, &ny); + nevent.SetPoint( wxPoint(nx, ny)); + nevent.SetEventObject(/*this*/m_owner); + m_owner->GetEventHandler()->ProcessEvent(nevent); + } + else if ( event.LeftUp() ) + { + if ( m_lastOnSame ) + { + if ( ( item == m_current ) && + ( flags & wxTREE_HITTEST_ONITEMLABEL ) && + HasFlag(wxTR_EDIT_LABELS ) ) + { + if ( m_renameTimer->IsRunning() ) + m_renameTimer->Stop(); + + m_renameTimer->Start( 100, TRUE ); + } + + m_lastOnSame = FALSE; + } + } + else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick() + { + if ( event.LeftDown() ) + { + SetFocus(); + m_lastOnSame = item == m_current; + } + + if ((flags & wxTREE_HITTEST_ONITEMBUTTON) || + ((flags & wxTREE_HITTEST_ONITEMICON)) && + !HasButtons() && item->HasPlus()) + { + // only toggle the item for a single click, double click on + // the button doesn't do anything (it toggles the item twice) + if ( event.LeftDown() ) + { + Toggle( item ); + } + + // don't select the item if the button was clicked + return; + } + + // 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); + + SelectItem (item, unselect_others, extended_select); + + // For some reason, Windows isn't recognizing a left double-click, + // so we need to simulate it here. Allow 200 milliseconds for now. + if ( event.LeftDClick() ) + { + // double clicking should not start editing the item label + m_renameTimer->Stop(); + m_lastOnSame = FALSE; + + // send activate event first + wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, + m_owner->GetId() ); + nevent.SetItem( (long) item ); + int nx, ny; + CalcScrolledPosition(x, y, &nx, &ny); + nevent.SetPoint( wxPoint(nx, ny) ); + nevent.SetEventObject( /*this*/m_owner ); + if ( !m_owner->GetEventHandler()->ProcessEvent( nevent ) ) + { + // if the user code didn't process the activate event, + // handle it ourselves by toggling the item when it is + // double clicked + if ( item->HasPlus() ) + { + Toggle(item); + } + } + } + } + } +} + +void wxTreeListMainWindow::OnIdle( wxIdleEvent &WXUNUSED(event) ) +{ + /* after all changes have been done to the tree control, + * we actually redraw the tree when everything is over */ + + if (!m_dirty) return; + + m_dirty = FALSE; + + CalculatePositions(); + Refresh(); + AdjustMyScrollbars(); +} + +void wxTreeListMainWindow::OnSize(wxSizeEvent& WXUNUSED(event)) +{ +// int w, h; +// GetClientSize(&w, &h); +// m_header_win->SetSize(0, 0, w, HEADER_HEIGHT); +} + +void wxTreeListMainWindow::OnScroll(wxScrollWinEvent& event) +{ + // FIXME +#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) + wxScrolledWindow::OnScroll(event); +#else + HandleOnScroll( event ); +#endif + + if(event.GetOrientation() == wxHORIZONTAL) + { + m_owner->GetHeaderWindow()->Refresh(); +#ifdef __WXMAC__ + m_owner->GetHeaderWindow()->MacUpdateImmediately(); +#endif + } +} + + +void wxTreeListMainWindow::CalculateSize( wxTreeListItem *item, wxDC &dc ) +{ + wxCoord text_w = 0; + wxCoord text_h = 0; + + if (item->IsBold()) + dc.SetFont(m_boldFont); + + dc.GetTextExtent( item->GetText(/*ALB*/m_main_column), &text_w, &text_h ); + text_h+=2; + + // restore normal font + dc.SetFont( m_normalFont ); + + int image = item->GetCurrentImage(); + int total_h = (m_imgHeight > text_h) ? m_imgHeight : text_h; + + item->SetHeight(total_h); + if (total_h>m_lineHeight) + m_lineHeight=total_h; + + item->SetWidth(m_imgWidth + text_w+2); +} + +// ----------------------------------------------------------------------------- +// for developper : y is now the top of the level +// not the middle of it ! +void wxTreeListMainWindow::CalculateLevel( wxTreeListItem *item, wxDC &dc, + int level, int &y, int x_colstart ) +{ + // calculate position of vertical lines + int x = x_colstart + MARGIN; // start of column + if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root + if (HasButtons()) x += m_btnWidth2; // space for buttons etc. + if (!HasFlag(wxTR_HIDE_ROOT)) x += m_indent; // indent root as well + x += m_indent * level; // indent according to level + + // a hidden root is not evaluated, but its children are always + if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse; + + CalculateSize( item, dc ); + + // set its position + item->SetX (x); + item->SetY (y); + y += GetLineHeight(item); + + // we don't need to calculate collapsed branches + if ( !item->IsExpanded() ) return; + +Recurse: + wxArrayTreeListItems& children = item->GetChildren(); + size_t n, count = children.Count(); + ++level; + for (n = 0; n < count; ++n ) + CalculateLevel( children[n], dc, level, y, x_colstart ); // recurse +} + +void wxTreeListMainWindow::CalculatePositions() +{ + if ( !m_anchor ) return; + + wxClientDC dc(this); + PrepareDC( dc ); + + dc.SetFont( m_normalFont ); + + dc.SetPen( m_dottedPen ); + //if(GetImageList() == NULL) + // m_lineHeight = (int)(dc.GetCharHeight() + 4); + + int y = 2; + int x_colstart = 0; + for(size_t i = 0; i < GetMainColumn(); ++i) { + if (!m_owner->GetHeaderWindow()->GetColumnShown(i)) continue; + x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i); + } + CalculateLevel( m_anchor, dc, 0, y, x_colstart ); // start recursion +} + +void wxTreeListMainWindow::RefreshSubtree(wxTreeListItem *item) +{ + if (m_dirty) return; + + wxClientDC dc(this); + PrepareDC(dc); + + int cw = 0; + int ch = 0; + GetClientSize( &cw, &ch ); + + wxRect rect; + rect.x = dc.LogicalToDeviceX( 0 ); + rect.width = cw; + rect.y = dc.LogicalToDeviceY( item->GetY() - 2 ); + rect.height = ch; + + Refresh( TRUE, &rect ); + + AdjustMyScrollbars(); +} + +void wxTreeListMainWindow::RefreshLine( wxTreeListItem *item ) +{ + if (m_dirty) return; + + wxClientDC dc(this); + PrepareDC( dc ); + + int cw = 0; + int ch = 0; + GetClientSize( &cw, &ch ); + + wxRect rect; + rect.x = dc.LogicalToDeviceX( 0 ); + rect.y = dc.LogicalToDeviceY( item->GetY() ); + rect.width = cw; + rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6; + + Refresh( TRUE, &rect ); +} + +void wxTreeListMainWindow::RefreshSelected() +{ + // TODO: this is awfully inefficient, we should keep the list of all + // selected items internally, should be much faster + if ( m_anchor ) + RefreshSelectedUnder(m_anchor); +} + +void wxTreeListMainWindow::RefreshSelectedUnder(wxTreeListItem *item) +{ + if ( item->IsSelected() ) + RefreshLine(item); + + const wxArrayTreeListItems& children = item->GetChildren(); + size_t count = children.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + RefreshSelectedUnder(children[n]); + } +} + +// ---------------------------------------------------------------------------- +// changing colours: we need to refresh the tree control +// ---------------------------------------------------------------------------- + +bool wxTreeListMainWindow::SetBackgroundColour(const wxColour& colour) +{ + if ( !wxWindow::SetBackgroundColour(colour) ) + return FALSE; + + Refresh(); + + return TRUE; +} + +bool wxTreeListMainWindow::SetForegroundColour(const wxColour& colour) +{ + if ( !wxWindow::SetForegroundColour(colour) ) + return FALSE; + + Refresh(); + + return TRUE; +} + +//----------- ALB ------------- +inline +void wxTreeListMainWindow::SetItemText(const wxTreeItemId& item, size_t column, + const wxString& text) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxClientDC dc(this); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->SetText(column, text); + CalculateSize(pItem, dc); + RefreshLine(pItem); +} + +inline +wxString wxTreeListMainWindow::GetItemText(const wxTreeItemId& item, + size_t column) const +{ + wxCHECK_MSG( item.IsOk(), wxT(""), wxT("invalid tree item") ); + + return ((wxTreeListItem*) item.m_pItem)->GetText(column); +} + +//----------------------------- + +//----------------------------------------------------------------------------- +// wxTreeListCtrl +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl); + +BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl) + EVT_SIZE(wxTreeListCtrl::OnSize) +END_EVENT_TABLE(); + +bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, const wxValidator &validator, + const wxString& name) +{ + long main_style = style & ~(wxRAISED_BORDER|wxSUNKEN_BORDER + |wxSIMPLE_BORDER|wxNO_BORDER|wxDOUBLE_BORDER + |wxSTATIC_BORDER); + long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL); + + if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) { + return false; + } + m_main_win = new wxTreeListMainWindow(this, -1, wxPoint(0, 0), size, + main_style, validator); + m_header_win = new wxTreeListHeaderWindow(this, -1, m_main_win, + wxPoint(0, 0), wxDefaultSize, + wxTAB_TRAVERSAL); + return TRUE; +} + +void wxTreeListCtrl::OnSize(wxSizeEvent& event) +{ + int w, h; + GetClientSize(&w, &h); + if(m_header_win) + m_header_win->SetSize(0, 0, w, HEADER_HEIGHT); + if(m_main_win) + m_main_win->SetSize(0, HEADER_HEIGHT + 1, w, h - HEADER_HEIGHT - 1); +} + + +size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); } + +unsigned int wxTreeListCtrl::GetIndent() const +{ return m_main_win->GetIndent(); } + +void wxTreeListCtrl::SetIndent(unsigned int indent) +{ m_main_win->SetIndent(indent); } + +unsigned int wxTreeListCtrl::GetLineSpacing() const +{ return m_main_win->GetLineSpacing(); } + +void wxTreeListCtrl::SetLineSpacing(unsigned int spacing) +{ m_main_win->SetLineSpacing(spacing); } + +wxImageList* wxTreeListCtrl::GetImageList() const +{ return m_main_win->GetImageList(); } + +wxImageList* wxTreeListCtrl::GetStateImageList() const +{ return m_main_win->GetStateImageList(); } + +wxImageList* wxTreeListCtrl::GetButtonsImageList() const +{ return m_main_win->GetButtonsImageList(); } + +void wxTreeListCtrl::SetImageList(wxImageList* imageList) +{ m_main_win->SetImageList(imageList); } + +void wxTreeListCtrl::SetStateImageList(wxImageList* imageList) +{ m_main_win->SetStateImageList(imageList); } + +void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList) +{ m_main_win->SetButtonsImageList(imageList); } + +void wxTreeListCtrl::AssignImageList(wxImageList* imageList) +{ m_main_win->AssignImageList(imageList); } + +void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList) +{ m_main_win->AssignStateImageList(imageList); } + +void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList) +{ m_main_win->AssignButtonsImageList(imageList); } + +wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, size_t column) + const +{ return m_main_win->GetItemText(item, column); } + +int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, size_t column, + wxTreeItemIcon which) const +{ return m_main_win->GetItemImage(item, column, which); } + +wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const +{ return m_main_win->GetItemData(item); } + +bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const +{ return m_main_win->GetItemBold(item); } + +wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const +{ return m_main_win->GetItemTextColour(item); } + +wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item) + const +{ return m_main_win->GetItemBackgroundColour(item); } + +wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const +{ return m_main_win->GetItemFont(item); } + + +void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, size_t column, + const wxString& text) +{ m_main_win->SetItemText(item, column, text); } + +void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, + size_t column, + int image, + wxTreeItemIcon which) +{ m_main_win->SetItemImage(item, column, image, which); } + +void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, + wxTreeItemData* data) +{ m_main_win->SetItemData(item, data); } + +void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has) +{ m_main_win->SetItemHasChildren(item, has); } + +void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, bool bold) +{ m_main_win->SetItemBold(item, bold); } + +void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, + const wxColour& col) +{ m_main_win->SetItemTextColour(item, col); } + +void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, + const wxColour& col) +{ m_main_win->SetItemBackgroundColour(item, col); } + +void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, + const wxFont& font) +{ m_main_win->SetItemFont(item, font); } + +bool wxTreeListCtrl::SetFont(const wxFont& font) +{ + if(m_header_win) m_header_win->SetFont(font); + if(m_main_win) + return m_main_win->SetFont(font); + else return FALSE; +} + +void wxTreeListCtrl::SetWindowStyle(const long style) +{ + if(m_main_win) + m_main_win->SetWindowStyle(style); + // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win +} + +long wxTreeListCtrl::GetWindowStyle() const +{ + long style = m_windowStyle; + if(m_main_win) + style |= m_main_win->GetWindowStyle(); + return style; +} + +bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item) const +{ return m_main_win->IsVisible(item); } + +bool wxTreeListCtrl::ItemHasChildren(const wxTreeItemId& item) const +{ return m_main_win->ItemHasChildren(item); } + +bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const +{ return m_main_win->IsExpanded(item); } + +bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const +{ return m_main_win->IsSelected(item); } + +bool wxTreeListCtrl::IsBold(const wxTreeItemId& item) const +{ return m_main_win->IsBold(item); } + +size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec) +{ return m_main_win->GetChildrenCount(item, rec); } + +wxTreeItemId wxTreeListCtrl::GetRootItem() const +{ return m_main_win->GetRootItem(); } + +wxTreeItemId wxTreeListCtrl::GetSelection() const +{ return m_main_win->GetSelection(); } + +size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const +{ return m_main_win->GetSelections(arr); } + +wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const +{ return m_main_win->GetItemParent(item); } + +wxTreeItemId wxTreeListCtrl::GetFirstChild(const wxTreeItemId& item, + long& cookie) const +{ return m_main_win->GetFirstChild(item, cookie); } + +wxTreeItemId wxTreeListCtrl::GetNextChild(const wxTreeItemId& item, + long& cookie) const +{ return m_main_win->GetNextChild(item, cookie); } + +wxTreeItemId wxTreeListCtrl::GetLastChild(const wxTreeItemId& item) const +{ return m_main_win->GetLastChild(item); } + +wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const +{ return m_main_win->GetNextSibling(item); } + +wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const +{ return m_main_win->GetPrevSibling(item); } + +wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem() const +{ return m_main_win->GetFirstVisibleItem(); } + +wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item) const +{ return m_main_win->GetNextVisible(item); } + +wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item) const +{ return m_main_win->GetPrevVisible(item); } + +wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const +{ return m_main_win->GetNext(item); } + +wxTreeItemId wxTreeListCtrl::AddRoot(const wxString& text, int image, + int selectedImage, wxTreeItemData* data) +{ return m_main_win->AddRoot(text, image, selectedImage, data); } + +wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent, + const wxString& text, int image, + int selectedImage, + wxTreeItemData* data) +{ return m_main_win->PrependItem(parent, text, image, selectedImage, data); } + +wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent, + const wxTreeItemId& previous, + const wxString& text, int image, + int selectedImage, + wxTreeItemData* data) +{ + return m_main_win->InsertItem(parent, previous, text, image, + selectedImage, data); +} + +wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent, + size_t index, + const wxString& text, int image, + int selectedImage, + wxTreeItemData* data) +{ + return m_main_win->InsertItem(parent, index, text, image, + selectedImage, data); +} + +wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent, + const wxString& text, int image, + int selectedImage, + wxTreeItemData* data) +{ return m_main_win->AppendItem(parent, text, image, selectedImage, data); } + +void wxTreeListCtrl::Delete(const wxTreeItemId& item) +{ m_main_win->Delete(item); } + +void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item) +{ m_main_win->DeleteChildren(item); } + +void wxTreeListCtrl::DeleteAllItems() +{ m_main_win->DeleteAllItems(); } + +void wxTreeListCtrl::Expand(const wxTreeItemId& item) +{ m_main_win->Expand(item); } + +void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item) +{ m_main_win->ExpandAll(item); } + +void wxTreeListCtrl::Collapse(const wxTreeItemId& item) +{ m_main_win->Collapse(item); } + +void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item) +{ m_main_win->CollapseAndReset(item); } + +void wxTreeListCtrl::Toggle(const wxTreeItemId& item) +{ m_main_win->Toggle(item); } + +void wxTreeListCtrl::Unselect() +{ m_main_win->Unselect(); } + +void wxTreeListCtrl::UnselectAll() +{ m_main_win->UnselectAll(); } + +void wxTreeListCtrl::SelectItem(const wxTreeItemId& item, bool unselect_others, + bool extended_select) +{ m_main_win->SelectItem(item, unselect_others, extended_select); } + +void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item) +{ m_main_win->EnsureVisible(item); } + +void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item) +{ m_main_win->ScrollTo(item); } + +wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, + int& column) +{ + return m_main_win->HitTest(m_main_win->ScreenToClient(ClientToScreen(pos)), + flags, column); +} + +bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect, + bool textOnly) const +{ return m_main_win->GetBoundingRect(item, rect, textOnly); } + +void wxTreeListCtrl::Edit(const wxTreeItemId& item) +{ m_main_win->Edit(item); } + +int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2) +{ + // ALB: do the comparison here, and not delegate to m_main_win, in order + // to let the user override it + //return m_main_win->OnCompareItems(item1, item2); + return wxStrcmp(GetItemText(item1), GetItemText(item2)); +} + +void wxTreeListCtrl::SortChildren(const wxTreeItemId& item) +{ m_main_win->SortChildren(item); } + +bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour) +{ return m_main_win->SetBackgroundColour(colour); } + +bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour) +{ return m_main_win->SetForegroundColour(colour); } + +size_t wxTreeListCtrl::GetColumnCount() const +{ return m_main_win->GetColumnCount(); } + +void wxTreeListCtrl::SetColumnWidth(size_t column, size_t width) +{ m_header_win->SetColumnWidth(column, width); } + +int wxTreeListCtrl::GetColumnWidth(size_t column) const +{ return m_header_win->GetColumnWidth(column); } + +void wxTreeListCtrl::SetMainColumn(size_t column) +{ m_main_win->SetMainColumn(column); } + +size_t wxTreeListCtrl::GetMainColumn() const +{ return m_main_win->GetMainColumn(); } + +void wxTreeListCtrl::SetColumnText(size_t column, const wxString& text) +{ + m_header_win->SetColumnText(column, text); + m_header_win->Refresh(); +} + +wxString wxTreeListCtrl::GetColumnText(size_t column) const +{ return m_header_win->GetColumnText(column); } + +void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& col) +{ m_header_win->AddColumn(col); } + +void wxTreeListCtrl::InsertColumn(size_t before, + const wxTreeListColumnInfo& col) +{ m_header_win->InsertColumn(before, col); } + +void wxTreeListCtrl::RemoveColumn(size_t column) +{ m_header_win->RemoveColumn(column); } + +void wxTreeListCtrl::SetColumn(size_t column, const wxTreeListColumnInfo& col) +{ m_header_win->SetColumn(column, col); } + +const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(size_t column) const +{ return m_header_win->GetColumn(column); } + +wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(size_t column) +{ return m_header_win->GetColumn(column); } + +void wxTreeListCtrl::SetColumnImage(size_t column, int image) +{ + m_header_win->SetColumn(column, GetColumn(column).SetImage(image)); +} + +int wxTreeListCtrl::GetColumnImage(size_t column) const +{ + return m_header_win->GetColumn(column).GetImage(); +} + +void wxTreeListCtrl::ShowColumn(size_t column, bool shown) +{ + m_header_win->SetColumn(column, GetColumn(column).SetShown(shown)); +} + +bool wxTreeListCtrl::IsColumnShown(size_t column) const +{ + return m_header_win->GetColumn(column).GetShown(); +} + +void wxTreeListCtrl::SetColumnAlignment(size_t column, + wxTreeListColumnAlign align) +{ + m_header_win->SetColumn(column, GetColumn(column).SetAlignment(align)); +} + +wxTreeListColumnAlign wxTreeListCtrl::GetColumnAlignment(size_t column) const +{ + return m_header_win->GetColumn(column).GetAlignment(); +} + +void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect) +{ + m_main_win->Refresh(erase, rect); + m_header_win->Refresh(erase, rect); +} + +void wxTreeListCtrl::SetFocus() +{ m_main_win->SetFocus(); }