Date: prev next · Thread: first prev next last
2013 Archives by date, by thread · List index


Hi,

I have submitted a patch for review:

    https://gerrit.libreoffice.org/1973

To pull it, you can do:

    git pull ssh://gerrit.libreoffice.org:29418/core refs/changes/73/1973/1

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
---
M vcl/inc/vcl/layout.hxx
M vcl/source/window/layout.cxx
2 files changed, 155 insertions(+), 54 deletions(-)



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 @@
 {
 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 @@
 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,23 +324,47 @@
     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),
         getSecondaryDimension(rReq.m_aSubGroupSize)));
 
     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
@@ -350,36 +374,110 @@
     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 @@
         }
         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 @@
 {
     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 @@
     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())
+        if (bIgnoreSecondaryPacking || !pChild->get_secondary())
         {
-            setPrimaryDimension(aChildSize, nSubGroupPrimaryDimension);
-            setLayoutAllocation(*pChild, aOtherGroupPos, aChildSize);
-            long nPrimaryCoordinate = getPrimaryCoordinate(aOtherGroupPos);
-            setPrimaryCoordinate(aOtherGroupPos, nPrimaryCoordinate + nSubGroupPrimaryDimension + 
m_nSpacing);
-        }
-        else
-        {
+            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);
         }
     }
 }

-- 
To view, visit https://gerrit.libreoffice.org/1973
To unsubscribe, visit https://gerrit.libreoffice.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ice514e741e3a7725d69e150e5752158a1c267141
Gerrit-PatchSet: 1
Gerrit-Project: core
Gerrit-Branch: libreoffice-4-0
Gerrit-Owner: Caolán McNamara <caolanm@redhat.com>

Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.