Files
libreoffice/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx
2010-01-28 13:00:30 +01:00

610 lines
14 KiB
C++

/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: SlsViewOverlay.cxx,v $
* $Revision: 1.16 $
*
* 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/SlsViewOverlay.hxx"
#include "SlideSorter.hxx"
#include "SlideSorterViewShell.hxx"
#include "SlsLayeredDevice.hxx"
#include "model/SlideSorterModel.hxx"
#include "model/SlsPageDescriptor.hxx"
#include "model/SlsPageEnumeration.hxx"
#include "view/SlideSorterView.hxx"
#include "view/SlsLayouter.hxx"
#include "SlsIcons.hxx"
#include "cache/SlsPageCache.hxx"
#include "ViewShell.hxx"
#include "ViewShellBase.hxx"
#include "UpdateLockManager.hxx"
#include "Window.hxx"
#include "sdpage.hxx"
#include "sdresid.hxx"
#include <basegfx/range/b2drectangle.hxx>
#include <basegfx/range/b2drange.hxx>
#include <basegfx/range/b2irange.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <svx/svdpagv.hxx>
#include <svx/sdrpagewindow.hxx>
#include <vcl/svapp.hxx>
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
using namespace ::sdr::overlay;
using namespace ::basegfx;
#define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
namespace {
#define AirForceBlue 0x5d8aa8
#define Arsenic 0x3b444b
#define Amber 0x007fff
#define Charcoal 0x36454f
Rectangle GrowRectangle (const Rectangle& rBox, const sal_Int32 nOffset)
{
return Rectangle (
rBox.Left() - nOffset,
rBox.Top() - nOffset,
rBox.Right() + nOffset,
rBox.Bottom() + nOffset);
}
Rectangle ConvertRectangle (const B2DRectangle& rBox)
{
const B2IRange rIntegerBox (unotools::b2ISurroundingRangeFromB2DRange(rBox));
return Rectangle(
rIntegerBox.getMinX(),
rIntegerBox.getMinY(),
rIntegerBox.getMaxX(),
rIntegerBox.getMaxY());
}
} // end of anonymous namespace
namespace sd { namespace slidesorter { namespace view {
//===== ViewOverlay =========================================================
ViewOverlay::ViewOverlay (
SlideSorter& rSlideSorter,
const ::boost::shared_ptr<LayeredDevice>& rpLayeredDevice)
: mrSlideSorter(rSlideSorter),
mpLayeredDevice(rpLayeredDevice),
mpSelectionRectangleOverlay(new SelectionRectangleOverlay(*this, 2)),
mpInsertionIndicatorOverlay(new InsertionIndicatorOverlay(*this, 3)),
mpSubstitutionOverlay(new SubstitutionOverlay(*this, 2))
{
}
ViewOverlay::~ViewOverlay (void)
{
}
::boost::shared_ptr<SelectionRectangleOverlay> ViewOverlay::GetSelectionRectangleOverlay (void)
{
return mpSelectionRectangleOverlay;
}
::boost::shared_ptr<InsertionIndicatorOverlay> ViewOverlay::GetInsertionIndicatorOverlay (void)
{
return mpInsertionIndicatorOverlay;
}
::boost::shared_ptr<SubstitutionOverlay> ViewOverlay::GetSubstitutionOverlay (void)
{
return mpSubstitutionOverlay;
}
SlideSorter& ViewOverlay::GetSlideSorter (void) const
{
return mrSlideSorter;
}
::boost::shared_ptr<LayeredDevice> ViewOverlay::GetLayeredDevice (void) const
{
return mpLayeredDevice;
}
//===== OverlayBase::Invalidator ==============================================
class OverlayBase::Invalidator
{
public:
Invalidator (OverlayBase& rOverlayObject)
: mrOverlayObject(rOverlayObject),
maOldBoundingBox(rOverlayObject.IsVisible()
? rOverlayObject.GetBoundingBox()
: Rectangle())
{
}
~Invalidator (void)
{
if ( ! maOldBoundingBox.IsEmpty())
mrOverlayObject.Invalidate(maOldBoundingBox);
if (mrOverlayObject.IsVisible())
mrOverlayObject.Invalidate(mrOverlayObject.GetBoundingBox());
}
private:
OverlayBase& mrOverlayObject;
const Rectangle maOldBoundingBox;
};
//===== OverlayBase =========================================================
OverlayBase::OverlayBase (
ViewOverlay& rViewOverlay,
const sal_Int32 nLayerIndex)
: mrViewOverlay(rViewOverlay),
mbIsVisible(false),
mnLayerIndex(nLayerIndex)
{
}
OverlayBase::~OverlayBase (void)
{
}
bool OverlayBase::IsVisible (void) const
{
return mbIsVisible;
}
void OverlayBase::SetIsVisible (const bool bIsVisible)
{
if (mbIsVisible != bIsVisible)
{
Invalidator aInvalidator (*this);
mbIsVisible = bIsVisible;
::boost::shared_ptr<LayeredDevice> pDevice (mrViewOverlay.GetLayeredDevice());
if (pDevice)
if (mbIsVisible)
{
pDevice->RegisterPainter(shared_from_this(), GetLayerIndex());
Invalidate(GetBoundingBox());
}
else
{
Invalidate(GetBoundingBox());
pDevice->RemovePainter(shared_from_this(), GetLayerIndex());
}
}
}
void OverlayBase::SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator)
{
if ( ! rpInvalidator)
Invalidate(GetBoundingBox());
mpLayerInvalidator = rpInvalidator;
if (mbIsVisible)
Invalidate(GetBoundingBox());
}
void OverlayBase::Invalidate (const Rectangle& rInvalidationBox)
{
if (mpLayerInvalidator)
mpLayerInvalidator->Invalidate(rInvalidationBox);
}
sal_Int32 OverlayBase::GetLayerIndex (void) const
{
return mnLayerIndex;
}
//===== SubstitutionOverlay =================================================
const sal_Int32 SubstitutionOverlay::mnCenterTransparency (60);
const sal_Int32 SubstitutionOverlay::mnSideTransparency (85);
const sal_Int32 SubstitutionOverlay::mnCornerTransparency (95);
SubstitutionOverlay::SubstitutionOverlay (
ViewOverlay& rViewOverlay,
const sal_Int32 nLayerIndex)
: OverlayBase(rViewOverlay, nLayerIndex),
maPosition(0,0),
maTranslation(0,0),
maItems(),
maBoundingBox()
{
}
SubstitutionOverlay::~SubstitutionOverlay (void)
{
}
void SubstitutionOverlay::Create (
model::PageEnumeration& rSelection,
const Point& rPosition,
const model::SharedPageDescriptor& rpHitDescriptor)
{
maPosition = rPosition;
maTranslation = Point(0,0);
::boost::shared_ptr<cache::PageCache> pPreviewCache (
mrViewOverlay.GetSlideSorter().GetView().GetPreviewCache());
view::Layouter& rLayouter (mrViewOverlay.GetSlideSorter().GetView().GetLayouter());
::boost::shared_ptr<view::PageObjectLayouter> pPageObjectLayouter (
rLayouter.GetPageObjectLayouter());
const sal_Int32 nRow0 (rpHitDescriptor
? rLayouter.GetRow(rpHitDescriptor->GetPageIndex())
: -1);
const sal_Int32 nColumn0 (rpHitDescriptor
? rLayouter.GetColumn(rpHitDescriptor->GetPageIndex())
: -1);
maItems.clear();
while (rSelection.HasMoreElements())
{
model::SharedPageDescriptor pDescriptor (rSelection.GetNextElement());
sal_uInt8 nTransparency (128);
// Calculate distance between current page object and the one under
// the mouse.
if (nRow0>=0 || nColumn0>=0)
{
const sal_Int32 nRow (rLayouter.GetRow(pDescriptor->GetPageIndex()));
const sal_Int32 nColumn (rLayouter.GetColumn(pDescriptor->GetPageIndex()));
const sal_Int32 nRowDistance (abs(nRow - nRow0));
const sal_Int32 nColumnDistance (abs(nColumn - nColumn0));
if (nRowDistance>1 || nColumnDistance>1)
continue;
if (nRowDistance!=0 && nColumnDistance!=0)
nTransparency = 255 * mnCornerTransparency / 100;
else if (nRowDistance!=0 || nColumnDistance!=0)
nTransparency = 255 * mnSideTransparency / 100;
else
nTransparency = 255 * mnCenterTransparency / 100;
}
const Rectangle aBox (pDescriptor->GetBoundingBox());
maBoundingBox.Union(aBox);
basegfx::B2DRectangle aB2DBox(
aBox.Left(),
aBox.Top(),
aBox.Right(),
aBox.Bottom());
const Bitmap aBitmap (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage()).GetBitmap());
AlphaMask aMask (aBitmap.GetSizePixel());
aMask.Erase(nTransparency);
maItems.push_back(ItemDescriptor());
maItems.back().maImage = BitmapEx(
aBitmap,
aMask);
maItems.back().maLocation = pPageObjectLayouter->GetBoundingBox(
pDescriptor,
PageObjectLayouter::Preview,
PageObjectLayouter::WindowCoordinateSystem).TopLeft();
maItems.back().mnTransparency = nTransparency/255.0;
maItems.back().maShape = basegfx::tools::createPolygonFromRect(aB2DBox);
}
SetIsVisible(maItems.size() > 0);
}
void SubstitutionOverlay::Clear (void)
{
SetIsVisible(false);
maItems.clear();
}
void SubstitutionOverlay::Move (const Point& rOffset)
{
Invalidator aInvalidator (*this);
maPosition += rOffset;
maTranslation += rOffset;
maBoundingBox.Move(rOffset.X(), rOffset.Y());
}
void SubstitutionOverlay::SetPosition (const Point& rPosition)
{
Move(rPosition - GetPosition());
}
Point SubstitutionOverlay::GetPosition (void) const
{
return maPosition;
}
void SubstitutionOverlay::Paint (
OutputDevice& rDevice,
const Rectangle& rRepaintArea)
{
(void)rRepaintArea;
if ( ! IsVisible())
return;
basegfx::B2DHomMatrix aTranslation;
aTranslation.translate(maTranslation.X(), maTranslation.Y());
rDevice.SetFillColor(Color(AirForceBlue));
rDevice.SetLineColor();
for (::std::vector<ItemDescriptor>::const_iterator
iItem(maItems.begin()),
iEnd(maItems.end());
iItem!=iEnd;
++iItem)
{
::basegfx::B2DPolyPolygon aPolygon (iItem->maShape);
aPolygon.transform(aTranslation);
rDevice.DrawTransparent(aPolygon, iItem->mnTransparency);
rDevice.DrawBitmapEx(iItem->maLocation+maTranslation, iItem->maImage);
}
}
Rectangle SubstitutionOverlay::GetBoundingBox (void) const
{
return maBoundingBox;
}
//===== SelectionRectangleOverlay ===========================================
SelectionRectangleOverlay::SelectionRectangleOverlay (
ViewOverlay& rViewOverlay,
const sal_Int32 nLayerIndex)
: OverlayBase (rViewOverlay, nLayerIndex),
maAnchor(0,0),
maSecondCorner(0,0)
{
}
Rectangle SelectionRectangleOverlay::GetSelectionRectangle (void)
{
return Rectangle(maAnchor, maSecondCorner);
}
void SelectionRectangleOverlay::Start (const Point& rAnchor)
{
SetIsVisible(false);
maAnchor = rAnchor;
maSecondCorner = rAnchor;
}
void SelectionRectangleOverlay::Update (const Point& rSecondCorner)
{
Invalidator aInvalidator (*this);
maSecondCorner = rSecondCorner;
SetIsVisible(true);
}
void SelectionRectangleOverlay::Paint (
OutputDevice& rDevice,
const Rectangle& rRepaintArea)
{
if ( ! IsVisible())
return;
rDevice.SetFillColor(Color(Amber));
rDevice.SetLineColor(Color(Amber));
const Rectangle aBox (
::std::min(maAnchor.X(), maSecondCorner.X()),
::std::min(maAnchor.Y(), maSecondCorner.Y()),
::std::max(maAnchor.X(), maSecondCorner.X()),
::std::max(maAnchor.Y(), maSecondCorner.Y()));
if (rRepaintArea.IsOver(aBox))
rDevice.DrawTransparent(
::basegfx::B2DPolyPolygon(
::basegfx::tools::createPolygonFromRect(
::basegfx::B2DRectangle(aBox.Left(), aBox.Top(), aBox.Right(), aBox.Bottom()),
5.0/aBox.GetWidth(),
5.0/aBox.GetHeight())),
0.5);
}
Rectangle SelectionRectangleOverlay::GetBoundingBox (void) const
{
return GrowRectangle(Rectangle(
::std::min(maAnchor.X(), maSecondCorner.X()),
::std::min(maAnchor.Y(), maSecondCorner.Y()),
::std::max(maAnchor.X(), maSecondCorner.X()),
::std::max(maAnchor.Y(), maSecondCorner.Y())),
+1);
}
//===== InsertionIndicatorOverlay ===========================================
InsertionIndicatorOverlay::InsertionIndicatorOverlay (
ViewOverlay& rViewOverlay,
const sal_Int32 nLayerIndex)
: OverlayBase (rViewOverlay, nLayerIndex),
maLocation(),
maIconWithBorder(),
maIcon(),
maMask()
{
LocalResource aResource (IMG_ICONS);
maIconWithBorder = Image(SdResId(IMAGE_INSERTION_INDICATOR_SELECT));
maIcon = Image(SdResId(IMAGE_INSERTION_INDICATOR_NORMAL));
maMask = Image(SdResId(IMAGE_INSERTION_INDICATOR_MASK));
}
void InsertionIndicatorOverlay::SetLocation (const Point& rLocation)
{
const Point aTopLeft (
rLocation - Point(
maIconWithBorder.GetSizePixel().Width()/2,
maIconWithBorder.GetSizePixel().Height()/2));
if (maLocation != aTopLeft)
{
Invalidator aInvalidator (*this);
maLocation = aTopLeft;
}
}
void InsertionIndicatorOverlay::Paint (
OutputDevice& rDevice,
const Rectangle& rRepaintArea)
{
(void)rRepaintArea;
if ( ! IsVisible())
return;
rDevice.DrawImage(
maLocation,
maIconWithBorder);
}
Rectangle InsertionIndicatorOverlay::GetBoundingBox (void) const
{
return Rectangle(maLocation, maIconWithBorder.GetSizePixel());
}
} } } // end of namespace ::sd::slidesorter::view