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