1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "precompiled_vcl.hxx" 29 30 #include "svdata.hxx" 31 32 #include "vcl/arrange.hxx" 33 #include "vcl/edit.hxx" 34 #include "vcl/svapp.hxx" 35 36 #include "com/sun/star/beans/PropertyValue.hpp" 37 #include "com/sun/star/awt/Rectangle.hpp" 38 39 #include "osl/diagnose.h" 40 41 using namespace vcl; 42 using namespace com::sun::star; 43 44 // ---------------------------------------- 45 // vcl::WindowArranger 46 //----------------------------------------- 47 48 long WindowArranger::getDefaultBorder() 49 { 50 ImplSVData* pSVData = ImplGetSVData(); 51 long nResult = pSVData->maAppData.mnDefaultLayoutBorder; 52 if( nResult < 0 ) 53 { 54 OutputDevice* pDefDev = Application::GetDefaultDevice(); 55 if( pDefDev ) 56 { 57 Size aBorder( pDefDev->LogicToPixel( Size( 3, 3 ), MapMode( MAP_APPFONT ) ) ); 58 nResult = pSVData->maAppData.mnDefaultLayoutBorder = aBorder.Height(); 59 } 60 } 61 return nResult > 0 ? nResult : 0; 62 } 63 64 WindowArranger::~WindowArranger() 65 {} 66 67 void WindowArranger::setParent( WindowArranger* i_pParent ) 68 { 69 OSL_VERIFY( i_pParent->m_pParentWindow == m_pParentWindow || m_pParentWindow == NULL ); 70 71 m_pParentArranger = i_pParent; 72 m_pParentWindow = i_pParent->m_pParentWindow; 73 setParentWindow( m_pParentWindow ); 74 } 75 76 void WindowArranger::setParentWindow( Window* i_pNewParent ) 77 { 78 m_pParentWindow = i_pNewParent; 79 80 size_t nEle = countElements(); 81 for( size_t i = 0; i < nEle; i++ ) 82 { 83 Element* pEle = getElement( i ); 84 if( pEle ) // sanity check 85 { 86 #if OSL_DEBUG_LEVEL > 0 87 if( pEle->m_pElement ) 88 { 89 OSL_VERIFY( pEle->m_pElement->GetParent() == i_pNewParent ); 90 } 91 #endif 92 if( pEle->m_pChild ) 93 pEle->m_pChild->setParentWindow( i_pNewParent ); 94 } 95 } 96 } 97 98 void WindowArranger::show( bool i_bShow, bool i_bImmediateUpdate ) 99 { 100 size_t nEle = countElements(); 101 for( size_t i = 0; i < nEle; i++ ) 102 { 103 Element* pEle = getElement( i ); 104 if( pEle ) // sanity check 105 { 106 pEle->m_bHidden = ! i_bShow; 107 if( pEle->m_pElement ) 108 pEle->m_pElement->Show( i_bShow ); 109 if( pEle->m_pChild.get() ) 110 pEle->m_pChild->show( i_bShow, false ); 111 } 112 } 113 if( m_pParentArranger ) 114 { 115 nEle = m_pParentArranger->countElements(); 116 for( size_t i = 0; i < nEle; i++ ) 117 { 118 Element* pEle = m_pParentArranger->getElement( i ); 119 if( pEle && pEle->m_pChild.get() == this ) 120 { 121 pEle->m_bHidden = ! i_bShow; 122 break; 123 } 124 } 125 } 126 if( i_bImmediateUpdate ) 127 { 128 // find the topmost parent 129 WindowArranger* pResize = this; 130 while( pResize->m_pParentArranger ) 131 pResize = pResize->m_pParentArranger; 132 pResize->resize(); 133 } 134 } 135 136 bool WindowArranger::isVisible() const 137 { 138 size_t nEle = countElements(); 139 for( size_t i = 0; i < nEle; i++ ) 140 { 141 const Element* pEle = getConstElement( i ); 142 if( pEle->isVisible() ) 143 return true; 144 } 145 return false; 146 } 147 148 bool WindowArranger::Element::isVisible() const 149 { 150 bool bVisible = false; 151 if( ! m_bHidden ) 152 { 153 if( m_pElement ) 154 bVisible = m_pElement->IsVisible(); 155 else if( m_pChild ) 156 bVisible = m_pChild->isVisible(); 157 } 158 return bVisible; 159 } 160 161 sal_Int32 WindowArranger::Element::getExpandPriority() const 162 { 163 sal_Int32 nPrio = m_nExpandPriority; 164 if( m_pChild && m_nExpandPriority >= 0 ) 165 { 166 size_t nElements = m_pChild->countElements(); 167 for( size_t i = 0; i < nElements; i++ ) 168 { 169 sal_Int32 nCPrio = m_pChild->getExpandPriority( i ); 170 if( nCPrio > nPrio ) 171 nPrio = nCPrio; 172 } 173 } 174 return nPrio; 175 } 176 177 Size WindowArranger::Element::getOptimalSize( WindowSizeType i_eType ) const 178 { 179 Size aResult; 180 if( ! m_bHidden ) 181 { 182 bool bVisible = false; 183 if( m_pElement && m_pElement->IsVisible() ) 184 { 185 aResult = m_pElement->GetOptimalSize( i_eType ); 186 bVisible = true; 187 } 188 else if( m_pChild && m_pChild->isVisible() ) 189 { 190 aResult = m_pChild->getOptimalSize( i_eType ); 191 bVisible = true; 192 } 193 if( bVisible ) 194 { 195 if( aResult.Width() < m_aMinSize.Width() ) 196 aResult.Width() = m_aMinSize.Width(); 197 if( aResult.Height() < m_aMinSize.Height() ) 198 aResult.Height() = m_aMinSize.Height(); 199 aResult.Width() += getBorderValue( m_nLeftBorder ) + getBorderValue( m_nRightBorder ); 200 aResult.Height() += getBorderValue( m_nTopBorder ) + getBorderValue( m_nBottomBorder ); 201 } 202 } 203 204 return aResult; 205 } 206 207 void WindowArranger::Element::setPosSize( const Point& i_rPos, const Size& i_rSize ) 208 { 209 Point aPoint( i_rPos ); 210 Size aSize( i_rSize ); 211 aPoint.X() += getBorderValue( m_nLeftBorder ); 212 aPoint.Y() += getBorderValue( m_nTopBorder ); 213 aSize.Width() -= getBorderValue( m_nLeftBorder ) + getBorderValue( m_nRightBorder ); 214 aSize.Height() -= getBorderValue( m_nTopBorder ) + getBorderValue( m_nBottomBorder ); 215 if( m_pElement ) 216 m_pElement->SetPosSizePixel( aPoint, aSize ); 217 else if( m_pChild ) 218 m_pChild->setManagedArea( Rectangle( aPoint, aSize ) ); 219 } 220 221 uno::Sequence< beans::PropertyValue > WindowArranger::getProperties() const 222 { 223 uno::Sequence< beans::PropertyValue > aRet( 3 ); 224 aRet[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OuterBorder" ) ); 225 aRet[0].Value = uno::makeAny( sal_Int32( getBorderValue( m_nOuterBorder ) ) ); 226 aRet[1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ManagedArea" ) ); 227 awt::Rectangle aArea( m_aManagedArea.getX(), m_aManagedArea.getY(), m_aManagedArea.getWidth(), m_aManagedArea.getHeight() ); 228 aRet[1].Value = uno::makeAny( aArea ); 229 aRet[2].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) ); 230 aRet[2].Value = uno::makeAny( sal_Bool( isVisible() ) ); 231 return aRet; 232 } 233 234 void WindowArranger::setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) 235 { 236 const beans::PropertyValue* pProps = i_rProps.getConstArray(); 237 bool bResize = false; 238 for( sal_Int32 i = 0; i < i_rProps.getLength(); i++ ) 239 { 240 if( pProps[i].Name.equalsAscii( "OuterBorder" ) ) 241 { 242 sal_Int32 nVal = 0; 243 if( pProps[i].Value >>= nVal ) 244 { 245 if( getBorderValue( m_nOuterBorder ) != nVal ) 246 { 247 m_nOuterBorder = nVal; 248 bResize = true; 249 } 250 } 251 } 252 else if( pProps[i].Name.equalsAscii( "ManagedArea" ) ) 253 { 254 awt::Rectangle aArea( 0, 0, 0, 0 ); 255 if( pProps[i].Value >>= aArea ) 256 { 257 m_aManagedArea.setX( aArea.X ); 258 m_aManagedArea.setY( aArea.Y ); 259 m_aManagedArea.setWidth( aArea.Width ); 260 m_aManagedArea.setHeight( aArea.Height ); 261 bResize = true; 262 } 263 } 264 else if( pProps[i].Name.equalsAscii( "Visible" ) ) 265 { 266 sal_Bool bVal = sal_False; 267 if( pProps[i].Value >>= bVal ) 268 { 269 show( bVal, false ); 270 bResize = true; 271 } 272 } 273 } 274 if( bResize ) 275 resize(); 276 } 277 278 279 // ---------------------------------------- 280 // vcl::RowOrColumn 281 //----------------------------------------- 282 283 RowOrColumn::~RowOrColumn() 284 { 285 for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); 286 it != m_aElements.end(); ++it ) 287 { 288 it->deleteChild(); 289 } 290 } 291 292 Size RowOrColumn::getOptimalSize( WindowSizeType i_eType ) const 293 { 294 Size aRet( 0, 0 ); 295 long nDistance = getBorderValue( m_nBorderWidth ); 296 for( std::vector< WindowArranger::Element >::const_iterator it = m_aElements.begin(); 297 it != m_aElements.end(); ++it ) 298 { 299 if( it->isVisible() ) 300 { 301 // get the size of type of the managed element 302 Size aElementSize( it->getOptimalSize( i_eType ) ); 303 if( m_bColumn ) 304 { 305 // add the distance between elements 306 aRet.Height() += nDistance; 307 // check if the width needs adjustment 308 if( aRet.Width() < aElementSize.Width() ) 309 aRet.Width() = aElementSize.Width(); 310 aRet.Height() += aElementSize.Height(); 311 } 312 else 313 { 314 // add the distance between elements 315 aRet.Width() += nDistance; 316 // check if the height needs adjustment 317 if( aRet.Height() < aElementSize.Height() ) 318 aRet.Height() = aElementSize.Height(); 319 aRet.Width() += aElementSize.Width(); 320 } 321 } 322 } 323 324 if( aRet.Width() != 0 || aRet.Height() != 0 ) 325 { 326 // subtract the border for the first element 327 if( m_bColumn ) 328 aRet.Height() -= nDistance; 329 else 330 aRet.Width() -= nDistance; 331 332 // add the outer border 333 long nOuterBorder = getBorderValue( m_nOuterBorder ); 334 aRet.Width() += 2*nOuterBorder; 335 aRet.Height() += 2*nOuterBorder; 336 } 337 338 return aRet; 339 } 340 341 void RowOrColumn::distributeRowWidth( std::vector<Size>& io_rSizes, long /*i_nUsedWidth*/, long i_nExtraWidth ) 342 { 343 if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() ) 344 { 345 // find all elements with the highest expand priority 346 size_t nElements = m_aElements.size(); 347 std::vector< size_t > aIndices; 348 sal_Int32 nHighPrio = 0; 349 for( size_t i = 0; i < nElements; i++ ) 350 { 351 if( m_aElements[ i ].isVisible() ) 352 { 353 sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority(); 354 if( nCurPrio > nHighPrio ) 355 { 356 aIndices.clear(); 357 nHighPrio = nCurPrio; 358 } 359 if( nCurPrio == nHighPrio ) 360 aIndices.push_back( i ); 361 } 362 } 363 364 // distribute extra space evenly among collected elements 365 nElements = aIndices.size(); 366 if( nElements > 0 ) 367 { 368 long nDelta = i_nExtraWidth / nElements; 369 for( size_t i = 0; i < nElements; i++ ) 370 { 371 io_rSizes[ aIndices[i] ].Width() += nDelta; 372 i_nExtraWidth -= nDelta; 373 } 374 // add the last pixels to the last row element 375 if( i_nExtraWidth > 0 && nElements > 0 ) 376 io_rSizes[aIndices.back()].Width() += i_nExtraWidth; 377 } 378 } 379 } 380 381 void RowOrColumn::distributeColumnHeight( std::vector<Size>& io_rSizes, long /*i_nUsedHeight*/, long i_nExtraHeight ) 382 { 383 if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() ) 384 { 385 // find all elements with the highest expand priority 386 size_t nElements = m_aElements.size(); 387 std::vector< size_t > aIndices; 388 sal_Int32 nHighPrio = 3; 389 for( size_t i = 0; i < nElements; i++ ) 390 { 391 if( m_aElements[ i ].isVisible() ) 392 { 393 sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority(); 394 if( nCurPrio > nHighPrio ) 395 { 396 aIndices.clear(); 397 nHighPrio = nCurPrio; 398 } 399 if( nCurPrio == nHighPrio ) 400 aIndices.push_back( i ); 401 } 402 } 403 404 // distribute extra space evenly among collected elements 405 nElements = aIndices.size(); 406 if( nElements > 0 ) 407 { 408 long nDelta = i_nExtraHeight / nElements; 409 for( size_t i = 0; i < nElements; i++ ) 410 { 411 io_rSizes[ aIndices[i] ].Height() += nDelta; 412 i_nExtraHeight -= nDelta; 413 } 414 // add the last pixels to the last row element 415 if( i_nExtraHeight > 0 && nElements > 0 ) 416 io_rSizes[aIndices.back()].Height() += i_nExtraHeight; 417 } 418 } 419 } 420 421 void RowOrColumn::resize() 422 { 423 // check if we can get optimal size, else fallback to minimal size 424 Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED ) ); 425 WindowSizeType eType = WINDOWSIZE_PREFERRED; 426 if( m_bColumn ) 427 { 428 if( aOptSize.Height() > m_aManagedArea.GetHeight() ) 429 eType = WINDOWSIZE_MINIMUM; 430 } 431 else 432 { 433 if( aOptSize.Width() > m_aManagedArea.GetWidth() ) 434 eType = WINDOWSIZE_MINIMUM; 435 } 436 437 size_t nElements = m_aElements.size(); 438 // get all element sizes for sizing 439 std::vector<Size> aElementSizes( nElements ); 440 long nDistance = getBorderValue( m_nBorderWidth ); 441 long nOuterBorder = getBorderValue( m_nOuterBorder ); 442 long nUsedWidth = 2*nOuterBorder - (nElements ? nDistance : 0); 443 for( size_t i = 0; i < nElements; i++ ) 444 { 445 if( m_aElements[i].isVisible() ) 446 { 447 aElementSizes[i] = m_aElements[i].getOptimalSize( eType ); 448 if( m_bColumn ) 449 { 450 aElementSizes[i].Width() = m_aManagedArea.GetWidth() - 2 * nOuterBorder; 451 nUsedWidth += aElementSizes[i].Height() + nDistance; 452 } 453 else 454 { 455 aElementSizes[i].Height() = m_aManagedArea.GetHeight() - 2 * nOuterBorder; 456 nUsedWidth += aElementSizes[i].Width() + nDistance; 457 } 458 } 459 } 460 461 long nExtraWidth = (m_bColumn ? m_aManagedArea.GetHeight() : m_aManagedArea.GetWidth()) - nUsedWidth; 462 if( nExtraWidth > 0 ) 463 { 464 if( m_bColumn ) 465 distributeColumnHeight( aElementSizes, nUsedWidth, nExtraWidth ); 466 else 467 distributeRowWidth( aElementSizes, nUsedWidth, nExtraWidth ); 468 } 469 470 // get starting position 471 Point aElementPos( m_aManagedArea.TopLeft() ); 472 // outer border 473 aElementPos.X() += nOuterBorder; 474 aElementPos.Y() += nOuterBorder; 475 476 // position managed windows 477 for( size_t i = 0; i < nElements; i++ ) 478 { 479 // get the size of type of the managed element 480 if( m_aElements[i].isVisible() ) 481 { 482 m_aElements[i].setPosSize( aElementPos, aElementSizes[i] ); 483 if( m_bColumn ) 484 aElementPos.Y() += nDistance + aElementSizes[i].Height(); 485 else 486 aElementPos.X() += nDistance + aElementSizes[i].Width(); 487 } 488 } 489 } 490 491 size_t RowOrColumn::addWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio, const Size& i_rMinSize, size_t i_nIndex ) 492 { 493 size_t nIndex = i_nIndex; 494 if( i_nIndex >= m_aElements.size() ) 495 { 496 nIndex = m_aElements.size(); 497 m_aElements.push_back( WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) ); 498 } 499 else 500 { 501 std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); 502 while( i_nIndex-- ) 503 ++it; 504 m_aElements.insert( it, WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) ); 505 } 506 return nIndex; 507 } 508 509 size_t RowOrColumn::addChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio, size_t i_nIndex ) 510 { 511 size_t nIndex = i_nIndex; 512 if( i_nIndex >= m_aElements.size() ) 513 { 514 nIndex = m_aElements.size(); 515 m_aElements.push_back( WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) ); 516 } 517 else 518 { 519 std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); 520 while( i_nIndex-- ) 521 ++it; 522 m_aElements.insert( it, WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) ); 523 } 524 return nIndex; 525 } 526 527 void RowOrColumn::remove( Window* i_pWindow ) 528 { 529 if( i_pWindow ) 530 { 531 for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); 532 it != m_aElements.end(); ++it ) 533 { 534 if( it->m_pElement == i_pWindow ) 535 { 536 m_aElements.erase( it ); 537 return; 538 } 539 } 540 } 541 } 542 543 void RowOrColumn::remove( boost::shared_ptr<WindowArranger> const & i_pChild ) 544 { 545 if( i_pChild ) 546 { 547 for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); 548 it != m_aElements.end(); ++it ) 549 { 550 if( it->m_pChild == i_pChild ) 551 { 552 m_aElements.erase( it ); 553 return; 554 } 555 } 556 } 557 } 558 559 // ---------------------------------------- 560 // vcl::LabeledElement 561 //----------------------------------------- 562 563 LabeledElement::~LabeledElement() 564 { 565 m_aLabel.deleteChild(); 566 m_aElement.deleteChild(); 567 } 568 569 Size LabeledElement::getOptimalSize( WindowSizeType i_eType ) const 570 { 571 Size aRet( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) ); 572 if( aRet.Width() != 0 ) 573 { 574 if( m_nLabelColumnWidth != 0 ) 575 aRet.Width() = m_nLabelColumnWidth; 576 else 577 aRet.Width() += getBorderValue( m_nDistance ); 578 } 579 Size aElementSize( m_aElement.getOptimalSize( i_eType ) ); 580 aRet.Width() += aElementSize.Width(); 581 if( aElementSize.Height() > aRet.Height() ) 582 aRet.Height() = aElementSize.Height(); 583 if( aRet.Height() != 0 ) 584 aRet.Height() += 2 * getBorderValue( m_nOuterBorder ); 585 586 return aRet; 587 } 588 589 void LabeledElement::resize() 590 { 591 Size aLabelSize( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) ); 592 Size aElementSize( m_aElement.getOptimalSize( WINDOWSIZE_PREFERRED ) ); 593 long nDistance = getBorderValue( m_nDistance ); 594 long nOuterBorder = getBorderValue( m_nOuterBorder ); 595 if( nDistance + aLabelSize.Width() + aElementSize.Width() > m_aManagedArea.GetWidth() ) 596 aElementSize = m_aElement.getOptimalSize( WINDOWSIZE_MINIMUM ); 597 598 // align label and element vertically in LabeledElement 599 long nYOff = (m_aManagedArea.GetHeight() - 2*nOuterBorder - aLabelSize.Height()) / 2; 600 Point aPos( m_aManagedArea.Left(), 601 m_aManagedArea.Top() + nOuterBorder + nYOff ); 602 Size aSize( aLabelSize ); 603 if( m_nLabelColumnWidth != 0 ) 604 aSize.Width() = m_nLabelColumnWidth; 605 m_aLabel.setPosSize( aPos, aSize ); 606 607 aPos.X() += aSize.Width() + nDistance; 608 nYOff = (m_aManagedArea.GetHeight() - 2*nOuterBorder - aElementSize.Height()) / 2; 609 aPos.Y() = m_aManagedArea.Top() + nOuterBorder + nYOff; 610 aSize.Width() = aElementSize.Width(); 611 aSize.Height() = m_aManagedArea.GetHeight() - 2*nOuterBorder; 612 613 // label style 614 // 0: position left and right 615 // 1: keep the element close to label and grow it 616 // 2: keep the element close and don't grow it 617 if( m_nLabelStyle == 0) 618 { 619 if( aPos.X() + aSize.Width() < m_aManagedArea.Right() ) 620 aPos.X() = m_aManagedArea.Right() - aSize.Width(); 621 } 622 else if( m_nLabelStyle == 1 ) 623 { 624 if( aPos.X() + aSize.Width() < m_aManagedArea.Right() ) 625 aSize.Width() = m_aManagedArea.Right() - aPos.X(); 626 } 627 m_aElement.setPosSize( aPos, aSize ); 628 } 629 630 void LabeledElement::setLabel( Window* i_pLabel ) 631 { 632 m_aLabel.m_pElement = i_pLabel; 633 m_aLabel.m_pChild.reset(); 634 } 635 636 void LabeledElement::setLabel( boost::shared_ptr<WindowArranger> const & i_pLabel ) 637 { 638 m_aLabel.m_pElement = NULL; 639 m_aLabel.m_pChild = i_pLabel; 640 } 641 642 void LabeledElement::setElement( Window* i_pElement ) 643 { 644 m_aElement.m_pElement = i_pElement; 645 m_aElement.m_pChild.reset(); 646 } 647 648 void LabeledElement::setElement( boost::shared_ptr<WindowArranger> const & i_pElement ) 649 { 650 m_aElement.m_pElement = NULL; 651 m_aElement.m_pChild = i_pElement; 652 } 653 654 // ---------------------------------------- 655 // vcl::LabelColumn 656 //----------------------------------------- 657 LabelColumn::~LabelColumn() 658 { 659 } 660 661 long LabelColumn::getLabelWidth() const 662 { 663 long nWidth = 0; 664 665 size_t nEle = countElements(); 666 for( size_t i = 0; i < nEle; i++ ) 667 { 668 const Element* pEle = getConstElement( i ); 669 if( pEle && pEle->m_pChild.get() ) 670 { 671 const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get()); 672 if( pLabel ) 673 { 674 Window* pLW = pLabel->getWindow( 0 ); 675 if( pLW ) 676 { 677 Size aLabSize( pLW->GetOptimalSize( WINDOWSIZE_MINIMUM ) ); 678 long nLB = 0; 679 pLabel->getBorders(0, &nLB); 680 aLabSize.Width() += getBorderValue( nLB ); 681 if( aLabSize.Width() > nWidth ) 682 nWidth = aLabSize.Width(); 683 } 684 } 685 } 686 } 687 return nWidth + getBorderValue( getBorderWidth() ); 688 } 689 690 Size LabelColumn::getOptimalSize( WindowSizeType i_eType ) const 691 { 692 long nWidth = getLabelWidth(); 693 long nOuterBorder = getBorderValue( m_nOuterBorder ); 694 Size aColumnSize; 695 696 // every child is a LabeledElement 697 size_t nEle = countElements(); 698 for( size_t i = 0; i < nEle; i++ ) 699 { 700 Size aElementSize; 701 const Element* pEle = getConstElement( i ); 702 if( pEle && pEle->m_pChild.get() ) 703 { 704 const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get()); 705 if( pLabel ) // we have a label 706 { 707 aElementSize = pLabel->getLabelSize( WINDOWSIZE_MINIMUM ); 708 if( aElementSize.Width() ) 709 aElementSize.Width() = nWidth; 710 Size aSize( pLabel->getElementSize( i_eType ) ); 711 aElementSize.Width() += aSize.Width(); 712 if( aSize.Height() > aElementSize.Height() ) 713 aElementSize.Height() = aSize.Height(); 714 } 715 else // a non label, just treat it as a row 716 { 717 aElementSize = pEle->getOptimalSize( i_eType ); 718 } 719 } 720 else if( pEle && pEle->m_pElement ) // a general window, treat is as a row 721 { 722 aElementSize = pEle->getOptimalSize( i_eType ); 723 } 724 if( aElementSize.Width() ) 725 { 726 aElementSize.Width() += 2*nOuterBorder; 727 if( aElementSize.Width() > aColumnSize.Width() ) 728 aColumnSize.Width() = aElementSize.Width(); 729 } 730 if( aElementSize.Height() ) 731 { 732 aColumnSize.Height() += getBorderValue( getBorderWidth() ) + aElementSize.Height(); 733 } 734 } 735 if( nEle > 0 && aColumnSize.Height() ) 736 { 737 aColumnSize.Height() -= getBorderValue( getBorderWidth() ); // for the first element 738 aColumnSize.Height() += 2*nOuterBorder; 739 } 740 return aColumnSize; 741 } 742 743 void LabelColumn::resize() 744 { 745 long nWidth = getLabelWidth(); 746 size_t nEle = countElements(); 747 for( size_t i = 0; i < nEle; i++ ) 748 { 749 Element* pEle = getElement( i ); 750 if( pEle && pEle->m_pChild.get() ) 751 { 752 LabeledElement* pLabel = dynamic_cast< LabeledElement* >(pEle->m_pChild.get()); 753 if( pLabel ) 754 pLabel->setLabelColumnWidth( nWidth ); 755 } 756 } 757 RowOrColumn::resize(); 758 } 759 760 size_t LabelColumn::addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent ) 761 { 762 boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) ); 763 xLabel->setLabel( i_pLabel ); 764 xLabel->setBorders( 0, i_nIndent, 0, 0, 0 ); 765 xLabel->setElement( i_rElement ); 766 size_t nIndex = addChild( xLabel ); 767 resize(); 768 return nIndex; 769 } 770 771 size_t LabelColumn::addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent, const Size& i_rElementMinSize ) 772 { 773 boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) ); 774 xLabel->setLabel( i_pLabel ); 775 xLabel->setBorders( 0, i_nIndent, 0, 0, 0 ); 776 xLabel->setElement( i_pElement ); 777 xLabel->setMinimumSize( 1, i_rElementMinSize ); 778 size_t nIndex = addChild( xLabel ); 779 resize(); 780 return nIndex; 781 } 782 783 // ---------------------------------------- 784 // vcl::Indenter 785 //----------------------------------------- 786 787 Indenter::~Indenter() 788 { 789 m_aElement.deleteChild(); 790 } 791 792 Size Indenter::getOptimalSize( WindowSizeType i_eType ) const 793 { 794 Size aSize( m_aElement.getOptimalSize( i_eType ) ); 795 long nOuterBorder = getBorderValue( m_nOuterBorder ); 796 long nIndent = getBorderValue( m_nIndent ); 797 aSize.Width() += 2*nOuterBorder + nIndent; 798 aSize.Height() += 2*nOuterBorder; 799 return aSize; 800 } 801 802 void Indenter::resize() 803 { 804 long nOuterBorder = getBorderValue( m_nOuterBorder ); 805 long nIndent = getBorderValue( m_nIndent ); 806 Point aPt( m_aManagedArea.TopLeft() ); 807 aPt.X() += nOuterBorder + nIndent; 808 aPt.Y() += nOuterBorder; 809 Size aSz( m_aManagedArea.GetSize() ); 810 aSz.Width() -= 2*nOuterBorder + nIndent; 811 aSz.Height() -= 2*nOuterBorder; 812 m_aElement.setPosSize( aPt, aSz ); 813 } 814 815 void Indenter::setWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio ) 816 { 817 OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0) || i_pWindow == 0 ); 818 OSL_VERIFY( i_pWindow == 0 || i_pWindow->GetParent() == m_pParentWindow ); 819 m_aElement.m_pElement = i_pWindow; 820 m_aElement.m_nExpandPriority = i_nExpandPrio; 821 } 822 823 void Indenter::setChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio ) 824 { 825 OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0 ) || i_pChild == 0 ); 826 m_aElement.m_pChild = i_pChild; 827 m_aElement.m_nExpandPriority = i_nExpandPrio; 828 } 829 830 // ---------------------------------------- 831 // vcl::MatrixArranger 832 //----------------------------------------- 833 MatrixArranger::~MatrixArranger() 834 { 835 } 836 837 Size MatrixArranger::getOptimalSize( WindowSizeType i_eType, 838 std::vector<long>& o_rColumnWidths, std::vector<long>& o_rRowHeights, 839 std::vector<sal_Int32>& o_rColumnPrio, std::vector<sal_Int32>& o_rRowPrio 840 ) const 841 { 842 long nOuterBorder = getBorderValue( m_nOuterBorder ); 843 Size aMatrixSize( 2*nOuterBorder, 2*nOuterBorder ); 844 845 // first find out the current number of rows and columns 846 sal_uInt32 nRows = 0, nColumns = 0; 847 for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin(); 848 it != m_aElements.end(); ++it ) 849 { 850 if( it->m_nX >= nColumns ) 851 nColumns = it->m_nX+1; 852 if( it->m_nY >= nRows ) 853 nRows = it->m_nY+1; 854 } 855 856 // now allocate row and column depth vectors 857 o_rColumnWidths = std::vector< long >( nColumns, 0 ); 858 o_rRowHeights = std::vector< long >( nRows, 0 ); 859 o_rColumnPrio = std::vector< sal_Int32 >( nColumns, 0 ); 860 o_rRowPrio = std::vector< sal_Int32 >( nRows, 0 ); 861 862 // get sizes an allocate them into rows/columns 863 for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin(); 864 it != m_aElements.end(); ++it ) 865 { 866 Size aSize( it->getOptimalSize( i_eType ) ); 867 if( aSize.Width() > o_rColumnWidths[ it->m_nX ] ) 868 o_rColumnWidths[ it->m_nX ] = aSize.Width(); 869 if( aSize.Height() > o_rRowHeights[ it->m_nY ] ) 870 o_rRowHeights[ it->m_nY ] = aSize.Height(); 871 if( it->m_nExpandPriority > o_rColumnPrio[ it->m_nX ] ) 872 o_rColumnPrio[ it->m_nX ] = it->m_nExpandPriority; 873 if( it->m_nExpandPriority > o_rRowPrio[ it->m_nY ] ) 874 o_rRowPrio[ it->m_nY ] = it->m_nExpandPriority; 875 } 876 877 // add up sizes 878 long nDistanceX = getBorderValue( m_nBorderX ); 879 long nDistanceY = getBorderValue( m_nBorderY ); 880 for( sal_uInt32 i = 0; i < nColumns; i++ ) 881 aMatrixSize.Width() += o_rColumnWidths[i] + nDistanceX; 882 if( nColumns > 0 ) 883 aMatrixSize.Width() -= nDistanceX; 884 885 for( sal_uInt32 i = 0; i < nRows; i++ ) 886 aMatrixSize.Height() += o_rRowHeights[i] + nDistanceY; 887 if( nRows > 0 ) 888 aMatrixSize.Height() -= nDistanceY; 889 890 return aMatrixSize; 891 } 892 893 Size MatrixArranger::getOptimalSize( WindowSizeType i_eType ) const 894 { 895 std::vector<long> aColumnWidths, aRowHeights; 896 std::vector<sal_Int32> aColumnPrio, aRowPrio; 897 return getOptimalSize( i_eType, aColumnWidths, aRowHeights, aColumnPrio, aRowPrio ); 898 } 899 900 void MatrixArranger::distributeExtraSize( std::vector<long>& io_rSizes, const std::vector<sal_Int32>& i_rPrios, long i_nExtraWidth ) 901 { 902 if( ! io_rSizes.empty() && io_rSizes.size() == i_rPrios.size() ) // sanity check 903 { 904 // find all elements with the highest expand priority 905 size_t nElements = io_rSizes.size(); 906 std::vector< size_t > aIndices; 907 sal_Int32 nHighPrio = 0; 908 for( size_t i = 0; i < nElements; i++ ) 909 { 910 sal_Int32 nCurPrio = i_rPrios[ i ]; 911 if( nCurPrio > nHighPrio ) 912 { 913 aIndices.clear(); 914 nHighPrio = nCurPrio; 915 } 916 if( nCurPrio == nHighPrio ) 917 aIndices.push_back( i ); 918 } 919 920 // distribute extra space evenly among collected elements 921 nElements = aIndices.size(); 922 if( nElements > 0 ) 923 { 924 long nDelta = i_nExtraWidth / nElements; 925 for( size_t i = 0; i < nElements; i++ ) 926 { 927 io_rSizes[ aIndices[i] ] += nDelta; 928 i_nExtraWidth -= nDelta; 929 } 930 // add the last pixels to the last row element 931 if( i_nExtraWidth > 0 && nElements > 0 ) 932 io_rSizes[aIndices.back()] += i_nExtraWidth; 933 } 934 } 935 } 936 937 938 void MatrixArranger::resize() 939 { 940 // assure that we have at least one row and column 941 if( m_aElements.empty() ) 942 return; 943 944 // check if we can get optimal size, else fallback to minimal size 945 std::vector<long> aColumnWidths, aRowHeights; 946 std::vector<sal_Int32> aColumnPrio, aRowPrio; 947 Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED, aColumnWidths, aRowHeights, aColumnPrio, aRowPrio ) ); 948 if( aOptSize.Height() > m_aManagedArea.GetHeight() || 949 aOptSize.Width() > m_aManagedArea.GetWidth() ) 950 { 951 std::vector<long> aMinColumnWidths, aMinRowHeights; 952 getOptimalSize( WINDOWSIZE_MINIMUM, aMinColumnWidths, aMinRowHeights, aColumnPrio, aRowPrio ); 953 if( aOptSize.Height() > m_aManagedArea.GetHeight() ) 954 aRowHeights = aMinRowHeights; 955 if( aOptSize.Width() > m_aManagedArea.GetWidth() ) 956 aColumnWidths = aMinColumnWidths; 957 } 958 959 // distribute extra space available 960 long nExtraSize = m_aManagedArea.GetWidth(); 961 for( size_t i = 0; i < aColumnWidths.size(); ++i ) 962 nExtraSize -= aColumnWidths[i] + m_nBorderX; 963 if( nExtraSize > 0 ) 964 distributeExtraSize( aColumnWidths, aColumnPrio, nExtraSize ); 965 nExtraSize = m_aManagedArea.GetHeight(); 966 for( size_t i = 0; i < aRowHeights.size(); ++i ) 967 nExtraSize -= aRowHeights[i] + m_nBorderY; 968 if( nExtraSize > 0 ) 969 distributeExtraSize( aRowHeights, aRowPrio, nExtraSize ); 970 971 // prepare offsets 972 long nDistanceX = getBorderValue( m_nBorderX ); 973 long nDistanceY = getBorderValue( m_nBorderY ); 974 long nOuterBorder = getBorderValue( m_nOuterBorder ); 975 std::vector<long> aColumnX( aColumnWidths.size() ); 976 aColumnX[0] = m_aManagedArea.Left() + nOuterBorder; 977 for( size_t i = 1; i < aColumnX.size(); i++ ) 978 aColumnX[i] = aColumnX[i-1] + aColumnWidths[i-1] + nDistanceX; 979 980 std::vector<long> aRowY( aRowHeights.size() ); 981 aRowY[0] = m_aManagedArea.Top() + nOuterBorder; 982 for( size_t i = 1; i < aRowY.size(); i++ ) 983 aRowY[i] = aRowY[i-1] + aRowHeights[i-1] + nDistanceY; 984 985 // now iterate over the elements and assign their positions 986 for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); 987 it != m_aElements.end(); ++it ) 988 { 989 Point aCellPos( aColumnX[it->m_nX], aRowY[it->m_nY] ); 990 Size aCellSize( aColumnWidths[it->m_nX], aRowHeights[it->m_nY] ); 991 it->setPosSize( aCellPos, aCellSize ); 992 } 993 } 994 995 size_t MatrixArranger::addWindow( Window* i_pWindow, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio, const Size& i_rMinSize ) 996 { 997 sal_uInt64 nMapValue = getMap( i_nX, i_nY ); 998 std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue ); 999 size_t nIndex = 0; 1000 if( it == m_aMatrixMap.end() ) 1001 { 1002 m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size(); 1003 m_aElements.push_back( MatrixElement( i_pWindow, i_nX, i_nY, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) ); 1004 } 1005 else 1006 { 1007 MatrixElement& rEle( m_aElements[ it->second ] ); 1008 rEle.m_pElement = i_pWindow; 1009 rEle.m_pChild.reset(); 1010 rEle.m_nExpandPriority = i_nExpandPrio; 1011 rEle.m_aMinSize = i_rMinSize; 1012 rEle.m_nX = i_nX; 1013 rEle.m_nY = i_nY; 1014 nIndex = it->second; 1015 } 1016 return nIndex; 1017 } 1018 1019 void MatrixArranger::remove( Window* i_pWindow ) 1020 { 1021 if( i_pWindow ) 1022 { 1023 for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); 1024 it != m_aElements.end(); ++it ) 1025 { 1026 if( it->m_pElement == i_pWindow ) 1027 { 1028 m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) ); 1029 m_aElements.erase( it ); 1030 return; 1031 } 1032 } 1033 } 1034 } 1035 1036 size_t MatrixArranger::addChild( boost::shared_ptr<WindowArranger> const &i_pChild, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio ) 1037 { 1038 sal_uInt64 nMapValue = getMap( i_nX, i_nY ); 1039 std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue ); 1040 size_t nIndex = 0; 1041 if( it == m_aMatrixMap.end() ) 1042 { 1043 m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size(); 1044 m_aElements.push_back( MatrixElement( NULL, i_nX, i_nY, i_pChild, i_nExpandPrio ) ); 1045 } 1046 else 1047 { 1048 MatrixElement& rEle( m_aElements[ it->second ] ); 1049 rEle.m_pElement = 0; 1050 rEle.m_pChild = i_pChild; 1051 rEle.m_nExpandPriority = i_nExpandPrio; 1052 rEle.m_nX = i_nX; 1053 rEle.m_nY = i_nY; 1054 nIndex = it->second; 1055 } 1056 return nIndex; 1057 } 1058 1059 void MatrixArranger::remove( boost::shared_ptr<WindowArranger> const &i_pChild ) 1060 { 1061 if( i_pChild ) 1062 { 1063 for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); 1064 it != m_aElements.end(); ++it ) 1065 { 1066 if( it->m_pChild == i_pChild ) 1067 { 1068 m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) ); 1069 m_aElements.erase( it ); 1070 return; 1071 } 1072 } 1073 } 1074 } 1075 1076