1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "precompiled_sd.hxx"
25 
26 #include "view/SlsLayouter.hxx"
27 #include "model/SlideSorterModel.hxx"
28 #include "model/SlsPageDescriptor.hxx"
29 #include "Window.hxx"
30 #include <rtl/math.hxx>
31 #include <basegfx/numeric/ftools.hxx>
32 
33 namespace {
RoundToInt(const double nValue)34     sal_Int32 RoundToInt (const double nValue)
35     {
36         return sal_Int32(::rtl::math::round(nValue));
37     }
38 }
39 
40 
41 namespace sd { namespace slidesorter { namespace view {
42 
43 class Layouter::Implementation
44 {
45 public:
46     SharedSdWindow mpWindow;
47     sal_Int32 mnRequestedLeftBorder;
48     sal_Int32 mnRequestedRightBorder;
49     sal_Int32 mnRequestedTopBorder;
50     sal_Int32 mnRequestedBottomBorder;
51     sal_Int32 mnLeftBorder;
52     sal_Int32 mnRightBorder;
53     sal_Int32 mnTopBorder;
54     sal_Int32 mnBottomBorder;
55     sal_Int32 mnVerticalGap;
56     sal_Int32 mnHorizontalGap;
57     Size maMinimalSize;
58     Size maPreferredSize;
59     Size maMaximalSize;
60     sal_Int32 mnMinimalColumnCount;
61     sal_Int32 mnMaximalColumnCount;
62     sal_Int32 mnPageCount;
63     sal_Int32 mnColumnCount;
64     sal_Int32 mnRowCount;
65     /// The maximum number of columns.  Can only be larger than the current
66     /// number of columns when there are not enough pages to fill all
67     /// available columns.
68     sal_Int32 mnMaxColumnCount;
69     /// The maximum number of rows.  Can only be larger than the current
70     /// number of rows when there are not enough pages to fill all available
71     /// rows.
72     sal_Int32 mnMaxRowCount;
73     Size maPageObjectSize;
74     ::boost::shared_ptr<PageObjectLayouter> mpPageObjectLayouter;
75     ::boost::shared_ptr<view::Theme> mpTheme;
76 
77     /** Specify how the gap between two page objects is associated with the
78       page objects.
79     */
80     enum GapMembership {
81         GM_NONE,       // Gap is not associated with any page object.
82         GM_PREVIOUS,   // The whole gap is associated with the previous page
83                        // object (left or above the gap.)
84         GM_BOTH,       // Half of the gap is associated with previous, half
85                        // with the next page object.
86         GM_NEXT,       // The whole gap is associated with the next page
87                        // object (right or below the gap.)
88         GM_PAGE_BORDER
89     };
90 
91     static Implementation* Create (
92         const Implementation& rImplementation,
93         const Layouter::Orientation eOrientation);
94 
95     virtual Layouter::Orientation GetOrientation (void) const = 0;
96 
97     bool Rearrange (
98         const Size& rWindowSize,
99         const Size& rPreviewModelSize,
100         const sal_uInt32 nPageCount);
101 
102     /** Calculate the row that the point with the given vertical coordinate
103         is over.  The horizontal component is ignored.
104         @param nYPosition
105             Vertical position in model coordinates.
106         @param bIncludeBordersAndGaps
107             When this flag is <TRUE/> then the area of borders and gaps are
108             interpreted as belonging to one of the rows.
109         @param eGapMembership
110             Specifies to what row the gap areas belong.  Here GM_NONE
111             corresponds to bIncludeBordersAndGaps being <FALSE/>.  When
112             GM_BOTH is given then the upper half is associated to the row
113             above and the lower half to the row below.  Values of
114             GM_PREVIOUS and GM_NEXT associate the whole gap area with the
115             row above or below respectively.
116     */
117     sal_Int32 GetRowAtPosition (
118         sal_Int32 nYPosition,
119         bool bIncludeBordersAndGaps,
120         GapMembership eGapMembership = GM_NONE) const;
121 
122     /** Calculate the column that the point with the given horizontal
123         coordinate is over.  The verical component is ignored.
124         @param nXPosition
125             Horizontal position in model coordinates.
126         @param bIncludeBordersAndGaps
127             When this flag is <TRUE/> then the area of borders and gaps are
128             interpreted as belonging to one of the columns.
129         @param eGapMembership
130             Specifies to what column the gap areas belong.
131     */
132     sal_Int32 GetColumnAtPosition (
133         sal_Int32 nXPosition,
134         bool bIncludeBordersAndGaps,
135         GapMembership eGapMembership = GM_NONE) const;
136 
137     /** This method is typically called from GetRowAtPosition() and
138         GetColumnAtPosition() to handle a position that lies inside the gap
139         between two adjacent rows or columns.
140         @param nDistanceIntoGap
141             Vertical distance from the bottom of the upper row down into the
142             gap or or horizontal distance from the right edge right into the
143             gap.
144         @param eGapMemberhship
145             This value decides what areas in the gap belong to which (or no)
146             row or column.
147         @param nIndex
148             The row index of the upper row or the column index of the left
149             column.
150         @param nGap
151              Width or height of the gap in model coordiantes between the
152              page borders.
153         @return
154            Returns either the index of the upper row (as given as nRow), the
155            index of the lower row (nRow+1) or -1 to indicate that the
156            position belongs to no row.
157         */
158     sal_Int32 ResolvePositionInGap (
159         sal_Int32 nDistanceIntoGap,
160         GapMembership eGapMembership,
161         sal_Int32 nIndex,
162         sal_Int32 nGap) const;
163 
164     /** Calculate the logical part of the insert position, i.e. the page
165         after whicht to insert.
166     */
167     virtual void CalculateLogicalInsertPosition (
168         const Point& rModelPosition,
169         InsertPosition& rPosition) const = 0;
170 
171     /** Calculate the geometrical part of the insert position, i.e. the
172         location of where to display the insertion indicator and the
173         distances about which the leading and trailing pages have to be
174         moved to make room for the indicator.
175     */
176     void CalculateGeometricPosition (
177         InsertPosition& rPosition,
178         const Size& rIndicatorSize,
179         const bool bIsVertical,
180         model::SlideSorterModel& rModel) const;
181 
182     /** Return the bounding box of the preview or, when selected, of the page
183         object.  Thus, it returns something like a visual bounding box.
184     */
185     Rectangle GetInnerBoundingBox (
186         model::SlideSorterModel& rModel,
187         const sal_Int32 nIndex) const;
188 
189     Range GetValidHorizontalSizeRange (void) const;
190     Range GetValidVerticalSizeRange (void) const;
191 
192     Range GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const;
193     sal_Int32 GetIndex (
194         const sal_Int32 nRow,
195         const sal_Int32 nColumn,
196         const bool bClampToValidRange) const;
197 
198         Rectangle GetPageObjectBox (
199         const sal_Int32 nIndex,
200         const bool bIncludeBorderAndGap = false) const;
201 
202     Rectangle GetPageObjectBox (
203         const sal_Int32 nRow,
204         const sal_Int32 nColumn) const;
205 
206     Rectangle AddBorderAndGap (
207         const Rectangle& rBoundingBox,
208         const sal_Int32 nRow,
209         const sal_Int32 nColumn) const;
210 
211     Rectangle GetTotalBoundingBox (void) const;
212 
213     virtual ~Implementation (void);
214 
215 protected:
216     Implementation (
217         const SharedSdWindow& rpWindow,
218         const ::boost::shared_ptr<view::Theme>& rpTheme);
219     Implementation (const Implementation& rImplementation);
220 
221     virtual void CalculateRowAndColumnCount (const Size& rWindowSize) = 0;
222     virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) = 0;
223     virtual Size CalculateTargetSize (
224         const Size& rWindowSize,
225         const Size& rPreviewModelSize) const = 0;
226     Size GetTargetSize (
227         const Size& rWindowSize,
228         const Size& rPreviewModelSize,
229         const bool bCalculateWidth,
230         const bool bCalculateHeight) const;
231     void CalculateVerticalLogicalInsertPosition (
232         const Point& rModelPosition,
233         InsertPosition& rPosition) const;
234 };
235 
236 
237 /** The vertical layouter has one column and as many rows as there are
238     pages.
239 */
240 class VerticalImplementation : public Layouter::Implementation
241 {
242 public:
243     VerticalImplementation (
244         const SharedSdWindow& rpWindow,
245         const ::boost::shared_ptr<view::Theme>& rpTheme);
246     VerticalImplementation (const Implementation& rImplementation);
247 
248     virtual Layouter::Orientation GetOrientation (void) const;
249 
250     void CalculateLogicalInsertPosition (
251         const Point& rModelPosition,
252         InsertPosition& rPosition) const;
253 
254 protected:
255     virtual void CalculateRowAndColumnCount (const Size& rWindowSize);
256     virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize);
257     virtual Size CalculateTargetSize (
258         const Size& rWindowSize,
259         const Size& rPreviewModelSize) const;
260 };
261 
262 
263 /** The horizontal layouter has one row and as many columns as there are
264     pages.
265 */
266 class HorizontalImplementation : public Layouter::Implementation
267 {
268 public:
269     HorizontalImplementation (
270         const SharedSdWindow& rpWindow,
271         const ::boost::shared_ptr<view::Theme>& rpTheme);
272     HorizontalImplementation (const Implementation& rImplementation);
273 
274     virtual Layouter::Orientation GetOrientation (void) const;
275 
276     void CalculateLogicalInsertPosition (
277         const Point& rModelPosition,
278         InsertPosition& rPosition) const;
279 
280 protected:
281     virtual void CalculateRowAndColumnCount (const Size& rWindowSize);
282     virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize);
283     virtual Size CalculateTargetSize (
284         const Size& rWindowSize,
285         const Size& rPreviewModelSize) const;
286 };
287 
288 
289 /** The number of columns of the grid layouter is defined via a control in
290     the slide sorter tool bar.  The number of rows is calculated from the
291     number of columns and the number of pages.
292 */
293 class GridImplementation : public Layouter::Implementation
294 {
295 public:
296     GridImplementation (
297         const SharedSdWindow& rpWindow,
298         const ::boost::shared_ptr<view::Theme>& rpTheme);
299     GridImplementation (const Implementation& rImplementation);
300 
301     virtual Layouter::Orientation GetOrientation (void) const;
302 
303     void CalculateLogicalInsertPosition (
304         const Point& rModelPosition,
305         InsertPosition& rPosition) const;
306 
307 protected:
308     virtual void CalculateRowAndColumnCount (const Size& rWindowSize);
309     virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize);
310     virtual Size CalculateTargetSize (
311         const Size& rWindowSize,
312         const Size& rPreviewModelSize) const;
313 };
314 
315 
316 
317 
318 //===== Layouter ==============================================================
319 
Layouter(const SharedSdWindow & rpWindow,const::boost::shared_ptr<Theme> & rpTheme)320 Layouter::Layouter (
321     const SharedSdWindow& rpWindow,
322     const ::boost::shared_ptr<Theme>& rpTheme)
323     : mpImplementation(new GridImplementation(rpWindow, rpTheme)),
324       mpWindow(rpWindow)
325 {
326 }
327 
328 
329 
330 
~Layouter(void)331 Layouter::~Layouter (void)
332 {
333 }
334 
335 
336 
337 
GetPageObjectLayouter(void) const338 ::boost::shared_ptr<PageObjectLayouter> Layouter::GetPageObjectLayouter (void) const
339 {
340     return mpImplementation->mpPageObjectLayouter;
341 }
342 
343 
344 
345 
SetBorders(sal_Int32 nLeftBorder,sal_Int32 nRightBorder,sal_Int32 nTopBorder,sal_Int32 nBottomBorder)346 void Layouter::SetBorders (
347     sal_Int32 nLeftBorder,
348     sal_Int32 nRightBorder,
349     sal_Int32 nTopBorder,
350     sal_Int32 nBottomBorder)
351 {
352     if (nLeftBorder >= 0)
353         mpImplementation->mnRequestedLeftBorder = nLeftBorder;
354     if (nRightBorder >= 0)
355         mpImplementation->mnRequestedRightBorder = nRightBorder;
356     if (nTopBorder >= 0)
357         mpImplementation->mnRequestedTopBorder = nTopBorder;
358     if (nBottomBorder >= 0)
359         mpImplementation->mnRequestedBottomBorder = nBottomBorder;
360 }
361 
362 
363 
364 
SetColumnCount(sal_Int32 nMinimalColumnCount,sal_Int32 nMaximalColumnCount)365 void Layouter::SetColumnCount (
366     sal_Int32 nMinimalColumnCount,
367         sal_Int32 nMaximalColumnCount)
368 {
369     if (nMinimalColumnCount <= nMaximalColumnCount)
370     {
371         mpImplementation->mnMinimalColumnCount = nMinimalColumnCount;
372         mpImplementation->mnMaximalColumnCount = nMaximalColumnCount;
373     }
374 }
375 
376 
377 
378 
Rearrange(const Orientation eOrientation,const Size & rWindowSize,const Size & rPageSize,const sal_uInt32 nPageCount)379 bool Layouter::Rearrange (
380     const Orientation eOrientation,
381     const Size& rWindowSize,
382     const Size& rPageSize,
383     const sal_uInt32 nPageCount)
384 {
385     OSL_ASSERT(mpWindow);
386 
387     if (eOrientation != mpImplementation->GetOrientation())
388         mpImplementation.reset(Implementation::Create(*mpImplementation, eOrientation));
389 
390     return mpImplementation->Rearrange(rWindowSize, rPageSize, nPageCount);
391 }
392 
393 
394 
395 
_SetZoom(double nZoomFactor)396 void Layouter::_SetZoom (double nZoomFactor)
397 {
398     _SetZoom(Fraction(nZoomFactor));
399 }
400 
401 
402 
403 
_SetZoom(Fraction nZoomFactor)404 void Layouter::_SetZoom (Fraction nZoomFactor)
405 {
406     OSL_ASSERT(mpWindow);
407 
408     MapMode aMapMode (mpWindow->GetMapMode());
409     aMapMode.SetScaleX (nZoomFactor);
410     aMapMode.SetScaleY (nZoomFactor);
411     mpWindow->SetMapMode (aMapMode);
412 }
413 
414 
415 
416 
GetColumnCount(void) const417 sal_Int32 Layouter::GetColumnCount (void) const
418 {
419     return mpImplementation->mnColumnCount;
420 }
421 
422 
423 
424 
GetRowCount(void) const425 sal_Int32 Layouter::GetRowCount (void) const
426 {
427     return mpImplementation->mnRowCount;
428 }
429 
430 
431 
432 
GetRow(const sal_Int32 nIndex) const433 sal_Int32 Layouter::GetRow (const sal_Int32 nIndex) const
434 {
435     return nIndex / mpImplementation->mnColumnCount;
436 }
437 
438 
439 
440 
GetColumn(const sal_Int32 nIndex) const441 sal_Int32 Layouter::GetColumn (const sal_Int32 nIndex) const
442 {
443     return nIndex % mpImplementation->mnColumnCount;
444 }
445 
446 
447 
448 
GetIndex(const sal_Int32 nRow,const sal_Int32 nColumn) const449 sal_Int32 Layouter::GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const
450 {
451     return mpImplementation->GetIndex(nRow,nColumn,true);
452 }
453 
454 
455 
456 
GetPageObjectSize(void) const457 Size Layouter::GetPageObjectSize (void) const
458 {
459     return mpImplementation->maPageObjectSize;
460 }
461 
462 
463 
464 
GetPageObjectBox(const sal_Int32 nIndex,const bool bIncludeBorderAndGap) const465 Rectangle Layouter::GetPageObjectBox (
466     const sal_Int32 nIndex,
467     const bool bIncludeBorderAndGap) const
468 {
469     return mpImplementation->GetPageObjectBox(nIndex, bIncludeBorderAndGap);
470 }
471 
472 
473 
474 
GetTotalBoundingBox(void) const475 Rectangle Layouter::GetTotalBoundingBox (void) const
476 {
477     return mpImplementation->GetTotalBoundingBox();
478 }
479 
480 
481 
482 
GetInsertPosition(const Point & rModelPosition,const Size & rIndicatorSize,model::SlideSorterModel & rModel) const483 InsertPosition Layouter::GetInsertPosition (
484     const Point& rModelPosition,
485     const Size& rIndicatorSize,
486     model::SlideSorterModel& rModel) const
487 {
488     InsertPosition aPosition;
489     mpImplementation->CalculateLogicalInsertPosition(
490         rModelPosition,
491         aPosition);
492     mpImplementation->CalculateGeometricPosition(
493         aPosition,
494         rIndicatorSize,
495         GetColumnCount()==1,
496         rModel);
497     return aPosition;
498 }
499 
500 
501 
502 
GetValidHorizontalSizeRange(void) const503 Range Layouter::GetValidHorizontalSizeRange (void) const
504 {
505     return mpImplementation->GetValidHorizontalSizeRange();
506 }
507 
508 
509 
510 
GetValidVerticalSizeRange(void) const511 Range Layouter::GetValidVerticalSizeRange (void) const
512 {
513     return mpImplementation->GetValidVerticalSizeRange();
514 }
515 
516 
517 
518 
GetRangeOfVisiblePageObjects(const Rectangle & aVisibleArea) const519 Range Layouter::GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const
520 {
521     return mpImplementation->GetRangeOfVisiblePageObjects(aVisibleArea);
522 }
523 
524 
525 
526 
GetIndexAtPoint(const Point & rPosition,const bool bIncludePageBorders,const bool bClampToValidRange) const527 sal_Int32 Layouter::GetIndexAtPoint (
528     const Point& rPosition,
529     const bool bIncludePageBorders,
530     const bool bClampToValidRange) const
531 {
532     const sal_Int32 nRow (
533         mpImplementation->GetRowAtPosition (
534             rPosition.Y(),
535             bIncludePageBorders,
536             bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE));
537     const sal_Int32 nColumn (
538         mpImplementation->GetColumnAtPosition (
539             rPosition.X(),
540             bIncludePageBorders,
541             bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE));
542 
543     return mpImplementation->GetIndex(nRow,nColumn,bClampToValidRange);
544 }
545 
546 
547 
548 
549 //===== Layouter::Implementation ==============================================
550 
Create(const Implementation & rImplementation,const Layouter::Orientation eOrientation)551 Layouter::Implementation* Layouter::Implementation::Create (
552     const Implementation& rImplementation,
553     const Layouter::Orientation eOrientation)
554 {
555     switch (eOrientation)
556     {
557         case HORIZONTAL: return new HorizontalImplementation(rImplementation);
558         case VERTICAL: return new VerticalImplementation(rImplementation);
559         case GRID:
560         default: return new GridImplementation(rImplementation);
561     }
562 }
563 
564 
565 
566 
Implementation(const SharedSdWindow & rpWindow,const::boost::shared_ptr<view::Theme> & rpTheme)567 Layouter::Implementation::Implementation (
568     const SharedSdWindow& rpWindow,
569     const ::boost::shared_ptr<view::Theme>& rpTheme)
570     : mpWindow(rpWindow),
571       mnRequestedLeftBorder(5),
572       mnRequestedRightBorder(5),
573       mnRequestedTopBorder(5),
574       mnRequestedBottomBorder(5),
575       mnLeftBorder(5),
576       mnRightBorder(5),
577       mnTopBorder(5),
578       mnBottomBorder(5),
579       mnVerticalGap (10 - 2*rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)),
580       mnHorizontalGap(10 - 2*rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)),
581       maMinimalSize(132,98),
582       maPreferredSize(200,150),
583       maMaximalSize(300,200),
584       mnMinimalColumnCount(1),
585       mnMaximalColumnCount(15),
586       mnPageCount(0),
587       mnColumnCount(1),
588       mnRowCount(0),
589       mnMaxColumnCount(0),
590       mnMaxRowCount(0),
591       maPageObjectSize(1,1),
592       mpPageObjectLayouter(),
593       mpTheme(rpTheme)
594 {
595 }
596 
597 
598 
599 
Implementation(const Implementation & rImplementation)600 Layouter::Implementation::Implementation (const Implementation& rImplementation)
601     : mpWindow(rImplementation.mpWindow),
602       mnRequestedLeftBorder(rImplementation.mnRequestedLeftBorder),
603       mnRequestedRightBorder(rImplementation.mnRequestedRightBorder),
604       mnRequestedTopBorder(rImplementation.mnRequestedTopBorder),
605       mnRequestedBottomBorder(rImplementation.mnRequestedBottomBorder),
606       mnLeftBorder(rImplementation.mnLeftBorder),
607       mnRightBorder(rImplementation.mnRightBorder),
608       mnTopBorder(rImplementation.mnTopBorder),
609       mnBottomBorder(rImplementation.mnBottomBorder),
610       mnVerticalGap(rImplementation.mnVerticalGap),
611       mnHorizontalGap(rImplementation.mnHorizontalGap),
612       maMinimalSize(rImplementation.maMinimalSize),
613       maPreferredSize(rImplementation.maPreferredSize),
614       maMaximalSize(rImplementation.maMaximalSize),
615       mnMinimalColumnCount(rImplementation.mnMinimalColumnCount),
616       mnMaximalColumnCount(rImplementation.mnMaximalColumnCount),
617       mnPageCount(rImplementation.mnPageCount),
618       mnColumnCount(rImplementation.mnColumnCount),
619       mnRowCount(rImplementation.mnRowCount),
620       mnMaxColumnCount(rImplementation.mnMaxColumnCount),
621       mnMaxRowCount(rImplementation.mnMaxRowCount),
622       maPageObjectSize(rImplementation.maPageObjectSize),
623       mpPageObjectLayouter(),
624       mpTheme(rImplementation.mpTheme)
625 {
626 }
627 
628 
629 
630 
~Implementation(void)631 Layouter::Implementation::~Implementation (void)
632 {
633 }
634 
635 
636 
637 
Rearrange(const Size & rWindowSize,const Size & rPreviewModelSize,const sal_uInt32 nPageCount)638 bool Layouter::Implementation::Rearrange  (
639     const Size& rWindowSize,
640     const Size& rPreviewModelSize,
641     const sal_uInt32 nPageCount)
642 {
643     mnPageCount = nPageCount;
644 
645     // Return early when the window or the model have not yet been initialized.
646     if (rWindowSize.Width()<=0 || rWindowSize.Height()<=0)
647         return false;
648     if (rPreviewModelSize.Width()<=0 || rPreviewModelSize.Height()<=0)
649         return false;
650 
651     CalculateRowAndColumnCount(rWindowSize);
652 
653     // Update the border values.
654     mnLeftBorder = mnRequestedLeftBorder;
655     mnTopBorder = mnRequestedTopBorder;
656     mnRightBorder = mnRequestedRightBorder;
657     mnBottomBorder = mnRequestedBottomBorder;
658     if (mnColumnCount > 1)
659     {
660         int nMinimumBorderWidth = mnHorizontalGap/2;
661         if (mnLeftBorder < nMinimumBorderWidth)
662             mnLeftBorder = nMinimumBorderWidth;
663         if (mnRightBorder < nMinimumBorderWidth)
664             mnRightBorder = nMinimumBorderWidth;
665     }
666     else
667     {
668         int nMinimumBorderHeight = mnVerticalGap/2;
669         if (mnTopBorder < nMinimumBorderHeight)
670             mnTopBorder = nMinimumBorderHeight;
671         if (mnBottomBorder < nMinimumBorderHeight)
672             mnBottomBorder = nMinimumBorderHeight;
673     }
674 
675     mpPageObjectLayouter.reset(
676         new PageObjectLayouter(
677             mpTheme,
678             CalculateTargetSize(rWindowSize, rPreviewModelSize),
679             rPreviewModelSize,
680             mpWindow,
681             mnPageCount));
682     maPageObjectSize = mpPageObjectLayouter->GetSize(
683         PageObjectLayouter::FocusIndicator,
684         PageObjectLayouter::WindowCoordinateSystem);
685 
686     CalculateMaxRowAndColumnCount(rWindowSize);
687 
688     return true;
689 }
690 
691 
692 
693 
GetRowAtPosition(sal_Int32 nYPosition,bool bIncludeBordersAndGaps,GapMembership eGapMembership) const694 sal_Int32 Layouter::Implementation::GetRowAtPosition (
695     sal_Int32 nYPosition,
696     bool bIncludeBordersAndGaps,
697     GapMembership eGapMembership) const
698 {
699     sal_Int32 nRow = -1;
700 
701     const sal_Int32 nY = nYPosition - mnTopBorder;
702     if (nY >= 0)
703     {
704         // Vertical distance from one row to the next.
705         const sal_Int32 nRowOffset (maPageObjectSize.Height() + mnVerticalGap);
706 
707         // Calculate row consisting of page objects and gap below.
708         nRow = nY / nRowOffset;
709 
710         const sal_Int32 nDistanceIntoGap ((nY - nRow*nRowOffset) - maPageObjectSize.Height());
711         // When inside the gap below then nYPosition is not over a page
712         // object.
713         if (nDistanceIntoGap > 0)
714             nRow = ResolvePositionInGap (
715                 nDistanceIntoGap,
716                 eGapMembership,
717                 nRow,
718                 mnVerticalGap);
719     }
720     else if (bIncludeBordersAndGaps)
721     {
722         // We are in the top border area.  Set nRow to the first row when
723         // the top border shall be considered to belong to the first row.
724         nRow = 0;
725     }
726 
727     return nRow;
728 }
729 
730 
731 
732 
GetColumnAtPosition(sal_Int32 nXPosition,bool bIncludeBordersAndGaps,GapMembership eGapMembership) const733 sal_Int32 Layouter::Implementation::GetColumnAtPosition (
734     sal_Int32 nXPosition,
735     bool bIncludeBordersAndGaps,
736     GapMembership eGapMembership) const
737 {
738     sal_Int32 nColumn = -1;
739 
740     sal_Int32 nX = nXPosition - mnLeftBorder;
741     if (nX >= 0)
742     {
743         // Horizontal distance from one column to the next.
744         const sal_Int32 nColumnOffset (maPageObjectSize.Width() + mnHorizontalGap);
745 
746         // Calculate row consisting of page objects and gap below.
747         nColumn = nX / nColumnOffset;
748         if (nColumn < 0)
749             nColumn = 0;
750         else if (nColumn >= mnColumnCount)
751             nColumn = mnColumnCount-1;
752 
753         const sal_Int32 nDistanceIntoGap ((nX - nColumn*nColumnOffset) - maPageObjectSize.Width());
754         // When inside the gap at the right then nXPosition is not over a
755         // page object.
756         if (nDistanceIntoGap > 0)
757             nColumn = ResolvePositionInGap (
758                 nDistanceIntoGap,
759                 eGapMembership,
760                 nColumn,
761                 mnHorizontalGap);
762     }
763     else if (bIncludeBordersAndGaps)
764     {
765         // We are in the left border area.  Set nColumn to the first column
766         // when the left border shall be considered to belong to the first
767         // column.
768         nColumn = 0;
769     }
770     return nColumn;
771 }
772 
773 
774 
775 
ResolvePositionInGap(sal_Int32 nDistanceIntoGap,GapMembership eGapMembership,sal_Int32 nIndex,sal_Int32 nGap) const776 sal_Int32 Layouter::Implementation::ResolvePositionInGap (
777     sal_Int32 nDistanceIntoGap,
778     GapMembership eGapMembership,
779     sal_Int32 nIndex,
780     sal_Int32 nGap) const
781 {
782     switch (eGapMembership)
783     {
784         case GM_NONE:
785             // The gap is no man's land.
786             nIndex = -1;
787             break;
788 
789         case GM_BOTH:
790         {
791             // The lower half of the gap belongs to the next row or column.
792             sal_Int32 nFirstHalfGapWidth = nGap / 2;
793             if (nDistanceIntoGap > nFirstHalfGapWidth)
794                 nIndex ++;
795             break;
796         }
797 
798         case GM_PREVIOUS:
799             // Row or column already at correct value.
800             break;
801 
802         case GM_NEXT:
803             // The complete gap belongs to the next row or column.
804             nIndex ++;
805             break;
806 
807         case GM_PAGE_BORDER:
808             if (nDistanceIntoGap > 0)
809             {
810                 if (nDistanceIntoGap > nGap)
811                 {
812                     // Inside the border of the next row or column.
813                     nIndex ++;
814                 }
815                 else
816                 {
817                     // Inside the gap between the page borders.
818                     nIndex = -1;
819                 }
820             }
821             break;
822 
823         default:
824             nIndex = -1;
825     }
826 
827     return nIndex;
828 }
829 
830 
831 
832 
CalculateGeometricPosition(InsertPosition & rPosition,const Size & rIndicatorSize,const bool bIsVertical,model::SlideSorterModel & rModel) const833 void Layouter::Implementation::CalculateGeometricPosition (
834     InsertPosition& rPosition,
835     const Size& rIndicatorSize,
836     const bool bIsVertical,
837     model::SlideSorterModel& rModel) const
838 {
839     // 1. Determine right/bottom of the leading page and the left/top of the
840     // trailing page object and how to distribute the missing space.
841     sal_Int32 nLeadingLocation (0);
842     sal_Int32 nTrailingLocation (0);
843     bool bIsLeadingFixed (false);
844     bool bIsTrailingFixed (false);
845     sal_Int32 nSecondaryLocation (0);
846     const sal_Int32 nIndex (rPosition.GetIndex());
847 
848     if (rPosition.IsAtRunStart())
849     {
850         // Place indicator at the top of the column.
851         const Rectangle aOuterBox (GetPageObjectBox(nIndex));
852         const Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex));
853         if (bIsVertical)
854         {
855             nLeadingLocation = aOuterBox.Top();
856             nTrailingLocation = aInnerBox.Top();
857             nSecondaryLocation = aInnerBox.Center().X();
858         }
859         else
860         {
861             nLeadingLocation = aOuterBox.Left();
862             nTrailingLocation = aInnerBox.Left();
863             nSecondaryLocation = aInnerBox.Center().Y();
864         }
865         bIsLeadingFixed = true;
866     }
867     else if (rPosition.IsAtRunEnd())
868     {
869         // Place indicator at the bottom/right of the column/row.
870 
871         const Rectangle aOuterBox (GetPageObjectBox(nIndex-1));
872         const Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex-1));
873         if (bIsVertical)
874         {
875             nLeadingLocation = aInnerBox.Bottom();
876             nTrailingLocation = aOuterBox.Bottom();
877             nSecondaryLocation = aInnerBox.Center().X();
878         }
879         else
880         {
881             nLeadingLocation = aInnerBox.Right();
882             nTrailingLocation = aOuterBox.Right();
883             nSecondaryLocation = aInnerBox.Center().Y();
884         }
885         bIsTrailingFixed = true;
886         if ( ! rPosition.IsExtraSpaceNeeded())
887             bIsLeadingFixed = true;
888     }
889     else
890     {
891         // Place indicator between two rows/columns.
892         const Rectangle aBox1 (GetInnerBoundingBox(rModel, nIndex-1));
893         const Rectangle aBox2 (GetInnerBoundingBox(rModel, nIndex));
894         if (bIsVertical)
895         {
896             nLeadingLocation = aBox1.Bottom();
897             nTrailingLocation = aBox2.Top();
898             nSecondaryLocation = (aBox1.Center().X() + aBox2.Center().X()) / 2;
899         }
900         else
901         {
902             nLeadingLocation = aBox1.Right();
903             nTrailingLocation = aBox2.Left();
904             nSecondaryLocation = (aBox1.Center().Y() + aBox2.Center().Y()) / 2;
905         }
906     }
907 
908     // 2. Calculate the location of the insert indicator and the offsets of
909     // leading and trailing pages.
910     const sal_Int32 nAvailableSpace (nTrailingLocation - nLeadingLocation);
911     const sal_Int32 nRequiredSpace (bIsVertical ? rIndicatorSize.Height():rIndicatorSize.Width());
912     const sal_Int32 nMissingSpace (::std::max(sal_Int32(0), nRequiredSpace - nAvailableSpace));
913     sal_Int32 nPrimaryLocation (0);
914     sal_Int32 nLeadingOffset (0);
915     sal_Int32 nTrailingOffset (0);
916     if (bIsLeadingFixed)
917     {
918         nPrimaryLocation = nLeadingLocation + nRequiredSpace/2;
919         if ( ! bIsTrailingFixed)
920             nTrailingOffset = nMissingSpace;
921     }
922     else if (bIsTrailingFixed)
923     {
924         nPrimaryLocation = nTrailingLocation - nRequiredSpace/2;
925         nLeadingOffset = -nMissingSpace;
926     }
927     else
928     {
929         nPrimaryLocation = (nLeadingLocation + nTrailingLocation) /2;
930         nLeadingOffset = -nMissingSpace/2;
931         nTrailingOffset = nMissingSpace + nLeadingOffset;
932     }
933 
934     if (bIsVertical)
935     {
936         rPosition.SetGeometricalPosition(
937             Point(nSecondaryLocation, nPrimaryLocation),
938             Point(0, nLeadingOffset),
939             Point(0, nTrailingOffset));
940     }
941     else
942     {
943         rPosition.SetGeometricalPosition(
944             Point(nPrimaryLocation, nSecondaryLocation),
945             Point(nLeadingOffset, 0),
946             Point(nTrailingOffset, 0));
947     }
948 }
949 
950 
951 
952 
GetInnerBoundingBox(model::SlideSorterModel & rModel,const sal_Int32 nIndex) const953 Rectangle Layouter::Implementation::GetInnerBoundingBox (
954     model::SlideSorterModel& rModel,
955     const sal_Int32 nIndex) const
956 {
957     model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
958     if ( ! pDescriptor)
959         return Rectangle();
960 
961     const Point aLocation (pDescriptor->GetLocation(true));
962     if (pDescriptor->HasState(model::PageDescriptor::ST_Selected))
963         return mpPageObjectLayouter->GetBoundingBox(
964             aLocation,
965             PageObjectLayouter::PageObject,
966             PageObjectLayouter::ModelCoordinateSystem);
967     else
968         return mpPageObjectLayouter->GetBoundingBox(
969             aLocation,
970             PageObjectLayouter::Preview,
971             PageObjectLayouter::ModelCoordinateSystem);
972 }
973 
974 
975 
976 
GetValidHorizontalSizeRange(void) const977 Range Layouter::Implementation::GetValidHorizontalSizeRange (void) const
978 {
979     return Range(
980         mnLeftBorder + maMinimalSize.Width() + mnRightBorder,
981         mnLeftBorder + maMaximalSize.Width() + mnRightBorder);
982 }
983 
984 
985 
986 
GetValidVerticalSizeRange(void) const987 Range Layouter::Implementation::GetValidVerticalSizeRange (void) const
988 {
989     return Range(
990         mnTopBorder + maMinimalSize.Height() + mnBottomBorder,
991         mnTopBorder + maMaximalSize.Height() + mnBottomBorder);
992 }
993 
994 
995 
996 
GetRangeOfVisiblePageObjects(const Rectangle & aVisibleArea) const997 Range Layouter::Implementation::GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const
998 {
999     const sal_Int32 nRow0 (GetRowAtPosition(aVisibleArea.Top(), true, GM_NEXT));
1000     const sal_Int32 nCol0 (GetColumnAtPosition(aVisibleArea.Left(),true, GM_NEXT));
1001     const sal_Int32 nRow1 (GetRowAtPosition(aVisibleArea.Bottom(), true, GM_PREVIOUS));
1002     const sal_Int32 nCol1 (GetColumnAtPosition(aVisibleArea.Right(), true, GM_PREVIOUS));
1003 
1004     // When start and end lie in different rows then the range may include
1005     // slides outside (left or right of) the given area.
1006     return Range(GetIndex(nRow0,nCol0,true), GetIndex(nRow1,nCol1,true));
1007 }
1008 
1009 
1010 
1011 
GetTargetSize(const Size & rWindowSize,const Size & rPreviewModelSize,const bool bCalculateWidth,const bool bCalculateHeight) const1012 Size Layouter::Implementation::GetTargetSize (
1013     const Size& rWindowSize,
1014     const Size& rPreviewModelSize,
1015     const bool bCalculateWidth,
1016     const bool bCalculateHeight) const
1017 {
1018     (void)rPreviewModelSize;
1019 
1020     if (mnColumnCount<=0 || mnRowCount<=0)
1021         return maPreferredSize;
1022     if ( ! (bCalculateWidth || bCalculateHeight))
1023     {
1024         OSL_ASSERT(bCalculateWidth || bCalculateHeight);
1025         return maPreferredSize;
1026     }
1027 
1028     // Calculate the width of each page object.
1029     Size aTargetSize (0,0);
1030     if (bCalculateWidth)
1031         aTargetSize.setWidth(
1032             (rWindowSize.Width() - mnLeftBorder - mnRightBorder
1033                 - (mnColumnCount-1) * mnHorizontalGap)
1034                     / mnColumnCount);
1035     else if (bCalculateHeight)
1036         aTargetSize.setHeight(
1037             (rWindowSize.Height() - mnTopBorder - mnBottomBorder
1038                 - (mnRowCount-1) * mnVerticalGap)
1039                     / mnRowCount);
1040 
1041     if (bCalculateWidth)
1042     {
1043         if (aTargetSize.Width() < maMinimalSize.Width())
1044             aTargetSize.setWidth(maMinimalSize.Width());
1045         else if (aTargetSize.Width() > maMaximalSize.Width())
1046             aTargetSize.setWidth(maMaximalSize.Width());
1047     }
1048     else if (bCalculateHeight)
1049     {
1050         if (aTargetSize.Height() < maMinimalSize.Height())
1051             aTargetSize.setHeight(maMinimalSize.Height());
1052         else if (aTargetSize.Height() > maMaximalSize.Height())
1053             aTargetSize.setHeight(maMaximalSize.Height());
1054     }
1055 
1056     return aTargetSize;
1057 }
1058 
1059 
1060 
1061 
GetIndex(const sal_Int32 nRow,const sal_Int32 nColumn,const bool bClampToValidRange) const1062 sal_Int32 Layouter::Implementation::GetIndex (
1063     const sal_Int32 nRow,
1064     const sal_Int32 nColumn,
1065     const bool bClampToValidRange) const
1066 {
1067     if (nRow >= 0 && nColumn >= 0)
1068     {
1069         const sal_Int32 nIndex (nRow * mnColumnCount + nColumn);
1070         if (nIndex >= mnPageCount)
1071             if (bClampToValidRange)
1072                 return mnPageCount-1;
1073             else
1074                 return -1;
1075         else
1076             return nIndex;
1077     }
1078     else if (bClampToValidRange)
1079         return 0;
1080     else
1081         return -1;
1082 }
1083 
1084 
1085 
1086 
GetPageObjectBox(const sal_Int32 nIndex,const bool bIncludeBorderAndGap) const1087 Rectangle Layouter::Implementation::GetPageObjectBox (
1088     const sal_Int32 nIndex,
1089     const bool bIncludeBorderAndGap) const
1090 {
1091     const sal_Int32 nRow (nIndex / mnColumnCount);
1092     const sal_Int32 nColumn (nIndex % mnColumnCount);
1093 
1094     const Rectangle aBoundingBox (GetPageObjectBox(nRow,nColumn));
1095     if (bIncludeBorderAndGap)
1096         return AddBorderAndGap(aBoundingBox, nRow, nColumn);
1097     else
1098         return aBoundingBox;
1099 }
1100 
1101 
1102 
1103 
GetPageObjectBox(const sal_Int32 nRow,const sal_Int32 nColumn) const1104 Rectangle Layouter::Implementation::GetPageObjectBox (
1105     const sal_Int32 nRow,
1106     const sal_Int32 nColumn) const
1107 {
1108     return Rectangle(
1109         Point (mnLeftBorder
1110             + nColumn * maPageObjectSize.Width()
1111             + (nColumn>0 ? nColumn : 0) * mnHorizontalGap,
1112             mnTopBorder
1113             + nRow * maPageObjectSize.Height()
1114             + (nRow>0 ? nRow : 0) * mnVerticalGap),
1115         maPageObjectSize);
1116 }
1117 
1118 
1119 
1120 
1121 
AddBorderAndGap(const Rectangle & rBoundingBox,const sal_Int32 nRow,const sal_Int32 nColumn) const1122 Rectangle Layouter::Implementation::AddBorderAndGap (
1123     const Rectangle& rBoundingBox,
1124     const sal_Int32 nRow,
1125     const sal_Int32 nColumn) const
1126 {
1127     Rectangle aBoundingBox (rBoundingBox);
1128 
1129     if (nColumn == 0)
1130         aBoundingBox.Left() = 0;
1131     else
1132         aBoundingBox.Left() -= mnHorizontalGap/2;
1133     if (nColumn == mnColumnCount-1)
1134         aBoundingBox.Right() += mnRightBorder;
1135     else
1136         aBoundingBox.Right() += mnHorizontalGap/2;
1137     if (nRow == 0)
1138         aBoundingBox.Top() = 0;
1139     else
1140         aBoundingBox.Top() -= mnVerticalGap/2;
1141     if (nRow == mnRowCount-1)
1142         aBoundingBox.Bottom() += mnBottomBorder;
1143     else
1144         aBoundingBox.Bottom() += mnVerticalGap/2;
1145     return aBoundingBox;
1146 }
1147 
1148 
1149 
1150 
GetTotalBoundingBox(void) const1151 Rectangle Layouter::Implementation::GetTotalBoundingBox (void) const
1152 {
1153     sal_Int32 nHorizontalSize = 0;
1154     sal_Int32 nVerticalSize = 0;
1155     if (mnColumnCount > 0)
1156     {
1157         sal_Int32 nRowCount = (mnPageCount+mnColumnCount-1) / mnColumnCount;
1158         nHorizontalSize =
1159             mnLeftBorder
1160             + mnRightBorder
1161             + mnColumnCount * maPageObjectSize.Width();
1162         if (mnColumnCount > 1)
1163             nHorizontalSize +=  (mnColumnCount-1) * mnHorizontalGap;
1164         nVerticalSize =
1165             mnTopBorder
1166             + mnBottomBorder
1167             + nRowCount * maPageObjectSize.Height();
1168         if (nRowCount > 1)
1169             nVerticalSize += (nRowCount-1) * mnVerticalGap;
1170     }
1171 
1172     return Rectangle (
1173         Point(0,0),
1174         Size (nHorizontalSize, nVerticalSize)
1175         );
1176 }
1177 
1178 
1179 
1180 
CalculateVerticalLogicalInsertPosition(const Point & rModelPosition,InsertPosition & rPosition) const1181 void Layouter::Implementation::CalculateVerticalLogicalInsertPosition (
1182     const Point& rModelPosition,
1183     InsertPosition& rPosition) const
1184 {
1185     const sal_Int32 nY = rModelPosition.Y() - mnTopBorder + maPageObjectSize.Height()/2;
1186     const sal_Int32 nRowHeight (maPageObjectSize.Height() + mnVerticalGap);
1187     const sal_Int32 nRow (::std::min(mnPageCount, nY / nRowHeight));
1188     rPosition.SetLogicalPosition (
1189         nRow,
1190         0,
1191         nRow,
1192         (nRow == 0),
1193         (nRow == mnRowCount),
1194         (nRow >= mnMaxRowCount));
1195 }
1196 
1197 
1198 
1199 
1200 //===== HorizontalImplementation ================================================
1201 
HorizontalImplementation(const SharedSdWindow & rpWindow,const::boost::shared_ptr<view::Theme> & rpTheme)1202 HorizontalImplementation::HorizontalImplementation (
1203     const SharedSdWindow& rpWindow,
1204     const ::boost::shared_ptr<view::Theme>& rpTheme)
1205     : Implementation(rpWindow, rpTheme)
1206 {
1207 }
1208 
1209 
1210 
1211 
HorizontalImplementation(const Implementation & rImplementation)1212 HorizontalImplementation::HorizontalImplementation (const Implementation& rImplementation)
1213     : Implementation(rImplementation)
1214 {
1215 }
1216 
1217 
1218 
1219 
GetOrientation(void) const1220 Layouter::Orientation HorizontalImplementation::GetOrientation (void) const
1221 {
1222     return Layouter::HORIZONTAL;
1223 }
1224 
1225 
1226 
1227 
CalculateRowAndColumnCount(const Size & rWindowSize)1228 void HorizontalImplementation::CalculateRowAndColumnCount (const Size& rWindowSize)
1229 {
1230     (void)rWindowSize;
1231 
1232     // Row and column count are fixed (for a given page count.)
1233     mnColumnCount = mnPageCount;
1234     mnRowCount = 1;
1235 }
1236 
1237 
1238 
1239 
CalculateMaxRowAndColumnCount(const Size & rWindowSize)1240 void HorizontalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize)
1241 {
1242     mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder)
1243         / (maPageObjectSize.Width()  + mnHorizontalGap);
1244     mnMaxRowCount = 1;
1245 }
1246 
1247 
1248 
1249 
CalculateTargetSize(const Size & rWindowSize,const Size & rPreviewModelSize) const1250 Size HorizontalImplementation::CalculateTargetSize (
1251     const Size& rWindowSize,
1252     const Size& rPreviewModelSize) const
1253 {
1254     return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, false, true);
1255 }
1256 
1257 
1258 
1259 
CalculateLogicalInsertPosition(const Point & rModelPosition,InsertPosition & rPosition) const1260 void HorizontalImplementation::CalculateLogicalInsertPosition (
1261     const Point& rModelPosition,
1262     InsertPosition& rPosition) const
1263 {
1264     const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2;
1265     const sal_Int32 nColumnWidth (maPageObjectSize.Width() + mnHorizontalGap);
1266     const sal_Int32 nColumn (::std::min(mnPageCount, nX / nColumnWidth));
1267     rPosition.SetLogicalPosition (
1268         0,
1269         nColumn,
1270         nColumn,
1271         (nColumn == 0),
1272         (nColumn == mnColumnCount),
1273         (nColumn >= mnMaxColumnCount));
1274 }
1275 
1276 
1277 
1278 
1279 //===== VerticalImplementation ================================================
1280 
VerticalImplementation(const SharedSdWindow & rpWindow,const::boost::shared_ptr<view::Theme> & rpTheme)1281 VerticalImplementation::VerticalImplementation (
1282     const SharedSdWindow& rpWindow,
1283     const ::boost::shared_ptr<view::Theme>& rpTheme)
1284     : Implementation(rpWindow, rpTheme)
1285 {
1286 }
1287 
1288 
1289 
1290 
VerticalImplementation(const Implementation & rImplementation)1291 VerticalImplementation::VerticalImplementation (const Implementation& rImplementation)
1292     : Implementation(rImplementation)
1293 {
1294 }
1295 
1296 
1297 
1298 
GetOrientation(void) const1299 Layouter::Orientation VerticalImplementation::GetOrientation (void) const
1300 {
1301     return Layouter::VERTICAL;
1302 }
1303 
1304 
1305 
1306 
CalculateRowAndColumnCount(const Size & rWindowSize)1307 void VerticalImplementation::CalculateRowAndColumnCount (const Size& rWindowSize)
1308 {
1309     (void)rWindowSize;
1310 
1311     // Row and column count are fixed (for a given page count.)
1312     mnRowCount = mnPageCount;
1313     mnColumnCount = 1;
1314 
1315 }
1316 
1317 
1318 
1319 
CalculateMaxRowAndColumnCount(const Size & rWindowSize)1320 void VerticalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize)
1321 {
1322     mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder)
1323         / (maPageObjectSize.Height()  + mnVerticalGap);
1324     mnMaxColumnCount = 1;
1325 }
1326 
1327 
1328 
1329 
CalculateTargetSize(const Size & rWindowSize,const Size & rPreviewModelSize) const1330 Size VerticalImplementation::CalculateTargetSize (
1331     const Size& rWindowSize,
1332     const Size& rPreviewModelSize) const
1333 {
1334     return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, true, false);
1335 }
1336 
1337 
1338 
1339 
CalculateLogicalInsertPosition(const Point & rModelPosition,InsertPosition & rPosition) const1340 void VerticalImplementation::CalculateLogicalInsertPosition (
1341     const Point& rModelPosition,
1342     InsertPosition& rPosition) const
1343 {
1344     return CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition);
1345 }
1346 
1347 
1348 
1349 
1350 //===== GridImplementation ================================================
1351 
GridImplementation(const SharedSdWindow & rpWindow,const::boost::shared_ptr<view::Theme> & rpTheme)1352 GridImplementation::GridImplementation (
1353     const SharedSdWindow& rpWindow,
1354     const ::boost::shared_ptr<view::Theme>& rpTheme)
1355     : Implementation(rpWindow, rpTheme)
1356 {
1357 }
1358 
1359 
1360 
1361 
GridImplementation(const Implementation & rImplementation)1362 GridImplementation::GridImplementation (const Implementation& rImplementation)
1363     : Implementation(rImplementation)
1364 {
1365 }
1366 
1367 
1368 
1369 
GetOrientation(void) const1370 Layouter::Orientation GridImplementation::GetOrientation (void) const
1371 {
1372     return Layouter::GRID;
1373 }
1374 
1375 
1376 
1377 
CalculateRowAndColumnCount(const Size & rWindowSize)1378 void GridImplementation::CalculateRowAndColumnCount (const Size& rWindowSize)
1379 {
1380     // Calculate the column count.
1381     mnColumnCount
1382         = (rWindowSize.Width() - mnRequestedLeftBorder - mnRequestedRightBorder)
1383         / (maPreferredSize.Width()  + mnHorizontalGap);
1384     if (mnColumnCount < mnMinimalColumnCount)
1385         mnColumnCount = mnMinimalColumnCount;
1386     if (mnColumnCount > mnMaximalColumnCount)
1387         mnColumnCount = mnMaximalColumnCount;
1388     mnRowCount = (mnPageCount + mnColumnCount-1)/mnColumnCount;
1389 }
1390 
1391 
1392 
1393 
CalculateMaxRowAndColumnCount(const Size & rWindowSize)1394 void GridImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize)
1395 {
1396     mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder)
1397         / (maPageObjectSize.Width()  + mnHorizontalGap);
1398     mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder)
1399         / (maPageObjectSize.Height()  + mnVerticalGap);
1400 }
1401 
1402 
1403 
1404 
1405 
CalculateTargetSize(const Size & rWindowSize,const Size & rPreviewModelSize) const1406 Size GridImplementation::CalculateTargetSize (
1407     const Size& rWindowSize,
1408     const Size& rPreviewModelSize) const
1409 {
1410     return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, true, true);
1411 }
1412 
1413 
1414 
1415 
CalculateLogicalInsertPosition(const Point & rModelPosition,InsertPosition & rPosition) const1416 void GridImplementation::CalculateLogicalInsertPosition (
1417     const Point& rModelPosition,
1418     InsertPosition& rPosition) const
1419 {
1420     if (mnColumnCount == 1)
1421     {
1422         CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition);
1423     }
1424     else
1425     {
1426         // Handle the general case of more than one column.
1427         sal_Int32 nRow (::std::min(
1428             mnRowCount-1,
1429             GetRowAtPosition (rModelPosition.Y(), true, GM_BOTH)));
1430         const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2;
1431         const sal_Int32 nColumnWidth (maPageObjectSize.Width() + mnHorizontalGap);
1432         sal_Int32 nColumn (::std::min(mnColumnCount, nX / nColumnWidth));
1433         sal_Int32 nIndex (nRow * mnColumnCount + nColumn);
1434         bool bIsAtRunEnd (nColumn == mnColumnCount);
1435 
1436         if (nIndex >= mnPageCount)
1437         {
1438             nIndex = mnPageCount;
1439             nRow = mnRowCount-1;
1440             nColumn = ::std::min(::std::min(mnPageCount, mnColumnCount), nColumn);
1441             bIsAtRunEnd = true;
1442         }
1443 
1444         rPosition.SetLogicalPosition (
1445             nRow,
1446             nColumn,
1447             nIndex,
1448             (nColumn == 0),
1449             bIsAtRunEnd,
1450             (nColumn >= mnMaxColumnCount));
1451     }
1452 }
1453 
1454 
1455 
1456 
1457 //===== InsertPosition ========================================================
1458 
InsertPosition(void)1459 InsertPosition::InsertPosition (void)
1460     : mnRow(-1),
1461       mnColumn(-1),
1462       mnIndex(-1),
1463       mbIsAtRunStart(false),
1464       mbIsAtRunEnd(false),
1465       mbIsExtraSpaceNeeded(false),
1466       maLocation(0,0),
1467       maLeadingOffset(0,0),
1468       maTrailingOffset(0,0)
1469 {
1470 }
1471 
1472 
1473 
1474 
operator =(const InsertPosition & rInsertPosition)1475 InsertPosition& InsertPosition::operator= (const InsertPosition& rInsertPosition)
1476 {
1477     if (this != &rInsertPosition)
1478     {
1479         mnRow = rInsertPosition.mnRow;
1480         mnColumn = rInsertPosition.mnColumn;
1481         mnIndex = rInsertPosition.mnIndex;
1482         mbIsAtRunStart = rInsertPosition.mbIsAtRunStart;
1483         mbIsAtRunEnd = rInsertPosition.mbIsAtRunEnd;
1484         mbIsExtraSpaceNeeded = rInsertPosition.mbIsExtraSpaceNeeded;
1485         maLocation = rInsertPosition.maLocation;
1486         maLeadingOffset = rInsertPosition.maLeadingOffset;
1487         maTrailingOffset = rInsertPosition.maTrailingOffset;
1488     }
1489     return *this;
1490 }
1491 
1492 
1493 
1494 
operator ==(const InsertPosition & rInsertPosition) const1495 bool InsertPosition::operator== (const InsertPosition& rInsertPosition) const
1496 {
1497     // Do not compare the geometrical information (maLocation).
1498     return mnRow==rInsertPosition.mnRow
1499         && mnColumn==rInsertPosition.mnColumn
1500         && mnIndex==rInsertPosition.mnIndex
1501         && mbIsAtRunStart==rInsertPosition.mbIsAtRunStart
1502         && mbIsAtRunEnd==rInsertPosition.mbIsAtRunEnd
1503         && mbIsExtraSpaceNeeded==rInsertPosition.mbIsExtraSpaceNeeded;
1504 }
1505 
1506 
1507 
1508 
operator !=(const InsertPosition & rInsertPosition) const1509 bool InsertPosition::operator!= (const InsertPosition& rInsertPosition) const
1510 {
1511     return !operator==(rInsertPosition);
1512 }
1513 
1514 
1515 
1516 
SetLogicalPosition(const sal_Int32 nRow,const sal_Int32 nColumn,const sal_Int32 nIndex,const bool bIsAtRunStart,const bool bIsAtRunEnd,const bool bIsExtraSpaceNeeded)1517 void InsertPosition::SetLogicalPosition (
1518     const sal_Int32 nRow,
1519     const sal_Int32 nColumn,
1520     const sal_Int32 nIndex,
1521     const bool bIsAtRunStart,
1522     const bool bIsAtRunEnd,
1523     const bool bIsExtraSpaceNeeded)
1524 {
1525     mnRow = nRow;
1526     mnColumn = nColumn;
1527     mnIndex = nIndex;
1528     mbIsAtRunStart = bIsAtRunStart;
1529     mbIsAtRunEnd = bIsAtRunEnd;
1530     mbIsExtraSpaceNeeded = bIsExtraSpaceNeeded;
1531 }
1532 
1533 
1534 
1535 
SetGeometricalPosition(const Point aLocation,const Point aLeadingOffset,const Point aTrailingOffset)1536 void InsertPosition::SetGeometricalPosition(
1537     const Point aLocation,
1538     const Point aLeadingOffset,
1539     const Point aTrailingOffset)
1540 {
1541     maLocation = aLocation;
1542     maLeadingOffset = aLeadingOffset;
1543     maTrailingOffset = aTrailingOffset;
1544 }
1545 
1546 
1547 
1548 } } } // end of namespace ::sd::slidesorter::namespace
1549