LibreOffice Module sd (master) 1
SlsLayouter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <utility>
22#include <view/SlsTheme.hxx>
23#include <view/SlsLayouter.hxx>
26#include <Window.hxx>
27#include <osl/diagnose.h>
28
29namespace sd::slidesorter::view {
30
32{
33public:
35 static const sal_Int32 mnRequestedLeftBorder = 5;
36 static const sal_Int32 mnRequestedRightBorder = 5;
37 static const sal_Int32 mnRequestedTopBorder = 5;
38 static const sal_Int32 mnRequestedBottomBorder = 5;
39 sal_Int32 mnLeftBorder;
40 sal_Int32 mnRightBorder;
41 sal_Int32 mnTopBorder;
42 sal_Int32 mnBottomBorder;
43 static const sal_Int32 gnVerticalGap = 10 - 2*Theme_FocusIndicatorWidth;
44 static const sal_Int32 gnHorizontalGap = 10 - 2*Theme_FocusIndicatorWidth;
50 sal_Int32 mnPageCount;
51 sal_Int32 mnColumnCount;
52 sal_Int32 mnRowCount;
60 sal_Int32 mnMaxRowCount;
62 std::shared_ptr<PageObjectLayouter> mpPageObjectLayouter;
63 std::shared_ptr<view::Theme> mpTheme;
64
69 GM_NONE, // Gap is not associated with any page object.
70 GM_PREVIOUS, // The whole gap is associated with the previous page
71 // object (left or above the gap.)
72 GM_BOTH, // Half of the gap is associated with previous, half
73 // with the next page object.
74 GM_NEXT, // The whole gap is associated with the next page
75 // object (right or below the gap.)
77 };
78
79 static Implementation* Create (
80 const Implementation& rImplementation,
81 const Layouter::Orientation eOrientation);
82
84
85 bool Rearrange (
86 const Size& rWindowSize,
87 const Size& rPreviewModelSize,
88 const sal_uInt32 nPageCount);
89
105 sal_Int32 GetRowAtPosition (
106 sal_Int32 nYPosition,
107 bool bIncludeBordersAndGaps,
108 GapMembership eGapMembership) const;
109
120 sal_Int32 GetColumnAtPosition (
121 sal_Int32 nXPosition,
122 bool bIncludeBordersAndGaps,
123 GapMembership eGapMembership) const;
124
146 static sal_Int32 ResolvePositionInGap (
147 sal_Int32 nDistanceIntoGap,
148 GapMembership eGapMembership,
149 sal_Int32 nIndex,
150 sal_Int32 nGap);
151
156 const Point& rModelPosition,
157 InsertPosition& rPosition) const = 0;
158
165 InsertPosition& rPosition,
166 const Size& rIndicatorSize,
167 const bool bIsVertical,
168 model::SlideSorterModel const & rModel) const;
169
174 model::SlideSorterModel const & rModel,
175 const sal_Int32 nIndex) const;
176
179
180 Range GetRangeOfVisiblePageObjects (const ::tools::Rectangle& aVisibleArea) const;
181 sal_Int32 GetIndex (
182 const sal_Int32 nRow,
183 const sal_Int32 nColumn,
184 const bool bClampToValidRange) const;
185
187 const sal_Int32 nIndex,
188 const bool bIncludeBorderAndGap = false) const;
189
191 const sal_Int32 nRow,
192 const sal_Int32 nColumn) const;
193
195 const ::tools::Rectangle& rBoundingBox,
196 const sal_Int32 nRow,
197 const sal_Int32 nColumn) const;
198
200
201 virtual ~Implementation();
202
203protected:
205 sd::Window *pWindow,
206 std::shared_ptr<view::Theme> pTheme);
207 explicit Implementation (const Implementation& rImplementation);
208
209 virtual void CalculateRowAndColumnCount (const Size& rWindowSize) = 0;
210 virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) = 0;
212 const Size& rWindowSize) const = 0;
214 const Size& rWindowSize,
215 const bool bCalculateWidth,
216 const bool bCalculateHeight) const;
218 const Point& rModelPosition,
219 InsertPosition& rPosition) const;
220};
221
222namespace {
223
227class VerticalImplementation : public Layouter::Implementation
228{
229public:
230 explicit VerticalImplementation (const Implementation& rImplementation);
231
232 virtual Layouter::Orientation GetOrientation() const override;
233
234 void CalculateLogicalInsertPosition (
235 const Point& rModelPosition,
236 InsertPosition& rPosition) const override;
237
238protected:
239 virtual void CalculateRowAndColumnCount (const Size& rWindowSize) override;
240 virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) override;
241 virtual Size CalculateTargetSize (
242 const Size& rWindowSize) const override;
243};
244
248class HorizontalImplementation : public Layouter::Implementation
249{
250public:
251 explicit HorizontalImplementation(const Implementation& rImplementation);
252
253 virtual Layouter::Orientation GetOrientation() const override;
254
255 void CalculateLogicalInsertPosition (
256 const Point& rModelPosition,
257 InsertPosition& rPosition) const override;
258
259protected:
260 virtual void CalculateRowAndColumnCount (const Size& rWindowSize) override;
261 virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) override;
262 virtual Size CalculateTargetSize (
263 const Size& rWindowSize) const override;
264};
265
270class GridImplementation : public Layouter::Implementation
271{
272public:
273 GridImplementation (
274 sd::Window *pWindow,
275 const std::shared_ptr<view::Theme>& rpTheme);
276 explicit GridImplementation(const Implementation& rImplementation);
277
278 virtual Layouter::Orientation GetOrientation() const override;
279
280 void CalculateLogicalInsertPosition (
281 const Point& rModelPosition,
282 InsertPosition& rPosition) const override;
283
284protected:
285 virtual void CalculateRowAndColumnCount (const Size& rWindowSize) override;
286 virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) override;
287 virtual Size CalculateTargetSize (
288 const Size& rWindowSize) const override;
289};
290
291}
292
293//===== Layouter ==============================================================
294
296 sd::Window *pWindow,
297 const std::shared_ptr<Theme>& rpTheme)
298 : mpImplementation(new GridImplementation(pWindow, rpTheme)),
299 mpWindow(pWindow)
300{
301}
302
304{
305}
306
307std::shared_ptr<PageObjectLayouter> const & Layouter::GetPageObjectLayouter() const
308{
309 return mpImplementation->mpPageObjectLayouter;
310}
311
313 sal_Int32 nMinimalColumnCount,
314 sal_Int32 nMaximalColumnCount)
315{
316 if (nMinimalColumnCount <= nMaximalColumnCount)
317 {
318 mpImplementation->mnMinimalColumnCount = nMinimalColumnCount;
319 mpImplementation->mnMaximalColumnCount = nMaximalColumnCount;
320 }
321}
322
324 const Orientation eOrientation,
325 const Size& rWindowSize,
326 const Size& rPageSize,
327 const sal_uInt32 nPageCount)
328{
329 OSL_ASSERT(mpWindow);
330
331 if (eOrientation != mpImplementation->GetOrientation())
333
334 return mpImplementation->Rearrange(rWindowSize, rPageSize, nPageCount);
335}
336
338{
339 return mpImplementation->mnColumnCount;
340}
341
342sal_Int32 Layouter::GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const
343{
344 return mpImplementation->GetIndex(nRow,nColumn,true);
345}
346
348{
349 return mpImplementation->maPageObjectSize;
350}
351
353 const sal_Int32 nIndex,
354 const bool bIncludeBorderAndGap) const
355{
356 return mpImplementation->GetPageObjectBox(nIndex, bIncludeBorderAndGap);
357}
358
360{
361 return mpImplementation->GetTotalBoundingBox();
362}
363
365 const Point& rModelPosition,
366 const Size& rIndicatorSize,
367 model::SlideSorterModel const & rModel) const
368{
369 InsertPosition aPosition;
370 mpImplementation->CalculateLogicalInsertPosition(
371 rModelPosition,
372 aPosition);
373 mpImplementation->CalculateGeometricPosition(
374 aPosition,
375 rIndicatorSize,
376 GetColumnCount()==1,
377 rModel);
378 return aPosition;
379}
380
382{
383 return mpImplementation->GetValidHorizontalSizeRange();
384}
385
387{
388 return mpImplementation->GetValidVerticalSizeRange();
389}
390
391Range Layouter::GetRangeOfVisiblePageObjects (const ::tools::Rectangle& aVisibleArea) const
392{
393 return mpImplementation->GetRangeOfVisiblePageObjects(aVisibleArea);
394}
395
397 const Point& rPosition,
398 const bool bIncludePageBorders,
399 const bool bClampToValidRange) const
400{
401 const sal_Int32 nRow (
402 mpImplementation->GetRowAtPosition (
403 rPosition.Y(),
404 bIncludePageBorders,
406 const sal_Int32 nColumn (
407 mpImplementation->GetColumnAtPosition (
408 rPosition.X(),
409 bIncludePageBorders,
411
412 return mpImplementation->GetIndex(nRow,nColumn,bClampToValidRange);
413}
414
415//===== Layouter::Implementation ==============================================
416
418 const Implementation& rImplementation,
419 const Layouter::Orientation eOrientation)
420{
421 switch (eOrientation)
422 {
423 case HORIZONTAL: return new HorizontalImplementation(rImplementation);
424 case VERTICAL: return new VerticalImplementation(rImplementation);
425 case GRID:
426 default: return new GridImplementation(rImplementation);
427 }
428}
429
431 sd::Window *pWindow,
432 std::shared_ptr<view::Theme> pTheme)
433 : mpWindow(pWindow),
434 mnLeftBorder(5),
435 mnRightBorder(5),
436 mnTopBorder(5),
437 mnBottomBorder(5),
438 maMinimalSize(132,98),
439 maPreferredSize(200,150),
440 maMaximalSize(600,400),
441 mnMinimalColumnCount(1),
442 mnMaximalColumnCount(15),
443 mnPageCount(0),
444 mnColumnCount(1),
445 mnRowCount(0),
446 mnMaxColumnCount(0),
447 mnMaxRowCount(0),
448 maPageObjectSize(1,1),
449 mpTheme(std::move(pTheme))
450{
451}
452
454 : mpWindow(rImplementation.mpWindow),
455 mnLeftBorder(rImplementation.mnLeftBorder),
456 mnRightBorder(rImplementation.mnRightBorder),
457 mnTopBorder(rImplementation.mnTopBorder),
458 mnBottomBorder(rImplementation.mnBottomBorder),
459 maMinimalSize(rImplementation.maMinimalSize),
460 maPreferredSize(rImplementation.maPreferredSize),
461 maMaximalSize(rImplementation.maMaximalSize),
462 mnMinimalColumnCount(rImplementation.mnMinimalColumnCount),
463 mnMaximalColumnCount(rImplementation.mnMaximalColumnCount),
464 mnPageCount(rImplementation.mnPageCount),
465 mnColumnCount(rImplementation.mnColumnCount),
466 mnRowCount(rImplementation.mnRowCount),
467 mnMaxColumnCount(rImplementation.mnMaxColumnCount),
468 mnMaxRowCount(rImplementation.mnMaxRowCount),
469 maPageObjectSize(rImplementation.maPageObjectSize),
470 mpTheme(rImplementation.mpTheme)
471{
472}
473
475{
476}
477
479 const Size& rWindowSize,
480 const Size& rPreviewModelSize,
481 const sal_uInt32 nPageCount)
482{
483 mnPageCount = nPageCount;
484
485 // Return early when the window or the model have not yet been initialized.
486 if (rWindowSize.IsEmpty())
487 return false;
488 if (rPreviewModelSize.IsEmpty())
489 return false;
490
491 CalculateRowAndColumnCount(rWindowSize);
492
493 // Update the border values.
494 mnLeftBorder = mnRequestedLeftBorder;
495 mnTopBorder = mnRequestedTopBorder;
496 mnRightBorder = mnRequestedRightBorder;
497 mnBottomBorder = mnRequestedBottomBorder;
498 if (mnColumnCount > 1)
499 {
500 int nMinimumBorderWidth = gnHorizontalGap/2;
501 if (mnLeftBorder < nMinimumBorderWidth)
502 mnLeftBorder = nMinimumBorderWidth;
503 if (mnRightBorder < nMinimumBorderWidth)
504 mnRightBorder = nMinimumBorderWidth;
505 }
506 else
507 {
508 int nMinimumBorderHeight = gnVerticalGap/2;
509 if (mnTopBorder < nMinimumBorderHeight)
510 mnTopBorder = nMinimumBorderHeight;
511 if (mnBottomBorder < nMinimumBorderHeight)
512 mnBottomBorder = nMinimumBorderHeight;
513 }
514
515 mpPageObjectLayouter =
516 std::make_shared<PageObjectLayouter>(
517 CalculateTargetSize(rWindowSize),
518 rPreviewModelSize,
519 mpWindow,
520 mnPageCount);
521
522 maPageObjectSize = mpPageObjectLayouter->GetGridMaxSize();
523
524 CalculateMaxRowAndColumnCount(rWindowSize);
525
526 return true;
527}
528
530 sal_Int32 nYPosition,
531 bool bIncludeBordersAndGaps,
532 GapMembership eGapMembership) const
533{
534 sal_Int32 nRow = -1;
535
536 const sal_Int32 nY = nYPosition - mnTopBorder;
537 if (nY >= 0)
538 {
539 // Vertical distance from one row to the next.
540 const sal_Int32 nRowOffset (maPageObjectSize.Height() + gnVerticalGap);
541
542 // Calculate row consisting of page objects and gap below.
543 nRow = nY / nRowOffset;
544
545 const sal_Int32 nDistanceIntoGap ((nY - nRow*nRowOffset) - maPageObjectSize.Height());
546 // When inside the gap below then nYPosition is not over a page
547 // object.
548 if (nDistanceIntoGap > 0)
549 {
550 sal_Int32 nResolvedRow = ResolvePositionInGap(
551 nDistanceIntoGap,
552 eGapMembership,
553 nRow,
554 gnVerticalGap);
555 if (!bIncludeBordersAndGaps || nResolvedRow != -1)
556 nRow = nResolvedRow;
557 }
558 }
559 else if (bIncludeBordersAndGaps)
560 {
561 // We are in the top border area. Set nRow to the first row when
562 // the top border shall be considered to belong to the first row.
563 nRow = 0;
564 }
565
566 return nRow;
567}
568
570 sal_Int32 nXPosition,
571 bool bIncludeBordersAndGaps,
572 GapMembership eGapMembership) const
573{
574 sal_Int32 nColumn = -1;
575
576 sal_Int32 nX = nXPosition - mnLeftBorder;
577 if (nX >= 0)
578 {
579 // Horizontal distance from one column to the next.
580 const sal_Int32 nColumnOffset (maPageObjectSize.Width() + gnHorizontalGap);
581
582 // Calculate row consisting of page objects and gap below.
583 nColumn = nX / nColumnOffset;
584 if (nColumn < 0)
585 nColumn = 0;
586 else if (nColumn >= mnColumnCount)
587 nColumn = mnColumnCount-1;
588
589 const sal_Int32 nDistanceIntoGap ((nX - nColumn*nColumnOffset) - maPageObjectSize.Width());
590 // When inside the gap at the right then nXPosition is not over a
591 // page object.
592 if (nDistanceIntoGap > 0)
593 {
594 sal_Int32 nResolvedColumn = ResolvePositionInGap(
595 nDistanceIntoGap,
596 eGapMembership,
597 nColumn,
598 gnHorizontalGap);
599 if (!bIncludeBordersAndGaps || nResolvedColumn != -1)
600 nColumn = nResolvedColumn;
601 }
602 }
603 else if (bIncludeBordersAndGaps)
604 {
605 // We are in the left border area. Set nColumn to the first column
606 // when the left border shall be considered to belong to the first
607 // column.
608 nColumn = 0;
609 }
610 return nColumn;
611}
612
614 sal_Int32 nDistanceIntoGap,
615 GapMembership eGapMembership,
616 sal_Int32 nIndex,
617 sal_Int32 nGap)
618{
619 switch (eGapMembership)
620 {
621 case GM_NONE:
622 // The gap is no man's land.
623 nIndex = -1;
624 break;
625
626 case GM_BOTH:
627 {
628 // The lower half of the gap belongs to the next row or column.
629 sal_Int32 nFirstHalfGapWidth = nGap / 2;
630 if (nDistanceIntoGap > nFirstHalfGapWidth)
631 nIndex ++;
632 break;
633 }
634
635 case GM_PREVIOUS:
636 // Row or column already at correct value.
637 break;
638
639 case GM_NEXT:
640 // The complete gap belongs to the next row or column.
641 nIndex ++;
642 break;
643
644 case GM_PAGE_BORDER:
645 if (nDistanceIntoGap > 0)
646 {
647 if (nDistanceIntoGap > nGap)
648 {
649 // Inside the border of the next row or column.
650 nIndex ++;
651 }
652 else
653 {
654 // Inside the gap between the page borders.
655 nIndex = -1;
656 }
657 }
658 break;
659
660 default:
661 nIndex = -1;
662 }
663
664 return nIndex;
665}
666
668 InsertPosition& rPosition,
669 const Size& rIndicatorSize,
670 const bool bIsVertical,
671 model::SlideSorterModel const & rModel) const
672{
673 // 1. Determine right/bottom of the leading page and the left/top of the
674 // trailing page object and how to distribute the missing space.
675 sal_Int32 nLeadingLocation (0);
676 sal_Int32 nTrailingLocation (0);
677 bool bIsLeadingFixed (false);
678 bool bIsTrailingFixed (false);
679 sal_Int32 nSecondaryLocation (0);
680 const sal_Int32 nIndex (rPosition.GetIndex());
681
682 if (rPosition.IsAtRunStart())
683 {
684 // Place indicator at the top of the column.
685 const ::tools::Rectangle aOuterBox (GetPageObjectBox(nIndex));
686 const ::tools::Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex));
687 if (bIsVertical)
688 {
689 nLeadingLocation = aOuterBox.Top();
690 nTrailingLocation = aInnerBox.Top();
691 nSecondaryLocation = aInnerBox.Center().X();
692 }
693 else
694 {
695 nLeadingLocation = aOuterBox.Left();
696 nTrailingLocation = aInnerBox.Left();
697 nSecondaryLocation = aInnerBox.Center().Y();
698 }
699 bIsLeadingFixed = true;
700 }
701 else if (rPosition.IsAtRunEnd())
702 {
703 // Place indicator at the bottom/right of the column/row.
704
705 const ::tools::Rectangle aOuterBox (GetPageObjectBox(nIndex-1));
706 const ::tools::Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex-1));
707 if (bIsVertical)
708 {
709 nLeadingLocation = aInnerBox.Bottom();
710 nTrailingLocation = aOuterBox.Bottom();
711 nSecondaryLocation = aInnerBox.Center().X();
712 }
713 else
714 {
715 nLeadingLocation = aInnerBox.Right();
716 nTrailingLocation = aOuterBox.Right();
717 nSecondaryLocation = aInnerBox.Center().Y();
718 }
719 bIsTrailingFixed = true;
720 if ( ! rPosition.IsExtraSpaceNeeded())
721 bIsLeadingFixed = true;
722 }
723 else
724 {
725 // Place indicator between two rows/columns.
726 const ::tools::Rectangle aBox1 (GetInnerBoundingBox(rModel, nIndex-1));
727 const ::tools::Rectangle aBox2 (GetInnerBoundingBox(rModel, nIndex));
728 if (bIsVertical)
729 {
730 nLeadingLocation = aBox1.Bottom();
731 nTrailingLocation = aBox2.Top();
732 nSecondaryLocation = (aBox1.Center().X() + aBox2.Center().X()) / 2;
733 }
734 else
735 {
736 nLeadingLocation = aBox1.Right();
737 nTrailingLocation = aBox2.Left();
738 nSecondaryLocation = (aBox1.Center().Y() + aBox2.Center().Y()) / 2;
739 }
740 }
741
742 // 2. Calculate the location of the insert indicator and the offsets of
743 // leading and trailing pages.
744 const sal_Int32 nAvailableSpace (nTrailingLocation - nLeadingLocation);
745 const sal_Int32 nRequiredSpace (bIsVertical ? rIndicatorSize.Height():rIndicatorSize.Width());
746 const sal_Int32 nMissingSpace (::std::max(sal_Int32(0), nRequiredSpace - nAvailableSpace));
747 sal_Int32 nPrimaryLocation (0);
748 sal_Int32 nLeadingOffset (0);
749 sal_Int32 nTrailingOffset (0);
750 if (bIsLeadingFixed)
751 {
752 nPrimaryLocation = nLeadingLocation + nRequiredSpace/2;
753 if ( ! bIsTrailingFixed)
754 nTrailingOffset = nMissingSpace;
755 }
756 else if (bIsTrailingFixed)
757 {
758 nPrimaryLocation = nTrailingLocation - nRequiredSpace/2;
759 nLeadingOffset = -nMissingSpace;
760 }
761 else
762 {
763 nPrimaryLocation = (nLeadingLocation + nTrailingLocation) /2;
764 nLeadingOffset = -nMissingSpace/2;
765 nTrailingOffset = nMissingSpace + nLeadingOffset;
766 }
767
768 if (bIsVertical)
769 {
770 rPosition.SetGeometricalPosition(
771 Point(nSecondaryLocation, nPrimaryLocation),
772 Point(0, nLeadingOffset),
773 Point(0, nTrailingOffset));
774 }
775 else
776 {
777 rPosition.SetGeometricalPosition(
778 Point(nPrimaryLocation, nSecondaryLocation),
779 Point(nLeadingOffset, 0),
780 Point(nTrailingOffset, 0));
781 }
782}
783
785 model::SlideSorterModel const & rModel,
786 const sal_Int32 nIndex) const
787{
789 if ( ! pDescriptor)
790 return ::tools::Rectangle();
791
793
794 if (pDescriptor->HasState(model::PageDescriptor::ST_Selected))
796
797 return mpPageObjectLayouter->GetBoundingBox(
798 pDescriptor, ePart,
800}
801
803{
804 return Range(
805 mnLeftBorder + maMinimalSize.Width() + mnRightBorder,
806 mnLeftBorder + maMaximalSize.Width() + mnRightBorder);
807}
808
810{
811 return Range(
812 mnTopBorder + maMinimalSize.Height() + mnBottomBorder,
813 mnTopBorder + maMaximalSize.Height() + mnBottomBorder);
814}
815
816Range Layouter::Implementation::GetRangeOfVisiblePageObjects (const ::tools::Rectangle& aVisibleArea) const
817{
818 // technically that's not empty, but it's the default, so...
819 if (aVisibleArea.IsEmpty())
820 return Range(-1, -1);
821
822 const sal_Int32 nRow0 (GetRowAtPosition(aVisibleArea.Top(), true, GM_NEXT));
823 const sal_Int32 nCol0 (GetColumnAtPosition(aVisibleArea.Left(),true, GM_NEXT));
824 const sal_Int32 nRow1 (GetRowAtPosition(aVisibleArea.Bottom(), true, GM_PREVIOUS));
825 const sal_Int32 nCol1 (GetColumnAtPosition(aVisibleArea.Right(), true, GM_PREVIOUS));
826
827 // When start and end lie in different rows then the range may include
828 // slides outside (left or right of) the given area.
829 return Range(GetIndex(nRow0,nCol0,true), GetIndex(nRow1,nCol1,true));
830}
831
833 const Size& rWindowSize,
834 const bool bCalculateWidth,
835 const bool bCalculateHeight) const
836{
837 if (mnColumnCount<=0 || mnRowCount<=0)
838 return maPreferredSize;
839 if ( ! (bCalculateWidth || bCalculateHeight))
840 {
841 OSL_ASSERT(bCalculateWidth || bCalculateHeight);
842 return maPreferredSize;
843 }
844
845 // Calculate the width of each page object.
846 Size aTargetSize (0,0);
847 if (bCalculateWidth)
848 aTargetSize.setWidth(
849 (rWindowSize.Width() - mnLeftBorder - mnRightBorder
850 - (mnColumnCount-1) * gnHorizontalGap)
851 / mnColumnCount);
852 else if (bCalculateHeight)
853 aTargetSize.setHeight(
854 (rWindowSize.Height() - mnTopBorder - mnBottomBorder
855 - (mnRowCount-1) * gnVerticalGap)
856 / mnRowCount);
857
858 if (bCalculateWidth)
859 {
860 if (aTargetSize.Width() < maMinimalSize.Width())
861 aTargetSize.setWidth(maMinimalSize.Width());
862 else if (aTargetSize.Width() > maMaximalSize.Width())
863 aTargetSize.setWidth(maMaximalSize.Width());
864 }
865 else if (bCalculateHeight)
866 {
867 if (aTargetSize.Height() < maMinimalSize.Height())
868 aTargetSize.setHeight(maMinimalSize.Height());
869 else if (aTargetSize.Height() > maMaximalSize.Height())
870 aTargetSize.setHeight(maMaximalSize.Height());
871 }
872
873 return aTargetSize;
874}
875
877 const sal_Int32 nRow,
878 const sal_Int32 nColumn,
879 const bool bClampToValidRange) const
880{
881 if (nRow >= 0 && nColumn >= 0)
882 {
883 const sal_Int32 nIndex (nRow * mnColumnCount + nColumn);
884 if (nIndex >= mnPageCount)
885 if (bClampToValidRange)
886 return mnPageCount-1;
887 else
888 return -1;
889 else
890 return nIndex;
891 }
892 else if (bClampToValidRange)
893 return 0;
894 else
895 return -1;
896}
897
899 const sal_Int32 nIndex,
900 const bool bIncludeBorderAndGap) const
901{
902 const sal_Int32 nRow (nIndex / mnColumnCount);
903 const sal_Int32 nColumn (nIndex % mnColumnCount);
904
905 const ::tools::Rectangle aBoundingBox (GetPageObjectBox(nRow,nColumn));
906 if (bIncludeBorderAndGap)
907 return AddBorderAndGap(aBoundingBox, nRow, nColumn);
908 else
909 return aBoundingBox;
910}
911
913 const sal_Int32 nRow,
914 const sal_Int32 nColumn) const
915{
916 return ::tools::Rectangle(
917 Point (mnLeftBorder
918 + nColumn * maPageObjectSize.Width()
919 + std::max<sal_Int32>(nColumn,0) * gnHorizontalGap,
920 mnTopBorder
921 + nRow * maPageObjectSize.Height()
922 + std::max<sal_Int32>(nRow,0) * gnVerticalGap),
923 maPageObjectSize);
924}
925
927 const ::tools::Rectangle& rBoundingBox,
928 const sal_Int32 nRow,
929 const sal_Int32 nColumn) const
930{
931 ::tools::Rectangle aBoundingBox (rBoundingBox);
932
933 if (nColumn == 0)
934 aBoundingBox.SetLeft( 0 );
935 else
936 aBoundingBox.AdjustLeft( -(gnHorizontalGap/2) );
937 if (nColumn == mnColumnCount-1)
938 aBoundingBox.AdjustRight(mnRightBorder );
939 else
940 aBoundingBox.AdjustRight(gnHorizontalGap/2 );
941 if (nRow == 0)
942 aBoundingBox.SetTop( 0 );
943 else
944 aBoundingBox.AdjustTop( -(gnVerticalGap/2) );
945 if (nRow == mnRowCount-1)
946 aBoundingBox.AdjustBottom(mnBottomBorder );
947 else
948 aBoundingBox.AdjustBottom(gnVerticalGap/2 );
949 return aBoundingBox;
950}
951
953{
954 sal_Int32 nHorizontalSize = 0;
955 sal_Int32 nVerticalSize = 0;
956 if (mnColumnCount > 0)
957 {
958 sal_Int32 nRowCount = (mnPageCount+mnColumnCount-1) / mnColumnCount;
959 nHorizontalSize =
960 mnLeftBorder
961 + mnRightBorder
962 + mnColumnCount * maPageObjectSize.Width();
963 if (mnColumnCount > 1)
964 nHorizontalSize += (mnColumnCount-1) * gnHorizontalGap;
965 nVerticalSize =
966 mnTopBorder
967 + mnBottomBorder
968 + nRowCount * maPageObjectSize.Height();
969 if (nRowCount > 1)
970 nVerticalSize += (nRowCount-1) * gnVerticalGap;
971 }
972
973 return ::tools::Rectangle (
974 Point(0,0),
975 Size (nHorizontalSize, nVerticalSize)
976 );
977}
978
980 const Point& rModelPosition,
981 InsertPosition& rPosition) const
982{
983 const sal_Int32 nY = rModelPosition.Y() - mnTopBorder + maPageObjectSize.Height()/2;
984 const sal_Int32 nRowHeight (maPageObjectSize.Height() + gnVerticalGap);
985 const sal_Int32 nRow (::std::min(mnPageCount, nY / nRowHeight));
986 rPosition.SetLogicalPosition (
987 nRow,
988 0,
989 nRow,
990 (nRow == 0),
991 (nRow == mnRowCount),
992 (nRow >= mnMaxRowCount));
993}
994
995//===== HorizontalImplementation ================================================
996
997HorizontalImplementation::HorizontalImplementation (const Implementation& rImplementation)
998 : Implementation(rImplementation)
999{
1000}
1001
1002Layouter::Orientation HorizontalImplementation::GetOrientation() const
1003{
1004 return Layouter::HORIZONTAL;
1005}
1006
1007void HorizontalImplementation::CalculateRowAndColumnCount (const Size&)
1008{
1009 // Row and column count are fixed (for a given page count.)
1010 mnColumnCount = mnPageCount;
1011 mnRowCount = 1;
1012}
1013
1014void HorizontalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize)
1015{
1016 mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder)
1017 / (maPageObjectSize.Width() + gnHorizontalGap);
1018 mnMaxRowCount = 1;
1019}
1020
1021Size HorizontalImplementation::CalculateTargetSize (
1022 const Size& rWindowSize) const
1023{
1024 return Implementation::GetTargetSize(rWindowSize, false, true);
1025}
1026
1027void HorizontalImplementation::CalculateLogicalInsertPosition (
1028 const Point& rModelPosition,
1029 InsertPosition& rPosition) const
1030{
1031 const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2;
1032 const sal_Int32 nColumnWidth (maPageObjectSize.Width() + gnHorizontalGap);
1033 const sal_Int32 nColumn (::std::min(mnPageCount, nX / nColumnWidth));
1034 rPosition.SetLogicalPosition (
1035 0,
1036 nColumn,
1037 nColumn,
1038 (nColumn == 0),
1039 (nColumn == mnColumnCount),
1040 (nColumn >= mnMaxColumnCount));
1041}
1042
1043//===== VerticalImplementation ================================================
1044
1045VerticalImplementation::VerticalImplementation (const Implementation& rImplementation)
1046 : Implementation(rImplementation)
1047{
1048}
1049
1050Layouter::Orientation VerticalImplementation::GetOrientation() const
1051{
1052 return Layouter::VERTICAL;
1053}
1054
1055void VerticalImplementation::CalculateRowAndColumnCount (const Size&)
1056{
1057 // Row and column count are fixed (for a given page count.)
1058 mnRowCount = mnPageCount;
1059 mnColumnCount = 1;
1060
1061}
1062
1063void VerticalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize)
1064{
1065 mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder)
1066 / (maPageObjectSize.Height() + gnVerticalGap);
1067 mnMaxColumnCount = 1;
1068}
1069
1070Size VerticalImplementation::CalculateTargetSize (
1071 const Size& rWindowSize) const
1072{
1073 return Implementation::GetTargetSize(rWindowSize, true, false);
1074}
1075
1076void VerticalImplementation::CalculateLogicalInsertPosition (
1077 const Point& rModelPosition,
1078 InsertPosition& rPosition) const
1079{
1080 return CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition);
1081}
1082
1083//===== GridImplementation ================================================
1084
1085GridImplementation::GridImplementation (
1086 sd::Window *pWindow,
1087 const std::shared_ptr<view::Theme>& rpTheme)
1088 : Implementation(pWindow, rpTheme)
1089{
1090}
1091
1092GridImplementation::GridImplementation (const Implementation& rImplementation)
1093 : Implementation(rImplementation)
1094{
1095}
1096
1097Layouter::Orientation GridImplementation::GetOrientation() const
1098{
1099 return Layouter::GRID;
1100}
1101
1102void GridImplementation::CalculateRowAndColumnCount (const Size& rWindowSize)
1103{
1104 // Calculate the column count.
1105 mnColumnCount
1106 = (rWindowSize.Width() - mnRequestedLeftBorder - mnRequestedRightBorder)
1107 / (maPreferredSize.Width() + gnHorizontalGap);
1108 if (mnColumnCount < mnMinimalColumnCount)
1109 mnColumnCount = mnMinimalColumnCount;
1110 if (mnColumnCount > mnMaximalColumnCount)
1111 mnColumnCount = mnMaximalColumnCount;
1112 mnRowCount = (mnPageCount + mnColumnCount-1)/mnColumnCount;
1113}
1114
1115void GridImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize)
1116{
1117 mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder)
1118 / (maPageObjectSize.Width() + gnHorizontalGap);
1119 mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder)
1120 / (maPageObjectSize.Height() + gnVerticalGap);
1121}
1122
1123Size GridImplementation::CalculateTargetSize (
1124 const Size& rWindowSize) const
1125{
1126 return Implementation::GetTargetSize(rWindowSize, true, true);
1127}
1128
1129void GridImplementation::CalculateLogicalInsertPosition (
1130 const Point& rModelPosition,
1131 InsertPosition& rPosition) const
1132{
1133 if (mnColumnCount == 1)
1134 {
1135 CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition);
1136 }
1137 else
1138 {
1139 // Handle the general case of more than one column.
1140 sal_Int32 nRow (::std::min(
1141 mnRowCount-1,
1142 GetRowAtPosition (rModelPosition.Y(), true, GM_BOTH)));
1143 const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2;
1144 const sal_Int32 nColumnWidth (maPageObjectSize.Width() + gnHorizontalGap);
1145 sal_Int32 nColumn (::std::min(mnColumnCount, nX / nColumnWidth));
1146 sal_Int32 nIndex (nRow * mnColumnCount + nColumn);
1147 bool bIsAtRunEnd (nColumn == mnColumnCount);
1148
1149 if (nIndex >= mnPageCount)
1150 {
1151 nIndex = mnPageCount;
1152 nRow = mnRowCount-1;
1153 nColumn = ::std::min(::std::min(mnPageCount, mnColumnCount), nColumn);
1154 bIsAtRunEnd = true;
1155 }
1156
1157 rPosition.SetLogicalPosition (
1158 nRow,
1159 nColumn,
1160 nIndex,
1161 (nColumn == 0),
1162 bIsAtRunEnd,
1163 (nColumn >= mnMaxColumnCount));
1164 }
1165}
1166
1167//===== InsertPosition ========================================================
1168
1170 : mnRow(-1),
1171 mnColumn(-1),
1172 mnIndex(-1),
1173 mbIsAtRunStart(false),
1174 mbIsAtRunEnd(false),
1175 mbIsExtraSpaceNeeded(false),
1176 maLocation(0,0),
1177 maLeadingOffset(0,0),
1178 maTrailingOffset(0,0)
1179{
1180}
1181
1182bool InsertPosition::operator== (const InsertPosition& rInsertPosition) const
1183{
1184 // Do not compare the geometrical information (maLocation).
1185 return mnRow==rInsertPosition.mnRow
1186 && mnColumn==rInsertPosition.mnColumn
1187 && mnIndex==rInsertPosition.mnIndex
1188 && mbIsAtRunStart==rInsertPosition.mbIsAtRunStart
1189 && mbIsAtRunEnd==rInsertPosition.mbIsAtRunEnd
1190 && mbIsExtraSpaceNeeded==rInsertPosition.mbIsExtraSpaceNeeded;
1191}
1192
1193bool InsertPosition::operator!= (const InsertPosition& rInsertPosition) const
1194{
1195 return !operator==(rInsertPosition);
1196}
1197
1199 const sal_Int32 nRow,
1200 const sal_Int32 nColumn,
1201 const sal_Int32 nIndex,
1202 const bool bIsAtRunStart,
1203 const bool bIsAtRunEnd,
1204 const bool bIsExtraSpaceNeeded)
1205{
1206 mnRow = nRow;
1207 mnColumn = nColumn;
1208 mnIndex = nIndex;
1209 mbIsAtRunStart = bIsAtRunStart;
1210 mbIsAtRunEnd = bIsAtRunEnd;
1211 mbIsExtraSpaceNeeded = bIsExtraSpaceNeeded;
1212}
1213
1215 const Point& rLocation,
1216 const Point& rLeadingOffset,
1217 const Point& rTrailingOffset)
1218{
1219 maLocation = rLocation;
1220 maLeadingOffset = rLeadingOffset;
1221 maTrailingOffset = rTrailingOffset;
1222}
1223
1224} // end of namespace ::sd::slidesorter::namespace
1225
1226/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
awt::Point maLocation
constexpr tools::Long Y() const
constexpr tools::Long X() const
bool IsEmpty() const
constexpr tools::Long Height() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
An SdWindow contains the actual working area of ViewShell.
Definition: Window.hxx:45
The model of the slide sorter gives access to the slides that are to be displayed in the slide sorter...
SharedPageDescriptor GetPageDescriptor(const sal_Int32 nPageIndex, const bool bCreate=true) const
Return a page descriptor for the page with the specified index.
Collect all values concerning the logical and visual properties of the insertion position that is use...
bool operator!=(const InsertPosition &rInsertPosition) const
void SetGeometricalPosition(const Point &rLocation, const Point &rLeadingOffset, const Point &rTrailingOffset)
bool operator==(const InsertPosition &rInsertPosition) const
void SetLogicalPosition(const sal_Int32 nRow, const sal_Int32 nColumn, const sal_Int32 nIndex, const bool bIsAtRunStart, const bool bIsAtRunEnd, const bool bIsExtraSpaceNeeded)
static sal_Int32 ResolvePositionInGap(sal_Int32 nDistanceIntoGap, GapMembership eGapMembership, sal_Int32 nIndex, sal_Int32 nGap)
This method is typically called from GetRowAtPosition() and GetColumnAtPosition() to handle a positio...
::tools::Rectangle GetTotalBoundingBox() const
virtual Size CalculateTargetSize(const Size &rWindowSize) const =0
Size GetTargetSize(const Size &rWindowSize, const bool bCalculateWidth, const bool bCalculateHeight) const
::tools::Rectangle AddBorderAndGap(const ::tools::Rectangle &rBoundingBox, const sal_Int32 nRow, const sal_Int32 nColumn) const
Implementation(sd::Window *pWindow, std::shared_ptr< view::Theme > pTheme)
sal_Int32 GetRowAtPosition(sal_Int32 nYPosition, bool bIncludeBordersAndGaps, GapMembership eGapMembership) const
Calculate the row that the point with the given vertical coordinate is over.
std::shared_ptr< view::Theme > mpTheme
Definition: SlsLayouter.cxx:63
GapMembership
Specify how the gap between two page objects is associated with the page objects.
Definition: SlsLayouter.cxx:68
virtual void CalculateMaxRowAndColumnCount(const Size &rWindowSize)=0
void CalculateGeometricPosition(InsertPosition &rPosition, const Size &rIndicatorSize, const bool bIsVertical, model::SlideSorterModel const &rModel) const
Calculate the geometrical part of the insert position, i.e.
::tools::Rectangle GetPageObjectBox(const sal_Int32 nIndex, const bool bIncludeBorderAndGap=false) const
sal_Int32 GetColumnAtPosition(sal_Int32 nXPosition, bool bIncludeBordersAndGaps, GapMembership eGapMembership) const
Calculate the column that the point with the given horizontal coordinate is over.
sal_Int32 GetIndex(const sal_Int32 nRow, const sal_Int32 nColumn, const bool bClampToValidRange) const
sal_Int32 mnMaxColumnCount
The maximum number of columns.
Definition: SlsLayouter.cxx:56
bool Rearrange(const Size &rWindowSize, const Size &rPreviewModelSize, const sal_uInt32 nPageCount)
Range GetRangeOfVisiblePageObjects(const ::tools::Rectangle &aVisibleArea) const
static Implementation * Create(const Implementation &rImplementation, const Layouter::Orientation eOrientation)
::tools::Rectangle GetInnerBoundingBox(model::SlideSorterModel const &rModel, const sal_Int32 nIndex) const
Return the bounding box of the preview or, when selected, of the page object.
sal_Int32 mnMaxRowCount
The maximum number of rows.
Definition: SlsLayouter.cxx:60
virtual void CalculateLogicalInsertPosition(const Point &rModelPosition, InsertPosition &rPosition) const =0
Calculate the logical part of the insert position, i.e.
virtual void CalculateRowAndColumnCount(const Size &rWindowSize)=0
std::shared_ptr< PageObjectLayouter > mpPageObjectLayouter
Definition: SlsLayouter.cxx:62
virtual Layouter::Orientation GetOrientation() const =0
void CalculateVerticalLogicalInsertPosition(const Point &rModelPosition, InsertPosition &rPosition) const
sal_Int32 GetIndexAtPoint(const Point &rModelPosition, const bool bIncludePageBorders, const bool bClampToValidRange=true) const
Return the index of the page object that is rendered at the given point.
std::unique_ptr< Implementation > mpImplementation
InsertPosition GetInsertPosition(const Point &rModelPosition, const Size &rIndicatorSize, model::SlideSorterModel const &rModel) const
Return an object that describes the logical and visual properties of where to do an insert operation ...
sal_Int32 GetIndex(const sal_Int32 nRow, const sal_Int32 nColumn) const
std::shared_ptr< PageObjectLayouter > const & GetPageObjectLayouter() const
Range GetRangeOfVisiblePageObjects(const ::tools::Rectangle &rVisibleArea) const
Return the index of the first fully or partially visible page object.
void SetColumnCount(sal_Int32 nMinimalColumnCount, sal_Int32 nMaximalColumnCount)
Set the interval of valid column counts.
VclPtr< sd::Window > mpWindow
sal_Int32 GetColumnCount() const
Return the number of columns.
::tools::Rectangle GetPageObjectBox(const sal_Int32 nIndex, const bool bIncludeBorderAndGap) const
Return the bounding box in window coordinates of the nIndex-th page object.
bool Rearrange(const Orientation eOrientation, const Size &rWindowSize, const Size &rPreviewModelSize, const sal_uInt32 nPageCount)
Central method of this class.
::tools::Rectangle GetTotalBoundingBox() const
Return the bounding box in model coordinates of the page that contains the given amount of page objec...
Size const & GetPageObjectSize() const
Layouter(sd::Window *rpWindow, const std::shared_ptr< Theme > &rpTheme)
Range GetValidHorizontalSizeRange() const
constexpr void SetLeft(tools::Long v)
constexpr void SetTop(tools::Long v)
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
sal_Int32 mnRow
sal_Int32 nIndex
std::shared_ptr< PageDescriptor > SharedPageDescriptor
const int Theme_FocusIndicatorWidth
Definition: SlsTheme.hxx:33
sal_uInt32 mnIndex
VclPtr< vcl::Window > mpWindow