+/////////////////////////////////////////////////////////////////////////////
+// Name: src/generic/tabg.cpp
+// Purpose: Generic tabbed dialogs
+// Author: Julian Smart
+// Modified by:
+// Created: 01/02/97
+// RCS-ID: $Id$
+// Copyright: (c)
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#if wxUSE_TAB_DIALOG
+
+#ifndef WX_PRECOMP
+ #include "wx/settings.h"
+ #include "wx/intl.h"
+ #include "wx/dcclient.h"
+ #include "wx/math.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "wx/tab.h"
+#include "wx/listimpl.cpp"
+
+WX_DEFINE_LIST(wxTabLayerList)
+
+// not defined: use old, square tab implementation (fills in tabs)
+// defined: use new, rounded tab implementation (doesn't colour in tabs)
+// #define wxUSE_NEW_METHOD
+
+IMPLEMENT_DYNAMIC_CLASS(wxTabControl, wxObject)
+
+// IMPLEMENT_DYNAMIC_CLASS(wxTabLayer, wxList)
+
+wxTabControl::wxTabControl(wxTabView *v)
+{
+ m_view = v;
+ m_isSelected = false;
+ m_offsetX = 0;
+ m_offsetY = 0;
+ m_width = 0;
+ m_height = 0;
+ m_id = 0;
+ m_rowPosition = 0;
+ m_colPosition = 0;
+}
+
+wxTabControl::~wxTabControl(void)
+{
+}
+
+void wxTabControl::OnDraw(wxDC& dc, bool lastInRow)
+{
+ // Old, but in some ways better (drawing opaque tabs)
+#ifndef wxUSE_NEW_METHOD
+ if (!m_view)
+ return;
+
+ // Top-left of tab view area
+ int viewX = m_view->GetViewRect().x;
+ int viewY = m_view->GetViewRect().y;
+
+ // Top-left of tab control
+ int tabX = GetX() + viewX;
+ int tabY = GetY() + viewY;
+ int tabHeightInc = 0;
+ if (m_isSelected)
+ {
+ tabHeightInc = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight());
+ tabY -= tabHeightInc;
+ }
+
+ dc.SetPen(*wxTRANSPARENT_PEN);
+
+ // Draw grey background
+ if (m_view->GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR)
+ {
+ if(m_view->GetBackgroundBrush())
+ dc.SetBrush(*m_view->GetBackgroundBrush());
+
+ // Add 1 because the pen is transparent. Under Motif, may be different.
+#ifdef __WXMOTIF__
+ dc.DrawRectangle(tabX, tabY, (GetWidth()+1), (GetHeight() + tabHeightInc));
+#else
+ dc.DrawRectangle(tabX, tabY, (GetWidth()+1), (GetHeight() + 1 + tabHeightInc));
+#endif
+ }
+
+ // Draw highlight and shadow
+ dc.SetPen(*m_view->GetHighlightPen());
+
+ // Calculate the top of the tab beneath. It's the height of the tab, MINUS
+ // a bit if the tab below happens to be selected. Check.
+ wxTabControl *tabBeneath = NULL;
+ int subtractThis = 0;
+ if (GetColPosition() > 0)
+ tabBeneath = m_view->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition());
+ if (tabBeneath && tabBeneath->IsSelected())
+ subtractThis = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight());
+
+ // Vertical highlight: if first tab, draw to bottom of view
+ if (tabX == m_view->GetViewRect().x && (m_view->GetTabStyle() & wxTAB_STYLE_DRAW_BOX))
+ dc.DrawLine(tabX, tabY, tabX, (m_view->GetViewRect().y + m_view->GetViewRect().height));
+ else if (tabX == m_view->GetViewRect().x)
+ // Not box drawing, just to top of view.
+ dc.DrawLine(tabX, tabY, tabX, (m_view->GetViewRect().y));
+ else
+ dc.DrawLine(tabX, tabY, tabX, (tabY + GetHeight() + tabHeightInc - subtractThis));
+
+ dc.DrawLine(tabX, tabY, (tabX + GetWidth()), tabY);
+ dc.SetPen(*m_view->GetShadowPen());
+
+ // Test if we're outside the right-hand edge of the view area
+ if (((tabX + GetWidth()) >= m_view->GetViewRect().x + m_view->GetViewRect().width) && (m_view->GetTabStyle() & wxTAB_STYLE_DRAW_BOX))
+ {
+ int bottomY = m_view->GetViewRect().y + m_view->GetViewRect().height + GetY() + m_view->GetTabHeight() + m_view->GetTopMargin();
+ // Add a tab height since we wish to draw to the bottom of the view.
+ dc.DrawLine((tabX + GetWidth()), tabY,
+ (tabX + GetWidth()), bottomY);
+
+ // Calculate the far-right of the view, since we don't wish to
+ // draw inside that
+ int rightOfView = m_view->GetViewRect().x + m_view->GetViewRect().width + 1;
+
+ // Draw the horizontal bit to connect to the view rectangle
+ dc.DrawLine((wxMax((tabX + GetWidth() - m_view->GetHorizontalTabOffset()), rightOfView)), (bottomY-1),
+ (tabX + GetWidth()), (bottomY-1));
+
+ // Draw black line to emphasize shadow
+ dc.SetPen(*wxBLACK_PEN);
+ dc.DrawLine((tabX + GetWidth() + 1), (tabY+1),
+ (tabX + GetWidth() + 1), bottomY);
+
+ // Draw the horizontal bit to connect to the view rectangle
+ dc.DrawLine((wxMax((tabX + GetWidth() - m_view->GetHorizontalTabOffset()), rightOfView)), (bottomY),
+ (tabX + GetWidth() + 1), (bottomY));
+ }
+ else
+ {
+ if (lastInRow)
+ {
+ // 25/5/97 UNLESS it's less than the max number of positions in this row
+
+ int topY = m_view->GetViewRect().y - m_view->GetTopMargin();
+
+ int maxPositions = ((wxTabLayer *)m_view->GetLayers().Item(0)->GetData())->GetCount();
+
+ // Only down to the bottom of the tab, not to the top of the view
+ if ( GetRowPosition() < (maxPositions - 1) )
+ topY = tabY + GetHeight() + tabHeightInc;
+
+#ifdef __WXMOTIF__
+ topY -= 1;
+#endif
+
+ // Shadow
+ dc.DrawLine((tabX + GetWidth()), tabY, (tabX + GetWidth()), topY);
+ // Draw black line to emphasize shadow
+ dc.SetPen(*wxBLACK_PEN);
+ dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), (tabX + GetWidth() + 1),
+ topY);
+ }
+ else
+ {
+ // Calculate the top of the tab beneath. It's the height of the tab, MINUS
+ // a bit if the tab below (and next col along) happens to be selected. Check.
+ wxTabControl *tabBeneath = NULL;
+ int subtractThis = 0;
+ if (GetColPosition() > 0)
+ tabBeneath = m_view->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition() + 1);
+ if (tabBeneath && tabBeneath->IsSelected())
+ subtractThis = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight());
+
+#ifdef __WXMOTIF__
+ subtractThis += 1;
+#endif
+
+ // Draw only to next tab down.
+ dc.DrawLine((tabX + GetWidth()), tabY,
+ (tabX + GetWidth()), (tabY + GetHeight() + tabHeightInc - subtractThis));
+
+ // Draw black line to emphasize shadow
+ dc.SetPen(*wxBLACK_PEN);
+ dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), (tabX + GetWidth() + 1),
+ (tabY + GetHeight() + tabHeightInc - subtractThis));
+ }
+ }
+
+ // Draw centered text
+ int textY = tabY + m_view->GetVerticalTabTextSpacing() + tabHeightInc;
+
+ if (m_isSelected)
+ dc.SetFont(* m_view->GetSelectedTabFont());
+ else
+ dc.SetFont(* GetFont());
+
+ wxColour col(m_view->GetTextColour());
+ dc.SetTextForeground(col);
+ dc.SetBackgroundMode(wxTRANSPARENT);
+ wxCoord textWidth, textHeight;
+ dc.GetTextExtent(GetLabel(), &textWidth, &textHeight);
+
+ int textX = (int)(tabX + (GetWidth() - textWidth)/2.0);
+ if (textX < (tabX + 2))
+ textX = (tabX + 2);
+
+ dc.SetClippingRegion(tabX, tabY, GetWidth(), GetHeight());
+ dc.DrawText(GetLabel(), textX, textY);
+ dc.DestroyClippingRegion();
+
+ if (m_isSelected)
+ {
+ dc.SetPen(*m_view->GetHighlightPen());
+
+ // Draw white highlight from the tab's left side to the left hand edge of the view
+ dc.DrawLine(m_view->GetViewRect().x, (tabY + GetHeight() + tabHeightInc),
+ tabX, (tabY + GetHeight() + tabHeightInc));
+
+ // Draw white highlight from the tab's right side to the right hand edge of the view
+ dc.DrawLine((tabX + GetWidth()), (tabY + GetHeight() + tabHeightInc),
+ m_view->GetViewRect().x + m_view->GetViewRect().width, (tabY + GetHeight() + tabHeightInc));
+ }
+#else
+ // New HEL version with rounder tabs
+
+ if (!m_view) return;
+
+ int tabInc = 0;
+ if (m_isSelected)
+ {
+ tabInc = m_view->GetTabSelectionHeight() - m_view->GetTabHeight();
+ }
+ int tabLeft = GetX() + m_view->GetViewRect().x;
+ int tabTop = GetY() + m_view->GetViewRect().y - tabInc;
+ int tabRight = tabLeft + m_view->GetTabWidth();
+ int left = m_view->GetViewRect().x;
+ int top = tabTop + m_view->GetTabHeight() + tabInc;
+ int right = left + m_view->GetViewRect().width;
+ int bottom = top + m_view->GetViewRect().height;
+
+ if (m_isSelected)
+ {
+ // TAB is selected - draw TAB and the View's full outline
+
+ dc.SetPen(*(m_view->GetHighlightPen()));
+ wxPoint pnts[10];
+ int n = 0;
+ pnts[n].x = left; pnts[n++].y = bottom;
+ pnts[n].x = left; pnts[n++].y = top;
+ pnts[n].x = tabLeft; pnts[n++].y = top;
+ pnts[n].x = tabLeft; pnts[n++].y = tabTop + 2;
+ pnts[n].x = tabLeft + 2; pnts[n++].y = tabTop;
+ pnts[n].x = tabRight - 1; pnts[n++].y = tabTop;
+ dc.DrawLines(n, pnts);
+ if (!lastInRow)
+ {
+ dc.DrawLine(
+ (tabRight + 2),
+ top,
+ right,
+ top
+ );
+ }
+
+ dc.SetPen(*(m_view->GetShadowPen()));
+ dc.DrawLine(
+ tabRight,
+ tabTop + 2,
+ tabRight,
+ top
+ );
+ dc.DrawLine(
+ right,
+ top,
+ right,
+ bottom
+ );
+ dc.DrawLine(
+ right,
+ bottom,
+ left,
+ bottom
+ );
+
+ dc.SetPen(*wxBLACK_PEN);
+ dc.DrawPoint(
+ tabRight,
+ tabTop + 1
+ );
+ dc.DrawPoint(
+ tabRight + 1,
+ tabTop + 2
+ );
+ if (lastInRow)
+ {
+ dc.DrawLine(
+ tabRight + 1,
+ bottom,
+ tabRight + 1,
+ tabTop + 1
+ );
+ }
+ else
+ {
+ dc.DrawLine(
+ tabRight + 1,
+ tabTop + 2,
+ tabRight + 1,
+ top
+ );
+ dc.DrawLine(
+ right + 1,
+ top,
+ right + 1,
+ bottom + 1
+ );
+ }
+ dc.DrawLine(
+ right + 1,
+ bottom + 1,
+ left + 1,
+ bottom + 1
+ );
+ }
+ else
+ {
+ // TAB is not selected - just draw TAB outline and RH edge
+ // if the TAB is the last in the row
+
+ int maxPositions = ((wxTabLayer*)m_view->GetLayers().Item(0)->GetData())->GetCount();
+ wxTabControl* tabBelow = 0;
+ wxTabControl* tabBelowRight = 0;
+ if (GetColPosition() > 0)
+ {
+ tabBelow = m_view->FindTabControlForPosition(
+ GetColPosition() - 1,
+ GetRowPosition()
+ );
+ }
+ if (!lastInRow && GetColPosition() > 0)
+ {
+ tabBelowRight = m_view->FindTabControlForPosition(
+ GetColPosition() - 1,
+ GetRowPosition() + 1
+ );
+ }
+
+ float raisedTop = top - m_view->GetTabSelectionHeight() +
+ m_view->GetTabHeight();
+
+ dc.SetPen(*(m_view->GetHighlightPen()));
+ wxPoint pnts[10];
+ int n = 0;
+
+ pnts[n].x = tabLeft;
+
+ if (tabBelow && tabBelow->IsSelected())
+ {
+ pnts[n++].y = (long)raisedTop;
+ }
+ else
+ {
+ pnts[n++].y = top;
+ }
+ pnts[n].x = tabLeft; pnts[n++].y = tabTop + 2;
+ pnts[n].x = tabLeft + 2; pnts[n++].y = tabTop;
+ pnts[n].x = tabRight - 1; pnts[n++].y = tabTop;
+ dc.DrawLines(n, pnts);
+
+ dc.SetPen(*(m_view->GetShadowPen()));
+ if (GetRowPosition() >= maxPositions - 1)
+ {
+ dc.DrawLine(
+ tabRight,
+ (tabTop + 2),
+ tabRight,
+ bottom
+ );
+ dc.DrawLine(
+ tabRight,
+ bottom,
+ (tabRight - m_view->GetHorizontalTabOffset()),
+ bottom
+ );
+ }
+ else
+ {
+ if (tabBelowRight && tabBelowRight->IsSelected())
+ {
+ dc.DrawLine(
+ tabRight,
+ (long)raisedTop,
+ tabRight,
+ tabTop + 1
+ );
+ }
+ else
+ {
+ dc.DrawLine(
+ tabRight,
+ top - 1,
+ tabRight,
+ tabTop + 1
+ );
+ }
+ }
+
+ dc.SetPen(*wxBLACK_PEN);
+ dc.DrawPoint(
+ tabRight,
+ tabTop + 1
+ );
+ dc.DrawPoint(
+ tabRight + 1,
+ tabTop + 2
+ );
+ if (GetRowPosition() >= maxPositions - 1)
+ {
+ // draw right hand edge to bottom of view
+ dc.DrawLine(
+ tabRight + 1,
+ bottom + 1,
+ tabRight + 1,
+ tabTop + 2
+ );
+ dc.DrawLine(
+ tabRight + 1,
+ bottom + 1,
+ (tabRight - m_view->GetHorizontalTabOffset()),
+ bottom + 1
+ );
+ }
+ else
+ {
+ // draw right hand edge of TAB
+ if (tabBelowRight && tabBelowRight->IsSelected())
+ {
+ dc.DrawLine(
+ tabRight + 1,
+ (long)(raisedTop - 1),
+ tabRight + 1,
+ tabTop + 2
+ );
+ }
+ else
+ {
+ dc.DrawLine(
+ tabRight + 1,
+ top - 1,
+ tabRight + 1,
+ tabTop + 2
+ );
+ }
+ }
+ }
+
+ // Draw centered text
+ dc.SetPen(*wxBLACK_PEN);
+ if (m_isSelected)
+ {
+ dc.SetFont(*(m_view->GetSelectedTabFont()));
+ }
+ else
+ {
+ dc.SetFont(*(GetFont()));
+ }
+
+ wxColour col(m_view->GetTextColour());
+ dc.SetTextForeground(col);
+ dc.SetBackgroundMode(wxTRANSPARENT);
+ long textWidth, textHeight;
+ dc.GetTextExtent(GetLabel(), &textWidth, &textHeight);
+
+ float textX = (tabLeft + tabRight - textWidth) / 2;
+ float textY = (tabInc + tabTop + m_view->GetVerticalTabTextSpacing());
+
+ dc.DrawText(GetLabel(), (long)textX, (long)textY);
+#endif
+}
+
+bool wxTabControl::HitTest(int x, int y) const
+{
+ // Top-left of tab control
+ int tabX1 = GetX() + m_view->GetViewRect().x;
+ int tabY1 = GetY() + m_view->GetViewRect().y;
+
+ // Bottom-right
+ int tabX2 = tabX1 + GetWidth();
+ int tabY2 = tabY1 + GetHeight();
+
+ if (x >= tabX1 && y >= tabY1 && x <= tabX2 && y <= tabY2)
+ return true;
+ else
+ return false;
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxTabView, wxObject)
+
+wxTabView::wxTabView(long style)
+{
+ m_noTabs = 0;
+ m_tabStyle = style;
+ m_tabSelection = -1;
+ m_tabHeight = 20;
+ m_tabSelectionHeight = m_tabHeight + 2;
+ m_tabWidth = 80;
+ m_tabHorizontalOffset = 10;
+ m_tabHorizontalSpacing = 2;
+ m_tabVerticalTextSpacing = 3;
+ m_topMargin = 5;
+ m_tabViewRect.x = 20;
+ m_tabViewRect.y = 20;
+ m_tabViewRect.width = 300;
+ m_tabViewRect.x = 300;
+ m_highlightColour = *wxWHITE;
+ m_shadowColour = wxColour(128, 128, 128);
+ // m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
+ m_textColour = *wxBLACK;
+ m_highlightPen = wxWHITE_PEN;
+ m_shadowPen = wxGREY_PEN;
+ // SetBackgroundColour(m_backgroundColour);
+ m_tabFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+ m_tabSelectedFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+ m_window = (wxWindow *) NULL;
+}
+
+wxTabView::~wxTabView()
+{
+ ClearTabs(true);
+}
+
+// Automatically positions tabs
+// TODO: this should just add the tab to a list, and then
+// a layout function (e.g. Realize) should be called when all tabs have been added.
+// The view rect could easily change as the view window is resized.
+wxTabControl *wxTabView::AddTab(int id, const wxString& label, wxTabControl *existingTab)
+{
+ // First, find which layer we should be adding to.
+ wxTabLayerList::compatibility_iterator node = m_layers.GetLast();
+ if (!node)
+ {
+ wxTabLayer *newLayer = new wxTabLayer;
+ node = m_layers.Append(newLayer);
+ }
+ // Check if adding another tab control would go off the
+ // right-hand edge of the layer.
+ wxTabLayer *tabLayer = (wxTabLayer *)node->GetData();
+ wxList::compatibility_iterator lastTabNode = tabLayer->GetLast();
+ if (lastTabNode)
+ {
+ wxTabControl *lastTab = (wxTabControl *)lastTabNode->GetData();
+ // Start another layer (row).
+ // Tricky choice: can't just check if will be overlapping the edge, because
+ // this happens anyway for 2nd and subsequent rows.
+ // Should check this for 1st row, and then subsequent rows should not exceed 1st
+ // in length.
+ if (((tabLayer == m_layers.GetFirst()->GetData()) && ((lastTab->GetX() + 2*lastTab->GetWidth() + GetHorizontalTabSpacing())
+ > GetViewRect().width)) ||
+ ((tabLayer != m_layers.GetFirst()->GetData()) && (tabLayer->GetCount() == ((wxTabLayer *)m_layers.GetFirst()->GetData())->GetCount())))
+ {
+ tabLayer = new wxTabLayer;
+ m_layers.Append(tabLayer);
+ lastTabNode = wxList::compatibility_iterator();
+ }
+ }
+ int layer = m_layers.GetCount() - 1;
+
+ wxTabControl *tabControl = existingTab;
+ if (!existingTab)
+ tabControl = OnCreateTabControl();
+ tabControl->SetRowPosition(tabLayer->GetCount());
+ tabControl->SetColPosition(layer);
+
+ wxTabControl *lastTab = (wxTabControl *) NULL;
+ if (lastTabNode)
+ lastTab = (wxTabControl *)lastTabNode->GetData();
+
+ // Top of new tab
+ int verticalOffset = (- GetTopMargin()) - ((layer+1)*GetTabHeight());
+ // Offset from view top-left
+ int horizontalOffset = 0;
+ if (!lastTab)
+ horizontalOffset = layer*GetHorizontalTabOffset();
+ else
+ horizontalOffset = lastTab->GetX() + GetTabWidth() + GetHorizontalTabSpacing();
+
+ tabControl->SetPosition(horizontalOffset, verticalOffset);
+ tabControl->SetSize(GetTabWidth(), GetTabHeight());
+ tabControl->SetId(id);
+ tabControl->SetLabel(label);
+ tabControl->SetFont(* GetTabFont());
+
+ tabLayer->Append(tabControl);
+ m_noTabs ++;
+
+ return tabControl;
+}
+
+// Remove the tab without deleting the window
+bool wxTabView::RemoveTab(int id)
+{
+ wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst();
+ while (layerNode)
+ {
+ wxTabLayer *layer = (wxTabLayer *)layerNode->GetData();
+ wxList::compatibility_iterator tabNode = layer->GetFirst();
+ while (tabNode)
+ {
+ wxTabControl *tab = (wxTabControl *)tabNode->GetData();
+ if (tab->GetId() == id)
+ {
+ if (id == m_tabSelection)
+ m_tabSelection = -1;
+ delete tab;
+ layer->Erase(tabNode);
+ m_noTabs --;
+
+ // The layout has changed
+ LayoutTabs();
+ return true;
+ }
+ tabNode = tabNode->GetNext();
+ }
+ layerNode = layerNode->GetNext();
+ }
+ return false;
+}
+
+bool wxTabView::SetTabText(int id, const wxString& label)
+{
+ wxTabControl* control = FindTabControlForId(id);
+ if (!control)
+ return false;
+ control->SetLabel(label);
+ return true;
+}
+
+wxString wxTabView::GetTabText(int id) const
+{
+ wxTabControl* control = FindTabControlForId(id);
+ if (!control)
+ return wxEmptyString;
+ else
+ return control->GetLabel();
+}
+
+// Returns the total height of the tabs component -- this may be several
+// times the height of a tab, if there are several tab layers (rows).
+int wxTabView::GetTotalTabHeight()
+{
+ int minY = 0;
+
+ wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst();
+ while (layerNode)
+ {
+ wxTabLayer *layer = (wxTabLayer *)layerNode->GetData();
+ wxList::compatibility_iterator tabNode = layer->GetFirst();
+ while (tabNode)
+ {
+ wxTabControl *tab = (wxTabControl *)tabNode->GetData();
+
+ if (tab->GetY() < minY)
+ minY = tab->GetY();
+
+ tabNode = tabNode->GetNext();
+ }
+ layerNode = layerNode->GetNext();
+ }
+
+ return - minY;
+}
+
+void wxTabView::ClearTabs(bool deleteTabs)
+{
+ wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst();
+ while (layerNode)
+ {
+ wxTabLayer *layer = (wxTabLayer *)layerNode->GetData();
+ wxList::compatibility_iterator tabNode = layer->GetFirst();
+ while (tabNode)
+ {
+ wxTabControl *tab = (wxTabControl *)tabNode->GetData();
+ if (deleteTabs)
+ delete tab;
+ wxList::compatibility_iterator next = tabNode->GetNext();
+ layer->Erase(tabNode);
+ tabNode = next;
+ }
+ wxTabLayerList::compatibility_iterator nextLayerNode = layerNode->GetNext();
+ delete layer;
+ m_layers.Erase(layerNode);
+ layerNode = nextLayerNode;
+ }
+ m_noTabs = 0;
+ m_tabSelection = -1;
+}
+
+
+// Layout tabs (optional, e.g. if resizing window)
+void wxTabView::LayoutTabs(void)
+{
+ // Make a list of the tab controls, deleting the wxTabLayers.
+ wxList controls;
+
+ wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst();
+ while (layerNode)
+ {
+ wxTabLayer *layer = (wxTabLayer *)layerNode->GetData();
+ wxList::compatibility_iterator tabNode = layer->GetFirst();
+ while (tabNode)
+ {
+ wxTabControl *tab = (wxTabControl *)tabNode->GetData();
+ controls.Append(tab);
+ wxList::compatibility_iterator next = tabNode->GetNext();
+ layer->Erase(tabNode);
+ tabNode = next;
+ }
+ wxTabLayerList::compatibility_iterator nextLayerNode = layerNode->GetNext();
+ delete layer;
+ m_layers.Erase(layerNode);
+ layerNode = nextLayerNode;
+ }
+
+ wxTabControl *lastTab = (wxTabControl *) NULL;
+
+ wxTabLayer *currentLayer = new wxTabLayer;
+ m_layers.Append(currentLayer);
+
+ wxList::compatibility_iterator node = controls.GetFirst();
+ while (node)
+ {
+ wxTabControl *tabControl = (wxTabControl *)node->GetData();
+ if (lastTab)
+ {
+ // Start another layer (row).
+ // Tricky choice: can't just check if will be overlapping the edge, because
+ // this happens anyway for 2nd and subsequent rows.
+ // Should check this for 1st row, and then subsequent rows should not exceed 1st
+ // in length.
+ if (((currentLayer == m_layers.GetFirst()->GetData()) && ((lastTab->GetX() + 2*lastTab->GetWidth() + GetHorizontalTabSpacing())
+ > GetViewRect().width)) ||
+ ((currentLayer != m_layers.GetFirst()->GetData()) && (currentLayer->GetCount() == ((wxTabLayer *)m_layers.GetFirst()->GetData())->GetCount())))
+ {
+ currentLayer = new wxTabLayer;
+ m_layers.Append(currentLayer);
+ lastTab = (wxTabControl *) NULL;
+ }
+ }
+
+ int layer = m_layers.GetCount() - 1;
+
+ tabControl->SetRowPosition(currentLayer->GetCount());
+ tabControl->SetColPosition(layer);
+
+ // Top of new tab
+ int verticalOffset = (- GetTopMargin()) - ((layer+1)*GetTabHeight());
+ // Offset from view top-left
+ int horizontalOffset = 0;
+ if (!lastTab)
+ horizontalOffset = layer*GetHorizontalTabOffset();
+ else
+ horizontalOffset = lastTab->GetX() + GetTabWidth() + GetHorizontalTabSpacing();
+
+ tabControl->SetPosition(horizontalOffset, verticalOffset);
+ tabControl->SetSize(GetTabWidth(), GetTabHeight());
+
+ currentLayer->Append(tabControl);
+ lastTab = tabControl;
+
+ node = node->GetNext();
+ }
+
+ // Move the selected tab to the bottom
+ wxTabControl *control = FindTabControlForId(m_tabSelection);
+ if (control)
+ MoveSelectionTab(control);
+
+}
+
+// Draw all tabs
+void wxTabView::Draw(wxDC& dc)
+{
+ // Don't draw anything if there are no tabs.
+ if (GetNumberOfTabs() == 0)
+ return;
+
+ // Draw top margin area (beneath tabs and above view area)
+ if (GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR)
+ {
+ dc.SetPen(*wxTRANSPARENT_PEN);
+ if(GetBackgroundBrush())
+ dc.SetBrush(*GetBackgroundBrush());
+
+ // Add 1 because the pen is transparent. Under Motif, may be different.
+ dc.DrawRectangle(
+ m_tabViewRect.x,
+ (m_tabViewRect.y - m_topMargin),
+ (m_tabViewRect.width + 1),
+ (m_topMargin + 1)
+ );
+ }
+
+ // Draw layers in reverse order
+ wxTabLayerList::compatibility_iterator node = m_layers.GetLast();
+ while (node)
+ {
+ wxTabLayer *layer = (wxTabLayer *)node->GetData();
+ wxList::compatibility_iterator node2 = layer->GetFirst();
+ while (node2)
+ {
+ wxTabControl *control = (wxTabControl *)node2->GetData();
+ control->OnDraw(dc, (!node2->GetNext()));
+ node2 = node2->GetNext();
+ }
+
+ node = node->GetPrevious();
+ }
+
+
+#ifndef wxUSE_NEW_METHOD
+ if (GetTabStyle() & wxTAB_STYLE_DRAW_BOX)
+ {
+ dc.SetPen(* GetShadowPen());
+
+ // Draw bottom line
+ dc.DrawLine(
+ (GetViewRect().x + 1),
+ (GetViewRect().y + GetViewRect().height),
+ (GetViewRect().x + GetViewRect().width + 1),
+ (GetViewRect().y + GetViewRect().height)
+ );
+
+ // Draw right line
+ dc.DrawLine(
+ (GetViewRect().x + GetViewRect().width),
+ (GetViewRect().y - GetTopMargin() + 1),
+ (GetViewRect().x + GetViewRect().width),
+ (GetViewRect().y + GetViewRect().height)
+ );
+
+ dc.SetPen(* wxBLACK_PEN);
+
+ // Draw bottom line
+ dc.DrawLine(
+ (GetViewRect().x),
+ (GetViewRect().y + GetViewRect().height + 1),
+#if defined(__WXMOTIF__)
+ (GetViewRect().x + GetViewRect().width + 1),
+#else
+ (GetViewRect().x + GetViewRect().width + 2),
+#endif
+
+ (GetViewRect().y + GetViewRect().height + 1)
+ );
+
+ // Draw right line
+ dc.DrawLine(
+ (GetViewRect().x + GetViewRect().width + 1),
+ (GetViewRect().y - GetTopMargin()),
+ (GetViewRect().x + GetViewRect().width + 1),
+ (GetViewRect().y + GetViewRect().height + 1)
+ );
+ }
+#endif
+}
+
+// Process mouse event, return false if we didn't process it
+bool wxTabView::OnEvent(wxMouseEvent& event)
+{
+ if (!event.LeftDown())
+ return false;
+
+ wxCoord x, y;
+ event.GetPosition(&x, &y);
+
+ wxTabControl *hitControl = (wxTabControl *) NULL;
+
+ wxTabLayerList::compatibility_iterator node = m_layers.GetFirst();
+ while (node)
+ {
+ wxTabLayer *layer = (wxTabLayer *)node->GetData();
+ wxList::compatibility_iterator node2 = layer->GetFirst();
+ while (node2)
+ {
+ wxTabControl *control = (wxTabControl *)node2->GetData();
+ if (control->HitTest((int)x, (int)y))
+ {
+ hitControl = control;
+ node = wxTabLayerList::compatibility_iterator();
+ node2 = wxList::compatibility_iterator();
+ }
+ else
+ node2 = node2->GetNext();
+ }
+
+ if (node)
+ node = node->GetNext();
+ }
+
+ if (!hitControl)
+ return false;
+
+ wxTabControl *currentTab = FindTabControlForId(m_tabSelection);
+
+ if (hitControl == currentTab)
+ return false;
+
+ ChangeTab(hitControl);
+
+ return true;
+}
+
+bool wxTabView::ChangeTab(wxTabControl *control)
+{
+ wxTabControl *currentTab = FindTabControlForId(m_tabSelection);
+ int oldTab = -1;
+ if (currentTab)
+ oldTab = currentTab->GetId();
+
+ if (control == currentTab)
+ return true;
+
+ if (m_layers.GetCount() == 0)
+ return false;
+
+ if (!OnTabPreActivate(control->GetId(), oldTab))
+ return false;
+
+ // Move the tab to the bottom
+ MoveSelectionTab(control);
+
+ if (currentTab)
+ currentTab->SetSelected(false);
+
+ control->SetSelected(true);
+ m_tabSelection = control->GetId();
+
+ OnTabActivate(control->GetId(), oldTab);
+
+ // Leave window refresh for the implementing window
+
+ return true;
+}
+
+// Move the selected tab to the bottom layer, if necessary,
+// without calling app activation code
+bool wxTabView::MoveSelectionTab(wxTabControl *control)
+{
+ if (m_layers.GetCount() == 0)
+ return false;
+
+ wxTabLayer *firstLayer = (wxTabLayer *)m_layers.GetFirst()->GetData();
+
+ // Find what column this tab is at, so we can swap with the one at the bottom.
+ // If we're on the bottom layer, then no need to swap.
+ if (!firstLayer->Member(control))
+ {
+ // Do a swap
+ int col = 0;
+ wxList::compatibility_iterator thisNode = FindTabNodeAndColumn(control, &col);
+ if (!thisNode)
+ return false;
+ wxList::compatibility_iterator otherNode = firstLayer->Item(col);
+ if (!otherNode)
+ return false;
+
+ // If this is already in the bottom layer, return now
+ if (otherNode == thisNode)
+ return true;
+
+ wxTabControl *otherTab = (wxTabControl *)otherNode->GetData();
+
+ // We now have pointers to the tab to be changed to,
+ // and the tab on the first layer. Swap tab structures and
+ // position details.
+
+ int thisX = control->GetX();
+ int thisY = control->GetY();
+ int thisColPos = control->GetColPosition();
+ int otherX = otherTab->GetX();
+ int otherY = otherTab->GetY();
+ int otherColPos = otherTab->GetColPosition();
+
+ control->SetPosition(otherX, otherY);
+ control->SetColPosition(otherColPos);
+ otherTab->SetPosition(thisX, thisY);
+ otherTab->SetColPosition(thisColPos);
+
+ // Swap the data for the nodes
+ thisNode->SetData(otherTab);
+ otherNode->SetData(control);
+ }
+ return true;
+}
+
+// Called when a tab is activated
+void wxTabView::OnTabActivate(int /*activateId*/, int /*deactivateId*/)
+{
+}
+
+void wxTabView::SetHighlightColour(const wxColour& col)
+{
+ m_highlightColour = col;
+ m_highlightPen = wxThePenList->FindOrCreatePen(col);
+}
+
+void wxTabView::SetShadowColour(const wxColour& col)
+{
+ m_shadowColour = col;
+ m_shadowPen = wxThePenList->FindOrCreatePen(col);
+}
+
+void wxTabView::SetBackgroundColour(const wxColour& col)
+{
+ m_backgroundColour = col;
+ m_backgroundPen = wxThePenList->FindOrCreatePen(col);
+ m_backgroundBrush = wxTheBrushList->FindOrCreateBrush(col);
+}
+
+// this may be called with sel = zero (which doesn't match any page)
+// when wxMotif deletes a page
+// so return the first tab...
+
+void wxTabView::SetTabSelection(int sel, bool activateTool)
+{
+ if ( sel==m_tabSelection )
+ return;
+
+ int oldSel = m_tabSelection;
+ wxTabControl *control = FindTabControlForId(sel);
+ if (sel == 0) sel=control->GetId();
+ wxTabControl *oldControl = FindTabControlForId(m_tabSelection);
+
+ if (!OnTabPreActivate(sel, oldSel))
+ return;
+
+ if (control)
+ control->SetSelected((sel != -1)); // TODO ??
+ else if (sel != -1)
+ {
+ wxFAIL_MSG(_("Could not find tab for id"));
+ return;
+ }
+
+ if (oldControl)
+ oldControl->SetSelected(false);
+
+ m_tabSelection = sel;
+
+ if (control)
+ MoveSelectionTab(control);
+
+ if (activateTool)
+ OnTabActivate(sel, oldSel);
+}
+
+// Find tab control for id
+// this may be called with zero (which doesn't match any page)
+// so return the first control...
+wxTabControl *wxTabView::FindTabControlForId(int id) const
+{
+ wxTabLayerList::compatibility_iterator node1 = m_layers.GetFirst();
+ while (node1)
+ {
+ wxTabLayer *layer = (wxTabLayer *)node1->GetData();
+ wxList::compatibility_iterator node2 = layer->GetFirst();
+ while (node2)
+ {
+ wxTabControl *control = (wxTabControl *)node2->GetData();
+ if (control->GetId() == id || id == 0)
+ return control;
+ node2 = node2->GetNext();
+ }
+ node1 = node1->GetNext();
+ }
+ return (wxTabControl *) NULL;
+}
+
+// Find tab control for layer, position (starting from zero)
+wxTabControl *wxTabView::FindTabControlForPosition(int layer, int position) const
+{
+ wxTabLayerList::compatibility_iterator node1 = m_layers.Item(layer);
+ if (!node1)
+ return (wxTabControl *) NULL;
+ wxTabLayer *tabLayer = (wxTabLayer *)node1->GetData();
+ wxList::compatibility_iterator node2 = tabLayer->Item(position);
+ if (!node2)
+ return (wxTabControl *) NULL;
+ return (wxTabControl *)node2->GetData();
+}
+
+// Find the node and the column at which this control is positioned.
+wxList::compatibility_iterator wxTabView::FindTabNodeAndColumn(wxTabControl *control, int *col) const
+{
+ wxTabLayerList::compatibility_iterator node1 = m_layers.GetFirst();
+ while (node1)
+ {
+ wxTabLayer *layer = (wxTabLayer *)node1->GetData();
+ int c = 0;
+ wxList::compatibility_iterator node2 = layer->GetFirst();
+ while (node2)
+ {
+ wxTabControl *cnt = (wxTabControl *)node2->GetData();
+ if (cnt == control)
+ {
+ *col = c;
+ return node2;
+ }
+ node2 = node2->GetNext();
+ c ++;
+ }
+ node1 = node1->GetNext();
+ }
+ return wxList::compatibility_iterator();
+}
+
+int wxTabView::CalculateTabWidth(int noTabs, bool adjustView)
+{
+ m_tabWidth = (int)((m_tabViewRect.width - ((noTabs - 1)*GetHorizontalTabSpacing()))/noTabs);
+ if (adjustView)
+ {
+ m_tabViewRect.width = noTabs*m_tabWidth + ((noTabs-1)*GetHorizontalTabSpacing());
+ }
+ return m_tabWidth;
+}
+
+/*
+ * wxTabbedDialog
+ */
+
+IMPLEMENT_CLASS(wxTabbedDialog, wxDialog)
+
+BEGIN_EVENT_TABLE(wxTabbedDialog, wxDialog)
+ EVT_CLOSE(wxTabbedDialog::OnCloseWindow)
+ EVT_MOUSE_EVENTS(wxTabbedDialog::OnMouseEvent)
+ EVT_PAINT(wxTabbedDialog::OnPaint)
+END_EVENT_TABLE()
+
+wxTabbedDialog::wxTabbedDialog(wxWindow *parent, wxWindowID id,
+ const wxString& title,
+ const wxPoint& pos, const wxSize& size,
+ long windowStyle, const wxString& name):
+ wxDialog(parent, id, title, pos, size, windowStyle, name)
+{
+ m_tabView = (wxTabView *) NULL;
+}
+
+wxTabbedDialog::~wxTabbedDialog(void)
+{
+ if (m_tabView)
+ delete m_tabView;
+}
+
+void wxTabbedDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event) )
+{
+ Destroy();
+}
+
+void wxTabbedDialog::OnMouseEvent(wxMouseEvent& event )
+{
+ if (m_tabView)
+ m_tabView->OnEvent(event);
+}
+
+void wxTabbedDialog::OnPaint(wxPaintEvent& WXUNUSED(event) )
+{
+ wxPaintDC dc(this);
+ if (m_tabView)
+ m_tabView->Draw(dc);
+}
+
+/*
+ * wxTabbedPanel
+ */
+
+IMPLEMENT_CLASS(wxTabbedPanel, wxPanel)
+
+BEGIN_EVENT_TABLE(wxTabbedPanel, wxPanel)
+ EVT_MOUSE_EVENTS(wxTabbedPanel::OnMouseEvent)
+ EVT_PAINT(wxTabbedPanel::OnPaint)
+END_EVENT_TABLE()
+
+wxTabbedPanel::wxTabbedPanel(wxWindow *parent, wxWindowID id, const wxPoint& pos,
+ const wxSize& size, long windowStyle, const wxString& name):
+ wxPanel(parent, id, pos, size, windowStyle, name)
+{
+ m_tabView = (wxTabView *) NULL;
+}
+
+wxTabbedPanel::~wxTabbedPanel(void)
+{
+ delete m_tabView;
+}
+
+void wxTabbedPanel::OnMouseEvent(wxMouseEvent& event)
+{
+ if (m_tabView)
+ m_tabView->OnEvent(event);
+}
+
+void wxTabbedPanel::OnPaint(wxPaintEvent& WXUNUSED(event) )
+{
+ wxPaintDC dc(this);
+ if (m_tabView)
+ m_tabView->Draw(dc);
+}
+
+/*
+ * wxPanelTabView
+ */
+
+IMPLEMENT_CLASS(wxPanelTabView, wxTabView)
+
+wxPanelTabView::wxPanelTabView(wxPanel *pan, long style)
+ : wxTabView(style)
+{
+ m_panel = pan;
+ m_currentWindow = (wxWindow *) NULL;
+
+ if (m_panel->IsKindOf(CLASSINFO(wxTabbedDialog)))
+ ((wxTabbedDialog *)m_panel)->SetTabView(this);
+ else if (m_panel->IsKindOf(CLASSINFO(wxTabbedPanel)))
+ ((wxTabbedPanel *)m_panel)->SetTabView(this);
+
+ SetWindow(m_panel);
+}
+
+wxPanelTabView::~wxPanelTabView(void)
+{
+ ClearWindows(true);
+}
+
+// Called when a tab is activated
+void wxPanelTabView::OnTabActivate(int activateId, int deactivateId)
+{
+ if (!m_panel)
+ return;
+
+ wxWindow *oldWindow = ((deactivateId == -1) ? 0 : GetTabWindow(deactivateId));
+ wxWindow *newWindow = GetTabWindow(activateId);
+
+ if (oldWindow)
+ oldWindow->Show(false);
+ if (newWindow)
+ newWindow->Show(true);
+
+ m_panel->Refresh();
+}
+
+
+void wxPanelTabView::AddTabWindow(int id, wxWindow *window)
+{
+ wxASSERT(m_tabWindows.find(id) == m_tabWindows.end());
+ m_tabWindows[id] = window;
+ window->Show(false);
+}
+
+wxWindow *wxPanelTabView::GetTabWindow(int id) const
+{
+ wxIntToWindowHashMap::const_iterator it = m_tabWindows.find(id);
+ return it == m_tabWindows.end() ? NULL : it->second;
+}
+
+void wxPanelTabView::ClearWindows(bool deleteWindows)
+{
+ if (deleteWindows)
+ WX_CLEAR_HASH_MAP(wxIntToWindowHashMap, m_tabWindows);
+ m_tabWindows.clear();
+}
+
+void wxPanelTabView::ShowWindowForTab(int id)
+{
+ wxWindow *newWindow = GetTabWindow(id);
+ if (newWindow == m_currentWindow)
+ return;
+ if (m_currentWindow)
+ m_currentWindow->Show(false);
+ newWindow->Show(true);
+ newWindow->Refresh();
+}
+
+#endif // wxUSE_TAB_DIALOG