From eca15c0d5497309e402d4bb91f8e479b4fb70fa9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Oct 2005 18:40:36 +0000 Subject: [PATCH] Added wxTreebook: - added the control itself - added protected wxBookCtrlBase::AllowNullPage() to accommodate it - big changes to the sample to get rid of (most) ugly macros - added XRC handler for the control - added docs - and wxUSE_TREEBOOK everywhere git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35862 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- build/bakefiles/files.bkl | 3 + configure.in | 10 + docs/changes.txt | 1 + docs/latex/wx/category.tex | 2 + docs/latex/wx/classes.tex | 2 + docs/latex/wx/treebook.tex | 269 +++++++++++ docs/latex/wx/treebookevent.tex | 80 ++++ docs/latex/wx/treebookevt.inc | 12 + docs/latex/wx/tsamples.tex | 6 +- include/wx/bookctrl.h | 7 + include/wx/mac/setup0.h | 8 + include/wx/msw/setup0.h | 8 + include/wx/msw/wince/setup.h | 8 + include/wx/setup_inc.h | 8 + include/wx/treebook.h | 298 ++++++++++++ include/wx/univ/setup0.h | 8 + include/wx/xrc/xh_all.h | 1 + include/wx/xrc/xh_treebk.h | 81 ++++ samples/notebook/notebook.cpp | 702 +++++++++++++++------------ samples/notebook/notebook.h | 63 ++- samples/xrc/rc/controls.xrc | 37 ++ setup.h.in | 2 + setup.h_vms | 2 + src/common/bookctrl.cpp | 20 +- src/generic/treebkg.cpp | 807 ++++++++++++++++++++++++++++++++ src/xrc/xh_treebk.cpp | 134 ++++++ src/xrc/xmlrsall.cpp | 3 + 27 files changed, 2250 insertions(+), 332 deletions(-) create mode 100644 docs/latex/wx/treebook.tex create mode 100644 docs/latex/wx/treebookevent.tex create mode 100644 docs/latex/wx/treebookevt.inc create mode 100644 include/wx/treebook.h create mode 100644 include/wx/xrc/xh_treebk.h create mode 100644 src/generic/treebkg.cpp create mode 100644 src/xrc/xh_treebk.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index f720c8d2ad..f56d135978 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -627,6 +627,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/generic/textdlgg.cpp src/generic/tipwin.cpp src/generic/treectlg.cpp + src/generic/treebkg.cpp src/generic/vlbox.cpp src/generic/vscroll.cpp @@ -793,6 +794,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/tooltip.h wx/toplevel.h wx/treebase.h + wx/treebook.h wx/treectrl.h wx/valgen.h wx/vidmode.h @@ -2610,6 +2612,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/xrc/xh_tglbtn.cpp src/xrc/xh_toolb.cpp src/xrc/xh_tree.cpp + src/xrc/xh_treebk.cpp src/xrc/xh_unkwn.cpp src/xrc/xh_wizrd.cpp src/xrc/xmlres.cpp diff --git a/configure.in b/configure.in index 6fec5fa511..2b85a555a1 100644 --- a/configure.in +++ b/configure.in @@ -527,6 +527,7 @@ if test $DEBUG_CONFIGURE = 1; then DEFAULT_wxUSE_TOOLBAR=no DEFAULT_wxUSE_TOOLBAR_NATIVE=no DEFAULT_wxUSE_TOOLBAR_SIMPLE=no + DEFAULT_wxUSE_TREEBOOK=no DEFAULT_wxUSE_TREECTRL=no DEFAULT_wxUSE_POPUPWIN=no DEFAULT_wxUSE_TIPWINDOW=no @@ -723,6 +724,7 @@ else DEFAULT_wxUSE_TOOLBAR=yes DEFAULT_wxUSE_TOOLBAR_NATIVE=yes DEFAULT_wxUSE_TOOLBAR_SIMPLE=yes + DEFAULT_wxUSE_TREEBOOK=yes DEFAULT_wxUSE_TREECTRL=yes DEFAULT_wxUSE_POPUPWIN=yes DEFAULT_wxUSE_TIPWINDOW=yes @@ -1025,6 +1027,7 @@ if test "$wxUSE_CONTROLS" = "yes"; then DEFAULT_wxUSE_TOOLBAR_NATIVE=yes DEFAULT_wxUSE_TOOLBAR_SIMPLE=yes DEFAULT_wxUSE_TOOLTIPS=yes + DEFAULT_wxUSE_TREEBOOK=yes DEFAULT_wxUSE_TREECTRL=yes DEFAULT_wxUSE_POPUPWIN=yes DEFAULT_wxUSE_TIPWINDOW=yes @@ -1065,6 +1068,7 @@ elif test "$wxUSE_CONTROLS" = "no"; then DEFAULT_wxUSE_TOOLBAR_NATIVE=no DEFAULT_wxUSE_TOOLBAR_SIMPLE=no DEFAULT_wxUSE_TOOLTIPS=no + DEFAULT_wxUSE_TREEBOOK=no DEFAULT_wxUSE_TREECTRL=no DEFAULT_wxUSE_POPUPWIN=no DEFAULT_wxUSE_TIPWINDOW=no @@ -1108,6 +1112,7 @@ WX_ARG_ENABLE(togglebtn, [ --enable-togglebtn use wxToggleButton class], WX_ARG_ENABLE(toolbar, [ --enable-toolbar use wxToolBar class], wxUSE_TOOLBAR) WX_ARG_ENABLE(tbarnative, [ --enable-tbarnative use native wxToolBar class], wxUSE_TOOLBAR_NATIVE) WX_ARG_ENABLE(tbarsmpl, [ --enable-tbarsmpl use wxToolBarSimple class], wxUSE_TOOLBAR_SIMPLE) +WX_ARG_ENABLE(treebook, [ --enable-treebook use wxTreebook class], wxUSE_TREEBOOK) WX_ARG_ENABLE(treectrl, [ --enable-treectrl use wxTreeCtrl class], wxUSE_TREECTRL) WX_ARG_ENABLE(tipwindow, [ --enable-tipwindow use wxTipWindow class], wxUSE_TIPWINDOW) WX_ARG_ENABLE(popupwin, [ --enable-popupwin use wxPopUpWindow class], wxUSE_POPUPWIN) @@ -6393,6 +6398,11 @@ if test "$wxUSE_TOOLTIPS" = "yes"; then fi fi +if test "$wxUSE_TREEBOOK" = "yes"; then + AC_DEFINE(wxUSE_TREEBOOK) + USES_CONTROLS=1 +fi + if test "$wxUSE_TREECTRL" = "yes"; then if test "$wxUSE_IMAGLIST" = "yes"; then AC_DEFINE(wxUSE_TREECTRL) diff --git a/docs/changes.txt b/docs/changes.txt index d8a0460092..1c5fc8e5f3 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -11,6 +11,7 @@ All: All (GUI): +- added wxTreeBook - added wxDialog::SetEscapeId() - wxItemContainerImmutable::FindString unified (affects wxRadioBox, wxListBox, wxComboBox and wxChoice) diff --git a/docs/latex/wx/category.tex b/docs/latex/wx/category.tex index 31a4d13114..f1ae1587ba 100644 --- a/docs/latex/wx/category.tex +++ b/docs/latex/wx/category.tex @@ -44,6 +44,7 @@ The following are a variety of classes that are derived from wxWindow. \twocolitem{\helpref{wxNotebook}{wxnotebook}}{Notebook class} \twocolitem{\helpref{wxListbook}{wxlistbook}}{Similar to notebook but using list control} \twocolitem{\helpref{wxChoicebook}{wxchoicebook}}{Similar to notebook but using choice control} +\twocolitem{\helpref{wxTreebook}{wxtreebook}}{Similar to notebook but using tree control} \twocolitem{\helpref{wxSashWindow}{wxsashwindow}}{Window with four optional sashes that can be dragged} \twocolitem{\helpref{wxSashLayoutWindow}{wxsashlayoutwindow}}{Window that can be involved in an IDE-like layout arrangement} \twocolitem{\helpref{wxVScrolledWindow}{wxvscrolledwindow}}{As wxScrolledWindow but supports lines of variable height} @@ -252,6 +253,7 @@ An event object contains information about a specific event. Event handlers \twocolitem{\helpref{wxSplitterEvent}{wxsplitterevent}}{An event from \helpref{wxSplitterWindow}{wxsplitterwindow}} \twocolitem{\helpref{wxSysColourChangedEvent}{wxsyscolourchangedevent}}{A system colour change event} \twocolitem{\helpref{wxTimerEvent}{wxtimerevent}}{A timer expiration event} +\twocolitem{\helpref{wxTreebookEvent}{wxtreebookevent}}{A treebook control event} \twocolitem{\helpref{wxTreeEvent}{wxtreeevent}}{A tree control event} \twocolitem{\helpref{wxUpdateUIEvent}{wxupdateuievent}}{A user interface update event} \twocolitem{\helpref{wxWindowCreateEvent}{wxwindowcreateevent}}{A window creation event} diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex index 6c55698d6d..ffbe9e6dcc 100644 --- a/docs/latex/wx/classes.tex +++ b/docs/latex/wx/classes.tex @@ -348,6 +348,8 @@ \input toolbar.tex \input tooltip.tex \input tlw.tex +\input treebook.tex +\input treebookevent.tex \input treectrl.tex \input treeevt.tex \input treedata.tex diff --git a/docs/latex/wx/treebook.tex b/docs/latex/wx/treebook.tex new file mode 100644 index 0000000000..5fb0b255f8 --- /dev/null +++ b/docs/latex/wx/treebook.tex @@ -0,0 +1,269 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Name: treebook.tex +%% Purpose: wxTreebook documentation +%% Author: Evgeniy Tarassov +%% Modified by: +%% Created: 2005-10-04 +%% RCS-ID: $Id$ +%% Copyright: (c) 2005 Vadim Zeitlin +%% License: wxWindows license +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\section{\class{wxTreebook}}\label{wxtreebook} + +This class is an extension of the Notebook class that allows a tree structured +set of pages to be shown in a control. +A classic example is a netscape preferences dialog that shows a tree +of preference sections on the left and select section page on the right. + +To use the class simply create it and populate with pages using +\helpref{InsertPage}{wxtreebookinsertpage}, +\helpref{AddPage}{wxtreebookaddpage}, +\helpref{AddSubPage}{wxtreebookaddsubpage}. + +If your tree is no more than 1 level in depth then you could +simply use \helpref{AddPage}{wxtreebookaddpage} and +\helpref{AddSubPage}{wxtreebookaddsubpage} to sequentially populate your tree +by adding at every step a page or a subpage to the end of the tree. + + +\wxheading{Derived from} + +wxBookCtrlBase\\ +\helpref{wxControl}{wxcontrol}\\ +\helpref{wxWindow}{wxwindow}\\ +\helpref{wxEvtHandler}{wxevthandler}\\ +\helpref{wxObject}{wxobject} + + +\wxheading{Include files} + + + +\input treebookevt.inc + + +\wxheading{See also} + +\helpref{wxNotebook}{wxnotebook}, \helpref{wxTreebookEvent}{wxtreebookevent}, \helpref{wxImageList}{wximagelist}, \helpref{notebook sample}{samplenotebook} + + + +\latexignore{\rtfignore{\wxheading{Members}}} + + +\membersection{wxTreebook::wxTreebook}\label{wxtreebookwxtreebook} + +\func{}{wxTreebook}{\void} + +Default constructor. + + +\func{}{wxTreebook}{ + \param{wxWindow* }{parent}, + \param{wxWindowID }{id}, + \param{const wxPoint\& }{pos = wxDefaultPosition}, + \param{const wxSize\& }{size = wxDefaultSize}, + \param{long }{style = wxTBK\_DEFAULT}, + \param{const wxString\& }{name = wxEmptyString}} + +Creates an empty TreeBook control. + +\wxheading{Parameters} + +\docparam{parent}{The parent window. Must be non-NULL.} + +\docparam{id}{The window identifier.} + +\docparam{pos}{The window position.} + +\docparam{size}{The window size.} + +\docparam{style}{The window style. See \helpref{wxNotebook}{wxnotebook}.} + +\docparam{name}{The name of the control (used only under Motif).} + + + +\membersection{wxTreebook::\destruct{wxTreebook}}\label{wxtreebookdtor} + +\func{}{\destruct{wxTreebook}}{\void} + +Destroys the wxTreebook object. + +Also deletes all the pages owned by the control (inserted previously into it). + + + +\membersection{wxTreebook::AddPage}\label{wxtreebookaddpage} + +\func{bool}{AddPage}{ + \param{wxWindow* }{page}, + \param{const wxString\& }{text}, + \param{bool }{bSelect = false}, + \param{int }{imageId = wxNOT\_FOUND}} + +Adds a new page. The page is placed at the topmost level after all other pages. +NULL could be specified for page to create an empty page. + + + +\membersection{wxTreebook::AddSubPage}\label{wxtreebookaddsubpage} + +\func{bool}{AddSubPage}{\param{wxWindow* }{page}, \param{const wxString\& }{text}, \param{bool }{bSelect = false}, \param{int }{imageId = wxNOT\_FOUND}} + +\func{bool}{AddSubPage}{\param{size\_t }{pagePos}, \param{wxWindow* }{page}, \param{const wxString\& }{text}, \param{bool }{bSelect = false}, \param{int }{imageId = wxNOT\_FOUND}} + +Adds a new child-page to either the last or the specified top-level. +NULL could be specified for page to create an empty page. + + + +\membersection{wxTreebook::AssignImageList}\label{wxtreebookassignimagelist} + +\func{void}{AssignImageList}{\param{wxImageList* }{imageList}} + +Sets the image list for the page control and takes ownership of the list. + +\wxheading{See also} + +\helpref{wxImageList}{wximagelist}, \helpref{SetImageList}{wxtreebooksetimagelist} + + + +\membersection{wxTreebook::CollapseNode}\label{wxtreebookcollapsenode} + +\func{bool}{CollapseNode}{\param{size\_t }{pageId}} + +Shortcut for \helpref{ExpandNode}{wxtreebookexpandnode}(pageId, false). + + + +\membersection{wxTreebook::Create}\label{wxtreebookcreate} + +\func{bool}{Create}{\param{wxWindow* }{parent}, \param{wxWindowID }{id}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{long }{style = wxTBK\_DEFAULT}, \param{const wxString\& }{name = wxEmptyString}} + +Creates a treebook control. See \helpref{wxTreebook::wxTreebook}{wxtreebookwxtreebook} for the description of the parameters. + + + +\membersection{wxTreebook::DeleteAllPages}\label{wxtreebookdeleteallpages} + +\func{bool}{DeleteAllPages}{\void} + +Deletes all pages inserted into the treebook. No event is generated. + + + +\membersection{wxTreebook::DeletePage}\label{wxtreebookdeletepage} + +\func{bool}{DeletePage}{\param{size\_t }{pagePos}} + +Deletes the page at the specified position and all its children. Could trigger page selection change +in a case when selected page is removed. In that case its parent is selected +(or the next page if no parent). + + + +\membersection{wxTreebook::ExpandNode}\label{wxtreebookexpandnode} + +\func{bool}{ExpandNode}{\param{size\_t }{pageId}, \param{bool }{expand = true}} + +Expands (collapses) the pageId node. Returns the previous state. +May generate page changing events (if selected page +is under the collapsed branch, then its parent is autoselected). + + +\membersection{wxTreebook::GetPageImage}\label{wxtreebookgetpageimage} + +\constfunc{int}{GetPageImage}{\param{size\_t }{n}} + +Returns the image index for the given page. + + +\membersection{wxTreebook::GetPageParent}\label{wxtreebookgetpageparent} + +\constfunc{int}{GetPageParent}{\param{size\_t }{page}} + +Returns the parent page of the given one or \texttt{wxNOT\_FOUND} if this is a +top-level page. + + +\membersection{wxTreebook::GetPageText}\label{wxtreebookgetpagetext} + +\constfunc{wxString}{GetPageText}{\param{size\_t }{n}} + +Returns the string for the given page. + + + +\membersection{wxTreebook::GetSelection}\label{wxtreebookgetselection} + +\constfunc{int}{GetSelection}{\void} + +Returns the currently selected page, or wxNOT\_FOUND if none was selected. + +Note that this method may return either the previously or newly selected page +when called from the EVT\_TREEBOOK\_PAGE\_CHANGED handler +depending on the platform and so wxTreebookEvent::GetSelection should be used instead in this case. + + + +\membersection{wxTreebook::InsertPage}\label{wxtreebookinsertpage} + +\func{bool}{InsertPage}{\param{size\_t }{pagePos}, \param{wxWindow* }{page}, \param{const wxString\& }{text}, \param{bool }{bSelect = false}, \param{int }{imageId = wxNOT\_FOUND}} + +Inserts a new page just before the page indicated by pagePos. +The new page is placed before pagePos page and on the same level. +NULL could be specified for page to create an empty page. + + +\membersection{wxTreebook::IsNodeExpanded}\label{wxtreebookisnodeexpanded} + +\constfunc{bool}{IsNodeExpanded}{\param{size\_t }{pageId}} + +Gets the pagePos page state -- whether it is expanded or collapsed + + + +\membersection{wxTreebook::SetImageList}\label{wxtreebooksetimagelist} + +\func{void}{SetImageList}{\param{wxImageList* }{imageList}} + +Sets the image list for the page control. It does not take ownership of the image list, you must delete it yourself. + +\wxheading{See also} + +\helpref{wxImageList}{wximagelist}, \helpref{AssignImageList}{wxtreebookassignimagelist} + + + +\membersection{wxTreebook::SetPageImage}\label{wxtreebooksetpageimage} + +\func{bool}{SetPageImage}{\param{size\_t }{page}, \param{int }{imageId}} + +Sets the image index for the given page. ImageId is an index into the image list +which was set with \helpref{SetImageList}{wxtreebooksetimagelist}. + + + +\membersection{wxTreebook::SetPageText}\label{wxtreebooksetpagetext} + +\func{bool}{SetPageText}{\param{size\_t }{page}, \param{const wxString\& }{text}} + +Sets the text for the given page. + + + +\membersection{wxTreebook::SetSelection}\label{wxtreebooksetselection} + +\func{int}{SetSelection}{\param{size\_t }{n}} + +Sets the selection for the given page, returning the previous selection. + +The call to this function generates the page changing events. + +\wxheading{See also} + +\helpref{wxTreebook::GetSelection}{wxtreebookgetselection} + diff --git a/docs/latex/wx/treebookevent.tex b/docs/latex/wx/treebookevent.tex new file mode 100644 index 0000000000..289e9a52ed --- /dev/null +++ b/docs/latex/wx/treebookevent.tex @@ -0,0 +1,80 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Name: treebookevent.tex +%% Purpose: wxTreebookEvent documentation +%% Author: Evgeniy Tarassov +%% Modified by: +%% Created: 2005-10-04 +%% RCS-ID: $Id$ +%% Copyright: (c) 2005 Vadim Zeitlin +%% License: wxWindows license +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\section{\class{wxTreebookEvent}}\label{wxtreebookevent} + +This class represents the events generated by a treebook control: currently, +there are four of them. The PAGE\_CHANGING and PAGE\_CHANGED - have exactly the same +behaviour as \helpref{wxNotebookEvent}{wxnotebookevent}. + +The other two NODE\_COLLAPSED and NODE\_EXPANDED are triggered when page node in the tree control +is collapsed/expanded. The page index could be retreived by calling +\helpref{wxTreebookEvent::GetSelection}{wxtreebookeventgetselection}. + + + +\wxheading{Derived from} + +wxBookCtrlBaseEvent\\ +\helpref{wxNotifyEvent}{wxnotifyevent}\\ +\helpref{wxCommandEvent}{wxcommandevent}\\ +\helpref{wxEvent}{wxevent}\\ +\helpref{wxObject}{wxobject} + + + +\wxheading{Include files} + + + + + +\input treebookevt.inc + + + +\wxheading{See also} + +\helpref{wxNotebookEvent}{wxnotebookevent}, \helpref{wxTreebook}{wxtreebook} + + + +\latexignore{\rtfignore{\wxheading{Members}}} + + +\membersection{wxTreebookEvent::wxTreebookEvent}\label{wxtreebookeventwxtreebookevent} + +\func{}{wxTreebookEvent}{\param{wxEventType }{commandType = wxEVT\_NULL}, \param{int }{id = 0}, \param{int }{nSel = wxNOT\_FOUND}, \param{int }{nOldSel = wxNOT\_FOUND}} + +\wxheading{See also} + +\helpref{wxNotebookEvent}{wxnotebookevent} + + + +\membersection{wxTreebookEvent::GetOldSelection}\label{wxtreebookeventgetoldselection} + +\constfunc{int}{GetOldSelection}{\void} + +Returns the page that was selected before the change, wxNOT\_FOUND if none was selected. + + + +\membersection{wxTreebookEvent::GetSelection}\label{wxtreebookeventgetselection} + +\constfunc{int}{GetSelection}{\void} + +Returns the currently selected page, or wxNOT\_FOUND if none was selected. + +\wxheading{See also} + +\helpref{wxNotebookEvent::GetSelection}{wxnotebookeventgetselection} + diff --git a/docs/latex/wx/treebookevt.inc b/docs/latex/wx/treebookevt.inc new file mode 100644 index 0000000000..5c3e3d8668 --- /dev/null +++ b/docs/latex/wx/treebookevt.inc @@ -0,0 +1,12 @@ +\wxheading{Event handling} + +To process input from a treebook control, use the following event handler macros +to direct input to member functions that take a \helpref{wxTreebookEvent}{wxtreebookevent} argument. + +\twocolwidtha{10cm} +\begin{twocollist}\itemsep=0pt +\twocolitem{{\bf EVT\_TREEBOOK\_PAGE\_CHANGED(id, func)}}{The page selection was changed. Processes a wxEVT\_COMMAND\_TREEBOOK\_PAGE\_CHANGED event.} +\twocolitem{{\bf EVT\_TREEBOOK\_PAGE\_CHANGING(id, func)}}{The page selection is about to be changed. Processes a wxEVT\_COMMAND\_TREEBOOK\_PAGE\_CHANGING event. This event can be \helpref{vetoed}{wxnotifyeventveto}.} +\twocolitem{{\bf EVT\_TREEBOOK\_NODE\_COLLAPSED(id, func)}}{The page node is going to be collapsed. Processes a wxEVT\_COMMAND\_TREEBOOK\_NODE\_COLLAPSED event.} +\twocolitem{{\bf EVT\_TREEBOOK\_NODE\_EXPANDED(id, func)}}{The page node is going to be expanded. Processes a wxEVT\_COMMAND\_TREEBOOK\_NODE\_EXPANDED event.} +\end{twocollist} diff --git a/docs/latex/wx/tsamples.tex b/docs/latex/wx/tsamples.tex index 08ef75068d..347dbb5ee0 100644 --- a/docs/latex/wx/tsamples.tex +++ b/docs/latex/wx/tsamples.tex @@ -369,9 +369,9 @@ It replaces the old dynamic sample. This samples shows \helpref{wxBookCtrl}{wxbookctrloverview} family of controls. Although initially it was written to demonstrate \helpref{wxNotebook}{wxnotebook} -only, it can now be also used to see \helpref{wxListbook}{wxlistbook} and -\helpref{wxChoicebook}{wxchoicebook} in action. Test each of the controls, their -orientation, images and pages using commands through menu. +only, it can now be also used to see \helpref{wxListbook}{wxlistbook}, +\helpref{wxChoicebook}{wxchoicebook} and \helpref{wxTreebook}{wxtreebook} in action. +Test each of the controls, their orientation, images and pages using commands through menu. diff --git a/include/wx/bookctrl.h b/include/wx/bookctrl.h index 95e79de2ab..347dc6ba0c 100644 --- a/include/wx/bookctrl.h +++ b/include/wx/bookctrl.h @@ -176,6 +176,13 @@ public: } protected: + // Should we accept NULL page pointers in Add/InsertPage()? + // + // Default is no but derived classes may override it if they can treat NULL + // pages in some sensible way (e.g. wxTreebook overrides this to allow + // having nodes without any associated page) + virtual bool AllowNullPage() const { return false; } + // remove the page and return a pointer to it virtual wxWindow *DoRemovePage(size_t page) = 0; diff --git a/include/wx/mac/setup0.h b/include/wx/mac/setup0.h index 3af04ca034..dc853edc9f 100644 --- a/include/wx/mac/setup0.h +++ b/include/wx/mac/setup0.h @@ -614,6 +614,14 @@ // Recommended setting: 1 #define wxUSE_CHOICEBOOK 1 +// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of +// the tabs +// +// Default is 1. +// +// Recommended setting: 1 +#define wxUSE_TREEBOOK 1 + // wxTabDialog is a generic version of wxNotebook but it is incompatible with // the new class. It shouldn't be used in new code. // diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h index 1f53738b08..7e34e7e226 100644 --- a/include/wx/msw/setup0.h +++ b/include/wx/msw/setup0.h @@ -613,6 +613,14 @@ // Recommended setting: 1 #define wxUSE_CHOICEBOOK 1 +// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of +// the tabs +// +// Default is 1. +// +// Recommended setting: 1 +#define wxUSE_TREEBOOK 1 + // wxTabDialog is a generic version of wxNotebook but it is incompatible with // the new class. It shouldn't be used in new code. // diff --git a/include/wx/msw/wince/setup.h b/include/wx/msw/wince/setup.h index 03451f486e..8cd7baf9d1 100644 --- a/include/wx/msw/wince/setup.h +++ b/include/wx/msw/wince/setup.h @@ -613,6 +613,14 @@ // Recommended setting: 1 #define wxUSE_CHOICEBOOK 1 +// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of +// the tabs +// +// Default is 1. +// +// Recommended setting: 1 +#define wxUSE_TREEBOOK 1 + // wxTabDialog is a generic version of wxNotebook but it is incompatible with // the new class. It shouldn't be used in new code. // diff --git a/include/wx/setup_inc.h b/include/wx/setup_inc.h index 9f955e23b4..c8e48f7d7d 100644 --- a/include/wx/setup_inc.h +++ b/include/wx/setup_inc.h @@ -609,6 +609,14 @@ // Recommended setting: 1 #define wxUSE_CHOICEBOOK 1 +// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of +// the tabs +// +// Default is 1. +// +// Recommended setting: 1 +#define wxUSE_TREEBOOK 1 + // wxTabDialog is a generic version of wxNotebook but it is incompatible with // the new class. It shouldn't be used in new code. // diff --git a/include/wx/treebook.h b/include/wx/treebook.h new file mode 100644 index 0000000000..34f0090f89 --- /dev/null +++ b/include/wx/treebook.h @@ -0,0 +1,298 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/treebook.h +// Purpose: wxTreebook: wxNotebook-like control presenting pages in a tree +// Author: Evgeniy Tarassov, Vadim Zeitlin +// Modified by: +// Created: 2005-09-15 +// RCS-ID: $Id$ +// Copyright: (c) 2005 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_TREEBOOK_H_ +#define _WX_TREEBOOK_H_ + +#include "wx/defs.h" + +#if wxUSE_TREEBOOK + +#include "wx/bookctrl.h" +#include "wx/treectrl.h" // for wxArrayTreeItemIds + +typedef wxWindow wxTreebookPage; + +class WXDLLEXPORT wxTreeEvent; + +// ---------------------------------------------------------------------------- +// style flags +// ---------------------------------------------------------------------------- + +// This is a set of synonyms of wxNB_XXX, which still could be used directly +// for styling the control. Defined for consistency with wxListbook and +// wxChoicebook only. +#define wxTBK_LEFT wxNB_LEFT +#define wxTBK_RIGHT wxNB_RIGHT + +// we don't support TOP/BOTTOM orientations but still define the flags (again, +// for consistency with others) +#define wxTBK_TOP wxTBK_LEFT +#define wxTBK_BOTTOM wxTBK_RIGHT + +#define wxTBK_ALIGN_MASK (wxTBK_LEFT | wxTBK_RIGHT) +#define wxTBK_DEFAULT wxTBK_LEFT + +// ---------------------------------------------------------------------------- +// wxTreebook +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxTreebook : public wxBookCtrlBase +{ +public: + // Constructors and such + // --------------------- + + // Default ctor doesn't create the control, use Create() afterwards + wxTreebook() + { + Init(); + } + + // This ctor creates the tree book control + wxTreebook(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTBK_DEFAULT, + const wxString& name = wxEmptyString) + { + Init(); + + (void)Create(parent, id, pos, size, style, name); + } + + // Really creates the control + bool Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTBK_DEFAULT, + const wxString& name = wxEmptyString); + + + // Page insertion operations + // ------------------------- + + // Notice that page pointer may be NULL in which case the next non NULL + // page (usually the first child page of a node) is shown when this page is + // selected + + // Inserts a new page just before the page indicated by page. + // The new page is placed on the same level as page. + virtual bool InsertPage(size_t pos, + wxWindow *page, + const wxString& text, + bool bSelect = false, + int imageId = wxNOT_FOUND); + + // Inserts a new sub-page to the end of children of the page at given pos. + virtual bool AddSubPage(size_t pos, + wxWindow *page, + const wxString& text, + bool bSelect = false, + int imageId = wxNOT_FOUND); + + // Adds a new page at top level after all other pages. + virtual bool AddPage(wxWindow *page, + const wxString& text, + bool bSelect = false, + int imageId = wxNOT_FOUND); + + // Adds a new child-page to the last top-level page inserted. + // Useful when constructing 1 level tree structure. + virtual bool AddSubPage(wxWindow *page, + const wxString& text, + bool bSelect = false, + int imageId = wxNOT_FOUND); + + // Deletes the page and ALL its children. Could trigger page selection + // change in a case when selected page is removed. In that case its parent + // is selected (or the next page if no parent). + virtual bool DeletePage(size_t pos); + + + // Tree operations + // --------------- + + // Gets the page node state -- node is expanded or collapsed + virtual bool IsNodeExpanded(size_t pos) const; + + // Expands or collapses the page node. Returns the previous state. + // May generate page changing events (if selected page + // is under the collapsed branch, then parent is autoselected). + virtual bool ExpandNode(size_t pos, bool expand = true); + + // shortcut for ExpandNode(pos, false) + bool CollapseNode(size_t pos) { return ExpandNode(pos, false); } + + // get the parent page or wxNOT_FOUND if this is a top level page + int GetPageParent(size_t pos) const; + + + // Standard operations inherited from wxBookCtrlBase + // ------------------------------------------------- + + virtual int GetSelection() const; + virtual bool SetPageText(size_t n, const wxString& strText); + virtual wxString GetPageText(size_t n) const; + virtual int GetPageImage(size_t n) const; + virtual bool SetPageImage(size_t n, int imageId); + virtual wxSize CalcSizeFromPage(const wxSize& sizePage) const; + virtual int SetSelection(size_t n); + virtual void SetImageList(wxImageList *imageList); + virtual void AssignImageList(wxImageList *imageList); + virtual bool DeleteAllPages(); + +protected: + // This subclass of wxBookCtrlBase accepts NULL page pointers (empty pages) + virtual bool AllowNullPage() const { return true; } + + // get the size which the tree control should have + wxSize GetTreeSize() const; + + // get the page area + wxRect GetPageRect() const; + + // event handlers + void OnSize(wxSizeEvent& event); + void OnTreeSelectionChange(wxTreeEvent& event); + void OnTreeNodeExpandedCollapsed(wxTreeEvent& event); + + + // the tree control we use for showing the pages index tree + wxTreeCtrl *m_tree; + + // array of page ids and page windows + wxArrayTreeItemIds m_treeIds; + + // the currently selected page or wxNOT_FOUND if none + int m_selection; + + // in the situation when m_selection page is not wxNOT_FOUND but page is + // NULL this is the first (sub)child that has a non-NULL page + int m_actualSelection; + +private: + // common part of all constructors + void Init(); + + // The real implementations of page insertion functions + // ------------------------------------------------------ + // All DoInsert/Add(Sub)Page functions add the page into : + // - the base class + // - the tree control + // - update the index/TreeItemId corespondance array + bool DoInsertPage(size_t pos, + wxWindow *page, + const wxString& text, + bool bSelect = false, + int imageId = wxNOT_FOUND); + bool DoInsertSubPage(size_t pos, + wxWindow *page, + const wxString& text, + bool bSelect = false, + int imageId = wxNOT_FOUND); + bool DoAddSubPage(wxWindow *page, + const wxString& text, + bool bSelect = false, + int imageId = wxNOT_FOUND); + + // Implementation of a page removal. See DeletPage for comments. + wxTreebookPage *DoRemovePage(size_t pos); + + // Sets selection in the tree control and updates the page being shown. + int DoSetSelection(size_t pos); + + // Returns currently shown page. In a case when selected the node + // has empty (NULL) page finds first (sub)child with not-empty page. + wxTreebookPage *DoGetCurrentPage() const; + + // Does the selection update. Called from page insertion functions + // to update selection if the selected page was pushed by the newly inserted + void DoUpdateSelection(bool bSelect, int page); + + + // Operations on the internal private members of the class + // ------------------------------------------------------- + // Returns the page TreeItemId for the page. + // Or, if the page index is incorrect, a fake one (fakePage.IsOk() == false) + wxTreeItemId DoInternalGetPage(size_t pos) const; + + // Linear search for a page with the id specified. If no page + // found wxNOT_FOUND is returned. The function is used when we catch an event + // from m_tree (wxTreeCtrl) component. + int DoInternalFindPageById(wxTreeItemId page) const; + + // Updates page and wxTreeItemId correspondance. + void DoInternalAddPage(size_t newPos, wxWindow *page, wxTreeItemId pageId); + + // Removes the page from internal structure. + void DoInternalRemovePage(size_t pos) + { DoInternalRemovePageRange(pos, 0); } + + // Removes the page and all its children designated by subCount + // from internal structures of the control. + void DoInternalRemovePageRange(size_t pos, size_t subCount); + + // Returns internal number of pages which can be different from + // GetPageCount() while performing a page insertion or removal. + size_t DoInternalGetPageCount() const { return m_treeIds.Count(); } + + + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS_NO_COPY(wxTreebook) +}; + + +// ---------------------------------------------------------------------------- +// treebook event class and related stuff +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxTreebookEvent : public wxBookCtrlBaseEvent +{ +public: + wxTreebookEvent(wxEventType commandType = wxEVT_NULL, int id = 0, + int nSel = wxNOT_FOUND, int nOldSel = wxNOT_FOUND) + : wxBookCtrlBaseEvent(commandType, id, nSel, nOldSel) + { + } + +private: + DECLARE_DYNAMIC_CLASS_NO_COPY(wxTreebookEvent) +}; + +extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED; +extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING; +extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED; +extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED; + +typedef void (wxEvtHandler::*wxTreebookEventFunction)(wxTreebookEvent&); + +#define wxTreebookEventHandler(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxTreebookEventFunction, &func) + +#define EVT_TREEBOOK_PAGE_CHANGED(winid, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED, winid, wxTreebookEventHandler(fn)) + +#define EVT_TREEBOOK_PAGE_CHANGING(winid, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, winid, wxTreebookEventHandler(fn)) + +#define EVT_TREEBOOK_NODE_COLLAPSED(winid, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED, winid, wxTreebookEventHandler(fn)) + +#define EVT_TREEBOOK_NODE_EXPANDED(winid, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED, winid, wxTreebookEventHandler(fn)) + + +#endif // wxUSE_TREEBOOK + +#endif // _WX_TREEBOOK_H_ diff --git a/include/wx/univ/setup0.h b/include/wx/univ/setup0.h index 1c2f618990..b22c5318d9 100644 --- a/include/wx/univ/setup0.h +++ b/include/wx/univ/setup0.h @@ -649,6 +649,14 @@ // Recommended setting: 1 #define wxUSE_CHOICEBOOK 1 +// wxTreebook control is similar to wxNotebook but uses wxTreeCtrl instead of +// the tabs +// +// Default is 1. +// +// Recommended setting: 1 +#define wxUSE_TREEBOOK 1 + // wxTabDialog is a generic version of wxNotebook but it is incompatible with // the new class. It shouldn't be used in new code. // diff --git a/include/wx/xrc/xh_all.h b/include/wx/xrc/xh_all.h index 41baf0cbb1..b3f42aa180 100644 --- a/include/wx/xrc/xh_all.h +++ b/include/wx/xrc/xh_all.h @@ -36,6 +36,7 @@ #include "wx/xrc/xh_notbk.h" #include "wx/xrc/xh_listbk.h" #include "wx/xrc/xh_choicbk.h" +#include "wx/xrc/xh_treebk.h" #include "wx/xrc/xh_text.h" #include "wx/xrc/xh_listb.h" #include "wx/xrc/xh_toolb.h" diff --git a/include/wx/xrc/xh_treebk.h b/include/wx/xrc/xh_treebk.h new file mode 100644 index 0000000000..cc2cd4d479 --- /dev/null +++ b/include/wx/xrc/xh_treebk.h @@ -0,0 +1,81 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: xh_treebk.h +// Purpose: XML resource handler for wxTreebook +// Author: Evgeniy Tarassov +// Created: 2005/09/28 +// Copyright: (c) 2005 TT-Solutions +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_XH_TREEBK_H_ +#define _WX_XH_TREEBK_H_ + +#include "wx/xrc/xmlres.h" + +#if wxUSE_TREEBOOK + +#include "wx/treebook.h" + +WX_DEFINE_ARRAY_INT(size_t, wxArrayTbkPageIndexes); + +// --------------------------------------------------------------------- +// wxTreebookXmlHandler class +// --------------------------------------------------------------------- +// Resource xml structure have to be almost the "same" as for wxNotebook +// except the additional (size_t)depth parameter for treebookpage nodes +// which indicates the depth of the page in the tree. +// There is only one logical constraint on this parameter : +// it cannot be greater than the previous page depth plus one +class WXDLLIMPEXP_XRC wxTreebookXmlHandler : public wxXmlResourceHandler +{ +DECLARE_DYNAMIC_CLASS(wxTreebookXmlHandler) +public: + wxTreebookXmlHandler(); + virtual wxObject *DoCreateResource(); + virtual bool CanHandle(wxXmlNode *node); + +private: + bool m_isInside; + wxTreebook * m_tbk; + wxArrayTbkPageIndexes m_treeContext; +}; + + +// Example: +// ------- +// Label +// \--First +// | \--Second +// \--Third +// +// +// ... +// +// +// +// +// 0 +// +// +// +// +// 1 +// +// +// +// +// 2 +// +// +// +// +// 1 +// +// +// ... +// + +#endif + +#endif // _WX_XH_TREEBK_H_ + diff --git a/samples/notebook/notebook.cpp b/samples/notebook/notebook.cpp index ad083b352e..c9e3cb44ca 100644 --- a/samples/notebook/notebook.cpp +++ b/samples/notebook/notebook.cpp @@ -33,7 +33,7 @@ IMPLEMENT_APP(MyApp) bool MyApp::OnInit() { // Create the main window - MyFrame *frame = new MyFrame( wxT("Notebook sample") ); + MyFrame *frame = new MyFrame(); // Problem with generic wxNotebook implementation whereby it doesn't size // properly unless you set the size again @@ -153,51 +153,40 @@ void CreateInitialPages(wxBookCtrlBase *parent) wxPanel *CreatePage(wxBookCtrlBase *parent, const wxString&pageName) { - if - ( - pageName.Contains(INSERTED_PAGE_NAME) - || pageName.Contains(ADDED_PAGE_NAME) - ) - { + if ( pageName.Contains(INSERTED_PAGE_NAME) || + pageName.Contains(ADDED_PAGE_NAME) || + pageName.Contains(ADDED_SUB_PAGE_NAME) || + pageName.Contains(ADDED_PAGE_NAME_BEFORE) ) return CreateUserCreatedPage(parent); - } - if (pageName == I_WAS_INSERTED_PAGE_NAME) - { + if ( pageName == I_WAS_INSERTED_PAGE_NAME ) return CreateInsertPage(parent); - } - if (pageName == VETO_PAGE_NAME) - { + if ( pageName == VETO_PAGE_NAME ) return CreateVetoPage(parent); - } - if (pageName == RADIOBUTTONS_PAGE_NAME) - { + if ( pageName == RADIOBUTTONS_PAGE_NAME ) return CreateRadioButtonsPage(parent); - } - - if (pageName == MAXIMIZED_BUTTON_PAGE_NAME) - { + if ( pageName == MAXIMIZED_BUTTON_PAGE_NAME ) return CreateBigButtonPage(parent); - } - wxFAIL; + wxFAIL_MSG( _T("unknown page name") ); - return (wxPanel *) NULL; + return NULL; } -MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, - long style) - : wxFrame((wxWindow *) NULL, wxID_ANY, title, pos, size, style) +MyFrame::MyFrame() + : wxFrame(NULL, wxID_ANY, wxString(wxT("wxWidgets book controls sample"))) { #if wxUSE_NOTEBOOK - m_type = ID_BOOK_NOTEBOOK; + m_type = Type_Notebook; #elif wxUSE_CHOICEBOOK - m_type = ID_BOOK_CHOICEBOOK; + m_type = Type_Choicebook; #elif wxUSE_LISTBOOK - m_type = ID_BOOK_LISTBOOK; + m_type = Type_Listbook; +#elif wxUSE_TREEBOOK + m_type = Type_Treebook; #elif #error "Don't use Notebook sample without any book enabled in wxWidgets build!" #endif @@ -219,21 +208,30 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, #if wxUSE_CHOICEBOOK menuType->AppendRadioItem(ID_BOOK_CHOICEBOOK, wxT("&Choicebook\tCtrl-3")); #endif - menuType->Check(m_type, true); +#if wxUSE_TREEBOOK + menuType->AppendRadioItem(ID_BOOK_TREEBOOK, wxT("&Treebook\tCtrl-4")); +#endif + + menuType->Check(ID_BOOK_NOTEBOOK + m_type, true); wxMenu *menuOrient = new wxMenu; - menuOrient->AppendRadioItem(ID_ORIENT_DEFAULT, wxT("&Default\tCtrl-4")); - menuOrient->AppendRadioItem(ID_ORIENT_TOP, wxT("&Top\tCtrl-5")); - menuOrient->AppendRadioItem(ID_ORIENT_BOTTOM, wxT("&Bottom\tCtrl-6")); - menuOrient->AppendRadioItem(ID_ORIENT_LEFT, wxT("&Left\tCtrl-7")); - menuOrient->AppendRadioItem(ID_ORIENT_RIGHT, wxT("&Right\tCtrl-8")); + menuOrient->AppendRadioItem(ID_ORIENT_DEFAULT, wxT("&Default\tCtrl-5")); + menuOrient->AppendRadioItem(ID_ORIENT_TOP, wxT("&Top\tCtrl-6")); + menuOrient->AppendRadioItem(ID_ORIENT_BOTTOM, wxT("&Bottom\tCtrl-7")); + menuOrient->AppendRadioItem(ID_ORIENT_LEFT, wxT("&Left\tCtrl-8")); + menuOrient->AppendRadioItem(ID_ORIENT_RIGHT, wxT("&Right\tCtrl-9")); - wxMenu *menuDo = new wxMenu; - menuDo->Append(ID_ADD_PAGE, wxT("&Add page\tAlt-A")); - menuDo->Append(ID_INSERT_PAGE, wxT("&Insert page\tAlt-I")); - menuDo->Append(ID_DELETE_CUR_PAGE, wxT("&Delete current page\tAlt-D")); - menuDo->Append(ID_DELETE_LAST_PAGE, wxT("D&elete last page\tAlt-L")); - menuDo->Append(ID_NEXT_PAGE, wxT("&Next page\tAlt-N")); + wxMenu *menuOperations = new wxMenu; + menuOperations->Append(ID_ADD_PAGE, wxT("&Add page\tAlt-A")); + menuOperations->Append(ID_INSERT_PAGE, wxT("&Insert page\tAlt-I")); + menuOperations->Append(ID_DELETE_CUR_PAGE, wxT("&Delete current page\tAlt-D")); + menuOperations->Append(ID_DELETE_LAST_PAGE, wxT("D&elete last page\tAlt-L")); + menuOperations->Append(ID_NEXT_PAGE, wxT("&Next page\tAlt-N")); +#if wxUSE_TREEBOOK + menuOperations->AppendSeparator(); + menuOperations->Append(ID_ADD_PAGE_BEFORE, wxT("Insert page &before\tAlt-B")); + menuOperations->Append(ID_ADD_SUB_PAGE, wxT("Add s&ub page\tAlt-U")); +#endif wxMenu *menuFile = new wxMenu; menuFile->Append(wxID_ANY, wxT("&Type"), menuType, wxT("Type of control")); @@ -247,54 +245,32 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, wxMenuBar *menuBar = new wxMenuBar; menuBar->Append(menuFile, wxT("&File")); - menuBar->Append(menuDo, wxT("&Operations")); + menuBar->Append(menuOperations, wxT("&Operations")); SetMenuBar(menuBar); // books creation - - m_panel = (wxPanel *) NULL; -#if wxUSE_NOTEBOOK - m_notebook = (wxNotebook *) NULL; -#endif -#if wxUSE_CHOICEBOOK - m_choicebook = (wxChoicebook *) NULL; -#endif -#if wxUSE_LISTBOOK - m_listbook = (wxListbook *) NULL; -#endif + m_panel = NULL; + m_bookCtrl = NULL; // create a dummy image list with a few icons - wxSize imageSize(32, 32); + const wxSize imageSize(32, 32); - m_imageList - = new wxImageList( imageSize.GetWidth(), imageSize.GetHeight() ); + m_imageList = new wxImageList(imageSize.GetWidth(), imageSize.GetHeight()); + m_imageList-> + Add(wxArtProvider::GetIcon(wxART_INFORMATION, wxART_OTHER, imageSize)); + m_imageList-> + Add(wxArtProvider::GetIcon(wxART_QUESTION, wxART_OTHER, imageSize)); + m_imageList-> + Add(wxArtProvider::GetIcon(wxART_WARNING, wxART_OTHER, imageSize)); + m_imageList-> + Add(wxArtProvider::GetIcon(wxART_ERROR, wxART_OTHER, imageSize)); - m_imageList->Add - ( - wxArtProvider::GetIcon(wxART_INFORMATION, wxART_OTHER, imageSize) - ); - - m_imageList->Add - ( - wxArtProvider::GetIcon(wxART_QUESTION, wxART_OTHER, imageSize) - ); - - m_imageList->Add - ( - wxArtProvider::GetIcon(wxART_WARNING, wxART_OTHER, imageSize) - ); - - m_imageList->Add - ( - wxArtProvider::GetIcon(wxART_ERROR, wxART_OTHER, imageSize) - ); - - m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, - wxTAB_TRAVERSAL | wxCLIP_CHILDREN | wxNO_BORDER | wxNO_FULL_REPAINT_ON_RESIZE); + m_panel = new wxPanel(this); #if USE_LOG m_text = new wxTextCtrl(m_panel, wxID_ANY, wxEmptyString, - wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY); + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxTE_READONLY); m_logTargetOld = wxLog::SetActiveTarget( new wxLogTextCtrl(m_text) ); #endif // USE_LOG @@ -306,7 +282,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, m_sizerFrame->Add(m_text, 1, wxEXPAND); #endif // USE_LOG - RecreateBooks(); + RecreateBook(); m_panel->SetSizer(m_sizerFrame); @@ -322,160 +298,175 @@ MyFrame::~MyFrame() delete wxLog::SetActiveTarget(m_logTargetOld); #endif // USE_LOG - if (m_imageList) - { - delete m_imageList; - m_imageList = (wxImageList *) NULL; - } + delete m_imageList; } -int MyFrame::SelectFlag(int id, int nb, int lb, int chb) -{ - switch (id) - { - case ID_NOTEBOOK: return nb; - case ID_LISTBOOK: return lb; - case ID_CHOICEBOOK: return chb; - } - return 0; -} - -#ifdef __SMARTPHONE__ - #define MARGIN 0 +// DISPATCH_ON_TYPE() macro is an ugly way to write the "same" code for +// different wxBookCtrlBase-derived classes without duplicating code and +// without using templates, it expands into "before after" where "xxx" +// part is control class-specific +#if wxUSE_NOTEBOOK + #define CASE_NOTEBOOK(x) case Type_Notebook: x; break; #else - #define MARGIN 4 + #define CASE_NOTEBOOK(x) #endif -#define RECREATE( wxBookType , idBook, oldBook , newBook ) \ -{ \ - int flags; \ - \ - switch ( m_orient ) \ - { \ - case ID_ORIENT_TOP: \ - flags = SelectFlag(idBook, wxNB_TOP, wxLB_TOP, wxCHB_TOP); \ - break; \ - \ - case ID_ORIENT_BOTTOM: \ - flags = SelectFlag(idBook, wxNB_BOTTOM, wxLB_BOTTOM, wxCHB_BOTTOM); \ - break; \ - \ - case ID_ORIENT_LEFT: \ - flags = SelectFlag(idBook, wxNB_LEFT, wxLB_LEFT, wxCHB_LEFT); \ - break; \ - \ - case ID_ORIENT_RIGHT: \ - flags = SelectFlag(idBook, wxNB_RIGHT, wxLB_RIGHT, wxCHB_RIGHT); \ - break; \ - \ - default: \ - flags = SelectFlag(idBook, wxNB_DEFAULT, wxLB_DEFAULT, wxCHB_DEFAULT); \ - } \ - \ - if ( m_multi && ( idBook == ID_NOTEBOOK ) ) \ - flags |= wxNB_MULTILINE; \ - \ - wxBookType *oldBook = newBook; \ - \ - newBook = new wxBookType(m_panel, idBook, \ - wxDefaultPosition, wxDefaultSize, \ - flags); \ - \ - if ( m_chkShowImages ) \ - { \ - newBook->SetImageList(m_imageList); \ - } \ - \ - if (oldBook) \ - { \ - int sel = oldBook->GetSelection(); \ - \ - int count = oldBook->GetPageCount(); \ - for (int n = 0; n < count; n++) \ - { \ - wxString str = oldBook->GetPageText(n); \ - \ - wxWindow *page = CreatePage(newBook, str); \ - newBook->AddPage(page, str, false, GetIconIndex(newBook) ); \ - } \ - \ - m_sizerFrame->Detach(oldBook); \ - \ - delete oldBook; \ - \ - if (sel != wxNOT_FOUND) \ - { \ - newBook->SetSelection(sel); \ - } \ - \ - } \ - else \ - { \ - CreateInitialPages(newBook); \ - } \ - \ - m_sizerFrame->Insert(0, newBook, 5, wxEXPAND | wxALL, MARGIN); \ - \ - m_sizerFrame->Hide(newBook); \ -} - -void MyFrame::RecreateBooks() -{ -#if wxUSE_NOTEBOOK - RECREATE( wxNotebook , ID_NOTEBOOK , notebook , m_notebook ); -#endif -#if wxUSE_LISTBOOK - RECREATE( wxListbook , ID_LISTBOOK , listbook , m_listbook ); -#endif #if wxUSE_CHOICEBOOK - RECREATE( wxChoicebook , ID_CHOICEBOOK , choicebook , m_choicebook ); + #define CASE_CHOICEBOOK(x) case Type_Choicebook: x; break; +#else + #define CASE_CHOICEBOOK(x) #endif - ShowCurrentBook(); -} - -wxBookCtrlBase *MyFrame::GetCurrentBook() -{ - switch (m_type) - { -#if wxUSE_NOTEBOOK - case ID_BOOK_NOTEBOOK: return m_notebook; -#endif #if wxUSE_LISTBOOK - case ID_BOOK_LISTBOOK: return m_listbook; + #define CASE_LISTBOOK(x) case Type_Listbook: x; break; +#else + #define CASE_LISTBOOK(x) #endif -#if wxUSE_CHOICEBOOK - case ID_BOOK_CHOICEBOOK: return m_choicebook; -#endif - } - return NULL; -} -void MyFrame::ShowCurrentBook() -{ - switch(m_type) - { -#if wxUSE_NOTEBOOK - case ID_BOOK_NOTEBOOK: if(m_notebook) m_sizerFrame->Show(m_notebook); break; -#endif -#if wxUSE_LISTBOOK - case ID_BOOK_LISTBOOK: if(m_listbook) m_sizerFrame->Show(m_listbook); break; -#endif -#if wxUSE_CHOICEBOOK - case ID_BOOK_CHOICEBOOK: if(m_choicebook) m_sizerFrame->Show(m_choicebook); break; +#if wxUSE_TREEBOOK + #define CASE_TREEBOOK(x) case Type_Treebook: x; break; +#else + #define CASE_TREEBOOK(x) #endif + +#define DISPATCH_ON_TYPE(before, nb, lb, cb, tb, after) \ + switch ( m_type ) \ + { \ + CASE_NOTEBOOK(before nb after) \ + CASE_CHOICEBOOK(before cb after) \ + CASE_LISTBOOK(before lb after) \ + CASE_TREEBOOK(before tb after) \ + \ + default: \ + wxFAIL_MSG( _T("unknown book control type") ); \ } +int MyFrame::TranslateBookFlag(int nb, int lb, int chb, int tbk) const +{ + int flag = 0; + + DISPATCH_ON_TYPE(flag =, nb, lb, chb, tbk, + 0); + + return flag; +} + +void MyFrame::RecreateBook() +{ +#define SELECT_FLAG(flag) \ + TranslateBookFlag(wxNB_##flag, wxCHB_##flag, wxLB_##flag, wxTBK_##flag) + + int flags; + switch ( m_orient ) + { + case ID_ORIENT_TOP: + flags = SELECT_FLAG(TOP); + break; + + case ID_ORIENT_BOTTOM: + flags = SELECT_FLAG(BOTTOM); + break; + + case ID_ORIENT_LEFT: + flags = SELECT_FLAG(LEFT); + break; + + case ID_ORIENT_RIGHT: + flags = SELECT_FLAG(RIGHT); + break; + + default: + flags = SELECT_FLAG(DEFAULT); + } + +#undef SELECT_FLAG + + if ( m_multi && m_type == Type_Notebook ) + flags |= wxNB_MULTILINE; + flags |= wxDOUBLE_BORDER; + + wxBookCtrlBase *oldBook = m_bookCtrl; + + m_bookCtrl = NULL; + + DISPATCH_ON_TYPE(m_bookCtrl = new, + wxNotebook, + wxChoicebook, + wxListbook, + wxTreebook, + (m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, flags)); + + if ( !m_bookCtrl ) + return; + + m_bookCtrl->Hide(); + + if ( m_chkShowImages ) + { + m_bookCtrl->SetImageList(m_imageList); + } + + if ( oldBook ) + { +#if wxUSE_TREEBOOK + // we only need the old treebook if we're recreating another treebook + wxTreebook *tbkOld = m_type == Type_Treebook + ? wxDynamicCast(oldBook, wxTreebook) + : NULL; +#endif // wxUSE_TREEBOOK + + const int count = oldBook->GetPageCount(); + for ( int n = 0; n < count; n++ ) + { + const int image = GetIconIndex(m_bookCtrl); + const wxString str = oldBook->GetPageText(n); + + wxWindow *page = CreatePage(m_bookCtrl, str); + + // treebook complication: need to account for possible parent page +#if wxUSE_TREEBOOK + if ( tbkOld ) + { + const int parent = tbkOld->GetPageParent(n); + if ( parent != wxNOT_FOUND ) + { + wxStaticCast(m_bookCtrl, wxTreebook)-> + AddSubPage(parent, page, str, false, image); + + // skip adding it again below + continue; + } + } +#endif // wxUSE_TREEBOOK + + m_bookCtrl->AddPage(page, str, false, image); + } + + const int sel = oldBook->GetSelection(); + if ( sel != wxNOT_FOUND ) + m_bookCtrl->SetSelection(sel); + + + m_sizerFrame->Detach(oldBook); + delete oldBook; + } + else // no old book + { + CreateInitialPages(m_bookCtrl); + } + + m_sizerFrame->Insert(0, m_bookCtrl, wxSizerFlags(5).Expand().Border()); + + m_sizerFrame->Show(m_bookCtrl); m_sizerFrame->Layout(); } BEGIN_EVENT_TABLE(MyFrame, wxFrame) // File menu - EVT_MENU_RANGE(ID_BOOK_NOTEBOOK,ID_BOOK_MAX,MyFrame::OnType) - EVT_MENU_RANGE(ID_ORIENT_DEFAULT,ID_ORIENT_MAX,MyFrame::OnOrient) + EVT_MENU_RANGE(ID_BOOK_NOTEBOOK, ID_BOOK_MAX, MyFrame::OnType) + EVT_MENU_RANGE(ID_ORIENT_DEFAULT, ID_ORIENT_MAX, MyFrame::OnOrient) EVT_MENU(ID_SHOW_IMAGES, MyFrame::OnShowImages) EVT_MENU(ID_MULTI, MyFrame::OnMulti) - EVT_MENU(wxID_EXIT,MyFrame::OnExit) + EVT_MENU(wxID_EXIT, MyFrame::OnExit) // Operations menu EVT_MENU(ID_ADD_PAGE, MyFrame::OnAddPage) @@ -483,55 +474,74 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(ID_DELETE_CUR_PAGE, MyFrame::OnDeleteCurPage) EVT_MENU(ID_DELETE_LAST_PAGE, MyFrame::OnDeleteLastPage) EVT_MENU(ID_NEXT_PAGE, MyFrame::OnNextPage) + EVT_MENU(ID_ADD_SUB_PAGE, MyFrame::OnAddSubPage) + EVT_MENU(ID_ADD_PAGE_BEFORE, MyFrame::OnAddPageBefore) // Book controls #if wxUSE_NOTEBOOK - EVT_NOTEBOOK_PAGE_CHANGED(ID_NOTEBOOK, MyFrame::OnNotebook) - EVT_NOTEBOOK_PAGE_CHANGING(ID_NOTEBOOK, MyFrame::OnNotebook) + EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, MyFrame::OnNotebook) + EVT_NOTEBOOK_PAGE_CHANGING(wxID_ANY, MyFrame::OnNotebook) #endif #if wxUSE_LISTBOOK - EVT_LISTBOOK_PAGE_CHANGED(ID_LISTBOOK, MyFrame::OnListbook) - EVT_LISTBOOK_PAGE_CHANGING(ID_LISTBOOK, MyFrame::OnListbook) + EVT_LISTBOOK_PAGE_CHANGED(wxID_ANY, MyFrame::OnListbook) + EVT_LISTBOOK_PAGE_CHANGING(wxID_ANY, MyFrame::OnListbook) #endif #if wxUSE_CHOICEBOOK - EVT_CHOICEBOOK_PAGE_CHANGED(ID_CHOICEBOOK, MyFrame::OnChoicebook) - EVT_CHOICEBOOK_PAGE_CHANGING(ID_CHOICEBOOK, MyFrame::OnChoicebook) + EVT_CHOICEBOOK_PAGE_CHANGED(wxID_ANY, MyFrame::OnChoicebook) + EVT_CHOICEBOOK_PAGE_CHANGING(wxID_ANY, MyFrame::OnChoicebook) +#endif +#if wxUSE_CHOICEBOOK + EVT_TREEBOOK_PAGE_CHANGED(wxID_ANY, MyFrame::OnTreebook) + EVT_TREEBOOK_PAGE_CHANGING(wxID_ANY, MyFrame::OnTreebook) #endif // Update title in idle time EVT_IDLE(MyFrame::OnIdle) + +#if wxUSE_TREEBOOK + EVT_UPDATE_UI_RANGE(ID_ADD_PAGE_BEFORE, ID_ADD_SUB_PAGE, + MyFrame::OnUpdateTreeMenu) +#endif // wxUSE_TREEBOOK END_EVENT_TABLE() void MyFrame::OnType(wxCommandEvent& event) { - wxBookCtrlBase *currBook = GetCurrentBook(); + m_type = wx_static_cast(BookType, event.GetId() - ID_BOOK_NOTEBOOK); - m_type = event.GetId(); + if ( m_bookCtrl ) + m_sizerFrame->Hide(m_bookCtrl); - if (currBook) - m_sizerFrame->Hide(currBook); - - ShowCurrentBook(); + RecreateBook(); } +#if wxUSE_TREEBOOK + +void MyFrame::OnUpdateTreeMenu(wxUpdateUIEvent& event) +{ + event.Enable(m_type == Type_Treebook); +} + +#endif // wxUSE_TREEBOOK + + void MyFrame::OnOrient(wxCommandEvent& event) { m_orient = event.GetId(); - RecreateBooks(); + RecreateBook(); m_sizerFrame->Layout(); } void MyFrame::OnShowImages(wxCommandEvent& event) { m_chkShowImages = event.IsChecked(); - RecreateBooks(); + RecreateBook(); m_sizerFrame->Layout(); } void MyFrame::OnMulti(wxCommandEvent& event) { m_multi = event.IsChecked(); - RecreateBooks(); + RecreateBook(); m_sizerFrame->Layout(); wxLogMessage(_T("Multiline setting works only in wxNotebook.")); } @@ -541,25 +551,85 @@ void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event)) Close(); } +wxPanel *MyFrame::CreateNewPage() const +{ + wxPanel *panel = new wxPanel(m_bookCtrl, wxID_ANY ); + (void) new wxButton(panel, wxID_ANY, wxT("First button"), wxPoint(10, 10)); + (void) new wxButton(panel, wxID_ANY, wxT("Second button"), wxPoint(50, 100)); + + return panel; +} + void MyFrame::OnAddPage(wxCommandEvent& WXUNUSED(event)) { - static unsigned s_pageAdded = 0; - wxBookCtrlBase *currBook = GetCurrentBook(); if ( currBook ) { - wxPanel *panel = new wxPanel( currBook, wxID_ANY ); - (void) new wxButton( panel, wxID_ANY, wxT("First button"), - wxPoint(10, 10), wxDefaultSize ); - (void) new wxButton( panel, wxID_ANY, wxT("Second button"), - wxPoint(50, 100), wxDefaultSize ); - - currBook->AddPage(panel, wxString::Format(ADDED_PAGE_NAME wxT("%u"), - ++s_pageAdded), true, GetIconIndex(currBook) ); + static unsigned s_pageAdded = 0; + currBook->AddPage(CreateNewPage(), + wxString::Format + ( + ADDED_PAGE_NAME wxT("%u"), + ++s_pageAdded + ), + true, + GetIconIndex(currBook)); } } +#if wxUSE_TREEBOOK +void MyFrame::OnAddSubPage(wxCommandEvent& WXUNUSED(event)) +{ + wxTreebook *currBook = wxDynamicCast(GetCurrentBook(), wxTreebook); + if ( currBook ) + { + const int selPos = currBook->GetSelection(); + if ( selPos == wxNOT_FOUND ) + { + wxLogError(_T("Select the parent page first!")); + return; + } + + static unsigned s_subPageAdded = 0; + currBook->AddSubPage(selPos, + CreateNewPage(), + wxString::Format + ( + ADDED_SUB_PAGE_NAME wxT("%u"), + ++s_subPageAdded + ), + true, + GetIconIndex(currBook)); + } +} + +void MyFrame::OnAddPageBefore(wxCommandEvent& WXUNUSED(event)) +{ + wxBookCtrlBase *currBook = GetCurrentBook(); + if ( currBook ) + { + const int selPos = currBook->GetSelection(); + if ( selPos == wxNOT_FOUND ) + { + wxLogError(_T("Select the parent page first!")); + return; + } + + static unsigned s_subPageAdded = 0; + currBook->InsertPage(selPos, + CreateNewPage(), + wxString::Format + ( + ADDED_PAGE_NAME_BEFORE wxT("%u"), + ++s_subPageAdded + ), + true, + GetIconIndex(currBook)); + } +} +#endif // wxUSE_TREEBOOK + void MyFrame::OnInsertPage(wxCommandEvent& WXUNUSED(event)) { static unsigned s_pageIns = 0; @@ -648,65 +718,103 @@ void MyFrame::OnIdle( wxIdleEvent& WXUNUSED(event) ) } } -#if USE_LOG - #define BOOKEVENT_LOG m_text->SetInsertionPointEnd(); -#else - #define BOOKEVENT_LOG -#endif +void MyFrame::OnBookCtrl(wxBookCtrlBaseEvent& event) +{ + static const struct EventInfo + { + wxEventType typeChanged, + typeChanging; + const wxChar *name; + } events[] = + { +#if wxUSE_NOTEBOOK + { + wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, + wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, + _T("wxNotebook") + }, +#endif // wxUSE_NOTEBOOK +#if wxUSE_CHOICEBOOK + { + wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED, + wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING, + _T("wxChoicebook") + }, +#endif // wxUSE_CHOICEBOOK +#if wxUSE_LISTBOOK + { + wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED, + wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING, + _T("wxListbook") + }, +#endif // wxUSE_LISTBOOK +#if wxUSE_TREEBOOK + { + wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED, + wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, + _T("wxTreebook") + }, +#endif // wxUSE_TREEBOOK + }; -#define BOOKEVENT(OnBook,wxBookEvent,bookStr,wxEVT_PAGE_CHANGED,wxEVT_PAGE_CHANGING,s_num) \ -void MyFrame::OnBook(wxBookEvent& event) \ -{ \ - wxString str = wxT("Unknown "); \ - str << wxT(bookStr); \ - str << wxT(" event"); \ - \ - wxEventType eventType = event.GetEventType(); \ - \ - if (eventType == wxEVT_PAGE_CHANGED) \ - { \ - str = wxT("Changed"); \ - } \ - else if (eventType == wxEVT_PAGE_CHANGING) \ - { \ - int idx = event.GetOldSelection(); \ - wxBookCtrlBase *book = (wxBookCtrlBase *)event.GetEventObject(); \ - if ( idx != wxNOT_FOUND && book && book->GetPageText(idx) == VETO_PAGE_NAME ) \ - { \ - if \ - ( \ - wxMessageBox( \ - wxT("Are you sure you want to leave this page?\n") \ - wxT("(This demonstrates veto-ing)"), \ - wxT("Notebook sample"), \ - wxICON_QUESTION | wxYES_NO, this) != wxYES ) \ - { \ - event.Veto(); \ - } \ - \ - } \ - \ - str = wxT("Changing"); \ - } \ - \ - static int s_num = 0; \ - \ - wxString logMsg; \ - logMsg.Printf(wxT("%s event #%d: %s (%d) Sel %d, OldSel %d"), \ - wxT(bookStr),s_num++, str.c_str(), eventType, \ - event.GetSelection(), event.GetOldSelection()); \ - \ - wxLogMessage(logMsg.c_str()); \ - \ - BOOKEVENT_LOG \ + + wxString nameEvent, + nameControl, + veto; + const wxEventType eventType = event.GetEventType(); + for ( size_t n = 0; n < WXSIZEOF(events); n++ ) + { + const EventInfo& ei = events[n]; + if ( eventType == ei.typeChanged ) + { + nameEvent = wxT("Changed"); + } + else if ( eventType == ei.typeChanging ) + { + const int idx = event.GetOldSelection(); + const wxBookCtrlBase * const + book = wxStaticCast(event.GetEventObject(), wxBookCtrlBase); + if ( idx != wxNOT_FOUND && + book && book->GetPageText(idx) == VETO_PAGE_NAME ) + { + if ( wxMessageBox + ( + wxT("Are you sure you want to leave this page?\n") + wxT("(This demonstrates veto-ing)"), + wxT("Notebook sample"), + wxICON_QUESTION | wxYES_NO, + this + ) != wxYES ) + { + event.Veto(); + veto = _T(" (vetoed)"); + } + } + + nameEvent = wxT("Changing"); + } + else // skip end of the loop + { + continue; + } + + nameControl = ei.name; + break; + } + + static int s_num = 0; + + wxLogMessage(wxT("Event #%d: %s: %s (%d) new sel %d, old %d%s"), + ++s_num, + nameControl.c_str(), + nameEvent.c_str(), + eventType, + event.GetSelection(), + event.GetOldSelection(), + veto.c_str()); + +#if USE_LOG + m_text->SetInsertionPointEnd(); +#endif } -#if wxUSE_NOTEBOOK -BOOKEVENT(OnNotebook,wxNotebookEvent,"wxNotebook",wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING,s_numNotebookEvents) -#endif -#if wxUSE_CHOICEBOOK -BOOKEVENT(OnChoicebook,wxChoicebookEvent,"wxChoicebook",wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED,wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING,s_numChoicebookEvents) -#endif -#if wxUSE_LISTBOOK -BOOKEVENT(OnListbook,wxListbookEvent,"wxListbook",wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED,wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING,s_numListbookEvents) -#endif diff --git a/samples/notebook/notebook.h b/samples/notebook/notebook.h index 1eac27735d..42bd6088af 100644 --- a/samples/notebook/notebook.h +++ b/samples/notebook/notebook.h @@ -11,6 +11,7 @@ #include "wx/choicebk.h" #include "wx/listbook.h" +#include "wx/treebook.h" #include "wx/notebook.h" #if wxUSE_LOG && !defined( __SMARTPHONE__ ) @@ -28,12 +29,11 @@ public: DECLARE_APP(MyApp) + class MyFrame : public wxFrame { public: - MyFrame(const wxString& title, const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE|wxCLIP_CHILDREN|wxNO_FULL_REPAINT_ON_RESIZE); - + MyFrame(); virtual ~MyFrame(); void OnType(wxCommandEvent& event); @@ -48,29 +48,47 @@ public: void OnDeleteLastPage(wxCommandEvent& event); void OnNextPage(wxCommandEvent& event); + void OnAddSubPage(wxCommandEvent& event); + void OnAddPageBefore(wxCommandEvent& event); + + void OnBookCtrl(wxBookCtrlBaseEvent& event); #if wxUSE_NOTEBOOK - void OnNotebook(wxNotebookEvent& event); + void OnNotebook(wxNotebookEvent& event) { OnBookCtrl(event); } #endif #if wxUSE_CHOICEBOOK - void OnChoicebook(wxChoicebookEvent& event); + void OnChoicebook(wxChoicebookEvent& event) { OnBookCtrl(event); } #endif #if wxUSE_LISTBOOK - void OnListbook(wxListbookEvent& event); + void OnListbook(wxListbookEvent& event) { OnBookCtrl(event); } +#endif +#if wxUSE_TREEBOOK + void OnTreebook(wxTreebookEvent& event) { OnBookCtrl(event); } #endif void OnIdle(wxIdleEvent& event); - wxBookCtrlBase *GetCurrentBook(); +#if wxUSE_TREEBOOK + void OnUpdateTreeMenu(wxUpdateUIEvent& event); +#endif // wxUSE_TREEBOOK + + wxBookCtrlBase *GetCurrentBook() const { return m_bookCtrl; } private: wxLog *m_logTargetOld; - int SelectFlag(int id, int nb, int lb, int chb); - void ShowCurrentBook(); - void RecreateBooks(); + void RecreateBook(); + wxPanel *CreateNewPage() const; + int TranslateBookFlag(int nb, int lb, int chb, int tbk) const; // Sample setup - int m_type; + enum BookType + { + Type_Notebook, + Type_Choicebook, + Type_Listbook, + Type_Treebook, + Type_Max + } m_type; int m_orient; bool m_chkShowImages; bool m_multi; @@ -78,16 +96,7 @@ private: // Controls wxPanel *m_panel; // Panel containing notebook and other controls - -#if wxUSE_NOTEBOOK - wxNotebook *m_notebook; -#endif -#if wxUSE_CHOICEBOOK - wxChoicebook *m_choicebook; -#endif -#if wxUSE_LISTBOOK - wxListbook *m_listbook; -#endif + wxBookCtrlBase *m_bookCtrl; #if USE_LOG // Log window @@ -103,10 +112,13 @@ private: enum ID_COMMANDS { + // these should be in the same order as Type_XXX elements above ID_BOOK_NOTEBOOK = wxID_HIGHEST, ID_BOOK_LISTBOOK, ID_BOOK_CHOICEBOOK, + ID_BOOK_TREEBOOK, ID_BOOK_MAX, + ID_ORIENT_DEFAULT, ID_ORIENT_TOP, ID_ORIENT_BOTTOM, @@ -120,9 +132,8 @@ enum ID_COMMANDS ID_DELETE_CUR_PAGE, ID_DELETE_LAST_PAGE, ID_NEXT_PAGE, - ID_NOTEBOOK, - ID_LISTBOOK, - ID_CHOICEBOOK + ID_ADD_PAGE_BEFORE, + ID_ADD_SUB_PAGE }; /* @@ -139,3 +150,7 @@ to decide what type of page it is. // Pages that can be added by the user #define INSERTED_PAGE_NAME wxT("Inserted ") #define ADDED_PAGE_NAME wxT("Added ") +#define ADDED_PAGE_NAME_BEFORE wxT(" Inserted before ") +#define ADDED_SUB_PAGE_NAME wxT(" Inserted sub-page ") + + diff --git a/samples/xrc/rc/controls.xrc b/samples/xrc/rc/controls.xrc index 8826f43fde..9c71c14d5f 100644 --- a/samples/xrc/rc/controls.xrc +++ b/samples/xrc/rc/controls.xrc @@ -19,6 +19,43 @@ 1 550,200 + + + + 350,280 + + + + 0 + + 200,180 + + + + + + 1 + + + + 2 + + 200,180 + + + + + + 1 + + 200,180 + + + + + + + diff --git a/setup.h.in b/setup.h.in index 089f1c568e..1b8e5a8d0a 100644 --- a/setup.h.in +++ b/setup.h.in @@ -329,6 +329,8 @@ #define wxUSE_CHOICEBOOK 0 +#define wxUSE_TREEBOOK 0 + #define wxUSE_TAB_DIALOG 0 #define wxUSE_GRID 0 diff --git a/setup.h_vms b/setup.h_vms index 6eb38eeeaa..760f35b260 100644 --- a/setup.h_vms +++ b/setup.h_vms @@ -344,6 +344,8 @@ #define wxUSE_CHOICEBOOK 1 +#define wxUSE_TREEBOOK 1 + #define wxUSE_TAB_DIALOG 1 #define wxUSE_GRID 1 diff --git a/src/common/bookctrl.cpp b/src/common/bookctrl.cpp index 2a995a9e51..eccc863d6a 100644 --- a/src/common/bookctrl.cpp +++ b/src/common/bookctrl.cpp @@ -114,14 +114,17 @@ wxSize wxBookCtrlBase::DoGetBestSize() const const size_t nCount = m_pages.size(); for ( size_t nPage = 0; nPage < nCount; nPage++ ) { - wxWindow *pPage = m_pages[nPage]; - wxSize childBestSize(pPage->GetBestSize()); + const wxWindow * const pPage = m_pages[nPage]; + if( pPage ) + { + wxSize childBestSize(pPage->GetBestSize()); - if ( childBestSize.x > bestSize.x ) - bestSize.x = childBestSize.x; + if ( childBestSize.x > bestSize.x ) + bestSize.x = childBestSize.x; - if ( childBestSize.y > bestSize.y ) - bestSize.y = childBestSize.y; + if ( childBestSize.y > bestSize.y ) + bestSize.y = childBestSize.y; + } } // convert display area to window area, adding the size necessary for the @@ -142,7 +145,7 @@ wxBookCtrlBase::InsertPage(size_t nPage, bool WXUNUSED(bSelect), int WXUNUSED(imageId)) { - wxCHECK_MSG( page, false, _T("NULL page in wxBookCtrlBase::InsertPage()") ); + wxCHECK_MSG( page || AllowNullPage(), false, _T("NULL page in wxBookCtrlBase::InsertPage()") ); wxCHECK_MSG( nPage <= m_pages.size(), false, _T("invalid page index in wxBookCtrlBase::InsertPage()") ); @@ -155,9 +158,10 @@ wxBookCtrlBase::InsertPage(size_t nPage, bool wxBookCtrlBase::DeletePage(size_t nPage) { wxWindow *page = DoRemovePage(nPage); - if ( !page ) + if ( !(page || AllowNullPage()) ) return false; + // delete NULL is harmless delete page; return true; diff --git a/src/generic/treebkg.cpp b/src/generic/treebkg.cpp new file mode 100644 index 0000000000..3b085c01b5 --- /dev/null +++ b/src/generic/treebkg.cpp @@ -0,0 +1,807 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/treebkg.cpp +// Purpose: generic implementation of wxTreebook +// Author: Evgeniy Tarassov, Vadim Zeitlin +// Modified by: +// Created: 2005-09-15 +// RCS-ID: $Id$ +// Copyright: (c) 2005 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TREEBOOK + +#include "wx/treebook.h" +#include "wx/imaglist.h" +#include "wx/settings.h" + +// ---------------------------------------------------------------------------- +// various wxWidgets macros +// ---------------------------------------------------------------------------- + +// check that the page index is valid +#define IS_VALID_PAGE(nPage) ((nPage) < DoInternalGetPageCount()) + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTreebook, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxTreebookEvent, wxNotifyEvent) + +const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING = wxNewEventType(); +const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED = wxNewEventType(); +const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED = wxNewEventType(); +const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED = wxNewEventType(); +const int wxID_TREEBOOKTREEVIEW = wxNewId(); + +BEGIN_EVENT_TABLE(wxTreebook, wxBookCtrlBase) + EVT_SIZE(wxTreebook::OnSize) + EVT_TREE_SEL_CHANGED (wxID_TREEBOOKTREEVIEW, wxTreebook::OnTreeSelectionChange) + EVT_TREE_ITEM_EXPANDED (wxID_TREEBOOKTREEVIEW, wxTreebook::OnTreeNodeExpandedCollapsed) + EVT_TREE_ITEM_COLLAPSED(wxID_TREEBOOKTREEVIEW, wxTreebook::OnTreeNodeExpandedCollapsed) +END_EVENT_TABLE() + +// ============================================================================ +// wxTreebook implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxTreebook creation +// ---------------------------------------------------------------------------- + +void wxTreebook::Init() +{ + m_tree = NULL; + m_selection = + m_actualSelection = wxNOT_FOUND; +} + +bool +wxTreebook::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + // Check the style flag to have either wxTBK_RIGHT or wxTBK_LEFT + if ( style & wxTBK_RIGHT ) + { + wxASSERT_MSG( !(style & wxTBK_LEFT), + _T("RIGHT and LEFT can't be used together") ); + } + else + { + style |= wxTBK_LEFT; + } + + // no border for this control, it doesn't look nice together with the tree + style &= ~wxBORDER_MASK; + style |= wxBORDER_NONE; + + if ( !wxControl::Create(parent, id, pos, size, + style, wxDefaultValidator, name) ) + return false; + + m_tree = new wxTreeCtrl + ( + this, + wxID_TREEBOOKTREEVIEW, + wxDefaultPosition, + wxDefaultSize, + wxBORDER_SIMPLE | + wxTR_HAS_BUTTONS | + wxTR_HIDE_ROOT | + wxTR_LINES_AT_ROOT | + wxTR_SINGLE + ); + m_tree->AddRoot(wxEmptyString); // label doesn't matter, it's hidden + +#ifdef __WXMSW__ + // see listbook.h for origins of that + // On XP with themes enabled the GetViewRect used in GetListSize to + // determine the space needed for the list view will incorrectly return + // (0,0,0,0) the first time. So send a pending event so OnSize will be + // called again after the window is ready to go. Technically we don't + // need to do this on non-XP windows, but if things are already sized + // correctly then nothing changes and so there is no harm. + wxSizeEvent evt; + GetEventHandler()->AddPendingEvent(evt); +#endif + + return true; +} + + +// insert a new page just before the pagePos +bool wxTreebook::InsertPage(size_t pagePos, + wxWindow *page, + const wxString& text, + bool bSelect, + int imageId) +{ + return DoInsertPage(pagePos, page, text, bSelect, imageId); +} + +bool wxTreebook::AddSubPage(size_t pagePos, + wxWindow *page, + const wxString& text, + bool bSelect, + int imageId) +{ + return DoInsertSubPage(pagePos, page, text, bSelect, imageId); +} + +bool wxTreebook::AddPage(wxWindow *page, const wxString& text, bool bSelect, + int imageId) +{ + return DoInsertPage(m_treeIds.GetCount(), page, text, bSelect, imageId); +} + +// insertion time is linear to the number of top-pages +bool wxTreebook::AddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId) +{ + return DoAddSubPage(page, text, bSelect, imageId); +} + + +bool wxTreebook::DoInsertPage(size_t pagePos, + wxWindow *page, + const wxString& text, + bool bSelect, + int imageId) +{ + wxCHECK_MSG( pagePos <= DoInternalGetPageCount(), false, + wxT("Invalid treebook page position") ); + + if ( !wxBookCtrlBase::InsertPage(pagePos, page, text, bSelect, imageId) ) + return false; + + wxTreeItemId newId; + if ( pagePos == DoInternalGetPageCount() ) + { + // append the page to the end + wxTreeItemId rootId = m_tree->GetRootItem(); + + newId = m_tree->AppendItem(rootId, text, imageId); + } + else // insert the new page before the given one + { + wxTreeItemId nodeId = m_treeIds[pagePos]; + + wxTreeItemId previousId = m_tree->GetPrevSibling(nodeId); + wxTreeItemId parentId = m_tree->GetItemParent(nodeId); + + if ( previousId.IsOk() ) + { + // insert before the sibling - previousId + newId = m_tree->InsertItem(parentId, previousId, text, imageId); + } + else // no prev siblings -- insert as a first child + { + wxASSERT_MSG( parentId.IsOk(), wxT( "Tree has no root node?" ) ); + + newId = m_tree->PrependItem(parentId, text, imageId); + } + } + + if ( !newId.IsOk() ) + { + //something wrong -> cleaning and returning with false + (void)wxBookCtrlBase::DoRemovePage(pagePos); + + wxFAIL_MSG( wxT("Failed to insert treebook page") ); + return false; + } + + DoInternalAddPage(pagePos, page, newId); + + DoUpdateSelection(bSelect, pagePos); + + return true; +} + +bool wxTreebook::DoAddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId) +{ + wxTreeItemId rootId = m_tree->GetRootItem(); + + wxTreeItemId lastNodeId = m_tree->GetLastChild(rootId); + + wxCHECK_MSG( lastNodeId.IsOk(), false, + _T("Can't insert sub page when there are no pages") ); + + // now calculate its position (should we save/update it too?) + size_t newPos = m_tree->GetCount() - + (m_tree->GetChildrenCount(lastNodeId, true) + 1); + + return DoInsertSubPage(newPos, page, text, bSelect, imageId); +} + +bool wxTreebook::DoInsertSubPage(size_t pagePos, + wxTreebookPage *page, + const wxString& text, + bool bSelect, + int imageId) +{ + wxTreeItemId parentId = DoInternalGetPage(pagePos); + wxCHECK_MSG( parentId.IsOk(), false, wxT("invalid tree item") ); + + size_t newPos = pagePos + m_tree->GetChildrenCount(parentId, true) + 1; + wxASSERT_MSG( newPos <= DoInternalGetPageCount(), + wxT("Internal error in tree insert point calculation") ); + + if ( !wxBookCtrlBase::InsertPage(newPos, page, text, bSelect, imageId) ) + return false; + + wxTreeItemId newId = m_tree->AppendItem(parentId, text, imageId); + + if ( !newId.IsOk() ) + { + (void)wxBookCtrlBase::DoRemovePage(newPos); + + wxFAIL_MSG( wxT("Failed to insert treebook page") ); + return false; + } + + DoInternalAddPage(newPos, page, newId); + + DoUpdateSelection(bSelect, newPos); + + return true; +} + +bool wxTreebook::DeletePage(size_t pagePos) +{ + wxCHECK_MSG( IS_VALID_PAGE(pagePos), false, wxT("Invalid tree index") ); + + wxTreebookPage *oldPage = DoRemovePage(pagePos); + if ( !oldPage ) + return false; + + delete oldPage; + + return true; +} + +wxTreebookPage *wxTreebook::DoRemovePage(size_t pagePos) +{ + wxTreeItemId pageId = DoInternalGetPage(pagePos); + wxCHECK_MSG( pageId.IsOk(), NULL, wxT("Invalid tree index") ); + + wxTreebookPage * oldPage = GetPage(pagePos); + + size_t subCount = m_tree->GetChildrenCount(pageId, true); + wxASSERT_MSG ( IS_VALID_PAGE(pagePos + subCount), + wxT("Internal error in wxTreebook::DoRemovePage") ); + + // here we are going to delete ALL the pages in the range + // [pagePos, pagePos + subCount] -- the page and its children + + // deleting all the pages from the base class + for ( size_t i = 0; i <= subCount; ++i ) + { + wxTreebookPage *page = wxBookCtrlBase::DoRemovePage(pagePos); + + // don't delete the page itself though -- it will be deleted in + // DeletePage() when we return + if ( i ) + { + delete page; + } + } + + DoInternalRemovePageRange(pagePos, subCount); + + m_tree->DeleteChildren( pageId ); + m_tree->Delete( pageId ); + + return oldPage; +} + +bool wxTreebook::DeleteAllPages() +{ + wxBookCtrlBase::DeleteAllPages(); + m_treeIds.Clear(); + m_selection = + m_actualSelection = wxNOT_FOUND; + + m_tree->DeleteChildren(m_tree->GetRootItem()); + + return true; +} + +void wxTreebook::DoInternalAddPage(size_t newPos, + wxTreebookPage *page, + wxTreeItemId pageId) +{ + wxASSERT_MSG( newPos <= m_treeIds.GetCount(), wxT("Ivalid index passed to wxTreebook::DoInternalAddPage") ); + + // hide newly inserted page initially (it will be shown when selected) + if ( page ) + page->Hide(); + + if ( newPos == m_treeIds.GetCount() ) + { + // append + m_treeIds.Add(pageId); + } + else // insert + { + m_treeIds.Insert(pageId, newPos); + + if ( m_selection != wxNOT_FOUND && newPos <= (size_t)m_selection ) + { + // selection has been moved one unit toward the end + ++m_selection; + if ( m_actualSelection != wxNOT_FOUND ) + ++m_actualSelection; + } + else if ( m_actualSelection != wxNOT_FOUND && + newPos <= (size_t)m_actualSelection ) + { + DoSetSelection(m_selection); + } + } +} + +void wxTreebook::DoInternalRemovePageRange(size_t pagePos, size_t subCount) +{ + // Attention: this function is only for a situation when we delete a node + // with all its children so pagePos is the node's index and subCount is the + // node children count + wxASSERT_MSG( pagePos + subCount < m_treeIds.GetCount(), + wxT("Ivalid page index") ); + + wxTreeItemId pageId = m_treeIds[pagePos]; + + m_treeIds.RemoveAt(pagePos, subCount + 1); + + if ( m_selection != wxNOT_FOUND ) + { + if ( (size_t)m_selection > pagePos + subCount) + { + // selection is far after the deleted page, so just update the index and move on + m_selection -= 1 + subCount; + if ( m_actualSelection != wxNOT_FOUND) + { + m_actualSelection -= subCount + 1; + } + } + else if ( (size_t)m_selection >= pagePos ) + { + // as selected page is going to be deleted, try to select the next + // sibling if exists, if not then the parent + wxTreeItemId nodeId = m_tree->GetNextSibling(pageId); + + m_selection = wxNOT_FOUND; + m_actualSelection = wxNOT_FOUND; + + if ( nodeId.IsOk() ) + { + // selecting next siblings + m_tree->SelectItem(nodeId); + } + else // no next sibling, select the parent + { + wxTreeItemId parentId = m_tree->GetItemParent(pageId); + + if ( parentId.IsOk() && parentId != m_tree->GetRootItem() ) + { + m_tree->SelectItem(parentId); + } + else // parent is root + { + // we can't select it as it's hidden + DoUpdateSelection(false, wxNOT_FOUND); + } + } + } + else if ( m_actualSelection != wxNOT_FOUND && + (size_t)m_actualSelection >= pagePos ) + { + // nothing to do -- selection is before the deleted node, but + // actually shown page (the first (sub)child with page != NULL) is + // already deleted + m_actualSelection = m_selection; + DoSetSelection(m_selection); + } + //else: nothing to do -- selection is before the deleted node + } + else + { + DoUpdateSelection(false, wxNOT_FOUND); + } +} + + +void wxTreebook::DoUpdateSelection(bool bSelect, int newPos) +{ + int newSelPos; + if ( bSelect ) + { + newSelPos = newPos; + } + else if ( m_selection == wxNOT_FOUND && DoInternalGetPageCount() > 0 ) + { + newSelPos = 0; + } + else + { + newSelPos = wxNOT_FOUND; + } + + if ( newSelPos != wxNOT_FOUND ) + { + SetSelection((size_t)newSelPos); + } +} + +wxTreeItemId wxTreebook::DoInternalGetPage(size_t pagePos) const +{ + if ( pagePos >= m_treeIds.GetCount() ) + { + // invalid position but ok here, in this internal function, don't assert + // (the caller will do it) + return wxTreeItemId(); + } + + return m_treeIds[pagePos]; +} + +int wxTreebook::DoInternalFindPageById(wxTreeItemId pageId) const +{ + const size_t count = m_treeIds.GetCount(); + for ( size_t i = 0; i < count; ++i ) + { + if ( m_treeIds[i] == pageId ) + return i; + } + + return wxNOT_FOUND; +} + +bool wxTreebook::IsNodeExpanded(size_t pagePos) const +{ + wxTreeItemId pageId = DoInternalGetPage(pagePos); + + wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); + + return m_tree->IsExpanded(pageId); +} + +bool wxTreebook::ExpandNode(size_t pagePos, bool expand) +{ + wxTreeItemId pageId = DoInternalGetPage(pagePos); + + wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); + + if ( expand ) + { + m_tree->Expand( pageId ); + } + else // collapse + { + m_tree->Collapse( pageId ); + + // rely on the events generated by wxTreeCtrl to update selection + } + + return true; +} + +int wxTreebook::GetPageParent(size_t pagePos) const +{ + wxTreeItemId nodeId = DoInternalGetPage( pagePos ); + wxCHECK_MSG( nodeId.IsOk(), wxNOT_FOUND, wxT("Invalid page index spacified!") ); + + const wxTreeItemId parent = m_tree->GetItemParent( nodeId ); + + return parent.IsOk() ? DoInternalFindPageById(parent) : wxNOT_FOUND; +} + +bool wxTreebook::SetPageText(size_t n, const wxString& strText) +{ + wxTreeItemId pageId = DoInternalGetPage(n); + + wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); + + m_tree->SetItemText(pageId, strText); + + return true; +} + +wxString wxTreebook::GetPageText(size_t n) const +{ + wxTreeItemId pageId = DoInternalGetPage(n); + + wxCHECK_MSG( pageId.IsOk(), wxString(), wxT("invalid tree item") ); + + return m_tree->GetItemText(pageId); +} + +int wxTreebook::GetPageImage(size_t n) const +{ + wxTreeItemId pageId = DoInternalGetPage(n); + + wxCHECK_MSG( pageId.IsOk(), wxNOT_FOUND, wxT("invalid tree item") ); + + return m_tree->GetItemImage(pageId); +} + +bool wxTreebook::SetPageImage(size_t n, int imageId) +{ + wxTreeItemId pageId = DoInternalGetPage(n); + + wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); + + m_tree->SetItemImage(pageId, imageId); + + return true; +} + +wxSize wxTreebook::CalcSizeFromPage(const wxSize& sizePage) const +{ + const wxSize sizeTree = GetTreeSize(); + + wxSize size = sizePage; + size.x += sizeTree.x; + + return size; +} + +int wxTreebook::GetSelection() const +{ + return m_selection; +} + +int wxTreebook::SetSelection(size_t pagePos) +{ + if ( (size_t)m_selection != pagePos ) + return DoSetSelection(pagePos); + + return m_selection; +} + +int wxTreebook::DoSetSelection(size_t pagePos) +{ + wxCHECK_MSG( IS_VALID_PAGE(pagePos), wxNOT_FOUND, + wxT("invalid page index in wxListbook::SetSelection()") ); + wxASSERT_MSG( GetPageCount() == DoInternalGetPageCount(), + wxT("wxTreebook logic error: m_treeIds and m_pages not in sync!")); + + const int oldSel = m_selection; + + wxTreebookEvent event(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, m_windowId); + event.SetEventObject(this); + event.SetSelection(pagePos); + event.SetOldSelection(m_selection); + + // don't send the event if the old and new pages are the same; do send it + // otherwise and be prepared for it to be vetoed + if ( (int)pagePos == m_selection || + !GetEventHandler()->ProcessEvent(event) || + event.IsAllowed() ) + { + // hide the previously shown page + wxTreebookPage * const oldPage = DoGetCurrentPage(); + if ( oldPage ) + oldPage->Hide(); + + // then show the new one + m_selection = pagePos; + wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection); + if ( !page ) + { + // find the next page suitable to be shown: the first (grand)child + // of this one with a non-NULL associated page + wxTreeItemId childId = m_treeIds[pagePos]; + m_actualSelection = pagePos; + while ( !page && childId.IsOk() ) + { + wxTreeItemIdValue cookie; + childId = m_tree->GetFirstChild( childId, cookie ); + if ( childId.IsOk() ) + { + page = wxBookCtrlBase::GetPage(++m_actualSelection); + } + } + + wxASSERT_MSG( page, wxT("no page to show found!") ); + } + + if ( page ) + { + page->SetSize(GetPageRect()); + page->Show(); + } + + m_tree->SelectItem(DoInternalGetPage(pagePos)); + + // notify about the (now completed) page change + event.SetEventType(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED); + (void)GetEventHandler()->ProcessEvent(event); + } + else // page change vetoed + { + // tree selection might have already had changed + m_tree->SelectItem(DoInternalGetPage(oldSel)); + } + + return oldSel; +} + +void wxTreebook::SetImageList(wxImageList *imageList) +{ + wxBookCtrlBase::SetImageList(imageList); + m_tree->SetImageList(imageList); +} + +void wxTreebook::AssignImageList(wxImageList *imageList) +{ + wxBookCtrlBase::AssignImageList(imageList); + m_tree->SetImageList(imageList); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxTreebook::OnTreeSelectionChange(wxTreeEvent& event) +{ + wxTreeItemId newId = event.GetItem(); + + if ( (m_selection == wxNOT_FOUND && + (!newId.IsOk() || newId == m_tree->GetRootItem())) || + (m_selection != wxNOT_FOUND && newId == m_treeIds[m_selection]) ) + { + // this event can only come when we modify the tree selection ourselves + // so we should simply ignore it + return; + } + + int newPos = DoInternalFindPageById(newId); + + if ( newPos != wxNOT_FOUND ) + SetSelection( newPos ); +} + +void wxTreebook::OnTreeNodeExpandedCollapsed(wxTreeEvent & event) +{ + wxTreeItemId nodeId = event.GetItem(); + if ( !nodeId.IsOk() || nodeId == m_tree->GetRootItem() ) + return; + int pagePos = DoInternalFindPageById(nodeId); + wxCHECK_RET( pagePos != wxNOT_FOUND, wxT("Internal problem in wxTreebook!..") ); + + wxTreebookEvent ev(m_tree->IsExpanded(nodeId) + ? wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED + : wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED, + m_windowId); + + ev.SetSelection(pagePos); + ev.SetOldSelection(pagePos); + ev.SetEventObject(this); + + GetEventHandler()->ProcessEvent(ev); +} + +// ---------------------------------------------------------------------------- +// wxTreebook geometry management +// ---------------------------------------------------------------------------- + +wxSize wxTreebook::GetTreeSize() const +{ + const wxSize sizeClient = GetClientSize(), + sizeBorder = m_tree->GetSize() - m_tree->GetClientSize(), + sizeTree = m_tree->GetBestSize() + sizeBorder; + + wxSize size; + + size.x = sizeTree.x; + size.y = sizeClient.y; + + return size; +} + +wxRect wxTreebook::GetPageRect() const +{ + const wxSize sizeTree = m_tree->GetSize(); + + wxPoint pt; + wxRect rectPage(pt, GetClientSize()); + switch ( GetWindowStyle() & wxTBK_ALIGN_MASK ) + { + default: + wxFAIL_MSG( _T("unexpected wxTreebook alignment") ); + // fall through + + case wxTBK_LEFT: + rectPage.x = sizeTree.x; // + MARGIN; + // fall through + + case wxTBK_RIGHT: + rectPage.width -= sizeTree.x; // + MARGIN; + break; + } + + return rectPage; +} + +void wxTreebook::OnSize(wxSizeEvent& event) +{ + event.Skip(); + + if ( !m_tree ) + { + // we're not fully created yet + return; + } + + // resize the list control and the page area to fit inside our new size + const wxSize sizeClient = GetClientSize(), + sizeBorder = m_tree->GetSize() - m_tree->GetClientSize(), + sizeTree = GetTreeSize(); + + m_tree->SetClientSize( sizeTree.x - sizeBorder.x, sizeTree.y - sizeBorder.y ); + + const wxSize sizeNew = m_tree->GetSize(); + wxPoint posTree; + switch ( GetWindowStyle() & wxTBK_ALIGN_MASK ) + { + default: + wxFAIL_MSG( _T("unexpected wxTreebook alignment") ); + // fall through + + case wxTBK_LEFT: + // posTree is already ok + break; + + case wxTBK_RIGHT: + posTree.x = sizeClient.x - sizeNew.x; + break; + } + + if ( m_tree->GetPosition() != posTree ) + m_tree->Move(posTree); + + // resize the currently shown page + wxTreebookPage *page = DoGetCurrentPage(); + if ( page ) + { + wxRect rectPage = GetPageRect(); + page->SetSize(rectPage); + } +} + +wxTreebookPage * wxTreebook::DoGetCurrentPage() const +{ + if ( m_selection == wxNOT_FOUND ) + return NULL; + + wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection); + if ( !page && m_actualSelection != wxNOT_FOUND ) + { + page = wxBookCtrlBase::GetPage(m_actualSelection); + } + + return page; +} + +#endif // wxUSE_TREEBOOK + diff --git a/src/xrc/xh_treebk.cpp b/src/xrc/xh_treebk.cpp new file mode 100644 index 0000000000..9b4513fdcc --- /dev/null +++ b/src/xrc/xh_treebk.cpp @@ -0,0 +1,134 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: xh_treebk.cpp +// Purpose: XRC resource handler for wxTreebook +// Author: Evgeniy Tarassov +// Created: 2005/09/28 +// RCS-ID: $Id$ +// Copyright: (c) 2005 TT-Solutions +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_XRC && wxUSE_TREEBOOK + +#include "wx/xrc/xh_treebk.h" + +#include "wx/treebook.h" +#include "wx/imaglist.h" +#include "wx/log.h" + +IMPLEMENT_DYNAMIC_CLASS(wxTreebookXmlHandler, wxXmlResourceHandler) + +wxTreebookXmlHandler::wxTreebookXmlHandler() +: wxXmlResourceHandler(), m_isInside(false), m_tbk(NULL), m_treeContext() +{ + XRC_ADD_STYLE(wxTBK_DEFAULT); + XRC_ADD_STYLE(wxTBK_LEFT); + XRC_ADD_STYLE(wxTBK_RIGHT); + + AddWindowStyles(); +} + +bool wxTreebookXmlHandler::CanHandle(wxXmlNode *node) +{ + return ((!m_isInside && IsOfClass(node, wxT("wxTreebook"))) || + (m_isInside && IsOfClass(node, wxT("treebookpage")))); +} + + +wxObject *wxTreebookXmlHandler::DoCreateResource() +{ + if (m_class == wxT("wxTreebook")) + { + XRC_MAKE_INSTANCE(tbk, wxTreebook) + + tbk->Create(m_parentAsWindow, + GetID(), + GetPosition(), GetSize(), + GetStyle(wxT("style")), + GetName()); + + wxTreebook * old_par = m_tbk; + m_tbk = tbk; + + bool old_ins = m_isInside; + m_isInside = true; + + wxArrayTbkPageIndexes old_treeContext = m_treeContext; + m_treeContext.Clear(); + + CreateChildren(m_tbk, true/*only this handler*/); + + m_treeContext = old_treeContext; + m_isInside = old_ins; + m_tbk = old_par; + + return tbk; + } + +// else ( m_class == wxT("treebookpage") ) + wxXmlNode *n = GetParamNode(wxT("object")); + wxWindow *wnd = NULL; + + if ( !n ) + n = GetParamNode(wxT("object_ref")); + + if (n) + { + bool old_ins = m_isInside; + m_isInside = false; + wxObject *item = CreateResFromNode(n, m_tbk, NULL); + m_isInside = old_ins; + wnd = wxDynamicCast(item, wxWindow); + + if (wnd == NULL && item != NULL) + wxLogError(wxT("Error in resource: control within treebook's tag is not a window.")); + } + + size_t depth = GetLong( wxT("depth") ); + + if( depth <= m_treeContext.Count() ) + { + // first prepare the icon + int imgIndex = wxNOT_FOUND; + if ( HasParam(wxT("bitmap")) ) + { + wxBitmap bmp = GetBitmap(wxT("bitmap"), wxART_OTHER); + wxImageList *imgList = m_tbk->GetImageList(); + if ( imgList == NULL ) + { + imgList = new wxImageList( bmp.GetWidth(), bmp.GetHeight() ); + m_tbk->AssignImageList( imgList ); + } + imgIndex = imgList->Add(bmp); + } + + // then add the page to the corresponding parent + if( depth < m_treeContext.Count() ) + m_treeContext.RemoveAt(depth, m_treeContext.Count() - depth ); + if( depth == 0) + { + m_tbk->AddPage(wnd, + GetText(wxT("label")), GetBool(wxT("selected")), imgIndex); + } + else + { + m_tbk->AddSubPage(m_treeContext.Item(depth - 1), wnd, + GetText(wxT("label")), GetBool(wxT("selected")), imgIndex); + } + + m_treeContext.Add( m_tbk->GetPageCount() - 1); + + } + else + wxLogError(wxT("Error in resource. wxTreebookPage has an invalid depth.")); + return wnd; +} + +#endif // wxUSE_XRC && wxUSE_TREEBOOK diff --git a/src/xrc/xmlrsall.cpp b/src/xrc/xmlrsall.cpp index c4d5b04ba7..db1d0e9003 100644 --- a/src/xrc/xmlrsall.cpp +++ b/src/xrc/xmlrsall.cpp @@ -85,6 +85,9 @@ void wxXmlResource::InitAllHandlers() #endif #if wxUSE_CHOICEBOOK AddHandler(new wxChoicebookXmlHandler); +#endif +#if wxUSE_TREEBOOK + AddHandler(new wxTreebookXmlHandler); #endif AddHandler(new wxTextCtrlXmlHandler); #if wxUSE_LISTBOX