1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 
25 #include "precompiled_sw.hxx"
26 
27 #include <AnchorOverlayObject.hxx>
28 #include <SidebarWindowsConsts.hxx>
29 
30 #include <swrect.hxx>
31 #include <view.hxx>
32 #include <svx/sdrpaintwindow.hxx>
33 #include <svx/svdview.hxx>
34 #include <svx/sdr/overlay/overlaymanager.hxx>
35 
36 #include <sw_primitivetypes2d.hxx>
37 #include <drawinglayer/primitive2d/primitivetools2d.hxx>
38 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
39 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
40 #include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
41 
42 namespace sw { namespace sidebarwindows {
43 
44 //////////////////////////////////////////////////////////////////////////////
45 // helper class: Primitive for discrete visualisation
46 
47 class AnchorPrimitive : public drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D
48 {
49 private:
50     basegfx::B2DPolygon             maTriangle;
51     basegfx::B2DPolygon             maLine;
52     basegfx::B2DPolygon             maLineTop;
53     const AnchorState               maAnchorState;
54     basegfx::BColor                 maColor;
55 
56     // discrete line width
57     double                          mfLogicLineWidth;
58 
59     // bitfield
60     bool                            mbShadow : 1;
61     bool                            mbLineSolid : 1;
62 
63 protected:
64     virtual drawinglayer::primitive2d::Primitive2DSequence create2DDecomposition(
65         const drawinglayer::geometry::ViewInformation2D& rViewInformation) const;
66 
67 public:
68     AnchorPrimitive( const basegfx::B2DPolygon& rTriangle,
69                      const basegfx::B2DPolygon& rLine,
70                      const basegfx::B2DPolygon& rLineTop,
71                      AnchorState aAnchorState,
72                      const basegfx::BColor& rColor,
73                      double fLogicLineWidth,
74                      bool bShadow,
75                      bool bLineSolid )
76     :   drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D(),
77         maTriangle(rTriangle),
78         maLine(rLine),
79         maLineTop(rLineTop),
80         maAnchorState(aAnchorState),
81         maColor(rColor),
82         mfLogicLineWidth(fLogicLineWidth),
83         mbShadow(bShadow),
84         mbLineSolid(bLineSolid)
85     {}
86 
87     // data access
88     const basegfx::B2DPolygon& getTriangle() const { return maTriangle; }
89     const basegfx::B2DPolygon& getLine() const { return maLine; }
90     const basegfx::B2DPolygon& getLineTop() const { return maLineTop; }
91     AnchorState getAnchorState() const { return maAnchorState; }
92     const basegfx::BColor& getColor() const { return maColor; }
93     double getLogicLineWidth() const { return mfLogicLineWidth; }
94     bool getShadow() const { return mbShadow; }
95     bool getLineSolid() const { return mbLineSolid; }
96 
97     virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
98 
99     DeclPrimitrive2DIDBlock()
100 };
101 
102 drawinglayer::primitive2d::Primitive2DSequence AnchorPrimitive::create2DDecomposition(
103     const drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/) const
104 {
105     drawinglayer::primitive2d::Primitive2DSequence aRetval;
106 
107     if ( AS_TRI == maAnchorState ||
108          AS_ALL == maAnchorState ||
109          AS_START == maAnchorState )
110     {
111         // create triangle
112         const drawinglayer::primitive2d::Primitive2DReference aTriangle(
113             new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
114                 basegfx::B2DPolyPolygon(getTriangle()),
115                 getColor()));
116 
117         drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, aTriangle);
118     }
119 
120     if ( AS_ALL == maAnchorState ||
121          AS_START == maAnchorState )
122     {
123         // create line start
124         const drawinglayer::attribute::LineAttribute aLineAttribute(
125             getColor(),
126             getLogicLineWidth() / (basegfx::fTools::equalZero(getDiscreteUnit()) ? 1.0 : getDiscreteUnit()));
127 
128         if(getLineSolid())
129         {
130             const drawinglayer::primitive2d::Primitive2DReference aSolidLine(
131                 new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
132                     getLine(),
133                     aLineAttribute));
134 
135             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, aSolidLine);
136         }
137         else
138         {
139             ::std::vector< double > aDotDashArray;
140             const double fDistance(3.0 * 15.0);
141             const double fDashLen(5.0 * 15.0);
142 
143             aDotDashArray.push_back(fDashLen);
144             aDotDashArray.push_back(fDistance);
145 
146             const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(
147                 aDotDashArray,
148                 fDistance + fDashLen);
149 
150             const drawinglayer::primitive2d::Primitive2DReference aStrokedLine(
151                 new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
152                     getLine(),
153                     aLineAttribute,
154                     aStrokeAttribute));
155 
156             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, aStrokedLine);
157         }
158     }
159 
160     if(aRetval.hasElements() && getShadow())
161     {
162         // shadow is only for triangle and line start, and in upper left
163         // and lower right direction, in different colors
164         const double fColorChange(20.0 / 255.0);
165         const basegfx::B3DTuple aColorChange(fColorChange, fColorChange, fColorChange);
166         basegfx::BColor aLighterColor(getColor() + aColorChange);
167         basegfx::BColor aDarkerColor(getColor() - aColorChange);
168 
169         aLighterColor.clamp();
170         aDarkerColor.clamp();
171 
172         // create shadow sequence
173         drawinglayer::primitive2d::Primitive2DSequence aShadows(2);
174         basegfx::B2DHomMatrix aTransform;
175 
176         aTransform.set(0, 2, -getDiscreteUnit());
177         aTransform.set(1, 2, -getDiscreteUnit());
178 
179         aShadows[0] = drawinglayer::primitive2d::Primitive2DReference(
180             new drawinglayer::primitive2d::ShadowPrimitive2D(
181                 aTransform,
182                 aLighterColor,
183                 aRetval));
184 
185         aTransform.set(0, 2, getDiscreteUnit());
186         aTransform.set(1, 2, getDiscreteUnit());
187 
188         aShadows[1] = drawinglayer::primitive2d::Primitive2DReference(
189             new drawinglayer::primitive2d::ShadowPrimitive2D(
190                 aTransform,
191                 aDarkerColor,
192                 aRetval));
193 
194         // add shadow before geometry to make it be proccessed first
195         const drawinglayer::primitive2d::Primitive2DSequence aTemporary(aRetval);
196 
197         aRetval = aShadows;
198         drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetval, aTemporary);
199     }
200 
201     if ( AS_ALL == maAnchorState ||
202          AS_END == maAnchorState )
203     {
204         // LineTop has to be created, too, but uses no shadow, so add after
205         // the other parts are created
206         const drawinglayer::attribute::LineAttribute aLineAttribute(
207             getColor(),
208             getLogicLineWidth() / (basegfx::fTools::equalZero(getDiscreteUnit()) ? 1.0 : getDiscreteUnit()));
209 
210         const drawinglayer::primitive2d::Primitive2DReference aLineTop(
211             new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
212                 getLineTop(),
213                 aLineAttribute));
214 
215         drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, aLineTop);
216     }
217 
218     return aRetval;
219 }
220 
221 bool AnchorPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
222 {
223     if(drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
224     {
225         const AnchorPrimitive& rCompare = static_cast< const AnchorPrimitive& >(rPrimitive);
226 
227         return (getTriangle() == rCompare.getTriangle()
228             && getLine() == rCompare.getLine()
229             && getLineTop() == rCompare.getLineTop()
230             && getAnchorState() == rCompare.getAnchorState()
231             && getColor() == rCompare.getColor()
232             && getLogicLineWidth() == rCompare.getLogicLineWidth()
233             && getShadow() == rCompare.getShadow()
234             && getLineSolid() == rCompare.getLineSolid());
235     }
236 
237     return false;
238 }
239 
240 ImplPrimitrive2DIDBlock(AnchorPrimitive, PRIMITIVE2D_ID_SWSIDEBARANCHORPRIMITIVE)
241 
242 /****** AnchorOverlayObject    ***********************************************************/
243 /*static*/ AnchorOverlayObject* AnchorOverlayObject::CreateAnchorOverlayObject(
244                                                        SwView& rDocView,
245                                                        const SwRect& aAnchorRect,
246                                                        const long& aPageBorder,
247                                                        const Point& aLineStart,
248                                                        const Point& aLineEnd,
249                                                        const Color& aColorAnchor )
250 {
251     AnchorOverlayObject* pAnchorOverlayObject( 0 );
252     if ( rDocView.GetDrawView() )
253     {
254         SdrPaintWindow* pPaintWindow = rDocView.GetDrawView()->GetPaintWindow(0);
255         if( pPaintWindow )
256         {
257             sdr::overlay::OverlayManager* pOverlayManager = pPaintWindow->GetOverlayManager();
258 
259             if ( pOverlayManager )
260             {
261                 pAnchorOverlayObject = new AnchorOverlayObject(
262                     basegfx::B2DPoint( aAnchorRect.Left() , aAnchorRect.Bottom()-5*15),
263                     basegfx::B2DPoint( aAnchorRect.Left()-5*15 , aAnchorRect.Bottom()+5*15),
264                     basegfx::B2DPoint( aAnchorRect.Left()+5*15 , aAnchorRect.Bottom()+5*15),
265                     basegfx::B2DPoint( aAnchorRect.Left(), aAnchorRect.Bottom()+2*15),
266                     basegfx::B2DPoint( aPageBorder ,aAnchorRect.Bottom()+2*15),
267                     basegfx::B2DPoint( aLineStart.X(),aLineStart.Y()),
268                     basegfx::B2DPoint( aLineEnd.X(),aLineEnd.Y()) ,
269                     aColorAnchor,
270                     false,
271                     false);
272                 pOverlayManager->add(*pAnchorOverlayObject);
273             }
274         }
275     }
276 
277     return pAnchorOverlayObject;
278 }
279 
280 /*static*/ void AnchorOverlayObject::DestroyAnchorOverlayObject( AnchorOverlayObject* pAnchor )
281 {
282     if ( pAnchor )
283     {
284         if ( pAnchor->getOverlayManager() )
285         {
286             // remove this object from the chain
287             pAnchor->getOverlayManager()->remove(*pAnchor);
288         }
289         delete pAnchor;
290     }
291 }
292 
293 AnchorOverlayObject::AnchorOverlayObject( const basegfx::B2DPoint& rBasePos,
294                                           const basegfx::B2DPoint& rSecondPos,
295                                           const basegfx::B2DPoint& rThirdPos,
296                                           const basegfx::B2DPoint& rFourthPos,
297                                           const basegfx::B2DPoint& rFifthPos,
298                                           const basegfx::B2DPoint& rSixthPos,
299                                           const basegfx::B2DPoint& rSeventhPos,
300                                           const Color aBaseColor,
301                                           const bool bShadowedEffect,
302                                           const bool bLineSolid)
303     : OverlayObjectWithBasePosition( rBasePos, aBaseColor )
304     , maSecondPosition(rSecondPos)
305     , maThirdPosition(rThirdPos)
306     , maFourthPosition(rFourthPos)
307     , maFifthPosition(rFifthPos)
308     , maSixthPosition(rSixthPos)
309     , maSeventhPosition(rSeventhPos)
310     , maTriangle()
311     , maLine()
312     , maLineTop()
313     , mHeight(0)
314     , mAnchorState(AS_ALL)
315     , mbShadowedEffect(bShadowedEffect)
316     , mbLineSolid(bLineSolid)
317 {
318 }
319 
320 AnchorOverlayObject::~AnchorOverlayObject()
321 {
322 }
323 
324 void AnchorOverlayObject::implEnsureGeometry()
325 {
326     if(!maTriangle.count())
327     {
328         maTriangle.append(getBasePosition());
329         maTriangle.append(GetSecondPosition());
330         maTriangle.append(GetThirdPosition());
331         maTriangle.setClosed(true);
332     }
333 
334     if(!maLine.count())
335     {
336         maLine.append(GetFourthPosition());
337         maLine.append(GetFifthPosition());
338         maLine.append(GetSixthPosition());
339     }
340 
341   if(!maLineTop.count())
342     {
343         maLineTop.append(GetSixthPosition());
344         maLineTop.append(GetSeventhPosition());
345     }
346 }
347 
348 void AnchorOverlayObject::implResetGeometry()
349 {
350     maTriangle.clear();
351     maLine.clear();
352     maLineTop.clear();
353 }
354 
355 drawinglayer::primitive2d::Primitive2DSequence AnchorOverlayObject::createOverlayObjectPrimitive2DSequence()
356 {
357     implEnsureGeometry();
358 
359     const drawinglayer::primitive2d::Primitive2DReference aReference(
360         new AnchorPrimitive( maTriangle,
361                              maLine,
362                              maLineTop,
363                              GetAnchorState(),
364                              getBaseColor().getBColor(),
365                              ANCHORLINE_WIDTH * 15.0,
366                              getShadowedEffect(),
367                              getLineSolid()) );
368 
369     return drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1);
370 }
371 
372 void AnchorOverlayObject::SetAllPosition( const basegfx::B2DPoint& rPoint1,
373                                           const basegfx::B2DPoint& rPoint2,
374                                           const basegfx::B2DPoint& rPoint3,
375                                           const basegfx::B2DPoint& rPoint4,
376                                           const basegfx::B2DPoint& rPoint5,
377                                           const basegfx::B2DPoint& rPoint6,
378                                           const basegfx::B2DPoint& rPoint7)
379 {
380     if ( rPoint1 != getBasePosition() ||
381          rPoint2 != GetSecondPosition() ||
382          rPoint3 != GetThirdPosition() ||
383          rPoint4 != GetFourthPosition() ||
384          rPoint5 != GetFifthPosition() ||
385          rPoint6 != GetSixthPosition() ||
386          rPoint7 != GetSeventhPosition() )
387     {
388         maBasePosition = rPoint1;
389         maSecondPosition = rPoint2;
390         maThirdPosition = rPoint3;
391         maFourthPosition = rPoint4;
392         maFifthPosition = rPoint5;
393         maSixthPosition = rPoint6;
394         maSeventhPosition = rPoint7;
395 
396         implResetGeometry();
397         objectChange();
398     }
399 }
400 
401 void AnchorOverlayObject::SetSixthPosition(const basegfx::B2DPoint& rNew)
402 {
403   if(rNew != maSixthPosition)
404   {
405       maSixthPosition = rNew;
406         implResetGeometry();
407       objectChange();
408   }
409 }
410 
411 void AnchorOverlayObject::SetSeventhPosition(const basegfx::B2DPoint& rNew)
412 {
413   if(rNew != maSeventhPosition)
414   {
415       maSeventhPosition = rNew;
416         implResetGeometry();
417       objectChange();
418   }
419 }
420 
421 void AnchorOverlayObject::SetTriPosition(const basegfx::B2DPoint& rPoint1,const basegfx::B2DPoint& rPoint2,const basegfx::B2DPoint& rPoint3,
422                                   const basegfx::B2DPoint& rPoint4,const basegfx::B2DPoint& rPoint5)
423 {
424     if(rPoint1 != getBasePosition()
425         || rPoint2 != GetSecondPosition()
426         || rPoint3 != GetThirdPosition()
427         || rPoint4 != GetFourthPosition()
428         || rPoint5 != GetFifthPosition())
429     {
430       maBasePosition = rPoint1;
431       maSecondPosition = rPoint2;
432       maThirdPosition = rPoint3;
433       maFourthPosition = rPoint4;
434       maFifthPosition = rPoint5;
435 
436       implResetGeometry();
437       objectChange();
438     }
439 }
440 
441 void AnchorOverlayObject::setLineSolid( const bool bNew )
442 {
443   if ( bNew != getLineSolid() )
444   {
445       mbLineSolid = bNew;
446       objectChange();
447   }
448 }
449 
450 void AnchorOverlayObject::SetAnchorState( const AnchorState aState)
451 {
452   if ( mAnchorState != aState)
453   {
454       mAnchorState = aState;
455       objectChange();
456   }
457 }
458 
459 } } // end of namespace sw::annotation
460 
461