diff options
author | Caolán McNamara <caolanm@redhat.com> | 2013-01-01 15:13:42 +0000 |
---|---|---|
committer | Miklos Vajna <vmiklos@suse.cz> | 2013-02-06 09:11:19 +0000 |
commit | 62208797e776d4e9533832f9134e5815c1a2e4de (patch) | |
tree | 7615a1b97244405c3250e3165416237e5c6b4425 /vcl | |
parent | 6769538b2e3ff454c4462e64372c50ff9d70df3e (diff) |
implement spread button layout
Change-Id: Ia17d3f4d14319adec6b0b20dced5daf5b8018c36
(cherry picked from commit 5dc0c03f797e53aef7411c26782b6d39b7e93d0c)
Resolves: fdo#59767 detect outlier widths and exclude from size normalization
For non-homogeneous (the default) button boxes we want in general to give all
buttons the same width as the max button width.
But if we detect that certain buttons are > 1.5 the average button width, then
leave those outliers at their natural size and set the rest of the buttons to
the max width of the remainder.
(cherry picked from commit 6e81082dbb2d16f0e61527c5ad13f91d49828125)
Conflicts:
vcl/source/window/layout.cxx
Change-Id: Ice514e741e3a7725d69e150e5752158a1c267141
Reviewed-on: https://gerrit.libreoffice.org/1973
Reviewed-by: Miklos Vajna <vmiklos@suse.cz>
Tested-by: Miklos Vajna <vmiklos@suse.cz>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/vcl/layout.hxx | 14 | ||||
-rw-r--r-- | vcl/source/window/layout.cxx | 195 |
2 files changed, 155 insertions, 54 deletions
diff --git a/vcl/inc/vcl/layout.hxx b/vcl/inc/vcl/layout.hxx index d9c5e6352a7f..3caae71df84d 100644 --- a/vcl/inc/vcl/layout.hxx +++ b/vcl/inc/vcl/layout.hxx @@ -201,9 +201,8 @@ class VCL_DLLPUBLIC VclButtonBox : public VclBox { public: VclButtonBox(Window *pParent, int nSpacing) - : VclBox(pParent, true, nSpacing) + : VclBox(pParent, false, nSpacing) , m_eLayoutStyle(VCL_BUTTONBOX_DEFAULT_STYLE) - , m_bHomogeneousGroups(false) { } void set_layout(VclButtonBoxStyle eStyle) @@ -218,20 +217,15 @@ public: protected: virtual Size calculateRequisition() const; virtual void setAllocation(const Size &rAllocation); + Size addSpacing(const Size &rSize, sal_uInt16 nVisibleChildren) const; private: VclButtonBoxStyle m_eLayoutStyle; - bool m_bHomogeneousGroups; struct Requisition { - sal_uInt16 m_nMainGroupChildren; - sal_uInt16 m_nSubGroupChildren; + std::vector<long> m_aMainGroupDimensions; + std::vector<long> m_aSubGroupDimensions; Size m_aMainGroupSize; Size m_aSubGroupSize; - Requisition() - : m_nMainGroupChildren(0) - , m_nSubGroupChildren(0) - { - } }; Requisition calculatePrimarySecondaryRequisitions() const; Size addReqGroups(const VclButtonBox::Requisition &rReq) const; diff --git a/vcl/source/window/layout.cxx b/vcl/source/window/layout.cxx index 91017d5cb9ca..ad1991411a3c 100644 --- a/vcl/source/window/layout.cxx +++ b/vcl/source/window/layout.cxx @@ -324,17 +324,7 @@ Size VclButtonBox::addReqGroups(const VclButtonBox::Requisition &rReq) const long nMainGroupDimension = getPrimaryDimension(rReq.m_aMainGroupSize); long nSubGroupDimension = getPrimaryDimension(rReq.m_aSubGroupSize); - assert(m_bHomogeneous); - - if (m_bHomogeneousGroups) - setPrimaryDimension(aRet, std::max(nMainGroupDimension, nSubGroupDimension)); - else - { - setPrimaryDimension(aRet, - (rReq.m_nMainGroupChildren * nMainGroupDimension - + rReq.m_nSubGroupChildren * nSubGroupDimension) / - (rReq.m_nMainGroupChildren + rReq.m_nSubGroupChildren)); - } + setPrimaryDimension(aRet, nMainGroupDimension + nSubGroupDimension); setSecondaryDimension(aRet, std::max(getSecondaryDimension(rReq.m_aMainGroupSize), @@ -343,6 +333,40 @@ Size VclButtonBox::addReqGroups(const VclButtonBox::Requisition &rReq) const return aRet; } +static long getMaxNonOutlier(const std::vector<long> &rG, long nAvgDimension) +{ + long nMaxDimensionNonOutlier = 0; + for (std::vector<long>::const_iterator aI = rG.begin(), + aEnd = rG.end(); aI != aEnd; ++aI) + { + long nPrimaryChildDimension = *aI; + if (nPrimaryChildDimension <= nAvgDimension * 1.5) + { + nMaxDimensionNonOutlier = std::max(nPrimaryChildDimension, + nMaxDimensionNonOutlier); + } + } + return nMaxDimensionNonOutlier; +} + +static std::vector<long> setButtonSizes(const std::vector<long> &rG, + long nAvgDimension, long nMaxNonOutlier) +{ + std::vector<long> aVec; + //set everything < 1.5 times the average to the same width, leave the + //outliers un-touched + for (std::vector<long>::const_iterator aI = rG.begin(), aEnd = rG.end(); + aI != aEnd; ++aI) + { + long nPrimaryChildDimension = *aI; + if (nPrimaryChildDimension <= nAvgDimension * 1.5) + aVec.push_back(nMaxNonOutlier); + else + aVec.push_back(nPrimaryChildDimension); + } + return aVec; +} + VclButtonBox::Requisition VclButtonBox::calculatePrimarySecondaryRequisitions() const { Requisition aReq; @@ -350,36 +374,110 @@ VclButtonBox::Requisition VclButtonBox::calculatePrimarySecondaryRequisitions() Size aMainGroupSize(DEFAULT_CHILD_MIN_WIDTH, DEFAULT_CHILD_MIN_HEIGHT); //to-do, pull from theme Size aSubGroupSize(DEFAULT_CHILD_MIN_WIDTH, DEFAULT_CHILD_MIN_HEIGHT); //to-do, pull from theme + long nMinMainGroupPrimary = getPrimaryDimension(aMainGroupSize); + long nMinSubGroupPrimary = getPrimaryDimension(aSubGroupSize); + long nMainGroupSecondary = getSecondaryDimension(aMainGroupSize); + long nSubGroupSecondary = getSecondaryDimension(aSubGroupSize); + + bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VCL_BUTTONBOX_SPREAD || m_eLayoutStyle == VCL_BUTTONBOX_CENTER); + + std::vector<long> aMainGroupSizes; + std::vector<long> aSubGroupSizes; + for (const Window *pChild = GetWindow(WINDOW_FIRSTCHILD); pChild; pChild = pChild->GetWindow(WINDOW_NEXT)) { if (!pChild->IsVisible()) continue; Size aChildSize = getLayoutRequisition(*pChild); - if (!pChild->get_secondary()) + if (bIgnoreSecondaryPacking || !pChild->get_secondary()) { - ++aReq.m_nMainGroupChildren; - accumulateMaxes(aChildSize, aMainGroupSize); + //set the max secondary dimension + nMainGroupSecondary = std::max(nMainGroupSecondary, getSecondaryDimension(aChildSize)); + //collect the primary dimensions + aMainGroupSizes.push_back(std::max(nMinMainGroupPrimary, getPrimaryDimension(aChildSize))); } else { - ++aReq.m_nSubGroupChildren; - accumulateMaxes(aChildSize, aSubGroupSize); + nSubGroupSecondary = std::max(nSubGroupSecondary, getSecondaryDimension(aChildSize)); + aSubGroupSizes.push_back(std::max(nMinSubGroupPrimary, getPrimaryDimension(aChildSize))); } } - if (aReq.m_nMainGroupChildren) - aReq.m_aMainGroupSize = aMainGroupSize; - if (aReq.m_nSubGroupChildren) - aReq.m_aSubGroupSize = aSubGroupSize; + if (m_bHomogeneous) + { + long nMaxMainDimension = aMainGroupSizes.empty() ? 0 : + *std::max_element(aMainGroupSizes.begin(), aMainGroupSizes.end()); + long nMaxSubDimension = aSubGroupSizes.empty() ? 0 : + *std::max_element(aSubGroupSizes.begin(), aSubGroupSizes.end()); + long nMaxDimension = std::max(nMaxMainDimension, nMaxSubDimension); + aReq.m_aMainGroupDimensions.resize(aMainGroupSizes.size(), nMaxDimension); + aReq.m_aSubGroupDimensions.resize(aSubGroupSizes.size(), nMaxDimension); + } + else + { + //Ideally set everything to the same size, but find outlier widgets + //that are way wider than the average and leave them + //at their natural size and set the remainder to share the + //max size of the remaining members of the buttonbox + long nAccDimension = std::accumulate(aMainGroupSizes.begin(), + aMainGroupSizes.end(), 0); + nAccDimension = std::accumulate(aSubGroupSizes.begin(), + aSubGroupSizes.end(), nAccDimension); + + long nAvgDimension = nAccDimension / + (aMainGroupSizes.size() + aSubGroupSizes.size()); + + long nMaxMainNonOutlier = getMaxNonOutlier(aMainGroupSizes, + nAvgDimension); + long nMaxSubNonOutlier = getMaxNonOutlier(aSubGroupSizes, + nAvgDimension); + long nMaxNonOutlier = std::max(nMaxMainNonOutlier, nMaxSubNonOutlier); + + aReq.m_aMainGroupDimensions = setButtonSizes(aMainGroupSizes, + nAvgDimension, nMaxNonOutlier); + aReq.m_aSubGroupDimensions = setButtonSizes(aSubGroupSizes, + nAvgDimension, nMaxNonOutlier); + } + + if (!aReq.m_aMainGroupDimensions.empty()) + { + setSecondaryDimension(aReq.m_aMainGroupSize, nMainGroupSecondary); + setPrimaryDimension(aReq.m_aMainGroupSize, + std::accumulate(aReq.m_aMainGroupDimensions.begin(), + aReq.m_aMainGroupDimensions.end(), 0)); + } + if (!aReq.m_aSubGroupDimensions.empty()) + { + setSecondaryDimension(aReq.m_aSubGroupSize, nSubGroupSecondary); + setPrimaryDimension(aReq.m_aSubGroupSize, + std::accumulate(aReq.m_aSubGroupDimensions.begin(), + aReq.m_aSubGroupDimensions.end(), 0)); + } return aReq; } +Size VclButtonBox::addSpacing(const Size &rSize, sal_uInt16 nVisibleChildren) const +{ + Size aRet; + + if (nVisibleChildren) + { + long nPrimaryDimension = getPrimaryDimension(rSize); + setPrimaryDimension(aRet, + nPrimaryDimension + m_nSpacing * (nVisibleChildren-1)); + setSecondaryDimension(aRet, getSecondaryDimension(rSize)); + } + + return aRet; +} + Size VclButtonBox::calculateRequisition() const { Requisition aReq(calculatePrimarySecondaryRequisitions()); - sal_uInt16 nVisibleChildren = aReq.m_nMainGroupChildren + aReq.m_nSubGroupChildren; - return finalizeMaxes(addReqGroups(aReq), nVisibleChildren); + sal_uInt16 nVisibleChildren = aReq.m_aMainGroupDimensions.size() + + aReq.m_aSubGroupDimensions.size(); + return addSpacing(addReqGroups(aReq), nVisibleChildren); } bool VclButtonBox::set_property(const rtl::OString &rKey, const rtl::OString &rValue) @@ -405,8 +503,6 @@ bool VclButtonBox::set_property(const rtl::OString &rKey, const rtl::OString &rV } set_layout(eStyle); } - else if (rKey.equalsL(RTL_CONSTASCII_STRINGPARAM("homogeneous"))) - m_bHomogeneousGroups = toBool(rValue); else return VclBox::set_property(rKey, rValue); return true; @@ -416,39 +512,45 @@ void VclButtonBox::setAllocation(const Size &rAllocation) { Requisition aReq(calculatePrimarySecondaryRequisitions()); - sal_uInt16 nVisibleChildren = aReq.m_nMainGroupChildren + aReq.m_nSubGroupChildren; - if (!nVisibleChildren) + if (aReq.m_aMainGroupDimensions.empty() && aReq.m_aSubGroupDimensions.empty()) return; long nAllocPrimaryDimension = getPrimaryDimension(rAllocation); - long nMainGroupPrimaryDimension = getPrimaryDimension(aReq.m_aMainGroupSize); - long nSubGroupPrimaryDimension = getPrimaryDimension(aReq.m_aSubGroupSize); - if (m_bHomogeneousGroups) - nSubGroupPrimaryDimension = nMainGroupPrimaryDimension = std::max(nSubGroupPrimaryDimension, nMainGroupPrimaryDimension); - Point aMainGroupPos, aOtherGroupPos; + int nSpacing = m_nSpacing; //To-Do, other layout styles switch (m_eLayoutStyle) { case VCL_BUTTONBOX_START: - if (aReq.m_nSubGroupChildren) + if (!aReq.m_aSubGroupDimensions.empty()) { long nOtherPrimaryDimension = getPrimaryDimension( - finalizeMaxes(aReq.m_aSubGroupSize, aReq.m_nSubGroupChildren)); + addSpacing(aReq.m_aSubGroupSize, aReq.m_aSubGroupDimensions.size())); setPrimaryCoordinate(aOtherGroupPos, nAllocPrimaryDimension - nOtherPrimaryDimension); } break; + case VCL_BUTTONBOX_SPREAD: + if (!aReq.m_aMainGroupDimensions.empty()) + { + long nMainPrimaryDimension = getPrimaryDimension( + addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size())); + long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension; + nExtraSpace += (aReq.m_aMainGroupDimensions.size()-1) * nSpacing; + nSpacing = nExtraSpace/(aReq.m_aMainGroupDimensions.size()+1); + setPrimaryCoordinate(aMainGroupPos, nSpacing); + } + break; default: SAL_WARN("vcl.layout", "todo unimplemented layout style"); case VCL_BUTTONBOX_DEFAULT_STYLE: case VCL_BUTTONBOX_END: - if (aReq.m_nMainGroupChildren) + if (!aReq.m_aMainGroupDimensions.empty()) { long nMainPrimaryDimension = getPrimaryDimension( - finalizeMaxes(aReq.m_aMainGroupSize, aReq.m_nMainGroupChildren)); + addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size())); setPrimaryCoordinate(aMainGroupPos, nAllocPrimaryDimension - nMainPrimaryDimension); } @@ -458,24 +560,29 @@ void VclButtonBox::setAllocation(const Size &rAllocation) Size aChildSize; setSecondaryDimension(aChildSize, getSecondaryDimension(rAllocation)); + std::vector<long>::const_iterator aPrimaryI = aReq.m_aMainGroupDimensions.begin(); + std::vector<long>::const_iterator aSecondaryI = aReq.m_aSubGroupDimensions.begin(); + bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VCL_BUTTONBOX_SPREAD || m_eLayoutStyle == VCL_BUTTONBOX_CENTER); for (Window *pChild = GetWindow(WINDOW_FIRSTCHILD); pChild; pChild = pChild->GetWindow(WINDOW_NEXT)) { if (!pChild->IsVisible()) continue; - if (pChild->get_secondary()) - { - setPrimaryDimension(aChildSize, nSubGroupPrimaryDimension); - setLayoutAllocation(*pChild, aOtherGroupPos, aChildSize); - long nPrimaryCoordinate = getPrimaryCoordinate(aOtherGroupPos); - setPrimaryCoordinate(aOtherGroupPos, nPrimaryCoordinate + nSubGroupPrimaryDimension + m_nSpacing); - } - else + if (bIgnoreSecondaryPacking || !pChild->get_secondary()) { + long nMainGroupPrimaryDimension = *aPrimaryI++; setPrimaryDimension(aChildSize, nMainGroupPrimaryDimension); setLayoutAllocation(*pChild, aMainGroupPos, aChildSize); long nPrimaryCoordinate = getPrimaryCoordinate(aMainGroupPos); - setPrimaryCoordinate(aMainGroupPos, nPrimaryCoordinate + nMainGroupPrimaryDimension + m_nSpacing); + setPrimaryCoordinate(aMainGroupPos, nPrimaryCoordinate + nMainGroupPrimaryDimension + nSpacing); + } + else + { + long nSubGroupPrimaryDimension = *aSecondaryI++; + setPrimaryDimension(aChildSize, nSubGroupPrimaryDimension); + setLayoutAllocation(*pChild, aOtherGroupPos, aChildSize); + long nPrimaryCoordinate = getPrimaryCoordinate(aOtherGroupPos); + setPrimaryCoordinate(aOtherGroupPos, nPrimaryCoordinate + nSubGroupPrimaryDimension + nSpacing); } } } |