LibreOffice Module sd (master) 1
SlsPageObjectPainter.cxx
Go to the documentation of this file.
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
21
25#include <view/SlsLayouter.hxx>
26#include <view/SlsTheme.hxx>
27#include <SlideSorter.hxx>
28#include "SlsFramePainter.hxx"
30#include <Window.hxx>
31#include <sdpage.hxx>
32#include <vcl/virdev.hxx>
34#include <osl/diagnose.h>
35#include <memory>
36
37using namespace ::drawinglayer::primitive2d;
38
39namespace sd::slidesorter::view {
40
41//===== PageObjectPainter =====================================================
42
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)))
51{
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);
59}
60
62{
63}
64
66 OutputDevice& rDevice,
67 const model::SharedPageDescriptor& rpDescriptor)
68{
70 return;
71
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);
77
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);
85}
86
88{
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)
93 {
94 OSL_FAIL("no page object layouter");
95 return false;
96 }
97
98 return true;
99}
100
101void PageObjectPainter::SetTheme (const std::shared_ptr<view::Theme>& rpTheme)
102{
103 mpTheme = rpTheme;
104}
105
107 PageObjectLayouter *pPageObjectLayouter,
108 OutputDevice& rDevice,
109 const model::SharedPageDescriptor& rpDescriptor) const
110{
111 PaintBackgroundDetail(pPageObjectLayouter, rDevice, rpDescriptor);
112
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)
117 {
118 rDevice.SetFillColor(pPage->GetPageBackgroundColor(nullptr));
119 rDevice.SetLineColor(pPage->GetPageBackgroundColor(nullptr));
120 const ::tools::Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
121 rpDescriptor,
124 rDevice.DrawRect(aPreviewBox);
125 }
126}
127
129 PageObjectLayouter *pPageObjectLayouter,
130 OutputDevice& rDevice,
131 const model::SharedPageDescriptor& rpDescriptor) const
132{
133 const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
134 rpDescriptor,
137
138 if (mpCache == nullptr)
139 return;
140
141 const SdrPage* pPage = rpDescriptor->GetPage();
142 mpCache->SetPreciousFlag(pPage, true);
143
144 const BitmapEx aPreview (GetPreviewBitmap(rpDescriptor, &rDevice));
145 if ( ! aPreview.IsEmpty())
146 {
147 if (aPreview.GetSizePixel() != aBox.GetSize())
148 rDevice.DrawBitmapEx(aBox.TopLeft(), aBox.GetSize(), aPreview);
149 else
150 rDevice.DrawBitmapEx(aBox.TopLeft(), aPreview);
151 }
152}
153
155 const Size& rSize,
156 const BitmapEx& rPreview,
157 const BitmapEx& rOverlay,
158 const OutputDevice* pReferenceDevice)
159{
161 if (pReferenceDevice != nullptr)
162 pDevice.disposeAndReset(VclPtr<VirtualDevice>::Create(*pReferenceDevice));
163 else
165 pDevice->SetOutputSizePixel(rSize);
166
167 pDevice->DrawBitmapEx(Point(0,0), rSize, rPreview);
168
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)
173 {
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);
177 }
178 return pDevice->GetBitmapEx(Point(0,0), rSize);
179}
180
182 const model::SharedPageDescriptor& rpDescriptor,
183 const OutputDevice* pReferenceDevice) const
184{
185 const SdrPage* pPage = rpDescriptor->GetPage();
186 const bool bIsExcluded (rpDescriptor->HasState(model::PageDescriptor::ST_Excluded));
187
188 if (bIsExcluded)
189 {
190 PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
191
192 BitmapEx aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage));
193 const ::tools::Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
194 rpDescriptor,
197 if (aMarkedPreview.IsEmpty() || aMarkedPreview.GetSizePixel()!=aPreviewBox.GetSize())
198 {
199 aMarkedPreview = CreateMarkedPreview(
200 aPreviewBox.GetSize(),
201 mpCache->GetPreviewBitmap(pPage,true),
203 pReferenceDevice);
204 mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview);
205 }
206 return aMarkedPreview;
207 }
208 else
209 {
210 return mpCache->GetPreviewBitmap(pPage,false);
211 }
212}
213
215 PageObjectLayouter *pPageObjectLayouter,
216 OutputDevice& rDevice,
217 const model::SharedPageDescriptor& rpDescriptor) const
218{
219 const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
220 rpDescriptor,
223
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))
228 {
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);
233 }
234 else
235 {
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);
242 else
243 {
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)
249 {
250 if (nBackgroundLuminance > nFontLuminance-30)
251 aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberBrightBackground);
252 else
253 aPageNumberColor = mpTheme->GetColor(Theme::Color_PageNumberDarkBackground);
254 }
255 }
256 }
257
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);
265}
266
268 PageObjectLayouter *pPageObjectLayouter,
269 OutputDevice& rDevice,
270 const model::SharedPageDescriptor& rpDescriptor)
271{
272 const SdPage* pPage = rpDescriptor->GetPage();
273 if (pPage!=nullptr && pPage->getTransitionType() > 0)
274 {
275 const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
276 rpDescriptor,
279
280 rDevice.DrawBitmapEx(
281 aBox.TopCenter(),
282 pPageObjectLayouter->GetTransitionEffectIcon().GetBitmapEx());
283 }
284}
285
287 PageObjectLayouter *pPageObjectLayouter,
288 OutputDevice& rDevice,
289 const model::SharedPageDescriptor& rpDescriptor)
290{
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();
295 if ( aIter != aEnd )
296 {
297 const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
298 rpDescriptor,
301 rDevice.DrawBitmapEx(
302 aBox.TopCenter(),
303 pPageObjectLayouter->GetCustomAnimationEffectIcon().GetBitmapEx());
304 }
305}
306
308 PageObjectLayouter *pPageObjectLayouter,
309 OutputDevice& rDevice,
310 const model::SharedPageDescriptor& rpDescriptor) const
311{
312 enum State { None = 0x00, Selected = 0x01, MouseOver = 0x02, Focused = 0x04 };
313 const int eState =
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);
317
318 bool bHasFocusBorder;
319 Theme::GradientColorType eColorType;
320
321 switch (eState)
322 {
323 case MouseOver | Selected | Focused:
325 bHasFocusBorder = true;
326 break;
327
328 case MouseOver | Selected:
330 bHasFocusBorder = false;
331 break;
332
333 case MouseOver:
335 bHasFocusBorder = false;
336 break;
337
338 case MouseOver | Focused:
340 bHasFocusBorder = true;
341 break;
342
343 case Selected | Focused:
345 bHasFocusBorder = true;
346 break;
347
348 case Selected:
349 eColorType = Theme::Gradient_SelectedPage;
350 bHasFocusBorder = false;
351 break;
352
353 case Focused:
354 eColorType = Theme::Gradient_FocusedPage;
355 bHasFocusBorder = true;
356 break;
357
358 case None:
359 default:
360 eColorType = Theme::Gradient_NormalPage;
361 bHasFocusBorder = false;
362 break;
363 }
364
365 const ::tools::Rectangle aFocusSize (pPageObjectLayouter->GetBoundingBox(
366 rpDescriptor,
369
370 const ::tools::Rectangle aPageObjectBox (pPageObjectLayouter->GetBoundingBox(
371 rpDescriptor,
374
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);
380
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)
386 {
387 Gradient gradient(css::awt::GradientStyle_LINEAR, aTopColor, aBottomColor);
388 rDevice.DrawGradient(aPageObjectBox, gradient);
389 }
390 else
391 {
392 rDevice.SetFillColor(aTopColor);
393 rDevice.DrawRect(aPageObjectBox);
394 }
395
396 // Paint the simple border and, for some backgrounds, the focus border.
397 if (bHasFocusBorder)
398 mpFocusBorderPainter->PaintFrame(rDevice, aPageObjectBox);
399 else
400 PaintBorder(rDevice, eColorType, aPageObjectBox);
401
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(
405 rpDescriptor,
408 ::tools::Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1);
409 mpShadowPainter->PaintFrame(rDevice, aFrameBox);
410}
411
413 OutputDevice& rDevice,
414 const Theme::GradientColorType eColorType,
415 const ::tools::Rectangle& rBox) const
416{
417 rDevice.SetFillColor();
418 const sal_Int32 nBorderWidth (1);
419 for (int nIndex=0; nIndex<nBorderWidth; ++nIndex)
420 {
421 const int nDelta (nIndex);
422 rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Border2));
423 rDevice.DrawLine(
424 Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
425 Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta));
426 rDevice.DrawLine(
427 Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta),
428 Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta));
429 rDevice.DrawLine(
430 Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta),
431 Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
432
433 rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::GradientColorClass::Border1));
434 rDevice.DrawLine(
435 Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
436 Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
437 }
438}
439
440} // end of namespace sd::slidesorter::view
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AntialiasingFlags
constexpr int nBorderWidth
bool IsEmpty() const
const Size & GetSizePixel() const
sal_uInt8 GetLuminance() const
void RGBtoHSB(sal_uInt16 &nHue, sal_uInt16 &nSaturation, sal_uInt16 &nBrightness) const
static Color HSBtoRGB(sal_uInt16 nHue, sal_uInt16 nSaturation, sal_uInt16 nBrightness)
BitmapEx GetBitmapEx() const
void DrawBitmapEx(const Point &rDestPt, const BitmapEx &rBitmapEx)
void SetAntialiasing(AntialiasingFlags nMode)
void SetFont(const vcl::Font &rNewFont)
void DrawRect(const tools::Rectangle &rRect)
void DrawLine(const Point &rStartPt, const Point &rEndPt)
void SetLineColor()
void SetTextColor(const Color &rColor)
void SetFillColor()
void DrawGradient(const tools::Rectangle &rRect, const Gradient &rGradient)
AntialiasingFlags GetAntialiasing() const
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
void disposeAndReset(reference_type *pBody)
sal_Int16 getTransitionType() const
Definition: sdpage.hxx:236
std::shared_ptr< sd::MainSequence > const & getMainSequence()
returns a helper class to manipulate effects inside the main sequence
Color GetPageBackgroundColor() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
Show previews for all the slides in a document and allow the user to insert or delete slides and modi...
Definition: SlideSorter.hxx:62
std::shared_ptr< PageObjectLayouter > const & GetPageObjectLayouter() const
In contrast to the Layouter that places page objects in the view, the PageObjectLayouter places the p...
::tools::Rectangle GetBoundingBox(const model::SharedPageDescriptor &rpPageDescriptor, const Part ePart, const CoordinateSystem eCoordinateSystem, bool bIgnoreLocation=false)
Return the bounding box of the page object or one of its graphical parts.
bool UpdatePageObjectLayouter()
Update the local pointer to the page object layouter to the one owned by the general layouter.
void PaintPageNumber(PageObjectLayouter *pPageObjectLayouter, OutputDevice &rDevice, const model::SharedPageDescriptor &rpDescriptor) const
std::shared_ptr< cache::PageCache > mpCache
void PaintPageObject(OutputDevice &rDevice, const model::SharedPageDescriptor &rpDescriptor)
static BitmapEx CreateMarkedPreview(const Size &rSize, const BitmapEx &rPreview, const BitmapEx &rOverlay, const OutputDevice *pReferenceDevice)
std::shared_ptr< vcl::Font > mpPageNumberFont
void SetTheme(const std::shared_ptr< view::Theme > &rpTheme)
Called when the theme changes, either because it is replaced with another or because the system color...
BitmapEx GetPreviewBitmap(const model::SharedPageDescriptor &rpDescriptor, const OutputDevice *pReferenceDevice) const
Return a preview bitmap for the given page descriptor.
static void PaintTransitionEffect(PageObjectLayouter *pPageObjectLayouter, OutputDevice &rDevice, const model::SharedPageDescriptor &rpDescriptor)
void PaintPreview(PageObjectLayouter *pPageObjectLayouter, OutputDevice &rDevice, const model::SharedPageDescriptor &rpDescriptor) const
PageObjectPainter(const SlideSorter &rSlideSorter)
static void PaintCustomAnimationEffect(PageObjectLayouter *pPageObjectLayouter, OutputDevice &rDevice, const model::SharedPageDescriptor &rpDescriptor)
void PaintBackgroundDetail(PageObjectLayouter *pPageObjectLayouter, OutputDevice &rDevice, const model::SharedPageDescriptor &rpDescriptor) const
std::unique_ptr< FramePainter > mpFocusBorderPainter
std::unique_ptr< FramePainter > mpShadowPainter
void PaintBackground(PageObjectLayouter *pPageObjectLayouter, OutputDevice &rDevice, const model::SharedPageDescriptor &rpDescriptor) const
void PaintBorder(OutputDevice &rDevice, const Theme::GradientColorType eColorType, const ::tools::Rectangle &rBox) const
Collection of colors and styles that are used to paint the slide sorter view.
Definition: SlsTheme.hxx:39
sal_Int32 nIndex
None
std::shared_ptr< PageDescriptor > SharedPageDescriptor
long Long
State
vcl::Font GetFont(vcl::Font const &rFont, DrawModeFlags nDrawMode, StyleSettings const &rStyleSettings)
SwNodeOffset abs(const SwNodeOffset &a)