1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "DeckLayouter.hxx"
21 #include <sfx2/sidebar/Theme.hxx>
23 #include "PanelTitleBar.hxx"
26 #include <vcl/window.hxx>
27 #include <vcl/scrbar.hxx>
30 using namespace css::uno
;
32 namespace sfx2
{ namespace sidebar
{
35 static const sal_Int32
MinimalPanelHeight (25);
46 VclPtr
<Panel
> mpPanel
;
47 css::ui::LayoutSize maLayoutSize
;
48 sal_Int32 mnDistributedHeight
;
50 sal_Int32 mnPanelIndex
;
54 : mpPanel(),maLayoutSize(0,0,0),mnDistributedHeight(0),mnWeight(0),mnPanelIndex(0),mbShowTitleBar(true)
57 Rectangle
LayoutPanels (
58 const Rectangle
& rContentArea
,
59 sal_Int32
& rMinimalWidth
,
60 ::std::vector
<LayoutItem
>& rLayoutItems
,
61 vcl::Window
& rScrollClipWindow
,
62 vcl::Window
& rScrollContainer
,
63 ScrollBar
& pVerticalScrollBar
,
64 const bool bShowVerticalScrollBar
);
65 void GetRequestedSizes (
66 ::std::vector
<LayoutItem
>& rLayoutItem
,
67 sal_Int32
& rAvailableHeight
,
68 sal_Int32
& rMinimalWidth
,
69 const Rectangle
& rContentBox
);
70 void DistributeHeights (
71 ::std::vector
<LayoutItem
>& rLayoutItems
,
72 const sal_Int32 nHeightToDistribute
,
73 const sal_Int32 nContainerHeight
,
74 const bool bMinimumHeightIsBase
);
75 sal_Int32
PlacePanels (
76 ::std::vector
<LayoutItem
>& rLayoutItems
,
77 const sal_Int32 nWidth
,
78 const LayoutMode eMode
,
79 vcl::Window
& rScrollContainer
);
80 Rectangle
PlaceDeckTitle (
81 vcl::Window
& rTittleBar
,
82 const Rectangle
& rAvailableSpace
);
83 Rectangle
PlaceVerticalScrollBar (
84 ScrollBar
& rVerticalScrollBar
,
85 const Rectangle
& rAvailableSpace
,
86 const bool bShowVerticalScrollBar
);
87 void SetupVerticalScrollBar(
88 ScrollBar
& rVerticalScrollBar
,
89 const sal_Int32 nContentHeight
,
90 const sal_Int32 nVisibleHeight
);
93 const Rectangle
& rBox
);
96 #define IterateLayoutItems(iterator_name,container) \
97 for(::std::vector<LayoutItem>::iterator \
98 iterator_name(container.begin()), \
99 iEnd(container.end()); \
100 iterator_name!=iEnd; \
103 void DeckLayouter::LayoutDeck (
104 const Rectangle
& rContentArea
,
105 sal_Int32
& rMinimalWidth
,
106 SharedPanelContainer
& rPanels
,
107 vcl::Window
& rDeckTitleBar
,
108 vcl::Window
& rScrollClipWindow
,
109 vcl::Window
& rScrollContainer
,
110 vcl::Window
& rFiller
,
111 ScrollBar
& rVerticalScrollBar
)
113 if (rContentArea
.GetWidth()<=0 || rContentArea
.GetHeight()<=0)
115 Rectangle
aBox (PlaceDeckTitle(rDeckTitleBar
, rContentArea
));
117 if ( ! rPanels
.empty())
119 // Prepare the layout item container.
120 ::std::vector
<LayoutItem
> aLayoutItems
;
121 aLayoutItems
.resize(rPanels
.size());
122 for (sal_Int32
nIndex(0),nCount(rPanels
.size()); nIndex
<nCount
; ++nIndex
)
124 aLayoutItems
[nIndex
].mpPanel
= rPanels
[nIndex
];
125 aLayoutItems
[nIndex
].mnPanelIndex
= nIndex
;
136 UpdateFiller(rFiller
, aBox
);
141 Rectangle
LayoutPanels (
142 const Rectangle
& rContentArea
,
143 sal_Int32
& rMinimalWidth
,
144 ::std::vector
<LayoutItem
>& rLayoutItems
,
145 vcl::Window
& rScrollClipWindow
,
146 vcl::Window
& rScrollContainer
,
147 ScrollBar
& rVerticalScrollBar
,
148 const bool bShowVerticalScrollBar
)
150 Rectangle
aBox (PlaceVerticalScrollBar(rVerticalScrollBar
, rContentArea
, bShowVerticalScrollBar
));
152 const sal_Int32
nWidth (aBox
.GetWidth());
154 // Get the requested heights of the panels and the available
155 // height that is left when all panel titles and separators are
156 // taken into account.
157 sal_Int32
nAvailableHeight (aBox
.GetHeight());
158 GetRequestedSizes(rLayoutItems
, nAvailableHeight
, rMinimalWidth
, aBox
);
159 const sal_Int32
nTotalDecorationHeight (aBox
.GetHeight() - nAvailableHeight
);
161 // Analyze the requested heights.
162 // Determine the height that is available for panel content
163 // and count the different layouts.
164 sal_Int32
nTotalPreferredHeight (0);
165 sal_Int32
nTotalMinimumHeight (0);
166 IterateLayoutItems(iItem
,rLayoutItems
)
168 nTotalMinimumHeight
+= iItem
->maLayoutSize
.Minimum
;
169 nTotalPreferredHeight
+= iItem
->maLayoutSize
.Preferred
;
172 if (nTotalMinimumHeight
> nAvailableHeight
173 && ! bShowVerticalScrollBar
)
175 // Not enough space, even when all panels are shrunk to their
177 // Show a vertical scrollbar.
188 // We are now in one of three modes.
189 // - The preferred height fits into the available size:
190 // Use the preferred size, distribute the remaining height bei
192 // - The total minimum height fits into the available size:
193 // Use the minimum size, distribute the remaining height bei
195 // - The total minimum height does not fit into the available
197 // Use the unmodified preferred height for all panels.
199 LayoutMode
eMode (MinimumOrLarger
);
200 if (bShowVerticalScrollBar
)
202 else if (nTotalPreferredHeight
<= nAvailableHeight
)
203 eMode
= PreferredOrLarger
;
205 eMode
= MinimumOrLarger
;
207 if (eMode
!= Preferred
)
209 const sal_Int32
nTotalHeight (eMode
==MinimumOrLarger
? nTotalMinimumHeight
: nTotalPreferredHeight
);
213 nAvailableHeight
-nTotalHeight
,
215 eMode
==MinimumOrLarger
);
218 // Set position and size of the mpScrollClipWindow to the available
219 // size. Its child, the mpScrollContainer, may have a bigger
221 rScrollClipWindow
.setPosSizePixel(aBox
.Left(), aBox
.Top(), aBox
.GetWidth(), aBox
.GetHeight());
223 const sal_Int32
nContentHeight (
225 ? nTotalPreferredHeight
+ nTotalDecorationHeight
227 sal_Int32 nY
= rVerticalScrollBar
.GetThumbPos();
228 if (nContentHeight
-nY
< aBox
.GetHeight())
229 nY
= nContentHeight
-aBox
.GetHeight();
232 rScrollContainer
.setPosSizePixel(
238 if (bShowVerticalScrollBar
)
239 SetupVerticalScrollBar(rVerticalScrollBar
, nContentHeight
, aBox
.GetHeight());
241 const sal_Int32
nUsedHeight (PlacePanels(rLayoutItems
, nWidth
, eMode
, rScrollContainer
));
242 aBox
.Top() += nUsedHeight
;
246 sal_Int32
PlacePanels (
247 ::std::vector
<LayoutItem
>& rLayoutItems
,
248 const sal_Int32 nWidth
,
249 const LayoutMode eMode
,
250 vcl::Window
& rScrollContainer
)
252 ::std::vector
<sal_Int32
> aSeparators
;
253 const sal_Int32
nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight
));
256 // Assign heights and places.
257 IterateLayoutItems(iItem
,rLayoutItems
)
262 Panel
& rPanel (*iItem
->mpPanel
);
264 // Separator above the panel title bar.
265 aSeparators
.push_back(nY
);
266 nY
+= nDeckSeparatorHeight
;
268 // Place the title bar.
269 PanelTitleBar
* pTitleBar
= rPanel
.GetTitleBar();
270 if (pTitleBar
!= NULL
)
272 const sal_Int32
nPanelTitleBarHeight (Theme::GetInteger(Theme::Int_PanelTitleBarHeight
) * rPanel
.GetDPIScaleFactor());
274 if (iItem
->mbShowTitleBar
)
276 pTitleBar
->setPosSizePixel(0, nY
, nWidth
, nPanelTitleBarHeight
);
278 nY
+= nPanelTitleBarHeight
;
286 if (rPanel
.IsExpanded())
290 // Determine the height of the panel depending on layout
291 // mode and distributed heights.
292 sal_Int32
nPanelHeight (0);
295 case MinimumOrLarger
:
296 nPanelHeight
= iItem
->maLayoutSize
.Minimum
+ iItem
->mnDistributedHeight
;
298 case PreferredOrLarger
:
299 nPanelHeight
= iItem
->maLayoutSize
.Preferred
+ iItem
->mnDistributedHeight
;
302 nPanelHeight
= iItem
->maLayoutSize
.Preferred
;
310 rPanel
.setPosSizePixel(0, nY
, nWidth
, nPanelHeight
);
319 // Add a separator below the collapsed panel, if it is the
320 // last panel in the deck.
321 if (iItem
== rLayoutItems
.end()-1)
323 // Separator below the panel title bar.
324 aSeparators
.push_back(nY
);
325 nY
+= nDeckSeparatorHeight
;
330 Deck::ScrollContainerWindow
* pScrollContainerWindow
331 = dynamic_cast<Deck::ScrollContainerWindow
*>(&rScrollContainer
);
332 if (pScrollContainerWindow
!= NULL
)
333 pScrollContainerWindow
->SetSeparators(aSeparators
);
338 void GetRequestedSizes (
339 ::std::vector
<LayoutItem
>& rLayoutItems
,
340 sal_Int32
& rAvailableHeight
,
341 sal_Int32
& rMinimalWidth
,
342 const Rectangle
& rContentBox
)
344 rAvailableHeight
= rContentBox
.GetHeight();
346 const sal_Int32
nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight
));
348 IterateLayoutItems(iItem
,rLayoutItems
)
350 ui::LayoutSize
aLayoutSize (ui::LayoutSize(0,0,0));
351 if (iItem
->mpPanel
!= nullptr)
353 if (rLayoutItems
.size() == 1
354 && iItem
->mpPanel
->IsTitleBarOptional())
356 // There is only one panel and its title bar is
357 // optional => hide it.
358 rAvailableHeight
-= nDeckSeparatorHeight
;
359 iItem
->mbShowTitleBar
= false;
363 // Show the title bar and a separator above and below
365 const sal_Int32
nPanelTitleBarHeight (Theme::GetInteger(Theme::Int_PanelTitleBarHeight
) * iItem
->mpPanel
->GetDPIScaleFactor());
367 rAvailableHeight
-= nPanelTitleBarHeight
;
368 rAvailableHeight
-= nDeckSeparatorHeight
;
371 if (iItem
->mpPanel
->IsExpanded())
373 Reference
<ui::XSidebarPanel
> xPanel (iItem
->mpPanel
->GetPanelComponent());
376 aLayoutSize
= xPanel
->getHeightForWidth(rContentBox
.GetWidth());
378 sal_Int32 nWidth
= xPanel
->getMinimalWidth();
379 if (nWidth
> rMinimalWidth
)
380 rMinimalWidth
= nWidth
;
383 aLayoutSize
= ui::LayoutSize(MinimalPanelHeight
, -1, 0);
386 iItem
->maLayoutSize
= aLayoutSize
;
390 void DistributeHeights (
391 ::std::vector
<LayoutItem
>& rLayoutItems
,
392 const sal_Int32 nHeightToDistribute
,
393 const sal_Int32 nContainerHeight
,
394 const bool bMinimumHeightIsBase
)
396 if (nHeightToDistribute
<= 0)
399 sal_Int32
nRemainingHeightToDistribute (nHeightToDistribute
);
401 // Compute the weights as difference between panel base height
402 // (either its minimum or preferred height) and the container height.
403 sal_Int32
nTotalWeight (0);
404 sal_Int32
nNoMaximumCount (0);
405 IterateLayoutItems(iItem
,rLayoutItems
)
407 if (iItem
->maLayoutSize
.Maximum
== 0)
409 if (iItem
->maLayoutSize
.Maximum
< 0)
412 const sal_Int32
nBaseHeight (
414 ? iItem
->maLayoutSize
.Minimum
415 : iItem
->maLayoutSize
.Preferred
);
416 if (nBaseHeight
< nContainerHeight
)
418 iItem
->mnWeight
= nContainerHeight
- nBaseHeight
;
419 nTotalWeight
+= iItem
->mnWeight
;
423 if (nTotalWeight
== 0)
426 // First pass of height distribution.
427 IterateLayoutItems(iItem
,rLayoutItems
)
429 const sal_Int32
nBaseHeight (
431 ? iItem
->maLayoutSize
.Minimum
432 : iItem
->maLayoutSize
.Preferred
);
433 sal_Int32
nDistributedHeight (iItem
->mnWeight
* nHeightToDistribute
/ nTotalWeight
);
434 if (nBaseHeight
+nDistributedHeight
> iItem
->maLayoutSize
.Maximum
435 && iItem
->maLayoutSize
.Maximum
>= 0)
437 nDistributedHeight
= ::std::max
<sal_Int32
>(0,iItem
->maLayoutSize
.Maximum
- nBaseHeight
);
439 iItem
->mnDistributedHeight
= nDistributedHeight
;
440 nRemainingHeightToDistribute
-= nDistributedHeight
;
443 if (nRemainingHeightToDistribute
== 0)
445 OSL_ASSERT(nRemainingHeightToDistribute
> 0);
447 // It is possible that not all of the height could be distributed
448 // because of Maximum heights being smaller than expected.
449 // Distribute the remaining height between the panels that have no
450 // Maximum (ie Maximum==-1).
451 if (nNoMaximumCount
== 0)
453 // There are no panels with unrestricted height.
456 const sal_Int32
nAdditionalHeightPerPanel (nRemainingHeightToDistribute
/ nNoMaximumCount
);
457 // Handle rounding error.
458 sal_Int32
nAdditionalHeightForFirstPanel (nRemainingHeightToDistribute
459 - nNoMaximumCount
*nAdditionalHeightPerPanel
);
460 IterateLayoutItems(iItem
,rLayoutItems
)
462 if (iItem
->maLayoutSize
.Maximum
< 0)
464 iItem
->mnDistributedHeight
+= nAdditionalHeightPerPanel
+ nAdditionalHeightForFirstPanel
;
465 nRemainingHeightToDistribute
-= nAdditionalHeightPerPanel
+ nAdditionalHeightForFirstPanel
;
469 OSL_ASSERT(nRemainingHeightToDistribute
==0);
472 Rectangle
PlaceDeckTitle (
473 vcl::Window
& rDeckTitleBar
,
474 const Rectangle
& rAvailableSpace
)
476 if (static_cast<DockingWindow
*>(rDeckTitleBar
.GetParent()->GetParent())->IsFloatingMode())
478 // When the side bar is undocked then the outer system window displays the deck title.
479 rDeckTitleBar
.Hide();
480 return rAvailableSpace
;
484 const sal_Int32
nDeckTitleBarHeight (Theme::GetInteger(Theme::Int_DeckTitleBarHeight
) * rDeckTitleBar
.GetDPIScaleFactor());
485 rDeckTitleBar
.setPosSizePixel(
486 rAvailableSpace
.Left(),
487 rAvailableSpace
.Top(),
488 rAvailableSpace
.GetWidth(),
489 nDeckTitleBarHeight
);
490 rDeckTitleBar
.Show();
492 rAvailableSpace
.Left(),
493 rAvailableSpace
.Top() + nDeckTitleBarHeight
,
494 rAvailableSpace
.Right(),
495 rAvailableSpace
.Bottom());
499 Rectangle
PlaceVerticalScrollBar (
500 ScrollBar
& rVerticalScrollBar
,
501 const Rectangle
& rAvailableSpace
,
502 const bool bShowVerticalScrollBar
)
504 if (bShowVerticalScrollBar
)
506 const sal_Int32
nScrollBarWidth (rVerticalScrollBar
.GetSizePixel().Width());
507 rVerticalScrollBar
.setPosSizePixel(
508 rAvailableSpace
.Right() - nScrollBarWidth
+ 1,
509 rAvailableSpace
.Top(),
511 rAvailableSpace
.GetHeight());
512 rVerticalScrollBar
.Show();
514 rAvailableSpace
.Left(),
515 rAvailableSpace
.Top(),
516 rAvailableSpace
.Right() - nScrollBarWidth
,
517 rAvailableSpace
.Bottom());
521 rVerticalScrollBar
.Hide();
522 return rAvailableSpace
;
526 void SetupVerticalScrollBar(
527 ScrollBar
& rVerticalScrollBar
,
528 const sal_Int32 nContentHeight
,
529 const sal_Int32 nVisibleHeight
)
531 OSL_ASSERT(nContentHeight
> nVisibleHeight
);
533 rVerticalScrollBar
.SetRangeMin(0);
534 rVerticalScrollBar
.SetRangeMax(nContentHeight
-1);
535 rVerticalScrollBar
.SetVisibleSize(nVisibleHeight
);
539 vcl::Window
& rFiller
,
540 const Rectangle
& rBox
)
542 if (rBox
.GetHeight() > 0)
545 rFiller
.SetBackground(Theme::GetPaint(Theme::Paint_PanelBackground
).GetWallpaper());
546 rFiller
.SetPosSizePixel(rBox
.TopLeft(), rBox
.GetSize());
558 } } // end of namespace sfx2::sidebar
560 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */