tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsPageObjectPainter.cxx
blob8cd6d3e87cc9ff80ca2f22b1761463aa77000849
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 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())
68 return;
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");
93 return false;
96 return true;
99 void PageObjectPainter::SetTheme (const std::shared_ptr<view::Theme>& rpTheme)
101 mpTheme = 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(
119 rpDescriptor,
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(
132 rpDescriptor,
133 PageObjectLayouter::Part::Preview,
134 PageObjectLayouter::ModelCoordinateSystem));
136 if (mpCache == nullptr)
137 return;
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);
147 else
148 rDevice.DrawBitmapEx(aBox.TopLeft(), aPreview);
152 BitmapEx PageObjectPainter::CreateMarkedPreview (
153 const Size& rSize,
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));
161 else
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));
186 if (bIsExcluded)
188 PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
190 BitmapEx aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage));
191 const ::tools::Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
192 rpDescriptor,
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),
201 pReferenceDevice);
202 mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview);
204 return aMarkedPreview;
206 else
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(
218 rpDescriptor,
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);
232 else
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);
240 else
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);
250 else
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(
274 rpDescriptor,
275 PageObjectLayouter::Part::TransitionEffectIndicator,
276 PageObjectLayouter::ModelCoordinateSystem));
278 rDevice.DrawBitmapEx(
279 aBox.TopCenter(),
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();
293 if ( aIter != aEnd )
295 const ::tools::Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
296 rpDescriptor,
297 PageObjectLayouter::Part::CustomAnimationEffectIndicator,
298 PageObjectLayouter::ModelCoordinateSystem));
299 rDevice.DrawBitmapEx(
300 aBox.TopCenter(),
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 };
311 const int eState =
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;
319 switch (eState)
321 case MouseOver | Selected | Focused:
322 eColorType = Theme::Gradient_MouseOverSelectedAndFocusedPage;
323 bHasFocusBorder = true;
324 break;
326 case MouseOver | Selected:
327 eColorType = Theme::Gradient_MouseOverSelected;
328 bHasFocusBorder = false;
329 break;
331 case MouseOver:
332 eColorType = Theme::Gradient_MouseOverPage;
333 bHasFocusBorder = false;
334 break;
336 case MouseOver | Focused:
337 eColorType = Theme::Gradient_MouseOverPage;
338 bHasFocusBorder = true;
339 break;
341 case Selected | Focused:
342 eColorType = Theme::Gradient_SelectedAndFocusedPage;
343 bHasFocusBorder = true;
344 break;
346 case Selected:
347 eColorType = Theme::Gradient_SelectedPage;
348 bHasFocusBorder = false;
349 break;
351 case Focused:
352 eColorType = Theme::Gradient_FocusedPage;
353 bHasFocusBorder = true;
354 break;
356 case None:
357 default:
358 eColorType = Theme::Gradient_NormalPage;
359 bHasFocusBorder = false;
360 break;
363 const ::tools::Rectangle aFocusSize (pPageObjectLayouter->GetBoundingBox(
364 rpDescriptor,
365 PageObjectLayouter::Part::FocusIndicator,
366 PageObjectLayouter::ModelCoordinateSystem));
368 const ::tools::Rectangle aPageObjectBox (pPageObjectLayouter->GetBoundingBox(
369 rpDescriptor,
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);
388 else
390 rDevice.SetFillColor(aTopColor);
391 rDevice.DrawRect(aPageObjectBox);
394 // Paint the simple border and, for some backgrounds, the focus border.
395 if (bHasFocusBorder)
396 mpFocusBorderPainter->PaintFrame(rDevice, aPageObjectBox);
397 else
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(
403 rpDescriptor,
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));
421 rDevice.DrawLine(
422 Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
423 Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta));
424 rDevice.DrawLine(
425 Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta),
426 Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta));
427 rDevice.DrawLine(
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));
432 rDevice.DrawLine(
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: */