diff options
author | Caolán McNamara <caolanm@redhat.com> | 2012-02-01 10:12:42 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2012-09-28 08:48:07 +0100 |
commit | 5e5f693a14e788862ff65ed6976a9c336596cfea (patch) | |
tree | 2b7d78b9ca568803a9b333365efc26cd9eea1b75 | |
parent | 3aaeca4c1b7a67fc33208fdf63d30de8af53049e (diff) |
add a grid container
-rw-r--r-- | vcl/inc/vcl/layout.hxx | 62 | ||||
-rw-r--r-- | vcl/source/window/layout.cxx | 180 |
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; |