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 $
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>
38 #include <vcl/svdata.hxx>
40 #include <vcl/svapp.hxx>
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>
56 // =======================================================================
61 USHORT mnTabPageResId
;
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 // -----------------------------------------------------------------------
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 )
113 // -----------------------------------------------------------------------
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
) )
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
);
150 mnLastFirstPagePos
= 0;
152 mbRestoreHelpId
= FALSE
;
153 mbRestoreUnqId
= FALSE
;
154 mbSingleLine
= 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();
181 Font aFont
= rStyleSettings
.GetAppFont();
182 if ( IsControlFont() )
183 aFont
.Merge( GetControlFont() );
184 SetZoomedPointFont( aFont
);
187 if ( bForeground
|| bFont
)
190 if ( IsControlForeground() )
191 aColor
= GetControlForeground();
193 aColor
= rStyleSettings
.GetButtonTextColor();
194 SetTextColor( aColor
);
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
);
213 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
217 EnableChildTransparentMode( FALSE
);
218 SetParentClipMode( 0 );
219 SetPaintTransparent( FALSE
);
221 if ( IsControlBackground() )
222 SetBackground( GetControlBackground() );
224 SetBackground( pParent
->GetBackground() );
228 ImplScrollBtnsColor();
231 // -----------------------------------------------------------------------
233 void TabControl::ImplFreeLayoutData()
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
) )
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();
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
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
)
317 // -----------------------------------------------------------------------
319 void TabControl::ImplScrollBtnsColor()
321 if ( mpTabCtrlData
&& mpTabCtrlData
->mpLeftBtn
)
323 mpTabCtrlData
->mpLeftBtn
->SetControlForeground();
324 mpTabCtrlData
->mpRightBtn
->SetControlForeground();
328 // -----------------------------------------------------------------------
330 void TabControl::ImplSetScrollBtnsState()
334 mpTabCtrlData
->mpLeftBtn
->Enable( mnFirstPagePos
!= 0 );
335 mpTabCtrlData
->mpRightBtn
->Enable( mnFirstPagePos
< mnLastFirstPagePos
);
339 // -----------------------------------------------------------------------
341 void TabControl::ImplPosScrollBtns()
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
);
367 mpTabCtrlData
->mpLeftBtn
->SetPosSizePixel( nX
, nY
, mnBtnSize
, mnBtnSize
);
368 ImplScrollBtnsColor();
369 ImplSetScrollBtnsState();
370 mpTabCtrlData
->mpLeftBtn
->Show();
371 mpTabCtrlData
->mpRightBtn
->Show();
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
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( '.' );
443 if( pItem
->maFormatText
.Len() == 0 )
445 if( aSize
.Height() < aImageSize
.Height()+4 ) //leave space for focus rect
446 aSize
.Height() = aImageSize
.Height()+4;
452 // -----------------------------------------------------------------------
454 Rectangle
TabControl::ImplGetTabRect( USHORT nItemPos
, long nWidth
, long nHeight
)
456 Size aWinSize
= Control::GetOutputSizePixel();
458 nWidth
= aWinSize
.Width();
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
)
472 nLastPos
= GetPagePos( mnCurPageId
);
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 ) );
485 if ( (nWidth
<= 0) || (nHeight
<= 0) )
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
);
505 long nTextWidth2
= GetTextWidth( aTestStr
);
506 mbExtraSpace
= (nTextWidth1
== nTextWidth2
);
509 const long nOffsetX
= 2 + GetItemsOffset().X();
510 const long nOffsetY
= 2 + GetItemsOffset().Y();
513 long nMaxWidth
= nWidth
;
516 if ( (mnMaxPageWidth
> 0) && (mnMaxPageWidth
< nMaxWidth
) )
517 nMaxWidth
= mnMaxPageWidth
;
518 nMaxWidth
-= GetItemsOffset().X();
524 long nLineWidthAry
[100];
525 USHORT nLinePosAry
[101];
527 nLineWidthAry
[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
) )
540 nY
+= aSize
.Height();
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
;
551 it
->mbFullVisible
= TRUE
;
553 nLineWidthAry
[nLines
] += aSize
.Width();
556 if ( it
->mnId
== mnCurPageId
)
562 if ( nLines
&& !mpTabCtrlData
->maItemList
.empty() )
569 long nLineHeightAry
[100];
570 long nIH
= mpTabCtrlData
->maItemList
[0].maRect
.Bottom()-2;
573 while ( i
< nLines
+1 )
576 nLineHeightAry
[i
] = nIH
*(nLines
-(nCurLine
-i
)) + GetItemsOffset().Y();
578 nLineHeightAry
[i
] = nIH
*(i
-nCurLine
-1) + GetItemsOffset().Y();
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
] )
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
);
601 // FIXME: this is a bad case of tabctrl way too small
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
;
617 it
->maRect
.Right()++;
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
;
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
) )
674 aRect
.Right() = Control::GetOutputSizePixel().Width();
682 nPos
= GetPagePos( nOldId
);
683 aRect
= ImplGetTabRect( nPos
);
691 if ( pOldPage
== pPage
)
694 Rectangle aRect
= ImplGetTabRect( TAB_PAGERECT
);
698 if ( mbRestoreHelpId
)
699 pCtrlParent
->SetHelpId( 0 );
700 if ( mbRestoreUnqId
)
701 pCtrlParent
->SetUniqueId( 0 );
702 pOldPage
->DeactivatePage();
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
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() )
727 Window
* pFirstChild
= pPage
->ImplGetDlgWindow( n
, DLGWINDOW_FIRST
);
729 pFirstChild
->ImplControlFocus( GETFOCUS_INIT
);
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
;
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() );
770 // -----------------------------------------------------------------------
772 void TabControl::ImplActivateTabPage( BOOL bNext
)
774 USHORT nCurPos
= GetPagePos( GetCurPageId() );
777 nCurPos
= (nCurPos
+ 1) % GetPageCount();
781 nCurPos
= GetPageCount()-1;
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() )
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
);
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
);
820 if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_MONO
) )
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;
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;
858 // -----------------------------------------------------------------------
860 void TabControl::ImplDrawItem( ImplTabItem
* pItem
, const Rectangle
& rCurRect
, bool bLayout
, bool bFirstInGroup
, bool bLastInGroup
, bool bIsCurrentItem
)
862 if ( pItem
->maRect
.IsEmpty() )
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
;
883 BOOL bNativeOK
= FALSE
;
888 if ( !(rStyleSettings
.GetOptions() & STYLE_OPTION_MONO
) )
893 // Wenn wir die aktuelle Page sind, muessen wir etwas mehr zeichnen
894 if ( pItem
->mnId
== mnCurPageId
)
897 if( ! ImplGetSVData()->maNWFData
.mbNoActiveTabTextRaise
)
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
) )
909 aRightTestPos
.X() += 2;
910 if ( rCurRect
.IsInside( aRightTestPos
) )
911 bRightBorder
= FALSE
;
915 if ( rCurRect
.IsInside( aLeftTestPos
) )
917 if ( rCurRect
.IsInside( aRightTestPos
) )
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
933 nState
|= CTRL_STATE_FOCUSED
;
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
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
;
957 tiValue
.mnAlignment
|= TABITEM_FIRST_IN_GROUP
;
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
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
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 ) );
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
) );
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
) );
1005 DrawLine( Point( aRect
.Right()+nOff2
-1, aRect
.Top()+2-nOff2
),
1006 Point( aRect
.Right()+nOff2
-1, nRightBottom
-1 ) );
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
);
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();
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
);
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
)
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
)
1132 // Draw the TabPage border
1133 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
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() )
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
;
1162 nState
&= ~CTRL_STATE_ENABLED
;
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() );
1179 if ( !(rStyleSettings
.GetOptions() & STYLE_OPTION_MONO
) )
1180 SetLineColor( rStyleSettings
.GetLightColor() );
1182 SetLineColor( Color( COL_BLACK
) );
1183 if ( pCurItem
&& !pCurItem
->maRect
.IsEmpty() )
1185 aCurRect
= pCurItem
->maRect
;
1187 DrawLine( aRect
.TopLeft(), Point( aCurRect
.Left()-2, aRect
.Top() ) );
1188 if ( aCurRect
.Right()+1 < aRect
.Right() )
1191 DrawLine( Point( aCurRect
.Right(), aRect
.Top() ), aRect
.TopRight() );
1198 DrawLine( aRect
.TopLeft(), aRect
.TopRight() );
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
1209 SetLineColor( rStyleSettings
.GetDialogColor() );
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 ) );
1217 SetLineColor( rStyleSettings
.GetDialogColor() );
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() ) );
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
;
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.
1246 pFirstTab
= &mpTabCtrlData
->maItemList
.front();
1247 pLastTab
= &mpTabCtrlData
->maItemList
.back();
1248 idx
= mpTabCtrlData
->maItemList
.size()-1;
1252 pLastTab
= &mpTabCtrlData
->maItemList
.back();
1253 pFirstTab
= &mpTabCtrlData
->maItemList
.front();
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
);
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() )
1291 mbSmallInvalidate
= TRUE
;
1294 // -----------------------------------------------------------------------
1296 void TabControl::Resize()
1298 ImplFreeLayoutData();
1300 if ( !IsReallyShown() )
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();
1311 mbSmallInvalidate
= FALSE
;
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
;
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
;
1334 Invalidate( aRect
, INVALIDATE_NOCHILDREN
);
1336 Invalidate( aRect
);
1342 Invalidate( INVALIDATE_NOCHILDREN
);
1348 // -----------------------------------------------------------------------
1350 void TabControl::GetFocus()
1353 SetInputContext( InputContext( GetFont() ) );
1354 Control::GetFocus();
1357 // -----------------------------------------------------------------------
1359 void TabControl::LoseFocus()
1362 Control::LoseFocus();
1365 // -----------------------------------------------------------------------
1367 void TabControl::RequestHelp( const HelpEvent
& rHEvt
)
1369 USHORT nItemId
= rHEvt
.KeyboardActivated() ? mnCurPageId
: GetPageId( ScreenToOutputPixel( rHEvt
.GetMousePosPixel() ) );
1373 if ( rHEvt
.GetMode() & HELPMODE_BALLOON
)
1375 XubString aStr
= GetHelpText( nItemId
);
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
);
1389 else if ( rHEvt
.GetMode() & HELPMODE_EXTENDED
)
1391 ULONG nHelpId
= GetHelpId( nItemId
);
1394 // Wenn eine Hilfe existiert, dann ausloesen
1395 Help
* pHelp
= Application::GetHelp();
1397 pHelp
->Start( nHelpId
, this );
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();
1419 if ( rHEvt
.GetMode() & HELPMODE_BALLOON
)
1420 Help::ShowBalloon( this, aItemRect
.Center(), aItemRect
, rStr
);
1422 Help::ShowQuickHelp( this, aItemRect
, rStr
);
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
);
1448 Control::RequestHelp( rHEvt
);
1451 // -----------------------------------------------------------------------
1453 void TabControl::Command( const CommandEvent
& rCEvt
)
1455 if ( (rCEvt
.GetCommand() == COMMAND_CONTEXTMENU
) && (GetPageCount() > 1) )
1459 if ( rCEvt
.IsMouseEvent() )
1461 aMenuPos
= rCEvt
.GetMousePosPixel();
1462 bMenu
= GetPageId( aMenuPos
) != 0;
1466 aMenuPos
= ImplGetTabRect( GetPagePos( mnCurPageId
) ).Center();
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
);
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() )
1505 else if ( (nType
== STATE_CHANGE_ZOOM
) ||
1506 (nType
== STATE_CHANGE_CONTROLFONT
) )
1508 ImplInitSettings( TRUE
, FALSE
, FALSE
);
1511 else if ( nType
== STATE_CHANGE_CONTROLFOREGROUND
)
1513 ImplInitSettings( FALSE
, TRUE
, FALSE
);
1516 else if ( nType
== STATE_CHANGE_CONTROLBACKGROUND
)
1518 ImplInitSettings( FALSE
, FALSE
, TRUE
);
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
);
1539 // -----------------------------------------------------------------------
1541 Rectangle
* TabControl::ImplFindPartRect( const Point
& rPt
)
1543 ImplTabItem
* pFoundItem
= NULL
;
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
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
)
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()) )
1578 // allow for slightly bigger tabitems
1580 // TODO: query for the correct sizes
1581 Rectangle
aRect(*pLastRect
);
1585 aClipRgn
.Union( aRect
);
1589 // allow for slightly bigger tabitems
1591 // TODO: query for the correct sizes
1592 Rectangle
aRect(*pRect
);
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
);
1630 if ( (nKeyCode
== KEY_TAB
) || (nKeyCode
== KEY_PAGEDOWN
) )
1632 ImplActivateTabPage( 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 );
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();
1691 if ( nObjMask
& RSC_TABCONTROLITEM_ID
)
1692 nItemId
= sal::static_int_cast
<USHORT
>(ReadLongRes());
1696 if( nObjMask
& RSC_TABCONTROLITEM_TEXT
)
1697 aTmpStr
= ReadStringRes();
1698 InsertPage( nItemId
, aTmpStr
, nPos
);
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
,
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
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();
1730 std::vector
< ImplTabItem
>::iterator new_it
=
1731 mpTabCtrlData
->maItemList
.insert( mpTabCtrlData
->maItemList
.begin() + nPos
, ImplTabItem() );
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
;
1744 if ( IsUpdateMode() )
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
)
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
)
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
);
1786 if ( IsUpdateMode() )
1789 ImplFreeLayoutData();
1791 ImplCallEventListeners( VCLEVENT_TABPAGE_REMOVED
, (void*) (ULONG
) nPageId
);
1795 // -----------------------------------------------------------------------
1797 void TabControl::Clear()
1800 mpTabCtrlData
->maItemList
.clear();
1803 ImplFreeLayoutData();
1806 if ( IsUpdateMode() )
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
;
1822 if( pItem
->mnId
== mnCurPageId
)
1824 // SetCurPageId will change to an enabled page
1825 SetCurPageId( mnCurPageId
);
1827 else if ( IsUpdateMode() )
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
;
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
;
1875 // -----------------------------------------------------------------------
1877 void TabControl::SetCurPageId( USHORT nPageId
)
1879 USHORT nPos
= GetPagePos( nPageId
);
1880 while( nPos
!= TAB_PAGE_NOTFOUND
&&
1881 ! mpTabCtrlData
->maItemList
[nPos
].mbEnabled
)
1884 if( size_t(nPos
) >= mpTabCtrlData
->maItemList
.size() )
1886 if( mpTabCtrlData
->maItemList
[nPos
].mnId
== nPageId
)
1890 if( nPos
!= TAB_PAGE_NOTFOUND
)
1892 nPageId
= mpTabCtrlData
->maItemList
[nPos
].mnId
;
1893 if ( nPageId
== mnCurPageId
)
1896 mnActPageId
= nPageId
;
1901 mnActPageId
= nPageId
;
1905 USHORT nOldId
= mnCurPageId
;
1906 mnCurPageId
= nPageId
;
1907 ImplChangeTabPage( nPageId
, nOldId
);
1912 // -----------------------------------------------------------------------
1914 USHORT
TabControl::GetCurPageId() const
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
;
1942 // Page koennte im Activate-Handler umgeschaltet wurden sein
1943 nPageId
= mnActPageId
;
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
) )
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 );
1972 pItem
->mpTabPage
= NULL
;
1976 // -----------------------------------------------------------------------
1978 TabPage
* TabControl::GetTabPage( USHORT nPageId
) const
1980 ImplTabItem
* pItem
= ImplGetItem( nPageId
);
1983 return pItem
->mpTabPage
;
1988 // -----------------------------------------------------------------------
1990 USHORT
TabControl::GetTabPageResId( USHORT nPageId
) const
1992 ImplTabItem
* pItem
= ImplGetItem( nPageId
);
1995 return pItem
->mnTabPageResId
;
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
;
2010 if ( IsUpdateMode() )
2012 ImplFreeLayoutData();
2013 ImplCallEventListeners( VCLEVENT_TABPAGE_PAGETEXTCHANGED
, (void*) (ULONG
) nPageId
);
2017 // -----------------------------------------------------------------------
2019 XubString
TabControl::GetPageText( USHORT nPageId
) const
2021 ImplTabItem
* pItem
= ImplGetItem( nPageId
);
2024 return pItem
->maText
;
2026 return ImplGetSVEmptyStr();
2029 // -----------------------------------------------------------------------
2031 void TabControl::SetHelpText( USHORT nPageId
, const XubString
& rText
)
2033 ImplTabItem
* pItem
= ImplGetItem( nPageId
);
2036 pItem
->maHelpText
= rText
;
2039 // -----------------------------------------------------------------------
2041 const XubString
& TabControl::GetHelpText( USHORT nPageId
) const
2043 ImplTabItem
* pItem
= ImplGetItem( nPageId
);
2047 if ( !pItem
->maHelpText
.Len() && pItem
->mnHelpId
)
2049 Help
* pHelp
= Application::GetHelp();
2051 pItem
->maHelpText
= pHelp
->GetHelpText( pItem
->mnHelpId
, this );
2054 return pItem
->maHelpText
;
2057 return ImplGetSVEmptyStr();
2060 // -----------------------------------------------------------------------
2062 void TabControl::SetHelpId( USHORT nPageId
, ULONG nHelpId
)
2064 ImplTabItem
* pItem
= ImplGetItem( nPageId
);
2067 pItem
->mnHelpId
= nHelpId
;
2070 // -----------------------------------------------------------------------
2072 ULONG
TabControl::GetHelpId( USHORT nPageId
) const
2074 ImplTabItem
* pItem
= ImplGetItem( nPageId
);
2077 return pItem
->mnHelpId
;
2082 // -----------------------------------------------------------------------
2084 void TabControl::SetPageImage( USHORT i_nPageId
, const Image
& i_rImage
)
2086 ImplTabItem
* pItem
= ImplGetItem( i_nPageId
);
2090 pItem
->maTabImage
= i_rImage
;
2092 if ( IsUpdateMode() )
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
2111 if( ! mpLayoutData
|| ! mpTabCtrlData
->maLayoutPageIdToLine
.size() )
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
);
2128 // -----------------------------------------------------------------------
2130 long TabControl::GetIndexForPoint( const Point
& rPoint
, USHORT
& rPageId
) const
2134 if( ! mpLayoutData
|| ! mpTabCtrlData
->maLayoutPageIdToLine
.size() )
2139 int nIndex
= mpLayoutData
->GetIndexForPoint( rPoint
);
2142 // what line (->pageid) is this index in ?
2143 int nLines
= mpLayoutData
->GetLineCount();
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
];
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
2176 if( ! mpLayoutData
|| ! mpTabCtrlData
->maLayoutPageIdToLine
.size() )
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
) );
2195 // -----------------------------------------------------------------------
2197 Rectangle
TabControl::GetTabBounds( USHORT nPageId
) const
2201 ImplTabItem
* pItem
= ImplGetItem( nPageId
);
2203 aRet
= pItem
->maRect
;
2208 // -----------------------------------------------------------------------
2210 void TabControl::SetItemsOffset( const Point
& rOffs
)
2213 mpTabCtrlData
->maItemsOffset
= rOffs
;
2216 Point
TabControl::GetItemsOffset() const
2219 return mpTabCtrlData
->maItemsOffset
;
2224 // -----------------------------------------------------------------------