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 vertical 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 coordinates 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 which 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