1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "view/SlsLayouter.hxx"
21 #include "model/SlideSorterModel.hxx"
22 #include "model/SlsPageDescriptor.hxx"
24 #include <rtl/math.hxx>
25 #include <basegfx/numeric/ftools.hxx>
27 namespace sd
{ namespace slidesorter
{ namespace view
{
29 class Layouter::Implementation
32 VclPtr
<sd::Window
> mpWindow
;
33 sal_Int32 mnRequestedLeftBorder
;
34 sal_Int32 mnRequestedRightBorder
;
35 sal_Int32 mnRequestedTopBorder
;
36 sal_Int32 mnRequestedBottomBorder
;
37 sal_Int32 mnLeftBorder
;
38 sal_Int32 mnRightBorder
;
39 sal_Int32 mnTopBorder
;
40 sal_Int32 mnBottomBorder
;
41 sal_Int32 mnVerticalGap
;
42 sal_Int32 mnHorizontalGap
;
46 sal_Int32 mnMinimalColumnCount
;
47 sal_Int32 mnMaximalColumnCount
;
48 sal_Int32 mnPageCount
;
49 sal_Int32 mnColumnCount
;
51 /// The maximum number of columns. Can only be larger than the current
52 /// number of columns when there are not enough pages to fill all
53 /// available columns.
54 sal_Int32 mnMaxColumnCount
;
55 /// The maximum number of rows. Can only be larger than the current
56 /// number of rows when there are not enough pages to fill all available
58 sal_Int32 mnMaxRowCount
;
59 Size maPageObjectSize
;
60 ::boost::shared_ptr
<PageObjectLayouter
> mpPageObjectLayouter
;
61 ::boost::shared_ptr
<view::Theme
> mpTheme
;
63 /** Specify how the gap between two page objects is associated with the
67 GM_NONE
, // Gap is not associated with any page object.
68 GM_PREVIOUS
, // The whole gap is associated with the previous page
69 // object (left or above the gap.)
70 GM_BOTH
, // Half of the gap is associated with previous, half
71 // with the next page object.
72 GM_NEXT
, // The whole gap is associated with the next page
73 // object (right or below the gap.)
77 static Implementation
* Create (
78 const Implementation
& rImplementation
,
79 const Layouter::Orientation eOrientation
);
81 virtual Layouter::Orientation
GetOrientation() const = 0;
84 const Size
& rWindowSize
,
85 const Size
& rPreviewModelSize
,
86 const sal_uInt32 nPageCount
);
88 /** Calculate the row that the point with the given vertical coordinate
89 is over. The horizontal component is ignored.
91 Vertical position in model coordinates.
92 @param bIncludeBordersAndGaps
93 When this flag is <TRUE/> then the area of borders and gaps are
94 interpreted as belonging to one of the rows.
96 Specifies to what row the gap areas belong. Here GM_NONE
97 corresponds to bIncludeBordersAndGaps being <FALSE/>. When
98 GM_BOTH is given then the upper half is associated to the row
99 above and the lower half to the row below. Values of
100 GM_PREVIOUS and GM_NEXT associate the whole gap area with the
101 row above or below respectively.
103 sal_Int32
GetRowAtPosition (
104 sal_Int32 nYPosition
,
105 bool bIncludeBordersAndGaps
,
106 GapMembership eGapMembership
= GM_NONE
) const;
108 /** Calculate the column that the point with the given horizontal
109 coordinate is over. The vertical component is ignored.
111 Horizontal position in model coordinates.
112 @param bIncludeBordersAndGaps
113 When this flag is <TRUE/> then the area of borders and gaps are
114 interpreted as belonging to one of the columns.
115 @param eGapMembership
116 Specifies to what column the gap areas belong.
118 sal_Int32
GetColumnAtPosition (
119 sal_Int32 nXPosition
,
120 bool bIncludeBordersAndGaps
,
121 GapMembership eGapMembership
= GM_NONE
) const;
123 /** This method is typically called from GetRowAtPosition() and
124 GetColumnAtPosition() to handle a position that lies inside the gap
125 between two adjacent rows or columns.
126 @param nDistanceIntoGap
127 Vertical distance from the bottom of the upper row down into the
128 gap or horizontal distance from the right edge right into the
130 @param eGapMemberhship
131 This value decides what areas in the gap belong to which (or no)
134 The row index of the upper row or the column index of the left
137 Width or height of the gap in model coordiantes between the
140 Returns either the index of the upper row (as given as nRow), the
141 index of the lower row (nRow+1) or -1 to indicate that the
142 position belongs to no row.
144 static sal_Int32
ResolvePositionInGap (
145 sal_Int32 nDistanceIntoGap
,
146 GapMembership eGapMembership
,
150 /** Calculate the logical part of the insert position, i.e. the page
151 after whicht to insert.
153 virtual void CalculateLogicalInsertPosition (
154 const Point
& rModelPosition
,
155 InsertPosition
& rPosition
) const = 0;
157 /** Calculate the geometrical part of the insert position, i.e. the
158 location of where to display the insertion indicator and the
159 distances about which the leading and trailing pages have to be
160 moved to make room for the indicator.
162 void CalculateGeometricPosition (
163 InsertPosition
& rPosition
,
164 const Size
& rIndicatorSize
,
165 const bool bIsVertical
,
166 model::SlideSorterModel
& rModel
) const;
168 /** Return the bounding box of the preview or, when selected, of the page
169 object. Thus, it returns something like a visual bounding box.
171 Rectangle
GetInnerBoundingBox (
172 model::SlideSorterModel
& rModel
,
173 const sal_Int32 nIndex
) const;
175 Range
GetValidHorizontalSizeRange() const;
176 Range
GetValidVerticalSizeRange() const;
178 Range
GetRangeOfVisiblePageObjects (const Rectangle
& aVisibleArea
) const;
180 const sal_Int32 nRow
,
181 const sal_Int32 nColumn
,
182 const bool bClampToValidRange
) const;
184 Rectangle
GetPageObjectBox (
185 const sal_Int32 nIndex
,
186 const bool bIncludeBorderAndGap
= false) const;
188 Rectangle
GetPageObjectBox (
189 const sal_Int32 nRow
,
190 const sal_Int32 nColumn
) const;
192 Rectangle
AddBorderAndGap (
193 const Rectangle
& rBoundingBox
,
194 const sal_Int32 nRow
,
195 const sal_Int32 nColumn
) const;
197 Rectangle
GetTotalBoundingBox() const;
199 virtual ~Implementation();
204 const ::boost::shared_ptr
<view::Theme
>& rpTheme
);
205 Implementation (const Implementation
& rImplementation
);
207 virtual void CalculateRowAndColumnCount (const Size
& rWindowSize
) = 0;
208 virtual void CalculateMaxRowAndColumnCount (const Size
& rWindowSize
) = 0;
209 virtual Size
CalculateTargetSize (
210 const Size
& rWindowSize
,
211 const Size
& rPreviewModelSize
) const = 0;
213 const Size
& rWindowSize
,
214 const Size
& rPreviewModelSize
,
215 const bool bCalculateWidth
,
216 const bool bCalculateHeight
) const;
217 void CalculateVerticalLogicalInsertPosition (
218 const Point
& rModelPosition
,
219 InsertPosition
& rPosition
) const;
222 /** The vertical layouter has one column and as many rows as there are
225 class VerticalImplementation
: public Layouter::Implementation
228 VerticalImplementation (const Implementation
& rImplementation
);
230 virtual Layouter::Orientation
GetOrientation() const SAL_OVERRIDE
;
232 void CalculateLogicalInsertPosition (
233 const Point
& rModelPosition
,
234 InsertPosition
& rPosition
) const SAL_OVERRIDE
;
237 virtual void CalculateRowAndColumnCount (const Size
& rWindowSize
) SAL_OVERRIDE
;
238 virtual void CalculateMaxRowAndColumnCount (const Size
& rWindowSize
) SAL_OVERRIDE
;
239 virtual Size
CalculateTargetSize (
240 const Size
& rWindowSize
,
241 const Size
& rPreviewModelSize
) const SAL_OVERRIDE
;
244 /** The horizontal layouter has one row and as many columns as there are
247 class HorizontalImplementation
: public Layouter::Implementation
250 HorizontalImplementation (const Implementation
& rImplementation
);
252 virtual Layouter::Orientation
GetOrientation() const SAL_OVERRIDE
;
254 void CalculateLogicalInsertPosition (
255 const Point
& rModelPosition
,
256 InsertPosition
& rPosition
) const SAL_OVERRIDE
;
259 virtual void CalculateRowAndColumnCount (const Size
& rWindowSize
) SAL_OVERRIDE
;
260 virtual void CalculateMaxRowAndColumnCount (const Size
& rWindowSize
) SAL_OVERRIDE
;
261 virtual Size
CalculateTargetSize (
262 const Size
& rWindowSize
,
263 const Size
& rPreviewModelSize
) const SAL_OVERRIDE
;
266 /** The number of columns of the grid layouter is defined via a control in
267 the slide sorter tool bar. The number of rows is calculated from the
268 number of columns and the number of pages.
270 class GridImplementation
: public Layouter::Implementation
275 const ::boost::shared_ptr
<view::Theme
>& rpTheme
);
276 GridImplementation (const Implementation
& rImplementation
);
278 virtual Layouter::Orientation
GetOrientation() const SAL_OVERRIDE
;
280 void CalculateLogicalInsertPosition (
281 const Point
& rModelPosition
,
282 InsertPosition
& rPosition
) const SAL_OVERRIDE
;
285 virtual void CalculateRowAndColumnCount (const Size
& rWindowSize
) SAL_OVERRIDE
;
286 virtual void CalculateMaxRowAndColumnCount (const Size
& rWindowSize
) SAL_OVERRIDE
;
287 virtual Size
CalculateTargetSize (
288 const Size
& rWindowSize
,
289 const Size
& rPreviewModelSize
) const SAL_OVERRIDE
;
292 //===== Layouter ==============================================================
296 const ::boost::shared_ptr
<Theme
>& rpTheme
)
297 : mpImplementation(new GridImplementation(pWindow
, rpTheme
)),
302 Layouter::~Layouter()
306 ::boost::shared_ptr
<PageObjectLayouter
> Layouter::GetPageObjectLayouter() const
308 return mpImplementation
->mpPageObjectLayouter
;
311 void Layouter::SetColumnCount (
312 sal_Int32 nMinimalColumnCount
,
313 sal_Int32 nMaximalColumnCount
)
315 if (nMinimalColumnCount
<= nMaximalColumnCount
)
317 mpImplementation
->mnMinimalColumnCount
= nMinimalColumnCount
;
318 mpImplementation
->mnMaximalColumnCount
= nMaximalColumnCount
;
322 bool Layouter::Rearrange (
323 const Orientation eOrientation
,
324 const Size
& rWindowSize
,
325 const Size
& rPageSize
,
326 const sal_uInt32 nPageCount
)
328 OSL_ASSERT(mpWindow
);
330 if (eOrientation
!= mpImplementation
->GetOrientation())
331 mpImplementation
.reset(Implementation::Create(*mpImplementation
, eOrientation
));
333 return mpImplementation
->Rearrange(rWindowSize
, rPageSize
, nPageCount
);
336 sal_Int32
Layouter::GetColumnCount() const
338 return mpImplementation
->mnColumnCount
;
341 sal_Int32
Layouter::GetIndex (const sal_Int32 nRow
, const sal_Int32 nColumn
) const
343 return mpImplementation
->GetIndex(nRow
,nColumn
,true);
346 Size
Layouter::GetPageObjectSize() const
348 return mpImplementation
->maPageObjectSize
;
351 Rectangle
Layouter::GetPageObjectBox (
352 const sal_Int32 nIndex
,
353 const bool bIncludeBorderAndGap
) const
355 return mpImplementation
->GetPageObjectBox(nIndex
, bIncludeBorderAndGap
);
358 Rectangle
Layouter::GetTotalBoundingBox() const
360 return mpImplementation
->GetTotalBoundingBox();
363 InsertPosition
Layouter::GetInsertPosition (
364 const Point
& rModelPosition
,
365 const Size
& rIndicatorSize
,
366 model::SlideSorterModel
& rModel
) const
368 InsertPosition aPosition
;
369 mpImplementation
->CalculateLogicalInsertPosition(
372 mpImplementation
->CalculateGeometricPosition(
380 Range
Layouter::GetValidHorizontalSizeRange() const
382 return mpImplementation
->GetValidHorizontalSizeRange();
385 Range
Layouter::GetValidVerticalSizeRange() const
387 return mpImplementation
->GetValidVerticalSizeRange();
390 Range
Layouter::GetRangeOfVisiblePageObjects (const Rectangle
& aVisibleArea
) const
392 return mpImplementation
->GetRangeOfVisiblePageObjects(aVisibleArea
);
395 sal_Int32
Layouter::GetIndexAtPoint (
396 const Point
& rPosition
,
397 const bool bIncludePageBorders
,
398 const bool bClampToValidRange
) const
400 const sal_Int32
nRow (
401 mpImplementation
->GetRowAtPosition (
404 bIncludePageBorders
? Implementation::GM_PAGE_BORDER
: Implementation::GM_NONE
));
405 const sal_Int32
nColumn (
406 mpImplementation
->GetColumnAtPosition (
409 bIncludePageBorders
? Implementation::GM_PAGE_BORDER
: Implementation::GM_NONE
));
411 return mpImplementation
->GetIndex(nRow
,nColumn
,bClampToValidRange
);
414 //===== Layouter::Implementation ==============================================
416 Layouter::Implementation
* Layouter::Implementation::Create (
417 const Implementation
& rImplementation
,
418 const Layouter::Orientation eOrientation
)
420 switch (eOrientation
)
422 case HORIZONTAL
: return new HorizontalImplementation(rImplementation
);
423 case VERTICAL
: return new VerticalImplementation(rImplementation
);
425 default: return new GridImplementation(rImplementation
);
429 Layouter::Implementation::Implementation (
431 const ::boost::shared_ptr
<view::Theme
>& rpTheme
)
433 mnRequestedLeftBorder(5),
434 mnRequestedRightBorder(5),
435 mnRequestedTopBorder(5),
436 mnRequestedBottomBorder(5),
441 mnVerticalGap (10 - 2*Theme_FocusIndicatorWidth
),
442 mnHorizontalGap(10 - 2*Theme_FocusIndicatorWidth
),
443 maMinimalSize(132,98),
444 maPreferredSize(200,150),
445 maMaximalSize(600,400),
446 mnMinimalColumnCount(1),
447 mnMaximalColumnCount(15),
453 maPageObjectSize(1,1),
454 mpPageObjectLayouter(),
459 Layouter::Implementation::Implementation (const Implementation
& rImplementation
)
460 : mpWindow(rImplementation
.mpWindow
),
461 mnRequestedLeftBorder(rImplementation
.mnRequestedLeftBorder
),
462 mnRequestedRightBorder(rImplementation
.mnRequestedRightBorder
),
463 mnRequestedTopBorder(rImplementation
.mnRequestedTopBorder
),
464 mnRequestedBottomBorder(rImplementation
.mnRequestedBottomBorder
),
465 mnLeftBorder(rImplementation
.mnLeftBorder
),
466 mnRightBorder(rImplementation
.mnRightBorder
),
467 mnTopBorder(rImplementation
.mnTopBorder
),
468 mnBottomBorder(rImplementation
.mnBottomBorder
),
469 mnVerticalGap(rImplementation
.mnVerticalGap
),
470 mnHorizontalGap(rImplementation
.mnHorizontalGap
),
471 maMinimalSize(rImplementation
.maMinimalSize
),
472 maPreferredSize(rImplementation
.maPreferredSize
),
473 maMaximalSize(rImplementation
.maMaximalSize
),
474 mnMinimalColumnCount(rImplementation
.mnMinimalColumnCount
),
475 mnMaximalColumnCount(rImplementation
.mnMaximalColumnCount
),
476 mnPageCount(rImplementation
.mnPageCount
),
477 mnColumnCount(rImplementation
.mnColumnCount
),
478 mnRowCount(rImplementation
.mnRowCount
),
479 mnMaxColumnCount(rImplementation
.mnMaxColumnCount
),
480 mnMaxRowCount(rImplementation
.mnMaxRowCount
),
481 maPageObjectSize(rImplementation
.maPageObjectSize
),
482 mpPageObjectLayouter(),
483 mpTheme(rImplementation
.mpTheme
)
487 Layouter::Implementation::~Implementation()
491 bool Layouter::Implementation::Rearrange (
492 const Size
& rWindowSize
,
493 const Size
& rPreviewModelSize
,
494 const sal_uInt32 nPageCount
)
496 mnPageCount
= nPageCount
;
498 // Return early when the window or the model have not yet been initialized.
499 if (rWindowSize
.Width()<=0 || rWindowSize
.Height()<=0)
501 if (rPreviewModelSize
.Width()<=0 || rPreviewModelSize
.Height()<=0)
504 CalculateRowAndColumnCount(rWindowSize
);
506 // Update the border values.
507 mnLeftBorder
= mnRequestedLeftBorder
;
508 mnTopBorder
= mnRequestedTopBorder
;
509 mnRightBorder
= mnRequestedRightBorder
;
510 mnBottomBorder
= mnRequestedBottomBorder
;
511 if (mnColumnCount
> 1)
513 int nMinimumBorderWidth
= mnHorizontalGap
/2;
514 if (mnLeftBorder
< nMinimumBorderWidth
)
515 mnLeftBorder
= nMinimumBorderWidth
;
516 if (mnRightBorder
< nMinimumBorderWidth
)
517 mnRightBorder
= nMinimumBorderWidth
;
521 int nMinimumBorderHeight
= mnVerticalGap
/2;
522 if (mnTopBorder
< nMinimumBorderHeight
)
523 mnTopBorder
= nMinimumBorderHeight
;
524 if (mnBottomBorder
< nMinimumBorderHeight
)
525 mnBottomBorder
= nMinimumBorderHeight
;
528 mpPageObjectLayouter
.reset(
529 new PageObjectLayouter(
530 CalculateTargetSize(rWindowSize
, rPreviewModelSize
),
535 maPageObjectSize
= mpPageObjectLayouter
->GetGridMaxSize(
536 PageObjectLayouter::WindowCoordinateSystem
);
538 CalculateMaxRowAndColumnCount(rWindowSize
);
543 sal_Int32
Layouter::Implementation::GetRowAtPosition (
544 sal_Int32 nYPosition
,
545 bool bIncludeBordersAndGaps
,
546 GapMembership eGapMembership
) const
550 const sal_Int32 nY
= nYPosition
- mnTopBorder
;
553 // Vertical distance from one row to the next.
554 const sal_Int32
nRowOffset (maPageObjectSize
.Height() + mnVerticalGap
);
556 // Calculate row consisting of page objects and gap below.
557 nRow
= nY
/ nRowOffset
;
559 const sal_Int32
nDistanceIntoGap ((nY
- nRow
*nRowOffset
) - maPageObjectSize
.Height());
560 // When inside the gap below then nYPosition is not over a page
562 if (nDistanceIntoGap
> 0)
564 sal_Int32 nResolvedRow
= ResolvePositionInGap(
569 if (!bIncludeBordersAndGaps
|| nResolvedRow
!= -1)
573 else if (bIncludeBordersAndGaps
)
575 // We are in the top border area. Set nRow to the first row when
576 // the top border shall be considered to belong to the first row.
583 sal_Int32
Layouter::Implementation::GetColumnAtPosition (
584 sal_Int32 nXPosition
,
585 bool bIncludeBordersAndGaps
,
586 GapMembership eGapMembership
) const
588 sal_Int32 nColumn
= -1;
590 sal_Int32 nX
= nXPosition
- mnLeftBorder
;
593 // Horizontal distance from one column to the next.
594 const sal_Int32
nColumnOffset (maPageObjectSize
.Width() + mnHorizontalGap
);
596 // Calculate row consisting of page objects and gap below.
597 nColumn
= nX
/ nColumnOffset
;
600 else if (nColumn
>= mnColumnCount
)
601 nColumn
= mnColumnCount
-1;
603 const sal_Int32
nDistanceIntoGap ((nX
- nColumn
*nColumnOffset
) - maPageObjectSize
.Width());
604 // When inside the gap at the right then nXPosition is not over a
606 if (nDistanceIntoGap
> 0)
608 sal_Int32 nResolvedColumn
= ResolvePositionInGap(
613 if (!bIncludeBordersAndGaps
|| nResolvedColumn
!= -1)
614 nColumn
= nResolvedColumn
;
617 else if (bIncludeBordersAndGaps
)
619 // We are in the left border area. Set nColumn to the first column
620 // when the left border shall be considered to belong to the first
627 sal_Int32
Layouter::Implementation::ResolvePositionInGap (
628 sal_Int32 nDistanceIntoGap
,
629 GapMembership eGapMembership
,
633 switch (eGapMembership
)
636 // The gap is no man's land.
642 // The lower half of the gap belongs to the next row or column.
643 sal_Int32 nFirstHalfGapWidth
= nGap
/ 2;
644 if (nDistanceIntoGap
> nFirstHalfGapWidth
)
650 // Row or column already at correct value.
654 // The complete gap belongs to the next row or column.
659 if (nDistanceIntoGap
> 0)
661 if (nDistanceIntoGap
> nGap
)
663 // Inside the border of the next row or column.
668 // Inside the gap between the page borders.
681 void Layouter::Implementation::CalculateGeometricPosition (
682 InsertPosition
& rPosition
,
683 const Size
& rIndicatorSize
,
684 const bool bIsVertical
,
685 model::SlideSorterModel
& rModel
) const
687 // 1. Determine right/bottom of the leading page and the left/top of the
688 // trailing page object and how to distribute the missing space.
689 sal_Int32
nLeadingLocation (0);
690 sal_Int32
nTrailingLocation (0);
691 bool bIsLeadingFixed (false);
692 bool bIsTrailingFixed (false);
693 sal_Int32
nSecondaryLocation (0);
694 const sal_Int32
nIndex (rPosition
.GetIndex());
696 if (rPosition
.IsAtRunStart())
698 // Place indicator at the top of the column.
699 const Rectangle
aOuterBox (GetPageObjectBox(nIndex
));
700 const Rectangle
aInnerBox (GetInnerBoundingBox(rModel
, nIndex
));
703 nLeadingLocation
= aOuterBox
.Top();
704 nTrailingLocation
= aInnerBox
.Top();
705 nSecondaryLocation
= aInnerBox
.Center().X();
709 nLeadingLocation
= aOuterBox
.Left();
710 nTrailingLocation
= aInnerBox
.Left();
711 nSecondaryLocation
= aInnerBox
.Center().Y();
713 bIsLeadingFixed
= true;
715 else if (rPosition
.IsAtRunEnd())
717 // Place indicator at the bottom/right of the column/row.
719 const Rectangle
aOuterBox (GetPageObjectBox(nIndex
-1));
720 const Rectangle
aInnerBox (GetInnerBoundingBox(rModel
, nIndex
-1));
723 nLeadingLocation
= aInnerBox
.Bottom();
724 nTrailingLocation
= aOuterBox
.Bottom();
725 nSecondaryLocation
= aInnerBox
.Center().X();
729 nLeadingLocation
= aInnerBox
.Right();
730 nTrailingLocation
= aOuterBox
.Right();
731 nSecondaryLocation
= aInnerBox
.Center().Y();
733 bIsTrailingFixed
= true;
734 if ( ! rPosition
.IsExtraSpaceNeeded())
735 bIsLeadingFixed
= true;
739 // Place indicator between two rows/columns.
740 const Rectangle
aBox1 (GetInnerBoundingBox(rModel
, nIndex
-1));
741 const Rectangle
aBox2 (GetInnerBoundingBox(rModel
, nIndex
));
744 nLeadingLocation
= aBox1
.Bottom();
745 nTrailingLocation
= aBox2
.Top();
746 nSecondaryLocation
= (aBox1
.Center().X() + aBox2
.Center().X()) / 2;
750 nLeadingLocation
= aBox1
.Right();
751 nTrailingLocation
= aBox2
.Left();
752 nSecondaryLocation
= (aBox1
.Center().Y() + aBox2
.Center().Y()) / 2;
756 // 2. Calculate the location of the insert indicator and the offsets of
757 // leading and trailing pages.
758 const sal_Int32
nAvailableSpace (nTrailingLocation
- nLeadingLocation
);
759 const sal_Int32
nRequiredSpace (bIsVertical
? rIndicatorSize
.Height():rIndicatorSize
.Width());
760 const sal_Int32
nMissingSpace (::std::max(sal_Int32(0), nRequiredSpace
- nAvailableSpace
));
761 sal_Int32
nPrimaryLocation (0);
762 sal_Int32
nLeadingOffset (0);
763 sal_Int32
nTrailingOffset (0);
766 nPrimaryLocation
= nLeadingLocation
+ nRequiredSpace
/2;
767 if ( ! bIsTrailingFixed
)
768 nTrailingOffset
= nMissingSpace
;
770 else if (bIsTrailingFixed
)
772 nPrimaryLocation
= nTrailingLocation
- nRequiredSpace
/2;
773 nLeadingOffset
= -nMissingSpace
;
777 nPrimaryLocation
= (nLeadingLocation
+ nTrailingLocation
) /2;
778 nLeadingOffset
= -nMissingSpace
/2;
779 nTrailingOffset
= nMissingSpace
+ nLeadingOffset
;
784 rPosition
.SetGeometricalPosition(
785 Point(nSecondaryLocation
, nPrimaryLocation
),
786 Point(0, nLeadingOffset
),
787 Point(0, nTrailingOffset
));
791 rPosition
.SetGeometricalPosition(
792 Point(nPrimaryLocation
, nSecondaryLocation
),
793 Point(nLeadingOffset
, 0),
794 Point(nTrailingOffset
, 0));
798 Rectangle
Layouter::Implementation::GetInnerBoundingBox (
799 model::SlideSorterModel
& rModel
,
800 const sal_Int32 nIndex
) const
802 model::SharedPageDescriptor
pDescriptor (rModel
.GetPageDescriptor(nIndex
));
806 PageObjectLayouter::Part ePart
= PageObjectLayouter::Preview
;
808 if (pDescriptor
->HasState(model::PageDescriptor::ST_Selected
))
809 ePart
= PageObjectLayouter::PageObject
;
811 return mpPageObjectLayouter
->GetBoundingBox(
813 PageObjectLayouter::ModelCoordinateSystem
, true);
816 Range
Layouter::Implementation::GetValidHorizontalSizeRange() const
819 mnLeftBorder
+ maMinimalSize
.Width() + mnRightBorder
,
820 mnLeftBorder
+ maMaximalSize
.Width() + mnRightBorder
);
823 Range
Layouter::Implementation::GetValidVerticalSizeRange() const
826 mnTopBorder
+ maMinimalSize
.Height() + mnBottomBorder
,
827 mnTopBorder
+ maMaximalSize
.Height() + mnBottomBorder
);
830 Range
Layouter::Implementation::GetRangeOfVisiblePageObjects (const Rectangle
& aVisibleArea
) const
832 const sal_Int32
nRow0 (GetRowAtPosition(aVisibleArea
.Top(), true, GM_NEXT
));
833 const sal_Int32
nCol0 (GetColumnAtPosition(aVisibleArea
.Left(),true, GM_NEXT
));
834 const sal_Int32
nRow1 (GetRowAtPosition(aVisibleArea
.Bottom(), true, GM_PREVIOUS
));
835 const sal_Int32
nCol1 (GetColumnAtPosition(aVisibleArea
.Right(), true, GM_PREVIOUS
));
837 // When start and end lie in different rows then the range may include
838 // slides outside (left or right of) the given area.
839 return Range(GetIndex(nRow0
,nCol0
,true), GetIndex(nRow1
,nCol1
,true));
842 Size
Layouter::Implementation::GetTargetSize (
843 const Size
& rWindowSize
,
844 const Size
& rPreviewModelSize
,
845 const bool bCalculateWidth
,
846 const bool bCalculateHeight
) const
848 (void)rPreviewModelSize
;
850 if (mnColumnCount
<=0 || mnRowCount
<=0)
851 return maPreferredSize
;
852 if ( ! (bCalculateWidth
|| bCalculateHeight
))
854 OSL_ASSERT(bCalculateWidth
|| bCalculateHeight
);
855 return maPreferredSize
;
858 // Calculate the width of each page object.
859 Size
aTargetSize (0,0);
861 aTargetSize
.setWidth(
862 (rWindowSize
.Width() - mnLeftBorder
- mnRightBorder
863 - (mnColumnCount
-1) * mnHorizontalGap
)
865 else if (bCalculateHeight
)
866 aTargetSize
.setHeight(
867 (rWindowSize
.Height() - mnTopBorder
- mnBottomBorder
868 - (mnRowCount
-1) * mnVerticalGap
)
873 if (aTargetSize
.Width() < maMinimalSize
.Width())
874 aTargetSize
.setWidth(maMinimalSize
.Width());
875 else if (aTargetSize
.Width() > maMaximalSize
.Width())
876 aTargetSize
.setWidth(maMaximalSize
.Width());
878 else if (bCalculateHeight
)
880 if (aTargetSize
.Height() < maMinimalSize
.Height())
881 aTargetSize
.setHeight(maMinimalSize
.Height());
882 else if (aTargetSize
.Height() > maMaximalSize
.Height())
883 aTargetSize
.setHeight(maMaximalSize
.Height());
889 sal_Int32
Layouter::Implementation::GetIndex (
890 const sal_Int32 nRow
,
891 const sal_Int32 nColumn
,
892 const bool bClampToValidRange
) const
894 if (nRow
>= 0 && nColumn
>= 0)
896 const sal_Int32
nIndex (nRow
* mnColumnCount
+ nColumn
);
897 if (nIndex
>= mnPageCount
)
898 if (bClampToValidRange
)
899 return mnPageCount
-1;
905 else if (bClampToValidRange
)
911 Rectangle
Layouter::Implementation::GetPageObjectBox (
912 const sal_Int32 nIndex
,
913 const bool bIncludeBorderAndGap
) const
915 const sal_Int32
nRow (nIndex
/ mnColumnCount
);
916 const sal_Int32
nColumn (nIndex
% mnColumnCount
);
918 const Rectangle
aBoundingBox (GetPageObjectBox(nRow
,nColumn
));
919 if (bIncludeBorderAndGap
)
920 return AddBorderAndGap(aBoundingBox
, nRow
, nColumn
);
925 Rectangle
Layouter::Implementation::GetPageObjectBox (
926 const sal_Int32 nRow
,
927 const sal_Int32 nColumn
) const
931 + nColumn
* maPageObjectSize
.Width()
932 + (nColumn
>0 ? nColumn
: 0) * mnHorizontalGap
,
934 + nRow
* maPageObjectSize
.Height()
935 + (nRow
>0 ? nRow
: 0) * mnVerticalGap
),
939 Rectangle
Layouter::Implementation::AddBorderAndGap (
940 const Rectangle
& rBoundingBox
,
941 const sal_Int32 nRow
,
942 const sal_Int32 nColumn
) const
944 Rectangle
aBoundingBox (rBoundingBox
);
947 aBoundingBox
.Left() = 0;
949 aBoundingBox
.Left() -= mnHorizontalGap
/2;
950 if (nColumn
== mnColumnCount
-1)
951 aBoundingBox
.Right() += mnRightBorder
;
953 aBoundingBox
.Right() += mnHorizontalGap
/2;
955 aBoundingBox
.Top() = 0;
957 aBoundingBox
.Top() -= mnVerticalGap
/2;
958 if (nRow
== mnRowCount
-1)
959 aBoundingBox
.Bottom() += mnBottomBorder
;
961 aBoundingBox
.Bottom() += mnVerticalGap
/2;
965 Rectangle
Layouter::Implementation::GetTotalBoundingBox() const
967 sal_Int32 nHorizontalSize
= 0;
968 sal_Int32 nVerticalSize
= 0;
969 if (mnColumnCount
> 0)
971 sal_Int32 nRowCount
= (mnPageCount
+mnColumnCount
-1) / mnColumnCount
;
975 + mnColumnCount
* maPageObjectSize
.Width();
976 if (mnColumnCount
> 1)
977 nHorizontalSize
+= (mnColumnCount
-1) * mnHorizontalGap
;
981 + nRowCount
* maPageObjectSize
.Height();
983 nVerticalSize
+= (nRowCount
-1) * mnVerticalGap
;
988 Size (nHorizontalSize
, nVerticalSize
)
992 void Layouter::Implementation::CalculateVerticalLogicalInsertPosition (
993 const Point
& rModelPosition
,
994 InsertPosition
& rPosition
) const
996 const sal_Int32 nY
= rModelPosition
.Y() - mnTopBorder
+ maPageObjectSize
.Height()/2;
997 const sal_Int32
nRowHeight (maPageObjectSize
.Height() + mnVerticalGap
);
998 const sal_Int32
nRow (::std::min(mnPageCount
, nY
/ nRowHeight
));
999 rPosition
.SetLogicalPosition (
1004 (nRow
== mnRowCount
),
1005 (nRow
>= mnMaxRowCount
));
1008 //===== HorizontalImplementation ================================================
1010 HorizontalImplementation::HorizontalImplementation (const Implementation
& rImplementation
)
1011 : Implementation(rImplementation
)
1015 Layouter::Orientation
HorizontalImplementation::GetOrientation() const
1017 return Layouter::HORIZONTAL
;
1020 void HorizontalImplementation::CalculateRowAndColumnCount (const Size
& rWindowSize
)
1024 // Row and column count are fixed (for a given page count.)
1025 mnColumnCount
= mnPageCount
;
1029 void HorizontalImplementation::CalculateMaxRowAndColumnCount (const Size
& rWindowSize
)
1031 mnMaxColumnCount
= (rWindowSize
.Width() - mnLeftBorder
- mnRightBorder
)
1032 / (maPageObjectSize
.Width() + mnHorizontalGap
);
1036 Size
HorizontalImplementation::CalculateTargetSize (
1037 const Size
& rWindowSize
,
1038 const Size
& rPreviewModelSize
) const
1040 return Implementation::GetTargetSize(rWindowSize
, rPreviewModelSize
, false, true);
1043 void HorizontalImplementation::CalculateLogicalInsertPosition (
1044 const Point
& rModelPosition
,
1045 InsertPosition
& rPosition
) const
1047 const sal_Int32 nX
= rModelPosition
.X() - mnLeftBorder
+ maPageObjectSize
.Width()/2;
1048 const sal_Int32
nColumnWidth (maPageObjectSize
.Width() + mnHorizontalGap
);
1049 const sal_Int32
nColumn (::std::min(mnPageCount
, nX
/ nColumnWidth
));
1050 rPosition
.SetLogicalPosition (
1055 (nColumn
== mnColumnCount
),
1056 (nColumn
>= mnMaxColumnCount
));
1059 //===== VerticalImplementation ================================================
1061 VerticalImplementation::VerticalImplementation (const Implementation
& rImplementation
)
1062 : Implementation(rImplementation
)
1066 Layouter::Orientation
VerticalImplementation::GetOrientation() const
1068 return Layouter::VERTICAL
;
1071 void VerticalImplementation::CalculateRowAndColumnCount (const Size
& rWindowSize
)
1075 // Row and column count are fixed (for a given page count.)
1076 mnRowCount
= mnPageCount
;
1081 void VerticalImplementation::CalculateMaxRowAndColumnCount (const Size
& rWindowSize
)
1083 mnMaxRowCount
= (rWindowSize
.Height() - mnTopBorder
- mnBottomBorder
)
1084 / (maPageObjectSize
.Height() + mnVerticalGap
);
1085 mnMaxColumnCount
= 1;
1088 Size
VerticalImplementation::CalculateTargetSize (
1089 const Size
& rWindowSize
,
1090 const Size
& rPreviewModelSize
) const
1092 return Implementation::GetTargetSize(rWindowSize
, rPreviewModelSize
, true, false);
1095 void VerticalImplementation::CalculateLogicalInsertPosition (
1096 const Point
& rModelPosition
,
1097 InsertPosition
& rPosition
) const
1099 return CalculateVerticalLogicalInsertPosition(rModelPosition
, rPosition
);
1102 //===== GridImplementation ================================================
1104 GridImplementation::GridImplementation (
1105 sd::Window
*pWindow
,
1106 const ::boost::shared_ptr
<view::Theme
>& rpTheme
)
1107 : Implementation(pWindow
, rpTheme
)
1111 GridImplementation::GridImplementation (const Implementation
& rImplementation
)
1112 : Implementation(rImplementation
)
1116 Layouter::Orientation
GridImplementation::GetOrientation() const
1118 return Layouter::GRID
;
1121 void GridImplementation::CalculateRowAndColumnCount (const Size
& rWindowSize
)
1123 // Calculate the column count.
1125 = (rWindowSize
.Width() - mnRequestedLeftBorder
- mnRequestedRightBorder
)
1126 / (maPreferredSize
.Width() + mnHorizontalGap
);
1127 if (mnColumnCount
< mnMinimalColumnCount
)
1128 mnColumnCount
= mnMinimalColumnCount
;
1129 if (mnColumnCount
> mnMaximalColumnCount
)
1130 mnColumnCount
= mnMaximalColumnCount
;
1131 mnRowCount
= (mnPageCount
+ mnColumnCount
-1)/mnColumnCount
;
1134 void GridImplementation::CalculateMaxRowAndColumnCount (const Size
& rWindowSize
)
1136 mnMaxColumnCount
= (rWindowSize
.Width() - mnLeftBorder
- mnRightBorder
)
1137 / (maPageObjectSize
.Width() + mnHorizontalGap
);
1138 mnMaxRowCount
= (rWindowSize
.Height() - mnTopBorder
- mnBottomBorder
)
1139 / (maPageObjectSize
.Height() + mnVerticalGap
);
1142 Size
GridImplementation::CalculateTargetSize (
1143 const Size
& rWindowSize
,
1144 const Size
& rPreviewModelSize
) const
1146 return Implementation::GetTargetSize(rWindowSize
, rPreviewModelSize
, true, true);
1149 void GridImplementation::CalculateLogicalInsertPosition (
1150 const Point
& rModelPosition
,
1151 InsertPosition
& rPosition
) const
1153 if (mnColumnCount
== 1)
1155 CalculateVerticalLogicalInsertPosition(rModelPosition
, rPosition
);
1159 // Handle the general case of more than one column.
1160 sal_Int32
nRow (::std::min(
1162 GetRowAtPosition (rModelPosition
.Y(), true, GM_BOTH
)));
1163 const sal_Int32 nX
= rModelPosition
.X() - mnLeftBorder
+ maPageObjectSize
.Width()/2;
1164 const sal_Int32
nColumnWidth (maPageObjectSize
.Width() + mnHorizontalGap
);
1165 sal_Int32
nColumn (::std::min(mnColumnCount
, nX
/ nColumnWidth
));
1166 sal_Int32
nIndex (nRow
* mnColumnCount
+ nColumn
);
1167 bool bIsAtRunEnd (nColumn
== mnColumnCount
);
1169 if (nIndex
>= mnPageCount
)
1171 nIndex
= mnPageCount
;
1172 nRow
= mnRowCount
-1;
1173 nColumn
= ::std::min(::std::min(mnPageCount
, mnColumnCount
), nColumn
);
1177 rPosition
.SetLogicalPosition (
1183 (nColumn
>= mnMaxColumnCount
));
1187 //===== InsertPosition ========================================================
1189 InsertPosition::InsertPosition()
1193 mbIsAtRunStart(false),
1194 mbIsAtRunEnd(false),
1195 mbIsExtraSpaceNeeded(false),
1197 maLeadingOffset(0,0),
1198 maTrailingOffset(0,0)
1202 InsertPosition
& InsertPosition::operator= (const InsertPosition
& rInsertPosition
)
1204 if (this != &rInsertPosition
)
1206 mnRow
= rInsertPosition
.mnRow
;
1207 mnColumn
= rInsertPosition
.mnColumn
;
1208 mnIndex
= rInsertPosition
.mnIndex
;
1209 mbIsAtRunStart
= rInsertPosition
.mbIsAtRunStart
;
1210 mbIsAtRunEnd
= rInsertPosition
.mbIsAtRunEnd
;
1211 mbIsExtraSpaceNeeded
= rInsertPosition
.mbIsExtraSpaceNeeded
;
1212 maLocation
= rInsertPosition
.maLocation
;
1213 maLeadingOffset
= rInsertPosition
.maLeadingOffset
;
1214 maTrailingOffset
= rInsertPosition
.maTrailingOffset
;
1219 bool InsertPosition::operator== (const InsertPosition
& rInsertPosition
) const
1221 // Do not compare the geometrical information (maLocation).
1222 return mnRow
==rInsertPosition
.mnRow
1223 && mnColumn
==rInsertPosition
.mnColumn
1224 && mnIndex
==rInsertPosition
.mnIndex
1225 && mbIsAtRunStart
==rInsertPosition
.mbIsAtRunStart
1226 && mbIsAtRunEnd
==rInsertPosition
.mbIsAtRunEnd
1227 && mbIsExtraSpaceNeeded
==rInsertPosition
.mbIsExtraSpaceNeeded
;
1230 bool InsertPosition::operator!= (const InsertPosition
& rInsertPosition
) const
1232 return !operator==(rInsertPosition
);
1235 void InsertPosition::SetLogicalPosition (
1236 const sal_Int32 nRow
,
1237 const sal_Int32 nColumn
,
1238 const sal_Int32 nIndex
,
1239 const bool bIsAtRunStart
,
1240 const bool bIsAtRunEnd
,
1241 const bool bIsExtraSpaceNeeded
)
1246 mbIsAtRunStart
= bIsAtRunStart
;
1247 mbIsAtRunEnd
= bIsAtRunEnd
;
1248 mbIsExtraSpaceNeeded
= bIsExtraSpaceNeeded
;
1251 void InsertPosition::SetGeometricalPosition(
1252 const Point
& rLocation
,
1253 const Point
& rLeadingOffset
,
1254 const Point
& rTrailingOffset
)
1256 maLocation
= rLocation
;
1257 maLeadingOffset
= rLeadingOffset
;
1258 maTrailingOffset
= rTrailingOffset
;
1261 } } } // end of namespace ::sd::slidesorter::namespace
1263 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */