Line data Source code
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 "view/SlsPageObjectPainter.hxx"
21 :
22 : #include "model/SlsPageDescriptor.hxx"
23 : #include "view/SlideSorterView.hxx"
24 : #include "view/SlsPageObjectLayouter.hxx"
25 : #include "view/SlsLayouter.hxx"
26 : #include "view/SlsTheme.hxx"
27 : #include "SlsFramePainter.hxx"
28 : #include "cache/SlsPageCache.hxx"
29 : #include "controller/SlsProperties.hxx"
30 : #include "Window.hxx"
31 : #include "sdpage.hxx"
32 : #include "sdresid.hxx"
33 : #include <vcl/svapp.hxx>
34 : #include <vcl/vclenum.hxx>
35 : #include <vcl/virdev.hxx>
36 : #include <boost/scoped_ptr.hpp>
37 : #include "CustomAnimationEffect.hxx"
38 :
39 : using namespace ::drawinglayer::primitive2d;
40 :
41 : namespace sd { namespace slidesorter { namespace view {
42 :
43 : //===== PageObjectPainter =====================================================
44 :
45 109 : PageObjectPainter::PageObjectPainter (
46 : const SlideSorter& rSlideSorter)
47 109 : : mrLayouter(rSlideSorter.GetView().GetLayouter()),
48 109 : mpCache(rSlideSorter.GetView().GetPreviewCache()),
49 : mpProperties(rSlideSorter.GetProperties()),
50 : mpTheme(rSlideSorter.GetTheme()),
51 218 : mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rSlideSorter.GetContentWindow())),
52 218 : mpShadowPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_RawShadow))),
53 545 : mpFocusBorderPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_FocusBorder)))
54 : {
55 : // Replace the color (not the alpha values) in the focus border with a
56 : // color derived from the current selection color.
57 109 : Color aColor (mpTheme->GetColor(Theme::Color_Selection));
58 : sal_uInt16 nHue, nSat, nBri;
59 109 : aColor.RGBtoHSB(nHue, nSat, nBri);
60 109 : aColor = Color::HSBtoRGB(nHue, 28, 65);
61 109 : mpFocusBorderPainter->AdaptColor(aColor, true);
62 109 : }
63 :
64 109 : PageObjectPainter::~PageObjectPainter (void)
65 : {
66 109 : }
67 :
68 474 : void PageObjectPainter::PaintPageObject (
69 : OutputDevice& rDevice,
70 : const model::SharedPageDescriptor& rpDescriptor)
71 : {
72 474 : if (UpdatePageObjectLayouter())
73 : {
74 474 : PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
75 : // Turn off antialiasing to avoid the bitmaps from being
76 : // shifted by fractions of a pixel and thus show blurry edges.
77 474 : const sal_uInt16 nSavedAntialiasingMode (rDevice.GetAntialiasing());
78 474 : rDevice.SetAntialiasing(nSavedAntialiasingMode & ~ANTIALIASING_ENABLE_B2DDRAW);
79 :
80 474 : PaintBackground(pPageObjectLayouter, rDevice, rpDescriptor);
81 474 : PaintPreview(pPageObjectLayouter, rDevice, rpDescriptor);
82 474 : PaintPageNumber(pPageObjectLayouter, rDevice, rpDescriptor);
83 474 : PaintTransitionEffect(pPageObjectLayouter, rDevice, rpDescriptor);
84 474 : if (rpDescriptor->GetPage()->hasAnimationNode())
85 2 : PaintCustomAnimationEffect(pPageObjectLayouter, rDevice, rpDescriptor);
86 474 : rDevice.SetAntialiasing(nSavedAntialiasingMode);
87 : }
88 474 : }
89 :
90 474 : bool PageObjectPainter::UpdatePageObjectLayouter (void)
91 : {
92 : // The page object layouter is quite volatile. It may have been replaced
93 : // since the last call. Update it now.
94 474 : PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
95 474 : if ( ! pPageObjectLayouter)
96 : {
97 : OSL_FAIL("no page object layouter");
98 0 : return false;
99 : }
100 :
101 474 : return true;
102 : }
103 :
104 0 : void PageObjectPainter::SetTheme (const ::boost::shared_ptr<view::Theme>& rpTheme)
105 : {
106 0 : mpTheme = rpTheme;
107 0 : }
108 :
109 474 : void PageObjectPainter::PaintBackground (
110 : PageObjectLayouter *pPageObjectLayouter,
111 : OutputDevice& rDevice,
112 : const model::SharedPageDescriptor& rpDescriptor) const
113 : {
114 474 : PaintBackgroundDetail(pPageObjectLayouter, rDevice, rpDescriptor);
115 :
116 : // Fill the interior of the preview area with the default background
117 : // color of the page.
118 474 : SdPage* pPage = rpDescriptor->GetPage();
119 474 : if (pPage != NULL)
120 : {
121 474 : rDevice.SetFillColor(pPage->GetPageBackgroundColor(NULL));
122 474 : rDevice.SetLineColor(pPage->GetPageBackgroundColor(NULL));
123 : const Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
124 : rpDescriptor,
125 : PageObjectLayouter::Preview,
126 474 : PageObjectLayouter::ModelCoordinateSystem));
127 474 : rDevice.DrawRect(aPreviewBox);
128 : }
129 474 : }
130 :
131 474 : void PageObjectPainter::PaintPreview (
132 : PageObjectLayouter *pPageObjectLayouter,
133 : OutputDevice& rDevice,
134 : const model::SharedPageDescriptor& rpDescriptor) const
135 : {
136 : const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
137 : rpDescriptor,
138 : PageObjectLayouter::Preview,
139 474 : PageObjectLayouter::ModelCoordinateSystem));
140 :
141 474 : if (mpCache != 0)
142 : {
143 474 : const SdrPage* pPage = rpDescriptor->GetPage();
144 474 : mpCache->SetPreciousFlag(pPage, true);
145 :
146 474 : const Bitmap aPreview (GetPreviewBitmap(rpDescriptor, &rDevice));
147 474 : if ( ! aPreview.IsEmpty())
148 : {
149 220 : if (aPreview.GetSizePixel() != aBox.GetSize())
150 18 : rDevice.DrawBitmap(aBox.TopLeft(), aBox.GetSize(), aPreview);
151 : else
152 202 : rDevice.DrawBitmap(aBox.TopLeft(), aPreview);
153 474 : }
154 : }
155 474 : }
156 :
157 0 : Bitmap PageObjectPainter::CreateMarkedPreview (
158 : const Size& rSize,
159 : const Bitmap& rPreview,
160 : const BitmapEx& rOverlay,
161 : const OutputDevice* pReferenceDevice) const
162 : {
163 0 : ::boost::scoped_ptr<VirtualDevice> pDevice;
164 0 : if (pReferenceDevice != NULL)
165 0 : pDevice.reset(new VirtualDevice(*pReferenceDevice));
166 : else
167 0 : pDevice.reset(new VirtualDevice());
168 0 : pDevice->SetOutputSizePixel(rSize);
169 :
170 0 : pDevice->DrawBitmap(Point(0,0), rSize, rPreview);
171 :
172 : // Paint bitmap tiled over the preview to mark it as excluded.
173 0 : const sal_Int32 nIconWidth (rOverlay.GetSizePixel().Width());
174 0 : const sal_Int32 nIconHeight (rOverlay.GetSizePixel().Height());
175 0 : if (nIconWidth>0 && nIconHeight>0)
176 : {
177 0 : for (sal_Int32 nX=0; nX<rSize.Width(); nX+=nIconWidth)
178 0 : for (sal_Int32 nY=0; nY<rSize.Height(); nY+=nIconHeight)
179 0 : pDevice->DrawBitmapEx(Point(nX,nY), rOverlay);
180 : }
181 0 : return pDevice->GetBitmap(Point(0,0), rSize);
182 : }
183 :
184 474 : Bitmap PageObjectPainter::GetPreviewBitmap (
185 : const model::SharedPageDescriptor& rpDescriptor,
186 : const OutputDevice* pReferenceDevice) const
187 : {
188 474 : const SdrPage* pPage = rpDescriptor->GetPage();
189 474 : const bool bIsExcluded (rpDescriptor->HasState(model::PageDescriptor::ST_Excluded));
190 :
191 474 : if (bIsExcluded)
192 : {
193 0 : PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
194 :
195 0 : Bitmap aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage,false));
196 : const Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
197 : rpDescriptor,
198 : PageObjectLayouter::Preview,
199 0 : PageObjectLayouter::ModelCoordinateSystem));
200 0 : if (aMarkedPreview.IsEmpty() || aMarkedPreview.GetSizePixel()!=aPreviewBox.GetSize())
201 : {
202 0 : aMarkedPreview = CreateMarkedPreview(
203 : aPreviewBox.GetSize(),
204 : mpCache->GetPreviewBitmap(pPage,true),
205 0 : mpTheme->GetIcon(Theme::Icon_HideSlideOverlay),
206 0 : pReferenceDevice);
207 0 : mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview);
208 : }
209 0 : return aMarkedPreview;
210 : }
211 : else
212 : {
213 474 : return mpCache->GetPreviewBitmap(pPage,false);
214 : }
215 : }
216 :
217 474 : void PageObjectPainter::PaintPageNumber (
218 : PageObjectLayouter *pPageObjectLayouter,
219 : OutputDevice& rDevice,
220 : const model::SharedPageDescriptor& rpDescriptor) const
221 : {
222 : const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
223 : rpDescriptor,
224 : PageObjectLayouter::PageNumber,
225 474 : PageObjectLayouter::ModelCoordinateSystem));
226 :
227 : // Determine the color of the page number.
228 474 : Color aPageNumberColor (mpTheme->GetColor(Theme::Color_PageNumberDefault));
229 948 : if (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ||
230 474 : rpDescriptor->HasState(model::PageDescriptor::ST_Selected))
231 : {
232 : // Page number is painted on background for hover or selection or
233 : // both. Each of these background colors has a predefined luminance
234 : // which is compatible with the PageNumberHover color.
235 409 : aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHover));
236 : }
237 : else
238 : {
239 65 : const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
240 65 : const sal_Int32 nBackgroundLuminance (aBackgroundColor.GetLuminance());
241 : // When the background color is black then this is interpreted as
242 : // high contrast mode and the font color is set to white.
243 65 : if (nBackgroundLuminance == 0)
244 0 : aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHighContrast));
245 : else
246 : {
247 : // Compare luminance of default page number color and background
248 : // color. When the two are similar then use a darker
249 : // (preferred) or brighter font color.
250 65 : const sal_Int32 nFontLuminance (aPageNumberColor.GetLuminance());
251 65 : if (abs(nBackgroundLuminance - nFontLuminance) < 60)
252 : {
253 0 : if (nBackgroundLuminance > nFontLuminance-30)
254 0 : aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberBrightBackground));
255 : else
256 0 : aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberDarkBackground));
257 : }
258 : }
259 : }
260 :
261 : // Paint the page number.
262 : OSL_ASSERT(rpDescriptor->GetPage()!=NULL);
263 474 : const sal_Int32 nPageNumber ((rpDescriptor->GetPage()->GetPageNum() - 1) / 2 + 1);
264 474 : const OUString sPageNumber(OUString::number(nPageNumber));
265 474 : rDevice.SetFont(*mpPageNumberFont);
266 474 : rDevice.SetTextColor(aPageNumberColor);
267 474 : rDevice.DrawText(aBox, sPageNumber, TEXT_DRAW_RIGHT | TEXT_DRAW_VCENTER);
268 474 : }
269 :
270 474 : void PageObjectPainter::PaintTransitionEffect (
271 : PageObjectLayouter *pPageObjectLayouter,
272 : OutputDevice& rDevice,
273 : const model::SharedPageDescriptor& rpDescriptor) const
274 : {
275 474 : const SdPage* pPage = rpDescriptor->GetPage();
276 474 : if (pPage!=NULL && pPage->getTransitionType() > 0)
277 : {
278 : const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
279 : rpDescriptor,
280 : PageObjectLayouter::TransitionEffectIndicator,
281 0 : PageObjectLayouter::ModelCoordinateSystem));
282 :
283 : rDevice.DrawBitmapEx(
284 : aBox.TopCenter(),
285 0 : pPageObjectLayouter->GetTransitionEffectIcon().GetBitmapEx());
286 : }
287 474 : }
288 :
289 2 : void PageObjectPainter::PaintCustomAnimationEffect (
290 : PageObjectLayouter *pPageObjectLayouter,
291 : OutputDevice& rDevice,
292 : const model::SharedPageDescriptor& rpDescriptor) const
293 : {
294 2 : SdPage* pPage = rpDescriptor->GetPage();
295 2 : boost::shared_ptr< MainSequence > aMainSequence = pPage->getMainSequence();
296 2 : EffectSequence::iterator aIter = aMainSequence->getBegin();
297 2 : EffectSequence::iterator aEnd = aMainSequence->getEnd();
298 2 : if ( aIter != aEnd )
299 : {
300 : const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
301 : rpDescriptor,
302 : PageObjectLayouter::CustomAnimationEffectIndicator,
303 0 : PageObjectLayouter::ModelCoordinateSystem));
304 : rDevice.DrawBitmapEx(
305 : aBox.TopCenter(),
306 0 : pPageObjectLayouter->GetCustomAnimationEffectIcon().GetBitmapEx());
307 2 : }
308 2 : }
309 :
310 474 : void PageObjectPainter::PaintBackgroundDetail (
311 : PageObjectLayouter *pPageObjectLayouter,
312 : OutputDevice& rDevice,
313 : const model::SharedPageDescriptor& rpDescriptor) const
314 : {
315 : enum State { None = 0x00, Selected = 0x01, MouseOver = 0x02, Focused = 0x04 };
316 : const int eState =
317 474 : (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) ? Selected : None)
318 474 : | (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ? MouseOver : None)
319 474 : | (rpDescriptor->HasState(model::PageDescriptor::ST_Focused) ? Focused : None);
320 :
321 : bool bHasFocusBorder;
322 : Theme::GradientColorType eColorType;
323 :
324 474 : switch (eState)
325 : {
326 : case MouseOver | Selected | Focused:
327 0 : eColorType = Theme::Gradient_MouseOverSelectedAndFocusedPage;
328 0 : bHasFocusBorder = true;
329 0 : break;
330 :
331 : case MouseOver | Selected:
332 0 : eColorType = Theme::Gradient_MouseOverSelected;
333 0 : bHasFocusBorder = false;
334 0 : break;
335 :
336 : case MouseOver:
337 0 : eColorType = Theme::Gradient_MouseOverPage;
338 0 : bHasFocusBorder = false;
339 0 : break;
340 :
341 : case MouseOver | Focused:
342 0 : eColorType = Theme::Gradient_MouseOverPage;
343 0 : bHasFocusBorder = true;
344 0 : break;
345 :
346 : case Selected | Focused:
347 0 : eColorType = Theme::Gradient_SelectedAndFocusedPage;
348 0 : bHasFocusBorder = true;
349 0 : break;
350 :
351 : case Selected:
352 409 : eColorType = Theme::Gradient_SelectedPage;
353 409 : bHasFocusBorder = false;
354 409 : break;
355 :
356 : case Focused:
357 0 : eColorType = Theme::Gradient_FocusedPage;
358 0 : bHasFocusBorder = true;
359 0 : break;
360 :
361 : case None:
362 : default:
363 65 : eColorType = Theme::Gradient_NormalPage;
364 65 : bHasFocusBorder = false;
365 65 : break;
366 : }
367 :
368 : const Rectangle aFocusSize (pPageObjectLayouter->GetBoundingBox(
369 : rpDescriptor,
370 : PageObjectLayouter::FocusIndicator,
371 474 : PageObjectLayouter::ModelCoordinateSystem));
372 :
373 : const Rectangle aPageObjectBox (pPageObjectLayouter->GetBoundingBox(
374 : rpDescriptor,
375 : PageObjectLayouter::PageObject,
376 474 : PageObjectLayouter::ModelCoordinateSystem));
377 :
378 : // Fill the background with the background color of the slide sorter.
379 474 : const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
380 474 : rDevice.SetFillColor(aBackgroundColor);
381 474 : rDevice.SetLineColor(aBackgroundColor);
382 474 : rDevice.DrawRect(aFocusSize);
383 :
384 : // Paint the slide area with a linear gradient that starts some pixels
385 : // below the top and ends some pixels above the bottom.
386 474 : const Color aTopColor(mpTheme->GetGradientColor(eColorType, Theme::Fill1));
387 474 : const Color aBottomColor(mpTheme->GetGradientColor(eColorType, Theme::Fill2));
388 474 : if (aTopColor != aBottomColor)
389 : {
390 409 : const sal_Int32 nHeight (aPageObjectBox.GetHeight());
391 409 : const sal_Int32 nDefaultConstantSize(nHeight/4);
392 409 : const sal_Int32 nMinimalGradientSize(40);
393 : const sal_Int32 nY1 (
394 : ::std::max<sal_Int32>(
395 : 0,
396 : ::std::min<sal_Int32>(
397 : nDefaultConstantSize,
398 409 : (nHeight - nMinimalGradientSize)/2)));
399 409 : const sal_Int32 nY2 (nHeight-nY1);
400 409 : const sal_Int32 nTop (aPageObjectBox.Top());
401 87523 : for (sal_Int32 nY=0; nY<nHeight; ++nY)
402 : {
403 87114 : if (nY<=nY1)
404 22050 : rDevice.SetLineColor(aTopColor);
405 65064 : else if (nY>=nY2)
406 21641 : rDevice.SetLineColor(aBottomColor);
407 : else
408 : {
409 43423 : Color aColor (aTopColor);
410 43423 : aColor.Merge(aBottomColor, 255 * (nY2-nY) / (nY2-nY1));
411 43423 : rDevice.SetLineColor(aColor);
412 : }
413 : rDevice.DrawLine(
414 87114 : Point(aPageObjectBox.Left(), nY+nTop),
415 174228 : Point(aPageObjectBox.Right(), nY+nTop));
416 : }
417 : }
418 : else
419 : {
420 65 : rDevice.SetFillColor(aTopColor);
421 65 : rDevice.DrawRect(aPageObjectBox);
422 : }
423 :
424 : // Paint the simple border and, for some backgrounds, the focus border.
425 474 : if (bHasFocusBorder)
426 0 : mpFocusBorderPainter->PaintFrame(rDevice, aPageObjectBox);
427 : else
428 474 : PaintBorder(rDevice, eColorType, aPageObjectBox);
429 :
430 : // Get bounding box of the preview around which a shadow is painted.
431 : // Compensate for the border around the preview.
432 : const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
433 : rpDescriptor,
434 : PageObjectLayouter::Preview,
435 474 : PageObjectLayouter::ModelCoordinateSystem));
436 474 : Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1);
437 474 : mpShadowPainter->PaintFrame(rDevice, aFrameBox);
438 474 : }
439 :
440 474 : void PageObjectPainter::PaintBorder (
441 : OutputDevice& rDevice,
442 : const Theme::GradientColorType eColorType,
443 : const Rectangle& rBox) const
444 : {
445 474 : rDevice.SetFillColor();
446 474 : const sal_Int32 nBorderWidth (1);
447 948 : for (int nIndex=0; nIndex<nBorderWidth; ++nIndex)
448 : {
449 474 : const int nDelta (nIndex);
450 474 : rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border2));
451 : rDevice.DrawLine(
452 948 : Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
453 1422 : Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta));
454 : rDevice.DrawLine(
455 948 : Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta),
456 1422 : Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta));
457 : rDevice.DrawLine(
458 948 : Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta),
459 1422 : Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
460 :
461 474 : rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border1));
462 : rDevice.DrawLine(
463 948 : Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
464 1422 : Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
465 : }
466 474 : }
467 :
468 114 : } } } // end of namespace sd::slidesorter::view
469 :
470 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|