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
getDefaultBorder()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
~WindowArranger()60 WindowArranger::~WindowArranger()
61 {}
62
setParent(WindowArranger * i_pParent)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
setParentWindow(Window * i_pNewParent)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
show(bool i_bShow,bool i_bImmediateUpdate)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
isVisible() const132 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
isVisible() const144 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
getExpandPriority() const157 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
getOptimalSize(WindowSizeType i_eType) const173 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
setPosSize(const Point & i_rPos,const Size & i_rSize)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
getProperties() const217 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
setProperties(const uno::Sequence<beans::PropertyValue> & i_rProps)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
~RowOrColumn()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
getOptimalSize(WindowSizeType i_eType) const288 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
distributeRowWidth(std::vector<Size> & io_rSizes,long,long i_nExtraWidth)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
distributeColumnHeight(std::vector<Size> & io_rSizes,long,long i_nExtraHeight)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
resize()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
addWindow(Window * i_pWindow,sal_Int32 i_nExpandPrio,const Size & i_rMinSize,size_t i_nIndex)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
addChild(boost::shared_ptr<WindowArranger> const & i_pChild,sal_Int32 i_nExpandPrio,size_t i_nIndex)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
remove(Window * i_pWindow)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
remove(boost::shared_ptr<WindowArranger> const & i_pChild)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
~LabeledElement()559 LabeledElement::~LabeledElement()
560 {
561 m_aLabel.deleteChild();
562 m_aElement.deleteChild();
563 }
564
getOptimalSize(WindowSizeType i_eType) const565 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
resize()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
setLabel(Window * i_pLabel)626 void LabeledElement::setLabel( Window* i_pLabel )
627 {
628 m_aLabel.m_pElement = i_pLabel;
629 m_aLabel.m_pChild.reset();
630 }
631
setLabel(boost::shared_ptr<WindowArranger> const & i_pLabel)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
setElement(Window * i_pElement)638 void LabeledElement::setElement( Window* i_pElement )
639 {
640 m_aElement.m_pElement = i_pElement;
641 m_aElement.m_pChild.reset();
642 }
643
setElement(boost::shared_ptr<WindowArranger> const & i_pElement)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 //-----------------------------------------
~LabelColumn()653 LabelColumn::~LabelColumn()
654 {
655 }
656
getLabelWidth() const657 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
getOptimalSize(WindowSizeType i_eType) const686 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
resize()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
addRow(Window * i_pLabel,boost::shared_ptr<WindowArranger> const & i_rElement,long i_nIndent)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
addRow(Window * i_pLabel,Window * i_pElement,long i_nIndent,const Size & i_rElementMinSize)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
~Indenter()783 Indenter::~Indenter()
784 {
785 m_aElement.deleteChild();
786 }
787
getOptimalSize(WindowSizeType i_eType) const788 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
resize()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
setWindow(Window * i_pWindow,sal_Int32 i_nExpandPrio)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
setChild(boost::shared_ptr<WindowArranger> const & i_pChild,sal_Int32 i_nExpandPrio)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 //-----------------------------------------
~MatrixArranger()829 MatrixArranger::~MatrixArranger()
830 {
831 }
832
getOptimalSize(WindowSizeType i_eType,std::vector<long> & o_rColumnWidths,std::vector<long> & o_rRowHeights,std::vector<sal_Int32> & o_rColumnPrio,std::vector<sal_Int32> & o_rRowPrio) const833 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
getOptimalSize(WindowSizeType i_eType) const889 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
distributeExtraSize(std::vector<long> & io_rSizes,const std::vector<sal_Int32> & i_rPrios,long i_nExtraWidth)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
resize()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
addWindow(Window * i_pWindow,sal_uInt32 i_nX,sal_uInt32 i_nY,sal_Int32 i_nExpandPrio,const Size & i_rMinSize)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
remove(Window * i_pWindow)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
addChild(boost::shared_ptr<WindowArranger> const & i_pChild,sal_uInt32 i_nX,sal_uInt32 i_nY,sal_Int32 i_nExpandPrio)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
remove(boost::shared_ptr<WindowArranger> const & i_pChild)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