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