Update ooo320-m1
[ooovba.git] / vcl / source / control / tabctrl.cxx
blob05e8b1b5bb4e47b1586d3ea316f411872c60106e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tabctrl.cxx,v $
10 * $Revision: 1.38 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 #include <tools/debug.hxx>
35 #ifndef _SV_RC_H
36 #include <tools/rc.h>
37 #endif
38 #include <vcl/svdata.hxx>
39 #ifndef _SV_APP_HXX
40 #include <vcl/svapp.hxx>
41 #endif
42 #include <vcl/help.hxx>
43 #include <vcl/event.hxx>
44 #include <vcl/menu.hxx>
45 #include <vcl/button.hxx>
46 #include <vcl/tabpage.hxx>
47 #include <vcl/tabctrl.hxx>
48 #include <vcl/controllayout.hxx>
49 #include <vcl/sound.hxx>
51 #include <vcl/window.h>
53 #include <hash_map>
54 #include <vector>
56 // =======================================================================
58 struct ImplTabItem
60 USHORT mnId;
61 USHORT mnTabPageResId;
62 TabPage* mpTabPage;
63 String maText;
64 String maFormatText;
65 String maHelpText;
66 ULONG mnHelpId;
67 Rectangle maRect;
68 USHORT mnLine;
69 bool mbFullVisible;
70 bool mbEnabled;
71 Image maTabImage;
73 ImplTabItem()
74 : mnId( 0 ), mnTabPageResId( 0 ), mpTabPage( NULL ), mnHelpId( 0 ),
75 mnLine( 0 ), mbFullVisible( FALSE ), mbEnabled( true )
79 // -----------------------------------------------------------------------
81 struct ImplTabCtrlData
83 PushButton* mpLeftBtn;
84 PushButton* mpRightBtn;
85 std::hash_map< int, int > maLayoutPageIdToLine;
86 std::hash_map< int, int > maLayoutLineToPageId;
87 std::vector< Rectangle > maTabRectangles;
88 Point maItemsOffset; // offset of the tabitems
89 std::vector< ImplTabItem > maItemList;
92 // -----------------------------------------------------------------------
94 #if 0
95 // not used
96 #define TABCOLORCOUNT 10
98 static ColorData aImplTabColorAry[TABCOLORCOUNT] =
100 RGB_COLORDATA( 80, 216, 248 ),
101 RGB_COLORDATA( 128, 216, 168 ),
102 RGB_COLORDATA( 128, 144, 248 ),
103 RGB_COLORDATA( 208, 180, 168 ),
104 RGB_COLORDATA( 248, 252, 168 ),
105 RGB_COLORDATA( 168, 144, 168 ),
106 RGB_COLORDATA( 248, 144, 80 ),
107 RGB_COLORDATA( 248, 216, 80 ),
108 RGB_COLORDATA( 248, 180, 168 ),
109 RGB_COLORDATA( 248, 216, 168 )
111 #endif
113 // -----------------------------------------------------------------------
115 #define TAB_OFFSET 3
116 #define TAB_TABOFFSET_X 3
117 #define TAB_TABOFFSET_Y 3
118 #define TAB_EXTRASPACE_X 6
119 #define TAB_BORDER_LEFT 1
120 #define TAB_BORDER_TOP 1
121 #define TAB_BORDER_RIGHT 2
122 #define TAB_BORDER_BOTTOM 2
124 // Fuer die Ermittlung von den Tab-Positionen
125 #define TAB_PAGERECT 0xFFFF
127 // =======================================================================
129 void TabControl::ImplInit( Window* pParent, WinBits nStyle )
131 if ( !(nStyle & WB_NOTABSTOP) )
132 nStyle |= WB_TABSTOP;
133 if ( !(nStyle & WB_NOGROUP) )
134 nStyle |= WB_GROUP;
135 if ( !(nStyle & WB_NODIALOGCONTROL) )
136 nStyle |= WB_DIALOGCONTROL;
138 // no single line tabs since NWF
139 nStyle &= ~WB_SINGLELINE;
141 Control::ImplInit( pParent, nStyle, NULL );
143 mnLastWidth = 0;
144 mnLastHeight = 0;
145 mnBtnSize = 0;
146 mnMaxPageWidth = 0;
147 mnActPageId = 0;
148 mnCurPageId = 0;
149 mnFirstPagePos = 0;
150 mnLastFirstPagePos = 0;
151 mbFormat = TRUE;
152 mbRestoreHelpId = FALSE;
153 mbRestoreUnqId = FALSE;
154 mbSingleLine = FALSE;
155 mbScroll = FALSE;
156 mbColored = FALSE;
157 mbSmallInvalidate = FALSE;
158 mbExtraSpace = FALSE;
159 mpTabCtrlData = new ImplTabCtrlData;
160 mpTabCtrlData->mpLeftBtn = NULL;
161 mpTabCtrlData->mpRightBtn = NULL;
164 ImplInitSettings( TRUE, TRUE, TRUE );
166 // if the tabcontrol is drawn (ie filled) by a native widget, make sure all contols will have transparent background
167 // otherwise they will paint with a wrong background
168 if( IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL) )
169 EnableChildTransparentMode( TRUE );
172 // -----------------------------------------------------------------------
174 void TabControl::ImplInitSettings( BOOL bFont,
175 BOOL bForeground, BOOL bBackground )
177 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
179 if ( bFont )
181 Font aFont = rStyleSettings.GetAppFont();
182 if ( IsControlFont() )
183 aFont.Merge( GetControlFont() );
184 SetZoomedPointFont( aFont );
187 if ( bForeground || bFont )
189 Color aColor;
190 if ( IsControlForeground() )
191 aColor = GetControlForeground();
192 else
193 aColor = rStyleSettings.GetButtonTextColor();
194 SetTextColor( aColor );
195 SetTextFillColor();
198 if ( bBackground )
200 Window* pParent = GetParent();
201 if ( !IsControlBackground() &&
202 (pParent->IsChildTransparentModeEnabled()
203 || IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL)
204 || IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) ) )
207 // set transparent mode for NWF tabcontrols to have
208 // the background always cleared properly
209 EnableChildTransparentMode( TRUE );
210 SetParentClipMode( PARENTCLIPMODE_NOCLIP );
211 SetPaintTransparent( TRUE );
212 SetBackground();
213 ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
215 else
217 EnableChildTransparentMode( FALSE );
218 SetParentClipMode( 0 );
219 SetPaintTransparent( FALSE );
221 if ( IsControlBackground() )
222 SetBackground( GetControlBackground() );
223 else
224 SetBackground( pParent->GetBackground() );
228 ImplScrollBtnsColor();
231 // -----------------------------------------------------------------------
233 void TabControl::ImplFreeLayoutData()
235 if( mpLayoutData )
237 delete mpLayoutData, mpLayoutData = NULL;
238 mpTabCtrlData->maLayoutPageIdToLine.clear();
239 mpTabCtrlData->maLayoutLineToPageId.clear();
243 // -----------------------------------------------------------------------
245 TabControl::TabControl( Window* pParent, WinBits nStyle ) :
246 Control( WINDOW_TABCONTROL )
248 ImplInit( pParent, nStyle );
251 // -----------------------------------------------------------------------
253 TabControl::TabControl( Window* pParent, const ResId& rResId ) :
254 Control( WINDOW_TABCONTROL )
256 rResId.SetRT( RSC_TABCONTROL );
257 WinBits nStyle = ImplInitRes( rResId );
258 ImplInit( pParent, nStyle );
259 ImplLoadRes( rResId );
261 if ( !(nStyle & WB_HIDE) )
262 Show();
265 // -----------------------------------------------------------------------
267 void TabControl::ImplLoadRes( const ResId& rResId )
269 Control::ImplLoadRes( rResId );
271 ULONG nObjMask = ReadLongRes();
273 if ( nObjMask & RSC_TABCONTROL_ITEMLIST )
275 ULONG nEle = ReadLongRes();
277 // Item hinzufuegen
278 for( ULONG i = 0; i < nEle; i++ )
280 InsertPage( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
281 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
286 // -----------------------------------------------------------------------
288 TabControl::~TabControl()
290 ImplFreeLayoutData();
292 // TabCtrl-Daten loeschen
293 if ( mpTabCtrlData )
295 if ( mpTabCtrlData->mpLeftBtn )
296 delete mpTabCtrlData->mpLeftBtn;
297 if ( mpTabCtrlData->mpRightBtn )
298 delete mpTabCtrlData->mpRightBtn;
299 delete mpTabCtrlData;
303 // -----------------------------------------------------------------------
305 ImplTabItem* TabControl::ImplGetItem( USHORT nId ) const
307 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
308 it != mpTabCtrlData->maItemList.end(); ++it )
310 if( it->mnId == nId )
311 return &(*it);
314 return NULL;
317 // -----------------------------------------------------------------------
319 void TabControl::ImplScrollBtnsColor()
321 if ( mpTabCtrlData && mpTabCtrlData->mpLeftBtn )
323 mpTabCtrlData->mpLeftBtn->SetControlForeground();
324 mpTabCtrlData->mpRightBtn->SetControlForeground();
328 // -----------------------------------------------------------------------
330 void TabControl::ImplSetScrollBtnsState()
332 if ( mbScroll )
334 mpTabCtrlData->mpLeftBtn->Enable( mnFirstPagePos != 0 );
335 mpTabCtrlData->mpRightBtn->Enable( mnFirstPagePos < mnLastFirstPagePos );
339 // -----------------------------------------------------------------------
341 void TabControl::ImplPosScrollBtns()
343 if ( mbScroll )
345 if ( !mpTabCtrlData->mpLeftBtn )
347 mpTabCtrlData->mpLeftBtn = new PushButton( this, WB_RECTSTYLE | WB_SMALLSTYLE | WB_NOPOINTERFOCUS | WB_REPEAT );
348 mpTabCtrlData->mpLeftBtn->SetSymbol( SYMBOL_PREV );
349 mpTabCtrlData->mpLeftBtn->SetClickHdl( LINK( this, TabControl, ImplScrollBtnHdl ) );
351 if ( !mpTabCtrlData->mpRightBtn )
353 mpTabCtrlData->mpRightBtn = new PushButton( this, WB_RECTSTYLE | WB_SMALLSTYLE | WB_NOPOINTERFOCUS | WB_REPEAT );
354 mpTabCtrlData->mpRightBtn->SetSymbol( SYMBOL_NEXT );
355 mpTabCtrlData->mpRightBtn->SetClickHdl( LINK( this, TabControl, ImplScrollBtnHdl ) );
358 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
359 aRect.Left() -= TAB_OFFSET;
360 aRect.Top() -= TAB_OFFSET;
361 aRect.Right() += TAB_OFFSET;
362 aRect.Bottom() += TAB_OFFSET;
363 long nX = aRect.Right()-mnBtnSize+1;
364 long nY = aRect.Top()-mnBtnSize;
365 mpTabCtrlData->mpRightBtn->SetPosSizePixel( nX, nY, mnBtnSize, mnBtnSize );
366 nX -= mnBtnSize;
367 mpTabCtrlData->mpLeftBtn->SetPosSizePixel( nX, nY, mnBtnSize, mnBtnSize );
368 ImplScrollBtnsColor();
369 ImplSetScrollBtnsState();
370 mpTabCtrlData->mpLeftBtn->Show();
371 mpTabCtrlData->mpRightBtn->Show();
373 else
375 if ( mpTabCtrlData )
377 if ( mpTabCtrlData->mpLeftBtn )
378 mpTabCtrlData->mpLeftBtn->Hide();
379 if ( mpTabCtrlData->mpRightBtn )
380 mpTabCtrlData->mpRightBtn->Hide();
385 // -----------------------------------------------------------------------
387 Size TabControl::ImplGetItemSize( ImplTabItem* pItem, long nMaxWidth )
389 pItem->maFormatText = pItem->maText;
390 Size aSize( GetCtrlTextWidth( pItem->maFormatText ), GetTextHeight() );
391 Size aImageSize( 0, 0 );
392 if( !!pItem->maTabImage )
394 aImageSize = pItem->maTabImage.GetSizePixel();
395 if( pItem->maFormatText.Len() )
396 aImageSize.Width() += GetTextHeight()/4;
398 aSize.Width() += aImageSize.Width();
399 if( aImageSize.Height() > aSize.Height() )
400 aSize.Height() = aImageSize.Height();
402 Region aCtrlRegion( Rectangle( (const Point&)Point( 0, 0 ), aSize ) );
403 Region aBoundingRgn, aContentRgn;
404 const ImplControlValue aControlValue( BUTTONVALUE_DONTKNOW, rtl::OUString(), 0 );
405 if(GetNativeControlRegion( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion,
406 CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
407 aBoundingRgn, aContentRgn ) )
409 Rectangle aCont(aContentRgn.GetBoundRect());
410 return aCont.GetSize();
413 aSize.Width() += TAB_TABOFFSET_X*2;
414 aSize.Height() += TAB_TABOFFSET_Y*2;
415 // For systems without synthetic bold support
416 if ( mbExtraSpace )
417 aSize.Width() += TAB_EXTRASPACE_X;
418 // For languages with short names (e.g. Chinese), because the space is
419 // normally only one pixel per char
420 else if ( pItem->maFormatText.Len() < TAB_EXTRASPACE_X )
421 aSize.Width() += TAB_EXTRASPACE_X-pItem->maFormatText.Len();
423 // Evt. den Text kuerzen
424 if ( aSize.Width()+4 >= nMaxWidth )
426 XubString aAppendStr( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
427 pItem->maFormatText += aAppendStr;
430 pItem->maFormatText.Erase( pItem->maFormatText.Len()-aAppendStr.Len()-1, 1 );
431 aSize.Width() = GetCtrlTextWidth( pItem->maFormatText );
432 aSize.Width() += aImageSize.Width();
433 aSize.Width() += TAB_TABOFFSET_X*2;
435 while ( (aSize.Width()+4 >= nMaxWidth) && (pItem->maFormatText.Len() > aAppendStr.Len()) );
436 if ( aSize.Width()+4 >= nMaxWidth )
438 pItem->maFormatText.Assign( '.' );
439 aSize.Width() = 1;
443 if( pItem->maFormatText.Len() == 0 )
445 if( aSize.Height() < aImageSize.Height()+4 ) //leave space for focus rect
446 aSize.Height() = aImageSize.Height()+4;
449 return aSize;
452 // -----------------------------------------------------------------------
454 Rectangle TabControl::ImplGetTabRect( USHORT nItemPos, long nWidth, long nHeight )
456 Size aWinSize = Control::GetOutputSizePixel();
457 if ( nWidth == -1 )
458 nWidth = aWinSize.Width();
459 if ( nHeight == -1 )
460 nHeight = aWinSize.Height();
462 if ( mpTabCtrlData->maItemList.empty() )
464 return Rectangle( Point( TAB_OFFSET, TAB_OFFSET ),
465 Size( nWidth-TAB_OFFSET*2, nHeight-TAB_OFFSET*2 ) );
468 if ( nItemPos == TAB_PAGERECT )
470 USHORT nLastPos;
471 if ( mnCurPageId )
472 nLastPos = GetPagePos( mnCurPageId );
473 else
474 nLastPos = 0;
476 Rectangle aRect = ImplGetTabRect( nLastPos, nWidth, nHeight );
477 aRect = Rectangle( Point( TAB_OFFSET, aRect.Bottom()+TAB_OFFSET ),
478 Size( nWidth-TAB_OFFSET*2,
479 nHeight-aRect.Bottom()-TAB_OFFSET*2 ) );
480 return aRect;
483 nWidth -= 1;
485 if ( (nWidth <= 0) || (nHeight <= 0) )
486 return Rectangle();
488 if ( mbFormat || (mnLastWidth != nWidth) || (mnLastHeight != nHeight) )
490 Font aFont( GetFont() );
491 Font aLightFont = aFont;
492 aFont.SetTransparent( TRUE );
493 aFont.SetWeight( (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus) ? WEIGHT_BOLD : WEIGHT_LIGHT );
494 aLightFont.SetTransparent( TRUE );
495 aLightFont.SetWeight( WEIGHT_LIGHT );
497 // If Bold and none Bold strings have the same width, we
498 // add in the calcultion extra space, so that the tabs
499 // looks better. The could be the case on systems without
500 // an bold UI font and without synthetic bold support
501 XubString aTestStr( RTL_CONSTASCII_USTRINGPARAM( "Abc." ) );
502 SetFont( aLightFont );
503 long nTextWidth1 = GetTextWidth( aTestStr );
504 SetFont( aFont );
505 long nTextWidth2 = GetTextWidth( aTestStr );
506 mbExtraSpace = (nTextWidth1 == nTextWidth2);
508 Size aSize;
509 const long nOffsetX = 2 + GetItemsOffset().X();
510 const long nOffsetY = 2 + GetItemsOffset().Y();
511 long nX = nOffsetX;
512 long nY = nOffsetY;
513 long nMaxWidth = nWidth;
514 USHORT nPos = 0;
516 if ( (mnMaxPageWidth > 0) && (mnMaxPageWidth < nMaxWidth) )
517 nMaxWidth = mnMaxPageWidth;
518 nMaxWidth -= GetItemsOffset().X();
520 mbScroll = FALSE;
522 USHORT nLines = 0;
523 USHORT nCurLine = 0;
524 long nLineWidthAry[100];
525 USHORT nLinePosAry[101];
527 nLineWidthAry[0] = 0;
528 nLinePosAry[0] = 0;
529 for( std::vector<ImplTabItem>::iterator it = mpTabCtrlData->maItemList.begin();
530 it != mpTabCtrlData->maItemList.end(); ++it )
532 aSize = ImplGetItemSize( &(*it), nMaxWidth );
534 if ( ((nX+aSize.Width()) > nWidth - 2) && (nWidth > 2+nOffsetX) )
536 if ( nLines == 99 )
537 break;
539 nX = nOffsetX;
540 nY += aSize.Height();
541 nLines++;
542 nLineWidthAry[nLines] = 0;
543 nLinePosAry[nLines] = nPos;
546 Rectangle aNewRect( Point( nX, nY ), aSize );
547 if ( mbSmallInvalidate && (it->maRect != aNewRect) )
548 mbSmallInvalidate = FALSE;
549 it->maRect = aNewRect;
550 it->mnLine = nLines;
551 it->mbFullVisible = TRUE;
553 nLineWidthAry[nLines] += aSize.Width();
554 nX += aSize.Width();
556 if ( it->mnId == mnCurPageId )
557 nCurLine = nLines;
559 nPos++;
562 if ( nLines && !mpTabCtrlData->maItemList.empty() )
564 long nDX = 0;
565 long nModDX = 0;
566 long nIDX = 0;
567 USHORT i;
568 USHORT n;
569 long nLineHeightAry[100];
570 long nIH = mpTabCtrlData->maItemList[0].maRect.Bottom()-2;
572 i = 0;
573 while ( i < nLines+1 )
575 if ( i <= nCurLine )
576 nLineHeightAry[i] = nIH*(nLines-(nCurLine-i)) + GetItemsOffset().Y();
577 else
578 nLineHeightAry[i] = nIH*(i-nCurLine-1) + GetItemsOffset().Y();
579 i++;
582 i = 0;
583 n = 0;
584 nLinePosAry[nLines+1] = (USHORT)mpTabCtrlData->maItemList.size();
585 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
586 it != mpTabCtrlData->maItemList.end(); ++it )
588 if ( i == nLinePosAry[n] )
590 if ( n == nLines+1 )
591 break;
593 nIDX = 0;
594 if( nLinePosAry[n+1]-i > 0 )
596 nDX = (nWidth-nOffsetX-nLineWidthAry[n]) / (nLinePosAry[n+1]-i);
597 nModDX = (nWidth-nOffsetX-nLineWidthAry[n]) % (nLinePosAry[n+1]-i);
599 else
601 // FIXME: this is a bad case of tabctrl way too small
602 nDX = 0;
603 nModDX = 0;
605 n++;
608 it->maRect.Left() += nIDX;
609 it->maRect.Right() += nIDX+nDX;
610 it->maRect.Top() = nLineHeightAry[n-1];
611 it->maRect.Bottom() = nLineHeightAry[n-1]+nIH;
612 nIDX += nDX;
614 if ( nModDX )
616 nIDX++;
617 it->maRect.Right()++;
618 nModDX--;
621 i++;
624 else
625 {//only one line
626 if(ImplGetSVData()->maNWFData.mbCenteredTabs)
628 int nRightSpace=nMaxWidth;//space left on the right by the tabs
629 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
630 it != mpTabCtrlData->maItemList.end(); ++it )
632 nRightSpace-=it->maRect.Right()-it->maRect.Left();
634 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
635 it != mpTabCtrlData->maItemList.end(); ++it )
637 it->maRect.Left()+=(int) (nRightSpace/2);
638 it->maRect.Right()+=(int) (nRightSpace/2);
643 mnLastWidth = nWidth;
644 mnLastHeight = nHeight;
645 mbFormat = FALSE;
647 ImplPosScrollBtns();
650 return size_t(nItemPos) < mpTabCtrlData->maItemList.size() ? mpTabCtrlData->maItemList[nItemPos].maRect : Rectangle();
653 // -----------------------------------------------------------------------
655 void TabControl::ImplChangeTabPage( USHORT nId, USHORT nOldId )
657 ImplFreeLayoutData();
659 ImplTabItem* pOldItem = ImplGetItem( nOldId );
660 ImplTabItem* pItem = ImplGetItem( nId );
661 TabPage* pOldPage = (pOldItem) ? pOldItem->mpTabPage : NULL;
662 TabPage* pPage = (pItem) ? pItem->mpTabPage : NULL;
663 Window* pCtrlParent = GetParent();
665 if ( IsReallyVisible() && IsUpdateMode() )
667 USHORT nPos = GetPagePos( nId );
668 Rectangle aRect = ImplGetTabRect( nPos );
670 if ( !pOldItem || (pOldItem->mnLine != pItem->mnLine) )
672 aRect.Left() = 0;
673 aRect.Top() = 0;
674 aRect.Right() = Control::GetOutputSizePixel().Width();
676 else
678 aRect.Left() -= 3;
679 aRect.Top() -= 2;
680 aRect.Right() += 3;
681 Invalidate( aRect );
682 nPos = GetPagePos( nOldId );
683 aRect = ImplGetTabRect( nPos );
684 aRect.Left() -= 3;
685 aRect.Top() -= 2;
686 aRect.Right() += 3;
688 Invalidate( aRect );
691 if ( pOldPage == pPage )
692 return;
694 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
696 if ( pOldPage )
698 if ( mbRestoreHelpId )
699 pCtrlParent->SetHelpId( 0 );
700 if ( mbRestoreUnqId )
701 pCtrlParent->SetUniqueId( 0 );
702 pOldPage->DeactivatePage();
705 if ( pPage )
707 pPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
709 // Hier Page aktivieren, damit die Controls entsprechend umgeschaltet
710 // werden koennen und HilfeId gegebenenfalls beim Parent umsetzen
711 if ( !GetHelpId() )
713 mbRestoreHelpId = TRUE;
714 pCtrlParent->SetHelpId( pPage->GetHelpId() );
716 if ( !pCtrlParent->GetUniqueId() )
718 mbRestoreUnqId = TRUE;
719 pCtrlParent->SetUniqueId( pPage->GetUniqueId() );
722 pPage->ActivatePage();
724 if ( pOldPage && pOldPage->HasChildPathFocus() )
726 USHORT n = 0;
727 Window* pFirstChild = pPage->ImplGetDlgWindow( n, DLGWINDOW_FIRST );
728 if ( pFirstChild )
729 pFirstChild->ImplControlFocus( GETFOCUS_INIT );
730 else
731 GrabFocus();
734 pPage->Show();
737 if ( pOldPage )
738 pOldPage->Hide();
740 // Invalidate the same region that will be send to NWF
741 // to always allow for bitmap caching
742 // see Window::DrawNativeControl()
743 if( IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL ) )
745 aRect.Left() -= TAB_OFFSET;
746 aRect.Top() -= TAB_OFFSET;
747 aRect.Right() += TAB_OFFSET;
748 aRect.Bottom() += TAB_OFFSET;
751 Invalidate( aRect );
754 // -----------------------------------------------------------------------
756 BOOL TabControl::ImplPosCurTabPage()
758 // Aktuelle TabPage resizen/positionieren
759 ImplTabItem* pItem = ImplGetItem( GetCurPageId() );
760 if ( pItem && pItem->mpTabPage )
762 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
763 pItem->mpTabPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
764 return TRUE;
767 return FALSE;
770 // -----------------------------------------------------------------------
772 void TabControl::ImplActivateTabPage( BOOL bNext )
774 USHORT nCurPos = GetPagePos( GetCurPageId() );
776 if ( bNext )
777 nCurPos = (nCurPos + 1) % GetPageCount();
778 else
780 if ( !nCurPos )
781 nCurPos = GetPageCount()-1;
782 else
783 nCurPos--;
786 SelectTabPage( GetPageId( nCurPos ) );
789 // -----------------------------------------------------------------------
791 void TabControl::ImplSetFirstPagePos( USHORT )
793 return; // was only required for single line
796 // -----------------------------------------------------------------------
798 void TabControl::ImplShowFocus()
800 if ( !GetPageCount() )
801 return;
803 // make sure the focussed item rect is computed using a bold font
804 // the font may have changed meanwhile due to mouse over
806 Font aOldFont( GetFont() );
807 Font aFont( aOldFont );
808 aFont.SetWeight( (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus) ? WEIGHT_BOLD : WEIGHT_LIGHT );
809 SetFont( aFont );
811 USHORT nCurPos = GetPagePos( mnCurPageId );
812 Rectangle aRect = ImplGetTabRect( nCurPos );
813 const ImplTabItem& rItem = mpTabCtrlData->maItemList[ nCurPos ];
814 Size aTabSize = aRect.GetSize();
815 Size aImageSize( 0, 0 );
816 long nTextHeight = GetTextHeight();
817 long nTextWidth = GetCtrlTextWidth( rItem.maFormatText );
818 USHORT nOff;
820 if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_MONO) )
821 nOff = 1;
822 else
823 nOff = 0;
825 if( !! rItem.maTabImage )
827 aImageSize = rItem.maTabImage.GetSizePixel();
828 if( rItem.maFormatText.Len() )
829 aImageSize.Width() += GetTextHeight()/4;
832 if( rItem.maFormatText.Len() )
834 // show focus around text
835 aRect.Left() = aRect.Left()+aImageSize.Width()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1-1;
836 aRect.Top() = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-1-1;
837 aRect.Right() = aRect.Left()+nTextWidth+2;
838 aRect.Bottom() = aRect.Top()+nTextHeight+2;
840 else
842 // show focus around image
843 long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1;
844 long nYPos = aRect.Top();
845 if( aImageSize.Height() < aRect.GetHeight() )
846 nYPos += (aRect.GetHeight() - aImageSize.Height())/2;
848 aRect.Left() = nXPos - 2;
849 aRect.Top() = nYPos - 2;
850 aRect.Right() = aRect.Left() + aImageSize.Width() + 4;
851 aRect.Bottom() = aRect.Top() + aImageSize.Height() + 4;
853 ShowFocus( aRect );
855 SetFont( aOldFont );
858 // -----------------------------------------------------------------------
860 void TabControl::ImplDrawItem( ImplTabItem* pItem, const Rectangle& rCurRect, bool bLayout, bool bFirstInGroup, bool bLastInGroup, bool bIsCurrentItem )
862 if ( pItem->maRect.IsEmpty() )
863 return;
865 if( bLayout )
867 if( ! mpLayoutData )
869 mpLayoutData = new vcl::ControlLayoutData();
870 mpTabCtrlData->maLayoutLineToPageId.clear();
871 mpTabCtrlData->maLayoutPageIdToLine.clear();
872 mpTabCtrlData->maTabRectangles.clear();
876 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
877 Rectangle aRect = pItem->maRect;
878 long nLeftBottom = aRect.Bottom();
879 long nRightBottom = aRect.Bottom();
880 BOOL bLeftBorder = TRUE;
881 BOOL bRightBorder = TRUE;
882 USHORT nOff;
883 BOOL bNativeOK = FALSE;
885 USHORT nOff2 = 0;
886 USHORT nOff3 = 0;
888 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
889 nOff = 1;
890 else
891 nOff = 0;
893 // Wenn wir die aktuelle Page sind, muessen wir etwas mehr zeichnen
894 if ( pItem->mnId == mnCurPageId )
896 nOff2 = 2;
897 if( ! ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise )
898 nOff3 = 1;
900 else
902 Point aLeftTestPos = aRect.BottomLeft();
903 Point aRightTestPos = aRect.BottomRight();
904 if ( aLeftTestPos.Y() == rCurRect.Bottom() )
906 aLeftTestPos.X() -= 2;
907 if ( rCurRect.IsInside( aLeftTestPos ) )
908 bLeftBorder = FALSE;
909 aRightTestPos.X() += 2;
910 if ( rCurRect.IsInside( aRightTestPos ) )
911 bRightBorder = FALSE;
913 else
915 if ( rCurRect.IsInside( aLeftTestPos ) )
916 nLeftBottom -= 2;
917 if ( rCurRect.IsInside( aRightTestPos ) )
918 nRightBottom -= 2;
922 if( !bLayout && (bNativeOK = IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL)) == TRUE )
924 ImplControlValue aControlValue;
925 Region aCtrlRegion( pItem->maRect );
926 ControlState nState = 0;
928 if( pItem->mnId == mnCurPageId )
930 nState |= CTRL_STATE_SELECTED;
931 // only the selected item can be focussed
932 if ( HasFocus() )
933 nState |= CTRL_STATE_FOCUSED;
935 if ( IsEnabled() )
936 nState |= CTRL_STATE_ENABLED;
937 if( IsMouseOver() && pItem->maRect.IsInside( GetPointerPosPixel() ) )
939 nState |= CTRL_STATE_ROLLOVER;
940 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
941 it != mpTabCtrlData->maItemList.end(); ++it )
943 if( (&(*it) != pItem) && (it->maRect.IsInside( GetPointerPosPixel() ) ) )
945 nState &= ~CTRL_STATE_ROLLOVER; // avoid multiple highlighted tabs
946 break;
951 TabitemValue tiValue;
952 if(pItem->maRect.Left() < 5)
953 tiValue.mnAlignment |= TABITEM_LEFTALIGNED;
954 if(pItem->maRect.Right() > mnLastWidth - 5)
955 tiValue.mnAlignment |= TABITEM_RIGHTALIGNED;
956 if ( bFirstInGroup )
957 tiValue.mnAlignment |= TABITEM_FIRST_IN_GROUP;
958 if ( bLastInGroup )
959 tiValue.mnAlignment |= TABITEM_LAST_IN_GROUP;
960 aControlValue.setOptionalVal( (void *)(&tiValue) );
962 bNativeOK = DrawNativeControl( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
963 aControlValue, rtl::OUString() );
966 if( ! bLayout && !bNativeOK )
968 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
970 SetLineColor( rStyleSettings.GetLightColor() );
971 DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) ); // diagonally indented top-left pixel
972 if ( bLeftBorder )
974 DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
975 Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
977 DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ), // top line starting 2px from left border
978 Point( aRect.Right()+nOff2-3, aRect.Top()-nOff2 ) ); // ending 3px from right border
980 if ( bRightBorder )
982 SetLineColor( rStyleSettings.GetShadowColor() );
983 DrawLine( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ),
984 Point( aRect.Right()+nOff2-2, nRightBottom-1 ) );
986 SetLineColor( rStyleSettings.GetDarkShadowColor() );
987 DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+3-nOff2 ),
988 Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
991 else
993 SetLineColor( Color( COL_BLACK ) );
994 DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) );
995 DrawPixel( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ) );
996 if ( bLeftBorder )
998 DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
999 Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
1001 DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ),
1002 Point( aRect.Right()-3, aRect.Top()-nOff2 ) );
1003 if ( bRightBorder )
1005 DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+2-nOff2 ),
1006 Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
1011 if( bLayout )
1013 int nLine = mpLayoutData->m_aLineIndices.size();
1014 mpLayoutData->m_aLineIndices.push_back( mpLayoutData->m_aDisplayText.Len() );
1015 mpTabCtrlData->maLayoutPageIdToLine[ (int)pItem->mnId ] = nLine;
1016 mpTabCtrlData->maLayoutLineToPageId[ nLine ] = (int)pItem->mnId;
1017 mpTabCtrlData->maTabRectangles.push_back( aRect );
1020 // set font accordingly, current item is painted bold
1021 // we set the font attributes always before drawing to be re-entrant (DrawNativeControl may trigger additional paints)
1022 Font aFont( GetFont() );
1023 aFont.SetTransparent( TRUE );
1024 aFont.SetWeight( ((bIsCurrentItem) && (!ImplGetSVData()->maNWFData.mbNoBoldTabFocus)) ? WEIGHT_BOLD : WEIGHT_LIGHT );
1025 SetFont( aFont );
1027 Size aTabSize = aRect.GetSize();
1028 Size aImageSize( 0, 0 );
1029 long nTextHeight = GetTextHeight();
1030 long nTextWidth = GetCtrlTextWidth( pItem->maFormatText );
1031 if( !! pItem->maTabImage )
1033 aImageSize = pItem->maTabImage.GetSizePixel();
1034 if( pItem->maFormatText.Len() )
1035 aImageSize.Width() += GetTextHeight()/4;
1037 long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-nOff3;
1038 long nYPos = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-nOff3;
1039 if( pItem->maFormatText.Len() )
1041 USHORT nStyle = TEXT_DRAW_MNEMONIC;
1042 if( ! pItem->mbEnabled )
1043 nStyle |= TEXT_DRAW_DISABLE;
1044 DrawCtrlText( Point( nXPos + aImageSize.Width(), nYPos ),
1045 pItem->maFormatText,
1046 0, STRING_LEN, nStyle,
1047 bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL,
1048 bLayout ? &mpLayoutData->m_aDisplayText : NULL
1052 if( !! pItem->maTabImage )
1054 Point aImgTL( nXPos, aRect.Top() );
1055 if( aImageSize.Height() < aRect.GetHeight() )
1056 aImgTL.Y() += (aRect.GetHeight() - aImageSize.Height())/2;
1057 DrawImage( aImgTL, pItem->maTabImage, pItem->mbEnabled ? 0 : IMAGE_DRAW_DISABLE );
1061 // -----------------------------------------------------------------------
1063 IMPL_LINK( TabControl, ImplScrollBtnHdl, PushButton*, EMPTYARG )
1065 ImplSetScrollBtnsState();
1066 return 0;
1069 // -----------------------------------------------------------------------
1071 void TabControl::MouseButtonDown( const MouseEvent& rMEvt )
1073 if ( rMEvt.IsLeft() )
1075 USHORT nPageId = GetPageId( rMEvt.GetPosPixel() );
1076 ImplTabItem* pItem = ImplGetItem( nPageId );
1077 if( pItem && pItem->mbEnabled )
1078 SelectTabPage( nPageId );
1079 else
1080 Sound::Beep( SOUND_ERROR, this );
1084 // -----------------------------------------------------------------------
1086 void TabControl::KeyInput( const KeyEvent& rKEvt )
1088 if ( GetPageCount() > 1 )
1090 KeyCode aKeyCode = rKEvt.GetKeyCode();
1091 USHORT nKeyCode = aKeyCode.GetCode();
1093 if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_RIGHT) )
1095 BOOL bNext = (nKeyCode == KEY_RIGHT);
1096 ImplActivateTabPage( bNext );
1100 Control::KeyInput( rKEvt );
1103 // -----------------------------------------------------------------------
1105 void TabControl::Paint( const Rectangle& rRect )
1107 ImplPaint( rRect, false );
1110 // -----------------------------------------------------------------------
1112 void TabControl::ImplPaint( const Rectangle& rRect, bool bLayout )
1114 if( ! bLayout )
1115 HideFocus();
1117 // Hier wird gegebenenfalls auch neu formatiert
1118 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
1120 // find current item
1121 ImplTabItem* pCurItem = NULL;
1122 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1123 it != mpTabCtrlData->maItemList.end(); ++it )
1125 if ( it->mnId == mnCurPageId )
1127 pCurItem = &(*it);
1128 break;
1132 // Draw the TabPage border
1133 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1134 Rectangle aCurRect;
1135 long nTopOff = 1;
1136 aRect.Left() -= TAB_OFFSET;
1137 aRect.Top() -= TAB_OFFSET;
1138 aRect.Right() += TAB_OFFSET;
1139 aRect.Bottom() += TAB_OFFSET;
1141 // if we have an invisible tabpage or no tabpage at all the tabpage rect should be
1142 // increased to avoid round corners that might be drawn by a theme
1143 // in this case we're only interested in the top border of the tabpage because the tabitems are used
1144 // standalone (eg impress)
1145 BOOL bNoTabPage = FALSE;
1146 TabPage* pCurPage = (pCurItem) ? pCurItem->mpTabPage : NULL;
1147 if( !pCurPage || !pCurPage->IsVisible() )
1149 bNoTabPage = TRUE;
1150 aRect.Left()-=10;
1151 aRect.Right()+=10;
1154 BOOL bNativeOK = FALSE;
1155 if( ! bLayout && (bNativeOK = IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL) ) == TRUE )
1157 const ImplControlValue aControlValue( BUTTONVALUE_DONTKNOW, rtl::OUString(), 0 );
1159 ControlState nState = CTRL_STATE_ENABLED;
1160 int part = PART_ENTIRE_CONTROL;
1161 if ( !IsEnabled() )
1162 nState &= ~CTRL_STATE_ENABLED;
1163 if ( HasFocus() )
1164 nState |= CTRL_STATE_FOCUSED;
1166 Region aClipRgn( GetActiveClipRegion() );
1167 aClipRgn.Intersect( aRect );
1168 if( !rRect.IsEmpty() )
1169 aClipRgn.Intersect( rRect );
1171 Region aCtrlRegion( aRect );
1172 Rectangle aClipRect( aClipRgn.GetBoundRect() );
1173 if( !aClipRgn.IsEmpty() ) //&& aClipRect.getHeight() && aClipRect.getWidth() )
1174 bNativeOK = DrawNativeControl( CTRL_TAB_PANE, part, aCtrlRegion, nState,
1175 aControlValue, rtl::OUString() );
1177 else
1179 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
1180 SetLineColor( rStyleSettings.GetLightColor() );
1181 else
1182 SetLineColor( Color( COL_BLACK ) );
1183 if ( pCurItem && !pCurItem->maRect.IsEmpty() )
1185 aCurRect = pCurItem->maRect;
1186 if( ! bLayout )
1187 DrawLine( aRect.TopLeft(), Point( aCurRect.Left()-2, aRect.Top() ) );
1188 if ( aCurRect.Right()+1 < aRect.Right() )
1190 if( ! bLayout )
1191 DrawLine( Point( aCurRect.Right(), aRect.Top() ), aRect.TopRight() );
1193 else
1194 nTopOff = 0;
1196 else
1197 if( ! bLayout )
1198 DrawLine( aRect.TopLeft(), aRect.TopRight() );
1200 if( ! bLayout )
1202 DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
1204 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
1206 // if we have not tab page the bottom line of the tab page
1207 // directly touches the tab items, so choose a color that fits seamlessly
1208 if( bNoTabPage )
1209 SetLineColor( rStyleSettings.GetDialogColor() );
1210 else
1211 SetLineColor( rStyleSettings.GetShadowColor() );
1212 DrawLine( Point( 1, aRect.Bottom()-1 ),
1213 Point( aRect.Right()-1, aRect.Bottom()-1 ) );
1214 DrawLine( Point( aRect.Right()-1, aRect.Top()+nTopOff ),
1215 Point( aRect.Right()-1, aRect.Bottom()-1 ) );
1216 if( bNoTabPage )
1217 SetLineColor( rStyleSettings.GetDialogColor() );
1218 else
1219 SetLineColor( rStyleSettings.GetDarkShadowColor() );
1220 DrawLine( Point( 0, aRect.Bottom() ),
1221 Point( aRect.Right(), aRect.Bottom() ) );
1222 DrawLine( Point( aRect.Right(), aRect.Top()+nTopOff ),
1223 Point( aRect.Right(), aRect.Bottom() ) );
1225 else
1227 DrawLine( aRect.TopRight(), aRect.BottomRight() );
1228 DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
1233 if ( !mpTabCtrlData->maItemList.empty() )
1235 // Some native toolkits (GTK+) draw tabs right-to-left, with an
1236 // overlap between adjacent tabs
1237 bool bDrawTabsRTL = IsNativeControlSupported( CTRL_TAB_ITEM, PART_TABS_DRAW_RTL );
1238 ImplTabItem * pFirstTab = NULL;
1239 ImplTabItem * pLastTab = NULL;
1240 size_t idx;
1242 // Event though there is a tab overlap with GTK+, the first tab is not
1243 // overlapped on the left side. Other tookits ignore this option.
1244 if ( bDrawTabsRTL )
1246 pFirstTab = &mpTabCtrlData->maItemList.front();
1247 pLastTab = &mpTabCtrlData->maItemList.back();
1248 idx = mpTabCtrlData->maItemList.size()-1;
1250 else
1252 pLastTab = &mpTabCtrlData->maItemList.back();
1253 pFirstTab = &mpTabCtrlData->maItemList.front();
1254 idx = 0;
1257 while ( idx < mpTabCtrlData->maItemList.size() )
1259 ImplTabItem* pItem = &mpTabCtrlData->maItemList[idx];
1260 if ( pItem != pCurItem )
1262 Region aClipRgn( GetActiveClipRegion() );
1263 aClipRgn.Intersect( pItem->maRect );
1264 if( !rRect.IsEmpty() )
1265 aClipRgn.Intersect( rRect );
1266 if( bLayout || !aClipRgn.IsEmpty() )
1267 ImplDrawItem( pItem, aCurRect, bLayout, (pItem==pFirstTab), (pItem==pLastTab), FALSE );
1270 if ( bDrawTabsRTL )
1271 idx--;
1272 else
1273 idx++;
1276 if ( pCurItem )
1278 Region aClipRgn( GetActiveClipRegion() );
1279 aClipRgn.Intersect( pCurItem->maRect );
1280 if( !rRect.IsEmpty() )
1281 aClipRgn.Intersect( rRect );
1282 if( bLayout || !aClipRgn.IsEmpty() )
1283 ImplDrawItem( pCurItem, aCurRect, bLayout, (pCurItem==pFirstTab), (pCurItem==pLastTab), TRUE );
1287 if ( !bLayout && HasFocus() )
1288 ImplShowFocus();
1290 if( ! bLayout )
1291 mbSmallInvalidate = TRUE;
1294 // -----------------------------------------------------------------------
1296 void TabControl::Resize()
1298 ImplFreeLayoutData();
1300 if ( !IsReallyShown() )
1301 return;
1303 mbFormat = TRUE;
1305 // Aktuelle TabPage resizen/positionieren
1306 BOOL bTabPage = ImplPosCurTabPage();
1307 // Feststellen, was invalidiert werden muss
1308 Size aNewSize = Control::GetOutputSizePixel();
1309 long nNewWidth = aNewSize.Width();
1310 if ( mbScroll )
1311 mbSmallInvalidate = FALSE;
1312 else
1314 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1315 it != mpTabCtrlData->maItemList.end(); ++it )
1317 if ( !it->mbFullVisible ||
1318 (it->maRect.Right()-2 >= nNewWidth) )
1320 mbSmallInvalidate = FALSE;
1321 break;
1326 if ( mbSmallInvalidate )
1328 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
1329 aRect.Left() -= TAB_OFFSET+TAB_BORDER_LEFT;
1330 aRect.Top() -= TAB_OFFSET+TAB_BORDER_TOP;
1331 aRect.Right() += TAB_OFFSET+TAB_BORDER_RIGHT;
1332 aRect.Bottom() += TAB_OFFSET+TAB_BORDER_BOTTOM;
1333 if ( bTabPage )
1334 Invalidate( aRect, INVALIDATE_NOCHILDREN );
1335 else
1336 Invalidate( aRect );
1339 else
1341 if ( bTabPage )
1342 Invalidate( INVALIDATE_NOCHILDREN );
1343 else
1344 Invalidate();
1348 // -----------------------------------------------------------------------
1350 void TabControl::GetFocus()
1352 ImplShowFocus();
1353 SetInputContext( InputContext( GetFont() ) );
1354 Control::GetFocus();
1357 // -----------------------------------------------------------------------
1359 void TabControl::LoseFocus()
1361 HideFocus();
1362 Control::LoseFocus();
1365 // -----------------------------------------------------------------------
1367 void TabControl::RequestHelp( const HelpEvent& rHEvt )
1369 USHORT nItemId = rHEvt.KeyboardActivated() ? mnCurPageId : GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
1371 if ( nItemId )
1373 if ( rHEvt.GetMode() & HELPMODE_BALLOON )
1375 XubString aStr = GetHelpText( nItemId );
1376 if ( aStr.Len() )
1378 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1379 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1380 aItemRect.Left() = aPt.X();
1381 aItemRect.Top() = aPt.Y();
1382 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1383 aItemRect.Right() = aPt.X();
1384 aItemRect.Bottom() = aPt.Y();
1385 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
1386 return;
1389 else if ( rHEvt.GetMode() & HELPMODE_EXTENDED )
1391 ULONG nHelpId = GetHelpId( nItemId );
1392 if ( nHelpId )
1394 // Wenn eine Hilfe existiert, dann ausloesen
1395 Help* pHelp = Application::GetHelp();
1396 if ( pHelp )
1397 pHelp->Start( nHelpId, this );
1398 return;
1402 // Bei Quick- oder Balloon-Help zeigen wir den Text an,
1403 // wenn dieser abgeschnitten ist
1404 if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) )
1406 ImplTabItem* pItem = ImplGetItem( nItemId );
1407 const XubString& rStr = pItem->maText;
1408 if ( rStr != pItem->maFormatText )
1410 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1411 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1412 aItemRect.Left() = aPt.X();
1413 aItemRect.Top() = aPt.Y();
1414 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1415 aItemRect.Right() = aPt.X();
1416 aItemRect.Bottom() = aPt.Y();
1417 if ( rStr.Len() )
1419 if ( rHEvt.GetMode() & HELPMODE_BALLOON )
1420 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, rStr );
1421 else
1422 Help::ShowQuickHelp( this, aItemRect, rStr );
1423 return;
1428 if ( rHEvt.GetMode() & HELPMODE_QUICK )
1430 ImplTabItem* pItem = ImplGetItem( nItemId );
1431 const XubString& rHelpText = pItem->maHelpText;
1432 // show tooltip if not text but image is set and helptext is available
1433 if ( rHelpText.Len() > 0 && pItem->maText.Len() == 0 && !!pItem->maTabImage )
1435 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1436 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1437 aItemRect.Left() = aPt.X();
1438 aItemRect.Top() = aPt.Y();
1439 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1440 aItemRect.Right() = aPt.X();
1441 aItemRect.Bottom() = aPt.Y();
1442 Help::ShowQuickHelp( this, aItemRect, rHelpText );
1443 return;
1448 Control::RequestHelp( rHEvt );
1451 // -----------------------------------------------------------------------
1453 void TabControl::Command( const CommandEvent& rCEvt )
1455 if ( (rCEvt.GetCommand() == COMMAND_CONTEXTMENU) && (GetPageCount() > 1) )
1457 Point aMenuPos;
1458 BOOL bMenu;
1459 if ( rCEvt.IsMouseEvent() )
1461 aMenuPos = rCEvt.GetMousePosPixel();
1462 bMenu = GetPageId( aMenuPos ) != 0;
1464 else
1466 aMenuPos = ImplGetTabRect( GetPagePos( mnCurPageId ) ).Center();
1467 bMenu = TRUE;
1470 if ( bMenu )
1472 PopupMenu aMenu;
1473 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1474 it != mpTabCtrlData->maItemList.end(); ++it )
1476 aMenu.InsertItem( it->mnId, it->maText, MIB_CHECKABLE | MIB_RADIOCHECK );
1477 if ( it->mnId == mnCurPageId )
1478 aMenu.CheckItem( it->mnId );
1479 aMenu.SetHelpId( it->mnId, it->mnHelpId );
1482 USHORT nId = aMenu.Execute( this, aMenuPos );
1483 if ( nId && (nId != mnCurPageId) )
1484 SelectTabPage( nId );
1485 return;
1489 Control::Command( rCEvt );
1492 // -----------------------------------------------------------------------
1494 void TabControl::StateChanged( StateChangedType nType )
1496 Control::StateChanged( nType );
1498 if ( nType == STATE_CHANGE_INITSHOW )
1499 ImplPosCurTabPage();
1500 else if ( nType == STATE_CHANGE_UPDATEMODE )
1502 if ( IsUpdateMode() )
1503 Invalidate();
1505 else if ( (nType == STATE_CHANGE_ZOOM) ||
1506 (nType == STATE_CHANGE_CONTROLFONT) )
1508 ImplInitSettings( TRUE, FALSE, FALSE );
1509 Invalidate();
1511 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
1513 ImplInitSettings( FALSE, TRUE, FALSE );
1514 Invalidate();
1516 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
1518 ImplInitSettings( FALSE, FALSE, TRUE );
1519 Invalidate();
1523 // -----------------------------------------------------------------------
1525 void TabControl::DataChanged( const DataChangedEvent& rDCEvt )
1527 Control::DataChanged( rDCEvt );
1529 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
1530 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
1531 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1532 (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
1534 ImplInitSettings( TRUE, TRUE, TRUE );
1535 Invalidate();
1539 // -----------------------------------------------------------------------
1541 Rectangle* TabControl::ImplFindPartRect( const Point& rPt )
1543 ImplTabItem* pFoundItem = NULL;
1544 int nFound = 0;
1545 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1546 it != mpTabCtrlData->maItemList.end(); ++it )
1548 if ( it->maRect.IsInside( rPt ) )
1550 // assure that only one tab is highlighted at a time
1551 nFound++;
1552 pFoundItem = &(*it);
1555 // assure that only one tab is highlighted at a time
1556 return nFound == 1 ? &pFoundItem->maRect : NULL;
1559 long TabControl::PreNotify( NotifyEvent& rNEvt )
1561 long nDone = 0;
1562 const MouseEvent* pMouseEvt = NULL;
1564 if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
1566 if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1568 // trigger redraw if mouse over state has changed
1569 if( IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) )
1571 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
1572 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
1573 if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
1575 Region aClipRgn;
1576 if( pLastRect )
1578 // allow for slightly bigger tabitems
1579 // as used by gtk
1580 // TODO: query for the correct sizes
1581 Rectangle aRect(*pLastRect);
1582 aRect.nLeft-=2;
1583 aRect.nRight+=2;
1584 aRect.nTop-=3;
1585 aClipRgn.Union( aRect );
1587 if( pRect )
1589 // allow for slightly bigger tabitems
1590 // as used by gtk
1591 // TODO: query for the correct sizes
1592 Rectangle aRect(*pRect);
1593 aRect.nLeft-=2;
1594 aRect.nRight+=2;
1595 aRect.nTop-=3;
1596 aClipRgn.Union( aRect );
1598 if( !aClipRgn.IsEmpty() )
1599 Invalidate( aClipRgn );
1605 return nDone ? nDone : Control::PreNotify(rNEvt);
1608 // -----------------------------------------------------------------------
1610 long TabControl::Notify( NotifyEvent& rNEvt )
1612 if ( (rNEvt.GetType() == EVENT_KEYINPUT) && (GetPageCount() > 1) )
1614 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
1615 KeyCode aKeyCode = pKEvt->GetKeyCode();
1616 USHORT nKeyCode = aKeyCode.GetCode();
1618 if ( aKeyCode.IsMod1() )
1620 if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) )
1622 if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) )
1624 ImplActivateTabPage( FALSE );
1625 return TRUE;
1628 else
1630 if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) )
1632 ImplActivateTabPage( TRUE );
1633 return TRUE;
1639 return Control::Notify( rNEvt );
1642 // -----------------------------------------------------------------------
1644 void TabControl::ActivatePage()
1646 maActivateHdl.Call( this );
1649 // -----------------------------------------------------------------------
1651 long TabControl::DeactivatePage()
1653 if ( maDeactivateHdl.IsSet() )
1654 return maDeactivateHdl.Call( this );
1655 else
1656 return TRUE;
1659 // -----------------------------------------------------------------------
1661 void TabControl::SetTabPageSizePixel( const Size& rSize )
1663 ImplFreeLayoutData();
1665 Size aNewSize( rSize );
1666 aNewSize.Width() += TAB_OFFSET*2;
1667 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT,
1668 aNewSize.Width(), aNewSize.Height() );
1669 aNewSize.Height() += aRect.Top()+TAB_OFFSET;
1670 Window::SetOutputSizePixel( aNewSize );
1673 // -----------------------------------------------------------------------
1675 Size TabControl::GetTabPageSizePixel() const
1677 Rectangle aRect = ((TabControl*)this)->ImplGetTabRect( TAB_PAGERECT );
1678 return aRect.GetSize();
1681 // -----------------------------------------------------------------------
1683 void TabControl::InsertPage( const ResId& rResId, USHORT nPos )
1685 GetRes( rResId.SetRT( RSC_TABCONTROLITEM ) );
1687 ULONG nObjMask = ReadLongRes();
1688 USHORT nItemId = 1;
1690 // ID
1691 if ( nObjMask & RSC_TABCONTROLITEM_ID )
1692 nItemId = sal::static_int_cast<USHORT>(ReadLongRes());
1694 // Text
1695 XubString aTmpStr;
1696 if( nObjMask & RSC_TABCONTROLITEM_TEXT )
1697 aTmpStr = ReadStringRes();
1698 InsertPage( nItemId, aTmpStr, nPos );
1700 // PageResID
1701 if ( nObjMask & RSC_TABCONTROLITEM_PAGERESID )
1703 ImplTabItem& rItem = mpTabCtrlData->maItemList[ GetPagePos( nItemId ) ];
1704 rItem.mnTabPageResId = sal::static_int_cast<USHORT>(ReadLongRes());
1708 // -----------------------------------------------------------------------
1710 void TabControl::InsertPage( USHORT nPageId, const XubString& rText,
1711 USHORT nPos )
1713 DBG_ASSERT( nPageId, "TabControl::InsertPage(): PageId == 0" );
1714 DBG_ASSERT( GetPagePos( nPageId ) == TAB_PAGE_NOTFOUND,
1715 "TabControl::InsertPage(): PageId already exists" );
1717 // set current page id
1718 if ( !mnCurPageId )
1719 mnCurPageId = nPageId;
1721 // insert new page item
1722 ImplTabItem* pItem = NULL;
1723 if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1725 mpTabCtrlData->maItemList.push_back( ImplTabItem() );
1726 pItem = &mpTabCtrlData->maItemList.back();
1728 else
1730 std::vector< ImplTabItem >::iterator new_it =
1731 mpTabCtrlData->maItemList.insert( mpTabCtrlData->maItemList.begin() + nPos, ImplTabItem() );
1732 pItem = &(*new_it);
1735 // init new page item
1736 pItem->mnId = nPageId;
1737 pItem->mpTabPage = NULL;
1738 pItem->mnTabPageResId = 0;
1739 pItem->mnHelpId = 0;
1740 pItem->maText = rText;
1741 pItem->mbFullVisible = FALSE;
1743 mbFormat = TRUE;
1744 if ( IsUpdateMode() )
1745 Invalidate();
1747 ImplFreeLayoutData();
1749 ImplCallEventListeners( VCLEVENT_TABPAGE_INSERTED, (void*) (ULONG)nPageId );
1752 // -----------------------------------------------------------------------
1754 void TabControl::RemovePage( USHORT nPageId )
1756 USHORT nPos = GetPagePos( nPageId );
1758 // does the item exist ?
1759 if ( nPos != TAB_PAGE_NOTFOUND )
1761 //remove page item
1762 std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos;
1763 bool bIsCurrentPage = (it->mnId == mnCurPageId);
1764 mpTabCtrlData->maItemList.erase( it );
1766 // If current page is removed, than first page gets the current page
1767 if ( bIsCurrentPage )
1769 mnCurPageId = 0;
1771 if( ! mpTabCtrlData->maItemList.empty() )
1773 // don't do this by simply setting mnCurPageId to pFirstItem->mnId
1774 // this leaves a lot of stuff (such trivias as _showing_ the new current page) undone
1775 // instead, call SetCurPageId
1776 // without this, the next (outside) call to SetCurPageId with the id of the first page
1777 // will result in doing nothing (as we assume that nothing changed, then), and the page
1778 // will never be shown.
1779 // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com
1781 SetCurPageId( mpTabCtrlData->maItemList[0].mnId );
1785 mbFormat = TRUE;
1786 if ( IsUpdateMode() )
1787 Invalidate();
1789 ImplFreeLayoutData();
1791 ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVED, (void*) (ULONG) nPageId );
1795 // -----------------------------------------------------------------------
1797 void TabControl::Clear()
1799 // clear item list
1800 mpTabCtrlData->maItemList.clear();
1801 mnCurPageId = 0;
1803 ImplFreeLayoutData();
1805 mbFormat = TRUE;
1806 if ( IsUpdateMode() )
1807 Invalidate();
1809 ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVEDALL );
1812 // -----------------------------------------------------------------------
1814 void TabControl::EnablePage( USHORT i_nPageId, bool i_bEnable )
1816 ImplTabItem* pItem = ImplGetItem( i_nPageId );
1818 if ( pItem && pItem->mbEnabled != i_bEnable )
1820 pItem->mbEnabled = i_bEnable;
1821 mbFormat = TRUE;
1822 if( pItem->mnId == mnCurPageId )
1824 // SetCurPageId will change to an enabled page
1825 SetCurPageId( mnCurPageId );
1827 else if ( IsUpdateMode() )
1828 Invalidate();
1832 // -----------------------------------------------------------------------
1834 USHORT TabControl::GetPageCount() const
1836 return (USHORT)mpTabCtrlData->maItemList.size();
1839 // -----------------------------------------------------------------------
1841 USHORT TabControl::GetPageId( USHORT nPos ) const
1843 if( size_t(nPos) < mpTabCtrlData->maItemList.size() )
1844 return mpTabCtrlData->maItemList[ nPos ].mnId;
1845 return 0;
1848 // -----------------------------------------------------------------------
1850 USHORT TabControl::GetPagePos( USHORT nPageId ) const
1852 for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
1853 it != mpTabCtrlData->maItemList.end(); ++it )
1855 if ( it->mnId == nPageId )
1856 return (USHORT)(it - mpTabCtrlData->maItemList.begin());
1859 return TAB_PAGE_NOTFOUND;
1862 // -----------------------------------------------------------------------
1864 USHORT TabControl::GetPageId( const Point& rPos ) const
1866 for( size_t i = 0; i < mpTabCtrlData->maItemList.size(); ++i )
1868 if ( ((TabControl*)this)->ImplGetTabRect( static_cast<USHORT>(i) ).IsInside( rPos ) )
1869 return mpTabCtrlData->maItemList[ i ].mnId;
1872 return 0;
1875 // -----------------------------------------------------------------------
1877 void TabControl::SetCurPageId( USHORT nPageId )
1879 USHORT nPos = GetPagePos( nPageId );
1880 while( nPos != TAB_PAGE_NOTFOUND &&
1881 ! mpTabCtrlData->maItemList[nPos].mbEnabled )
1883 nPos++;
1884 if( size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1885 nPos = 0;
1886 if( mpTabCtrlData->maItemList[nPos].mnId == nPageId )
1887 break;
1890 if( nPos != TAB_PAGE_NOTFOUND )
1892 nPageId = mpTabCtrlData->maItemList[nPos].mnId;
1893 if ( nPageId == mnCurPageId )
1895 if ( mnActPageId )
1896 mnActPageId = nPageId;
1897 return;
1900 if ( mnActPageId )
1901 mnActPageId = nPageId;
1902 else
1904 mbFormat = TRUE;
1905 USHORT nOldId = mnCurPageId;
1906 mnCurPageId = nPageId;
1907 ImplChangeTabPage( nPageId, nOldId );
1912 // -----------------------------------------------------------------------
1914 USHORT TabControl::GetCurPageId() const
1916 if ( mnActPageId )
1917 return mnActPageId;
1918 else
1919 return mnCurPageId;
1922 // -----------------------------------------------------------------------
1924 void TabControl::SetFirstPageId( USHORT )
1926 return; // was only required for single line
1929 // -----------------------------------------------------------------------
1931 void TabControl::SelectTabPage( USHORT nPageId )
1933 if ( nPageId && (nPageId != mnCurPageId) )
1935 ImplFreeLayoutData();
1937 ImplCallEventListeners( VCLEVENT_TABPAGE_DEACTIVATE, (void*) (ULONG) mnCurPageId );
1938 if ( DeactivatePage() )
1940 mnActPageId = nPageId;
1941 ActivatePage();
1942 // Page koennte im Activate-Handler umgeschaltet wurden sein
1943 nPageId = mnActPageId;
1944 mnActPageId = 0;
1945 SetCurPageId( nPageId );
1946 ImplCallEventListeners( VCLEVENT_TABPAGE_ACTIVATE, (void*) (ULONG) nPageId );
1951 // -----------------------------------------------------------------------
1953 void TabControl::SetTabPage( USHORT nPageId, TabPage* pTabPage )
1955 ImplTabItem* pItem = ImplGetItem( nPageId );
1957 if ( pItem && (pItem->mpTabPage != pTabPage) )
1959 if ( pTabPage )
1961 DBG_ASSERT( !pTabPage->IsVisible(), "TabControl::SetTabPage() - Page is visible" );
1963 if ( IsDefaultSize() )
1964 SetTabPageSizePixel( pTabPage->GetSizePixel() );
1966 // Erst hier setzen, damit Resize nicht TabPage umpositioniert
1967 pItem->mpTabPage = pTabPage;
1968 if ( pItem->mnId == mnCurPageId )
1969 ImplChangeTabPage( pItem->mnId, 0 );
1971 else
1972 pItem->mpTabPage = NULL;
1976 // -----------------------------------------------------------------------
1978 TabPage* TabControl::GetTabPage( USHORT nPageId ) const
1980 ImplTabItem* pItem = ImplGetItem( nPageId );
1982 if ( pItem )
1983 return pItem->mpTabPage;
1984 else
1985 return NULL;
1988 // -----------------------------------------------------------------------
1990 USHORT TabControl::GetTabPageResId( USHORT nPageId ) const
1992 ImplTabItem* pItem = ImplGetItem( nPageId );
1994 if ( pItem )
1995 return pItem->mnTabPageResId;
1996 else
1997 return 0;
2000 // -----------------------------------------------------------------------
2002 void TabControl::SetPageText( USHORT nPageId, const XubString& rText )
2004 ImplTabItem* pItem = ImplGetItem( nPageId );
2006 if ( pItem && pItem->maText != rText )
2008 pItem->maText = rText;
2009 mbFormat = TRUE;
2010 if ( IsUpdateMode() )
2011 Invalidate();
2012 ImplFreeLayoutData();
2013 ImplCallEventListeners( VCLEVENT_TABPAGE_PAGETEXTCHANGED, (void*) (ULONG) nPageId );
2017 // -----------------------------------------------------------------------
2019 XubString TabControl::GetPageText( USHORT nPageId ) const
2021 ImplTabItem* pItem = ImplGetItem( nPageId );
2023 if ( pItem )
2024 return pItem->maText;
2025 else
2026 return ImplGetSVEmptyStr();
2029 // -----------------------------------------------------------------------
2031 void TabControl::SetHelpText( USHORT nPageId, const XubString& rText )
2033 ImplTabItem* pItem = ImplGetItem( nPageId );
2035 if ( pItem )
2036 pItem->maHelpText = rText;
2039 // -----------------------------------------------------------------------
2041 const XubString& TabControl::GetHelpText( USHORT nPageId ) const
2043 ImplTabItem* pItem = ImplGetItem( nPageId );
2045 if ( pItem )
2047 if ( !pItem->maHelpText.Len() && pItem->mnHelpId )
2049 Help* pHelp = Application::GetHelp();
2050 if ( pHelp )
2051 pItem->maHelpText = pHelp->GetHelpText( pItem->mnHelpId, this );
2054 return pItem->maHelpText;
2056 else
2057 return ImplGetSVEmptyStr();
2060 // -----------------------------------------------------------------------
2062 void TabControl::SetHelpId( USHORT nPageId, ULONG nHelpId )
2064 ImplTabItem* pItem = ImplGetItem( nPageId );
2066 if ( pItem )
2067 pItem->mnHelpId = nHelpId;
2070 // -----------------------------------------------------------------------
2072 ULONG TabControl::GetHelpId( USHORT nPageId ) const
2074 ImplTabItem* pItem = ImplGetItem( nPageId );
2076 if ( pItem )
2077 return pItem->mnHelpId;
2078 else
2079 return 0;
2082 // -----------------------------------------------------------------------
2084 void TabControl::SetPageImage( USHORT i_nPageId, const Image& i_rImage )
2086 ImplTabItem* pItem = ImplGetItem( i_nPageId );
2088 if ( pItem )
2090 pItem->maTabImage = i_rImage;
2091 mbFormat = TRUE;
2092 if ( IsUpdateMode() )
2093 Invalidate();
2097 // -----------------------------------------------------------------------
2099 const Image* TabControl::GetPageImage( USHORT i_nPageId ) const
2101 const ImplTabItem* pItem = ImplGetItem( i_nPageId );
2102 return pItem ? &pItem->maTabImage : NULL;
2105 // -----------------------------------------------------------------------
2107 Rectangle TabControl::GetCharacterBounds( USHORT nPageId, long nIndex ) const
2109 Rectangle aRet;
2111 if( ! mpLayoutData || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2112 FillLayoutData();
2114 if( mpLayoutData )
2116 std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPageId );
2117 if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
2119 Pair aPair = mpLayoutData->GetLineStartEnd( it->second );
2120 if( (aPair.B() - aPair.A()) >= nIndex )
2121 aRet = mpLayoutData->GetCharacterBounds( aPair.A() + nIndex );
2125 return aRet;
2128 // -----------------------------------------------------------------------
2130 long TabControl::GetIndexForPoint( const Point& rPoint, USHORT& rPageId ) const
2132 long nRet = -1;
2134 if( ! mpLayoutData || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2135 FillLayoutData();
2137 if( mpLayoutData )
2139 int nIndex = mpLayoutData->GetIndexForPoint( rPoint );
2140 if( nIndex != -1 )
2142 // what line (->pageid) is this index in ?
2143 int nLines = mpLayoutData->GetLineCount();
2144 int nLine = -1;
2145 while( ++nLine < nLines )
2147 Pair aPair = mpLayoutData->GetLineStartEnd( nLine );
2148 if( aPair.A() <= nIndex && aPair.B() >= nIndex )
2150 nRet = nIndex - aPair.A();
2151 rPageId = (USHORT)mpTabCtrlData->maLayoutLineToPageId[ nLine ];
2152 break;
2158 return nRet;
2161 // -----------------------------------------------------------------------
2163 void TabControl::FillLayoutData() const
2165 mpTabCtrlData->maLayoutLineToPageId.clear();
2166 mpTabCtrlData->maLayoutPageIdToLine.clear();
2167 const_cast<TabControl*>(this)->ImplPaint( Rectangle(), true );
2170 // -----------------------------------------------------------------------
2172 Rectangle TabControl::GetTabPageBounds( USHORT nPage ) const
2174 Rectangle aRet;
2176 if( ! mpLayoutData || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2177 FillLayoutData();
2179 if( mpLayoutData )
2181 std::hash_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPage );
2182 if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
2184 if( it->second >= 0 && it->second < static_cast<int>(mpTabCtrlData->maTabRectangles.size()) )
2186 aRet = mpTabCtrlData->maTabRectangles[ it->second ];
2187 aRet.Union( const_cast<TabControl*>(this)->ImplGetTabRect( TAB_PAGERECT ) );
2192 return aRet;
2195 // -----------------------------------------------------------------------
2197 Rectangle TabControl::GetTabBounds( USHORT nPageId ) const
2199 Rectangle aRet;
2201 ImplTabItem* pItem = ImplGetItem( nPageId );
2202 if(pItem)
2203 aRet = pItem->maRect;
2205 return aRet;
2208 // -----------------------------------------------------------------------
2210 void TabControl::SetItemsOffset( const Point& rOffs )
2212 if( mpTabCtrlData )
2213 mpTabCtrlData->maItemsOffset = rOffs;
2216 Point TabControl::GetItemsOffset() const
2218 if( mpTabCtrlData )
2219 return mpTabCtrlData->maItemsOffset;
2220 else
2221 return Point();
2224 // -----------------------------------------------------------------------