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>
34 #include <osl/diagnose.h>
37 using namespace ::drawinglayer::primitive2d
;
39 namespace sd::slidesorter::view
{
41 //===== PageObjectPainter =====================================================
43 PageObjectPainter::PageObjectPainter (
44 const SlideSorter
& rSlideSorter
)
45 : mrLayouter(rSlideSorter
.GetView().GetLayouter()),
46 mpCache(rSlideSorter
.GetView().GetPreviewCache()),
47 mpTheme(rSlideSorter
.GetTheme()),
48 mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber
, *rSlideSorter
.GetContentWindow()->GetOutDev())),
49 mpShadowPainter(new FramePainter(mpTheme
->GetIcon(Theme::Icon_RawShadow
))),
50 mpFocusBorderPainter(new FramePainter(mpTheme
->GetIcon(Theme::Icon_FocusBorder
)))
52 // Replace the color (not the alpha values) in the focus border with a
53 // color derived from the current selection color.
54 Color
aColor (mpTheme
->GetColor(Theme::Color_Selection
));
55 sal_uInt16 nHue
, nSat
, nBri
;
56 aColor
.RGBtoHSB(nHue
, nSat
, nBri
);
57 aColor
= Color::HSBtoRGB(nHue
, 28, 65);
58 mpFocusBorderPainter
->AdaptColor(aColor
);
61 PageObjectPainter::~PageObjectPainter()
65 void PageObjectPainter::PaintPageObject (
66 OutputDevice
& rDevice
,
67 const model::SharedPageDescriptor
& rpDescriptor
)
69 if (!UpdatePageObjectLayouter())
72 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
73 // Turn off antialiasing to avoid the bitmaps from being
74 // shifted by fractions of a pixel and thus show blurry edges.
75 const AntialiasingFlags
nSavedAntialiasingMode (rDevice
.GetAntialiasing());
76 rDevice
.SetAntialiasing(nSavedAntialiasingMode
& ~AntialiasingFlags::Enable
);
78 PaintBackground(pPageObjectLayouter
, rDevice
, rpDescriptor
);
79 PaintPreview(pPageObjectLayouter
, rDevice
, rpDescriptor
);
80 PaintPageNumber(pPageObjectLayouter
, rDevice
, rpDescriptor
);
81 PaintTransitionEffect(pPageObjectLayouter
, rDevice
, rpDescriptor
);
82 if (rpDescriptor
->GetPage()->hasAnimationNode())
83 PaintCustomAnimationEffect(pPageObjectLayouter
, rDevice
, rpDescriptor
);
84 rDevice
.SetAntialiasing(nSavedAntialiasingMode
);
87 bool PageObjectPainter::UpdatePageObjectLayouter()
89 // The page object layouter is quite volatile. It may have been replaced
90 // since the last call. Update it now.
91 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
92 if ( ! pPageObjectLayouter
)
94 OSL_FAIL("no page object layouter");
101 void PageObjectPainter::SetTheme (const std::shared_ptr
<view::Theme
>& rpTheme
)
106 void PageObjectPainter::PaintBackground (
107 PageObjectLayouter
*pPageObjectLayouter
,
108 OutputDevice
& rDevice
,
109 const model::SharedPageDescriptor
& rpDescriptor
) const
111 PaintBackgroundDetail(pPageObjectLayouter
, rDevice
, rpDescriptor
);
113 // Fill the interior of the preview area with the default background
114 // color of the page.
115 SdPage
* pPage
= rpDescriptor
->GetPage();
116 if (pPage
!= nullptr)
118 rDevice
.SetFillColor(pPage
->GetPageBackgroundColor(nullptr));
119 rDevice
.SetLineColor(pPage
->GetPageBackgroundColor(nullptr));
120 const ::tools::Rectangle
aPreviewBox (pPageObjectLayouter
->GetBoundingBox(
122 PageObjectLayouter::Part::Preview
,
123 PageObjectLayouter::ModelCoordinateSystem
));
124 rDevice
.DrawRect(aPreviewBox
);
128 void PageObjectPainter::PaintPreview (
129 PageObjectLayouter
*pPageObjectLayouter
,
130 OutputDevice
& rDevice
,
131 const model::SharedPageDescriptor
& rpDescriptor
) const
133 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
135 PageObjectLayouter::Part::Preview
,
136 PageObjectLayouter::ModelCoordinateSystem
));
138 if (mpCache
== nullptr)
141 const SdrPage
* pPage
= rpDescriptor
->GetPage();
142 mpCache
->SetPreciousFlag(pPage
, true);
144 const BitmapEx
aPreview (GetPreviewBitmap(rpDescriptor
, &rDevice
));
145 if ( ! aPreview
.IsEmpty())
147 if (aPreview
.GetSizePixel() != aBox
.GetSize())
148 rDevice
.DrawBitmapEx(aBox
.TopLeft(), aBox
.GetSize(), aPreview
);
150 rDevice
.DrawBitmapEx(aBox
.TopLeft(), aPreview
);
154 BitmapEx
PageObjectPainter::CreateMarkedPreview (
156 const BitmapEx
& rPreview
,
157 const BitmapEx
& rOverlay
,
158 const OutputDevice
* pReferenceDevice
)
160 ScopedVclPtr
<VirtualDevice
> pDevice
;
161 if (pReferenceDevice
!= nullptr)
162 pDevice
.disposeAndReset(VclPtr
<VirtualDevice
>::Create(*pReferenceDevice
));
164 pDevice
.disposeAndReset(VclPtr
<VirtualDevice
>::Create());
165 pDevice
->SetOutputSizePixel(rSize
);
167 pDevice
->DrawBitmapEx(Point(0,0), rSize
, rPreview
);
169 // Paint bitmap tiled over the preview to mark it as excluded.
170 const sal_Int32
nIconWidth (rOverlay
.GetSizePixel().Width());
171 const sal_Int32
nIconHeight (rOverlay
.GetSizePixel().Height());
172 if (nIconWidth
>0 && nIconHeight
>0)
174 for (::tools::Long nX
=0; nX
<rSize
.Width(); nX
+=nIconWidth
)
175 for (::tools::Long nY
=0; nY
<rSize
.Height(); nY
+=nIconHeight
)
176 pDevice
->DrawBitmapEx(Point(nX
,nY
), rOverlay
);
178 return pDevice
->GetBitmapEx(Point(0,0), rSize
);
181 BitmapEx
PageObjectPainter::GetPreviewBitmap (
182 const model::SharedPageDescriptor
& rpDescriptor
,
183 const OutputDevice
* pReferenceDevice
) const
185 const SdrPage
* pPage
= rpDescriptor
->GetPage();
186 const bool bIsExcluded (rpDescriptor
->HasState(model::PageDescriptor::ST_Excluded
));
190 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
192 BitmapEx
aMarkedPreview (mpCache
->GetMarkedPreviewBitmap(pPage
));
193 const ::tools::Rectangle
aPreviewBox (pPageObjectLayouter
->GetBoundingBox(
195 PageObjectLayouter::Part::Preview
,
196 PageObjectLayouter::ModelCoordinateSystem
));
197 if (aMarkedPreview
.IsEmpty() || aMarkedPreview
.GetSizePixel()!=aPreviewBox
.GetSize())
199 aMarkedPreview
= CreateMarkedPreview(
200 aPreviewBox
.GetSize(),
201 mpCache
->GetPreviewBitmap(pPage
,true),
202 mpTheme
->GetIcon(Theme::Icon_HideSlideOverlay
),
204 mpCache
->SetMarkedPreviewBitmap(pPage
, aMarkedPreview
);
206 return aMarkedPreview
;
210 return mpCache
->GetPreviewBitmap(pPage
,false);
214 void PageObjectPainter::PaintPageNumber (
215 PageObjectLayouter
*pPageObjectLayouter
,
216 OutputDevice
& rDevice
,
217 const model::SharedPageDescriptor
& rpDescriptor
) const
219 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
221 PageObjectLayouter::Part::PageNumber
,
222 PageObjectLayouter::ModelCoordinateSystem
));
224 // Determine the color of the page number.
225 Color
aPageNumberColor (mpTheme
->GetColor(Theme::Color_PageNumberDefault
));
226 if (rpDescriptor
->HasState(model::PageDescriptor::ST_MouseOver
) ||
227 rpDescriptor
->HasState(model::PageDescriptor::ST_Selected
))
229 // Page number is painted on background for hover or selection or
230 // both. Each of these background colors has a predefined luminance
231 // which is compatible with the PageNumberHover color.
232 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberHover
);
236 const Color
aBackgroundColor (mpTheme
->GetColor(Theme::Color_Background
));
237 const sal_Int32
nBackgroundLuminance (aBackgroundColor
.GetLuminance());
238 // When the background color is black then this is interpreted as
239 // high contrast mode and the font color is set to white.
240 if (nBackgroundLuminance
== 0)
241 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberHighContrast
);
244 // Compare luminance of default page number color and background
245 // color. When the two are similar then use a darker
246 // (preferred) or brighter font color.
247 const sal_Int32
nFontLuminance (aPageNumberColor
.GetLuminance());
248 if (abs(nBackgroundLuminance
- nFontLuminance
) < 60)
250 if (nBackgroundLuminance
> nFontLuminance
-30)
251 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberBrightBackground
);
253 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberDarkBackground
);
258 // Paint the page number.
259 OSL_ASSERT(rpDescriptor
->GetPage()!=nullptr);
260 const sal_Int32
nPageNumber ((rpDescriptor
->GetPage()->GetPageNum() - 1) / 2 + 1);
261 const OUString
sPageNumber(OUString::number(nPageNumber
));
262 rDevice
.SetFont(*mpPageNumberFont
);
263 rDevice
.SetTextColor(aPageNumberColor
);
264 rDevice
.DrawText(aBox
, sPageNumber
, DrawTextFlags::Right
| DrawTextFlags::VCenter
);
267 void PageObjectPainter::PaintTransitionEffect (
268 PageObjectLayouter
*pPageObjectLayouter
,
269 OutputDevice
& rDevice
,
270 const model::SharedPageDescriptor
& rpDescriptor
)
272 const SdPage
* pPage
= rpDescriptor
->GetPage();
273 if (pPage
!=nullptr && pPage
->getTransitionType() > 0)
275 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
277 PageObjectLayouter::Part::TransitionEffectIndicator
,
278 PageObjectLayouter::ModelCoordinateSystem
));
280 rDevice
.DrawBitmapEx(
282 pPageObjectLayouter
->GetTransitionEffectIcon().GetBitmapEx());
286 void PageObjectPainter::PaintCustomAnimationEffect (
287 PageObjectLayouter
*pPageObjectLayouter
,
288 OutputDevice
& rDevice
,
289 const model::SharedPageDescriptor
& rpDescriptor
)
291 SdPage
* pPage
= rpDescriptor
->GetPage();
292 std::shared_ptr
< MainSequence
> aMainSequence
= pPage
->getMainSequence();
293 EffectSequence::iterator aIter
= aMainSequence
->getBegin();
294 EffectSequence::iterator aEnd
= aMainSequence
->getEnd();
297 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
299 PageObjectLayouter::Part::CustomAnimationEffectIndicator
,
300 PageObjectLayouter::ModelCoordinateSystem
));
301 rDevice
.DrawBitmapEx(
303 pPageObjectLayouter
->GetCustomAnimationEffectIcon().GetBitmapEx());
307 void PageObjectPainter::PaintBackgroundDetail (
308 PageObjectLayouter
*pPageObjectLayouter
,
309 OutputDevice
& rDevice
,
310 const model::SharedPageDescriptor
& rpDescriptor
) const
312 enum State
{ None
= 0x00, Selected
= 0x01, MouseOver
= 0x02, Focused
= 0x04 };
314 (rpDescriptor
->HasState(model::PageDescriptor::ST_Selected
) ? Selected
: None
)
315 | (rpDescriptor
->HasState(model::PageDescriptor::ST_MouseOver
) ? MouseOver
: None
)
316 | (rpDescriptor
->HasState(model::PageDescriptor::ST_Focused
) ? Focused
: None
);
318 bool bHasFocusBorder
;
319 Theme::GradientColorType eColorType
;
323 case MouseOver
| Selected
| Focused
:
324 eColorType
= Theme::Gradient_MouseOverSelectedAndFocusedPage
;
325 bHasFocusBorder
= true;
328 case MouseOver
| Selected
:
329 eColorType
= Theme::Gradient_MouseOverSelected
;
330 bHasFocusBorder
= false;
334 eColorType
= Theme::Gradient_MouseOverPage
;
335 bHasFocusBorder
= false;
338 case MouseOver
| Focused
:
339 eColorType
= Theme::Gradient_MouseOverPage
;
340 bHasFocusBorder
= true;
343 case Selected
| Focused
:
344 eColorType
= Theme::Gradient_SelectedAndFocusedPage
;
345 bHasFocusBorder
= true;
349 eColorType
= Theme::Gradient_SelectedPage
;
350 bHasFocusBorder
= false;
354 eColorType
= Theme::Gradient_FocusedPage
;
355 bHasFocusBorder
= true;
360 eColorType
= Theme::Gradient_NormalPage
;
361 bHasFocusBorder
= false;
365 const ::tools::Rectangle
aFocusSize (pPageObjectLayouter
->GetBoundingBox(
367 PageObjectLayouter::Part::FocusIndicator
,
368 PageObjectLayouter::ModelCoordinateSystem
));
370 const ::tools::Rectangle
aPageObjectBox (pPageObjectLayouter
->GetBoundingBox(
372 PageObjectLayouter::Part::PageObject
,
373 PageObjectLayouter::ModelCoordinateSystem
));
375 // Fill the background with the background color of the slide sorter.
376 const Color
aBackgroundColor (mpTheme
->GetColor(Theme::Color_Background
));
377 rDevice
.SetFillColor(aBackgroundColor
);
378 rDevice
.SetLineColor(aBackgroundColor
);
379 rDevice
.DrawRect(aFocusSize
);
381 // Paint the slide area with a linear gradient that starts some pixels
382 // below the top and ends some pixels above the bottom.
383 const Color
aTopColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Fill1
));
384 const Color
aBottomColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Fill2
));
385 if (aTopColor
!= aBottomColor
)
387 Gradient
gradient(css::awt::GradientStyle_LINEAR
, aTopColor
, aBottomColor
);
388 rDevice
.DrawGradient(aPageObjectBox
, gradient
);
392 rDevice
.SetFillColor(aTopColor
);
393 rDevice
.DrawRect(aPageObjectBox
);
396 // Paint the simple border and, for some backgrounds, the focus border.
398 mpFocusBorderPainter
->PaintFrame(rDevice
, aPageObjectBox
);
400 PaintBorder(rDevice
, eColorType
, aPageObjectBox
);
402 // Get bounding box of the preview around which a shadow is painted.
403 // Compensate for the border around the preview.
404 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
406 PageObjectLayouter::Part::Preview
,
407 PageObjectLayouter::ModelCoordinateSystem
));
408 ::tools::Rectangle
aFrameBox (aBox
.Left()-1,aBox
.Top()-1,aBox
.Right()+1,aBox
.Bottom()+1);
409 mpShadowPainter
->PaintFrame(rDevice
, aFrameBox
);
412 void PageObjectPainter::PaintBorder (
413 OutputDevice
& rDevice
,
414 const Theme::GradientColorType eColorType
,
415 const ::tools::Rectangle
& rBox
) const
417 rDevice
.SetFillColor();
418 const sal_Int32
nBorderWidth (1);
419 for (int nIndex
=0; nIndex
<nBorderWidth
; ++nIndex
)
421 const int nDelta (nIndex
);
422 rDevice
.SetLineColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Border2
));
424 Point(rBox
.Left()-nDelta
, rBox
.Top()-nDelta
),
425 Point(rBox
.Left()-nDelta
, rBox
.Bottom()+nDelta
));
427 Point(rBox
.Left()-nDelta
, rBox
.Bottom()+nDelta
),
428 Point(rBox
.Right()+nDelta
, rBox
.Bottom()+nDelta
));
430 Point(rBox
.Right()+nDelta
, rBox
.Bottom()+nDelta
),
431 Point(rBox
.Right()+nDelta
, rBox
.Top()-nDelta
));
433 rDevice
.SetLineColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Border1
));
435 Point(rBox
.Left()-nDelta
, rBox
.Top()-nDelta
),
436 Point(rBox
.Right()+nDelta
, rBox
.Top()-nDelta
));
440 } // end of namespace sd::slidesorter::view
442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */