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/SlsPageObjectLayouter.hxx"
27 
28 #include "model/SlsPageDescriptor.hxx"
29 #include "view/SlsFontProvider.hxx"
30 #include "view/SlsTheme.hxx"
31 #include "tools/IconCache.hxx"
32 #include "Window.hxx"
33 #include "res_bmp.hrc"
34 
35 namespace sd { namespace slidesorter { namespace view {
36 
37 namespace {
38 const static sal_Int32 gnLeftPageNumberOffset = 2;
39 const static sal_Int32 gnRightPageNumberOffset = 5;
40 const static sal_Int32 gnOuterBorderWidth = 5;
41 const static sal_Int32 gnInfoAreaMinWidth = 26;
42 }
43 
PageObjectLayouter(const::boost::shared_ptr<Theme> & rpTheme,const Size & rPageObjectWindowSize,const Size & rPageSize,const SharedSdWindow & rpWindow,const sal_Int32 nPageCount)44 PageObjectLayouter::PageObjectLayouter (
45 	const ::boost::shared_ptr<Theme>& rpTheme,
46 	const Size& rPageObjectWindowSize,
47 	const Size& rPageSize,
48 	const SharedSdWindow& rpWindow,
49 	const sal_Int32 nPageCount)
50 	: mpWindow(rpWindow),
51 	  maPageObjectSize(rPageObjectWindowSize.Width(), rPageObjectWindowSize.Height()),
52 	  mnModelToWindowScale(1),
53 	  maPageObjectBoundingBox(),
54 	  maPageNumberAreaBoundingBox(),
55 	  maPreviewBoundingBox(),
56 	  maTransitionEffectBoundingBox(),
57 	  maTransitionEffectIcon(IconCache::Instance().GetIcon(BMP_FADE_EFFECT_INDICATOR)),
58 	  mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rpWindow))
59 {
60 	const Size aPageNumberAreaSize (GetPageNumberAreaSize(nPageCount));
61 
62 	const int nMaximumBorderWidth (gnOuterBorderWidth);
63 	const int nFocusIndicatorWidth (rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth));
64 
65 	maPreviewBoundingBox = CalculatePreviewBoundingBox(
66 		maPageObjectSize,
67 		Size(rPageSize.Width(), rPageSize.Height()),
68 		aPageNumberAreaSize.Width(),
69 		nFocusIndicatorWidth);
70 	maFocusIndicatorBoundingBox = Rectangle(Point(0,0), maPageObjectSize);
71 	maPageObjectBoundingBox = Rectangle(
72 		Point(
73 			nFocusIndicatorWidth,
74 			nFocusIndicatorWidth),
75 		Size(
76 			maPageObjectSize.Width()-2*nFocusIndicatorWidth,
77 			maPageObjectSize.Height()-2*nFocusIndicatorWidth));
78 
79 	maPageNumberAreaBoundingBox = Rectangle(
80 		Point(
81 			std::max(gnLeftPageNumberOffset,
82 				sal_Int32(maPreviewBoundingBox.Left()
83 				- gnRightPageNumberOffset
84 				- aPageNumberAreaSize.Width())),
85 			nMaximumBorderWidth),
86 		aPageNumberAreaSize);
87 
88 	const Size aIconSize (maTransitionEffectIcon.GetSizePixel());
89 	maTransitionEffectBoundingBox = Rectangle(
90 		Point(
91 			(maPreviewBoundingBox.Left() - aIconSize.Width()) / 2,
92 			maPreviewBoundingBox.Bottom() - aIconSize.Height()),
93 		aIconSize);
94 }
95 
96 
97 
98 
~PageObjectLayouter(void)99 PageObjectLayouter::~PageObjectLayouter(void)
100 {
101 }
102 
103 
104 
105 
CalculatePreviewBoundingBox(Size & rPageObjectSize,const Size & rPageSize,const sal_Int32 nPageNumberAreaWidth,const sal_Int32 nFocusIndicatorWidth)106 Rectangle PageObjectLayouter::CalculatePreviewBoundingBox (
107 	Size& rPageObjectSize,
108 	const Size& rPageSize,
109 	const sal_Int32 nPageNumberAreaWidth,
110 	const sal_Int32 nFocusIndicatorWidth)
111 {
112 	const sal_Int32 nIconWidth (maTransitionEffectIcon.GetSizePixel().Width());
113 	const sal_Int32 nLeftAreaWidth (
114 		::std::max(
115 			gnInfoAreaMinWidth,
116 			gnRightPageNumberOffset
117 				+ ::std::max(
118 					nPageNumberAreaWidth,
119 					nIconWidth)));
120 	sal_Int32 nPreviewWidth;
121 	sal_Int32 nPreviewHeight;
122 	const double nPageAspectRatio (double(rPageSize.Width()) / double(rPageSize.Height()));
123 	if (rPageObjectSize.Height() == 0)
124 	{
125 		// Calculate height so that the preview fills the available
126 		// horizontal space completely while observing the aspect ratio of
127 		// the preview.
128 		nPreviewWidth = rPageObjectSize.Width()
129 			- nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
130 		nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio);
131 		rPageObjectSize.setHeight(nPreviewHeight + 2*gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1);
132 	}
133 	else if (rPageObjectSize.Width() == 0)
134 	{
135 		// Calculate the width of the page object so that the preview fills
136 		// the available vertical space completely while observing the
137 		// aspect ratio of the preview.
138 		nPreviewHeight = rPageObjectSize.Height() - 2*gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
139 		nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio);
140 		rPageObjectSize.setWidth(nPreviewWidth
141 			+ nLeftAreaWidth + gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1);
142 
143 	}
144 	else
145 	{
146 		// The size of the page object is given. Calculate the size of the
147 		// preview.
148 		nPreviewWidth = rPageObjectSize.Width()
149 			- nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
150 		nPreviewHeight = rPageObjectSize.Height()
151 			- gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1;
152 		if (double(nPreviewWidth)/double(nPreviewHeight) > nPageAspectRatio)
153 			nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio);
154 		else
155 			nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio);
156 	}
157 	// When the preview does not fill the available space completely then
158 	// place it flush right and vertically centered.
159 	const int nLeft (rPageObjectSize.Width()
160 		- gnOuterBorderWidth - nPreviewWidth - nFocusIndicatorWidth - 1);
161 	const int nTop ((rPageObjectSize.Height() - nPreviewHeight)/2);
162 	return Rectangle(
163 		nLeft,
164 		nTop,
165 		nLeft + nPreviewWidth,
166 		nTop + nPreviewHeight);
167 }
168 
169 
170 
171 
GetBoundingBox(const model::SharedPageDescriptor & rpPageDescriptor,const Part ePart,const CoordinateSystem eCoordinateSystem)172 Rectangle PageObjectLayouter::GetBoundingBox (
173 	const model::SharedPageDescriptor& rpPageDescriptor,
174 	const Part ePart,
175 	const CoordinateSystem eCoordinateSystem)
176 {
177 	OSL_ASSERT(rpPageDescriptor);
178 	Point aLocation (rpPageDescriptor ? rpPageDescriptor->GetLocation() : Point(0,0));
179 	return GetBoundingBox(aLocation, ePart, eCoordinateSystem);
180 }
181 
182 
183 
184 
GetBoundingBox(const Point & rPageObjectLocation,const Part ePart,const CoordinateSystem eCoordinateSystem)185 Rectangle PageObjectLayouter::GetBoundingBox (
186 	const Point& rPageObjectLocation,
187 	const Part ePart,
188 	const CoordinateSystem eCoordinateSystem)
189 {
190 	Rectangle aBoundingBox;
191 	switch (ePart)
192 	{
193 		case FocusIndicator:
194 			aBoundingBox = maFocusIndicatorBoundingBox;
195 			break;
196 
197 		case PageObject:
198 		case MouseOverIndicator:
199 			aBoundingBox = maPageObjectBoundingBox;
200 			break;
201 
202 		case Preview:
203 			aBoundingBox = maPreviewBoundingBox;
204 			break;
205 
206 		case PageNumber:
207 			aBoundingBox = maPageNumberAreaBoundingBox;
208 			break;
209 
210 		case Name:
211 			aBoundingBox = maPageNumberAreaBoundingBox;
212 			break;
213 
214 		case TransitionEffectIndicator:
215 			aBoundingBox = maTransitionEffectBoundingBox;
216 			break;
217 	}
218 
219 	// Adapt coordinates to the requested coordinate system.
220 	Point aLocation (rPageObjectLocation);
221 	if (eCoordinateSystem == WindowCoordinateSystem)
222 		aLocation += mpWindow->GetMapMode().GetOrigin();
223 
224 	return Rectangle(
225 		aBoundingBox.TopLeft() + aLocation,
226 		aBoundingBox.BottomRight() + aLocation);
227 }
228 
229 
230 
231 
GetSize(const Part ePart,const CoordinateSystem eCoordinateSystem)232 Size PageObjectLayouter::GetSize (
233 	const Part ePart,
234 	const CoordinateSystem eCoordinateSystem)
235 {
236 	return GetBoundingBox(Point(0,0), ePart, eCoordinateSystem).GetSize();
237 }
238 
239 
240 
241 
GetPageNumberAreaSize(const int nPageCount)242 Size PageObjectLayouter::GetPageNumberAreaSize (const int nPageCount)
243 {
244 	OSL_ASSERT(mpWindow);
245 
246 	// Set the correct font.
247 	Font aOriginalFont (mpWindow->GetFont());
248 	if (mpPageNumberFont)
249 		mpWindow->SetFont(*mpPageNumberFont);
250 
251 	String sPageNumberTemplate;
252 	if (nPageCount < 10)
253 		sPageNumberTemplate = String::CreateFromAscii("9");
254 	else if (nPageCount < 100)
255 		sPageNumberTemplate = String::CreateFromAscii("99");
256 	else if (nPageCount < 200)
257 		// Just for the case that 1 is narrower than 9.
258 		sPageNumberTemplate = String::CreateFromAscii("199");
259 	else if (nPageCount < 1000)
260 		sPageNumberTemplate = String::CreateFromAscii("999");
261 	else
262 		sPageNumberTemplate = String::CreateFromAscii("9999");
263 	// More than 9999 pages are not handled.
264 
265 	const Size aSize (
266 		mpWindow->GetTextWidth(sPageNumberTemplate),
267 		mpWindow->GetTextHeight());
268 
269 	mpWindow->SetFont(aOriginalFont);
270 
271 	return aSize;
272 }
273 
274 
275 
276 
GetTransitionEffectIcon(void) const277 Image PageObjectLayouter::GetTransitionEffectIcon (void) const
278 {
279 	return maTransitionEffectIcon;
280 }
281 
282 
283 } } } // end of namespace ::sd::slidesorter::view
284