bump product version to 4.1.6.2
[LibreOffice.git] / vcl / source / control / tabctrl.cxx
blob53594a91e93b78a2d124e1764666bfd1e31f3cec
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "tools/debug.hxx"
22 #include "tools/rc.h"
24 #include "vcl/svapp.hxx"
25 #include "vcl/help.hxx"
26 #include "vcl/event.hxx"
27 #include "vcl/menu.hxx"
28 #include "vcl/button.hxx"
29 #include "vcl/tabpage.hxx"
30 #include "vcl/tabctrl.hxx"
31 #include "vcl/controllayout.hxx"
32 #include "vcl/layout.hxx"
33 #include "vcl/lstbox.hxx"
35 #include "controldata.hxx"
36 #include "svdata.hxx"
37 #include "window.h"
39 #include <boost/unordered_map.hpp>
40 #include <vector>
42 // =======================================================================
44 struct ImplTabItem
46 sal_uInt16 mnId;
47 TabPage* mpTabPage;
48 String maText;
49 String maFormatText;
50 String maHelpText;
51 OString maHelpId;
52 OString maTabName;
53 Rectangle maRect;
54 sal_uInt16 mnLine;
55 bool mbFullVisible;
56 bool mbEnabled;
57 Image maTabImage;
59 ImplTabItem()
60 : mnId( 0 ), mpTabPage( NULL ),
61 mnLine( 0 ), mbFullVisible( sal_False ), mbEnabled( true )
65 // -----------------------------------------------------------------------
67 struct ImplTabCtrlData
69 boost::unordered_map< int, int > maLayoutPageIdToLine;
70 boost::unordered_map< int, int > maLayoutLineToPageId;
71 std::vector< Rectangle > maTabRectangles;
72 Point maItemsOffset; // offset of the tabitems
73 std::vector< ImplTabItem > maItemList;
74 ListBox* mpListBox;
77 // -----------------------------------------------------------------------
79 #define TAB_OFFSET 3
80 #define TAB_TABOFFSET_X 3
81 #define TAB_TABOFFSET_Y 3
82 #define TAB_EXTRASPACE_X 6
83 #define TAB_BORDER_LEFT 1
84 #define TAB_BORDER_TOP 1
85 #define TAB_BORDER_RIGHT 2
86 #define TAB_BORDER_BOTTOM 2
88 // for the Tab positions
89 #define TAB_PAGERECT 0xFFFF
91 // =======================================================================
93 void TabControl::ImplInit( Window* pParent, WinBits nStyle )
95 mbLayoutDirty = true;
97 if ( !(nStyle & WB_NOTABSTOP) )
98 nStyle |= WB_TABSTOP;
99 if ( !(nStyle & WB_NOGROUP) )
100 nStyle |= WB_GROUP;
101 if ( !(nStyle & WB_NODIALOGCONTROL) )
102 nStyle |= WB_DIALOGCONTROL;
104 Control::ImplInit( pParent, nStyle, NULL );
106 mnLastWidth = 0;
107 mnLastHeight = 0;
108 mnBtnSize = 0;
109 mnMaxPageWidth = 0;
110 mnActPageId = 0;
111 mnCurPageId = 0;
112 mbFormat = sal_True;
113 mbRestoreHelpId = sal_False;
114 mbRestoreUnqId = sal_False;
115 mbSmallInvalidate = sal_False;
116 mpTabCtrlData = new ImplTabCtrlData;
117 mpTabCtrlData->mpListBox = NULL;
120 ImplInitSettings( sal_True, sal_True, sal_True );
122 if( (nStyle & WB_DROPDOWN) )
124 mpTabCtrlData->mpListBox = new ListBox( this, WB_DROPDOWN );
125 mpTabCtrlData->mpListBox->SetPosSizePixel( Point( 0, 0 ), Size( 200, 20 ) );
126 mpTabCtrlData->mpListBox->SetSelectHdl( LINK( this, TabControl, ImplListBoxSelectHdl ) );
127 mpTabCtrlData->mpListBox->Show();
130 // if the tabcontrol is drawn (ie filled) by a native widget, make sure all contols will have transparent background
131 // otherwise they will paint with a wrong background
132 if( IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL) )
133 EnableChildTransparentMode( sal_True );
135 if ( pParent->IsDialog() )
136 pParent->AddChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
139 // -----------------------------------------------------------------
141 const Font& TabControl::GetCanonicalFont( const StyleSettings& _rStyle ) const
143 return _rStyle.GetAppFont();
146 // -----------------------------------------------------------------
147 const Color& TabControl::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
149 return _rStyle.GetButtonTextColor();
152 // -----------------------------------------------------------------------
154 void TabControl::ImplInitSettings( sal_Bool bFont,
155 sal_Bool bForeground, sal_Bool bBackground )
157 Control::ImplInitSettings( bFont, bForeground );
159 if ( bBackground )
161 Window* pParent = GetParent();
162 if ( !IsControlBackground() &&
163 (pParent->IsChildTransparentModeEnabled()
164 || IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL)
165 || IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) ) )
168 // set transparent mode for NWF tabcontrols to have
169 // the background always cleared properly
170 EnableChildTransparentMode( sal_True );
171 SetParentClipMode( PARENTCLIPMODE_NOCLIP );
172 SetPaintTransparent( sal_True );
173 SetBackground();
174 ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
176 else
178 EnableChildTransparentMode( sal_False );
179 SetParentClipMode( 0 );
180 SetPaintTransparent( sal_False );
182 if ( IsControlBackground() )
183 SetBackground( GetControlBackground() );
184 else
185 SetBackground( pParent->GetBackground() );
190 // -----------------------------------------------------------------------
192 void TabControl::ImplFreeLayoutData()
194 if( HasLayoutData() )
196 ImplClearLayoutData();
197 mpTabCtrlData->maLayoutPageIdToLine.clear();
198 mpTabCtrlData->maLayoutLineToPageId.clear();
202 // -----------------------------------------------------------------------
204 TabControl::TabControl( Window* pParent, WinBits nStyle ) :
205 Control( WINDOW_TABCONTROL )
207 ImplInit( pParent, nStyle );
208 OSL_TRACE("*** TABCONTROL no notabs? %s", ( GetStyle() & WB_NOBORDER ) ? "true" : "false" );
211 // -----------------------------------------------------------------------
213 TabControl::TabControl( Window* pParent, const ResId& rResId ) :
214 Control( WINDOW_TABCONTROL )
216 rResId.SetRT( RSC_TABCONTROL );
217 WinBits nStyle = ImplInitRes( rResId );
218 ImplInit( pParent, nStyle );
219 ImplLoadRes( rResId );
221 if ( !(nStyle & WB_HIDE) )
222 Show();
225 // -----------------------------------------------------------------------
227 void TabControl::ImplLoadRes( const ResId& rResId )
229 Control::ImplLoadRes( rResId );
231 sal_uLong nObjMask = ReadLongRes();
233 if ( nObjMask & RSC_TABCONTROL_ITEMLIST )
235 sal_uLong nEle = ReadLongRes();
237 // add item
238 for( sal_uLong i = 0; i < nEle; i++ )
240 InsertPage( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
241 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
246 // -----------------------------------------------------------------------
248 TabControl::~TabControl()
250 if ( GetParent()->IsDialog() )
251 GetParent()->RemoveChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
253 ImplFreeLayoutData();
255 // delete TabCtrl data
256 if ( mpTabCtrlData )
258 if( mpTabCtrlData->mpListBox )
259 delete mpTabCtrlData->mpListBox;
260 delete mpTabCtrlData;
264 // -----------------------------------------------------------------------
266 ImplTabItem* TabControl::ImplGetItem( sal_uInt16 nId ) const
268 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
269 it != mpTabCtrlData->maItemList.end(); ++it )
271 if( it->mnId == nId )
272 return &(*it);
275 return NULL;
278 // -----------------------------------------------------------------------
280 Size TabControl::ImplGetItemSize( ImplTabItem* pItem, long nMaxWidth )
282 pItem->maFormatText = pItem->maText;
283 Size aSize( GetCtrlTextWidth( pItem->maFormatText ), GetTextHeight() );
284 Size aImageSize( 0, 0 );
285 if( !!pItem->maTabImage )
287 aImageSize = pItem->maTabImage.GetSizePixel();
288 if( pItem->maFormatText.Len() )
289 aImageSize.Width() += GetTextHeight()/4;
291 aSize.Width() += aImageSize.Width();
292 if( aImageSize.Height() > aSize.Height() )
293 aSize.Height() = aImageSize.Height();
295 aSize.Width() += TAB_TABOFFSET_X*2;
296 aSize.Height() += TAB_TABOFFSET_Y*2;
298 Rectangle aCtrlRegion( Point( 0, 0 ), aSize );
299 Rectangle aBoundingRgn, aContentRgn;
300 const ImplControlValue aControlValue;
301 if(GetNativeControlRegion( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion,
302 CTRL_STATE_ENABLED, aControlValue, OUString(),
303 aBoundingRgn, aContentRgn ) )
305 return aContentRgn.GetSize();
308 // For languages with short names (e.g. Chinese), because the space is
309 // normally only one pixel per char
310 if ( pItem->maFormatText.Len() < TAB_EXTRASPACE_X )
311 aSize.Width() += TAB_EXTRASPACE_X-pItem->maFormatText.Len();
313 // shorten Text if needed
314 if ( aSize.Width()+4 >= nMaxWidth )
316 OUString aAppendStr("...");
317 pItem->maFormatText += aAppendStr;
320 pItem->maFormatText.Erase( pItem->maFormatText.Len()-aAppendStr.getLength()-1, 1 );
321 aSize.Width() = GetCtrlTextWidth( pItem->maFormatText );
322 aSize.Width() += aImageSize.Width();
323 aSize.Width() += TAB_TABOFFSET_X*2;
325 while ( (aSize.Width()+4 >= nMaxWidth) && (pItem->maFormatText.Len() > aAppendStr.getLength()) );
326 if ( aSize.Width()+4 >= nMaxWidth )
328 pItem->maFormatText.Assign( '.' );
329 aSize.Width() = 1;
333 if( pItem->maFormatText.Len() == 0 )
335 if( aSize.Height() < aImageSize.Height()+4 ) //leave space for focus rect
336 aSize.Height() = aImageSize.Height()+4;
339 return aSize;
342 // -----------------------------------------------------------------------
344 Rectangle TabControl::ImplGetTabRect( sal_uInt16 nItemPos, long nWidth, long nHeight )
346 Size aWinSize = Control::GetOutputSizePixel();
347 if ( nWidth < 0 )
348 nWidth = aWinSize.Width();
349 if ( nHeight < 0 )
350 nHeight = aWinSize.Height();
352 if ( mpTabCtrlData->maItemList.empty() )
354 long nW = nWidth-TAB_OFFSET*2;
355 long nH = nHeight-TAB_OFFSET*2;
356 return (nW > 0 && nH > 0)
357 ? Rectangle( Point( TAB_OFFSET, TAB_OFFSET ), Size( nW, nH ) )
358 : Rectangle();
361 if ( nItemPos == TAB_PAGERECT )
363 sal_uInt16 nLastPos;
364 if ( mnCurPageId )
365 nLastPos = GetPagePos( mnCurPageId );
366 else
367 nLastPos = 0;
369 Rectangle aRect = ImplGetTabRect( nLastPos, nWidth, nHeight );
370 long nW = nWidth-TAB_OFFSET*2;
371 long nH = nHeight-aRect.Bottom()-TAB_OFFSET*2;
372 aRect = (nW > 0 && nH > 0)
373 ? Rectangle( Point( TAB_OFFSET, aRect.Bottom()+TAB_OFFSET ), Size( nW, nH ) )
374 : Rectangle();
375 return aRect;
378 nWidth -= 1;
380 if ( (nWidth <= 0) || (nHeight <= 0) )
381 return Rectangle();
383 if ( mbFormat || (mnLastWidth != nWidth) || (mnLastHeight != nHeight) )
385 Font aFont( GetFont() );
386 aFont.SetTransparent( sal_True );
387 SetFont( aFont );
389 Size aSize;
390 const long nOffsetX = 2 + GetItemsOffset().X();
391 const long nOffsetY = 2 + GetItemsOffset().Y();
392 long nX = nOffsetX;
393 long nY = nOffsetY;
394 long nMaxWidth = nWidth;
395 sal_uInt16 nPos = 0;
397 if ( (mnMaxPageWidth > 0) && (mnMaxPageWidth < nMaxWidth) )
398 nMaxWidth = mnMaxPageWidth;
399 nMaxWidth -= GetItemsOffset().X();
401 sal_uInt16 nLines = 0;
402 sal_uInt16 nCurLine = 0;
403 long nLineWidthAry[100];
404 sal_uInt16 nLinePosAry[101];
406 nLineWidthAry[0] = 0;
407 nLinePosAry[0] = 0;
408 for( std::vector<ImplTabItem>::iterator it = mpTabCtrlData->maItemList.begin();
409 it != mpTabCtrlData->maItemList.end(); ++it )
411 aSize = ImplGetItemSize( &(*it), nMaxWidth );
413 if ( ((nX+aSize.Width()) > nWidth - 2) && (nWidth > 2+nOffsetX) )
415 if ( nLines == 99 )
416 break;
418 nX = nOffsetX;
419 nY += aSize.Height();
420 nLines++;
421 nLineWidthAry[nLines] = 0;
422 nLinePosAry[nLines] = nPos;
425 Rectangle aNewRect( Point( nX, nY ), aSize );
426 if ( mbSmallInvalidate && (it->maRect != aNewRect) )
427 mbSmallInvalidate = sal_False;
428 it->maRect = aNewRect;
429 it->mnLine = nLines;
430 it->mbFullVisible = sal_True;
432 nLineWidthAry[nLines] += aSize.Width();
433 nX += aSize.Width();
435 if ( it->mnId == mnCurPageId )
436 nCurLine = nLines;
438 nPos++;
441 if ( nLines && !mpTabCtrlData->maItemList.empty() )
443 long nDX = 0;
444 long nModDX = 0;
445 long nIDX = 0;
446 sal_uInt16 i;
447 sal_uInt16 n;
448 long nLineHeightAry[100];
449 long nIH = mpTabCtrlData->maItemList[0].maRect.Bottom()-2;
451 i = 0;
452 while ( i < nLines+1 )
454 if ( i <= nCurLine )
455 nLineHeightAry[i] = nIH*(nLines-(nCurLine-i)) + GetItemsOffset().Y();
456 else
457 nLineHeightAry[i] = nIH*(i-nCurLine-1) + GetItemsOffset().Y();
458 i++;
461 i = 0;
462 n = 0;
463 nLinePosAry[nLines+1] = (sal_uInt16)mpTabCtrlData->maItemList.size();
464 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
465 it != mpTabCtrlData->maItemList.end(); ++it )
467 if ( i == nLinePosAry[n] )
469 if ( n == nLines+1 )
470 break;
472 nIDX = 0;
473 if( nLinePosAry[n+1]-i > 0 )
475 nDX = (nWidth-nOffsetX-nLineWidthAry[n]) / (nLinePosAry[n+1]-i);
476 nModDX = (nWidth-nOffsetX-nLineWidthAry[n]) % (nLinePosAry[n+1]-i);
478 else
480 // FIXME: this is a bad case of tabctrl way too small
481 nDX = 0;
482 nModDX = 0;
484 n++;
487 it->maRect.Left() += nIDX;
488 it->maRect.Right() += nIDX+nDX;
489 it->maRect.Top() = nLineHeightAry[n-1];
490 it->maRect.Bottom() = nLineHeightAry[n-1]+nIH;
491 nIDX += nDX;
493 if ( nModDX )
495 nIDX++;
496 it->maRect.Right()++;
497 nModDX--;
500 i++;
503 else
504 {//only one line
505 if(ImplGetSVData()->maNWFData.mbCenteredTabs)
507 int nRightSpace=nMaxWidth;//space left on the right by the tabs
508 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
509 it != mpTabCtrlData->maItemList.end(); ++it )
511 nRightSpace-=it->maRect.Right()-it->maRect.Left();
513 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
514 it != mpTabCtrlData->maItemList.end(); ++it )
516 it->maRect.Left()+=(int) (nRightSpace/2);
517 it->maRect.Right()+=(int) (nRightSpace/2);
522 mnLastWidth = nWidth;
523 mnLastHeight = nHeight;
524 mbFormat = sal_False;
527 return size_t(nItemPos) < mpTabCtrlData->maItemList.size() ? mpTabCtrlData->maItemList[nItemPos].maRect : Rectangle();
530 // -----------------------------------------------------------------------
532 void TabControl::ImplChangeTabPage( sal_uInt16 nId, sal_uInt16 nOldId )
534 ImplFreeLayoutData();
536 ImplTabItem* pOldItem = ImplGetItem( nOldId );
537 ImplTabItem* pItem = ImplGetItem( nId );
538 TabPage* pOldPage = (pOldItem) ? pOldItem->mpTabPage : NULL;
539 TabPage* pPage = (pItem) ? pItem->mpTabPage : NULL;
540 Window* pCtrlParent = GetParent();
542 if ( IsReallyVisible() && IsUpdateMode() )
544 sal_uInt16 nPos = GetPagePos( nId );
545 Rectangle aRect = ImplGetTabRect( nPos );
547 if ( !pOldItem || (pOldItem->mnLine != pItem->mnLine) )
549 aRect.Left() = 0;
550 aRect.Top() = 0;
551 aRect.Right() = Control::GetOutputSizePixel().Width();
553 else
555 aRect.Left() -= 3;
556 aRect.Top() -= 2;
557 aRect.Right() += 3;
558 Invalidate( aRect );
559 nPos = GetPagePos( nOldId );
560 aRect = ImplGetTabRect( nPos );
561 aRect.Left() -= 3;
562 aRect.Top() -= 2;
563 aRect.Right() += 3;
565 Invalidate( aRect );
568 if ( pOldPage == pPage )
569 return;
571 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
573 if ( pOldPage )
575 if ( mbRestoreHelpId )
576 pCtrlParent->SetHelpId( OString() );
577 if ( mbRestoreUnqId )
578 pCtrlParent->SetUniqueId( OString() );
579 pOldPage->DeactivatePage();
582 if ( pPage )
584 if ( ( GetStyle() & WB_NOBORDER ) )
586 Rectangle aRectNoTab( (const Point&)Point( 0, 0 ), GetSizePixel() );
587 pPage->SetPosSizePixel( aRectNoTab.TopLeft(), aRectNoTab.GetSize() );
589 else
590 pPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
592 // activate page here so the conbtrols can be switched
593 // also set the help id of the parent window to that of the tab page
594 if ( GetHelpId().isEmpty() )
596 mbRestoreHelpId = sal_True;
597 pCtrlParent->SetHelpId( pPage->GetHelpId() );
599 if ( pCtrlParent->GetUniqueId().isEmpty() )
601 mbRestoreUnqId = sal_True;
602 pCtrlParent->SetUniqueId( pPage->GetUniqueId() );
605 pPage->ActivatePage();
607 if ( pOldPage && pOldPage->HasChildPathFocus() )
609 sal_uInt16 n = 0;
610 Window* pFirstChild = pPage->ImplGetDlgWindow( n, DLGWINDOW_FIRST );
611 if ( pFirstChild )
612 pFirstChild->ImplControlFocus( GETFOCUS_INIT );
613 else
614 GrabFocus();
617 pPage->Show();
620 if ( pOldPage )
621 pOldPage->Hide();
623 // Invalidate the same region that will be send to NWF
624 // to always allow for bitmap caching
625 // see Window::DrawNativeControl()
626 if( IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL ) )
628 aRect.Left() -= TAB_OFFSET;
629 aRect.Top() -= TAB_OFFSET;
630 aRect.Right() += TAB_OFFSET;
631 aRect.Bottom() += TAB_OFFSET;
634 Invalidate( aRect );
637 // -----------------------------------------------------------------------
639 sal_Bool TabControl::ImplPosCurTabPage()
641 // resize/position current TabPage
642 ImplTabItem* pItem = ImplGetItem( GetCurPageId() );
643 if ( pItem && pItem->mpTabPage )
645 if ( ( GetStyle() & WB_NOBORDER ) )
647 Rectangle aRectNoTab( (const Point&)Point( 0, 0 ), GetSizePixel() );
648 pItem->mpTabPage->SetPosSizePixel( aRectNoTab.TopLeft(), aRectNoTab.GetSize() );
649 return sal_True;
651 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
652 pItem->mpTabPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
653 return sal_True;
656 return sal_False;
659 // -----------------------------------------------------------------------
661 void TabControl::ImplActivateTabPage( sal_Bool bNext )
663 sal_uInt16 nCurPos = GetPagePos( GetCurPageId() );
665 if ( bNext )
666 nCurPos = (nCurPos + 1) % GetPageCount();
667 else
669 if ( !nCurPos )
670 nCurPos = GetPageCount()-1;
671 else
672 nCurPos--;
675 SelectTabPage( GetPageId( nCurPos ) );
678 // -----------------------------------------------------------------------
680 void TabControl::ImplShowFocus()
682 if ( !GetPageCount() || mpTabCtrlData->mpListBox )
683 return;
685 sal_uInt16 nCurPos = GetPagePos( mnCurPageId );
686 Rectangle aRect = ImplGetTabRect( nCurPos );
687 const ImplTabItem& rItem = mpTabCtrlData->maItemList[ nCurPos ];
688 Size aTabSize = aRect.GetSize();
689 Size aImageSize( 0, 0 );
690 long nTextHeight = GetTextHeight();
691 long nTextWidth = GetCtrlTextWidth( rItem.maFormatText );
692 sal_uInt16 nOff;
694 if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_MONO) )
695 nOff = 1;
696 else
697 nOff = 0;
699 if( !! rItem.maTabImage )
701 aImageSize = rItem.maTabImage.GetSizePixel();
702 if( rItem.maFormatText.Len() )
703 aImageSize.Width() += GetTextHeight()/4;
706 if( rItem.maFormatText.Len() )
708 // show focus around text
709 aRect.Left() = aRect.Left()+aImageSize.Width()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1-1;
710 aRect.Top() = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-1-1;
711 aRect.Right() = aRect.Left()+nTextWidth+2;
712 aRect.Bottom() = aRect.Top()+nTextHeight+2;
714 else
716 // show focus around image
717 long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1;
718 long nYPos = aRect.Top();
719 if( aImageSize.Height() < aRect.GetHeight() )
720 nYPos += (aRect.GetHeight() - aImageSize.Height())/2;
722 aRect.Left() = nXPos - 2;
723 aRect.Top() = nYPos - 2;
724 aRect.Right() = aRect.Left() + aImageSize.Width() + 4;
725 aRect.Bottom() = aRect.Top() + aImageSize.Height() + 4;
727 ShowFocus( aRect );
730 // -----------------------------------------------------------------------
732 void TabControl::ImplDrawItem( ImplTabItem* pItem, const Rectangle& rCurRect, bool bLayout, bool bFirstInGroup, bool bLastInGroup, bool /* bIsCurrentItem */ )
734 if ( pItem->maRect.IsEmpty() )
735 return;
737 if( bLayout )
739 if( !HasLayoutData() )
741 mpControlData->mpLayoutData = new vcl::ControlLayoutData();
742 mpTabCtrlData->maLayoutLineToPageId.clear();
743 mpTabCtrlData->maLayoutPageIdToLine.clear();
744 mpTabCtrlData->maTabRectangles.clear();
748 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
749 Rectangle aRect = pItem->maRect;
750 long nLeftBottom = aRect.Bottom();
751 long nRightBottom = aRect.Bottom();
752 bool bLeftBorder = true;
753 bool bRightBorder = true;
754 sal_uInt16 nOff;
755 sal_Bool bNativeOK = sal_False;
757 sal_uInt16 nOff2 = 0;
758 sal_uInt16 nOff3 = 0;
760 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
761 nOff = 1;
762 else
763 nOff = 0;
765 // if this is the active Page, we have to draw a little more
766 if ( pItem->mnId == mnCurPageId )
768 nOff2 = 2;
769 if( ! ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise )
770 nOff3 = 1;
772 else
774 Point aLeftTestPos = aRect.BottomLeft();
775 Point aRightTestPos = aRect.BottomRight();
776 if ( aLeftTestPos.Y() == rCurRect.Bottom() )
778 aLeftTestPos.X() -= 2;
779 if ( rCurRect.IsInside( aLeftTestPos ) )
780 bLeftBorder = false;
781 aRightTestPos.X() += 2;
782 if ( rCurRect.IsInside( aRightTestPos ) )
783 bRightBorder = false;
785 else
787 if ( rCurRect.IsInside( aLeftTestPos ) )
788 nLeftBottom -= 2;
789 if ( rCurRect.IsInside( aRightTestPos ) )
790 nRightBottom -= 2;
794 if( !bLayout && (bNativeOK = IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL)) == sal_True )
796 Rectangle aCtrlRegion( pItem->maRect );
797 ControlState nState = 0;
799 if( pItem->mnId == mnCurPageId )
801 nState |= CTRL_STATE_SELECTED;
802 // only the selected item can be focussed
803 if ( HasFocus() )
804 nState |= CTRL_STATE_FOCUSED;
806 if ( IsEnabled() )
807 nState |= CTRL_STATE_ENABLED;
808 if( IsMouseOver() && pItem->maRect.IsInside( GetPointerPosPixel() ) )
810 nState |= CTRL_STATE_ROLLOVER;
811 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
812 it != mpTabCtrlData->maItemList.end(); ++it )
814 if( (&(*it) != pItem) && (it->maRect.IsInside( GetPointerPosPixel() ) ) )
816 nState &= ~CTRL_STATE_ROLLOVER; // avoid multiple highlighted tabs
817 break;
822 TabitemValue tiValue;
823 if(pItem->maRect.Left() < 5)
824 tiValue.mnAlignment |= TABITEM_LEFTALIGNED;
825 if(pItem->maRect.Right() > mnLastWidth - 5)
826 tiValue.mnAlignment |= TABITEM_RIGHTALIGNED;
827 if ( bFirstInGroup )
828 tiValue.mnAlignment |= TABITEM_FIRST_IN_GROUP;
829 if ( bLastInGroup )
830 tiValue.mnAlignment |= TABITEM_LAST_IN_GROUP;
832 bNativeOK = DrawNativeControl( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
833 tiValue, OUString() );
836 if( ! bLayout && !bNativeOK )
838 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
840 SetLineColor( rStyleSettings.GetLightColor() );
841 DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) ); // diagonally indented top-left pixel
842 if ( bLeftBorder )
844 DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
845 Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
847 DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ), // top line starting 2px from left border
848 Point( aRect.Right()+nOff2-3, aRect.Top()-nOff2 ) ); // ending 3px from right border
850 if ( bRightBorder )
852 SetLineColor( rStyleSettings.GetShadowColor() );
853 DrawLine( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ),
854 Point( aRect.Right()+nOff2-2, nRightBottom-1 ) );
856 SetLineColor( rStyleSettings.GetDarkShadowColor() );
857 DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+3-nOff2 ),
858 Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
861 else
863 SetLineColor( Color( COL_BLACK ) );
864 DrawPixel( Point( aRect.Left()+1-nOff2, aRect.Top()+1-nOff2 ) );
865 DrawPixel( Point( aRect.Right()+nOff2-2, aRect.Top()+1-nOff2 ) );
866 if ( bLeftBorder )
868 DrawLine( Point( aRect.Left()-nOff2, aRect.Top()+2-nOff2 ),
869 Point( aRect.Left()-nOff2, nLeftBottom-1 ) );
871 DrawLine( Point( aRect.Left()+2-nOff2, aRect.Top()-nOff2 ),
872 Point( aRect.Right()-3, aRect.Top()-nOff2 ) );
873 if ( bRightBorder )
875 DrawLine( Point( aRect.Right()+nOff2-1, aRect.Top()+2-nOff2 ),
876 Point( aRect.Right()+nOff2-1, nRightBottom-1 ) );
881 if( bLayout )
883 int nLine = mpControlData->mpLayoutData->m_aLineIndices.size();
884 mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.getLength() );
885 mpTabCtrlData->maLayoutPageIdToLine[ (int)pItem->mnId ] = nLine;
886 mpTabCtrlData->maLayoutLineToPageId[ nLine ] = (int)pItem->mnId;
887 mpTabCtrlData->maTabRectangles.push_back( aRect );
890 // set font accordingly, current item is painted bold
891 // we set the font attributes always before drawing to be re-entrant (DrawNativeControl may trigger additional paints)
892 Font aFont( GetFont() );
893 aFont.SetTransparent( sal_True );
894 SetFont( aFont );
896 Size aTabSize = aRect.GetSize();
897 Size aImageSize( 0, 0 );
898 long nTextHeight = GetTextHeight();
899 long nTextWidth = GetCtrlTextWidth( pItem->maFormatText );
900 if( !! pItem->maTabImage )
902 aImageSize = pItem->maTabImage.GetSizePixel();
903 if( pItem->maFormatText.Len() )
904 aImageSize.Width() += GetTextHeight()/4;
906 long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-nOff3;
907 long nYPos = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-nOff3;
908 if( pItem->maFormatText.Len() )
910 sal_uInt16 nStyle = TEXT_DRAW_MNEMONIC;
911 if( ! pItem->mbEnabled )
912 nStyle |= TEXT_DRAW_DISABLE;
913 DrawCtrlText( Point( nXPos + aImageSize.Width(), nYPos ),
914 pItem->maFormatText,
915 0, STRING_LEN, nStyle,
916 bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL,
917 bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL
921 if( !! pItem->maTabImage )
923 Point aImgTL( nXPos, aRect.Top() );
924 if( aImageSize.Height() < aRect.GetHeight() )
925 aImgTL.Y() += (aRect.GetHeight() - aImageSize.Height())/2;
926 DrawImage( aImgTL, pItem->maTabImage, pItem->mbEnabled ? 0 : IMAGE_DRAW_DISABLE );
930 // -----------------------------------------------------------------------
932 long TabControl::ImplHandleKeyEvent( const KeyEvent& rKeyEvent )
934 long nRet = 0;
936 if ( GetPageCount() > 1 )
938 KeyCode aKeyCode = rKeyEvent.GetKeyCode();
939 sal_uInt16 nKeyCode = aKeyCode.GetCode();
941 if ( aKeyCode.IsMod1() )
943 if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) )
945 if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) )
947 ImplActivateTabPage( sal_False );
948 nRet = 1;
951 else
953 if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) )
955 ImplActivateTabPage( sal_True );
956 nRet = 1;
962 return nRet;
966 // -----------------------------------------------------------------------
968 IMPL_LINK_NOARG(TabControl, ImplListBoxSelectHdl)
970 SelectTabPage( GetPageId( mpTabCtrlData->mpListBox->GetSelectEntryPos() ) );
971 return 0;
974 // -----------------------------------------------------------------------
976 IMPL_LINK( TabControl, ImplWindowEventListener, VclSimpleEvent*, pEvent )
978 if ( pEvent && pEvent->ISA( VclWindowEvent ) && (pEvent->GetId() == VCLEVENT_WINDOW_KEYINPUT) )
980 VclWindowEvent* pWindowEvent = static_cast< VclWindowEvent* >(pEvent);
981 // Do not handle events from TabControl or it's children, which is done in Notify(), where the events can be consumed.
982 if ( !IsWindowOrChild( pWindowEvent->GetWindow() ) )
984 KeyEvent* pKeyEvent = static_cast< KeyEvent* >(pWindowEvent->GetData());
985 ImplHandleKeyEvent( *pKeyEvent );
988 return 0;
992 // -----------------------------------------------------------------------
994 void TabControl::MouseButtonDown( const MouseEvent& rMEvt )
996 if( mpTabCtrlData->mpListBox == NULL )
998 if( rMEvt.IsLeft() )
1000 sal_uInt16 nPageId = GetPageId( rMEvt.GetPosPixel() );
1001 ImplTabItem* pItem = ImplGetItem( nPageId );
1002 if( pItem && pItem->mbEnabled )
1003 SelectTabPage( nPageId );
1008 // -----------------------------------------------------------------------
1010 void TabControl::KeyInput( const KeyEvent& rKEvt )
1012 if( mpTabCtrlData->mpListBox )
1013 mpTabCtrlData->mpListBox->KeyInput( rKEvt );
1014 else if ( GetPageCount() > 1 )
1016 KeyCode aKeyCode = rKEvt.GetKeyCode();
1017 sal_uInt16 nKeyCode = aKeyCode.GetCode();
1019 if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_RIGHT) )
1021 sal_Bool bNext = (nKeyCode == KEY_RIGHT);
1022 ImplActivateTabPage( bNext );
1026 Control::KeyInput( rKEvt );
1029 // -----------------------------------------------------------------------
1031 void TabControl::Paint( const Rectangle& rRect )
1033 if ( !( GetStyle() & WB_NOBORDER ) )
1034 ImplPaint( rRect, false );
1037 // -----------------------------------------------------------------------
1039 void TabControl::ImplPaint( const Rectangle& rRect, bool bLayout )
1041 if( ! bLayout )
1042 HideFocus();
1044 // reformat if needed
1045 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
1047 // find current item
1048 ImplTabItem* pCurItem = NULL;
1049 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1050 it != mpTabCtrlData->maItemList.end(); ++it )
1052 if ( it->mnId == mnCurPageId )
1054 pCurItem = &(*it);
1055 break;
1059 // Draw the TabPage border
1060 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1061 Rectangle aCurRect;
1062 aRect.Left() -= TAB_OFFSET;
1063 aRect.Top() -= TAB_OFFSET;
1064 aRect.Right() += TAB_OFFSET;
1065 aRect.Bottom() += TAB_OFFSET;
1067 // if we have an invisible tabpage or no tabpage at all the tabpage rect should be
1068 // increased to avoid round corners that might be drawn by a theme
1069 // in this case we're only interested in the top border of the tabpage because the tabitems are used
1070 // standalone (eg impress)
1071 bool bNoTabPage = false;
1072 TabPage* pCurPage = pCurItem ? pCurItem->mpTabPage : NULL;
1073 if( !pCurPage || !pCurPage->IsVisible() )
1075 bNoTabPage = true;
1076 aRect.Left()-=10;
1077 aRect.Right()+=10;
1080 sal_Bool bNativeOK = sal_False;
1081 if( ! bLayout && (bNativeOK = IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL) ) == sal_True )
1083 const ImplControlValue aControlValue;
1085 ControlState nState = CTRL_STATE_ENABLED;
1086 int part = PART_ENTIRE_CONTROL;
1087 if ( !IsEnabled() )
1088 nState &= ~CTRL_STATE_ENABLED;
1089 if ( HasFocus() )
1090 nState |= CTRL_STATE_FOCUSED;
1092 Region aClipRgn( GetActiveClipRegion() );
1093 aClipRgn.Intersect( aRect );
1094 if( !rRect.IsEmpty() )
1095 aClipRgn.Intersect( rRect );
1097 if( !aClipRgn.IsEmpty() )
1098 bNativeOK = DrawNativeControl( CTRL_TAB_PANE, part, aRect, nState,
1099 aControlValue, OUString() );
1101 else
1103 long nTopOff = 1;
1104 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
1105 SetLineColor( rStyleSettings.GetLightColor() );
1106 else
1107 SetLineColor( Color( COL_BLACK ) );
1108 if ( pCurItem && !pCurItem->maRect.IsEmpty() )
1110 aCurRect = pCurItem->maRect;
1111 if( ! bLayout )
1112 DrawLine( aRect.TopLeft(), Point( aCurRect.Left()-2, aRect.Top() ) );
1113 if ( aCurRect.Right()+1 < aRect.Right() )
1115 if( ! bLayout )
1116 DrawLine( Point( aCurRect.Right(), aRect.Top() ), aRect.TopRight() );
1118 else
1119 nTopOff = 0;
1121 else
1122 if( ! bLayout )
1123 DrawLine( aRect.TopLeft(), aRect.TopRight() );
1125 if( ! bLayout )
1127 DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
1129 if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) )
1131 // if we have not tab page the bottom line of the tab page
1132 // directly touches the tab items, so choose a color that fits seamlessly
1133 if( bNoTabPage )
1134 SetLineColor( rStyleSettings.GetDialogColor() );
1135 else
1136 SetLineColor( rStyleSettings.GetShadowColor() );
1137 DrawLine( Point( 1, aRect.Bottom()-1 ),
1138 Point( aRect.Right()-1, aRect.Bottom()-1 ) );
1139 DrawLine( Point( aRect.Right()-1, aRect.Top()+nTopOff ),
1140 Point( aRect.Right()-1, aRect.Bottom()-1 ) );
1141 if( bNoTabPage )
1142 SetLineColor( rStyleSettings.GetDialogColor() );
1143 else
1144 SetLineColor( rStyleSettings.GetDarkShadowColor() );
1145 DrawLine( Point( 0, aRect.Bottom() ),
1146 Point( aRect.Right(), aRect.Bottom() ) );
1147 DrawLine( Point( aRect.Right(), aRect.Top()+nTopOff ),
1148 Point( aRect.Right(), aRect.Bottom() ) );
1150 else
1152 DrawLine( aRect.TopRight(), aRect.BottomRight() );
1153 DrawLine( aRect.BottomLeft(), aRect.BottomRight() );
1158 if ( !mpTabCtrlData->maItemList.empty() && mpTabCtrlData->mpListBox == NULL )
1160 // Some native toolkits (GTK+) draw tabs right-to-left, with an
1161 // overlap between adjacent tabs
1162 bool bDrawTabsRTL = IsNativeControlSupported( CTRL_TAB_ITEM, PART_TABS_DRAW_RTL );
1163 ImplTabItem * pFirstTab = NULL;
1164 ImplTabItem * pLastTab = NULL;
1165 size_t idx;
1167 // Event though there is a tab overlap with GTK+, the first tab is not
1168 // overlapped on the left side. Other tookits ignore this option.
1169 if ( bDrawTabsRTL )
1171 pFirstTab = &mpTabCtrlData->maItemList.front();
1172 pLastTab = &mpTabCtrlData->maItemList.back();
1173 idx = mpTabCtrlData->maItemList.size()-1;
1175 else
1177 pLastTab = &mpTabCtrlData->maItemList.back();
1178 pFirstTab = &mpTabCtrlData->maItemList.front();
1179 idx = 0;
1182 while ( idx < mpTabCtrlData->maItemList.size() )
1184 ImplTabItem* pItem = &mpTabCtrlData->maItemList[idx];
1185 if ( pItem != pCurItem )
1187 Region aClipRgn( GetActiveClipRegion() );
1188 aClipRgn.Intersect( pItem->maRect );
1189 if( !rRect.IsEmpty() )
1190 aClipRgn.Intersect( rRect );
1191 if( bLayout || !aClipRgn.IsEmpty() )
1192 ImplDrawItem( pItem, aCurRect, bLayout, (pItem==pFirstTab), (pItem==pLastTab), sal_False );
1195 if ( bDrawTabsRTL )
1196 idx--;
1197 else
1198 idx++;
1201 if ( pCurItem )
1203 Region aClipRgn( GetActiveClipRegion() );
1204 aClipRgn.Intersect( pCurItem->maRect );
1205 if( !rRect.IsEmpty() )
1206 aClipRgn.Intersect( rRect );
1207 if( bLayout || !aClipRgn.IsEmpty() )
1208 ImplDrawItem( pCurItem, aCurRect, bLayout, (pCurItem==pFirstTab), (pCurItem==pLastTab), sal_True );
1212 if ( !bLayout && HasFocus() )
1213 ImplShowFocus();
1215 if( ! bLayout )
1216 mbSmallInvalidate = sal_True;
1219 // -----------------------------------------------------------------------
1221 void TabControl::setAllocation(const Size &rAllocation)
1223 ImplFreeLayoutData();
1225 if ( !IsReallyShown() )
1226 return;
1228 if( mpTabCtrlData->mpListBox )
1230 // get the listbox' preferred size
1231 Size aTabCtrlSize( GetSizePixel() );
1232 long nPrefWidth = mpTabCtrlData->mpListBox->get_preferred_size().Width();
1233 if( nPrefWidth > aTabCtrlSize.Width() )
1234 nPrefWidth = aTabCtrlSize.Width();
1235 Size aNewSize( nPrefWidth, LogicToPixel( Size( 12, 12 ), MapMode( MAP_APPFONT ) ).Height() );
1236 Point aNewPos( (aTabCtrlSize.Width() - nPrefWidth) / 2, 0 );
1237 mpTabCtrlData->mpListBox->SetPosSizePixel( aNewPos, aNewSize );
1240 mbFormat = sal_True;
1242 // resize/position active TabPage
1243 sal_Bool bTabPage = ImplPosCurTabPage();
1245 // check what needs to be invalidated
1246 Size aNewSize = rAllocation;
1247 long nNewWidth = aNewSize.Width();
1248 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1249 it != mpTabCtrlData->maItemList.end(); ++it )
1251 if ( !it->mbFullVisible ||
1252 (it->maRect.Right()-2 >= nNewWidth) )
1254 mbSmallInvalidate = sal_False;
1255 break;
1259 if ( mbSmallInvalidate )
1261 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
1262 aRect.Left() -= TAB_OFFSET+TAB_BORDER_LEFT;
1263 aRect.Top() -= TAB_OFFSET+TAB_BORDER_TOP;
1264 aRect.Right() += TAB_OFFSET+TAB_BORDER_RIGHT;
1265 aRect.Bottom() += TAB_OFFSET+TAB_BORDER_BOTTOM;
1266 if ( bTabPage )
1267 Invalidate( aRect, INVALIDATE_NOCHILDREN );
1268 else
1269 Invalidate( aRect );
1272 else
1274 if ( bTabPage )
1275 Invalidate( INVALIDATE_NOCHILDREN );
1276 else
1277 Invalidate();
1280 mbLayoutDirty = false;
1283 void TabControl::SetPosSizePixel(const Point& rNewPos, const Size& rNewSize)
1285 Window::SetPosSizePixel(rNewPos, rNewSize);
1286 //if size changed, TabControl::Resize got called already
1287 if (mbLayoutDirty)
1288 setAllocation(rNewSize);
1291 void TabControl::SetSizePixel(const Size& rNewSize)
1293 Window::SetSizePixel(rNewSize);
1294 //if size changed, TabControl::Resize got called already
1295 if (mbLayoutDirty)
1296 setAllocation(rNewSize);
1299 void TabControl::SetPosPixel(const Point& rPos)
1301 Window::SetPosPixel(rPos);
1302 if (mbLayoutDirty)
1303 setAllocation(GetOutputSizePixel());
1306 void TabControl::Resize()
1308 setAllocation(Control::GetOutputSizePixel());
1311 // -----------------------------------------------------------------------
1313 void TabControl::GetFocus()
1315 if( ! mpTabCtrlData->mpListBox )
1317 ImplShowFocus();
1318 SetInputContext( InputContext( GetFont() ) );
1320 else
1322 if( mpTabCtrlData->mpListBox->IsReallyVisible() )
1323 mpTabCtrlData->mpListBox->GrabFocus();
1325 Control::GetFocus();
1328 // -----------------------------------------------------------------------
1330 void TabControl::LoseFocus()
1332 if( ! mpTabCtrlData->mpListBox )
1333 HideFocus();
1334 Control::LoseFocus();
1337 // -----------------------------------------------------------------------
1339 void TabControl::RequestHelp( const HelpEvent& rHEvt )
1341 sal_uInt16 nItemId = rHEvt.KeyboardActivated() ? mnCurPageId : GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
1343 if ( nItemId )
1345 if ( rHEvt.GetMode() & HELPMODE_BALLOON )
1347 XubString aStr = GetHelpText( nItemId );
1348 if ( aStr.Len() )
1350 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1351 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1352 aItemRect.Left() = aPt.X();
1353 aItemRect.Top() = aPt.Y();
1354 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1355 aItemRect.Right() = aPt.X();
1356 aItemRect.Bottom() = aPt.Y();
1357 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
1358 return;
1361 else if ( rHEvt.GetMode() & HELPMODE_EXTENDED )
1363 OUString aHelpId( OStringToOUString( GetHelpId( nItemId ), RTL_TEXTENCODING_UTF8 ) );
1364 if ( !aHelpId.isEmpty() )
1366 // call Help if existing
1367 Help* pHelp = Application::GetHelp();
1368 if ( pHelp )
1369 pHelp->Start( aHelpId, this );
1370 return;
1374 // for Quick or Ballon Help, we show the text, if it is cut
1375 if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) )
1377 ImplTabItem* pItem = ImplGetItem( nItemId );
1378 const XubString& rStr = pItem->maText;
1379 if ( rStr != pItem->maFormatText )
1381 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1382 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1383 aItemRect.Left() = aPt.X();
1384 aItemRect.Top() = aPt.Y();
1385 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1386 aItemRect.Right() = aPt.X();
1387 aItemRect.Bottom() = aPt.Y();
1388 if ( rStr.Len() )
1390 if ( rHEvt.GetMode() & HELPMODE_BALLOON )
1391 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, rStr );
1392 else
1393 Help::ShowQuickHelp( this, aItemRect, rStr );
1394 return;
1399 if ( rHEvt.GetMode() & HELPMODE_QUICK )
1401 ImplTabItem* pItem = ImplGetItem( nItemId );
1402 const XubString& rHelpText = pItem->maHelpText;
1403 // show tooltip if not text but image is set and helptext is available
1404 if ( rHelpText.Len() > 0 && pItem->maText.Len() == 0 && !!pItem->maTabImage )
1406 Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1407 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1408 aItemRect.Left() = aPt.X();
1409 aItemRect.Top() = aPt.Y();
1410 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1411 aItemRect.Right() = aPt.X();
1412 aItemRect.Bottom() = aPt.Y();
1413 Help::ShowQuickHelp( this, aItemRect, rHelpText );
1414 return;
1419 Control::RequestHelp( rHEvt );
1422 // -----------------------------------------------------------------------
1424 void TabControl::Command( const CommandEvent& rCEvt )
1426 if( (mpTabCtrlData->mpListBox == NULL) && (rCEvt.GetCommand() == COMMAND_CONTEXTMENU) && (GetPageCount() > 1) )
1428 Point aMenuPos;
1429 bool bMenu;
1430 if ( rCEvt.IsMouseEvent() )
1432 aMenuPos = rCEvt.GetMousePosPixel();
1433 bMenu = GetPageId( aMenuPos ) != 0;
1435 else
1437 aMenuPos = ImplGetTabRect( GetPagePos( mnCurPageId ) ).Center();
1438 bMenu = true;
1441 if ( bMenu )
1443 PopupMenu aMenu;
1444 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1445 it != mpTabCtrlData->maItemList.end(); ++it )
1447 aMenu.InsertItem( it->mnId, it->maText, MIB_CHECKABLE | MIB_RADIOCHECK );
1448 if ( it->mnId == mnCurPageId )
1449 aMenu.CheckItem( it->mnId );
1450 aMenu.SetHelpId( it->mnId, it->maHelpId );
1453 sal_uInt16 nId = aMenu.Execute( this, aMenuPos );
1454 if ( nId && (nId != mnCurPageId) )
1455 SelectTabPage( nId );
1456 return;
1460 Control::Command( rCEvt );
1463 // -----------------------------------------------------------------------
1465 void TabControl::StateChanged( StateChangedType nType )
1467 Control::StateChanged( nType );
1469 if ( nType == STATE_CHANGE_INITSHOW )
1471 ImplPosCurTabPage();
1472 if( mpTabCtrlData->mpListBox )
1473 Resize();
1475 else if ( nType == STATE_CHANGE_UPDATEMODE )
1477 if ( IsUpdateMode() )
1478 Invalidate();
1480 else if ( (nType == STATE_CHANGE_ZOOM) ||
1481 (nType == STATE_CHANGE_CONTROLFONT) )
1483 ImplInitSettings( sal_True, sal_False, sal_False );
1484 Invalidate();
1486 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
1488 ImplInitSettings( sal_False, sal_True, sal_False );
1489 Invalidate();
1491 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
1493 ImplInitSettings( sal_False, sal_False, sal_True );
1494 Invalidate();
1498 // -----------------------------------------------------------------------
1500 void TabControl::DataChanged( const DataChangedEvent& rDCEvt )
1502 Control::DataChanged( rDCEvt );
1504 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
1505 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
1506 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1507 (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
1509 ImplInitSettings( sal_True, sal_True, sal_True );
1510 Invalidate();
1514 // -----------------------------------------------------------------------
1516 Rectangle* TabControl::ImplFindPartRect( const Point& rPt )
1518 ImplTabItem* pFoundItem = NULL;
1519 int nFound = 0;
1520 for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1521 it != mpTabCtrlData->maItemList.end(); ++it )
1523 if ( it->maRect.IsInside( rPt ) )
1525 // assure that only one tab is highlighted at a time
1526 nFound++;
1527 pFoundItem = &(*it);
1530 // assure that only one tab is highlighted at a time
1531 return nFound == 1 ? &pFoundItem->maRect : NULL;
1534 long TabControl::PreNotify( NotifyEvent& rNEvt )
1536 long nDone = 0;
1537 const MouseEvent* pMouseEvt = NULL;
1539 if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
1541 if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1543 // trigger redraw if mouse over state has changed
1544 if( IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) )
1546 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
1547 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
1548 if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
1550 Region aClipRgn;
1551 if( pLastRect )
1553 // allow for slightly bigger tabitems
1554 // as used by gtk
1555 // TODO: query for the correct sizes
1556 Rectangle aRect(*pLastRect);
1557 aRect.Left()-=2;
1558 aRect.Right()+=2;
1559 aRect.Top()-=3;
1560 aClipRgn.Union( aRect );
1562 if( pRect )
1564 // allow for slightly bigger tabitems
1565 // as used by gtk
1566 // TODO: query for the correct sizes
1567 Rectangle aRect(*pRect);
1568 aRect.Left()-=2;
1569 aRect.Right()+=2;
1570 aRect.Top()-=3;
1571 aClipRgn.Union( aRect );
1573 if( !aClipRgn.IsEmpty() )
1574 Invalidate( aClipRgn );
1580 return nDone ? nDone : Control::PreNotify(rNEvt);
1583 // -----------------------------------------------------------------------
1585 long TabControl::Notify( NotifyEvent& rNEvt )
1587 long nRet = 0;
1589 if ( rNEvt.GetType() == EVENT_KEYINPUT )
1590 nRet = ImplHandleKeyEvent( *rNEvt.GetKeyEvent() );
1592 return nRet ? nRet : Control::Notify( rNEvt );
1595 // -----------------------------------------------------------------------
1597 void TabControl::ActivatePage()
1599 maActivateHdl.Call( this );
1602 // -----------------------------------------------------------------------
1604 long TabControl::DeactivatePage()
1606 if ( maDeactivateHdl.IsSet() )
1607 return maDeactivateHdl.Call( this );
1608 else
1609 return sal_True;
1612 // -----------------------------------------------------------------------
1614 void TabControl::SetTabPageSizePixel( const Size& rSize )
1616 ImplFreeLayoutData();
1618 Size aNewSize( rSize );
1619 aNewSize.Width() += TAB_OFFSET*2;
1620 Rectangle aRect = ImplGetTabRect( TAB_PAGERECT,
1621 aNewSize.Width(), aNewSize.Height() );
1622 aNewSize.Height() += aRect.Top()+TAB_OFFSET;
1623 Window::SetOutputSizePixel( aNewSize );
1626 // -----------------------------------------------------------------------
1628 Size TabControl::GetTabPageSizePixel() const
1630 Rectangle aRect = ((TabControl*)this)->ImplGetTabRect( TAB_PAGERECT );
1631 return aRect.GetSize();
1634 // -----------------------------------------------------------------------
1636 void TabControl::InsertPage( const ResId& rResId, sal_uInt16 nPos )
1638 GetRes( rResId.SetRT( RSC_TABCONTROLITEM ) );
1640 sal_uLong nObjMask = ReadLongRes();
1641 sal_uInt16 nItemId = 1;
1643 // ID
1644 if ( nObjMask & RSC_TABCONTROLITEM_ID )
1645 nItemId = sal::static_int_cast<sal_uInt16>(ReadLongRes());
1647 // Text
1648 XubString aTmpStr;
1649 if( nObjMask & RSC_TABCONTROLITEM_TEXT )
1650 aTmpStr = ReadStringRes();
1651 InsertPage( nItemId, aTmpStr, nPos );
1653 // PageResID
1654 if ( nObjMask & RSC_TABCONTROLITEM_PAGERESID )
1656 //skip unused TabPageResId value
1657 ReadLongRes();
1661 // -----------------------------------------------------------------------
1663 void TabControl::InsertPage( sal_uInt16 nPageId, const XubString& rText,
1664 sal_uInt16 nPos )
1666 DBG_ASSERT( nPageId, "TabControl::InsertPage(): PageId == 0" );
1667 DBG_ASSERT( GetPagePos( nPageId ) == TAB_PAGE_NOTFOUND,
1668 "TabControl::InsertPage(): PageId already exists" );
1670 // insert new page item
1671 ImplTabItem* pItem = NULL;
1672 if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1674 mpTabCtrlData->maItemList.push_back( ImplTabItem() );
1675 pItem = &mpTabCtrlData->maItemList.back();
1676 if( mpTabCtrlData->mpListBox )
1677 mpTabCtrlData->mpListBox->InsertEntry( rText );
1679 else
1681 std::vector< ImplTabItem >::iterator new_it =
1682 mpTabCtrlData->maItemList.insert( mpTabCtrlData->maItemList.begin() + nPos, ImplTabItem() );
1683 pItem = &(*new_it);
1684 if( mpTabCtrlData->mpListBox )
1685 mpTabCtrlData->mpListBox->InsertEntry( rText, nPos);
1687 if( mpTabCtrlData->mpListBox )
1689 if( ! mnCurPageId )
1690 mpTabCtrlData->mpListBox->SelectEntryPos( 0 );
1691 mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1694 // set current page id
1695 if ( !mnCurPageId )
1696 mnCurPageId = nPageId;
1698 // init new page item
1699 pItem->mnId = nPageId;
1700 pItem->mpTabPage = NULL;
1701 pItem->maText = rText;
1702 pItem->mbFullVisible = sal_False;
1704 mbFormat = sal_True;
1705 if ( IsUpdateMode() )
1706 Invalidate();
1708 ImplFreeLayoutData();
1709 if( mpTabCtrlData->mpListBox ) // reposition/resize listbox
1710 Resize();
1712 ImplCallEventListeners( VCLEVENT_TABPAGE_INSERTED, (void*) (sal_uLong)nPageId );
1715 // -----------------------------------------------------------------------
1717 void TabControl::RemovePage( sal_uInt16 nPageId )
1719 sal_uInt16 nPos = GetPagePos( nPageId );
1721 // does the item exist ?
1722 if ( nPos != TAB_PAGE_NOTFOUND )
1724 //remove page item
1725 std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos;
1726 bool bIsCurrentPage = (it->mnId == mnCurPageId);
1727 mpTabCtrlData->maItemList.erase( it );
1728 if( mpTabCtrlData->mpListBox )
1730 mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1731 mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1734 // If current page is removed, than first page gets the current page
1735 if ( bIsCurrentPage )
1737 mnCurPageId = 0;
1739 if( ! mpTabCtrlData->maItemList.empty() )
1741 // don't do this by simply setting mnCurPageId to pFirstItem->mnId
1742 // this leaves a lot of stuff (such trivias as _showing_ the new current page) undone
1743 // instead, call SetCurPageId
1744 // without this, the next (outside) call to SetCurPageId with the id of the first page
1745 // will result in doing nothing (as we assume that nothing changed, then), and the page
1746 // will never be shown.
1747 // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com
1749 SetCurPageId( mpTabCtrlData->maItemList[0].mnId );
1753 mbFormat = sal_True;
1754 if ( IsUpdateMode() )
1755 Invalidate();
1757 ImplFreeLayoutData();
1759 ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVED, (void*) (sal_uLong) nPageId );
1763 // -----------------------------------------------------------------------
1765 void TabControl::Clear()
1767 // clear item list
1768 mpTabCtrlData->maItemList.clear();
1769 mnCurPageId = 0;
1770 if( mpTabCtrlData->mpListBox )
1771 mpTabCtrlData->mpListBox->Clear();
1773 ImplFreeLayoutData();
1775 mbFormat = sal_True;
1776 if ( IsUpdateMode() )
1777 Invalidate();
1779 ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVEDALL );
1782 // -----------------------------------------------------------------------
1784 void TabControl::EnablePage( sal_uInt16 i_nPageId, bool i_bEnable )
1786 ImplTabItem* pItem = ImplGetItem( i_nPageId );
1788 if ( pItem && pItem->mbEnabled != i_bEnable )
1790 pItem->mbEnabled = i_bEnable;
1791 mbFormat = sal_True;
1792 if( mpTabCtrlData->mpListBox )
1793 mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ),
1794 i_bEnable ? 0 : (LISTBOX_ENTRY_FLAG_DISABLE_SELECTION | LISTBOX_ENTRY_FLAG_DRAW_DISABLED) );
1795 if( pItem->mnId == mnCurPageId )
1797 // SetCurPageId will change to an enabled page
1798 SetCurPageId( mnCurPageId );
1800 else if ( IsUpdateMode() )
1801 Invalidate();
1805 // -----------------------------------------------------------------------
1807 sal_uInt16 TabControl::GetPageCount() const
1809 return (sal_uInt16)mpTabCtrlData->maItemList.size();
1812 // -----------------------------------------------------------------------
1814 sal_uInt16 TabControl::GetPageId( sal_uInt16 nPos ) const
1816 if( size_t(nPos) < mpTabCtrlData->maItemList.size() )
1817 return mpTabCtrlData->maItemList[ nPos ].mnId;
1818 return 0;
1821 // -----------------------------------------------------------------------
1823 sal_uInt16 TabControl::GetPagePos( sal_uInt16 nPageId ) const
1825 for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
1826 it != mpTabCtrlData->maItemList.end(); ++it )
1828 if ( it->mnId == nPageId )
1829 return (sal_uInt16)(it - mpTabCtrlData->maItemList.begin());
1832 return TAB_PAGE_NOTFOUND;
1835 // -----------------------------------------------------------------------
1837 sal_uInt16 TabControl::GetPageId( const Point& rPos ) const
1839 for( size_t i = 0; i < mpTabCtrlData->maItemList.size(); ++i )
1841 if ( ((TabControl*)this)->ImplGetTabRect( static_cast<sal_uInt16>(i) ).IsInside( rPos ) )
1842 return mpTabCtrlData->maItemList[ i ].mnId;
1845 return 0;
1848 sal_uInt16 TabControl::GetPageId( const TabPage& rPage ) const
1850 for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
1851 it != mpTabCtrlData->maItemList.end(); ++it )
1853 if ( it->mpTabPage == &rPage )
1854 return it->mnId;
1857 return 0;
1860 sal_uInt16 TabControl::GetPageId( const OString& rName ) const
1862 for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
1863 it != mpTabCtrlData->maItemList.end(); ++it )
1865 if ( it->maTabName == rName )
1866 return it->mnId;
1869 return 0;
1872 // -----------------------------------------------------------------------
1874 void TabControl::SetCurPageId( sal_uInt16 nPageId )
1876 sal_uInt16 nPos = GetPagePos( nPageId );
1877 while( nPos != TAB_PAGE_NOTFOUND &&
1878 ! mpTabCtrlData->maItemList[nPos].mbEnabled )
1880 nPos++;
1881 if( size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1882 nPos = 0;
1883 if( mpTabCtrlData->maItemList[nPos].mnId == nPageId )
1884 break;
1887 if( nPos != TAB_PAGE_NOTFOUND )
1889 nPageId = mpTabCtrlData->maItemList[nPos].mnId;
1890 if ( nPageId == mnCurPageId )
1892 if ( mnActPageId )
1893 mnActPageId = nPageId;
1894 return;
1897 if ( mnActPageId )
1898 mnActPageId = nPageId;
1899 else
1901 mbFormat = sal_True;
1902 sal_uInt16 nOldId = mnCurPageId;
1903 mnCurPageId = nPageId;
1904 ImplChangeTabPage( nPageId, nOldId );
1909 // -----------------------------------------------------------------------
1911 sal_uInt16 TabControl::GetCurPageId() const
1913 if ( mnActPageId )
1914 return mnActPageId;
1915 else
1916 return mnCurPageId;
1919 // -----------------------------------------------------------------------
1921 void TabControl::SelectTabPage( sal_uInt16 nPageId )
1923 if ( nPageId && (nPageId != mnCurPageId) )
1925 ImplFreeLayoutData();
1927 ImplCallEventListeners( VCLEVENT_TABPAGE_DEACTIVATE, (void*) (sal_uLong) mnCurPageId );
1928 if ( DeactivatePage() )
1930 mnActPageId = nPageId;
1931 ActivatePage();
1932 // Page could have been switched by the Activate handler
1933 nPageId = mnActPageId;
1934 mnActPageId = 0;
1935 SetCurPageId( nPageId );
1936 if( mpTabCtrlData->mpListBox )
1937 mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) );
1938 ImplCallEventListeners( VCLEVENT_TABPAGE_ACTIVATE, (void*) (sal_uLong) nPageId );
1943 // -----------------------------------------------------------------------
1945 void TabControl::SetTabPage( sal_uInt16 nPageId, TabPage* pTabPage )
1947 ImplTabItem* pItem = ImplGetItem( nPageId );
1949 if ( pItem && (pItem->mpTabPage != pTabPage) )
1951 if ( pTabPage )
1953 DBG_ASSERT( !pTabPage->IsVisible() || isLayoutEnabled(pTabPage),
1954 "TabControl::SetTabPage() - Non-Layout Enabled Page is visible" );
1956 if ( IsDefaultSize() )
1957 SetTabPageSizePixel( pTabPage->GetSizePixel() );
1959 // only set here, so that Resize does not reposition TabPage
1960 pItem->mpTabPage = pTabPage;
1961 queue_resize();
1962 if ( pItem->mnId == mnCurPageId )
1963 ImplChangeTabPage( pItem->mnId, 0 );
1965 else
1967 pItem->mpTabPage = NULL;
1968 queue_resize();
1973 // -----------------------------------------------------------------------
1975 TabPage* TabControl::GetTabPage( sal_uInt16 nPageId ) const
1977 ImplTabItem* pItem = ImplGetItem( nPageId );
1979 if ( pItem )
1980 return pItem->mpTabPage;
1981 else
1982 return NULL;
1985 // -----------------------------------------------------------------------
1987 void TabControl::SetPageText( sal_uInt16 nPageId, const XubString& rText )
1989 ImplTabItem* pItem = ImplGetItem( nPageId );
1991 if ( pItem && pItem->maText != rText )
1993 pItem->maText = rText;
1994 mbFormat = sal_True;
1995 if( mpTabCtrlData->mpListBox )
1997 sal_uInt16 nPos = GetPagePos( nPageId );
1998 mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1999 mpTabCtrlData->mpListBox->InsertEntry( rText, nPos );
2001 if ( IsUpdateMode() )
2002 Invalidate();
2003 ImplFreeLayoutData();
2004 ImplCallEventListeners( VCLEVENT_TABPAGE_PAGETEXTCHANGED, (void*) (sal_uLong) nPageId );
2008 // -----------------------------------------------------------------------
2010 XubString TabControl::GetPageText( sal_uInt16 nPageId ) const
2012 ImplTabItem* pItem = ImplGetItem( nPageId );
2014 if ( pItem )
2015 return pItem->maText;
2016 else
2017 return ImplGetSVEmptyStr();
2020 // -----------------------------------------------------------------------
2022 void TabControl::SetHelpText( sal_uInt16 nPageId, const XubString& rText )
2024 ImplTabItem* pItem = ImplGetItem( nPageId );
2026 if ( pItem )
2027 pItem->maHelpText = rText;
2030 // -----------------------------------------------------------------------
2032 const XubString& TabControl::GetHelpText( sal_uInt16 nPageId ) const
2034 ImplTabItem* pItem = ImplGetItem( nPageId );
2036 if ( pItem )
2038 if ( !pItem->maHelpText.Len() && !pItem->maHelpId.isEmpty() )
2040 Help* pHelp = Application::GetHelp();
2041 if ( pHelp )
2042 pItem->maHelpText = pHelp->GetHelpText( OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this );
2045 return pItem->maHelpText;
2047 else
2048 return ImplGetSVEmptyStr();
2051 // -----------------------------------------------------------------------
2053 void TabControl::SetHelpId( sal_uInt16 nPageId, const OString& rId ) const
2055 ImplTabItem* pItem = ImplGetItem( nPageId );
2057 if ( pItem )
2058 pItem->maHelpId = rId;
2061 OString TabControl::GetHelpId( sal_uInt16 nPageId ) const
2063 ImplTabItem* pItem = ImplGetItem( nPageId );
2065 if (pItem)
2066 return pItem->maHelpId;
2068 return OString();
2071 void TabControl::SetPageName( sal_uInt16 nPageId, const OString& rName ) const
2073 ImplTabItem* pItem = ImplGetItem( nPageId );
2075 if ( pItem )
2076 pItem->maTabName = rName;
2079 OString TabControl::GetPageName( sal_uInt16 nPageId ) const
2081 ImplTabItem* pItem = ImplGetItem( nPageId );
2083 if (pItem)
2084 return pItem->maTabName;
2086 return OString();
2089 // -----------------------------------------------------------------------
2091 void TabControl::SetPageImage( sal_uInt16 i_nPageId, const Image& i_rImage )
2093 ImplTabItem* pItem = ImplGetItem( i_nPageId );
2095 if ( pItem )
2097 pItem->maTabImage = i_rImage;
2098 mbFormat = sal_True;
2099 if ( IsUpdateMode() )
2100 Invalidate();
2104 // -----------------------------------------------------------------------
2106 Rectangle TabControl::GetCharacterBounds( sal_uInt16 nPageId, long nIndex ) const
2108 Rectangle aRet;
2110 if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2111 FillLayoutData();
2113 if( HasLayoutData() )
2115 boost::unordered_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPageId );
2116 if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
2118 Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( it->second );
2119 if( (aPair.B() - aPair.A()) >= nIndex )
2120 aRet = mpControlData->mpLayoutData->GetCharacterBounds( aPair.A() + nIndex );
2124 return aRet;
2127 // -----------------------------------------------------------------------
2129 long TabControl::GetIndexForPoint( const Point& rPoint, sal_uInt16& rPageId ) const
2131 long nRet = -1;
2133 if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2134 FillLayoutData();
2136 if( HasLayoutData() )
2138 int nIndex = mpControlData->mpLayoutData->GetIndexForPoint( rPoint );
2139 if( nIndex != -1 )
2141 // what line (->pageid) is this index in ?
2142 int nLines = mpControlData->mpLayoutData->GetLineCount();
2143 int nLine = -1;
2144 while( ++nLine < nLines )
2146 Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( nLine );
2147 if( aPair.A() <= nIndex && aPair.B() >= nIndex )
2149 nRet = nIndex - aPair.A();
2150 rPageId = (sal_uInt16)mpTabCtrlData->maLayoutLineToPageId[ nLine ];
2151 break;
2157 return nRet;
2160 // -----------------------------------------------------------------------
2162 void TabControl::FillLayoutData() const
2164 mpTabCtrlData->maLayoutLineToPageId.clear();
2165 mpTabCtrlData->maLayoutPageIdToLine.clear();
2166 const_cast<TabControl*>(this)->ImplPaint( Rectangle(), true );
2169 // -----------------------------------------------------------------------
2171 Rectangle TabControl::GetTabBounds( sal_uInt16 nPageId ) const
2173 Rectangle aRet;
2175 ImplTabItem* pItem = ImplGetItem( nPageId );
2176 if(pItem)
2177 aRet = pItem->maRect;
2179 return aRet;
2182 // -----------------------------------------------------------------------
2184 void TabControl::SetItemsOffset( const Point& rOffs )
2186 if( mpTabCtrlData )
2187 mpTabCtrlData->maItemsOffset = rOffs;
2190 Point TabControl::GetItemsOffset() const
2192 if( mpTabCtrlData )
2193 return mpTabCtrlData->maItemsOffset;
2194 else
2195 return Point();
2198 // -----------------------------------------------------------------------
2200 Size TabControl::calculateRequisition() const
2202 Size aOptimalPageSize(0, 0);
2204 sal_uInt16 nOrigPageId = GetCurPageId();
2205 for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
2206 it != mpTabCtrlData->maItemList.end(); ++it )
2208 const TabPage *pPage = it->mpTabPage;
2209 //it's a real nuisance if the page is not inserted yet :-(
2210 //We need to force all tabs to exist to get overall optimal size for dialog
2211 if (!pPage)
2213 TabControl *pThis = const_cast<TabControl*>(this);
2214 pThis->SetCurPageId(it->mnId);
2215 pThis->ActivatePage();
2216 pPage = it->mpTabPage;
2219 if (!pPage)
2220 continue;
2222 Size aPageSize(VclContainer::getLayoutRequisition(*pPage));
2224 if (aPageSize.Width() > aOptimalPageSize.Width())
2225 aOptimalPageSize.Width() = aPageSize.Width();
2226 if (aPageSize.Height() > aOptimalPageSize.Height())
2227 aOptimalPageSize.Height() = aPageSize.Height();
2230 //fdo#61940 If we were forced to activate pages in order to on-demand
2231 //create them to get their optimal size, then switch back to the original
2232 //page and re-activate it
2233 if (nOrigPageId != GetCurPageId())
2235 TabControl *pThis = const_cast<TabControl*>(this);
2236 pThis->SetCurPageId(nOrigPageId);
2237 pThis->ActivatePage();
2240 long nTabLabelsBottom = 0, nTabLabelsRight = 0;
2241 for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
2242 it != mpTabCtrlData->maItemList.end(); ++it )
2244 TabControl* pThis = const_cast<TabControl*>(this);
2246 sal_uInt16 nPos = it - mpTabCtrlData->maItemList.begin();
2247 Rectangle aTabRect = pThis->ImplGetTabRect(nPos, aOptimalPageSize.Width(), LONG_MAX);
2248 if (aTabRect.Bottom() > nTabLabelsBottom)
2249 nTabLabelsBottom = aTabRect.Bottom();
2250 if (aTabRect.Right() > nTabLabelsRight)
2251 nTabLabelsRight = aTabRect.Right();
2254 Size aOptimalSize(aOptimalPageSize);
2255 aOptimalSize.Height() += nTabLabelsBottom;
2256 aOptimalSize.Width() = std::max(nTabLabelsRight, aOptimalSize.Width());
2258 aOptimalSize.Width() += TAB_OFFSET * 2;
2259 aOptimalSize.Height() += TAB_OFFSET * 2;
2261 return aOptimalSize;
2264 Size TabControl::GetOptimalSize() const
2266 return calculateRequisition();
2269 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */