summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2013-01-01 15:13:42 +0000
committerMiklos Vajna <vmiklos@suse.cz>2013-02-06 09:11:19 +0000
commit62208797e776d4e9533832f9134e5815c1a2e4de (patch)
tree7615a1b97244405c3250e3165416237e5c6b4425 /vcl
parent6769538b2e3ff454c4462e64372c50ff9d70df3e (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.hxx14
-rw-r--r--vcl/source/window/layout.cxx195
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);
}
}
}