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                          mfDiscreteLineWidth;
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:
AnchorPrimitive(const basegfx::B2DPolygon & rTriangle,const basegfx::B2DPolygon & rLine,const basegfx::B2DPolygon & rLineTop,AnchorState aAnchorState,const basegfx::BColor & rColor,double fDiscreteLineWidth,bool bShadow,bool bLineSolid)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 fDiscreteLineWidth,
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         mfDiscreteLineWidth(fDiscreteLineWidth),
83         mbShadow(bShadow),
84         mbLineSolid(bLineSolid)
85     {}
86 
87     // data access
getTriangle() const88     const basegfx::B2DPolygon& getTriangle() const { return maTriangle; }
getLine() const89     const basegfx::B2DPolygon& getLine() const { return maLine; }
getLineTop() const90     const basegfx::B2DPolygon& getLineTop() const { return maLineTop; }
getAnchorState() const91     AnchorState getAnchorState() const { return maAnchorState; }
getColor() const92     const basegfx::BColor& getColor() const { return maColor; }
getDiscreteLineWidth() const93     double getDiscreteLineWidth() const { return mfDiscreteLineWidth; }
getShadow() const94     bool getShadow() const { return mbShadow; }
getLineSolid() const95     bool getLineSolid() const { return mbLineSolid; }
96 
97     virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const;
98 
99     DeclPrimitrive2DIDBlock()
100 };
101 
create2DDecomposition(const drawinglayer::geometry::ViewInformation2D &) const102 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     // prepare view-independent LineWidth and color
121     const drawinglayer::attribute::LineAttribute aLineAttribute(
122         getColor(),
123         getDiscreteLineWidth() * getDiscreteUnit());
124 
125     if ( AS_ALL == maAnchorState ||
126          AS_START == maAnchorState )
127     {
128         // create line start
129         if(getLineSolid())
130         {
131             const drawinglayer::primitive2d::Primitive2DReference aSolidLine(
132                 new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
133                     getLine(),
134                     aLineAttribute));
135 
136             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, aSolidLine);
137         }
138         else
139         {
140             ::std::vector< double > aDotDashArray;
141             const double fDistance(3.0 * 15.0);
142             const double fDashLen(5.0 * 15.0);
143 
144             aDotDashArray.push_back(fDashLen);
145             aDotDashArray.push_back(fDistance);
146 
147             const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(
148                 aDotDashArray,
149                 fDistance + fDashLen);
150 
151             const drawinglayer::primitive2d::Primitive2DReference aStrokedLine(
152                 new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
153                     getLine(),
154                     aLineAttribute,
155                     aStrokeAttribute));
156 
157             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, aStrokedLine);
158         }
159     }
160 
161     if(aRetval.hasElements() && getShadow())
162     {
163         // shadow is only for triangle and line start, and in upper left
164         // and lower right direction, in different colors
165         const double fColorChange(20.0 / 255.0);
166         const basegfx::B3DTuple aColorChange(fColorChange, fColorChange, fColorChange);
167         basegfx::BColor aLighterColor(getColor() + aColorChange);
168         basegfx::BColor aDarkerColor(getColor() - aColorChange);
169 
170         aLighterColor.clamp();
171         aDarkerColor.clamp();
172 
173         // create shadow sequence
174         drawinglayer::primitive2d::Primitive2DSequence aShadows(2);
175         basegfx::B2DHomMatrix aTransform;
176 
177         aTransform.set(0, 2, -getDiscreteUnit());
178         aTransform.set(1, 2, -getDiscreteUnit());
179 
180         aShadows[0] = drawinglayer::primitive2d::Primitive2DReference(
181             new drawinglayer::primitive2d::ShadowPrimitive2D(
182                 aTransform,
183                 aLighterColor,
184                 aRetval));
185 
186         aTransform.set(0, 2, getDiscreteUnit());
187         aTransform.set(1, 2, getDiscreteUnit());
188 
189         aShadows[1] = drawinglayer::primitive2d::Primitive2DReference(
190             new drawinglayer::primitive2d::ShadowPrimitive2D(
191                 aTransform,
192                 aDarkerColor,
193                 aRetval));
194 
195         // add shadow before geometry to make it be proccessed first
196         const drawinglayer::primitive2d::Primitive2DSequence aTemporary(aRetval);
197 
198         aRetval = aShadows;
199         drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aRetval, aTemporary);
200     }
201 
202     if ( AS_ALL == maAnchorState ||
203          AS_END == maAnchorState )
204     {
205         // LineTop has to be created, too, but uses no shadow, so add after
206         // the other parts are created
207         const drawinglayer::primitive2d::Primitive2DReference aLineTop(
208             new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
209                 getLineTop(),
210                 aLineAttribute));
211 
212         drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, aLineTop);
213     }
214 
215     return aRetval;
216 }
217 
operator ==(const drawinglayer::primitive2d::BasePrimitive2D & rPrimitive) const218 bool AnchorPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const
219 {
220     if(drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
221     {
222         const AnchorPrimitive& rCompare = static_cast< const AnchorPrimitive& >(rPrimitive);
223 
224         return (getTriangle() == rCompare.getTriangle()
225             && getLine() == rCompare.getLine()
226             && getLineTop() == rCompare.getLineTop()
227             && getAnchorState() == rCompare.getAnchorState()
228             && getColor() == rCompare.getColor()
229             && getDiscreteLineWidth() == rCompare.getDiscreteLineWidth()
230             && getShadow() == rCompare.getShadow()
231             && getLineSolid() == rCompare.getLineSolid());
232     }
233 
234     return false;
235 }
236 
ImplPrimitrive2DIDBlock(AnchorPrimitive,PRIMITIVE2D_ID_SWSIDEBARANCHORPRIMITIVE)237 ImplPrimitrive2DIDBlock(AnchorPrimitive, PRIMITIVE2D_ID_SWSIDEBARANCHORPRIMITIVE)
238 
239 /****** AnchorOverlayObject    ***********************************************************/
240 /*static*/ AnchorOverlayObject* AnchorOverlayObject::CreateAnchorOverlayObject(
241                                                        SwView& rDocView,
242                                                        const SwRect& aAnchorRect,
243                                                        const long& aPageBorder,
244                                                        const Point& aLineStart,
245                                                        const Point& aLineEnd,
246                                                        const Color& aColorAnchor )
247 {
248     AnchorOverlayObject* pAnchorOverlayObject( 0 );
249     if ( rDocView.GetDrawView() )
250     {
251         SdrPaintWindow* pPaintWindow = rDocView.GetDrawView()->GetPaintWindow(0);
252         if( pPaintWindow )
253         {
254             sdr::overlay::OverlayManager* pOverlayManager = pPaintWindow->GetOverlayManager();
255 
256             if ( pOverlayManager )
257             {
258                 pAnchorOverlayObject = new AnchorOverlayObject(
259                     basegfx::B2DPoint( aAnchorRect.Left() , aAnchorRect.Bottom()-5*15),
260                     basegfx::B2DPoint( aAnchorRect.Left()-5*15 , aAnchorRect.Bottom()+5*15),
261                     basegfx::B2DPoint( aAnchorRect.Left()+5*15 , aAnchorRect.Bottom()+5*15),
262                     basegfx::B2DPoint( aAnchorRect.Left(), aAnchorRect.Bottom()+2*15),
263                     basegfx::B2DPoint( aPageBorder ,aAnchorRect.Bottom()+2*15),
264                     basegfx::B2DPoint( aLineStart.X(),aLineStart.Y()),
265                     basegfx::B2DPoint( aLineEnd.X(),aLineEnd.Y()) ,
266                     aColorAnchor,
267                     false,
268                     false);
269                 pOverlayManager->add(*pAnchorOverlayObject);
270             }
271         }
272     }
273 
274     return pAnchorOverlayObject;
275 }
276 
DestroyAnchorOverlayObject(AnchorOverlayObject * pAnchor)277 /*static*/ void AnchorOverlayObject::DestroyAnchorOverlayObject( AnchorOverlayObject* pAnchor )
278 {
279     if ( pAnchor )
280     {
281         if ( pAnchor->getOverlayManager() )
282         {
283             // remove this object from the chain
284             pAnchor->getOverlayManager()->remove(*pAnchor);
285         }
286         delete pAnchor;
287     }
288 }
289 
AnchorOverlayObject(const basegfx::B2DPoint & rBasePos,const basegfx::B2DPoint & rSecondPos,const basegfx::B2DPoint & rThirdPos,const basegfx::B2DPoint & rFourthPos,const basegfx::B2DPoint & rFifthPos,const basegfx::B2DPoint & rSixthPos,const basegfx::B2DPoint & rSeventhPos,const Color aBaseColor,const bool bShadowedEffect,const bool bLineSolid)290 AnchorOverlayObject::AnchorOverlayObject( const basegfx::B2DPoint& rBasePos,
291                                           const basegfx::B2DPoint& rSecondPos,
292                                           const basegfx::B2DPoint& rThirdPos,
293                                           const basegfx::B2DPoint& rFourthPos,
294                                           const basegfx::B2DPoint& rFifthPos,
295                                           const basegfx::B2DPoint& rSixthPos,
296                                           const basegfx::B2DPoint& rSeventhPos,
297                                           const Color aBaseColor,
298                                           const bool bShadowedEffect,
299                                           const bool bLineSolid)
300     : OverlayObjectWithBasePosition( rBasePos, aBaseColor )
301     , maSecondPosition(rSecondPos)
302     , maThirdPosition(rThirdPos)
303     , maFourthPosition(rFourthPos)
304     , maFifthPosition(rFifthPos)
305     , maSixthPosition(rSixthPos)
306     , maSeventhPosition(rSeventhPos)
307     , maTriangle()
308     , maLine()
309     , maLineTop()
310     , mHeight(0)
311     , mAnchorState(AS_ALL)
312     , mbShadowedEffect(bShadowedEffect)
313     , mbLineSolid(bLineSolid)
314 {
315 }
316 
~AnchorOverlayObject()317 AnchorOverlayObject::~AnchorOverlayObject()
318 {
319 }
320 
implEnsureGeometry()321 void AnchorOverlayObject::implEnsureGeometry()
322 {
323     if(!maTriangle.count())
324     {
325         maTriangle.append(getBasePosition());
326         maTriangle.append(GetSecondPosition());
327         maTriangle.append(GetThirdPosition());
328         maTriangle.setClosed(true);
329     }
330 
331     if(!maLine.count())
332     {
333         maLine.append(GetFourthPosition());
334         maLine.append(GetFifthPosition());
335         maLine.append(GetSixthPosition());
336     }
337 
338   if(!maLineTop.count())
339     {
340         maLineTop.append(GetSixthPosition());
341         maLineTop.append(GetSeventhPosition());
342     }
343 }
344 
implResetGeometry()345 void AnchorOverlayObject::implResetGeometry()
346 {
347     maTriangle.clear();
348     maLine.clear();
349     maLineTop.clear();
350 }
351 
createOverlayObjectPrimitive2DSequence()352 drawinglayer::primitive2d::Primitive2DSequence AnchorOverlayObject::createOverlayObjectPrimitive2DSequence()
353 {
354     implEnsureGeometry();
355 
356     static double aDiscreteLineWidth(1.6);
357     const drawinglayer::primitive2d::Primitive2DReference aReference(
358         new AnchorPrimitive( maTriangle,
359                              maLine,
360                              maLineTop,
361                              GetAnchorState(),
362                              getBaseColor().getBColor(),
363                              ANCHORLINE_WIDTH * aDiscreteLineWidth,
364                              getShadowedEffect(),
365                              getLineSolid()) );
366 
367     return drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1);
368 }
369 
SetAllPosition(const basegfx::B2DPoint & rPoint1,const basegfx::B2DPoint & rPoint2,const basegfx::B2DPoint & rPoint3,const basegfx::B2DPoint & rPoint4,const basegfx::B2DPoint & rPoint5,const basegfx::B2DPoint & rPoint6,const basegfx::B2DPoint & rPoint7)370 void AnchorOverlayObject::SetAllPosition( const basegfx::B2DPoint& rPoint1,
371                                           const basegfx::B2DPoint& rPoint2,
372                                           const basegfx::B2DPoint& rPoint3,
373                                           const basegfx::B2DPoint& rPoint4,
374                                           const basegfx::B2DPoint& rPoint5,
375                                           const basegfx::B2DPoint& rPoint6,
376                                           const basegfx::B2DPoint& rPoint7)
377 {
378     if ( rPoint1 != getBasePosition() ||
379          rPoint2 != GetSecondPosition() ||
380          rPoint3 != GetThirdPosition() ||
381          rPoint4 != GetFourthPosition() ||
382          rPoint5 != GetFifthPosition() ||
383          rPoint6 != GetSixthPosition() ||
384          rPoint7 != GetSeventhPosition() )
385     {
386         maBasePosition = rPoint1;
387         maSecondPosition = rPoint2;
388         maThirdPosition = rPoint3;
389         maFourthPosition = rPoint4;
390         maFifthPosition = rPoint5;
391         maSixthPosition = rPoint6;
392         maSeventhPosition = rPoint7;
393 
394         implResetGeometry();
395         objectChange();
396     }
397 }
398 
SetSixthPosition(const basegfx::B2DPoint & rNew)399 void AnchorOverlayObject::SetSixthPosition(const basegfx::B2DPoint& rNew)
400 {
401   if(rNew != maSixthPosition)
402   {
403       maSixthPosition = rNew;
404         implResetGeometry();
405       objectChange();
406   }
407 }
408 
SetSeventhPosition(const basegfx::B2DPoint & rNew)409 void AnchorOverlayObject::SetSeventhPosition(const basegfx::B2DPoint& rNew)
410 {
411   if(rNew != maSeventhPosition)
412   {
413       maSeventhPosition = rNew;
414         implResetGeometry();
415       objectChange();
416   }
417 }
418 
SetTriPosition(const basegfx::B2DPoint & rPoint1,const basegfx::B2DPoint & rPoint2,const basegfx::B2DPoint & rPoint3,const basegfx::B2DPoint & rPoint4,const basegfx::B2DPoint & rPoint5)419 void AnchorOverlayObject::SetTriPosition(const basegfx::B2DPoint& rPoint1,const basegfx::B2DPoint& rPoint2,const basegfx::B2DPoint& rPoint3,
420                                   const basegfx::B2DPoint& rPoint4,const basegfx::B2DPoint& rPoint5)
421 {
422     if(rPoint1 != getBasePosition()
423         || rPoint2 != GetSecondPosition()
424         || rPoint3 != GetThirdPosition()
425         || rPoint4 != GetFourthPosition()
426         || rPoint5 != GetFifthPosition())
427     {
428       maBasePosition = rPoint1;
429       maSecondPosition = rPoint2;
430       maThirdPosition = rPoint3;
431       maFourthPosition = rPoint4;
432       maFifthPosition = rPoint5;
433 
434       implResetGeometry();
435       objectChange();
436     }
437 }
438 
setLineSolid(const bool bNew)439 void AnchorOverlayObject::setLineSolid( const bool bNew )
440 {
441   if ( bNew != getLineSolid() )
442   {
443       mbLineSolid = bNew;
444       objectChange();
445   }
446 }
447 
SetAnchorState(const AnchorState aState)448 void AnchorOverlayObject::SetAnchorState( const AnchorState aState)
449 {
450   if ( mAnchorState != aState)
451   {
452       mAnchorState = aState;
453       objectChange();
454   }
455 }
456 
457 } } // end of namespace sw::annotation
458 
459