Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / source / window / layout.cxx
blob981ac621aa60f7635546c62aab4ce149ce8a9be9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <com/sun/star/accessibility/AccessibleRole.hpp>
11 #include <o3tl/enumarray.hxx>
12 #include <o3tl/enumrange.hxx>
13 #include <vcl/decoview.hxx>
14 #include <vcl/dialog.hxx>
15 #include <vcl/layout.hxx>
16 #include <vcl/stdtext.hxx>
17 #include <vcl/svapp.hxx>
18 #include <vcl/settings.hxx>
19 #include <messagedialog.hxx>
20 #include <window.h>
21 #include <boost/multi_array.hpp>
22 #include <boost/property_tree/ptree.hpp>
23 #include <vcl/vclmedit.hxx>
24 #include <sal/log.hxx>
26 VclContainer::VclContainer(vcl::Window *pParent, WinBits nStyle)
27 : Window(WindowType::CONTAINER)
28 , m_bLayoutDirty(true)
30 ImplInit(pParent, nStyle, nullptr);
31 EnableChildTransparentMode();
32 SetPaintTransparent(true);
33 SetBackground();
36 sal_uInt16 VclContainer::getDefaultAccessibleRole() const
38 return css::accessibility::AccessibleRole::PANEL;
41 Size VclContainer::GetOptimalSize() const
43 return calculateRequisition();
46 void VclContainer::setLayoutPosSize(vcl::Window &rWindow, const Point &rPos, const Size &rSize)
48 sal_Int32 nBorderWidth = rWindow.get_border_width();
49 sal_Int32 nLeft = rWindow.get_margin_left() + nBorderWidth;
50 sal_Int32 nTop = rWindow.get_margin_top() + nBorderWidth;
51 sal_Int32 nRight = rWindow.get_margin_right() + nBorderWidth;
52 sal_Int32 nBottom = rWindow.get_margin_bottom() + nBorderWidth;
53 Point aPos(rPos.X() + nLeft, rPos.Y() + nTop);
54 Size aSize(rSize.Width() - nLeft - nRight, rSize.Height() - nTop - nBottom);
55 rWindow.SetPosSizePixel(aPos, aSize);
58 void VclContainer::setLayoutAllocation(vcl::Window &rChild, const Point &rAllocPos, const Size &rChildAlloc)
60 VclAlign eHalign = rChild.get_halign();
61 VclAlign eValign = rChild.get_valign();
63 //typical case
64 if (eHalign == VclAlign::Fill && eValign == VclAlign::Fill)
66 setLayoutPosSize(rChild, rAllocPos, rChildAlloc);
67 return;
70 Point aChildPos(rAllocPos);
71 Size aChildSize(rChildAlloc);
72 Size aChildPreferredSize(getLayoutRequisition(rChild));
74 switch (eHalign)
76 case VclAlign::Fill:
77 break;
78 case VclAlign::Start:
79 if (aChildPreferredSize.Width() < rChildAlloc.Width())
80 aChildSize.setWidth( aChildPreferredSize.Width() );
81 break;
82 case VclAlign::End:
83 if (aChildPreferredSize.Width() < rChildAlloc.Width())
84 aChildSize.setWidth( aChildPreferredSize.Width() );
85 aChildPos.AdjustX(rChildAlloc.Width() );
86 aChildPos.AdjustX( -(aChildSize.Width()) );
87 break;
88 case VclAlign::Center:
89 if (aChildPreferredSize.Width() < aChildSize.Width())
90 aChildSize.setWidth( aChildPreferredSize.Width() );
91 aChildPos.AdjustX((rChildAlloc.Width() - aChildSize.Width()) / 2 );
92 break;
95 switch (eValign)
97 case VclAlign::Fill:
98 break;
99 case VclAlign::Start:
100 if (aChildPreferredSize.Height() < rChildAlloc.Height())
101 aChildSize.setHeight( aChildPreferredSize.Height() );
102 break;
103 case VclAlign::End:
104 if (aChildPreferredSize.Height() < rChildAlloc.Height())
105 aChildSize.setHeight( aChildPreferredSize.Height() );
106 aChildPos.AdjustY(rChildAlloc.Height() );
107 aChildPos.AdjustY( -(aChildSize.Height()) );
108 break;
109 case VclAlign::Center:
110 if (aChildPreferredSize.Height() < aChildSize.Height())
111 aChildSize.setHeight( aChildPreferredSize.Height() );
112 aChildPos.AdjustY((rChildAlloc.Height() - aChildSize.Height()) / 2 );
113 break;
116 setLayoutPosSize(rChild, aChildPos, aChildSize);
119 namespace
121 Size subtractBorder(const vcl::Window &rWindow, const Size& rSize)
123 sal_Int32 nBorderWidth = rWindow.get_border_width();
124 sal_Int32 nLeft = rWindow.get_margin_left() + nBorderWidth;
125 sal_Int32 nTop = rWindow.get_margin_top() + nBorderWidth;
126 sal_Int32 nRight = rWindow.get_margin_right() + nBorderWidth;
127 sal_Int32 nBottom = rWindow.get_margin_bottom() + nBorderWidth;
128 Size aSize(rSize);
129 return Size(aSize.Width() + nLeft + nRight, aSize.Height() + nTop + nBottom);
133 Size VclContainer::getLayoutRequisition(const vcl::Window &rWindow)
135 return subtractBorder(rWindow, rWindow.get_preferred_size());
138 void VclContainer::SetPosSizePixel(const Point& rAllocPos, const Size& rAllocation)
140 bool bSizeChanged = rAllocation != GetOutputSizePixel();
141 Window::SetPosSizePixel(rAllocPos, rAllocation);
142 if (m_bLayoutDirty || bSizeChanged)
144 m_bLayoutDirty = false;
145 setAllocation(rAllocation);
149 void VclContainer::SetPosPixel(const Point& rAllocPos)
151 Point aAllocPos = rAllocPos;
152 sal_Int32 nBorderWidth = get_border_width();
153 aAllocPos.AdjustX(nBorderWidth + get_margin_left() );
154 aAllocPos.AdjustY(nBorderWidth + get_margin_top() );
156 if (aAllocPos != GetPosPixel())
157 Window::SetPosPixel(aAllocPos);
160 void VclContainer::SetSizePixel(const Size& rAllocation)
162 Size aAllocation = rAllocation;
163 sal_Int32 nBorderWidth = get_border_width();
164 aAllocation.AdjustWidth( -(nBorderWidth*2 + get_margin_left() + get_margin_right()) );
165 aAllocation.AdjustHeight( -(nBorderWidth*2 + get_margin_top() + get_margin_bottom()) );
166 bool bSizeChanged = aAllocation != GetSizePixel();
167 if (bSizeChanged)
168 Window::SetSizePixel(aAllocation);
169 if (m_bLayoutDirty || bSizeChanged)
171 m_bLayoutDirty = false;
172 setAllocation(aAllocation);
176 void VclContainer::queue_resize(StateChangedType eReason)
178 m_bLayoutDirty = true;
179 Window::queue_resize(eReason);
182 // support for screenshot context menu
183 void VclContainer::Command(const CommandEvent& rCEvt)
185 if (CommandEventId::ContextMenu == rCEvt.GetCommand())
187 auto pParent = GetParent();
188 if (pParent)
190 CommandEvent aCEvt(rCEvt.GetMousePosPixel() + GetPosPixel(), rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetEventData());
191 pParent->Command(aCEvt);
192 return;
196 // call parent (do not consume)
197 Window::Command(rCEvt);
200 void VclBox::accumulateMaxes(const Size &rChildSize, Size &rSize) const
202 long nSecondaryChildDimension = getSecondaryDimension(rChildSize);
203 long nSecondaryBoxDimension = getSecondaryDimension(rSize);
204 setSecondaryDimension(rSize, std::max(nSecondaryChildDimension, nSecondaryBoxDimension));
206 long nPrimaryChildDimension = getPrimaryDimension(rChildSize);
207 long nPrimaryBoxDimension = getPrimaryDimension(rSize);
208 if (m_bHomogeneous)
209 setPrimaryDimension(rSize, std::max(nPrimaryBoxDimension, nPrimaryChildDimension));
210 else
211 setPrimaryDimension(rSize, nPrimaryBoxDimension + nPrimaryChildDimension);
214 Size VclBox::calculateRequisition() const
216 sal_uInt16 nVisibleChildren = 0;
218 Size aSize;
219 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
221 if (!pChild->IsVisible())
222 continue;
223 ++nVisibleChildren;
224 Size aChildSize = getLayoutRequisition(*pChild);
226 long nPrimaryDimension = getPrimaryDimension(aChildSize);
227 nPrimaryDimension += pChild->get_padding() * 2;
228 setPrimaryDimension(aChildSize, nPrimaryDimension);
230 accumulateMaxes(aChildSize, aSize);
233 return finalizeMaxes(aSize, nVisibleChildren);
236 void VclBox::setAllocation(const Size &rAllocation)
238 sal_uInt16 nVisibleChildren = 0, nExpandChildren = 0;
239 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
241 if (!pChild->IsVisible())
242 continue;
243 ++nVisibleChildren;
244 bool bExpand = getPrimaryDimensionChildExpand(*pChild);
245 if (bExpand)
246 ++nExpandChildren;
249 if (!nVisibleChildren)
250 return;
252 long nAllocPrimaryDimension = getPrimaryDimension(rAllocation);
254 long nHomogeneousDimension = 0, nExtraSpace = 0;
255 if (m_bHomogeneous)
257 nHomogeneousDimension = (nAllocPrimaryDimension -
258 (nVisibleChildren - 1) * m_nSpacing) / nVisibleChildren;
260 else if (nExpandChildren)
262 Size aRequisition = calculateRequisition();
263 nExtraSpace = (getPrimaryDimension(rAllocation) - getPrimaryDimension(aRequisition)) / nExpandChildren;
266 //Split into those we pack from the start onwards, and those we pack from the end backwards
267 o3tl::enumarray<VclPackType,std::vector<vcl::Window*>> aWindows;
268 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
270 if (!pChild->IsVisible())
271 continue;
273 VclPackType ePacking = pChild->get_pack_type();
274 aWindows[ePacking].push_back(pChild);
277 //See VclBuilder::sortIntoBestTabTraversalOrder for why they are in visual
278 //order under the parent which requires us to reverse them here to
279 //pack from the end back
280 std::reverse(aWindows[VclPackType::End].begin(),aWindows[VclPackType::End].end());
282 for (VclPackType ePackType : o3tl::enumrange<VclPackType>())
284 Point aPos(0, 0);
285 if (ePackType == VclPackType::End)
287 long nPrimaryCoordinate = getPrimaryCoordinate(aPos);
288 setPrimaryCoordinate(aPos, nPrimaryCoordinate + nAllocPrimaryDimension);
291 for (auto const& window : aWindows[ePackType])
293 vcl::Window *pChild = window;
295 long nPadding = pChild->get_padding();
297 Size aBoxSize;
298 if (m_bHomogeneous)
299 setPrimaryDimension(aBoxSize, nHomogeneousDimension);
300 else
302 aBoxSize = getLayoutRequisition(*pChild);
303 long nPrimaryDimension = getPrimaryDimension(aBoxSize);
304 nPrimaryDimension += nPadding * 2;
305 if (getPrimaryDimensionChildExpand(*pChild))
306 nPrimaryDimension += nExtraSpace;
307 setPrimaryDimension(aBoxSize, nPrimaryDimension);
309 setSecondaryDimension(aBoxSize, getSecondaryDimension(rAllocation));
311 Point aChildPos(aPos);
312 Size aChildSize(aBoxSize);
313 long nPrimaryCoordinate = getPrimaryCoordinate(aPos);
315 bool bFill = pChild->get_fill();
316 if (bFill)
318 setPrimaryDimension(aChildSize, std::max(static_cast<long>(1),
319 getPrimaryDimension(aBoxSize) - nPadding * 2));
321 setPrimaryCoordinate(aChildPos, nPrimaryCoordinate + nPadding);
323 else
325 setPrimaryDimension(aChildSize,
326 getPrimaryDimension(getLayoutRequisition(*pChild)));
328 setPrimaryCoordinate(aChildPos, nPrimaryCoordinate +
329 (getPrimaryDimension(aBoxSize) - getPrimaryDimension(aChildSize)) / 2);
332 long nDiff = getPrimaryDimension(aBoxSize) + m_nSpacing;
333 if (ePackType == VclPackType::Start)
334 setPrimaryCoordinate(aPos, nPrimaryCoordinate + nDiff);
335 else
337 setPrimaryCoordinate(aPos, nPrimaryCoordinate - nDiff);
338 setPrimaryCoordinate(aChildPos, getPrimaryCoordinate(aChildPos) -
339 getPrimaryDimension(aBoxSize));
342 setLayoutAllocation(*pChild, aChildPos, aChildSize);
347 bool VclBox::set_property(const OString &rKey, const OUString &rValue)
349 if (rKey == "spacing")
350 set_spacing(rValue.toInt32());
351 else if (rKey == "homogeneous")
352 set_homogeneous(toBool(rValue));
353 else
354 return VclContainer::set_property(rKey, rValue);
355 return true;
358 boost::property_tree::ptree VclBox::DumpAsPropertyTree()
360 boost::property_tree::ptree aTree(VclContainer::DumpAsPropertyTree());
361 aTree.put("vertical", m_bVerticalContainer);
362 return aTree;
365 sal_uInt16 VclBox::getDefaultAccessibleRole() const
367 #if defined(_WIN32)
368 //fdo#74284 call Boxes Panels, keep then as "Filler" under
369 //at least Linux seeing as that's what Gtk does for GtkBoxes
370 return css::accessibility::AccessibleRole::PANEL;
371 #else
372 return css::accessibility::AccessibleRole::FILLER;
373 #endif
376 #define DEFAULT_CHILD_MIN_WIDTH 85
377 #define DEFAULT_CHILD_MIN_HEIGHT 27
379 Size VclBox::finalizeMaxes(const Size &rSize, sal_uInt16 nVisibleChildren) const
381 Size aRet;
383 if (nVisibleChildren)
385 long nPrimaryDimension = getPrimaryDimension(rSize);
386 if (m_bHomogeneous)
387 nPrimaryDimension *= nVisibleChildren;
388 setPrimaryDimension(aRet, nPrimaryDimension + m_nSpacing * (nVisibleChildren-1));
389 setSecondaryDimension(aRet, getSecondaryDimension(rSize));
392 return aRet;
395 Size VclButtonBox::addReqGroups(const VclButtonBox::Requisition &rReq) const
397 Size aRet;
399 long nMainGroupDimension = getPrimaryDimension(rReq.m_aMainGroupSize);
400 long nSubGroupDimension = getPrimaryDimension(rReq.m_aSubGroupSize);
402 setPrimaryDimension(aRet, nMainGroupDimension + nSubGroupDimension);
404 setSecondaryDimension(aRet,
405 std::max(getSecondaryDimension(rReq.m_aMainGroupSize),
406 getSecondaryDimension(rReq.m_aSubGroupSize)));
408 return aRet;
411 static long getMaxNonOutlier(const std::vector<long> &rG, long nAvgDimension)
413 long nMaxDimensionNonOutlier = 0;
414 for (auto const& nPrimaryChildDimension : rG)
416 if (nPrimaryChildDimension < nAvgDimension * 1.5)
418 nMaxDimensionNonOutlier = std::max(nPrimaryChildDimension,
419 nMaxDimensionNonOutlier);
422 return nMaxDimensionNonOutlier;
425 static std::vector<long> setButtonSizes(const std::vector<long> &rG,
426 const std::vector<bool> &rNonHomogeneous,
427 long nAvgDimension, long nMaxNonOutlier, long nMinWidth)
429 std::vector<long> aVec;
430 //set everything < 1.5 times the average to the same width, leave the
431 //outliers un-touched
432 std::vector<bool>::const_iterator aJ = rNonHomogeneous.begin();
433 auto nNonOutlierWidth = std::max(nMaxNonOutlier, nMinWidth);
434 for (auto const& nPrimaryChildDimension : rG)
436 bool bNonHomogeneous = *aJ;
437 if (!bNonHomogeneous && nPrimaryChildDimension < nAvgDimension * 1.5)
439 aVec.push_back(nNonOutlierWidth);
441 else
443 aVec.push_back(std::max(nPrimaryChildDimension, nMinWidth));
445 ++aJ;
447 return aVec;
450 VclButtonBox::Requisition VclButtonBox::calculatePrimarySecondaryRequisitions() const
452 Requisition aReq;
454 Size aMainGroupSize(DEFAULT_CHILD_MIN_WIDTH, DEFAULT_CHILD_MIN_HEIGHT); //to-do, pull from theme
455 Size aSubGroupSize(DEFAULT_CHILD_MIN_WIDTH, DEFAULT_CHILD_MIN_HEIGHT); //to-do, pull from theme
457 long nMinMainGroupPrimary = getPrimaryDimension(aMainGroupSize);
458 long nMinSubGroupPrimary = getPrimaryDimension(aSubGroupSize);
459 long nMainGroupSecondary = getSecondaryDimension(aMainGroupSize);
460 long nSubGroupSecondary = getSecondaryDimension(aSubGroupSize);
462 bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VclButtonBoxStyle::Spread || m_eLayoutStyle == VclButtonBoxStyle::Center);
464 std::vector<long> aMainGroupSizes;
465 std::vector<bool> aMainGroupNonHomogeneous;
466 std::vector<long> aSubGroupSizes;
467 std::vector<bool> aSubGroupNonHomogeneous;
469 for (const vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
471 if (!pChild->IsVisible())
472 continue;
473 Size aChildSize = getLayoutRequisition(*pChild);
474 if (bIgnoreSecondaryPacking || !pChild->get_secondary())
476 //set the max secondary dimension
477 nMainGroupSecondary = std::max(nMainGroupSecondary, getSecondaryDimension(aChildSize));
478 //collect the primary dimensions
479 aMainGroupSizes.push_back(getPrimaryDimension(aChildSize));
480 aMainGroupNonHomogeneous.push_back(pChild->get_non_homogeneous());
482 else
484 nSubGroupSecondary = std::max(nSubGroupSecondary, getSecondaryDimension(aChildSize));
485 aSubGroupSizes.push_back(getPrimaryDimension(aChildSize));
486 aSubGroupNonHomogeneous.push_back(pChild->get_non_homogeneous());
490 if (m_bHomogeneous)
492 long nMaxMainDimension = aMainGroupSizes.empty() ? 0 :
493 *std::max_element(aMainGroupSizes.begin(), aMainGroupSizes.end());
494 nMaxMainDimension = std::max(nMaxMainDimension, nMinMainGroupPrimary);
495 long nMaxSubDimension = aSubGroupSizes.empty() ? 0 :
496 *std::max_element(aSubGroupSizes.begin(), aSubGroupSizes.end());
497 nMaxSubDimension = std::max(nMaxSubDimension, nMinSubGroupPrimary);
498 long nMaxDimension = std::max(nMaxMainDimension, nMaxSubDimension);
499 aReq.m_aMainGroupDimensions.resize(aMainGroupSizes.size(), nMaxDimension);
500 aReq.m_aSubGroupDimensions.resize(aSubGroupSizes.size(), nMaxDimension);
502 else
504 //Ideally set everything to the same size, but find outlier widgets
505 //that are way wider than the average and leave them
506 //at their natural size and set the remainder to share the
507 //max size of the remaining members of the buttonbox
508 long nAccDimension = std::accumulate(aMainGroupSizes.begin(),
509 aMainGroupSizes.end(), 0);
510 nAccDimension = std::accumulate(aSubGroupSizes.begin(),
511 aSubGroupSizes.end(), nAccDimension);
513 size_t nTotalSize = aMainGroupSizes.size() + aSubGroupSizes.size();
515 long nAvgDimension = nTotalSize ? nAccDimension / nTotalSize : 0;
517 long nMaxMainNonOutlier = getMaxNonOutlier(aMainGroupSizes,
518 nAvgDimension);
519 long nMaxSubNonOutlier = getMaxNonOutlier(aSubGroupSizes,
520 nAvgDimension);
521 long nMaxNonOutlier = std::max(nMaxMainNonOutlier, nMaxSubNonOutlier);
523 aReq.m_aMainGroupDimensions = setButtonSizes(aMainGroupSizes,
524 aMainGroupNonHomogeneous,
525 nAvgDimension, nMaxNonOutlier, nMinMainGroupPrimary);
526 aReq.m_aSubGroupDimensions = setButtonSizes(aSubGroupSizes,
527 aSubGroupNonHomogeneous,
528 nAvgDimension, nMaxNonOutlier, nMinSubGroupPrimary);
531 if (!aReq.m_aMainGroupDimensions.empty())
533 setSecondaryDimension(aReq.m_aMainGroupSize, nMainGroupSecondary);
534 setPrimaryDimension(aReq.m_aMainGroupSize,
535 std::accumulate(aReq.m_aMainGroupDimensions.begin(),
536 aReq.m_aMainGroupDimensions.end(), 0));
538 if (!aReq.m_aSubGroupDimensions.empty())
540 setSecondaryDimension(aReq.m_aSubGroupSize, nSubGroupSecondary);
541 setPrimaryDimension(aReq.m_aSubGroupSize,
542 std::accumulate(aReq.m_aSubGroupDimensions.begin(),
543 aReq.m_aSubGroupDimensions.end(), 0));
546 return aReq;
549 Size VclButtonBox::addSpacing(const Size &rSize, sal_uInt16 nVisibleChildren) const
551 Size aRet;
553 if (nVisibleChildren)
555 long nPrimaryDimension = getPrimaryDimension(rSize);
556 setPrimaryDimension(aRet,
557 nPrimaryDimension + m_nSpacing * (nVisibleChildren-1));
558 setSecondaryDimension(aRet, getSecondaryDimension(rSize));
561 return aRet;
564 Size VclButtonBox::calculateRequisition() const
566 Requisition aReq(calculatePrimarySecondaryRequisitions());
567 sal_uInt16 nVisibleChildren = aReq.m_aMainGroupDimensions.size() +
568 aReq.m_aSubGroupDimensions.size();
569 return addSpacing(addReqGroups(aReq), nVisibleChildren);
572 bool VclButtonBox::set_property(const OString &rKey, const OUString &rValue)
574 if (rKey == "layout-style")
576 VclButtonBoxStyle eStyle = VclButtonBoxStyle::Default;
577 if (rValue == "spread")
578 eStyle = VclButtonBoxStyle::Spread;
579 else if (rValue == "edge")
580 eStyle = VclButtonBoxStyle::Edge;
581 else if (rValue == "start")
582 eStyle = VclButtonBoxStyle::Start;
583 else if (rValue == "end")
584 eStyle = VclButtonBoxStyle::End;
585 else if (rValue == "center")
586 eStyle = VclButtonBoxStyle::Center;
587 else
589 SAL_WARN("vcl.layout", "unknown layout style " << rValue);
591 m_eLayoutStyle = eStyle;
593 else
594 return VclBox::set_property(rKey, rValue);
595 return true;
598 void VclButtonBox::setAllocation(const Size &rAllocation)
600 Requisition aReq(calculatePrimarySecondaryRequisitions());
602 if (aReq.m_aMainGroupDimensions.empty() && aReq.m_aSubGroupDimensions.empty())
603 return;
605 long nAllocPrimaryDimension = getPrimaryDimension(rAllocation);
607 Point aMainGroupPos, aOtherGroupPos;
608 int nSpacing = m_nSpacing;
610 //To-Do, other layout styles
611 switch (m_eLayoutStyle)
613 case VclButtonBoxStyle::Start:
614 if (!aReq.m_aSubGroupDimensions.empty())
616 long nOtherPrimaryDimension = getPrimaryDimension(
617 addSpacing(aReq.m_aSubGroupSize, aReq.m_aSubGroupDimensions.size()));
618 setPrimaryCoordinate(aOtherGroupPos,
619 nAllocPrimaryDimension - nOtherPrimaryDimension);
621 break;
622 case VclButtonBoxStyle::Spread:
623 if (!aReq.m_aMainGroupDimensions.empty())
625 long nMainPrimaryDimension = getPrimaryDimension(
626 addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size()));
627 long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension;
628 nExtraSpace += (aReq.m_aMainGroupDimensions.size()-1) * nSpacing;
629 nSpacing = nExtraSpace/(aReq.m_aMainGroupDimensions.size()+1);
630 setPrimaryCoordinate(aMainGroupPos, nSpacing);
632 break;
633 case VclButtonBoxStyle::Center:
634 if (!aReq.m_aMainGroupDimensions.empty())
636 long nMainPrimaryDimension = getPrimaryDimension(
637 addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size()));
638 long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension;
639 setPrimaryCoordinate(aMainGroupPos, nExtraSpace/2);
641 break;
642 default:
643 SAL_WARN("vcl.layout", "todo unimplemented layout style");
644 [[fallthrough]];
645 case VclButtonBoxStyle::Default:
646 case VclButtonBoxStyle::End:
647 if (!aReq.m_aMainGroupDimensions.empty())
649 long nMainPrimaryDimension = getPrimaryDimension(
650 addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size()));
651 setPrimaryCoordinate(aMainGroupPos,
652 nAllocPrimaryDimension - nMainPrimaryDimension);
654 break;
657 Size aChildSize;
658 setSecondaryDimension(aChildSize, getSecondaryDimension(rAllocation));
660 std::vector<long>::const_iterator aPrimaryI = aReq.m_aMainGroupDimensions.begin();
661 std::vector<long>::const_iterator aSecondaryI = aReq.m_aSubGroupDimensions.begin();
662 bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VclButtonBoxStyle::Spread || m_eLayoutStyle == VclButtonBoxStyle::Center);
663 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
665 if (!pChild->IsVisible())
666 continue;
668 if (bIgnoreSecondaryPacking || !pChild->get_secondary())
670 long nMainGroupPrimaryDimension = *aPrimaryI++;
671 setPrimaryDimension(aChildSize, nMainGroupPrimaryDimension);
672 setLayoutAllocation(*pChild, aMainGroupPos, aChildSize);
673 long nPrimaryCoordinate = getPrimaryCoordinate(aMainGroupPos);
674 setPrimaryCoordinate(aMainGroupPos, nPrimaryCoordinate + nMainGroupPrimaryDimension + nSpacing);
676 else
678 long nSubGroupPrimaryDimension = *aSecondaryI++;
679 setPrimaryDimension(aChildSize, nSubGroupPrimaryDimension);
680 setLayoutAllocation(*pChild, aOtherGroupPos, aChildSize);
681 long nPrimaryCoordinate = getPrimaryCoordinate(aOtherGroupPos);
682 setPrimaryCoordinate(aOtherGroupPos, nPrimaryCoordinate + nSubGroupPrimaryDimension + nSpacing);
687 struct ButtonOrder
689 const char* m_aType;
690 int const m_nPriority;
693 static int getButtonPriority(const OString &rType)
695 static const size_t N_TYPES = 6;
696 static const ButtonOrder aDiscardCancelSave[N_TYPES] =
698 { "/discard", 0 },
699 { "/cancel", 1 },
700 { "/no", 2 },
701 { "/save", 3 },
702 { "/yes", 3 },
703 { "/ok", 3 }
706 static const ButtonOrder aSaveDiscardCancel[N_TYPES] =
708 { "/save", 0 },
709 { "/yes", 0 },
710 { "/ok", 0 },
711 { "/discard", 1 },
712 { "/no", 1 },
713 { "/cancel", 2 }
716 const ButtonOrder* pOrder = &aDiscardCancelSave[0];
718 const OUString &rEnv = Application::GetDesktopEnvironment();
720 if (rEnv.equalsIgnoreAsciiCase("windows") ||
721 rEnv.equalsIgnoreAsciiCase("tde") ||
722 rEnv.startsWithIgnoreAsciiCase("kde"))
724 pOrder = &aSaveDiscardCancel[0];
727 for (size_t i = 0; i < N_TYPES; ++i, ++pOrder)
729 if (rType.endsWith(pOrder->m_aType))
730 return pOrder->m_nPriority;
733 return -1;
736 class sortButtons
738 bool const m_bVerticalContainer;
739 public:
740 explicit sortButtons(bool bVerticalContainer)
741 : m_bVerticalContainer(bVerticalContainer)
744 bool operator()(const vcl::Window *pA, const vcl::Window *pB) const;
747 bool sortButtons::operator()(const vcl::Window *pA, const vcl::Window *pB) const
749 //sort into two groups of pack start and pack end
750 VclPackType ePackA = pA->get_pack_type();
751 VclPackType ePackB = pB->get_pack_type();
752 if (ePackA < ePackB)
753 return true;
754 if (ePackA > ePackB)
755 return false;
756 bool bPackA = pA->get_secondary();
757 bool bPackB = pB->get_secondary();
758 if (!m_bVerticalContainer)
760 //for horizontal boxes group secondaries before primaries
761 if (bPackA > bPackB)
762 return true;
763 if (bPackA < bPackB)
764 return false;
766 else
768 //for vertical boxes group secondaries after primaries
769 if (bPackA < bPackB)
770 return true;
771 if (bPackA > bPackB)
772 return false;
775 //now order within groups according to platform rules
776 return getButtonPriority(pA->GetHelpId()) < getButtonPriority(pB->GetHelpId());
779 void VclButtonBox::sort_native_button_order()
781 std::vector<vcl::Window*> aChilds;
782 for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
783 pChild = pChild->GetWindow(GetWindowType::Next))
785 aChilds.push_back(pChild);
788 //sort child order within parent so that we match the platform
789 //button order
790 std::stable_sort(aChilds.begin(), aChilds.end(), sortButtons(m_bVerticalContainer));
791 BuilderUtils::reorderWithinParent(aChilds, true);
794 struct GridEntry
796 VclPtr<vcl::Window> pChild;
797 sal_Int32 nSpanWidth;
798 sal_Int32 nSpanHeight;
799 int x;
800 int y;
801 GridEntry()
802 : pChild(nullptr)
803 , nSpanWidth(0)
804 , nSpanHeight(0)
805 , x(-1)
806 , y(-1)
811 typedef boost::multi_array<GridEntry, 2> array_type;
813 static array_type assembleGrid(const VclGrid &rGrid);
814 static bool isNullGrid(const array_type& A);
815 static void calcMaxs(const array_type &A, std::vector<VclGrid::Value> &rWidths, std::vector<VclGrid::Value> &rHeights);
817 array_type assembleGrid(const VclGrid &rGrid)
819 array_type A;
821 for (vcl::Window* pChild = rGrid.GetWindow(GetWindowType::FirstChild); pChild;
822 pChild = pChild->GetWindow(GetWindowType::Next))
824 sal_Int32 nLeftAttach = std::max<sal_Int32>(pChild->get_grid_left_attach(), 0);
825 sal_Int32 nWidth = pChild->get_grid_width();
826 sal_Int32 nMaxXPos = nLeftAttach+nWidth-1;
828 sal_Int32 nTopAttach = std::max<sal_Int32>(pChild->get_grid_top_attach(), 0);
829 sal_Int32 nHeight = pChild->get_grid_height();
830 sal_Int32 nMaxYPos = nTopAttach+nHeight-1;
832 sal_Int32 nCurrentMaxXPos = A.shape()[0]-1;
833 sal_Int32 nCurrentMaxYPos = A.shape()[1]-1;
834 if (nMaxXPos > nCurrentMaxXPos || nMaxYPos > nCurrentMaxYPos)
836 nCurrentMaxXPos = std::max(nMaxXPos, nCurrentMaxXPos);
837 nCurrentMaxYPos = std::max(nMaxYPos, nCurrentMaxYPos);
838 A.resize(boost::extents[nCurrentMaxXPos+1][nCurrentMaxYPos+1]);
841 GridEntry &rEntry = A[nLeftAttach][nTopAttach];
842 rEntry.pChild = pChild;
843 rEntry.nSpanWidth = nWidth;
844 rEntry.nSpanHeight = nHeight;
845 rEntry.x = nLeftAttach;
846 rEntry.y = nTopAttach;
848 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
850 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
852 GridEntry &rSpan = A[nLeftAttach+nSpanX][nTopAttach+nSpanY];
853 rSpan.x = nLeftAttach;
854 rSpan.y = nTopAttach;
859 //see if we have any empty rows/cols
860 sal_Int32 nMaxX = A.shape()[0];
861 sal_Int32 nMaxY = A.shape()[1];
863 std::vector<bool> aNonEmptyCols(nMaxX);
864 std::vector<bool> aNonEmptyRows(nMaxY);
866 for (sal_Int32 x = 0; x < nMaxX; ++x)
868 for (sal_Int32 y = 0; y < nMaxY; ++y)
870 const GridEntry &rEntry = A[x][y];
871 const vcl::Window *pChild = rEntry.pChild;
872 if (pChild && pChild->IsVisible())
874 aNonEmptyCols[x] = true;
875 if (rGrid.get_column_homogeneous())
877 for (sal_Int32 nSpanX = 1; nSpanX < rEntry.nSpanWidth; ++nSpanX)
878 aNonEmptyCols[x+nSpanX] = true;
880 aNonEmptyRows[y] = true;
881 if (rGrid.get_row_homogeneous())
883 for (sal_Int32 nSpanY = 1; nSpanY < rEntry.nSpanHeight; ++nSpanY)
884 aNonEmptyRows[y+nSpanY] = true;
890 if (!rGrid.get_column_homogeneous())
892 //reduce the spans of elements that span empty columns
893 for (sal_Int32 x = 0; x < nMaxX; ++x)
895 std::set<GridEntry*> candidates;
896 for (sal_Int32 y = 0; y < nMaxY; ++y)
898 if (aNonEmptyCols[x])
899 continue;
900 GridEntry &rSpan = A[x][y];
901 //cell x/y is spanned by the widget at cell rSpan.x/rSpan.y,
902 //just points back to itself if there's no cell spanning
903 if ((rSpan.x == -1) || (rSpan.y == -1))
905 //there is no entry for this cell, i.e. this is a cell
906 //with no widget in it, or spanned by any other widget
907 continue;
909 GridEntry &rEntry = A[rSpan.x][rSpan.y];
910 candidates.insert(&rEntry);
912 for (auto const& candidate : candidates)
914 GridEntry *pEntry = candidate;
915 --pEntry->nSpanWidth;
920 if (!rGrid.get_row_homogeneous())
922 //reduce the spans of elements that span empty rows
923 for (sal_Int32 y = 0; y < nMaxY; ++y)
925 std::set<GridEntry*> candidates;
926 for (sal_Int32 x = 0; x < nMaxX; ++x)
928 if (aNonEmptyRows[y])
929 continue;
930 GridEntry &rSpan = A[x][y];
931 //cell x/y is spanned by the widget at cell rSpan.x/rSpan.y,
932 //just points back to itself if there's no cell spanning
933 if ((rSpan.x == -1) || (rSpan.y == -1))
935 //there is no entry for this cell, i.e. this is a cell
936 //with no widget in it, or spanned by any other widget
937 continue;
939 GridEntry &rEntry = A[rSpan.x][rSpan.y];
940 candidates.insert(&rEntry);
942 for (auto const& candidate : candidates)
944 GridEntry *pEntry = candidate;
945 --pEntry->nSpanHeight;
950 sal_Int32 nNonEmptyCols = std::count(aNonEmptyCols.begin(), aNonEmptyCols.end(), true);
951 sal_Int32 nNonEmptyRows = std::count(aNonEmptyRows.begin(), aNonEmptyRows.end(), true);
953 //make new grid without empty rows and columns
954 array_type B(boost::extents[nNonEmptyCols][nNonEmptyRows]);
955 for (sal_Int32 x = 0, x2 = 0; x < nMaxX; ++x)
957 if (!aNonEmptyCols[x])
958 continue;
959 for (sal_Int32 y = 0, y2 = 0; y < nMaxY; ++y)
961 if (!aNonEmptyRows[y])
962 continue;
963 GridEntry &rEntry = A[x][y];
964 B[x2][y2++] = rEntry;
966 ++x2;
969 return B;
972 static bool isNullGrid(const array_type &A)
974 sal_Int32 nMaxX = A.shape()[0];
975 sal_Int32 nMaxY = A.shape()[1];
977 return !nMaxX || !nMaxY;
980 static void calcMaxs(const array_type &A, std::vector<VclGrid::Value> &rWidths, std::vector<VclGrid::Value> &rHeights)
982 sal_Int32 nMaxX = A.shape()[0];
983 sal_Int32 nMaxY = A.shape()[1];
985 rWidths.resize(nMaxX);
986 rHeights.resize(nMaxY);
988 //first use the non spanning entries to set default width/heights
989 for (sal_Int32 x = 0; x < nMaxX; ++x)
991 for (sal_Int32 y = 0; y < nMaxY; ++y)
993 const GridEntry &rEntry = A[x][y];
994 const vcl::Window *pChild = rEntry.pChild;
995 if (!pChild || !pChild->IsVisible())
996 continue;
998 sal_Int32 nWidth = rEntry.nSpanWidth;
999 sal_Int32 nHeight = rEntry.nSpanHeight;
1001 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1002 rWidths[x+nSpanX].m_bExpand |= pChild->get_hexpand();
1004 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1005 rHeights[y+nSpanY].m_bExpand |= pChild->get_vexpand();
1007 if (nWidth == 1 || nHeight == 1)
1009 Size aChildSize = VclContainer::getLayoutRequisition(*pChild);
1010 if (nWidth == 1)
1011 rWidths[x].m_nValue = std::max(rWidths[x].m_nValue, aChildSize.Width());
1012 if (nHeight == 1)
1013 rHeights[y].m_nValue = std::max(rHeights[y].m_nValue, aChildSize.Height());
1018 //now use the spanning entries and split any extra sizes across expanding rows/cols
1019 //where possible
1020 for (sal_Int32 x = 0; x < nMaxX; ++x)
1022 for (sal_Int32 y = 0; y < nMaxY; ++y)
1024 const GridEntry &rEntry = A[x][y];
1025 const vcl::Window *pChild = rEntry.pChild;
1026 if (!pChild || !pChild->IsVisible())
1027 continue;
1029 sal_Int32 nWidth = rEntry.nSpanWidth;
1030 sal_Int32 nHeight = rEntry.nSpanHeight;
1032 if (nWidth == 1 && nHeight == 1)
1033 continue;
1035 Size aChildSize = VclContainer::getLayoutRequisition(*pChild);
1037 if (nWidth > 1)
1039 sal_Int32 nExistingWidth = 0;
1040 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1041 nExistingWidth += rWidths[x+nSpanX].m_nValue;
1043 sal_Int32 nExtraWidth = aChildSize.Width() - nExistingWidth;
1045 if (nExtraWidth > 0)
1047 bool bForceExpandAll = false;
1048 sal_Int32 nExpandables = 0;
1049 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1050 if (rWidths[x+nSpanX].m_bExpand)
1051 ++nExpandables;
1052 if (nExpandables == 0)
1054 nExpandables = nWidth;
1055 bForceExpandAll = true;
1058 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1060 if (rWidths[x+nSpanX].m_bExpand || bForceExpandAll)
1061 rWidths[x+nSpanX].m_nValue += nExtraWidth/nExpandables;
1066 if (nHeight > 1)
1068 sal_Int32 nExistingHeight = 0;
1069 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1070 nExistingHeight += rHeights[y+nSpanY].m_nValue;
1072 sal_Int32 nExtraHeight = aChildSize.Height() - nExistingHeight;
1074 if (nExtraHeight > 0)
1076 bool bForceExpandAll = false;
1077 sal_Int32 nExpandables = 0;
1078 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1079 if (rHeights[y+nSpanY].m_bExpand)
1080 ++nExpandables;
1081 if (nExpandables == 0)
1083 nExpandables = nHeight;
1084 bForceExpandAll = true;
1087 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1089 if (rHeights[y+nSpanY].m_bExpand || bForceExpandAll)
1090 rHeights[y+nSpanY].m_nValue += nExtraHeight/nExpandables;
1098 static bool compareValues(const VclGrid::Value &i, const VclGrid::Value &j)
1100 return i.m_nValue < j.m_nValue;
1103 static VclGrid::Value accumulateValues(const VclGrid::Value &i, const VclGrid::Value &j)
1105 VclGrid::Value aRet;
1106 aRet.m_nValue = i.m_nValue + j.m_nValue;
1107 aRet.m_bExpand = i.m_bExpand || j.m_bExpand;
1108 return aRet;
1111 Size VclGrid::calculateRequisition() const
1113 return calculateRequisitionForSpacings(get_row_spacing(), get_column_spacing());
1116 Size VclGrid::calculateRequisitionForSpacings(sal_Int32 nRowSpacing, sal_Int32 nColSpacing) const
1118 array_type A = assembleGrid(*this);
1120 if (isNullGrid(A))
1121 return Size();
1123 std::vector<Value> aWidths;
1124 std::vector<Value> aHeights;
1125 calcMaxs(A, aWidths, aHeights);
1127 long nTotalWidth = 0;
1128 if (get_column_homogeneous())
1130 nTotalWidth = std::max_element(aWidths.begin(), aWidths.end(), compareValues)->m_nValue;
1131 nTotalWidth *= aWidths.size();
1133 else
1135 nTotalWidth = std::accumulate(aWidths.begin(), aWidths.end(), Value(), accumulateValues).m_nValue;
1138 nTotalWidth += nColSpacing * (aWidths.size()-1);
1140 long nTotalHeight = 0;
1141 if (get_row_homogeneous())
1143 nTotalHeight = std::max_element(aHeights.begin(), aHeights.end(), compareValues)->m_nValue;
1144 nTotalHeight *= aHeights.size();
1146 else
1148 nTotalHeight = std::accumulate(aHeights.begin(), aHeights.end(), Value(), accumulateValues).m_nValue;
1151 nTotalHeight += nRowSpacing * (aHeights.size()-1);
1153 return Size(nTotalWidth, nTotalHeight);
1156 void VclGrid::setAllocation(const Size& rAllocation)
1158 array_type A = assembleGrid(*this);
1160 if (isNullGrid(A))
1161 return;
1163 sal_Int32 nMaxX = A.shape()[0];
1164 sal_Int32 nMaxY = A.shape()[1];
1166 Size aRequisition;
1167 std::vector<Value> aWidths(nMaxX);
1168 std::vector<Value> aHeights(nMaxY);
1169 if (!get_column_homogeneous() || !get_row_homogeneous())
1171 aRequisition = calculateRequisition();
1172 calcMaxs(A, aWidths, aHeights);
1175 sal_Int32 nColSpacing(get_column_spacing());
1176 sal_Int32 nRowSpacing(get_row_spacing());
1178 long nAvailableWidth = rAllocation.Width();
1179 if (nMaxX)
1180 nAvailableWidth -= nColSpacing * (nMaxX - 1);
1181 if (get_column_homogeneous())
1183 for (sal_Int32 x = 0; x < nMaxX; ++x)
1184 aWidths[x].m_nValue = nAvailableWidth/nMaxX;
1186 else if (rAllocation.Width() != aRequisition.Width())
1188 sal_Int32 nExpandables = 0;
1189 for (sal_Int32 x = 0; x < nMaxX; ++x)
1190 if (aWidths[x].m_bExpand)
1191 ++nExpandables;
1192 long nExtraWidthForExpanders = nExpandables ? (rAllocation.Width() - aRequisition.Width()) / nExpandables : 0;
1194 //We don't fit and there is no volunteer to be shrunk
1195 if (!nExpandables && rAllocation.Width() < aRequisition.Width())
1197 //first reduce spacing
1198 while (nColSpacing)
1200 nColSpacing /= 2;
1201 aRequisition = calculateRequisitionForSpacings(nRowSpacing, nColSpacing);
1202 if (aRequisition.Width() <= rAllocation.Width())
1203 break;
1206 //share out the remaining pain to everyone
1207 long nExtraWidth = (rAllocation.Width() - aRequisition.Width()) / nMaxX;
1209 for (sal_Int32 x = 0; x < nMaxX; ++x)
1210 aWidths[x].m_nValue += nExtraWidth;
1213 if (nExtraWidthForExpanders)
1215 for (sal_Int32 x = 0; x < nMaxX; ++x)
1216 if (aWidths[x].m_bExpand)
1217 aWidths[x].m_nValue += nExtraWidthForExpanders;
1221 long nAvailableHeight = rAllocation.Height();
1222 if (nMaxY)
1223 nAvailableHeight -= nRowSpacing * (nMaxY - 1);
1224 if (get_row_homogeneous())
1226 for (sal_Int32 y = 0; y < nMaxY; ++y)
1227 aHeights[y].m_nValue = nAvailableHeight/nMaxY;
1229 else if (rAllocation.Height() != aRequisition.Height())
1231 sal_Int32 nExpandables = 0;
1232 for (sal_Int32 y = 0; y < nMaxY; ++y)
1233 if (aHeights[y].m_bExpand)
1234 ++nExpandables;
1235 long nExtraHeightForExpanders = nExpandables ? (rAllocation.Height() - aRequisition.Height()) / nExpandables : 0;
1237 //We don't fit and there is no volunteer to be shrunk
1238 if (!nExpandables && rAllocation.Height() < aRequisition.Height())
1240 //first reduce spacing
1241 while (nRowSpacing)
1243 nRowSpacing /= 2;
1244 aRequisition = calculateRequisitionForSpacings(nRowSpacing, nColSpacing);
1245 if (aRequisition.Height() <= rAllocation.Height())
1246 break;
1249 //share out the remaining pain to everyone
1250 long nExtraHeight = (rAllocation.Height() - aRequisition.Height()) / nMaxY;
1252 for (sal_Int32 y = 0; y < nMaxY; ++y)
1253 aHeights[y].m_nValue += nExtraHeight;
1256 if (nExtraHeightForExpanders)
1258 for (sal_Int32 y = 0; y < nMaxY; ++y)
1259 if (aHeights[y].m_bExpand)
1260 aHeights[y].m_nValue += nExtraHeightForExpanders;
1264 Point aAllocPos(0, 0);
1265 for (sal_Int32 x = 0; x < nMaxX; ++x)
1267 for (sal_Int32 y = 0; y < nMaxY; ++y)
1269 GridEntry &rEntry = A[x][y];
1270 vcl::Window *pChild = rEntry.pChild;
1271 if (pChild)
1273 Size aChildAlloc(0, 0);
1275 sal_Int32 nWidth = rEntry.nSpanWidth;
1276 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1277 aChildAlloc.AdjustWidth(aWidths[x+nSpanX].m_nValue );
1278 aChildAlloc.AdjustWidth(nColSpacing*(nWidth-1) );
1280 sal_Int32 nHeight = rEntry.nSpanHeight;
1281 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1282 aChildAlloc.AdjustHeight(aHeights[y+nSpanY].m_nValue );
1283 aChildAlloc.AdjustHeight(nRowSpacing*(nHeight-1) );
1285 setLayoutAllocation(*pChild, aAllocPos, aChildAlloc);
1287 aAllocPos.AdjustY(aHeights[y].m_nValue + nRowSpacing );
1289 aAllocPos.AdjustX(aWidths[x].m_nValue + nColSpacing );
1290 aAllocPos.setY( 0 );
1294 boost::property_tree::ptree VclGrid::DumpAsPropertyTree()
1296 boost::property_tree::ptree aTree(VclContainer::DumpAsPropertyTree());
1297 aTree.put("type", "grid");
1298 return aTree;
1301 bool toBool(const OUString &rValue)
1303 return (!rValue.isEmpty() && (rValue[0] == 't' || rValue[0] == 'T' || rValue[0] == '1'));
1306 bool VclGrid::set_property(const OString &rKey, const OUString &rValue)
1308 if (rKey == "row-spacing")
1309 set_row_spacing(rValue.toInt32());
1310 else if (rKey == "column-spacing")
1311 set_column_spacing(rValue.toInt32());
1312 else if (rKey == "row-homogeneous")
1313 m_bRowHomogeneous = toBool(rValue);
1314 else if (rKey == "column-homogeneous")
1315 m_bColumnHomogeneous = toBool(rValue);
1316 else if (rKey == "n-rows")
1317 /*nothing to do*/;
1318 else
1319 return VclContainer::set_property(rKey, rValue);
1320 return true;
1323 const vcl::Window *VclBin::get_child() const
1325 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1327 return pWindowImpl->mpFirstChild;
1330 vcl::Window *VclBin::get_child()
1332 return const_cast<vcl::Window*>(const_cast<const VclBin*>(this)->get_child());
1335 Size VclBin::calculateRequisition() const
1337 const vcl::Window *pChild = get_child();
1338 if (pChild && pChild->IsVisible())
1339 return getLayoutRequisition(*pChild);
1340 return Size(0, 0);
1343 void VclBin::setAllocation(const Size &rAllocation)
1345 vcl::Window *pChild = get_child();
1346 if (pChild && pChild->IsVisible())
1347 setLayoutAllocation(*pChild, Point(0, 0), rAllocation);
1350 VclFrame::~VclFrame()
1352 disposeOnce();
1355 void VclFrame::dispose()
1357 m_pLabel.clear();
1358 VclBin::dispose();
1361 //To-Do, hook a DecorationView into VclFrame ?
1363 Size VclFrame::calculateRequisition() const
1365 Size aRet(0, 0);
1367 const vcl::Window *pChild = get_child();
1368 const vcl::Window *pLabel = get_label_widget();
1370 if (pChild && pChild->IsVisible())
1371 aRet = getLayoutRequisition(*pChild);
1373 if (pLabel && pLabel->IsVisible())
1375 Size aLabelSize = getLayoutRequisition(*pLabel);
1376 aRet.AdjustHeight(aLabelSize.Height() );
1377 aRet.setWidth( std::max(aLabelSize.Width(), aRet.Width()) );
1380 return aRet;
1383 void VclFrame::setAllocation(const Size &rAllocation)
1385 //SetBackground( Color(0xFF, 0x00, 0xFF) );
1387 Size aAllocation(rAllocation);
1388 Point aChildPos;
1390 vcl::Window *pChild = get_child();
1391 vcl::Window *pLabel = get_label_widget();
1393 if (pLabel && pLabel->IsVisible())
1395 Size aLabelSize = getLayoutRequisition(*pLabel);
1396 aLabelSize.setHeight( std::min(aLabelSize.Height(), aAllocation.Height()) );
1397 aLabelSize.setWidth( std::min(aLabelSize.Width(), aAllocation.Width()) );
1398 setLayoutAllocation(*pLabel, aChildPos, aLabelSize);
1399 aAllocation.AdjustHeight( -(aLabelSize.Height()) );
1400 aChildPos.AdjustY(aLabelSize.Height() );
1403 if (pChild && pChild->IsVisible())
1404 setLayoutAllocation(*pChild, aChildPos, aAllocation);
1407 IMPL_LINK(VclFrame, WindowEventListener, VclWindowEvent&, rEvent, void)
1409 if (rEvent.GetId() == VclEventId::ObjectDying)
1410 designate_label(nullptr);
1413 void VclFrame::designate_label(vcl::Window *pWindow)
1415 assert(!pWindow || pWindow->GetParent() == this);
1416 if (m_pLabel)
1417 m_pLabel->RemoveEventListener(LINK(this, VclFrame, WindowEventListener));
1418 m_pLabel = pWindow;
1419 if (m_pLabel)
1420 m_pLabel->AddEventListener(LINK(this, VclFrame, WindowEventListener));
1423 const vcl::Window *VclFrame::get_label_widget() const
1425 assert(GetChildCount() == 2);
1426 if (m_pLabel)
1427 return m_pLabel;
1428 //The label widget is normally the first (of two) children
1429 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1430 if (pWindowImpl->mpFirstChild == pWindowImpl->mpLastChild) //no label exists
1431 return nullptr;
1432 return pWindowImpl->mpFirstChild;
1435 vcl::Window *VclFrame::get_label_widget()
1437 return const_cast<vcl::Window*>(const_cast<const VclFrame*>(this)->get_label_widget());
1440 const vcl::Window *VclFrame::get_child() const
1442 //The child widget is the normally the last (of two) children
1443 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1444 assert(GetChildCount() == 2 || pWindowImpl->mbInDispose);
1445 if (!m_pLabel)
1446 return pWindowImpl->mpLastChild;
1447 if (pWindowImpl->mpFirstChild == pWindowImpl->mpLastChild) //only label exists
1448 return nullptr;
1449 return pWindowImpl->mpLastChild;
1452 vcl::Window *VclFrame::get_child()
1454 return const_cast<vcl::Window*>(const_cast<const VclFrame*>(this)->get_child());
1457 void VclFrame::set_label(const OUString &rLabel)
1459 vcl::Window *pLabel = get_label_widget();
1460 assert(pLabel);
1461 pLabel->SetText(rLabel);
1464 OUString VclFrame::get_label() const
1466 const vcl::Window *pLabel = get_label_widget();
1467 assert(pLabel);
1468 return pLabel->GetText();
1471 OUString VclFrame::getDefaultAccessibleName() const
1473 const vcl::Window *pLabel = get_label_widget();
1474 if (pLabel)
1475 return pLabel->GetAccessibleName();
1476 return VclBin::getDefaultAccessibleName();
1479 boost::property_tree::ptree VclFrame::DumpAsPropertyTree()
1481 boost::property_tree::ptree aTree(VclBin::DumpAsPropertyTree());
1482 aTree.put("type", "frame");
1483 return aTree;
1486 Size VclAlignment::calculateRequisition() const
1488 Size aRet(m_nLeftPadding + m_nRightPadding,
1489 m_nTopPadding + m_nBottomPadding);
1491 const vcl::Window *pChild = get_child();
1492 if (pChild && pChild->IsVisible())
1494 Size aChildSize = getLayoutRequisition(*pChild);
1495 aRet.AdjustWidth(aChildSize.Width() );
1496 aRet.AdjustHeight(aChildSize.Height() );
1499 return aRet;
1502 void VclAlignment::setAllocation(const Size &rAllocation)
1504 vcl::Window *pChild = get_child();
1505 if (!pChild || !pChild->IsVisible())
1506 return;
1508 Point aChildPos(m_nLeftPadding, m_nTopPadding);
1510 Size aAllocation;
1511 aAllocation.setWidth( rAllocation.Width() - (m_nLeftPadding + m_nRightPadding) );
1512 aAllocation.setHeight( rAllocation.Height() - (m_nTopPadding + m_nBottomPadding) );
1514 setLayoutAllocation(*pChild, aChildPos, aAllocation);
1517 bool VclAlignment::set_property(const OString &rKey, const OUString &rValue)
1519 if (rKey == "bottom-padding")
1520 m_nBottomPadding = rValue.toInt32();
1521 else if (rKey == "left-padding")
1522 m_nLeftPadding = rValue.toInt32();
1523 else if (rKey == "right-padding")
1524 m_nRightPadding = rValue.toInt32();
1525 else if (rKey == "top-padding")
1526 m_nTopPadding = rValue.toInt32();
1527 else
1528 return VclBin::set_property(rKey, rValue);
1529 return true;
1532 void VclExpander::dispose()
1534 m_pDisclosureButton.disposeAndClear();
1535 VclBin::dispose();
1538 const vcl::Window *VclExpander::get_child() const
1540 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1542 assert(pWindowImpl->mpFirstChild == m_pDisclosureButton);
1544 return pWindowImpl->mpFirstChild->GetWindow(GetWindowType::Next);
1547 vcl::Window *VclExpander::get_child()
1549 return const_cast<vcl::Window*>(const_cast<const VclExpander*>(this)->get_child());
1552 Size VclExpander::calculateRequisition() const
1554 Size aRet(0, 0);
1556 WindowImpl* pWindowImpl = ImplGetWindowImpl();
1558 const vcl::Window *pChild = get_child();
1559 const vcl::Window *pLabel = pChild != pWindowImpl->mpLastChild ? pWindowImpl->mpLastChild.get() : nullptr;
1561 if (pChild && pChild->IsVisible() && m_pDisclosureButton->IsChecked())
1562 aRet = getLayoutRequisition(*pChild);
1564 Size aExpanderSize = getLayoutRequisition(*m_pDisclosureButton);
1566 if (pLabel && pLabel->IsVisible())
1568 Size aLabelSize = getLayoutRequisition(*pLabel);
1569 aExpanderSize.setHeight( std::max(aExpanderSize.Height(), aLabelSize.Height()) );
1570 aExpanderSize.AdjustWidth(aLabelSize.Width() );
1573 aRet.AdjustHeight(aExpanderSize.Height() );
1574 aRet.setWidth( std::max(aExpanderSize.Width(), aRet.Width()) );
1576 return aRet;
1579 void VclExpander::setAllocation(const Size &rAllocation)
1581 Size aAllocation(rAllocation);
1582 Point aChildPos;
1584 WindowImpl* pWindowImpl = ImplGetWindowImpl();
1586 //The label widget is the last (of two) children
1587 vcl::Window *pChild = get_child();
1588 vcl::Window *pLabel = pChild != pWindowImpl->mpLastChild.get() ? pWindowImpl->mpLastChild.get() : nullptr;
1590 Size aButtonSize = getLayoutRequisition(*m_pDisclosureButton);
1591 Size aLabelSize;
1592 Size aExpanderSize = aButtonSize;
1593 if (pLabel && pLabel->IsVisible())
1595 aLabelSize = getLayoutRequisition(*pLabel);
1596 aExpanderSize.setHeight( std::max(aExpanderSize.Height(), aLabelSize.Height()) );
1597 aExpanderSize.AdjustWidth(aLabelSize.Width() );
1600 aExpanderSize.setHeight( std::min(aExpanderSize.Height(), aAllocation.Height()) );
1601 aExpanderSize.setWidth( std::min(aExpanderSize.Width(), aAllocation.Width()) );
1603 aButtonSize.setHeight( std::min(aButtonSize.Height(), aExpanderSize.Height()) );
1604 aButtonSize.setWidth( std::min(aButtonSize.Width(), aExpanderSize.Width()) );
1606 long nExtraExpanderHeight = aExpanderSize.Height() - aButtonSize.Height();
1607 Point aButtonPos(aChildPos.X(), aChildPos.Y() + nExtraExpanderHeight/2);
1608 setLayoutAllocation(*m_pDisclosureButton, aButtonPos, aButtonSize);
1610 if (pLabel && pLabel->IsVisible())
1612 aLabelSize.setHeight( std::min(aLabelSize.Height(), aExpanderSize.Height()) );
1613 aLabelSize.setWidth( std::min(aLabelSize.Width(),
1614 aExpanderSize.Width() - aButtonSize.Width()) );
1616 long nExtraLabelHeight = aExpanderSize.Height() - aLabelSize.Height();
1617 Point aLabelPos(aChildPos.X() + aButtonSize.Width(), aChildPos.Y() + nExtraLabelHeight/2);
1618 setLayoutAllocation(*pLabel, aLabelPos, aLabelSize);
1621 aAllocation.AdjustHeight( -(aExpanderSize.Height()) );
1622 aChildPos.AdjustY(aExpanderSize.Height() );
1624 if (pChild && pChild->IsVisible())
1626 if (!m_pDisclosureButton->IsChecked())
1627 aAllocation = Size();
1628 setLayoutAllocation(*pChild, aChildPos, aAllocation);
1632 bool VclExpander::set_property(const OString &rKey, const OUString &rValue)
1634 if (rKey == "expanded")
1635 set_expanded(toBool(rValue));
1636 else if (rKey == "resize-toplevel")
1637 m_bResizeTopLevel = toBool(rValue);
1638 else
1639 return VclBin::set_property(rKey, rValue);
1640 return true;
1643 void VclExpander::StateChanged(StateChangedType nType)
1645 VclBin::StateChanged( nType );
1647 if (nType == StateChangedType::InitShow)
1649 vcl::Window *pChild = get_child();
1650 if (pChild)
1651 pChild->Show(m_pDisclosureButton->IsChecked());
1655 IMPL_LINK( VclExpander, ClickHdl, CheckBox&, rBtn, void )
1657 vcl::Window *pChild = get_child();
1658 if (pChild)
1660 pChild->Show(rBtn.IsChecked());
1661 queue_resize();
1662 Dialog* pResizeDialog = m_bResizeTopLevel ? GetParentDialog() : nullptr;
1663 if (pResizeDialog)
1664 pResizeDialog->setOptimalLayoutSize();
1666 maExpandedHdl.Call(*this);
1669 VclScrolledWindow::VclScrolledWindow(vcl::Window *pParent)
1670 : VclBin(pParent, WB_HIDE | WB_CLIPCHILDREN | WB_AUTOHSCROLL | WB_AUTOVSCROLL | WB_TABSTOP)
1671 , m_bUserManagedScrolling(false)
1672 , m_pVScroll(VclPtr<ScrollBar>::Create(this, WB_HIDE | WB_VERT))
1673 , m_pHScroll(VclPtr<ScrollBar>::Create(this, WB_HIDE | WB_HORZ))
1674 , m_aScrollBarBox(VclPtr<ScrollBarBox>::Create(this, WB_HIDE))
1676 SetType(WindowType::SCROLLWINDOW);
1678 Link<ScrollBar*,void> aLink( LINK( this, VclScrolledWindow, ScrollBarHdl ) );
1679 m_pVScroll->SetScrollHdl(aLink);
1680 m_pHScroll->SetScrollHdl(aLink);
1683 void VclScrolledWindow::dispose()
1685 m_pVScroll.disposeAndClear();
1686 m_pHScroll.disposeAndClear();
1687 m_aScrollBarBox.disposeAndClear();
1688 VclBin::dispose();
1691 IMPL_LINK_NOARG(VclScrolledWindow, ScrollBarHdl, ScrollBar*, void)
1693 vcl::Window *pChild = get_child();
1694 if (!pChild)
1695 return;
1697 assert(dynamic_cast<VclViewport*>(pChild) && "scrolledwindow child should be a Viewport");
1699 pChild = pChild->GetWindow(GetWindowType::FirstChild);
1701 if (!pChild)
1702 return;
1704 Point aWinPos(-m_pHScroll->GetThumbPos(), -m_pVScroll->GetThumbPos());
1705 pChild->SetPosPixel(aWinPos);
1708 const vcl::Window *VclScrolledWindow::get_child() const
1710 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1711 assert(GetChildCount() == 4 || pWindowImpl->mbInDispose);
1712 return pWindowImpl->mpLastChild;
1715 vcl::Window *VclScrolledWindow::get_child()
1717 return const_cast<vcl::Window*>(const_cast<const VclScrolledWindow*>(this)->get_child());
1720 Size VclScrolledWindow::calculateRequisition() const
1722 Size aRet(0, 0);
1724 const vcl::Window *pChild = get_child();
1725 if (pChild && pChild->IsVisible())
1726 aRet = getLayoutRequisition(*pChild);
1728 if (GetStyle() & WB_VSCROLL)
1729 aRet.AdjustWidth(getLayoutRequisition(*m_pVScroll).Width() );
1731 if (GetStyle() & WB_HSCROLL)
1732 aRet.AdjustHeight(getLayoutRequisition(*m_pHScroll).Height() );
1734 aRet.AdjustHeight(2);
1735 aRet.AdjustWidth(2);
1737 return aRet;
1740 void VclScrolledWindow::InitScrollBars(const Size &rRequest)
1742 const vcl::Window *pChild = get_child();
1743 if (!pChild || !pChild->IsVisible())
1744 return;
1746 Size aOutSize(getVisibleChildSize());
1748 m_pVScroll->SetRangeMax(rRequest.Height());
1749 m_pVScroll->SetVisibleSize(aOutSize.Height());
1750 m_pVScroll->SetPageSize(16);
1752 m_pHScroll->SetRangeMax(rRequest.Width());
1753 m_pHScroll->SetVisibleSize(aOutSize.Width());
1754 m_pHScroll->SetPageSize(16);
1756 m_pVScroll->Scroll();
1757 m_pHScroll->Scroll();
1760 void VclScrolledWindow::doSetAllocation(const Size &rAllocation, bool bRetryOnFailure)
1762 Size aChildReq;
1764 vcl::Window *pChild = get_child();
1765 if (pChild && pChild->IsVisible())
1766 aChildReq = getLayoutRequisition(*pChild);
1768 long nAvailHeight = rAllocation.Height() - 2;
1769 long nAvailWidth = rAllocation.Width() - 2;
1770 // vert. ScrollBar
1771 if (GetStyle() & WB_AUTOVSCROLL)
1773 m_pVScroll->Show(nAvailHeight < aChildReq.Height());
1775 else if (m_pVScroll->IsVisible() != bool(GetStyle() & WB_VSCROLL))
1776 m_pVScroll->Show((GetStyle() & WB_VSCROLL) != 0);
1778 if (m_pVScroll->IsVisible())
1779 nAvailWidth -= getLayoutRequisition(*m_pVScroll).Width();
1781 // horz. ScrollBar
1782 if (GetStyle() & WB_AUTOHSCROLL)
1784 bool bShowHScroll = nAvailWidth < aChildReq.Width();
1785 m_pHScroll->Show(bShowHScroll);
1787 if (bShowHScroll)
1788 nAvailHeight -= getLayoutRequisition(*m_pHScroll).Height();
1790 if (GetStyle() & WB_AUTOVSCROLL)
1791 m_pVScroll->Show(nAvailHeight < aChildReq.Height());
1793 else if (m_pHScroll->IsVisible() != bool(GetStyle() & WB_HSCROLL))
1794 m_pHScroll->Show((GetStyle() & WB_HSCROLL) != 0);
1796 Size aInnerSize(rAllocation);
1797 aInnerSize.AdjustWidth(-2);
1798 aInnerSize.AdjustHeight(-2);
1800 bool bBothVisible = m_pVScroll->IsVisible() && m_pHScroll->IsVisible();
1801 auto nScrollBarWidth = getLayoutRequisition(*m_pVScroll).Width();
1802 auto nScrollBarHeight = getLayoutRequisition(*m_pHScroll).Height();
1804 if (m_pVScroll->IsVisible())
1806 Point aScrollPos(rAllocation.Width() - nScrollBarWidth - 2, 1);
1807 Size aScrollSize(nScrollBarWidth, rAllocation.Height() - 2);
1808 if (bBothVisible)
1809 aScrollSize.AdjustHeight(-nScrollBarHeight);
1810 setLayoutAllocation(*m_pVScroll, aScrollPos, aScrollSize);
1811 aInnerSize.AdjustWidth( -nScrollBarWidth );
1814 if (m_pHScroll->IsVisible())
1816 Point aScrollPos(1, rAllocation.Height() - nScrollBarHeight);
1817 Size aScrollSize(rAllocation.Width() - 2, nScrollBarHeight);
1818 if (bBothVisible)
1819 aScrollSize.AdjustWidth(-nScrollBarWidth);
1820 setLayoutAllocation(*m_pHScroll, aScrollPos, aScrollSize);
1821 aInnerSize.AdjustHeight( -nScrollBarHeight );
1824 if (bBothVisible)
1826 Point aBoxPos(aInnerSize.Width() + 1, aInnerSize.Height() + 1);
1827 m_aScrollBarBox->SetPosSizePixel(aBoxPos, Size(nScrollBarWidth, nScrollBarHeight));
1828 m_aScrollBarBox->Show();
1830 else
1832 m_aScrollBarBox->Hide();
1835 if (pChild && pChild->IsVisible())
1837 assert(dynamic_cast<VclViewport*>(pChild) && "scrolledwindow child should be a Viewport");
1839 WinBits nOldBits = (GetStyle() & (WB_AUTOVSCROLL | WB_VSCROLL | WB_AUTOHSCROLL | WB_HSCROLL));
1841 setLayoutAllocation(*pChild, Point(1, 1), aInnerSize);
1843 // tdf#128758 if the layout allocation triggered some callback that
1844 // immediately invalidates the layout by adding scrollbars then
1845 // normally this would simply retrigger layout and another toplevel
1846 // attempt is made later. But the initial layout attempt blocks
1847 // relayouts, so just make another single effort here.
1848 WinBits nNewBits = (GetStyle() & (WB_AUTOVSCROLL | WB_VSCROLL | WB_AUTOHSCROLL | WB_HSCROLL));
1849 if (nOldBits != nNewBits && bRetryOnFailure)
1851 doSetAllocation(rAllocation, false);
1852 return;
1856 if (!m_bUserManagedScrolling)
1857 InitScrollBars(aChildReq);
1860 void VclScrolledWindow::setAllocation(const Size &rAllocation)
1862 doSetAllocation(rAllocation, true);
1865 Size VclScrolledWindow::getVisibleChildSize() const
1867 Size aRet(GetSizePixel());
1868 if (m_pVScroll->IsVisible())
1869 aRet.AdjustWidth( -(m_pVScroll->GetSizePixel().Width()) );
1870 if (m_pHScroll->IsVisible())
1871 aRet.AdjustHeight( -(m_pHScroll->GetSizePixel().Height()) );
1872 aRet.AdjustHeight(-2);
1873 aRet.AdjustWidth(-2);
1874 return aRet;
1877 bool VclScrolledWindow::set_property(const OString &rKey, const OUString &rValue)
1879 bool bRet = VclBin::set_property(rKey, rValue);
1880 m_pVScroll->Show((GetStyle() & WB_VSCROLL) != 0);
1881 m_pHScroll->Show((GetStyle() & WB_HSCROLL) != 0);
1882 return bRet;
1885 bool VclScrolledWindow::EventNotify(NotifyEvent& rNEvt)
1887 bool bDone = false;
1888 if ( rNEvt.GetType() == MouseNotifyEvent::COMMAND )
1890 const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
1891 if ( rCEvt.GetCommand() == CommandEventId::Wheel )
1893 const CommandWheelData* pData = rCEvt.GetWheelData();
1894 if( !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) )
1896 bDone = HandleScrollCommand(rCEvt, m_pHScroll, m_pVScroll);
1901 return bDone || VclBin::EventNotify( rNEvt );
1904 void VclScrolledWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
1906 VclBin::Paint(rRenderContext, rRect);
1907 DecorationView aDecoView(&rRenderContext);
1908 aDecoView.DrawFrame(tools::Rectangle(Point(0,0), GetSizePixel()));
1911 void VclViewport::setAllocation(const Size &rAllocation)
1913 vcl::Window *pChild = get_child();
1914 if (pChild && pChild->IsVisible())
1916 Size aReq(getLayoutRequisition(*pChild));
1917 aReq.setWidth( std::max(aReq.Width(), rAllocation.Width()) );
1918 aReq.setHeight( std::max(aReq.Height(), rAllocation.Height()) );
1919 Point aKeepPos(pChild->GetPosPixel());
1920 if (m_bInitialAllocation)
1922 aKeepPos = Point(0, 0);
1923 m_bInitialAllocation = false;
1925 setLayoutAllocation(*pChild, aKeepPos, aReq);
1929 const vcl::Window *VclEventBox::get_child() const
1931 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1933 assert(pWindowImpl->mpFirstChild.get() == m_aEventBoxHelper.get());
1935 return pWindowImpl->mpFirstChild->GetWindow(GetWindowType::Next);
1938 vcl::Window *VclEventBox::get_child()
1940 return const_cast<vcl::Window*>(const_cast<const VclEventBox*>(this)->get_child());
1943 void VclEventBox::setAllocation(const Size& rAllocation)
1945 Point aChildPos(0, 0);
1946 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
1948 if (!pChild->IsVisible())
1949 continue;
1950 setLayoutAllocation(*pChild, aChildPos, rAllocation);
1954 Size VclEventBox::calculateRequisition() const
1956 Size aRet(0, 0);
1958 for (const vcl::Window* pChild = get_child(); pChild;
1959 pChild = pChild->GetWindow(GetWindowType::Next))
1961 if (!pChild->IsVisible())
1962 continue;
1963 Size aChildSize = getLayoutRequisition(*pChild);
1964 aRet.setWidth( std::max(aRet.Width(), aChildSize.Width()) );
1965 aRet.setHeight( std::max(aRet.Height(), aChildSize.Height()) );
1968 return aRet;
1971 void VclEventBox::Command(const CommandEvent&)
1973 //discard events by default to block them reaching children
1976 VclEventBox::~VclEventBox()
1978 disposeOnce();
1981 void VclEventBox::dispose()
1983 m_aEventBoxHelper.disposeAndClear();
1984 VclBin::dispose();
1987 void VclSizeGroup::trigger_queue_resize()
1989 //sufficient to trigger one widget to trigger all of them
1990 if (!m_aWindows.empty())
1992 (*m_aWindows.begin())->queue_resize();
1996 void VclSizeGroup::set_ignore_hidden(bool bIgnoreHidden)
1998 if (bIgnoreHidden != m_bIgnoreHidden)
2000 m_bIgnoreHidden = bIgnoreHidden;
2001 trigger_queue_resize();
2005 void VclSizeGroup::set_mode(VclSizeGroupMode eMode)
2007 if (eMode != m_eMode)
2009 m_eMode = eMode;
2010 trigger_queue_resize();
2015 void VclSizeGroup::set_property(const OString &rKey, const OUString &rValue)
2017 if (rKey == "ignore-hidden")
2018 set_ignore_hidden(toBool(rValue));
2019 else if (rKey == "mode")
2021 VclSizeGroupMode eMode = VclSizeGroupMode::Horizontal;
2022 if (rValue == "none")
2023 eMode = VclSizeGroupMode::NONE;
2024 else if (rValue == "horizontal")
2025 eMode = VclSizeGroupMode::Horizontal;
2026 else if (rValue == "vertical")
2027 eMode = VclSizeGroupMode::Vertical;
2028 else if (rValue == "both")
2029 eMode = VclSizeGroupMode::Both;
2030 else
2032 SAL_WARN("vcl.layout", "unknown size group mode" << rValue);
2034 set_mode(eMode);
2036 else
2038 SAL_INFO("vcl.layout", "unhandled property: " << rKey);
2042 void MessageDialog::create_message_area()
2044 setDeferredProperties();
2046 if (!m_pGrid)
2048 VclContainer *pContainer = get_content_area();
2049 assert(pContainer);
2051 m_pGrid.set( VclPtr<VclGrid>::Create(pContainer) );
2052 m_pGrid->reorderWithinParent(0);
2053 m_pGrid->set_column_spacing(12);
2054 m_pMessageBox.set(VclPtr<VclVBox>::Create(m_pGrid));
2055 m_pMessageBox->set_grid_left_attach(1);
2056 m_pMessageBox->set_grid_top_attach(0);
2057 m_pMessageBox->set_spacing(GetTextHeight());
2059 m_pImage = VclPtr<FixedImage>::Create(m_pGrid, WB_CENTER | WB_VCENTER | WB_3DLOOK);
2060 switch (m_eMessageType)
2062 case VclMessageType::Info:
2063 m_pImage->SetImage(GetStandardInfoBoxImage());
2064 break;
2065 case VclMessageType::Warning:
2066 m_pImage->SetImage(GetStandardWarningBoxImage());
2067 break;
2068 case VclMessageType::Question:
2069 m_pImage->SetImage(GetStandardQueryBoxImage());
2070 break;
2071 case VclMessageType::Error:
2072 m_pImage->SetImage(GetStandardErrorBoxImage());
2073 break;
2075 m_pImage->set_grid_left_attach(0);
2076 m_pImage->set_grid_top_attach(0);
2077 m_pImage->set_valign(VclAlign::Start);
2078 m_pImage->Show();
2080 WinBits nWinStyle = WB_CLIPCHILDREN | WB_LEFT | WB_VCENTER | WB_NOLABEL | WB_NOTABSTOP;
2082 bool bHasSecondaryText = !m_sSecondaryString.isEmpty();
2084 m_pPrimaryMessage = VclPtr<VclMultiLineEdit>::Create(m_pMessageBox, nWinStyle);
2085 m_pPrimaryMessage->SetPaintTransparent(true);
2086 m_pPrimaryMessage->EnableCursor(false);
2088 m_pPrimaryMessage->set_hexpand(true);
2089 m_pPrimaryMessage->SetText(m_sPrimaryString);
2090 m_pPrimaryMessage->Show(!m_sPrimaryString.isEmpty());
2092 m_pSecondaryMessage = VclPtr<VclMultiLineEdit>::Create(m_pMessageBox, nWinStyle);
2093 m_pSecondaryMessage->SetPaintTransparent(true);
2094 m_pSecondaryMessage->EnableCursor(false);
2095 m_pSecondaryMessage->set_hexpand(true);
2096 m_pSecondaryMessage->SetText(m_sSecondaryString);
2097 m_pSecondaryMessage->Show(bHasSecondaryText);
2099 MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, bHasSecondaryText ? m_pSecondaryMessage.get() : nullptr);
2101 VclButtonBox *pButtonBox = get_action_area();
2102 assert(pButtonBox);
2104 VclPtr<PushButton> pBtn;
2105 short nDefaultResponse = get_default_response();
2106 switch (m_eButtonsType)
2108 case VclButtonsType::NONE:
2109 break;
2110 case VclButtonsType::Ok:
2111 pBtn.set( VclPtr<OKButton>::Create(pButtonBox) );
2112 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2113 pBtn->Show();
2114 pBtn->set_id("ok");
2115 add_button(pBtn, RET_OK, true);
2116 nDefaultResponse = RET_OK;
2117 break;
2118 case VclButtonsType::Close:
2119 pBtn.set( VclPtr<CloseButton>::Create(pButtonBox) );
2120 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2121 pBtn->Show();
2122 pBtn->set_id("close");
2123 add_button(pBtn, RET_CLOSE, true);
2124 nDefaultResponse = RET_CLOSE;
2125 break;
2126 case VclButtonsType::Cancel:
2127 pBtn.set( VclPtr<CancelButton>::Create(pButtonBox) );
2128 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2129 pBtn->Show();
2130 pBtn->set_id("cancel");
2131 add_button(pBtn, RET_CANCEL, true);
2132 nDefaultResponse = RET_CANCEL;
2133 break;
2134 case VclButtonsType::YesNo:
2135 pBtn = VclPtr<PushButton>::Create(pButtonBox);
2136 pBtn->SetText(GetStandardText(StandardButtonType::Yes));
2137 pBtn->Show();
2138 pBtn->set_id("yes");
2139 add_button(pBtn, RET_YES, true);
2141 pBtn.set( VclPtr<PushButton>::Create(pButtonBox) );
2142 pBtn->SetText(GetStandardText(StandardButtonType::No));
2143 pBtn->Show();
2144 pBtn->set_id("no");
2145 add_button(pBtn, RET_NO, true);
2146 nDefaultResponse = RET_NO;
2147 break;
2148 case VclButtonsType::OkCancel:
2149 pBtn.set( VclPtr<OKButton>::Create(pButtonBox) );
2150 pBtn->Show();
2151 pBtn->set_id("ok");
2152 add_button(pBtn, RET_OK, true);
2154 pBtn.set( VclPtr<CancelButton>::Create(pButtonBox) );
2155 pBtn->Show();
2156 pBtn->set_id("cancel");
2157 add_button(pBtn, RET_CANCEL, true);
2158 nDefaultResponse = RET_CANCEL;
2159 break;
2161 set_default_response(nDefaultResponse);
2162 pButtonBox->sort_native_button_order();
2163 m_pMessageBox->Show();
2164 m_pGrid->Show();
2168 void MessageDialog::create_owned_areas()
2170 #if defined WNT
2171 set_border_width(3);
2172 #else
2173 set_border_width(12);
2174 #endif
2175 m_pOwnedContentArea.set(VclPtr<VclVBox>::Create(this, false, 24));
2176 set_content_area(m_pOwnedContentArea);
2177 m_pOwnedContentArea->Show();
2178 m_pOwnedActionArea.set( VclPtr<VclHButtonBox>::Create(m_pOwnedContentArea) );
2179 set_action_area(m_pOwnedActionArea);
2180 m_pOwnedActionArea->Show();
2183 MessageDialog::MessageDialog(vcl::Window* pParent, WinBits nStyle)
2184 : Dialog(pParent, nStyle)
2185 , m_eButtonsType(VclButtonsType::NONE)
2186 , m_eMessageType(VclMessageType::Info)
2187 , m_pOwnedContentArea(nullptr)
2188 , m_pOwnedActionArea(nullptr)
2189 , m_pGrid(nullptr)
2190 , m_pMessageBox(nullptr)
2191 , m_pImage(nullptr)
2192 , m_pPrimaryMessage(nullptr)
2193 , m_pSecondaryMessage(nullptr)
2195 SetType(WindowType::MESSBOX);
2198 MessageDialog::MessageDialog(vcl::Window* pParent,
2199 const OUString &rMessage,
2200 VclMessageType eMessageType,
2201 VclButtonsType eButtonsType)
2202 : Dialog(pParent, WB_MOVEABLE | WB_3DLOOK | WB_CLOSEABLE)
2203 , m_eButtonsType(eButtonsType)
2204 , m_eMessageType(eMessageType)
2205 , m_pGrid(nullptr)
2206 , m_pMessageBox(nullptr)
2207 , m_pImage(nullptr)
2208 , m_pPrimaryMessage(nullptr)
2209 , m_pSecondaryMessage(nullptr)
2210 , m_sPrimaryString(rMessage)
2212 SetType(WindowType::MESSBOX);
2213 create_owned_areas();
2214 create_message_area();
2216 switch (m_eMessageType)
2218 case VclMessageType::Info:
2219 SetText(GetStandardInfoBoxText());
2220 break;
2221 case VclMessageType::Warning:
2222 SetText(GetStandardWarningBoxText());
2223 break;
2224 case VclMessageType::Question:
2225 SetText(GetStandardQueryBoxText());
2226 break;
2227 case VclMessageType::Error:
2228 SetText(GetStandardErrorBoxText());
2229 break;
2233 void MessageDialog::dispose()
2235 disposeOwnedButtons();
2236 m_pPrimaryMessage.disposeAndClear();
2237 m_pSecondaryMessage.disposeAndClear();
2238 m_pImage.disposeAndClear();
2239 m_pMessageBox.disposeAndClear();
2240 m_pGrid.disposeAndClear();
2241 m_pOwnedActionArea.disposeAndClear();
2242 m_pOwnedContentArea.disposeAndClear();
2243 Dialog::dispose();
2246 MessageDialog::~MessageDialog()
2248 disposeOnce();
2251 void MessageDialog::SetMessagesWidths(vcl::Window const *pParent,
2252 VclMultiLineEdit *pPrimaryMessage, VclMultiLineEdit *pSecondaryMessage)
2254 if (pSecondaryMessage)
2256 assert(pPrimaryMessage);
2257 vcl::Font aFont = pParent->GetSettings().GetStyleSettings().GetLabelFont();
2258 aFont.SetFontSize(Size(0, aFont.GetFontSize().Height() * 1.2));
2259 aFont.SetWeight(WEIGHT_BOLD);
2260 pPrimaryMessage->SetControlFont(aFont);
2261 pPrimaryMessage->SetMaxTextWidth(pPrimaryMessage->approximate_char_width() * 44);
2262 pSecondaryMessage->SetMaxTextWidth(pSecondaryMessage->approximate_char_width() * 60);
2264 else
2265 pPrimaryMessage->SetMaxTextWidth(pPrimaryMessage->approximate_char_width() * 60);
2268 OUString const & MessageDialog::get_primary_text() const
2270 const_cast<MessageDialog*>(this)->setDeferredProperties();
2272 return m_sPrimaryString;
2275 OUString const & MessageDialog::get_secondary_text() const
2277 const_cast<MessageDialog*>(this)->setDeferredProperties();
2279 return m_sSecondaryString;
2282 bool MessageDialog::set_property(const OString &rKey, const OUString &rValue)
2284 if (rKey == "text")
2285 set_primary_text(rValue);
2286 else if (rKey == "secondary-text")
2287 set_secondary_text(rValue);
2288 else if (rKey == "message-type")
2290 VclMessageType eMode = VclMessageType::Info;
2291 if (rValue == "info")
2292 eMode = VclMessageType::Info;
2293 else if (rValue == "warning")
2294 eMode = VclMessageType::Warning;
2295 else if (rValue == "question")
2296 eMode = VclMessageType::Question;
2297 else if (rValue == "error")
2298 eMode = VclMessageType::Error;
2299 else
2301 SAL_WARN("vcl.layout", "unknown message type mode" << rValue);
2303 m_eMessageType = eMode;
2305 else if (rKey == "buttons")
2307 VclButtonsType eMode = VclButtonsType::NONE;
2308 if (rValue == "none")
2309 eMode = VclButtonsType::NONE;
2310 else if (rValue == "ok")
2311 eMode = VclButtonsType::Ok;
2312 else if (rValue == "cancel")
2313 eMode = VclButtonsType::Cancel;
2314 else if (rValue == "close")
2315 eMode = VclButtonsType::Close;
2316 else if (rValue == "yes-no")
2317 eMode = VclButtonsType::YesNo;
2318 else if (rValue == "ok-cancel")
2319 eMode = VclButtonsType::OkCancel;
2320 else
2322 SAL_WARN("vcl.layout", "unknown buttons type mode" << rValue);
2324 m_eButtonsType = eMode;
2326 else
2327 return Dialog::set_property(rKey, rValue);
2328 return true;
2331 void MessageDialog::set_primary_text(const OUString &rPrimaryString)
2333 m_sPrimaryString = rPrimaryString;
2334 if (m_pPrimaryMessage)
2336 m_pPrimaryMessage->SetText(m_sPrimaryString);
2337 m_pPrimaryMessage->Show(!m_sPrimaryString.isEmpty());
2338 MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, !m_sSecondaryString.isEmpty() ? m_pSecondaryMessage.get() : nullptr);
2342 void MessageDialog::set_secondary_text(const OUString &rSecondaryString)
2344 m_sSecondaryString = rSecondaryString;
2345 if (m_pSecondaryMessage)
2347 m_pSecondaryMessage->SetText("\n" + m_sSecondaryString);
2348 m_pSecondaryMessage->Show(!m_sSecondaryString.isEmpty());
2349 MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, !m_sSecondaryString.isEmpty() ? m_pSecondaryMessage.get() : nullptr);
2353 void MessageDialog::StateChanged(StateChangedType nType)
2355 Dialog::StateChanged(nType);
2356 if (nType == StateChangedType::InitShow)
2358 // MessageBox should be at least as wide as to see the title
2359 auto nTitleWidth = CalcTitleWidth();
2360 // Extra-Width for Close button
2361 nTitleWidth += mpWindowImpl->mnTopBorder;
2362 if (get_preferred_size().Width() < nTitleWidth)
2364 set_width_request(nTitleWidth);
2365 DoInitialLayout();
2370 VclPaned::VclPaned(vcl::Window *pParent, bool bVertical)
2371 : VclContainer(pParent, WB_HIDE | WB_CLIPCHILDREN)
2372 , m_pSplitter(VclPtr<Splitter>::Create(this, bVertical ? WB_VSCROLL : WB_HSCROLL))
2373 , m_nPosition(-1)
2375 m_pSplitter->SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFaceColor()));
2376 m_pSplitter->Show();
2379 void VclPaned::dispose()
2381 m_pSplitter.disposeAndClear();
2382 VclContainer::dispose();
2385 VclVPaned::VclVPaned(vcl::Window *pParent)
2386 : VclPaned(pParent, true)
2388 m_pSplitter->SetSplitHdl(LINK(this, VclVPaned, SplitHdl));
2391 IMPL_LINK(VclVPaned, SplitHdl, Splitter*, pSplitter, void)
2393 long nSize = pSplitter->GetSplitPosPixel();
2394 Size aSplitterSize(m_pSplitter->GetSizePixel());
2395 Size aAllocation(GetSizePixel());
2396 arrange(aAllocation, nSize, aAllocation.Height() - nSize - aSplitterSize.Height());
2399 void VclVPaned::arrange(const Size& rAllocation, long nFirstHeight, long nSecondHeight)
2401 Size aSplitterSize(rAllocation.Width(), getLayoutRequisition(*m_pSplitter).Height());
2402 Size aFirstChildSize(rAllocation.Width(), nFirstHeight);
2403 Size aSecondChildSize(rAllocation.Width(), nSecondHeight);
2404 int nElement = 0;
2405 for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2406 pChild = pChild->GetWindow(GetWindowType::Next))
2408 if (!pChild->IsVisible())
2409 continue;
2410 if (nElement == 0)
2412 Point aSplitterPos(0, aFirstChildSize.Height());
2413 setLayoutAllocation(*m_pSplitter, aSplitterPos, aSplitterSize);
2414 set_position(aSplitterPos.Y() + aSplitterSize.Height() / 2);
2416 else if (nElement == 1)
2418 Point aChildPos(0, 0);
2419 setLayoutAllocation(*pChild, aChildPos, aFirstChildSize);
2421 else if (nElement == 2)
2423 Point aChildPos(0, aFirstChildSize.Height() + aSplitterSize.Height());
2424 setLayoutAllocation(*pChild, aChildPos, aSecondChildSize);
2426 ++nElement;
2430 void VclVPaned::setAllocation(const Size& rAllocation)
2432 //supporting "shrink" could be done by adjusting the allowed drag rectangle
2433 m_pSplitter->SetDragRectPixel(tools::Rectangle(Point(0, 0), rAllocation));
2434 Size aSplitterSize(rAllocation.Width(), getLayoutRequisition(*m_pSplitter).Height());
2435 const long nHeight = rAllocation.Height() - aSplitterSize.Height();
2437 long nFirstHeight = 0;
2438 long nSecondHeight = 0;
2439 bool bFirstCanResize = true;
2440 bool bSecondCanResize = true;
2441 const bool bInitialAllocation = get_position() < 0;
2442 int nElement = 0;
2443 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2444 pChild = pChild->GetWindow(GetWindowType::Next))
2446 if (!pChild->IsVisible())
2447 continue;
2448 if (nElement == 1)
2450 if (bInitialAllocation)
2451 nFirstHeight = getLayoutRequisition(*pChild).Height();
2452 else
2453 nFirstHeight = pChild->GetSizePixel().Height();
2454 bFirstCanResize = pChild->get_expand();
2456 else if (nElement == 2)
2458 if (bInitialAllocation)
2459 nSecondHeight = getLayoutRequisition(*pChild).Height();
2460 else
2461 nSecondHeight = pChild->GetSizePixel().Height();
2462 bSecondCanResize = pChild->get_expand();
2464 ++nElement;
2466 long nHeightRequest = nFirstHeight + nSecondHeight;
2467 long nHeightDiff = nHeight - nHeightRequest;
2468 if (bFirstCanResize == bSecondCanResize)
2469 nFirstHeight += nHeightDiff/2;
2470 else if (bFirstCanResize)
2471 nFirstHeight += nHeightDiff;
2472 arrange(rAllocation, nFirstHeight, rAllocation.Height() - nFirstHeight - aSplitterSize.Height());
2475 Size VclVPaned::calculateRequisition() const
2477 Size aRet(0, 0);
2479 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2480 pChild = pChild->GetWindow(GetWindowType::Next))
2482 if (!pChild->IsVisible())
2483 continue;
2484 Size aChildSize = getLayoutRequisition(*pChild);
2485 aRet.setWidth( std::max(aRet.Width(), aChildSize.Width()) );
2486 aRet.AdjustHeight(aChildSize.Height() );
2489 return aRet;
2492 VclHPaned::VclHPaned(vcl::Window *pParent)
2493 : VclPaned(pParent, false)
2495 m_pSplitter->SetSplitHdl(LINK(this, VclHPaned, SplitHdl));
2498 IMPL_LINK(VclHPaned, SplitHdl, Splitter*, pSplitter, void)
2500 long nSize = pSplitter->GetSplitPosPixel();
2501 Size aSplitterSize(m_pSplitter->GetSizePixel());
2502 Size aAllocation(GetSizePixel());
2503 arrange(aAllocation, nSize, aAllocation.Width() - nSize - aSplitterSize.Width());
2506 void VclHPaned::arrange(const Size& rAllocation, long nFirstWidth, long nSecondWidth)
2508 Size aSplitterSize(getLayoutRequisition(*m_pSplitter).Width(), rAllocation.Height());
2509 Size aFirstChildSize(nFirstWidth, rAllocation.Height());
2510 Size aSecondChildSize(nSecondWidth, rAllocation.Height());
2511 int nElement = 0;
2512 for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2513 pChild = pChild->GetWindow(GetWindowType::Next))
2515 if (!pChild->IsVisible())
2516 continue;
2517 if (nElement == 0)
2519 Point aSplitterPos(aFirstChildSize.Width(), 0);
2520 setLayoutAllocation(*m_pSplitter, aSplitterPos, aSplitterSize);
2521 set_position(aSplitterPos.X() + aSplitterSize.Width() / 2);
2523 else if (nElement == 1)
2525 Point aChildPos(0, 0);
2526 setLayoutAllocation(*pChild, aChildPos, aFirstChildSize);
2528 else if (nElement == 2)
2530 Point aChildPos(aFirstChildSize.Width() + aSplitterSize.Width(), 0);
2531 setLayoutAllocation(*pChild, aChildPos, aSecondChildSize);
2533 ++nElement;
2537 void VclHPaned::setAllocation(const Size& rAllocation)
2539 //supporting "shrink" could be done by adjusting the allowed drag rectangle
2540 m_pSplitter->SetDragRectPixel(tools::Rectangle(Point(0, 0), rAllocation));
2541 Size aSplitterSize(getLayoutRequisition(*m_pSplitter).Width(), rAllocation.Height());
2542 const long nWidth = rAllocation.Width() - aSplitterSize.Width();
2544 long nFirstWidth = 0;
2545 long nSecondWidth = 0;
2546 bool bFirstCanResize = true;
2547 bool bSecondCanResize = true;
2548 const bool bInitialAllocation = get_position() < 0;
2549 int nElement = 0;
2550 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2551 pChild = pChild->GetWindow(GetWindowType::Next))
2553 if (!pChild->IsVisible())
2554 continue;
2555 if (nElement == 1)
2557 if (bInitialAllocation)
2558 nFirstWidth = getLayoutRequisition(*pChild).Width();
2559 else
2560 nFirstWidth = pChild->GetSizePixel().Width();
2561 bFirstCanResize = pChild->get_expand();
2563 else if (nElement == 2)
2565 if (bInitialAllocation)
2566 nSecondWidth = getLayoutRequisition(*pChild).Width();
2567 else
2568 nSecondWidth = pChild->GetSizePixel().Width();
2569 bSecondCanResize = pChild->get_expand();
2571 ++nElement;
2573 long nWidthRequest = nFirstWidth + nSecondWidth;
2574 long nWidthDiff = nWidth - nWidthRequest;
2575 if (bFirstCanResize == bSecondCanResize)
2576 nFirstWidth += nWidthDiff/2;
2577 else if (bFirstCanResize)
2578 nFirstWidth += nWidthDiff;
2579 arrange(rAllocation, nFirstWidth, rAllocation.Width() - nFirstWidth - aSplitterSize.Width());
2582 Size VclHPaned::calculateRequisition() const
2584 Size aRet(0, 0);
2586 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2587 pChild = pChild->GetWindow(GetWindowType::Next))
2589 if (!pChild->IsVisible())
2590 continue;
2591 Size aChildSize = getLayoutRequisition(*pChild);
2592 aRet.setHeight( std::max(aRet.Height(), aChildSize.Height()) );
2593 aRet.AdjustWidth(aChildSize.Width() );
2596 return aRet;
2599 Size getLegacyBestSizeForChildren(const vcl::Window &rWindow)
2601 tools::Rectangle aBounds;
2603 for (const vcl::Window* pChild = rWindow.GetWindow(GetWindowType::FirstChild); pChild;
2604 pChild = pChild->GetWindow(GetWindowType::Next))
2606 if (!pChild->IsVisible())
2607 continue;
2609 tools::Rectangle aChildBounds(pChild->GetPosPixel(), pChild->GetSizePixel());
2610 aBounds.Union(aChildBounds);
2613 if (aBounds.IsEmpty())
2614 return rWindow.GetSizePixel();
2616 Size aRet(aBounds.GetSize());
2617 Point aTopLeft(aBounds.TopLeft());
2618 aRet.AdjustWidth(aTopLeft.X()*2 );
2619 aRet.AdjustHeight(aTopLeft.Y()*2 );
2621 return aRet;
2624 vcl::Window* getNonLayoutParent(vcl::Window *pWindow)
2626 while (pWindow)
2628 pWindow = pWindow->GetParent();
2629 if (!pWindow || !isContainerWindow(*pWindow))
2630 break;
2632 return pWindow;
2635 bool isVisibleInLayout(const vcl::Window *pWindow)
2637 bool bVisible = true;
2638 while (bVisible)
2640 bVisible = pWindow->IsVisible();
2641 pWindow = pWindow->GetParent();
2642 if (!pWindow || !isContainerWindow(*pWindow))
2643 break;
2645 return bVisible;
2648 bool isEnabledInLayout(const vcl::Window *pWindow)
2650 bool bEnabled = true;
2651 while (bEnabled)
2653 bEnabled = pWindow->IsEnabled();
2654 pWindow = pWindow->GetParent();
2655 if (!pWindow || !isContainerWindow(*pWindow))
2656 break;
2658 return bEnabled;
2661 bool isLayoutEnabled(const vcl::Window *pWindow)
2663 //Child is a container => we're layout enabled
2664 const vcl::Window *pChild = pWindow ? pWindow->GetWindow(GetWindowType::FirstChild) : nullptr;
2665 return pChild && isContainerWindow(*pChild) && !pChild->GetWindow(GetWindowType::Next);
2668 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */