Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "tools/debug.hxx"
21 : #include "tools/rc.h"
22 :
23 : #include "vcl/svapp.hxx"
24 : #include "vcl/help.hxx"
25 : #include "vcl/event.hxx"
26 : #include "vcl/menu.hxx"
27 : #include "vcl/button.hxx"
28 : #include "vcl/tabpage.hxx"
29 : #include "vcl/tabctrl.hxx"
30 : #include "vcl/controllayout.hxx"
31 : #include "vcl/layout.hxx"
32 : #include "vcl/lstbox.hxx"
33 : #include "vcl/settings.hxx"
34 :
35 : #include "controldata.hxx"
36 : #include "svdata.hxx"
37 : #include "window.h"
38 :
39 : #include <unordered_map>
40 : #include <vector>
41 :
42 1189 : struct ImplTabItem
43 : {
44 : sal_uInt16 mnId;
45 : VclPtr<TabPage> mpTabPage;
46 : OUString maText;
47 : OUString maFormatText;
48 : OUString maHelpText;
49 : OString maHelpId;
50 : OString maTabName;
51 : Rectangle maRect;
52 : sal_uInt16 mnLine;
53 : bool mbFullVisible;
54 : bool mbEnabled;
55 : Image maTabImage;
56 :
57 205 : ImplTabItem()
58 : : mnId( 0 ), mpTabPage( NULL ),
59 205 : mnLine( 0 ), mbFullVisible( false ), mbEnabled( true )
60 205 : {}
61 : };
62 :
63 88 : struct ImplTabCtrlData
64 : {
65 : std::unordered_map< int, int > maLayoutPageIdToLine;
66 : std::unordered_map< int, int > maLayoutLineToPageId;
67 : std::vector< Rectangle > maTabRectangles;
68 : Point maItemsOffset; // offset of the tabitems
69 : std::vector< ImplTabItem > maItemList;
70 : VclPtr<ListBox> mpListBox;
71 : };
72 :
73 : // for the Tab positions
74 : #define TAB_PAGERECT 0xFFFF
75 :
76 44 : void TabControl::ImplInit( vcl::Window* pParent, WinBits nStyle )
77 : {
78 44 : mbLayoutDirty = true;
79 :
80 44 : if ( !(nStyle & WB_NOTABSTOP) )
81 44 : nStyle |= WB_TABSTOP;
82 44 : if ( !(nStyle & WB_NOGROUP) )
83 44 : nStyle |= WB_GROUP;
84 44 : if ( !(nStyle & WB_NODIALOGCONTROL) )
85 44 : nStyle |= WB_DIALOGCONTROL;
86 :
87 44 : Control::ImplInit( pParent, nStyle, NULL );
88 :
89 44 : mnLastWidth = 0;
90 44 : mnLastHeight = 0;
91 44 : mnBtnSize = 0;
92 44 : mnMaxPageWidth = 0;
93 44 : mnActPageId = 0;
94 44 : mnCurPageId = 0;
95 44 : mbFormat = true;
96 44 : mbRestoreHelpId = false;
97 44 : mbRestoreUnqId = false;
98 44 : mbSmallInvalidate = false;
99 44 : mpTabCtrlData = new ImplTabCtrlData;
100 44 : mpTabCtrlData->mpListBox = NULL;
101 :
102 44 : ImplInitSettings( true, true, true );
103 :
104 44 : if( (nStyle & WB_DROPDOWN) )
105 : {
106 0 : mpTabCtrlData->mpListBox = VclPtr<ListBox>::Create( this, WB_DROPDOWN );
107 0 : mpTabCtrlData->mpListBox->SetPosSizePixel( Point( 0, 0 ), Size( 200, 20 ) );
108 0 : mpTabCtrlData->mpListBox->SetSelectHdl( LINK( this, TabControl, ImplListBoxSelectHdl ) );
109 0 : mpTabCtrlData->mpListBox->Show();
110 : }
111 :
112 : // if the tabcontrol is drawn (ie filled) by a native widget, make sure all contols will have transparent background
113 : // otherwise they will paint with a wrong background
114 44 : if( IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL) )
115 0 : EnableChildTransparentMode( true );
116 :
117 44 : if (pParent && pParent->IsDialog())
118 0 : pParent->AddChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
119 44 : }
120 :
121 67 : const vcl::Font& TabControl::GetCanonicalFont( const StyleSettings& _rStyle ) const
122 : {
123 67 : return _rStyle.GetTabFont();
124 : }
125 :
126 67 : const Color& TabControl::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
127 : {
128 67 : return _rStyle.GetTabTextColor();
129 : }
130 :
131 46 : void TabControl::ImplInitSettings( bool bFont,
132 : bool bForeground, bool bBackground )
133 : {
134 46 : Control::ImplInitSettings( bFont, bForeground );
135 :
136 46 : if ( bBackground )
137 : {
138 46 : vcl::Window* pParent = GetParent();
139 92 : if ( !IsControlBackground() &&
140 46 : (pParent->IsChildTransparentModeEnabled()
141 46 : || IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL)
142 46 : || IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) ) )
143 :
144 : {
145 : // set transparent mode for NWF tabcontrols to have
146 : // the background always cleared properly
147 0 : EnableChildTransparentMode( true );
148 0 : SetParentClipMode( ParentClipMode::NoClip );
149 0 : SetPaintTransparent( true );
150 0 : SetBackground();
151 0 : ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
152 : }
153 : else
154 : {
155 46 : EnableChildTransparentMode( false );
156 46 : SetParentClipMode( ParentClipMode::NONE );
157 46 : SetPaintTransparent( false );
158 :
159 46 : if ( IsControlBackground() )
160 0 : SetBackground( GetControlBackground() );
161 : else
162 46 : SetBackground( pParent->GetBackground() );
163 : }
164 : }
165 46 : }
166 :
167 836 : void TabControl::ImplFreeLayoutData()
168 : {
169 836 : if( HasLayoutData() )
170 : {
171 0 : ImplClearLayoutData();
172 0 : mpTabCtrlData->maLayoutPageIdToLine.clear();
173 0 : mpTabCtrlData->maLayoutLineToPageId.clear();
174 : }
175 836 : }
176 :
177 44 : TabControl::TabControl( vcl::Window* pParent, WinBits nStyle ) :
178 44 : Control( WINDOW_TABCONTROL )
179 : {
180 44 : ImplInit( pParent, nStyle );
181 : OSL_TRACE("*** TABCONTROL no notabs? %s", ( GetStyle() & WB_NOBORDER ) ? "true" : "false" );
182 44 : }
183 :
184 90 : TabControl::~TabControl()
185 : {
186 44 : disposeOnce();
187 46 : }
188 :
189 44 : void TabControl::dispose()
190 : {
191 44 : Window *pParent = GetParent();
192 44 : if (pParent && pParent->IsDialog())
193 0 : GetParent()->RemoveChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
194 :
195 44 : ImplFreeLayoutData();
196 :
197 : // delete TabCtrl data
198 44 : if (mpTabCtrlData)
199 44 : mpTabCtrlData->mpListBox.disposeAndClear();
200 44 : delete mpTabCtrlData;
201 44 : mpTabCtrlData = NULL;
202 44 : Control::dispose();
203 44 : }
204 :
205 2758 : ImplTabItem* TabControl::ImplGetItem( sal_uInt16 nId ) const
206 : {
207 17478 : for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
208 11652 : it != mpTabCtrlData->maItemList.end(); ++it )
209 : {
210 5744 : if( it->mnId == nId )
211 2676 : return &(*it);
212 : }
213 :
214 82 : return NULL;
215 : }
216 :
217 2692 : Size TabControl::ImplGetItemSize( ImplTabItem* pItem, long nMaxWidth )
218 : {
219 2692 : pItem->maFormatText = pItem->maText;
220 2692 : Size aSize( GetCtrlTextWidth( pItem->maFormatText ), GetTextHeight() );
221 2692 : Size aImageSize( 0, 0 );
222 2692 : if( !!pItem->maTabImage )
223 : {
224 0 : aImageSize = pItem->maTabImage.GetSizePixel();
225 0 : if( !pItem->maFormatText.isEmpty() )
226 0 : aImageSize.Width() += GetTextHeight()/4;
227 : }
228 2692 : aSize.Width() += aImageSize.Width();
229 2692 : if( aImageSize.Height() > aSize.Height() )
230 0 : aSize.Height() = aImageSize.Height();
231 :
232 2692 : aSize.Width() += TAB_TABOFFSET_X*2;
233 2692 : aSize.Height() += TAB_TABOFFSET_Y*2;
234 :
235 2692 : Rectangle aCtrlRegion( Point( 0, 0 ), aSize );
236 2692 : Rectangle aBoundingRgn, aContentRgn;
237 : const TabitemValue aControlValue(Rectangle(TAB_TABOFFSET_X, TAB_TABOFFSET_Y,
238 2692 : aSize.Width() - TAB_TABOFFSET_X * 2,
239 5384 : aSize.Height() - TAB_TABOFFSET_Y * 2));
240 5384 : if(GetNativeControlRegion( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion,
241 : ControlState::ENABLED, aControlValue, OUString(),
242 5384 : aBoundingRgn, aContentRgn ) )
243 : {
244 0 : return aContentRgn.GetSize();
245 : }
246 :
247 : // For languages with short names (e.g. Chinese), because the space is
248 : // normally only one pixel per char
249 2692 : if ( pItem->maFormatText.getLength() < TAB_EXTRASPACE_X )
250 522 : aSize.Width() += TAB_EXTRASPACE_X-pItem->maFormatText.getLength();
251 :
252 : // shorten Text if needed
253 2692 : if ( aSize.Width()+4 >= nMaxWidth )
254 : {
255 152 : OUString aAppendStr("...");
256 152 : pItem->maFormatText += aAppendStr;
257 1010 : do
258 : {
259 1010 : pItem->maFormatText = pItem->maFormatText.replaceAt( pItem->maFormatText.getLength()-aAppendStr.getLength()-1, 1, "" );
260 1010 : aSize.Width() = GetCtrlTextWidth( pItem->maFormatText );
261 1010 : aSize.Width() += aImageSize.Width();
262 1010 : aSize.Width() += TAB_TABOFFSET_X*2;
263 : }
264 1010 : while ( (aSize.Width()+4 >= nMaxWidth) && (pItem->maFormatText.getLength() > aAppendStr.getLength()) );
265 152 : if ( aSize.Width()+4 >= nMaxWidth )
266 : {
267 152 : pItem->maFormatText = ".";
268 152 : aSize.Width() = 1;
269 152 : }
270 : }
271 :
272 2692 : if( pItem->maFormatText.isEmpty() )
273 : {
274 0 : if( aSize.Height() < aImageSize.Height()+4 ) //leave space for focus rect
275 0 : aSize.Height() = aImageSize.Height()+4;
276 : }
277 :
278 2692 : return aSize;
279 : }
280 :
281 : // Feel free to move this to some more general place for reuse
282 : // http://en.wikipedia.org/wiki/Word_wrap#Minimum_raggedness
283 : // Mostly based on Alexey Frunze's nifty example at
284 : // http://stackoverflow.com/questions/9071205/balanced-word-wrap-minimum-raggedness-in-php
285 : namespace MinimumRaggednessWrap
286 : {
287 302 : std::deque<size_t> GetEndOfLineIndexes(const std::vector<sal_Int32>& rWidthsOf, sal_Int32 nLineWidth)
288 : {
289 302 : ++nLineWidth;
290 :
291 302 : size_t nWidthsCount = rWidthsOf.size();
292 302 : std::vector<sal_Int32> aCosts(nWidthsCount * nWidthsCount);
293 :
294 : // cost function c(i, j) that computes the cost of a line consisting of
295 : // the words Word[i] to Word[j]
296 1648 : for (size_t i = 0; i < nWidthsCount; ++i)
297 : {
298 7912 : for (size_t j = 0; j < nWidthsCount; ++j)
299 : {
300 6566 : if (j >= i)
301 : {
302 3956 : sal_Int32 c = nLineWidth - (j - i);
303 13132 : for (size_t k = i; k <= j; ++k)
304 9176 : c -= rWidthsOf[k];
305 3956 : c = (c >= 0) ? c * c : SAL_MAX_INT32;
306 3956 : aCosts[j * nWidthsCount + i] = c;
307 : }
308 : else
309 : {
310 2610 : aCosts[j * nWidthsCount + i] = SAL_MAX_INT32;
311 : }
312 : }
313 : }
314 :
315 604 : std::vector<sal_Int32> aFunction(nWidthsCount);
316 604 : std::vector<sal_Int32> aWrapPoints(nWidthsCount);
317 :
318 : // f(j) in aFunction[], collect wrap points in aWrapPoints[]
319 1648 : for (size_t j = 0; j < nWidthsCount; ++j)
320 : {
321 1346 : aFunction[j] = aCosts[j * nWidthsCount];
322 1346 : if (aFunction[j] == SAL_MAX_INT32)
323 : {
324 146 : for (size_t k = 0; k < j; ++k)
325 : {
326 : sal_Int32 s;
327 70 : if (aFunction[k] == SAL_MAX_INT32 || aCosts[j * nWidthsCount + k + 1] == SAL_MAX_INT32)
328 70 : s = SAL_MAX_INT32;
329 : else
330 0 : s = aFunction[k] + aCosts[j * nWidthsCount + k + 1];
331 70 : if (aFunction[j] > s)
332 : {
333 0 : aFunction[j] = s;
334 0 : aWrapPoints[j] = k + 1;
335 : }
336 : }
337 : }
338 : }
339 :
340 302 : std::deque<size_t> aSolution;
341 :
342 : // no solution
343 302 : if (aFunction[nWidthsCount - 1] == SAL_MAX_INT32)
344 48 : return aSolution;
345 :
346 : // optimal solution
347 254 : size_t j = nWidthsCount - 1;
348 : while (true)
349 : {
350 254 : aSolution.push_front(j);
351 254 : if (!aWrapPoints[j])
352 254 : break;
353 0 : j = aWrapPoints[j] - 1;
354 : }
355 :
356 556 : return aSolution;
357 : }
358 : };
359 :
360 812 : Rectangle TabControl::ImplGetTabRect( sal_uInt16 nItemPos, long nWidth, long nHeight )
361 : {
362 812 : Size aWinSize = Control::GetOutputSizePixel();
363 812 : if ( nWidth < 0 )
364 371 : nWidth = aWinSize.Width();
365 812 : if ( nHeight < 0 )
366 371 : nHeight = aWinSize.Height();
367 :
368 812 : if ( mpTabCtrlData->maItemList.empty() )
369 : {
370 0 : long nW = nWidth-TAB_OFFSET*2;
371 0 : long nH = nHeight-TAB_OFFSET*2;
372 0 : return (nW > 0 && nH > 0)
373 : ? Rectangle( Point( TAB_OFFSET, TAB_OFFSET ), Size( nW, nH ) )
374 0 : : Rectangle();
375 : }
376 :
377 812 : if ( nItemPos == TAB_PAGERECT )
378 : {
379 : sal_uInt16 nLastPos;
380 400 : if ( mnCurPageId )
381 400 : nLastPos = GetPagePos( mnCurPageId );
382 : else
383 0 : nLastPos = 0;
384 :
385 400 : Rectangle aRect = ImplGetTabRect( nLastPos, nWidth, nHeight );
386 400 : long nW = nWidth-TAB_OFFSET*2;
387 400 : long nH = nHeight-aRect.Bottom()-TAB_OFFSET*2;
388 293 : aRect = (nW > 0 && nH > 0)
389 128 : ? Rectangle( Point( TAB_OFFSET, aRect.Bottom()+TAB_OFFSET ), Size( nW, nH ) )
390 656 : : Rectangle();
391 400 : return aRect;
392 : }
393 :
394 412 : nWidth -= 1;
395 :
396 412 : if ( (nWidth <= 0) || (nHeight <= 0) )
397 59 : return Rectangle();
398 :
399 353 : if ( mbFormat || (mnLastWidth != nWidth) || (mnLastHeight != nHeight) )
400 : {
401 302 : vcl::Font aFont( GetFont() );
402 302 : aFont.SetTransparent( true );
403 302 : SetFont( aFont );
404 :
405 302 : Size aSize;
406 302 : const long nOffsetX = 2 + GetItemsOffset().X();
407 302 : const long nOffsetY = 2 + GetItemsOffset().Y();
408 302 : long nX = nOffsetX;
409 302 : long nY = nOffsetY;
410 302 : long nMaxWidth = nWidth;
411 302 : sal_uInt16 nPos = 0;
412 :
413 : //fdo#66435 throw Knuth/Tex minimum raggedness algorithm at the problem
414 : //of ugly bare tabs on lines of their own
415 :
416 : //collect widths
417 604 : std::vector<sal_Int32> aWidths;
418 4944 : for( std::vector<ImplTabItem>::iterator it = mpTabCtrlData->maItemList.begin();
419 3296 : it != mpTabCtrlData->maItemList.end(); ++it )
420 : {
421 1346 : aWidths.push_back(ImplGetItemSize( &(*it), nMaxWidth ).Width());
422 : }
423 :
424 : //aBreakIndexes will contain the indexes of the last tab on each row
425 604 : std::deque<size_t> aBreakIndexes(MinimumRaggednessWrap::GetEndOfLineIndexes(aWidths, nMaxWidth - nOffsetX - 2));
426 :
427 302 : if ( (mnMaxPageWidth > 0) && (mnMaxPageWidth < nMaxWidth) )
428 0 : nMaxWidth = mnMaxPageWidth;
429 302 : nMaxWidth -= GetItemsOffset().X();
430 :
431 302 : sal_uInt16 nLines = 0;
432 302 : sal_uInt16 nCurLine = 0;
433 : long nLineWidthAry[100];
434 : sal_uInt16 nLinePosAry[101];
435 :
436 302 : nLineWidthAry[0] = 0;
437 302 : nLinePosAry[0] = 0;
438 302 : size_t nIndex = 0;
439 4944 : for( std::vector<ImplTabItem>::iterator it = mpTabCtrlData->maItemList.begin();
440 3296 : it != mpTabCtrlData->maItemList.end(); ++it, ++nIndex )
441 : {
442 1346 : aSize = ImplGetItemSize( &(*it), nMaxWidth );
443 :
444 1346 : bool bNewLine = false;
445 1346 : if (!aBreakIndexes.empty() && nIndex > aBreakIndexes.front())
446 : {
447 0 : aBreakIndexes.pop_front();
448 0 : bNewLine = true;
449 : }
450 :
451 1346 : if ( bNewLine && (nWidth > 2+nOffsetX) )
452 : {
453 0 : if ( nLines == 99 )
454 0 : break;
455 :
456 0 : nX = nOffsetX;
457 0 : nY += aSize.Height();
458 0 : nLines++;
459 0 : nLineWidthAry[nLines] = 0;
460 0 : nLinePosAry[nLines] = nPos;
461 : }
462 :
463 1346 : Rectangle aNewRect( Point( nX, nY ), aSize );
464 1346 : if ( mbSmallInvalidate && (it->maRect != aNewRect) )
465 0 : mbSmallInvalidate = false;
466 1346 : it->maRect = aNewRect;
467 1346 : it->mnLine = nLines;
468 1346 : it->mbFullVisible = true;
469 :
470 1346 : nLineWidthAry[nLines] += aSize.Width();
471 1346 : nX += aSize.Width();
472 :
473 1346 : if ( it->mnId == mnCurPageId )
474 302 : nCurLine = nLines;
475 :
476 1346 : nPos++;
477 : }
478 :
479 302 : if ( nLines && !mpTabCtrlData->maItemList.empty() )
480 : {
481 0 : long nDX = 0;
482 0 : long nModDX = 0;
483 0 : long nIDX = 0;
484 : sal_uInt16 i;
485 : sal_uInt16 n;
486 : long nLineHeightAry[100];
487 0 : long nIH = mpTabCtrlData->maItemList[0].maRect.Bottom()-2;
488 :
489 0 : i = 0;
490 0 : while ( i < nLines+1 )
491 : {
492 0 : if ( i <= nCurLine )
493 0 : nLineHeightAry[i] = nIH*(nLines-(nCurLine-i)) + GetItemsOffset().Y();
494 : else
495 0 : nLineHeightAry[i] = nIH*(i-nCurLine-1) + GetItemsOffset().Y();
496 0 : i++;
497 : }
498 :
499 0 : i = 0;
500 0 : n = 0;
501 0 : nLinePosAry[nLines+1] = (sal_uInt16)mpTabCtrlData->maItemList.size();
502 0 : for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
503 0 : it != mpTabCtrlData->maItemList.end(); ++it )
504 : {
505 0 : if ( i == nLinePosAry[n] )
506 : {
507 0 : if ( n == nLines+1 )
508 0 : break;
509 :
510 0 : nIDX = 0;
511 0 : if( nLinePosAry[n+1]-i > 0 )
512 : {
513 0 : nDX = (nWidth-nOffsetX-nLineWidthAry[n]) / (nLinePosAry[n+1]-i);
514 0 : nModDX = (nWidth-nOffsetX-nLineWidthAry[n]) % (nLinePosAry[n+1]-i);
515 : }
516 : else
517 : {
518 : // FIXME: this is a bad case of tabctrl way too small
519 0 : nDX = 0;
520 0 : nModDX = 0;
521 : }
522 0 : n++;
523 : }
524 :
525 0 : it->maRect.Left() += nIDX;
526 0 : it->maRect.Right() += nIDX+nDX;
527 0 : it->maRect.Top() = nLineHeightAry[n-1];
528 0 : it->maRect.Bottom() = nLineHeightAry[n-1]+nIH;
529 0 : nIDX += nDX;
530 :
531 0 : if ( nModDX )
532 : {
533 0 : nIDX++;
534 0 : it->maRect.Right()++;
535 0 : nModDX--;
536 : }
537 :
538 0 : i++;
539 : }
540 : }
541 : else
542 : {//only one line
543 302 : if(ImplGetSVData()->maNWFData.mbCenteredTabs)
544 : {
545 0 : int nRightSpace=nMaxWidth;//space left on the right by the tabs
546 0 : for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
547 0 : it != mpTabCtrlData->maItemList.end(); ++it )
548 : {
549 0 : nRightSpace-=it->maRect.Right()-it->maRect.Left();
550 : }
551 0 : for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
552 0 : it != mpTabCtrlData->maItemList.end(); ++it )
553 : {
554 0 : it->maRect.Left()+=(int) (nRightSpace/2);
555 0 : it->maRect.Right()+=(int) (nRightSpace/2);
556 : }
557 : }
558 : }
559 :
560 302 : mnLastWidth = nWidth;
561 302 : mnLastHeight = nHeight;
562 604 : mbFormat = false;
563 : }
564 :
565 353 : return size_t(nItemPos) < mpTabCtrlData->maItemList.size() ? mpTabCtrlData->maItemList[nItemPos].maRect : Rectangle();
566 : }
567 :
568 47 : void TabControl::ImplChangeTabPage( sal_uInt16 nId, sal_uInt16 nOldId )
569 : {
570 47 : ImplFreeLayoutData();
571 :
572 47 : ImplTabItem* pOldItem = ImplGetItem( nOldId );
573 47 : ImplTabItem* pItem = ImplGetItem( nId );
574 47 : TabPage* pOldPage = (pOldItem) ? pOldItem->mpTabPage.get() : NULL;
575 47 : TabPage* pPage = (pItem) ? pItem->mpTabPage.get() : NULL;
576 47 : vcl::Window* pCtrlParent = GetParent();
577 :
578 47 : if ( IsReallyVisible() && IsUpdateMode() )
579 : {
580 6 : sal_uInt16 nPos = GetPagePos( nId );
581 6 : Rectangle aRect = ImplGetTabRect( nPos );
582 :
583 6 : if ( !pOldItem || !pItem || (pOldItem->mnLine != pItem->mnLine) )
584 : {
585 0 : aRect.Left() = 0;
586 0 : aRect.Top() = 0;
587 0 : aRect.Right() = Control::GetOutputSizePixel().Width();
588 : }
589 : else
590 : {
591 6 : aRect.Left() -= 3;
592 6 : aRect.Top() -= 2;
593 6 : aRect.Right() += 3;
594 6 : Invalidate( aRect );
595 6 : nPos = GetPagePos( nOldId );
596 6 : aRect = ImplGetTabRect( nPos );
597 6 : aRect.Left() -= 3;
598 6 : aRect.Top() -= 2;
599 6 : aRect.Right() += 3;
600 : }
601 6 : Invalidate( aRect );
602 : }
603 :
604 47 : if ( pOldPage == pPage )
605 53 : return;
606 :
607 41 : Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
608 :
609 41 : if ( pOldPage )
610 : {
611 0 : if ( mbRestoreHelpId )
612 0 : pCtrlParent->SetHelpId( OString() );
613 0 : if ( mbRestoreUnqId )
614 0 : pCtrlParent->SetUniqueId( OString() );
615 0 : pOldPage->DeactivatePage();
616 : }
617 :
618 41 : if ( pPage )
619 : {
620 41 : if ( ( GetStyle() & WB_NOBORDER ) )
621 : {
622 0 : Rectangle aRectNoTab(Point(0, 0), GetSizePixel());
623 0 : pPage->SetPosSizePixel( aRectNoTab.TopLeft(), aRectNoTab.GetSize() );
624 : }
625 : else
626 41 : pPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
627 :
628 : // activate page here so the conbtrols can be switched
629 : // also set the help id of the parent window to that of the tab page
630 41 : if ( GetHelpId().isEmpty() )
631 : {
632 41 : mbRestoreHelpId = true;
633 41 : pCtrlParent->SetHelpId( pPage->GetHelpId() );
634 : }
635 41 : if ( pCtrlParent->GetUniqueId().isEmpty() )
636 : {
637 41 : mbRestoreUnqId = true;
638 41 : pCtrlParent->SetUniqueId( pPage->GetUniqueId() );
639 : }
640 :
641 41 : pPage->ActivatePage();
642 41 : pPage->Show();
643 :
644 41 : if ( pOldPage && pOldPage->HasChildPathFocus() )
645 : {
646 0 : sal_uInt16 n = 0;
647 0 : vcl::Window* pFirstChild = pPage->ImplGetDlgWindow( n, GetDlgWindowType::First );
648 0 : if ( pFirstChild )
649 0 : pFirstChild->ImplControlFocus( GetFocusFlags::Init );
650 : else
651 0 : GrabFocus();
652 : }
653 : }
654 :
655 41 : if ( pOldPage )
656 0 : pOldPage->Hide();
657 :
658 : // Invalidate the same region that will be send to NWF
659 : // to always allow for bitmap caching
660 : // see Window::DrawNativeControl()
661 41 : if( IsNativeControlSupported( CTRL_TAB_PANE, PART_ENTIRE_CONTROL ) )
662 : {
663 0 : aRect.Left() -= TAB_OFFSET;
664 0 : aRect.Top() -= TAB_OFFSET;
665 0 : aRect.Right() += TAB_OFFSET;
666 0 : aRect.Bottom() += TAB_OFFSET;
667 : }
668 :
669 41 : Invalidate( aRect );
670 : }
671 :
672 273 : bool TabControl::ImplPosCurTabPage()
673 : {
674 : // resize/position current TabPage
675 273 : ImplTabItem* pItem = ImplGetItem( GetCurPageId() );
676 273 : if ( pItem && pItem->mpTabPage )
677 : {
678 273 : if ( ( GetStyle() & WB_NOBORDER ) )
679 : {
680 0 : Rectangle aRectNoTab(Point(0, 0), GetSizePixel());
681 0 : pItem->mpTabPage->SetPosSizePixel( aRectNoTab.TopLeft(), aRectNoTab.GetSize() );
682 0 : return true;
683 : }
684 273 : Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
685 273 : pItem->mpTabPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
686 273 : return true;
687 : }
688 :
689 0 : return false;
690 : }
691 :
692 0 : void TabControl::ImplActivateTabPage( bool bNext )
693 : {
694 0 : sal_uInt16 nCurPos = GetPagePos( GetCurPageId() );
695 :
696 0 : if ( bNext )
697 0 : nCurPos = (nCurPos + 1) % GetPageCount();
698 : else
699 : {
700 0 : if ( !nCurPos )
701 0 : nCurPos = GetPageCount()-1;
702 : else
703 0 : nCurPos--;
704 : }
705 :
706 0 : SelectTabPage( GetPageId( nCurPos ) );
707 0 : }
708 :
709 0 : void TabControl::ImplShowFocus()
710 : {
711 0 : if ( !GetPageCount() || mpTabCtrlData->mpListBox )
712 0 : return;
713 :
714 0 : sal_uInt16 nCurPos = GetPagePos( mnCurPageId );
715 0 : Rectangle aRect = ImplGetTabRect( nCurPos );
716 0 : const ImplTabItem& rItem = mpTabCtrlData->maItemList[ nCurPos ];
717 0 : Size aTabSize = aRect.GetSize();
718 0 : Size aImageSize( 0, 0 );
719 0 : long nTextHeight = GetTextHeight();
720 0 : long nTextWidth = GetCtrlTextWidth( rItem.maFormatText );
721 : sal_uInt16 nOff;
722 :
723 0 : if ( !(GetSettings().GetStyleSettings().GetOptions() & StyleSettingsOptions::Mono) )
724 0 : nOff = 1;
725 : else
726 0 : nOff = 0;
727 :
728 0 : if( !! rItem.maTabImage )
729 : {
730 0 : aImageSize = rItem.maTabImage.GetSizePixel();
731 0 : if( !rItem.maFormatText.isEmpty() )
732 0 : aImageSize.Width() += GetTextHeight()/4;
733 : }
734 :
735 0 : if( !rItem.maFormatText.isEmpty() )
736 : {
737 : // show focus around text
738 0 : aRect.Left() = aRect.Left()+aImageSize.Width()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1-1;
739 0 : aRect.Top() = aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-1-1;
740 0 : aRect.Right() = aRect.Left()+nTextWidth+2;
741 0 : aRect.Bottom() = aRect.Top()+nTextHeight+2;
742 : }
743 : else
744 : {
745 : // show focus around image
746 0 : long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1;
747 0 : long nYPos = aRect.Top();
748 0 : if( aImageSize.Height() < aRect.GetHeight() )
749 0 : nYPos += (aRect.GetHeight() - aImageSize.Height())/2;
750 :
751 0 : aRect.Left() = nXPos - 2;
752 0 : aRect.Top() = nYPos - 2;
753 0 : aRect.Right() = aRect.Left() + aImageSize.Width() + 4;
754 0 : aRect.Bottom() = aRect.Top() + aImageSize.Height() + 4;
755 : }
756 0 : ShowFocus( aRect );
757 : }
758 :
759 105 : void TabControl::ImplDrawItem(vcl::RenderContext& rRenderContext, ImplTabItem* pItem, const Rectangle& rCurRect,
760 : bool bLayout, bool bFirstInGroup, bool bLastInGroup, bool /* bIsCurrentItem */ )
761 : {
762 105 : if (pItem->maRect.IsEmpty())
763 105 : return;
764 :
765 105 : if (bLayout)
766 : {
767 0 : if (!HasLayoutData())
768 : {
769 0 : mpControlData->mpLayoutData = new vcl::ControlLayoutData();
770 0 : mpTabCtrlData->maLayoutLineToPageId.clear();
771 0 : mpTabCtrlData->maLayoutPageIdToLine.clear();
772 0 : mpTabCtrlData->maTabRectangles.clear();
773 : }
774 : }
775 :
776 105 : const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
777 105 : Rectangle aRect = pItem->maRect;
778 105 : long nLeftBottom = aRect.Bottom();
779 105 : long nRightBottom = aRect.Bottom();
780 105 : bool bLeftBorder = true;
781 105 : bool bRightBorder = true;
782 : sal_uInt16 nOff;
783 105 : bool bNativeOK = false;
784 :
785 105 : sal_uInt16 nOff2 = 0;
786 105 : sal_uInt16 nOff3 = 0;
787 :
788 105 : if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
789 105 : nOff = 1;
790 : else
791 0 : nOff = 0;
792 :
793 : // if this is the active Page, we have to draw a little more
794 105 : if (pItem->mnId == mnCurPageId)
795 : {
796 21 : nOff2 = 2;
797 21 : if (!ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise)
798 21 : nOff3 = 1;
799 : }
800 : else
801 : {
802 84 : Point aLeftTestPos = aRect.BottomLeft();
803 84 : Point aRightTestPos = aRect.BottomRight();
804 84 : if (aLeftTestPos.Y() == rCurRect.Bottom())
805 : {
806 84 : aLeftTestPos.X() -= 2;
807 84 : if (rCurRect.IsInside(aLeftTestPos))
808 21 : bLeftBorder = false;
809 84 : aRightTestPos.X() += 2;
810 84 : if (rCurRect.IsInside(aRightTestPos))
811 0 : bRightBorder = false;
812 : }
813 : else
814 : {
815 0 : if (rCurRect.IsInside(aLeftTestPos))
816 0 : nLeftBottom -= 2;
817 0 : if (rCurRect.IsInside(aRightTestPos))
818 0 : nRightBottom -= 2;
819 : }
820 : }
821 :
822 105 : ControlState nState = ControlState::NONE;
823 :
824 105 : if (pItem->mnId == mnCurPageId)
825 : {
826 21 : nState |= ControlState::SELECTED;
827 : // only the selected item can be focussed
828 21 : if (HasFocus())
829 0 : nState |= ControlState::FOCUSED;
830 : }
831 105 : if (IsEnabled())
832 105 : nState |= ControlState::ENABLED;
833 105 : if (IsMouseOver() && pItem->maRect.IsInside(GetPointerPosPixel()))
834 : {
835 0 : nState |= ControlState::ROLLOVER;
836 0 : for (std::vector<ImplTabItem>::iterator it = mpTabCtrlData->maItemList.begin();
837 0 : it != mpTabCtrlData->maItemList.end(); ++it)
838 : {
839 0 : if( (&(*it) != pItem) && (it->maRect.IsInside(GetPointerPosPixel())))
840 : {
841 0 : nState &= ~ControlState::ROLLOVER; // avoid multiple highlighted tabs
842 0 : break;
843 : }
844 : }
845 : }
846 :
847 105 : if (!bLayout && (bNativeOK = rRenderContext.IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL)))
848 : {
849 0 : TabitemValue tiValue(Rectangle(pItem->maRect.Left() + TAB_TABOFFSET_X,
850 0 : pItem->maRect.Right() - TAB_TABOFFSET_X,
851 0 : pItem->maRect.Top() + TAB_TABOFFSET_Y,
852 0 : pItem->maRect.Bottom() - TAB_TABOFFSET_Y));
853 0 : if (pItem->maRect.Left() < 5)
854 0 : tiValue.mnAlignment |= TabitemFlags::LeftAligned;
855 0 : if (pItem->maRect.Right() > mnLastWidth - 5)
856 0 : tiValue.mnAlignment |= TabitemFlags::RightAligned;
857 0 : if (bFirstInGroup)
858 0 : tiValue.mnAlignment |= TabitemFlags::FirstInGroup;
859 0 : if (bLastInGroup)
860 0 : tiValue.mnAlignment |= TabitemFlags::LastInGroup;
861 :
862 0 : Rectangle aCtrlRegion( pItem->maRect );
863 : bNativeOK = rRenderContext.DrawNativeControl(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL,
864 0 : aCtrlRegion, nState, tiValue, OUString() );
865 : }
866 :
867 105 : if (!bLayout && !bNativeOK)
868 : {
869 105 : if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
870 : {
871 105 : rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
872 105 : rRenderContext.DrawPixel(Point(aRect.Left() + 1 - nOff2, aRect.Top() + 1 - nOff2)); // diagonally indented top-left pixel
873 105 : if (bLeftBorder)
874 : {
875 168 : rRenderContext.DrawLine(Point(aRect.Left() - nOff2, aRect.Top() + 2 - nOff2),
876 252 : Point(aRect.Left() - nOff2, nLeftBottom - 1));
877 : }
878 210 : rRenderContext.DrawLine(Point(aRect.Left() + 2 - nOff2, aRect.Top() - nOff2), // top line starting 2px from left border
879 315 : Point(aRect.Right() + nOff2 - 3, aRect.Top() - nOff2)); // ending 3px from right border
880 :
881 105 : if (bRightBorder)
882 : {
883 105 : rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
884 210 : rRenderContext.DrawLine(Point(aRect.Right() + nOff2 - 2, aRect.Top() + 1 - nOff2),
885 315 : Point(aRect.Right() + nOff2 - 2, nRightBottom - 1));
886 :
887 105 : rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
888 210 : rRenderContext.DrawLine(Point(aRect.Right() + nOff2 - 1, aRect.Top() + 3 - nOff2),
889 315 : Point(aRect.Right() + nOff2 - 1, nRightBottom - 1));
890 : }
891 : }
892 : else
893 : {
894 0 : rRenderContext.SetLineColor(Color(COL_BLACK));
895 0 : rRenderContext.DrawPixel(Point(aRect.Left() + 1 - nOff2, aRect.Top() + 1 - nOff2));
896 0 : rRenderContext.DrawPixel(Point(aRect.Right() + nOff2 - 2, aRect.Top() + 1 - nOff2));
897 0 : if (bLeftBorder)
898 : {
899 0 : rRenderContext.DrawLine(Point(aRect.Left() - nOff2, aRect.Top() + 2 - nOff2),
900 0 : Point(aRect.Left() - nOff2, nLeftBottom - 1));
901 : }
902 0 : rRenderContext.DrawLine(Point(aRect.Left() + 2 - nOff2, aRect.Top() - nOff2),
903 0 : Point(aRect.Right() - 3, aRect.Top() - nOff2));
904 0 : if (bRightBorder)
905 : {
906 0 : rRenderContext.DrawLine(Point(aRect.Right() + nOff2 - 1, aRect.Top() + 2 - nOff2),
907 0 : Point(aRect.Right() + nOff2 - 1, nRightBottom - 1));
908 : }
909 : }
910 : }
911 :
912 105 : if (bLayout)
913 : {
914 0 : int nLine = mpControlData->mpLayoutData->m_aLineIndices.size();
915 0 : mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.getLength() );
916 0 : mpTabCtrlData->maLayoutPageIdToLine[ (int)pItem->mnId ] = nLine;
917 0 : mpTabCtrlData->maLayoutLineToPageId[ nLine ] = (int)pItem->mnId;
918 0 : mpTabCtrlData->maTabRectangles.push_back( aRect );
919 : }
920 :
921 : // set font accordingly, current item is painted bold
922 : // we set the font attributes always before drawing to be re-entrant (DrawNativeControl may trigger additional paints)
923 105 : vcl::Font aFont(rRenderContext.GetFont());
924 105 : aFont.SetTransparent(true);
925 105 : rRenderContext.SetFont(aFont);
926 :
927 105 : Size aTabSize = aRect.GetSize();
928 105 : Size aImageSize(0, 0);
929 105 : long nTextHeight = rRenderContext.GetTextHeight();
930 105 : long nTextWidth = rRenderContext.GetCtrlTextWidth(pItem->maFormatText);
931 105 : if (!!pItem->maTabImage)
932 : {
933 0 : aImageSize = pItem->maTabImage.GetSizePixel();
934 0 : if (!pItem->maFormatText.isEmpty())
935 0 : aImageSize.Width() += GetTextHeight() / 4;
936 : }
937 105 : long nXPos = aRect.Left() + ((aTabSize.Width() - nTextWidth - aImageSize.Width()) / 2) - nOff - nOff3;
938 105 : long nYPos = aRect.Top() + ((aTabSize.Height() - nTextHeight) / 2) - nOff3;
939 105 : if (!pItem->maFormatText.isEmpty())
940 : {
941 105 : DrawTextFlags nStyle = DrawTextFlags::Mnemonic;
942 105 : if (!pItem->mbEnabled)
943 0 : nStyle |= DrawTextFlags::Disable;
944 :
945 105 : Color aColor(rStyleSettings.GetTabTextColor());
946 105 : if (nState & ControlState::SELECTED)
947 21 : aColor = rStyleSettings.GetTabHighlightTextColor();
948 84 : else if (nState & ControlState::ROLLOVER)
949 0 : aColor = rStyleSettings.GetTabRolloverTextColor();
950 :
951 105 : Color aOldColor(rRenderContext.GetTextColor());
952 105 : rRenderContext.SetTextColor(aColor);
953 :
954 105 : Rectangle aOutRect(nXPos + aImageSize.Width(), nYPos,
955 210 : nXPos + aImageSize.Width() + nTextWidth, nYPos + nTextHeight);
956 : DrawControlText(rRenderContext, aOutRect, pItem->maFormatText, nStyle,
957 : bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL,
958 105 : bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL);
959 :
960 105 : rRenderContext.SetTextColor(aOldColor);
961 : }
962 :
963 105 : if (!!pItem->maTabImage)
964 : {
965 0 : Point aImgTL( nXPos, aRect.Top() );
966 0 : if (aImageSize.Height() < aRect.GetHeight())
967 0 : aImgTL.Y() += (aRect.GetHeight() - aImageSize.Height()) / 2;
968 0 : rRenderContext.DrawImage(aImgTL, pItem->maTabImage, pItem->mbEnabled ? DrawImageFlags::NONE : DrawImageFlags::Disable );
969 105 : }
970 : }
971 :
972 0 : bool TabControl::ImplHandleKeyEvent( const KeyEvent& rKeyEvent )
973 : {
974 0 : bool nRet = false;
975 :
976 0 : if ( GetPageCount() > 1 )
977 : {
978 0 : vcl::KeyCode aKeyCode = rKeyEvent.GetKeyCode();
979 0 : sal_uInt16 nKeyCode = aKeyCode.GetCode();
980 :
981 0 : if ( aKeyCode.IsMod1() )
982 : {
983 0 : if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) )
984 : {
985 0 : if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) )
986 : {
987 0 : ImplActivateTabPage( false );
988 0 : nRet = true;
989 : }
990 : }
991 : else
992 : {
993 0 : if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) )
994 : {
995 0 : ImplActivateTabPage( true );
996 0 : nRet = true;
997 : }
998 : }
999 : }
1000 : }
1001 :
1002 0 : return nRet;
1003 : }
1004 :
1005 0 : IMPL_LINK_NOARG(TabControl, ImplListBoxSelectHdl)
1006 : {
1007 0 : SelectTabPage( GetPageId( mpTabCtrlData->mpListBox->GetSelectEntryPos() ) );
1008 0 : return 0;
1009 : }
1010 :
1011 0 : IMPL_LINK( TabControl, ImplWindowEventListener, VclSimpleEvent*, pEvent )
1012 : {
1013 0 : if ( pEvent && pEvent->ISA( VclWindowEvent ) && (pEvent->GetId() == VCLEVENT_WINDOW_KEYINPUT) )
1014 : {
1015 0 : VclWindowEvent* pWindowEvent = static_cast< VclWindowEvent* >(pEvent);
1016 : // Do not handle events from TabControl or its children, which is done in Notify(), where the events can be consumed.
1017 0 : if ( !IsWindowOrChild( pWindowEvent->GetWindow() ) )
1018 : {
1019 0 : KeyEvent* pKeyEvent = static_cast< KeyEvent* >(pWindowEvent->GetData());
1020 0 : ImplHandleKeyEvent( *pKeyEvent );
1021 : }
1022 : }
1023 0 : return 0;
1024 : }
1025 :
1026 0 : void TabControl::MouseButtonDown( const MouseEvent& rMEvt )
1027 : {
1028 0 : if( mpTabCtrlData->mpListBox.get() == NULL )
1029 : {
1030 0 : if( rMEvt.IsLeft() )
1031 : {
1032 0 : sal_uInt16 nPageId = GetPageId( rMEvt.GetPosPixel() );
1033 0 : ImplTabItem* pItem = ImplGetItem( nPageId );
1034 0 : if( pItem && pItem->mbEnabled )
1035 0 : SelectTabPage( nPageId );
1036 : }
1037 : }
1038 0 : }
1039 :
1040 0 : void TabControl::KeyInput( const KeyEvent& rKEvt )
1041 : {
1042 0 : if( mpTabCtrlData->mpListBox )
1043 0 : mpTabCtrlData->mpListBox->KeyInput( rKEvt );
1044 0 : else if ( GetPageCount() > 1 )
1045 : {
1046 0 : vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1047 0 : sal_uInt16 nKeyCode = aKeyCode.GetCode();
1048 :
1049 0 : if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_RIGHT) )
1050 : {
1051 0 : bool bNext = (nKeyCode == KEY_RIGHT);
1052 0 : ImplActivateTabPage( bNext );
1053 : }
1054 : }
1055 :
1056 0 : Control::KeyInput( rKEvt );
1057 0 : }
1058 :
1059 21 : void TabControl::Paint( vcl::RenderContext& rRenderContext, const Rectangle& rRect)
1060 : {
1061 21 : if (!(GetStyle() & WB_NOBORDER))
1062 21 : ImplPaint(rRenderContext, rRect, false);
1063 21 : }
1064 :
1065 21 : void TabControl::ImplPaint(vcl::RenderContext& rRenderContext, const Rectangle& rRect, bool bLayout)
1066 : {
1067 21 : if (!bLayout)
1068 21 : HideFocus();
1069 :
1070 : // reformat if needed
1071 21 : Rectangle aRect = ImplGetTabRect(TAB_PAGERECT);
1072 :
1073 : // find current item
1074 21 : ImplTabItem* pCurItem = NULL;
1075 63 : for (std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1076 42 : it != mpTabCtrlData->maItemList.end(); ++it )
1077 : {
1078 21 : if (it->mnId == mnCurPageId)
1079 : {
1080 21 : pCurItem = &(*it);
1081 21 : break;
1082 : }
1083 : }
1084 :
1085 : // Draw the TabPage border
1086 21 : const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1087 21 : Rectangle aCurRect;
1088 21 : aRect.Left() -= TAB_OFFSET;
1089 21 : aRect.Top() -= TAB_OFFSET;
1090 21 : aRect.Right() += TAB_OFFSET;
1091 21 : aRect.Bottom() += TAB_OFFSET;
1092 :
1093 : // if we have an invisible tabpage or no tabpage at all the tabpage rect should be
1094 : // increased to avoid round corners that might be drawn by a theme
1095 : // in this case we're only interested in the top border of the tabpage because the tabitems are used
1096 : // standalone (eg impress)
1097 21 : bool bNoTabPage = false;
1098 21 : TabPage* pCurPage = pCurItem ? pCurItem->mpTabPage.get() : NULL;
1099 21 : if (!pCurPage || !pCurPage->IsVisible())
1100 : {
1101 21 : bNoTabPage = true;
1102 21 : aRect.Left() -= 10;
1103 21 : aRect.Right() += 10;
1104 : }
1105 :
1106 21 : if (!bLayout && rRenderContext.IsNativeControlSupported(CTRL_TAB_PANE, PART_ENTIRE_CONTROL))
1107 : {
1108 0 : const ImplControlValue aControlValue;
1109 :
1110 0 : ControlState nState = ControlState::ENABLED;
1111 0 : if (!IsEnabled())
1112 0 : nState &= ~ControlState::ENABLED;
1113 0 : if (HasFocus())
1114 0 : nState |= ControlState::FOCUSED;
1115 :
1116 0 : vcl::Region aClipRgn(rRenderContext.GetActiveClipRegion());
1117 0 : aClipRgn.Intersect(aRect);
1118 0 : if (!rRect.IsEmpty())
1119 0 : aClipRgn.Intersect(rRect);
1120 :
1121 0 : if (!aClipRgn.IsEmpty())
1122 : {
1123 : rRenderContext.DrawNativeControl(CTRL_TAB_PANE, PART_ENTIRE_CONTROL,
1124 0 : aRect, nState, aControlValue, OUString());
1125 : }
1126 :
1127 0 : if (rRenderContext.IsNativeControlSupported(CTRL_TAB_HEADER, PART_ENTIRE_CONTROL))
1128 : {
1129 0 : Rectangle aHeaderRect(aRect.Left(), 0, aRect.Right(), aRect.Top());
1130 :
1131 0 : aClipRgn = rRenderContext.GetActiveClipRegion();
1132 0 : aClipRgn.Intersect(aHeaderRect);
1133 0 : if (!rRect.IsEmpty())
1134 0 : aClipRgn.Intersect(rRect);
1135 :
1136 0 : if (!aClipRgn.IsEmpty())
1137 : {
1138 : rRenderContext.DrawNativeControl(CTRL_TAB_HEADER, PART_ENTIRE_CONTROL,
1139 0 : aHeaderRect, nState, aControlValue, OUString());
1140 : }
1141 0 : }
1142 : }
1143 : else
1144 : {
1145 21 : long nTopOff = 1;
1146 21 : if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
1147 21 : rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
1148 : else
1149 0 : rRenderContext.SetLineColor(Color(COL_BLACK));
1150 21 : if (pCurItem && !pCurItem->maRect.IsEmpty())
1151 : {
1152 21 : aCurRect = pCurItem->maRect;
1153 21 : if (!bLayout)
1154 21 : rRenderContext.DrawLine(aRect.TopLeft(), Point(aCurRect.Left() - 2, aRect.Top()));
1155 21 : if (aCurRect.Right() + 1 < aRect.Right())
1156 : {
1157 0 : if (!bLayout)
1158 0 : rRenderContext.DrawLine(Point(aCurRect.Right(), aRect.Top()), aRect.TopRight());
1159 : }
1160 : else
1161 : {
1162 21 : nTopOff = 0;
1163 : }
1164 : }
1165 : else
1166 0 : if (!bLayout)
1167 0 : rRenderContext.DrawLine(aRect.TopLeft(), aRect.TopRight());
1168 :
1169 21 : if (!bLayout)
1170 : {
1171 21 : rRenderContext.DrawLine(aRect.TopLeft(), aRect.BottomLeft());
1172 :
1173 21 : if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
1174 : {
1175 : // if we have not tab page the bottom line of the tab page
1176 : // directly touches the tab items, so choose a color that fits seamlessly
1177 21 : if (bNoTabPage)
1178 21 : rRenderContext.SetLineColor(rStyleSettings.GetDialogColor());
1179 : else
1180 0 : rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
1181 21 : rRenderContext.DrawLine(Point(1, aRect.Bottom() - 1), Point(aRect.Right() - 1, aRect.Bottom() - 1));
1182 21 : rRenderContext.DrawLine(Point(aRect.Right() - 1, aRect.Top() + nTopOff), Point(aRect.Right() - 1, aRect.Bottom() - 1));
1183 21 : if (bNoTabPage)
1184 21 : rRenderContext.SetLineColor(rStyleSettings.GetDialogColor());
1185 : else
1186 0 : rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
1187 21 : rRenderContext.DrawLine(Point(0, aRect.Bottom()), Point(aRect.Right(), aRect.Bottom()));
1188 21 : rRenderContext.DrawLine(Point(aRect.Right(), aRect.Top() + nTopOff), Point(aRect.Right(), aRect.Bottom()));
1189 : }
1190 : else
1191 : {
1192 0 : rRenderContext.DrawLine(aRect.TopRight(), aRect.BottomRight());
1193 0 : rRenderContext.DrawLine(aRect.BottomLeft(), aRect.BottomRight());
1194 : }
1195 : }
1196 : }
1197 :
1198 21 : if (!mpTabCtrlData->maItemList.empty() && mpTabCtrlData->mpListBox == nullptr)
1199 : {
1200 : // Some native toolkits (GTK+) draw tabs right-to-left, with an
1201 : // overlap between adjacent tabs
1202 21 : bool bDrawTabsRTL = rRenderContext.IsNativeControlSupported(CTRL_TAB_ITEM, PART_TABS_DRAW_RTL);
1203 21 : ImplTabItem* pFirstTab = NULL;
1204 21 : ImplTabItem* pLastTab = NULL;
1205 : size_t idx;
1206 :
1207 : // Event though there is a tab overlap with GTK+, the first tab is not
1208 : // overlapped on the left side. Other tookits ignore this option.
1209 21 : if (bDrawTabsRTL)
1210 : {
1211 0 : pFirstTab = &mpTabCtrlData->maItemList.front();
1212 0 : pLastTab = &mpTabCtrlData->maItemList.back();
1213 0 : idx = mpTabCtrlData->maItemList.size() - 1;
1214 : }
1215 : else
1216 : {
1217 21 : pLastTab = &mpTabCtrlData->maItemList.back();
1218 21 : pFirstTab = &mpTabCtrlData->maItemList.front();
1219 21 : idx = 0;
1220 : }
1221 :
1222 147 : while (idx < mpTabCtrlData->maItemList.size())
1223 : {
1224 105 : ImplTabItem* pItem = &mpTabCtrlData->maItemList[idx];
1225 105 : if (pItem != pCurItem)
1226 : {
1227 84 : vcl::Region aClipRgn(rRenderContext.GetActiveClipRegion());
1228 84 : aClipRgn.Intersect(pItem->maRect);
1229 84 : if (!rRect.IsEmpty())
1230 84 : aClipRgn.Intersect(rRect);
1231 84 : if (bLayout || !aClipRgn.IsEmpty())
1232 : {
1233 : ImplDrawItem(rRenderContext, pItem, aCurRect, bLayout,
1234 84 : pItem == pFirstTab, pItem == pLastTab, false);
1235 84 : }
1236 : }
1237 :
1238 105 : if (bDrawTabsRTL)
1239 0 : idx--;
1240 : else
1241 105 : idx++;
1242 : }
1243 :
1244 21 : if (pCurItem)
1245 : {
1246 21 : vcl::Region aClipRgn(rRenderContext.GetActiveClipRegion());
1247 21 : aClipRgn.Intersect(pCurItem->maRect);
1248 21 : if (!rRect.IsEmpty())
1249 21 : aClipRgn.Intersect(rRect);
1250 21 : if (bLayout || !aClipRgn.IsEmpty())
1251 : {
1252 : ImplDrawItem(rRenderContext, pCurItem, aCurRect, bLayout,
1253 21 : pCurItem == pFirstTab, pCurItem == pLastTab, true);
1254 21 : }
1255 : }
1256 : }
1257 :
1258 21 : if (!bLayout && HasFocus())
1259 0 : ImplShowFocus();
1260 :
1261 21 : if (!bLayout)
1262 21 : mbSmallInvalidate = true;
1263 21 : }
1264 :
1265 495 : void TabControl::setAllocation(const Size &rAllocation)
1266 : {
1267 495 : ImplFreeLayoutData();
1268 :
1269 495 : if ( !IsReallyShown() )
1270 758 : return;
1271 :
1272 232 : if( mpTabCtrlData->mpListBox )
1273 : {
1274 : // get the listbox' preferred size
1275 0 : Size aTabCtrlSize( GetSizePixel() );
1276 0 : long nPrefWidth = mpTabCtrlData->mpListBox->get_preferred_size().Width();
1277 0 : if( nPrefWidth > aTabCtrlSize.Width() )
1278 0 : nPrefWidth = aTabCtrlSize.Width();
1279 0 : Size aNewSize( nPrefWidth, LogicToPixel( Size( 12, 12 ), MapMode( MAP_APPFONT ) ).Height() );
1280 0 : Point aNewPos( (aTabCtrlSize.Width() - nPrefWidth) / 2, 0 );
1281 0 : mpTabCtrlData->mpListBox->SetPosSizePixel( aNewPos, aNewSize );
1282 : }
1283 :
1284 232 : mbFormat = true;
1285 :
1286 : // resize/position active TabPage
1287 232 : bool bTabPage = ImplPosCurTabPage();
1288 :
1289 : // check what needs to be invalidated
1290 232 : Size aNewSize = rAllocation;
1291 232 : long nNewWidth = aNewSize.Width();
1292 4176 : for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1293 2784 : it != mpTabCtrlData->maItemList.end(); ++it )
1294 : {
1295 2320 : if ( !it->mbFullVisible ||
1296 1160 : (it->maRect.Right()-2 >= nNewWidth) )
1297 : {
1298 0 : mbSmallInvalidate = false;
1299 0 : break;
1300 : }
1301 : }
1302 :
1303 232 : if ( mbSmallInvalidate )
1304 : {
1305 24 : Rectangle aRect = ImplGetTabRect( TAB_PAGERECT );
1306 24 : aRect.Left() -= TAB_OFFSET+TAB_BORDER_LEFT;
1307 24 : aRect.Top() -= TAB_OFFSET+TAB_BORDER_TOP;
1308 24 : aRect.Right() += TAB_OFFSET+TAB_BORDER_RIGHT;
1309 24 : aRect.Bottom() += TAB_OFFSET+TAB_BORDER_BOTTOM;
1310 24 : if ( bTabPage )
1311 24 : Invalidate( aRect, InvalidateFlags::NoChildren );
1312 : else
1313 0 : Invalidate( aRect );
1314 :
1315 : }
1316 : else
1317 : {
1318 208 : if ( bTabPage )
1319 208 : Invalidate( InvalidateFlags::NoChildren );
1320 : else
1321 0 : Invalidate();
1322 : }
1323 :
1324 232 : mbLayoutDirty = false;
1325 : }
1326 :
1327 302 : void TabControl::SetPosSizePixel(const Point& rNewPos, const Size& rNewSize)
1328 : {
1329 302 : Window::SetPosSizePixel(rNewPos, rNewSize);
1330 : //if size changed, TabControl::Resize got called already
1331 302 : if (mbLayoutDirty)
1332 70 : setAllocation(rNewSize);
1333 302 : }
1334 :
1335 41 : void TabControl::SetSizePixel(const Size& rNewSize)
1336 : {
1337 41 : Window::SetSizePixel(rNewSize);
1338 : //if size changed, TabControl::Resize got called already
1339 41 : if (mbLayoutDirty)
1340 41 : setAllocation(rNewSize);
1341 41 : }
1342 :
1343 0 : void TabControl::SetPosPixel(const Point& rPos)
1344 : {
1345 0 : Window::SetPosPixel(rPos);
1346 0 : if (mbLayoutDirty)
1347 0 : setAllocation(GetOutputSizePixel());
1348 0 : }
1349 :
1350 384 : void TabControl::Resize()
1351 : {
1352 384 : setAllocation(Control::GetOutputSizePixel());
1353 384 : }
1354 :
1355 0 : void TabControl::GetFocus()
1356 : {
1357 0 : if( ! mpTabCtrlData->mpListBox )
1358 : {
1359 0 : ImplShowFocus();
1360 0 : SetInputContext( InputContext( GetFont() ) );
1361 : }
1362 : else
1363 : {
1364 0 : if( mpTabCtrlData->mpListBox->IsReallyVisible() )
1365 0 : mpTabCtrlData->mpListBox->GrabFocus();
1366 : }
1367 0 : Control::GetFocus();
1368 0 : }
1369 :
1370 0 : void TabControl::LoseFocus()
1371 : {
1372 0 : if( mpTabCtrlData && ! mpTabCtrlData->mpListBox )
1373 0 : HideFocus();
1374 0 : Control::LoseFocus();
1375 0 : }
1376 :
1377 0 : void TabControl::RequestHelp( const HelpEvent& rHEvt )
1378 : {
1379 0 : sal_uInt16 nItemId = rHEvt.KeyboardActivated() ? mnCurPageId : GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
1380 :
1381 0 : if ( nItemId )
1382 : {
1383 0 : if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
1384 : {
1385 0 : OUString aStr = GetHelpText( nItemId );
1386 0 : if ( !aStr.isEmpty() )
1387 : {
1388 0 : Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1389 0 : Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1390 0 : aItemRect.Left() = aPt.X();
1391 0 : aItemRect.Top() = aPt.Y();
1392 0 : aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1393 0 : aItemRect.Right() = aPt.X();
1394 0 : aItemRect.Bottom() = aPt.Y();
1395 0 : Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
1396 0 : return;
1397 0 : }
1398 : }
1399 0 : else if ( rHEvt.GetMode() & HelpEventMode::EXTENDED )
1400 : {
1401 0 : OUString aHelpId( OStringToOUString( GetHelpId( nItemId ), RTL_TEXTENCODING_UTF8 ) );
1402 0 : if ( !aHelpId.isEmpty() )
1403 : {
1404 : // call Help if existing
1405 0 : Help* pHelp = Application::GetHelp();
1406 0 : if ( pHelp )
1407 0 : pHelp->Start( aHelpId, this );
1408 0 : return;
1409 0 : }
1410 : }
1411 :
1412 : // for Quick or Ballon Help, we show the text, if it is cut
1413 0 : if ( rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON) )
1414 : {
1415 0 : ImplTabItem* pItem = ImplGetItem( nItemId );
1416 0 : const OUString& rStr = pItem->maText;
1417 0 : if ( rStr != pItem->maFormatText )
1418 : {
1419 0 : Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1420 0 : Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1421 0 : aItemRect.Left() = aPt.X();
1422 0 : aItemRect.Top() = aPt.Y();
1423 0 : aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1424 0 : aItemRect.Right() = aPt.X();
1425 0 : aItemRect.Bottom() = aPt.Y();
1426 0 : if ( !rStr.isEmpty() )
1427 : {
1428 0 : if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
1429 0 : Help::ShowBalloon( this, aItemRect.Center(), aItemRect, rStr );
1430 : else
1431 0 : Help::ShowQuickHelp( this, aItemRect, rStr );
1432 0 : return;
1433 : }
1434 : }
1435 : }
1436 :
1437 0 : if ( rHEvt.GetMode() & HelpEventMode::QUICK )
1438 : {
1439 0 : ImplTabItem* pItem = ImplGetItem( nItemId );
1440 0 : const OUString& rHelpText = pItem->maHelpText;
1441 : // show tooltip if not text but image is set and helptext is available
1442 0 : if ( !rHelpText.isEmpty() && pItem->maText.isEmpty() && !!pItem->maTabImage )
1443 : {
1444 0 : Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1445 0 : Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1446 0 : aItemRect.Left() = aPt.X();
1447 0 : aItemRect.Top() = aPt.Y();
1448 0 : aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1449 0 : aItemRect.Right() = aPt.X();
1450 0 : aItemRect.Bottom() = aPt.Y();
1451 0 : Help::ShowQuickHelp( this, aItemRect, rHelpText );
1452 0 : return;
1453 : }
1454 : }
1455 : }
1456 :
1457 0 : Control::RequestHelp( rHEvt );
1458 : }
1459 :
1460 0 : void TabControl::Command( const CommandEvent& rCEvt )
1461 : {
1462 0 : if( (mpTabCtrlData->mpListBox == nullptr) && (rCEvt.GetCommand() == CommandEventId::ContextMenu) && (GetPageCount() > 1) )
1463 : {
1464 0 : Point aMenuPos;
1465 : bool bMenu;
1466 0 : if ( rCEvt.IsMouseEvent() )
1467 : {
1468 0 : aMenuPos = rCEvt.GetMousePosPixel();
1469 0 : bMenu = GetPageId( aMenuPos ) != 0;
1470 : }
1471 : else
1472 : {
1473 0 : aMenuPos = ImplGetTabRect( GetPagePos( mnCurPageId ) ).Center();
1474 0 : bMenu = true;
1475 : }
1476 :
1477 0 : if ( bMenu )
1478 : {
1479 0 : PopupMenu aMenu;
1480 0 : for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1481 0 : it != mpTabCtrlData->maItemList.end(); ++it )
1482 : {
1483 0 : aMenu.InsertItem( it->mnId, it->maText, MenuItemBits::CHECKABLE | MenuItemBits::RADIOCHECK );
1484 0 : if ( it->mnId == mnCurPageId )
1485 0 : aMenu.CheckItem( it->mnId );
1486 0 : aMenu.SetHelpId( it->mnId, it->maHelpId );
1487 : }
1488 :
1489 0 : sal_uInt16 nId = aMenu.Execute( this, aMenuPos );
1490 0 : if ( nId && (nId != mnCurPageId) )
1491 0 : SelectTabPage( nId );
1492 0 : return;
1493 : }
1494 : }
1495 :
1496 0 : Control::Command( rCEvt );
1497 : }
1498 :
1499 86 : void TabControl::StateChanged( StateChangedType nType )
1500 : {
1501 86 : Control::StateChanged( nType );
1502 :
1503 86 : if ( nType == StateChangedType::InitShow )
1504 : {
1505 41 : ImplPosCurTabPage();
1506 41 : if( mpTabCtrlData->mpListBox )
1507 0 : Resize();
1508 : }
1509 45 : else if ( nType == StateChangedType::UpdateMode )
1510 : {
1511 0 : if ( IsUpdateMode() )
1512 0 : Invalidate();
1513 : }
1514 45 : else if ( (nType == StateChangedType::Zoom) ||
1515 : (nType == StateChangedType::ControlFont) )
1516 : {
1517 0 : ImplInitSettings( true, false, false );
1518 0 : Invalidate();
1519 : }
1520 45 : else if ( nType == StateChangedType::ControlForeground )
1521 : {
1522 0 : ImplInitSettings( false, true, false );
1523 0 : Invalidate();
1524 : }
1525 45 : else if ( nType == StateChangedType::ControlBackground )
1526 : {
1527 0 : ImplInitSettings( false, false, true );
1528 0 : Invalidate();
1529 : }
1530 86 : }
1531 :
1532 2 : void TabControl::DataChanged( const DataChangedEvent& rDCEvt )
1533 : {
1534 2 : Control::DataChanged( rDCEvt );
1535 :
1536 8 : if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
1537 8 : (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
1538 6 : ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1539 8 : (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
1540 : {
1541 2 : ImplInitSettings( true, true, true );
1542 2 : Invalidate();
1543 : }
1544 2 : }
1545 :
1546 0 : Rectangle* TabControl::ImplFindPartRect( const Point& rPt )
1547 : {
1548 0 : ImplTabItem* pFoundItem = NULL;
1549 0 : int nFound = 0;
1550 0 : for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin();
1551 0 : it != mpTabCtrlData->maItemList.end(); ++it )
1552 : {
1553 0 : if ( it->maRect.IsInside( rPt ) )
1554 : {
1555 : // assure that only one tab is highlighted at a time
1556 0 : nFound++;
1557 0 : pFoundItem = &(*it);
1558 : }
1559 : }
1560 : // assure that only one tab is highlighted at a time
1561 0 : return nFound == 1 ? &pFoundItem->maRect : NULL;
1562 : }
1563 :
1564 0 : bool TabControl::PreNotify( NotifyEvent& rNEvt )
1565 : {
1566 0 : const MouseEvent* pMouseEvt = NULL;
1567 :
1568 0 : if( (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
1569 : {
1570 0 : if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1571 : {
1572 : // trigger redraw if mouse over state has changed
1573 0 : if( IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL) )
1574 : {
1575 0 : Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
1576 0 : Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
1577 0 : if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
1578 : {
1579 0 : vcl::Region aClipRgn;
1580 0 : if( pLastRect )
1581 : {
1582 : // allow for slightly bigger tabitems
1583 : // as used by gtk
1584 : // TODO: query for the correct sizes
1585 0 : Rectangle aRect(*pLastRect);
1586 0 : aRect.Left()-=2;
1587 0 : aRect.Right()+=2;
1588 0 : aRect.Top()-=3;
1589 0 : aClipRgn.Union( aRect );
1590 : }
1591 0 : if( pRect )
1592 : {
1593 : // allow for slightly bigger tabitems
1594 : // as used by gtk
1595 : // TODO: query for the correct sizes
1596 0 : Rectangle aRect(*pRect);
1597 0 : aRect.Left()-=2;
1598 0 : aRect.Right()+=2;
1599 0 : aRect.Top()-=3;
1600 0 : aClipRgn.Union( aRect );
1601 : }
1602 0 : if( !aClipRgn.IsEmpty() )
1603 0 : Invalidate( aClipRgn );
1604 : }
1605 : }
1606 : }
1607 : }
1608 :
1609 0 : return Control::PreNotify(rNEvt);
1610 : }
1611 :
1612 41 : bool TabControl::Notify( NotifyEvent& rNEvt )
1613 : {
1614 41 : bool nRet = false;
1615 :
1616 41 : if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
1617 0 : nRet = ImplHandleKeyEvent( *rNEvt.GetKeyEvent() );
1618 :
1619 41 : return nRet || Control::Notify( rNEvt );
1620 : }
1621 :
1622 211 : void TabControl::ActivatePage()
1623 : {
1624 211 : maActivateHdl.Call( this );
1625 211 : }
1626 :
1627 0 : bool TabControl::DeactivatePage()
1628 : {
1629 0 : return !maDeactivateHdl.IsSet() || maDeactivateHdl.Call( this );
1630 : }
1631 :
1632 41 : void TabControl::SetTabPageSizePixel( const Size& rSize )
1633 : {
1634 41 : ImplFreeLayoutData();
1635 :
1636 41 : Size aNewSize( rSize );
1637 41 : aNewSize.Width() += TAB_OFFSET*2;
1638 : Rectangle aRect = ImplGetTabRect( TAB_PAGERECT,
1639 41 : aNewSize.Width(), aNewSize.Height() );
1640 41 : aNewSize.Height() += aRect.Top()+TAB_OFFSET;
1641 41 : Window::SetOutputSizePixel( aNewSize );
1642 41 : }
1643 :
1644 0 : Size TabControl::GetTabPageSizePixel() const
1645 : {
1646 0 : Rectangle aRect = const_cast<TabControl*>(this)->ImplGetTabRect( TAB_PAGERECT );
1647 0 : return aRect.GetSize();
1648 : }
1649 :
1650 205 : void TabControl::InsertPage( sal_uInt16 nPageId, const OUString& rText,
1651 : sal_uInt16 nPos )
1652 : {
1653 : DBG_ASSERT( nPageId, "TabControl::InsertPage(): PageId == 0" );
1654 : DBG_ASSERT( GetPagePos( nPageId ) == TAB_PAGE_NOTFOUND,
1655 : "TabControl::InsertPage(): PageId already exists" );
1656 :
1657 : // insert new page item
1658 205 : ImplTabItem* pItem = NULL;
1659 205 : if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1660 : {
1661 205 : mpTabCtrlData->maItemList.push_back( ImplTabItem() );
1662 205 : pItem = &mpTabCtrlData->maItemList.back();
1663 205 : if( mpTabCtrlData->mpListBox )
1664 0 : mpTabCtrlData->mpListBox->InsertEntry( rText );
1665 : }
1666 : else
1667 : {
1668 : std::vector< ImplTabItem >::iterator new_it =
1669 0 : mpTabCtrlData->maItemList.insert( mpTabCtrlData->maItemList.begin() + nPos, ImplTabItem() );
1670 0 : pItem = &(*new_it);
1671 0 : if( mpTabCtrlData->mpListBox )
1672 0 : mpTabCtrlData->mpListBox->InsertEntry( rText, nPos);
1673 : }
1674 205 : if( mpTabCtrlData->mpListBox )
1675 : {
1676 0 : if( ! mnCurPageId )
1677 0 : mpTabCtrlData->mpListBox->SelectEntryPos( 0 );
1678 0 : mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1679 : }
1680 :
1681 : // set current page id
1682 205 : if ( !mnCurPageId )
1683 41 : mnCurPageId = nPageId;
1684 :
1685 : // init new page item
1686 205 : pItem->mnId = nPageId;
1687 205 : pItem->mpTabPage = NULL;
1688 205 : pItem->maText = rText;
1689 205 : pItem->mbFullVisible = false;
1690 :
1691 205 : mbFormat = true;
1692 205 : if ( IsUpdateMode() )
1693 205 : Invalidate();
1694 :
1695 205 : ImplFreeLayoutData();
1696 205 : if( mpTabCtrlData->mpListBox ) // reposition/resize listbox
1697 0 : Resize();
1698 :
1699 205 : CallEventListeners( VCLEVENT_TABPAGE_INSERTED, reinterpret_cast<void*>(nPageId) );
1700 205 : }
1701 :
1702 0 : void TabControl::RemovePage( sal_uInt16 nPageId )
1703 : {
1704 0 : sal_uInt16 nPos = GetPagePos( nPageId );
1705 :
1706 : // does the item exist ?
1707 0 : if ( nPos != TAB_PAGE_NOTFOUND )
1708 : {
1709 : //remove page item
1710 0 : std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos;
1711 0 : bool bIsCurrentPage = (it->mnId == mnCurPageId);
1712 0 : mpTabCtrlData->maItemList.erase( it );
1713 0 : if( mpTabCtrlData->mpListBox )
1714 : {
1715 0 : mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1716 0 : mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1717 : }
1718 :
1719 : // If current page is removed, than first page gets the current page
1720 0 : if ( bIsCurrentPage )
1721 : {
1722 0 : mnCurPageId = 0;
1723 :
1724 0 : if( ! mpTabCtrlData->maItemList.empty() )
1725 : {
1726 : // don't do this by simply setting mnCurPageId to pFirstItem->mnId
1727 : // this leaves a lot of stuff (such trivias as _showing_ the new current page) undone
1728 : // instead, call SetCurPageId
1729 : // without this, the next (outside) call to SetCurPageId with the id of the first page
1730 : // will result in doing nothing (as we assume that nothing changed, then), and the page
1731 : // will never be shown.
1732 : // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com
1733 :
1734 0 : SetCurPageId( mpTabCtrlData->maItemList[0].mnId );
1735 : }
1736 : }
1737 :
1738 0 : mbFormat = true;
1739 0 : if ( IsUpdateMode() )
1740 0 : Invalidate();
1741 :
1742 0 : ImplFreeLayoutData();
1743 :
1744 0 : CallEventListeners( VCLEVENT_TABPAGE_REMOVED, reinterpret_cast<void*>(nPageId) );
1745 : }
1746 0 : }
1747 :
1748 4 : void TabControl::Clear()
1749 : {
1750 : // clear item list
1751 4 : mpTabCtrlData->maItemList.clear();
1752 4 : mnCurPageId = 0;
1753 4 : if( mpTabCtrlData->mpListBox )
1754 0 : mpTabCtrlData->mpListBox->Clear();
1755 :
1756 4 : ImplFreeLayoutData();
1757 :
1758 4 : mbFormat = true;
1759 4 : if ( IsUpdateMode() )
1760 4 : Invalidate();
1761 :
1762 4 : CallEventListeners( VCLEVENT_TABPAGE_REMOVEDALL );
1763 4 : }
1764 :
1765 0 : void TabControl::EnablePage( sal_uInt16 i_nPageId, bool i_bEnable )
1766 : {
1767 0 : ImplTabItem* pItem = ImplGetItem( i_nPageId );
1768 :
1769 0 : if ( pItem && pItem->mbEnabled != i_bEnable )
1770 : {
1771 0 : pItem->mbEnabled = i_bEnable;
1772 0 : mbFormat = true;
1773 0 : if( mpTabCtrlData->mpListBox )
1774 0 : mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ),
1775 0 : i_bEnable ? ListBoxEntryFlags::NONE : (ListBoxEntryFlags::DisableSelection | ListBoxEntryFlags::DrawDisabled) );
1776 0 : if( pItem->mnId == mnCurPageId )
1777 : {
1778 : // SetCurPageId will change to an enabled page
1779 0 : SetCurPageId( mnCurPageId );
1780 : }
1781 0 : else if ( IsUpdateMode() )
1782 0 : Invalidate();
1783 : }
1784 0 : }
1785 :
1786 676 : sal_uInt16 TabControl::GetPageCount() const
1787 : {
1788 676 : return (sal_uInt16)mpTabCtrlData->maItemList.size();
1789 : }
1790 :
1791 0 : sal_uInt16 TabControl::GetPageId( sal_uInt16 nPos ) const
1792 : {
1793 0 : if( size_t(nPos) < mpTabCtrlData->maItemList.size() )
1794 0 : return mpTabCtrlData->maItemList[ nPos ].mnId;
1795 0 : return 0;
1796 : }
1797 :
1798 623 : sal_uInt16 TabControl::GetPagePos( sal_uInt16 nPageId ) const
1799 : {
1800 2247 : for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
1801 1498 : it != mpTabCtrlData->maItemList.end(); ++it )
1802 : {
1803 749 : if ( it->mnId == nPageId )
1804 623 : return (sal_uInt16)(it - mpTabCtrlData->maItemList.begin());
1805 : }
1806 :
1807 0 : return TAB_PAGE_NOTFOUND;
1808 : }
1809 :
1810 0 : sal_uInt16 TabControl::GetPageId( const Point& rPos ) const
1811 : {
1812 0 : for( size_t i = 0; i < mpTabCtrlData->maItemList.size(); ++i )
1813 : {
1814 0 : if ( const_cast<TabControl*>(this)->ImplGetTabRect( static_cast<sal_uInt16>(i) ).IsInside( rPos ) )
1815 0 : return mpTabCtrlData->maItemList[ i ].mnId;
1816 : }
1817 :
1818 0 : return 0;
1819 : }
1820 :
1821 0 : sal_uInt16 TabControl::GetPageId( const TabPage& rPage ) const
1822 : {
1823 0 : for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
1824 0 : it != mpTabCtrlData->maItemList.end(); ++it )
1825 : {
1826 0 : if ( it->mpTabPage == &rPage )
1827 0 : return it->mnId;
1828 : }
1829 :
1830 0 : return 0;
1831 : }
1832 :
1833 0 : sal_uInt16 TabControl::GetPageId( const OString& rName ) const
1834 : {
1835 0 : for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
1836 0 : it != mpTabCtrlData->maItemList.end(); ++it )
1837 : {
1838 0 : if ( it->maTabName == rName )
1839 0 : return it->mnId;
1840 : }
1841 :
1842 0 : return 0;
1843 : }
1844 :
1845 211 : void TabControl::SetCurPageId( sal_uInt16 nPageId )
1846 : {
1847 211 : sal_uInt16 nPos = GetPagePos( nPageId );
1848 633 : while( nPos != TAB_PAGE_NOTFOUND &&
1849 211 : ! mpTabCtrlData->maItemList[nPos].mbEnabled )
1850 : {
1851 0 : nPos++;
1852 0 : if( size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1853 0 : nPos = 0;
1854 0 : if( mpTabCtrlData->maItemList[nPos].mnId == nPageId )
1855 0 : break;
1856 : }
1857 :
1858 211 : if( nPos != TAB_PAGE_NOTFOUND )
1859 : {
1860 211 : nPageId = mpTabCtrlData->maItemList[nPos].mnId;
1861 211 : if ( nPageId == mnCurPageId )
1862 : {
1863 205 : if ( mnActPageId )
1864 0 : mnActPageId = nPageId;
1865 416 : return;
1866 : }
1867 :
1868 6 : if ( mnActPageId )
1869 0 : mnActPageId = nPageId;
1870 : else
1871 : {
1872 6 : mbFormat = true;
1873 6 : sal_uInt16 nOldId = mnCurPageId;
1874 6 : mnCurPageId = nPageId;
1875 6 : ImplChangeTabPage( nPageId, nOldId );
1876 : }
1877 : }
1878 : }
1879 :
1880 614 : sal_uInt16 TabControl::GetCurPageId() const
1881 : {
1882 614 : if ( mnActPageId )
1883 0 : return mnActPageId;
1884 : else
1885 614 : return mnCurPageId;
1886 : }
1887 :
1888 0 : void TabControl::SelectTabPage( sal_uInt16 nPageId )
1889 : {
1890 0 : if ( nPageId && (nPageId != mnCurPageId) )
1891 : {
1892 0 : ImplFreeLayoutData();
1893 :
1894 0 : CallEventListeners( VCLEVENT_TABPAGE_DEACTIVATE, reinterpret_cast<void*>(mnCurPageId) );
1895 0 : if ( DeactivatePage() )
1896 : {
1897 0 : mnActPageId = nPageId;
1898 0 : ActivatePage();
1899 : // Page could have been switched by the Activate handler
1900 0 : nPageId = mnActPageId;
1901 0 : mnActPageId = 0;
1902 0 : SetCurPageId( nPageId );
1903 0 : if( mpTabCtrlData->mpListBox )
1904 0 : mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) );
1905 0 : CallEventListeners( VCLEVENT_TABPAGE_ACTIVATE, reinterpret_cast<void*>(nPageId) );
1906 : }
1907 : }
1908 0 : }
1909 :
1910 820 : void TabControl::SetTabPage( sal_uInt16 nPageId, TabPage* pTabPage )
1911 : {
1912 820 : ImplTabItem* pItem = ImplGetItem( nPageId );
1913 :
1914 820 : if ( pItem && (pItem->mpTabPage.get() != pTabPage) )
1915 : {
1916 369 : if ( pTabPage )
1917 : {
1918 : DBG_ASSERT( !pTabPage->IsVisible() || isLayoutEnabled(pTabPage),
1919 : "TabControl::SetTabPage() - Non-Layout Enabled Page is visible" );
1920 :
1921 205 : if ( IsDefaultSize() )
1922 41 : SetTabPageSizePixel( pTabPage->GetSizePixel() );
1923 :
1924 : // only set here, so that Resize does not reposition TabPage
1925 205 : pItem->mpTabPage = pTabPage;
1926 205 : queue_resize();
1927 205 : if ( pItem->mnId == mnCurPageId )
1928 41 : ImplChangeTabPage( pItem->mnId, 0 );
1929 : }
1930 : else
1931 : {
1932 164 : pItem->mpTabPage = NULL;
1933 164 : queue_resize();
1934 : }
1935 : }
1936 820 : }
1937 :
1938 341 : TabPage* TabControl::GetTabPage( sal_uInt16 nPageId ) const
1939 : {
1940 341 : ImplTabItem* pItem = ImplGetItem( nPageId );
1941 :
1942 341 : if ( pItem )
1943 341 : return pItem->mpTabPage;
1944 : else
1945 0 : return NULL;
1946 : }
1947 :
1948 615 : void TabControl::SetPageText( sal_uInt16 nPageId, const OUString& rText )
1949 : {
1950 615 : ImplTabItem* pItem = ImplGetItem( nPageId );
1951 :
1952 615 : if ( pItem && pItem->maText != rText )
1953 : {
1954 0 : pItem->maText = rText;
1955 0 : mbFormat = true;
1956 0 : if( mpTabCtrlData->mpListBox )
1957 : {
1958 0 : sal_uInt16 nPos = GetPagePos( nPageId );
1959 0 : mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1960 0 : mpTabCtrlData->mpListBox->InsertEntry( rText, nPos );
1961 : }
1962 0 : if ( IsUpdateMode() )
1963 0 : Invalidate();
1964 0 : ImplFreeLayoutData();
1965 0 : CallEventListeners( VCLEVENT_TABPAGE_PAGETEXTCHANGED, reinterpret_cast<void*>(nPageId) );
1966 : }
1967 615 : }
1968 :
1969 0 : OUString TabControl::GetPageText( sal_uInt16 nPageId ) const
1970 : {
1971 0 : ImplTabItem* pItem = ImplGetItem( nPageId );
1972 :
1973 : assert( pItem );
1974 :
1975 0 : return pItem->maText;
1976 : }
1977 :
1978 615 : void TabControl::SetHelpText( sal_uInt16 nPageId, const OUString& rText )
1979 : {
1980 615 : ImplTabItem* pItem = ImplGetItem( nPageId );
1981 :
1982 : assert( pItem );
1983 :
1984 615 : pItem->maHelpText = rText;
1985 615 : }
1986 :
1987 0 : const OUString& TabControl::GetHelpText( sal_uInt16 nPageId ) const
1988 : {
1989 0 : ImplTabItem* pItem = ImplGetItem( nPageId );
1990 :
1991 : assert( pItem );
1992 :
1993 0 : if ( pItem->maHelpText.isEmpty() && !pItem->maHelpId.isEmpty() )
1994 : {
1995 0 : Help* pHelp = Application::GetHelp();
1996 0 : if ( pHelp )
1997 0 : pItem->maHelpText = pHelp->GetHelpText( OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this );
1998 : }
1999 0 : return pItem->maHelpText;
2000 : }
2001 :
2002 0 : void TabControl::SetHelpId( sal_uInt16 nPageId, const OString& rId ) const
2003 : {
2004 0 : ImplTabItem* pItem = ImplGetItem( nPageId );
2005 :
2006 0 : if ( pItem )
2007 0 : pItem->maHelpId = rId;
2008 0 : }
2009 :
2010 0 : OString TabControl::GetHelpId( sal_uInt16 nPageId ) const
2011 : {
2012 0 : ImplTabItem* pItem = ImplGetItem( nPageId );
2013 :
2014 0 : if (pItem)
2015 0 : return pItem->maHelpId;
2016 :
2017 0 : return OString();
2018 : }
2019 :
2020 0 : void TabControl::SetPageName( sal_uInt16 nPageId, const OString& rName ) const
2021 : {
2022 0 : ImplTabItem* pItem = ImplGetItem( nPageId );
2023 :
2024 0 : if ( pItem )
2025 0 : pItem->maTabName = rName;
2026 0 : }
2027 :
2028 0 : OString TabControl::GetPageName( sal_uInt16 nPageId ) const
2029 : {
2030 0 : ImplTabItem* pItem = ImplGetItem( nPageId );
2031 :
2032 0 : if (pItem)
2033 0 : return pItem->maTabName;
2034 :
2035 0 : return OString();
2036 : }
2037 :
2038 0 : void TabControl::SetPageImage( sal_uInt16 i_nPageId, const Image& i_rImage )
2039 : {
2040 0 : ImplTabItem* pItem = ImplGetItem( i_nPageId );
2041 :
2042 0 : if ( pItem )
2043 : {
2044 0 : pItem->maTabImage = i_rImage;
2045 0 : mbFormat = true;
2046 0 : if ( IsUpdateMode() )
2047 0 : Invalidate();
2048 : }
2049 0 : }
2050 :
2051 0 : Rectangle TabControl::GetCharacterBounds( sal_uInt16 nPageId, long nIndex ) const
2052 : {
2053 0 : Rectangle aRet;
2054 :
2055 0 : if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2056 0 : FillLayoutData();
2057 :
2058 0 : if( HasLayoutData() )
2059 : {
2060 0 : std::unordered_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( (int)nPageId );
2061 0 : if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
2062 : {
2063 0 : Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( it->second );
2064 0 : if( (aPair.B() - aPair.A()) >= nIndex )
2065 0 : aRet = mpControlData->mpLayoutData->GetCharacterBounds( aPair.A() + nIndex );
2066 : }
2067 : }
2068 :
2069 0 : return aRet;
2070 : }
2071 :
2072 0 : long TabControl::GetIndexForPoint( const Point& rPoint, sal_uInt16& rPageId ) const
2073 : {
2074 0 : long nRet = -1;
2075 :
2076 0 : if( !HasLayoutData() || ! mpTabCtrlData->maLayoutPageIdToLine.size() )
2077 0 : FillLayoutData();
2078 :
2079 0 : if( HasLayoutData() )
2080 : {
2081 0 : int nIndex = mpControlData->mpLayoutData->GetIndexForPoint( rPoint );
2082 0 : if( nIndex != -1 )
2083 : {
2084 : // what line (->pageid) is this index in ?
2085 0 : int nLines = mpControlData->mpLayoutData->GetLineCount();
2086 0 : int nLine = -1;
2087 0 : while( ++nLine < nLines )
2088 : {
2089 0 : Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( nLine );
2090 0 : if( aPair.A() <= nIndex && aPair.B() >= nIndex )
2091 : {
2092 0 : nRet = nIndex - aPair.A();
2093 0 : rPageId = (sal_uInt16)mpTabCtrlData->maLayoutLineToPageId[ nLine ];
2094 0 : break;
2095 : }
2096 : }
2097 : }
2098 : }
2099 :
2100 0 : return nRet;
2101 : }
2102 :
2103 0 : void TabControl::FillLayoutData() const
2104 : {
2105 0 : mpTabCtrlData->maLayoutLineToPageId.clear();
2106 0 : mpTabCtrlData->maLayoutPageIdToLine.clear();
2107 0 : const_cast<TabControl*>(this)->Invalidate();
2108 0 : }
2109 :
2110 0 : Rectangle TabControl::GetTabBounds( sal_uInt16 nPageId ) const
2111 : {
2112 0 : Rectangle aRet;
2113 :
2114 0 : ImplTabItem* pItem = ImplGetItem( nPageId );
2115 0 : if(pItem)
2116 0 : aRet = pItem->maRect;
2117 :
2118 0 : return aRet;
2119 : }
2120 :
2121 41 : void TabControl::SetItemsOffset( const Point& rOffs )
2122 : {
2123 41 : if( mpTabCtrlData )
2124 41 : mpTabCtrlData->maItemsOffset = rOffs;
2125 41 : }
2126 :
2127 906 : Point TabControl::GetItemsOffset() const
2128 : {
2129 906 : if( mpTabCtrlData )
2130 906 : return mpTabCtrlData->maItemsOffset;
2131 : else
2132 0 : return Point();
2133 : }
2134 :
2135 0 : Size TabControl::calculateRequisition() const
2136 : {
2137 0 : Size aOptimalPageSize(0, 0);
2138 :
2139 0 : sal_uInt16 nOrigPageId = GetCurPageId();
2140 0 : for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
2141 0 : it != mpTabCtrlData->maItemList.end(); ++it )
2142 : {
2143 0 : const TabPage *pPage = it->mpTabPage;
2144 : //it's a real nuisance if the page is not inserted yet :-(
2145 : //We need to force all tabs to exist to get overall optimal size for dialog
2146 0 : if (!pPage)
2147 : {
2148 0 : TabControl *pThis = const_cast<TabControl*>(this);
2149 0 : pThis->SetCurPageId(it->mnId);
2150 0 : pThis->ActivatePage();
2151 0 : pPage = it->mpTabPage;
2152 : }
2153 :
2154 0 : if (!pPage)
2155 0 : continue;
2156 :
2157 0 : Size aPageSize(VclContainer::getLayoutRequisition(*pPage));
2158 :
2159 0 : if (aPageSize.Width() > aOptimalPageSize.Width())
2160 0 : aOptimalPageSize.Width() = aPageSize.Width();
2161 0 : if (aPageSize.Height() > aOptimalPageSize.Height())
2162 0 : aOptimalPageSize.Height() = aPageSize.Height();
2163 : }
2164 :
2165 : //fdo#61940 If we were forced to activate pages in order to on-demand
2166 : //create them to get their optimal size, then switch back to the original
2167 : //page and re-activate it
2168 0 : if (nOrigPageId != GetCurPageId())
2169 : {
2170 0 : TabControl *pThis = const_cast<TabControl*>(this);
2171 0 : pThis->SetCurPageId(nOrigPageId);
2172 0 : pThis->ActivatePage();
2173 : }
2174 :
2175 0 : long nTabLabelsBottom = 0, nTabLabelsRight = 0;
2176 0 : for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin();
2177 0 : it != mpTabCtrlData->maItemList.end(); ++it )
2178 : {
2179 0 : TabControl* pThis = const_cast<TabControl*>(this);
2180 :
2181 0 : sal_uInt16 nPos = it - mpTabCtrlData->maItemList.begin();
2182 0 : Rectangle aTabRect = pThis->ImplGetTabRect(nPos, aOptimalPageSize.Width(), LONG_MAX);
2183 0 : if (aTabRect.Bottom() > nTabLabelsBottom)
2184 0 : nTabLabelsBottom = aTabRect.Bottom();
2185 0 : if (aTabRect.Right() > nTabLabelsRight)
2186 0 : nTabLabelsRight = aTabRect.Right();
2187 : }
2188 :
2189 0 : Size aOptimalSize(aOptimalPageSize);
2190 0 : aOptimalSize.Height() += nTabLabelsBottom;
2191 0 : aOptimalSize.Width() = std::max(nTabLabelsRight, aOptimalSize.Width());
2192 :
2193 0 : aOptimalSize.Width() += TAB_OFFSET * 2;
2194 0 : aOptimalSize.Height() += TAB_OFFSET * 2;
2195 :
2196 0 : return aOptimalSize;
2197 : }
2198 :
2199 0 : Size TabControl::GetOptimalSize() const
2200 : {
2201 0 : return calculateRequisition();
2202 : }
2203 :
2204 537 : void TabControl::queue_resize(StateChangedType eReason)
2205 : {
2206 537 : markLayoutDirty();
2207 537 : Window::queue_resize(eReason);
2208 1338 : }
2209 :
2210 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|