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 64 : PageObjectPainter::PageObjectPainter (
46 : const SlideSorter& rSlideSorter)
47 64 : : mrLayouter(rSlideSorter.GetView().GetLayouter()),
48 64 : mpCache(rSlideSorter.GetView().GetPreviewCache()),
49 : mpProperties(rSlideSorter.GetProperties()),
50 : mpTheme(rSlideSorter.GetTheme()),
51 128 : mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rSlideSorter.GetContentWindow())),
52 128 : mpShadowPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_RawShadow))),
53 320 : 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 64 : Color aColor (mpTheme->GetColor(Theme::Color_Selection));
58 : sal_uInt16 nHue, nSat, nBri;
59 64 : aColor.RGBtoHSB(nHue, nSat, nBri);
60 64 : aColor = Color::HSBtoRGB(nHue, 28, 65);
61 64 : mpFocusBorderPainter->AdaptColor(aColor, true);
62 64 : }
63 :
64 64 : PageObjectPainter::~PageObjectPainter()
65 : {
66 64 : }
67 :
68 320 : void PageObjectPainter::PaintPageObject (
69 : OutputDevice& rDevice,
70 : const model::SharedPageDescriptor& rpDescriptor)
71 : {
72 320 : if (UpdatePageObjectLayouter())
73 : {
74 320 : 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 320 : const AntialiasingFlags nSavedAntialiasingMode (rDevice.GetAntialiasing());
78 320 : rDevice.SetAntialiasing(nSavedAntialiasingMode & ~AntialiasingFlags::EnableB2dDraw);
79 :
80 320 : PaintBackground(pPageObjectLayouter, rDevice, rpDescriptor);
81 320 : PaintPreview(pPageObjectLayouter, rDevice, rpDescriptor);
82 320 : PaintPageNumber(pPageObjectLayouter, rDevice, rpDescriptor);
83 320 : PaintTransitionEffect(pPageObjectLayouter, rDevice, rpDescriptor);
84 320 : if (rpDescriptor->GetPage()->hasAnimationNode())
85 0 : PaintCustomAnimationEffect(pPageObjectLayouter, rDevice, rpDescriptor);
86 320 : rDevice.SetAntialiasing(nSavedAntialiasingMode);
87 : }
88 320 : }
89 :
90 320 : bool PageObjectPainter::UpdatePageObjectLayouter()
91 : {
92 : // The page object layouter is quite volatile. It may have been replaced
93 : // since the last call. Update it now.
94 320 : PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
95 320 : if ( ! pPageObjectLayouter)
96 : {
97 : OSL_FAIL("no page object layouter");
98 0 : return false;
99 : }
100 :
101 320 : 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 320 : void PageObjectPainter::PaintBackground (
110 : PageObjectLayouter *pPageObjectLayouter,
111 : OutputDevice& rDevice,
112 : const model::SharedPageDescriptor& rpDescriptor) const
113 : {
114 320 : PaintBackgroundDetail(pPageObjectLayouter, rDevice, rpDescriptor);
115 :
116 : // Fill the interior of the preview area with the default background
117 : // color of the page.
118 320 : SdPage* pPage = rpDescriptor->GetPage();
119 320 : if (pPage != NULL)
120 : {
121 320 : rDevice.SetFillColor(pPage->GetPageBackgroundColor(NULL));
122 320 : rDevice.SetLineColor(pPage->GetPageBackgroundColor(NULL));
123 : const Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
124 : rpDescriptor,
125 : PageObjectLayouter::Preview,
126 320 : PageObjectLayouter::ModelCoordinateSystem));
127 320 : rDevice.DrawRect(aPreviewBox);
128 : }
129 320 : }
130 :
131 320 : 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 320 : PageObjectLayouter::ModelCoordinateSystem));
140 :
141 320 : if (mpCache != 0)
142 : {
143 320 : const SdrPage* pPage = rpDescriptor->GetPage();
144 320 : mpCache->SetPreciousFlag(pPage, true);
145 :
146 320 : const Bitmap aPreview (GetPreviewBitmap(rpDescriptor, &rDevice));
147 320 : if ( ! aPreview.IsEmpty())
148 : {
149 204 : if (aPreview.GetSizePixel() != aBox.GetSize())
150 2 : rDevice.DrawBitmap(aBox.TopLeft(), aBox.GetSize(), aPreview);
151 : else
152 202 : rDevice.DrawBitmap(aBox.TopLeft(), aPreview);
153 320 : }
154 : }
155 320 : }
156 :
157 0 : Bitmap PageObjectPainter::CreateMarkedPreview (
158 : const Size& rSize,
159 : const Bitmap& rPreview,
160 : const BitmapEx& rOverlay,
161 : const OutputDevice* pReferenceDevice)
162 : {
163 0 : ScopedVclPtr<VirtualDevice> pDevice;
164 0 : if (pReferenceDevice != NULL)
165 0 : pDevice.reset(VclPtr<VirtualDevice>::Create(*pReferenceDevice));
166 : else
167 0 : pDevice.reset(VclPtr<VirtualDevice>::Create());
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 (long nX=0; nX<rSize.Width(); nX+=nIconWidth)
178 0 : for (long 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 320 : Bitmap PageObjectPainter::GetPreviewBitmap (
185 : const model::SharedPageDescriptor& rpDescriptor,
186 : const OutputDevice* pReferenceDevice) const
187 : {
188 320 : const SdrPage* pPage = rpDescriptor->GetPage();
189 320 : const bool bIsExcluded (rpDescriptor->HasState(model::PageDescriptor::ST_Excluded));
190 :
191 320 : 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 320 : return mpCache->GetPreviewBitmap(pPage,false);
214 : }
215 : }
216 :
217 320 : 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 320 : PageObjectLayouter::ModelCoordinateSystem));
226 :
227 : // Determine the color of the page number.
228 320 : Color aPageNumberColor (mpTheme->GetColor(Theme::Color_PageNumberDefault));
229 640 : if (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ||
230 320 : 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 280 : aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHover));
236 : }
237 : else
238 : {
239 40 : const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
240 40 : 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 40 : 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 40 : const sal_Int32 nFontLuminance (aPageNumberColor.GetLuminance());
251 40 : 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 320 : const sal_Int32 nPageNumber ((rpDescriptor->GetPage()->GetPageNum() - 1) / 2 + 1);
264 320 : const OUString sPageNumber(OUString::number(nPageNumber));
265 320 : rDevice.SetFont(*mpPageNumberFont);
266 320 : rDevice.SetTextColor(aPageNumberColor);
267 320 : rDevice.DrawText(aBox, sPageNumber, DrawTextFlags::Right | DrawTextFlags::VCenter);
268 320 : }
269 :
270 320 : void PageObjectPainter::PaintTransitionEffect (
271 : PageObjectLayouter *pPageObjectLayouter,
272 : OutputDevice& rDevice,
273 : const model::SharedPageDescriptor& rpDescriptor)
274 : {
275 320 : const SdPage* pPage = rpDescriptor->GetPage();
276 320 : 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 320 : }
288 :
289 0 : void PageObjectPainter::PaintCustomAnimationEffect (
290 : PageObjectLayouter *pPageObjectLayouter,
291 : OutputDevice& rDevice,
292 : const model::SharedPageDescriptor& rpDescriptor)
293 : {
294 0 : SdPage* pPage = rpDescriptor->GetPage();
295 0 : boost::shared_ptr< MainSequence > aMainSequence = pPage->getMainSequence();
296 0 : EffectSequence::iterator aIter = aMainSequence->getBegin();
297 0 : EffectSequence::iterator aEnd = aMainSequence->getEnd();
298 0 : 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 0 : }
308 0 : }
309 :
310 320 : 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 320 : (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) ? Selected : None)
318 320 : | (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ? MouseOver : None)
319 320 : | (rpDescriptor->HasState(model::PageDescriptor::ST_Focused) ? Focused : None);
320 :
321 : bool bHasFocusBorder;
322 : Theme::GradientColorType eColorType;
323 :
324 320 : 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 280 : eColorType = Theme::Gradient_SelectedPage;
353 280 : bHasFocusBorder = false;
354 280 : 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 40 : eColorType = Theme::Gradient_NormalPage;
364 40 : bHasFocusBorder = false;
365 40 : break;
366 : }
367 :
368 : const Rectangle aFocusSize (pPageObjectLayouter->GetBoundingBox(
369 : rpDescriptor,
370 : PageObjectLayouter::FocusIndicator,
371 320 : PageObjectLayouter::ModelCoordinateSystem));
372 :
373 : const Rectangle aPageObjectBox (pPageObjectLayouter->GetBoundingBox(
374 : rpDescriptor,
375 : PageObjectLayouter::PageObject,
376 320 : PageObjectLayouter::ModelCoordinateSystem));
377 :
378 : // Fill the background with the background color of the slide sorter.
379 320 : const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
380 320 : rDevice.SetFillColor(aBackgroundColor);
381 320 : rDevice.SetLineColor(aBackgroundColor);
382 320 : 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 320 : const Color aTopColor(mpTheme->GetGradientColor(eColorType, Theme::Fill1));
387 320 : const Color aBottomColor(mpTheme->GetGradientColor(eColorType, Theme::Fill2));
388 320 : if (aTopColor != aBottomColor)
389 : {
390 280 : const sal_Int32 nHeight (aPageObjectBox.GetHeight());
391 280 : const sal_Int32 nDefaultConstantSize(nHeight/4);
392 280 : 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 280 : (nHeight - nMinimalGradientSize)/2)));
399 280 : const sal_Int32 nY2 (nHeight-nY1);
400 280 : const sal_Int32 nTop (aPageObjectBox.Top());
401 44212 : for (sal_Int32 nY=0; nY<nHeight; ++nY)
402 : {
403 43932 : if (nY<=nY1)
404 11168 : rDevice.SetLineColor(aTopColor);
405 32764 : else if (nY>=nY2)
406 10888 : rDevice.SetLineColor(aBottomColor);
407 : else
408 : {
409 21876 : Color aColor (aTopColor);
410 21876 : aColor.Merge(aBottomColor, 255 * (nY2-nY) / (nY2-nY1));
411 21876 : rDevice.SetLineColor(aColor);
412 : }
413 : rDevice.DrawLine(
414 43932 : Point(aPageObjectBox.Left(), nY+nTop),
415 87864 : Point(aPageObjectBox.Right(), nY+nTop));
416 : }
417 : }
418 : else
419 : {
420 40 : rDevice.SetFillColor(aTopColor);
421 40 : rDevice.DrawRect(aPageObjectBox);
422 : }
423 :
424 : // Paint the simple border and, for some backgrounds, the focus border.
425 320 : if (bHasFocusBorder)
426 0 : mpFocusBorderPainter->PaintFrame(rDevice, aPageObjectBox);
427 : else
428 320 : 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 320 : PageObjectLayouter::ModelCoordinateSystem));
436 320 : Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1);
437 320 : mpShadowPainter->PaintFrame(rDevice, aFrameBox);
438 320 : }
439 :
440 320 : void PageObjectPainter::PaintBorder (
441 : OutputDevice& rDevice,
442 : const Theme::GradientColorType eColorType,
443 : const Rectangle& rBox) const
444 : {
445 320 : rDevice.SetFillColor();
446 320 : const sal_Int32 nBorderWidth (1);
447 640 : for (int nIndex=0; nIndex<nBorderWidth; ++nIndex)
448 : {
449 320 : const int nDelta (nIndex);
450 320 : rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border2));
451 : rDevice.DrawLine(
452 640 : Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
453 960 : Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta));
454 : rDevice.DrawLine(
455 640 : Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta),
456 960 : Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta));
457 : rDevice.DrawLine(
458 640 : Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta),
459 960 : Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
460 :
461 320 : rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border1));
462 : rDevice.DrawLine(
463 640 : Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
464 960 : Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
465 : }
466 320 : }
467 :
468 66 : } } } // end of namespace sd::slidesorter::view
469 :
470 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|