diff options
Diffstat (limited to 'sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx')
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx new file mode 100644 index 000000000000..abaa5a43b215 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx @@ -0,0 +1,448 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 <vcl/virdev.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + + +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 controller::Transferable* pTransferable) +{ + if (pTransferable == NULL) + return; + + sal_Int32 nSelectionCount (0); + if (pTransferable->HasPageBookmarks()) + nSelectionCount = pTransferable->GetPageBookmarks().Count(); + else + { + DrawDocShell* pDataDocShell = dynamic_cast<DrawDocShell*>(&pTransferable->GetDocShell()); + if (pDataDocShell != NULL) + { + SdDrawDocument* pDataDocument = pDataDocShell->GetDoc(); + if (pDataDocument != NULL) + nSelectionCount = pDataDocument->GetSdPageCount(PK_STANDARD); + } + } + Create(pTransferable->GetRepresentatives(), nSelectionCount); +} + + + + +void InsertionIndicatorOverlay::Create ( + const ::std::vector<controller::Transferable::Representative>& rRepresentatives, + const sal_Int32 nSelectionCount) +{ + view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); + ::boost::shared_ptr<view::PageObjectLayouter> pPageObjectLayouter ( + rLayouter.GetPageObjectLayouter()); + ::boost::shared_ptr<view::Theme> 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<model::SharedPageDescriptor>& 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<controller::Transferable::Representative>& 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.85; + break; + case 1: + aPageOffset = Point(nOffset, 0); + nTransparency = 0.75; + break; + case 2: + aPageOffset = Point(2*nOffset, 2*nOffset); + nTransparency = 0.65; + 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_INTERPOLATE); + 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; nX<aPreviewSize.Width(); nX+=nIconWidth) + for (sal_Int32 nY=0; nY<aPreviewSize.Height(); nY+=nIconHeight) + rContent.DrawBitmapEx(Point(nX,nY)+aPageOffset, aExclusionOverlay); + } + rContent.SetClipRegion(aSavedClipRegion); + } + + // Tone down the bitmap. The further back the darker it becomes. + Rectangle aBox ( + aPageOffset.X(), + aPageOffset.Y(), + aPageOffset.X()+aPreviewSize.Width()-1, + aPageOffset.Y()+aPreviewSize.Height()-1); + rContent.SetFillColor(COL_BLACK); + rContent.SetLineColor(); + rContent.DrawTransparent( + ::basegfx::B2DPolyPolygon(::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle(aBox.Left(), aBox.Top(), aBox.Right()+1, aBox.Bottom()+1), + 0, + 0)), + nTransparency); + + // Draw border around preview. + Rectangle aBorderBox (GrowRectangle(aBox, 1)); + rContent.SetLineColor(COL_GRAY); + rContent.SetFillColor(); + rContent.DrawRect(aBorderBox); + + // Draw shadow around preview. + mpShadowPainter->PaintFrame(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<view::Theme> pTheme (mrSlideSorter.GetTheme()); + ::boost::shared_ptr<Font> 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<LayeredDevice> 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<LayeredDevice> 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 + |