+
+ // draw the tabs
+
+ size_t active = 999;
+ int active_offset = 0;
+ wxRect active_rect;
+
+ int x_extent = 0;
+ wxRect rect = m_rect;
+ rect.y = 0;
+ rect.height = m_rect.height;
+
+ for (i = m_tabOffset; i < page_count; ++i)
+ {
+ wxAuiNotebookPage& page = m_pages.Item(i);
+ wxAuiTabContainerButton& tab_button = m_tabCloseButtons.Item(i);
+
+ // determine if a close button is on this tab
+ if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
+ ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
+ {
+ if (tab_button.curState == wxAUI_BUTTON_STATE_HIDDEN)
+ {
+ tab_button.id = wxAUI_BUTTON_CLOSE;
+ tab_button.curState = wxAUI_BUTTON_STATE_NORMAL;
+ tab_button.location = wxCENTER;
+ }
+ }
+ else
+ {
+ tab_button.curState = wxAUI_BUTTON_STATE_HIDDEN;
+ }
+
+ rect.x = offset;
+ rect.width = m_rect.width - right_buttons_width - offset - 2;
+
+ if (rect.width <= 0)
+ break;
+
+ m_art->DrawTab(dc,
+ wnd,
+ page,
+ rect,
+ tab_button.curState,
+ &page.rect,
+ &tab_button.rect,
+ &x_extent);
+
+ if (page.active)
+ {
+ active = i;
+ active_offset = offset;
+ active_rect = rect;
+ }
+
+ offset += x_extent;
+ }
+
+
+ // make sure to deactivate buttons which are off the screen to the right
+ for (++i; i < m_tabCloseButtons.GetCount(); ++i)
+ {
+ m_tabCloseButtons.Item(i).curState = wxAUI_BUTTON_STATE_HIDDEN;
+ }
+
+
+ // draw the active tab again so it stands in the foreground
+ if (active >= m_tabOffset && active < m_pages.GetCount())
+ {
+ wxAuiNotebookPage& page = m_pages.Item(active);
+
+ wxAuiTabContainerButton& tab_button = m_tabCloseButtons.Item(active);
+
+ rect.x = active_offset;
+ m_art->DrawTab(dc,
+ wnd,
+ page,
+ active_rect,
+ tab_button.curState,
+ &page.rect,
+ &tab_button.rect,
+ &x_extent);
+ }
+
+
+ raw_dc->Blit(m_rect.x, m_rect.y,
+ m_rect.GetWidth(), m_rect.GetHeight(),
+ &dc, 0, 0);
+}
+
+// Is the tab visible?
+bool wxAuiTabContainer::IsTabVisible(int tabPage, int tabOffset, wxDC* dc, wxWindow* wnd)
+{
+ if (!dc || !dc->IsOk())
+ return false;
+
+ size_t i;
+ size_t page_count = m_pages.GetCount();
+ size_t button_count = m_buttons.GetCount();
+
+ // Hasn't been rendered yet; assume it's visible
+ if (m_tabCloseButtons.GetCount() < page_count)
+ return true;
+
+ // First check if both buttons are disabled - if so, there's no need to
+ // check further for visibility.
+ int arrowButtonVisibleCount = 0;
+ for (i = 0; i < button_count; ++i)
+ {
+ wxAuiTabContainerButton& button = m_buttons.Item(i);
+ if (button.id == wxAUI_BUTTON_LEFT ||
+ button.id == wxAUI_BUTTON_RIGHT)
+ {
+ if ((button.curState & wxAUI_BUTTON_STATE_HIDDEN) == 0)
+ arrowButtonVisibleCount ++;
+ }
+ }
+
+ // Tab must be visible
+ if (arrowButtonVisibleCount == 0)
+ return true;
+
+ // If tab is less than the given offset, it must be invisible by definition
+ if (tabPage < tabOffset)
+ return false;
+
+ // draw buttons
+ int left_buttons_width = 0;
+ int right_buttons_width = 0;
+
+ // calculate size of the buttons on the right side
+ int offset = m_rect.x + m_rect.width;
+ for (i = 0; i < button_count; ++i)
+ {
+ wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
+
+ if (button.location != wxRIGHT)
+ continue;
+ if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
+ continue;
+
+ offset -= button.rect.GetWidth();
+ right_buttons_width += button.rect.GetWidth();
+ }
+
+ offset = 0;
+
+ // calculate size of the buttons on the left side
+ for (i = 0; i < button_count; ++i)
+ {
+ wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
+
+ if (button.location != wxLEFT)
+ continue;
+ if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
+ continue;
+
+ offset += button.rect.GetWidth();
+ left_buttons_width += button.rect.GetWidth();
+ }
+
+ offset = left_buttons_width;
+
+ if (offset == 0)
+ offset += m_art->GetIndentSize();
+
+ wxRect active_rect;
+
+ wxRect rect = m_rect;
+ rect.y = 0;
+ rect.height = m_rect.height;
+
+ // See if the given page is visible at the given tab offset (effectively scroll position)
+ for (i = tabOffset; i < page_count; ++i)
+ {
+ wxAuiNotebookPage& page = m_pages.Item(i);
+ wxAuiTabContainerButton& tab_button = m_tabCloseButtons.Item(i);
+
+ rect.x = offset;
+ rect.width = m_rect.width - right_buttons_width - offset - 2;
+
+ if (rect.width <= 0)
+ return false; // haven't found the tab, and we've run out of space, so return false
+
+ int x_extent = 0;
+ m_art->GetTabSize(*dc,
+ wnd,
+ page.caption,
+ page.bitmap,
+ page.active,
+ tab_button.curState,
+ &x_extent);
+
+ offset += x_extent;
+
+ if (i == (size_t) tabPage)
+ {
+ // If not all of the tab is visible, and supposing there's space to display it all,
+ // we could do better so we return false.
+ if (((m_rect.width - right_buttons_width - offset - 2) <= 0) && ((m_rect.width - right_buttons_width - left_buttons_width) > x_extent))
+ return false;
+ else
+ return true;
+ }
+ }
+
+ // Shouldn't really get here, but if it does, assume the tab is visible to prevent
+ // further looping in calling code.
+ return true;
+}
+
+// Make the tab visible if it wasn't already
+void wxAuiTabContainer::MakeTabVisible(int tabPage, wxWindow* win)
+{
+ wxClientDC dc(win);
+ if (!IsTabVisible(tabPage, GetTabOffset(), & dc, win))
+ {
+ int i;
+ for (i = 0; i < (int) m_pages.GetCount(); i++)
+ {
+ if (IsTabVisible(tabPage, i, & dc, win))
+ {
+ SetTabOffset(i);
+ win->Refresh();
+ return;
+ }
+ }
+ }
+}
+
+// TabHitTest() tests if a tab was hit, passing the window pointer
+// back if that condition was fulfilled. The function returns
+// true if a tab was hit, otherwise false
+bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
+{
+ if (!m_rect.Contains(x,y))
+ return false;
+
+ wxAuiTabContainerButton* btn = NULL;
+ if (ButtonHitTest(x, y, &btn) && !(btn->curState & wxAUI_BUTTON_STATE_DISABLED))
+ {
+ if (m_buttons.Index(*btn) != wxNOT_FOUND)
+ return false;
+ }
+
+ size_t i, page_count = m_pages.GetCount();
+
+ for (i = m_tabOffset; i < page_count; ++i)
+ {
+ wxAuiNotebookPage& page = m_pages.Item(i);
+ if (page.rect.Contains(x,y))
+ {
+ if (hit)
+ *hit = page.window;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// ButtonHitTest() tests if a button was hit. The function returns
+// true if a button was hit, otherwise false
+bool wxAuiTabContainer::ButtonHitTest(int x, int y,
+ wxAuiTabContainerButton** hit) const
+{
+ if (!m_rect.Contains(x,y))
+ return false;
+
+ size_t i, button_count;
+
+
+ button_count = m_buttons.GetCount();
+ for (i = 0; i < button_count; ++i)
+ {
+ wxAuiTabContainerButton& button = m_buttons.Item(i);
+ if (button.rect.Contains(x,y) &&
+ !(button.curState & wxAUI_BUTTON_STATE_HIDDEN ))
+ {
+ if (hit)
+ *hit = &button;
+ return true;
+ }
+ }
+
+ button_count = m_tabCloseButtons.GetCount();
+ for (i = 0; i < button_count; ++i)
+ {
+ wxAuiTabContainerButton& button = m_tabCloseButtons.Item(i);
+ if (button.rect.Contains(x,y) &&
+ !(button.curState & (wxAUI_BUTTON_STATE_HIDDEN |
+ wxAUI_BUTTON_STATE_DISABLED)))
+ {
+ if (hit)
+ *hit = &button;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+
+// the utility function ShowWnd() is the same as show,
+// except it handles wxAuiMDIChildFrame windows as well,
+// as the Show() method on this class is "unplugged"
+static void ShowWnd(wxWindow* wnd, bool show)
+{
+#if wxUSE_MDI
+ if (wxDynamicCast(wnd, wxAuiMDIChildFrame))
+ {
+ wxAuiMDIChildFrame* cf = (wxAuiMDIChildFrame*)wnd;
+ cf->DoShow(show);
+ }
+ else
+#endif
+ {
+ wnd->Show(show);
+ }
+}
+
+
+// DoShowHide() this function shows the active window, then
+// hides all of the other windows (in that order)
+void wxAuiTabContainer::DoShowHide()
+{
+ wxAuiNotebookPageArray& pages = GetPages();
+ size_t i, page_count = pages.GetCount();
+
+ // show new active page first
+ for (i = 0; i < page_count; ++i)
+ {
+ wxAuiNotebookPage& page = pages.Item(i);
+ if (page.active)
+ {
+ ShowWnd(page.window, true);
+ break;
+ }
+ }
+
+ // hide all other pages
+ for (i = 0; i < page_count; ++i)
+ {
+ wxAuiNotebookPage& page = pages.Item(i);
+ if (!page.active)
+ ShowWnd(page.window, false);
+ }
+}
+
+
+
+
+
+
+// -- wxAuiTabCtrl class implementation --
+
+
+
+BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
+ EVT_PAINT(wxAuiTabCtrl::OnPaint)
+ EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
+ EVT_SIZE(wxAuiTabCtrl::OnSize)
+ EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
+ EVT_LEFT_DCLICK(wxAuiTabCtrl::OnLeftDClick)
+ EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
+ EVT_MIDDLE_DOWN(wxAuiTabCtrl::OnMiddleDown)
+ EVT_MIDDLE_UP(wxAuiTabCtrl::OnMiddleUp)
+ EVT_RIGHT_DOWN(wxAuiTabCtrl::OnRightDown)
+ EVT_RIGHT_UP(wxAuiTabCtrl::OnRightUp)
+ EVT_MOTION(wxAuiTabCtrl::OnMotion)
+ EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
+ EVT_AUINOTEBOOK_BUTTON(wxID_ANY, wxAuiTabCtrl::OnButton)
+ EVT_SET_FOCUS(wxAuiTabCtrl::OnSetFocus)
+ EVT_KILL_FOCUS(wxAuiTabCtrl::OnKillFocus)
+ EVT_CHAR(wxAuiTabCtrl::OnChar)
+ EVT_MOUSE_CAPTURE_LOST(wxAuiTabCtrl::OnCaptureLost)
+END_EVENT_TABLE()
+
+
+wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style) : wxControl(parent, id, pos, size, style)
+{
+ SetName(wxT("wxAuiTabCtrl"));
+ m_clickPt = wxDefaultPosition;
+ m_isDragging = false;
+ m_hoverButton = NULL;
+ m_pressedButton = NULL;
+}
+
+wxAuiTabCtrl::~wxAuiTabCtrl()
+{
+}
+
+void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
+{
+ wxPaintDC dc(this);
+
+ dc.SetFont(GetFont());
+
+ if (GetPageCount() > 0)
+ Render(&dc, this);
+}
+
+void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
+{
+}
+
+void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
+{
+ wxSize s = evt.GetSize();
+ wxRect r(0, 0, s.GetWidth(), s.GetHeight());
+ SetRect(r);
+}
+
+void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
+{
+ CaptureMouse();
+ m_clickPt = wxDefaultPosition;
+ m_isDragging = false;
+ m_clickTab = NULL;
+ m_pressedButton = NULL;
+
+
+ wxWindow* wnd;
+ if (TabHitTest(evt.m_x, evt.m_y, &wnd))
+ {
+ int new_selection = GetIdxFromWindow(wnd);
+
+ // wxAuiNotebooks always want to receive this event
+ // even if the tab is already active, because they may
+ // have multiple tab controls
+ if ((new_selection != GetActivePage() ||
+ wxDynamicCast(GetParent(), wxAuiNotebook)) && !m_hoverButton)
+ {
+ wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
+ e.SetSelection(new_selection);
+ e.SetOldSelection(GetActivePage());
+ e.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(e);
+ }
+
+ m_clickPt.x = evt.m_x;
+ m_clickPt.y = evt.m_y;
+ m_clickTab = wnd;
+ }
+
+ if (m_hoverButton)
+ {
+ m_pressedButton = m_hoverButton;
+ m_pressedButton->curState = wxAUI_BUTTON_STATE_PRESSED;
+ Refresh();
+ Update();
+ }
+}
+
+void wxAuiTabCtrl::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
+{
+ if (m_isDragging)
+ {
+ m_isDragging = false;
+
+ wxAuiNotebookEvent evt(wxEVT_AUINOTEBOOK_CANCEL_DRAG, m_windowId);
+ evt.SetSelection(GetIdxFromWindow(m_clickTab));
+ evt.SetOldSelection(evt.GetSelection());