summaryrefslogtreecommitdiff
path: root/sd/source/ui/slidesorter/view/SlsLayouter.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sd/source/ui/slidesorter/view/SlsLayouter.cxx')
-rw-r--r--[-rwxr-xr-x]sd/source/ui/slidesorter/view/SlsLayouter.cxx1684
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