diff options
author | Caolán McNamara <caolanm@redhat.com> | 2013-02-01 07:24:16 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2013-02-02 10:15:14 +0000 |
commit | 6e81082dbb2d16f0e61527c5ad13f91d49828125 (patch) | |
tree | b995e2bd50c3ea75aa3f161ea1fcadb5321f0c6c /vcl/source | |
parent | c28c3c55c4bf672aa9f8028deb9891ae49b625e1 (diff) |
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.
Change-Id: Ice514e741e3a7725d69e150e5752158a1c267141
Diffstat (limited to 'vcl/source')
-rw-r--r-- | vcl/source/window/layout.cxx | 168 |
1 files changed, 130 insertions, 38 deletions
diff --git a/vcl/source/window/layout.cxx b/vcl/source/window/layout.cxx index 87c87d4c1b63..8f6893e293fe 100644 --- a/vcl/source/window/layout.cxx +++ b/vcl/source/window/layout.cxx @@ -333,17 +333,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), @@ -352,6 +342,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; @@ -359,8 +383,16 @@ 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()) @@ -368,29 +400,93 @@ VclButtonBox::Requisition VclButtonBox::calculatePrimarySecondaryRequisitions() Size aChildSize = getLayoutRequisition(*pChild); 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) @@ -414,8 +510,6 @@ bool VclButtonBox::set_property(const rtl::OString &rKey, const rtl::OString &rV } set_layout(eStyle); } - else if (rKey == "homogeneous") - m_bHomogeneousGroups = toBool(rValue); else return VclBox::set_property(rKey, rValue); return true; @@ -425,17 +519,11 @@ 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; @@ -443,22 +531,22 @@ void VclButtonBox::setAllocation(const Size &rAllocation) 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_nMainGroupChildren) + if (!aReq.m_aMainGroupDimensions.empty()) { long nMainPrimaryDimension = getPrimaryDimension( - finalizeMaxes(aReq.m_aMainGroupSize, aReq.m_nMainGroupChildren)); + addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size())); long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension; - nExtraSpace += (aReq.m_nMainGroupChildren-1) * nSpacing; - nSpacing = nExtraSpace/(aReq.m_nMainGroupChildren+1); + nExtraSpace += (aReq.m_aMainGroupDimensions.size()-1) * nSpacing; + nSpacing = nExtraSpace/(aReq.m_aMainGroupDimensions.size()+1); setPrimaryCoordinate(aMainGroupPos, nSpacing); } break; @@ -466,10 +554,10 @@ void VclButtonBox::setAllocation(const Size &rAllocation) 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); } @@ -479,6 +567,8 @@ 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)) { @@ -487,6 +577,7 @@ void VclButtonBox::setAllocation(const Size &rAllocation) if (bIgnoreSecondaryPacking || !pChild->get_secondary()) { + long nMainGroupPrimaryDimension = *aPrimaryI++; setPrimaryDimension(aChildSize, nMainGroupPrimaryDimension); setLayoutAllocation(*pChild, aMainGroupPos, aChildSize); long nPrimaryCoordinate = getPrimaryCoordinate(aMainGroupPos); @@ -494,6 +585,7 @@ void VclButtonBox::setAllocation(const Size &rAllocation) } else { + long nSubGroupPrimaryDimension = *aSecondaryI++; setPrimaryDimension(aChildSize, nSubGroupPrimaryDimension); setLayoutAllocation(*pChild, aOtherGroupPos, aChildSize); long nPrimaryCoordinate = getPrimaryCoordinate(aOtherGroupPos); |