summaryrefslogtreecommitdiff
path: root/vcl/source/control/tabctrl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/control/tabctrl.cxx')
-rw-r--r--vcl/source/control/tabctrl.cxx2347
1 files changed, 2347 insertions, 0 deletions
diff --git a/vcl/source/control/tabctrl.cxx b/vcl/source/control/tabctrl.cxx
new file mode 100644
index 000000000000..e9696aa8c492
--- /dev/null
+++ b/vcl/source/control/tabctrl.cxx
@@ -0,0 +1,2347 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include "tools/debug.hxx"
+
+#include "tools/rc.h"
+#include "vcl/svdata.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/help.hxx"
+#include "vcl/event.hxx"
+#include "vcl/menu.hxx"
+#include "vcl/button.hxx"
+#include "vcl/tabpage.hxx"
+#include "vcl/tabctrl.hxx"
+#include "vcl/controllayout.hxx"
+#include "vcl/controldata.hxx"
+#include "vcl/sound.hxx"
+#include "vcl/lstbox.hxx"
+
+#include "vcl/window.h"
+
+#include <hash_map>
+#include <vector>
+
+// =======================================================================
+
+struct ImplTabItem
+{
+ USHORT mnId;
+ USHORT mnTabPageResId;
+ TabPage* mpTabPage;
+ String maText;
+ String maFormatText;
+ String maHelpText;
+ rtl::OString maHelpId;
+ Rectangle maRect;
+ USHORT mnLine;
+ bool mbFullVisible;
+ bool mbEnabled;
+ Image maTabImage;
+
+ ImplTabItem()
+ : mnId( 0 ), mnTabPageResId( 0 ), mpTabPage( NULL ),
+ mnLine( 0 ), mbFullVisible( FALSE ), mbEnabled( true )
+ {}
+};
+
+// -----------------------------------------------------------------------
+
+struct ImplTabCtrlData
+{
+ PushButton* mpLeftBtn;
+ PushButton* mpRightBtn;
+ std::hash_map< int, int > maLayoutPageIdToLine;
+ std::hash_map< int, int > maLayoutLineToPageId;
+ std::vector< Rectangle > maTabRectangles;
+ Point maItemsOffset; // offset of the tabitems
+ std::vector< ImplTabItem > maItemList;
+ ListBox* mpListBox;
+ Size maMinSize;
+};
+
+// -----------------------------------------------------------------------
+
+#if 0
+// not used
+#define TABCOLORCOUNT 10
+
+static ColorData aImplTabColorAry[TABCOLORCOUNT] =
+{
+ RGB_COLORDATA( 80, 216, 248 ),
+ RGB_COLORDATA( 128, 216, 168 ),
+ RGB_COLORDATA( 128, 144, 248 ),
+ RGB_COLORDATA( 208, 180, 168 ),
+ RGB_COLORDATA( 248, 252, 168 ),
+ RGB_COLORDATA( 168, 144, 168 ),
+ RGB_COLORDATA( 248, 144, 80 ),
+ RGB_COLORDATA( 248, 216, 80 ),
+ RGB_COLORDATA( 248, 180, 168 ),
+ RGB_COLORDATA( 248, 216, 168 )
+};
+#endif
+
+// -----------------------------------------------------------------------
+
+#define TAB_OFFSET 3
+#define TAB_TABOFFSET_X 3
+#define TAB_TABOFFSET_Y 3
+#define TAB_EXTRASPACE_X 6
+#define TAB_BORDER_LEFT 1
+#define TAB_BORDER_TOP 1
+#define TAB_BORDER_RIGHT 2
+#define TAB_BORDER_BOTTOM 2
+
+// Fuer die Ermittlung von den Tab-Positionen
+#define TAB_PAGERECT 0xFFFF
+
+// =======================================================================
+
+void TabControl::ImplInit( Window* pParent, WinBits nStyle )
+{
+ if ( !(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+ if ( !(nStyle & WB_NOGROUP) )
+ nStyle |= WB_GROUP;
+ if ( !(nStyle & WB_NODIALOGCONTROL) )
+ nStyle |= WB_DIALOGCONTROL;
+
+ // no single line tabs since NWF
+ nStyle &= ~WB_SINGLELINE;
+
+ Control::ImplInit( pParent, nStyle, NULL );
+
+ mnLastWidth = 0;
+ mnLastHeight = 0;
+ mnBtnSize = 0;
+ mnMaxPageWidth = 0;
+ mnActPageId = 0;
+ mnCurPageId = 0;
+ mnFirstPagePos = 0;
+ mnLastFirstPagePos = 0;
+ mbFormat = TRUE;
+ mbRestoreHelpId = FALSE;
+ mbRestoreUnqId = FALSE;
+ mbSingleLine = FALSE;
+ mbScroll = FALSE;
+ mbSmallInvalidate = FALSE;
+ mbExtraSpace = FALSE;
+ mpTabCtrlData = new ImplTabCtrlData;
+ mpTabCtrlData->mpLeftBtn = NULL;
+ mpTabCtrlData->mpRightBtn = NULL;
+ mpTabCtrlData->mpListBox = NULL;
+
+
+ ImplInitSettings( TRUE, TRUE, TRUE );
+
+ if( (nStyle & WB_DROPDOWN) )
+ {
+ mpTabCtrlData->mpListBox = new ListBox( this, WB_DROPDOWN );
+ mpTabCtrlData->mpListBox->SetPosSizePixel( Point( 0, 0 ), Size( 200, 20 ) );
+ mpTabCtrlData->mpListBox->SetSelectHdl( LINK( this, TabControl, ImplListBoxSelectHdl ) );
+ mpTabCtrlData->mpListBox->Show();
+ }
+
+ // if the tabcontrol is drawn (ie filled) by a native widget, make sure all contols will have transparent background
+ // otherwise they will paint with a wrong background
+ if( IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL) )
+ EnableChildTransparentMode( TRUE );
+
+ if ( pParent->IsDialog() )
+ pParent->AddChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
+}
+
+// -----------------------------------------------------------------
+
+const Font& TabControl::GetCanonicalFont( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetAppFont();
+}
+
+// -----------------------------------------------------------------
+const Color& TabControl::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
+{
+ return _rStyle.GetButtonTextColor();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplInitSettings( BOOL bFont,
+ BOOL bForeground, BOOL bBackground )
+{
+ Control::ImplInitSettings( bFont, bForeground );
+
+ if ( bBackground )
+ {
+ Window* pParent = GetParent();
+ if ( !IsControlBackground() &&
+ (pParent->IsChildTransparentModeEnabled()
+ || IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL)
+ || IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) ) )
+
+ {
+ // set transparent mode for NWF tabcontrols to have
+ // the background always cleared properly
+ EnableChildTransparentMode( TRUE );
+ SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ SetPaintTransparent( TRUE );
+ SetBackground();
+ ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
+ }
+ else
+ {
+ EnableChildTransparentMode( FALSE );
+ SetParentClipMode( 0 );
+ SetPaintTransparent( FALSE );
+
+ if ( IsControlBackground() )
+ SetBackground( GetControlBackground() );
+ else
+ SetBackground( pParent->GetBackground() );
+ }
+ }
+
+ ImplScrollBtnsColor();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplFreeLayoutData()
+{
+ if( HasLayoutData() )
+ {
+ ImplClearLayoutData();
+ mpTabCtrlData->maLayoutPageIdToLine.clear();
+ mpTabCtrlData->maLayoutLineToPageId.clear();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+TabControl::TabControl( Window* pParent, WinBits nStyle ) :
+ Control( WINDOW_TABCONTROL )
+{
+ ImplInit( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+TabControl::TabControl( Window* pParent, const ResId& rResId ) :
+ Control( WINDOW_TABCONTROL )
+{
+ rResId.SetRT( RSC_TABCONTROL );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplLoadRes( const ResId& rResId )
+{
+ Control::ImplLoadRes( rResId );
+
+ ULONG nObjMask = ReadLongRes();
+
+ if ( nObjMask & RSC_TABCONTROL_ITEMLIST )
+ {
+ ULONG nEle = ReadLongRes();
+
+ // Item hinzufuegen
+ for( ULONG i = 0; i < nEle; i++ )
+ {
+ InsertPage( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
+ IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+TabControl::~TabControl()
+{
+ if ( GetParent()->IsDialog() )
+ GetParent()->RemoveChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
+
+ ImplFreeLayoutData();
+
+ // TabCtrl-Daten loeschen
+ if ( mpTabCtrlData )
+ {
+ if( mpTabCtrlData->mpListBox )
+ delete mpTabCtrlData->mpListBox;
+ if ( mpTabCtrlData->mpLeftBtn )
+ delete mpTabCtrlData->mpLeftBtn;
+ if ( mpTabCtrlData->mpRightBtn )
+ delete mpTabCtrlData->mpRightBtn;
+ delete mpTabCtrlData;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplTabItem* TabControl::ImplGetItem( USHORT nId ) const
+{
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if( it->mnId == nId )
+ return &(*it);
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplScrollBtnsColor()
+{
+ if ( mpTabCtrlData && mpTabCtrlData->mpLeftBtn )
+ {
+ mpTabCtrlData->mpLeftBtn->SetControlForeground();
+ mpTabCtrlData->mpRightBtn->SetControlForeground();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplSetScrollBtnsState()
+{
+ if ( mbScroll )
+ {
+ mpTabCtrlData->mpLeftBtn->Enable( mnFirstPagePos != 0 );
+ mpTabCtrlData->mpRightBtn->Enable( mnFirstPagePos < mnLastFirstPagePos );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplPosScrollBtns()
+{
+ if ( mbScroll )
+ {
+ if ( !mpTabCtrlData->mpLeftBtn )
+ {
+ mpTabCtrlData->mpLeftBtn = new PushButton( this, WB_RECTSTYLE | WB_SMALLSTYLE | WB_NOPOINTERFOCUS | WB_REPEAT );
+ mpTabCtrlData->mpLeftBtn->SetSymbol( SYMBOL_PREV );
+ mpTabCtrlData->mpLeftBtn->SetClickHdl( LINK( this, TabControl, ImplScrollBtnHdl ) );
+ }
+ if ( !mpTabCtrlData->mpRightBtn )
+ {
+ mpTabCtrlData->mpRightBtn = new PushButton( this, WB_RECTSTYLE | WB_SMALLSTYLE | WB_NOPOINTERFOCUS | WB_REPEAT );
+ mpTabCtrlData->mpRightBtn->SetSymbol( SYMBOL_NEXT );
+ mpTabCtrlData->mpRightBtn->SetClickHdl( LINK( this, TabControl, ImplScrollBtnHdl ) );
+ }
+
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+ aRect.Left() -= TAB_OFFSET;
+ aRect.Top() -= TAB_OFFSET;
+ aRect.Right() += TAB_OFFSET;
+ aRect.Bottom() += TAB_OFFSET;
+ long nX = aRect.Right()-mnBtnSize+1;
+ long nY = aRect.Top()-mnBtnSize;
+ mpTabCtrlData->mpRightBtn->SetPosSizePixel( nX, nY, mnBtnSize, mnBtnSize );
+ nX -= mnBtnSize;
+ mpTabCtrlData->mpLeftBtn->SetPosSizePixel( nX, nY, mnBtnSize, mnBtnSize );
+ ImplScrollBtnsColor();
+ ImplSetScrollBtnsState();
+ mpTabCtrlData->mpLeftBtn->Show();
+ mpTabCtrlData->mpRightBtn->Show();
+ }
+ else
+ {
+ if ( mpTabCtrlData )
+ {
+ if ( mpTabCtrlData->mpLeftBtn )
+ mpTabCtrlData->mpLeftBtn->Hide();
+ if ( mpTabCtrlData->mpRightBtn )
+ mpTabCtrlData->mpRightBtn->Hide();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size TabControl::ImplGetItemSize( ImplTabItem* pItem, long nMaxWidth )
+{
+ pItem->maFormatText = pItem->maText;
+ Size aSize( GetCtrlTextWidth( pItem->maFormatText ), GetTextHeight() );
+ Size aImageSize( 0, 0 );
+ if( !!pItem->maTabImage )
+ {
+ aImageSize = pItem->maTabImage.GetSizePixel();
+ if( pItem->maFormatText.Len() )
+ aImageSize.Width() += GetTextHeight()/4;
+ }
+ aSize.Width() += aImageSize.Width();
+ if( aImageSize.Height() > aSize.Height() )
+ aSize.Height() = aImageSize.Height();
+
+ aSize.Width() += TAB_TABOFFSET_X*2;
+ aSize.Height() += TAB_TABOFFSET_Y*2;
+
+ Rectangle aCtrlRegion( Point( 0, 0 ), aSize );
+ Rectangle aBoundingRgn, aContentRgn;
+ const ImplControlValue aControlValue;
+ if(GetNativeControlRegion( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ return aContentRgn.GetSize();
+ }
+
+ // For systems without synthetic bold support
+ if ( mbExtraSpace )
+ aSize.Width() += TAB_EXTRASPACE_X;
+ // For languages with short names (e.g. Chinese), because the space is
+ // normally only one pixel per char
+ else if ( pItem->maFormatText.Len() < TAB_EXTRASPACE_X )
+ aSize.Width() += TAB_EXTRASPACE_X-pItem->maFormatText.Len();
+
+ // Evt. den Text kuerzen
+ if ( aSize.Width()+4 >= nMaxWidth )
+ {
+ XubString aAppendStr( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
+ pItem->maFormatText += aAppendStr;
+ do
+ {
+ pItem->maFormatText.Erase( pItem->maFormatText.Len()-aAppendStr.Len()-1, 1 );
+ aSize.Width() = GetCtrlTextWidth( pItem->maFormatText );
+ aSize.Width() += aImageSize.Width();
+ aSize.Width() += TAB_TABOFFSET_X*2;
+ }
+ while ( (aSize.Width()+4 >= nMaxWidth) && (pItem->maFormatText.Len() > aAppendStr.Len()) );
+ if ( aSize.Width()+4 >= nMaxWidth )
+ {
+ pItem->maFormatText.Assign( '.' );
+ aSize.Width() = 1;
+ }
+ }
+
+ if( pItem->maFormatText.Len() == 0 )
+ {
+ if( aSize.Height() < aImageSize.Height()+4 ) //leave space for focus rect
+ aSize.Height() = aImageSize.Height()+4;
+ }
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle TabControl::ImplGetTabRect( USHORT nItemPos, long nWidth, long nHeight )
+{
+ Size aWinSize = Control::GetOutputSizePixel();
+ if ( nWidth == -1 )
+ nWidth = aWinSize.Width();
+ if ( nHeight == -1 )
+ nHeight = aWinSize.Height();
+
+ if ( mpTabCtrlData->maItemList.empty() )
+ {
+ return Rectangle( Point( TAB_OFFSET, TAB_OFFSET ),
+ Size( nWidth-TAB_OFFSET*2, nHeight-TAB_OFFSET*2 ) );
+ }
+
+ if ( nItemPos == TAB_PAGERECT )
+ {
+ USHORT nLastPos;
+ if ( mnCurPageId )
+ nLastPos = GetPagePos( mnCurPageId );
+ else
+ nLastPos = 0;
+
+ Rectangle aRect = ImplGetTabRect( nLastPos, nWidth, nHeight );
+ aRect = Rectangle( Point( TAB_OFFSET, aRect.Bottom()+TAB_OFFSET ),
+ Size( nWidth-TAB_OFFSET*2,
+ nHeight-aRect.Bottom()-TAB_OFFSET*2 ) );
+ return aRect;
+ }
+
+ nWidth -= 1;
+
+ if ( (nWidth <= 0) || (nHeight <= 0) )
+ return Rectangle();
+
+ if ( mbFormat || (mnLastWidth != nWidth) || (mnLastHeight != nHeight) )
+ {
+ Font aFont( GetFont() );
+ Font aLightFont = aFont;
+ aFont.SetTransparent( TRUE );
+ aFont.SetWeight( (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus) ? WEIGHT_BOLD : WEIGHT_LIGHT );
+ aLightFont.SetTransparent( TRUE );
+ aLightFont.SetWeight( WEIGHT_LIGHT );
+
+ // If Bold and none Bold strings have the same width, we
+ // add in the calcultion extra space, so that the tabs
+ // looks better. The could be the case on systems without
+ // an bold UI font and without synthetic bold support
+ XubString aTestStr( RTL_CONSTASCII_USTRINGPARAM( "Abc." ) );
+ SetFont( aLightFont );
+ long nTextWidth1 = GetTextWidth( aTestStr );
+ SetFont( aFont );
+ long nTextWidth2 = GetTextWidth( aTestStr );
+ mbExtraSpace = (nTextWidth1 == nTextWidth2);
+
+ Size aSize;
+ const long nOffsetX = 2 + GetItemsOffset().X();
+ const long nOffsetY = 2 + GetItemsOffset().Y();
+ long nX = nOffsetX;
+ long nY = nOffsetY;
+ long nMaxWidth = nWidth;
+ USHORT nPos = 0;
+
+ if ( (mnMaxPageWidth > 0) && (mnMaxPageWidth < nMaxWidth) )
+ nMaxWidth = mnMaxPageWidth;
+ nMaxWidth -= GetItemsOffset().X();
+
+ mbScroll = FALSE;
+
+ USHORT nLines = 0;
+ USHORT nCurLine = 0;
+ long nLineWidthAry[100];
+ USHORT nLinePosAry[101];
+
+ nLineWidthAry[0] = 0;
+ nLinePosAry[0] = 0;
+ for( std::vector<ImplTabItem>::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ aSize = ImplGetItemSize( &(*it), nMaxWidth );
+
+ if ( ((nX+aSize.Width()) > nWidth - 2) && (nWidth > 2+nOffsetX) )
+ {
+ if ( nLines == 99 )
+ break;
+
+ nX = nOffsetX;
+ nY += aSize.Height();
+ nLines++;
+ nLineWidthAry[nLines] = 0;
+ nLinePosAry[nLines] = nPos;
+ }
+
+ Rectangle aNewRect( Point( nX, nY ), aSize );
+ if ( mbSmallInvalidate && (it->maRect != aNewRect) )
+ mbSmallInvalidate = FALSE;
+ it->maRect = aNewRect;
+ it->mnLine = nLines;
+ it->mbFullVisible = TRUE;
+
+ nLineWidthAry[nLines] += aSize.Width();
+ nX += aSize.Width();
+
+ if ( it->mnId == mnCurPageId )
+ nCurLine = nLines;
+
+ nPos++;
+ }
+
+ if ( nLines && !mpTabCtrlData->maItemList.empty() )
+ {
+ long nDX = 0;
+ long nModDX = 0;
+ long nIDX = 0;
+ USHORT i;
+ USHORT n;
+ long nLineHeightAry[100];
+ long nIH = mpTabCtrlData->maItemList[0].maRect.Bottom()-2;
+
+ i = 0;
+ while ( i < nLines+1 )
+ {
+ if ( i <= nCurLine )
+ nLineHeightAry[i] = nIH*(nLines-(nCurLine-i)) + GetItemsOffset().Y();
+ else
+ nLineHeightAry[i] = nIH*(i-nCurLine-1) + GetItemsOffset().Y();
+ i++;
+ }
+
+ i = 0;
+ n = 0;
+ nLinePosAry[nLines+1] = (USHORT)mpTabCtrlData->maItemList.size();
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( i == nLinePosAry[n] )
+ {
+ if ( n == nLines+1 )
+ break;
+
+ nIDX = 0;
+ if( nLinePosAry[n+1]-i > 0 )
+ {
+ nDX = (nWidth-nOffsetX-nLineWidthAry[n]) / (nLinePosAry[n+1]-i);
+ nModDX = (nWidth-nOffsetX-nLineWidthAry[n]) % (nLinePosAry[n+1]-i);
+ }
+ else
+ {
+ // FIXME: this is a bad case of tabctrl way too small
+ nDX = 0;
+ nModDX = 0;
+ }
+ n++;
+ }
+
+ it->maRect.Left() += nIDX;
+ it->maRect.Right() += nIDX+nDX;
+ it->maRect.Top() = nLineHeightAry[n-1];
+ it->maRect.Bottom() = nLineHeightAry[n-1]+nIH;
+ nIDX += nDX;
+
+ if ( nModDX )
+ {
+ nIDX++;
+ it->maRect.Right()++;
+ nModDX--;
+ }
+
+ i++;
+ }
+ }
+ else
+ {//only one line
+ if(ImplGetSVData()->maNWFData.mbCenteredTabs)
+ {
+ int nRightSpace=nMaxWidth;//space left on the right by the tabs
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ nRightSpace-=it->maRect.Right()-it->maRect.Left();
+ }
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ it->maRect.Left()+=(int) (nRightSpace/2);
+ it->maRect.Right()+=(int) (nRightSpace/2);
+ }
+ }
+ }
+
+ mnLastWidth = nWidth;
+ mnLastHeight = nHeight;
+ mbFormat = FALSE;
+
+ ImplPosScrollBtns();
+ }
+
+ return size_t(nItemPos) < mpTabCtrlData->maItemList.size() ? mpTabCtrlData->maItemList[nItemPos].maRect : Rectangle();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplChangeTabPage( USHORT nId, USHORT nOldId )
+{
+ ImplFreeLayoutData();
+
+ ImplTabItem* pOldItem = ImplGetItem( nOldId );
+ ImplTabItem* pItem = ImplGetItem( nId );
+ TabPage* pOldPage = (pOldItem) ? pOldItem->mpTabPage : NULL;
+ TabPage* pPage = (pItem) ? pItem->mpTabPage : NULL;
+ Window* pCtrlParent = GetParent();
+
+ if ( IsReallyVisible() && IsUpdateMode() )
+ {
+ USHORT nPos = GetPagePos( nId );
+ Rectangle aRect = ImplGetTabRect( nPos );
+
+ if ( !pOldItem || (pOldItem->mnLine != pItem->mnLine) )
+ {
+ aRect.Left() = 0;
+ aRect.Top() = 0;
+ aRect.Right() = Control::GetOutputSizePixel().Width();
+ }
+ else
+ {
+ aRect.Left() -= 3;
+ aRect.Top() -= 2;
+ aRect.Right() += 3;
+ Invalidate( aRect );
+ nPos = GetPagePos( nOldId );
+ aRect = ImplGetTabRect( nPos );
+ aRect.Left() -= 3;
+ aRect.Top() -= 2;
+ aRect.Right() += 3;
+ }
+ Invalidate( aRect );
+ }
+
+ if ( pOldPage == pPage )
+ return;
+
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+
+ if ( pOldPage )
+ {
+ if ( mbRestoreHelpId )
+ pCtrlParent->SetHelpId( rtl::OString() );
+ if ( mbRestoreUnqId )
+ pCtrlParent->SetUniqueId( rtl::OString() );
+ pOldPage->DeactivatePage();
+ }
+
+ if ( pPage )
+ {
+ pPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
+
+ // activate page here so the conbtrols can be switched
+ // also set the help id of the parent window to that of the tab page
+ if ( !GetHelpId().getLength() )
+ {
+ mbRestoreHelpId = TRUE;
+ pCtrlParent->SetHelpId( pPage->GetHelpId() );
+ }
+ if ( !pCtrlParent->GetUniqueId().getLength() )
+ {
+ mbRestoreUnqId = TRUE;
+ pCtrlParent->SetUniqueId( pPage->GetUniqueId() );
+ }
+
+ pPage->ActivatePage();
+
+ if ( pOldPage && pOldPage->HasChildPathFocus() )
+ {
+ USHORT n = 0;
+ Window* pFirstChild = pPage->ImplGetDlgWindow( n, DLGWINDOW_FIRST );
+ if ( pFirstChild )
+ pFirstChild->ImplControlFocus( GETFOCUS_INIT );
+ else
+ GrabFocus();
+ }
+
+ pPage->Show();
+ }
+
+ if ( pOldPage )
+ pOldPage->Hide();
+
+ // Invalidate the same region that will be send to NWF
+ // to always allow for bitmap caching
+ // see Window::DrawNativeControl()
+ if( IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL ) )
+ {
+ aRect.Left() -= TAB_OFFSET;
+ aRect.Top() -= TAB_OFFSET;
+ aRect.Right() += TAB_OFFSET;
+ aRect.Bottom() += TAB_OFFSET;
+ }
+
+ Invalidate( aRect );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL TabControl::ImplPosCurTabPage()
+{
+ // Aktuelle TabPage resizen/positionieren
+ ImplTabItem* pItem = ImplGetItem( GetCurPageId() );
+ if ( pItem && pItem->mpTabPage )
+ {
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+ pItem->mpTabPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplActivateTabPage( BOOL bNext )
+{
+ USHORT nCurPos = GetPagePos( GetCurPageId() );
+
+ if ( bNext )
+ nCurPos = (nCurPos + 1) % GetPageCount();
+ else
+ {
+ if ( !nCurPos )
+ nCurPos = GetPageCount()-1;
+ else
+ nCurPos--;
+ }
+
+ SelectTabPage( GetPageId( nCurPos ) );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplSetFirstPagePos( USHORT )
+{
+ return; // was only required for single line
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplShowFocus()
+{
+ if ( !GetPageCount() || mpTabCtrlData->mpListBox )
+ return;
+
+ // make sure the focussed item rect is computed using a bold font
+ // the font may have changed meanwhile due to mouse over
+
+ Font aOldFont( GetFont() );
+ Font aFont( aOldFont );
+ aFont.SetWeight( (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus) ? WEIGHT_BOLD : WEIGHT_LIGHT );
+ SetFont( aFont );
+
+ USHORT nCurPos = GetPagePos( mnCurPageId );
+ Rectangle aRect = ImplGetTabRect( nCurPos );
+ const ImplTabItem& rItem = mpTabCtrlData->maItemList[ nCurPos ];
+ Size aTabSize = aRect.GetSize();
+ Size aImageSize( 0, 0 );
+ long nTextHeight = GetTextHeight();
+ long nTextWidth = GetCtrlTextWidth( rItem.maFormatText );
+ USHORT nOff;
+
+ if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_MONO) )
+ nOff = 1;
+ else
+ nOff = 0;
+
+ if( !! rItem.maTabImage )
+ {
+ aImageSize = rItem.maTabImage.GetSizePixel();
+ if( rItem.maFormatText.Len() )
+ aImageSize.Width() += GetTextHeight()/4;
+ }
+
+ if( rItem.maFormatText.Len() )
+ {
+ // show focus around text
+ aRect.Left() = aRect.Left()+aImageSize.Width()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1-1;
+ aRect.Top() = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-1-1;
+ aRect.Right() = aRect.Left()+nTextWidth+2;
+ aRect.Bottom() = aRect.Top()+nTextHeight+2;
+ }
+ else
+ {
+ // show focus around image
+ long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1;
+ long nYPos = aRect.Top();
+ if( aImageSize.Height() < aRect.GetHeight() )
+ nYPos += (aRect.GetHeight() - aImageSize.Height())/2;
+
+ aRect.Left() = nXPos - 2;
+ aRect.Top() = nYPos - 2;
+ aRect.Right() = aRect.Left() + aImageSize.Width() + 4;
+ aRect.Bottom() = aRect.Top() + aImageSize.Height() + 4;
+ }
+ ShowFocus( aRect );
+
+ SetFont( aOldFont );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplDrawItem( ImplTabItem* pItem, const Rectangle& rCurRect, bool bLayout, bool bFirstInGroup, bool bLastInGroup, bool bIsCurrentItem )
+{
+ if ( pItem->maRect.IsEmpty() )
+ return;
+
+ if( bLayout )
+ {
+ if( !HasLayoutData() )
+ {
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ mpTabCtrlData->maLayoutLineToPageId.clear();
+ mpTabCtrlData->maLayoutPageIdToLine.clear();
+ mpTabCtrlData->maTabRectangles.clear();
+ }
+ }
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Rectangle aRect = pItem->maRect;
+ long nLeftBottom = aRect.Bottom();
+ long nRightBottom = aRect.Bottom();
+ BOOL bLeftBorder = TRUE;
+ BOOL bRightBorder = TRUE;
+ USHORT nOff;
+ BOOL bNativeOK = FALSE;
+
+ USHORT nOff2 = 0;
+ USHORT nOff3 = 0;
+
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ nOff = 1;
+ else
+ nOff = 0;
+
+ // Wenn wir die aktuelle Page sind, muessen wir etwas mehr zeichnen
+ if ( pItem->mnId == mnCurPageId )
+ {
+ nOff2 = 2;
+ if( ! ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise )
+ nOff3 = 1;
+ }
+ else
+ {
+ Point aLeftTestPos = aRect.BottomLeft();
+ Point aRightTestPos = aRect.BottomRight();
+ if ( aLeftTestPos.Y() == rCurRect.Bottom() )
+ {
+ aLeftTestPos.X() -= 2;
+ if ( rCurRect.IsInside( aLeftTestPos ) )
+ bLeftBorder = FALSE;
+ aRightTestPos.X() += 2;
+ if ( rCurRect.IsInside( aRightTestPos ) )
+ bRightBorder = FALSE;
+ }
+ else
+ {
+ if ( rCurRect.IsInside( aLeftTestPos ) )
+ nLeftBottom -= 2;
+ if ( rCurRect.IsInside( aRightTestPos ) )
+ nRightBottom -= 2;
+ }
+ }
+
+ if( !bLayout && (bNativeOK = IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL)) == TRUE )
+ {
+ Rectangle aCtrlRegion( pItem->maRect );
+ ControlState nState = 0;
+
+ if( pItem->mnId == mnCurPageId )
+ {
+ nState |= CTRL_STATE_SELECTED;
+ // only the selected item can be focussed
+ if ( HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+ }
+ if ( IsEnabled() )
+ nState |= CTRL_STATE_ENABLED;
+ if( IsMouseOver() && pItem->maRect.IsInside( GetPointerPosPixel() ) )
+ {
+ nState |= CTRL_STATE_ROLLOVER;
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if( (&(*it) != pItem) && (it->maRect.IsInside( GetPointerPosPixel() ) ) )
+ {
+ nState &= ~CTRL_STATE_ROLLOVER; // avoid multiple highlighted tabs
+ break;
+ }
+ }
+ }
+
+ TabitemValue tiValue;
+ if(pItem->maRect.Left() < 5)
+ tiValue.mnAlignment |= TABITEM_LEFTALIGNED;
+ if(pItem->maRect.Right() > mnLastWidth - 5)
+ tiValue.mnAlignment |= TABITEM_RIGHTALIGNED;
+ if ( bFirstInGroup )
+ tiValue.mnAlignment |= TABITEM_FIRST_IN_GROUP;
+ if ( bLastInGroup )
+ tiValue.mnAlignment |= TABITEM_LAST_IN_GROUP;
+
+ bNativeOK = DrawNativeControl( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
+ tiValue, rtl::OUString() );
+ }
+
+ if( ! bLayout && !bNativeOK )
+ {
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ {
+ SetLineColor( rStyleSettings.GetLightColor() );
+ DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) ); // diagonally indented top-left pixel
+ if ( bLeftBorder )
+ {
+ DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
+ Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
+ }
+ DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ), // top line starting 2px from left border
+ Point( aRect.Right()+nOff2-3, aRect.Top()-nOff2 ) ); // ending 3px from right border
+
+ if ( bRightBorder )
+ {
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ DrawLine( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ),
+ Point( aRect.Right()+nOff2-2, nRightBottom-1 ) );
+
+ SetLineColor( rStyleSettings.GetDarkShadowColor() );
+ DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+3-nOff2 ),
+ Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
+ }
+ }
+ else
+ {
+ SetLineColor( Color( COL_BLACK ) );
+ DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) );
+ DrawPixel( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ) );
+ if ( bLeftBorder )
+ {
+ DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
+ Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
+ }
+ DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ),
+ Point( aRect.Right()-3, aRect.Top()-nOff2 ) );
+ if ( bRightBorder )
+ {
+ DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+2-nOff2 ),
+ Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
+ }
+ }
+ }
+
+ if( bLayout )
+ {
+ int nLine = mpControlData->mpLayoutData->m_aLineIndices.size();
+ mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
+ mpTabCtrlData->maLayoutPageIdToLine[ (int)pItem->mnId ] = nLine;
+ mpTabCtrlData->maLayoutLineToPageId[ nLine ] = (int)pItem->mnId;
+ mpTabCtrlData->maTabRectangles.push_back( aRect );
+ }
+
+ // set font accordingly, current item is painted bold
+ // we set the font attributes always before drawing to be re-entrant (DrawNativeControl may trigger additional paints)
+ Font aFont( GetFont() );
+ aFont.SetTransparent( TRUE );
+ aFont.SetWeight( ((bIsCurrentItem) && (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus)) ? WEIGHT_BOLD : WEIGHT_LIGHT );
+ SetFont( aFont );
+
+ Size aTabSize = aRect.GetSize();
+ Size aImageSize( 0, 0 );
+ long nTextHeight = GetTextHeight();
+ long nTextWidth = GetCtrlTextWidth( pItem->maFormatText );
+ if( !! pItem->maTabImage )
+ {
+ aImageSize = pItem->maTabImage.GetSizePixel();
+ if( pItem->maFormatText.Len() )
+ aImageSize.Width() += GetTextHeight()/4;
+ }
+ long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-nOff3;
+ long nYPos = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-nOff3;
+ if( pItem->maFormatText.Len() )
+ {
+ USHORT nStyle = TEXT_DRAW_MNEMONIC;
+ if( ! pItem->mbEnabled )
+ nStyle |= TEXT_DRAW_DISABLE;
+ DrawCtrlText( Point( nXPos + aImageSize.Width(), nYPos ),
+ pItem->maFormatText,
+ 0, STRING_LEN, nStyle,
+ bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL,
+ bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL
+ );
+ }
+
+ if( !! pItem->maTabImage )
+ {
+ Point aImgTL( nXPos, aRect.Top() );
+ if( aImageSize.Height() < aRect.GetHeight() )
+ aImgTL.Y() += (aRect.GetHeight() - aImageSize.Height())/2;
+ DrawImage( aImgTL, pItem->maTabImage, pItem->mbEnabled ? 0 : IMAGE_DRAW_DISABLE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long TabControl::ImplHandleKeyEvent( const KeyEvent& rKeyEvent )
+{
+ long nRet = 0;
+
+ if ( GetPageCount() > 1 )
+ {
+ KeyCode aKeyCode = rKeyEvent.GetKeyCode();
+ USHORT nKeyCode = aKeyCode.GetCode();
+
+ if ( aKeyCode.IsMod1() )
+ {
+ if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) )
+ {
+ if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) )
+ {
+ ImplActivateTabPage( FALSE );
+ nRet = 1;
+ }
+ }
+ else
+ {
+ if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) )
+ {
+ ImplActivateTabPage( TRUE );
+ nRet = 1;
+ }
+ }
+ }
+ }
+
+ return nRet;
+}
+
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( TabControl, ImplScrollBtnHdl, PushButton*, EMPTYARG )
+{
+ ImplSetScrollBtnsState();
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( TabControl, ImplListBoxSelectHdl, ListBox*, EMPTYARG )
+{
+ SelectTabPage( GetPageId( mpTabCtrlData->mpListBox->GetSelectEntryPos() ) );
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( TabControl, ImplWindowEventListener, VclSimpleEvent*, pEvent )
+{
+ if ( pEvent && pEvent->ISA( VclWindowEvent ) && (pEvent->GetId() == VCLEVENT_WINDOW_KEYINPUT) )
+ {
+ VclWindowEvent* pWindowEvent = static_cast< VclWindowEvent* >(pEvent);
+ // Do not handle events from TabControl or it's children, which is done in Notify(), where the events can be consumed.
+ if ( !IsWindowOrChild( pWindowEvent->GetWindow() ) )
+ {
+ KeyEvent* pKeyEvent = static_cast< KeyEvent* >(pWindowEvent->GetData());
+ ImplHandleKeyEvent( *pKeyEvent );
+ }
+ }
+ return 0;
+}
+
+
+// -----------------------------------------------------------------------
+
+void TabControl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if( mpTabCtrlData->mpListBox == NULL )
+ {
+ if( rMEvt.IsLeft() )
+ {
+ USHORT nPageId = GetPageId( rMEvt.GetPosPixel() );
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+ if( pItem && pItem->mbEnabled )
+ SelectTabPage( nPageId );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::KeyInput( const KeyEvent& rKEvt )
+{
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->KeyInput( rKEvt );
+ else if ( GetPageCount() > 1 )
+ {
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+ USHORT nKeyCode = aKeyCode.GetCode();
+
+ if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_RIGHT) )
+ {
+ BOOL bNext = (nKeyCode == KEY_RIGHT);
+ ImplActivateTabPage( bNext );
+ }
+ }
+
+ Control::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::Paint( const Rectangle& rRect )
+{
+ ImplPaint( rRect, false );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ImplPaint( const Rectangle& rRect, bool bLayout )
+{
+ if( ! bLayout )
+ HideFocus();
+
+ // Hier wird gegebenenfalls auch neu formatiert
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+
+ // find current item
+ ImplTabItem* pCurItem = NULL;
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( it->mnId == mnCurPageId )
+ {
+ pCurItem = &(*it);
+ break;
+ }
+ }
+
+ // Draw the TabPage border
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ Rectangle aCurRect;
+ long nTopOff = 1;
+ aRect.Left() -= TAB_OFFSET;
+ aRect.Top() -= TAB_OFFSET;
+ aRect.Right() += TAB_OFFSET;
+ aRect.Bottom() += TAB_OFFSET;
+
+ // if we have an invisible tabpage or no tabpage at all the tabpage rect should be
+ // increased to avoid round corners that might be drawn by a theme
+ // in this case we're only interested in the top border of the tabpage because the tabitems are used
+ // standalone (eg impress)
+ BOOL bNoTabPage = FALSE;
+ TabPage* pCurPage = (pCurItem) ? pCurItem->mpTabPage : NULL;
+ if( !pCurPage || !pCurPage->IsVisible() )
+ {
+ bNoTabPage = TRUE;
+ aRect.Left()-=10;
+ aRect.Right()+=10;
+ }
+
+ BOOL bNativeOK = FALSE;
+ if( ! bLayout && (bNativeOK = IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL) ) == TRUE )
+ {
+ const ImplControlValue aControlValue;
+
+ ControlState nState = CTRL_STATE_ENABLED;
+ int part = PART_ENTIRE_CONTROL;
+ if ( !IsEnabled() )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+
+ Region aClipRgn( GetActiveClipRegion() );
+ aClipRgn.Intersect( aRect );
+ if( !rRect.IsEmpty() )
+ aClipRgn.Intersect( rRect );
+
+ if( !aClipRgn.IsEmpty() )
+ bNativeOK = DrawNativeControl( CTRL_TAB_PANE, part, aRect, nState,
+ aControlValue, rtl::OUString() );
+ }
+ else
+ {
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ SetLineColor( rStyleSettings.GetLightColor() );
+ else
+ SetLineColor( Color( COL_BLACK ) );
+ if ( pCurItem && !pCurItem->maRect.IsEmpty() )
+ {
+ aCurRect = pCurItem->maRect;
+ if( ! bLayout )
+ DrawLine( aRect.TopLeft(), Point( aCurRect.Left()-2, aRect.Top() ) );
+ if ( aCurRect.Right()+1 < aRect.Right() )
+ {
+ if( ! bLayout )
+ DrawLine( Point( aCurRect.Right(), aRect.Top() ), aRect.TopRight() );
+ }
+ else
+ nTopOff = 0;
+ }
+ else
+ if( ! bLayout )
+ DrawLine( aRect.TopLeft(), aRect.TopRight() );
+
+ if( ! bLayout )
+ {
+ DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
+
+ if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
+ {
+ // if we have not tab page the bottom line of the tab page
+ // directly touches the tab items, so choose a color that fits seamlessly
+ if( bNoTabPage )
+ SetLineColor( rStyleSettings.GetDialogColor() );
+ else
+ SetLineColor( rStyleSettings.GetShadowColor() );
+ DrawLine( Point( 1, aRect.Bottom()-1 ),
+ Point( aRect.Right()-1, aRect.Bottom()-1 ) );
+ DrawLine( Point( aRect.Right()-1, aRect.Top()+nTopOff ),
+ Point( aRect.Right()-1, aRect.Bottom()-1 ) );
+ if( bNoTabPage )
+ SetLineColor( rStyleSettings.GetDialogColor() );
+ else
+ SetLineColor( rStyleSettings.GetDarkShadowColor() );
+ DrawLine( Point( 0, aRect.Bottom() ),
+ Point( aRect.Right(), aRect.Bottom() ) );
+ DrawLine( Point( aRect.Right(), aRect.Top()+nTopOff ),
+ Point( aRect.Right(), aRect.Bottom() ) );
+ }
+ else
+ {
+ DrawLine( aRect.TopRight(), aRect.BottomRight() );
+ DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
+ }
+ }
+ }
+
+ if ( !mpTabCtrlData->maItemList.empty() && mpTabCtrlData->mpListBox == NULL )
+ {
+ // Some native toolkits (GTK+) draw tabs right-to-left, with an
+ // overlap between adjacent tabs
+ bool bDrawTabsRTL = IsNativeControlSupported( CTRL_TAB_ITEM, PART_TABS_DRAW_RTL );
+ ImplTabItem * pFirstTab = NULL;
+ ImplTabItem * pLastTab = NULL;
+ size_t idx;
+
+ // Event though there is a tab overlap with GTK+, the first tab is not
+ // overlapped on the left side. Other tookits ignore this option.
+ if ( bDrawTabsRTL )
+ {
+ pFirstTab = &mpTabCtrlData->maItemList.front();
+ pLastTab = &mpTabCtrlData->maItemList.back();
+ idx = mpTabCtrlData->maItemList.size()-1;
+ }
+ else
+ {
+ pLastTab = &mpTabCtrlData->maItemList.back();
+ pFirstTab = &mpTabCtrlData->maItemList.front();
+ idx = 0;
+ }
+
+ while ( idx < mpTabCtrlData->maItemList.size() )
+ {
+ ImplTabItem* pItem = &mpTabCtrlData->maItemList[idx];
+ if ( pItem != pCurItem )
+ {
+ Region aClipRgn( GetActiveClipRegion() );
+ aClipRgn.Intersect( pItem->maRect );
+ if( !rRect.IsEmpty() )
+ aClipRgn.Intersect( rRect );
+ if( bLayout || !aClipRgn.IsEmpty() )
+ ImplDrawItem( pItem, aCurRect, bLayout, (pItem==pFirstTab), (pItem==pLastTab), FALSE );
+ }
+
+ if ( bDrawTabsRTL )
+ idx--;
+ else
+ idx++;
+ }
+
+ if ( pCurItem )
+ {
+ Region aClipRgn( GetActiveClipRegion() );
+ aClipRgn.Intersect( pCurItem->maRect );
+ if( !rRect.IsEmpty() )
+ aClipRgn.Intersect( rRect );
+ if( bLayout || !aClipRgn.IsEmpty() )
+ ImplDrawItem( pCurItem, aCurRect, bLayout, (pCurItem==pFirstTab), (pCurItem==pLastTab), TRUE );
+ }
+ }
+
+ if ( !bLayout && HasFocus() )
+ ImplShowFocus();
+
+ if( ! bLayout )
+ mbSmallInvalidate = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::Resize()
+{
+ ImplFreeLayoutData();
+
+ if ( !IsReallyShown() )
+ return;
+
+ if( mpTabCtrlData->mpListBox )
+ {
+ // get the listbox' preferred size
+ Size aTabCtrlSize( GetSizePixel() );
+ long nPrefWidth = mpTabCtrlData->mpListBox->GetOptimalSize( WINDOWSIZE_PREFERRED ).Width();
+ if( nPrefWidth > aTabCtrlSize.Width() )
+ nPrefWidth = aTabCtrlSize.Width();
+ Size aNewSize( nPrefWidth, LogicToPixel( Size( 12, 12 ), MapMode( MAP_APPFONT ) ).Height() );
+ Point aNewPos( (aTabCtrlSize.Width() - nPrefWidth) / 2, 0 );
+ mpTabCtrlData->mpListBox->SetPosSizePixel( aNewPos, aNewSize );
+ }
+
+ mbFormat = TRUE;
+
+ // Aktuelle TabPage resizen/positionieren
+ BOOL bTabPage = ImplPosCurTabPage();
+ // Feststellen, was invalidiert werden muss
+ Size aNewSize = Control::GetOutputSizePixel();
+ long nNewWidth = aNewSize.Width();
+ if ( mbScroll )
+ mbSmallInvalidate = FALSE;
+ else
+ {
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( !it->mbFullVisible ||
+ (it->maRect.Right()-2 >= nNewWidth) )
+ {
+ mbSmallInvalidate = FALSE;
+ break;
+ }
+ }
+ }
+
+ if ( mbSmallInvalidate )
+ {
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
+ aRect.Left() -= TAB_OFFSET+TAB_BORDER_LEFT;
+ aRect.Top() -= TAB_OFFSET+TAB_BORDER_TOP;
+ aRect.Right() += TAB_OFFSET+TAB_BORDER_RIGHT;
+ aRect.Bottom() += TAB_OFFSET+TAB_BORDER_BOTTOM;
+ if ( bTabPage )
+ Invalidate( aRect, INVALIDATE_NOCHILDREN );
+ else
+ Invalidate( aRect );
+
+ }
+ else
+ {
+ if ( bTabPage )
+ Invalidate( INVALIDATE_NOCHILDREN );
+ else
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::GetFocus()
+{
+ if( ! mpTabCtrlData->mpListBox )
+ {
+ ImplShowFocus();
+ SetInputContext( InputContext( GetFont() ) );
+ }
+ else
+ {
+ if( mpTabCtrlData->mpListBox->IsReallyVisible() )
+ mpTabCtrlData->mpListBox->GrabFocus();
+ }
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::LoseFocus()
+{
+ if( ! mpTabCtrlData->mpListBox )
+ HideFocus();
+ Control::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::RequestHelp( const HelpEvent& rHEvt )
+{
+ USHORT nItemId = rHEvt.KeyboardActivated() ? mnCurPageId : GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
+
+ if ( nItemId )
+ {
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ {
+ XubString aStr = GetHelpText( nItemId );
+ if ( aStr.Len() )
+ {
+ Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
+ Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.Left() = aPt.X();
+ aItemRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.Right() = aPt.X();
+ aItemRect.Bottom() = aPt.Y();
+ Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
+ return;
+ }
+ }
+ else if ( rHEvt.GetMode() & HELPMODE_EXTENDED )
+ {
+ rtl::OUString aHelpId( rtl::OStringToOUString( GetHelpId( nItemId ), RTL_TEXTENCODING_UTF8 ) );
+ if ( aHelpId.getLength() )
+ {
+ // Wenn eine Hilfe existiert, dann ausloesen
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ pHelp->Start( aHelpId, this );
+ return;
+ }
+ }
+
+ // Bei Quick- oder Balloon-Help zeigen wir den Text an,
+ // wenn dieser abgeschnitten ist
+ if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) )
+ {
+ ImplTabItem* pItem = ImplGetItem( nItemId );
+ const XubString& rStr = pItem->maText;
+ if ( rStr != pItem->maFormatText )
+ {
+ Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
+ Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.Left() = aPt.X();
+ aItemRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.Right() = aPt.X();
+ aItemRect.Bottom() = aPt.Y();
+ if ( rStr.Len() )
+ {
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ Help::ShowBalloon( this, aItemRect.Center(), aItemRect, rStr );
+ else
+ Help::ShowQuickHelp( this, aItemRect, rStr );
+ return;
+ }
+ }
+ }
+
+ if ( rHEvt.GetMode() & HELPMODE_QUICK )
+ {
+ ImplTabItem* pItem = ImplGetItem( nItemId );
+ const XubString& rHelpText = pItem->maHelpText;
+ // show tooltip if not text but image is set and helptext is available
+ if ( rHelpText.Len() > 0 && pItem->maText.Len() == 0 && !!pItem->maTabImage )
+ {
+ Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
+ Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.Left() = aPt.X();
+ aItemRect.Top() = aPt.Y();
+ aPt = OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.Right() = aPt.X();
+ aItemRect.Bottom() = aPt.Y();
+ Help::ShowQuickHelp( this, aItemRect, rHelpText );
+ return;
+ }
+ }
+ }
+
+ Control::RequestHelp( rHEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::Command( const CommandEvent& rCEvt )
+{
+ if( (mpTabCtrlData->mpListBox == NULL) && (rCEvt.GetCommand() == COMMAND_CONTEXTMENU) && (GetPageCount() > 1) )
+ {
+ Point aMenuPos;
+ BOOL bMenu;
+ if ( rCEvt.IsMouseEvent() )
+ {
+ aMenuPos = rCEvt.GetMousePosPixel();
+ bMenu = GetPageId( aMenuPos ) != 0;
+ }
+ else
+ {
+ aMenuPos = ImplGetTabRect( GetPagePos( mnCurPageId ) ).Center();
+ bMenu = TRUE;
+ }
+
+ if ( bMenu )
+ {
+ PopupMenu aMenu;
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ aMenu.InsertItem( it->mnId, it->maText, MIB_CHECKABLE | MIB_RADIOCHECK );
+ if ( it->mnId == mnCurPageId )
+ aMenu.CheckItem( it->mnId );
+ aMenu.SetHelpId( it->mnId, it->maHelpId );
+ }
+
+ USHORT nId = aMenu.Execute( this, aMenuPos );
+ if ( nId && (nId != mnCurPageId) )
+ SelectTabPage( nId );
+ return;
+ }
+ }
+
+ Control::Command( rCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ ImplPosCurTabPage();
+ if( mpTabCtrlData->mpListBox )
+ Resize();
+ }
+ else if ( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+ else if ( (nType == STATE_CHANGE_ZOOM) ||
+ (nType == STATE_CHANGE_CONTROLFONT) )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle* TabControl::ImplFindPartRect( const Point& rPt )
+{
+ ImplTabItem* pFoundItem = NULL;
+ int nFound = 0;
+ for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( it->maRect.IsInside( rPt ) )
+ {
+ // assure that only one tab is highlighted at a time
+ nFound++;
+ pFoundItem = &(*it);
+ }
+ }
+ // assure that only one tab is highlighted at a time
+ return nFound == 1 ? &pFoundItem->maRect : NULL;
+}
+
+long TabControl::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
+ {
+ // trigger redraw if mouse over state has changed
+ if( IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
+ if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
+ {
+ Region aClipRgn;
+ if( pLastRect )
+ {
+ // allow for slightly bigger tabitems
+ // as used by gtk
+ // TODO: query for the correct sizes
+ Rectangle aRect(*pLastRect);
+ aRect.nLeft-=2;
+ aRect.nRight+=2;
+ aRect.nTop-=3;
+ aClipRgn.Union( aRect );
+ }
+ if( pRect )
+ {
+ // allow for slightly bigger tabitems
+ // as used by gtk
+ // TODO: query for the correct sizes
+ Rectangle aRect(*pRect);
+ aRect.nLeft-=2;
+ aRect.nRight+=2;
+ aRect.nTop-=3;
+ aClipRgn.Union( aRect );
+ }
+ if( !aClipRgn.IsEmpty() )
+ Invalidate( aClipRgn );
+ }
+ }
+ }
+ }
+
+ return nDone ? nDone : Control::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+long TabControl::Notify( NotifyEvent& rNEvt )
+{
+ long nRet = 0;
+
+ if ( rNEvt.GetType() == EVENT_KEYINPUT )
+ nRet = ImplHandleKeyEvent( *rNEvt.GetKeyEvent() );
+
+ return nRet ? nRet : Control::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::ActivatePage()
+{
+ maActivateHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+long TabControl::DeactivatePage()
+{
+ if ( maDeactivateHdl.IsSet() )
+ return maDeactivateHdl.Call( this );
+ else
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetTabPageSizePixel( const Size& rSize )
+{
+ ImplFreeLayoutData();
+
+ Size aNewSize( rSize );
+ aNewSize.Width() += TAB_OFFSET*2;
+ Rectangle aRect = ImplGetTabRect( TAB_PAGERECT,
+ aNewSize.Width(), aNewSize.Height() );
+ aNewSize.Height() += aRect.Top()+TAB_OFFSET;
+ Window::SetOutputSizePixel( aNewSize );
+}
+
+// -----------------------------------------------------------------------
+
+Size TabControl::GetTabPageSizePixel() const
+{
+ Rectangle aRect = ((TabControl*)this)->ImplGetTabRect( TAB_PAGERECT );
+ return aRect.GetSize();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::InsertPage( const ResId& rResId, USHORT nPos )
+{
+ GetRes( rResId.SetRT( RSC_TABCONTROLITEM ) );
+
+ ULONG nObjMask = ReadLongRes();
+ USHORT nItemId = 1;
+
+ // ID
+ if ( nObjMask & RSC_TABCONTROLITEM_ID )
+ nItemId = sal::static_int_cast<USHORT>(ReadLongRes());
+
+ // Text
+ XubString aTmpStr;
+ if( nObjMask & RSC_TABCONTROLITEM_TEXT )
+ aTmpStr = ReadStringRes();
+ InsertPage( nItemId, aTmpStr, nPos );
+
+ // PageResID
+ if ( nObjMask & RSC_TABCONTROLITEM_PAGERESID )
+ {
+ ImplTabItem& rItem = mpTabCtrlData->maItemList[ GetPagePos( nItemId ) ];
+ rItem.mnTabPageResId = sal::static_int_cast<USHORT>(ReadLongRes());
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::InsertPage( USHORT nPageId, const XubString& rText,
+ USHORT nPos )
+{
+ DBG_ASSERT( nPageId, "TabControl::InsertPage(): PageId == 0" );
+ DBG_ASSERT( GetPagePos( nPageId ) == TAB_PAGE_NOTFOUND,
+ "TabControl::InsertPage(): PageId already exists" );
+
+ // insert new page item
+ ImplTabItem* pItem = NULL;
+ if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() )
+ {
+ mpTabCtrlData->maItemList.push_back( ImplTabItem() );
+ pItem = &mpTabCtrlData->maItemList.back();
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->InsertEntry( rText );
+ }
+ else
+ {
+ std::vector< ImplTabItem >::iterator new_it =
+ mpTabCtrlData->maItemList.insert( mpTabCtrlData->maItemList.begin() + nPos, ImplTabItem() );
+ pItem = &(*new_it);
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->InsertEntry( rText, nPos);
+ }
+ if( mpTabCtrlData->mpListBox )
+ {
+ if( ! mnCurPageId )
+ mpTabCtrlData->mpListBox->SelectEntryPos( 0 );
+ mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
+ }
+
+ // set current page id
+ if ( !mnCurPageId )
+ mnCurPageId = nPageId;
+
+ // init new page item
+ pItem->mnId = nPageId;
+ pItem->mpTabPage = NULL;
+ pItem->mnTabPageResId = 0;
+ pItem->maText = rText;
+ pItem->mbFullVisible = FALSE;
+
+ mbFormat = TRUE;
+ if ( IsUpdateMode() )
+ Invalidate();
+
+ ImplFreeLayoutData();
+ if( mpTabCtrlData->mpListBox ) // reposition/resize listbox
+ Resize();
+
+ ImplCallEventListeners( VCLEVENT_TABPAGE_INSERTED, (void*) (ULONG)nPageId );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::RemovePage( USHORT nPageId )
+{
+ USHORT nPos = GetPagePos( nPageId );
+
+ // does the item exist ?
+ if ( nPos != TAB_PAGE_NOTFOUND )
+ {
+ //remove page item
+ std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos;
+ bool bIsCurrentPage = (it->mnId == mnCurPageId);
+ mpTabCtrlData->maItemList.erase( it );
+ if( mpTabCtrlData->mpListBox )
+ {
+ mpTabCtrlData->mpListBox->RemoveEntry( nPos );
+ mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
+ }
+
+ // If current page is removed, than first page gets the current page
+ if ( bIsCurrentPage )
+ {
+ mnCurPageId = 0;
+
+ if( ! mpTabCtrlData->maItemList.empty() )
+ {
+ // don't do this by simply setting mnCurPageId to pFirstItem->mnId
+ // this leaves a lot of stuff (such trivias as _showing_ the new current page) undone
+ // instead, call SetCurPageId
+ // without this, the next (outside) call to SetCurPageId with the id of the first page
+ // will result in doing nothing (as we assume that nothing changed, then), and the page
+ // will never be shown.
+ // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com
+
+ SetCurPageId( mpTabCtrlData->maItemList[0].mnId );
+ }
+ }
+
+ mbFormat = TRUE;
+ if ( IsUpdateMode() )
+ Invalidate();
+
+ ImplFreeLayoutData();
+
+ ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVED, (void*) (ULONG) nPageId );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::Clear()
+{
+ // clear item list
+ mpTabCtrlData->maItemList.clear();
+ mnCurPageId = 0;
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->Clear();
+
+ ImplFreeLayoutData();
+
+ mbFormat = TRUE;
+ if ( IsUpdateMode() )
+ Invalidate();
+
+ ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVEDALL );
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::EnablePage( USHORT i_nPageId, bool i_bEnable )
+{
+ ImplTabItem* pItem = ImplGetItem( i_nPageId );
+
+ if ( pItem && pItem->mbEnabled != i_bEnable )
+ {
+ pItem->mbEnabled = i_bEnable;
+ mbFormat = TRUE;
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ),
+ i_bEnable ? 0 : (LISTBOX_ENTRY_FLAG_DISABLE_SELECTION | LISTBOX_ENTRY_FLAG_DRAW_DISABLED) );
+ if( pItem->mnId == mnCurPageId )
+ {
+ // SetCurPageId will change to an enabled page
+ SetCurPageId( mnCurPageId );
+ }
+ else if ( IsUpdateMode() )
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetPageCount() const
+{
+ return (USHORT)mpTabCtrlData->maItemList.size();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetPageId( USHORT nPos ) const
+{
+ if( size_t(nPos) < mpTabCtrlData->maItemList.size() )
+ return mpTabCtrlData->maItemList[ nPos ].mnId;
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetPagePos( USHORT nPageId ) const
+{
+ for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
+ it != mpTabCtrlData->maItemList.end(); ++it )
+ {
+ if ( it->mnId == nPageId )
+ return (USHORT)(it - mpTabCtrlData->maItemList.begin());
+ }
+
+ return TAB_PAGE_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetPageId( const Point& rPos ) const
+{
+ for( size_t i = 0; i < mpTabCtrlData->maItemList.size(); ++i )
+ {
+ if ( ((TabControl*)this)->ImplGetTabRect( static_cast<USHORT>(i) ).IsInside( rPos ) )
+ return mpTabCtrlData->maItemList[ i ].mnId;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetCurPageId( USHORT nPageId )
+{
+ USHORT nPos = GetPagePos( nPageId );
+ while( nPos != TAB_PAGE_NOTFOUND &&
+ ! mpTabCtrlData->maItemList[nPos].mbEnabled )
+ {
+ nPos++;
+ if( size_t(nPos) >= mpTabCtrlData->maItemList.size() )
+ nPos = 0;
+ if( mpTabCtrlData->maItemList[nPos].mnId == nPageId )
+ break;
+ }
+
+ if( nPos != TAB_PAGE_NOTFOUND )
+ {
+ nPageId = mpTabCtrlData->maItemList[nPos].mnId;
+ if ( nPageId == mnCurPageId )
+ {
+ if ( mnActPageId )
+ mnActPageId = nPageId;
+ return;
+ }
+
+ if ( mnActPageId )
+ mnActPageId = nPageId;
+ else
+ {
+ mbFormat = TRUE;
+ USHORT nOldId = mnCurPageId;
+ mnCurPageId = nPageId;
+ ImplChangeTabPage( nPageId, nOldId );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetCurPageId() const
+{
+ if ( mnActPageId )
+ return mnActPageId;
+ else
+ return mnCurPageId;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetFirstPageId( USHORT )
+{
+ return; // was only required for single line
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SelectTabPage( USHORT nPageId )
+{
+ if ( nPageId && (nPageId != mnCurPageId) )
+ {
+ ImplFreeLayoutData();
+
+ ImplCallEventListeners( VCLEVENT_TABPAGE_DEACTIVATE, (void*) (ULONG) mnCurPageId );
+ if ( DeactivatePage() )
+ {
+ mnActPageId = nPageId;
+ ActivatePage();
+ // Page koennte im Activate-Handler umgeschaltet wurden sein
+ nPageId = mnActPageId;
+ mnActPageId = 0;
+ SetCurPageId( nPageId );
+ if( mpTabCtrlData->mpListBox )
+ mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) );
+ ImplCallEventListeners( VCLEVENT_TABPAGE_ACTIVATE, (void*) (ULONG) nPageId );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetTabPage( USHORT nPageId, TabPage* pTabPage )
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem && (pItem->mpTabPage != pTabPage) )
+ {
+ if ( pTabPage )
+ {
+ DBG_ASSERT( !pTabPage->IsVisible(), "TabControl::SetTabPage() - Page is visible" );
+
+ if ( IsDefaultSize() )
+ SetTabPageSizePixel( pTabPage->GetSizePixel() );
+
+ // Erst hier setzen, damit Resize nicht TabPage umpositioniert
+ pItem->mpTabPage = pTabPage;
+ if ( pItem->mnId == mnCurPageId )
+ ImplChangeTabPage( pItem->mnId, 0 );
+ }
+ else
+ pItem->mpTabPage = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+TabPage* TabControl::GetTabPage( USHORT nPageId ) const
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ return pItem->mpTabPage;
+ else
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT TabControl::GetTabPageResId( USHORT nPageId ) const
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ return pItem->mnTabPageResId;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetPageText( USHORT nPageId, const XubString& rText )
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem && pItem->maText != rText )
+ {
+ pItem->maText = rText;
+ mbFormat = TRUE;
+ if( mpTabCtrlData->mpListBox )
+ {
+ USHORT nPos = GetPagePos( nPageId );
+ mpTabCtrlData->mpListBox->RemoveEntry( nPos );
+ mpTabCtrlData->mpListBox->InsertEntry( rText, nPos );
+ }
+ if ( IsUpdateMode() )
+ Invalidate();
+ ImplFreeLayoutData();
+ ImplCallEventListeners( VCLEVENT_TABPAGE_PAGETEXTCHANGED, (void*) (ULONG) nPageId );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString TabControl::GetPageText( USHORT nPageId ) const
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ return pItem->maText;
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetHelpText( USHORT nPageId, const XubString& rText )
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ pItem->maHelpText = rText;
+}
+
+// -----------------------------------------------------------------------
+
+const XubString& TabControl::GetHelpText( USHORT nPageId ) const
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ {
+ if ( !pItem->maHelpText.Len() && pItem->maHelpId.getLength() )
+ {
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ pItem->maHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this );
+ }
+
+ return pItem->maHelpText;
+ }
+ else
+ return ImplGetSVEmptyStr();
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetHelpId( USHORT nPageId, const rtl::OString& rHelpId )
+{
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ pItem->maHelpId = rHelpId;
+}
+
+// -----------------------------------------------------------------------
+
+rtl::OString TabControl::GetHelpId( USHORT nPageId ) const
+{
+ rtl::OString aRet;
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+
+ if ( pItem )
+ aRet = pItem->maHelpId;
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetPageImage( USHORT i_nPageId, const Image& i_rImage )
+{
+ ImplTabItem* pItem = ImplGetItem( i_nPageId );
+
+ if ( pItem )
+ {
+ pItem->maTabImage = i_rImage;
+ mbFormat = TRUE;
+ if ( IsUpdateMode() )
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const Image* TabControl::GetPageImage( USHORT i_nPageId ) const
+{
+ const ImplTabItem* pItem = ImplGetItem( i_nPageId );
+ return pItem ? &pItem->maTabImage : NULL;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle TabControl::GetCharacterBounds( USHORT nPageId, long nIndex ) const
+{
+ Rectangle aRet;
+
+ if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
+ FillLayoutData();
+
+ if( HasLayoutData() )
+ {
+ std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPageId );
+ if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
+ {
+ Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( it->second );
+ if( (aPair.B() - aPair.A()) >= nIndex )
+ aRet = mpControlData->mpLayoutData->GetCharacterBounds( aPair.A() + nIndex );
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+long TabControl::GetIndexForPoint( const Point& rPoint, USHORT& rPageId ) const
+{
+ long nRet = -1;
+
+ if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
+ FillLayoutData();
+
+ if( HasLayoutData() )
+ {
+ int nIndex = mpControlData->mpLayoutData->GetIndexForPoint( rPoint );
+ if( nIndex != -1 )
+ {
+ // what line (->pageid) is this index in ?
+ int nLines = mpControlData->mpLayoutData->GetLineCount();
+ int nLine = -1;
+ while( ++nLine < nLines )
+ {
+ Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( nLine );
+ if( aPair.A() <= nIndex && aPair.B() >= nIndex )
+ {
+ nRet = nIndex - aPair.A();
+ rPageId = (USHORT)mpTabCtrlData->maLayoutLineToPageId[ nLine ];
+ break;
+ }
+ }
+ }
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::FillLayoutData() const
+{
+ mpTabCtrlData->maLayoutLineToPageId.clear();
+ mpTabCtrlData->maLayoutPageIdToLine.clear();
+ const_cast<TabControl*>(this)->ImplPaint( Rectangle(), true );
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle TabControl::GetTabPageBounds( USHORT nPage ) const
+{
+ Rectangle aRet;
+
+ if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
+ FillLayoutData();
+
+ if( HasLayoutData() )
+ {
+ std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPage );
+ if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
+ {
+ if( it->second >= 0 && it->second < static_cast<int>(mpTabCtrlData->maTabRectangles.size()) )
+ {
+ aRet = mpTabCtrlData->maTabRectangles[ it->second ];
+ aRet.Union( const_cast<TabControl*>(this)->ImplGetTabRect( TAB_PAGERECT ) );
+ }
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle TabControl::GetTabBounds( USHORT nPageId ) const
+{
+ Rectangle aRet;
+
+ ImplTabItem* pItem = ImplGetItem( nPageId );
+ if(pItem)
+ aRet = pItem->maRect;
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetItemsOffset( const Point& rOffs )
+{
+ if( mpTabCtrlData )
+ mpTabCtrlData->maItemsOffset = rOffs;
+}
+
+Point TabControl::GetItemsOffset() const
+{
+ if( mpTabCtrlData )
+ return mpTabCtrlData->maItemsOffset;
+ else
+ return Point();
+}
+
+// -----------------------------------------------------------------------
+
+Size TabControl::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return mpTabCtrlData ? mpTabCtrlData->maMinSize : Size();
+ default:
+ return Control::GetOptimalSize( eType );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void TabControl::SetMinimumSizePixel( const Size& i_rSize )
+{
+ if( mpTabCtrlData )
+ mpTabCtrlData->maMinSize = i_rSize;
+}
+
+// -----------------------------------------------------------------------
+
+