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/SlsPageObjectLayouter.hxx>
21 #include <view/SlsTheme.hxx>
22 #include <view/SlsLayouter.hxx>
23 #include <model/SlideSorterModel.hxx>
24 #include <model/SlsPageDescriptor.hxx>
26 #include <rtl/math.hxx>
27 #include <basegfx/numeric/ftools.hxx>
28 #include <osl/diagnose.h>
30 namespace sd
{ namespace slidesorter
{ namespace view
{
32 class Layouter::Implementation
35 VclPtr
<sd::Window
> mpWindow
;
36 static const sal_Int32 mnRequestedLeftBorder
= 5;
37 static const sal_Int32 mnRequestedRightBorder
= 5;
38 static const sal_Int32 mnRequestedTopBorder
= 5;
39 static const sal_Int32 mnRequestedBottomBorder
= 5;
40 sal_Int32 mnLeftBorder
;
41 sal_Int32 mnRightBorder
;
42 sal_Int32 mnTopBorder
;
43 sal_Int32 mnBottomBorder
;
44 static const sal_Int32 gnVerticalGap
= 10 - 2*Theme_FocusIndicatorWidth
;
45 static const sal_Int32 gnHorizontalGap
= 10 - 2*Theme_FocusIndicatorWidth
;
46 Size
const maMinimalSize
;
47 Size
const maPreferredSize
;
48 Size
const maMaximalSize
;
49 sal_Int32 mnMinimalColumnCount
;
50 sal_Int32 mnMaximalColumnCount
;
51 sal_Int32 mnPageCount
;
52 sal_Int32 mnColumnCount
;
54 /// The maximum number of columns. Can only be larger than the current
55 /// number of columns when there are not enough pages to fill all
56 /// available columns.
57 sal_Int32 mnMaxColumnCount
;
58 /// The maximum number of rows. Can only be larger than the current
59 /// number of rows when there are not enough pages to fill all available
61 sal_Int32 mnMaxRowCount
;
62 Size maPageObjectSize
;
63 std::shared_ptr
<PageObjectLayouter
> mpPageObjectLayouter
;
64 std::shared_ptr
<view::Theme
> mpTheme
;
66 /** Specify how the gap between two page objects is associated with the
70 GM_NONE
, // Gap is not associated with any page object.
71 GM_PREVIOUS
, // The whole gap is associated with the previous page
72 // object (left or above the gap.)
73 GM_BOTH
, // Half of the gap is associated with previous, half
74 // with the next page object.
75 GM_NEXT
, // The whole gap is associated with the next page
76 // object (right or below the gap.)
80 static Implementation
* Create (
81 const Implementation
& rImplementation
,
82 const Layouter::Orientation eOrientation
);
84 virtual Layouter::Orientation
GetOrientation() const = 0;
87 const Size
& rWindowSize
,
88 const Size
& rPreviewModelSize
,
89 const sal_uInt32 nPageCount
);
91 /** Calculate the row that the point with the given vertical coordinate
92 is over. The horizontal component is ignored.
94 Vertical position in model coordinates.
95 @param bIncludeBordersAndGaps
96 When this flag is <TRUE/> then the area of borders and gaps are
97 interpreted as belonging to one of the rows.
99 Specifies to what row the gap areas belong. Here GM_NONE
100 corresponds to bIncludeBordersAndGaps being <FALSE/>. When
101 GM_BOTH is given then the upper half is associated to the row
102 above and the lower half to the row below. Values of
103 GM_PREVIOUS and GM_NEXT associate the whole gap area with the
104 row above or below respectively.
106 sal_Int32
GetRowAtPosition (
107 sal_Int32 nYPosition
,
108 bool bIncludeBordersAndGaps
,
109 GapMembership eGapMembership
) const;
111 /** Calculate the column that the point with the given horizontal
112 coordinate is over. The vertical component is ignored.
114 Horizontal position in model coordinates.
115 @param bIncludeBordersAndGaps
116 When this flag is <TRUE/> then the area of borders and gaps are
117 interpreted as belonging to one of the columns.
118 @param eGapMembership
119 Specifies to what column the gap areas belong.
121 sal_Int32
GetColumnAtPosition (
122 sal_Int32 nXPosition
,
123 bool bIncludeBordersAndGaps
,
124 GapMembership eGapMembership
) const;
126 /** This method is typically called from GetRowAtPosition() and
127 GetColumnAtPosition() to handle a position that lies inside the gap
128 between two adjacent rows or columns.
129 @param nDistanceIntoGap
130 Vertical distance from the bottom of the upper row down into the
131 gap or horizontal distance from the right edge right into the
133 @param eGapMemberhship
134 This value decides what areas in the gap belong to which (or no)
137 The row index of the upper row or the column index of the left
140 Width or height of the gap in model coordinates between the
143 Returns either the index of the upper row (as given as nRow), the
144 index of the lower row (nRow+1) or -1 to indicate that the
145 position belongs to no row.
147 static sal_Int32
ResolvePositionInGap (
148 sal_Int32 nDistanceIntoGap
,
149 GapMembership eGapMembership
,
153 /** Calculate the logical part of the insert position, i.e. the page
154 after which to insert.
156 virtual void CalculateLogicalInsertPosition (
157 const Point
& rModelPosition
,
158 InsertPosition
& rPosition
) const = 0;
160 /** Calculate the geometrical part of the insert position, i.e. the
161 location of where to display the insertion indicator and the
162 distances about which the leading and trailing pages have to be
163 moved to make room for the indicator.
165 void CalculateGeometricPosition (
166 InsertPosition
& rPosition
,
167 const Size
& rIndicatorSize
,
168 const bool bIsVertical
,
169 model::SlideSorterModel
const & rModel
) const;
171 /** Return the bounding box of the preview or, when selected, of the page
172 object. Thus, it returns something like a visual bounding box.
174 ::tools::Rectangle
GetInnerBoundingBox (
175 model::SlideSorterModel
const & rModel
,
176 const sal_Int32 nIndex
) const;
178 Range
GetValidHorizontalSizeRange() const;
179 Range
GetValidVerticalSizeRange() const;
181 Range
GetRangeOfVisiblePageObjects (const ::tools::Rectangle
& aVisibleArea
) const;
183 const sal_Int32 nRow
,
184 const sal_Int32 nColumn
,
185 const bool bClampToValidRange
) const;
187 ::tools::Rectangle
GetPageObjectBox (
188 const sal_Int32 nIndex
,
189 const bool bIncludeBorderAndGap
= false) const;
191 ::tools::Rectangle
GetPageObjectBox (
192 const sal_Int32 nRow
,
193 const sal_Int32 nColumn
) const;
195 ::tools::Rectangle
AddBorderAndGap (
196 const ::tools::Rectangle
& rBoundingBox
,
197 const sal_Int32 nRow
,
198 const sal_Int32 nColumn
) const;
200 ::tools::Rectangle
GetTotalBoundingBox() const;
202 virtual ~Implementation();
207 const std::shared_ptr
<view::Theme
>& rpTheme
);
208 explicit Implementation (const Implementation
& rImplementation
);
210 virtual void CalculateRowAndColumnCount (const Size
& rWindowSize
) = 0;
211 virtual void CalculateMaxRowAndColumnCount (const Size
& rWindowSize
) = 0;
212 virtual Size
CalculateTargetSize (
213 const Size
& rWindowSize
) const = 0;
215 const Size
& rWindowSize
,
216 const bool bCalculateWidth
,
217 const bool bCalculateHeight
) const;
218 void CalculateVerticalLogicalInsertPosition (
219 const Point
& rModelPosition
,
220 InsertPosition
& rPosition
) const;
223 /** The vertical layouter has one column and as many rows as there are
226 class VerticalImplementation
: public Layouter::Implementation
229 explicit VerticalImplementation (const Implementation
& rImplementation
);
231 virtual Layouter::Orientation
GetOrientation() const override
;
233 void CalculateLogicalInsertPosition (
234 const Point
& rModelPosition
,
235 InsertPosition
& rPosition
) const override
;
238 virtual void CalculateRowAndColumnCount (const Size
& rWindowSize
) override
;
239 virtual void CalculateMaxRowAndColumnCount (const Size
& rWindowSize
) override
;
240 virtual Size
CalculateTargetSize (
241 const Size
& rWindowSize
) const override
;
244 /** The horizontal layouter has one row and as many columns as there are
247 class HorizontalImplementation
: public Layouter::Implementation
250 explicit HorizontalImplementation(const Implementation
& rImplementation
);
252 virtual Layouter::Orientation
GetOrientation() const override
;
254 void CalculateLogicalInsertPosition (
255 const Point
& rModelPosition
,
256 InsertPosition
& rPosition
) const override
;
259 virtual void CalculateRowAndColumnCount (const Size
& rWindowSize
) override
;
260 virtual void CalculateMaxRowAndColumnCount (const Size
& rWindowSize
) override
;
261 virtual Size
CalculateTargetSize (
262 const Size
& rWindowSize
) const override
;
265 /** The number of columns of the grid layouter is defined via a control in
266 the slide sorter tool bar. The number of rows is calculated from the
267 number of columns and the number of pages.
269 class GridImplementation
: public Layouter::Implementation
274 const std::shared_ptr
<view::Theme
>& rpTheme
);
275 explicit GridImplementation(const Implementation
& rImplementation
);
277 virtual Layouter::Orientation
GetOrientation() const override
;
279 void CalculateLogicalInsertPosition (
280 const Point
& rModelPosition
,
281 InsertPosition
& rPosition
) const override
;
284 virtual void CalculateRowAndColumnCount (const Size
& rWindowSize
) override
;
285 virtual void CalculateMaxRowAndColumnCount (const Size
& rWindowSize
) override
;
286 virtual Size
CalculateTargetSize (
287 const Size
& rWindowSize
) const override
;
290 //===== Layouter ==============================================================
294 const std::shared_ptr
<Theme
>& rpTheme
)
295 : mpImplementation(new GridImplementation(pWindow
, rpTheme
)),
300 Layouter::~Layouter()
304 std::shared_ptr
<PageObjectLayouter
> const & Layouter::GetPageObjectLayouter() const
306 return mpImplementation
->mpPageObjectLayouter
;
309 void Layouter::SetColumnCount (
310 sal_Int32 nMinimalColumnCount
,
311 sal_Int32 nMaximalColumnCount
)
313 if (nMinimalColumnCount
<= nMaximalColumnCount
)
315 mpImplementation
->mnMinimalColumnCount
= nMinimalColumnCount
;
316 mpImplementation
->mnMaximalColumnCount
= nMaximalColumnCount
;
320 bool Layouter::Rearrange (
321 const Orientation eOrientation
,
322 const Size
& rWindowSize
,
323 const Size
& rPageSize
,
324 const sal_uInt32 nPageCount
)
326 OSL_ASSERT(mpWindow
);
328 if (eOrientation
!= mpImplementation
->GetOrientation())
329 mpImplementation
.reset(Implementation::Create(*mpImplementation
, eOrientation
));
331 return mpImplementation
->Rearrange(rWindowSize
, rPageSize
, nPageCount
);
334 sal_Int32
Layouter::GetColumnCount() const
336 return mpImplementation
->mnColumnCount
;
339 sal_Int32
Layouter::GetIndex (const sal_Int32 nRow
, const sal_Int32 nColumn
) const
341 return mpImplementation
->GetIndex(nRow
,nColumn
,true);
344 Size
const & Layouter::GetPageObjectSize() const
346 return mpImplementation
->maPageObjectSize
;
349 ::tools::Rectangle
Layouter::GetPageObjectBox (
350 const sal_Int32 nIndex
,
351 const bool bIncludeBorderAndGap
) const
353 return mpImplementation
->GetPageObjectBox(nIndex
, bIncludeBorderAndGap
);
356 ::tools::Rectangle
Layouter::GetTotalBoundingBox() const
358 return mpImplementation
->GetTotalBoundingBox();
361 InsertPosition
Layouter::GetInsertPosition (
362 const Point
& rModelPosition
,
363 const Size
& rIndicatorSize
,
364 model::SlideSorterModel
const & rModel
) const
366 InsertPosition aPosition
;
367 mpImplementation
->CalculateLogicalInsertPosition(
370 mpImplementation
->CalculateGeometricPosition(
378 Range
Layouter::GetValidHorizontalSizeRange() const
380 return mpImplementation
->GetValidHorizontalSizeRange();
383 Range
Layouter::GetValidVerticalSizeRange() const
385 return mpImplementation
->GetValidVerticalSizeRange();
388 Range
Layouter::GetRangeOfVisiblePageObjects (const ::tools::Rectangle
& aVisibleArea
) const
390 return mpImplementation
->GetRangeOfVisiblePageObjects(aVisibleArea
);
393 sal_Int32
Layouter::GetIndexAtPoint (
394 const Point
& rPosition
,
395 const bool bIncludePageBorders
,
396 const bool bClampToValidRange
) const
398 const sal_Int32
nRow (
399 mpImplementation
->GetRowAtPosition (
402 bIncludePageBorders
? Implementation::GM_PAGE_BORDER
: Implementation::GM_NONE
));
403 const sal_Int32
nColumn (
404 mpImplementation
->GetColumnAtPosition (
407 bIncludePageBorders
? Implementation::GM_PAGE_BORDER
: Implementation::GM_NONE
));
409 return mpImplementation
->GetIndex(nRow
,nColumn
,bClampToValidRange
);
412 //===== Layouter::Implementation ==============================================
414 Layouter::Implementation
* Layouter::Implementation::Create (
415 const Implementation
& rImplementation
,
416 const Layouter::Orientation eOrientation
)
418 switch (eOrientation
)
420 case HORIZONTAL
: return new HorizontalImplementation(rImplementation
);
421 case VERTICAL
: return new VerticalImplementation(rImplementation
);
423 default: return new GridImplementation(rImplementation
);
427 Layouter::Implementation::Implementation (
429 const std::shared_ptr
<view::Theme
>& rpTheme
)
435 maMinimalSize(132,98),
436 maPreferredSize(200,150),
437 maMaximalSize(600,400),
438 mnMinimalColumnCount(1),
439 mnMaximalColumnCount(15),
445 maPageObjectSize(1,1),
446 mpPageObjectLayouter(),
451 Layouter::Implementation::Implementation (const Implementation
& rImplementation
)
452 : mpWindow(rImplementation
.mpWindow
),
453 mnLeftBorder(rImplementation
.mnLeftBorder
),
454 mnRightBorder(rImplementation
.mnRightBorder
),
455 mnTopBorder(rImplementation
.mnTopBorder
),
456 mnBottomBorder(rImplementation
.mnBottomBorder
),
457 maMinimalSize(rImplementation
.maMinimalSize
),
458 maPreferredSize(rImplementation
.maPreferredSize
),
459 maMaximalSize(rImplementation
.maMaximalSize
),
460 mnMinimalColumnCount(rImplementation
.mnMinimalColumnCount
),
461 mnMaximalColumnCount(rImplementation
.mnMaximalColumnCount
),
462 mnPageCount(rImplementation
.mnPageCount
),
463 mnColumnCount(rImplementation
.mnColumnCount
),
464 mnRowCount(rImplementation
.mnRowCount
),
465 mnMaxColumnCount(rImplementation
.mnMaxColumnCount
),
466 mnMaxRowCount(rImplementation
.mnMaxRowCount
),
467 maPageObjectSize(rImplementation
.maPageObjectSize
),
468 mpPageObjectLayouter(),
469 mpTheme(rImplementation
.mpTheme
)
473 Layouter::Implementation::~Implementation()
477 bool Layouter::Implementation::Rearrange (
478 const Size
& rWindowSize
,
479 const Size
& rPreviewModelSize
,
480 const sal_uInt32 nPageCount
)
482 mnPageCount
= nPageCount
;
484 // Return early when the window or the model have not yet been initialized.
485 if (rWindowSize
.Width()<=0 || rWindowSize
.Height()<=0)
487 if (rPreviewModelSize
.Width()<=0 || rPreviewModelSize
.Height()<=0)
490 CalculateRowAndColumnCount(rWindowSize
);
492 // Update the border values.
493 mnLeftBorder
= mnRequestedLeftBorder
;
494 mnTopBorder
= mnRequestedTopBorder
;
495 mnRightBorder
= mnRequestedRightBorder
;
496 mnBottomBorder
= mnRequestedBottomBorder
;
497 if (mnColumnCount
> 1)
499 int nMinimumBorderWidth
= gnHorizontalGap
/2;
500 if (mnLeftBorder
< nMinimumBorderWidth
)
501 mnLeftBorder
= nMinimumBorderWidth
;
502 if (mnRightBorder
< nMinimumBorderWidth
)
503 mnRightBorder
= nMinimumBorderWidth
;
507 int nMinimumBorderHeight
= gnVerticalGap
/2;
508 if (mnTopBorder
< nMinimumBorderHeight
)
509 mnTopBorder
= nMinimumBorderHeight
;
510 if (mnBottomBorder
< nMinimumBorderHeight
)
511 mnBottomBorder
= nMinimumBorderHeight
;
514 mpPageObjectLayouter
.reset(
515 new PageObjectLayouter(
516 CalculateTargetSize(rWindowSize
),
521 maPageObjectSize
= mpPageObjectLayouter
->GetGridMaxSize();
523 CalculateMaxRowAndColumnCount(rWindowSize
);
528 sal_Int32
Layouter::Implementation::GetRowAtPosition (
529 sal_Int32 nYPosition
,
530 bool bIncludeBordersAndGaps
,
531 GapMembership eGapMembership
) const
535 const sal_Int32 nY
= nYPosition
- mnTopBorder
;
538 // Vertical distance from one row to the next.
539 const sal_Int32
nRowOffset (maPageObjectSize
.Height() + gnVerticalGap
);
541 // Calculate row consisting of page objects and gap below.
542 nRow
= nY
/ nRowOffset
;
544 const sal_Int32
nDistanceIntoGap ((nY
- nRow
*nRowOffset
) - maPageObjectSize
.Height());
545 // When inside the gap below then nYPosition is not over a page
547 if (nDistanceIntoGap
> 0)
549 sal_Int32 nResolvedRow
= ResolvePositionInGap(
554 if (!bIncludeBordersAndGaps
|| nResolvedRow
!= -1)
558 else if (bIncludeBordersAndGaps
)
560 // We are in the top border area. Set nRow to the first row when
561 // the top border shall be considered to belong to the first row.
568 sal_Int32
Layouter::Implementation::GetColumnAtPosition (
569 sal_Int32 nXPosition
,
570 bool bIncludeBordersAndGaps
,
571 GapMembership eGapMembership
) const
573 sal_Int32 nColumn
= -1;
575 sal_Int32 nX
= nXPosition
- mnLeftBorder
;
578 // Horizontal distance from one column to the next.
579 const sal_Int32
nColumnOffset (maPageObjectSize
.Width() + gnHorizontalGap
);
581 // Calculate row consisting of page objects and gap below.
582 nColumn
= nX
/ nColumnOffset
;
585 else if (nColumn
>= mnColumnCount
)
586 nColumn
= mnColumnCount
-1;
588 const sal_Int32
nDistanceIntoGap ((nX
- nColumn
*nColumnOffset
) - maPageObjectSize
.Width());
589 // When inside the gap at the right then nXPosition is not over a
591 if (nDistanceIntoGap
> 0)
593 sal_Int32 nResolvedColumn
= ResolvePositionInGap(
598 if (!bIncludeBordersAndGaps
|| nResolvedColumn
!= -1)
599 nColumn
= nResolvedColumn
;
602 else if (bIncludeBordersAndGaps
)
604 // We are in the left border area. Set nColumn to the first column
605 // when the left border shall be considered to belong to the first
612 sal_Int32
Layouter::Implementation::ResolvePositionInGap (
613 sal_Int32 nDistanceIntoGap
,
614 GapMembership eGapMembership
,
618 switch (eGapMembership
)
621 // The gap is no man's land.
627 // The lower half of the gap belongs to the next row or column.
628 sal_Int32 nFirstHalfGapWidth
= nGap
/ 2;
629 if (nDistanceIntoGap
> nFirstHalfGapWidth
)
635 // Row or column already at correct value.
639 // The complete gap belongs to the next row or column.
644 if (nDistanceIntoGap
> 0)
646 if (nDistanceIntoGap
> nGap
)
648 // Inside the border of the next row or column.
653 // Inside the gap between the page borders.
666 void Layouter::Implementation::CalculateGeometricPosition (
667 InsertPosition
& rPosition
,
668 const Size
& rIndicatorSize
,
669 const bool bIsVertical
,
670 model::SlideSorterModel
const & rModel
) const
672 // 1. Determine right/bottom of the leading page and the left/top of the
673 // trailing page object and how to distribute the missing space.
674 sal_Int32
nLeadingLocation (0);
675 sal_Int32
nTrailingLocation (0);
676 bool bIsLeadingFixed (false);
677 bool bIsTrailingFixed (false);
678 sal_Int32
nSecondaryLocation (0);
679 const sal_Int32
nIndex (rPosition
.GetIndex());
681 if (rPosition
.IsAtRunStart())
683 // Place indicator at the top of the column.
684 const ::tools::Rectangle
aOuterBox (GetPageObjectBox(nIndex
));
685 const ::tools::Rectangle
aInnerBox (GetInnerBoundingBox(rModel
, nIndex
));
688 nLeadingLocation
= aOuterBox
.Top();
689 nTrailingLocation
= aInnerBox
.Top();
690 nSecondaryLocation
= aInnerBox
.Center().X();
694 nLeadingLocation
= aOuterBox
.Left();
695 nTrailingLocation
= aInnerBox
.Left();
696 nSecondaryLocation
= aInnerBox
.Center().Y();
698 bIsLeadingFixed
= true;
700 else if (rPosition
.IsAtRunEnd())
702 // Place indicator at the bottom/right of the column/row.
704 const ::tools::Rectangle
aOuterBox (GetPageObjectBox(nIndex
-1));
705 const ::tools::Rectangle
aInnerBox (GetInnerBoundingBox(rModel
, nIndex
-1));
708 nLeadingLocation
= aInnerBox
.Bottom();
709 nTrailingLocation
= aOuterBox
.Bottom();
710 nSecondaryLocation
= aInnerBox
.Center().X();
714 nLeadingLocation
= aInnerBox
.Right();
715 nTrailingLocation
= aOuterBox
.Right();
716 nSecondaryLocation
= aInnerBox
.Center().Y();
718 bIsTrailingFixed
= true;
719 if ( ! rPosition
.IsExtraSpaceNeeded())
720 bIsLeadingFixed
= true;
724 // Place indicator between two rows/columns.
725 const ::tools::Rectangle
aBox1 (GetInnerBoundingBox(rModel
, nIndex
-1));
726 const ::tools::Rectangle
aBox2 (GetInnerBoundingBox(rModel
, nIndex
));
729 nLeadingLocation
= aBox1
.Bottom();
730 nTrailingLocation
= aBox2
.Top();
731 nSecondaryLocation
= (aBox1
.Center().X() + aBox2
.Center().X()) / 2;
735 nLeadingLocation
= aBox1
.Right();
736 nTrailingLocation
= aBox2
.Left();
737 nSecondaryLocation
= (aBox1
.Center().Y() + aBox2
.Center().Y()) / 2;
741 // 2. Calculate the location of the insert indicator and the offsets of
742 // leading and trailing pages.
743 const sal_Int32
nAvailableSpace (nTrailingLocation
- nLeadingLocation
);
744 const sal_Int32
nRequiredSpace (bIsVertical
? rIndicatorSize
.Height():rIndicatorSize
.Width());
745 const sal_Int32
nMissingSpace (::std::max(sal_Int32(0), nRequiredSpace
- nAvailableSpace
));
746 sal_Int32
nPrimaryLocation (0);
747 sal_Int32
nLeadingOffset (0);
748 sal_Int32
nTrailingOffset (0);
751 nPrimaryLocation
= nLeadingLocation
+ nRequiredSpace
/2;
752 if ( ! bIsTrailingFixed
)
753 nTrailingOffset
= nMissingSpace
;
755 else if (bIsTrailingFixed
)
757 nPrimaryLocation
= nTrailingLocation
- nRequiredSpace
/2;
758 nLeadingOffset
= -nMissingSpace
;
762 nPrimaryLocation
= (nLeadingLocation
+ nTrailingLocation
) /2;
763 nLeadingOffset
= -nMissingSpace
/2;
764 nTrailingOffset
= nMissingSpace
+ nLeadingOffset
;
769 rPosition
.SetGeometricalPosition(
770 Point(nSecondaryLocation
, nPrimaryLocation
),
771 Point(0, nLeadingOffset
),
772 Point(0, nTrailingOffset
));
776 rPosition
.SetGeometricalPosition(
777 Point(nPrimaryLocation
, nSecondaryLocation
),
778 Point(nLeadingOffset
, 0),
779 Point(nTrailingOffset
, 0));
783 ::tools::Rectangle
Layouter::Implementation::GetInnerBoundingBox (
784 model::SlideSorterModel
const & rModel
,
785 const sal_Int32 nIndex
) const
787 model::SharedPageDescriptor
pDescriptor (rModel
.GetPageDescriptor(nIndex
));
789 return ::tools::Rectangle();
791 PageObjectLayouter::Part ePart
= PageObjectLayouter::Part::Preview
;
793 if (pDescriptor
->HasState(model::PageDescriptor::ST_Selected
))
794 ePart
= PageObjectLayouter::Part::PageObject
;
796 return mpPageObjectLayouter
->GetBoundingBox(
798 PageObjectLayouter::ModelCoordinateSystem
, true);
801 Range
Layouter::Implementation::GetValidHorizontalSizeRange() const
804 mnLeftBorder
+ maMinimalSize
.Width() + mnRightBorder
,
805 mnLeftBorder
+ maMaximalSize
.Width() + mnRightBorder
);
808 Range
Layouter::Implementation::GetValidVerticalSizeRange() const
811 mnTopBorder
+ maMinimalSize
.Height() + mnBottomBorder
,
812 mnTopBorder
+ maMaximalSize
.Height() + mnBottomBorder
);
815 Range
Layouter::Implementation::GetRangeOfVisiblePageObjects (const ::tools::Rectangle
& aVisibleArea
) const
817 const sal_Int32
nRow0 (GetRowAtPosition(aVisibleArea
.Top(), true, GM_NEXT
));
818 const sal_Int32
nCol0 (GetColumnAtPosition(aVisibleArea
.Left(),true, GM_NEXT
));
819 const sal_Int32
nRow1 (GetRowAtPosition(aVisibleArea
.Bottom(), true, GM_PREVIOUS
));
820 const sal_Int32
nCol1 (GetColumnAtPosition(aVisibleArea
.Right(), true, GM_PREVIOUS
));
822 // When start and end lie in different rows then the range may include
823 // slides outside (left or right of) the given area.
824 return Range(GetIndex(nRow0
,nCol0
,true), GetIndex(nRow1
,nCol1
,true));
827 Size
Layouter::Implementation::GetTargetSize (
828 const Size
& rWindowSize
,
829 const bool bCalculateWidth
,
830 const bool bCalculateHeight
) const
832 if (mnColumnCount
<=0 || mnRowCount
<=0)
833 return maPreferredSize
;
834 if ( ! (bCalculateWidth
|| bCalculateHeight
))
836 OSL_ASSERT(bCalculateWidth
|| bCalculateHeight
);
837 return maPreferredSize
;
840 // Calculate the width of each page object.
841 Size
aTargetSize (0,0);
843 aTargetSize
.setWidth(
844 (rWindowSize
.Width() - mnLeftBorder
- mnRightBorder
845 - (mnColumnCount
-1) * gnHorizontalGap
)
847 else if (bCalculateHeight
)
848 aTargetSize
.setHeight(
849 (rWindowSize
.Height() - mnTopBorder
- mnBottomBorder
850 - (mnRowCount
-1) * gnVerticalGap
)
855 if (aTargetSize
.Width() < maMinimalSize
.Width())
856 aTargetSize
.setWidth(maMinimalSize
.Width());
857 else if (aTargetSize
.Width() > maMaximalSize
.Width())
858 aTargetSize
.setWidth(maMaximalSize
.Width());
860 else if (bCalculateHeight
)
862 if (aTargetSize
.Height() < maMinimalSize
.Height())
863 aTargetSize
.setHeight(maMinimalSize
.Height());
864 else if (aTargetSize
.Height() > maMaximalSize
.Height())
865 aTargetSize
.setHeight(maMaximalSize
.Height());
871 sal_Int32
Layouter::Implementation::GetIndex (
872 const sal_Int32 nRow
,
873 const sal_Int32 nColumn
,
874 const bool bClampToValidRange
) const
876 if (nRow
>= 0 && nColumn
>= 0)
878 const sal_Int32
nIndex (nRow
* mnColumnCount
+ nColumn
);
879 if (nIndex
>= mnPageCount
)
880 if (bClampToValidRange
)
881 return mnPageCount
-1;
887 else if (bClampToValidRange
)
893 ::tools::Rectangle
Layouter::Implementation::GetPageObjectBox (
894 const sal_Int32 nIndex
,
895 const bool bIncludeBorderAndGap
) const
897 const sal_Int32
nRow (nIndex
/ mnColumnCount
);
898 const sal_Int32
nColumn (nIndex
% mnColumnCount
);
900 const ::tools::Rectangle
aBoundingBox (GetPageObjectBox(nRow
,nColumn
));
901 if (bIncludeBorderAndGap
)
902 return AddBorderAndGap(aBoundingBox
, nRow
, nColumn
);
907 ::tools::Rectangle
Layouter::Implementation::GetPageObjectBox (
908 const sal_Int32 nRow
,
909 const sal_Int32 nColumn
) const
911 return ::tools::Rectangle(
913 + nColumn
* maPageObjectSize
.Width()
914 + std::max
<sal_Int32
>(nColumn
,0) * gnHorizontalGap
,
916 + nRow
* maPageObjectSize
.Height()
917 + std::max
<sal_Int32
>(nRow
,0) * gnVerticalGap
),
921 ::tools::Rectangle
Layouter::Implementation::AddBorderAndGap (
922 const ::tools::Rectangle
& rBoundingBox
,
923 const sal_Int32 nRow
,
924 const sal_Int32 nColumn
) const
926 ::tools::Rectangle
aBoundingBox (rBoundingBox
);
929 aBoundingBox
.SetLeft( 0 );
931 aBoundingBox
.AdjustLeft( -(gnHorizontalGap
/2) );
932 if (nColumn
== mnColumnCount
-1)
933 aBoundingBox
.AdjustRight(mnRightBorder
);
935 aBoundingBox
.AdjustRight(gnHorizontalGap
/2 );
937 aBoundingBox
.SetTop( 0 );
939 aBoundingBox
.AdjustTop( -(gnVerticalGap
/2) );
940 if (nRow
== mnRowCount
-1)
941 aBoundingBox
.AdjustBottom(mnBottomBorder
);
943 aBoundingBox
.AdjustBottom(gnVerticalGap
/2 );
947 ::tools::Rectangle
Layouter::Implementation::GetTotalBoundingBox() const
949 sal_Int32 nHorizontalSize
= 0;
950 sal_Int32 nVerticalSize
= 0;
951 if (mnColumnCount
> 0)
953 sal_Int32 nRowCount
= (mnPageCount
+mnColumnCount
-1) / mnColumnCount
;
957 + mnColumnCount
* maPageObjectSize
.Width();
958 if (mnColumnCount
> 1)
959 nHorizontalSize
+= (mnColumnCount
-1) * gnHorizontalGap
;
963 + nRowCount
* maPageObjectSize
.Height();
965 nVerticalSize
+= (nRowCount
-1) * gnVerticalGap
;
968 return ::tools::Rectangle (
970 Size (nHorizontalSize
, nVerticalSize
)
974 void Layouter::Implementation::CalculateVerticalLogicalInsertPosition (
975 const Point
& rModelPosition
,
976 InsertPosition
& rPosition
) const
978 const sal_Int32 nY
= rModelPosition
.Y() - mnTopBorder
+ maPageObjectSize
.Height()/2;
979 const sal_Int32
nRowHeight (maPageObjectSize
.Height() + gnVerticalGap
);
980 const sal_Int32
nRow (::std::min(mnPageCount
, nY
/ nRowHeight
));
981 rPosition
.SetLogicalPosition (
986 (nRow
== mnRowCount
),
987 (nRow
>= mnMaxRowCount
));
990 //===== HorizontalImplementation ================================================
992 HorizontalImplementation::HorizontalImplementation (const Implementation
& rImplementation
)
993 : Implementation(rImplementation
)
997 Layouter::Orientation
HorizontalImplementation::GetOrientation() const
999 return Layouter::HORIZONTAL
;
1002 void HorizontalImplementation::CalculateRowAndColumnCount (const Size
&)
1004 // Row and column count are fixed (for a given page count.)
1005 mnColumnCount
= mnPageCount
;
1009 void HorizontalImplementation::CalculateMaxRowAndColumnCount (const Size
& rWindowSize
)
1011 mnMaxColumnCount
= (rWindowSize
.Width() - mnLeftBorder
- mnRightBorder
)
1012 / (maPageObjectSize
.Width() + gnHorizontalGap
);
1016 Size
HorizontalImplementation::CalculateTargetSize (
1017 const Size
& rWindowSize
) const
1019 return Implementation::GetTargetSize(rWindowSize
, false, true);
1022 void HorizontalImplementation::CalculateLogicalInsertPosition (
1023 const Point
& rModelPosition
,
1024 InsertPosition
& rPosition
) const
1026 const sal_Int32 nX
= rModelPosition
.X() - mnLeftBorder
+ maPageObjectSize
.Width()/2;
1027 const sal_Int32
nColumnWidth (maPageObjectSize
.Width() + gnHorizontalGap
);
1028 const sal_Int32
nColumn (::std::min(mnPageCount
, nX
/ nColumnWidth
));
1029 rPosition
.SetLogicalPosition (
1034 (nColumn
== mnColumnCount
),
1035 (nColumn
>= mnMaxColumnCount
));
1038 //===== VerticalImplementation ================================================
1040 VerticalImplementation::VerticalImplementation (const Implementation
& rImplementation
)
1041 : Implementation(rImplementation
)
1045 Layouter::Orientation
VerticalImplementation::GetOrientation() const
1047 return Layouter::VERTICAL
;
1050 void VerticalImplementation::CalculateRowAndColumnCount (const Size
&)
1052 // Row and column count are fixed (for a given page count.)
1053 mnRowCount
= mnPageCount
;
1058 void VerticalImplementation::CalculateMaxRowAndColumnCount (const Size
& rWindowSize
)
1060 mnMaxRowCount
= (rWindowSize
.Height() - mnTopBorder
- mnBottomBorder
)
1061 / (maPageObjectSize
.Height() + gnVerticalGap
);
1062 mnMaxColumnCount
= 1;
1065 Size
VerticalImplementation::CalculateTargetSize (
1066 const Size
& rWindowSize
) const
1068 return Implementation::GetTargetSize(rWindowSize
, true, false);
1071 void VerticalImplementation::CalculateLogicalInsertPosition (
1072 const Point
& rModelPosition
,
1073 InsertPosition
& rPosition
) const
1075 return CalculateVerticalLogicalInsertPosition(rModelPosition
, rPosition
);
1078 //===== GridImplementation ================================================
1080 GridImplementation::GridImplementation (
1081 sd::Window
*pWindow
,
1082 const std::shared_ptr
<view::Theme
>& rpTheme
)
1083 : Implementation(pWindow
, rpTheme
)
1087 GridImplementation::GridImplementation (const Implementation
& rImplementation
)
1088 : Implementation(rImplementation
)
1092 Layouter::Orientation
GridImplementation::GetOrientation() const
1094 return Layouter::GRID
;
1097 void GridImplementation::CalculateRowAndColumnCount (const Size
& rWindowSize
)
1099 // Calculate the column count.
1101 = (rWindowSize
.Width() - mnRequestedLeftBorder
- mnRequestedRightBorder
)
1102 / (maPreferredSize
.Width() + gnHorizontalGap
);
1103 if (mnColumnCount
< mnMinimalColumnCount
)
1104 mnColumnCount
= mnMinimalColumnCount
;
1105 if (mnColumnCount
> mnMaximalColumnCount
)
1106 mnColumnCount
= mnMaximalColumnCount
;
1107 mnRowCount
= (mnPageCount
+ mnColumnCount
-1)/mnColumnCount
;
1110 void GridImplementation::CalculateMaxRowAndColumnCount (const Size
& rWindowSize
)
1112 mnMaxColumnCount
= (rWindowSize
.Width() - mnLeftBorder
- mnRightBorder
)
1113 / (maPageObjectSize
.Width() + gnHorizontalGap
);
1114 mnMaxRowCount
= (rWindowSize
.Height() - mnTopBorder
- mnBottomBorder
)
1115 / (maPageObjectSize
.Height() + gnVerticalGap
);
1118 Size
GridImplementation::CalculateTargetSize (
1119 const Size
& rWindowSize
) const
1121 return Implementation::GetTargetSize(rWindowSize
, true, true);
1124 void GridImplementation::CalculateLogicalInsertPosition (
1125 const Point
& rModelPosition
,
1126 InsertPosition
& rPosition
) const
1128 if (mnColumnCount
== 1)
1130 CalculateVerticalLogicalInsertPosition(rModelPosition
, rPosition
);
1134 // Handle the general case of more than one column.
1135 sal_Int32
nRow (::std::min(
1137 GetRowAtPosition (rModelPosition
.Y(), true, GM_BOTH
)));
1138 const sal_Int32 nX
= rModelPosition
.X() - mnLeftBorder
+ maPageObjectSize
.Width()/2;
1139 const sal_Int32
nColumnWidth (maPageObjectSize
.Width() + gnHorizontalGap
);
1140 sal_Int32
nColumn (::std::min(mnColumnCount
, nX
/ nColumnWidth
));
1141 sal_Int32
nIndex (nRow
* mnColumnCount
+ nColumn
);
1142 bool bIsAtRunEnd (nColumn
== mnColumnCount
);
1144 if (nIndex
>= mnPageCount
)
1146 nIndex
= mnPageCount
;
1147 nRow
= mnRowCount
-1;
1148 nColumn
= ::std::min(::std::min(mnPageCount
, mnColumnCount
), nColumn
);
1152 rPosition
.SetLogicalPosition (
1158 (nColumn
>= mnMaxColumnCount
));
1162 //===== InsertPosition ========================================================
1164 InsertPosition::InsertPosition()
1168 mbIsAtRunStart(false),
1169 mbIsAtRunEnd(false),
1170 mbIsExtraSpaceNeeded(false),
1172 maLeadingOffset(0,0),
1173 maTrailingOffset(0,0)
1177 bool InsertPosition::operator== (const InsertPosition
& rInsertPosition
) const
1179 // Do not compare the geometrical information (maLocation).
1180 return mnRow
==rInsertPosition
.mnRow
1181 && mnColumn
==rInsertPosition
.mnColumn
1182 && mnIndex
==rInsertPosition
.mnIndex
1183 && mbIsAtRunStart
==rInsertPosition
.mbIsAtRunStart
1184 && mbIsAtRunEnd
==rInsertPosition
.mbIsAtRunEnd
1185 && mbIsExtraSpaceNeeded
==rInsertPosition
.mbIsExtraSpaceNeeded
;
1188 bool InsertPosition::operator!= (const InsertPosition
& rInsertPosition
) const
1190 return !operator==(rInsertPosition
);
1193 void InsertPosition::SetLogicalPosition (
1194 const sal_Int32 nRow
,
1195 const sal_Int32 nColumn
,
1196 const sal_Int32 nIndex
,
1197 const bool bIsAtRunStart
,
1198 const bool bIsAtRunEnd
,
1199 const bool bIsExtraSpaceNeeded
)
1204 mbIsAtRunStart
= bIsAtRunStart
;
1205 mbIsAtRunEnd
= bIsAtRunEnd
;
1206 mbIsExtraSpaceNeeded
= bIsExtraSpaceNeeded
;
1209 void InsertPosition::SetGeometricalPosition(
1210 const Point
& rLocation
,
1211 const Point
& rLeadingOffset
,
1212 const Point
& rTrailingOffset
)
1214 maLocation
= rLocation
;
1215 maLeadingOffset
= rLeadingOffset
;
1216 maTrailingOffset
= rTrailingOffset
;
1219 } } } // end of namespace ::sd::slidesorter::namespace
1221 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */