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--sd/source/ui/slidesorter/view/SlsLayouter.cxx813
1 files changed, 813 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/view/SlsLayouter.cxx b/sd/source/ui/slidesorter/view/SlsLayouter.cxx
new file mode 100644
index 000000000000..1ba44caa24b0
--- /dev/null
+++ b/sd/source/ui/slidesorter/view/SlsLayouter.cxx
@@ -0,0 +1,813 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_sd.hxx"
+
+#include "view/SlsLayouter.hxx"
+
+#include <vcl/outdev.hxx>
+#include <rtl/math.hxx>
+
+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)
+{
+}
+
+
+
+
+Layouter::~Layouter (void)
+{
+}
+
+
+void Layouter::SetObjectWidth (
+ sal_Int32 nMinimalWidth,
+ sal_Int32 nMaximalWidth,
+ sal_Int32 nPreferredWidth)
+{
+ if (nMinimalWidth <= nPreferredWidth && nPreferredWidth <= nMaximalWidth)
+ {
+ mnMinimalWidth = nMinimalWidth;
+ mnPreferredWidth = nMaximalWidth;
+ mnMaximalWidth = nPreferredWidth;
+ }
+}
+
+
+
+
+void Layouter::SetBorders (
+ sal_Int32 nLeftBorder,
+ sal_Int32 nRightBorder,
+ sal_Int32 nTopBorder,
+ sal_Int32 nBottomBorder)
+{
+ if (nLeftBorder >= 0)
+ mnRequestedLeftBorder.mnScreen = nLeftBorder;
+ if (nRightBorder >= 0)
+ mnRequestedRightBorder.mnScreen = nRightBorder;
+ if (nTopBorder >= 0)
+ mnRequestedTopBorder.mnScreen = nTopBorder;
+ if (nBottomBorder >= 0)
+ mnRequestedBottomBorder.mnScreen = nBottomBorder;
+}
+
+
+
+
+void Layouter::SetPageBorders (
+ sal_Int32 nLeftBorder,
+ sal_Int32 nRightBorder,
+ sal_Int32 nTopBorder,
+ sal_Int32 nBottomBorder)
+{
+ if (nLeftBorder >= 0)
+ mnLeftPageBorder.mnScreen = nLeftBorder;
+ if (nRightBorder >= 0)
+ mnRightPageBorder.mnScreen = nRightBorder;
+ if (nTopBorder >= 0)
+ mnTopPageBorder.mnScreen = nTopBorder;
+ if (nBottomBorder >= 0)
+ mnBottomPageBorder.mnScreen = nBottomBorder;
+}
+
+
+
+
+void Layouter::SetGaps (
+ sal_Int32 nHorizontalGap,
+ sal_Int32 nVerticalGap)
+{
+ if (nHorizontalGap >= 0)
+ mnHorizontalGap.mnScreen = nHorizontalGap;
+ if (nVerticalGap >= 0)
+ mnVerticalGap.mnScreen = nVerticalGap;
+}
+
+
+
+
+
+void Layouter::SetColumnCount (
+ sal_Int32 nMinimalColumnCount,
+ sal_Int32 nMaximalColumnCount)
+{
+ if (nMinimalColumnCount <= nMaximalColumnCount)
+ {
+ mnMinimalColumnCount = nMinimalColumnCount;
+ mnMaximalColumnCount = nMaximalColumnCount;
+ }
+}
+
+
+
+
+bool Layouter::RearrangeHorizontal (
+ const Size& rWindowSize,
+ const Size& rPageObjectSize,
+ OutputDevice* pDevice,
+ 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;
+ }
+
+ // 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;
+}
+
+
+
+
+bool Layouter::RearrangeVertical (
+ const Size& rWindowSize,
+ const Size& rPageObjectSize,
+ OutputDevice* pDevice)
+{
+ 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;
+}
+
+
+
+
+void Layouter::SetZoom (double nZoomFactor, OutputDevice* pDevice)
+{
+ SetZoom(Fraction(nZoomFactor), pDevice);
+}
+
+
+
+
+void Layouter::SetZoom (Fraction nZoomFactor, OutputDevice* pDevice)
+{
+ MapMode aMapMode (pDevice->GetMapMode());
+ aMapMode.SetScaleX (nZoomFactor);
+ aMapMode.SetScaleY (nZoomFactor);
+ maPageObjectPixelSize = pDevice->LogicToPixel (maPageObjectModelSize);
+ pDevice->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();
+
+ 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::GetColumnCount (void) const
+{
+ return mnColumnCount;
+}
+
+
+
+
+bool Layouter::IsColumnCountFixed (void) const
+{
+ return mnMinimalColumnCount == mnMaximalColumnCount;
+}
+
+
+
+
+Size Layouter::GetPageObjectSize (void) const
+{
+ return maPageObjectModelSize;
+}
+
+
+
+
+Rectangle Layouter::GetPageObjectBox (sal_Int32 nIndex) 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);
+}
+
+
+
+
+Rectangle Layouter::GetPageBox (sal_Int32 nObjectCount) 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 Rectangle (
+ Point(0,0),
+ Size (nHorizontalSize, nVerticalSize)
+ );
+}
+
+
+
+
+Rectangle Layouter::GetInsertionMarkerBox (
+ sal_Int32 nIndex,
+ bool bVertical,
+ bool bLeftOrTop) const
+{
+ Rectangle aBox (GetPageObjectBox (nIndex));
+
+ 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;
+}
+
+
+
+
+sal_Int32 Layouter::GetIndexOfFirstVisiblePageObject (
+ const Rectangle& aVisibleArea) const
+{
+ sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Top(), true, GM_BOTH);
+ return nRow * mnColumnCount;
+}
+
+
+
+
+sal_Int32 Layouter::GetIndexOfLastVisiblePageObject (
+ const Rectangle& aVisibleArea) const
+{
+ sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Bottom(),
+ true, GM_BOTH);
+ return (nRow+1) * mnColumnCount - 1;
+}
+
+
+
+
+sal_Int32 Layouter::GetIndexAtPoint (
+ const Point& rPosition,
+ bool bIncludePageBorders) 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;
+}
+
+
+
+
+/** 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.
+
+ 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
+{
+ sal_Int32 nIndex = -1;
+
+ 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::DoublePoint
+ Layouter::ConvertModelToLayouterCoordinates (
+ const Point& rModelPoint) const
+{
+ 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));
+}
+
+
+
+
+Point Layouter::ConvertLayouterToModelCoordinates (
+ const DoublePoint & rLayouterPoint) const
+{
+ 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);
+
+ 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 Point (
+ mnLeftBorder.mnModel + mnLeftPageBorder.mnModel
+ + nColumn * nColumnWidth + nDistanceIntoColumn,
+ mnTopBorder.mnModel + mnTopPageBorder.mnModel
+ + nRow * nRowHeight + nDistanceIntoRow);
+}
+
+
+
+
+sal_Int32 Layouter::GetRowAtPosition (
+ sal_Int32 nYPosition,
+ bool bIncludeBordersAndGaps,
+ GapMembership eGapMembership) const
+{
+ sal_Int32 nRow = -1;
+
+ const sal_Int32 nY = nYPosition
+ - mnTopBorder.mnModel - mnTopPageBorder.mnModel;
+ if (nY >= 0)
+ {
+ // Vertical distance from one row to the next.
+ const sal_Int32 nRowOffset (
+ maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel);
+
+ // Calculate row consisting of page objects and gap below.
+ nRow = nY / nRowOffset;
+
+ const sal_Int32 nDistanceIntoGap (
+ (nY - nRow*nRowOffset) - maPageObjectModelSize.Height());
+ // When inside the gap below then nYPosition is not over a page
+ // object.
+ if (nDistanceIntoGap > 0)
+ nRow = ResolvePositionInGap (
+ nDistanceIntoGap,
+ eGapMembership,
+ nRow,
+ mnBottomPageBorder.mnModel,
+ mnVerticalGap.mnModel);
+ }
+ else if (bIncludeBordersAndGaps)
+ {
+ // We are in the top border area. Set nRow to the first row when
+ // the top border shall be considered to belong to the first row.
+ nRow = 0;
+ }
+
+ return nRow;
+}
+
+
+
+
+sal_Int32 Layouter::GetColumnAtPosition (
+ sal_Int32 nXPosition,
+ bool bIncludeBordersAndGaps,
+ GapMembership eGapMembership) const
+{
+ sal_Int32 nColumn = -1;
+
+ sal_Int32 nX = nXPosition
+ - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel;
+ if (nX >= 0)
+ {
+ // Horizontal distance from one column to the next.
+ const sal_Int32 nColumnOffset (
+ maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel);
+
+ // Calculate row consisting of page objects and gap below.
+ nColumn = nX / nColumnOffset;
+ if (nColumn < 0)
+ nColumn = 0;
+ else if (nColumn >= mnColumnCount)
+ nColumn = mnColumnCount-1;
+
+ const sal_Int32 nDistanceIntoGap (
+ (nX - nColumn*nColumnOffset) - maPageObjectModelSize.Width());
+ // When inside the gap at the right then nXPosition is not over a
+ // page object.
+ if (nDistanceIntoGap > 0)
+ nColumn = ResolvePositionInGap (
+ nDistanceIntoGap,
+ eGapMembership,
+ nColumn,
+ mnRightPageBorder.mnModel,
+ mnHorizontalGap.mnModel);
+ }
+ else if (bIncludeBordersAndGaps)
+ {
+ // We are in the left border area. Set nColumn to the first column
+ // when the left border shall be considered to belong to the first
+ // column.
+ nColumn = 0;
+ }
+ return nColumn;
+}
+
+
+
+
+sal_Int32 Layouter::ResolvePositionInGap (
+ sal_Int32 nDistanceIntoGap,
+ GapMembership eGapMembership,
+ sal_Int32 nIndex,
+ sal_Int32 nLeftOrTopPageBorder,
+ sal_Int32 nGap) const
+{
+ switch (eGapMembership)
+ {
+ case GM_NONE:
+ // The gap is no man's land.
+ nIndex = -1;
+ break;
+
+ case GM_BOTH:
+ {
+ // The lower half of the gap belongs to the next row or column.
+ sal_Int32 nFirstHalfGapWidth = nLeftOrTopPageBorder + nGap / 2;
+ if (nDistanceIntoGap > nFirstHalfGapWidth)
+ nIndex ++;
+ break;
+ }
+
+ case GM_PREVIOUS:
+ // Row or column already at correct value.
+ break;
+
+ case GM_NEXT:
+ // The complete gap belongs to the next row or column.
+ nIndex ++;
+ break;
+
+ case GM_PAGE_BORDER:
+ if (nDistanceIntoGap > nLeftOrTopPageBorder)
+ {
+ if (nDistanceIntoGap > nLeftOrTopPageBorder + nGap)
+ {
+ // Inside the border of the next row or column.
+ nIndex ++;
+ }
+ else
+ {
+ // Inside the gap between the page borders.
+ nIndex = -1;
+ }
+ }
+ break;
+
+ default:
+ nIndex = -1;
+ }
+
+ return nIndex;
+}
+
+
+
+
+const Layouter::BackgroundRectangleList&
+ Layouter::GetBackgroundRectangleList (void) const
+{
+ return maBackgroundRectangleList;
+}
+
+
+
+
+} } } // end of namespace ::sd::slidesorter::namespace