/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "precompiled_sd.hxx" #include "view/SlsInsertionIndicatorOverlay.hxx" #include "SlideSorter.hxx" #include "model/SlsPageEnumeration.hxx" #include "view/SlideSorterView.hxx" #include "view/SlsLayouter.hxx" #include "view/SlsPageObjectLayouter.hxx" #include "view/SlsTheme.hxx" #include "cache/SlsPageCache.hxx" #include "SlsFramePainter.hxx" #include "SlsLayeredDevice.hxx" #include "DrawDocShell.hxx" #include "drawdoc.hxx" #include "sdpage.hxx" #include "sdmod.hxx" #include #include #include #include #include namespace { static const double gnPreviewOffsetScale = 1.0 / 8.0; Rectangle GrowRectangle (const Rectangle& rBox, const sal_Int32 nOffset) { return Rectangle ( rBox.Left() - nOffset, rBox.Top() - nOffset, rBox.Right() + nOffset, rBox.Bottom() + nOffset); } sal_Int32 RoundToInt (const double nValue) { return sal_Int32(::rtl::math::round(nValue)); } } // end of anonymous namespace namespace sd { namespace slidesorter { namespace view { //===== InsertionIndicatorOverlay ============================================= const static sal_Int32 gnShadowBorder = 3; const static sal_Int32 gnSuperScaleFactor = 1; InsertionIndicatorOverlay::InsertionIndicatorOverlay (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), mbIsVisible(false), mnLayerIndex(2), mpLayerInvalidator(), maLocation(), maIcon(), maIconOffset(), mpShadowPainter( new FramePainter(mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_RawInsertShadow))) { } InsertionIndicatorOverlay::~InsertionIndicatorOverlay (void) { Hide(); } void InsertionIndicatorOverlay::Create (const SdTransferable* pTransferable) { if (pTransferable == NULL) return; ::boost::shared_ptr pData ( controller::TransferableData::GetFromTransferable(pTransferable)); if ( ! pData) return; sal_Int32 nSelectionCount (0); if (pTransferable->HasPageBookmarks()) nSelectionCount = pTransferable->GetPageBookmarks().Count(); else { DrawDocShell* pDataDocShell = dynamic_cast(&pTransferable->GetDocShell()); if (pDataDocShell != NULL) { SdDrawDocument* pDataDocument = pDataDocShell->GetDoc(); if (pDataDocument != NULL) nSelectionCount = pDataDocument->GetSdPageCount(PK_STANDARD); } } Create(pData->GetRepresentatives(), nSelectionCount); } void InsertionIndicatorOverlay::Create ( const ::std::vector& rRepresentatives, const sal_Int32 nSelectionCount) { view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); ::boost::shared_ptr pPageObjectLayouter ( rLayouter.GetPageObjectLayouter()); ::boost::shared_ptr pTheme (mrSlideSorter.GetTheme()); const Size aOriginalPreviewSize (pPageObjectLayouter->GetSize( PageObjectLayouter::Preview, PageObjectLayouter::WindowCoordinateSystem)); const double nPreviewScale (0.5); const Size aPreviewSize ( RoundToInt(aOriginalPreviewSize.Width()*nPreviewScale), RoundToInt(aOriginalPreviewSize.Height()*nPreviewScale)); const sal_Int32 nOffset ( RoundToInt(Min(aPreviewSize.Width(),aPreviewSize.Height()) * gnPreviewOffsetScale)); // Determine size and offset depending on the number of previews. sal_Int32 nCount (rRepresentatives.size()); if (nCount > 0) --nCount; Size aIconSize( aPreviewSize.Width() + 2 * gnShadowBorder + nCount*nOffset, aPreviewSize.Height() + 2 * gnShadowBorder + nCount*nOffset); maIconOffset = Point(gnShadowBorder, gnShadowBorder); // Create virtual devices for bitmap and mask whose bitmaps later be // combined to form the BitmapEx of the icon. VirtualDevice aContent ( *mrSlideSorter.GetContentWindow(), 0, 0); aContent.SetOutputSizePixel(aIconSize); aContent.SetFillColor(); aContent.SetLineColor(pTheme->GetColor(Theme::Color_PreviewBorder)); const Point aOffset = PaintRepresentatives(aContent, aPreviewSize, nOffset, rRepresentatives); PaintPageCount(aContent, nSelectionCount, aPreviewSize, aOffset); maIcon = aContent.GetBitmapEx(Point(0,0), aIconSize); maIcon.Scale(aIconSize); } void InsertionIndicatorOverlay::SelectRepresentatives ( model::PageEnumeration& rSelection, ::std::vector& rDescriptors) const { sal_Int32 nCount (0); while (rSelection.HasMoreElements()) { if (nCount++ >= 3) break; rDescriptors.push_back(rSelection.GetNextElement()); } } Point InsertionIndicatorOverlay::PaintRepresentatives ( OutputDevice& rContent, const Size aPreviewSize, const sal_Int32 nOffset, const ::std::vector& rRepresentatives) const { const Point aOffset (0,rRepresentatives.size()==1 ? -nOffset : 0); // Paint the pages. Point aPageOffset (0,0); double nTransparency (0); const BitmapEx aExclusionOverlay (mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_HideSlideOverlay)); for (sal_Int32 nIndex=2; nIndex>=0; --nIndex) { if (rRepresentatives.size() <= sal_uInt32(nIndex)) continue; switch(nIndex) { case 0 : aPageOffset = Point(0, nOffset); nTransparency = 0.95; break; case 1: aPageOffset = Point(nOffset, 0); nTransparency = 0.85; break; case 2: aPageOffset = Point(2*nOffset, 2*nOffset); nTransparency = 0.75; break; } aPageOffset += aOffset; aPageOffset.X() += gnShadowBorder; aPageOffset.Y() += gnShadowBorder; // Paint the preview. Bitmap aPreview (rRepresentatives[nIndex].maBitmap); const Size aSuperSampleSize( aPreviewSize.Width()*gnSuperScaleFactor, aPreviewSize.Height()*gnSuperScaleFactor); aPreview.Scale(aPreviewSize, BMP_SCALE_FASTESTINTERPOLATE); rContent.DrawBitmapEx(aPageOffset, aPreview); // When the page is marked as excluded from the slide show then // paint an overlay that visualizes this. if (rRepresentatives[nIndex].mbIsExcluded) { const Region aSavedClipRegion (rContent.GetClipRegion()); rContent.IntersectClipRegion(Rectangle(aPageOffset, aPreviewSize)); // Paint bitmap tiled over the preview to mark it as excluded. const sal_Int32 nIconWidth (aExclusionOverlay.GetSizePixel().Width()); const sal_Int32 nIconHeight (aExclusionOverlay.GetSizePixel().Height()); if (nIconWidth>0 && nIconHeight>0) { for (sal_Int32 nX=0; nXPaintFrame(rContent, aBorderBox); } return aPageOffset; } void InsertionIndicatorOverlay::PaintPageCount ( OutputDevice& rDevice, const sal_Int32 nSelectionCount, const Size aPreviewSize, const Point aFirstPageOffset) const { // Paint the number of slides. ::boost::shared_ptr pTheme (mrSlideSorter.GetTheme()); ::boost::shared_ptr pFont(Theme::GetFont(Theme::Font_PageCount, rDevice)); if (pFont) { ::rtl::OUString sNumber (::rtl::OUString::valueOf(nSelectionCount)); // Determine the size of the (painted) text and create a bounding // box that centers the text on the first preview. rDevice.SetFont(*pFont); Rectangle aTextBox; rDevice.GetTextBoundRect(aTextBox, sNumber); Point aTextOffset (aTextBox.TopLeft()); Size aTextSize (aTextBox.GetSize()); // Place text inside the first page preview. Point aTextLocation(aFirstPageOffset); // Center the text. aTextLocation += Point( (aPreviewSize.Width()-aTextBox.GetWidth())/2, (aPreviewSize.Height()-aTextBox.GetHeight())/2); aTextBox = Rectangle(aTextLocation, aTextSize); // Paint background, border and text. static const sal_Int32 nBorder = 5; rDevice.SetFillColor(pTheme->GetColor(Theme::Color_Selection)); rDevice.SetLineColor(pTheme->GetColor(Theme::Color_Selection)); rDevice.DrawRect(GrowRectangle(aTextBox, nBorder)); rDevice.SetFillColor(); rDevice.SetLineColor(pTheme->GetColor(Theme::Color_PageCountFontColor)); rDevice.DrawRect(GrowRectangle(aTextBox, nBorder-1)); rDevice.SetTextColor(pTheme->GetColor(Theme::Color_PageCountFontColor)); rDevice.DrawText(aTextBox.TopLeft()-aTextOffset, sNumber); } } void InsertionIndicatorOverlay::SetLocation (const Point& rLocation) { const Point aTopLeft ( rLocation - Point( maIcon.GetSizePixel().Width()/2, maIcon.GetSizePixel().Height()/2)); if (maLocation != aTopLeft) { const Rectangle aOldBoundingBox (GetBoundingBox()); maLocation = aTopLeft; if (mpLayerInvalidator && IsVisible()) { mpLayerInvalidator->Invalidate(aOldBoundingBox); mpLayerInvalidator->Invalidate(GetBoundingBox()); } } } void InsertionIndicatorOverlay::Paint ( OutputDevice& rDevice, const Rectangle& rRepaintArea) { (void)rRepaintArea; if ( ! IsVisible()) return; rDevice.DrawImage(maLocation, maIcon); } void InsertionIndicatorOverlay::SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator) { mpLayerInvalidator = rpInvalidator; if (mbIsVisible && mpLayerInvalidator) mpLayerInvalidator->Invalidate(GetBoundingBox()); } bool InsertionIndicatorOverlay::IsVisible (void) const { return mbIsVisible; } void InsertionIndicatorOverlay::Show (void) { if ( ! mbIsVisible) { mbIsVisible = true; ::boost::shared_ptr pLayeredDevice ( mrSlideSorter.GetView().GetLayeredDevice()); if (pLayeredDevice) { pLayeredDevice->RegisterPainter(shared_from_this(), mnLayerIndex); if (mpLayerInvalidator) mpLayerInvalidator->Invalidate(GetBoundingBox()); } } } void InsertionIndicatorOverlay::Hide (void) { if (mbIsVisible) { mbIsVisible = false; ::boost::shared_ptr pLayeredDevice ( mrSlideSorter.GetView().GetLayeredDevice()); if (pLayeredDevice) { if (mpLayerInvalidator) mpLayerInvalidator->Invalidate(GetBoundingBox()); pLayeredDevice->RemovePainter(shared_from_this(), mnLayerIndex); } } } Rectangle InsertionIndicatorOverlay::GetBoundingBox (void) const { return Rectangle(maLocation, maIcon.GetSizePixel()); } Size InsertionIndicatorOverlay::GetSize (void) const { return Size( maIcon.GetSizePixel().Width() + 10, maIcon.GetSizePixel().Height() + 10); } } } } // end of namespace ::sd::slidesorter::view /* vim: set noet sw=4 ts=4: */