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