Line data Source code
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 :
20 :
21 : #include "view/SlsInsertionIndicatorOverlay.hxx"
22 :
23 : #include "SlideSorter.hxx"
24 : #include "model/SlsPageEnumeration.hxx"
25 : #include "view/SlideSorterView.hxx"
26 : #include "view/SlsLayouter.hxx"
27 : #include "view/SlsPageObjectLayouter.hxx"
28 : #include "view/SlsTheme.hxx"
29 : #include "cache/SlsPageCache.hxx"
30 : #include "SlsFramePainter.hxx"
31 : #include "SlsLayeredDevice.hxx"
32 : #include "DrawDocShell.hxx"
33 : #include "drawdoc.hxx"
34 : #include "sdpage.hxx"
35 : #include "sdmod.hxx"
36 :
37 : #include <vcl/virdev.hxx>
38 : #include <basegfx/range/b2drectangle.hxx>
39 : #include <basegfx/tools/canvastools.hxx>
40 : #include <basegfx/polygon/b2dpolygon.hxx>
41 : #include <basegfx/polygon/b2dpolygontools.hxx>
42 :
43 :
44 : namespace {
45 :
46 :
47 : static const double gnPreviewOffsetScale = 1.0 / 8.0;
48 :
49 :
50 :
51 0 : Rectangle GrowRectangle (const Rectangle& rBox, const sal_Int32 nOffset)
52 : {
53 : return Rectangle (
54 0 : rBox.Left() - nOffset,
55 0 : rBox.Top() - nOffset,
56 0 : rBox.Right() + nOffset,
57 0 : rBox.Bottom() + nOffset);
58 : }
59 :
60 0 : sal_Int32 RoundToInt (const double nValue) { return sal_Int32(::rtl::math::round(nValue)); }
61 :
62 : } // end of anonymous namespace
63 :
64 :
65 : namespace sd { namespace slidesorter { namespace view {
66 :
67 :
68 : //===== InsertionIndicatorOverlay ===========================================
69 :
70 : const static sal_Int32 gnShadowBorder = 3;
71 : const static sal_Int32 gnSuperScaleFactor = 1;
72 :
73 0 : InsertionIndicatorOverlay::InsertionIndicatorOverlay (SlideSorter& rSlideSorter)
74 : : mrSlideSorter(rSlideSorter),
75 : mbIsVisible(false),
76 : mnLayerIndex(2),
77 : mpLayerInvalidator(),
78 : maLocation(),
79 : maIcon(),
80 : maIconOffset(),
81 : mpShadowPainter(
82 0 : new FramePainter(mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_RawInsertShadow)))
83 : {
84 0 : }
85 :
86 :
87 :
88 :
89 0 : InsertionIndicatorOverlay::~InsertionIndicatorOverlay (void)
90 : {
91 0 : Hide();
92 0 : }
93 :
94 :
95 :
96 :
97 0 : void InsertionIndicatorOverlay::Create (const SdTransferable* pTransferable)
98 : {
99 0 : if (pTransferable == NULL)
100 : return;
101 :
102 : ::boost::shared_ptr<controller::TransferableData> pData (
103 0 : controller::TransferableData::GetFromTransferable(pTransferable));
104 0 : if ( ! pData)
105 : return;
106 0 : sal_Int32 nSelectionCount (0);
107 0 : if (pTransferable->HasPageBookmarks())
108 0 : nSelectionCount = pTransferable->GetPageBookmarks().size();
109 : else
110 : {
111 0 : DrawDocShell* pDataDocShell = dynamic_cast<DrawDocShell*>(&pTransferable->GetDocShell());
112 0 : if (pDataDocShell != NULL)
113 : {
114 0 : SdDrawDocument* pDataDocument = pDataDocShell->GetDoc();
115 0 : if (pDataDocument != NULL)
116 0 : nSelectionCount = pDataDocument->GetSdPageCount(PK_STANDARD);
117 : }
118 : }
119 0 : Create(pData->GetRepresentatives(), nSelectionCount);
120 : }
121 :
122 :
123 :
124 :
125 0 : void InsertionIndicatorOverlay::Create (
126 : const ::std::vector<controller::TransferableData::Representative>& rRepresentatives,
127 : const sal_Int32 nSelectionCount)
128 : {
129 0 : view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter());
130 : ::boost::shared_ptr<view::PageObjectLayouter> pPageObjectLayouter (
131 0 : rLayouter.GetPageObjectLayouter());
132 0 : ::boost::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme());
133 : const Size aOriginalPreviewSize (pPageObjectLayouter->GetSize(
134 : PageObjectLayouter::Preview,
135 0 : PageObjectLayouter::WindowCoordinateSystem));
136 :
137 0 : const double nPreviewScale (0.5);
138 : const Size aPreviewSize (
139 0 : RoundToInt(aOriginalPreviewSize.Width()*nPreviewScale),
140 0 : RoundToInt(aOriginalPreviewSize.Height()*nPreviewScale));
141 : const sal_Int32 nOffset (
142 0 : RoundToInt(Min(aPreviewSize.Width(),aPreviewSize.Height()) * gnPreviewOffsetScale));
143 :
144 : // Determine size and offset depending on the number of previews.
145 0 : sal_Int32 nCount (rRepresentatives.size());
146 0 : if (nCount > 0)
147 0 : --nCount;
148 : Size aIconSize(
149 0 : aPreviewSize.Width() + 2 * gnShadowBorder + nCount*nOffset,
150 0 : aPreviewSize.Height() + 2 * gnShadowBorder + nCount*nOffset);
151 0 : maIconOffset = Point(gnShadowBorder, gnShadowBorder);
152 :
153 : // Create virtual devices for bitmap and mask whose bitmaps later be
154 : // combined to form the BitmapEx of the icon.
155 : VirtualDevice aContent (
156 0 : *mrSlideSorter.GetContentWindow(),
157 : 0,
158 0 : 0);
159 0 : aContent.SetOutputSizePixel(aIconSize);
160 :
161 0 : aContent.SetFillColor();
162 0 : aContent.SetLineColor(pTheme->GetColor(Theme::Color_PreviewBorder));
163 0 : const Point aOffset = PaintRepresentatives(aContent, aPreviewSize, nOffset, rRepresentatives);
164 :
165 0 : PaintPageCount(aContent, nSelectionCount, aPreviewSize, aOffset);
166 :
167 0 : maIcon = aContent.GetBitmapEx(Point(0,0), aIconSize);
168 0 : maIcon.Scale(aIconSize);
169 0 : }
170 :
171 :
172 :
173 :
174 0 : Point InsertionIndicatorOverlay::PaintRepresentatives (
175 : OutputDevice& rContent,
176 : const Size aPreviewSize,
177 : const sal_Int32 nOffset,
178 : const ::std::vector<controller::TransferableData::Representative>& rRepresentatives) const
179 : {
180 0 : const Point aOffset (0,rRepresentatives.size()==1 ? -nOffset : 0);
181 :
182 : // Paint the pages.
183 0 : Point aPageOffset (0,0);
184 0 : double nTransparency (0);
185 0 : const BitmapEx aExclusionOverlay (mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_HideSlideOverlay));
186 0 : for (sal_Int32 nIndex=2; nIndex>=0; --nIndex)
187 : {
188 0 : if (rRepresentatives.size() <= sal_uInt32(nIndex))
189 0 : continue;
190 0 : switch(nIndex)
191 : {
192 : case 0 :
193 0 : aPageOffset = Point(0, nOffset);
194 0 : nTransparency = 0.85;
195 0 : break;
196 : case 1:
197 0 : aPageOffset = Point(nOffset, 0);
198 0 : nTransparency = 0.75;
199 0 : break;
200 : case 2:
201 0 : aPageOffset = Point(2*nOffset, 2*nOffset);
202 0 : nTransparency = 0.65;
203 0 : break;
204 : }
205 0 : aPageOffset += aOffset;
206 0 : aPageOffset.X() += gnShadowBorder;
207 0 : aPageOffset.Y() += gnShadowBorder;
208 :
209 : // Paint the preview.
210 0 : Bitmap aPreview (rRepresentatives[nIndex].maBitmap);
211 : const Size aSuperSampleSize(
212 : aPreviewSize.Width()*gnSuperScaleFactor,
213 0 : aPreviewSize.Height()*gnSuperScaleFactor);
214 0 : aPreview.Scale(aPreviewSize, BMP_SCALE_BEST);
215 0 : rContent.DrawBitmapEx(aPageOffset, aPreview);
216 :
217 : // When the page is marked as excluded from the slide show then
218 : // paint an overlay that visualizes this.
219 0 : if (rRepresentatives[nIndex].mbIsExcluded)
220 : {
221 0 : const Region aSavedClipRegion (rContent.GetClipRegion());
222 0 : rContent.IntersectClipRegion(Rectangle(aPageOffset, aPreviewSize));
223 : // Paint bitmap tiled over the preview to mark it as excluded.
224 0 : const sal_Int32 nIconWidth (aExclusionOverlay.GetSizePixel().Width());
225 0 : const sal_Int32 nIconHeight (aExclusionOverlay.GetSizePixel().Height());
226 0 : if (nIconWidth>0 && nIconHeight>0)
227 : {
228 0 : for (sal_Int32 nX=0; nX<aPreviewSize.Width(); nX+=nIconWidth)
229 0 : for (sal_Int32 nY=0; nY<aPreviewSize.Height(); nY+=nIconHeight)
230 0 : rContent.DrawBitmapEx(Point(nX,nY)+aPageOffset, aExclusionOverlay);
231 : }
232 0 : rContent.SetClipRegion(aSavedClipRegion);
233 : }
234 :
235 : // Tone down the bitmap. The further back the darker it becomes.
236 : Rectangle aBox (
237 0 : aPageOffset.X(),
238 0 : aPageOffset.Y(),
239 0 : aPageOffset.X()+aPreviewSize.Width()-1,
240 0 : aPageOffset.Y()+aPreviewSize.Height()-1);
241 0 : rContent.SetFillColor(COL_BLACK);
242 0 : rContent.SetLineColor();
243 : rContent.DrawTransparent(
244 : ::basegfx::B2DPolyPolygon(::basegfx::tools::createPolygonFromRect(
245 0 : ::basegfx::B2DRectangle(aBox.Left(), aBox.Top(), aBox.Right()+1, aBox.Bottom()+1),
246 : 0,
247 : 0)),
248 0 : nTransparency);
249 :
250 : // Draw border around preview.
251 0 : Rectangle aBorderBox (GrowRectangle(aBox, 1));
252 0 : rContent.SetLineColor(COL_GRAY);
253 0 : rContent.SetFillColor();
254 0 : rContent.DrawRect(aBorderBox);
255 :
256 : // Draw shadow around preview.
257 0 : mpShadowPainter->PaintFrame(rContent, aBorderBox);
258 0 : }
259 :
260 0 : return aPageOffset;
261 : }
262 :
263 :
264 :
265 :
266 0 : void InsertionIndicatorOverlay::PaintPageCount (
267 : OutputDevice& rDevice,
268 : const sal_Int32 nSelectionCount,
269 : const Size aPreviewSize,
270 : const Point aFirstPageOffset) const
271 : {
272 : // Paint the number of slides.
273 0 : ::boost::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme());
274 0 : ::boost::shared_ptr<Font> pFont(Theme::GetFont(Theme::Font_PageCount, rDevice));
275 0 : if (pFont)
276 : {
277 0 : ::rtl::OUString sNumber (::rtl::OUString::valueOf(nSelectionCount));
278 :
279 : // Determine the size of the (painted) text and create a bounding
280 : // box that centers the text on the first preview.
281 0 : rDevice.SetFont(*pFont);
282 0 : Rectangle aTextBox;
283 0 : rDevice.GetTextBoundRect(aTextBox, sNumber);
284 0 : Point aTextOffset (aTextBox.TopLeft());
285 0 : Size aTextSize (aTextBox.GetSize());
286 : // Place text inside the first page preview.
287 0 : Point aTextLocation(aFirstPageOffset);
288 : // Center the text.
289 : aTextLocation += Point(
290 0 : (aPreviewSize.Width()-aTextBox.GetWidth())/2,
291 0 : (aPreviewSize.Height()-aTextBox.GetHeight())/2);
292 0 : aTextBox = Rectangle(aTextLocation, aTextSize);
293 :
294 : // Paint background, border and text.
295 : static const sal_Int32 nBorder = 5;
296 0 : rDevice.SetFillColor(pTheme->GetColor(Theme::Color_Selection));
297 0 : rDevice.SetLineColor(pTheme->GetColor(Theme::Color_Selection));
298 0 : rDevice.DrawRect(GrowRectangle(aTextBox, nBorder));
299 :
300 0 : rDevice.SetFillColor();
301 0 : rDevice.SetLineColor(pTheme->GetColor(Theme::Color_PageCountFontColor));
302 0 : rDevice.DrawRect(GrowRectangle(aTextBox, nBorder-1));
303 :
304 0 : rDevice.SetTextColor(pTheme->GetColor(Theme::Color_PageCountFontColor));
305 0 : rDevice.DrawText(aTextBox.TopLeft()-aTextOffset, sNumber);
306 0 : }
307 0 : }
308 :
309 :
310 :
311 :
312 0 : void InsertionIndicatorOverlay::SetLocation (const Point& rLocation)
313 : {
314 : const Point aTopLeft (
315 : rLocation - Point(
316 0 : maIcon.GetSizePixel().Width()/2,
317 0 : maIcon.GetSizePixel().Height()/2));
318 0 : if (maLocation != aTopLeft)
319 : {
320 0 : const Rectangle aOldBoundingBox (GetBoundingBox());
321 :
322 0 : maLocation = aTopLeft;
323 :
324 0 : if (mpLayerInvalidator && IsVisible())
325 : {
326 0 : mpLayerInvalidator->Invalidate(aOldBoundingBox);
327 0 : mpLayerInvalidator->Invalidate(GetBoundingBox());
328 : }
329 : }
330 0 : }
331 :
332 :
333 :
334 :
335 0 : void InsertionIndicatorOverlay::Paint (
336 : OutputDevice& rDevice,
337 : const Rectangle& rRepaintArea)
338 : {
339 : (void)rRepaintArea;
340 :
341 0 : if ( ! IsVisible())
342 0 : return;
343 :
344 0 : rDevice.DrawImage(maLocation, maIcon);
345 : }
346 :
347 :
348 :
349 :
350 0 : void InsertionIndicatorOverlay::SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator)
351 : {
352 0 : mpLayerInvalidator = rpInvalidator;
353 :
354 0 : if (mbIsVisible && mpLayerInvalidator)
355 0 : mpLayerInvalidator->Invalidate(GetBoundingBox());
356 0 : }
357 :
358 :
359 :
360 :
361 0 : bool InsertionIndicatorOverlay::IsVisible (void) const
362 : {
363 0 : return mbIsVisible;
364 : }
365 :
366 :
367 :
368 :
369 0 : void InsertionIndicatorOverlay::Show (void)
370 : {
371 0 : if ( ! mbIsVisible)
372 : {
373 0 : mbIsVisible = true;
374 :
375 : ::boost::shared_ptr<LayeredDevice> pLayeredDevice (
376 0 : mrSlideSorter.GetView().GetLayeredDevice());
377 0 : if (pLayeredDevice)
378 : {
379 0 : pLayeredDevice->RegisterPainter(shared_from_this(), mnLayerIndex);
380 0 : if (mpLayerInvalidator)
381 0 : mpLayerInvalidator->Invalidate(GetBoundingBox());
382 0 : }
383 : }
384 0 : }
385 :
386 :
387 :
388 :
389 0 : void InsertionIndicatorOverlay::Hide (void)
390 : {
391 0 : if (mbIsVisible)
392 : {
393 0 : mbIsVisible = false;
394 :
395 : ::boost::shared_ptr<LayeredDevice> pLayeredDevice (
396 0 : mrSlideSorter.GetView().GetLayeredDevice());
397 0 : if (pLayeredDevice)
398 : {
399 0 : if (mpLayerInvalidator)
400 0 : mpLayerInvalidator->Invalidate(GetBoundingBox());
401 0 : pLayeredDevice->RemovePainter(shared_from_this(), mnLayerIndex);
402 0 : }
403 : }
404 0 : }
405 :
406 :
407 :
408 :
409 0 : Rectangle InsertionIndicatorOverlay::GetBoundingBox (void) const
410 : {
411 0 : return Rectangle(maLocation, maIcon.GetSizePixel());
412 : }
413 :
414 :
415 :
416 :
417 0 : Size InsertionIndicatorOverlay::GetSize (void) const
418 : {
419 : return Size(
420 0 : maIcon.GetSizePixel().Width() + 10,
421 0 : maIcon.GetSizePixel().Height() + 10);
422 : }
423 :
424 :
425 :
426 : } } } // end of namespace ::sd::slidesorter::view
427 :
428 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|