1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "precompiled_sd.hxx"
29 
30 #include "view/SlsPageObjectLayouter.hxx"
31 
32 #include "model/SlsPageDescriptor.hxx"
33 #include "view/SlsFontProvider.hxx"
34 #include "view/SlsTheme.hxx"
35 #include "tools/IconCache.hxx"
36 #include "Window.hxx"
37 #include "res_bmp.hrc"
38 
39 namespace sd { namespace slidesorter { namespace view {
40 
41 namespace {
42 const static sal_Int32 gnLeftPageNumberOffset = 2;
43 const static sal_Int32 gnRightPageNumberOffset = 5;
44 const static sal_Int32 gnOuterBorderWidth = 5;
45 const static sal_Int32 gnInfoAreaMinWidth = 26;
46 }
47 
48 PageObjectLayouter::PageObjectLayouter (
49     const ::boost::shared_ptr<Theme>& rpTheme,
50     const Size& rPageObjectWindowSize,
51     const Size& rPageSize,
52     const SharedSdWindow& rpWindow,
53     const sal_Int32 nPageCount)
54     : mpWindow(rpWindow),
55       maPageObjectSize(rPageObjectWindowSize.Width(), rPageObjectWindowSize.Height()),
56       mnModelToWindowScale(1),
57       maPageObjectBoundingBox(),
58       maPageNumberAreaBoundingBox(),
59       maPreviewBoundingBox(),
60       maTransitionEffectBoundingBox(),
61       maTransitionEffectIcon(IconCache::Instance().GetIcon(BMP_FADE_EFFECT_INDICATOR)),
62       mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rpWindow))
63 {
64     const Size aPageNumberAreaSize (GetPageNumberAreaSize(nPageCount));
65 
66     const int nMaximumBorderWidth (gnOuterBorderWidth);
67     const int nFocusIndicatorWidth (rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth));
68 
69     maPreviewBoundingBox = CalculatePreviewBoundingBox(
70         maPageObjectSize,
71         Size(rPageSize.Width(), rPageSize.Height()),
72         aPageNumberAreaSize.Width(),
73         nFocusIndicatorWidth);
74     maFocusIndicatorBoundingBox = Rectangle(Point(0,0), maPageObjectSize);
75     maPageObjectBoundingBox = Rectangle(
76         Point(
77             nFocusIndicatorWidth,
78             nFocusIndicatorWidth),
79         Size(
80             maPageObjectSize.Width()-2*nFocusIndicatorWidth,
81             maPageObjectSize.Height()-2*nFocusIndicatorWidth));
82 
83     maPageNumberAreaBoundingBox = Rectangle(
84         Point(
85             std::max(gnLeftPageNumberOffset,
86                 sal_Int32(maPreviewBoundingBox.Left()
87                 - gnRightPageNumberOffset
88                 - aPageNumberAreaSize.Width())),
89             nMaximumBorderWidth),
90         aPageNumberAreaSize);
91 
92     const Size aIconSize (maTransitionEffectIcon.GetSizePixel());
93     maTransitionEffectBoundingBox = Rectangle(
94         Point(
95             (maPreviewBoundingBox.Left() - aIconSize.Width()) / 2,
96             maPreviewBoundingBox.Bottom() - aIconSize.Height()),
97         aIconSize);
98 }
99 
100 
101 
102 
103 PageObjectLayouter::~PageObjectLayouter(void)
104 {
105 }
106 
107 
108 
109 
110 Rectangle PageObjectLayouter::CalculatePreviewBoundingBox (
111     Size& rPageObjectSize,
112     const Size& rPageSize,
113     const sal_Int32 nPageNumberAreaWidth,
114     const sal_Int32 nFocusIndicatorWidth)
115 {
116     const sal_Int32 nIconWidth (maTransitionEffectIcon.GetSizePixel().Width());
117     const sal_Int32 nLeftAreaWidth (
118         ::std::max(
119             gnInfoAreaMinWidth,
120             gnRightPageNumberOffset
121                 + ::std::max(
122                     nPageNumberAreaWidth,
123                     nIconWidth)));
124     sal_Int32 nPreviewWidth;
125     sal_Int32 nPreviewHeight;
126     const double nPageAspectRatio (double(rPageSize.Width()) / double(rPageSize.Height()));
127     if (rPageObjectSize.Height() == 0)
128     {
129         // Calculate height so that the preview fills the available
130         // horizontal space completely while observing the aspect ratio of
131         // the preview.
132         nPreviewWidth = rPageObjectSize.Width()
133             - nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
134         nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio);
135         rPageObjectSize.setHeight(nPreviewHeight + 2*gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1);
136     }
137     else if (rPageObjectSize.Width() == 0)
138     {
139         // Calculate the width of the page object so that the preview fills
140         // the available vertical space completely while observing the
141         // aspect ratio of the preview.
142         nPreviewHeight = rPageObjectSize.Height() - 2*gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
143         nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio);
144         rPageObjectSize.setWidth(nPreviewWidth
145             + nLeftAreaWidth + gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1);
146 
147     }
148     else
149     {
150         // The size of the page object is given.  Calculate the size of the
151         // preview.
152         nPreviewWidth = rPageObjectSize.Width()
153             - nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
154         nPreviewHeight = rPageObjectSize.Height()
155             - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
156         if (double(nPreviewWidth)/double(nPreviewHeight) > nPageAspectRatio)
157             nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio);
158         else
159             nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio);
160     }
161     // When the preview does not fill the available space completely then
162     // place it flush right and vertically centered.
163     const int nLeft (rPageObjectSize.Width()
164         - gnOuterBorderWidth - nPreviewWidth - nFocusIndicatorWidth - 1);
165     const int nTop ((rPageObjectSize.Height() - nPreviewHeight)/2);
166     return Rectangle(
167         nLeft,
168         nTop,
169         nLeft + nPreviewWidth,
170         nTop + nPreviewHeight);
171 }
172 
173 
174 
175 
176 Rectangle PageObjectLayouter::GetBoundingBox (
177     const model::SharedPageDescriptor& rpPageDescriptor,
178     const Part ePart,
179     const CoordinateSystem eCoordinateSystem)
180 {
181     OSL_ASSERT(rpPageDescriptor);
182     Point aLocation (rpPageDescriptor ? rpPageDescriptor->GetLocation() : Point(0,0));
183     return GetBoundingBox(aLocation, ePart, eCoordinateSystem);
184 }
185 
186 
187 
188 
189 Rectangle PageObjectLayouter::GetBoundingBox (
190     const Point& rPageObjectLocation,
191     const Part ePart,
192     const CoordinateSystem eCoordinateSystem)
193 {
194     Rectangle aBoundingBox;
195     switch (ePart)
196     {
197         case FocusIndicator:
198             aBoundingBox = maFocusIndicatorBoundingBox;
199             break;
200 
201         case PageObject:
202         case MouseOverIndicator:
203             aBoundingBox = maPageObjectBoundingBox;
204             break;
205 
206         case Preview:
207             aBoundingBox = maPreviewBoundingBox;
208             break;
209 
210         case PageNumber:
211             aBoundingBox = maPageNumberAreaBoundingBox;
212             break;
213 
214         case Name:
215             aBoundingBox = maPageNumberAreaBoundingBox;
216             break;
217 
218         case TransitionEffectIndicator:
219             aBoundingBox = maTransitionEffectBoundingBox;
220             break;
221     }
222 
223     // Adapt coordinates to the requested coordinate system.
224     Point aLocation (rPageObjectLocation);
225     if (eCoordinateSystem == WindowCoordinateSystem)
226         aLocation += mpWindow->GetMapMode().GetOrigin();
227 
228     return Rectangle(
229         aBoundingBox.TopLeft() + aLocation,
230         aBoundingBox.BottomRight() + aLocation);
231 }
232 
233 
234 
235 
236 Size PageObjectLayouter::GetSize (
237     const Part ePart,
238     const CoordinateSystem eCoordinateSystem)
239 {
240     return GetBoundingBox(Point(0,0), ePart, eCoordinateSystem).GetSize();
241 }
242 
243 
244 
245 
246 Size PageObjectLayouter::GetPageNumberAreaSize (const int nPageCount)
247 {
248     OSL_ASSERT(mpWindow);
249 
250     // Set the correct font.
251     Font aOriginalFont (mpWindow->GetFont());
252     if (mpPageNumberFont)
253         mpWindow->SetFont(*mpPageNumberFont);
254 
255     String sPageNumberTemplate;
256     if (nPageCount < 10)
257         sPageNumberTemplate = String::CreateFromAscii("9");
258     else if (nPageCount < 100)
259         sPageNumberTemplate = String::CreateFromAscii("99");
260     else if (nPageCount < 200)
261         // Just for the case that 1 is narrower than 9.
262         sPageNumberTemplate = String::CreateFromAscii("199");
263     else if (nPageCount < 1000)
264         sPageNumberTemplate = String::CreateFromAscii("999");
265     else
266         sPageNumberTemplate = String::CreateFromAscii("9999");
267     // More then 9999 pages are not handled.
268 
269     const Size aSize (
270         mpWindow->GetTextWidth(sPageNumberTemplate),
271         mpWindow->GetTextHeight());
272 
273     mpWindow->SetFont(aOriginalFont);
274 
275     return aSize;
276 }
277 
278 
279 
280 
281 Image PageObjectLayouter::GetTransitionEffectIcon (void) const
282 {
283     return maTransitionEffectIcon;
284 }
285 
286 
287 } } } // end of namespace ::sd::slidesorter::view
288