Update ooo320-m1
[ooovba.git] / sd / source / ui / slidesorter / view / SlsLayouter.cxx
blob2b5e59d7e3e0076f30b9e19099625a4420fd2005
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SlsLayouter.cxx,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "precompiled_sd.hxx"
33 #include "view/SlsLayouter.hxx"
35 #include <vcl/outdev.hxx>
36 #include <rtl/math.hxx>
38 namespace sd { namespace slidesorter { namespace view {
40 Layouter::Layouter (void)
41 : mnRequestedLeftBorder(10),
42 mnRequestedRightBorder(10),
43 mnRequestedTopBorder(10),
44 mnRequestedBottomBorder(10),
45 mnLeftBorder(10),
46 mnRightBorder(10),
47 mnTopBorder(10),
48 mnBottomBorder(10),
49 mnLeftPageBorder(0),
50 mnRightPageBorder(0),
51 mnTopPageBorder(0),
52 mnBottomPageBorder(0),
53 mnVerticalGap (20),
54 mnHorizontalGap (20),
55 mnInsertionMarkerThickness (4),
56 mnTotalVerticalGap(0),
57 mnTotalHorizontalGap(0),
58 mnMinimalWidth (100),
59 mnPreferredWidth (200),
60 mnMaximalWidth (300),
61 mnMinimalColumnCount (1),
62 mnMaximalColumnCount (5),
63 mnColumnCount (1),
64 maPageObjectModelSize (1,1),
65 maPageObjectPixelSize (1,1)
72 Layouter::~Layouter (void)
77 void Layouter::SetObjectWidth (
78 sal_Int32 nMinimalWidth,
79 sal_Int32 nMaximalWidth,
80 sal_Int32 nPreferredWidth)
82 if (nMinimalWidth <= nPreferredWidth && nPreferredWidth <= nMaximalWidth)
84 mnMinimalWidth = nMinimalWidth;
85 mnPreferredWidth = nMaximalWidth;
86 mnMaximalWidth = nPreferredWidth;
93 void Layouter::SetBorders (
94 sal_Int32 nLeftBorder,
95 sal_Int32 nRightBorder,
96 sal_Int32 nTopBorder,
97 sal_Int32 nBottomBorder)
99 if (nLeftBorder >= 0)
100 mnRequestedLeftBorder.mnScreen = nLeftBorder;
101 if (nRightBorder >= 0)
102 mnRequestedRightBorder.mnScreen = nRightBorder;
103 if (nTopBorder >= 0)
104 mnRequestedTopBorder.mnScreen = nTopBorder;
105 if (nBottomBorder >= 0)
106 mnRequestedBottomBorder.mnScreen = nBottomBorder;
112 void Layouter::SetPageBorders (
113 sal_Int32 nLeftBorder,
114 sal_Int32 nRightBorder,
115 sal_Int32 nTopBorder,
116 sal_Int32 nBottomBorder)
118 if (nLeftBorder >= 0)
119 mnLeftPageBorder.mnScreen = nLeftBorder;
120 if (nRightBorder >= 0)
121 mnRightPageBorder.mnScreen = nRightBorder;
122 if (nTopBorder >= 0)
123 mnTopPageBorder.mnScreen = nTopBorder;
124 if (nBottomBorder >= 0)
125 mnBottomPageBorder.mnScreen = nBottomBorder;
131 void Layouter::SetGaps (
132 sal_Int32 nHorizontalGap,
133 sal_Int32 nVerticalGap)
135 if (nHorizontalGap >= 0)
136 mnHorizontalGap.mnScreen = nHorizontalGap;
137 if (nVerticalGap >= 0)
138 mnVerticalGap.mnScreen = nVerticalGap;
145 void Layouter::SetColumnCount (
146 sal_Int32 nMinimalColumnCount,
147 sal_Int32 nMaximalColumnCount)
149 if (nMinimalColumnCount <= nMaximalColumnCount)
151 mnMinimalColumnCount = nMinimalColumnCount;
152 mnMaximalColumnCount = nMaximalColumnCount;
159 bool Layouter::RearrangeHorizontal (
160 const Size& rWindowSize,
161 const Size& rPageObjectSize,
162 OutputDevice* pDevice,
163 const sal_uInt32 nPageCount)
165 if (rWindowSize.Width() > 0
166 && rWindowSize.Height() > 0
167 && rPageObjectSize.Width() > 0
168 && rPageObjectSize.Height() > 0)
170 mnTotalHorizontalGap.mnScreen = mnHorizontalGap.mnScreen
171 + mnRightPageBorder.mnScreen + mnLeftPageBorder.mnScreen;
172 mnTotalVerticalGap.mnScreen = mnVerticalGap.mnScreen
173 + mnTopPageBorder.mnScreen + mnBottomPageBorder.mnScreen;
175 // Calculate the column count.
176 mnColumnCount = nPageCount;
178 // Update the border values. The insertion marker has to have space.
179 mnLeftBorder.mnScreen = mnRequestedLeftBorder.mnScreen;
180 mnTopBorder.mnScreen = mnRequestedTopBorder.mnScreen;
181 mnRightBorder.mnScreen = mnRequestedRightBorder.mnScreen;
182 mnBottomBorder.mnScreen = mnRequestedBottomBorder.mnScreen;
183 if (mnColumnCount > 1)
185 int nMinimumBorderWidth = mnInsertionMarkerThickness.mnScreen
186 + mnHorizontalGap.mnScreen/2;
187 if (mnLeftBorder.mnScreen < nMinimumBorderWidth)
188 mnLeftBorder.mnScreen = nMinimumBorderWidth;
189 if (mnRightBorder.mnScreen < nMinimumBorderWidth)
190 mnRightBorder.mnScreen = nMinimumBorderWidth;
192 else
194 int nMinimumBorderHeight = mnInsertionMarkerThickness.mnScreen
195 + mnVerticalGap.mnScreen/2;
196 if (mnTopBorder.mnScreen < nMinimumBorderHeight)
197 mnTopBorder.mnScreen = nMinimumBorderHeight;
198 if (mnBottomBorder.mnScreen < nMinimumBorderHeight)
199 mnBottomBorder.mnScreen = nMinimumBorderHeight;
202 // Calculate the width of each page object.
203 sal_uInt32 nTargetHeight = 0;
204 sal_uInt32 nRowCount = 1;
205 if (mnColumnCount > 0)
206 nTargetHeight = (rWindowSize.Height()
207 - mnTopBorder.mnScreen
208 - mnBottomBorder.mnScreen
209 - nRowCount * (mnTopPageBorder.mnScreen
210 + mnBottomPageBorder.mnScreen)
211 - (nRowCount-1) * mnTotalVerticalGap.mnScreen
213 / nRowCount;
214 sal_uInt32 nMinimalHeight (
215 mnMinimalWidth * rPageObjectSize.Height() / rPageObjectSize.Width());
216 sal_uInt32 nMaximalHeight (
217 mnMaximalWidth * rPageObjectSize.Height() / rPageObjectSize.Width());
218 if (nTargetHeight < nMinimalHeight)
219 nTargetHeight = nMinimalHeight;
220 if (nTargetHeight > nMaximalHeight)
221 nTargetHeight = nMaximalHeight;
223 // Initialize the device with some arbitrary zoom factor just in
224 // case that the current zoom factor is numerically instable when
225 // used in a multiplication.
226 MapMode aMapMode (pDevice->GetMapMode());
227 aMapMode.SetScaleX (Fraction(1,1));
228 aMapMode.SetScaleY (Fraction(1,1));
229 pDevice->SetMapMode (aMapMode);
231 // Calculate the resulting scale factor and the page object size in
232 // pixels.
233 maPageObjectModelSize = rPageObjectSize;
234 int nPagePixelHeight (pDevice->LogicToPixel(maPageObjectModelSize).Height());
236 // Adapt the layout of the given output device to the new layout of
237 // page objects. The zoom factor is set so that the page objects in
238 // one column fill the screen.
239 Fraction aScaleFactor (nTargetHeight, nPagePixelHeight);
240 SetZoom (aMapMode.GetScaleX() * aScaleFactor, pDevice);
242 return true;
244 else
245 return false;
251 bool Layouter::RearrangeVertical (
252 const Size& rWindowSize,
253 const Size& rPageObjectSize,
254 OutputDevice* pDevice)
256 if (rWindowSize.Width() > 0
257 && rWindowSize.Height() > 0
258 && rPageObjectSize.Width() > 0
259 && rPageObjectSize.Height() > 0)
261 mnTotalHorizontalGap.mnScreen = mnHorizontalGap.mnScreen
262 + mnRightPageBorder.mnScreen + mnLeftPageBorder.mnScreen;
263 mnTotalVerticalGap.mnScreen = mnVerticalGap.mnScreen
264 + mnTopPageBorder.mnScreen + mnBottomPageBorder.mnScreen;
266 // Calculate the column count.
267 mnColumnCount = (rWindowSize.Width()
268 - mnRequestedLeftBorder.mnScreen - mnRequestedRightBorder.mnScreen)
269 / (mnPreferredWidth + mnTotalHorizontalGap.mnScreen);
270 if (mnColumnCount < mnMinimalColumnCount)
271 mnColumnCount = mnMinimalColumnCount;
272 if (mnColumnCount > mnMaximalColumnCount)
273 mnColumnCount = mnMaximalColumnCount;
275 // Update the border values. The insertion marker has to have space.
276 mnLeftBorder.mnScreen = mnRequestedLeftBorder.mnScreen;
277 mnTopBorder.mnScreen = mnRequestedTopBorder.mnScreen;
278 mnRightBorder.mnScreen = mnRequestedRightBorder.mnScreen;
279 mnBottomBorder.mnScreen = mnRequestedBottomBorder.mnScreen;
280 if (mnColumnCount > 1)
282 int nMinimumBorderWidth = mnInsertionMarkerThickness.mnScreen
283 + mnHorizontalGap.mnScreen/2;
284 if (mnLeftBorder.mnScreen < nMinimumBorderWidth)
285 mnLeftBorder.mnScreen = nMinimumBorderWidth;
286 if (mnRightBorder.mnScreen < nMinimumBorderWidth)
287 mnRightBorder.mnScreen = nMinimumBorderWidth;
289 else
291 int nMinimumBorderHeight = mnInsertionMarkerThickness.mnScreen
292 + mnVerticalGap.mnScreen/2;
293 if (mnTopBorder.mnScreen < nMinimumBorderHeight)
294 mnTopBorder.mnScreen = nMinimumBorderHeight;
295 if (mnBottomBorder.mnScreen < nMinimumBorderHeight)
296 mnBottomBorder.mnScreen = nMinimumBorderHeight;
299 // Calculate the width of each page object.
300 sal_Int32 nTargetWidth = 0;
301 if (mnColumnCount > 0)
302 nTargetWidth = (rWindowSize.Width()
303 - mnLeftBorder.mnScreen
304 - mnRightBorder.mnScreen
305 - mnColumnCount * (mnRightPageBorder.mnScreen
306 + mnLeftPageBorder.mnScreen)
307 - (mnColumnCount-1) * mnTotalHorizontalGap.mnScreen
309 / mnColumnCount;
310 if (nTargetWidth < mnMinimalWidth)
311 nTargetWidth = mnMinimalWidth;
312 if (nTargetWidth > mnMaximalWidth)
313 nTargetWidth = mnMaximalWidth;
315 // Initialize the device with some arbitrary zoom factor just in
316 // case that the current zoom factor is numerically instable when
317 // used in a multiplication.
318 MapMode aMapMode (pDevice->GetMapMode());
319 aMapMode.SetScaleX (Fraction(1,1));
320 aMapMode.SetScaleY (Fraction(1,1));
321 pDevice->SetMapMode (aMapMode);
323 // Calculate the resulting scale factor and the page object size in
324 // pixels.
325 maPageObjectModelSize = rPageObjectSize;
326 int nPagePixelWidth (pDevice->LogicToPixel (maPageObjectModelSize).Width());
328 // Adapt the layout of the given output device to the new layout of
329 // page objects. The zoom factor is set so that the page objects in
330 // one row fill the screen.
331 Fraction aScaleFactor (nTargetWidth, nPagePixelWidth);
332 SetZoom (aMapMode.GetScaleX() * aScaleFactor, pDevice);
334 return true;
336 else
337 return false;
343 void Layouter::SetZoom (double nZoomFactor, OutputDevice* pDevice)
345 SetZoom(Fraction(nZoomFactor), pDevice);
351 void Layouter::SetZoom (Fraction nZoomFactor, OutputDevice* pDevice)
353 MapMode aMapMode (pDevice->GetMapMode());
354 aMapMode.SetScaleX (nZoomFactor);
355 aMapMode.SetScaleY (nZoomFactor);
356 maPageObjectPixelSize = pDevice->LogicToPixel (maPageObjectModelSize);
357 pDevice->SetMapMode (aMapMode);
359 // Transform frequently used values from pixel to model coordinates.
361 Size aTotalGap (pDevice->PixelToLogic (Size (
362 mnTotalHorizontalGap.mnScreen,
363 mnTotalVerticalGap.mnScreen)));
364 mnTotalHorizontalGap.mnModel = aTotalGap.Width();
365 mnTotalVerticalGap.mnModel = aTotalGap.Height();
367 Size aGap (pDevice->PixelToLogic (Size (
368 mnHorizontalGap.mnScreen,
369 mnVerticalGap.mnScreen)));
370 mnHorizontalGap.mnModel = aGap.Width();
371 mnVerticalGap.mnModel = aGap.Height();
373 Size aTopLeftBorder (pDevice->PixelToLogic (Size (
374 mnLeftBorder.mnScreen,
375 mnTopBorder.mnScreen)));
376 mnLeftBorder.mnModel = aTopLeftBorder.Width();
377 mnTopBorder.mnModel = aTopLeftBorder.Height();
379 Size aBottomRightBorder (pDevice->PixelToLogic (Size (
380 mnLeftBorder.mnScreen,
381 mnTopBorder.mnScreen)));
382 mnRightBorder.mnModel = aBottomRightBorder.Width();
383 mnBottomBorder.mnModel = aBottomRightBorder.Height();
385 Size aTopLeftPageBorder (pDevice->PixelToLogic (Size (
386 mnLeftPageBorder.mnScreen,
387 mnTopPageBorder.mnScreen)));
388 mnLeftPageBorder.mnModel = aTopLeftPageBorder.Width();
389 mnTopPageBorder.mnModel = aTopLeftPageBorder.Height();
391 Size aBottomRightPageBorder (pDevice->PixelToLogic (Size (
392 mnRightPageBorder.mnScreen,
393 mnBottomPageBorder.mnScreen)));
394 mnRightPageBorder.mnModel = aBottomRightPageBorder.Width();
395 mnBottomPageBorder.mnModel = aBottomRightPageBorder.Height();
397 mnInsertionMarkerThickness.mnModel = pDevice->PixelToLogic (
398 Size(mnInsertionMarkerThickness.mnScreen,0)).Width();
404 sal_Int32 Layouter::GetColumnCount (void) const
406 return mnColumnCount;
412 bool Layouter::IsColumnCountFixed (void) const
414 return mnMinimalColumnCount == mnMaximalColumnCount;
420 Size Layouter::GetPageObjectSize (void) const
422 return maPageObjectModelSize;
428 Rectangle Layouter::GetPageObjectBox (sal_Int32 nIndex) const
430 int nColumn = nIndex % mnColumnCount;
431 int nRow = nIndex / mnColumnCount;
432 return Rectangle (
433 Point (mnLeftBorder.mnModel
434 + nColumn * maPageObjectModelSize.Width()
435 + mnLeftPageBorder.mnModel
436 + (nColumn>0 ? nColumn : 0) * mnTotalHorizontalGap.mnModel,
437 mnTopBorder.mnModel
438 + nRow * maPageObjectModelSize.Height()
439 + mnTopPageBorder.mnModel
440 + (nRow>0 ? nRow : 0) * mnTotalVerticalGap.mnModel),
441 maPageObjectModelSize);
447 Rectangle Layouter::GetPageBox (sal_Int32 nObjectCount) const
449 sal_Int32 nHorizontalSize = 0;
450 sal_Int32 nVerticalSize = 0;
451 if (mnColumnCount > 0)
453 sal_Int32 nRowCount = (nObjectCount+mnColumnCount-1) / mnColumnCount;
454 nHorizontalSize =
455 mnLeftBorder.mnModel
456 + mnRightBorder.mnModel
457 + mnColumnCount * maPageObjectModelSize.Width()
458 + mnLeftPageBorder.mnModel + mnRightPageBorder.mnModel;
459 if (mnColumnCount > 1)
460 nHorizontalSize
461 += (mnColumnCount-1) * mnTotalHorizontalGap.mnModel;
462 nVerticalSize =
463 mnTopBorder.mnModel
464 + mnBottomBorder.mnModel
465 + nRowCount * maPageObjectModelSize.Height()
466 + mnTopPageBorder.mnModel + mnBottomPageBorder.mnModel;
467 if (nRowCount > 1)
468 nVerticalSize += (nRowCount-1) * mnTotalVerticalGap.mnModel;
471 return Rectangle (
472 Point(0,0),
473 Size (nHorizontalSize, nVerticalSize)
480 Rectangle Layouter::GetInsertionMarkerBox (
481 sal_Int32 nIndex,
482 bool bVertical,
483 bool bLeftOrTop) const
485 Rectangle aBox (GetPageObjectBox (nIndex));
487 if (bVertical)
489 sal_Int32 nHorizontalInsertionMarkerOffset
490 = (mnHorizontalGap.mnModel-mnInsertionMarkerThickness.mnModel) / 2;
491 if (bLeftOrTop)
493 // Left.
494 aBox.Left() -= mnLeftPageBorder.mnModel
495 + mnHorizontalGap.mnModel
496 - nHorizontalInsertionMarkerOffset;
498 else
500 // Right.
501 aBox.Left() = aBox.Right()
502 + mnRightPageBorder.mnModel
503 + nHorizontalInsertionMarkerOffset;
505 aBox.Right() = aBox.Left() + mnInsertionMarkerThickness.mnModel;
507 else
509 sal_Int32 nVerticalInsertionMarkerOffset
510 = (mnVerticalGap.mnModel - mnInsertionMarkerThickness.mnModel) / 2;
511 if (bLeftOrTop)
513 // Above.
514 aBox.Top() -= mnTopPageBorder.mnModel
515 + mnVerticalGap.mnModel
516 - nVerticalInsertionMarkerOffset;
518 else
520 // Below.
521 aBox.Top() = aBox.Bottom()
522 + mnBottomPageBorder.mnModel
523 + nVerticalInsertionMarkerOffset;
525 aBox.Bottom() = aBox.Top() + mnInsertionMarkerThickness.mnModel;
528 return aBox;
534 sal_Int32 Layouter::GetIndexOfFirstVisiblePageObject (
535 const Rectangle& aVisibleArea) const
537 sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Top(), true, GM_BOTH);
538 return nRow * mnColumnCount;
544 sal_Int32 Layouter::GetIndexOfLastVisiblePageObject (
545 const Rectangle& aVisibleArea) const
547 sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Bottom(),
548 true, GM_BOTH);
549 return (nRow+1) * mnColumnCount - 1;
555 sal_Int32 Layouter::GetIndexAtPoint (
556 const Point& rPosition,
557 bool bIncludePageBorders) const
559 sal_Int32 nRow = GetRowAtPosition (rPosition.Y(),
560 bIncludePageBorders,
561 bIncludePageBorders ? GM_PAGE_BORDER : GM_NONE);
562 sal_Int32 nColumn = GetColumnAtPosition (rPosition.X(),
563 bIncludePageBorders,
564 bIncludePageBorders ? GM_PAGE_BORDER : GM_NONE);
566 if (nRow >= 0 && nColumn >= 0)
567 return nRow * mnColumnCount + nColumn;
568 else
569 return -1;
575 /** Calculation of the insertion index:
576 1. Determine the row. rPoint has to be in the row between upper and
577 lower border. If it is in a horizontal gap or border an invalid
578 insertion index (-1, which is a valid return value) will be returned.
579 2. Determine the column. Here both vertical borders and vertical gaps
580 will yield valid return values. The horizontal positions between the
581 center of page objects in column i and the center of page objects in
582 column i+1 will return column i+1 as insertion index.
584 When there is only one column and bAllowVerticalPosition is true than
585 take the vertical areas between rows into account as well.
587 sal_Int32 Layouter::GetInsertionIndex (
588 const Point& rPosition,
589 bool bAllowVerticalPosition) const
591 sal_Int32 nIndex = -1;
593 sal_Int32 nRow = GetRowAtPosition (rPosition.Y(), true,
594 (mnColumnCount==1 && bAllowVerticalPosition) ? GM_BOTH : GM_BOTH);
595 sal_Int32 nColumn = GetColumnAtPosition (rPosition.X(), true, GM_BOTH);
597 if (nRow >= 0 && nColumn >= 0)
598 nIndex = nRow * mnColumnCount + nColumn;
600 return nIndex;
606 Layouter::DoublePoint
607 Layouter::ConvertModelToLayouterCoordinates (
608 const Point& rModelPoint) const
610 sal_Int32 nColumn = GetColumnAtPosition (rModelPoint.X(), true, GM_BOTH);
611 sal_Int32 nColumnWidth
612 = maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel;
613 sal_Int32 nDistanceIntoColumn =
614 rModelPoint.X() - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel
615 - nColumn * nColumnWidth;
617 sal_Int32 nRow = GetRowAtPosition (rModelPoint.Y(), true, GM_BOTH);
618 sal_Int32 nRowHeight
619 = maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel;
620 sal_Int32 nDistanceIntoRow =
621 rModelPoint.Y() - mnTopBorder.mnModel - mnTopPageBorder.mnModel
622 - nRow * nRowHeight;
624 return DoublePoint (
625 nColumn + double(nDistanceIntoColumn) / double(nColumnWidth),
626 nRow + double(nDistanceIntoRow) / double(nRowHeight));
632 Point Layouter::ConvertLayouterToModelCoordinates (
633 const DoublePoint & rLayouterPoint) const
635 sal_Int32 nColumn = (sal_Int32) ::rtl::math::round(rLayouterPoint.first,
636 0,rtl_math_RoundingMode_Floor);
637 sal_Int32 nColumnWidth
638 = maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel;
639 sal_Int32 nDistanceIntoColumn
640 = (sal_Int32)((rLayouterPoint.first - nColumn) * nColumnWidth);
642 sal_Int32 nRow = (sal_Int32) ::rtl::math::round(rLayouterPoint.second,
643 0,rtl_math_RoundingMode_Floor);
644 sal_Int32 nRowHeight
645 = maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel;
646 sal_Int32 nDistanceIntoRow
647 = (sal_Int32)((rLayouterPoint.second - nRow) * nRowHeight);
649 return Point (
650 mnLeftBorder.mnModel + mnLeftPageBorder.mnModel
651 + nColumn * nColumnWidth + nDistanceIntoColumn,
652 mnTopBorder.mnModel + mnTopPageBorder.mnModel
653 + nRow * nRowHeight + nDistanceIntoRow);
659 sal_Int32 Layouter::GetRowAtPosition (
660 sal_Int32 nYPosition,
661 bool bIncludeBordersAndGaps,
662 GapMembership eGapMembership) const
664 sal_Int32 nRow = -1;
666 const sal_Int32 nY = nYPosition
667 - mnTopBorder.mnModel - mnTopPageBorder.mnModel;
668 if (nY >= 0)
670 // Vertical distance from one row to the next.
671 const sal_Int32 nRowOffset (
672 maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel);
674 // Calculate row consisting of page objects and gap below.
675 nRow = nY / nRowOffset;
677 const sal_Int32 nDistanceIntoGap (
678 (nY - nRow*nRowOffset) - maPageObjectModelSize.Height());
679 // When inside the gap below then nYPosition is not over a page
680 // object.
681 if (nDistanceIntoGap > 0)
682 nRow = ResolvePositionInGap (
683 nDistanceIntoGap,
684 eGapMembership,
685 nRow,
686 mnBottomPageBorder.mnModel,
687 mnVerticalGap.mnModel);
689 else if (bIncludeBordersAndGaps)
691 // We are in the top border area. Set nRow to the first row when
692 // the top border shall be considered to belong to the first row.
693 nRow = 0;
696 return nRow;
702 sal_Int32 Layouter::GetColumnAtPosition (
703 sal_Int32 nXPosition,
704 bool bIncludeBordersAndGaps,
705 GapMembership eGapMembership) const
707 sal_Int32 nColumn = -1;
709 sal_Int32 nX = nXPosition
710 - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel;
711 if (nX >= 0)
713 // Horizontal distance from one column to the next.
714 const sal_Int32 nColumnOffset (
715 maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel);
717 // Calculate row consisting of page objects and gap below.
718 nColumn = nX / nColumnOffset;
719 if (nColumn < 0)
720 nColumn = 0;
721 else if (nColumn >= mnColumnCount)
722 nColumn = mnColumnCount-1;
724 const sal_Int32 nDistanceIntoGap (
725 (nX - nColumn*nColumnOffset) - maPageObjectModelSize.Width());
726 // When inside the gap at the right then nXPosition is not over a
727 // page object.
728 if (nDistanceIntoGap > 0)
729 nColumn = ResolvePositionInGap (
730 nDistanceIntoGap,
731 eGapMembership,
732 nColumn,
733 mnRightPageBorder.mnModel,
734 mnHorizontalGap.mnModel);
736 else if (bIncludeBordersAndGaps)
738 // We are in the left border area. Set nColumn to the first column
739 // when the left border shall be considered to belong to the first
740 // column.
741 nColumn = 0;
743 return nColumn;
749 sal_Int32 Layouter::ResolvePositionInGap (
750 sal_Int32 nDistanceIntoGap,
751 GapMembership eGapMembership,
752 sal_Int32 nIndex,
753 sal_Int32 nLeftOrTopPageBorder,
754 sal_Int32 nGap) const
756 switch (eGapMembership)
758 case GM_NONE:
759 // The gap is no man's land.
760 nIndex = -1;
761 break;
763 case GM_BOTH:
765 // The lower half of the gap belongs to the next row or column.
766 sal_Int32 nFirstHalfGapWidth = nLeftOrTopPageBorder + nGap / 2;
767 if (nDistanceIntoGap > nFirstHalfGapWidth)
768 nIndex ++;
769 break;
772 case GM_PREVIOUS:
773 // Row or column already at correct value.
774 break;
776 case GM_NEXT:
777 // The complete gap belongs to the next row or column.
778 nIndex ++;
779 break;
781 case GM_PAGE_BORDER:
782 if (nDistanceIntoGap > nLeftOrTopPageBorder)
784 if (nDistanceIntoGap > nLeftOrTopPageBorder + nGap)
786 // Inside the border of the next row or column.
787 nIndex ++;
789 else
791 // Inside the gap between the page borders.
792 nIndex = -1;
795 break;
797 default:
798 nIndex = -1;
801 return nIndex;
807 const Layouter::BackgroundRectangleList&
808 Layouter::GetBackgroundRectangleList (void) const
810 return maBackgroundRectangleList;
816 } } } // end of namespace ::sd::slidesorter::namespace