[Libreoffice-commits] core.git: Branch 'libreoffice-4-0' - vcl/inc vcl/source

Caolán McNamara caolanm at redhat.com
Wed Feb 6 01:11:38 PST 2013


 vcl/inc/vcl/layout.hxx       |   14 ---
 vcl/source/window/layout.cxx |  195 +++++++++++++++++++++++++++++++++----------
 2 files changed, 155 insertions(+), 54 deletions(-)

New commits:
commit 62208797e776d4e9533832f9134e5815c1a2e4de
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue Jan 1 15:13:42 2013 +0000

    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 at suse.cz>
    Tested-by: Miklos Vajna <vmiklos at suse.cz>

diff --git a/vcl/inc/vcl/layout.hxx b/vcl/inc/vcl/layout.hxx
index d9c5e63..3caae71 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 91017d5..ad19914 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);
         }
     }
 }


More information about the Libreoffice-commits mailing list