summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2012-02-01 10:12:42 +0000
committerCaolán McNamara <caolanm@redhat.com>2012-09-28 08:48:07 +0100
commit5e5f693a14e788862ff65ed6976a9c336596cfea (patch)
tree2b7d78b9ca568803a9b333365efc26cd9eea1b75
parent3aaeca4c1b7a67fc33208fdf63d30de8af53049e (diff)
add a grid container
-rw-r--r--vcl/inc/vcl/layout.hxx62
-rw-r--r--vcl/source/window/layout.cxx180
2 files changed, 242 insertions, 0 deletions
diff --git a/vcl/inc/vcl/layout.hxx b/vcl/inc/vcl/layout.hxx
index 0aacc2db6bf0..9d15468bac3b 100644
--- a/vcl/inc/vcl/layout.hxx
+++ b/vcl/inc/vcl/layout.hxx
@@ -30,6 +30,7 @@
#include <vcl/dllapi.h>
#include <vcl/window.hxx>
+#include <boost/multi_array.hpp>
enum VclPackType
{
@@ -248,6 +249,67 @@ protected:
}
};
+class VCL_DLLPUBLIC Grid : public Window
+{
+private:
+ bool m_bRowHomogeneous;
+ bool m_bColumnHomogeneous;
+ int m_nRowSpacing;
+ int m_nColumnSpacing;
+ typedef boost::multi_array<Window*, 2> array_type;
+
+ array_type assembleGrid() const;
+ bool isNullGrid(const array_type& A) const;
+ void calcMaxs(const array_type &A, std::vector<long> &rWidths, std::vector<long> &rHeights) const;
+
+ Size calculateRequisition() const;
+ void setAllocation(const Size &rAllocation);
+public:
+ Grid(Window *pParent)
+ : Window(pParent)
+ , m_bRowHomogeneous(false), m_bColumnHomogeneous(false)
+ , m_nRowSpacing(0), m_nColumnSpacing(0)
+ {
+ Show();
+ }
+ void set_row_homogeneous(bool bHomogeneous)
+ {
+ m_bRowHomogeneous = bHomogeneous;
+ }
+ void set_column_homogeneous(bool bHomogeneous)
+ {
+ m_bColumnHomogeneous = bHomogeneous;
+ }
+ bool get_row_homogeneous() const
+ {
+ return m_bRowHomogeneous;
+ }
+ bool get_column_homogeneous() const
+ {
+ return m_bColumnHomogeneous;
+ }
+ void set_row_spacing(int nSpacing)
+ {
+ m_nRowSpacing = nSpacing;
+ }
+ void set_column_spacing(int nSpacing)
+ {
+ m_nColumnSpacing = nSpacing;
+ }
+ int get_row_spacing() const
+ {
+ return m_nRowSpacing;
+ }
+ int get_column_spacing() const
+ {
+ return m_nColumnSpacing;
+ }
+public:
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+ using Window::SetPosSizePixel;
+ virtual void SetPosSizePixel(const Point& rNewPos, const Size& rNewSize);
+};
+
//Get a Size which is large enough to contain all children with
//an equal amount of space at top left and bottom right
Size getLegacyBestSizeForChildren(const Window &rWindow);
diff --git a/vcl/source/window/layout.cxx b/vcl/source/window/layout.cxx
index cfa8324f804d..0a558f3808ae 100644
--- a/vcl/source/window/layout.cxx
+++ b/vcl/source/window/layout.cxx
@@ -318,6 +318,186 @@ void ButtonBox::setAllocation(const Size &rAllocation)
}
}
+Grid::array_type Grid::assembleGrid() const
+{
+ array_type A;
+
+ rtl::OString sLeftAttach(RTL_CONSTASCII_STRINGPARAM("left-attach"));
+ rtl::OString sWidth(RTL_CONSTASCII_STRINGPARAM("width"));
+ rtl::OString sTopAttach(RTL_CONSTASCII_STRINGPARAM("top-attach"));
+ rtl::OString sHeight(RTL_CONSTASCII_STRINGPARAM("height"));
+
+ int i = 0;
+
+ for (Window* pChild = GetWindow(WINDOW_FIRSTCHILD); pChild;
+ pChild = pChild->GetWindow(WINDOW_NEXT))
+ {
+ if (!pChild->IsVisible())
+ continue;
+
+ sal_Int32 nLeftAttach = pChild->getWidgetProperty<sal_Int32>(sLeftAttach);
+ sal_Int32 nWidth = pChild->getWidgetProperty<sal_Int32>(sWidth, 1);
+ sal_Int32 nMaxXPos = nLeftAttach+nWidth-1;
+
+ sal_Int32 nTopAttach = pChild->getWidgetProperty<sal_Int32>(sTopAttach);
+ sal_Int32 nHeight = pChild->getWidgetProperty<sal_Int32>(sHeight, 1);
+ sal_Int32 nMaxYPos = nTopAttach+nHeight-1;
+
+ sal_Int32 nCurrentMaxXPos = A.shape()[0]-1;
+ sal_Int32 nCurrentMaxYPos = A.shape()[1]-1;
+ if (nMaxXPos > nCurrentMaxXPos || nMaxYPos > nCurrentMaxYPos)
+ {
+ nCurrentMaxXPos = std::max(nMaxXPos, nCurrentMaxXPos);
+ nCurrentMaxYPos = std::max(nMaxYPos, nCurrentMaxYPos);
+ A.resize(boost::extents[nCurrentMaxXPos+1][nCurrentMaxYPos+1]);
+ }
+
+ A[nLeftAttach][nTopAttach] = pChild;
+ }
+
+ return A;
+}
+
+bool Grid::isNullGrid(const array_type &A) const
+{
+ sal_Int32 nMaxX = A.shape()[0];
+ sal_Int32 nMaxY = A.shape()[1];
+
+ if (!nMaxX || !nMaxY)
+ return true;
+ return false;
+}
+
+void Grid::calcMaxs(const array_type &A, std::vector<long> &rWidths, std::vector<long> &rHeights) const
+{
+ sal_Int32 nMaxX = A.shape()[0];
+ sal_Int32 nMaxY = A.shape()[1];
+
+ rWidths.resize(nMaxX);
+ rHeights.resize(nMaxY);
+
+ for (sal_Int32 x = 0; x < nMaxX; ++x)
+ {
+ for (sal_Int32 y = 0; y < nMaxY; ++y)
+ {
+ const Window *pChild = A[x][y];
+ if (!pChild)
+ continue;
+ Size aChildSize = pChild->GetOptimalSize(WINDOWSIZE_PREFERRED);
+ rWidths[x] = std::max(rWidths[x], aChildSize.Width());
+ rHeights[y] = std::max(rHeights[y], aChildSize.Height());
+ }
+ }
+}
+
+Size Grid::GetOptimalSize(WindowSizeType eType) const
+{
+ if (eType == WINDOWSIZE_MAXIMUM)
+ return Window::GetOptimalSize(eType);
+ return calculateRequisition();
+}
+
+//To-Do, col/row spanning ignored for now
+Size Grid::calculateRequisition() const
+{
+ array_type A = assembleGrid();
+
+ if (isNullGrid(A))
+ return Size();
+
+ std::vector<long> aWidths;
+ std::vector<long> aHeights;
+ calcMaxs(A, aWidths, aHeights);
+
+ long nTotalWidth = 0;
+ if (get_column_homogeneous())
+ {
+ nTotalWidth = *std::max_element(aWidths.begin(), aWidths.end());
+ nTotalWidth *= aWidths.size();
+ }
+ else
+ {
+ nTotalWidth = std::accumulate(aWidths.begin(), aWidths.end(), 0);
+ }
+
+ nTotalWidth += get_column_spacing() * (aWidths.size()-1);
+
+ long nTotalHeight = 0;
+ if (get_row_homogeneous())
+ {
+ nTotalHeight = *std::max_element(aHeights.begin(), aHeights.end());
+ nTotalHeight *= aHeights.size();
+ }
+ else
+ {
+ nTotalHeight = std::accumulate(aHeights.begin(), aHeights.end(), 0);
+ }
+
+ nTotalHeight += get_row_spacing() * (aHeights.size()-1);
+
+ return Size(nTotalWidth, nTotalHeight);
+}
+
+void Grid::SetPosSizePixel(const Point& rAllocPos, const Size& rAllocation)
+{
+ Window::SetPosSizePixel(rAllocPos, rAllocation);
+ setAllocation(rAllocation);
+}
+
+void Grid::setAllocation(const Size& rAllocation)
+{
+ array_type A = assembleGrid();
+
+ if (isNullGrid(A))
+ return;
+
+ sal_Int32 nMaxX = A.shape()[0];
+ sal_Int32 nMaxY = A.shape()[1];
+
+ Size aRequisition;
+ std::vector<long> aWidths(nMaxX);
+ std::vector<long> aHeights(nMaxY);
+ if (!get_column_homogeneous() || !get_row_homogeneous())
+ {
+ aRequisition = calculateRequisition();
+ calcMaxs(A, aWidths, aHeights);
+ }
+
+ long nAvailableWidth = rAllocation.Width() - (get_column_spacing() * nMaxX);
+ if (get_column_homogeneous())
+ std::fill(aWidths.begin(), aWidths.end(), nAvailableWidth/nMaxX);
+ else
+ {
+ long nExtraWidth = (rAllocation.Width() - aRequisition.Width()) / nMaxX;
+ for (sal_Int32 x = 0; x < nMaxX; ++x)
+ aWidths[x] += nExtraWidth;
+ }
+
+ long nAvailableHeight = rAllocation.Height() - (get_row_spacing() * nMaxY);
+ if (get_row_homogeneous())
+ std::fill(aHeights.begin(), aHeights.end(), nAvailableHeight/nMaxY);
+ else
+ {
+ long nExtraHeight = (rAllocation.Height() - aRequisition.Height()) / nMaxY;
+ for (sal_Int32 y = 0; y < nMaxY; ++y)
+ aHeights[y] += nExtraHeight;
+ }
+
+ Point aPosition(0, 0);
+ for (sal_Int32 x = 0; x < nMaxX; ++x)
+ {
+ for (sal_Int32 y = 0; y < nMaxY; ++y)
+ {
+ Window *pChild = A[x][y];
+ if (pChild)
+ pChild->SetPosSizePixel(aPosition, Size(aWidths[x], aHeights[y]));
+ aPosition.Y() += aHeights[y] + get_row_spacing();
+ }
+ aPosition.X() += aWidths[x] + get_column_spacing();
+ aPosition.Y() = 0;
+ }
+}
+
Size getLegacyBestSizeForChildren(const Window &rWindow)
{
Rectangle aBounds;