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 namespace sd::slidesorter::view
{
39 //===== PageObjectPainter =====================================================
41 PageObjectPainter::PageObjectPainter (
42 const SlideSorter
& rSlideSorter
)
43 : mrLayouter(rSlideSorter
.GetView().GetLayouter()),
44 mpCache(rSlideSorter
.GetView().GetPreviewCache()),
45 mpTheme(rSlideSorter
.GetTheme()),
46 mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber
, *rSlideSorter
.GetContentWindow()->GetOutDev())),
47 mpShadowPainter(new FramePainter(mpTheme
->GetIcon(Theme::Icon_RawShadow
))),
48 mpFocusBorderPainter(new FramePainter(mpTheme
->GetIcon(Theme::Icon_FocusBorder
)))
50 // Replace the color (not the alpha values) in the focus border with a
51 // color derived from the current selection color.
52 Color
aColor (mpTheme
->GetColor(Theme::Color_Selection
));
53 sal_uInt16 nHue
, nSat
, nBri
;
54 aColor
.RGBtoHSB(nHue
, nSat
, nBri
);
55 aColor
= Color::HSBtoRGB(nHue
, 28, 65);
56 mpFocusBorderPainter
->AdaptColor(aColor
);
59 PageObjectPainter::~PageObjectPainter()
63 void PageObjectPainter::PaintPageObject (
64 OutputDevice
& rDevice
,
65 const model::SharedPageDescriptor
& rpDescriptor
)
67 if (!UpdatePageObjectLayouter())
70 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
71 // Turn off antialiasing to avoid the bitmaps from being
72 // shifted by fractions of a pixel and thus show blurry edges.
73 const AntialiasingFlags
nSavedAntialiasingMode (rDevice
.GetAntialiasing());
74 rDevice
.SetAntialiasing(nSavedAntialiasingMode
& ~AntialiasingFlags::Enable
);
76 PaintBackground(pPageObjectLayouter
, rDevice
, rpDescriptor
);
77 PaintPreview(pPageObjectLayouter
, rDevice
, rpDescriptor
);
78 PaintPageNumber(pPageObjectLayouter
, rDevice
, rpDescriptor
);
79 PaintTransitionEffect(pPageObjectLayouter
, rDevice
, rpDescriptor
);
80 if (rpDescriptor
->GetPage()->hasAnimationNode())
81 PaintCustomAnimationEffect(pPageObjectLayouter
, rDevice
, rpDescriptor
);
82 rDevice
.SetAntialiasing(nSavedAntialiasingMode
);
85 bool PageObjectPainter::UpdatePageObjectLayouter()
87 // The page object layouter is quite volatile. It may have been replaced
88 // since the last call. Update it now.
89 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
90 if ( ! pPageObjectLayouter
)
92 OSL_FAIL("no page object layouter");
99 void PageObjectPainter::SetTheme (const std::shared_ptr
<view::Theme
>& rpTheme
)
104 void PageObjectPainter::PaintBackground (
105 PageObjectLayouter
*pPageObjectLayouter
,
106 OutputDevice
& rDevice
,
107 const model::SharedPageDescriptor
& rpDescriptor
) const
109 PaintBackgroundDetail(pPageObjectLayouter
, rDevice
, rpDescriptor
);
111 // Fill the interior of the preview area with the default background
112 // color of the page.
113 SdPage
* pPage
= rpDescriptor
->GetPage();
114 if (pPage
!= nullptr)
116 rDevice
.SetFillColor(pPage
->GetPageBackgroundColor(nullptr));
117 rDevice
.SetLineColor(pPage
->GetPageBackgroundColor(nullptr));
118 const ::tools::Rectangle
aPreviewBox (pPageObjectLayouter
->GetBoundingBox(
120 PageObjectLayouter::Part::Preview
,
121 PageObjectLayouter::ModelCoordinateSystem
));
122 rDevice
.DrawRect(aPreviewBox
);
126 void PageObjectPainter::PaintPreview (
127 PageObjectLayouter
*pPageObjectLayouter
,
128 OutputDevice
& rDevice
,
129 const model::SharedPageDescriptor
& rpDescriptor
) const
131 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
133 PageObjectLayouter::Part::Preview
,
134 PageObjectLayouter::ModelCoordinateSystem
));
136 if (mpCache
== nullptr)
139 const SdrPage
* pPage
= rpDescriptor
->GetPage();
140 mpCache
->SetPreciousFlag(pPage
, true);
142 const BitmapEx
aPreview (GetPreviewBitmap(rpDescriptor
, &rDevice
));
143 if ( ! aPreview
.IsEmpty())
145 if (aPreview
.GetSizePixel() != aBox
.GetSize())
146 rDevice
.DrawBitmapEx(aBox
.TopLeft(), aBox
.GetSize(), aPreview
);
148 rDevice
.DrawBitmapEx(aBox
.TopLeft(), aPreview
);
152 BitmapEx
PageObjectPainter::CreateMarkedPreview (
154 const BitmapEx
& rPreview
,
155 const BitmapEx
& rOverlay
,
156 const OutputDevice
* pReferenceDevice
)
158 ScopedVclPtr
<VirtualDevice
> pDevice
;
159 if (pReferenceDevice
!= nullptr)
160 pDevice
.disposeAndReset(VclPtr
<VirtualDevice
>::Create(*pReferenceDevice
));
162 pDevice
.disposeAndReset(VclPtr
<VirtualDevice
>::Create());
163 pDevice
->SetOutputSizePixel(rSize
);
165 pDevice
->DrawBitmapEx(Point(0,0), rSize
, rPreview
);
167 // Paint bitmap tiled over the preview to mark it as excluded.
168 const sal_Int32
nIconWidth (rOverlay
.GetSizePixel().Width());
169 const sal_Int32
nIconHeight (rOverlay
.GetSizePixel().Height());
170 if (nIconWidth
>0 && nIconHeight
>0)
172 for (::tools::Long nX
=0; nX
<rSize
.Width(); nX
+=nIconWidth
)
173 for (::tools::Long nY
=0; nY
<rSize
.Height(); nY
+=nIconHeight
)
174 pDevice
->DrawBitmapEx(Point(nX
,nY
), rOverlay
);
176 return pDevice
->GetBitmapEx(Point(0,0), rSize
);
179 BitmapEx
PageObjectPainter::GetPreviewBitmap (
180 const model::SharedPageDescriptor
& rpDescriptor
,
181 const OutputDevice
* pReferenceDevice
) const
183 const SdrPage
* pPage
= rpDescriptor
->GetPage();
184 const bool bIsExcluded (rpDescriptor
->HasState(model::PageDescriptor::ST_Excluded
));
188 PageObjectLayouter
*pPageObjectLayouter
= mrLayouter
.GetPageObjectLayouter().get();
190 BitmapEx
aMarkedPreview (mpCache
->GetMarkedPreviewBitmap(pPage
));
191 const ::tools::Rectangle
aPreviewBox (pPageObjectLayouter
->GetBoundingBox(
193 PageObjectLayouter::Part::Preview
,
194 PageObjectLayouter::ModelCoordinateSystem
));
195 if (aMarkedPreview
.IsEmpty() || aMarkedPreview
.GetSizePixel()!=aPreviewBox
.GetSize())
197 aMarkedPreview
= CreateMarkedPreview(
198 aPreviewBox
.GetSize(),
199 mpCache
->GetPreviewBitmap(pPage
,true),
200 mpTheme
->GetIcon(Theme::Icon_HideSlideOverlay
),
202 mpCache
->SetMarkedPreviewBitmap(pPage
, aMarkedPreview
);
204 return aMarkedPreview
;
208 return mpCache
->GetPreviewBitmap(pPage
,false);
212 void PageObjectPainter::PaintPageNumber (
213 PageObjectLayouter
*pPageObjectLayouter
,
214 OutputDevice
& rDevice
,
215 const model::SharedPageDescriptor
& rpDescriptor
) const
217 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
219 PageObjectLayouter::Part::PageNumber
,
220 PageObjectLayouter::ModelCoordinateSystem
));
222 // Determine the color of the page number.
223 Color
aPageNumberColor (mpTheme
->GetColor(Theme::Color_PageNumberDefault
));
224 if (rpDescriptor
->HasState(model::PageDescriptor::ST_MouseOver
) ||
225 rpDescriptor
->HasState(model::PageDescriptor::ST_Selected
))
227 // Page number is painted on background for hover or selection or
228 // both. Each of these background colors has a predefined luminance
229 // which is compatible with the PageNumberHover color.
230 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberHover
);
234 const Color
aBackgroundColor (mpTheme
->GetColor(Theme::Color_Background
));
235 const sal_Int32
nBackgroundLuminance (aBackgroundColor
.GetLuminance());
236 // When the background color is black then this is interpreted as
237 // high contrast mode and the font color is set to white.
238 if (nBackgroundLuminance
== 0)
239 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberHighContrast
);
242 // Compare luminance of default page number color and background
243 // color. When the two are similar then use a darker
244 // (preferred) or brighter font color.
245 const sal_Int32
nFontLuminance (aPageNumberColor
.GetLuminance());
246 if (abs(nBackgroundLuminance
- nFontLuminance
) < 60)
248 if (nBackgroundLuminance
> nFontLuminance
-30)
249 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberBrightBackground
);
251 aPageNumberColor
= mpTheme
->GetColor(Theme::Color_PageNumberDarkBackground
);
256 // Paint the page number.
257 OSL_ASSERT(rpDescriptor
->GetPage()!=nullptr);
258 const sal_Int32
nPageNumber ((rpDescriptor
->GetPage()->GetPageNum() - 1) / 2 + 1);
259 const OUString
sPageNumber(OUString::number(nPageNumber
));
260 rDevice
.SetFont(*mpPageNumberFont
);
261 rDevice
.SetTextColor(aPageNumberColor
);
262 rDevice
.DrawText(aBox
, sPageNumber
, DrawTextFlags::Right
| DrawTextFlags::VCenter
);
265 void PageObjectPainter::PaintTransitionEffect (
266 PageObjectLayouter
*pPageObjectLayouter
,
267 OutputDevice
& rDevice
,
268 const model::SharedPageDescriptor
& rpDescriptor
)
270 const SdPage
* pPage
= rpDescriptor
->GetPage();
271 if (pPage
!=nullptr && pPage
->getTransitionType() > 0)
273 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
275 PageObjectLayouter::Part::TransitionEffectIndicator
,
276 PageObjectLayouter::ModelCoordinateSystem
));
278 rDevice
.DrawBitmapEx(
280 pPageObjectLayouter
->GetTransitionEffectIcon().GetBitmapEx());
284 void PageObjectPainter::PaintCustomAnimationEffect (
285 PageObjectLayouter
*pPageObjectLayouter
,
286 OutputDevice
& rDevice
,
287 const model::SharedPageDescriptor
& rpDescriptor
)
289 SdPage
* pPage
= rpDescriptor
->GetPage();
290 std::shared_ptr
< MainSequence
> aMainSequence
= pPage
->getMainSequence();
291 EffectSequence::iterator aIter
= aMainSequence
->getBegin();
292 EffectSequence::iterator aEnd
= aMainSequence
->getEnd();
295 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
297 PageObjectLayouter::Part::CustomAnimationEffectIndicator
,
298 PageObjectLayouter::ModelCoordinateSystem
));
299 rDevice
.DrawBitmapEx(
301 pPageObjectLayouter
->GetCustomAnimationEffectIcon().GetBitmapEx());
305 void PageObjectPainter::PaintBackgroundDetail (
306 PageObjectLayouter
*pPageObjectLayouter
,
307 OutputDevice
& rDevice
,
308 const model::SharedPageDescriptor
& rpDescriptor
) const
310 enum State
{ None
= 0x00, Selected
= 0x01, MouseOver
= 0x02, Focused
= 0x04 };
312 (rpDescriptor
->HasState(model::PageDescriptor::ST_Selected
) ? Selected
: None
)
313 | (rpDescriptor
->HasState(model::PageDescriptor::ST_MouseOver
) ? MouseOver
: None
)
314 | (rpDescriptor
->HasState(model::PageDescriptor::ST_Focused
) ? Focused
: None
);
316 bool bHasFocusBorder
;
317 Theme::GradientColorType eColorType
;
321 case MouseOver
| Selected
| Focused
:
322 eColorType
= Theme::Gradient_MouseOverSelectedAndFocusedPage
;
323 bHasFocusBorder
= true;
326 case MouseOver
| Selected
:
327 eColorType
= Theme::Gradient_MouseOverSelected
;
328 bHasFocusBorder
= false;
332 eColorType
= Theme::Gradient_MouseOverPage
;
333 bHasFocusBorder
= false;
336 case MouseOver
| Focused
:
337 eColorType
= Theme::Gradient_MouseOverPage
;
338 bHasFocusBorder
= true;
341 case Selected
| Focused
:
342 eColorType
= Theme::Gradient_SelectedAndFocusedPage
;
343 bHasFocusBorder
= true;
347 eColorType
= Theme::Gradient_SelectedPage
;
348 bHasFocusBorder
= false;
352 eColorType
= Theme::Gradient_FocusedPage
;
353 bHasFocusBorder
= true;
358 eColorType
= Theme::Gradient_NormalPage
;
359 bHasFocusBorder
= false;
363 const ::tools::Rectangle
aFocusSize (pPageObjectLayouter
->GetBoundingBox(
365 PageObjectLayouter::Part::FocusIndicator
,
366 PageObjectLayouter::ModelCoordinateSystem
));
368 const ::tools::Rectangle
aPageObjectBox (pPageObjectLayouter
->GetBoundingBox(
370 PageObjectLayouter::Part::PageObject
,
371 PageObjectLayouter::ModelCoordinateSystem
));
373 // Fill the background with the background color of the slide sorter.
374 const Color
aBackgroundColor (mpTheme
->GetColor(Theme::Color_Background
));
375 rDevice
.SetFillColor(aBackgroundColor
);
376 rDevice
.SetLineColor(aBackgroundColor
);
377 rDevice
.DrawRect(aFocusSize
);
379 // Paint the slide area with a linear gradient that starts some pixels
380 // below the top and ends some pixels above the bottom.
381 const Color
aTopColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Fill1
));
382 const Color
aBottomColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Fill2
));
383 if (aTopColor
!= aBottomColor
)
385 Gradient
gradient(css::awt::GradientStyle_LINEAR
, aTopColor
, aBottomColor
);
386 rDevice
.DrawGradient(aPageObjectBox
, gradient
);
390 rDevice
.SetFillColor(aTopColor
);
391 rDevice
.DrawRect(aPageObjectBox
);
394 // Paint the simple border and, for some backgrounds, the focus border.
396 mpFocusBorderPainter
->PaintFrame(rDevice
, aPageObjectBox
);
398 PaintBorder(rDevice
, eColorType
, aPageObjectBox
);
400 // Get bounding box of the preview around which a shadow is painted.
401 // Compensate for the border around the preview.
402 const ::tools::Rectangle
aBox (pPageObjectLayouter
->GetBoundingBox(
404 PageObjectLayouter::Part::Preview
,
405 PageObjectLayouter::ModelCoordinateSystem
));
406 ::tools::Rectangle
aFrameBox (aBox
.Left()-1,aBox
.Top()-1,aBox
.Right()+1,aBox
.Bottom()+1);
407 mpShadowPainter
->PaintFrame(rDevice
, aFrameBox
);
410 void PageObjectPainter::PaintBorder (
411 OutputDevice
& rDevice
,
412 const Theme::GradientColorType eColorType
,
413 const ::tools::Rectangle
& rBox
) const
415 rDevice
.SetFillColor();
416 const sal_Int32
nBorderWidth (1);
417 for (int nIndex
=0; nIndex
<nBorderWidth
; ++nIndex
)
419 const int nDelta (nIndex
);
420 rDevice
.SetLineColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Border2
));
422 Point(rBox
.Left()-nDelta
, rBox
.Top()-nDelta
),
423 Point(rBox
.Left()-nDelta
, rBox
.Bottom()+nDelta
));
425 Point(rBox
.Left()-nDelta
, rBox
.Bottom()+nDelta
),
426 Point(rBox
.Right()+nDelta
, rBox
.Bottom()+nDelta
));
428 Point(rBox
.Right()+nDelta
, rBox
.Bottom()+nDelta
),
429 Point(rBox
.Right()+nDelta
, rBox
.Top()-nDelta
));
431 rDevice
.SetLineColor(mpTheme
->GetGradientColor(eColorType
, Theme::GradientColorClass::Border1
));
433 Point(rBox
.Left()-nDelta
, rBox
.Top()-nDelta
),
434 Point(rBox
.Right()+nDelta
, rBox
.Top()-nDelta
));
438 } // end of namespace sd::slidesorter::view
440 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */