android: Update app-specific/MIME type icons
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsPageObjectPainter.cxx
blob26131a8cd9390c3d8d627372cec2c74af75b1ccd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
30 #include <Window.hxx>
31 #include <sdpage.hxx>
32 #include <vcl/virdev.hxx>
33 #include <CustomAnimationEffect.hxx>
34 #include <osl/diagnose.h>
35 #include <memory>
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())
70 return;
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");
95 return false;
98 return true;
101 void PageObjectPainter::SetTheme (const std::shared_ptr<view::Theme>& rpTheme)
103 mpTheme = 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(
121 rpDescriptor,
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(
134 rpDescriptor,
135 PageObjectLayouter::Part::Preview,
136 PageObjectLayouter::ModelCoordinateSystem));
138 if (mpCache == nullptr)
139 return;
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);
149 else
150 rDevice.DrawBitmapEx(aBox.TopLeft(), aPreview);
154 BitmapEx PageObjectPainter::CreateMarkedPreview (
155 const Size& rSize,
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));
163 else
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));
188 if (bIsExcluded)
190 PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
192 BitmapEx aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage));
193 const ::tools::Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
194 rpDescriptor,
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),
203 pReferenceDevice);
204 mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview);
206 return aMarkedPreview;
208 else
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(
220 rpDescriptor,
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);
234 else
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
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);
252 else
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(
276 rpDescriptor,
277 PageObjectLayouter::Part::TransitionEffectIndicator,
278 PageObjectLayouter::ModelCoordinateSystem));
280 rDevice.DrawBitmapEx(
281 aBox.TopCenter(),
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();
295 if ( aIter != aEnd )
297 const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
298 rpDescriptor,
299 PageObjectLayouter::Part::CustomAnimationEffectIndicator,
300 PageObjectLayouter::ModelCoordinateSystem));
301 rDevice.DrawBitmapEx(
302 aBox.TopCenter(),
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 };
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);
318 bool bHasFocusBorder;
319 Theme::GradientColorType eColorType;
321 switch (eState)
323 case MouseOver | Selected | Focused:
324 eColorType = Theme::Gradient_MouseOverSelectedAndFocusedPage;
325 bHasFocusBorder = true;
326 break;
328 case MouseOver | Selected:
329 eColorType = Theme::Gradient_MouseOverSelected;
330 bHasFocusBorder = false;
331 break;
333 case MouseOver:
334 eColorType = Theme::Gradient_MouseOverPage;
335 bHasFocusBorder = false;
336 break;
338 case MouseOver | Focused:
339 eColorType = Theme::Gradient_MouseOverPage;
340 bHasFocusBorder = true;
341 break;
343 case Selected | Focused:
344 eColorType = Theme::Gradient_SelectedAndFocusedPage;
345 bHasFocusBorder = true;
346 break;
348 case Selected:
349 eColorType = Theme::Gradient_SelectedPage;
350 bHasFocusBorder = false;
351 break;
353 case Focused:
354 eColorType = Theme::Gradient_FocusedPage;
355 bHasFocusBorder = true;
356 break;
358 case None:
359 default:
360 eColorType = Theme::Gradient_NormalPage;
361 bHasFocusBorder = false;
362 break;
365 const ::tools::Rectangle aFocusSize (pPageObjectLayouter->GetBoundingBox(
366 rpDescriptor,
367 PageObjectLayouter::Part::FocusIndicator,
368 PageObjectLayouter::ModelCoordinateSystem));
370 const ::tools::Rectangle aPageObjectBox (pPageObjectLayouter->GetBoundingBox(
371 rpDescriptor,
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);
390 else
392 rDevice.SetFillColor(aTopColor);
393 rDevice.DrawRect(aPageObjectBox);
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);
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,
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));
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));
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));
440 } // end of namespace sd::slidesorter::view
442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */