1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "view/SlsPageObjectPainter.hxx"
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"
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"
39 using namespace ::drawinglayer::primitive2d
;
41 namespace sd
{ namespace slidesorter
{ namespace view
{
43 //===== PageObjectPainter =====================================================
45 PageObjectPainter::PageObjectPainter (
46 const SlideSorter
& rSlideSorter
)
47 : mrLayouter(rSlideSorter
.GetView().GetLayouter()),
48 mpCache(rSlideSorter
.GetView().GetPreviewCache()),
49 mpProperties(rSlideSorter
.GetProperties()),
50 mpTheme(rSlideSorter
.GetTheme()),
51 mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber
, *rSlideSorter
.GetContentWindow())),
52 mpShadowPainter(new FramePainter(mpTheme
->GetIcon(Theme::Icon_RawShadow
))),
53 mpFocusBorderPainter(new FramePainter(mpTheme
->GetIcon(Theme::Icon_FocusBorder
)))
55 // Replace the color (not the alpha values) in the focus border with a
56 // color derived from the current selection color.
57 Color
aColor (mpTheme
->GetColor(Theme::Color_Selection
));
58 sal_uInt16 nHue
, nSat
, nBri
;
59 aColor
.RGBtoHSB(nHue
, nSat
, nBri
);
60 aColor
= Color::HSBtoRGB(nHue
, 28, 65);
61 mpFocusBorderPainter
->AdaptColor(aColor
, true);
64 PageObjectPainter::~PageObjectPainter()
68 void PageObjectPainter::PaintPageObject (
69 OutputDevice
& rDevice
,
70 const model::SharedPageDescriptor
& rpDescriptor
)
72 if (UpdatePageObjectLayouter())
74 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 const AntialiasingFlags
nSavedAntialiasingMode (rDevice
.GetAntialiasing());
78 rDevice
.SetAntialiasing(nSavedAntialiasingMode
& ~AntialiasingFlags::EnableB2dDraw
);
80 PaintBackground(pPageObjectLayouter
, rDevice
, rpDescriptor
);
81 PaintPreview(pPageObjectLayouter
, rDevice
, rpDescriptor
);
82 PaintPageNumber(pPageObjectLayouter
, rDevice
, rpDescriptor
);
83 PaintTransitionEffect(pPageObjectLayouter
, rDevice
, rpDescriptor
);
84 if (rpDescriptor
->GetPage()->hasAnimationNode())
85 PaintCustomAnimationEffect(pPageObjectLayouter
, rDevice
, rpDescriptor
);
86 rDevice
.SetAntialiasing(nSavedAntialiasingMode
);
90 bool PageObjectPainter::UpdatePageObjectLayouter()
92 // The page object layouter is quite volatile. It may have been replaced
93 // since the last call. Update it now.
94 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
95 if ( ! pPageObjectLayouter
)
97 OSL_FAIL("no page object layouter");
104 void PageObjectPainter::SetTheme (const ::boost::shared_ptr
<view::Theme
>& rpTheme
)
109 void PageObjectPainter::PaintBackground (
110 PageObjectLayouter
*pPageObjectLayouter
,
111 OutputDevice
& rDevice
,
112 const model::SharedPageDescriptor
& rpDescriptor
) const
114 PaintBackgroundDetail(pPageObjectLayouter
, rDevice
, rpDescriptor
);
116 // Fill the interior of the preview area with the default background
117 // color of the page.
118 SdPage
* pPage
= rpDescriptor
->GetPage();
121 rDevice
.SetFillColor(pPage
->GetPageBackgroundColor(NULL
));
122 rDevice
.SetLineColor(pPage
->GetPageBackgroundColor(NULL
));
123 const Rectangle
aPreviewBox (pPageObjectLayouter
->GetBoundingBox(
125 PageObjectLayouter::Preview
,
126 PageObjectLayouter::ModelCoordinateSystem
));
127 rDevice
.DrawRect(aPreviewBox
);
131 void PageObjectPainter::PaintPreview (
132 PageObjectLayouter
*pPageObjectLayouter
,
133 OutputDevice
& rDevice
,
134 const model::SharedPageDescriptor
& rpDescriptor
) const
136 const Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
138 PageObjectLayouter::Preview
,
139 PageObjectLayouter::ModelCoordinateSystem
));
143 const SdrPage
* pPage
= rpDescriptor
->GetPage();
144 mpCache
->SetPreciousFlag(pPage
, true);
146 const Bitmap
aPreview (GetPreviewBitmap(rpDescriptor
, &rDevice
));
147 if ( ! aPreview
.IsEmpty())
149 if (aPreview
.GetSizePixel() != aBox
.GetSize())
150 rDevice
.DrawBitmap(aBox
.TopLeft(), aBox
.GetSize(), aPreview
);
152 rDevice
.DrawBitmap(aBox
.TopLeft(), aPreview
);
157 Bitmap
PageObjectPainter::CreateMarkedPreview (
159 const Bitmap
& rPreview
,
160 const BitmapEx
& rOverlay
,
161 const OutputDevice
* pReferenceDevice
)
163 ScopedVclPtr
<VirtualDevice
> pDevice
;
164 if (pReferenceDevice
!= NULL
)
165 pDevice
.reset(VclPtr
<VirtualDevice
>::Create(*pReferenceDevice
));
167 pDevice
.reset(VclPtr
<VirtualDevice
>::Create());
168 pDevice
->SetOutputSizePixel(rSize
);
170 pDevice
->DrawBitmap(Point(0,0), rSize
, rPreview
);
172 // Paint bitmap tiled over the preview to mark it as excluded.
173 const sal_Int32
nIconWidth (rOverlay
.GetSizePixel().Width());
174 const sal_Int32
nIconHeight (rOverlay
.GetSizePixel().Height());
175 if (nIconWidth
>0 && nIconHeight
>0)
177 for (sal_Int32 nX
=0; nX
<rSize
.Width(); nX
+=nIconWidth
)
178 for (sal_Int32 nY
=0; nY
<rSize
.Height(); nY
+=nIconHeight
)
179 pDevice
->DrawBitmapEx(Point(nX
,nY
), rOverlay
);
181 return pDevice
->GetBitmap(Point(0,0), rSize
);
184 Bitmap
PageObjectPainter::GetPreviewBitmap (
185 const model::SharedPageDescriptor
& rpDescriptor
,
186 const OutputDevice
* pReferenceDevice
) const
188 const SdrPage
* pPage
= rpDescriptor
->GetPage();
189 const bool bIsExcluded (rpDescriptor
->HasState(model::PageDescriptor::ST_Excluded
));
193 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
195 Bitmap
aMarkedPreview (mpCache
->GetMarkedPreviewBitmap(pPage
,false));
196 const Rectangle
aPreviewBox (pPageObjectLayouter
->GetBoundingBox(
198 PageObjectLayouter::Preview
,
199 PageObjectLayouter::ModelCoordinateSystem
));
200 if (aMarkedPreview
.IsEmpty() || aMarkedPreview
.GetSizePixel()!=aPreviewBox
.GetSize())
202 aMarkedPreview
= CreateMarkedPreview(
203 aPreviewBox
.GetSize(),
204 mpCache
->GetPreviewBitmap(pPage
,true),
205 mpTheme
->GetIcon(Theme::Icon_HideSlideOverlay
),
207 mpCache
->SetMarkedPreviewBitmap(pPage
, aMarkedPreview
);
209 return aMarkedPreview
;
213 return mpCache
->GetPreviewBitmap(pPage
,false);
217 void PageObjectPainter::PaintPageNumber (
218 PageObjectLayouter
*pPageObjectLayouter
,
219 OutputDevice
& rDevice
,
220 const model::SharedPageDescriptor
& rpDescriptor
) const
222 const Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
224 PageObjectLayouter::PageNumber
,
225 PageObjectLayouter::ModelCoordinateSystem
));
227 // Determine the color of the page number.
228 Color
aPageNumberColor (mpTheme
->GetColor(Theme::Color_PageNumberDefault
));
229 if (rpDescriptor
->HasState(model::PageDescriptor::ST_MouseOver
) ||
230 rpDescriptor
->HasState(model::PageDescriptor::ST_Selected
))
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 aPageNumberColor
= Color(mpTheme
->GetColor(Theme::Color_PageNumberHover
));
239 const Color
aBackgroundColor (mpTheme
->GetColor(Theme::Color_Background
));
240 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 if (nBackgroundLuminance
== 0)
244 aPageNumberColor
= Color(mpTheme
->GetColor(Theme::Color_PageNumberHighContrast
));
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 const sal_Int32
nFontLuminance (aPageNumberColor
.GetLuminance());
251 if (abs(nBackgroundLuminance
- nFontLuminance
) < 60)
253 if (nBackgroundLuminance
> nFontLuminance
-30)
254 aPageNumberColor
= Color(mpTheme
->GetColor(Theme::Color_PageNumberBrightBackground
));
256 aPageNumberColor
= Color(mpTheme
->GetColor(Theme::Color_PageNumberDarkBackground
));
261 // Paint the page number.
262 OSL_ASSERT(rpDescriptor
->GetPage()!=NULL
);
263 const sal_Int32
nPageNumber ((rpDescriptor
->GetPage()->GetPageNum() - 1) / 2 + 1);
264 const OUString
sPageNumber(OUString::number(nPageNumber
));
265 rDevice
.SetFont(*mpPageNumberFont
);
266 rDevice
.SetTextColor(aPageNumberColor
);
267 rDevice
.DrawText(aBox
, sPageNumber
, DrawTextFlags::Right
| DrawTextFlags::VCenter
);
270 void PageObjectPainter::PaintTransitionEffect (
271 PageObjectLayouter
*pPageObjectLayouter
,
272 OutputDevice
& rDevice
,
273 const model::SharedPageDescriptor
& rpDescriptor
)
275 const SdPage
* pPage
= rpDescriptor
->GetPage();
276 if (pPage
!=NULL
&& pPage
->getTransitionType() > 0)
278 const Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
280 PageObjectLayouter::TransitionEffectIndicator
,
281 PageObjectLayouter::ModelCoordinateSystem
));
283 rDevice
.DrawBitmapEx(
285 pPageObjectLayouter
->GetTransitionEffectIcon().GetBitmapEx());
289 void PageObjectPainter::PaintCustomAnimationEffect (
290 PageObjectLayouter
*pPageObjectLayouter
,
291 OutputDevice
& rDevice
,
292 const model::SharedPageDescriptor
& rpDescriptor
)
294 SdPage
* pPage
= rpDescriptor
->GetPage();
295 boost::shared_ptr
< MainSequence
> aMainSequence
= pPage
->getMainSequence();
296 EffectSequence::iterator aIter
= aMainSequence
->getBegin();
297 EffectSequence::iterator aEnd
= aMainSequence
->getEnd();
300 const Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
302 PageObjectLayouter::CustomAnimationEffectIndicator
,
303 PageObjectLayouter::ModelCoordinateSystem
));
304 rDevice
.DrawBitmapEx(
306 pPageObjectLayouter
->GetCustomAnimationEffectIcon().GetBitmapEx());
310 void PageObjectPainter::PaintBackgroundDetail (
311 PageObjectLayouter
*pPageObjectLayouter
,
312 OutputDevice
& rDevice
,
313 const model::SharedPageDescriptor
& rpDescriptor
) const
315 enum State
{ None
= 0x00, Selected
= 0x01, MouseOver
= 0x02, Focused
= 0x04 };
317 (rpDescriptor
->HasState(model::PageDescriptor::ST_Selected
) ? Selected
: None
)
318 | (rpDescriptor
->HasState(model::PageDescriptor::ST_MouseOver
) ? MouseOver
: None
)
319 | (rpDescriptor
->HasState(model::PageDescriptor::ST_Focused
) ? Focused
: None
);
321 bool bHasFocusBorder
;
322 Theme::GradientColorType eColorType
;
326 case MouseOver
| Selected
| Focused
:
327 eColorType
= Theme::Gradient_MouseOverSelectedAndFocusedPage
;
328 bHasFocusBorder
= true;
331 case MouseOver
| Selected
:
332 eColorType
= Theme::Gradient_MouseOverSelected
;
333 bHasFocusBorder
= false;
337 eColorType
= Theme::Gradient_MouseOverPage
;
338 bHasFocusBorder
= false;
341 case MouseOver
| Focused
:
342 eColorType
= Theme::Gradient_MouseOverPage
;
343 bHasFocusBorder
= true;
346 case Selected
| Focused
:
347 eColorType
= Theme::Gradient_SelectedAndFocusedPage
;
348 bHasFocusBorder
= true;
352 eColorType
= Theme::Gradient_SelectedPage
;
353 bHasFocusBorder
= false;
357 eColorType
= Theme::Gradient_FocusedPage
;
358 bHasFocusBorder
= true;
363 eColorType
= Theme::Gradient_NormalPage
;
364 bHasFocusBorder
= false;
368 const Rectangle
aFocusSize (pPageObjectLayouter
->GetBoundingBox(
370 PageObjectLayouter::FocusIndicator
,
371 PageObjectLayouter::ModelCoordinateSystem
));
373 const Rectangle
aPageObjectBox (pPageObjectLayouter
->GetBoundingBox(
375 PageObjectLayouter::PageObject
,
376 PageObjectLayouter::ModelCoordinateSystem
));
378 // Fill the background with the background color of the slide sorter.
379 const Color
aBackgroundColor (mpTheme
->GetColor(Theme::Color_Background
));
380 rDevice
.SetFillColor(aBackgroundColor
);
381 rDevice
.SetLineColor(aBackgroundColor
);
382 rDevice
.DrawRect(aFocusSize
);
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 const Color
aTopColor(mpTheme
->GetGradientColor(eColorType
, Theme::Fill1
));
387 const Color
aBottomColor(mpTheme
->GetGradientColor(eColorType
, Theme::Fill2
));
388 if (aTopColor
!= aBottomColor
)
390 const sal_Int32
nHeight (aPageObjectBox
.GetHeight());
391 const sal_Int32
nDefaultConstantSize(nHeight
/4);
392 const sal_Int32
nMinimalGradientSize(40);
393 const sal_Int32
nY1 (
394 ::std::max
<sal_Int32
>(
396 ::std::min
<sal_Int32
>(
397 nDefaultConstantSize
,
398 (nHeight
- nMinimalGradientSize
)/2)));
399 const sal_Int32
nY2 (nHeight
-nY1
);
400 const sal_Int32
nTop (aPageObjectBox
.Top());
401 for (sal_Int32 nY
=0; nY
<nHeight
; ++nY
)
404 rDevice
.SetLineColor(aTopColor
);
406 rDevice
.SetLineColor(aBottomColor
);
409 Color
aColor (aTopColor
);
410 aColor
.Merge(aBottomColor
, 255 * (nY2
-nY
) / (nY2
-nY1
));
411 rDevice
.SetLineColor(aColor
);
414 Point(aPageObjectBox
.Left(), nY
+nTop
),
415 Point(aPageObjectBox
.Right(), nY
+nTop
));
420 rDevice
.SetFillColor(aTopColor
);
421 rDevice
.DrawRect(aPageObjectBox
);
424 // Paint the simple border and, for some backgrounds, the focus border.
426 mpFocusBorderPainter
->PaintFrame(rDevice
, aPageObjectBox
);
428 PaintBorder(rDevice
, eColorType
, aPageObjectBox
);
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(
434 PageObjectLayouter::Preview
,
435 PageObjectLayouter::ModelCoordinateSystem
));
436 Rectangle
aFrameBox (aBox
.Left()-1,aBox
.Top()-1,aBox
.Right()+1,aBox
.Bottom()+1);
437 mpShadowPainter
->PaintFrame(rDevice
, aFrameBox
);
440 void PageObjectPainter::PaintBorder (
441 OutputDevice
& rDevice
,
442 const Theme::GradientColorType eColorType
,
443 const Rectangle
& rBox
) const
445 rDevice
.SetFillColor();
446 const sal_Int32
nBorderWidth (1);
447 for (int nIndex
=0; nIndex
<nBorderWidth
; ++nIndex
)
449 const int nDelta (nIndex
);
450 rDevice
.SetLineColor(mpTheme
->GetGradientColor(eColorType
, Theme::Border2
));
452 Point(rBox
.Left()-nDelta
, rBox
.Top()-nDelta
),
453 Point(rBox
.Left()-nDelta
, rBox
.Bottom()+nDelta
));
455 Point(rBox
.Left()-nDelta
, rBox
.Bottom()+nDelta
),
456 Point(rBox
.Right()+nDelta
, rBox
.Bottom()+nDelta
));
458 Point(rBox
.Right()+nDelta
, rBox
.Bottom()+nDelta
),
459 Point(rBox
.Right()+nDelta
, rBox
.Top()-nDelta
));
461 rDevice
.SetLineColor(mpTheme
->GetGradientColor(eColorType
, Theme::Border1
));
463 Point(rBox
.Left()-nDelta
, rBox
.Top()-nDelta
),
464 Point(rBox
.Right()+nDelta
, rBox
.Top()-nDelta
));
468 } } } // end of namespace sd::slidesorter::view
470 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */