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 <SlideSorter.hxx>
28 #include "SlsFramePainter.hxx"
29 #include <cache/SlsPageCache.hxx>
32 #include <vcl/virdev.hxx>
33 #include <CustomAnimationEffect.hxx>
36 using namespace ::drawinglayer::primitive2d
;
38 namespace sd
{ namespace slidesorter
{ namespace view
{
40 //===== PageObjectPainter =====================================================
42 PageObjectPainter::PageObjectPainter (
43 const SlideSorter
& rSlideSorter
)
44 : mrLayouter(rSlideSorter
.GetView().GetLayouter()),
45 mpCache(rSlideSorter
.GetView().GetPreviewCache()),
46 mpTheme(rSlideSorter
.GetTheme()),
47 mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber
, *rSlideSorter
.GetContentWindow())),
48 mpShadowPainter(new FramePainter(mpTheme
->GetIcon(Theme::Icon_RawShadow
))),
49 mpFocusBorderPainter(new FramePainter(mpTheme
->GetIcon(Theme::Icon_FocusBorder
)))
51 // Replace the color (not the alpha values) in the focus border with a
52 // color derived from the current selection color.
53 Color
aColor (mpTheme
->GetColor(Theme::Color_Selection
));
54 sal_uInt16 nHue
, nSat
, nBri
;
55 aColor
.RGBtoHSB(nHue
, nSat
, nBri
);
56 aColor
= Color::HSBtoRGB(nHue
, 28, 65);
57 mpFocusBorderPainter
->AdaptColor(aColor
);
60 PageObjectPainter::~PageObjectPainter()
64 void PageObjectPainter::PaintPageObject (
65 OutputDevice
& rDevice
,
66 const model::SharedPageDescriptor
& rpDescriptor
)
68 if (!UpdatePageObjectLayouter())
71 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
72 // Turn off antialiasing to avoid the bitmaps from being
73 // shifted by fractions of a pixel and thus show blurry edges.
74 const AntialiasingFlags
nSavedAntialiasingMode (rDevice
.GetAntialiasing());
75 rDevice
.SetAntialiasing(nSavedAntialiasingMode
& ~AntialiasingFlags::EnableB2dDraw
);
77 PaintBackground(pPageObjectLayouter
, rDevice
, rpDescriptor
);
78 PaintPreview(pPageObjectLayouter
, rDevice
, rpDescriptor
);
79 PaintPageNumber(pPageObjectLayouter
, rDevice
, rpDescriptor
);
80 PaintTransitionEffect(pPageObjectLayouter
, rDevice
, rpDescriptor
);
81 if (rpDescriptor
->GetPage()->hasAnimationNode())
82 PaintCustomAnimationEffect(pPageObjectLayouter
, rDevice
, rpDescriptor
);
83 rDevice
.SetAntialiasing(nSavedAntialiasingMode
);
86 bool PageObjectPainter::UpdatePageObjectLayouter()
88 // The page object layouter is quite volatile. It may have been replaced
89 // since the last call. Update it now.
90 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
91 if ( ! pPageObjectLayouter
)
93 OSL_FAIL("no page object layouter");
100 void PageObjectPainter::SetTheme (const std::shared_ptr
<view::Theme
>& rpTheme
)
105 void PageObjectPainter::PaintBackground (
106 PageObjectLayouter
*pPageObjectLayouter
,
107 OutputDevice
& rDevice
,
108 const model::SharedPageDescriptor
& rpDescriptor
) const
110 PaintBackgroundDetail(pPageObjectLayouter
, rDevice
, rpDescriptor
);
112 // Fill the interior of the preview area with the default background
113 // color of the page.
114 SdPage
* pPage
= rpDescriptor
->GetPage();
115 if (pPage
!= nullptr)
117 rDevice
.SetFillColor(pPage
->GetPageBackgroundColor(nullptr));
118 rDevice
.SetLineColor(pPage
->GetPageBackgroundColor(nullptr));
119 const ::tools::Rectangle
aPreviewBox (pPageObjectLayouter
->GetBoundingBox(
121 PageObjectLayouter::Part::Preview
,
122 PageObjectLayouter::ModelCoordinateSystem
));
123 rDevice
.DrawRect(aPreviewBox
);
127 void PageObjectPainter::PaintPreview (
128 PageObjectLayouter
*pPageObjectLayouter
,
129 OutputDevice
& rDevice
,
130 const model::SharedPageDescriptor
& rpDescriptor
) const
132 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
134 PageObjectLayouter::Part::Preview
,
135 PageObjectLayouter::ModelCoordinateSystem
));
137 if (mpCache
== nullptr)
140 const SdrPage
* pPage
= rpDescriptor
->GetPage();
141 mpCache
->SetPreciousFlag(pPage
, true);
143 const BitmapEx
aPreview (GetPreviewBitmap(rpDescriptor
, &rDevice
));
144 if ( ! aPreview
.IsEmpty())
146 if (aPreview
.GetSizePixel() != aBox
.GetSize())
147 rDevice
.DrawBitmapEx(aBox
.TopLeft(), aBox
.GetSize(), aPreview
);
149 rDevice
.DrawBitmapEx(aBox
.TopLeft(), aPreview
);
153 BitmapEx
PageObjectPainter::CreateMarkedPreview (
155 const BitmapEx
& rPreview
,
156 const BitmapEx
& rOverlay
,
157 const OutputDevice
* pReferenceDevice
)
159 ScopedVclPtr
<VirtualDevice
> pDevice
;
160 if (pReferenceDevice
!= nullptr)
161 pDevice
.disposeAndReset(VclPtr
<VirtualDevice
>::Create(*pReferenceDevice
));
163 pDevice
.disposeAndReset(VclPtr
<VirtualDevice
>::Create());
164 pDevice
->SetOutputSizePixel(rSize
);
166 pDevice
->DrawBitmapEx(Point(0,0), rSize
, rPreview
);
168 // Paint bitmap tiled over the preview to mark it as excluded.
169 const sal_Int32
nIconWidth (rOverlay
.GetSizePixel().Width());
170 const sal_Int32
nIconHeight (rOverlay
.GetSizePixel().Height());
171 if (nIconWidth
>0 && nIconHeight
>0)
173 for (long nX
=0; nX
<rSize
.Width(); nX
+=nIconWidth
)
174 for (long nY
=0; nY
<rSize
.Height(); nY
+=nIconHeight
)
175 pDevice
->DrawBitmapEx(Point(nX
,nY
), rOverlay
);
177 return pDevice
->GetBitmapEx(Point(0,0), rSize
);
180 BitmapEx
PageObjectPainter::GetPreviewBitmap (
181 const model::SharedPageDescriptor
& rpDescriptor
,
182 const OutputDevice
* pReferenceDevice
) const
184 const SdrPage
* pPage
= rpDescriptor
->GetPage();
185 const bool bIsExcluded (rpDescriptor
->HasState(model::PageDescriptor::ST_Excluded
));
189 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
191 BitmapEx
aMarkedPreview (mpCache
->GetMarkedPreviewBitmap(pPage
));
192 const ::tools::Rectangle
aPreviewBox (pPageObjectLayouter
->GetBoundingBox(
194 PageObjectLayouter::Part::Preview
,
195 PageObjectLayouter::ModelCoordinateSystem
));
196 if (aMarkedPreview
.IsEmpty() || aMarkedPreview
.GetSizePixel()!=aPreviewBox
.GetSize())
198 aMarkedPreview
= CreateMarkedPreview(
199 aPreviewBox
.GetSize(),
200 mpCache
->GetPreviewBitmap(pPage
,true),
201 mpTheme
->GetIcon(Theme::Icon_HideSlideOverlay
),
203 mpCache
->SetMarkedPreviewBitmap(pPage
, aMarkedPreview
);
205 return aMarkedPreview
;
209 return mpCache
->GetPreviewBitmap(pPage
,false);
213 void PageObjectPainter::PaintPageNumber (
214 PageObjectLayouter
*pPageObjectLayouter
,
215 OutputDevice
& rDevice
,
216 const model::SharedPageDescriptor
& rpDescriptor
) const
218 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
220 PageObjectLayouter::Part::PageNumber
,
221 PageObjectLayouter::ModelCoordinateSystem
));
223 // Determine the color of the page number.
224 Color
aPageNumberColor (mpTheme
->GetColor(Theme::Color_PageNumberDefault
));
225 if (rpDescriptor
->HasState(model::PageDescriptor::ST_MouseOver
) ||
226 rpDescriptor
->HasState(model::PageDescriptor::ST_Selected
))
228 // Page number is painted on background for hover or selection or
229 // both. Each of these background colors has a predefined luminance
230 // which is compatible with the PageNumberHover color.
231 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberHover
);
235 const Color
aBackgroundColor (mpTheme
->GetColor(Theme::Color_Background
));
236 const sal_Int32
nBackgroundLuminance (aBackgroundColor
.GetLuminance());
237 // When the background color is black then this is interpreted as
238 // high contrast mode and the font color is set to white.
239 if (nBackgroundLuminance
== 0)
240 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberHighContrast
);
243 // Compare luminance of default page number color and background
244 // color. When the two are similar then use a darker
245 // (preferred) or brighter font color.
246 const sal_Int32
nFontLuminance (aPageNumberColor
.GetLuminance());
247 if (abs(nBackgroundLuminance
- nFontLuminance
) < 60)
249 if (nBackgroundLuminance
> nFontLuminance
-30)
250 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberBrightBackground
);
252 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberDarkBackground
);
257 // Paint the page number.
258 OSL_ASSERT(rpDescriptor
->GetPage()!=nullptr);
259 const sal_Int32
nPageNumber ((rpDescriptor
->GetPage()->GetPageNum() - 1) / 2 + 1);
260 const OUString
sPageNumber(OUString::number(nPageNumber
));
261 rDevice
.SetFont(*mpPageNumberFont
);
262 rDevice
.SetTextColor(aPageNumberColor
);
263 rDevice
.DrawText(aBox
, sPageNumber
, DrawTextFlags::Right
| DrawTextFlags::VCenter
);
266 void PageObjectPainter::PaintTransitionEffect (
267 PageObjectLayouter
*pPageObjectLayouter
,
268 OutputDevice
& rDevice
,
269 const model::SharedPageDescriptor
& rpDescriptor
)
271 const SdPage
* pPage
= rpDescriptor
->GetPage();
272 if (pPage
!=nullptr && pPage
->getTransitionType() > 0)
274 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
276 PageObjectLayouter::Part::TransitionEffectIndicator
,
277 PageObjectLayouter::ModelCoordinateSystem
));
279 rDevice
.DrawBitmapEx(
281 pPageObjectLayouter
->GetTransitionEffectIcon().GetBitmapEx());
285 void PageObjectPainter::PaintCustomAnimationEffect (
286 PageObjectLayouter
*pPageObjectLayouter
,
287 OutputDevice
& rDevice
,
288 const model::SharedPageDescriptor
& rpDescriptor
)
290 SdPage
* pPage
= rpDescriptor
->GetPage();
291 std::shared_ptr
< MainSequence
> aMainSequence
= pPage
->getMainSequence();
292 EffectSequence::iterator aIter
= aMainSequence
->getBegin();
293 EffectSequence::iterator aEnd
= aMainSequence
->getEnd();
296 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
298 PageObjectLayouter::Part::CustomAnimationEffectIndicator
,
299 PageObjectLayouter::ModelCoordinateSystem
));
300 rDevice
.DrawBitmapEx(
302 pPageObjectLayouter
->GetCustomAnimationEffectIcon().GetBitmapEx());
306 void PageObjectPainter::PaintBackgroundDetail (
307 PageObjectLayouter
*pPageObjectLayouter
,
308 OutputDevice
& rDevice
,
309 const model::SharedPageDescriptor
& rpDescriptor
) const
311 enum State
{ None
= 0x00, Selected
= 0x01, MouseOver
= 0x02, Focused
= 0x04 };
313 (rpDescriptor
->HasState(model::PageDescriptor::ST_Selected
) ? Selected
: None
)
314 | (rpDescriptor
->HasState(model::PageDescriptor::ST_MouseOver
) ? MouseOver
: None
)
315 | (rpDescriptor
->HasState(model::PageDescriptor::ST_Focused
) ? Focused
: None
);
317 bool bHasFocusBorder
;
318 Theme::GradientColorType eColorType
;
322 case MouseOver
| Selected
| Focused
:
323 eColorType
= Theme::Gradient_MouseOverSelectedAndFocusedPage
;
324 bHasFocusBorder
= true;
327 case MouseOver
| Selected
:
328 eColorType
= Theme::Gradient_MouseOverSelected
;
329 bHasFocusBorder
= false;
333 eColorType
= Theme::Gradient_MouseOverPage
;
334 bHasFocusBorder
= false;
337 case MouseOver
| Focused
:
338 eColorType
= Theme::Gradient_MouseOverPage
;
339 bHasFocusBorder
= true;
342 case Selected
| Focused
:
343 eColorType
= Theme::Gradient_SelectedAndFocusedPage
;
344 bHasFocusBorder
= true;
348 eColorType
= Theme::Gradient_SelectedPage
;
349 bHasFocusBorder
= false;
353 eColorType
= Theme::Gradient_FocusedPage
;
354 bHasFocusBorder
= true;
359 eColorType
= Theme::Gradient_NormalPage
;
360 bHasFocusBorder
= false;
364 const ::tools::Rectangle
aFocusSize (pPageObjectLayouter
->GetBoundingBox(
366 PageObjectLayouter::Part::FocusIndicator
,
367 PageObjectLayouter::ModelCoordinateSystem
));
369 const ::tools::Rectangle
aPageObjectBox (pPageObjectLayouter
->GetBoundingBox(
371 PageObjectLayouter::Part::PageObject
,
372 PageObjectLayouter::ModelCoordinateSystem
));
374 // Fill the background with the background color of the slide sorter.
375 const Color
aBackgroundColor (mpTheme
->GetColor(Theme::Color_Background
));
376 rDevice
.SetFillColor(aBackgroundColor
);
377 rDevice
.SetLineColor(aBackgroundColor
);
378 rDevice
.DrawRect(aFocusSize
);
380 // Paint the slide area with a linear gradient that starts some pixels
381 // below the top and ends some pixels above the bottom.
382 const Color
aTopColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Fill1
));
383 const Color
aBottomColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Fill2
));
384 if (aTopColor
!= aBottomColor
)
386 const sal_Int32
nHeight (aPageObjectBox
.GetHeight());
387 const sal_Int32
nDefaultConstantSize(nHeight
/4);
388 const sal_Int32
nMinimalGradientSize(40);
389 const sal_Int32
nY1 (
390 ::std::max
<sal_Int32
>(
392 ::std::min
<sal_Int32
>(
393 nDefaultConstantSize
,
394 (nHeight
- nMinimalGradientSize
)/2)));
395 const sal_Int32
nY2 (nHeight
-nY1
);
396 const sal_Int32
nTop (aPageObjectBox
.Top());
397 for (sal_Int32 nY
=0; nY
<nHeight
; ++nY
)
400 rDevice
.SetLineColor(aTopColor
);
402 rDevice
.SetLineColor(aBottomColor
);
405 Color
aColor (aTopColor
);
406 aColor
.Merge(aBottomColor
, 255 * (nY2
-nY
) / (nY2
-nY1
));
407 rDevice
.SetLineColor(aColor
);
410 Point(aPageObjectBox
.Left(), nY
+nTop
),
411 Point(aPageObjectBox
.Right(), nY
+nTop
));
416 rDevice
.SetFillColor(aTopColor
);
417 rDevice
.DrawRect(aPageObjectBox
);
420 // Paint the simple border and, for some backgrounds, the focus border.
422 mpFocusBorderPainter
->PaintFrame(rDevice
, aPageObjectBox
);
424 PaintBorder(rDevice
, eColorType
, aPageObjectBox
);
426 // Get bounding box of the preview around which a shadow is painted.
427 // Compensate for the border around the preview.
428 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
430 PageObjectLayouter::Part::Preview
,
431 PageObjectLayouter::ModelCoordinateSystem
));
432 ::tools::Rectangle
aFrameBox (aBox
.Left()-1,aBox
.Top()-1,aBox
.Right()+1,aBox
.Bottom()+1);
433 mpShadowPainter
->PaintFrame(rDevice
, aFrameBox
);
436 void PageObjectPainter::PaintBorder (
437 OutputDevice
& rDevice
,
438 const Theme::GradientColorType eColorType
,
439 const ::tools::Rectangle
& rBox
) const
441 rDevice
.SetFillColor();
442 const sal_Int32
nBorderWidth (1);
443 for (int nIndex
=0; nIndex
<nBorderWidth
; ++nIndex
)
445 const int nDelta (nIndex
);
446 rDevice
.SetLineColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Border2
));
448 Point(rBox
.Left()-nDelta
, rBox
.Top()-nDelta
),
449 Point(rBox
.Left()-nDelta
, rBox
.Bottom()+nDelta
));
451 Point(rBox
.Left()-nDelta
, rBox
.Bottom()+nDelta
),
452 Point(rBox
.Right()+nDelta
, rBox
.Bottom()+nDelta
));
454 Point(rBox
.Right()+nDelta
, rBox
.Bottom()+nDelta
),
455 Point(rBox
.Right()+nDelta
, rBox
.Top()-nDelta
));
457 rDevice
.SetLineColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Border1
));
459 Point(rBox
.Left()-nDelta
, rBox
.Top()-nDelta
),
460 Point(rBox
.Right()+nDelta
, rBox
.Top()-nDelta
));
464 } } } // end of namespace sd::slidesorter::view
466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */