bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsInsertionIndicatorOverlay.cxx
blob8af23d854945a3ed965ed4250d4a2b24906ac7ee
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/SlsInsertionIndicatorOverlay.hxx>
22 #include <SlideSorter.hxx>
23 #include <model/SlsPageEnumeration.hxx>
24 #include <view/SlideSorterView.hxx>
25 #include <view/SlsLayouter.hxx>
26 #include <view/SlsPageObjectLayouter.hxx>
27 #include <view/SlsTheme.hxx>
28 #include <cache/SlsPageCache.hxx>
29 #include "SlsFramePainter.hxx"
30 #include "SlsLayeredDevice.hxx"
31 #include <DrawDocShell.hxx>
32 #include <drawdoc.hxx>
33 #include <sdpage.hxx>
34 #include <sdmod.hxx>
35 #include <Window.hxx>
37 #include <vcl/virdev.hxx>
38 #include <basegfx/range/b2drectangle.hxx>
39 #include <basegfx/utils/canvastools.hxx>
40 #include <basegfx/polygon/b2dpolygon.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
43 namespace {
45 static const double gnPreviewOffsetScale = 1.0 / 8.0;
47 ::tools::Rectangle GrowRectangle (const ::tools::Rectangle& rBox, const sal_Int32 nOffset)
49 return ::tools::Rectangle (
50 rBox.Left() - nOffset,
51 rBox.Top() - nOffset,
52 rBox.Right() + nOffset,
53 rBox.Bottom() + nOffset);
56 sal_Int32 RoundToInt (const double nValue) { return sal_Int32(::rtl::math::round(nValue)); }
58 } // end of anonymous namespace
60 namespace sd { namespace slidesorter { namespace view {
62 //===== InsertionIndicatorOverlay ===========================================
64 const static sal_Int32 gnShadowBorder = 3;
65 const static sal_Int32 gnLayerIndex = 2;
67 InsertionIndicatorOverlay::InsertionIndicatorOverlay (SlideSorter& rSlideSorter)
68 : mrSlideSorter(rSlideSorter),
69 mbIsVisible(false),
70 mpLayerInvalidator(),
71 maLocation(),
72 maIcon(),
73 mpShadowPainter(
74 new FramePainter(mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_RawInsertShadow)))
78 InsertionIndicatorOverlay::~InsertionIndicatorOverlay() COVERITY_NOEXCEPT_FALSE
80 Hide();
83 void InsertionIndicatorOverlay::Create (const SdTransferable* pTransferable)
85 if (pTransferable == nullptr)
86 return;
88 std::shared_ptr<controller::TransferableData> pData (
89 controller::TransferableData::GetFromTransferable(pTransferable));
90 if ( ! pData)
91 return;
92 sal_Int32 nSelectionCount (0);
93 if (pTransferable->HasPageBookmarks())
94 nSelectionCount = pTransferable->GetPageBookmarks().size();
95 else
97 DrawDocShell* pDataDocShell = dynamic_cast<DrawDocShell*>(pTransferable->GetDocShell().get());
98 if (pDataDocShell != nullptr)
100 SdDrawDocument* pDataDocument = pDataDocShell->GetDoc();
101 if (pDataDocument != nullptr)
102 nSelectionCount = pDataDocument->GetSdPageCount(PageKind::Standard);
105 Create(pData->GetRepresentatives(), nSelectionCount);
108 void InsertionIndicatorOverlay::Create (
109 const ::std::vector<controller::TransferableData::Representative>& rRepresentatives,
110 const sal_Int32 nSelectionCount)
112 view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter());
113 const std::shared_ptr<view::PageObjectLayouter>& pPageObjectLayouter (
114 rLayouter.GetPageObjectLayouter());
115 std::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme());
116 const Size aOriginalPreviewSize (pPageObjectLayouter->GetPreviewSize());
118 const double nPreviewScale (0.5);
119 const Size aPreviewSize (
120 RoundToInt(aOriginalPreviewSize.Width()*nPreviewScale),
121 RoundToInt(aOriginalPreviewSize.Height()*nPreviewScale));
122 const sal_Int32 nOffset (
123 RoundToInt(std::min(aPreviewSize.Width(),aPreviewSize.Height()) * gnPreviewOffsetScale));
125 // Determine size and offset depending on the number of previews.
126 sal_Int32 nCount (rRepresentatives.size());
127 if (nCount > 0)
128 --nCount;
129 Size aIconSize(
130 aPreviewSize.Width() + 2 * gnShadowBorder + nCount*nOffset,
131 aPreviewSize.Height() + 2 * gnShadowBorder + nCount*nOffset);
133 // Create virtual devices for bitmap and mask whose bitmaps later be
134 // combined to form the BitmapEx of the icon.
135 ScopedVclPtrInstance<VirtualDevice> pContent(
136 *mrSlideSorter.GetContentWindow(), DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
137 pContent->SetOutputSizePixel(aIconSize);
139 pContent->SetFillColor();
140 pContent->SetLineColor(pTheme->GetColor(Theme::Color_PreviewBorder));
141 const Point aOffset = PaintRepresentatives(*pContent, aPreviewSize, nOffset, rRepresentatives);
143 PaintPageCount(*pContent, nSelectionCount, aPreviewSize, aOffset);
145 maIcon = pContent->GetBitmapEx(Point(0,0), aIconSize);
146 maIcon.Scale(aIconSize);
149 Point InsertionIndicatorOverlay::PaintRepresentatives (
150 OutputDevice& rContent,
151 const Size& rPreviewSize,
152 const sal_Int32 nOffset,
153 const ::std::vector<controller::TransferableData::Representative>& rRepresentatives) const
155 const Point aOffset (0,rRepresentatives.size()==1 ? -nOffset : 0);
157 // Paint the pages.
158 Point aPageOffset (0,0);
159 double nTransparency (0);
160 const BitmapEx aExclusionOverlay (mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_HideSlideOverlay));
161 for (sal_Int32 nIndex=2; nIndex>=0; --nIndex)
163 if (rRepresentatives.size() <= sal_uInt32(nIndex))
164 continue;
165 switch(nIndex)
167 case 0 :
168 aPageOffset = Point(0, nOffset);
169 nTransparency = 0.85;
170 break;
171 case 1:
172 aPageOffset = Point(nOffset, 0);
173 nTransparency = 0.75;
174 break;
175 case 2:
176 aPageOffset = Point(2*nOffset, 2*nOffset);
177 nTransparency = 0.65;
178 break;
180 aPageOffset += aOffset;
181 aPageOffset.AdjustX(gnShadowBorder );
182 aPageOffset.AdjustY(gnShadowBorder );
184 // Paint the preview.
185 BitmapEx aPreview (rRepresentatives[nIndex].maBitmap);
186 aPreview.Scale(rPreviewSize, BmpScaleFlag::BestQuality);
187 rContent.DrawBitmapEx(aPageOffset, aPreview);
189 // When the page is marked as excluded from the slide show then
190 // paint an overlay that visualizes this.
191 if (rRepresentatives[nIndex].mbIsExcluded)
193 const vcl::Region aSavedClipRegion (rContent.GetClipRegion());
194 rContent.IntersectClipRegion(::tools::Rectangle(aPageOffset, rPreviewSize));
195 // Paint bitmap tiled over the preview to mark it as excluded.
196 const sal_Int32 nIconWidth (aExclusionOverlay.GetSizePixel().Width());
197 const sal_Int32 nIconHeight (aExclusionOverlay.GetSizePixel().Height());
198 if (nIconWidth>0 && nIconHeight>0)
200 for (long nX=0; nX<rPreviewSize.Width(); nX+=nIconWidth)
201 for (long nY=0; nY<rPreviewSize.Height(); nY+=nIconHeight)
202 rContent.DrawBitmapEx(Point(nX,nY)+aPageOffset, aExclusionOverlay);
204 rContent.SetClipRegion(aSavedClipRegion);
207 // Tone down the bitmap. The further back the darker it becomes.
208 ::tools::Rectangle aBox (
209 aPageOffset.X(),
210 aPageOffset.Y(),
211 aPageOffset.X()+rPreviewSize.Width()-1,
212 aPageOffset.Y()+rPreviewSize.Height()-1);
213 rContent.SetFillColor(COL_BLACK);
214 rContent.SetLineColor();
215 rContent.DrawTransparent(
216 basegfx::B2DHomMatrix(),
217 ::basegfx::B2DPolyPolygon(::basegfx::utils::createPolygonFromRect(
218 ::basegfx::B2DRectangle(aBox.Left(), aBox.Top(), aBox.Right()+1, aBox.Bottom()+1),
220 0)),
221 nTransparency);
223 // Draw border around preview.
224 ::tools::Rectangle aBorderBox (GrowRectangle(aBox, 1));
225 rContent.SetLineColor(COL_GRAY);
226 rContent.SetFillColor();
227 rContent.DrawRect(aBorderBox);
229 // Draw shadow around preview.
230 mpShadowPainter->PaintFrame(rContent, aBorderBox);
233 return aPageOffset;
236 void InsertionIndicatorOverlay::PaintPageCount (
237 OutputDevice& rDevice,
238 const sal_Int32 nSelectionCount,
239 const Size& rPreviewSize,
240 const Point& rFirstPageOffset) const
242 // Paint the number of slides.
243 std::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme());
244 std::shared_ptr<vcl::Font> pFont(Theme::GetFont(Theme::Font_PageCount, rDevice));
245 if (!pFont)
246 return;
248 OUString sNumber (OUString::number(nSelectionCount));
250 // Determine the size of the (painted) text and create a bounding
251 // box that centers the text on the first preview.
252 rDevice.SetFont(*pFont);
253 ::tools::Rectangle aTextBox;
254 rDevice.GetTextBoundRect(aTextBox, sNumber);
255 Point aTextOffset (aTextBox.TopLeft());
256 Size aTextSize (aTextBox.GetSize());
257 // Place text inside the first page preview.
258 Point aTextLocation(rFirstPageOffset);
259 // Center the text.
260 aTextLocation += Point(
261 (rPreviewSize.Width()-aTextBox.GetWidth())/2,
262 (rPreviewSize.Height()-aTextBox.GetHeight())/2);
263 aTextBox = ::tools::Rectangle(aTextLocation, aTextSize);
265 // Paint background, border and text.
266 static const sal_Int32 nBorder = 5;
267 rDevice.SetFillColor(pTheme->GetColor(Theme::Color_Selection));
268 rDevice.SetLineColor(pTheme->GetColor(Theme::Color_Selection));
269 rDevice.DrawRect(GrowRectangle(aTextBox, nBorder));
271 rDevice.SetFillColor();
272 rDevice.SetLineColor(pTheme->GetColor(Theme::Color_PageCountFontColor));
273 rDevice.DrawRect(GrowRectangle(aTextBox, nBorder-1));
275 rDevice.SetTextColor(pTheme->GetColor(Theme::Color_PageCountFontColor));
276 rDevice.DrawText(aTextBox.TopLeft()-aTextOffset, sNumber);
279 void InsertionIndicatorOverlay::SetLocation (const Point& rLocation)
281 const Point aTopLeft (
282 rLocation - Point(
283 maIcon.GetSizePixel().Width()/2,
284 maIcon.GetSizePixel().Height()/2));
285 if (maLocation != aTopLeft)
287 const ::tools::Rectangle aOldBoundingBox (GetBoundingBox());
289 maLocation = aTopLeft;
291 if (mpLayerInvalidator && IsVisible())
293 mpLayerInvalidator->Invalidate(aOldBoundingBox);
294 mpLayerInvalidator->Invalidate(GetBoundingBox());
299 void InsertionIndicatorOverlay::Paint (
300 OutputDevice& rDevice,
301 const ::tools::Rectangle&)
303 if ( ! IsVisible())
304 return;
306 rDevice.DrawImage(maLocation, Image(maIcon));
309 void InsertionIndicatorOverlay::SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator)
311 mpLayerInvalidator = rpInvalidator;
313 if (mbIsVisible && mpLayerInvalidator)
314 mpLayerInvalidator->Invalidate(GetBoundingBox());
317 void InsertionIndicatorOverlay::Show()
319 if ( mbIsVisible)
320 return;
322 mbIsVisible = true;
324 std::shared_ptr<LayeredDevice> pLayeredDevice (
325 mrSlideSorter.GetView().GetLayeredDevice());
326 if (pLayeredDevice)
328 pLayeredDevice->RegisterPainter(shared_from_this(), gnLayerIndex);
329 if (mpLayerInvalidator)
330 mpLayerInvalidator->Invalidate(GetBoundingBox());
334 void InsertionIndicatorOverlay::Hide()
336 if (!mbIsVisible)
337 return;
339 mbIsVisible = false;
341 std::shared_ptr<LayeredDevice> pLayeredDevice (
342 mrSlideSorter.GetView().GetLayeredDevice());
343 if (pLayeredDevice)
345 if (mpLayerInvalidator)
346 mpLayerInvalidator->Invalidate(GetBoundingBox());
347 pLayeredDevice->RemovePainter(shared_from_this(), gnLayerIndex);
351 ::tools::Rectangle InsertionIndicatorOverlay::GetBoundingBox() const
353 return ::tools::Rectangle(maLocation, maIcon.GetSizePixel());
356 Size InsertionIndicatorOverlay::GetSize() const
358 return Size(
359 maIcon.GetSizePixel().Width() + 10,
360 maIcon.GetSizePixel().Height() + 10);
363 } } } // end of namespace ::sd::slidesorter::view
365 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */