#if wxUSE_TREEBOOK
#include "wx/treebook.h"
+
+#ifndef WX_PRECOMP
+ #include "wx/settings.h"
+#endif
+
#include "wx/imaglist.h"
-#include "wx/settings.h"
// ----------------------------------------------------------------------------
// various wxWidgets macros
// event table
// ----------------------------------------------------------------------------
-IMPLEMENT_DYNAMIC_CLASS(wxTreebook, wxControl)
-IMPLEMENT_DYNAMIC_CLASS(wxTreebookEvent, wxNotifyEvent)
+IMPLEMENT_DYNAMIC_CLASS(wxTreebook, wxBookCtrlBase)
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)
+ EVT_TREE_SEL_CHANGED (wxID_ANY, wxTreebook::OnTreeSelectionChange)
+ EVT_TREE_ITEM_EXPANDED (wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed)
+ EVT_TREE_ITEM_COLLAPSED(wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed)
END_EVENT_TABLE()
// ============================================================================
void wxTreebook::Init()
{
- m_tree = NULL;
m_selection =
m_actualSelection = wxNOT_FOUND;
}
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
+ if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT )
{
- style |= wxTBK_LEFT;
+ style |= wxBK_LEFT;
}
+ style |= wxTAB_TRAVERSAL;
// no border for this control, it doesn't look nice together with the tree
style &= ~wxBORDER_MASK;
style, wxDefaultValidator, name) )
return false;
- m_tree = new wxTreeCtrl
+ m_bookctrl = new wxTreeCtrl
(
this,
- wxID_TREEBOOKTREEVIEW,
+ wxID_ANY,
wxDefaultPosition,
wxDefaultSize,
- wxBORDER_SIMPLE |
+ wxBORDER_THEME |
wxTR_DEFAULT_STYLE |
wxTR_HIDE_ROOT |
wxTR_SINGLE
);
- m_tree->AddRoot(wxEmptyString); // label doesn't matter, it's hidden
+ GetTreeCtrl()->SetQuickBestSize(false); // do full size calculation
+ GetTreeCtrl()->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.
+ // We need to add dummy size event to force possible scrollbar hiding
wxSizeEvent evt;
GetEventHandler()->AddPendingEvent(evt);
#endif
return DoInsertPage(pagePos, page, text, bSelect, imageId);
}
-bool wxTreebook::AddSubPage(size_t pagePos,
- wxWindow *page,
- const wxString& text,
- bool bSelect,
- int imageId)
+bool wxTreebook::InsertSubPage(size_t pagePos,
+ wxWindow *page,
+ const wxString& text,
+ bool bSelect,
+ int imageId)
{
return DoInsertSubPage(pagePos, page, text, bSelect, imageId);
}
if ( !wxBookCtrlBase::InsertPage(pagePos, page, text, bSelect, imageId) )
return false;
+ wxTreeCtrl *tree = GetTreeCtrl();
wxTreeItemId newId;
if ( pagePos == DoInternalGetPageCount() )
{
// append the page to the end
- wxTreeItemId rootId = m_tree->GetRootItem();
+ wxTreeItemId rootId = tree->GetRootItem();
- newId = m_tree->AppendItem(rootId, text, imageId);
+ newId = 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);
+ wxTreeItemId previousId = tree->GetPrevSibling(nodeId);
+ wxTreeItemId parentId = tree->GetItemParent(nodeId);
if ( previousId.IsOk() )
{
// insert before the sibling - previousId
- newId = m_tree->InsertItem(parentId, previousId, text, imageId);
+ newId = 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);
+ newId = tree->PrependItem(parentId, text, imageId);
}
}
DoUpdateSelection(bSelect, pagePos);
- m_tree->InvalidateBestSize();
-
return true;
}
bool wxTreebook::DoAddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId)
{
- wxTreeItemId rootId = m_tree->GetRootItem();
+ wxTreeCtrl *tree = GetTreeCtrl();
- wxTreeItemId lastNodeId = m_tree->GetLastChild(rootId);
+ wxTreeItemId rootId = tree->GetRootItem();
+
+ wxTreeItemId lastNodeId = 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);
+ size_t newPos = tree->GetCount() -
+ (tree->GetChildrenCount(lastNodeId, true) + 1);
return DoInsertSubPage(newPos, page, text, bSelect, imageId);
}
wxTreeItemId parentId = DoInternalGetPage(pagePos);
wxCHECK_MSG( parentId.IsOk(), false, wxT("invalid tree item") );
- size_t newPos = pagePos + m_tree->GetChildrenCount(parentId, true) + 1;
+ wxTreeCtrl *tree = GetTreeCtrl();
+
+ size_t newPos = pagePos + 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);
+ wxTreeItemId newId = tree->AppendItem(parentId, text, imageId);
if ( !newId.IsOk() )
{
DoUpdateSelection(bSelect, newPos);
- m_tree->InvalidateBestSize();
-
return true;
}
wxCHECK_MSG( pageId.IsOk(), NULL, wxT("Invalid tree index") );
wxTreebookPage * oldPage = GetPage(pagePos);
+ wxTreeCtrl *tree = GetTreeCtrl();
- size_t subCount = m_tree->GetChildrenCount(pageId, true);
+ size_t subCount = tree->GetChildrenCount(pageId, true);
wxASSERT_MSG ( IS_VALID_PAGE(pagePos + subCount),
wxT("Internal error in wxTreebook::DoRemovePage") );
DoInternalRemovePageRange(pagePos, subCount);
- m_tree->DeleteChildren( pageId );
- m_tree->Delete( pageId );
- m_tree->InvalidateBestSize();
+ tree->DeleteChildren( pageId );
+ tree->Delete( pageId );
return oldPage;
}
m_selection =
m_actualSelection = wxNOT_FOUND;
- m_tree->DeleteChildren(m_tree->GetRootItem());
+ wxTreeCtrl *tree = GetTreeCtrl();
+ tree->DeleteChildren(tree->GetRootItem());
return true;
}
}
else if ( (size_t)m_selection >= pagePos )
{
+ wxTreeCtrl *tree = GetTreeCtrl();
+
// 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);
+ wxTreeItemId nodeId = tree->GetNextSibling(pageId);
m_selection = wxNOT_FOUND;
m_actualSelection = wxNOT_FOUND;
if ( nodeId.IsOk() )
{
// selecting next siblings
- m_tree->SelectItem(nodeId);
+ tree->SelectItem(nodeId);
}
else // no next sibling, select the parent
{
- wxTreeItemId parentId = m_tree->GetItemParent(pageId);
+ wxTreeItemId parentId = tree->GetItemParent(pageId);
- if ( parentId.IsOk() && parentId != m_tree->GetRootItem() )
+ if ( parentId.IsOk() && parentId != tree->GetRootItem() )
{
- m_tree->SelectItem(parentId);
+ tree->SelectItem(parentId);
}
else // parent is root
{
// actually shown page (the first (sub)child with page != NULL) is
// already deleted
m_actualSelection = m_selection;
- DoSetSelection(m_selection);
+
+ // send event as documented
+ DoSetSelection(m_selection, SetSelection_SendEvent);
}
//else: nothing to do -- selection is before the deleted node
}
wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
- return m_tree->IsExpanded(pageId);
+ return GetTreeCtrl()->IsExpanded(pageId);
}
bool wxTreebook::ExpandNode(size_t pagePos, bool expand)
if ( expand )
{
- m_tree->Expand( pageId );
+ GetTreeCtrl()->Expand( pageId );
}
else // collapse
{
- m_tree->Collapse( pageId );
+ GetTreeCtrl()->Collapse( pageId );
// rely on the events generated by wxTreeCtrl to update selection
}
wxTreeItemId nodeId = DoInternalGetPage( pagePos );
wxCHECK_MSG( nodeId.IsOk(), wxNOT_FOUND, wxT("Invalid page index spacified!") );
- const wxTreeItemId parent = m_tree->GetItemParent( nodeId );
+ const wxTreeItemId parent = GetTreeCtrl()->GetItemParent( nodeId );
return parent.IsOk() ? DoInternalFindPageById(parent) : wxNOT_FOUND;
}
wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
- m_tree->SetItemText(pageId, strText);
+ GetTreeCtrl()->SetItemText(pageId, strText);
return true;
}
wxCHECK_MSG( pageId.IsOk(), wxString(), wxT("invalid tree item") );
- return m_tree->GetItemText(pageId);
+ return GetTreeCtrl()->GetItemText(pageId);
}
int wxTreebook::GetPageImage(size_t n) const
wxCHECK_MSG( pageId.IsOk(), wxNOT_FOUND, wxT("invalid tree item") );
- return m_tree->GetItemImage(pageId);
+ return GetTreeCtrl()->GetItemImage(pageId);
}
bool wxTreebook::SetPageImage(size_t n, int imageId)
wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
- m_tree->SetItemImage(pageId, imageId);
+ GetTreeCtrl()->SetItemImage(pageId, imageId);
return true;
}
wxSize wxTreebook::CalcSizeFromPage(const wxSize& sizePage) const
{
- const wxSize sizeTree = GetTreeSize();
+ const wxSize sizeTree = GetControllerSize();
wxSize size = sizePage;
size.x += sizeTree.x;
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)
+int wxTreebook::DoSetSelection(size_t pagePos, int flags)
{
wxCHECK_MSG( IS_VALID_PAGE(pagePos), wxNOT_FOUND,
- wxT("invalid page index in wxListbook::SetSelection()") );
+ wxT("invalid page index in wxListbook::DoSetSelection()") );
wxASSERT_MSG( GetPageCount() == DoInternalGetPageCount(),
wxT("wxTreebook logic error: m_treeIds and m_pages not in sync!"));
+ wxBookCtrlEvent event(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, m_windowId);
const int oldSel = m_selection;
+ wxTreeCtrl *tree = GetTreeCtrl();
+ bool allowed = false;
- wxTreebookEvent event(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, m_windowId);
- event.SetEventObject(this);
- event.SetSelection(pagePos);
- event.SetOldSelection(m_selection);
+ if (flags & SetSelection_SendEvent)
+ {
+ 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
+ allowed = (int)pagePos == m_selection ||
+ !GetEventHandler()->ProcessEvent(event) ||
+ event.IsAllowed();
+ }
- // 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() )
+ if ( !(flags & SetSelection_SendEvent) || allowed )
{
// hide the previously shown page
wxTreebookPage * const oldPage = DoGetCurrentPage();
// 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;
+ int actualPagePos = pagePos;
while ( !page && childId.IsOk() )
{
wxTreeItemIdValue cookie;
- childId = m_tree->GetFirstChild( childId, cookie );
+ childId = tree->GetFirstChild( childId, cookie );
if ( childId.IsOk() )
{
- page = wxBookCtrlBase::GetPage(++m_actualSelection);
+ page = wxBookCtrlBase::GetPage(++actualPagePos);
}
}
- wxASSERT_MSG( page, wxT("no page to show found!") );
+ m_actualSelection = page ? actualPagePos : m_selection;
}
if ( page )
- {
- page->SetSize(GetPageRect());
page->Show();
- }
- m_tree->SelectItem(DoInternalGetPage(pagePos));
+ tree->SelectItem(DoInternalGetPage(pagePos));
- // notify about the (now completed) page change
- event.SetEventType(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED);
- (void)GetEventHandler()->ProcessEvent(event);
+ if (flags & SetSelection_SendEvent)
+ {
+ // notify about the (now completed) page change
+ event.SetEventType(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED);
+ (void)GetEventHandler()->ProcessEvent(event);
+ }
}
- else // page change vetoed
+ else if ( (flags & SetSelection_SendEvent) && !allowed) // page change vetoed
{
// tree selection might have already had changed
- m_tree->SelectItem(DoInternalGetPage(oldSel));
+ if ( oldSel != wxNOT_FOUND )
+ tree->SelectItem(DoInternalGetPage(oldSel));
}
return oldSel;
}
+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;
+}
+
void wxTreebook::SetImageList(wxImageList *imageList)
{
wxBookCtrlBase::SetImageList(imageList);
- m_tree->SetImageList(imageList);
+ GetTreeCtrl()->SetImageList(imageList);
}
void wxTreebook::AssignImageList(wxImageList *imageList)
{
wxBookCtrlBase::AssignImageList(imageList);
- m_tree->SetImageList(imageList);
+ GetTreeCtrl()->SetImageList(imageList);
}
// ----------------------------------------------------------------------------
void wxTreebook::OnTreeSelectionChange(wxTreeEvent& event)
{
+ if ( event.GetEventObject() != m_bookctrl )
+ {
+ event.Skip();
+ return;
+ }
+
wxTreeItemId newId = event.GetItem();
if ( (m_selection == wxNOT_FOUND &&
- (!newId.IsOk() || newId == m_tree->GetRootItem())) ||
+ (!newId.IsOk() || newId == GetTreeCtrl()->GetRootItem())) ||
(m_selection != wxNOT_FOUND && newId == m_treeIds[m_selection]) )
{
// this event can only come when we modify the tree selection ourselves
void wxTreebook::OnTreeNodeExpandedCollapsed(wxTreeEvent & event)
{
+ if ( event.GetEventObject() != m_bookctrl )
+ {
+ event.Skip();
+ return;
+ }
+
wxTreeItemId nodeId = event.GetItem();
- if ( !nodeId.IsOk() || nodeId == m_tree->GetRootItem() )
+ if ( !nodeId.IsOk() || nodeId == GetTreeCtrl()->GetRootItem() )
return;
int pagePos = DoInternalFindPageById(nodeId);
wxCHECK_RET( pagePos != wxNOT_FOUND, wxT("Internal problem in wxTreebook!..") );
- wxTreebookEvent ev(m_tree->IsExpanded(nodeId)
+ wxBookCtrlEvent ev(GetTreeCtrl()->IsExpanded(nodeId)
? wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED
: wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED,
m_windowId);
// 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
+int wxTreebook::HitTest(wxPoint const & pt, long * flags) 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
+ int pagePos = wxNOT_FOUND;
- case wxTBK_LEFT:
- rectPage.x = sizeTree.x; // + MARGIN;
- // fall through
+ if ( flags )
+ *flags = wxBK_HITTEST_NOWHERE;
- case wxTBK_RIGHT:
- rectPage.width -= sizeTree.x; // + MARGIN;
- break;
- }
-
- return rectPage;
-}
+ // convert from wxTreebook coorindates to wxTreeCtrl ones
+ const wxTreeCtrl * const tree = GetTreeCtrl();
+ const wxPoint treePt = tree->ScreenToClient(ClientToScreen(pt));
-void wxTreebook::OnSize(wxSizeEvent& event)
-{
- event.Skip();
-
- if ( !m_tree )
+ // is it over the tree?
+ if ( wxRect(tree->GetSize()).Contains(treePt) )
{
- // 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();
+ int flagsTree;
+ wxTreeItemId id = tree->HitTest(treePt, flagsTree);
- m_tree->SetClientSize( sizeTree.x - sizeBorder.x, sizeTree.y - sizeBorder.y );
+ if ( id.IsOk() && (flagsTree & wxTREE_HITTEST_ONITEM) )
+ {
+ pagePos = DoInternalFindPageById(id);
+ }
- const wxSize sizeNew = m_tree->GetSize();
- wxPoint posTree;
- switch ( GetWindowStyle() & wxTBK_ALIGN_MASK )
- {
- default:
- wxFAIL_MSG( _T("unexpected wxTreebook alignment") );
- // fall through
+ if ( flags )
+ {
+ if ( pagePos != wxNOT_FOUND )
+ *flags = 0;
- case wxTBK_LEFT:
- // posTree is already ok
- break;
+ if ( flagsTree & (wxTREE_HITTEST_ONITEMBUTTON |
+ wxTREE_HITTEST_ONITEMICON |
+ wxTREE_HITTEST_ONITEMSTATEICON) )
+ *flags |= wxBK_HITTEST_ONICON;
- case wxTBK_RIGHT:
- posTree.x = sizeClient.x - sizeNew.x;
- break;
+ if ( flagsTree & wxTREE_HITTEST_ONITEMLABEL )
+ *flags |= wxBK_HITTEST_ONLABEL;
+ }
}
-
- if ( m_tree->GetPosition() != posTree )
- m_tree->Move(posTree);
-
- // resize the currently shown page
- wxTreebookPage *page = DoGetCurrentPage();
- if ( page )
+ else // not over the tree
{
- wxRect rectPage = GetPageRect();
- page->SetSize(rectPage);
+ if ( flags && GetPageRect().Contains( pt ) )
+ *flags |= wxBK_HITTEST_ONPAGE;
}
-}
-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;
+ return pagePos;
}
#endif // wxUSE_TREEBOOK
-