LibreOffice Module svx (master) 1
IDiagramHelper.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21#include <svx/svdogrp.hxx>
22#include <svx/svdhdl.hxx>
23#include <svx/svdmrkv.hxx>
24#include <svx/svdpagv.hxx>
25#include <svx/sdrpagewindow.hxx>
37#include <officecfg/Office/Common.hxx>
38#include <svx/strings.hrc>
39#include <svx/dialmgr.hxx>
40
41namespace {
42
43// helper to create the geometry for a rounded polygon, maybe
44// containing a Lap positioned inside top-left for some text
45basegfx::B2DPolygon createRoundedPolygon(
46 const basegfx::B2DRange& rRange,
47 double fDistance,
48 bool bCreateLap,
49 double fTextWidth)
50{
51 basegfx::B2DPolygon aRetval;
52
53 // TopLeft rounded edge
54 aRetval.append(
56 basegfx::B2DPoint(rRange.getMinX(), rRange.getMinY()),
57 fDistance,
58 fDistance,
59 M_PI * 1.0,
60 M_PI * 1.5));
61
62 // create Lap topLeft inside
63 if(bCreateLap)
64 {
65 const double fLapLeft(rRange.getMinX() + fDistance);
66 double fLapRight(rRange.getMinX() + (rRange.getWidth() * 0.5) - fDistance);
67 const double fLapTop(rRange.getMinY() - fDistance);
68 const double fLapBottom(fLapTop + (fDistance * 2.0));
69 const double fExtendedTextWidth(fTextWidth + (fDistance * 3.0));
70
71 if(0.0 != fExtendedTextWidth && fLapLeft + fExtendedTextWidth < fLapRight)
72 {
73 fLapRight = fLapLeft + fExtendedTextWidth;
74 }
75
76 aRetval.append(basegfx::B2DPoint(fLapLeft, fLapTop));
77 aRetval.append(basegfx::B2DPoint(fLapLeft + (fDistance * 0.5), fLapBottom));
78 aRetval.append(basegfx::B2DPoint(fLapRight - (fDistance * 0.5), fLapBottom));
79 aRetval.append(basegfx::B2DPoint(fLapRight, fLapTop));
80 }
81
82 // TopRight rounded edge
83 aRetval.append(
85 basegfx::B2DPoint(rRange.getMaxX(), rRange.getMinY()),
86 fDistance,
87 fDistance,
88 M_PI * 1.5,
89 M_PI * 0.0));
90
91 // BottomRight rounded edge
92 aRetval.append(
94 basegfx::B2DPoint(rRange.getMaxX(), rRange.getMaxY()),
95 fDistance,
96 fDistance,
97 M_PI * 0.0,
98 M_PI * 0.5));
99
100 // BottomLeft rounded edge
101 aRetval.append(
103 basegfx::B2DPoint(rRange.getMinX(), rRange.getMaxY()),
104 fDistance,
105 fDistance,
106 M_PI * 0.5,
107 M_PI * 1.0));
108
109 aRetval.setClosed(true);
110
111 return aRetval;
112}
113
114// helper primitive to create/show the overlay geometry for a DynamicDiagram
115class OverlayDiagramPrimitive final : public drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D
116{
117private:
118 basegfx::B2DHomMatrix maTransformation; // object dimensions
119 double mfDiscreteDistance; // distance from object in pixels
120 double mfDiscreteGap; // gap/width of visualization in pixels
121 Color maColor; // base color (made lighter/darker as needed, should be system selection color)
122
123 virtual void create2DDecomposition(
125 const drawinglayer::geometry::ViewInformation2D& rViewInformation) const override;
126
127public:
128 OverlayDiagramPrimitive(
129 const basegfx::B2DHomMatrix& rTransformation,
130 double fDiscreteDistance,
131 double fDiscreteGap,
132 Color const & rColor);
133
134 virtual sal_uInt32 getPrimitive2DID() const override;
135};
136
137void OverlayDiagramPrimitive::create2DDecomposition(
139 const drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/) const
140{
141 // get the dimensions. Do *not* take rotation/shear into account,
142 // this is intended to be a pure expanded/frame visualization as
143 // needed in UI for simplified visualization
144 basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0);
145 aRange.transform(maTransformation);
146
147 basegfx::B2DPolyPolygon aPolyPolygon;
148 const double fInnerDistance(mfDiscreteDistance * getDiscreteUnit());
149 const double fOuterDistance((mfDiscreteDistance + mfDiscreteGap) * getDiscreteUnit());
150 bool bCreateLap(true);
151 basegfx::B2DPolyPolygon aTextAsPolyPolygon;
152 double fTextWidth(0.0);
153
154 // initially try to create lap
155 if(bCreateLap)
156 {
157 // take a resource text (for now existing one that fits)
158 const OUString aName(SvxResId(RID_STR_DATANAV_EDIT_ELEMENT));
161 std::vector<double> aDXArray;
162
163 // to simplify things for now, do not create a TextSimplePortionPrimitive2D
164 // and needed FontAttribute, just get the TextOutlines as geometry
165 aTextLayouter.getTextOutlines(
166 aTarget,
167 aName,
168 0,
169 aName.getLength(),
170 aDXArray,
171 {});
172
173 // put into one PolyPolygon (also simplification - overlapping chars
174 // may create XOR gaps, so these exist for a reason, but low probability)
175 for (auto const& elem : aTarget)
176 {
177 aTextAsPolyPolygon.append(elem);
178 }
179
180 // get text dimensions & transform to destination
181 const basegfx::B2DRange aTextRange(aTextAsPolyPolygon.getB2DRange());
182 basegfx::B2DHomMatrix aTextTransform;
183
184 aTextTransform.translate(aTextRange.getMinX(), aTextRange.getMinY());
185 const double fTargetTextHeight((mfDiscreteDistance + mfDiscreteGap - 2.0) * getDiscreteUnit());
186 const double fTextScale(fTargetTextHeight / aTextRange.getHeight());
187 aTextTransform.scale(fTextScale, fTextScale);
188 aTextTransform.translate(
189 aRange.getMinX() + (fInnerDistance * 2.0),
190 aRange.getMinY() + fTargetTextHeight + (fOuterDistance - fInnerDistance) - (2.0 * getDiscreteUnit()));
191 aTextAsPolyPolygon.transform(aTextTransform);
192
193 // check text size/position
194 fTextWidth = aTextRange.getWidth() * fTextScale;
195 const double fLapLeft(aRange.getMinX() + fInnerDistance);
196 const double fLapRight(aRange.getMinX() + (aRange.getWidth() * 0.5) - fInnerDistance);
197
198 // if text is too big, do not create a Lap at all
199 // to avoid trouble. It is expected that the user keeps
200 // the object he works with big enough to do useful actions
201 if(fTextWidth + (4.0 * getDiscreteUnit()) > fLapRight - fLapLeft)
202 bCreateLap = false;
203 }
204
205 // create outer polygon
206 aPolyPolygon.append(
207 createRoundedPolygon(
208 aRange,
209 fOuterDistance,
210 false,
211 0.0));
212
213 // create inner polygon, maybe with Lap
214 aPolyPolygon.append(
215 createRoundedPolygon(
216 aRange,
217 fInnerDistance,
218 bCreateLap,
219 fTextWidth));
220
221 Color aFillColor(maColor);
222 Color aLineColor(maColor);
223
224 aFillColor.IncreaseLuminance(10);
225 aLineColor.DecreaseLuminance(30);
226
227 const drawinglayer::attribute::LineAttribute aLineAttribute(
228 aLineColor.getBColor(),
229 1.0 * getDiscreteUnit());
230
231 // filled polygon as BG (may get transparence for better look ?)
232 rContainer.push_back(
234 aPolyPolygon,
235 aFillColor.getBColor()));
236
237 // outline polygon for visibility (may be accentuated shaded
238 // top/left, would require alternative creation)
239 rContainer.push_back(
241 std::move(aPolyPolygon),
242 aLineAttribute));
243
244 // top-left line pattern (as grep-here-sign to signal
245 // that this construct may be also dragged by the user)
246 const double fLapLeft(aRange.getMinX() + fInnerDistance);
247 const double fLapRight(aRange.getMinX() + (aRange.getWidth() * 0.5) - fInnerDistance);
248 const double fLapUp(aRange.getMinY() - ((mfDiscreteDistance + mfDiscreteDistance * 0.666) * getDiscreteUnit()));
249 const double fLapDown(aRange.getMinY() - ((mfDiscreteDistance + mfDiscreteDistance * 0.333) * getDiscreteUnit()));
250 basegfx::B2DPolygon aPolygonLapUp;
251 aPolygonLapUp.append(basegfx::B2DPoint(fLapLeft, fLapUp));
252 aPolygonLapUp.append(basegfx::B2DPoint(fLapRight, fLapUp));
253 basegfx::B2DPolygon aPolygonLapDown;
254 aPolygonLapDown.append(basegfx::B2DPoint(fLapLeft, fLapDown));
255 aPolygonLapDown.append(basegfx::B2DPoint(fLapRight, fLapDown));
256 drawinglayer::attribute::StrokeAttribute aStrokeAttribute({ 2.0 * getDiscreteUnit(), 2.0 * getDiscreteUnit() });
257
258 rContainer.push_back(
260 std::move(aPolygonLapUp),
261 aLineAttribute,
262 aStrokeAttribute));
263
264 rContainer.push_back(
266 std::move(aPolygonLapDown),
267 aLineAttribute,
268 std::move(aStrokeAttribute)));
269
270 // add text last. May use darker text color, go for same color
271 // as accentuation line for now
272 if(bCreateLap && 0 != aTextAsPolyPolygon.count())
273 {
274 rContainer.push_back(
276 std::move(aTextAsPolyPolygon),
277 aLineColor.getBColor()));
278 }
279}
280
281OverlayDiagramPrimitive::OverlayDiagramPrimitive(
282 const basegfx::B2DHomMatrix& rTransformation,
283 double fDiscreteDistance,
284 double fDiscreteGap,
285 Color const & rColor)
286: drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D()
287, maTransformation(rTransformation)
288, mfDiscreteDistance(fDiscreteDistance)
289, mfDiscreteGap(fDiscreteGap)
290, maColor(rColor)
291{
292}
293
294sal_uInt32 OverlayDiagramPrimitive::getPrimitive2DID() const
295{
297}
298
299// helper object for DiagramOverlay
300class OverlayDiagramFrame final : public sdr::overlay::OverlayObject
301{
302private:
303 basegfx::B2DHomMatrix maTransformation; // object dimensions
304 Color maColor; // base color
305
307
308public:
309 explicit OverlayDiagramFrame(
310 const basegfx::B2DHomMatrix& rTransformation,
311 Color const & rColor);
312};
313
314OverlayDiagramFrame::OverlayDiagramFrame(
315 const basegfx::B2DHomMatrix& rTransformation,
316 const Color& rColor)
317: sdr::overlay::OverlayObject(rColor)
318, maTransformation(rTransformation)
319, maColor(rColor)
320{
321}
322
323drawinglayer::primitive2d::Primitive2DContainer OverlayDiagramFrame::createOverlayObjectPrimitive2DSequence()
324{
326
327 if ( !officecfg::Office::Common::Misc::ExperimentalMode::get() )
328 return aReturnContainer;
329
330 if (getOverlayManager())
331 {
333 new OverlayDiagramPrimitive(
334 maTransformation,
335 8.0, // distance from geometry in pixels
336 8.0, // gap/width of visualization in pixels
337 maColor) };
338 }
339
340 return aReturnContainer;
341}
342
343} // end of anonymous namespace
344
345namespace svx { namespace diagram {
346
347void DiagramFrameHdl::clicked(const Point& /*rPnt*/)
348{
349 // this may check for a direct hit at the text later
350 // and only then take action. That would require
351 // to evaluate & keep that (maybe during creation).
352 // For now, just trigger to open the Dialog
353 comphelper::dispatchCommand(".uno:EditDiagram", {});
354}
355
357{
358 // first throw away old one
360
361 SdrMarkView* pView = pHdlList->GetView();
362
363 if(!pView || pView->areMarkHandlesHidden())
364 return;
365
366 SdrPageView* pPageView = pView->GetSdrPageView();
367
368 if(!pPageView)
369 return;
370
371 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
372 {
373 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
374
375 if(rPageWindow.GetPaintWindow().OutputToWindow())
376 {
378 if (xManager.is())
379 {
380 OutputDevice& rOutDev(rPageWindow.GetPaintWindow().GetOutputDevice());
381 const StyleSettings& rStyles(rOutDev.GetSettings().GetStyleSettings());
382 Color aFillColor(rStyles.GetHighlightColor());
383 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
384 new OverlayDiagramFrame(
386 aFillColor));
387
388 // OVERLAYMANAGER
390 std::move(pNewOverlayObject),
391 rPageWindow.GetObjectContact(),
392 *xManager);
393 }
394 }
395 }
396}
397
400, maTransformation(rTransformation)
401{
402}
403
405: mbUseDiagramThemeData(false)
406, mbUseDiagramModelData(true)
407, mbForceThemePtrRecreation(false)
408{
409}
410
412
414{
415 rTarget.mp_DiagramHelper.reset(this);
416}
417
419{
420 // create an extra frame visualization here
421 basegfx::B2DHomMatrix aTransformation;
422 basegfx::B2DPolyPolygon aPolyPolygon;
423 rTarget.TRGetBaseGeometry(aTransformation, aPolyPolygon);
424
425 std::unique_ptr<SdrHdl> pHdl(new DiagramFrameHdl(aTransformation));
426 rHdlList.AddHdl(std::move(pHdl));
427}
428
429}} // end of namespace
430
431/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
basegfx::BColor maColor
const StyleSettings & GetStyleSettings() const
const AllSettings & GetSettings() const
SdrMarkView * GetView() const
Definition: svdhdl.hxx:453
void AddHdl(std::unique_ptr< SdrHdl > pHdl)
Definition: svdhdl.cxx:2291
SdrHdlList * pHdlList
Definition: svdhdl.hxx:138
void insertNewlyCreatedOverlayObjectForSdrHdl(std::unique_ptr< sdr::overlay::OverlayObject > pOverlayObject, const sdr::contact::ObjectContact &rObjectContact, sdr::overlay::OverlayManager &rOverlayManager)
Definition: svdhdl.cxx:1080
void GetRidOfIAObject()
Definition: svdhdl.cxx:398
bool areMarkHandlesHidden() const
Definition: svdmrkv.hxx:283
sal_uInt32 PageWindowCount() const
Definition: svdpagv.hxx:89
SdrPageWindow * GetPageWindow(sal_uInt32 nIndex) const
Definition: svdpagv.cxx:83
rtl::Reference< sdr::overlay::OverlayManager > const & GetOverlayManager() const
SdrPaintWindow & GetPaintWindow() const
const sdr::contact::ObjectContact & GetObjectContact() const
SdrPageView * GetSdrPageView() const
Definition: svdpntv.hxx:323
OutputDevice & GetOutputDevice() const
bool OutputToWindow() const
const Color & GetHighlightColor() const
void translate(double fX, double fY)
void scale(double fX, double fY)
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
void transform(const basegfx::B2DHomMatrix &rMatrix)
B2DRange getB2DRange() const
sal_uInt32 count() const
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
void setClosed(bool bNew)
TYPE getMaxX() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
TYPE getMaxY() const
virtual sal_uInt32 getPrimitive2DID() const=0
virtual void create2DDecomposition(Primitive2DContainer &rContainer, const geometry::ViewInformation2D &rViewInformation) const=0
void getTextOutlines(basegfx::B2DPolyPolygonVector &, const OUString &rText, sal_uInt32 nIndex, sal_uInt32 nLength, const ::std::vector< double > &rDXArray, const ::std::vector< sal_Bool > &rKashidaArray) const
virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence()
virtual void CreateB2dIAObject() override
DiagramFrameHdl(const basegfx::B2DHomMatrix &rTransformation)
static void clicked(const Point &rPnt)
basegfx::B2DHomMatrix maTransformation
void anchorToSdrObjGroup(SdrObjGroup &rTarget)
static void AddAdditionalVisualization(const SdrObjGroup &rTarget, SdrHdlList &rHdlList)
OUString SvxResId(TranslateId aId)
Definition: dialmgr.cxx:24
FilterGroup & rTarget
OUString aName
B2DPolygon createPolygonFromEllipseSegment(const B2DPoint &rCenter, double fRadiusX, double fRadiusY, double fStart, double fEnd)
::std::vector< B2DPolyPolygon > B2DPolyPolygonVector
bool dispatchCommand(const OUString &rCommand, const uno::Reference< css::frame::XFrame > &rFrame, const css::uno::Sequence< css::beans::PropertyValue > &rArguments, const uno::Reference< css::frame::XDispatchResultListener > &rListener)
basegfx::B2DHomMatrix maTransformation
SdrHdlKind
Definition: svdhdl.hxx:53
#define PRIMITIVE2D_ID_OVERLAYDIAGRAMPRIMITIVE2D