diff options
Diffstat (limited to 'sd/source/ui/slidesorter/view/SlsLayouter.cxx')
-rw-r--r--[-rwxr-xr-x] | sd/source/ui/slidesorter/view/SlsLayouter.cxx | 1684 |
1 files changed, 1239 insertions, 445 deletions
diff --git a/sd/source/ui/slidesorter/view/SlsLayouter.cxx b/sd/source/ui/slidesorter/view/SlsLayouter.cxx index 3767a655c48b..ee81dbc45202 100755..100644 --- a/sd/source/ui/slidesorter/view/SlsLayouter.cxx +++ b/sd/source/ui/slidesorter/view/SlsLayouter.cxx @@ -28,38 +28,304 @@ #include "precompiled_sd.hxx" #include "view/SlsLayouter.hxx" - -#include <vcl/outdev.hxx> +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "Window.hxx" #include <rtl/math.hxx> +#include <basegfx/numeric/ftools.hxx> + +namespace { + sal_Int32 RoundToInt (const double nValue) + { + return sal_Int32(::rtl::math::round(nValue)); + } +} + namespace sd { namespace slidesorter { namespace view { -Layouter::Layouter (void) - : mnRequestedLeftBorder(10), - mnRequestedRightBorder(10), - mnRequestedTopBorder(10), - mnRequestedBottomBorder(10), - mnLeftBorder(10), - mnRightBorder(10), - mnTopBorder(10), - mnBottomBorder(10), - mnLeftPageBorder(0), - mnRightPageBorder(0), - mnTopPageBorder(0), - mnBottomPageBorder(0), - mnVerticalGap (20), - mnHorizontalGap (20), - mnInsertionMarkerThickness (4), - mnTotalVerticalGap(0), - mnTotalHorizontalGap(0), - mnMinimalWidth (100), - mnPreferredWidth (200), - mnMaximalWidth (300), - mnMinimalColumnCount (1), - mnMaximalColumnCount (5), - mnColumnCount (1), - maPageObjectModelSize (1,1), - maPageObjectPixelSize (1,1) +class Layouter::Implementation +{ +public: + SharedSdWindow mpWindow; + sal_Int32 mnRequestedLeftBorder; + sal_Int32 mnRequestedRightBorder; + sal_Int32 mnRequestedTopBorder; + sal_Int32 mnRequestedBottomBorder; + sal_Int32 mnLeftBorder; + sal_Int32 mnRightBorder; + sal_Int32 mnTopBorder; + sal_Int32 mnBottomBorder; + sal_Int32 mnVerticalGap; + sal_Int32 mnHorizontalGap; + Size maMinimalSize; + Size maPreferredSize; + Size maMaximalSize; + sal_Int32 mnMinimalColumnCount; + sal_Int32 mnMaximalColumnCount; + sal_Int32 mnPageCount; + sal_Int32 mnColumnCount; + sal_Int32 mnRowCount; + /// The maximum number of columns. Can only be larger than the current + /// number of columns when there are not enough pages to fill all + /// available columns. + sal_Int32 mnMaxColumnCount; + /// The maximum number of rows. Can only be larger than the current + /// number of rows when there are not enough pages to fill all available + /// rows. + sal_Int32 mnMaxRowCount; + Size maPageObjectSize; + ::boost::shared_ptr<PageObjectLayouter> mpPageObjectLayouter; + ::boost::shared_ptr<view::Theme> mpTheme; + + /** Specify how the gap between two page objects is associated with the + page objects. + */ + enum GapMembership { + GM_NONE, // Gap is not associated with any page object. + GM_PREVIOUS, // The whole gap is associated with the previous page + // object (left or above the gap.) + GM_BOTH, // Half of the gap is associated with previous, half + // with the next page object. + GM_NEXT, // The whole gap is associated with the next page + // object (right or below the gap.) + GM_PAGE_BORDER + }; + + static Implementation* Create ( + const Implementation& rImplementation, + const Layouter::Orientation eOrientation); + + virtual Layouter::Orientation GetOrientation (void) const = 0; + + bool Rearrange ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const sal_uInt32 nPageCount); + + /** Calculate the row that the point with the given vertical coordinate + is over. The horizontal component is ignored. + @param nYPosition + Vertical position in model coordinates. + @param bIncludeBordersAndGaps + When this flag is <TRUE/> then the area of borders and gaps are + interpreted as belonging to one of the rows. + @param eGapMembership + Specifies to what row the gap areas belong. Here GM_NONE + corresponds to bIncludeBordersAndGaps being <FALSE/>. When + GM_BOTH is given then the upper half is associated to the row + above and the lower half to the row below. Values of + GM_PREVIOUS and GM_NEXT associate the whole gap area with the + row above or below respectively. + */ + sal_Int32 GetRowAtPosition ( + sal_Int32 nYPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership = GM_NONE) const; + + /** Calculate the column that the point with the given horizontal + coordinate is over. The verical component is ignored. + @param nXPosition + Horizontal position in model coordinates. + @param bIncludeBordersAndGaps + When this flag is <TRUE/> then the area of borders and gaps are + interpreted as belonging to one of the columns. + @param eGapMembership + Specifies to what column the gap areas belong. + */ + sal_Int32 GetColumnAtPosition ( + sal_Int32 nXPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership = GM_NONE) const; + + /** This method is typically called from GetRowAtPosition() and + GetColumnAtPosition() to handle a position that lies inside the gap + between two adjacent rows or columns. + @param nDistanceIntoGap + Vertical distance from the bottom of the upper row down into the + gap or or horizontal distance from the right edge right into the + gap. + @param eGapMemberhship + This value decides what areas in the gap belong to which (or no) + row or column. + @param nIndex + The row index of the upper row or the column index of the left + column. + @param nGap + Width or height of the gap in model coordiantes between the + page borders. + @return + Returns either the index of the upper row (as given as nRow), the + index of the lower row (nRow+1) or -1 to indicate that the + position belongs to no row. + */ + sal_Int32 ResolvePositionInGap ( + sal_Int32 nDistanceIntoGap, + GapMembership eGapMembership, + sal_Int32 nIndex, + sal_Int32 nGap) const; + + /** Calculate the logical part of the insert position, i.e. the page + after whicht to insert. + */ + virtual void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const = 0; + + /** Calculate the geometrical part of the insert position, i.e. the + location of where to display the insertion indicator and the + distances about which the leading and trailing pages have to be + moved to make room for the indicator. + */ + void CalculateGeometricPosition ( + InsertPosition& rPosition, + const Size& rIndicatorSize, + const bool bIsVertical, + model::SlideSorterModel& rModel) const; + + /** Return the bounding box of the preview or, when selected, of the page + object. Thus, it returns something like a visual bounding box. + */ + Rectangle GetInnerBoundingBox ( + model::SlideSorterModel& rModel, + const sal_Int32 nIndex) const; + + Range GetValidHorizontalSizeRange (void) const; + Range GetValidVerticalSizeRange (void) const; + + Range GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const; + sal_Int32 GetIndex ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const bool bClampToValidRange) const; + + Rectangle GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap = false) const; + + Rectangle GetPageObjectBox ( + const sal_Int32 nRow, + const sal_Int32 nColumn) const; + + Rectangle AddBorderAndGap ( + const Rectangle& rBoundingBox, + const sal_Int32 nRow, + const sal_Int32 nColumn) const; + + Rectangle GetTotalBoundingBox (void) const; + + virtual ~Implementation (void); + +protected: + Implementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + Implementation (const Implementation& rImplementation); + + virtual void CalculateRowAndColumnCount (const Size& rWindowSize) = 0; + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) = 0; + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const = 0; + Size GetTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const bool bCalculateWidth, + const bool bCalculateHeight) const; + void CalculateVerticalLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; +}; + + +/** The vertical layouter has one column and as many rows as there are + pages. +*/ +class VerticalImplementation : public Layouter::Implementation +{ +public: + VerticalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + VerticalImplementation (const Implementation& rImplementation); + + virtual Layouter::Orientation GetOrientation (void) const; + + void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; + +protected: + virtual void CalculateRowAndColumnCount (const Size& rWindowSize); + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize); + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const; +}; + + +/** The horizontal layouter has one row and as many columns as there are + pages. +*/ +class HorizontalImplementation : public Layouter::Implementation +{ +public: + HorizontalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + HorizontalImplementation (const Implementation& rImplementation); + + virtual Layouter::Orientation GetOrientation (void) const; + + void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; + +protected: + virtual void CalculateRowAndColumnCount (const Size& rWindowSize); + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize); + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const; +}; + + +/** The number of columns of the grid layouter is defined via a control in + the slide sorter tool bar. The number of rows is calculated from the + number of columns and the number of pages. +*/ +class GridImplementation : public Layouter::Implementation +{ +public: + GridImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + GridImplementation (const Implementation& rImplementation); + + virtual Layouter::Orientation GetOrientation (void) const; + + void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; + +protected: + virtual void CalculateRowAndColumnCount (const Size& rWindowSize); + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize); + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const; +}; + + + + +//===== Layouter ============================================================== + +Layouter::Layouter ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<Theme>& rpTheme) + : mpImplementation(new GridImplementation(rpWindow, rpTheme)), + mpWindow(rpWindow) { } @@ -71,39 +337,30 @@ Layouter::~Layouter (void) } -void Layouter::SetBorders ( - sal_Int32 nLeftBorder, - sal_Int32 nRightBorder, - sal_Int32 nTopBorder, - sal_Int32 nBottomBorder) + + +::boost::shared_ptr<PageObjectLayouter> Layouter::GetPageObjectLayouter (void) const { - if (nLeftBorder >= 0) - mnRequestedLeftBorder.mnScreen = nLeftBorder; - if (nRightBorder >= 0) - mnRequestedRightBorder.mnScreen = nRightBorder; - if (nTopBorder >= 0) - mnRequestedTopBorder.mnScreen = nTopBorder; - if (nBottomBorder >= 0) - mnRequestedBottomBorder.mnScreen = nBottomBorder; + return mpImplementation->mpPageObjectLayouter; } -void Layouter::SetPageBorders ( +void Layouter::SetBorders ( sal_Int32 nLeftBorder, sal_Int32 nRightBorder, sal_Int32 nTopBorder, sal_Int32 nBottomBorder) { if (nLeftBorder >= 0) - mnLeftPageBorder.mnScreen = nLeftBorder; + mpImplementation->mnRequestedLeftBorder = nLeftBorder; if (nRightBorder >= 0) - mnRightPageBorder.mnScreen = nRightBorder; + mpImplementation->mnRequestedRightBorder = nRightBorder; if (nTopBorder >= 0) - mnTopPageBorder.mnScreen = nTopBorder; + mpImplementation->mnRequestedTopBorder = nTopBorder; if (nBottomBorder >= 0) - mnBottomPageBorder.mnScreen = nBottomBorder; + mpImplementation->mnRequestedBottomBorder = nBottomBorder; } @@ -115,389 +372,157 @@ void Layouter::SetColumnCount ( { if (nMinimalColumnCount <= nMaximalColumnCount) { - mnMinimalColumnCount = nMinimalColumnCount; - mnMaximalColumnCount = nMaximalColumnCount; + mpImplementation->mnMinimalColumnCount = nMinimalColumnCount; + mpImplementation->mnMaximalColumnCount = nMaximalColumnCount; } } -bool Layouter::RearrangeHorizontal ( +bool Layouter::Rearrange ( + const Orientation eOrientation, const Size& rWindowSize, - const Size& rPageObjectSize, - OutputDevice* pDevice, + const Size& rPageSize, const sal_uInt32 nPageCount) { - if (rWindowSize.Width() > 0 - && rWindowSize.Height() > 0 - && rPageObjectSize.Width() > 0 - && rPageObjectSize.Height() > 0) - { - mnTotalHorizontalGap.mnScreen = mnHorizontalGap.mnScreen - + mnRightPageBorder.mnScreen + mnLeftPageBorder.mnScreen; - mnTotalVerticalGap.mnScreen = mnVerticalGap.mnScreen - + mnTopPageBorder.mnScreen + mnBottomPageBorder.mnScreen; - - // Calculate the column count. - mnColumnCount = nPageCount; - - // Update the border values. The insertion marker has to have space. - mnLeftBorder.mnScreen = mnRequestedLeftBorder.mnScreen; - mnTopBorder.mnScreen = mnRequestedTopBorder.mnScreen; - mnRightBorder.mnScreen = mnRequestedRightBorder.mnScreen; - mnBottomBorder.mnScreen = mnRequestedBottomBorder.mnScreen; - if (mnColumnCount > 1) - { - int nMinimumBorderWidth = mnInsertionMarkerThickness.mnScreen - + mnHorizontalGap.mnScreen/2; - if (mnLeftBorder.mnScreen < nMinimumBorderWidth) - mnLeftBorder.mnScreen = nMinimumBorderWidth; - if (mnRightBorder.mnScreen < nMinimumBorderWidth) - mnRightBorder.mnScreen = nMinimumBorderWidth; - } - else - { - int nMinimumBorderHeight = mnInsertionMarkerThickness.mnScreen - + mnVerticalGap.mnScreen/2; - if (mnTopBorder.mnScreen < nMinimumBorderHeight) - mnTopBorder.mnScreen = nMinimumBorderHeight; - if (mnBottomBorder.mnScreen < nMinimumBorderHeight) - mnBottomBorder.mnScreen = nMinimumBorderHeight; - } + OSL_ASSERT(mpWindow); - // Calculate the width of each page object. - sal_uInt32 nTargetHeight = 0; - sal_uInt32 nRowCount = 1; - if (mnColumnCount > 0) - nTargetHeight = (rWindowSize.Height() - - mnTopBorder.mnScreen - - mnBottomBorder.mnScreen - - nRowCount * (mnTopPageBorder.mnScreen - + mnBottomPageBorder.mnScreen) - - (nRowCount-1) * mnTotalVerticalGap.mnScreen - ) - / nRowCount; - sal_uInt32 nMinimalHeight ( - mnMinimalWidth * rPageObjectSize.Height() / rPageObjectSize.Width()); - sal_uInt32 nMaximalHeight ( - mnMaximalWidth * rPageObjectSize.Height() / rPageObjectSize.Width()); - if (nTargetHeight < nMinimalHeight) - nTargetHeight = nMinimalHeight; - if (nTargetHeight > nMaximalHeight) - nTargetHeight = nMaximalHeight; - - // Initialize the device with some arbitrary zoom factor just in - // case that the current zoom factor is numerically instable when - // used in a multiplication. - MapMode aMapMode (pDevice->GetMapMode()); - aMapMode.SetScaleX (Fraction(1,1)); - aMapMode.SetScaleY (Fraction(1,1)); - pDevice->SetMapMode (aMapMode); - - // Calculate the resulting scale factor and the page object size in - // pixels. - maPageObjectModelSize = rPageObjectSize; - int nPagePixelHeight (pDevice->LogicToPixel(maPageObjectModelSize).Height()); - - // Adapt the layout of the given output device to the new layout of - // page objects. The zoom factor is set so that the page objects in - // one column fill the screen. - Fraction aScaleFactor (nTargetHeight, nPagePixelHeight); - SetZoom (aMapMode.GetScaleX() * aScaleFactor, pDevice); - - return true; - } - else - return false; + if (eOrientation != mpImplementation->GetOrientation()) + mpImplementation.reset(Implementation::Create(*mpImplementation, eOrientation)); + + return mpImplementation->Rearrange(rWindowSize, rPageSize, nPageCount); } -bool Layouter::RearrangeVertical ( - const Size& rWindowSize, - const Size& rPageObjectSize, - OutputDevice* pDevice) +void Layouter::_SetZoom (double nZoomFactor) { - if (rWindowSize.Width() > 0 - && rWindowSize.Height() > 0 - && rPageObjectSize.Width() > 0 - && rPageObjectSize.Height() > 0) - { - mnTotalHorizontalGap.mnScreen = mnHorizontalGap.mnScreen - + mnRightPageBorder.mnScreen + mnLeftPageBorder.mnScreen; - mnTotalVerticalGap.mnScreen = mnVerticalGap.mnScreen - + mnTopPageBorder.mnScreen + mnBottomPageBorder.mnScreen; - - // Calculate the column count. - mnColumnCount = (rWindowSize.Width() - - mnRequestedLeftBorder.mnScreen - mnRequestedRightBorder.mnScreen) - / (mnPreferredWidth + mnTotalHorizontalGap.mnScreen); - if (mnColumnCount < mnMinimalColumnCount) - mnColumnCount = mnMinimalColumnCount; - if (mnColumnCount > mnMaximalColumnCount) - mnColumnCount = mnMaximalColumnCount; - - // Update the border values. The insertion marker has to have space. - mnLeftBorder.mnScreen = mnRequestedLeftBorder.mnScreen; - mnTopBorder.mnScreen = mnRequestedTopBorder.mnScreen; - mnRightBorder.mnScreen = mnRequestedRightBorder.mnScreen; - mnBottomBorder.mnScreen = mnRequestedBottomBorder.mnScreen; - if (mnColumnCount > 1) - { - int nMinimumBorderWidth = mnInsertionMarkerThickness.mnScreen - + mnHorizontalGap.mnScreen/2; - if (mnLeftBorder.mnScreen < nMinimumBorderWidth) - mnLeftBorder.mnScreen = nMinimumBorderWidth; - if (mnRightBorder.mnScreen < nMinimumBorderWidth) - mnRightBorder.mnScreen = nMinimumBorderWidth; - } - else - { - int nMinimumBorderHeight = mnInsertionMarkerThickness.mnScreen - + mnVerticalGap.mnScreen/2; - if (mnTopBorder.mnScreen < nMinimumBorderHeight) - mnTopBorder.mnScreen = nMinimumBorderHeight; - if (mnBottomBorder.mnScreen < nMinimumBorderHeight) - mnBottomBorder.mnScreen = nMinimumBorderHeight; - } - - // Calculate the width of each page object. - sal_Int32 nTargetWidth = 0; - if (mnColumnCount > 0) - nTargetWidth = (rWindowSize.Width() - - mnLeftBorder.mnScreen - - mnRightBorder.mnScreen - - mnColumnCount * (mnRightPageBorder.mnScreen - + mnLeftPageBorder.mnScreen) - - (mnColumnCount-1) * mnTotalHorizontalGap.mnScreen - ) - / mnColumnCount; - if (nTargetWidth < mnMinimalWidth) - nTargetWidth = mnMinimalWidth; - if (nTargetWidth > mnMaximalWidth) - nTargetWidth = mnMaximalWidth; - - // Initialize the device with some arbitrary zoom factor just in - // case that the current zoom factor is numerically instable when - // used in a multiplication. - MapMode aMapMode (pDevice->GetMapMode()); - aMapMode.SetScaleX (Fraction(1,1)); - aMapMode.SetScaleY (Fraction(1,1)); - pDevice->SetMapMode (aMapMode); - - // Calculate the resulting scale factor and the page object size in - // pixels. - maPageObjectModelSize = rPageObjectSize; - int nPagePixelWidth (pDevice->LogicToPixel (maPageObjectModelSize).Width()); - - // Adapt the layout of the given output device to the new layout of - // page objects. The zoom factor is set so that the page objects in - // one row fill the screen. - Fraction aScaleFactor (nTargetWidth, nPagePixelWidth); - SetZoom (aMapMode.GetScaleX() * aScaleFactor, pDevice); - - return true; - } - else - return false; + _SetZoom(Fraction(nZoomFactor)); } -void Layouter::SetZoom (Fraction nZoomFactor, OutputDevice* pDevice) +void Layouter::_SetZoom (Fraction nZoomFactor) { - MapMode aMapMode (pDevice->GetMapMode()); + OSL_ASSERT(mpWindow); + + MapMode aMapMode (mpWindow->GetMapMode()); aMapMode.SetScaleX (nZoomFactor); aMapMode.SetScaleY (nZoomFactor); - maPageObjectPixelSize = pDevice->LogicToPixel (maPageObjectModelSize); - pDevice->SetMapMode (aMapMode); + mpWindow->SetMapMode (aMapMode); +} - // Transform frequently used values from pixel to model coordinates. - Size aTotalGap (pDevice->PixelToLogic (Size ( - mnTotalHorizontalGap.mnScreen, - mnTotalVerticalGap.mnScreen))); - mnTotalHorizontalGap.mnModel = aTotalGap.Width(); - mnTotalVerticalGap.mnModel = aTotalGap.Height(); - Size aGap (pDevice->PixelToLogic (Size ( - mnHorizontalGap.mnScreen, - mnVerticalGap.mnScreen))); - mnHorizontalGap.mnModel = aGap.Width(); - mnVerticalGap.mnModel = aGap.Height(); - Size aTopLeftBorder (pDevice->PixelToLogic (Size ( - mnLeftBorder.mnScreen, - mnTopBorder.mnScreen))); - mnLeftBorder.mnModel = aTopLeftBorder.Width(); - mnTopBorder.mnModel = aTopLeftBorder.Height(); +sal_Int32 Layouter::GetColumnCount (void) const +{ + return mpImplementation->mnColumnCount; +} - Size aBottomRightBorder (pDevice->PixelToLogic (Size ( - mnLeftBorder.mnScreen, - mnTopBorder.mnScreen))); - mnRightBorder.mnModel = aBottomRightBorder.Width(); - mnBottomBorder.mnModel = aBottomRightBorder.Height(); - Size aTopLeftPageBorder (pDevice->PixelToLogic (Size ( - mnLeftPageBorder.mnScreen, - mnTopPageBorder.mnScreen))); - mnLeftPageBorder.mnModel = aTopLeftPageBorder.Width(); - mnTopPageBorder.mnModel = aTopLeftPageBorder.Height(); - Size aBottomRightPageBorder (pDevice->PixelToLogic (Size ( - mnRightPageBorder.mnScreen, - mnBottomPageBorder.mnScreen))); - mnRightPageBorder.mnModel = aBottomRightPageBorder.Width(); - mnBottomPageBorder.mnModel = aBottomRightPageBorder.Height(); - mnInsertionMarkerThickness.mnModel = pDevice->PixelToLogic ( - Size(mnInsertionMarkerThickness.mnScreen,0)).Width(); +sal_Int32 Layouter::GetRowCount (void) const +{ + return mpImplementation->mnRowCount; } -sal_Int32 Layouter::GetColumnCount (void) const +sal_Int32 Layouter::GetRow (const sal_Int32 nIndex) const { - return mnColumnCount; + return nIndex / mpImplementation->mnColumnCount; } -Size Layouter::GetPageObjectSize (void) const +sal_Int32 Layouter::GetColumn (const sal_Int32 nIndex) const { - return maPageObjectModelSize; + return nIndex % mpImplementation->mnColumnCount; } -Rectangle Layouter::GetPageObjectBox (sal_Int32 nIndex) const +sal_Int32 Layouter::GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const { - int nColumn = nIndex % mnColumnCount; - int nRow = nIndex / mnColumnCount; - return Rectangle ( - Point (mnLeftBorder.mnModel - + nColumn * maPageObjectModelSize.Width() - + mnLeftPageBorder.mnModel - + (nColumn>0 ? nColumn : 0) * mnTotalHorizontalGap.mnModel, - mnTopBorder.mnModel - + nRow * maPageObjectModelSize.Height() - + mnTopPageBorder.mnModel - + (nRow>0 ? nRow : 0) * mnTotalVerticalGap.mnModel), - maPageObjectModelSize); + return mpImplementation->GetIndex(nRow,nColumn,true); } -Rectangle Layouter::GetPageBox (sal_Int32 nObjectCount) const +Size Layouter::GetPageObjectSize (void) const { - sal_Int32 nHorizontalSize = 0; - sal_Int32 nVerticalSize = 0; - if (mnColumnCount > 0) - { - sal_Int32 nRowCount = (nObjectCount+mnColumnCount-1) / mnColumnCount; - nHorizontalSize = - mnLeftBorder.mnModel - + mnRightBorder.mnModel - + mnColumnCount * maPageObjectModelSize.Width() - + mnLeftPageBorder.mnModel + mnRightPageBorder.mnModel; - if (mnColumnCount > 1) - nHorizontalSize - += (mnColumnCount-1) * mnTotalHorizontalGap.mnModel; - nVerticalSize = - mnTopBorder.mnModel - + mnBottomBorder.mnModel - + nRowCount * maPageObjectModelSize.Height() - + mnTopPageBorder.mnModel + mnBottomPageBorder.mnModel; - if (nRowCount > 1) - nVerticalSize += (nRowCount-1) * mnTotalVerticalGap.mnModel; - } + return mpImplementation->maPageObjectSize; +} - return Rectangle ( - Point(0,0), - Size (nHorizontalSize, nVerticalSize) - ); + + + +Rectangle Layouter::GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap) const +{ + return mpImplementation->GetPageObjectBox(nIndex, bIncludeBorderAndGap); } -Rectangle Layouter::GetInsertionMarkerBox ( - sal_Int32 nIndex, - bool bVertical, - bool bLeftOrTop) const +Rectangle Layouter::GetTotalBoundingBox (void) const { - Rectangle aBox (GetPageObjectBox (nIndex)); + return mpImplementation->GetTotalBoundingBox(); +} + + + + +InsertPosition Layouter::GetInsertPosition ( + const Point& rModelPosition, + const Size& rIndicatorSize, + model::SlideSorterModel& rModel) const +{ + InsertPosition aPosition; + mpImplementation->CalculateLogicalInsertPosition( + rModelPosition, + aPosition); + mpImplementation->CalculateGeometricPosition( + aPosition, + rIndicatorSize, + GetColumnCount()==1, + rModel); + return aPosition; +} - if (bVertical) - { - sal_Int32 nHorizontalInsertionMarkerOffset - = (mnHorizontalGap.mnModel-mnInsertionMarkerThickness.mnModel) / 2; - if (bLeftOrTop) - { - // Left. - aBox.Left() -= mnLeftPageBorder.mnModel - + mnHorizontalGap.mnModel - - nHorizontalInsertionMarkerOffset; - } - else - { - // Right. - aBox.Left() = aBox.Right() - + mnRightPageBorder.mnModel - + nHorizontalInsertionMarkerOffset; - } - aBox.Right() = aBox.Left() + mnInsertionMarkerThickness.mnModel; - } - else - { - sal_Int32 nVerticalInsertionMarkerOffset - = (mnVerticalGap.mnModel - mnInsertionMarkerThickness.mnModel) / 2; - if (bLeftOrTop) - { - // Above. - aBox.Top() -= mnTopPageBorder.mnModel - + mnVerticalGap.mnModel - - nVerticalInsertionMarkerOffset; - } - else - { - // Below. - aBox.Top() = aBox.Bottom() - + mnBottomPageBorder.mnModel - + nVerticalInsertionMarkerOffset; - } - aBox.Bottom() = aBox.Top() + mnInsertionMarkerThickness.mnModel; - } - return aBox; + + +Range Layouter::GetValidHorizontalSizeRange (void) const +{ + return mpImplementation->GetValidHorizontalSizeRange(); } -sal_Int32 Layouter::GetIndexOfFirstVisiblePageObject ( - const Rectangle& aVisibleArea) const +Range Layouter::GetValidVerticalSizeRange (void) const { - sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Top(), true, GM_BOTH); - return nRow * mnColumnCount; + return mpImplementation->GetValidVerticalSizeRange(); } -sal_Int32 Layouter::GetIndexOfLastVisiblePageObject ( - const Rectangle& aVisibleArea) const +Range Layouter::GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const { - sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Bottom(), - true, GM_BOTH); - return (nRow+1) * mnColumnCount - 1; + return mpImplementation->GetRangeOfVisiblePageObjects(aVisibleArea); } @@ -505,128 +530,188 @@ sal_Int32 Layouter::GetIndexOfLastVisiblePageObject ( sal_Int32 Layouter::GetIndexAtPoint ( const Point& rPosition, - bool bIncludePageBorders) const + const bool bIncludePageBorders, + const bool bClampToValidRange) const { - sal_Int32 nRow = GetRowAtPosition (rPosition.Y(), - bIncludePageBorders, - bIncludePageBorders ? GM_PAGE_BORDER : GM_NONE); - sal_Int32 nColumn = GetColumnAtPosition (rPosition.X(), - bIncludePageBorders, - bIncludePageBorders ? GM_PAGE_BORDER : GM_NONE); - - if (nRow >= 0 && nColumn >= 0) - return nRow * mnColumnCount + nColumn; - else - return -1; + const sal_Int32 nRow ( + mpImplementation->GetRowAtPosition ( + rPosition.Y(), + bIncludePageBorders, + bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE)); + const sal_Int32 nColumn ( + mpImplementation->GetColumnAtPosition ( + rPosition.X(), + bIncludePageBorders, + bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE)); + + return mpImplementation->GetIndex(nRow,nColumn,bClampToValidRange); } -/** Calculation of the insertion index: - 1. Determine the row. rPoint has to be in the row between upper and - lower border. If it is in a horizontal gap or border an invalid - insertion index (-1, which is a valid return value) will be returned. - 2. Determine the column. Here both vertical borders and vertical gaps - will yield valid return values. The horizontal positions between the - center of page objects in column i and the center of page objects in - column i+1 will return column i+1 as insertion index. +//===== Layouter::Implementation ============================================== - When there is only one column and bAllowVerticalPosition is true than - take the vertical areas between rows into account as well. -*/ -sal_Int32 Layouter::GetInsertionIndex ( - const Point& rPosition, - bool bAllowVerticalPosition) const +Layouter::Implementation* Layouter::Implementation::Create ( + const Implementation& rImplementation, + const Layouter::Orientation eOrientation) { - sal_Int32 nIndex = -1; + switch (eOrientation) + { + case HORIZONTAL: return new HorizontalImplementation(rImplementation); + case VERTICAL: return new VerticalImplementation(rImplementation); + case GRID: + default: return new GridImplementation(rImplementation); + } +} - sal_Int32 nRow = GetRowAtPosition (rPosition.Y(), true, - (mnColumnCount==1 && bAllowVerticalPosition) ? GM_BOTH : GM_BOTH); - sal_Int32 nColumn = GetColumnAtPosition (rPosition.X(), true, GM_BOTH); - if (nRow >= 0 && nColumn >= 0) - nIndex = nRow * mnColumnCount + nColumn; - return nIndex; + +Layouter::Implementation::Implementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : mpWindow(rpWindow), + mnRequestedLeftBorder(5), + mnRequestedRightBorder(5), + mnRequestedTopBorder(5), + mnRequestedBottomBorder(5), + mnLeftBorder(5), + mnRightBorder(5), + mnTopBorder(5), + mnBottomBorder(5), + mnVerticalGap (10 - 2*rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)), + mnHorizontalGap(10 - 2*rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)), + maMinimalSize(132,98), + maPreferredSize(200,150), + maMaximalSize(300,200), + mnMinimalColumnCount(1), + mnMaximalColumnCount(15), + mnPageCount(0), + mnColumnCount(1), + mnRowCount(0), + mnMaxColumnCount(0), + mnMaxRowCount(0), + maPageObjectSize(1,1), + mpPageObjectLayouter(), + mpTheme(rpTheme) +{ } -Layouter::DoublePoint - Layouter::ConvertModelToLayouterCoordinates ( - const Point& rModelPoint) const +Layouter::Implementation::Implementation (const Implementation& rImplementation) + : mpWindow(rImplementation.mpWindow), + mnRequestedLeftBorder(rImplementation.mnRequestedLeftBorder), + mnRequestedRightBorder(rImplementation.mnRequestedRightBorder), + mnRequestedTopBorder(rImplementation.mnRequestedTopBorder), + mnRequestedBottomBorder(rImplementation.mnRequestedBottomBorder), + mnLeftBorder(rImplementation.mnLeftBorder), + mnRightBorder(rImplementation.mnRightBorder), + mnTopBorder(rImplementation.mnTopBorder), + mnBottomBorder(rImplementation.mnBottomBorder), + mnVerticalGap(rImplementation.mnVerticalGap), + mnHorizontalGap(rImplementation.mnHorizontalGap), + maMinimalSize(rImplementation.maMinimalSize), + maPreferredSize(rImplementation.maPreferredSize), + maMaximalSize(rImplementation.maMaximalSize), + mnMinimalColumnCount(rImplementation.mnMinimalColumnCount), + mnMaximalColumnCount(rImplementation.mnMaximalColumnCount), + mnPageCount(rImplementation.mnPageCount), + mnColumnCount(rImplementation.mnColumnCount), + mnRowCount(rImplementation.mnRowCount), + mnMaxColumnCount(rImplementation.mnMaxColumnCount), + mnMaxRowCount(rImplementation.mnMaxRowCount), + maPageObjectSize(rImplementation.maPageObjectSize), + mpPageObjectLayouter(), + mpTheme(rImplementation.mpTheme) { - sal_Int32 nColumn = GetColumnAtPosition (rModelPoint.X(), true, GM_BOTH); - sal_Int32 nColumnWidth - = maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel; - sal_Int32 nDistanceIntoColumn = - rModelPoint.X() - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel - - nColumn * nColumnWidth; +} + + - sal_Int32 nRow = GetRowAtPosition (rModelPoint.Y(), true, GM_BOTH); - sal_Int32 nRowHeight - = maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel; - sal_Int32 nDistanceIntoRow = - rModelPoint.Y() - mnTopBorder.mnModel - mnTopPageBorder.mnModel - - nRow * nRowHeight; - return DoublePoint ( - nColumn + double(nDistanceIntoColumn) / double(nColumnWidth), - nRow + double(nDistanceIntoRow) / double(nRowHeight)); +Layouter::Implementation::~Implementation (void) +{ } -Point Layouter::ConvertLayouterToModelCoordinates ( - const DoublePoint & rLayouterPoint) const +bool Layouter::Implementation::Rearrange ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const sal_uInt32 nPageCount) { - sal_Int32 nColumn = (sal_Int32) ::rtl::math::round(rLayouterPoint.first, - 0,rtl_math_RoundingMode_Floor); - sal_Int32 nColumnWidth - = maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel; - sal_Int32 nDistanceIntoColumn - = (sal_Int32)((rLayouterPoint.first - nColumn) * nColumnWidth); + mnPageCount = nPageCount; - sal_Int32 nRow = (sal_Int32) ::rtl::math::round(rLayouterPoint.second, - 0,rtl_math_RoundingMode_Floor); - sal_Int32 nRowHeight - = maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel; - sal_Int32 nDistanceIntoRow - = (sal_Int32)((rLayouterPoint.second - nRow) * nRowHeight); + // Return early when the window or the model have not yet been initialized. + if (rWindowSize.Width()<=0 || rWindowSize.Height()<=0) + return false; + if (rPreviewModelSize.Width()<=0 || rPreviewModelSize.Height()<=0) + return false; - return Point ( - mnLeftBorder.mnModel + mnLeftPageBorder.mnModel - + nColumn * nColumnWidth + nDistanceIntoColumn, - mnTopBorder.mnModel + mnTopPageBorder.mnModel - + nRow * nRowHeight + nDistanceIntoRow); + CalculateRowAndColumnCount(rWindowSize); + + // Update the border values. + mnLeftBorder = mnRequestedLeftBorder; + mnTopBorder = mnRequestedTopBorder; + mnRightBorder = mnRequestedRightBorder; + mnBottomBorder = mnRequestedBottomBorder; + if (mnColumnCount > 1) + { + int nMinimumBorderWidth = mnHorizontalGap/2; + if (mnLeftBorder < nMinimumBorderWidth) + mnLeftBorder = nMinimumBorderWidth; + if (mnRightBorder < nMinimumBorderWidth) + mnRightBorder = nMinimumBorderWidth; + } + else + { + int nMinimumBorderHeight = mnVerticalGap/2; + if (mnTopBorder < nMinimumBorderHeight) + mnTopBorder = nMinimumBorderHeight; + if (mnBottomBorder < nMinimumBorderHeight) + mnBottomBorder = nMinimumBorderHeight; + } + + mpPageObjectLayouter.reset( + new PageObjectLayouter( + mpTheme, + CalculateTargetSize(rWindowSize, rPreviewModelSize), + rPreviewModelSize, + mpWindow, + mnPageCount)); + maPageObjectSize = mpPageObjectLayouter->GetSize( + PageObjectLayouter::FocusIndicator, + PageObjectLayouter::WindowCoordinateSystem); + + CalculateMaxRowAndColumnCount(rWindowSize); + + return true; } -sal_Int32 Layouter::GetRowAtPosition ( +sal_Int32 Layouter::Implementation::GetRowAtPosition ( sal_Int32 nYPosition, bool bIncludeBordersAndGaps, GapMembership eGapMembership) const { sal_Int32 nRow = -1; - const sal_Int32 nY = nYPosition - - mnTopBorder.mnModel - mnTopPageBorder.mnModel; + const sal_Int32 nY = nYPosition - mnTopBorder; if (nY >= 0) { // Vertical distance from one row to the next. - const sal_Int32 nRowOffset ( - maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel); + const sal_Int32 nRowOffset (maPageObjectSize.Height() + mnVerticalGap); // Calculate row consisting of page objects and gap below. nRow = nY / nRowOffset; - const sal_Int32 nDistanceIntoGap ( - (nY - nRow*nRowOffset) - maPageObjectModelSize.Height()); + const sal_Int32 nDistanceIntoGap ((nY - nRow*nRowOffset) - maPageObjectSize.Height()); // When inside the gap below then nYPosition is not over a page // object. if (nDistanceIntoGap > 0) @@ -634,8 +719,7 @@ sal_Int32 Layouter::GetRowAtPosition ( nDistanceIntoGap, eGapMembership, nRow, - mnBottomPageBorder.mnModel, - mnVerticalGap.mnModel); + mnVerticalGap); } else if (bIncludeBordersAndGaps) { @@ -650,20 +734,18 @@ sal_Int32 Layouter::GetRowAtPosition ( -sal_Int32 Layouter::GetColumnAtPosition ( +sal_Int32 Layouter::Implementation::GetColumnAtPosition ( sal_Int32 nXPosition, bool bIncludeBordersAndGaps, GapMembership eGapMembership) const { sal_Int32 nColumn = -1; - sal_Int32 nX = nXPosition - - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel; + sal_Int32 nX = nXPosition - mnLeftBorder; if (nX >= 0) { // Horizontal distance from one column to the next. - const sal_Int32 nColumnOffset ( - maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel); + const sal_Int32 nColumnOffset (maPageObjectSize.Width() + mnHorizontalGap); // Calculate row consisting of page objects and gap below. nColumn = nX / nColumnOffset; @@ -672,8 +754,7 @@ sal_Int32 Layouter::GetColumnAtPosition ( else if (nColumn >= mnColumnCount) nColumn = mnColumnCount-1; - const sal_Int32 nDistanceIntoGap ( - (nX - nColumn*nColumnOffset) - maPageObjectModelSize.Width()); + const sal_Int32 nDistanceIntoGap ((nX - nColumn*nColumnOffset) - maPageObjectSize.Width()); // When inside the gap at the right then nXPosition is not over a // page object. if (nDistanceIntoGap > 0) @@ -681,8 +762,7 @@ sal_Int32 Layouter::GetColumnAtPosition ( nDistanceIntoGap, eGapMembership, nColumn, - mnRightPageBorder.mnModel, - mnHorizontalGap.mnModel); + mnHorizontalGap); } else if (bIncludeBordersAndGaps) { @@ -697,11 +777,10 @@ sal_Int32 Layouter::GetColumnAtPosition ( -sal_Int32 Layouter::ResolvePositionInGap ( +sal_Int32 Layouter::Implementation::ResolvePositionInGap ( sal_Int32 nDistanceIntoGap, GapMembership eGapMembership, sal_Int32 nIndex, - sal_Int32 nLeftOrTopPageBorder, sal_Int32 nGap) const { switch (eGapMembership) @@ -714,7 +793,7 @@ sal_Int32 Layouter::ResolvePositionInGap ( case GM_BOTH: { // The lower half of the gap belongs to the next row or column. - sal_Int32 nFirstHalfGapWidth = nLeftOrTopPageBorder + nGap / 2; + sal_Int32 nFirstHalfGapWidth = nGap / 2; if (nDistanceIntoGap > nFirstHalfGapWidth) nIndex ++; break; @@ -730,9 +809,9 @@ sal_Int32 Layouter::ResolvePositionInGap ( break; case GM_PAGE_BORDER: - if (nDistanceIntoGap > nLeftOrTopPageBorder) + if (nDistanceIntoGap > 0) { - if (nDistanceIntoGap > nLeftOrTopPageBorder + nGap) + if (nDistanceIntoGap > nGap) { // Inside the border of the next row or column. nIndex ++; @@ -755,4 +834,719 @@ sal_Int32 Layouter::ResolvePositionInGap ( +void Layouter::Implementation::CalculateGeometricPosition ( + InsertPosition& rPosition, + const Size& rIndicatorSize, + const bool bIsVertical, + model::SlideSorterModel& rModel) const +{ + // 1. Determine right/bottom of the leading page and the left/top of the + // trailing page object and how to distribute the missing space. + sal_Int32 nLeadingLocation (0); + sal_Int32 nTrailingLocation (0); + bool bIsLeadingFixed (false); + bool bIsTrailingFixed (false); + sal_Int32 nSecondaryLocation (0); + const sal_Int32 nIndex (rPosition.GetIndex()); + + if (rPosition.IsAtRunStart()) + { + // Place indicator at the top of the column. + const Rectangle aOuterBox (GetPageObjectBox(nIndex)); + const Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex)); + if (bIsVertical) + { + nLeadingLocation = aOuterBox.Top(); + nTrailingLocation = aInnerBox.Top(); + nSecondaryLocation = aInnerBox.Center().X(); + } + else + { + nLeadingLocation = aOuterBox.Left(); + nTrailingLocation = aInnerBox.Left(); + nSecondaryLocation = aInnerBox.Center().Y(); + } + bIsLeadingFixed = true; + } + else if (rPosition.IsAtRunEnd()) + { + // Place indicator at the bottom/right of the column/row. + + const Rectangle aOuterBox (GetPageObjectBox(nIndex-1)); + const Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex-1)); + if (bIsVertical) + { + nLeadingLocation = aInnerBox.Bottom(); + nTrailingLocation = aOuterBox.Bottom(); + nSecondaryLocation = aInnerBox.Center().X(); + } + else + { + nLeadingLocation = aInnerBox.Right(); + nTrailingLocation = aOuterBox.Right(); + nSecondaryLocation = aInnerBox.Center().Y(); + } + bIsTrailingFixed = true; + if ( ! rPosition.IsExtraSpaceNeeded()) + bIsLeadingFixed = true; + } + else + { + // Place indicator between two rows/columns. + const Rectangle aBox1 (GetInnerBoundingBox(rModel, nIndex-1)); + const Rectangle aBox2 (GetInnerBoundingBox(rModel, nIndex)); + if (bIsVertical) + { + nLeadingLocation = aBox1.Bottom(); + nTrailingLocation = aBox2.Top(); + nSecondaryLocation = (aBox1.Center().X() + aBox2.Center().X()) / 2; + } + else + { + nLeadingLocation = aBox1.Right(); + nTrailingLocation = aBox2.Left(); + nSecondaryLocation = (aBox1.Center().Y() + aBox2.Center().Y()) / 2; + } + } + + // 2. Calculate the location of the insert indicator and the offsets of + // leading and trailing pages. + const sal_Int32 nAvailableSpace (nTrailingLocation - nLeadingLocation); + const sal_Int32 nRequiredSpace (bIsVertical ? rIndicatorSize.Height():rIndicatorSize.Width()); + const sal_Int32 nMissingSpace (::std::max(sal_Int32(0), nRequiredSpace - nAvailableSpace)); + sal_Int32 nPrimaryLocation (0); + sal_Int32 nLeadingOffset (0); + sal_Int32 nTrailingOffset (0); + if (bIsLeadingFixed) + { + nPrimaryLocation = nLeadingLocation + nRequiredSpace/2; + if ( ! bIsTrailingFixed) + nTrailingOffset = nMissingSpace; + } + else if (bIsTrailingFixed) + { + nPrimaryLocation = nTrailingLocation - nRequiredSpace/2; + nLeadingOffset = -nMissingSpace; + } + else + { + nPrimaryLocation = (nLeadingLocation + nTrailingLocation) /2; + nLeadingOffset = -nMissingSpace/2; + nTrailingOffset = nMissingSpace + nLeadingOffset; + } + + if (bIsVertical) + { + rPosition.SetGeometricalPosition( + Point(nSecondaryLocation, nPrimaryLocation), + Point(0, nLeadingOffset), + Point(0, nTrailingOffset)); + } + else + { + rPosition.SetGeometricalPosition( + Point(nPrimaryLocation, nSecondaryLocation), + Point(nLeadingOffset, 0), + Point(nTrailingOffset, 0)); + } +} + + + + +Rectangle Layouter::Implementation::GetInnerBoundingBox ( + model::SlideSorterModel& rModel, + const sal_Int32 nIndex) const +{ + model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if ( ! pDescriptor) + return Rectangle(); + + const Point aLocation (pDescriptor->GetLocation(true)); + if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) + return mpPageObjectLayouter->GetBoundingBox( + aLocation, + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem); + else + return mpPageObjectLayouter->GetBoundingBox( + aLocation, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem); +} + + + + +Range Layouter::Implementation::GetValidHorizontalSizeRange (void) const +{ + return Range( + mnLeftBorder + maMinimalSize.Width() + mnRightBorder, + mnLeftBorder + maMaximalSize.Width() + mnRightBorder); +} + + + + +Range Layouter::Implementation::GetValidVerticalSizeRange (void) const +{ + return Range( + mnTopBorder + maMinimalSize.Height() + mnBottomBorder, + mnTopBorder + maMaximalSize.Height() + mnBottomBorder); +} + + + + +Range Layouter::Implementation::GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const +{ + const sal_Int32 nRow0 (GetRowAtPosition(aVisibleArea.Top(), true, GM_NEXT)); + const sal_Int32 nCol0 (GetColumnAtPosition(aVisibleArea.Left(),true, GM_NEXT)); + const sal_Int32 nRow1 (GetRowAtPosition(aVisibleArea.Bottom(), true, GM_PREVIOUS)); + const sal_Int32 nCol1 (GetColumnAtPosition(aVisibleArea.Right(), true, GM_PREVIOUS)); + + // When start and end lie in different rows then the range may include + // slides outside (left or right of) the given area. + return Range(GetIndex(nRow0,nCol0,true), GetIndex(nRow1,nCol1,true)); +} + + + + +Size Layouter::Implementation::GetTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const bool bCalculateWidth, + const bool bCalculateHeight) const +{ + (void)rPreviewModelSize; + + if (mnColumnCount<=0 || mnRowCount<=0) + return maPreferredSize; + if ( ! (bCalculateWidth || bCalculateHeight)) + { + OSL_ASSERT(bCalculateWidth || bCalculateHeight); + return maPreferredSize; + } + + // Calculate the width of each page object. + Size aTargetSize (0,0); + if (bCalculateWidth) + aTargetSize.setWidth( + (rWindowSize.Width() - mnLeftBorder - mnRightBorder + - (mnColumnCount-1) * mnHorizontalGap) + / mnColumnCount); + else if (bCalculateHeight) + aTargetSize.setHeight( + (rWindowSize.Height() - mnTopBorder - mnBottomBorder + - (mnRowCount-1) * mnVerticalGap) + / mnRowCount); + + if (bCalculateWidth) + { + if (aTargetSize.Width() < maMinimalSize.Width()) + aTargetSize.setWidth(maMinimalSize.Width()); + else if (aTargetSize.Width() > maMaximalSize.Width()) + aTargetSize.setWidth(maMaximalSize.Width()); + } + else if (bCalculateHeight) + { + if (aTargetSize.Height() < maMinimalSize.Height()) + aTargetSize.setHeight(maMinimalSize.Height()); + else if (aTargetSize.Height() > maMaximalSize.Height()) + aTargetSize.setHeight(maMaximalSize.Height()); + } + + return aTargetSize; +} + + + + +sal_Int32 Layouter::Implementation::GetIndex ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const bool bClampToValidRange) const +{ + if (nRow >= 0 && nColumn >= 0) + { + const sal_Int32 nIndex (nRow * mnColumnCount + nColumn); + if (nIndex >= mnPageCount) + if (bClampToValidRange) + return mnPageCount-1; + else + return -1; + else + return nIndex; + } + else if (bClampToValidRange) + return 0; + else + return -1; +} + + + + +Rectangle Layouter::Implementation::GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap) const +{ + const sal_Int32 nRow (nIndex / mnColumnCount); + const sal_Int32 nColumn (nIndex % mnColumnCount); + + const Rectangle aBoundingBox (GetPageObjectBox(nRow,nColumn)); + if (bIncludeBorderAndGap) + return AddBorderAndGap(aBoundingBox, nRow, nColumn); + else + return aBoundingBox; +} + + + + +Rectangle Layouter::Implementation::GetPageObjectBox ( + const sal_Int32 nRow, + const sal_Int32 nColumn) const +{ + return Rectangle( + Point (mnLeftBorder + + nColumn * maPageObjectSize.Width() + + (nColumn>0 ? nColumn : 0) * mnHorizontalGap, + mnTopBorder + + nRow * maPageObjectSize.Height() + + (nRow>0 ? nRow : 0) * mnVerticalGap), + maPageObjectSize); +} + + + + + +Rectangle Layouter::Implementation::AddBorderAndGap ( + const Rectangle& rBoundingBox, + const sal_Int32 nRow, + const sal_Int32 nColumn) const +{ + Rectangle aBoundingBox (rBoundingBox); + + if (nColumn == 0) + aBoundingBox.Left() = 0; + else + aBoundingBox.Left() -= mnHorizontalGap/2; + if (nColumn == mnColumnCount-1) + aBoundingBox.Right() += mnRightBorder; + else + aBoundingBox.Right() += mnHorizontalGap/2; + if (nRow == 0) + aBoundingBox.Top() = 0; + else + aBoundingBox.Top() -= mnVerticalGap/2; + if (nRow == mnRowCount-1) + aBoundingBox.Bottom() += mnBottomBorder; + else + aBoundingBox.Bottom() += mnVerticalGap/2; + return aBoundingBox; +} + + + + +Rectangle Layouter::Implementation::GetTotalBoundingBox (void) const +{ + sal_Int32 nHorizontalSize = 0; + sal_Int32 nVerticalSize = 0; + if (mnColumnCount > 0) + { + sal_Int32 nRowCount = (mnPageCount+mnColumnCount-1) / mnColumnCount; + nHorizontalSize = + mnLeftBorder + + mnRightBorder + + mnColumnCount * maPageObjectSize.Width(); + if (mnColumnCount > 1) + nHorizontalSize += (mnColumnCount-1) * mnHorizontalGap; + nVerticalSize = + mnTopBorder + + mnBottomBorder + + nRowCount * maPageObjectSize.Height(); + if (nRowCount > 1) + nVerticalSize += (nRowCount-1) * mnVerticalGap; + } + + return Rectangle ( + Point(0,0), + Size (nHorizontalSize, nVerticalSize) + ); +} + + + + +void Layouter::Implementation::CalculateVerticalLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + const sal_Int32 nY = rModelPosition.Y() - mnTopBorder + maPageObjectSize.Height()/2; + const sal_Int32 nRowHeight (maPageObjectSize.Height() + mnVerticalGap); + const sal_Int32 nRow (::std::min(mnPageCount, nY / nRowHeight)); + rPosition.SetLogicalPosition ( + nRow, + 0, + nRow, + (nRow == 0), + (nRow == mnRowCount), + (nRow >= mnMaxRowCount)); +} + + + + +//===== HorizontalImplementation ================================================ + +HorizontalImplementation::HorizontalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : Implementation(rpWindow, rpTheme) +{ +} + + + + +HorizontalImplementation::HorizontalImplementation (const Implementation& rImplementation) + : Implementation(rImplementation) +{ +} + + + + +Layouter::Orientation HorizontalImplementation::GetOrientation (void) const +{ + return Layouter::HORIZONTAL; +} + + + + +void HorizontalImplementation::CalculateRowAndColumnCount (const Size& rWindowSize) +{ + (void)rWindowSize; + + // Row and column count are fixed (for a given page count.) + mnColumnCount = mnPageCount; + mnRowCount = 1; +} + + + + +void HorizontalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize) +{ + mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder) + / (maPageObjectSize.Width() + mnHorizontalGap); + mnMaxRowCount = 1; +} + + + + +Size HorizontalImplementation::CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const +{ + return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, false, true); +} + + + + +void HorizontalImplementation::CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2; + const sal_Int32 nColumnWidth (maPageObjectSize.Width() + mnHorizontalGap); + const sal_Int32 nColumn (::std::min(mnPageCount, nX / nColumnWidth)); + rPosition.SetLogicalPosition ( + 0, + nColumn, + nColumn, + (nColumn == 0), + (nColumn == mnColumnCount), + (nColumn >= mnMaxColumnCount)); +} + + + + +//===== VerticalImplementation ================================================ + +VerticalImplementation::VerticalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : Implementation(rpWindow, rpTheme) +{ +} + + + + +VerticalImplementation::VerticalImplementation (const Implementation& rImplementation) + : Implementation(rImplementation) +{ +} + + + + +Layouter::Orientation VerticalImplementation::GetOrientation (void) const +{ + return Layouter::VERTICAL; +} + + + + +void VerticalImplementation::CalculateRowAndColumnCount (const Size& rWindowSize) +{ + (void)rWindowSize; + + // Row and column count are fixed (for a given page count.) + mnRowCount = mnPageCount; + mnColumnCount = 1; + +} + + + + +void VerticalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize) +{ + mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder) + / (maPageObjectSize.Height() + mnVerticalGap); + mnMaxColumnCount = 1; +} + + + + +Size VerticalImplementation::CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const +{ + return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, true, false); +} + + + + +void VerticalImplementation::CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + return CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition); +} + + + + +//===== GridImplementation ================================================ + +GridImplementation::GridImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : Implementation(rpWindow, rpTheme) +{ +} + + + + +GridImplementation::GridImplementation (const Implementation& rImplementation) + : Implementation(rImplementation) +{ +} + + + + +Layouter::Orientation GridImplementation::GetOrientation (void) const +{ + return Layouter::GRID; +} + + + + +void GridImplementation::CalculateRowAndColumnCount (const Size& rWindowSize) +{ + // Calculate the column count. + mnColumnCount + = (rWindowSize.Width() - mnRequestedLeftBorder - mnRequestedRightBorder) + / (maPreferredSize.Width() + mnHorizontalGap); + if (mnColumnCount < mnMinimalColumnCount) + mnColumnCount = mnMinimalColumnCount; + if (mnColumnCount > mnMaximalColumnCount) + mnColumnCount = mnMaximalColumnCount; + mnRowCount = (mnPageCount + mnColumnCount-1)/mnColumnCount; +} + + + + +void GridImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize) +{ + mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder) + / (maPageObjectSize.Width() + mnHorizontalGap); + mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder) + / (maPageObjectSize.Height() + mnVerticalGap); +} + + + + + +Size GridImplementation::CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const +{ + return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, true, true); +} + + + + +void GridImplementation::CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + if (mnColumnCount == 1) + { + CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition); + } + else + { + // Handle the general case of more than one column. + sal_Int32 nRow (::std::min( + mnRowCount-1, + GetRowAtPosition (rModelPosition.Y(), true, GM_BOTH))); + const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2; + const sal_Int32 nColumnWidth (maPageObjectSize.Width() + mnHorizontalGap); + sal_Int32 nColumn (::std::min(mnColumnCount, nX / nColumnWidth)); + sal_Int32 nIndex (nRow * mnColumnCount + nColumn); + bool bIsAtRunEnd (nColumn == mnColumnCount); + + if (nIndex >= mnPageCount) + { + nIndex = mnPageCount; + nRow = mnRowCount-1; + nColumn = ::std::min(::std::min(mnPageCount, mnColumnCount), nColumn); + bIsAtRunEnd = true; + } + + rPosition.SetLogicalPosition ( + nRow, + nColumn, + nIndex, + (nColumn == 0), + bIsAtRunEnd, + (nColumn >= mnMaxColumnCount)); + } +} + + + + +//===== InsertPosition ======================================================== + +InsertPosition::InsertPosition (void) + : mnRow(-1), + mnColumn(-1), + mnIndex(-1), + mbIsAtRunStart(false), + mbIsAtRunEnd(false), + mbIsExtraSpaceNeeded(false), + maLocation(0,0), + maLeadingOffset(0,0), + maTrailingOffset(0,0) +{ +} + + + + +InsertPosition& InsertPosition::operator= (const InsertPosition& rInsertPosition) +{ + if (this != &rInsertPosition) + { + mnRow = rInsertPosition.mnRow; + mnColumn = rInsertPosition.mnColumn; + mnIndex = rInsertPosition.mnIndex; + mbIsAtRunStart = rInsertPosition.mbIsAtRunStart; + mbIsAtRunEnd = rInsertPosition.mbIsAtRunEnd; + mbIsExtraSpaceNeeded = rInsertPosition.mbIsExtraSpaceNeeded; + maLocation = rInsertPosition.maLocation; + maLeadingOffset = rInsertPosition.maLeadingOffset; + maTrailingOffset = rInsertPosition.maTrailingOffset; + } + return *this; +} + + + + +bool InsertPosition::operator== (const InsertPosition& rInsertPosition) const +{ + // Do not compare the geometrical information (maLocation). + return mnRow==rInsertPosition.mnRow + && mnColumn==rInsertPosition.mnColumn + && mnIndex==rInsertPosition.mnIndex + && mbIsAtRunStart==rInsertPosition.mbIsAtRunStart + && mbIsAtRunEnd==rInsertPosition.mbIsAtRunEnd + && mbIsExtraSpaceNeeded==rInsertPosition.mbIsExtraSpaceNeeded; +} + + + + +bool InsertPosition::operator!= (const InsertPosition& rInsertPosition) const +{ + return !operator==(rInsertPosition); +} + + + + +void InsertPosition::SetLogicalPosition ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const sal_Int32 nIndex, + const bool bIsAtRunStart, + const bool bIsAtRunEnd, + const bool bIsExtraSpaceNeeded) +{ + mnRow = nRow; + mnColumn = nColumn; + mnIndex = nIndex; + mbIsAtRunStart = bIsAtRunStart; + mbIsAtRunEnd = bIsAtRunEnd; + mbIsExtraSpaceNeeded = bIsExtraSpaceNeeded; +} + + + + +void InsertPosition::SetGeometricalPosition( + const Point aLocation, + const Point aLeadingOffset, + const Point aTrailingOffset) +{ + maLocation = aLocation; + maLeadingOffset = aLeadingOffset; + maTrailingOffset = aTrailingOffset; +} + + + } } } // end of namespace ::sd::slidesorter::namespace |