#include "wx/control.h"
+class wxAuiNotebook;
+
enum wxAuiNotebookOption
{
wxAUI_NB_BOTTOM = 1 << 3, // not implemented yet
wxAUI_NB_TAB_SPLIT = 1 << 4,
wxAUI_NB_TAB_MOVE = 1 << 5,
- wxAUI_NB_SCROLL_BUTTONS = 1 << 6,
- wxAUI_NB_WINDOWLIST_BUTTON = 1 << 7,
- wxAUI_NB_CLOSE_BUTTON = 1 << 8,
- wxAUI_NB_CLOSE_ON_ACTIVE_TAB = 1 << 9,
- wxAUI_NB_CLOSE_ON_ALL_TABS = 1 << 10,
+ wxAUI_NB_TAB_EXTERNAL_MOVE = 1 << 6,
+ wxAUI_NB_SCROLL_BUTTONS = 1 << 7,
+ wxAUI_NB_WINDOWLIST_BUTTON = 1 << 8,
+ wxAUI_NB_CLOSE_BUTTON = 1 << 9,
+ wxAUI_NB_CLOSE_ON_ACTIVE_TAB = 1 << 10,
+ wxAUI_NB_CLOSE_ON_ALL_TABS = 1 << 11,
+
wxAUI_NB_DEFAULT_STYLE = wxAUI_NB_TOP |
wxAUI_NB_TAB_SPLIT |
int win_id = 0)
: wxNotifyEvent(command_type, win_id)
{
+ old_selection = -1;
+ selection = -1;
+ drag_source = NULL;
}
#ifndef SWIG
wxAuiNotebookEvent(const wxAuiNotebookEvent& c) : wxNotifyEvent(c)
{
old_selection = c.old_selection;
selection = c.selection;
+ drag_source = c.drag_source;
}
#endif
wxEvent *Clone() const { return new wxAuiNotebookEvent(*this); }
void SetSelection(int s) { selection = s; m_commandInt = s; }
- void SetOldSelection(int s) { old_selection = s; }
int GetSelection() const { return selection; }
+
+ void SetOldSelection(int s) { old_selection = s; }
int GetOldSelection() const { return old_selection; }
+
+ void SetDragSource(wxAuiNotebook* s) { drag_source = s; }
+ wxAuiNotebook* GetDragSource() const { return drag_source; }
public:
int old_selection;
int selection;
+ wxAuiNotebook* drag_source;
#ifndef SWIG
private:
wxAuiTabContainerButton* m_hover_button;
#ifndef SWIG
+ DECLARE_CLASS(wxAuiTabCtrl)
DECLARE_EVENT_TABLE()
#endif
};
DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_AUI, wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 0)
DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_AUI, wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 0)
DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_AUI, wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 0)
+ DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_AUI, wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 0)
END_DECLARE_EVENT_TYPES()
typedef void (wxEvtHandler::*wxAuiNotebookEventFunction)(wxAuiNotebookEvent&);
wx__DECLARE_EVT1(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, winid, wxAuiNotebookEventHandler(fn))
#define EVT_AUINOTEBOOK_DRAG_MOTION(winid, fn) \
wx__DECLARE_EVT1(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, winid, wxAuiNotebookEventHandler(fn))
+#define EVT_AUINOTEBOOK_ALLOW_DND(winid, fn) \
+ wx__DECLARE_EVT1(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, winid, wxAuiNotebookEventHandler(fn))
#else
%constant wxEventType wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG;
%constant wxEventType wxEVT_COMMAND_AUINOTEBOOK_END_DRAG;
%constant wxEventType wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION;
+%constant wxEventType wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND;
%pythoncode {
EVT_AUINOTEBOOK_PAGE_CHANGED = wx.PyEventBinder( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 1 )
EVT_AUINOTEBOOK_BEGIN_DRAG = wx.PyEventBinder( wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 1 )
EVT_AUINOTEBOOK_END_DRAG = wx.PyEventBinder( wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 1 )
EVT_AUINOTEBOOK_DRAG_MOTION = wx.PyEventBinder( wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 1 )
+ EVT_AUINOTEBOOK_ALLOW_DND = wx.PyEventBinder( wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 1 )
}
#endif
ID_NotebookCloseButtonAll,
ID_NotebookCloseButtonActive,
ID_NotebookAllowTabMove,
+ ID_NotebookAllowTabExternalMove,
ID_NotebookAllowTabSplit,
ID_NotebookWindowList,
ID_NotebookScrollButtons,
void OnCopyPerspectiveCode(wxCommandEvent& evt);
void OnRestorePerspective(wxCommandEvent& evt);
void OnSettings(wxCommandEvent& evt);
+ void OnAllowNotebookDnD(wxAuiNotebookEvent& evt);
void OnExit(wxCommandEvent& evt);
void OnAbout(wxCommandEvent& evt);
EVT_MENU(ID_NotebookCloseButtonAll, MyFrame::OnNotebookFlag)
EVT_MENU(ID_NotebookCloseButtonActive, MyFrame::OnNotebookFlag)
EVT_MENU(ID_NotebookAllowTabMove, MyFrame::OnNotebookFlag)
+ EVT_MENU(ID_NotebookAllowTabExternalMove, MyFrame::OnNotebookFlag)
EVT_MENU(ID_NotebookAllowTabSplit, MyFrame::OnNotebookFlag)
EVT_MENU(ID_NotebookScrollButtons, MyFrame::OnNotebookFlag)
EVT_MENU(ID_NotebookWindowList, MyFrame::OnNotebookFlag)
EVT_UPDATE_UI(ID_NotebookCloseButtonAll, MyFrame::OnUpdateUI)
EVT_UPDATE_UI(ID_NotebookCloseButtonActive, MyFrame::OnUpdateUI)
EVT_UPDATE_UI(ID_NotebookAllowTabMove, MyFrame::OnUpdateUI)
+ EVT_UPDATE_UI(ID_NotebookAllowTabExternalMove, MyFrame::OnUpdateUI)
EVT_UPDATE_UI(ID_NotebookAllowTabSplit, MyFrame::OnUpdateUI)
EVT_UPDATE_UI(ID_NotebookScrollButtons, MyFrame::OnUpdateUI)
EVT_UPDATE_UI(ID_NotebookWindowList, MyFrame::OnUpdateUI)
EVT_MENU_RANGE(MyFrame::ID_FirstPerspective, MyFrame::ID_FirstPerspective+1000,
MyFrame::OnRestorePerspective)
EVT_AUI_PANECLOSE(MyFrame::OnPaneClose)
+ EVT_AUINOTEBOOK_ALLOW_DND(wxID_ANY, MyFrame::OnAllowNotebookDnD)
END_EVENT_TABLE()
SetIcon(wxIcon(sample_xpm));
// set up default notebook style
- m_notebook_style = wxAUI_NB_DEFAULT_STYLE | wxNO_BORDER;
+ m_notebook_style = wxAUI_NB_DEFAULT_STYLE | wxAUI_NB_TAB_EXTERNAL_MOVE | wxNO_BORDER;
// create menu
wxMenuBar* mb = new wxMenuBar;
notebook_menu->AppendRadioItem(ID_NotebookCloseButtonActive, _("Close Button on Active Tab"));
notebook_menu->AppendSeparator();
notebook_menu->AppendCheckItem(ID_NotebookAllowTabMove, _("Allow Tab Move"));
+ notebook_menu->AppendCheckItem(ID_NotebookAllowTabExternalMove, _("Allow External Tab Move"));
notebook_menu->AppendCheckItem(ID_NotebookAllowTabSplit, _("Allow Notebook Split"));
notebook_menu->AppendCheckItem(ID_NotebookScrollButtons, _("Scroll Buttons Visible"));
notebook_menu->AppendCheckItem(ID_NotebookWindowList, _("Window List Button Visible"));
if (id == ID_NotebookAllowTabMove)
{
m_notebook_style ^= wxAUI_NB_TAB_MOVE;
+ }
+ if (id == ID_NotebookAllowTabExternalMove)
+ {
+ m_notebook_style ^= wxAUI_NB_TAB_EXTERNAL_MOVE;
}
else if (id == ID_NotebookAllowTabSplit)
{
case ID_NotebookAllowTabMove:
event.Check((m_notebook_style & wxAUI_NB_TAB_MOVE) != 0);
break;
+ case ID_NotebookAllowTabExternalMove:
+ event.Check((m_notebook_style & wxAUI_NB_TAB_EXTERNAL_MOVE) != 0);
+ break;
case ID_NotebookScrollButtons:
event.Check((m_notebook_style & wxAUI_NB_SCROLL_BUTTONS) != 0);
break;
m_perspectives.Add(m_mgr.SavePerspective());
}
-void MyFrame::OnCopyPerspectiveCode(wxCommandEvent& WXUNUSED(event))
+void MyFrame::OnCopyPerspectiveCode(wxCommandEvent& WXUNUSED(evt))
{
wxString s = m_mgr.SavePerspective();
#endif
}
-void MyFrame::OnRestorePerspective(wxCommandEvent& event)
+void MyFrame::OnRestorePerspective(wxCommandEvent& evt)
{
- m_mgr.LoadPerspective(m_perspectives.Item(event.GetId() - ID_FirstPerspective));
+ m_mgr.LoadPerspective(m_perspectives.Item(evt.GetId() - ID_FirstPerspective));
}
+void MyFrame::OnAllowNotebookDnD(wxAuiNotebookEvent& evt)
+{
+ // for the purpose of this test application, explicitly
+ // allow all noteboko drag and drop events
+ evt.Allow();
+}
wxPoint MyFrame::GetStartPosition()
{
DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND)
IMPLEMENT_CLASS(wxAuiNotebook, wxControl)
+IMPLEMENT_CLASS(wxAuiTabCtrl, wxControl)
IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxEvent)
bool wxAuiNotebook::DeletePage(size_t page_idx)
{
wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
+
+ if (!RemovePage(page_idx))
+ return false;
+
+
+ // actually destroy the window now
+ if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
+ {
+ // delete the child frame with pending delete, as is
+ // customary with frame windows
+ if (!wxPendingDelete.Member(wnd))
+ wxPendingDelete.Append(wnd);
+ }
+ else
+ {
+ wnd->Destroy();
+ }
+
+ return true;
+
+/*
+
+ wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
wxWindow* new_active = NULL;
// find out which onscreen tab ctrl owns this tab
}
return true;
+ */
}
// but does not destroy the window
bool wxAuiNotebook::RemovePage(size_t page_idx)
{
- // remove the tab from our own catalog
wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
- if (!m_tabs.RemovePage(wnd))
- return false;
+ wxWindow* new_active = NULL;
- // remove the tab from the onscreen tab ctrl
+ // find out which onscreen tab ctrl owns this tab
wxAuiTabCtrl* ctrl;
int ctrl_idx;
- if (FindTab(wnd, &ctrl, &ctrl_idx))
+ if (!FindTab(wnd, &ctrl, &ctrl_idx))
+ return false;
+
+ // find a new page and set it as active
+ int new_idx = ctrl_idx+1;
+ if (new_idx >= (int)ctrl->GetPageCount())
+ new_idx = ctrl_idx-1;
+
+ if (new_idx >= 0 && new_idx < (int)ctrl->GetPageCount())
{
- ctrl->RemovePage(wnd);
- return true;
+ new_active = ctrl->GetWindowFromIdx(new_idx);
+ }
+ else
+ {
+ // set the active page to the first page that
+ // isn't the one being deleted
+ size_t i, page_count = m_tabs.GetPageCount();
+ for (i = 0; i < page_count; ++i)
+ {
+ wxWindow* w = m_tabs.GetWindowFromIdx(i);
+ if (wnd != w)
+ {
+ new_active = m_tabs.GetWindowFromIdx(i);
+ break;
+ }
+ }
}
- return false;
+ // remove the tab from main catalog
+ if (!m_tabs.RemovePage(wnd))
+ return false;
+
+ // remove the tab from the onscreen tab ctrl
+ ctrl->RemovePage(wnd);
+
+
+ RemoveEmptyTabFrames();
+
+ // set new active pane
+ if (new_active)
+ {
+ m_curpage = -1;
+ SetSelection(m_tabs.GetIdxFromWindow(new_active));
+ }
+
+ return true;
}
// SetPageText() changes the tab caption of the specified page
wxPoint zero(0,0);
wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
-
wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
+
if (dest_tabs == src_tabs)
{
if (src_tabs)
}
+ // if external drag is allowed, check if the tab is being dragged
+ // over a different wxAuiNotebook control
+ if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
+ {
+ wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
+
+ // if we are over a hint window, leave
+ if (tab_ctrl->IsKindOf(CLASSINFO(wxFrame)))
+ return;
+
+ while (tab_ctrl)
+ {
+ if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
+ break;
+ tab_ctrl = tab_ctrl->GetParent();
+ }
+
+ if (tab_ctrl)
+ {
+ wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
+
+ if (nb != this)
+ {
+ wxRect hint_rect = tab_ctrl->GetRect();
+ tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
+ m_mgr.ShowHint(hint_rect);
+ return;
+ }
+
+ }
+ }
+
+
// if tab moving is not allowed, leave
if (!(m_flags & wxAUI_NB_TAB_SPLIT))
{
m_mgr.HideHint();
- // if tab moving is not allowed, leave
- if (!(m_flags & wxAUI_NB_TAB_SPLIT))
- {
- return;
- }
- // set cursor back to an arrow
wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
+ wxAuiTabCtrl* dest_tabs = NULL;
if (src_tabs)
{
+ // set cursor back to an arrow
src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
}
wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
- // the src tab control is the control that fired this event
- wxAuiTabCtrl* dest_tabs = NULL;
-
- // If the pointer is in an existing tab frame, do a tab insert
- wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
- wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
- int insert_idx = -1;
- if (tab_frame)
+ // check for an external move
+ if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
{
- dest_tabs = tab_frame->m_tabs;
-
- if (dest_tabs == src_tabs)
- return;
+ wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
-
- wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
- wxWindow* target = NULL;
- dest_tabs->TabHitTest(pt.x, pt.y, &target);
- if (target)
+ while (tab_ctrl)
{
- insert_idx = dest_tabs->GetIdxFromWindow(target);
+ if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
+ break;
+ tab_ctrl = tab_ctrl->GetParent();
}
- }
- else
- {
- // If there is no tabframe at all, create one
- wxTabFrame* new_tabs = new wxTabFrame;
- new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
- new_tabs->m_tabs = new wxAuiTabCtrl(this,
- m_tab_id_counter++,
- wxDefaultPosition,
- wxDefaultSize,
- wxNO_BORDER);
- new_tabs->m_tabs->SetFlags(m_flags);
+
+ if (tab_ctrl)
+ {
+ wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
+
+ if (nb != this)
+ {
+ // find out from the destination control
+ // if it's ok to drop this tab here
+ wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);
+ e.SetSelection(evt.GetSelection());
+ e.SetOldSelection(evt.GetSelection());
+ e.SetEventObject(this);
+ e.SetDragSource(this);
+ e.Veto(); // dropping must be explicitly approved by control owner
+
+ nb->GetEventHandler()->ProcessEvent(e);
+
+ if (!e.IsAllowed())
+ {
+ // no answer or negative answer
+ m_mgr.HideHint();
+ return;
+ }
+
+ // drop was allowed
+ int src_idx = evt.GetSelection();
+ wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
+
+ // get main index of the page
+ int main_idx = m_tabs.GetIdxFromWindow(src_page);
+
+ // make a copy of the page info
+ wxAuiNotebookPage page_info = m_tabs.GetPage((size_t)main_idx);
+
+ // remove the page from the source notebook
+ RemovePage(main_idx);
+
+ // reparent the page
+ src_page->Reparent(nb);
+
+
+ // found out the insert idx
+ wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
+ wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
+
+ wxWindow* target = NULL;
+ int insert_idx = -1;
+ dest_tabs->TabHitTest(pt.x, pt.y, &target);
+ if (target)
+ {
+ insert_idx = dest_tabs->GetIdxFromWindow(target);
+ }
- m_mgr.AddPane(new_tabs,
- wxAuiPaneInfo().Bottom().CaptionVisible(false),
- mouse_client_pt);
- m_mgr.Update();
- dest_tabs = new_tabs->m_tabs;
+
+ // add the page to the new notebook
+ if (insert_idx == -1)
+ insert_idx = dest_tabs->GetPageCount();
+ dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
+ nb->m_tabs.AddPage(page_info.window, page_info);
+
+ nb->DoSizing();
+ dest_tabs->DoShowHide();
+ dest_tabs->Refresh();
+
+ // set the selection in the destination tab control
+ nb->SetSelection(nb->m_tabs.GetIdxFromWindow(page_info.window));
+
+ return;
+ }
+ }
}
- // remove the page from the source tabs
- wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
- page_info.active = false;
- src_tabs->RemovePage(page_info.window);
- if (src_tabs->GetPageCount() > 0)
+
+ // only perform a tab split if it's allowed
+ if (m_flags & wxAUI_NB_TAB_SPLIT)
{
- src_tabs->SetActivePage((size_t)0);
- src_tabs->DoShowHide();
- src_tabs->Refresh();
- }
+ // If the pointer is in an existing tab frame, do a tab insert
+ wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
+ wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
+ int insert_idx = -1;
+ if (tab_frame)
+ {
+ dest_tabs = tab_frame->m_tabs;
+ if (dest_tabs == src_tabs)
+ return;
+
+
+ wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
+ wxWindow* target = NULL;
+ dest_tabs->TabHitTest(pt.x, pt.y, &target);
+ if (target)
+ {
+ insert_idx = dest_tabs->GetIdxFromWindow(target);
+ }
+ }
+ else
+ {
+ // If there is no tabframe at all, create one
+ wxTabFrame* new_tabs = new wxTabFrame;
+ new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
+ new_tabs->m_tabs = new wxAuiTabCtrl(this,
+ m_tab_id_counter++,
+ wxDefaultPosition,
+ wxDefaultSize,
+ wxNO_BORDER);
+ new_tabs->m_tabs->SetFlags(m_flags);
+
+ m_mgr.AddPane(new_tabs,
+ wxAuiPaneInfo().Bottom().CaptionVisible(false),
+ mouse_client_pt);
+ m_mgr.Update();
+ dest_tabs = new_tabs->m_tabs;
+ }
- // add the page to the destination tabs
- if (insert_idx == -1)
- insert_idx = dest_tabs->GetPageCount();
- dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
- if (src_tabs->GetPageCount() == 0)
- {
- RemoveEmptyTabFrames();
- }
+ // remove the page from the source tabs
+ wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
+ page_info.active = false;
+ src_tabs->RemovePage(page_info.window);
+ if (src_tabs->GetPageCount() > 0)
+ {
+ src_tabs->SetActivePage((size_t)0);
+ src_tabs->DoShowHide();
+ src_tabs->Refresh();
+ }
- DoSizing();
- dest_tabs->DoShowHide();
- dest_tabs->Refresh();
- SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
+
+ // add the page to the destination tabs
+ if (insert_idx == -1)
+ insert_idx = dest_tabs->GetPageCount();
+ dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
+
+ if (src_tabs->GetPageCount() == 0)
+ {
+ RemoveEmptyTabFrames();
+ }
+
+ DoSizing();
+ dest_tabs->DoShowHide();
+ dest_tabs->Refresh();
+
+ SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
+ }
}