diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /svx/source/sdr/overlay | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svx/source/sdr/overlay')
18 files changed, 2975 insertions, 0 deletions
diff --git a/svx/source/sdr/overlay/overlayanimatedbitmapex.cxx b/svx/source/sdr/overlay/overlayanimatedbitmapex.cxx new file mode 100644 index 000000000..967e9665b --- /dev/null +++ b/svx/source/sdr/overlay/overlayanimatedbitmapex.cxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <svx/sdr/overlay/overlayanimatedbitmapex.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <sdr/overlay/overlaytools.hxx> + + +namespace sdr::overlay +{ + drawinglayer::primitive2d::Primitive2DContainer OverlayAnimatedBitmapEx::createOverlayObjectPrimitive2DSequence() + { + if(mbOverlayState) + { + const drawinglayer::primitive2d::Primitive2DReference aPrimitive( + new drawinglayer::primitive2d::OverlayBitmapExPrimitive( + maBitmapEx1, + getBasePosition(), + mnCenterX1, + mnCenterY1, + getShearX(), + getRotation())); + + return drawinglayer::primitive2d::Primitive2DContainer { aPrimitive }; + } + else + { + const drawinglayer::primitive2d::Primitive2DReference aPrimitive( + new drawinglayer::primitive2d::OverlayBitmapExPrimitive( + maBitmapEx2, + getBasePosition(), + mnCenterX2, + mnCenterY2, + getShearX(), + getRotation())); + + return drawinglayer::primitive2d::Primitive2DContainer { aPrimitive }; + } + } + + OverlayAnimatedBitmapEx::OverlayAnimatedBitmapEx( + const basegfx::B2DPoint& rBasePos, + const BitmapEx& rBitmapEx1, + const BitmapEx& rBitmapEx2, + sal_uInt64 nBlinkTime, + sal_uInt16 nCenX1, + sal_uInt16 nCenY1, + sal_uInt16 nCenX2, + sal_uInt16 nCenY2, + double fShearX, + double fRotation) + : OverlayObjectWithBasePosition(rBasePos, COL_WHITE), + maBitmapEx1(rBitmapEx1), + maBitmapEx2(rBitmapEx2), + mnCenterX1(nCenX1), mnCenterY1(nCenY1), + mnCenterX2(nCenX2), mnCenterY2(nCenY2), + mnBlinkTime(impCheckBlinkTimeValueRange(nBlinkTime)), + mfShearX(fShearX), + mfRotation(fRotation), + mbOverlayState(false) + { + // set AllowsAnimation flag to mark this object as animation capable + mbAllowsAnimation = true; + } + + OverlayAnimatedBitmapEx::~OverlayAnimatedBitmapEx() + { + } + + void OverlayAnimatedBitmapEx::Trigger(sal_uInt32 nTime) + { + if(!getOverlayManager()) + return; + + // #i53216# produce event after nTime + x + SetTime(nTime + mnBlinkTime); + + // switch state + if(mbOverlayState) + { + mbOverlayState = false; + } + else + { + mbOverlayState = true; + } + + // re-insert me as event + getOverlayManager()->InsertEvent(*this); + + // register change (after change) + objectChange(); + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlaybitmapex.cxx b/svx/source/sdr/overlay/overlaybitmapex.cxx new file mode 100644 index 000000000..54ccf788b --- /dev/null +++ b/svx/source/sdr/overlay/overlaybitmapex.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> +#include <svx/sdr/overlay/overlaybitmapex.hxx> +#include <sdr/overlay/overlaytools.hxx> + + +namespace sdr::overlay +{ + drawinglayer::primitive2d::Primitive2DContainer OverlayBitmapEx::createOverlayObjectPrimitive2DSequence() + { + drawinglayer::primitive2d::Primitive2DReference aReference( + new drawinglayer::primitive2d::OverlayBitmapExPrimitive( + maBitmapEx, + getBasePosition(), + mnCenterX, + mnCenterY, + mfShearX, + mfRotation)); + + if(basegfx::fTools::more(mfAlpha, 0.0)) + { + drawinglayer::primitive2d::Primitive2DContainer aNewTransPrimitiveVector { aReference }; + aReference = drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aNewTransPrimitiveVector), mfAlpha)); + } + + return drawinglayer::primitive2d::Primitive2DContainer { aReference }; + } + + OverlayBitmapEx::OverlayBitmapEx( + const basegfx::B2DPoint& rBasePos, + const BitmapEx& rBitmapEx, + sal_uInt16 nCenX, + sal_uInt16 nCenY, + double fAlpha, + double fShearX, + double fRotation) + : OverlayObjectWithBasePosition(rBasePos, COL_WHITE), + maBitmapEx(rBitmapEx), + mnCenterX(nCenX), + mnCenterY(nCenY), + mfAlpha(fAlpha), + mfShearX(fShearX), + mfRotation(fRotation) + { + } + + OverlayBitmapEx::~OverlayBitmapEx() + { + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlaycrosshair.cxx b/svx/source/sdr/overlay/overlaycrosshair.cxx new file mode 100644 index 000000000..942534d68 --- /dev/null +++ b/svx/source/sdr/overlay/overlaycrosshair.cxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sdr/overlay/overlaycrosshair.hxx> +#include <sdr/overlay/overlaytools.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> + + +namespace sdr::overlay +{ + drawinglayer::primitive2d::Primitive2DContainer OverlayCrosshairStriped::createOverlayObjectPrimitive2DSequence() + { + drawinglayer::primitive2d::Primitive2DContainer aRetval; + + if(getOverlayManager()) + { + const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor()); + const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor()); + const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel()); + + const drawinglayer::primitive2d::Primitive2DReference aReference( + new drawinglayer::primitive2d::OverlayCrosshairPrimitive( + getBasePosition(), + aRGBColorA, + aRGBColorB, + fStripeLengthPixel)); + + aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference }; + } + + return aRetval; + } + + void OverlayCrosshairStriped::stripeDefinitionHasChanged() + { + // react on OverlayManager's stripe definition change + objectChange(); + } + + OverlayCrosshairStriped::OverlayCrosshairStriped(const basegfx::B2DPoint& rBasePos) + : OverlayObjectWithBasePosition(rBasePos, COL_BLACK) + { + } + + OverlayCrosshairStriped::~OverlayCrosshairStriped() + { + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayhandle.cxx b/svx/source/sdr/overlay/overlayhandle.cxx new file mode 100644 index 000000000..c94da8e07 --- /dev/null +++ b/svx/source/sdr/overlay/overlayhandle.cxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sdr/overlay/overlayhandle.hxx> +#include <sdr/overlay/overlaytools.hxx> + +namespace sdr::overlay { + +using namespace drawinglayer; +using namespace basegfx; + +primitive2d::Primitive2DContainer OverlayHandle::createOverlayObjectPrimitive2DSequence() +{ + basegfx::BColor aStrokeColor = maStrokeColor.getBColor(); + basegfx::BColor aFillColor = getBaseColor().getBColor(); + + const primitive2d::Primitive2DReference aReference( + new primitive2d::OverlayStaticRectanglePrimitive(maBasePosition, maSize, aStrokeColor, aFillColor, 0.3f, 0.0f)); + + return primitive2d::Primitive2DContainer { aReference }; +} + +OverlayHandle::OverlayHandle(const B2DPoint& rBasePos, + const B2DSize& rSize, + Color const & rStrokeColor, + Color const & rFillColor) + : OverlayObjectWithBasePosition(rBasePos, rFillColor) + , maSize(rSize) + , maStrokeColor(rStrokeColor) +{ +} + +OverlayHandle::~OverlayHandle() +{ +} + +} // end of namespace sdr::overlay + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayhelpline.cxx b/svx/source/sdr/overlay/overlayhelpline.cxx new file mode 100644 index 000000000..9955122bb --- /dev/null +++ b/svx/source/sdr/overlay/overlayhelpline.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sdr/overlay/overlayhelpline.hxx> +#include <sdr/overlay/overlaytools.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> + + +namespace sdr::overlay +{ + drawinglayer::primitive2d::Primitive2DContainer OverlayHelplineStriped::createOverlayObjectPrimitive2DSequence() + { + drawinglayer::primitive2d::Primitive2DContainer aRetval; + + if(getOverlayManager()) + { + const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor()); + const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor()); + const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel()); + const drawinglayer::primitive2d::HelplineStyle aStyle( + SdrHelpLineKind::Point == getKind() ? drawinglayer::primitive2d::HELPLINESTYLE_POINT : + SdrHelpLineKind::Vertical == getKind() ? drawinglayer::primitive2d::HELPLINESTYLE_VERTICAL : + drawinglayer::primitive2d::HELPLINESTYLE_HORIZONTAL); + + const drawinglayer::primitive2d::Primitive2DReference aReference( + new drawinglayer::primitive2d::OverlayHelplineStripedPrimitive( + getBasePosition(), + aStyle, + aRGBColorA, + aRGBColorB, + fStripeLengthPixel)); + + aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference }; + } + + return aRetval; + } + + void OverlayHelplineStriped::stripeDefinitionHasChanged() + { + // react on OverlayManager's stripe definition change + objectChange(); + } + + OverlayHelplineStriped::OverlayHelplineStriped( + const basegfx::B2DPoint& rBasePos, + SdrHelpLineKind eNewKind) + : OverlayObjectWithBasePosition(rBasePos, COL_BLACK), + meKind(eNewKind) + { + } + + OverlayHelplineStriped::~OverlayHelplineStriped() + { + } +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayline.cxx b/svx/source/sdr/overlay/overlayline.cxx new file mode 100644 index 000000000..30c08f026 --- /dev/null +++ b/svx/source/sdr/overlay/overlayline.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sdr/overlay/overlayline.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx> + + +namespace sdr::overlay +{ + drawinglayer::primitive2d::Primitive2DContainer OverlayLineStriped::createOverlayObjectPrimitive2DSequence() + { + drawinglayer::primitive2d::Primitive2DContainer aRetval; + + if(getOverlayManager()) + { + const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor()); + const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor()); + const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel()); + basegfx::B2DPolygon aLine; + + aLine.append(getBasePosition()); + aLine.append(getSecondPosition()); + + const drawinglayer::primitive2d::Primitive2DReference aReference( + new drawinglayer::primitive2d::PolygonMarkerPrimitive2D( + aLine, + aRGBColorA, + aRGBColorB, + fStripeLengthPixel)); + + aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference }; + } + + return aRetval; + } + + void OverlayLineStriped::stripeDefinitionHasChanged() + { + // react on OverlayManager's stripe definition change + objectChange(); + } + + OverlayLineStriped::OverlayLineStriped( + const basegfx::B2DPoint& rBasePos, + const basegfx::B2DPoint& rSecondPos) + : OverlayObjectWithBasePosition(rBasePos, COL_BLACK), + maSecondPosition(rSecondPos) + { + } + + OverlayLineStriped::~OverlayLineStriped() + { + } +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlaymanager.cxx b/svx/source/sdr/overlay/overlaymanager.cxx new file mode 100644 index 000000000..3cbd821fb --- /dev/null +++ b/svx/source/sdr/overlay/overlaymanager.cxx @@ -0,0 +1,346 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <basegfx/range/b2drange.hxx> +#include <comphelper/propertyvalue.hxx> +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> +#include <svx/sdr/overlay/overlayobject.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/processor2d/processor2dtools.hxx> +#include <svtools/optionsdrawinglayer.hxx> +#include <osl/diagnose.h> +#include <memory> + + +using namespace com::sun::star; + + +namespace sdr::overlay +{ + void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const + { + const sal_uInt32 nSize(maOverlayObjects.size()); + + if(!nSize) + return; + + const AntialiasingFlags nOriginalAA(rDestinationDevice.GetAntialiasing()); + const bool bIsAntiAliasing(SvtOptionsDrawinglayer::IsAntiAliasing()); + + // create processor + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice( + rDestinationDevice, + getCurrentViewInformation2D())); + + for(const auto& rpOverlayObject : maOverlayObjects) + { + OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)"); + const OverlayObject& rCandidate = *rpOverlayObject; + + if(rCandidate.isVisible()) + { + const drawinglayer::primitive2d::Primitive2DContainer& rSequence = rCandidate.getOverlayObjectPrimitive2DSequence(); + + if(!rSequence.empty()) + { + if(rRange.overlaps(rCandidate.getBaseRange())) + { + if(bIsAntiAliasing && rCandidate.allowsAntiAliase()) + { + rDestinationDevice.SetAntialiasing(nOriginalAA | AntialiasingFlags::Enable); + } + else + { + rDestinationDevice.SetAntialiasing(nOriginalAA & ~AntialiasingFlags::Enable); + } + + pProcessor->process(rSequence); + } + } + } + } + + pProcessor.reset(); + + // restore AA settings + rDestinationDevice.SetAntialiasing(nOriginalAA); + } + + void OverlayManager::ImpStripeDefinitionChanged() + { + const sal_uInt32 nSize(maOverlayObjects.size()); + + if(nSize) + { + for(const auto& rpOverlayObject : maOverlayObjects) + { + OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)"); + OverlayObject& rCandidate = *rpOverlayObject; + rCandidate.stripeDefinitionHasChanged(); + } + } + } + + double OverlayManager::getDiscreteOne() const + { + if(basegfx::fTools::equalZero(mfDiscreteOne)) + { + const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0)); + const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength(); + } + + return mfDiscreteOne; + } + + OverlayManager::OverlayManager(OutputDevice& rOutputDevice) + : mrOutputDevice(rOutputDevice), + maStripeColorA(COL_BLACK), + maStripeColorB(COL_WHITE), + mnStripeLengthPixel(5), + mfDiscreteOne(0.0) + { + // set Property 'ReducedDisplayQuality' to true to allow simpler interaction + // visualisations + uno::Sequence< beans::PropertyValue > xProperties{ + comphelper::makePropertyValue("ReducedDisplayQuality", true) + }; + maViewInformation2D = drawinglayer::geometry::createViewInformation2D(xProperties); + } + + rtl::Reference<OverlayManager> OverlayManager::create(OutputDevice& rOutputDevice) + { + return rtl::Reference<OverlayManager>(new OverlayManager(rOutputDevice)); + } + + drawinglayer::geometry::ViewInformation2D const & OverlayManager::getCurrentViewInformation2D() const + { + if(getOutputDevice().GetViewTransformation() != maViewTransformation) + { + basegfx::B2DRange aViewRange(maViewInformation2D.getViewport()); + + if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType()) + { + const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel()); + + // only set when we *have* an output size, else let aViewRange + // stay on empty + if(aOutputSizePixel.Width() && aOutputSizePixel.Height()) + { + aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight()); + aViewRange.transform(getOutputDevice().GetInverseViewTransformation()); + } + } + + OverlayManager* pThis = const_cast< OverlayManager* >(this); + + pThis->maViewTransformation = getOutputDevice().GetViewTransformation(); + pThis->maViewInformation2D = drawinglayer::geometry::ViewInformation2D( + maViewInformation2D.getObjectTransformation(), + maViewTransformation, + aViewRange, + maViewInformation2D.getVisualizedPage(), + maViewInformation2D.getViewTime()); + pThis->mfDiscreteOne = 0.0; + } + + return maViewInformation2D; + } + + void OverlayManager::impApplyRemoveActions(OverlayObject& rTarget) + { + // handle evtl. animation + if(rTarget.allowsAnimation()) + { + // remove from event chain + RemoveEvent(&rTarget); + } + + // make invisible + invalidateRange(rTarget.getBaseRange()); + + // clear manager + rTarget.mpOverlayManager = nullptr; + } + + void OverlayManager::impApplyAddActions(OverlayObject& rTarget) + { + // set manager + rTarget.mpOverlayManager = this; + + // make visible + invalidateRange(rTarget.getBaseRange()); + + // handle evtl. animation + if(rTarget.allowsAnimation()) + { + // Trigger at current time to get alive. This will do the + // object-specific next time calculation and hand over adding + // again to the scheduler to the animated object, too. This works for + // a paused or non-paused animator. + rTarget.Trigger(GetTime()); + } + } + + OverlayManager::~OverlayManager() + { + // The OverlayManager is not the owner of the OverlayObjects + // and thus will not delete them, but remove them. Profit here + // from knowing that all will be removed + const sal_uInt32 nSize(maOverlayObjects.size()); + + if(nSize) + { + for(const auto& rpOverlayObject : maOverlayObjects) + { + OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)"); + OverlayObject& rCandidate = *rpOverlayObject; + impApplyRemoveActions(rCandidate); + } + + // erase vector + maOverlayObjects.clear(); + } + } + + void OverlayManager::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const + { + if(rRegion.IsEmpty() || maOverlayObjects.empty()) + return; + + // check for changed MapModes. That may influence the + // logical size of pixel based OverlayObjects (like BitmapHandles) + //ImpCheckMapModeChange(); + + // paint members + const tools::Rectangle aRegionBoundRect(rRegion.GetBoundRect()); + const basegfx::B2DRange aRegionRange = vcl::unotools::b2DRectangleFromRectangle(aRegionBoundRect); + + OutputDevice& rTarget = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice(); + ImpDrawMembers(aRegionRange, rTarget); + } + + void OverlayManager::flush() + { + // default has nothing to do + } + + void OverlayManager::add(OverlayObject& rOverlayObject) + { + OSL_ENSURE(nullptr == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)"); + + // add to the end of chain to preserve display order in paint + maOverlayObjects.push_back(&rOverlayObject); + + // execute add actions + impApplyAddActions(rOverlayObject); + } + + void OverlayManager::remove(OverlayObject& rOverlayObject) + { + OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)"); + + // execute remove actions + impApplyRemoveActions(rOverlayObject); + + // remove from vector + const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject); + const bool bFound(aFindResult != maOverlayObjects.end()); + OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)"); + + if(bFound) + { + maOverlayObjects.erase(aFindResult); + } + } + + tools::Rectangle OverlayManager::RangeToInvalidateRectangle(const basegfx::B2DRange& rRange) const + { + if (rRange.isEmpty()) { + return {}; + } + if (SvtOptionsDrawinglayer::IsAntiAliasing()) + { + // assume AA needs one pixel more and invalidate one pixel more + const double fDiscreteOne(getDiscreteOne()); + const tools::Rectangle aInvalidateRectangle( + static_cast<tools::Long>(floor(rRange.getMinX() - fDiscreteOne)), + static_cast<tools::Long>(floor(rRange.getMinY() - fDiscreteOne)), + static_cast<tools::Long>(ceil(rRange.getMaxX() + fDiscreteOne)), + static_cast<tools::Long>(ceil(rRange.getMaxY() + fDiscreteOne))); + return aInvalidateRectangle; + } + else + { + // #i77674# transform to rectangle. Use floor/ceil to get all covered + // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange + const tools::Rectangle aInvalidateRectangle( + static_cast<sal_Int32>(floor(rRange.getMinX())), static_cast<sal_Int32>(floor(rRange.getMinY())), + static_cast<sal_Int32>(ceil(rRange.getMaxX())), static_cast<sal_Int32>(ceil(rRange.getMaxY()))); + return aInvalidateRectangle; + } + } + + void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange) + { + if (OUTDEV_WINDOW == getOutputDevice().GetOutDevType()) + { + tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange)); + // simply invalidate + getOutputDevice().GetOwnerWindow()->Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase); + } + } + + // stripe support ColA + void OverlayManager::setStripeColorA(Color aNew) + { + if(aNew != maStripeColorA) + { + maStripeColorA = aNew; + ImpStripeDefinitionChanged(); + } + } + + // stripe support ColB + void OverlayManager::setStripeColorB(Color aNew) + { + if(aNew != maStripeColorB) + { + maStripeColorB = aNew; + ImpStripeDefinitionChanged(); + } + } + + // stripe support StripeLengthPixel + void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew) + { + if(nNew != mnStripeLengthPixel) + { + mnStripeLengthPixel = nNew; + ImpStripeDefinitionChanged(); + } + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlaymanagerbuffered.cxx b/svx/source/sdr/overlay/overlaymanagerbuffered.cxx new file mode 100644 index 000000000..ae37c2ce4 --- /dev/null +++ b/svx/source/sdr/overlay/overlaymanagerbuffered.cxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sdr/overlay/overlaymanagerbuffered.hxx> +#include <svx/sdrpaintwindow.hxx> +#include <vcl/outdev.hxx> +#include <basegfx/range/b2drange.hxx> +#include <vcl/window.hxx> +#include <tools/fract.hxx> +#include <vcl/cursor.hxx> +#include <svtools/optionsdrawinglayer.hxx> + + +namespace sdr::overlay +{ + void OverlayManagerBuffered::ImpPrepareBufferDevice() + { + // compare size of mpBufferDevice with size of visible area + if(mpBufferDevice->GetOutputSizePixel() != getOutputDevice().GetOutputSizePixel()) + { + // set new buffer size, copy as much content as possible (use bool parameter for vcl). + // Newly uncovered regions will be repainted. + mpBufferDevice->SetOutputSizePixel(getOutputDevice().GetOutputSizePixel(), false); + } + + // compare the MapModes for zoom/scroll changes + if(mpBufferDevice->GetMapMode() != getOutputDevice().GetMapMode()) + { + const bool bZoomed( + mpBufferDevice->GetMapMode().GetScaleX() != getOutputDevice().GetMapMode().GetScaleX() + || mpBufferDevice->GetMapMode().GetScaleY() != getOutputDevice().GetMapMode().GetScaleY()); + + if(!bZoomed) + { + const Point& rOriginOld = mpBufferDevice->GetMapMode().GetOrigin(); + const Point& rOriginNew = getOutputDevice().GetMapMode().GetOrigin(); + const bool bScrolled(rOriginOld != rOriginNew); + + + if(bScrolled) + { + // get pixel bounds (tdf#149322 do subtraction in logic units before converting result back to pixel) + const Point aLogicOriginDiff(rOriginNew - rOriginOld); + const Size aPixelOriginDiff(mpBufferDevice->LogicToPixel(Size(aLogicOriginDiff.X(), aLogicOriginDiff.Y()))); + const Point aDestinationOffsetPixel(aPixelOriginDiff.Width(), aPixelOriginDiff.Height()); + const Size aOutputSizePixel(mpBufferDevice->GetOutputSizePixel()); + + // remember and switch off MapMode + const bool bMapModeWasEnabled(mpBufferDevice->IsMapModeEnabled()); + mpBufferDevice->EnableMapMode(false); + + // scroll internally buffered stuff + mpBufferDevice->DrawOutDev( + aDestinationOffsetPixel, aOutputSizePixel, // destination + Point(), aOutputSizePixel); // source + + // restore MapMode + mpBufferDevice->EnableMapMode(bMapModeWasEnabled); + + // scroll remembered region, too. + if(!maBufferRememberedRangePixel.isEmpty()) + { + const basegfx::B2IPoint aIPointDestinationOffsetPixel(aDestinationOffsetPixel.X(), aDestinationOffsetPixel.Y()); + const basegfx::B2IPoint aNewMinimum(maBufferRememberedRangePixel.getMinimum() + aIPointDestinationOffsetPixel); + const basegfx::B2IPoint aNewMaximum(maBufferRememberedRangePixel.getMaximum() + aIPointDestinationOffsetPixel); + maBufferRememberedRangePixel = basegfx::B2IRange(aNewMinimum, aNewMaximum); + } + } + } + + // copy new MapMode + mpBufferDevice->SetMapMode(getOutputDevice().GetMapMode()); + } + + // #i29186# + mpBufferDevice->SetDrawMode(getOutputDevice().GetDrawMode()); + mpBufferDevice->SetSettings(getOutputDevice().GetSettings()); + mpBufferDevice->SetAntialiasing(getOutputDevice().GetAntialiasing()); + } + + void OverlayManagerBuffered::ImpRestoreBackground() const + { + const tools::Rectangle aRegionRectanglePixel( + maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(), + maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY()); + const vcl::Region aRegionPixel(aRegionRectanglePixel); + + ImpRestoreBackground(aRegionPixel); + } + + void OverlayManagerBuffered::ImpRestoreBackground(const vcl::Region& rRegionPixel) const + { + // MapModes off + const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled()); + const bool bMapModeWasEnabledSource(mpBufferDevice->IsMapModeEnabled()); + getOutputDevice().EnableMapMode(false); + const_cast<OverlayManagerBuffered*>(this)->mpBufferDevice->EnableMapMode(false); + + // local region + RectangleVector aRectangles; + rRegionPixel.GetRegionRectangles(aRectangles); + + for(const auto& rRect : aRectangles) + { + // restore the area + const Point aTopLeft(rRect.TopLeft()); + const Size aSize(rRect.GetSize()); + + getOutputDevice().DrawOutDev( + aTopLeft, aSize, // destination + aTopLeft, aSize, // source + *mpBufferDevice); + } + + // restore MapModes + getOutputDevice().EnableMapMode(bMapModeWasEnabledDest); + const_cast<OverlayManagerBuffered*>(this)->mpBufferDevice->EnableMapMode(bMapModeWasEnabledSource); + } + + void OverlayManagerBuffered::ImpSaveBackground(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) + { + // prepare source + OutputDevice& rSource = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice(); + + // Ensure buffer is valid + ImpPrepareBufferDevice(); + + // build region which needs to be copied + vcl::Region aRegion(rSource.LogicToPixel(rRegion)); + + // limit to PaintRegion if it's a window. This will be evtl. the expanded one, + // but always the exact redraw area + if(OUTDEV_WINDOW == rSource.GetOutDevType()) + { + vcl::Window& rWindow = *rSource.GetOwnerWindow(); + vcl::Region aPaintRegionPixel = rWindow.LogicToPixel(rWindow.GetPaintRegion()); + aRegion.Intersect(aPaintRegionPixel); + + // #i72754# Make sure content is completely rendered, the window + // will be used as source of a DrawOutDev soon + rWindow.GetOutDev()->Flush(); + } + + // also limit to buffer size + const tools::Rectangle aBufferDeviceRectanglePixel(Point(), mpBufferDevice->GetOutputSizePixel()); + aRegion.Intersect(aBufferDeviceRectanglePixel); + + // MapModes off + const bool bMapModeWasEnabledDest(rSource.IsMapModeEnabled()); + const bool bMapModeWasEnabledSource(mpBufferDevice->IsMapModeEnabled()); + rSource.EnableMapMode(false); + mpBufferDevice->EnableMapMode(false); + + // prepare to iterate over the rectangles from the region in pixels + RectangleVector aRectangles; + aRegion.GetRegionRectangles(aRectangles); + + for(const auto& rRect : aRectangles) + { + // for each rectangle, save the area + const Point aTopLeft(rRect.TopLeft()); + const Size aSize(rRect.GetSize()); + + mpBufferDevice->DrawOutDev( + aTopLeft, aSize, // destination + aTopLeft, aSize, // source + rSource); + } + + // restore MapModes + rSource.EnableMapMode(bMapModeWasEnabledDest); + mpBufferDevice->EnableMapMode(bMapModeWasEnabledSource); + } + + IMPL_LINK_NOARG(OverlayManagerBuffered, ImpBufferTimerHandler, Timer*, void) + { + //Resolves: fdo#46728 ensure this exists until end of scope + rtl::Reference<OverlayManager> xKeepAlive(this); + + // stop timer + maBufferIdle.Stop(); + + if(maBufferRememberedRangePixel.isEmpty()) + return; + + // logic size for impDrawMember call + basegfx::B2DRange aBufferRememberedRangeLogic( + maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(), + maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY()); + aBufferRememberedRangeLogic.transform(getOutputDevice().GetInverseViewTransformation()); + + // prepare cursor handling + const bool bTargetIsWindow(OUTDEV_WINDOW == mrOutputDevice.GetOutDevType()); + bool bCursorWasEnabled(false); + + // #i80730# switch off VCL cursor during overlay refresh + if(bTargetIsWindow) + { + vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow(); + vcl::Cursor* pCursor = rWindow.GetCursor(); + + if(pCursor && pCursor->IsVisible()) + { + pCursor->Hide(); + bCursorWasEnabled = true; + } + } + + // refresh with prerendering + { + // #i73602# ensure valid and sized mpOutputBufferDevice + const Size aDestinationSizePixel(mpBufferDevice->GetOutputSizePixel()); + const Size aOutputBufferSizePixel(mpOutputBufferDevice->GetOutputSizePixel()); + + if(aDestinationSizePixel != aOutputBufferSizePixel) + { + mpOutputBufferDevice->SetOutputSizePixel(aDestinationSizePixel); + } + + mpOutputBufferDevice->SetMapMode(getOutputDevice().GetMapMode()); + mpOutputBufferDevice->EnableMapMode(false); + mpOutputBufferDevice->SetDrawMode(mpBufferDevice->GetDrawMode()); + mpOutputBufferDevice->SetSettings(mpBufferDevice->GetSettings()); + mpOutputBufferDevice->SetAntialiasing(mpBufferDevice->GetAntialiasing()); + + // calculate sizes + tools::Rectangle aRegionRectanglePixel( + maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(), + maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY()); + + // truncate aRegionRectanglePixel to destination pixel size, more does + // not need to be prepared since destination is a buffer for a window. So, + // maximum size indirectly shall be limited to getOutputDevice().GetOutputSizePixel() + if(aRegionRectanglePixel.Left() < 0) + { + aRegionRectanglePixel.SetLeft( 0 ); + } + + if(aRegionRectanglePixel.Top() < 0) + { + aRegionRectanglePixel.SetTop( 0 ); + } + + if(aRegionRectanglePixel.Right() > aDestinationSizePixel.getWidth()) + { + aRegionRectanglePixel.SetRight( aDestinationSizePixel.getWidth() ); + } + + if(aRegionRectanglePixel.Bottom() > aDestinationSizePixel.getHeight()) + { + aRegionRectanglePixel.SetBottom( aDestinationSizePixel.getHeight() ); + } + + // get sizes + const Point aTopLeft(aRegionRectanglePixel.TopLeft()); + const Size aSize(aRegionRectanglePixel.GetSize()); + + { + const bool bMapModeWasEnabledDest(mpBufferDevice->IsMapModeEnabled()); + mpBufferDevice->EnableMapMode(false); + + mpOutputBufferDevice->DrawOutDev( + aTopLeft, aSize, // destination + aTopLeft, aSize, // source + *mpBufferDevice); + + // restore MapModes + mpBufferDevice->EnableMapMode(bMapModeWasEnabledDest); + } + + // paint overlay content for remembered region, use + // method from base class directly + mpOutputBufferDevice->EnableMapMode(); + OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic, *mpOutputBufferDevice); + mpOutputBufferDevice->EnableMapMode(false); + + // copy to output + { + const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled()); + getOutputDevice().EnableMapMode(false); + + getOutputDevice().DrawOutDev( + aTopLeft, aSize, // destination + aTopLeft, aSize, // source + *mpOutputBufferDevice); + + // debug + /*getOutputDevice().SetLineCOL_RED); + getOutputDevice().SetFillColor(); + getOutputDevice().DrawRect(Rectangle(aTopLeft, aSize));*/ + + // restore MapModes + getOutputDevice().EnableMapMode(bMapModeWasEnabledDest); + } + } + + // VCL hack for transparent child windows + // Problem is e.g. a radiobutton form control in life mode. The used window + // is a transparence vcl childwindow. This flag only allows the parent window to + // paint into the child windows area, but there is no mechanism which takes + // care for a repaint of the child window. A transparent child window is NOT + // a window which always keeps it's content consistent over the parent, but it's + // more like just a paint flag for the parent. + // To get the update, the windows in question are updated manually here. + if(bTargetIsWindow) + { + vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow(); + + const tools::Rectangle aRegionRectanglePixel( + maBufferRememberedRangePixel.getMinX(), + maBufferRememberedRangePixel.getMinY(), + maBufferRememberedRangePixel.getMaxX(), + maBufferRememberedRangePixel.getMaxY()); + PaintTransparentChildren(rWindow, aRegionRectanglePixel); + } + + // #i80730# restore visibility of VCL cursor + if(bCursorWasEnabled) + { + vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow(); + vcl::Cursor* pCursor = rWindow.GetCursor(); + + if(pCursor) + { + // check if cursor still exists. It may have been deleted from someone + pCursor->Show(); + } + } + + // forget remembered Region + maBufferRememberedRangePixel.reset(); + } + + OverlayManagerBuffered::OverlayManagerBuffered( + OutputDevice& rOutputDevice) + : OverlayManager(rOutputDevice), + mpBufferDevice(VclPtr<VirtualDevice>::Create()), + mpOutputBufferDevice(VclPtr<VirtualDevice>::Create()), + maBufferIdle( "sdr::overlay::OverlayManagerBuffered maBufferIdle" ) + { + // Init timer + maBufferIdle.SetPriority( TaskPriority::POST_PAINT ); + maBufferIdle.SetInvokeHandler(LINK(this, OverlayManagerBuffered, ImpBufferTimerHandler)); + } + + rtl::Reference<OverlayManager> OverlayManagerBuffered::create( + OutputDevice& rOutputDevice) + { + return rtl::Reference<OverlayManager>(new OverlayManagerBuffered(rOutputDevice)); + } + + OverlayManagerBuffered::~OverlayManagerBuffered() + { + // Clear timer + maBufferIdle.Stop(); + + if(!maBufferRememberedRangePixel.isEmpty()) + { + // Restore all rectangles for remembered region from buffer + ImpRestoreBackground(); + } + } + + void OverlayManagerBuffered::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const + { + if(!rRegion.IsEmpty()) + { + // save new background + const_cast<OverlayManagerBuffered*>(this)->ImpSaveBackground(rRegion, pPreRenderDevice); + } + + // call parent + OverlayManager::completeRedraw(rRegion, pPreRenderDevice); + } + + void OverlayManagerBuffered::flush() + { + // call timer handler direct + ImpBufferTimerHandler(nullptr); + } + + void OverlayManagerBuffered::invalidateRange(const basegfx::B2DRange& rRange) + { + if(rRange.isEmpty()) + return; + + // buffered output, do not invalidate but use the timer + // to trigger a timer event for refresh + maBufferIdle.Start(); + + // add the discrete range to the remembered region + // #i75163# use double precision and floor/ceil rounding to get overlapped pixel region, even + // when the given logic region has a width/height of 0.0. This does NOT work with LogicToPixel + // since it just transforms the top left and bottom right points equally without taking + // discrete pixel coverage into account. An empty B2DRange and thus empty logic Rectangle translated + // to an also empty discrete pixel rectangle - what is wrong. + basegfx::B2DRange aDiscreteRange(rRange); + aDiscreteRange.transform(getOutputDevice().GetViewTransformation()); + + if(SvtOptionsDrawinglayer::IsAntiAliasing()) + { + // assume AA needs one pixel more and invalidate one pixel more + const double fDiscreteOne(getDiscreteOne()); + const basegfx::B2IPoint aTopLeft( + static_cast<sal_Int32>(floor(aDiscreteRange.getMinX() - fDiscreteOne)), + static_cast<sal_Int32>(floor(aDiscreteRange.getMinY() - fDiscreteOne))); + const basegfx::B2IPoint aBottomRight( + static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxX() + fDiscreteOne)), + static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxY() + fDiscreteOne))); + + maBufferRememberedRangePixel.expand(aTopLeft); + maBufferRememberedRangePixel.expand(aBottomRight); + } + else + { + const basegfx::B2IPoint aTopLeft(static_cast<sal_Int32>(floor(aDiscreteRange.getMinX())), static_cast<sal_Int32>(floor(aDiscreteRange.getMinY()))); + const basegfx::B2IPoint aBottomRight(static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxX())), static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxY()))); + + maBufferRememberedRangePixel.expand(aTopLeft); + maBufferRememberedRangePixel.expand(aBottomRight); + } + } +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayobject.cxx b/svx/source/sdr/overlay/overlayobject.cxx new file mode 100644 index 000000000..4fd227977 --- /dev/null +++ b/svx/source/sdr/overlay/overlayobject.cxx @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <svx/sdr/overlay/overlayobject.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <osl/diagnose.h> + +namespace sdr::overlay +{ + void OverlayObject::objectChange() + { + const basegfx::B2DRange aPreviousRange(maBaseRange); + maBaseRange.reset(); + resetPrimitive2DSequence(); +// setPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DContainer()); + + if(getOverlayManager() && !aPreviousRange.isEmpty()) + { + getOverlayManager()->invalidateRange(aPreviousRange); + } + + const basegfx::B2DRange& rCurrentRange = getBaseRange(); + + if(getOverlayManager() && rCurrentRange != aPreviousRange && !rCurrentRange.isEmpty()) + { + getOverlayManager()->invalidateRange(rCurrentRange); + } + } + + // OverlayObject implementations. + drawinglayer::primitive2d::Primitive2DContainer OverlayObject::createOverlayObjectPrimitive2DSequence() + { + // Default implementation has to assert a missing implementation. It cannot + // be useful to have overlay object derivations which have no visualisation + // at all + OSL_FAIL("OverlayObject derivation without visualisation definition (missing createOverlayObjectPrimitive2DSequence implementation) (!)"); + return drawinglayer::primitive2d::Primitive2DContainer(); + } + + sal_uInt32 OverlayObject::impCheckBlinkTimeValueRange(sal_uInt64 nBlinkTime) + { + if(nBlinkTime < 25) + { + nBlinkTime = 25; + } + else if(nBlinkTime > 10000) + { + nBlinkTime = 10000; + } + + return nBlinkTime; + } + + void OverlayObject::allowAntiAliase(bool bNew) + { + if(bNew != mbAllowsAntiAliase) + { + // remember new value + mbAllowsAntiAliase = bNew; + + // register change (after change) + objectChange(); + } + } + + OverlayObject::OverlayObject(Color aBaseColor) + : mpOverlayManager(nullptr), + maOffset(0.0, 0.0), + maBaseColor(aBaseColor), + mbIsVisible(true), + mbIsHittable(true), + mbAllowsAnimation(false), + mbAllowsAntiAliase(true) + { + } + + OverlayObject::~OverlayObject() + { + OSL_ENSURE(nullptr == getOverlayManager(), "OverlayObject is destructed which is still registered at OverlayManager (!)"); + } + + drawinglayer::primitive2d::Primitive2DContainer OverlayObject::getOverlayObjectPrimitive2DSequence() const + { + if(getPrimitive2DSequence().empty()) + { + // no existing sequence; create one + const_cast< OverlayObject* >(this)->maPrimitive2DSequence = const_cast< OverlayObject* >(this)->createOverlayObjectPrimitive2DSequence(); + + if(!getOffset().equalZero()) + { + // embed to offset transformation + const basegfx::B2DHomMatrix aTranslateGridOffset( + basegfx::utils::createTranslateB2DHomMatrix( + getOffset())); + drawinglayer::primitive2d::Primitive2DReference aEmbed( + new drawinglayer::primitive2d::TransformPrimitive2D( + aTranslateGridOffset, + std::move(const_cast<drawinglayer::primitive2d::Primitive2DContainer&>(maPrimitive2DSequence)))); + + const_cast< OverlayObject* >(this)->maPrimitive2DSequence = drawinglayer::primitive2d::Primitive2DContainer { aEmbed }; + } + } + + return getPrimitive2DSequence(); + } + + const basegfx::B2DRange& OverlayObject::getBaseRange() const + { + if(getOverlayManager() && maBaseRange.isEmpty()) + { + const drawinglayer::primitive2d::Primitive2DContainer& rSequence = getOverlayObjectPrimitive2DSequence(); + + if(!rSequence.empty()) + { + const drawinglayer::geometry::ViewInformation2D & aViewInformation2D(getOverlayManager()->getCurrentViewInformation2D()); + + const_cast< sdr::overlay::OverlayObject* >(this)->maBaseRange = + rSequence.getB2DRange(aViewInformation2D); + } + } + + return maBaseRange; + } + + void OverlayObject::setVisible(bool bNew) + { + if(bNew != mbIsVisible) + { + // remember new value + mbIsVisible = bNew; + + // register change (after change) + objectChange(); + } + } + + void OverlayObject::setHittable(bool bNew) + { + if(bNew != mbIsHittable) + { + // remember new value + mbIsHittable = bNew; + + // register change (after change) + objectChange(); + } + } + + void OverlayObject::setBaseColor(Color aNew) + { + if(aNew != maBaseColor) + { + // remember new value + maBaseColor = aNew; + + // register change (after change) + objectChange(); + } + } + + void OverlayObject::setOffset(const basegfx::B2DVector& rOffset) + { + if(rOffset != maOffset) + { + // remember new value + maOffset = rOffset; + + // register change (after change) + objectChange(); + } + } + + void OverlayObject::Trigger(sal_uInt32 /*nTime*/) + { + // default does not register again + } + + void OverlayObject::stripeDefinitionHasChanged() + { + // default does not need to do anything + } + + + OverlayObjectWithBasePosition::OverlayObjectWithBasePosition(const basegfx::B2DPoint& rBasePos, Color aBaseColor) + : OverlayObject(aBaseColor), + maBasePosition(rBasePos) + { + } + + OverlayObjectWithBasePosition::~OverlayObjectWithBasePosition() + { + } + + void OverlayObjectWithBasePosition::setBasePosition(const basegfx::B2DPoint& rNew) + { + if(rNew != maBasePosition) + { + // remember new value + maBasePosition = rNew; + + // register change (after change) + objectChange(); + } + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayobjectcell.cxx b/svx/source/sdr/overlay/overlayobjectcell.cxx new file mode 100644 index 000000000..a7da6a299 --- /dev/null +++ b/svx/source/sdr/overlay/overlayobjectcell.cxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + + +#include <basegfx/numeric/ftools.hxx> +#include <sdr/overlay/overlayobjectcell.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> + +using namespace ::basegfx; + +namespace sdr::overlay +{ + OverlayObjectCell::OverlayObjectCell( const Color& rColor, RangeVector&& rRects ) + : OverlayObject( rColor ), + maRectangles( std::move(rRects) ) + { + // no AA for selection overlays + allowAntiAliase(false); + } + + OverlayObjectCell::~OverlayObjectCell() + { + } + + drawinglayer::primitive2d::Primitive2DContainer OverlayObjectCell::createOverlayObjectPrimitive2DSequence() + { + drawinglayer::primitive2d::Primitive2DContainer aRetval; + const sal_uInt32 nCount(maRectangles.size()); + + if(nCount) + { + const basegfx::BColor aRGBColor(getBaseColor().getBColor()); + aRetval.resize(nCount); + + // create primitives for all ranges + for(sal_uInt32 a(0); a < nCount; a++) + { + const basegfx::B2DRange& rRange(maRectangles[a]); + const basegfx::B2DPolygon aPolygon(basegfx::utils::createPolygonFromRect(rRange)); + + aRetval[a] = drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + aRGBColor)); + } + + + // embed in 50% transparent paint + drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparence( + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + std::move(aRetval), + 0.5)); + + aRetval = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparence }; + } + + return aRetval; + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayobjectlist.cxx b/svx/source/sdr/overlay/overlayobjectlist.cxx new file mode 100644 index 000000000..d71f6c278 --- /dev/null +++ b/svx/source/sdr/overlay/overlayobjectlist.cxx @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <svx/sdr/overlay/overlayobjectlist.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <vcl/outdev.hxx> +#include <tools/gen.hxx> + +#include <drawinglayer/processor2d/hittestprocessor2d.hxx> +#include <comphelper/lok.hxx> + +#define DEFAULT_VALUE_FOR_HITTEST_PIXEL (2) +#define DEFAULT_VALUE_FOR_HITTEST_TWIP (30) + +namespace sdr::overlay +{ + OverlayObjectList::~OverlayObjectList() + { + clear(); + } + + void OverlayObjectList::clear() + { + for(auto & pCandidate : maVector) + { + if(pCandidate->getOverlayManager()) + pCandidate->getOverlayManager()->remove(*pCandidate); + } + maVector.clear(); + } + + void OverlayObjectList::append(std::unique_ptr<OverlayObject> pOverlayObject) + { + assert(pOverlayObject && "tried to add invalid OverlayObject to OverlayObjectList"); + maVector.push_back(std::move(pOverlayObject)); + } + + bool OverlayObjectList::isHitLogic(const basegfx::B2DPoint& rLogicPosition, double fLogicTolerance) const + { + if(!maVector.empty()) + { + OverlayObject* pFirst = maVector.front().get(); + OverlayManager* pManager = pFirst->getOverlayManager(); + + if(pManager) + { + if(0.0 == fLogicTolerance) + { + Size aSizeLogic(pManager->getOutputDevice().PixelToLogic( + Size(DEFAULT_VALUE_FOR_HITTEST_PIXEL, DEFAULT_VALUE_FOR_HITTEST_PIXEL))); + + // When tiled rendering, we always work in logic units, use the non-pixel default. + if (comphelper::LibreOfficeKit::isActive()) + { + aSizeLogic = Size(DEFAULT_VALUE_FOR_HITTEST_TWIP, DEFAULT_VALUE_FOR_HITTEST_TWIP); + if (pManager->getOutputDevice().GetMapMode().GetMapUnit() == MapUnit::Map100thMM) + aSizeLogic = o3tl::convert(aSizeLogic, o3tl::Length::twip, o3tl::Length::mm100); + } + + fLogicTolerance = aSizeLogic.Width(); + } + + const drawinglayer::geometry::ViewInformation2D& aViewInformation2D(pManager->getCurrentViewInformation2D()); + drawinglayer::processor2d::HitTestProcessor2D aHitTestProcessor2D( + aViewInformation2D, + rLogicPosition, + fLogicTolerance, + false); + + for(auto & pCandidate : maVector) + { + if(pCandidate->isHittable()) + { + const drawinglayer::primitive2d::Primitive2DContainer& rSequence = pCandidate->getOverlayObjectPrimitive2DSequence(); + + if(!rSequence.empty()) + { + aHitTestProcessor2D.process(rSequence); + + if(aHitTestProcessor2D.getHit()) + { + return true; + } + } + } + } + } + } + + return false; + } + + bool OverlayObjectList::isHitPixel(const Point& rDiscretePosition) const + { + constexpr sal_uInt32 nDiscreteTolerance = DEFAULT_VALUE_FOR_HITTEST_PIXEL; + if(!maVector.empty()) + { + OverlayObject* pCandidate = maVector.front().get(); + OverlayManager* pManager = pCandidate->getOverlayManager(); + + if(pManager) + { + const Point aPosLogic(pManager->getOutputDevice().PixelToLogic(rDiscretePosition)); + const basegfx::B2DPoint aPosition(aPosLogic.X(), aPosLogic.Y()); + + const Size aSizeLogic(pManager->getOutputDevice().PixelToLogic(Size(nDiscreteTolerance, nDiscreteTolerance))); + return isHitLogic(aPosition, static_cast<double>(aSizeLogic.Width())); + } + } + + return false; + } + + basegfx::B2DRange OverlayObjectList::getBaseRange() const + { + basegfx::B2DRange aRetval; + + for(auto & pCandidate : maVector) + { + aRetval.expand(pCandidate->getBaseRange()); + } + + return aRetval; + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlaypolypolygon.cxx b/svx/source/sdr/overlay/overlaypolypolygon.cxx new file mode 100644 index 000000000..69dacf375 --- /dev/null +++ b/svx/source/sdr/overlay/overlaypolypolygon.cxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <svx/sdr/overlay/overlaypolypolygon.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> +#include <svtools/optionsdrawinglayer.hxx> + + +namespace sdr::overlay +{ + OverlayPolyPolygon::OverlayPolyPolygon( + const basegfx::B2DPolyPolygon& rLinePolyPolygon, + Color const & rLineColor, + double fLineWidth, + Color const & rFillColor) + : OverlayObject(rLineColor) + , maLinePolyPolygon(rLinePolyPolygon) + , mfLineWidth(fLineWidth) + , maFillColor(rFillColor) + { + } + + OverlayPolyPolygon::~OverlayPolyPolygon() = default; + + drawinglayer::primitive2d::Primitive2DContainer OverlayPolyPolygon::createOverlayObjectPrimitive2DSequence() + { + drawinglayer::primitive2d::Primitive2DContainer aReturnContainer; + + if (getOverlayManager()) + { + const drawinglayer::attribute::LineAttribute aLineAttribute(getBaseColor().getBColor(), mfLineWidth); + + aReturnContainer = drawinglayer::primitive2d::Primitive2DContainer { + new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(maLinePolyPolygon, aLineAttribute) }; + + if (maFillColor.GetAlpha() != 0) + { + aReturnContainer.push_back(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(maLinePolyPolygon, maFillColor.getBColor())); + } + + sal_uInt8 nTransparency = 255 - getBaseColor().GetAlpha(); + if (nTransparency > 0) + { + drawinglayer::primitive2d::Primitive2DReference aTransparencePrimitive( + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aReturnContainer), nTransparency / 255.0)); + aReturnContainer = drawinglayer::primitive2d::Primitive2DContainer{ aTransparencePrimitive }; + } + } + + return aReturnContainer; + } + + drawinglayer::primitive2d::Primitive2DContainer OverlayPolyPolygonStripedAndFilled::createOverlayObjectPrimitive2DSequence() + { + drawinglayer::primitive2d::Primitive2DContainer aRetval; + + if(getOverlayManager()) + { + const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor()); + const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor()); + const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel()); + const drawinglayer::primitive2d::Primitive2DReference aStriped( + new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D( + getLinePolyPolygon(), + aRGBColorA, + aRGBColorB, + fStripeLengthPixel)); + + aRetval = drawinglayer::primitive2d::Primitive2DContainer { aStriped }; + + const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor()); + const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01); + + const drawinglayer::primitive2d::Primitive2DReference aFilled( + new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D( + getLinePolyPolygon(), + aHilightColor, + fTransparence, + 3.0, + false)); + + aRetval.push_back(aFilled); + } + + return aRetval; + } + + void OverlayPolyPolygonStripedAndFilled::stripeDefinitionHasChanged() + { + // react on OverlayManager's stripe definition change + objectChange(); + } + + OverlayPolyPolygonStripedAndFilled::OverlayPolyPolygonStripedAndFilled( + const basegfx::B2DPolyPolygon& rLinePolyPolygon) + : OverlayObject(COL_BLACK), + maLinePolyPolygon(rLinePolyPolygon) + { + } + + OverlayPolyPolygonStripedAndFilled::~OverlayPolyPolygonStripedAndFilled() + { + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx b/svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx new file mode 100644 index 000000000..eabd290f8 --- /dev/null +++ b/svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + + +#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx> + + +namespace sdr::overlay +{ + drawinglayer::primitive2d::Primitive2DContainer OverlayPrimitive2DSequenceObject::createOverlayObjectPrimitive2DSequence() + { + return maSequence; + } + + OverlayPrimitive2DSequenceObject::OverlayPrimitive2DSequenceObject(drawinglayer::primitive2d::Primitive2DContainer&& rSequence) + : OverlayObjectWithBasePosition(basegfx::B2DPoint(), COL_BLACK), + maSequence(std::move(rSequence)) + { + } + + OverlayPrimitive2DSequenceObject::~OverlayPrimitive2DSequenceObject() + { + } +} // end of namespace sdr::overlay + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayrectangle.cxx b/svx/source/sdr/overlay/overlayrectangle.cxx new file mode 100644 index 000000000..617c6d4dc --- /dev/null +++ b/svx/source/sdr/overlay/overlayrectangle.cxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sdr/overlay/overlayrectangle.hxx> +#include <sdr/overlay/overlaytools.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + + +namespace sdr::overlay +{ + drawinglayer::primitive2d::Primitive2DContainer OverlayRectangle::createOverlayObjectPrimitive2DSequence() + { + const basegfx::B2DRange aHatchRange(getBasePosition(), maSecondPosition); + basegfx::BColor aColor(getBaseColor().getBColor()); + static const double fChange(0.1); // just small optical change, do not make it annoying + + if(mbOverlayState) + { + aColor += basegfx::B3DTuple(fChange, fChange, fChange); + aColor.clamp(); + } + else + { + aColor -= basegfx::B3DTuple(fChange, fChange, fChange); + aColor.clamp(); + } + + const drawinglayer::primitive2d::Primitive2DReference aReference( + new drawinglayer::primitive2d::OverlayRectanglePrimitive( + aHatchRange, + aColor, + mfTransparence, + mfDiscreteGrow, + mfDiscreteShrink, + mfRotation)); + + return drawinglayer::primitive2d::Primitive2DContainer { aReference }; + } + + OverlayRectangle::OverlayRectangle( + const basegfx::B2DPoint& rBasePosition, + const basegfx::B2DPoint& rSecondPosition, + const Color& rHatchColor, + double fTransparence, + double fDiscreteGrow, + double fDiscreteShrink, + double fRotation, + bool bAnimate) + : OverlayObjectWithBasePosition(rBasePosition, rHatchColor), + maSecondPosition(rSecondPosition), + mfTransparence(fTransparence), + mfDiscreteGrow(fDiscreteGrow), + mfDiscreteShrink(fDiscreteShrink), + mfRotation(fRotation), + mnBlinkTime(impCheckBlinkTimeValueRange(500)), + mbOverlayState(false) + { + if(Application::GetSettings().GetStyleSettings().GetHighContrastMode()) + { + // no animation in high contrast mode + bAnimate = false; + } + + // set AllowsAnimation flag to mark this object as animation capable + mbAllowsAnimation = bAnimate; + } + + void OverlayRectangle::Trigger(sal_uInt32 nTime) + { + if(!getOverlayManager()) + return; + + // #i53216# produce event after nTime + x + SetTime(nTime + mnBlinkTime); + + // switch state + if(mbOverlayState) + { + mbOverlayState = false; + } + else + { + mbOverlayState = true; + } + + // re-insert me as event + getOverlayManager()->InsertEvent(*this); + + // register change (after change) + objectChange(); + } +} // end of namespace + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayrollingrectangle.cxx b/svx/source/sdr/overlay/overlayrollingrectangle.cxx new file mode 100644 index 000000000..f03380edd --- /dev/null +++ b/svx/source/sdr/overlay/overlayrollingrectangle.cxx @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sdr/overlay/overlayrollingrectangle.hxx> +#include <sdr/overlay/overlaytools.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx> +#include <svtools/optionsdrawinglayer.hxx> + +namespace sdr::overlay +{ + drawinglayer::primitive2d::Primitive2DContainer OverlayRollingRectangleStriped::createOverlayObjectPrimitive2DSequence() + { + drawinglayer::primitive2d::Primitive2DContainer aRetval; + + if(getOverlayManager() && (mbShowBounds || mbExtendedLines)) + { + const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor()); + const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor()); + const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel()); + const basegfx::B2DRange aRollingRectangle(getBasePosition(), getSecondPosition()); + + if(mbShowBounds) + { + // view-independent part, create directly + const basegfx::B2DPolygon aPolygon(basegfx::utils::createPolygonFromRect(aRollingRectangle)); + + aRetval.resize(2); + aRetval[0] = new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + aRGBColorA, + aRGBColorB, + fStripeLengthPixel); + + const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor()); + const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01); + + aRetval[1] = new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + aHilightColor, + fTransparence, + 3.0, + false); + } + + if(mbExtendedLines) + { + // view-dependent part, use helper primitive + const drawinglayer::primitive2d::Primitive2DReference aReference( + new drawinglayer::primitive2d::OverlayRollingRectanglePrimitive( + aRollingRectangle, + aRGBColorA, + aRGBColorB, + fStripeLengthPixel)); + + aRetval.push_back(aReference); + } + } + + return aRetval; + } + + void OverlayRollingRectangleStriped::stripeDefinitionHasChanged() + { + // react on OverlayManager's stripe definition change + objectChange(); + } + + OverlayRollingRectangleStriped::OverlayRollingRectangleStriped( + const basegfx::B2DPoint& rBasePos, + const basegfx::B2DPoint& rSecondPos, + bool bExtendedLines, + bool bShowBounds) + : OverlayObjectWithBasePosition(rBasePos, COL_BLACK), + maSecondPosition(rSecondPos), + mbExtendedLines(bExtendedLines), + mbShowBounds(bShowBounds) + { + } + + OverlayRollingRectangleStriped::~OverlayRollingRectangleStriped() + { + } + + void OverlayRollingRectangleStriped::setSecondPosition(const basegfx::B2DPoint& rNew) + { + if(rNew != maSecondPosition) + { + // remember new value + maSecondPosition = rNew; + + // register change (after change) + objectChange(); + } + } +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlayselection.cxx b/svx/source/sdr/overlay/overlayselection.cxx new file mode 100644 index 000000000..0463567c5 --- /dev/null +++ b/svx/source/sdr/overlay/overlayselection.cxx @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <svx/sdr/overlay/overlayselection.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolyPolygonHairlinePrimitive2D.hxx> +#include <svtools/optionsdrawinglayer.hxx> +#include <vcl/svapp.hxx> +#include <vcl/outdev.hxx> +#include <vcl/settings.hxx> +#include <drawinglayer/primitive2d/invertprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> + + +namespace sdr::overlay +{ + // combine rages geometrically to a single, ORed polygon + static basegfx::B2DPolyPolygon impCombineRangesToPolyPolygon(const std::vector< basegfx::B2DRange >& rRanges) + { + const sal_uInt32 nCount(rRanges.size()); + basegfx::B2DPolyPolygon aRetval; + + for(sal_uInt32 a(0); a < nCount; a++) + { + const basegfx::B2DPolygon aDiscretePolygon(basegfx::utils::createPolygonFromRect(rRanges[a])); + + if(0 == a) + { + aRetval.append(aDiscretePolygon); + } + else + { + aRetval = basegfx::utils::solvePolygonOperationOr(aRetval, basegfx::B2DPolyPolygon(aDiscretePolygon)); + } + } + + return aRetval; + } + + // check if wanted type OverlayType::Transparent or OverlayType::Solid + // is possible. If not, fallback to invert mode (classic mode) + static OverlayType impCheckPossibleOverlayType(OverlayType aOverlayType) + { + if(OverlayType::Invert != aOverlayType) + { + if(!SvtOptionsDrawinglayer::IsTransparentSelection()) + { + // not possible when switched off by user + return OverlayType::Invert; + } + else if (const OutputDevice* pOut = Application::GetDefaultDevice()) + { + + if(pOut->GetSettings().GetStyleSettings().GetHighContrastMode()) + { + // not possible when in high contrast mode + return OverlayType::Invert; + } + + if(!pOut->SupportsOperation(OutDevSupportType::TransparentRect)) + { + // not possible when no fast transparence paint is supported on the system + return OverlayType::Invert; + } + } + } + + return aOverlayType; + } + + drawinglayer::primitive2d::Primitive2DContainer OverlaySelection::createOverlayObjectPrimitive2DSequence() + { + drawinglayer::primitive2d::Primitive2DContainer aRetval; + const sal_uInt32 nCount(getRanges().size()); + + if(nCount) + { + // create range primitives + const bool bInvert(OverlayType::Invert == maLastOverlayType); + basegfx::BColor aRGBColor(getBaseColor().getBColor()); + aRetval.resize(nCount); + + if(bInvert) + { + // force color to white for invert to get a full invert + aRGBColor = basegfx::BColor(1.0, 1.0, 1.0); + } + + for(sal_uInt32 a(0);a < nCount; a++) + { + const basegfx::B2DPolygon aPolygon(basegfx::utils::createPolygonFromRect(maRanges[a])); + aRetval[a] = drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + aRGBColor)); + } + + if(bInvert) + { + // embed all in invert primitive + drawinglayer::primitive2d::Primitive2DReference aInvert( + new drawinglayer::primitive2d::InvertPrimitive2D( + std::move(aRetval))); + aRetval = drawinglayer::primitive2d::Primitive2DContainer { aInvert }; + } + else if(OverlayType::Transparent == maLastOverlayType) + { + // embed all rectangles in transparent paint + const double fTransparence(mnLastTransparence / 100.0); + const drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparence( + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + std::move(aRetval), + fTransparence)); + + if(mbBorder) + { + const basegfx::B2DPolyPolygon aPolyPolygon(impCombineRangesToPolyPolygon(getRanges())); + const drawinglayer::primitive2d::Primitive2DReference aSelectionOutline( + new drawinglayer::primitive2d::PolyPolygonHairlinePrimitive2D( + aPolyPolygon, + aRGBColor)); + + // add both to result + aRetval = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparence, aSelectionOutline }; + } + else + { + // just add transparent part + aRetval = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparence }; + } + } + } + + return aRetval; + } + + OverlaySelection::OverlaySelection( + OverlayType eType, + const Color& rColor, + std::vector< basegfx::B2DRange >&& rRanges, + bool bBorder) + : OverlayObject(rColor), + meOverlayType(eType), + maRanges(std::move(rRanges)), + maLastOverlayType(eType), + mnLastTransparence(0), + mbBorder(bBorder) + { + // no AA for selection overlays + allowAntiAliase(false); + } + + OverlaySelection::~OverlaySelection() + { + if(getOverlayManager()) + { + getOverlayManager()->remove(*this); + } + } + + drawinglayer::primitive2d::Primitive2DContainer OverlaySelection::getOverlayObjectPrimitive2DSequence() const + { + // get current values + const OverlayType aNewOverlayType(impCheckPossibleOverlayType(meOverlayType)); + const sal_uInt16 nNewTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent()); + + if(!getPrimitive2DSequence().empty()) + { + if(aNewOverlayType != maLastOverlayType + || nNewTransparence != mnLastTransparence) + { + // conditions of last local decomposition have changed, delete + const_cast< OverlaySelection* >(this)->resetPrimitive2DSequence(); + } + } + + if(getPrimitive2DSequence().empty()) + { + // remember new values + const_cast< OverlaySelection* >(this)->maLastOverlayType = aNewOverlayType; + const_cast< OverlaySelection* >(this)->mnLastTransparence = nNewTransparence; + } + + // call base implementation + return OverlayObject::getOverlayObjectPrimitive2DSequence(); + } + + void OverlaySelection::setRanges(std::vector< basegfx::B2DRange >&& rNew) + { + if(rNew != maRanges) + { + maRanges = std::move(rNew); + objectChange(); + } + } +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlaytools.cxx b/svx/source/sdr/overlay/overlaytools.cxx new file mode 100644 index 000000000..ceeb32b3f --- /dev/null +++ b/svx/source/sdr/overlay/overlaytools.cxx @@ -0,0 +1,601 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + + +#include <sdr/overlay/overlaytools.hxx> +#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <toolkit/helper/vclunohelper.hxx> + + +namespace drawinglayer::primitive2d +{ + +OverlayStaticRectanglePrimitive::OverlayStaticRectanglePrimitive( + const basegfx::B2DPoint& rPosition, + const basegfx::B2DSize& rSize, + const basegfx::BColor& rStrokeColor, + const basegfx::BColor& rFillColor, + double fTransparence, + double fRotation) + : maPosition(rPosition) + , maSize(rSize) + , maStrokeColor(rStrokeColor) + , maFillColor(rFillColor) + , mfTransparence(fTransparence) + , mfRotation(fRotation) +{} + +void OverlayStaticRectanglePrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const +{ + Primitive2DContainer aPrimitive2DSequence; + const double fHalfWidth = maSize.getX() * getDiscreteUnit() / 2.0; + const double fHalfHeight = maSize.getY() * getDiscreteUnit() / 2.0; + + basegfx::B2DRange aRange( + maPosition.getX() - fHalfWidth, maPosition.getY() - fHalfHeight, + maPosition.getX() + fHalfWidth, maPosition.getY() + fHalfHeight); + + if (basegfx::fTools::more(getDiscreteUnit(), 0.0) && mfTransparence <= 1.0) + { + basegfx::B2DPolygon aPolygon( + basegfx::utils::createPolygonFromRect(aRange)); + + // create filled primitive + basegfx::B2DPolyPolygon aPolyPolygon; + aPolyPolygon.append(aPolygon); + + const attribute::LineAttribute aLineAttribute(maStrokeColor, 1.0); + + // create data + const Primitive2DReference aStroke( + new PolyPolygonStrokePrimitive2D(aPolyPolygon, aLineAttribute)); + + // create fill primitive + const Primitive2DReference aFill( + new PolyPolygonColorPrimitive2D(aPolyPolygon, maFillColor)); + + aPrimitive2DSequence = Primitive2DContainer(2); + aPrimitive2DSequence[0] = aFill; + aPrimitive2DSequence[1] = aStroke; + + // embed filled to transparency (if used) + if (mfTransparence > 0.0) + { + const Primitive2DReference aFillTransparent( + new UnifiedTransparencePrimitive2D( + std::move(aPrimitive2DSequence), + mfTransparence)); + + aPrimitive2DSequence = Primitive2DContainer { aFillTransparent }; + } + } + + rContainer.append(std::move(aPrimitive2DSequence)); +} + +bool OverlayStaticRectanglePrimitive::operator==(const BasePrimitive2D& rPrimitive) const +{ + if (DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) + { + const OverlayStaticRectanglePrimitive& rCompare = static_cast<const OverlayStaticRectanglePrimitive&>(rPrimitive); + + return (maPosition == rCompare.maPosition + && maSize == rCompare.maSize + && maStrokeColor == rCompare.maStrokeColor + && maFillColor == rCompare.maFillColor + && mfTransparence == rCompare.mfTransparence + && mfRotation == rCompare.mfRotation); + } + + return false; +} + +sal_uInt32 OverlayStaticRectanglePrimitive::getPrimitive2DID() const +{ + return PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE; +} + + + + OverlayBitmapExPrimitive::OverlayBitmapExPrimitive( + const BitmapEx& rBitmapEx, + const basegfx::B2DPoint& rBasePosition, + sal_uInt16 nCenterX, + sal_uInt16 nCenterY, + double fShearX, + double fRotation) + : maBitmapEx(rBitmapEx), + maBasePosition(rBasePosition), + mnCenterX(nCenterX), + mnCenterY(nCenterY), + mfShearX(fShearX), + mfRotation(fRotation) + {} + + void OverlayBitmapExPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const + { + const Size aBitmapSize(getBitmapEx().GetSizePixel()); + + if(!aBitmapSize.Width() || !aBitmapSize.Height() || !basegfx::fTools::more(getDiscreteUnit(), 0.0)) + return; + + // calculate back from internal bitmap's extreme coordinates (the edges) + // to logical coordinates. Only use a unified scaling value (getDiscreteUnit(), + // the prepared one which expresses how many logic units form a discrete unit) + // for this step. This primitive is to be displayed always unscaled (in its pixel size) + // and unrotated, more like a marker + const double fLeft((0.0 - getCenterX()) * getDiscreteUnit()); + const double fTop((0.0 - getCenterY()) * getDiscreteUnit()); + const double fRight((aBitmapSize.getWidth() - getCenterX()) * getDiscreteUnit()); + const double fBottom((aBitmapSize.getHeight() - getCenterY()) * getDiscreteUnit()); + + // create a BitmapPrimitive2D using those positions + basegfx::B2DHomMatrix aTransform; + + aTransform.set(0, 0, fRight - fLeft); + aTransform.set(1, 1, fBottom - fTop); + aTransform.set(0, 2, fLeft); + aTransform.set(1, 2, fTop); + + // if shearX is used, apply it, too + if(!basegfx::fTools::equalZero(getShearX())) + { + aTransform.shearX(getShearX()); + } + + // if rotation is used, apply it, too + if(!basegfx::fTools::equalZero(getRotation())) + { + aTransform.rotate(getRotation()); + } + + // add BasePosition + aTransform.translate(getBasePosition().getX(), getBasePosition().getY()); + + rContainer.push_back( + new BitmapPrimitive2D( + VCLUnoHelper::CreateVCLXBitmap(getBitmapEx()), + aTransform)); + } + + bool OverlayBitmapExPrimitive::operator==( const BasePrimitive2D& rPrimitive ) const + { + if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) + { + const OverlayBitmapExPrimitive& rCompare = static_cast< const OverlayBitmapExPrimitive& >(rPrimitive); + + return (getBitmapEx() == rCompare.getBitmapEx() + && getBasePosition() == rCompare.getBasePosition() + && getCenterX() == rCompare.getCenterX() + && getCenterY() == rCompare.getCenterY() + && getShearX() == rCompare.getShearX() + && getRotation() == rCompare.getRotation()); + } + + return false; + } + + sal_uInt32 OverlayBitmapExPrimitive::getPrimitive2DID() const + { + return PRIMITIVE2D_ID_OVERLAYBITMAPEXPRIMITIVE; + } + + + + OverlayCrosshairPrimitive::OverlayCrosshairPrimitive( + const basegfx::B2DPoint& rBasePosition, + const basegfx::BColor& rRGBColorA, + const basegfx::BColor& rRGBColorB, + double fDiscreteDashLength) + : maBasePosition(rBasePosition), + maRGBColorA(rRGBColorA), + maRGBColorB(rRGBColorB), + mfDiscreteDashLength(fDiscreteDashLength) + {} + + void OverlayCrosshairPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // use the prepared Viewport information accessible using getViewport() + + if(getViewport().isEmpty()) + return; + + basegfx::B2DPolygon aPolygon; + + aPolygon.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY())); + aPolygon.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY())); + + rContainer.push_back( + new PolygonMarkerPrimitive2D( + aPolygon, + getRGBColorA(), + getRGBColorB(), + getDiscreteDashLength())); + + aPolygon.clear(); + aPolygon.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY())); + aPolygon.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY())); + + rContainer.push_back( + new PolygonMarkerPrimitive2D( + aPolygon, + getRGBColorA(), + getRGBColorB(), + getDiscreteDashLength())); + } + + bool OverlayCrosshairPrimitive::operator==( const BasePrimitive2D& rPrimitive ) const + { + if(ViewportDependentPrimitive2D::operator==(rPrimitive)) + { + const OverlayCrosshairPrimitive& rCompare = static_cast< const OverlayCrosshairPrimitive& >(rPrimitive); + + return (getBasePosition() == rCompare.getBasePosition() + && getRGBColorA() == rCompare.getRGBColorA() + && getRGBColorB() == rCompare.getRGBColorB() + && getDiscreteDashLength() == rCompare.getDiscreteDashLength()); + } + + return false; + } + + sal_uInt32 OverlayCrosshairPrimitive::getPrimitive2DID() const + { + return PRIMITIVE2D_ID_OVERLAYCROSSHAIRPRIMITIVE; + } + + + + OverlayRectanglePrimitive::OverlayRectanglePrimitive( + const basegfx::B2DRange& rObjectRange, + const basegfx::BColor& rColor, + double fTransparence, + double fDiscreteGrow, + double fDiscreteShrink, + double fRotation) + : maObjectRange(rObjectRange), + maColor(rColor), + mfTransparence(fTransparence), + mfDiscreteGrow(fDiscreteGrow), + mfDiscreteShrink(fDiscreteShrink), + mfRotation(fRotation) + {} + + void OverlayRectanglePrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const + { + Primitive2DContainer aRetval; + basegfx::B2DRange aInnerRange(getObjectRange()); + + if(!aInnerRange.isEmpty() && basegfx::fTools::more(getDiscreteUnit(), 0.0) && getTransparence() <= 1.0) + { + basegfx::B2DRange aOuterRange(getObjectRange()); + + // grow/shrink inner/outer polygons + aOuterRange.grow(getDiscreteUnit() * getDiscreteGrow()); + aInnerRange.grow(getDiscreteUnit() * -getDiscreteShrink()); + + // convert to polygons + const double fFullGrow(getDiscreteGrow() + getDiscreteShrink()); + const double fRelativeRadiusX(fFullGrow / aOuterRange.getWidth()); + const double fRelativeRadiusY(fFullGrow / aOuterRange.getHeight()); + basegfx::B2DPolygon aOuterPolygon( + basegfx::utils::createPolygonFromRect( + aOuterRange, + fRelativeRadiusX, + fRelativeRadiusY)); + basegfx::B2DPolygon aInnerPolygon( + basegfx::utils::createPolygonFromRect( + aInnerRange)); + + // apply evtl. existing rotation + if(!basegfx::fTools::equalZero(getRotation())) + { + const basegfx::B2DHomMatrix aTransform(basegfx::utils::createRotateAroundPoint( + getObjectRange().getMinX(), getObjectRange().getMinY(), getRotation())); + + aOuterPolygon.transform(aTransform); + aInnerPolygon.transform(aTransform); + } + + // create filled primitive + basegfx::B2DPolyPolygon aPolyPolygon; + + aPolyPolygon.append(aOuterPolygon); + aPolyPolygon.append(aInnerPolygon); + + if(Application::GetSettings().GetStyleSettings().GetHighContrastMode()) + { + // for high contrast, use hatch + const basegfx::BColor aHighContrastLineColor(Application::GetSettings().GetStyleSettings().GetFontColor().getBColor()); + const basegfx::BColor aEmptyColor(0.0, 0.0, 0.0); + const double fHatchRotation(basegfx::deg2rad(45)); + const double fDiscreteHatchDistance(3.0); + const drawinglayer::attribute::FillHatchAttribute aFillHatchAttribute( + drawinglayer::attribute::HatchStyle::Single, + fDiscreteHatchDistance * getDiscreteUnit(), + fHatchRotation - getRotation(), + aHighContrastLineColor, + 3, // same default as VCL, a minimum of three discrete units (pixels) offset + false); + const Primitive2DReference aHatch( + new PolyPolygonHatchPrimitive2D( + aPolyPolygon, + aEmptyColor, + aFillHatchAttribute)); + + aRetval = Primitive2DContainer { aHatch }; + } + else + { + // create fill primitive + const Primitive2DReference aFill( + new PolyPolygonColorPrimitive2D( + aPolyPolygon, + getColor())); + + aRetval = Primitive2DContainer { aFill }; + + // embed filled to transparency (if used) + if(getTransparence() > 0.0) + { + Primitive2DReference aFillTransparent( + new UnifiedTransparencePrimitive2D( + std::move(aRetval), + getTransparence())); + + aRetval = Primitive2DContainer { aFillTransparent }; + } + } + } + + rContainer.append(std::move(aRetval)); + } + + bool OverlayRectanglePrimitive::operator==( const BasePrimitive2D& rPrimitive ) const + { + if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) + { + const OverlayRectanglePrimitive& rCompare = static_cast< const OverlayRectanglePrimitive& >(rPrimitive); + + return (getObjectRange() == rCompare.getObjectRange() + && getColor() == rCompare.getColor() + && getTransparence() == rCompare.getTransparence() + && getDiscreteGrow() == rCompare.getDiscreteGrow() + && getDiscreteShrink() == rCompare.getDiscreteShrink() + && getRotation() == rCompare.getRotation()); + } + + return false; + } + + sal_uInt32 OverlayRectanglePrimitive::getPrimitive2DID() const + { + return PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE; + } + + + + OverlayHelplineStripedPrimitive::OverlayHelplineStripedPrimitive( + const basegfx::B2DPoint& rBasePosition, + HelplineStyle eStyle, + const basegfx::BColor& rRGBColorA, + const basegfx::BColor& rRGBColorB, + double fDiscreteDashLength) + : maBasePosition(rBasePosition), + meStyle(eStyle), + maRGBColorA(rRGBColorA), + maRGBColorB(rRGBColorB), + mfDiscreteDashLength(fDiscreteDashLength) + {} + + void OverlayHelplineStripedPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const + { + // use the prepared Viewport information accessible using getViewport() + + if(getViewport().isEmpty()) + return; + + switch(getStyle()) + { + case HELPLINESTYLE_VERTICAL : + { + basegfx::B2DPolygon aLine; + + aLine.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY())); + aLine.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY())); + + rContainer.push_back( + new PolygonMarkerPrimitive2D( + aLine, + getRGBColorA(), + getRGBColorB(), + getDiscreteDashLength())); + break; + } + + case HELPLINESTYLE_HORIZONTAL : + { + basegfx::B2DPolygon aLine; + + aLine.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY())); + aLine.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY())); + + rContainer.push_back( + new PolygonMarkerPrimitive2D( + aLine, + getRGBColorA(), + getRGBColorB(), + getDiscreteDashLength())); + break; + } + + default: // case HELPLINESTYLE_POINT : + { + const double fDiscreteUnit((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength()); + basegfx::B2DPolygon aLineA, aLineB; + + aLineA.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() - fDiscreteUnit)); + aLineA.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() + fDiscreteUnit)); + + rContainer.push_back( + new PolygonMarkerPrimitive2D( + aLineA, + getRGBColorA(), + getRGBColorB(), + getDiscreteDashLength())); + + aLineB.append(basegfx::B2DPoint(getBasePosition().getX() - fDiscreteUnit, getBasePosition().getY())); + aLineB.append(basegfx::B2DPoint(getBasePosition().getX() + fDiscreteUnit, getBasePosition().getY())); + + rContainer.push_back( + new PolygonMarkerPrimitive2D( + aLineB, + getRGBColorA(), + getRGBColorB(), + getDiscreteDashLength())); + + break; + } + } + } + + bool OverlayHelplineStripedPrimitive::operator==( const BasePrimitive2D& rPrimitive ) const + { + if(ViewportDependentPrimitive2D::operator==(rPrimitive)) + { + const OverlayHelplineStripedPrimitive& rCompare = static_cast< const OverlayHelplineStripedPrimitive& >(rPrimitive); + + return (getBasePosition() == rCompare.getBasePosition() + && getStyle() == rCompare.getStyle() + && getRGBColorA() == rCompare.getRGBColorA() + && getRGBColorB() == rCompare.getRGBColorB() + && getDiscreteDashLength() == rCompare.getDiscreteDashLength()); + } + + return false; + } + + sal_uInt32 OverlayHelplineStripedPrimitive::getPrimitive2DID() const + { + return PRIMITIVE2D_ID_OVERLAYHELPLINESTRIPEDPRIMITIVE; + } + + + + OverlayRollingRectanglePrimitive::OverlayRollingRectanglePrimitive( + const basegfx::B2DRange& aRollingRectangle, + const basegfx::BColor& rRGBColorA, + const basegfx::BColor& rRGBColorB, + double fDiscreteDashLength) + : maRollingRectangle(aRollingRectangle), + maRGBColorA(rRGBColorA), + maRGBColorB(rRGBColorB), + mfDiscreteDashLength(fDiscreteDashLength) + {} + + void OverlayRollingRectanglePrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // use the prepared Viewport information accessible using getViewport() + + if(getViewport().isEmpty()) + return; + + basegfx::B2DPolygon aLine; + + // Left lines + aLine.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMinY())); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY())); + rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength())); + + aLine.clear(); + aLine.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMaxY())); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY())); + rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength())); + + // Right lines + aLine.clear(); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY())); + aLine.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMinY())); + rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength())); + + aLine.clear(); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY())); + aLine.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMaxY())); + rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength())); + + // Top lines + aLine.clear(); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMinY())); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY())); + rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength())); + + aLine.clear(); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMinY())); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY())); + rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength())); + + // Bottom lines + aLine.clear(); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY())); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMaxY())); + rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength())); + + aLine.clear(); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY())); + aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMaxY())); + rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength())); + + } + + bool OverlayRollingRectanglePrimitive::operator==( const BasePrimitive2D& rPrimitive ) const + { + if(ViewportDependentPrimitive2D::operator==(rPrimitive)) + { + const OverlayRollingRectanglePrimitive& rCompare = static_cast< const OverlayRollingRectanglePrimitive& >(rPrimitive); + + return (getRollingRectangle() == rCompare.getRollingRectangle() + && getRGBColorA() == rCompare.getRGBColorA() + && getRGBColorB() == rCompare.getRGBColorB() + && getDiscreteDashLength() == rCompare.getDiscreteDashLength()); + } + + return false; + } + + sal_uInt32 OverlayRollingRectanglePrimitive::getPrimitive2DID() const + { + return PRIMITIVE2D_ID_OVERLAYROLLINGRECTANGLEPRIMITIVE; + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/sdr/overlay/overlaytriangle.cxx b/svx/source/sdr/overlay/overlaytriangle.cxx new file mode 100644 index 000000000..f46fcf1e2 --- /dev/null +++ b/svx/source/sdr/overlay/overlaytriangle.cxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sdr/overlay/overlaytriangle.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> + + +namespace sdr::overlay +{ + drawinglayer::primitive2d::Primitive2DContainer OverlayTriangle::createOverlayObjectPrimitive2DSequence() + { + basegfx::B2DPolygon aPolygon; + + aPolygon.append(getBasePosition()); + aPolygon.append(maSecondPosition); + aPolygon.append(maThirdPosition); + aPolygon.setClosed(true); + + const drawinglayer::primitive2d::Primitive2DReference aReference( + new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + getBaseColor().getBColor())); + + return drawinglayer::primitive2d::Primitive2DContainer { aReference }; + } + + OverlayTriangle::OverlayTriangle( + const basegfx::B2DPoint& rBasePos, + const basegfx::B2DPoint& rSecondPos, + const basegfx::B2DPoint& rThirdPos, + Color aTriangleColor) + : OverlayObjectWithBasePosition(rBasePos, aTriangleColor), + maSecondPosition(rSecondPos), + maThirdPosition(rThirdPos) + { + } + + OverlayTriangle::~OverlayTriangle() + { + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |