summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/svx/diagram/IDiagramHelper.hxx19
-rw-r--r--include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx1
-rw-r--r--sd/source/ui/func/fusel.cxx26
-rw-r--r--svx/source/diagram/IDiagramHelper.cxx360
4 files changed, 359 insertions, 47 deletions
diff --git a/include/svx/diagram/IDiagramHelper.hxx b/include/svx/diagram/IDiagramHelper.hxx
index c0bf0539050d..e93056f70049 100644
--- a/include/svx/diagram/IDiagramHelper.hxx
+++ b/include/svx/diagram/IDiagramHelper.hxx
@@ -22,6 +22,7 @@
#include <vector>
#include <svx/svxdllapi.h>
#include <rtl/ustring.hxx>
+#include <svx/svdhdl.hxx>
// Forward declarations
class SdrObjGroup;
@@ -29,6 +30,24 @@ class SdrHdlList;
namespace svx { namespace diagram {
+// Helper class to visualize an imminently recognizable
+// additional visualization for DynamicDiagrams that can also
+// be used to show/hide the DiagramDialog by the user
+// Note: is also used as additional drag/move handle
+class SVXCORE_DLLPUBLIC DiagramFrameHdl final : public SdrHdl
+{
+ // object dimensions
+ basegfx::B2DHomMatrix maTransformation;
+
+ // create marker for this kind
+ virtual void CreateB2dIAObject() override;
+
+public:
+ DiagramFrameHdl(const basegfx::B2DHomMatrix& rTransformation);
+
+ static void clicked(const Point& rPnt);
+};
+
class DiagramDataState;
// Helper class to allow administer advanced Diagram related
diff --git a/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx b/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx
index d6cb948a6bf6..0af20f04d710 100644
--- a/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx
+++ b/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx
@@ -48,6 +48,7 @@
#define PRIMITIVE2D_ID_SDRAUTOFITTEXTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_SVX| 22)
#define PRIMITIVE2D_ID_SDRCHAINEDTEXTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_SVX| 23)
#define PRIMITIVE2D_ID_SDRFRAMEBORDERTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_SVX| 24)
+#define PRIMITIVE2D_ID_OVERLAYDIAGRAMPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_SVX| 25)
#endif // INCLUDED_SVX_SDR_PRIMITIVE2D_SVX_PRIMITIVETYPES2D_HXX
diff --git a/sd/source/ui/func/fusel.cxx b/sd/source/ui/func/fusel.cxx
index 5b5e37ab5779..bd82a7a97da0 100644
--- a/sd/source/ui/func/fusel.cxx
+++ b/sd/source/ui/func/fusel.cxx
@@ -55,6 +55,7 @@
#include <svx/svdundo.hxx>
#include <svx/sdrhittesthelper.hxx>
+#include <svx/diagram/IDiagramHelper.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/lok.hxx>
@@ -674,7 +675,7 @@ bool FuSelection::MouseButtonUp(const MouseEvent& rMEvt)
}
mpView->SetDragWithCopy(bDragWithCopy);
- mpView->EndDragObj( mpView->IsDragWithCopy() );
+ bool bWasDragged(mpView->EndDragObj( mpView->IsDragWithCopy() ));
mpView->ForceMarkedToAnotherPage();
@@ -695,9 +696,8 @@ bool FuSelection::MouseButtonUp(const MouseEvent& rMEvt)
mpView->MarkObj(pObj,pPV);
return true;
}
- /**************************************************************
- * Toggle between selection and rotation
- **************************************************************/
+
+ // check for single object selected
SdrObject* pSingleObj = nullptr;
if (mpView->GetMarkedObjectList().GetMarkCount()==1)
@@ -705,6 +705,24 @@ bool FuSelection::MouseButtonUp(const MouseEvent& rMEvt)
pSingleObj = mpView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
}
+ // Check for klick on svx::diagram::DiagramFrameHdl
+ // - if we hit a SdrHdl
+ // - if it was not moved
+ // - if single object is selected
+ // - and it is a Diagram
+ if(pHdl && !bWasDragged && nullptr != pSingleObj && pSingleObj->isDiagram())
+ {
+ svx::diagram::DiagramFrameHdl* pDiagramFrameHdl(dynamic_cast<svx::diagram::DiagramFrameHdl*>(pHdl));
+ if(nullptr != pDiagramFrameHdl)
+ {
+ // let the DiagramFrameHdl decide what to do
+ svx::diagram::DiagramFrameHdl::clicked(aPnt);
+ }
+ }
+
+ /**************************************************************
+ * Toggle between selection and rotation
+ **************************************************************/
if (nSlotId == SID_OBJECT_SELECT
&& !comphelper::LibreOfficeKit::isActive()
&& mpView->IsRotateAllowed()
diff --git a/svx/source/diagram/IDiagramHelper.cxx b/svx/source/diagram/IDiagramHelper.cxx
index 80cd2242b411..25acb3719a1c 100644
--- a/svx/source/diagram/IDiagramHelper.cxx
+++ b/svx/source/diagram/IDiagramHelper.cxx
@@ -19,29 +19,335 @@
#include <svx/diagram/IDiagramHelper.hxx>
#include <svx/svdogrp.hxx>
-
#include <svx/svdhdl.hxx>
#include <svx/svdmrkv.hxx>
#include <svx/svdpagv.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrpaintwindow.hxx>
-#include <svx/sdr/overlay/overlaypolypolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/primitivetools2d.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <comphelper/dispatchcommand.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
namespace {
-class DiagramFrameHdl final : public SdrHdl
+// helper to create the geometry for a rounded polygon, maybe
+// containing a Lap positioned inside top-left for some text
+basegfx::B2DPolygon createRoundedPolygon(
+ const basegfx::B2DRange& rRange,
+ double fDistance,
+ bool bCreateLap,
+ double fTextWidth)
{
- basegfx::B2DHomMatrix maTransformation;
+ basegfx::B2DPolygon aRetval;
+
+ // TopLeft rounded edge
+ aRetval.append(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(rRange.getMinX(), rRange.getMinY()),
+ fDistance,
+ fDistance,
+ M_PI * 1.0,
+ M_PI * 1.5));
+
+ // create Lap topLeft inside
+ if(bCreateLap)
+ {
+ const double fLapLeft(rRange.getMinX() + fDistance);
+ double fLapRight(rRange.getMinX() + (rRange.getWidth() * 0.5) - fDistance);
+ const double fLapTop(rRange.getMinY() - fDistance);
+ const double fLapBottom(fLapTop + (fDistance * 2.0));
+ const double fExtendedTextWidth(fTextWidth + (fDistance * 3.0));
+
+ if(0.0 != fExtendedTextWidth && fLapLeft + fExtendedTextWidth < fLapRight)
+ {
+ fLapRight = fLapLeft + fExtendedTextWidth;
+ }
+
+ aRetval.append(basegfx::B2DPoint(fLapLeft, fLapTop));
+ aRetval.append(basegfx::B2DPoint(fLapLeft + (fDistance * 0.5), fLapBottom));
+ aRetval.append(basegfx::B2DPoint(fLapRight - (fDistance * 0.5), fLapBottom));
+ aRetval.append(basegfx::B2DPoint(fLapRight, fLapTop));
+ }
+
+ // TopRight rounded edge
+ aRetval.append(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(rRange.getMaxX(), rRange.getMinY()),
+ fDistance,
+ fDistance,
+ M_PI * 1.5,
+ M_PI * 0.0));
+
+ // BottomRight rounded edge
+ aRetval.append(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(rRange.getMaxX(), rRange.getMaxY()),
+ fDistance,
+ fDistance,
+ M_PI * 0.0,
+ M_PI * 0.5));
+
+ // BottomLeft rounded edge
+ aRetval.append(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(rRange.getMinX(), rRange.getMaxY()),
+ fDistance,
+ fDistance,
+ M_PI * 0.5,
+ M_PI * 1.0));
- // create marker for this kind
- virtual void CreateB2dIAObject() override;
+ aRetval.setClosed(true);
+
+ return aRetval;
+}
+
+// helper primitive to create/show the overlay geometry for a DynamicDiagram
+class OverlayDiagramPrimitive final : public drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D
+{
+private:
+ basegfx::B2DHomMatrix maTransformation; // object dimensions
+ double mfDiscreteDistance; // distance from object in pixels
+ double mfDiscreteGap; // gap/widh of visualization in pixels
+ Color maColor; // base color (made lighter/darker as needed, should be system selection color)
+
+ virtual void create2DDecomposition(
+ drawinglayer::primitive2d::Primitive2DContainer& rContainer,
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation) const override;
public:
- DiagramFrameHdl(const basegfx::B2DHomMatrix& rTransformation);
- // virtual ~DiagramFrameHdl() override;
+ OverlayDiagramPrimitive(
+ const basegfx::B2DHomMatrix& rTransformation,
+ double fDiscreteDistance,
+ double fDiscreteGap,
+ Color const & rColor);
+
+ virtual sal_uInt32 getPrimitive2DID() const override;
};
+void OverlayDiagramPrimitive::create2DDecomposition(
+ drawinglayer::primitive2d::Primitive2DContainer& rContainer,
+ const drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/) const
+{
+ // get the dimensions. Do *not* take rotation/shear into account,
+ // this is intended to be a pure expanded/frame visualization as
+ // needed in UI for simplified visualization
+ basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0);
+ aRange.transform(maTransformation);
+
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ const double fInnerDistance(mfDiscreteDistance * getDiscreteUnit());
+ const double fOuterDistance((mfDiscreteDistance + mfDiscreteGap) * getDiscreteUnit());
+ bool bCreateLap(true);
+ basegfx::B2DPolyPolygon aTextAsPolyPolygon;
+ double fTextWidth(0.0);
+
+ // initially try to create lap
+ if(bCreateLap)
+ {
+ // take a ressource text (for now existing one that fits)
+ const OUString aName(SvxResId(RID_STR_DATANAV_EDIT_ELEMENT));
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
+ basegfx::B2DPolyPolygonVector aTarget;
+ std::vector<double> aDXArray;
+
+ // to simplify things for now, do not create a TextSimplePortionPrimitive2D
+ // and needed FontAttribute, just get the TextOutlines as geometry
+ aTextLayouter.getTextOutlines(
+ aTarget,
+ aName,
+ 0,
+ aName.getLength(),
+ aDXArray);
+
+ // put into one PolyPolygon (also simplification - overlapping chars
+ // may create XOR gaps, so these exist for a reason, but low probability)
+ for (auto const& elem : aTarget)
+ {
+ aTextAsPolyPolygon.append(elem);
+ }
+
+ // get text dimensions & transform to destination
+ const basegfx::B2DRange aTextRange(aTextAsPolyPolygon.getB2DRange());
+ basegfx::B2DHomMatrix aTextTransform;
+
+ aTextTransform.translate(aTextRange.getMinX(), aTextRange.getMinY());
+ const double fTargetTextHeight((mfDiscreteDistance + mfDiscreteGap - 2.0) * getDiscreteUnit());
+ const double fTextScale(fTargetTextHeight / aTextRange.getHeight());
+ aTextTransform.scale(fTextScale, fTextScale);
+ aTextTransform.translate(
+ aRange.getMinX() + (fInnerDistance * 2.0),
+ aRange.getMinY() + fTargetTextHeight + (fOuterDistance - fInnerDistance) - (2.0 * getDiscreteUnit()));
+ aTextAsPolyPolygon.transform(aTextTransform);
+
+ // check text size/position
+ fTextWidth = aTextRange.getWidth() * fTextScale;
+ const double fLapLeft(aRange.getMinX() + fInnerDistance);
+ const double fLapRight(aRange.getMinX() + (aRange.getWidth() * 0.5) - fInnerDistance);
+
+ // if text is too big, do not create a Lap at all
+ // to avoid trouble. It is expected that the user keeps
+ // the object he works with big enough to do useful actions
+ if(fTextWidth + (4.0 * getDiscreteUnit()) > fLapRight - fLapLeft)
+ bCreateLap = false;
+ }
+
+ // create outer polygon
+ aPolyPolygon.append(
+ createRoundedPolygon(
+ aRange,
+ fOuterDistance,
+ false,
+ 0.0));
+
+ // create inner polygon, maybe with Lap
+ aPolyPolygon.append(
+ createRoundedPolygon(
+ aRange,
+ fInnerDistance,
+ bCreateLap,
+ fTextWidth));
+
+ Color aFillColor(maColor);
+ Color aLineColor(maColor);
+
+ aFillColor.IncreaseLuminance(10);
+ aLineColor.DecreaseLuminance(30);
+
+ const drawinglayer::attribute::LineAttribute aLineAttribute(
+ aLineColor.getBColor(),
+ 1.0 * getDiscreteUnit());
+
+ // filled polygon as BG (may get transparence for better look ?)
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ aPolyPolygon,
+ aFillColor.getBColor()));
+
+ // outline polygon for visibility (may be accentuated shaded
+ // top/left, would require alternative creation)
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
+ aPolyPolygon,
+ aLineAttribute));
+
+ // top-left line pattern (as grep-here-sign to signal
+ // that this construct may be also dragged by the user)
+ const double fLapLeft(aRange.getMinX() + fInnerDistance);
+ const double fLapRight(aRange.getMinX() + (aRange.getWidth() * 0.5) - fInnerDistance);
+ const double fLapUp(aRange.getMinY() - ((mfDiscreteDistance + mfDiscreteDistance * 0.666) * getDiscreteUnit()));
+ const double fLapDown(aRange.getMinY() - ((mfDiscreteDistance + mfDiscreteDistance * 0.333) * getDiscreteUnit()));
+ basegfx::B2DPolygon aPolygonLapUp;
+ aPolygonLapUp.append(basegfx::B2DPoint(fLapLeft, fLapUp));
+ aPolygonLapUp.append(basegfx::B2DPoint(fLapRight, fLapUp));
+ basegfx::B2DPolygon aPolygonLapDown;
+ aPolygonLapDown.append(basegfx::B2DPoint(fLapLeft, fLapDown));
+ aPolygonLapDown.append(basegfx::B2DPoint(fLapRight, fLapDown));
+ drawinglayer::attribute::StrokeAttribute aStrokeAttribute({ 2.0 * getDiscreteUnit(), 2.0 * getDiscreteUnit() });
+
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ aPolygonLapUp,
+ aLineAttribute,
+ aStrokeAttribute));
+
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ aPolygonLapDown,
+ aLineAttribute,
+ aStrokeAttribute));
+
+ // add text last. May use darker text color, go for same color
+ // as accentuation line for now
+ if(bCreateLap && 0 != aTextAsPolyPolygon.count())
+ {
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ aTextAsPolyPolygon,
+ aLineColor.getBColor()));
+ }
+}
+
+OverlayDiagramPrimitive::OverlayDiagramPrimitive(
+ const basegfx::B2DHomMatrix& rTransformation,
+ double fDiscreteDistance,
+ double fDiscreteGap,
+ Color const & rColor)
+: drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D()
+, maTransformation(rTransformation)
+, mfDiscreteDistance(fDiscreteDistance)
+, mfDiscreteGap(fDiscreteGap)
+, maColor(rColor)
+{
+}
+
+sal_uInt32 OverlayDiagramPrimitive::getPrimitive2DID() const
+{
+ return PRIMITIVE2D_ID_OVERLAYDIAGRAMPRIMITIVE2D;
+}
+
+// helper object for DiagramOverlay
+class OverlayDiagramFrame final : public sdr::overlay::OverlayObject
+{
+private:
+ basegfx::B2DHomMatrix maTransformation; // object dimensions
+ Color maColor; // base color
+
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+public:
+ explicit OverlayDiagramFrame(
+ const basegfx::B2DHomMatrix& rTransformation,
+ Color const & rColor);
+};
+
+OverlayDiagramFrame::OverlayDiagramFrame(
+ const basegfx::B2DHomMatrix& rTransformation,
+ const Color& rColor)
+: sdr::overlay::OverlayObject(rColor)
+, maTransformation(rTransformation)
+, maColor(rColor)
+{
+}
+
+drawinglayer::primitive2d::Primitive2DContainer OverlayDiagramFrame::createOverlayObjectPrimitive2DSequence()
+{
+ drawinglayer::primitive2d::Primitive2DContainer aReturnContainer;
+
+ if (getOverlayManager())
+ {
+ aReturnContainer = drawinglayer::primitive2d::Primitive2DContainer {
+ new OverlayDiagramPrimitive(
+ maTransformation,
+ 8.0, // distance from geometry in pixels
+ 8.0, // gap/width of visualization in pixels
+ maColor) };
+ }
+
+ return aReturnContainer;
+}
+
+} // end of anonymous namespace
+
+namespace svx { namespace diagram {
+
+void DiagramFrameHdl::clicked(const Point& /*rPnt*/)
+{
+ // this may check for a direct hit at the text later
+ // and only then take action. That would require
+ // to evaluate & keep that (maybe during creation).
+ // For now, just trigger to open the Dialog
+ comphelper::dispatchCommand(".uno:EditDiagram", {});
+}
+
void DiagramFrameHdl::CreateB2dIAObject()
{
// first throw away old one
@@ -67,36 +373,12 @@ void DiagramFrameHdl::CreateB2dIAObject()
if (xManager.is())
{
OutputDevice& rOutDev(rPageWindow.GetPaintWindow().GetOutputDevice());
- const basegfx::B2DVector aDiscreteInLogic(rOutDev.GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
- const double fDiscretePixelSize(aDiscreteInLogic.getLength());
- const double fOuterDistance(7.0);
- const double fInnerDistance(5.0);
-
- basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0);
- aRange.transform(maTransformation);
-
- basegfx::B2DRange aOuterRange(aRange);
- aOuterRange.grow(fDiscretePixelSize * fOuterDistance);
-
- basegfx::B2DRange aInnerRange(aRange);
- aInnerRange.grow(fDiscretePixelSize * fInnerDistance);
-
- basegfx::B2DPolyPolygon aPolyPolygon;
- aPolyPolygon.append(basegfx::utils::createPolygonFromRect(aOuterRange));
- aPolyPolygon.append(basegfx::utils::createPolygonFromRect(aInnerRange));
-
const StyleSettings& rStyles(rOutDev.GetSettings().GetStyleSettings());
Color aFillColor(rStyles.GetHighlightColor());
- Color aLineColor(aFillColor);
- aFillColor.IncreaseLuminance(10);
- aLineColor.DecreaseLuminance(30);
-
std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
- new sdr::overlay::OverlayPolyPolygon(
- aPolyPolygon,
- aLineColor, // Line
- fDiscretePixelSize * 2.0,
- aFillColor)); // Fill
+ new OverlayDiagramFrame(
+ maTransformation,
+ aFillColor));
// OVERLAYMANAGER
insertNewlyCreatedOverlayObjectForSdrHdl(
@@ -114,14 +396,6 @@ DiagramFrameHdl::DiagramFrameHdl(const basegfx::B2DHomMatrix& rTransformation)
{
}
-// DiagramFrameHdl::~DiagramFrameHdl()
-// {
-// }
-
-} // end of anonymous namespace
-
-namespace svx { namespace diagram {
-
IDiagramHelper::IDiagramHelper()
: mbUseDiagramThemeData(false)
, mbUseDiagramModelData(true)