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 // put into one PolyPolygon (also simplification - overlapping chars
173 // may create XOR gaps, so these exist for a reason, but low probability)
174 for (auto const& elem : aTarget)
175 {
176 aTextAsPolyPolygon.append(elem);
177 }
178
179 // get text dimensions & transform to destination
180 const basegfx::B2DRange aTextRange(aTextAsPolyPolygon.getB2DRange());
181 basegfx::B2DHomMatrix aTextTransform;
182
183 aTextTransform.translate(aTextRange.getMinX(), aTextRange.getMinY());
184 const double fTargetTextHeight((mfDiscreteDistance + mfDiscreteGap - 2.0) * getDiscreteUnit());
185 const double fTextScale(fTargetTextHeight / aTextRange.getHeight());
186 aTextTransform.scale(fTextScale, fTextScale);
187 aTextTransform.translate(
188 aRange.getMinX() + (fInnerDistance * 2.0),
189 aRange.getMinY() + fTargetTextHeight + (fOuterDistance - fInnerDistance) - (2.0 * getDiscreteUnit()));
190 aTextAsPolyPolygon.transform(aTextTransform);
191
192 // check text size/position
193 fTextWidth = aTextRange.getWidth() * fTextScale;
194 const double fLapLeft(aRange.getMinX() + fInnerDistance);
195 const double fLapRight(aRange.getMinX() + (aRange.getWidth() * 0.5) - fInnerDistance);
196
197 // if text is too big, do not create a Lap at all
198 // to avoid trouble. It is expected that the user keeps
199 // the object he works with big enough to do useful actions
200 if(fTextWidth + (4.0 * getDiscreteUnit()) > fLapRight - fLapLeft)
201 bCreateLap = false;
202 }
203
204 // create outer polygon
205 aPolyPolygon.append(
206 createRoundedPolygon(
207 aRange,
208 fOuterDistance,
209 false,
210 0.0));
211
212 // create inner polygon, maybe with Lap
213 aPolyPolygon.append(
214 createRoundedPolygon(
215 aRange,
216 fInnerDistance,
217 bCreateLap,
218 fTextWidth));
219
220 Color aFillColor(maColor);
221 Color aLineColor(maColor);
222
223 aFillColor.IncreaseLuminance(10);
224 aLineColor.DecreaseLuminance(30);
225
226 const drawinglayer::attribute::LineAttribute aLineAttribute(
227 aLineColor.getBColor(),
228 1.0 * getDiscreteUnit());
229
230 // filled polygon as BG (may get transparence for better look ?)
231 rContainer.push_back(
233 aPolyPolygon,
234 aFillColor.getBColor()));
235
236 // outline polygon for visibility (may be accentuated shaded
237 // top/left, would require alternative creation)
238 rContainer.push_back(
240 std::move(aPolyPolygon),
241 aLineAttribute));
242
243 // top-left line pattern (as grep-here-sign to signal
244 // that this construct may be also dragged by the user)
245 const double fLapLeft(aRange.getMinX() + fInnerDistance);
246 const double fLapRight(aRange.getMinX() + (aRange.getWidth() * 0.5) - fInnerDistance);
247 const double fLapUp(aRange.getMinY() - ((mfDiscreteDistance + mfDiscreteDistance * 0.666) * getDiscreteUnit()));
248 const double fLapDown(aRange.getMinY() - ((mfDiscreteDistance + mfDiscreteDistance * 0.333) * getDiscreteUnit()));
249 basegfx::B2DPolygon aPolygonLapUp;
250 aPolygonLapUp.append(basegfx::B2DPoint(fLapLeft, fLapUp));
251 aPolygonLapUp.append(basegfx::B2DPoint(fLapRight, fLapUp));
252 basegfx::B2DPolygon aPolygonLapDown;
253 aPolygonLapDown.append(basegfx::B2DPoint(fLapLeft, fLapDown));
254 aPolygonLapDown.append(basegfx::B2DPoint(fLapRight, fLapDown));
255 drawinglayer::attribute::StrokeAttribute aStrokeAttribute({ 2.0 * getDiscreteUnit(), 2.0 * getDiscreteUnit() });
256
257 rContainer.push_back(
259 std::move(aPolygonLapUp),
260 aLineAttribute,
261 aStrokeAttribute));
262
263 rContainer.push_back(
265 std::move(aPolygonLapDown),
266 aLineAttribute,
267 std::move(aStrokeAttribute)));
268
269 // add text last. May use darker text color, go for same color
270 // as accentuation line for now
271 if(bCreateLap && 0 != aTextAsPolyPolygon.count())
272 {
273 rContainer.push_back(
275 std::move(aTextAsPolyPolygon),
276 aLineColor.getBColor()));
277 }
278}
279
280OverlayDiagramPrimitive::OverlayDiagramPrimitive(
281 const basegfx::B2DHomMatrix& rTransformation,
282 double fDiscreteDistance,
283 double fDiscreteGap,
284 Color const & rColor)
285: drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D()
286, maTransformation(rTransformation)
287, mfDiscreteDistance(fDiscreteDistance)
288, mfDiscreteGap(fDiscreteGap)
289, maColor(rColor)
290{
291}
292
293sal_uInt32 OverlayDiagramPrimitive::getPrimitive2DID() const
294{
296}
297
298// helper object for DiagramOverlay
299class OverlayDiagramFrame final : public sdr::overlay::OverlayObject
300{
301private:
302 basegfx::B2DHomMatrix maTransformation; // object dimensions
303 Color maColor; // base color
304
306
307public:
308 explicit OverlayDiagramFrame(
309 const basegfx::B2DHomMatrix& rTransformation,
310 Color const & rColor);
311};
312
313OverlayDiagramFrame::OverlayDiagramFrame(
314 const basegfx::B2DHomMatrix& rTransformation,
315 const Color& rColor)
316: sdr::overlay::OverlayObject(rColor)
317, maTransformation(rTransformation)
318, maColor(rColor)
319{
320}
321
322drawinglayer::primitive2d::Primitive2DContainer OverlayDiagramFrame::createOverlayObjectPrimitive2DSequence()
323{
325
326 if ( !officecfg::Office::Common::Misc::ExperimentalMode::get() )
327 return aReturnContainer;
328
329 if (getOverlayManager())
330 {
332 new OverlayDiagramPrimitive(
333 maTransformation,
334 8.0, // distance from geometry in pixels
335 8.0, // gap/width of visualization in pixels
336 maColor) };
337 }
338
339 return aReturnContainer;
340}
341
342} // end of anonymous namespace
343
344namespace svx { namespace diagram {
345
346void DiagramFrameHdl::clicked(const Point& /*rPnt*/)
347{
348 // this may check for a direct hit at the text later
349 // and only then take action. That would require
350 // to evaluate & keep that (maybe during creation).
351 // For now, just trigger to open the Dialog
352 comphelper::dispatchCommand(".uno:EditDiagram", {});
353}
354
356{
357 // first throw away old one
359
360 SdrMarkView* pView = pHdlList->GetView();
361
362 if(!pView || pView->areMarkHandlesHidden())
363 return;
364
365 SdrPageView* pPageView = pView->GetSdrPageView();
366
367 if(!pPageView)
368 return;
369
370 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
371 {
372 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
373
374 if(rPageWindow.GetPaintWindow().OutputToWindow())
375 {
377 if (xManager.is())
378 {
379 OutputDevice& rOutDev(rPageWindow.GetPaintWindow().GetOutputDevice());
380 const StyleSettings& rStyles(rOutDev.GetSettings().GetStyleSettings());
381 Color aFillColor(rStyles.GetHighlightColor());
382 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
383 new OverlayDiagramFrame(
385 aFillColor));
386
387 // OVERLAYMANAGER
389 std::move(pNewOverlayObject),
390 rPageWindow.GetObjectContact(),
391 *xManager);
392 }
393 }
394 }
395}
396
399, maTransformation(rTransformation)
400{
401}
402
404: mbUseDiagramThemeData(false)
405, mbUseDiagramModelData(true)
406, mbForceThemePtrRecreation(false)
407{
408}
409
411
413{
414 rTarget.mp_DiagramHelper.reset(this);
415}
416
418{
419 // create an extra frame visualization here
420 basegfx::B2DHomMatrix aTransformation;
421 basegfx::B2DPolyPolygon aPolyPolygon;
422 rTarget.TRGetBaseGeometry(aTransformation, aPolyPolygon);
423
424 std::unique_ptr<SdrHdl> pHdl(new DiagramFrameHdl(aTransformation));
425 rHdlList.AddHdl(std::move(pHdl));
426}
427
428}} // end of namespace
429
430/* 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:299
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
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