bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsPageObjectPainter.cxx
blob79eea5518bc78c185272dfdcffa8b1a617a69686
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 "SlsFramePainter.hxx"
28 #include "cache/SlsPageCache.hxx"
29 #include "controller/SlsProperties.hxx"
30 #include "Window.hxx"
31 #include "sdpage.hxx"
32 #include "sdresid.hxx"
33 #include <vcl/svapp.hxx>
34 #include <vcl/vclenum.hxx>
35 #include <vcl/virdev.hxx>
36 #include <boost/scoped_ptr.hpp>
37 #include "CustomAnimationEffect.hxx"
39 using namespace ::drawinglayer::primitive2d;
41 namespace sd { namespace slidesorter { namespace view {
43 //===== PageObjectPainter =====================================================
45 PageObjectPainter::PageObjectPainter (
46 const SlideSorter& rSlideSorter)
47 : mrLayouter(rSlideSorter.GetView().GetLayouter()),
48 mpCache(rSlideSorter.GetView().GetPreviewCache()),
49 mpProperties(rSlideSorter.GetProperties()),
50 mpTheme(rSlideSorter.GetTheme()),
51 mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rSlideSorter.GetContentWindow())),
52 mpShadowPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_RawShadow))),
53 mpFocusBorderPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_FocusBorder)))
55 // Replace the color (not the alpha values) in the focus border with a
56 // color derived from the current selection color.
57 Color aColor (mpTheme->GetColor(Theme::Color_Selection));
58 sal_uInt16 nHue, nSat, nBri;
59 aColor.RGBtoHSB(nHue, nSat, nBri);
60 aColor = Color::HSBtoRGB(nHue, 28, 65);
61 mpFocusBorderPainter->AdaptColor(aColor, true);
64 PageObjectPainter::~PageObjectPainter()
68 void PageObjectPainter::PaintPageObject (
69 OutputDevice& rDevice,
70 const model::SharedPageDescriptor& rpDescriptor)
72 if (UpdatePageObjectLayouter())
74 PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
75 // Turn off antialiasing to avoid the bitmaps from being
76 // shifted by fractions of a pixel and thus show blurry edges.
77 const AntialiasingFlags nSavedAntialiasingMode (rDevice.GetAntialiasing());
78 rDevice.SetAntialiasing(nSavedAntialiasingMode & ~AntialiasingFlags::EnableB2dDraw);
80 PaintBackground(pPageObjectLayouter, rDevice, rpDescriptor);
81 PaintPreview(pPageObjectLayouter, rDevice, rpDescriptor);
82 PaintPageNumber(pPageObjectLayouter, rDevice, rpDescriptor);
83 PaintTransitionEffect(pPageObjectLayouter, rDevice, rpDescriptor);
84 if (rpDescriptor->GetPage()->hasAnimationNode())
85 PaintCustomAnimationEffect(pPageObjectLayouter, rDevice, rpDescriptor);
86 rDevice.SetAntialiasing(nSavedAntialiasingMode);
90 bool PageObjectPainter::UpdatePageObjectLayouter()
92 // The page object layouter is quite volatile. It may have been replaced
93 // since the last call. Update it now.
94 PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
95 if ( ! pPageObjectLayouter)
97 OSL_FAIL("no page object layouter");
98 return false;
101 return true;
104 void PageObjectPainter::SetTheme (const ::boost::shared_ptr<view::Theme>& rpTheme)
106 mpTheme = rpTheme;
109 void PageObjectPainter::PaintBackground (
110 PageObjectLayouter *pPageObjectLayouter,
111 OutputDevice& rDevice,
112 const model::SharedPageDescriptor& rpDescriptor) const
114 PaintBackgroundDetail(pPageObjectLayouter, rDevice, rpDescriptor);
116 // Fill the interior of the preview area with the default background
117 // color of the page.
118 SdPage* pPage = rpDescriptor->GetPage();
119 if (pPage != NULL)
121 rDevice.SetFillColor(pPage->GetPageBackgroundColor(NULL));
122 rDevice.SetLineColor(pPage->GetPageBackgroundColor(NULL));
123 const Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
124 rpDescriptor,
125 PageObjectLayouter::Preview,
126 PageObjectLayouter::ModelCoordinateSystem));
127 rDevice.DrawRect(aPreviewBox);
131 void PageObjectPainter::PaintPreview (
132 PageObjectLayouter *pPageObjectLayouter,
133 OutputDevice& rDevice,
134 const model::SharedPageDescriptor& rpDescriptor) const
136 const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
137 rpDescriptor,
138 PageObjectLayouter::Preview,
139 PageObjectLayouter::ModelCoordinateSystem));
141 if (mpCache != 0)
143 const SdrPage* pPage = rpDescriptor->GetPage();
144 mpCache->SetPreciousFlag(pPage, true);
146 const Bitmap aPreview (GetPreviewBitmap(rpDescriptor, &rDevice));
147 if ( ! aPreview.IsEmpty())
149 if (aPreview.GetSizePixel() != aBox.GetSize())
150 rDevice.DrawBitmap(aBox.TopLeft(), aBox.GetSize(), aPreview);
151 else
152 rDevice.DrawBitmap(aBox.TopLeft(), aPreview);
157 Bitmap PageObjectPainter::CreateMarkedPreview (
158 const Size& rSize,
159 const Bitmap& rPreview,
160 const BitmapEx& rOverlay,
161 const OutputDevice* pReferenceDevice)
163 ScopedVclPtr<VirtualDevice> pDevice;
164 if (pReferenceDevice != NULL)
165 pDevice.reset(VclPtr<VirtualDevice>::Create(*pReferenceDevice));
166 else
167 pDevice.reset(VclPtr<VirtualDevice>::Create());
168 pDevice->SetOutputSizePixel(rSize);
170 pDevice->DrawBitmap(Point(0,0), rSize, rPreview);
172 // Paint bitmap tiled over the preview to mark it as excluded.
173 const sal_Int32 nIconWidth (rOverlay.GetSizePixel().Width());
174 const sal_Int32 nIconHeight (rOverlay.GetSizePixel().Height());
175 if (nIconWidth>0 && nIconHeight>0)
177 for (sal_Int32 nX=0; nX<rSize.Width(); nX+=nIconWidth)
178 for (sal_Int32 nY=0; nY<rSize.Height(); nY+=nIconHeight)
179 pDevice->DrawBitmapEx(Point(nX,nY), rOverlay);
181 return pDevice->GetBitmap(Point(0,0), rSize);
184 Bitmap PageObjectPainter::GetPreviewBitmap (
185 const model::SharedPageDescriptor& rpDescriptor,
186 const OutputDevice* pReferenceDevice) const
188 const SdrPage* pPage = rpDescriptor->GetPage();
189 const bool bIsExcluded (rpDescriptor->HasState(model::PageDescriptor::ST_Excluded));
191 if (bIsExcluded)
193 PageObjectLayouter *pPageObjectLayouter = mrLayouter.GetPageObjectLayouter().get();
195 Bitmap aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage,false));
196 const Rectangle aPreviewBox (pPageObjectLayouter->GetBoundingBox(
197 rpDescriptor,
198 PageObjectLayouter::Preview,
199 PageObjectLayouter::ModelCoordinateSystem));
200 if (aMarkedPreview.IsEmpty() || aMarkedPreview.GetSizePixel()!=aPreviewBox.GetSize())
202 aMarkedPreview = CreateMarkedPreview(
203 aPreviewBox.GetSize(),
204 mpCache->GetPreviewBitmap(pPage,true),
205 mpTheme->GetIcon(Theme::Icon_HideSlideOverlay),
206 pReferenceDevice);
207 mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview);
209 return aMarkedPreview;
211 else
213 return mpCache->GetPreviewBitmap(pPage,false);
217 void PageObjectPainter::PaintPageNumber (
218 PageObjectLayouter *pPageObjectLayouter,
219 OutputDevice& rDevice,
220 const model::SharedPageDescriptor& rpDescriptor) const
222 const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
223 rpDescriptor,
224 PageObjectLayouter::PageNumber,
225 PageObjectLayouter::ModelCoordinateSystem));
227 // Determine the color of the page number.
228 Color aPageNumberColor (mpTheme->GetColor(Theme::Color_PageNumberDefault));
229 if (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ||
230 rpDescriptor->HasState(model::PageDescriptor::ST_Selected))
232 // Page number is painted on background for hover or selection or
233 // both. Each of these background colors has a predefined luminance
234 // which is compatible with the PageNumberHover color.
235 aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHover));
237 else
239 const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
240 const sal_Int32 nBackgroundLuminance (aBackgroundColor.GetLuminance());
241 // When the background color is black then this is interpreted as
242 // high contrast mode and the font color is set to white.
243 if (nBackgroundLuminance == 0)
244 aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHighContrast));
245 else
247 // Compare luminance of default page number color and background
248 // color. When the two are similar then use a darker
249 // (preferred) or brighter font color.
250 const sal_Int32 nFontLuminance (aPageNumberColor.GetLuminance());
251 if (abs(nBackgroundLuminance - nFontLuminance) < 60)
253 if (nBackgroundLuminance > nFontLuminance-30)
254 aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberBrightBackground));
255 else
256 aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberDarkBackground));
261 // Paint the page number.
262 OSL_ASSERT(rpDescriptor->GetPage()!=NULL);
263 const sal_Int32 nPageNumber ((rpDescriptor->GetPage()->GetPageNum() - 1) / 2 + 1);
264 const OUString sPageNumber(OUString::number(nPageNumber));
265 rDevice.SetFont(*mpPageNumberFont);
266 rDevice.SetTextColor(aPageNumberColor);
267 rDevice.DrawText(aBox, sPageNumber, DrawTextFlags::Right | DrawTextFlags::VCenter);
270 void PageObjectPainter::PaintTransitionEffect (
271 PageObjectLayouter *pPageObjectLayouter,
272 OutputDevice& rDevice,
273 const model::SharedPageDescriptor& rpDescriptor)
275 const SdPage* pPage = rpDescriptor->GetPage();
276 if (pPage!=NULL && pPage->getTransitionType() > 0)
278 const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
279 rpDescriptor,
280 PageObjectLayouter::TransitionEffectIndicator,
281 PageObjectLayouter::ModelCoordinateSystem));
283 rDevice.DrawBitmapEx(
284 aBox.TopCenter(),
285 pPageObjectLayouter->GetTransitionEffectIcon().GetBitmapEx());
289 void PageObjectPainter::PaintCustomAnimationEffect (
290 PageObjectLayouter *pPageObjectLayouter,
291 OutputDevice& rDevice,
292 const model::SharedPageDescriptor& rpDescriptor)
294 SdPage* pPage = rpDescriptor->GetPage();
295 boost::shared_ptr< MainSequence > aMainSequence = pPage->getMainSequence();
296 EffectSequence::iterator aIter = aMainSequence->getBegin();
297 EffectSequence::iterator aEnd = aMainSequence->getEnd();
298 if ( aIter != aEnd )
300 const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
301 rpDescriptor,
302 PageObjectLayouter::CustomAnimationEffectIndicator,
303 PageObjectLayouter::ModelCoordinateSystem));
304 rDevice.DrawBitmapEx(
305 aBox.TopCenter(),
306 pPageObjectLayouter->GetCustomAnimationEffectIcon().GetBitmapEx());
310 void PageObjectPainter::PaintBackgroundDetail (
311 PageObjectLayouter *pPageObjectLayouter,
312 OutputDevice& rDevice,
313 const model::SharedPageDescriptor& rpDescriptor) const
315 enum State { None = 0x00, Selected = 0x01, MouseOver = 0x02, Focused = 0x04 };
316 const int eState =
317 (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) ? Selected : None)
318 | (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ? MouseOver : None)
319 | (rpDescriptor->HasState(model::PageDescriptor::ST_Focused) ? Focused : None);
321 bool bHasFocusBorder;
322 Theme::GradientColorType eColorType;
324 switch (eState)
326 case MouseOver | Selected | Focused:
327 eColorType = Theme::Gradient_MouseOverSelectedAndFocusedPage;
328 bHasFocusBorder = true;
329 break;
331 case MouseOver | Selected:
332 eColorType = Theme::Gradient_MouseOverSelected;
333 bHasFocusBorder = false;
334 break;
336 case MouseOver:
337 eColorType = Theme::Gradient_MouseOverPage;
338 bHasFocusBorder = false;
339 break;
341 case MouseOver | Focused:
342 eColorType = Theme::Gradient_MouseOverPage;
343 bHasFocusBorder = true;
344 break;
346 case Selected | Focused:
347 eColorType = Theme::Gradient_SelectedAndFocusedPage;
348 bHasFocusBorder = true;
349 break;
351 case Selected:
352 eColorType = Theme::Gradient_SelectedPage;
353 bHasFocusBorder = false;
354 break;
356 case Focused:
357 eColorType = Theme::Gradient_FocusedPage;
358 bHasFocusBorder = true;
359 break;
361 case None:
362 default:
363 eColorType = Theme::Gradient_NormalPage;
364 bHasFocusBorder = false;
365 break;
368 const Rectangle aFocusSize (pPageObjectLayouter->GetBoundingBox(
369 rpDescriptor,
370 PageObjectLayouter::FocusIndicator,
371 PageObjectLayouter::ModelCoordinateSystem));
373 const Rectangle aPageObjectBox (pPageObjectLayouter->GetBoundingBox(
374 rpDescriptor,
375 PageObjectLayouter::PageObject,
376 PageObjectLayouter::ModelCoordinateSystem));
378 // Fill the background with the background color of the slide sorter.
379 const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background));
380 rDevice.SetFillColor(aBackgroundColor);
381 rDevice.SetLineColor(aBackgroundColor);
382 rDevice.DrawRect(aFocusSize);
384 // Paint the slide area with a linear gradient that starts some pixels
385 // below the top and ends some pixels above the bottom.
386 const Color aTopColor(mpTheme->GetGradientColor(eColorType, Theme::Fill1));
387 const Color aBottomColor(mpTheme->GetGradientColor(eColorType, Theme::Fill2));
388 if (aTopColor != aBottomColor)
390 const sal_Int32 nHeight (aPageObjectBox.GetHeight());
391 const sal_Int32 nDefaultConstantSize(nHeight/4);
392 const sal_Int32 nMinimalGradientSize(40);
393 const sal_Int32 nY1 (
394 ::std::max<sal_Int32>(
396 ::std::min<sal_Int32>(
397 nDefaultConstantSize,
398 (nHeight - nMinimalGradientSize)/2)));
399 const sal_Int32 nY2 (nHeight-nY1);
400 const sal_Int32 nTop (aPageObjectBox.Top());
401 for (sal_Int32 nY=0; nY<nHeight; ++nY)
403 if (nY<=nY1)
404 rDevice.SetLineColor(aTopColor);
405 else if (nY>=nY2)
406 rDevice.SetLineColor(aBottomColor);
407 else
409 Color aColor (aTopColor);
410 aColor.Merge(aBottomColor, 255 * (nY2-nY) / (nY2-nY1));
411 rDevice.SetLineColor(aColor);
413 rDevice.DrawLine(
414 Point(aPageObjectBox.Left(), nY+nTop),
415 Point(aPageObjectBox.Right(), nY+nTop));
418 else
420 rDevice.SetFillColor(aTopColor);
421 rDevice.DrawRect(aPageObjectBox);
424 // Paint the simple border and, for some backgrounds, the focus border.
425 if (bHasFocusBorder)
426 mpFocusBorderPainter->PaintFrame(rDevice, aPageObjectBox);
427 else
428 PaintBorder(rDevice, eColorType, aPageObjectBox);
430 // Get bounding box of the preview around which a shadow is painted.
431 // Compensate for the border around the preview.
432 const Rectangle aBox (pPageObjectLayouter->GetBoundingBox(
433 rpDescriptor,
434 PageObjectLayouter::Preview,
435 PageObjectLayouter::ModelCoordinateSystem));
436 Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1);
437 mpShadowPainter->PaintFrame(rDevice, aFrameBox);
440 void PageObjectPainter::PaintBorder (
441 OutputDevice& rDevice,
442 const Theme::GradientColorType eColorType,
443 const Rectangle& rBox) const
445 rDevice.SetFillColor();
446 const sal_Int32 nBorderWidth (1);
447 for (int nIndex=0; nIndex<nBorderWidth; ++nIndex)
449 const int nDelta (nIndex);
450 rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border2));
451 rDevice.DrawLine(
452 Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
453 Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta));
454 rDevice.DrawLine(
455 Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta),
456 Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta));
457 rDevice.DrawLine(
458 Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta),
459 Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
461 rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border1));
462 rDevice.DrawLine(
463 Point(rBox.Left()-nDelta, rBox.Top()-nDelta),
464 Point(rBox.Right()+nDelta, rBox.Top()-nDelta));
468 } } } // end of namespace sd::slidesorter::view
470 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */