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