1355 lines
53 KiB
C++
1355 lines
53 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: SlsPageObjectViewObjectContact.cxx,v $
|
|
* $Revision: 1.23 $
|
|
*
|
|
* 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/SlsPageObjectViewObjectContact.hxx"
|
|
|
|
#include "controller/SlsProperties.hxx"
|
|
#include "view/SlideSorterView.hxx"
|
|
#include "view/SlsPageObjectViewContact.hxx"
|
|
#include "view/SlsPageObject.hxx"
|
|
#include "view/SlsFontProvider.hxx"
|
|
#include "model/SlsPageDescriptor.hxx"
|
|
#include "cache/SlsPageCache.hxx"
|
|
#include "cache/SlsPageCacheManager.hxx"
|
|
#include "res_bmp.hrc"
|
|
#include "tools/IconCache.hxx"
|
|
#include "PreviewRenderer.hxx"
|
|
|
|
#include "sdpage.hxx"
|
|
#include "sdresid.hxx"
|
|
#include "glob.hrc"
|
|
#include "drawdoc.hxx"
|
|
#include <svx/sdr/contact/displayinfo.hxx>
|
|
#include <svx/sdr/contact/viewcontact.hxx>
|
|
#include <svx/svdopage.hxx>
|
|
#include <svx/svdpagv.hxx>
|
|
#include <svx/xlndsit.hxx>
|
|
#include <svx/xlnclit.hxx>
|
|
#include <svx/svdoutl.hxx>
|
|
#include <svx/sdrpagewindow.hxx>
|
|
#include <vcl/bitmap.hxx>
|
|
#include <vcl/outdev.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <vcl/lineinfo.hxx>
|
|
#include <tools/color.hxx>
|
|
#include <boost/shared_ptr.hpp>
|
|
#include <com/sun/star/uno/Exception.hpp>
|
|
#include <vcl/svapp.hxx>
|
|
|
|
using namespace ::sdr::contact;
|
|
using namespace ::sd::slidesorter::model;
|
|
|
|
using drawinglayer::primitive2d::Primitive2DReference;
|
|
using drawinglayer::primitive2d::Primitive2DSequence;
|
|
|
|
namespace sd { namespace slidesorter { namespace view {
|
|
|
|
|
|
const sal_Int32 PageObjectViewObjectContact::mnSelectionIndicatorOffset = 2;
|
|
const sal_Int32 PageObjectViewObjectContact::mnSelectionIndicatorThickness = 3;
|
|
const sal_Int32 PageObjectViewObjectContact::mnFocusIndicatorOffset = 3;
|
|
const sal_Int32 PageObjectViewObjectContact::mnFadeEffectIndicatorOffset = 9;
|
|
const sal_Int32 PageObjectViewObjectContact::mnFadeEffectIndicatorSize = 14;
|
|
const sal_Int32 PageObjectViewObjectContact::mnPageNumberOffset = 9;
|
|
const sal_Int32 PageObjectViewObjectContact::mnMouseOverEffectOffset = 3;
|
|
const sal_Int32 PageObjectViewObjectContact::mnMouseOverEffectThickness = 1;
|
|
|
|
PageObjectViewObjectContact::PageObjectViewObjectContact (
|
|
ObjectContact& rObjectContact,
|
|
ViewContact& rViewContact,
|
|
const ::boost::shared_ptr<cache::PageCache>& rpCache,
|
|
const ::boost::shared_ptr<controller::Properties>& rpProperties)
|
|
: ViewObjectContactOfPageObj(rObjectContact, rViewContact),
|
|
mbInDestructor(false),
|
|
mxCurrentPageContents(),
|
|
mpCache(rpCache),
|
|
mpProperties(rpProperties)
|
|
{
|
|
SharedPageDescriptor pDescriptor (GetPageDescriptor());
|
|
OSL_ASSERT(pDescriptor.get()!=NULL);
|
|
if (pDescriptor.get() != NULL)
|
|
pDescriptor->SetViewObjectContact(this);
|
|
}
|
|
|
|
|
|
|
|
|
|
PageObjectViewObjectContact::~PageObjectViewObjectContact (void)
|
|
{
|
|
mbInDestructor = true;
|
|
|
|
GetPageDescriptor()->SetViewObjectContact(NULL);
|
|
|
|
if (mpCache.get() != NULL)
|
|
{
|
|
const SdrPage* pPage = GetPage();
|
|
|
|
if(pPage)
|
|
{
|
|
mpCache->ReleasePreviewBitmap(GetPage());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void PageObjectViewObjectContact::SetCache (const ::boost::shared_ptr<cache::PageCache>& rpCache)
|
|
{
|
|
mpCache = rpCache;
|
|
}
|
|
|
|
|
|
|
|
|
|
Rectangle PageObjectViewObjectContact::GetBoundingBox (
|
|
OutputDevice& rDevice,
|
|
BoundingBoxType eType,
|
|
CoordinateSystem eCoordinateSystem) const
|
|
{
|
|
// Most of the bounding boxes are based on the bounding box of the preview.
|
|
// SdrPageObj is a SdrObject, so use SdrObject::aOutRect as model data
|
|
const PageObjectViewContact& rPaObVOC(static_cast<PageObjectViewContact&>(GetViewContact()));
|
|
Rectangle aBoundingBox(rPaObVOC.GetPageObject().GetLastBoundRect());
|
|
|
|
CoordinateSystem eCurrentCoordinateSystem (ModelCoordinateSystem);
|
|
switch(eType)
|
|
{
|
|
case PageObjectBoundingBox:
|
|
{
|
|
const SvBorder aPageDescriptorBorder(GetPageDescriptor()->GetModelBorder());
|
|
aBoundingBox.Left() -= aPageDescriptorBorder.Left();
|
|
aBoundingBox.Top() -= aPageDescriptorBorder.Top();
|
|
aBoundingBox.Right() += aPageDescriptorBorder.Right();
|
|
aBoundingBox.Bottom() += aPageDescriptorBorder.Bottom();
|
|
break;
|
|
}
|
|
case PreviewBoundingBox:
|
|
{
|
|
// The aBoundingBox already has the right value.
|
|
break;
|
|
}
|
|
case MouseOverIndicatorBoundingBox:
|
|
{
|
|
const sal_Int32 nBorderWidth (mnMouseOverEffectOffset+mnMouseOverEffectThickness);
|
|
const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth)));
|
|
aBoundingBox.Left() -= aBorderSize.Width();
|
|
aBoundingBox.Top() -= aBorderSize.Height();
|
|
aBoundingBox.Right() += aBorderSize.Width();
|
|
aBoundingBox.Bottom() += aBorderSize.Height();
|
|
break;
|
|
}
|
|
case FocusIndicatorBoundingBox:
|
|
{
|
|
const sal_Int32 nBorderWidth (mnFocusIndicatorOffset+1);
|
|
const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth)));
|
|
aBoundingBox.Left() -= aBorderSize.Width();
|
|
aBoundingBox.Top() -= aBorderSize.Height();
|
|
aBoundingBox.Right() += aBorderSize.Width();
|
|
aBoundingBox.Bottom() += aBorderSize.Height();
|
|
break;
|
|
}
|
|
case SelectionIndicatorBoundingBox:
|
|
{
|
|
const sal_Int32 nBorderWidth(mnSelectionIndicatorOffset+mnSelectionIndicatorThickness);
|
|
const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth)));
|
|
aBoundingBox.Left() -= aBorderSize.Width();
|
|
aBoundingBox.Top() -= aBorderSize.Height();
|
|
aBoundingBox.Right() += aBorderSize.Width();
|
|
aBoundingBox.Bottom() += aBorderSize.Height();
|
|
break;
|
|
}
|
|
case PageNumberBoundingBox:
|
|
{
|
|
Size aModelOffset = rDevice.PixelToLogic(Size(mnPageNumberOffset,mnPageNumberOffset));
|
|
Size aNumberSize (GetPageDescriptor()->GetPageNumberAreaModelSize());
|
|
aBoundingBox = Rectangle (
|
|
Point (
|
|
aBoundingBox.Left() - aModelOffset.Width() - aNumberSize.Width(),
|
|
aBoundingBox.Top()),
|
|
aNumberSize);
|
|
break;
|
|
}
|
|
|
|
case NameBoundingBox:
|
|
break;
|
|
|
|
case FadeEffectIndicatorBoundingBox:
|
|
Size aModelOffset = rDevice.PixelToLogic(Size (0, mnFadeEffectIndicatorOffset));
|
|
// Flush left just outside the selection rectangle.
|
|
aBoundingBox = Rectangle (
|
|
Point (
|
|
aBoundingBox.Left(),
|
|
aBoundingBox.Bottom() + aModelOffset.Height()
|
|
),
|
|
rDevice.PixelToLogic (
|
|
IconCache::Instance().GetIcon(BMP_FADE_EFFECT_INDICATOR).GetSizePixel())
|
|
);
|
|
break;
|
|
}
|
|
|
|
// Make sure the bounding box uses the requested coordinate system.
|
|
if (eCurrentCoordinateSystem != eCoordinateSystem)
|
|
{
|
|
if (eCoordinateSystem == ModelCoordinateSystem)
|
|
aBoundingBox = Rectangle(
|
|
rDevice.PixelToLogic(aBoundingBox.TopLeft()),
|
|
rDevice.PixelToLogic(aBoundingBox.GetSize()));
|
|
else
|
|
aBoundingBox = Rectangle(
|
|
rDevice.LogicToPixel(aBoundingBox.TopLeft()),
|
|
rDevice.LogicToPixel(aBoundingBox.GetSize()));
|
|
}
|
|
return aBoundingBox;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
// example implementation for primitive usage for PageObjectViewObjectContact
|
|
|
|
} } } // end of namespace ::sd::slidesorter::view
|
|
|
|
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
#include <basegfx/matrix/b2dhommatrix.hxx>
|
|
#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
|
|
#include <sd_primitivetypes2d.hxx>
|
|
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
|
|
#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
|
|
#include <drawinglayer/primitive2d/textprimitive2d.hxx>
|
|
#include <drawinglayer/geometry/viewinformation2d.hxx>
|
|
#include <svx/sdr/contact/objectcontact.hxx>
|
|
|
|
namespace sd { namespace slidesorter { namespace view {
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
// All primitives for SdrPageObject visualisation are based on one range which describes
|
|
// the size of the inner rectangle for PagePreview visualisation. Use a common implementation
|
|
// class for all derived SdPageObjectPrimitives. The SdPageObjectBasePrimitive itself
|
|
// is pure virtual
|
|
|
|
class SdPageObjectBasePrimitive : public drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
|
|
{
|
|
private:
|
|
// the inner range of the SdPageObject visualisation
|
|
basegfx::B2DRange maRange;
|
|
|
|
public:
|
|
// constructor and destructor
|
|
SdPageObjectBasePrimitive(const basegfx::B2DRange& rRange);
|
|
virtual ~SdPageObjectBasePrimitive();
|
|
|
|
// data access
|
|
const basegfx::B2DRange& getPageObjectRange() const { return maRange; }
|
|
|
|
// compare operator
|
|
virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
|
|
};
|
|
|
|
SdPageObjectBasePrimitive::SdPageObjectBasePrimitive(const basegfx::B2DRange& rRange)
|
|
: drawinglayer::primitive2d::BufferedDecompositionPrimitive2D(),
|
|
maRange(rRange)
|
|
{
|
|
}
|
|
|
|
SdPageObjectBasePrimitive::~SdPageObjectBasePrimitive()
|
|
{
|
|
}
|
|
|
|
bool SdPageObjectBasePrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
|
|
{
|
|
if(drawinglayer::primitive2d::BufferedDecompositionPrimitive2D::operator==(rPrimitive))
|
|
{
|
|
const SdPageObjectBasePrimitive& rCompare = static_cast< const SdPageObjectBasePrimitive& >(rPrimitive);
|
|
return (getPageObjectRange() == rCompare.getPageObjectRange());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
// SdPageObjectPrimitive for selected visualisation
|
|
|
|
class SdPageObjectPageBitmapPrimitive : public SdPageObjectBasePrimitive
|
|
{
|
|
private:
|
|
// the bitmap containing the PagePreview
|
|
BitmapEx maBitmapEx;
|
|
|
|
protected:
|
|
// method which is to be used to implement the local decomposition of a 2D primitive.
|
|
virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
|
|
|
|
public:
|
|
// constructor and destructor
|
|
SdPageObjectPageBitmapPrimitive(
|
|
const basegfx::B2DRange& rRange,
|
|
const BitmapEx& rBitmapEx);
|
|
~SdPageObjectPageBitmapPrimitive();
|
|
|
|
// data access
|
|
const BitmapEx& getBitmapEx() const { return maBitmapEx; }
|
|
|
|
// compare operator
|
|
virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
|
|
|
|
// provide unique ID
|
|
DeclPrimitrive2DIDBlock()
|
|
};
|
|
|
|
Primitive2DSequence SdPageObjectPageBitmapPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
|
|
{
|
|
// add bitmap primitive
|
|
// to avoid scaling, use the Bitmap pixel size as primitive size
|
|
basegfx::B2DHomMatrix aBitmapTransform;
|
|
const Size aBitmapSize(getBitmapEx().GetSizePixel());
|
|
const basegfx::B2DVector aBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() *
|
|
basegfx::B2DVector(aBitmapSize.getWidth() - 1, aBitmapSize.getHeight() - 1));
|
|
|
|
// short form for scale and translate transformation
|
|
aBitmapTransform.set(0L, 0L, aBitmapSizeLogic.getX());
|
|
aBitmapTransform.set(1L, 1L, aBitmapSizeLogic.getY());
|
|
aBitmapTransform.set(0L, 2L, getPageObjectRange().getMinX());
|
|
aBitmapTransform.set(1L, 2L, getPageObjectRange().getMinY());
|
|
|
|
// add a BitmapPrimitive2D to the result
|
|
const Primitive2DReference xReference(
|
|
new drawinglayer::primitive2d::BitmapPrimitive2D(getBitmapEx(), aBitmapTransform));
|
|
return Primitive2DSequence(&xReference, 1);
|
|
}
|
|
|
|
SdPageObjectPageBitmapPrimitive::SdPageObjectPageBitmapPrimitive(
|
|
const basegfx::B2DRange& rRange,
|
|
const BitmapEx& rBitmapEx)
|
|
: SdPageObjectBasePrimitive(rRange),
|
|
maBitmapEx(rBitmapEx)
|
|
{
|
|
}
|
|
|
|
SdPageObjectPageBitmapPrimitive::~SdPageObjectPageBitmapPrimitive()
|
|
{
|
|
}
|
|
|
|
bool SdPageObjectPageBitmapPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
|
|
{
|
|
if(SdPageObjectBasePrimitive::operator==(rPrimitive))
|
|
{
|
|
const SdPageObjectPageBitmapPrimitive& rCompare = static_cast< const SdPageObjectPageBitmapPrimitive& >(rPrimitive);
|
|
return (getBitmapEx() == rCompare.getBitmapEx());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ImplPrimitrive2DIDBlock(SdPageObjectPageBitmapPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTPAGEBITMAPPRIMITIVE)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
// SdPageObjectPrimitive for selected visualisation
|
|
|
|
class SdPageObjectSelectPrimitive : public SdPageObjectBasePrimitive
|
|
{
|
|
private:
|
|
/// Gap between border of page object and inside of selection rectangle.
|
|
static const sal_Int32 mnSelectionIndicatorOffset;
|
|
|
|
/// Thickness of the selection rectangle.
|
|
static const sal_Int32 mnSelectionIndicatorThickness;
|
|
|
|
protected:
|
|
// method which is to be used to implement the local decomposition of a 2D primitive.
|
|
virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
|
|
|
|
public:
|
|
// constructor and destructor
|
|
SdPageObjectSelectPrimitive(const basegfx::B2DRange& rRange);
|
|
~SdPageObjectSelectPrimitive();
|
|
|
|
// provide unique ID
|
|
DeclPrimitrive2DIDBlock()
|
|
};
|
|
|
|
const sal_Int32 SdPageObjectSelectPrimitive::mnSelectionIndicatorOffset(1);
|
|
const sal_Int32 SdPageObjectSelectPrimitive::mnSelectionIndicatorThickness(3);
|
|
|
|
Primitive2DSequence SdPageObjectSelectPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
|
|
{
|
|
Primitive2DSequence xRetval(2);
|
|
|
|
// since old Width/Height calculations always added a single pixel value,
|
|
// it is necessary to create a inner range which is one display unit less
|
|
// at the bottom right.
|
|
const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
|
|
const basegfx::B2DRange aAdaptedInnerRange(
|
|
getPageObjectRange().getMinX(), getPageObjectRange().getMinY(),
|
|
getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY());
|
|
|
|
// PaintSelectionIndicator replacement. Grow by offset first
|
|
basegfx::B2DRange aDiscreteOuterRange(aAdaptedInnerRange);
|
|
aDiscreteOuterRange.grow(mnSelectionIndicatorOffset * aDiscretePixel.getX());
|
|
|
|
// Remember inner border. Make it one bigger in top left since polygons
|
|
// do not paint their lower-right corners. Since this is the inner polygon,
|
|
// the top-left corders are the ones to grow here
|
|
const basegfx::B2DRange aDiscreteInnerRange(
|
|
aDiscreteOuterRange.getMinimum() + aDiscretePixel,
|
|
aDiscreteOuterRange.getMaximum() - aDiscretePixel);
|
|
|
|
// grow by line width
|
|
aDiscreteOuterRange.grow((mnSelectionIndicatorThickness - 1) * aDiscretePixel.getX());
|
|
|
|
// create a PolyPolygon from those ranges. For the outer polygon, round edges by
|
|
// giving a relative radius to the polygon creator (use mnSelectionIndicatorThickness here, too)
|
|
const double fPixelFactor(aDiscretePixel.getX() * (mnSelectionIndicatorThickness + 2.5));
|
|
const double fRelativeRadiusX(fPixelFactor / ::std::max(aDiscreteOuterRange.getWidth(), 1.0));
|
|
const double fRelativeRadiusY(fPixelFactor / ::std::max(aDiscreteOuterRange.getHeight(), 1.0));
|
|
basegfx::B2DPolyPolygon aFramePolyPolygon;
|
|
const basegfx::B2DPolygon aRoundedOuterPolygon(basegfx::tools::createPolygonFromRect(aDiscreteOuterRange, fRelativeRadiusX, fRelativeRadiusY));
|
|
|
|
aFramePolyPolygon.append(aRoundedOuterPolygon);
|
|
aFramePolyPolygon.append(basegfx::tools::createPolygonFromRect(aDiscreteInnerRange));
|
|
|
|
// add colored PolyPolygon
|
|
const svtools::ColorConfig aColorConfig;
|
|
static bool bTestWithBrightColors(false);
|
|
const basegfx::BColor aFrameColor(bTestWithBrightColors ? basegfx::BColor(0,1,0) : Application::GetSettings().GetStyleSettings().GetMenuHighlightColor().getBColor());
|
|
|
|
xRetval[0] = Primitive2DReference(
|
|
new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(aFramePolyPolygon, aFrameColor));
|
|
|
|
// add aRoundedOuterPolygon again as non-filled line polygon to get the roundungs
|
|
// painted correctly
|
|
xRetval[1] = Primitive2DReference(
|
|
new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aRoundedOuterPolygon, aFrameColor));
|
|
|
|
return xRetval;
|
|
}
|
|
|
|
SdPageObjectSelectPrimitive::SdPageObjectSelectPrimitive(const basegfx::B2DRange& rRange)
|
|
: SdPageObjectBasePrimitive(rRange)
|
|
{
|
|
}
|
|
|
|
SdPageObjectSelectPrimitive::~SdPageObjectSelectPrimitive()
|
|
{
|
|
}
|
|
|
|
ImplPrimitrive2DIDBlock(SdPageObjectSelectPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTSELECTPRIMITIVE)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
// SdPageObjectPrimitive for border around bitmap visualisation
|
|
|
|
class SdPageObjectBorderPrimitive : public SdPageObjectBasePrimitive
|
|
{
|
|
protected:
|
|
// method which is to be used to implement the local decomposition of a 2D primitive.
|
|
virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
|
|
|
|
public:
|
|
// constructor and destructor
|
|
SdPageObjectBorderPrimitive(const basegfx::B2DRange& rRange);
|
|
~SdPageObjectBorderPrimitive();
|
|
|
|
// provide unique ID
|
|
DeclPrimitrive2DIDBlock()
|
|
};
|
|
|
|
Primitive2DSequence SdPageObjectBorderPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
|
|
{
|
|
// since old Width/Height calculations always added a single pixel value,
|
|
// it is necessary to create a inner range which is one display unit less
|
|
// at the bottom right.
|
|
const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
|
|
const basegfx::B2DRange aAdaptedInnerRange(
|
|
getPageObjectRange().getMinX(), getPageObjectRange().getMinY(),
|
|
getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY());
|
|
|
|
// Paint_Border replacement. (use aBorderColor)
|
|
static bool bTestWithBrightColors(false);
|
|
const svtools::ColorConfig aColorConfig;
|
|
const basegfx::BColor aBorderColor(bTestWithBrightColors ? basegfx::BColor(1,0,0) : Color(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor).getBColor());
|
|
|
|
const Primitive2DReference xReference(
|
|
new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(basegfx::tools::createPolygonFromRect(aAdaptedInnerRange), aBorderColor));
|
|
return Primitive2DSequence(&xReference, 1);
|
|
}
|
|
|
|
SdPageObjectBorderPrimitive::SdPageObjectBorderPrimitive(const basegfx::B2DRange& rRange)
|
|
: SdPageObjectBasePrimitive(rRange)
|
|
{
|
|
}
|
|
|
|
SdPageObjectBorderPrimitive::~SdPageObjectBorderPrimitive()
|
|
{
|
|
}
|
|
|
|
ImplPrimitrive2DIDBlock(SdPageObjectBorderPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTBORDERPRIMITIVE)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
// SdPageObjectPrimitive for focus visualisation
|
|
|
|
class SdPageObjectFocusPrimitive : public SdPageObjectBasePrimitive
|
|
{
|
|
private:
|
|
/// Gap between border of page object and inside of focus rectangle.
|
|
static const sal_Int32 mnFocusIndicatorOffset;
|
|
|
|
protected:
|
|
// method which is to be used to implement the local decomposition of a 2D primitive.
|
|
virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
|
|
|
|
public:
|
|
// constructor and destructor
|
|
SdPageObjectFocusPrimitive(const basegfx::B2DRange& rRange);
|
|
~SdPageObjectFocusPrimitive();
|
|
|
|
// provide unique ID
|
|
DeclPrimitrive2DIDBlock()
|
|
};
|
|
|
|
const sal_Int32 SdPageObjectFocusPrimitive::mnFocusIndicatorOffset(2);
|
|
|
|
Primitive2DSequence SdPageObjectFocusPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
|
|
{
|
|
Primitive2DSequence xRetval(2);
|
|
|
|
// since old Width/Height calculations always added a single pixel value,
|
|
// it is necessary to create a inner range which is one display unit less
|
|
// at the bottom right.
|
|
const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
|
|
const basegfx::B2DRange aAdaptedInnerRange(
|
|
getPageObjectRange().getMinX(), getPageObjectRange().getMinY(),
|
|
getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY());
|
|
|
|
// Paint_FocusIndicator replacement. (black and white).
|
|
// imitate Paint_DottedRectangle: First paint a white rectangle and above it a black dotted one
|
|
basegfx::B2DRange aFocusIndicatorRange(aAdaptedInnerRange);
|
|
aFocusIndicatorRange.grow(mnFocusIndicatorOffset * aDiscretePixel.getX());
|
|
|
|
// create polygon
|
|
const basegfx::B2DPolygon aIndicatorPolygon(basegfx::tools::createPolygonFromRect(aFocusIndicatorRange));
|
|
|
|
// white rectangle
|
|
xRetval[0] = Primitive2DReference(
|
|
new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aIndicatorPolygon, Color(COL_WHITE).getBColor()));
|
|
|
|
// dotted black rectangle with same geometry
|
|
::std::vector< double > aDotDashArray;
|
|
|
|
aDotDashArray.push_back(aDiscretePixel.getX());
|
|
aDotDashArray.push_back(aDiscretePixel.getX());
|
|
|
|
// prepare line and stroke attributes
|
|
const drawinglayer::attribute::LineAttribute aLineAttribute(Color(COL_BLACK).getBColor());
|
|
const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDotDashArray, 2.0 * aDiscretePixel.getX());
|
|
|
|
xRetval[1] = Primitive2DReference(
|
|
new drawinglayer::primitive2d::PolygonStrokePrimitive2D(aIndicatorPolygon, aLineAttribute, aStrokeAttribute));
|
|
|
|
return xRetval;
|
|
}
|
|
|
|
SdPageObjectFocusPrimitive::SdPageObjectFocusPrimitive(const basegfx::B2DRange& rRange)
|
|
: SdPageObjectBasePrimitive(rRange)
|
|
{
|
|
}
|
|
|
|
SdPageObjectFocusPrimitive::~SdPageObjectFocusPrimitive()
|
|
{
|
|
}
|
|
|
|
ImplPrimitrive2DIDBlock(SdPageObjectFocusPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTFOCUSPRIMITIVE)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
// SdPageObjectPrimitive for fade effect visualisation
|
|
|
|
class SdPageObjectFadeNameNumberPrimitive : public SdPageObjectBasePrimitive
|
|
{
|
|
private:
|
|
/// Size of width and height of the fade effect indicator in pixels.
|
|
static const sal_Int32 mnFadeEffectIndicatorOffset;
|
|
|
|
/// Gap between border of page object and number rectangle.
|
|
static const sal_Int32 mnPageNumberOffset;
|
|
|
|
/// the FadeEffect bitmap. Static since it is usable outside this primitive
|
|
/// for size comparisons
|
|
static BitmapEx* mpFadeEffectIconBitmap;
|
|
|
|
/// page name, number and needed infos
|
|
String maPageName;
|
|
sal_uInt32 mnPageNumber;
|
|
Font maPageNameFont;
|
|
Size maPageNumberAreaModelSize;
|
|
|
|
// bitfield
|
|
bool mbShowFadeEffectIcon : 1;
|
|
bool mbExcluded : 1;
|
|
|
|
// private helpers
|
|
const BitmapEx& getFadeEffectIconBitmap() const;
|
|
|
|
protected:
|
|
// method which is to be used to implement the local decomposition of a 2D primitive.
|
|
virtual Primitive2DSequence create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
|
|
|
|
public:
|
|
// constructor and destructor
|
|
SdPageObjectFadeNameNumberPrimitive(
|
|
const basegfx::B2DRange& rRange,
|
|
const String& rPageName,
|
|
sal_uInt32 nPageNumber,
|
|
const Font& rPageNameFont,
|
|
const Size& rPageNumberAreaModelSize,
|
|
bool bShowFadeEffectIcon,
|
|
bool bExcluded);
|
|
~SdPageObjectFadeNameNumberPrimitive();
|
|
|
|
// data access
|
|
const String& getPageName() const { return maPageName; }
|
|
sal_uInt32 getPageNumber() const { return mnPageNumber; }
|
|
const Font& getPageNameFont() const { return maPageNameFont; }
|
|
const Size& getPageNumberAreaModelSize() const { return maPageNumberAreaModelSize; }
|
|
bool getShowFadeEffectIcon() const { return mbShowFadeEffectIcon; }
|
|
bool getExcluded() const { return mbExcluded; }
|
|
|
|
// compare operator
|
|
virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
|
|
|
|
// provide unique ID
|
|
DeclPrimitrive2DIDBlock()
|
|
};
|
|
|
|
const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnFadeEffectIndicatorOffset(9);
|
|
const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnPageNumberOffset(9);
|
|
BitmapEx* SdPageObjectFadeNameNumberPrimitive::mpFadeEffectIconBitmap = 0;
|
|
|
|
const BitmapEx& SdPageObjectFadeNameNumberPrimitive::getFadeEffectIconBitmap() const
|
|
{
|
|
if(mpFadeEffectIconBitmap == NULL)
|
|
{
|
|
// prepare FadeEffectIconBitmap on demand
|
|
const sal_uInt16 nIconId(Application::GetSettings().GetStyleSettings().GetHighContrastMode()
|
|
? BMP_FADE_EFFECT_INDICATOR_H
|
|
: BMP_FADE_EFFECT_INDICATOR);
|
|
const BitmapEx aFadeEffectIconBitmap(IconCache::Instance().GetIcon(nIconId).GetBitmapEx());
|
|
const_cast< SdPageObjectFadeNameNumberPrimitive* >(this)->mpFadeEffectIconBitmap = new BitmapEx(aFadeEffectIconBitmap);
|
|
}
|
|
|
|
return *mpFadeEffectIconBitmap;
|
|
}
|
|
|
|
Primitive2DSequence SdPageObjectFadeNameNumberPrimitive::create2DDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
|
|
{
|
|
const xub_StrLen nTextLength(getPageName().Len());
|
|
const sal_uInt32 nCount(
|
|
(getShowFadeEffectIcon() ? 1 : 0) + // FadeEffect icon
|
|
(nTextLength ? 1 : 0) + // PageName
|
|
1 + // PageNumber (always)
|
|
(getExcluded() ? 2 : 0) // PageNumber crossed out
|
|
);
|
|
sal_uInt32 nInsert(0);
|
|
Primitive2DSequence xRetval(nCount);
|
|
|
|
// since old Width/Height calculations always added a single pixel value,
|
|
// it is necessary to create a inner range which is one display unit less
|
|
// at the bottom right.
|
|
const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
|
|
const basegfx::B2DRange aAdaptedInnerRange(
|
|
getPageObjectRange().getMinX(), getPageObjectRange().getMinY(),
|
|
getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY());
|
|
|
|
// preapre TextLayouter
|
|
drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
|
|
aTextLayouter.setFont(getPageNameFont());
|
|
|
|
// get font attributes
|
|
::basegfx::B2DVector aTextSizeAttribute;
|
|
const drawinglayer::primitive2d::FontAttributes aFontAttributes(drawinglayer::primitive2d::getFontAttributesFromVclFont(
|
|
aTextSizeAttribute,
|
|
getPageNameFont(),
|
|
false,
|
|
false));
|
|
|
|
// prepare DXTextArray (can be empty one)
|
|
const ::std::vector< double > aDXArray;
|
|
|
|
// prepare locale; this may need some more information in the future
|
|
const ::com::sun::star::lang::Locale aLocale;
|
|
|
|
// prepare font color from System
|
|
const basegfx::BColor aFontColor(Application::GetSettings().GetStyleSettings().GetFontColor().getBColor());
|
|
|
|
if(getShowFadeEffectIcon())
|
|
{
|
|
// prepare fFadeEffect Sizes
|
|
const basegfx::B2DVector aFadeEffectBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() *
|
|
basegfx::B2DVector(
|
|
getFadeEffectIconBitmap().GetSizePixel().getWidth() - 1,
|
|
getFadeEffectIconBitmap().GetSizePixel().getHeight() - 1));
|
|
|
|
// Paint_FadeEffectIndicator replacement.
|
|
// create transformation. To avoid bitmap scaling, use bitmap size as size
|
|
basegfx::B2DHomMatrix aBitmapTransform;
|
|
|
|
// short form for scale and translate transformation
|
|
aBitmapTransform.set(0L, 0L, aFadeEffectBitmapSizeLogic.getX());
|
|
aBitmapTransform.set(1L, 1L, aFadeEffectBitmapSizeLogic.getY());
|
|
aBitmapTransform.set(0L, 2L, aAdaptedInnerRange.getMinX());
|
|
aBitmapTransform.set(1L, 2L, aAdaptedInnerRange.getMaxY() + ((mnFadeEffectIndicatorOffset + 1) * aDiscretePixel.getX()));
|
|
|
|
xRetval[nInsert++] = Primitive2DReference(
|
|
new drawinglayer::primitive2d::BitmapPrimitive2D(getFadeEffectIconBitmap(), aBitmapTransform));
|
|
}
|
|
|
|
if(nTextLength)
|
|
{
|
|
// prepare fFadeEffect Sizes since it consumes from text size
|
|
const basegfx::B2DVector aFadeEffectBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() *
|
|
basegfx::B2DVector(
|
|
getFadeEffectIconBitmap().GetSizePixel().getWidth() - 1,
|
|
getFadeEffectIconBitmap().GetSizePixel().getHeight() - 1));
|
|
|
|
// Paint_PageName replacement. Get text size
|
|
const double fTextWidth(aTextLayouter.getTextWidth(getPageName(), 0, nTextLength));
|
|
const double fTextHeight(getPageNameFont().GetHeight());
|
|
const double fFadeEffectWidth(aFadeEffectBitmapSizeLogic.getX() * 2.0);
|
|
const double fFadeEffectTextGap(((mnFadeEffectIndicatorOffset + 2) * aDiscretePixel.getX()));
|
|
String aPageName(getPageName());
|
|
|
|
// calculate text start position
|
|
double fStartX(
|
|
aAdaptedInnerRange.getMaxX()
|
|
- fTextWidth
|
|
+ (aDiscretePixel.getX() * 3.0));
|
|
const double fStartY(
|
|
aAdaptedInnerRange.getMaxY()
|
|
+ fTextHeight
|
|
+ fFadeEffectTextGap);
|
|
const bool bNeedClipping(fStartX < aAdaptedInnerRange.getMinX() + fFadeEffectWidth);
|
|
|
|
// if text is too big, clip it
|
|
if(bNeedClipping)
|
|
{
|
|
// new left start
|
|
fStartX = aAdaptedInnerRange.getMinX() + fFadeEffectWidth;
|
|
|
|
// find out how many characters to use
|
|
const double fAvailableLength(aAdaptedInnerRange.getWidth() - fFadeEffectWidth);
|
|
static const String aThreePoints(String::CreateFromAscii("..."));
|
|
const double fWidthThreePoints(aTextLayouter.getTextWidth(aThreePoints, 0, aThreePoints.Len()));
|
|
xub_StrLen a(1);
|
|
|
|
for(; a < (xub_StrLen)nTextLength; a++)
|
|
{
|
|
const double fSnippetLength(aTextLayouter.getTextWidth(aPageName, 0, a));
|
|
|
|
if(fSnippetLength + fWidthThreePoints > fAvailableLength)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// build new string
|
|
aPageName = String(aPageName, 0, a - 1);
|
|
aPageName += aThreePoints;
|
|
}
|
|
|
|
// fill text matrix
|
|
::basegfx::B2DHomMatrix aTextMatrix;
|
|
|
|
aTextMatrix.set(0L, 0L, aTextSizeAttribute.getX());
|
|
aTextMatrix.set(1L, 1L, aTextSizeAttribute.getY());
|
|
aTextMatrix.set(0L, 2L, fStartX);
|
|
aTextMatrix.set(1L, 2L, fStartY);
|
|
|
|
// create Text primitive and add to target
|
|
xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
|
|
aTextMatrix, aPageName, 0, aPageName.Len(), aDXArray, aFontAttributes, aLocale, aFontColor));
|
|
}
|
|
|
|
{
|
|
// Paint_PageNumber replacement. Get the range where it shall be centered and prepare the string
|
|
const double fLeft(aAdaptedInnerRange.getMinX() - (mnPageNumberOffset * aDiscretePixel.getX()) - getPageNumberAreaModelSize().Width());
|
|
const double fTop(aAdaptedInnerRange.getMinY());
|
|
const basegfx::B2DRange aNumberRange(fLeft, fTop,
|
|
fLeft + getPageNumberAreaModelSize().Width(), fTop + getPageNumberAreaModelSize().Height());
|
|
const String aPageNumber(String::CreateFromInt32(getPageNumber()));
|
|
const xub_StrLen nNumberLen(aPageNumber.Len());
|
|
|
|
// Get text size
|
|
const double fTextWidth(aTextLayouter.getTextWidth(aPageNumber, 0, nNumberLen));
|
|
const double fTextHeight(getPageNameFont().GetHeight());
|
|
|
|
// get text start postion
|
|
const double fStartX(aNumberRange.getCenterX() - (fTextWidth / 2.0));
|
|
const double fStartY(aNumberRange.getMinY() + fTextHeight + aDiscretePixel.getX());
|
|
|
|
// fill text matrix
|
|
::basegfx::B2DHomMatrix aTextMatrix;
|
|
|
|
aTextMatrix.set(0L, 0L, aTextSizeAttribute.getX());
|
|
aTextMatrix.set(1L, 1L, aTextSizeAttribute.getY());
|
|
aTextMatrix.set(0L, 2L, fStartX);
|
|
aTextMatrix.set(1L, 2L, fStartY);
|
|
|
|
// create Text primitive
|
|
xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
|
|
aTextMatrix, aPageNumber, 0, nNumberLen, aDXArray, aFontAttributes, aLocale, aFontColor));
|
|
|
|
if(getExcluded())
|
|
{
|
|
// create a box with strikethrough from top left to bottom right
|
|
const basegfx::BColor aActiveColor(Application::GetSettings().GetStyleSettings().GetActiveColor().getBColor());
|
|
basegfx::B2DPolygon aStrikethrough;
|
|
|
|
aStrikethrough.append(aNumberRange.getMinimum());
|
|
aStrikethrough.append(aNumberRange.getMaximum());
|
|
|
|
xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
|
|
basegfx::tools::createPolygonFromRect(aNumberRange), aActiveColor));
|
|
|
|
xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
|
|
aStrikethrough, aActiveColor));
|
|
}
|
|
}
|
|
|
|
return xRetval;
|
|
}
|
|
|
|
SdPageObjectFadeNameNumberPrimitive::SdPageObjectFadeNameNumberPrimitive(
|
|
const basegfx::B2DRange& rRange,
|
|
const String& rPageName,
|
|
sal_uInt32 nPageNumber,
|
|
const Font& rPageNameFont,
|
|
const Size& rPageNumberAreaModelSize,
|
|
bool bShowFadeEffectIcon,
|
|
bool bExcluded)
|
|
: SdPageObjectBasePrimitive(rRange),
|
|
maPageName(rPageName),
|
|
mnPageNumber(nPageNumber),
|
|
maPageNameFont(rPageNameFont),
|
|
maPageNumberAreaModelSize(rPageNumberAreaModelSize),
|
|
mbShowFadeEffectIcon(bShowFadeEffectIcon),
|
|
mbExcluded(bExcluded)
|
|
{
|
|
}
|
|
|
|
SdPageObjectFadeNameNumberPrimitive::~SdPageObjectFadeNameNumberPrimitive()
|
|
{
|
|
}
|
|
|
|
bool SdPageObjectFadeNameNumberPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
|
|
{
|
|
if(SdPageObjectBasePrimitive::operator==(rPrimitive))
|
|
{
|
|
const SdPageObjectFadeNameNumberPrimitive& rCompare = static_cast< const SdPageObjectFadeNameNumberPrimitive& >(rPrimitive);
|
|
|
|
return (getPageName() == rCompare.getPageName()
|
|
&& getPageNumber() == rCompare.getPageNumber()
|
|
&& getPageNameFont() == rCompare.getPageNameFont()
|
|
&& getPageNumberAreaModelSize() == rCompare.getPageNumberAreaModelSize()
|
|
&& getShowFadeEffectIcon() == rCompare.getShowFadeEffectIcon()
|
|
&& getExcluded() == rCompare.getExcluded());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ImplPrimitrive2DIDBlock(SdPageObjectFadeNameNumberPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTFADENAMENUMBERPRIMITIVE)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
// createPrimitive2DSequence
|
|
//
|
|
// This method will replace the whole painting mechanism. Task is no longer to paint stuff to an OutDev,
|
|
// but to provide the necessary geometrical information using primitives.
|
|
|
|
Primitive2DSequence PageObjectViewObjectContact::createPrimitive2DSequence(const sdr::contact::DisplayInfo& rDisplayInfo) const
|
|
{
|
|
// OutputDevice* pDevice = rDisplayInfo.GetDIOutputDevice();
|
|
OutputDevice* pDevice = GetObjectContact().TryToGetOutputDevice();
|
|
|
|
// get primitive vector from parent class. Do remember the contents for later use; this
|
|
// is done to create the page content renderer (see PagePrimitiveExtractor in svx) at the
|
|
// original object and to setup the draw hierarchy there so that changes to VCs of displayed
|
|
// objects will lead to InvalidatePartOfView-calls which will be forwarded from the helper-OC
|
|
// to this VOC in calling a ActionChanged().
|
|
//
|
|
// This already produces the displayable page content as a primitive sequence, complete with
|
|
// embedding in the page visualizer, clipping if needed and object and aspect ratio
|
|
// preparations. It would thus be the base for creating the cached visualisation, too,
|
|
// by just painting extactly this primitive sequence.
|
|
//
|
|
// Currently, this slows down PagePane display heavily. Reason is that the current mechanism
|
|
// to react on a SdrObject change in an edit view is to react on the ModelChange and to completely
|
|
// reset the PagePane (delete SdrPageObjs, re-create and layout them). This works, but kicks
|
|
// the complete sequence of primitive creation at VOCs and VCs and their buffering out of
|
|
// memory each time. So there are two choices:
|
|
//
|
|
// 1, disable getting the sequence of primtives
|
|
// -> invalidate uses ModelChange
|
|
// -> cache repaint uses complete view creation and repainting
|
|
//
|
|
// 2, create and use the sequence of primitives
|
|
// -> invalidate would not need ModelChange, no destroy/recreate of SdrObjects, no rearrange,
|
|
// the invalidate and the following repaint would exactly update the SdrPages involved and
|
|
// use the DrawingLayer provided ActionChanged() invalidations over the VOCs and VCs
|
|
// -> cache repaint could use the here offered sequence of primitives to re-create the bitmap
|
|
// (just hand over the local member to the cache)
|
|
//
|
|
// For the moment i will use (1) and disable primitive creation for SdrPageObj contents here
|
|
|
|
// const_cast< PageObjectViewObjectContact* >(this)->mxCurrentPageContents = ViewObjectContactOfPageObj::createPrimitive2DSequence(rDisplayInfo);
|
|
|
|
// assert when this call is issued indirectly from the destructor of
|
|
// this instance. This is not allowed and needs to be looked at
|
|
#ifdef DBG_UTIL
|
|
if(mbInDestructor)
|
|
{
|
|
OSL_ENSURE(false, "Higher call inside PageObjectViewObjectContact in destructor (!)");
|
|
}
|
|
#endif
|
|
|
|
// Check if buffering can and shall be done.
|
|
if (pDevice != NULL
|
|
&& !GetObjectContact().isOutputToPrinter()
|
|
&& !GetObjectContact().isOutputToRecordingMetaFile()
|
|
&& !mbInDestructor)
|
|
{
|
|
// get inner and outer logic rectangles. Use model data directly for creation. Do NOT use getBoundRect()/
|
|
// getSnapRect() functionality; these will use the sequence of primitives in the long run itself. SdrPageObj
|
|
// is a SdrObject, so use SdrObject::aOutRect as model data. Access using GetLastBoundRect() to not execute anything
|
|
PageObjectViewContact& rPaObVOC(static_cast< PageObjectViewContact& >(GetViewContact()));
|
|
const Rectangle aInnerLogic(rPaObVOC.GetPageObject().GetLastBoundRect());
|
|
|
|
// get BitmapEx from cache. Do exactly the same as Paint_Preview() to avoid a repaint loop
|
|
// caused by slightly different pixel sizes of what the cache sees as pixel size and what is
|
|
// calculated here in discrete coordinates. This includes to not use LogicToPiyel on the Rectangle,
|
|
// but to do the same as the GetBoundingBox() implementation
|
|
const Rectangle aInnerPixel(Rectangle(pDevice->LogicToPixel(aInnerLogic.TopLeft()), pDevice->LogicToPixel(aInnerLogic.GetSize())));
|
|
BitmapEx aBitmapEx(const_cast< PageObjectViewObjectContact* >(this)->GetPreview(rDisplayInfo, aInnerPixel));
|
|
|
|
// prepare inner range
|
|
const basegfx::B2DRange aInnerRange(aInnerLogic.Left(), aInnerLogic.Top(), aInnerLogic.Right(), aInnerLogic.Bottom());
|
|
|
|
// provide default parameters
|
|
String aPageName;
|
|
Font aPageNameFont;
|
|
sal_uInt32 nPageNumber(0);
|
|
Size aPageNumberAreaModelSize;
|
|
bool bShowFadeEffectIcon(false);
|
|
bool bExcluded(false);
|
|
|
|
if(GetPage())
|
|
{
|
|
const SdPage* pPage = static_cast<const SdPage*>(GetPage());
|
|
|
|
// decide if fade effect indicator will be painted
|
|
if(pPage->getTransitionType() > 0)
|
|
{
|
|
bShowFadeEffectIcon = true;
|
|
}
|
|
|
|
// prepare PageName, PageNumber, font and AreaModelSize
|
|
aPageName = pPage->GetName();
|
|
aPageNameFont = *FontProvider::Instance().GetFont(*pDevice);
|
|
nPageNumber = ((pPage->GetPageNum() - 1) / 2) + 1;
|
|
aPageNumberAreaModelSize = GetPageDescriptor()->GetPageNumberAreaModelSize();
|
|
|
|
if(!aPageName.Len())
|
|
{
|
|
aPageName = String(SdResId(STR_PAGE));
|
|
aPageName += String::CreateFromInt32(nPageNumber);
|
|
}
|
|
|
|
// decide if page is excluded
|
|
bExcluded = pPage->IsExcluded();
|
|
}
|
|
|
|
// create specialized primitives for focus, select and PagePreview itself
|
|
const bool bCreateBitmap(!aBitmapEx.IsEmpty());
|
|
const bool bCreateFocused(GetPageDescriptor()->IsFocused());
|
|
const bool bCreateSelected(GetPageDescriptor()->IsSelected());
|
|
|
|
const sal_uInt32 nCount(
|
|
(bCreateBitmap ? 1 : 0) + // bitmap itself
|
|
1 + // border around bitmap (always)
|
|
1 + // FadeEffect, PageName and PageNumber visualisation (always)
|
|
(bCreateFocused ? 1 : 0) + // create focused
|
|
(bCreateSelected ? 1 : 0) // create selected
|
|
);
|
|
sal_uInt32 nInsert(0);
|
|
Primitive2DSequence xRetval(nCount);
|
|
|
|
if(bCreateBitmap)
|
|
{
|
|
// add selection indicator if used
|
|
xRetval[nInsert++] = Primitive2DReference(new SdPageObjectPageBitmapPrimitive(aInnerRange, aBitmapEx));
|
|
}
|
|
|
|
if(true)
|
|
{
|
|
// add border (always)
|
|
xRetval[nInsert++] = Primitive2DReference(new SdPageObjectBorderPrimitive(aInnerRange));
|
|
}
|
|
|
|
if(true)
|
|
{
|
|
// add fade effext, page name and number if used
|
|
xRetval[nInsert++] = Primitive2DReference(new SdPageObjectFadeNameNumberPrimitive(
|
|
aInnerRange,
|
|
aPageName,
|
|
nPageNumber,
|
|
aPageNameFont,
|
|
aPageNumberAreaModelSize,
|
|
bShowFadeEffectIcon,
|
|
bExcluded));
|
|
}
|
|
|
|
if(bCreateSelected)
|
|
{
|
|
// add selection indicator if used
|
|
xRetval[nInsert++] = Primitive2DReference(new SdPageObjectSelectPrimitive(aInnerRange));
|
|
}
|
|
|
|
if(bCreateFocused)
|
|
{
|
|
// add focus indicator if used
|
|
xRetval[nInsert++] = Primitive2DReference(new SdPageObjectFocusPrimitive(aInnerRange));
|
|
}
|
|
|
|
return xRetval;
|
|
}
|
|
else
|
|
{
|
|
// Call parent. Output to printer or metafile will use vector data, not cached bitmaps
|
|
return ViewObjectContactOfPageObj::createPrimitive2DSequence(rDisplayInfo);
|
|
}
|
|
}
|
|
|
|
BitmapEx PageObjectViewObjectContact::CreatePreview (const DisplayInfo& /*rDisplayInfo*/)
|
|
{
|
|
const SdPage* pPage = static_cast<const SdPage*>(GetPage());
|
|
OutputDevice* pDevice = GetObjectContact().TryToGetOutputDevice();
|
|
|
|
if(pDevice)
|
|
{
|
|
Rectangle aPreviewPixelBox (GetBoundingBox(*pDevice,PreviewBoundingBox,PixelCoordinateSystem));
|
|
|
|
PreviewRenderer aRenderer (pDevice);
|
|
Image aPreview (aRenderer.RenderPage(
|
|
pPage,
|
|
aPreviewPixelBox.GetSize(),
|
|
String()));
|
|
|
|
return aPreview.GetBitmapEx();
|
|
}
|
|
else
|
|
{
|
|
return BitmapEx();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
BitmapEx PageObjectViewObjectContact::GetPreview (
|
|
const DisplayInfo& rDisplayInfo,
|
|
const Rectangle& rNewSizePixel)
|
|
{
|
|
BitmapEx aBitmap;
|
|
|
|
try
|
|
{
|
|
// assert when this call is issued indirectly from the destructor of
|
|
// this instance. This is not allowed and needs to be looked at
|
|
OSL_ENSURE(!mbInDestructor, "Higher call inside PageObjectViewObjectContact in destructor (!)");
|
|
|
|
if (!mbInDestructor)
|
|
{
|
|
if (mpCache != NULL)
|
|
{
|
|
aBitmap = mpCache->GetPreviewBitmap(
|
|
GetPage(),
|
|
rNewSizePixel.GetSize());
|
|
mpCache->SetPreciousFlag(GetPage(), true);
|
|
}
|
|
else
|
|
aBitmap = CreatePreview(rDisplayInfo);
|
|
}
|
|
}
|
|
catch (const ::com::sun::star::uno::Exception&)
|
|
{
|
|
OSL_TRACE("PageObjectViewObjectContact::GetPreview: caught exception");
|
|
}
|
|
|
|
return aBitmap;
|
|
}
|
|
|
|
|
|
|
|
|
|
const SdrPage* PageObjectViewObjectContact::GetPage (void) const
|
|
{
|
|
return static_cast<PageObjectViewContact&>(GetViewContact()).GetPage();
|
|
}
|
|
|
|
|
|
|
|
|
|
void PageObjectViewObjectContact::ActionChanged (void)
|
|
{
|
|
// Even when we are called from destructor we still have to invalide
|
|
// the preview bitmap in the cache.
|
|
const SdrPage* pPage = GetPage();
|
|
SdDrawDocument* pDocument = dynamic_cast<SdDrawDocument*>(pPage->GetModel());
|
|
if (mpCache!=NULL && pPage!=NULL && pDocument!=NULL)
|
|
{
|
|
cache::PageCacheManager::Instance()->InvalidatePreviewBitmap(
|
|
pDocument->getUnoModel(),
|
|
GetPage());
|
|
}
|
|
|
|
// call parent
|
|
ViewObjectContactOfPageObj::ActionChanged();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// helper MouseOverEffectPrimitive
|
|
//
|
|
// Used to allow view-dependent primitive definition. For that purpose, the
|
|
// initially created primitive (here: in createMouseOverEffectPrimitive2DSequence())
|
|
// always has to be view-independent, but the decomposition is made view-dependent.
|
|
// Very simple primitive which just remembers the discrete data and applies
|
|
// it at decomposition time.
|
|
|
|
class MouseOverEffectPrimitive : public drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
|
|
{
|
|
private:
|
|
basegfx::B2DRange maLogicRange;
|
|
sal_uInt32 mnDiscreteOffset;
|
|
sal_uInt32 mnDiscreteWidth;
|
|
basegfx::BColor maRGBColor;
|
|
|
|
protected:
|
|
virtual drawinglayer::primitive2d::Primitive2DSequence create2DDecomposition(
|
|
const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
|
|
|
|
public:
|
|
MouseOverEffectPrimitive(
|
|
const basegfx::B2DRange& rLogicRange,
|
|
sal_uInt32 nDiscreteOffset,
|
|
sal_uInt32 nDiscreteWidth,
|
|
const basegfx::BColor& rRGBColor)
|
|
: drawinglayer::primitive2d::BufferedDecompositionPrimitive2D(),
|
|
maLogicRange(rLogicRange),
|
|
mnDiscreteOffset(nDiscreteOffset),
|
|
mnDiscreteWidth(nDiscreteWidth),
|
|
maRGBColor(rRGBColor)
|
|
{}
|
|
|
|
// data access
|
|
const basegfx::B2DRange& getLogicRange() const { return maLogicRange; }
|
|
sal_uInt32 getDiscreteOffset() const { return mnDiscreteOffset; }
|
|
sal_uInt32 getDiscreteWidth() const { return mnDiscreteWidth; }
|
|
const basegfx::BColor& getRGBColor() const { return maRGBColor; }
|
|
|
|
virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
|
|
|
|
DeclPrimitrive2DIDBlock()
|
|
};
|
|
|
|
drawinglayer::primitive2d::Primitive2DSequence MouseOverEffectPrimitive::create2DDecomposition(
|
|
const drawinglayer::geometry::ViewInformation2D& rViewInformation) const
|
|
{
|
|
// get logic sizes in object coordinate system
|
|
const double fDiscreteWidth((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength());
|
|
const double fOffset(fDiscreteWidth * getDiscreteOffset());
|
|
const double fWidth(fDiscreteWidth * getDiscreteWidth());
|
|
|
|
// create range (one pixel less to get a good fitting)
|
|
basegfx::B2DRange aRange(
|
|
getLogicRange().getMinimum(),
|
|
getLogicRange().getMaximum() - basegfx::B2DTuple(fDiscreteWidth, fDiscreteWidth));
|
|
|
|
// grow range
|
|
aRange.grow(fOffset - (fWidth * 0.5));
|
|
|
|
// create fat line with parameters. The formerly hand-painted edge
|
|
// roundings will now be done using rounded edges of this fat line
|
|
const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aRange));
|
|
const drawinglayer::attribute::LineAttribute aLineAttribute(getRGBColor(), fWidth);
|
|
const drawinglayer::primitive2d::Primitive2DReference xReference(
|
|
new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
|
|
aPolygon,
|
|
aLineAttribute));
|
|
|
|
return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1);
|
|
}
|
|
|
|
bool MouseOverEffectPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
|
|
{
|
|
if(drawinglayer::primitive2d::BufferedDecompositionPrimitive2D::operator==(rPrimitive))
|
|
{
|
|
const MouseOverEffectPrimitive& rCompare = static_cast< const MouseOverEffectPrimitive& >(rPrimitive);
|
|
|
|
return (getLogicRange() == rCompare.getLogicRange()
|
|
&& getDiscreteOffset() == rCompare.getDiscreteOffset()
|
|
&& getDiscreteWidth() == rCompare.getDiscreteWidth()
|
|
&& getRGBColor() == rCompare.getRGBColor());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ImplPrimitrive2DIDBlock(MouseOverEffectPrimitive, PRIMITIVE2D_ID_SDMOUSEOVEREFFECTPRIMITIVE)
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
drawinglayer::primitive2d::Primitive2DSequence PageObjectViewObjectContact::createMouseOverEffectPrimitive2DSequence()
|
|
{
|
|
drawinglayer::primitive2d::Primitive2DSequence aRetval;
|
|
|
|
if(GetPageDescriptor()->IsSelected() && mpProperties.get() && mpProperties->IsShowSelection())
|
|
{
|
|
// When the selection frame is visualized the mouse over frame is not
|
|
// visible and does not have to be created.
|
|
}
|
|
else
|
|
{
|
|
const PageObjectViewContact& rPaObVOC(static_cast<PageObjectViewContact&>(GetViewContact()));
|
|
const Rectangle aBoundingBox(rPaObVOC.GetPageObject().GetLastBoundRect());
|
|
const basegfx::B2DRange aLogicRange(aBoundingBox.Left(), aBoundingBox.Top(), aBoundingBox.Right(), aBoundingBox.Bottom());
|
|
const basegfx::BColor aSelectionColor(mpProperties->GetSelectionColor().getBColor());
|
|
const drawinglayer::primitive2d::Primitive2DReference aReference(
|
|
new MouseOverEffectPrimitive(
|
|
aLogicRange,
|
|
mnMouseOverEffectOffset,
|
|
mnMouseOverEffectThickness,
|
|
aSelectionColor));
|
|
|
|
aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1);
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
|
|
|
|
|
|
|
|
SvBorder PageObjectViewObjectContact::CalculatePageModelBorder (
|
|
OutputDevice* pDevice,
|
|
int nPageCount)
|
|
{
|
|
SvBorder aModelBorder;
|
|
|
|
if (pDevice != NULL)
|
|
{
|
|
// 1. Initialize the border with the values that do not depend on
|
|
// the device.
|
|
Size aTopLeftBorders (pDevice->PixelToLogic (Size (
|
|
mnPageNumberOffset+1,
|
|
mnSelectionIndicatorOffset + mnSelectionIndicatorThickness)));
|
|
Size aBottomRightBorders (pDevice->PixelToLogic (Size (
|
|
mnSelectionIndicatorOffset + mnSelectionIndicatorThickness,
|
|
mnFadeEffectIndicatorOffset)));
|
|
aModelBorder = SvBorder (
|
|
aTopLeftBorders.Width(),
|
|
aTopLeftBorders.Height(),
|
|
aBottomRightBorders.Width(),
|
|
aBottomRightBorders.Height());
|
|
|
|
|
|
// 2. Add the device dependent values.
|
|
|
|
// Calculate the area of the page number.
|
|
Size aPageNumberModelSize (
|
|
CalculatePageNumberAreaModelSize (pDevice, nPageCount));
|
|
|
|
// Update the border.
|
|
aModelBorder.Left() += aPageNumberModelSize.Width();
|
|
// The height of the page number area is the same as the height of
|
|
// the page name area.
|
|
aModelBorder.Bottom() += aPageNumberModelSize.Height();
|
|
}
|
|
|
|
return aModelBorder;
|
|
}
|
|
|
|
|
|
|
|
|
|
Size PageObjectViewObjectContact::CalculatePageNumberAreaModelSize (
|
|
OutputDevice* pDevice,
|
|
int nPageCount)
|
|
{
|
|
// Set the correct font.
|
|
Font aOriginalFont (pDevice->GetFont());
|
|
pDevice->SetFont(*FontProvider::Instance().GetFont(*pDevice));
|
|
|
|
String sPageNumberTemplate;
|
|
if (nPageCount < 10)
|
|
sPageNumberTemplate = String::CreateFromAscii("9");
|
|
else if (nPageCount < 100)
|
|
sPageNumberTemplate = String::CreateFromAscii("99");
|
|
else if (nPageCount < 200)
|
|
// Just for the case that 1 is narrower than 9.
|
|
sPageNumberTemplate = String::CreateFromAscii("199");
|
|
else if (nPageCount < 1000)
|
|
sPageNumberTemplate = String::CreateFromAscii("999");
|
|
else
|
|
sPageNumberTemplate = String::CreateFromAscii("9999");
|
|
// More then 9999 pages are not handled.
|
|
|
|
Size aSize (
|
|
pDevice->GetTextWidth (sPageNumberTemplate),
|
|
pDevice->GetTextHeight ());
|
|
|
|
pDevice->SetFont (aOriginalFont);
|
|
|
|
return aSize;
|
|
}
|
|
|
|
|
|
|
|
|
|
model::SharedPageDescriptor
|
|
PageObjectViewObjectContact::GetPageDescriptor (void) const
|
|
{
|
|
PageObjectViewContact& rViewContact (
|
|
static_cast<PageObjectViewContact&>(GetViewContact()));
|
|
PageObject& rPageObject (
|
|
static_cast<PageObject&>(rViewContact.GetPageObject()));
|
|
return rPageObject.GetDescriptor();
|
|
}
|
|
|
|
|
|
|
|
} } } // end of namespace ::sd::slidesorter::view
|