build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / window / layout.cxx
blobd7c584bcefc13f2c2cd7b974234a4276b5c7a32f
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/dialog.hxx>
14 #include <vcl/IPrioritable.hxx>
15 #include <vcl/layout.hxx>
16 #include <vcl/msgbox.hxx>
17 #include <vcl/svapp.hxx>
18 #include <vcl/settings.hxx>
19 #include "window.h"
20 #include <boost/multi_array.hpp>
21 #include <officecfg/Office/Common.hxx>
22 #include <vcl/abstdlg.hxx>
24 VclContainer::VclContainer(vcl::Window *pParent, WinBits nStyle)
25 : Window(WINDOW_CONTAINER)
26 , IPrioritable()
27 , m_bLayoutDirty(true)
29 ImplInit(pParent, nStyle, nullptr);
30 EnableChildTransparentMode();
31 SetPaintTransparent(true);
32 SetBackground();
35 sal_uInt16 VclContainer::getDefaultAccessibleRole() const
37 return css::accessibility::AccessibleRole::PANEL;
40 Size VclContainer::GetOptimalSize() const
42 return calculateRequisition();
45 void VclContainer::setLayoutPosSize(vcl::Window &rWindow, const Point &rPos, const Size &rSize)
47 sal_Int32 nBorderWidth = rWindow.get_border_width();
48 sal_Int32 nLeft = rWindow.get_margin_left() + nBorderWidth;
49 sal_Int32 nTop = rWindow.get_margin_top() + nBorderWidth;
50 sal_Int32 nRight = rWindow.get_margin_right() + nBorderWidth;
51 sal_Int32 nBottom = rWindow.get_margin_bottom() + nBorderWidth;
52 Point aPos(rPos.X() + nLeft, rPos.Y() + nTop);
53 Size aSize(rSize.Width() - nLeft - nRight, rSize.Height() - nTop - nBottom);
54 rWindow.SetPosSizePixel(aPos, aSize);
57 void VclContainer::setLayoutAllocation(vcl::Window &rChild, const Point &rAllocPos, const Size &rChildAlloc)
59 VclAlign eHalign = rChild.get_halign();
60 VclAlign eValign = rChild.get_valign();
62 //typical case
63 if (eHalign == VclAlign::Fill && eValign == VclAlign::Fill)
65 setLayoutPosSize(rChild, rAllocPos, rChildAlloc);
66 return;
69 Point aChildPos(rAllocPos);
70 Size aChildSize(rChildAlloc);
71 Size aChildPreferredSize(getLayoutRequisition(rChild));
73 switch (eHalign)
75 case VclAlign::Fill:
76 break;
77 case VclAlign::Start:
78 if (aChildPreferredSize.Width() < rChildAlloc.Width())
79 aChildSize.Width() = aChildPreferredSize.Width();
80 break;
81 case VclAlign::End:
82 if (aChildPreferredSize.Width() < rChildAlloc.Width())
83 aChildSize.Width() = aChildPreferredSize.Width();
84 aChildPos.X() += rChildAlloc.Width();
85 aChildPos.X() -= aChildSize.Width();
86 break;
87 case VclAlign::Center:
88 if (aChildPreferredSize.Width() < aChildSize.Width())
89 aChildSize.Width() = aChildPreferredSize.Width();
90 aChildPos.X() += (rChildAlloc.Width() - aChildSize.Width()) / 2;
91 break;
94 switch (eValign)
96 case VclAlign::Fill:
97 break;
98 case VclAlign::Start:
99 if (aChildPreferredSize.Height() < rChildAlloc.Height())
100 aChildSize.Height() = aChildPreferredSize.Height();
101 break;
102 case VclAlign::End:
103 if (aChildPreferredSize.Height() < rChildAlloc.Height())
104 aChildSize.Height() = aChildPreferredSize.Height();
105 aChildPos.Y() += rChildAlloc.Height();
106 aChildPos.Y() -= aChildSize.Height();
107 break;
108 case VclAlign::Center:
109 if (aChildPreferredSize.Height() < aChildSize.Height())
110 aChildSize.Height() = aChildPreferredSize.Height();
111 aChildPos.Y() += (rChildAlloc.Height() - aChildSize.Height()) / 2;
112 break;
115 setLayoutPosSize(rChild, aChildPos, aChildSize);
118 namespace
120 Size subtractBorder(const vcl::Window &rWindow, const Size& rSize)
122 sal_Int32 nBorderWidth = rWindow.get_border_width();
123 sal_Int32 nLeft = rWindow.get_margin_left() + nBorderWidth;
124 sal_Int32 nTop = rWindow.get_margin_top() + nBorderWidth;
125 sal_Int32 nRight = rWindow.get_margin_right() + nBorderWidth;
126 sal_Int32 nBottom = rWindow.get_margin_bottom() + nBorderWidth;
127 Size aSize(rSize);
128 return Size(aSize.Width() + nLeft + nRight, aSize.Height() + nTop + nBottom);
132 Size VclContainer::getLayoutRequisition(const vcl::Window &rWindow)
134 return subtractBorder(rWindow, rWindow.get_preferred_size());
137 void VclContainer::SetPosSizePixel(const Point& rAllocPos, const Size& rAllocation)
139 bool bSizeChanged = rAllocation != GetOutputSizePixel();
140 Window::SetPosSizePixel(rAllocPos, rAllocation);
141 if (m_bLayoutDirty || bSizeChanged)
143 m_bLayoutDirty = false;
144 setAllocation(rAllocation);
148 void VclContainer::SetPosPixel(const Point& rAllocPos)
150 Point aAllocPos = rAllocPos;
151 sal_Int32 nBorderWidth = get_border_width();
152 aAllocPos.X() += nBorderWidth + get_margin_left();
153 aAllocPos.Y() += nBorderWidth + get_margin_top();
155 if (aAllocPos != GetPosPixel())
156 Window::SetPosPixel(aAllocPos);
159 void VclContainer::SetSizePixel(const Size& rAllocation)
161 Size aAllocation = rAllocation;
162 sal_Int32 nBorderWidth = get_border_width();
163 aAllocation.Width() -= nBorderWidth*2 + get_margin_left() + get_margin_right();
164 aAllocation.Height() -= nBorderWidth*2 + get_margin_top() + get_margin_bottom();
165 bool bSizeChanged = aAllocation != GetSizePixel();
166 if (bSizeChanged)
167 Window::SetSizePixel(aAllocation);
168 if (m_bLayoutDirty || bSizeChanged)
170 m_bLayoutDirty = false;
171 setAllocation(aAllocation);
175 void VclContainer::queue_resize(StateChangedType eReason)
177 m_bLayoutDirty = true;
178 Window::queue_resize(eReason);
182 Button* isVisibleButtonWithText(vcl::Window* pCandidate)
184 if (!pCandidate)
185 return nullptr;
187 if (!pCandidate->IsVisible())
188 return nullptr;
190 if (pCandidate->GetText().isEmpty())
191 return nullptr;
193 return dynamic_cast<Button*>(pCandidate);
196 // evtl. support for screenshot context menu
197 void VclContainer::Command(const CommandEvent& rCEvt)
199 if (rCEvt.IsMouseEvent() && CommandEventId::ContextMenu == rCEvt.GetCommand())
201 const bool bScreenshotMode(officecfg::Office::Common::Misc::ScreenshotMode::get());
203 if (bScreenshotMode)
205 bool bVisibleChildren(false);
206 vcl::Window* pChild(nullptr);
208 for (pChild = GetWindow(GetWindowType::FirstChild); !bVisibleChildren && pChild; pChild = pChild->GetWindow(GetWindowType::Next))
210 Button* pCandidate = isVisibleButtonWithText(pChild);
212 if (nullptr == pCandidate)
213 continue;
215 bVisibleChildren = true;
218 if (bVisibleChildren)
220 static bool bAddButtonsToMenu(true);
221 static bool bAddScreenshotButtonToMenu(true);
223 if (bAddButtonsToMenu || bAddScreenshotButtonToMenu)
225 const Point aMenuPos(rCEvt.GetMousePosPixel());
226 ScopedVclPtrInstance<PopupMenu> aMenu;
227 sal_uInt16 nLocalID(1);
228 sal_uInt16 nScreenshotButtonID(0);
230 if (bAddButtonsToMenu)
232 for (pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
234 Button* pCandidate = isVisibleButtonWithText(pChild);
236 if (nullptr == pCandidate)
237 continue;
239 aMenu->InsertItem(
240 nLocalID,
241 pChild->GetText());
242 aMenu->SetHelpText(
243 nLocalID,
244 pChild->GetHelpText());
245 aMenu->SetHelpId(
246 nLocalID,
247 pChild->GetHelpId());
248 aMenu->EnableItem(
249 nLocalID,
250 pChild->IsEnabled());
251 nLocalID++;
255 if (bAddScreenshotButtonToMenu)
257 if (nLocalID > 1)
259 aMenu->InsertSeparator();
262 aMenu->InsertItem(
263 nLocalID,
264 "Screenshot");
265 aMenu->SetHelpText(
266 nLocalID,
267 "Go into interactive screenshot annotation mode");
268 aMenu->SetHelpId(
269 nLocalID,
270 "InteractiveScreenshotMode");
271 aMenu->EnableItem(
272 nLocalID);
273 nScreenshotButtonID = nLocalID;
276 const sal_uInt16 nId(aMenu->Execute(this, aMenuPos));
278 // 0 == no selection (so not usable as ID)
279 if (0 != nId)
281 if (bAddButtonsToMenu && nId < nLocalID)
283 nLocalID = 1;
285 for (pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
287 Button* pCandidate = isVisibleButtonWithText(pChild);
289 if (nullptr == pCandidate)
290 continue;
292 if (nLocalID++ == nId)
294 // pCandidate is the selected button, trigger it
295 pCandidate->Click();
296 break;
301 if (bAddScreenshotButtonToMenu && nId == nScreenshotButtonID)
303 // screenshot was selected, access parent dialog (needed for
304 // screenshot and other data access)
305 Dialog* pParentDialog = GetParentDialog();
307 if (pParentDialog)
309 // open screenshot annotation dialog
310 VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
311 VclPtr<AbstractScreenshotAnnotationDlg> pTmp = pFact->CreateScreenshotAnnotationDlg(
312 Application::GetDefDialogParent(),
313 *pParentDialog);
314 ScopedVclPtr<AbstractScreenshotAnnotationDlg> pDialog(pTmp);
316 if (pDialog)
318 // currently just execute the dialog, no need to do
319 // different things for ok/cancel. This may change later,
320 // for that case use 'if (pDlg->Execute() == RET_OK)'
321 pDialog->Execute();
327 // consume event when:
328 // - CommandEventId::ContextMenu
329 // - bScreenshotMode
330 // - bVisibleChildren
331 return;
337 // call parent (do not consume)
338 Window::Command(rCEvt);
341 void VclBox::accumulateMaxes(const Size &rChildSize, Size &rSize) const
343 long nSecondaryChildDimension = getSecondaryDimension(rChildSize);
344 long nSecondaryBoxDimension = getSecondaryDimension(rSize);
345 setSecondaryDimension(rSize, std::max(nSecondaryChildDimension, nSecondaryBoxDimension));
347 long nPrimaryChildDimension = getPrimaryDimension(rChildSize);
348 long nPrimaryBoxDimension = getPrimaryDimension(rSize);
349 if (m_bHomogeneous)
350 setPrimaryDimension(rSize, std::max(nPrimaryBoxDimension, nPrimaryChildDimension));
351 else
352 setPrimaryDimension(rSize, nPrimaryBoxDimension + nPrimaryChildDimension);
355 Size VclBox::calculateRequisition() const
357 sal_uInt16 nVisibleChildren = 0;
359 Size aSize;
360 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
362 if (!pChild->IsVisible())
363 continue;
364 ++nVisibleChildren;
365 Size aChildSize = getLayoutRequisition(*pChild);
367 long nPrimaryDimension = getPrimaryDimension(aChildSize);
368 nPrimaryDimension += pChild->get_padding() * 2;
369 setPrimaryDimension(aChildSize, nPrimaryDimension);
371 accumulateMaxes(aChildSize, aSize);
374 return finalizeMaxes(aSize, nVisibleChildren);
377 void VclBox::setAllocation(const Size &rAllocation)
379 sal_uInt16 nVisibleChildren = 0, nExpandChildren = 0;
380 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
382 if (!pChild->IsVisible())
383 continue;
384 ++nVisibleChildren;
385 bool bExpand = getPrimaryDimensionChildExpand(*pChild);
386 if (bExpand)
387 ++nExpandChildren;
390 if (!nVisibleChildren)
391 return;
393 long nAllocPrimaryDimension = getPrimaryDimension(rAllocation);
395 long nHomogeneousDimension = 0, nExtraSpace = 0;
396 if (m_bHomogeneous)
398 nHomogeneousDimension = ((nAllocPrimaryDimension -
399 (nVisibleChildren - 1) * m_nSpacing)) / nVisibleChildren;
401 else if (nExpandChildren)
403 Size aRequisition = calculateRequisition();
404 nExtraSpace = (getPrimaryDimension(rAllocation) - getPrimaryDimension(aRequisition)) / nExpandChildren;
407 //Split into those we pack from the start onwards, and those we pack from the end backwards
408 o3tl::enumarray<VclPackType,std::vector<vcl::Window*>> aWindows;
409 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
411 if (!pChild->IsVisible())
412 continue;
414 VclPackType ePacking = pChild->get_pack_type();
415 aWindows[ePacking].push_back(pChild);
418 //See VclBuilder::sortIntoBestTabTraversalOrder for why they are in visual
419 //order under the parent which requires us to reverse them here to
420 //pack from the end back
421 std::reverse(aWindows[VclPackType::End].begin(),aWindows[VclPackType::End].end());
423 for (VclPackType ePackType : o3tl::enumrange<VclPackType>())
425 Point aPos(0, 0);
426 if (ePackType == VclPackType::End)
428 long nPrimaryCoordinate = getPrimaryCoordinate(aPos);
429 setPrimaryCoordinate(aPos, nPrimaryCoordinate + nAllocPrimaryDimension);
432 for (std::vector<vcl::Window*>::iterator aI = aWindows[ePackType].begin(), aEnd = aWindows[ePackType].end(); aI != aEnd; ++aI)
434 vcl::Window *pChild = *aI;
436 long nPadding = pChild->get_padding();
438 Size aBoxSize;
439 if (m_bHomogeneous)
440 setPrimaryDimension(aBoxSize, nHomogeneousDimension);
441 else
443 aBoxSize = getLayoutRequisition(*pChild);
444 long nPrimaryDimension = getPrimaryDimension(aBoxSize);
445 nPrimaryDimension += nPadding * 2;
446 if (getPrimaryDimensionChildExpand(*pChild))
447 nPrimaryDimension += nExtraSpace;
448 setPrimaryDimension(aBoxSize, nPrimaryDimension);
450 setSecondaryDimension(aBoxSize, getSecondaryDimension(rAllocation));
452 Point aChildPos(aPos);
453 Size aChildSize(aBoxSize);
454 long nPrimaryCoordinate = getPrimaryCoordinate(aPos);
456 bool bFill = pChild->get_fill();
457 if (bFill)
459 setPrimaryDimension(aChildSize, std::max(static_cast<long>(1),
460 getPrimaryDimension(aBoxSize) - nPadding * 2));
462 setPrimaryCoordinate(aChildPos, nPrimaryCoordinate + nPadding);
464 else
466 setPrimaryDimension(aChildSize,
467 getPrimaryDimension(getLayoutRequisition(*pChild)));
469 setPrimaryCoordinate(aChildPos, nPrimaryCoordinate +
470 (getPrimaryDimension(aBoxSize) - getPrimaryDimension(aChildSize)) / 2);
473 long nDiff = getPrimaryDimension(aBoxSize) + m_nSpacing;
474 if (ePackType == VclPackType::Start)
475 setPrimaryCoordinate(aPos, nPrimaryCoordinate + nDiff);
476 else
478 setPrimaryCoordinate(aPos, nPrimaryCoordinate - nDiff);
479 setPrimaryCoordinate(aChildPos, getPrimaryCoordinate(aChildPos) -
480 getPrimaryDimension(aBoxSize));
483 setLayoutAllocation(*pChild, aChildPos, aChildSize);
488 bool VclBox::set_property(const OString &rKey, const OString &rValue)
490 if (rKey == "spacing")
491 set_spacing(rValue.toInt32());
492 else if (rKey == "homogeneous")
493 set_homogeneous(toBool(rValue));
494 else
495 return VclContainer::set_property(rKey, rValue);
496 return true;
499 sal_uInt16 VclBox::getDefaultAccessibleRole() const
501 #if defined(_WIN32)
502 //fdo#74284 call Boxes Panels, keep then as "Filler" under
503 //at least Linux seeing as that's what Gtk does for GtkBoxes
504 return css::accessibility::AccessibleRole::PANEL;
505 #else
506 return css::accessibility::AccessibleRole::FILLER;
507 #endif
510 #define DEFAULT_CHILD_MIN_WIDTH 85
511 #define DEFAULT_CHILD_MIN_HEIGHT 27
513 Size VclBox::finalizeMaxes(const Size &rSize, sal_uInt16 nVisibleChildren) const
515 Size aRet;
517 if (nVisibleChildren)
519 long nPrimaryDimension = getPrimaryDimension(rSize);
520 if (m_bHomogeneous)
521 nPrimaryDimension *= nVisibleChildren;
522 setPrimaryDimension(aRet, nPrimaryDimension + m_nSpacing * (nVisibleChildren-1));
523 setSecondaryDimension(aRet, getSecondaryDimension(rSize));
526 return aRet;
529 Size VclButtonBox::addReqGroups(const VclButtonBox::Requisition &rReq) const
531 Size aRet;
533 long nMainGroupDimension = getPrimaryDimension(rReq.m_aMainGroupSize);
534 long nSubGroupDimension = getPrimaryDimension(rReq.m_aSubGroupSize);
536 setPrimaryDimension(aRet, nMainGroupDimension + nSubGroupDimension);
538 setSecondaryDimension(aRet,
539 std::max(getSecondaryDimension(rReq.m_aMainGroupSize),
540 getSecondaryDimension(rReq.m_aSubGroupSize)));
542 return aRet;
545 static long getMaxNonOutlier(const std::vector<long> &rG, long nAvgDimension)
547 long nMaxDimensionNonOutlier = 0;
548 for (std::vector<long>::const_iterator aI = rG.begin(),
549 aEnd = rG.end(); aI != aEnd; ++aI)
551 long nPrimaryChildDimension = *aI;
552 if (nPrimaryChildDimension < nAvgDimension * 1.5)
554 nMaxDimensionNonOutlier = std::max(nPrimaryChildDimension,
555 nMaxDimensionNonOutlier);
558 return nMaxDimensionNonOutlier;
561 static std::vector<long> setButtonSizes(const std::vector<long> &rG,
562 const std::vector<bool> &rNonHomogeneous,
563 long nAvgDimension, long nMaxNonOutlier, long nMinWidth)
565 std::vector<long> aVec;
566 //set everything < 1.5 times the average to the same width, leave the
567 //outliers un-touched
568 std::vector<bool>::const_iterator aJ = rNonHomogeneous.begin();
569 for (std::vector<long>::const_iterator aI = rG.begin(), aEnd = rG.end();
570 aI != aEnd; ++aI, ++aJ)
572 long nPrimaryChildDimension = *aI;
573 bool bNonHomogeneous = *aJ;
574 if (!bNonHomogeneous && nPrimaryChildDimension < nAvgDimension * 1.5)
576 aVec.push_back(std::max(nMaxNonOutlier, nMinWidth));
578 else
580 aVec.push_back(std::max(nPrimaryChildDimension, nMinWidth));
583 return aVec;
586 VclButtonBox::Requisition VclButtonBox::calculatePrimarySecondaryRequisitions() const
588 Requisition aReq;
590 Size aMainGroupSize(DEFAULT_CHILD_MIN_WIDTH, DEFAULT_CHILD_MIN_HEIGHT); //to-do, pull from theme
591 Size aSubGroupSize(DEFAULT_CHILD_MIN_WIDTH, DEFAULT_CHILD_MIN_HEIGHT); //to-do, pull from theme
593 long nMinMainGroupPrimary = getPrimaryDimension(aMainGroupSize);
594 long nMinSubGroupPrimary = getPrimaryDimension(aSubGroupSize);
595 long nMainGroupSecondary = getSecondaryDimension(aMainGroupSize);
596 long nSubGroupSecondary = getSecondaryDimension(aSubGroupSize);
598 bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VCL_BUTTONBOX_SPREAD || m_eLayoutStyle == VCL_BUTTONBOX_CENTER);
600 std::vector<long> aMainGroupSizes;
601 std::vector<bool> aMainGroupNonHomogeneous;
602 std::vector<long> aSubGroupSizes;
603 std::vector<bool> aSubGroupNonHomogeneous;
605 for (const vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
607 if (!pChild->IsVisible())
608 continue;
609 Size aChildSize = getLayoutRequisition(*pChild);
610 if (bIgnoreSecondaryPacking || !pChild->get_secondary())
612 //set the max secondary dimension
613 nMainGroupSecondary = std::max(nMainGroupSecondary, getSecondaryDimension(aChildSize));
614 //collect the primary dimensions
615 aMainGroupSizes.push_back(getPrimaryDimension(aChildSize));
616 aMainGroupNonHomogeneous.push_back(pChild->get_non_homogeneous());
618 else
620 nSubGroupSecondary = std::max(nSubGroupSecondary, getSecondaryDimension(aChildSize));
621 aSubGroupSizes.push_back(getPrimaryDimension(aChildSize));
622 aSubGroupNonHomogeneous.push_back(pChild->get_non_homogeneous());
626 if (m_bHomogeneous)
628 long nMaxMainDimension = aMainGroupSizes.empty() ? 0 :
629 *std::max_element(aMainGroupSizes.begin(), aMainGroupSizes.end());
630 nMaxMainDimension = std::max(nMaxMainDimension, nMinMainGroupPrimary);
631 long nMaxSubDimension = aSubGroupSizes.empty() ? 0 :
632 *std::max_element(aSubGroupSizes.begin(), aSubGroupSizes.end());
633 nMaxSubDimension = std::max(nMaxSubDimension, nMinSubGroupPrimary);
634 long nMaxDimension = std::max(nMaxMainDimension, nMaxSubDimension);
635 aReq.m_aMainGroupDimensions.resize(aMainGroupSizes.size(), nMaxDimension);
636 aReq.m_aSubGroupDimensions.resize(aSubGroupSizes.size(), nMaxDimension);
638 else
640 //Ideally set everything to the same size, but find outlier widgets
641 //that are way wider than the average and leave them
642 //at their natural size and set the remainder to share the
643 //max size of the remaining members of the buttonbox
644 long nAccDimension = std::accumulate(aMainGroupSizes.begin(),
645 aMainGroupSizes.end(), 0);
646 nAccDimension = std::accumulate(aSubGroupSizes.begin(),
647 aSubGroupSizes.end(), nAccDimension);
649 size_t nTotalSize = aMainGroupSizes.size() + aSubGroupSizes.size();
651 long nAvgDimension = nTotalSize ? nAccDimension / nTotalSize : 0;
653 long nMaxMainNonOutlier = getMaxNonOutlier(aMainGroupSizes,
654 nAvgDimension);
655 long nMaxSubNonOutlier = getMaxNonOutlier(aSubGroupSizes,
656 nAvgDimension);
657 long nMaxNonOutlier = std::max(nMaxMainNonOutlier, nMaxSubNonOutlier);
659 aReq.m_aMainGroupDimensions = setButtonSizes(aMainGroupSizes,
660 aMainGroupNonHomogeneous,
661 nAvgDimension, nMaxNonOutlier, nMinMainGroupPrimary);
662 aReq.m_aSubGroupDimensions = setButtonSizes(aSubGroupSizes,
663 aSubGroupNonHomogeneous,
664 nAvgDimension, nMaxNonOutlier, nMinSubGroupPrimary);
667 if (!aReq.m_aMainGroupDimensions.empty())
669 setSecondaryDimension(aReq.m_aMainGroupSize, nMainGroupSecondary);
670 setPrimaryDimension(aReq.m_aMainGroupSize,
671 std::accumulate(aReq.m_aMainGroupDimensions.begin(),
672 aReq.m_aMainGroupDimensions.end(), 0));
674 if (!aReq.m_aSubGroupDimensions.empty())
676 setSecondaryDimension(aReq.m_aSubGroupSize, nSubGroupSecondary);
677 setPrimaryDimension(aReq.m_aSubGroupSize,
678 std::accumulate(aReq.m_aSubGroupDimensions.begin(),
679 aReq.m_aSubGroupDimensions.end(), 0));
682 return aReq;
685 Size VclButtonBox::addSpacing(const Size &rSize, sal_uInt16 nVisibleChildren) const
687 Size aRet;
689 if (nVisibleChildren)
691 long nPrimaryDimension = getPrimaryDimension(rSize);
692 setPrimaryDimension(aRet,
693 nPrimaryDimension + m_nSpacing * (nVisibleChildren-1));
694 setSecondaryDimension(aRet, getSecondaryDimension(rSize));
697 return aRet;
700 Size VclButtonBox::calculateRequisition() const
702 Requisition aReq(calculatePrimarySecondaryRequisitions());
703 sal_uInt16 nVisibleChildren = aReq.m_aMainGroupDimensions.size() +
704 aReq.m_aSubGroupDimensions.size();
705 return addSpacing(addReqGroups(aReq), nVisibleChildren);
708 bool VclButtonBox::set_property(const OString &rKey, const OString &rValue)
710 if (rKey == "layout-style")
712 VclButtonBoxStyle eStyle = VCL_BUTTONBOX_DEFAULT_STYLE;
713 if (rValue == "spread")
714 eStyle = VCL_BUTTONBOX_SPREAD;
715 else if (rValue == "edge")
716 eStyle = VCL_BUTTONBOX_EDGE;
717 else if (rValue == "start")
718 eStyle = VCL_BUTTONBOX_START;
719 else if (rValue == "end")
720 eStyle = VCL_BUTTONBOX_END;
721 else if (rValue == "center")
722 eStyle = VCL_BUTTONBOX_CENTER;
723 else
725 SAL_WARN("vcl.layout", "unknown layout style " << rValue.getStr());
727 m_eLayoutStyle = eStyle;
729 else
730 return VclBox::set_property(rKey, rValue);
731 return true;
734 void VclButtonBox::setAllocation(const Size &rAllocation)
736 Requisition aReq(calculatePrimarySecondaryRequisitions());
738 if (aReq.m_aMainGroupDimensions.empty() && aReq.m_aSubGroupDimensions.empty())
739 return;
741 long nAllocPrimaryDimension = getPrimaryDimension(rAllocation);
743 Point aMainGroupPos, aOtherGroupPos;
744 int nSpacing = m_nSpacing;
746 //To-Do, other layout styles
747 switch (m_eLayoutStyle)
749 case VCL_BUTTONBOX_START:
750 if (!aReq.m_aSubGroupDimensions.empty())
752 long nOtherPrimaryDimension = getPrimaryDimension(
753 addSpacing(aReq.m_aSubGroupSize, aReq.m_aSubGroupDimensions.size()));
754 setPrimaryCoordinate(aOtherGroupPos,
755 nAllocPrimaryDimension - nOtherPrimaryDimension);
757 break;
758 case VCL_BUTTONBOX_SPREAD:
759 if (!aReq.m_aMainGroupDimensions.empty())
761 long nMainPrimaryDimension = getPrimaryDimension(
762 addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size()));
763 long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension;
764 nExtraSpace += (aReq.m_aMainGroupDimensions.size()-1) * nSpacing;
765 nSpacing = nExtraSpace/(aReq.m_aMainGroupDimensions.size()+1);
766 setPrimaryCoordinate(aMainGroupPos, nSpacing);
768 break;
769 case VCL_BUTTONBOX_CENTER:
770 if (!aReq.m_aMainGroupDimensions.empty())
772 long nMainPrimaryDimension = getPrimaryDimension(
773 addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size()));
774 long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension;
775 setPrimaryCoordinate(aMainGroupPos, nExtraSpace/2);
777 break;
778 default:
779 SAL_WARN("vcl.layout", "todo unimplemented layout style");
780 SAL_FALLTHROUGH;
781 case VCL_BUTTONBOX_DEFAULT_STYLE:
782 case VCL_BUTTONBOX_END:
783 if (!aReq.m_aMainGroupDimensions.empty())
785 long nMainPrimaryDimension = getPrimaryDimension(
786 addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size()));
787 setPrimaryCoordinate(aMainGroupPos,
788 nAllocPrimaryDimension - nMainPrimaryDimension);
790 break;
793 Size aChildSize;
794 setSecondaryDimension(aChildSize, getSecondaryDimension(rAllocation));
796 std::vector<long>::const_iterator aPrimaryI = aReq.m_aMainGroupDimensions.begin();
797 std::vector<long>::const_iterator aSecondaryI = aReq.m_aSubGroupDimensions.begin();
798 bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VCL_BUTTONBOX_SPREAD || m_eLayoutStyle == VCL_BUTTONBOX_CENTER);
799 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
801 if (!pChild->IsVisible())
802 continue;
804 if (bIgnoreSecondaryPacking || !pChild->get_secondary())
806 long nMainGroupPrimaryDimension = *aPrimaryI++;
807 setPrimaryDimension(aChildSize, nMainGroupPrimaryDimension);
808 setLayoutAllocation(*pChild, aMainGroupPos, aChildSize);
809 long nPrimaryCoordinate = getPrimaryCoordinate(aMainGroupPos);
810 setPrimaryCoordinate(aMainGroupPos, nPrimaryCoordinate + nMainGroupPrimaryDimension + nSpacing);
812 else
814 long nSubGroupPrimaryDimension = *aSecondaryI++;
815 setPrimaryDimension(aChildSize, nSubGroupPrimaryDimension);
816 setLayoutAllocation(*pChild, aOtherGroupPos, aChildSize);
817 long nPrimaryCoordinate = getPrimaryCoordinate(aOtherGroupPos);
818 setPrimaryCoordinate(aOtherGroupPos, nPrimaryCoordinate + nSubGroupPrimaryDimension + nSpacing);
823 struct ButtonOrder
825 OString m_aType;
826 int m_nPriority;
829 static int getButtonPriority(const OString &rType)
831 static const size_t N_TYPES = 3;
832 static const ButtonOrder aDiscardCancelSave[N_TYPES] =
834 { "/discard", 0 },
835 { "/cancel", 1 },
836 { "/save", 2 }
839 static const ButtonOrder aSaveDiscardCancel[N_TYPES] =
841 { "/save", 0 },
842 { "/discard", 1 },
843 { "/cancel", 2 }
846 const ButtonOrder* pOrder = &aDiscardCancelSave[0];
848 const OUString &rEnv = Application::GetDesktopEnvironment();
850 if (rEnv.equalsIgnoreAsciiCase("windows") ||
851 rEnv.equalsIgnoreAsciiCase("kde5") ||
852 rEnv.equalsIgnoreAsciiCase("kde4") ||
853 rEnv.equalsIgnoreAsciiCase("tde") ||
854 rEnv.equalsIgnoreAsciiCase("kde"))
856 pOrder = &aSaveDiscardCancel[0];
859 for (size_t i = 0; i < N_TYPES; ++i, ++pOrder)
861 if (rType.endsWith(pOrder->m_aType))
862 return pOrder->m_nPriority;
865 return -1;
868 class sortButtons
869 : public std::binary_function<const vcl::Window*, const vcl::Window*, bool>
871 bool m_bVerticalContainer;
872 public:
873 explicit sortButtons(bool bVerticalContainer)
874 : m_bVerticalContainer(bVerticalContainer)
877 bool operator()(const vcl::Window *pA, const vcl::Window *pB) const;
880 bool sortButtons::operator()(const vcl::Window *pA, const vcl::Window *pB) const
882 //sort into two groups of pack start and pack end
883 VclPackType ePackA = pA->get_pack_type();
884 VclPackType ePackB = pB->get_pack_type();
885 if (ePackA < ePackB)
886 return true;
887 if (ePackA > ePackB)
888 return false;
889 bool bPackA = pA->get_secondary();
890 bool bPackB = pB->get_secondary();
891 if (!m_bVerticalContainer)
893 //for horizontal boxes group secondaries before primaries
894 if (bPackA > bPackB)
895 return true;
896 if (bPackA < bPackB)
897 return false;
899 else
901 //for vertical boxes group secondaries after primaries
902 if (bPackA < bPackB)
903 return true;
904 if (bPackA > bPackB)
905 return false;
908 //now order within groups according to platform rules
909 return getButtonPriority(pA->GetHelpId()) < getButtonPriority(pB->GetHelpId());
912 void VclButtonBox::sort_native_button_order()
914 std::vector<vcl::Window*> aChilds;
915 for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
916 pChild = pChild->GetWindow(GetWindowType::Next))
918 aChilds.push_back(pChild);
921 //sort child order within parent so that we match the platform
922 //button order
923 std::stable_sort(aChilds.begin(), aChilds.end(), sortButtons(m_bVerticalContainer));
924 VclBuilder::reorderWithinParent(aChilds, true);
927 struct GridEntry
929 VclPtr<vcl::Window> pChild;
930 sal_Int32 nSpanWidth;
931 sal_Int32 nSpanHeight;
932 int x;
933 int y;
934 GridEntry()
935 : pChild(nullptr)
936 , nSpanWidth(0)
937 , nSpanHeight(0)
938 , x(-1)
939 , y(-1)
944 typedef boost::multi_array<GridEntry, 2> array_type;
946 static array_type assembleGrid(const VclGrid &rGrid);
947 static bool isNullGrid(const array_type& A);
948 static void calcMaxs(const array_type &A, std::vector<VclGrid::Value> &rWidths, std::vector<VclGrid::Value> &rHeights);
950 array_type assembleGrid(const VclGrid &rGrid)
952 array_type A;
954 for (vcl::Window* pChild = rGrid.GetWindow(GetWindowType::FirstChild); pChild;
955 pChild = pChild->GetWindow(GetWindowType::Next))
957 sal_Int32 nLeftAttach = std::max<sal_Int32>(pChild->get_grid_left_attach(), 0);
958 sal_Int32 nWidth = pChild->get_grid_width();
959 sal_Int32 nMaxXPos = nLeftAttach+nWidth-1;
961 sal_Int32 nTopAttach = std::max<sal_Int32>(pChild->get_grid_top_attach(), 0);
962 sal_Int32 nHeight = pChild->get_grid_height();
963 sal_Int32 nMaxYPos = nTopAttach+nHeight-1;
965 sal_Int32 nCurrentMaxXPos = A.shape()[0]-1;
966 sal_Int32 nCurrentMaxYPos = A.shape()[1]-1;
967 if (nMaxXPos > nCurrentMaxXPos || nMaxYPos > nCurrentMaxYPos)
969 nCurrentMaxXPos = std::max(nMaxXPos, nCurrentMaxXPos);
970 nCurrentMaxYPos = std::max(nMaxYPos, nCurrentMaxYPos);
971 A.resize(boost::extents[nCurrentMaxXPos+1][nCurrentMaxYPos+1]);
974 GridEntry &rEntry = A[nLeftAttach][nTopAttach];
975 rEntry.pChild = pChild;
976 rEntry.nSpanWidth = nWidth;
977 rEntry.nSpanHeight = nHeight;
978 rEntry.x = nLeftAttach;
979 rEntry.y = nTopAttach;
981 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
983 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
985 GridEntry &rSpan = A[nLeftAttach+nSpanX][nTopAttach+nSpanY];
986 rSpan.x = nLeftAttach;
987 rSpan.y = nTopAttach;
992 //see if we have any empty rows/cols
993 sal_Int32 nMaxX = A.shape()[0];
994 sal_Int32 nMaxY = A.shape()[1];
996 std::vector<bool> aNonEmptyCols(nMaxX);
997 std::vector<bool> aNonEmptyRows(nMaxY);
999 for (sal_Int32 x = 0; x < nMaxX; ++x)
1001 for (sal_Int32 y = 0; y < nMaxY; ++y)
1003 const GridEntry &rEntry = A[x][y];
1004 const vcl::Window *pChild = rEntry.pChild;
1005 if (pChild && pChild->IsVisible())
1007 aNonEmptyCols[x] = true;
1008 if (rGrid.get_column_homogeneous())
1010 for (sal_Int32 nSpanX = 1; nSpanX < rEntry.nSpanWidth; ++nSpanX)
1011 aNonEmptyCols[x+nSpanX] = true;
1013 aNonEmptyRows[y] = true;
1014 if (rGrid.get_row_homogeneous())
1016 for (sal_Int32 nSpanY = 1; nSpanY < rEntry.nSpanHeight; ++nSpanY)
1017 aNonEmptyRows[y+nSpanY] = true;
1023 if (!rGrid.get_column_homogeneous())
1025 //reduce the spans of elements that span empty columns
1026 for (sal_Int32 x = 0; x < nMaxX; ++x)
1028 std::set<GridEntry*> candidates;
1029 for (sal_Int32 y = 0; y < nMaxY; ++y)
1031 if (aNonEmptyCols[x])
1032 continue;
1033 GridEntry &rSpan = A[x][y];
1034 //cell x/y is spanned by the widget at cell rSpan.x/rSpan.y,
1035 //just points back to itself if there's no cell spanning
1036 if ((rSpan.x == -1) || (rSpan.y == -1))
1038 //there is no entry for this cell, i.e. this is a cell
1039 //with no widget in it, or spanned by any other widget
1040 continue;
1042 GridEntry &rEntry = A[rSpan.x][rSpan.y];
1043 candidates.insert(&rEntry);
1045 for (std::set<GridEntry*>::iterator aI = candidates.begin(), aEnd = candidates.end();
1046 aI != aEnd; ++aI)
1048 GridEntry *pEntry = *aI;
1049 --pEntry->nSpanWidth;
1054 if (!rGrid.get_row_homogeneous())
1056 //reduce the spans of elements that span empty rows
1057 for (sal_Int32 y = 0; y < nMaxY; ++y)
1059 std::set<GridEntry*> candidates;
1060 for (sal_Int32 x = 0; x < nMaxX; ++x)
1062 if (aNonEmptyRows[y])
1063 continue;
1064 GridEntry &rSpan = A[x][y];
1065 //cell x/y is spanned by the widget at cell rSpan.x/rSpan.y,
1066 //just points back to itself if there's no cell spanning
1067 if ((rSpan.x == -1) || (rSpan.y == -1))
1069 //there is no entry for this cell, i.e. this is a cell
1070 //with no widget in it, or spanned by any other widget
1071 continue;
1073 GridEntry &rEntry = A[rSpan.x][rSpan.y];
1074 candidates.insert(&rEntry);
1076 for (std::set<GridEntry*>::iterator aI = candidates.begin(), aEnd = candidates.end();
1077 aI != aEnd; ++aI)
1079 GridEntry *pEntry = *aI;
1080 --pEntry->nSpanHeight;
1085 sal_Int32 nNonEmptyCols = std::count(aNonEmptyCols.begin(), aNonEmptyCols.end(), true);
1086 sal_Int32 nNonEmptyRows = std::count(aNonEmptyRows.begin(), aNonEmptyRows.end(), true);
1088 //make new grid without empty rows and columns
1089 array_type B(boost::extents[nNonEmptyCols][nNonEmptyRows]);
1090 for (sal_Int32 x = 0, x2 = 0; x < nMaxX; ++x)
1092 if (!aNonEmptyCols[x])
1093 continue;
1094 for (sal_Int32 y = 0, y2 = 0; y < nMaxY; ++y)
1096 if (!aNonEmptyRows[y])
1097 continue;
1098 GridEntry &rEntry = A[x][y];
1099 B[x2][y2++] = rEntry;
1101 ++x2;
1104 return B;
1107 static bool isNullGrid(const array_type &A)
1109 sal_Int32 nMaxX = A.shape()[0];
1110 sal_Int32 nMaxY = A.shape()[1];
1112 if (!nMaxX || !nMaxY)
1113 return true;
1114 return false;
1117 static void calcMaxs(const array_type &A, std::vector<VclGrid::Value> &rWidths, std::vector<VclGrid::Value> &rHeights)
1119 sal_Int32 nMaxX = A.shape()[0];
1120 sal_Int32 nMaxY = A.shape()[1];
1122 rWidths.resize(nMaxX);
1123 rHeights.resize(nMaxY);
1125 //first use the non spanning entries to set default width/heights
1126 for (sal_Int32 x = 0; x < nMaxX; ++x)
1128 for (sal_Int32 y = 0; y < nMaxY; ++y)
1130 const GridEntry &rEntry = A[x][y];
1131 const vcl::Window *pChild = rEntry.pChild;
1132 if (!pChild || !pChild->IsVisible())
1133 continue;
1135 sal_Int32 nWidth = rEntry.nSpanWidth;
1136 sal_Int32 nHeight = rEntry.nSpanHeight;
1138 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1139 rWidths[x+nSpanX].m_bExpand |= pChild->get_hexpand();
1141 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1142 rHeights[y+nSpanY].m_bExpand |= pChild->get_vexpand();
1144 if (nWidth == 1 || nHeight == 1)
1146 Size aChildSize = VclContainer::getLayoutRequisition(*pChild);
1147 if (nWidth == 1)
1148 rWidths[x].m_nValue = std::max(rWidths[x].m_nValue, aChildSize.Width());
1149 if (nHeight == 1)
1150 rHeights[y].m_nValue = std::max(rHeights[y].m_nValue, aChildSize.Height());
1155 //now use the spanning entries and split any extra sizes across expanding rows/cols
1156 //where possible
1157 for (sal_Int32 x = 0; x < nMaxX; ++x)
1159 for (sal_Int32 y = 0; y < nMaxY; ++y)
1161 const GridEntry &rEntry = A[x][y];
1162 const vcl::Window *pChild = rEntry.pChild;
1163 if (!pChild || !pChild->IsVisible())
1164 continue;
1166 sal_Int32 nWidth = rEntry.nSpanWidth;
1167 sal_Int32 nHeight = rEntry.nSpanHeight;
1169 if (nWidth == 1 && nHeight == 1)
1170 continue;
1172 Size aChildSize = VclContainer::getLayoutRequisition(*pChild);
1174 if (nWidth > 1)
1176 sal_Int32 nExistingWidth = 0;
1177 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1178 nExistingWidth += rWidths[x+nSpanX].m_nValue;
1180 sal_Int32 nExtraWidth = aChildSize.Width() - nExistingWidth;
1182 if (nExtraWidth > 0)
1184 bool bForceExpandAll = false;
1185 sal_Int32 nExpandables = 0;
1186 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1187 if (rWidths[x+nSpanX].m_bExpand)
1188 ++nExpandables;
1189 if (nExpandables == 0)
1191 nExpandables = nWidth;
1192 bForceExpandAll = true;
1195 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1197 if (rWidths[x+nSpanX].m_bExpand || bForceExpandAll)
1198 rWidths[x+nSpanX].m_nValue += nExtraWidth/nExpandables;
1203 if (nHeight > 1)
1205 sal_Int32 nExistingHeight = 0;
1206 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1207 nExistingHeight += rHeights[y+nSpanY].m_nValue;
1209 sal_Int32 nExtraHeight = aChildSize.Height() - nExistingHeight;
1211 if (nExtraHeight > 0)
1213 bool bForceExpandAll = false;
1214 sal_Int32 nExpandables = 0;
1215 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1216 if (rHeights[y+nSpanY].m_bExpand)
1217 ++nExpandables;
1218 if (nExpandables == 0)
1220 nExpandables = nHeight;
1221 bForceExpandAll = true;
1224 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1226 if (rHeights[y+nSpanY].m_bExpand || bForceExpandAll)
1227 rHeights[y+nSpanY].m_nValue += nExtraHeight/nExpandables;
1235 bool compareValues(const VclGrid::Value &i, const VclGrid::Value &j)
1237 return i.m_nValue < j.m_nValue;
1240 VclGrid::Value accumulateValues(const VclGrid::Value &i, const VclGrid::Value &j)
1242 VclGrid::Value aRet;
1243 aRet.m_nValue = i.m_nValue + j.m_nValue;
1244 aRet.m_bExpand = i.m_bExpand || j.m_bExpand;
1245 return aRet;
1248 Size VclGrid::calculateRequisition() const
1250 return calculateRequisitionForSpacings(get_row_spacing(), get_column_spacing());
1253 Size VclGrid::calculateRequisitionForSpacings(sal_Int32 nRowSpacing, sal_Int32 nColSpacing) const
1255 array_type A = assembleGrid(*this);
1257 if (isNullGrid(A))
1258 return Size();
1260 std::vector<Value> aWidths;
1261 std::vector<Value> aHeights;
1262 calcMaxs(A, aWidths, aHeights);
1264 long nTotalWidth = 0;
1265 if (get_column_homogeneous())
1267 nTotalWidth = std::max_element(aWidths.begin(), aWidths.end(), compareValues)->m_nValue;
1268 nTotalWidth *= aWidths.size();
1270 else
1272 nTotalWidth = std::accumulate(aWidths.begin(), aWidths.end(), Value(), accumulateValues).m_nValue;
1275 nTotalWidth += nColSpacing * (aWidths.size()-1);
1277 long nTotalHeight = 0;
1278 if (get_row_homogeneous())
1280 nTotalHeight = std::max_element(aHeights.begin(), aHeights.end(), compareValues)->m_nValue;
1281 nTotalHeight *= aHeights.size();
1283 else
1285 nTotalHeight = std::accumulate(aHeights.begin(), aHeights.end(), Value(), accumulateValues).m_nValue;
1288 nTotalHeight += nRowSpacing * (aHeights.size()-1);
1290 return Size(nTotalWidth, nTotalHeight);
1293 void VclGrid::setAllocation(const Size& rAllocation)
1295 array_type A = assembleGrid(*this);
1297 if (isNullGrid(A))
1298 return;
1300 sal_Int32 nMaxX = A.shape()[0];
1301 sal_Int32 nMaxY = A.shape()[1];
1303 Size aRequisition;
1304 std::vector<Value> aWidths(nMaxX);
1305 std::vector<Value> aHeights(nMaxY);
1306 if (!get_column_homogeneous() || !get_row_homogeneous())
1308 aRequisition = calculateRequisition();
1309 calcMaxs(A, aWidths, aHeights);
1312 sal_Int32 nColSpacing(get_column_spacing());
1313 sal_Int32 nRowSpacing(get_row_spacing());
1315 long nAvailableWidth = rAllocation.Width();
1316 if (nMaxX)
1317 nAvailableWidth -= nColSpacing * (nMaxX - 1);
1318 if (get_column_homogeneous())
1320 for (sal_Int32 x = 0; x < nMaxX; ++x)
1321 aWidths[x].m_nValue = nAvailableWidth/nMaxX;
1323 else if (rAllocation.Width() != aRequisition.Width())
1325 sal_Int32 nExpandables = 0;
1326 for (sal_Int32 x = 0; x < nMaxX; ++x)
1327 if (aWidths[x].m_bExpand)
1328 ++nExpandables;
1329 long nExtraWidthForExpanders = nExpandables ? (rAllocation.Width() - aRequisition.Width()) / nExpandables : 0;
1331 //We don't fit and there is no volunteer to be shrunk
1332 if (!nExpandables && rAllocation.Width() < aRequisition.Width())
1334 //first reduce spacing
1335 while (nColSpacing)
1337 nColSpacing /= 2;
1338 aRequisition = calculateRequisitionForSpacings(nRowSpacing, nColSpacing);
1339 if (aRequisition.Width() <= rAllocation.Width())
1340 break;
1343 //share out the remaining pain to everyone
1344 long nExtraWidth = (rAllocation.Width() - aRequisition.Width()) / nMaxX;
1346 for (sal_Int32 x = 0; x < nMaxX; ++x)
1347 aWidths[x].m_nValue += nExtraWidth;
1350 if (nExtraWidthForExpanders)
1352 for (sal_Int32 x = 0; x < nMaxX; ++x)
1353 if (aWidths[x].m_bExpand)
1354 aWidths[x].m_nValue += nExtraWidthForExpanders;
1358 long nAvailableHeight = rAllocation.Height();
1359 if (nMaxY)
1360 nAvailableHeight -= nRowSpacing * (nMaxY - 1);
1361 if (get_row_homogeneous())
1363 for (sal_Int32 y = 0; y < nMaxY; ++y)
1364 aHeights[y].m_nValue = nAvailableHeight/nMaxY;
1366 else if (rAllocation.Height() != aRequisition.Height())
1368 sal_Int32 nExpandables = 0;
1369 for (sal_Int32 y = 0; y < nMaxY; ++y)
1370 if (aHeights[y].m_bExpand)
1371 ++nExpandables;
1372 long nExtraHeightForExpanders = nExpandables ? (rAllocation.Height() - aRequisition.Height()) / nExpandables : 0;
1374 //We don't fit and there is no volunteer to be shrunk
1375 if (!nExpandables && rAllocation.Height() < aRequisition.Height())
1377 //first reduce spacing
1378 while (nRowSpacing)
1380 nRowSpacing /= 2;
1381 aRequisition = calculateRequisitionForSpacings(nRowSpacing, nColSpacing);
1382 if (aRequisition.Height() <= rAllocation.Height())
1383 break;
1386 //share out the remaining pain to everyone
1387 long nExtraHeight = (rAllocation.Height() - aRequisition.Height()) / nMaxY;
1389 for (sal_Int32 y = 0; y < nMaxY; ++y)
1390 aHeights[y].m_nValue += nExtraHeight;
1393 if (nExtraHeightForExpanders)
1395 for (sal_Int32 y = 0; y < nMaxY; ++y)
1396 if (aHeights[y].m_bExpand)
1397 aHeights[y].m_nValue += nExtraHeightForExpanders;
1401 Point aAllocPos(0, 0);
1402 for (sal_Int32 x = 0; x < nMaxX; ++x)
1404 for (sal_Int32 y = 0; y < nMaxY; ++y)
1406 GridEntry &rEntry = A[x][y];
1407 vcl::Window *pChild = rEntry.pChild;
1408 if (pChild)
1410 Size aChildAlloc(0, 0);
1412 sal_Int32 nWidth = rEntry.nSpanWidth;
1413 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1414 aChildAlloc.Width() += aWidths[x+nSpanX].m_nValue;
1415 aChildAlloc.Width() += nColSpacing*(nWidth-1);
1417 sal_Int32 nHeight = rEntry.nSpanHeight;
1418 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1419 aChildAlloc.Height() += aHeights[y+nSpanY].m_nValue;
1420 aChildAlloc.Height() += nRowSpacing*(nHeight-1);
1422 setLayoutAllocation(*pChild, aAllocPos, aChildAlloc);
1424 aAllocPos.Y() += aHeights[y].m_nValue + nRowSpacing;
1426 aAllocPos.X() += aWidths[x].m_nValue + nColSpacing;
1427 aAllocPos.Y() = 0;
1431 bool toBool(const OString &rValue)
1433 return (!rValue.isEmpty() && (rValue[0] == 't' || rValue[0] == 'T' || rValue[0] == '1'));
1436 bool VclGrid::set_property(const OString &rKey, const OString &rValue)
1438 if (rKey == "row-spacing")
1439 set_row_spacing(rValue.toInt32());
1440 else if (rKey == "column-spacing")
1441 set_column_spacing(rValue.toInt32());
1442 else if (rKey == "row-homogeneous")
1443 m_bRowHomogeneous = toBool(rValue);
1444 else if (rKey == "column-homogeneous")
1445 m_bColumnHomogeneous = toBool(rValue);
1446 else if (rKey == "n-rows")
1447 /*nothing to do*/;
1448 else
1449 return VclContainer::set_property(rKey, rValue);
1450 return true;
1453 const vcl::Window *VclBin::get_child() const
1455 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1457 return pWindowImpl->mpFirstChild;
1460 vcl::Window *VclBin::get_child()
1462 return const_cast<vcl::Window*>(const_cast<const VclBin*>(this)->get_child());
1465 Size VclBin::calculateRequisition() const
1467 const vcl::Window *pChild = get_child();
1468 if (pChild && pChild->IsVisible())
1469 return getLayoutRequisition(*pChild);
1470 return Size(0, 0);
1473 void VclBin::setAllocation(const Size &rAllocation)
1475 vcl::Window *pChild = get_child();
1476 if (pChild && pChild->IsVisible())
1477 setLayoutAllocation(*pChild, Point(0, 0), rAllocation);
1480 VclFrame::~VclFrame()
1482 disposeOnce();
1485 void VclFrame::dispose()
1487 m_pLabel.clear();
1488 VclBin::dispose();
1491 //To-Do, hook a DecorationView into VclFrame ?
1493 Size VclFrame::calculateRequisition() const
1495 Size aRet(0, 0);
1497 const vcl::Window *pChild = get_child();
1498 const vcl::Window *pLabel = get_label_widget();
1500 if (pChild && pChild->IsVisible())
1501 aRet = getLayoutRequisition(*pChild);
1503 if (pLabel && pLabel->IsVisible())
1505 Size aLabelSize = getLayoutRequisition(*pLabel);
1506 aRet.Height() += aLabelSize.Height();
1507 aRet.Width() = std::max(aLabelSize.Width(), aRet.Width());
1510 const FrameStyle &rFrameStyle =
1511 GetSettings().GetStyleSettings().GetFrameStyle();
1512 aRet.Width() += rFrameStyle.left + rFrameStyle.right;
1513 aRet.Height() += rFrameStyle.top + rFrameStyle.bottom;
1515 return aRet;
1518 void VclFrame::setAllocation(const Size &rAllocation)
1520 //SetBackground( Color(0xFF, 0x00, 0xFF) );
1522 const FrameStyle &rFrameStyle =
1523 GetSettings().GetStyleSettings().GetFrameStyle();
1524 Size aAllocation(rAllocation.Width() - rFrameStyle.left - rFrameStyle.right,
1525 rAllocation.Height() - rFrameStyle.top - rFrameStyle.bottom);
1526 Point aChildPos(rFrameStyle.left, rFrameStyle.top);
1528 vcl::Window *pChild = get_child();
1529 vcl::Window *pLabel = get_label_widget();
1531 if (pLabel && pLabel->IsVisible())
1533 Size aLabelSize = getLayoutRequisition(*pLabel);
1534 aLabelSize.Height() = std::min(aLabelSize.Height(), aAllocation.Height());
1535 aLabelSize.Width() = std::min(aLabelSize.Width(), aAllocation.Width());
1536 setLayoutAllocation(*pLabel, aChildPos, aLabelSize);
1537 aAllocation.Height() -= aLabelSize.Height();
1538 aChildPos.Y() += aLabelSize.Height();
1541 if (pChild && pChild->IsVisible())
1542 setLayoutAllocation(*pChild, aChildPos, aAllocation);
1545 IMPL_LINK(VclFrame, WindowEventListener, VclWindowEvent&, rEvent, void)
1547 if (rEvent.GetId() == VCLEVENT_OBJECT_DYING)
1548 designate_label(nullptr);
1551 void VclFrame::designate_label(vcl::Window *pWindow)
1553 assert(!pWindow || pWindow->GetParent() == this);
1554 if (m_pLabel)
1555 m_pLabel->RemoveEventListener(LINK(this, VclFrame, WindowEventListener));
1556 m_pLabel = pWindow;
1557 if (m_pLabel)
1558 m_pLabel->AddEventListener(LINK(this, VclFrame, WindowEventListener));
1561 const vcl::Window *VclFrame::get_label_widget() const
1563 assert(GetChildCount() == 2);
1564 if (m_pLabel)
1565 return m_pLabel;
1566 //The label widget is normally the first (of two) children
1567 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1568 if (pWindowImpl->mpFirstChild == pWindowImpl->mpLastChild) //no label exists
1569 return nullptr;
1570 return pWindowImpl->mpFirstChild;
1573 vcl::Window *VclFrame::get_label_widget()
1575 return const_cast<vcl::Window*>(const_cast<const VclFrame*>(this)->get_label_widget());
1578 const vcl::Window *VclFrame::get_child() const
1580 assert(GetChildCount() == 2);
1581 //The child widget is the normally the last (of two) children
1582 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1583 if (!m_pLabel)
1584 return pWindowImpl->mpLastChild;
1585 if (pWindowImpl->mpFirstChild == pWindowImpl->mpLastChild) //only label exists
1586 return nullptr;
1587 return pWindowImpl->mpLastChild;
1590 vcl::Window *VclFrame::get_child()
1592 return const_cast<vcl::Window*>(const_cast<const VclFrame*>(this)->get_child());
1595 void VclFrame::set_label(const OUString &rLabel)
1597 vcl::Window *pLabel = get_label_widget();
1598 assert(pLabel);
1599 pLabel->SetText(rLabel);
1602 OUString VclFrame::get_label() const
1604 const vcl::Window *pLabel = get_label_widget();
1605 assert(pLabel);
1606 return pLabel->GetText();
1609 OUString VclFrame::getDefaultAccessibleName() const
1611 const vcl::Window *pLabel = get_label_widget();
1612 if (pLabel)
1613 return pLabel->GetAccessibleName();
1614 return VclBin::getDefaultAccessibleName();
1617 Size VclAlignment::calculateRequisition() const
1619 Size aRet(m_nLeftPadding + m_nRightPadding,
1620 m_nTopPadding + m_nBottomPadding);
1622 const vcl::Window *pChild = get_child();
1623 if (pChild && pChild->IsVisible())
1625 Size aChildSize = getLayoutRequisition(*pChild);
1626 aRet.Width() += aChildSize.Width();
1627 aRet.Height() += aChildSize.Height();
1630 return aRet;
1633 void VclAlignment::setAllocation(const Size &rAllocation)
1635 vcl::Window *pChild = get_child();
1636 if (!pChild || !pChild->IsVisible())
1637 return;
1639 Point aChildPos(m_nLeftPadding, m_nTopPadding);
1641 Size aAllocation;
1642 aAllocation.Width() = rAllocation.Width() - (m_nLeftPadding + m_nRightPadding);
1643 aAllocation.Height() = rAllocation.Height() - (m_nTopPadding + m_nBottomPadding);
1645 setLayoutAllocation(*pChild, aChildPos, aAllocation);
1648 bool VclAlignment::set_property(const OString &rKey, const OString &rValue)
1650 if (rKey == "bottom-padding")
1651 m_nBottomPadding = rValue.toInt32();
1652 else if (rKey == "left-padding")
1653 m_nLeftPadding = rValue.toInt32();
1654 else if (rKey == "right-padding")
1655 m_nRightPadding = rValue.toInt32();
1656 else if (rKey == "top-padding")
1657 m_nTopPadding = rValue.toInt32();
1658 else if (rKey == "xalign")
1659 m_fXAlign = rValue.toFloat();
1660 else if (rKey == "xscale")
1661 m_fXScale = rValue.toFloat();
1662 else if (rKey == "yalign")
1663 m_fYAlign = rValue.toFloat();
1664 else if (rKey == "yscale")
1665 m_fYScale = rValue.toFloat();
1666 else
1667 return VclBin::set_property(rKey, rValue);
1668 return true;
1671 void VclExpander::dispose()
1673 m_pDisclosureButton.disposeAndClear();
1674 VclBin::dispose();
1677 const vcl::Window *VclExpander::get_child() const
1679 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1681 assert(pWindowImpl->mpFirstChild == m_pDisclosureButton);
1683 return pWindowImpl->mpFirstChild->GetWindow(GetWindowType::Next);
1686 vcl::Window *VclExpander::get_child()
1688 return const_cast<vcl::Window*>(const_cast<const VclExpander*>(this)->get_child());
1691 Size VclExpander::calculateRequisition() const
1693 Size aRet(0, 0);
1695 WindowImpl* pWindowImpl = ImplGetWindowImpl();
1697 const vcl::Window *pChild = get_child();
1698 const vcl::Window *pLabel = pChild != pWindowImpl->mpLastChild ? pWindowImpl->mpLastChild.get() : nullptr;
1700 if (pChild && pChild->IsVisible() && m_pDisclosureButton->IsChecked())
1701 aRet = getLayoutRequisition(*pChild);
1703 Size aExpanderSize = getLayoutRequisition(*m_pDisclosureButton);
1705 if (pLabel && pLabel->IsVisible())
1707 Size aLabelSize = getLayoutRequisition(*pLabel);
1708 aExpanderSize.Height() = std::max(aExpanderSize.Height(), aLabelSize.Height());
1709 aExpanderSize.Width() += aLabelSize.Width();
1712 aRet.Height() += aExpanderSize.Height();
1713 aRet.Width() = std::max(aExpanderSize.Width(), aRet.Width());
1715 const FrameStyle &rFrameStyle =
1716 GetSettings().GetStyleSettings().GetFrameStyle();
1717 aRet.Width() += rFrameStyle.left + rFrameStyle.right;
1718 aRet.Height() += rFrameStyle.top + rFrameStyle.bottom;
1720 return aRet;
1723 void VclExpander::setAllocation(const Size &rAllocation)
1725 const FrameStyle &rFrameStyle =
1726 GetSettings().GetStyleSettings().GetFrameStyle();
1727 Size aAllocation(rAllocation.Width() - rFrameStyle.left - rFrameStyle.right,
1728 rAllocation.Height() - rFrameStyle.top - rFrameStyle.bottom);
1729 Point aChildPos(rFrameStyle.left, rFrameStyle.top);
1731 WindowImpl* pWindowImpl = ImplGetWindowImpl();
1733 //The label widget is the last (of two) children
1734 vcl::Window *pChild = get_child();
1735 vcl::Window *pLabel = pChild != pWindowImpl->mpLastChild.get() ? pWindowImpl->mpLastChild.get() : nullptr;
1737 Size aButtonSize = getLayoutRequisition(*m_pDisclosureButton);
1738 Size aLabelSize;
1739 Size aExpanderSize = aButtonSize;
1740 if (pLabel && pLabel->IsVisible())
1742 aLabelSize = getLayoutRequisition(*pLabel);
1743 aExpanderSize.Height() = std::max(aExpanderSize.Height(), aLabelSize.Height());
1744 aExpanderSize.Width() += aLabelSize.Width();
1747 aExpanderSize.Height() = std::min(aExpanderSize.Height(), aAllocation.Height());
1748 aExpanderSize.Width() = std::min(aExpanderSize.Width(), aAllocation.Width());
1750 aButtonSize.Height() = std::min(aButtonSize.Height(), aExpanderSize.Height());
1751 aButtonSize.Width() = std::min(aButtonSize.Width(), aExpanderSize.Width());
1753 long nExtraExpanderHeight = aExpanderSize.Height() - aButtonSize.Height();
1754 Point aButtonPos(aChildPos.X(), aChildPos.Y() + nExtraExpanderHeight/2);
1755 setLayoutAllocation(*m_pDisclosureButton, aButtonPos, aButtonSize);
1757 if (pLabel && pLabel->IsVisible())
1759 aLabelSize.Height() = std::min(aLabelSize.Height(), aExpanderSize.Height());
1760 aLabelSize.Width() = std::min(aLabelSize.Width(),
1761 aExpanderSize.Width() - aButtonSize.Width());
1763 long nExtraLabelHeight = aExpanderSize.Height() - aLabelSize.Height();
1764 Point aLabelPos(aChildPos.X() + aButtonSize.Width(), aChildPos.Y() + nExtraLabelHeight/2);
1765 setLayoutAllocation(*pLabel, aLabelPos, aLabelSize);
1768 aAllocation.Height() -= aExpanderSize.Height();
1769 aChildPos.Y() += aExpanderSize.Height();
1771 if (pChild && pChild->IsVisible())
1773 if (!m_pDisclosureButton->IsChecked())
1774 aAllocation = Size();
1775 setLayoutAllocation(*pChild, aChildPos, aAllocation);
1779 bool VclExpander::set_property(const OString &rKey, const OString &rValue)
1781 if (rKey == "expanded")
1782 set_expanded(toBool(rValue));
1783 else if (rKey == "resize-toplevel")
1784 m_bResizeTopLevel = toBool(rValue);
1785 else
1786 return VclBin::set_property(rKey, rValue);
1787 return true;
1790 void VclExpander::StateChanged(StateChangedType nType)
1792 VclBin::StateChanged( nType );
1794 if (nType == StateChangedType::InitShow)
1796 vcl::Window *pChild = get_child();
1797 if (pChild)
1798 pChild->Show(m_pDisclosureButton->IsChecked());
1802 IMPL_LINK( VclExpander, ClickHdl, CheckBox&, rBtn, void )
1804 vcl::Window *pChild = get_child();
1805 if (pChild)
1807 pChild->Show(rBtn.IsChecked());
1808 queue_resize();
1809 Dialog* pResizeDialog = m_bResizeTopLevel ? GetParentDialog() : nullptr;
1810 if (pResizeDialog)
1811 pResizeDialog->setOptimalLayoutSize();
1813 maExpandedHdl.Call(*this);
1816 VclScrolledWindow::VclScrolledWindow(vcl::Window *pParent)
1817 : VclBin(pParent, WB_HIDE | WB_CLIPCHILDREN | WB_AUTOHSCROLL | WB_AUTOVSCROLL | WB_TABSTOP)
1818 , m_bUserManagedScrolling(false)
1819 , m_pVScroll(VclPtr<ScrollBar>::Create(this, WB_HIDE | WB_VERT))
1820 , m_pHScroll(VclPtr<ScrollBar>::Create(this, WB_HIDE | WB_HORZ))
1821 , m_aScrollBarBox(VclPtr<ScrollBarBox>::Create(this, WB_HIDE))
1823 SetType(WINDOW_SCROLLWINDOW);
1825 Link<ScrollBar*,void> aLink( LINK( this, VclScrolledWindow, ScrollBarHdl ) );
1826 m_pVScroll->SetScrollHdl(aLink);
1827 m_pHScroll->SetScrollHdl(aLink);
1830 void VclScrolledWindow::dispose()
1832 m_pVScroll.disposeAndClear();
1833 m_pHScroll.disposeAndClear();
1834 m_aScrollBarBox.disposeAndClear();
1835 VclBin::dispose();
1838 IMPL_LINK_NOARG(VclScrolledWindow, ScrollBarHdl, ScrollBar*, void)
1840 vcl::Window *pChild = get_child();
1841 if (!pChild)
1842 return;
1844 assert(dynamic_cast<VclViewport*>(pChild) && "scrolledwindow child should be a Viewport");
1846 pChild = pChild->GetWindow(GetWindowType::FirstChild);
1848 if (!pChild)
1849 return;
1851 Point aWinPos;
1853 if (m_pHScroll->IsVisible())
1855 aWinPos.X() = -m_pHScroll->GetThumbPos();
1858 if (m_pVScroll->IsVisible())
1860 aWinPos.Y() = -m_pVScroll->GetThumbPos();
1863 pChild->SetPosPixel(aWinPos);
1866 const vcl::Window *VclScrolledWindow::get_child() const
1868 assert(GetChildCount() == 4);
1869 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1870 return pWindowImpl->mpLastChild;
1873 vcl::Window *VclScrolledWindow::get_child()
1875 return const_cast<vcl::Window*>(const_cast<const VclScrolledWindow*>(this)->get_child());
1878 Size VclScrolledWindow::calculateRequisition() const
1880 Size aRet(0, 0);
1882 const vcl::Window *pChild = get_child();
1883 if (pChild && pChild->IsVisible())
1884 aRet = getLayoutRequisition(*pChild);
1886 if (GetStyle() & WB_VSCROLL)
1887 aRet.Width() += getLayoutRequisition(*m_pVScroll).Width();
1889 if (GetStyle() & WB_HSCROLL)
1890 aRet.Height() += getLayoutRequisition(*m_pHScroll).Height();
1892 return aRet;
1895 void VclScrolledWindow::InitScrollBars(const Size &rRequest)
1897 const vcl::Window *pChild = get_child();
1898 if (!pChild || !pChild->IsVisible())
1899 return;
1901 Size aOutSize(getVisibleChildSize());
1903 if (m_pVScroll->IsVisible())
1905 m_pVScroll->SetRangeMax(rRequest.Height());
1906 m_pVScroll->SetVisibleSize(aOutSize.Height());
1907 m_pVScroll->SetPageSize(16);
1910 if (m_pHScroll->IsVisible())
1912 m_pHScroll->SetRangeMax(rRequest.Width());
1913 m_pHScroll->SetVisibleSize(aOutSize.Width());
1914 m_pHScroll->SetPageSize(16);
1918 void VclScrolledWindow::setAllocation(const Size &rAllocation)
1920 Size aChildAllocation(rAllocation);
1921 Size aChildReq;
1923 vcl::Window *pChild = get_child();
1924 if (pChild && pChild->IsVisible())
1925 aChildReq = getLayoutRequisition(*pChild);
1927 long nAvailHeight = rAllocation.Height();
1928 long nAvailWidth = rAllocation.Width();
1929 // vert. ScrollBar
1930 if (GetStyle() & WB_AUTOVSCROLL)
1932 m_pVScroll->Show(nAvailHeight < aChildReq.Height());
1935 if (m_pVScroll->IsVisible())
1936 nAvailWidth -= getLayoutRequisition(*m_pVScroll).Width();
1938 // horz. ScrollBar
1939 if (GetStyle() & WB_AUTOHSCROLL)
1941 bool bShowHScroll = nAvailWidth < aChildReq.Width();
1942 m_pHScroll->Show(bShowHScroll);
1944 if (bShowHScroll)
1945 nAvailHeight -= getLayoutRequisition(*m_pHScroll).Height();
1947 if (GetStyle() & WB_AUTOVSCROLL)
1948 m_pVScroll->Show(nAvailHeight < aChildReq.Height());
1951 Size aInnerSize(aChildAllocation);
1952 long nScrollBarWidth = 0, nScrollBarHeight = 0;
1954 if (m_pVScroll->IsVisible())
1956 nScrollBarWidth = getLayoutRequisition(*m_pVScroll).Width();
1957 Point aScrollPos(rAllocation.Width() - nScrollBarWidth, 0);
1958 Size aScrollSize(nScrollBarWidth, rAllocation.Height());
1959 setLayoutAllocation(*m_pVScroll, aScrollPos, aScrollSize);
1960 aChildAllocation.Width() -= nScrollBarWidth;
1961 aInnerSize.Width() -= nScrollBarWidth;
1962 aChildAllocation.Height() = aChildReq.Height();
1965 if (m_pHScroll->IsVisible())
1967 nScrollBarHeight = getLayoutRequisition(*m_pHScroll).Height();
1968 Point aScrollPos(0, rAllocation.Height() - nScrollBarHeight);
1969 Size aScrollSize(rAllocation.Width(), nScrollBarHeight);
1970 setLayoutAllocation(*m_pHScroll, aScrollPos, aScrollSize);
1971 aChildAllocation.Height() -= nScrollBarHeight;
1972 aInnerSize.Height() -= nScrollBarHeight;
1973 aChildAllocation.Width() = aChildReq.Width();
1976 if (m_pVScroll->IsVisible() && m_pHScroll->IsVisible())
1978 Point aBoxPos(aInnerSize.Width(), aInnerSize.Height());
1979 m_aScrollBarBox->SetPosSizePixel(aBoxPos, Size(nScrollBarWidth, nScrollBarHeight));
1980 m_aScrollBarBox->Show();
1982 else
1984 m_aScrollBarBox->Hide();
1987 if (pChild && pChild->IsVisible())
1989 assert(dynamic_cast<VclViewport*>(pChild) && "scrolledwindow child should be a Viewport");
1990 setLayoutAllocation(*pChild, Point(0, 0), aInnerSize);
1993 if (!m_bUserManagedScrolling)
1994 InitScrollBars(aChildReq);
1997 Size VclScrolledWindow::getVisibleChildSize() const
1999 Size aRet(GetSizePixel());
2000 if (m_pVScroll->IsVisible())
2001 aRet.Width() -= m_pVScroll->GetSizePixel().Width();
2002 if (m_pHScroll->IsVisible())
2003 aRet.Height() -= m_pHScroll->GetSizePixel().Height();
2004 return aRet;
2007 bool VclScrolledWindow::set_property(const OString &rKey, const OString &rValue)
2009 bool bRet = VclBin::set_property(rKey, rValue);
2010 m_pVScroll->Show((GetStyle() & WB_VSCROLL) != 0);
2011 m_pHScroll->Show((GetStyle() & WB_HSCROLL) != 0);
2012 return bRet;
2015 bool VclScrolledWindow::EventNotify(NotifyEvent& rNEvt)
2017 bool bDone = false;
2018 if ( rNEvt.GetType() == MouseNotifyEvent::COMMAND )
2020 const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2021 if ( rCEvt.GetCommand() == CommandEventId::Wheel )
2023 const CommandWheelData* pData = rCEvt.GetWheelData();
2024 if( !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) )
2026 bDone = HandleScrollCommand(rCEvt, m_pHScroll, m_pVScroll);
2031 return bDone || VclBin::EventNotify( rNEvt );
2034 void VclViewport::setAllocation(const Size &rAllocation)
2036 vcl::Window *pChild = get_child();
2037 if (pChild && pChild->IsVisible())
2039 Size aReq(getLayoutRequisition(*pChild));
2040 aReq.Width() = std::max(aReq.Width(), rAllocation.Width());
2041 aReq.Height() = std::max(aReq.Height(), rAllocation.Height());
2042 setLayoutAllocation(*pChild, Point(0, 0), aReq);
2046 const vcl::Window *VclEventBox::get_child() const
2048 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
2050 assert(pWindowImpl->mpFirstChild.get() == m_aEventBoxHelper.get());
2052 return pWindowImpl->mpFirstChild->GetWindow(GetWindowType::Next);
2055 vcl::Window *VclEventBox::get_child()
2057 return const_cast<vcl::Window*>(const_cast<const VclEventBox*>(this)->get_child());
2060 void VclEventBox::setAllocation(const Size& rAllocation)
2062 Point aChildPos(0, 0);
2063 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
2065 if (!pChild->IsVisible())
2066 continue;
2067 setLayoutAllocation(*pChild, aChildPos, rAllocation);
2071 Size VclEventBox::calculateRequisition() const
2073 Size aRet(0, 0);
2075 for (const vcl::Window* pChild = get_child(); pChild;
2076 pChild = pChild->GetWindow(GetWindowType::Next))
2078 if (!pChild->IsVisible())
2079 continue;
2080 Size aChildSize = getLayoutRequisition(*pChild);
2081 aRet.Width() = std::max(aRet.Width(), aChildSize.Width());
2082 aRet.Height() = std::max(aRet.Height(), aChildSize.Height());
2085 return aRet;
2088 void VclEventBox::Command(const CommandEvent&)
2090 //discard events by default to block them reaching children
2093 VclEventBox::~VclEventBox()
2095 disposeOnce();
2098 void VclEventBox::dispose()
2100 m_aEventBoxHelper.disposeAndClear();
2101 VclBin::dispose();
2104 void VclSizeGroup::trigger_queue_resize()
2106 //sufficient to trigger one widget to trigger all of them
2107 if (!m_aWindows.empty())
2109 (*m_aWindows.begin())->queue_resize();
2113 void VclSizeGroup::set_ignore_hidden(bool bIgnoreHidden)
2115 if (bIgnoreHidden != m_bIgnoreHidden)
2117 m_bIgnoreHidden = bIgnoreHidden;
2118 trigger_queue_resize();
2122 void VclSizeGroup::set_mode(VclSizeGroupMode eMode)
2124 if (eMode != m_eMode)
2126 m_eMode = eMode;
2127 trigger_queue_resize();
2132 bool VclSizeGroup::set_property(const OString &rKey, const OString &rValue)
2134 if (rKey == "ignore-hidden")
2135 set_ignore_hidden(toBool(rValue));
2136 else if (rKey == "mode")
2138 VclSizeGroupMode eMode = VCL_SIZE_GROUP_HORIZONTAL;
2139 if (rValue.equals("none"))
2140 eMode = VCL_SIZE_GROUP_NONE;
2141 else if (rValue.equals("horizontal"))
2142 eMode = VCL_SIZE_GROUP_HORIZONTAL;
2143 else if (rValue.equals("vertical"))
2144 eMode = VCL_SIZE_GROUP_VERTICAL;
2145 else if (rValue.equals("both"))
2146 eMode = VCL_SIZE_GROUP_BOTH;
2147 else
2149 SAL_WARN("vcl.layout", "unknown size group mode" << rValue.getStr());
2151 set_mode(eMode);
2153 else
2155 SAL_INFO("vcl.layout", "unhandled property: " << rKey.getStr());
2156 return false;
2158 return true;
2161 void MessageDialog::create_owned_areas()
2163 set_border_width(12);
2164 m_pOwnedContentArea.set(VclPtr<VclVBox>::Create(this, false, 24));
2165 set_content_area(m_pOwnedContentArea);
2166 m_pOwnedContentArea->Show();
2167 m_pOwnedActionArea.set( VclPtr<VclHButtonBox>::Create(m_pOwnedContentArea) );
2168 set_action_area(m_pOwnedActionArea);
2169 m_pOwnedActionArea->Show();
2172 MessageDialog::MessageDialog(vcl::Window* pParent, WinBits nStyle)
2173 : Dialog(pParent, nStyle)
2174 , m_eButtonsType(VCL_BUTTONS_NONE)
2175 , m_eMessageType(VclMessageType::Info)
2176 , m_pOwnedContentArea(nullptr)
2177 , m_pOwnedActionArea(nullptr)
2178 , m_pGrid(nullptr)
2179 , m_pImage(nullptr)
2180 , m_pPrimaryMessage(nullptr)
2181 , m_pSecondaryMessage(nullptr)
2183 SetType(WINDOW_MESSBOX);
2186 MessageDialog::MessageDialog(vcl::Window* pParent,
2187 const OUString &rMessage,
2188 VclMessageType eMessageType,
2189 VclButtonsType eButtonsType)
2190 : Dialog(pParent, WB_MOVEABLE | WB_3DLOOK | WB_CLOSEABLE)
2191 , m_eButtonsType(eButtonsType)
2192 , m_eMessageType(eMessageType)
2193 , m_pGrid(nullptr)
2194 , m_pImage(nullptr)
2195 , m_pPrimaryMessage(nullptr)
2196 , m_pSecondaryMessage(nullptr)
2197 , m_sPrimaryString(rMessage)
2199 SetType(WINDOW_MESSBOX);
2200 create_owned_areas();
2203 MessageDialog::MessageDialog(vcl::Window* pParent, const OString& rID, const OUString& rUIXMLDescription)
2204 : Dialog(pParent, OStringToOUString(rID, RTL_TEXTENCODING_UTF8), rUIXMLDescription, WINDOW_MESSBOX)
2205 , m_eButtonsType(VCL_BUTTONS_NONE)
2206 , m_eMessageType(VclMessageType::Info)
2207 , m_pOwnedContentArea(nullptr)
2208 , m_pOwnedActionArea(nullptr)
2209 , m_pGrid(nullptr)
2210 , m_pImage(nullptr)
2211 , m_pPrimaryMessage(nullptr)
2212 , m_pSecondaryMessage(nullptr)
2216 void MessageDialog::dispose()
2218 for (VclPtr<PushButton> & pOwnedButton : m_aOwnedButtons)
2219 pOwnedButton.disposeAndClear();
2220 m_aOwnedButtons.clear();
2222 m_pPrimaryMessage.disposeAndClear();
2223 m_pSecondaryMessage.disposeAndClear();
2224 m_pImage.disposeAndClear();
2225 m_pGrid.disposeAndClear();
2226 m_pOwnedActionArea.disposeAndClear();
2227 m_pOwnedContentArea.disposeAndClear();
2228 m_aResponses.clear();
2229 Dialog::dispose();
2232 MessageDialog::~MessageDialog()
2234 disposeOnce();
2237 void MessageDialog::response(short nResponseId)
2239 EndDialog(nResponseId);
2242 IMPL_LINK(MessageDialog, ButtonHdl, Button *, pButton, void)
2244 response(get_response(pButton));
2247 short MessageDialog::get_response(const vcl::Window *pWindow) const
2249 auto aFind = m_aResponses.find(pWindow);
2250 if (aFind != m_aResponses.end())
2251 return aFind->second;
2252 if (!m_pUIBuilder)
2253 return RET_CANCEL;
2254 return m_pUIBuilder->get_response(pWindow);
2257 void MessageDialog::setButtonHandlers(VclButtonBox *pButtonBox)
2259 assert(pButtonBox);
2260 for (vcl::Window* pChild = pButtonBox->GetWindow(GetWindowType::FirstChild); pChild;
2261 pChild = pChild->GetWindow(GetWindowType::Next))
2263 switch (pChild->GetType())
2265 case WINDOW_PUSHBUTTON:
2267 PushButton* pButton = static_cast<PushButton*>(pChild);
2268 pButton->SetClickHdl(LINK(this, MessageDialog, ButtonHdl));
2269 break;
2271 //insist that the response ids match the default actions for those
2272 //widgets, and leave their default handlers in place
2273 case WINDOW_OKBUTTON:
2274 assert(get_response(pChild) == RET_OK);
2275 break;
2276 case WINDOW_CANCELBUTTON:
2277 assert(get_response(pChild) == RET_CANCEL);
2278 break;
2279 case WINDOW_HELPBUTTON:
2280 assert(get_response(pChild) == RET_HELP);
2281 break;
2282 default:
2283 SAL_WARN("vcl.layout", "The type of widget " <<
2284 pChild->GetHelpId() << " is currently not handled");
2285 break;
2287 //The default is to stick the focus into the first widget
2288 //that accepts it, and if that happens and it's a button
2289 //then that becomes the new default button, so explicitly
2290 //put the focus into the default button
2291 if (pChild->GetStyle() & WB_DEFBUTTON)
2292 pChild->GrabFocus();
2296 void MessageDialog::SetMessagesWidths(vcl::Window *pParent,
2297 VclMultiLineEdit *pPrimaryMessage, VclMultiLineEdit *pSecondaryMessage)
2299 if (pSecondaryMessage)
2301 assert(pPrimaryMessage);
2302 vcl::Font aFont = pParent->GetSettings().GetStyleSettings().GetLabelFont();
2303 aFont.SetFontSize(Size(0, aFont.GetFontSize().Height() * 1.2));
2304 aFont.SetWeight(WEIGHT_BOLD);
2305 pPrimaryMessage->SetControlFont(aFont);
2306 pPrimaryMessage->SetMaxTextWidth(pPrimaryMessage->approximate_char_width() * 44);
2307 pSecondaryMessage->SetMaxTextWidth(pSecondaryMessage->approximate_char_width() * 60);
2309 else
2310 pPrimaryMessage->SetMaxTextWidth(pPrimaryMessage->approximate_char_width() * 60);
2313 void MessageDialog::InitExecute()
2315 setDeferredProperties();
2317 if (!m_pGrid)
2319 VclContainer *pContainer = get_content_area();
2320 assert(pContainer);
2322 m_pGrid.set( VclPtr<VclGrid>::Create(pContainer) );
2323 m_pGrid->reorderWithinParent(0);
2324 m_pGrid->set_column_spacing(12);
2325 m_pGrid->set_row_spacing(GetTextHeight());
2327 m_pImage = VclPtr<FixedImage>::Create(m_pGrid, WB_CENTER | WB_VCENTER | WB_3DLOOK);
2328 switch (m_eMessageType)
2330 case VclMessageType::Info:
2331 m_pImage->SetImage(InfoBox::GetStandardImage());
2332 break;
2333 case VclMessageType::Warning:
2334 m_pImage->SetImage(WarningBox::GetStandardImage());
2335 break;
2336 case VclMessageType::Question:
2337 m_pImage->SetImage(QueryBox::GetStandardImage());
2338 break;
2339 case VclMessageType::Error:
2340 m_pImage->SetImage(ErrorBox::GetStandardImage());
2341 break;
2343 m_pImage->set_grid_left_attach(0);
2344 m_pImage->set_grid_top_attach(0);
2345 m_pImage->set_valign(VclAlign::Start);
2346 m_pImage->Show();
2348 WinBits nWinStyle = WB_CLIPCHILDREN | WB_LEFT | WB_VCENTER | WB_NOLABEL | WB_NOTABSTOP;
2350 bool bHasSecondaryText = !m_sSecondaryString.isEmpty();
2352 m_pPrimaryMessage = VclPtr<VclMultiLineEdit>::Create(m_pGrid, nWinStyle);
2353 m_pPrimaryMessage->SetPaintTransparent(true);
2354 m_pPrimaryMessage->EnableCursor(false);
2356 m_pPrimaryMessage->set_grid_left_attach(1);
2357 m_pPrimaryMessage->set_grid_top_attach(0);
2358 m_pPrimaryMessage->set_hexpand(true);
2359 m_pPrimaryMessage->SetText(m_sPrimaryString);
2360 m_pPrimaryMessage->Show(!m_sPrimaryString.isEmpty());
2362 m_pSecondaryMessage = VclPtr<VclMultiLineEdit>::Create(m_pGrid, nWinStyle);
2363 m_pSecondaryMessage->SetPaintTransparent(true);
2364 m_pSecondaryMessage->EnableCursor(false);
2365 m_pSecondaryMessage->set_grid_left_attach(1);
2366 m_pSecondaryMessage->set_grid_top_attach(1);
2367 m_pSecondaryMessage->set_hexpand(true);
2368 m_pSecondaryMessage->SetText(m_sSecondaryString);
2369 m_pSecondaryMessage->Show(bHasSecondaryText);
2371 MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, bHasSecondaryText ? m_pSecondaryMessage.get() : nullptr);
2373 VclButtonBox *pButtonBox = get_action_area();
2374 assert(pButtonBox);
2376 VclPtr<PushButton> pBtn;
2377 switch (m_eButtonsType)
2379 case VCL_BUTTONS_NONE:
2380 break;
2381 case VCL_BUTTONS_OK:
2382 pBtn.set( VclPtr<OKButton>::Create(pButtonBox) );
2383 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2384 pBtn->Show();
2385 pBtn->set_id("ok");
2386 m_aOwnedButtons.push_back(pBtn);
2387 m_aResponses[pBtn] = RET_OK;
2388 break;
2389 case VCL_BUTTONS_CLOSE:
2390 pBtn.set( VclPtr<CloseButton>::Create(pButtonBox) );
2391 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2392 pBtn->Show();
2393 pBtn->set_id("close");
2394 m_aOwnedButtons.push_back(pBtn);
2395 m_aResponses[pBtn] = RET_CLOSE;
2396 break;
2397 case VCL_BUTTONS_CANCEL:
2398 pBtn.set( VclPtr<CancelButton>::Create(pButtonBox) );
2399 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2400 pBtn->set_id("cancel");
2401 m_aOwnedButtons.push_back(pBtn);
2402 m_aResponses[pBtn] = RET_CANCEL;
2403 break;
2404 case VCL_BUTTONS_YES_NO:
2405 pBtn = VclPtr<PushButton>::Create(pButtonBox);
2406 pBtn->SetText(Button::GetStandardText(StandardButtonType::Yes));
2407 pBtn->Show();
2408 pBtn->set_id("yes");
2409 m_aOwnedButtons.push_back(pBtn);
2410 m_aResponses[pBtn] = RET_YES;
2412 pBtn.set( VclPtr<PushButton>::Create(pButtonBox) );
2413 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2414 pBtn->SetText(Button::GetStandardText(StandardButtonType::No));
2415 pBtn->Show();
2416 pBtn->set_id("no");
2417 m_aOwnedButtons.push_back(pBtn);
2418 m_aResponses[pBtn] = RET_NO;
2419 break;
2420 case VCL_BUTTONS_OK_CANCEL:
2421 pBtn.set( VclPtr<OKButton>::Create(pButtonBox) );
2422 pBtn->Show();
2423 pBtn->set_id("ok");
2424 m_aOwnedButtons.push_back(pBtn);
2425 m_aResponses[pBtn] = RET_OK;
2427 pBtn.set( VclPtr<CancelButton>::Create(pButtonBox) );
2428 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2429 pBtn->Show();
2430 pBtn->set_id("cancel");
2431 m_aOwnedButtons.push_back(pBtn);
2432 m_aResponses[pBtn] = RET_CANCEL;
2433 break;
2435 setButtonHandlers(pButtonBox);
2436 pButtonBox->sort_native_button_order();
2437 m_pGrid->Show();
2441 bool MessageDialog::StartExecuteAsync(const std::function<void(sal_Int32)> &rEndDialogFn)
2443 InitExecute();
2444 return Dialog::StartExecuteAsync(rEndDialogFn);
2447 short MessageDialog::Execute()
2449 InitExecute();
2450 return Dialog::Execute();
2453 OUString const & MessageDialog::get_primary_text() const
2455 const_cast<MessageDialog*>(this)->setDeferredProperties();
2457 return m_sPrimaryString;
2460 OUString const & MessageDialog::get_secondary_text() const
2462 const_cast<MessageDialog*>(this)->setDeferredProperties();
2464 return m_sSecondaryString;
2467 bool MessageDialog::set_property(const OString &rKey, const OString &rValue)
2469 if (rKey == "text")
2470 set_primary_text(OStringToOUString(rValue, RTL_TEXTENCODING_UTF8));
2471 else if (rKey == "secondary-text")
2472 set_secondary_text(OStringToOUString(rValue, RTL_TEXTENCODING_UTF8));
2473 else if (rKey == "message-type")
2475 VclMessageType eMode = VclMessageType::Info;
2476 if (rValue.equals("info"))
2477 eMode = VclMessageType::Info;
2478 else if (rValue.equals("warning"))
2479 eMode = VclMessageType::Warning;
2480 else if (rValue.equals("question"))
2481 eMode = VclMessageType::Question;
2482 else if (rValue.equals("error"))
2483 eMode = VclMessageType::Error;
2484 else
2486 SAL_WARN("vcl.layout", "unknown message type mode" << rValue.getStr());
2488 m_eMessageType = eMode;
2490 else if (rKey == "buttons")
2492 VclButtonsType eMode = VCL_BUTTONS_NONE;
2493 if (rValue.equals("none"))
2494 eMode = VCL_BUTTONS_NONE;
2495 else if (rValue.equals("ok"))
2496 eMode = VCL_BUTTONS_OK;
2497 else if (rValue.equals("cancel"))
2498 eMode = VCL_BUTTONS_CANCEL;
2499 else if (rValue.equals("close"))
2500 eMode = VCL_BUTTONS_CLOSE;
2501 else if (rValue.equals("yes-no"))
2502 eMode = VCL_BUTTONS_YES_NO;
2503 else if (rValue.equals("ok-cancel"))
2504 eMode = VCL_BUTTONS_OK_CANCEL;
2505 else
2507 SAL_WARN("vcl.layout", "unknown buttons type mode" << rValue.getStr());
2509 m_eButtonsType = eMode;
2511 else
2512 return Dialog::set_property(rKey, rValue);
2513 return true;
2516 void MessageDialog::set_primary_text(const OUString &rPrimaryString)
2518 m_sPrimaryString = rPrimaryString;
2519 if (m_pPrimaryMessage)
2521 m_pPrimaryMessage->SetText(m_sPrimaryString);
2522 m_pPrimaryMessage->Show(!m_sPrimaryString.isEmpty());
2526 void MessageDialog::set_secondary_text(const OUString &rSecondaryString)
2528 m_sSecondaryString = rSecondaryString;
2529 if (m_pSecondaryMessage)
2531 m_pSecondaryMessage->SetText("\n" + m_sSecondaryString);
2532 m_pSecondaryMessage->Show(!m_sSecondaryString.isEmpty());
2536 VclVPaned::VclVPaned(vcl::Window *pParent, WinBits nStyle)
2537 : VclContainer(pParent, nStyle)
2538 , m_pSplitter(VclPtr<Splitter>::Create(this, WB_VSCROLL))
2539 , m_nPosition(-1)
2541 m_pSplitter->SetSplitHdl(LINK(this, VclVPaned, SplitHdl));
2542 m_pSplitter->SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFaceColor()));
2543 m_pSplitter->Show();
2546 void VclVPaned::dispose()
2548 m_pSplitter.disposeAndClear();
2549 VclContainer::dispose();
2552 IMPL_LINK(VclVPaned, SplitHdl, Splitter*, pSplitter, void)
2554 double nSize = pSplitter->GetSplitPosPixel();
2555 Size aSplitterSize(m_pSplitter->GetSizePixel());
2556 Size aAllocation(GetSizePixel());
2557 arrange(aAllocation, nSize, aAllocation.Height() - nSize - aSplitterSize.Height());
2560 void VclVPaned::arrange(const Size& rAllocation, long nFirstHeight, long nSecondHeight)
2562 Size aSplitterSize(rAllocation.Width(), getLayoutRequisition(*m_pSplitter).Height());
2563 Size aFirstChildSize(rAllocation.Width(), nFirstHeight);
2564 Size aSecondChildSize(rAllocation.Width(), nSecondHeight);
2565 int nElement = 0;
2566 for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2567 pChild = pChild->GetWindow(GetWindowType::Next))
2569 if (!pChild->IsVisible())
2570 continue;
2571 if (nElement == 0)
2573 Point aSplitterPos(0, aFirstChildSize.Height());
2574 setLayoutAllocation(*m_pSplitter, aSplitterPos, aSplitterSize);
2575 set_position(aSplitterPos.Y() + aSplitterSize.Height() / 2);
2577 else if (nElement == 1)
2579 Point aChildPos(0, 0);
2580 setLayoutAllocation(*pChild, aChildPos, aFirstChildSize);
2582 else if (nElement == 2)
2584 Point aChildPos(0, aFirstChildSize.Height() + aSplitterSize.Height());
2585 setLayoutAllocation(*pChild, aChildPos, aSecondChildSize);
2587 ++nElement;
2591 void VclVPaned::setAllocation(const Size& rAllocation)
2593 //supporting "shrink" could be done by adjusting the allowed drag rectangle
2594 m_pSplitter->SetDragRectPixel(Rectangle(Point(0, 0), rAllocation));
2595 Size aSplitterSize(rAllocation.Width(), getLayoutRequisition(*m_pSplitter).Height());
2596 const long nHeight = rAllocation.Height() - aSplitterSize.Height();
2598 long nFirstHeight = 0;
2599 long nSecondHeight = 0;
2600 bool bFirstCanResize = true;
2601 bool bSecondCanResize = true;
2602 const bool bInitialAllocation = get_position() < 0;
2603 int nElement = 0;
2604 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2605 pChild = pChild->GetWindow(GetWindowType::Next))
2607 if (!pChild->IsVisible())
2608 continue;
2609 if (nElement == 1)
2611 if (bInitialAllocation)
2612 nFirstHeight = getLayoutRequisition(*pChild).Height();
2613 else
2614 nFirstHeight = pChild->GetSizePixel().Height();
2615 bFirstCanResize = pChild->get_expand();
2617 else if (nElement == 2)
2619 if (bInitialAllocation)
2620 nSecondHeight = getLayoutRequisition(*pChild).Height();
2621 else
2622 nSecondHeight = pChild->GetSizePixel().Height();
2623 bSecondCanResize = pChild->get_expand();
2625 ++nElement;
2627 long nHeightRequest = nFirstHeight + nSecondHeight;
2628 long nHeightDiff = nHeight - nHeightRequest;
2629 if (bFirstCanResize == bSecondCanResize)
2630 nFirstHeight += nHeightDiff/2;
2631 else if (bFirstCanResize)
2632 nFirstHeight += nHeightDiff;
2633 arrange(rAllocation, nFirstHeight, nSecondHeight);
2636 Size VclVPaned::calculateRequisition() const
2638 Size aRet(0, 0);
2640 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2641 pChild = pChild->GetWindow(GetWindowType::Next))
2643 if (!pChild->IsVisible())
2644 continue;
2645 Size aChildSize = getLayoutRequisition(*pChild);
2646 aRet.Width() = std::max(aRet.Width(), aChildSize.Width());
2647 aRet.Height() += aChildSize.Height();
2650 return aRet;
2653 Size getLegacyBestSizeForChildren(const vcl::Window &rWindow)
2655 Rectangle aBounds;
2657 for (const vcl::Window* pChild = rWindow.GetWindow(GetWindowType::FirstChild); pChild;
2658 pChild = pChild->GetWindow(GetWindowType::Next))
2660 if (!pChild->IsVisible())
2661 continue;
2663 Rectangle aChildBounds(pChild->GetPosPixel(), pChild->GetSizePixel());
2664 aBounds.Union(aChildBounds);
2667 if (aBounds.IsEmpty())
2668 return rWindow.GetSizePixel();
2670 Size aRet(aBounds.GetSize());
2671 Point aTopLeft(aBounds.TopLeft());
2672 aRet.Width() += aTopLeft.X()*2;
2673 aRet.Height() += aTopLeft.Y()*2;
2675 return aRet;
2678 vcl::Window* getNonLayoutParent(vcl::Window *pWindow)
2680 while (pWindow)
2682 pWindow = pWindow->GetParent();
2683 if (!pWindow || !isContainerWindow(*pWindow))
2684 break;
2686 return pWindow;
2689 bool isVisibleInLayout(const vcl::Window *pWindow)
2691 bool bVisible = true;
2692 while (bVisible)
2694 bVisible = pWindow->IsVisible();
2695 pWindow = pWindow->GetParent();
2696 if (!pWindow || !isContainerWindow(*pWindow))
2697 break;
2699 return bVisible;
2702 bool isEnabledInLayout(const vcl::Window *pWindow)
2704 bool bEnabled = true;
2705 while (bEnabled)
2707 bEnabled = pWindow->IsEnabled();
2708 pWindow = pWindow->GetParent();
2709 if (!pWindow || !isContainerWindow(*pWindow))
2710 break;
2712 return bEnabled;
2715 bool isLayoutEnabled(const vcl::Window *pWindow)
2717 //Child is a container => we're layout enabled
2718 const vcl::Window *pChild = pWindow ? pWindow->GetWindow(GetWindowType::FirstChild) : nullptr;
2719 return pChild && isContainerWindow(*pChild) && !pChild->GetWindow(GetWindowType::Next);
2722 bool isInitialLayout(const vcl::Window *pWindow)
2724 Dialog *pParentDialog = pWindow ? pWindow->GetParentDialog() : nullptr;
2725 return pParentDialog && pParentDialog->isCalculatingInitialLayoutSize();
2728 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */