xref: /core/svx/source/toolbars/extrusionbar.cxx (revision e7cc35a41d74381b93313cb30b1ddb64378fc5c4)
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 
20 
21 #include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
22 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
23 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
24 #include <com/sun/star/drawing/ShadeMode.hpp>
25 #include <com/sun/star/drawing/Position3D.hpp>
26 #include <com/sun/star/drawing/Direction3D.hpp>
27 #include <com/sun/star/drawing/ProjectionMode.hpp>
28 #include <svx/svxids.hrc>
29 #include <svx/svdundo.hxx>
30 #include <sfx2/request.hxx>
31 #include <sfx2/objface.hxx>
32 #include <sfx2/viewsh.hxx>
33 #include <sfx2/bindings.hxx>
34 #include <svx/xsflclit.hxx>
35 #include <svx/dialmgr.hxx>
36 #include <svx/svdoashp.hxx>
37 #include <svx/strings.hrc>
38 #include <svx/svdview.hxx>
39 #include <editeng/colritem.hxx>
40 #include <svx/chrtitem.hxx>
41 #include <svx/sdasitm.hxx>
42 #include <svl/intitem.hxx>
43 #include <rtl/math.hxx>
44 #include <basegfx/numeric/ftools.hxx>
45 
46 #include <svx/extrusionbar.hxx>
47 #include <extrusiondepthdialog.hxx>
48 
49 using namespace ::svx;
50 using namespace ::com::sun::star::beans;
51 using namespace ::com::sun::star::drawing;
52 using namespace ::com::sun::star::uno;
53 
54 // Declare the default interface. (The slotmap must not be empty, so
55 // we enter something which never occurs here (hopefully).)
56 constexpr SfxSlot aExtrusionBarSlots_Impl[] =
57 {
58     { 0, SfxGroupId::NONE, SfxSlotMode::NONE, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, 0, SfxDisableFlags::NONE, u""_ustr }
59 };
60 
SFX_IMPL_INTERFACE(ExtrusionBar,SfxShell)61 SFX_IMPL_INTERFACE(ExtrusionBar, SfxShell)
62 
63 void ExtrusionBar::InitInterface_Impl()
64 {
65     GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Invisible, ToolbarId::Svx_Extrusion_Bar);
66 }
67 
68 
ExtrusionBar(SfxViewShell * pViewShell)69 ExtrusionBar::ExtrusionBar(SfxViewShell* pViewShell )
70 : SfxShell(pViewShell)
71 {
72     DBG_ASSERT( pViewShell, "svx::ExtrusionBar::ExtrusionBar(), I need a viewshell!" );
73     if( pViewShell )
74         SetPool(&pViewShell->GetPool());
75 
76     SetName(SvxResId(RID_SVX_EXTRUSION_BAR));
77 }
78 
~ExtrusionBar()79 ExtrusionBar::~ExtrusionBar()
80 {
81     SetRepeatTarget(nullptr);
82 }
83 
getLightingDirectionDefaults(const Direction3D ** pLighting1Defaults,const Direction3D ** pLighting2Defaults)84 static void getLightingDirectionDefaults( const Direction3D **pLighting1Defaults, const Direction3D **pLighting2Defaults )
85 {
86 
87     static const Direction3D aLighting1Defaults[9] =
88     {
89         Direction3D( -50000, -50000, 10000 ),
90         Direction3D( 0, -50000, 10000 ),
91         Direction3D( 50000, -50000, 10000 ),
92         Direction3D( -50000, 0, 10000 ),
93         Direction3D( 0, 0, 10000 ),
94         Direction3D( 50000, 0, 10000 ),
95         Direction3D( -50000, 50000, 10000 ),
96         Direction3D( 0, 50000, 10000 ),
97         Direction3D( 50000, 50000, 10000 )
98     };
99 
100     static const Direction3D aLighting2Defaults[9] =
101     {
102         Direction3D( 50000,0, 10000 ),
103         Direction3D( 0, 50000, 10000 ),
104         Direction3D( -50000, 0, 10000 ),
105         Direction3D( 50000, 0, 10000 ),
106         Direction3D( 0, 0, 10000 ),
107         Direction3D( -50000, 0, 10000 ),
108         Direction3D( 50000, 0, 10000 ),
109         Direction3D( 0, -50000, 10000 ),
110         Direction3D( -50000, 0, 10000 )
111     };
112 
113     *pLighting1Defaults = aLighting1Defaults;
114     *pLighting2Defaults = aLighting2Defaults;
115 };
116 
impl_execute(SfxRequest const & rReq,SdrCustomShapeGeometryItem & rGeometryItem,SdrObject * pObj)117 static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& rGeometryItem, SdrObject* pObj )
118 {
119     static constexpr OUString sExtrusion = u"Extrusion"_ustr;
120     static constexpr OUString sRotateAngle = u"RotateAngle"_ustr;
121 
122     sal_uInt16 nSID = rReq.GetSlot();
123     switch( nSID )
124     {
125     case SID_EXTRUSION_TOGGLE:
126     {
127         bool bOn(false);
128         css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
129         if ( pAny )
130         {
131             (*pAny) >>= bOn;
132             bOn = !bOn;
133             css::beans::PropertyValue aPropValue;
134             aPropValue.Name = sExtrusion;
135             aPropValue.Value <<= bOn;
136             rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
137         }
138         else
139         {
140             css::beans::PropertyValue aPropValue;
141             aPropValue.Name = sExtrusion;
142             aPropValue.Value <<= true;
143             rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
144             bOn = true;
145         }
146 
147         // draw:extrusion-diffusion has default 0% and c3DDiffuseAmt has default 100%. We set property
148         // "Diffusion" with value 100% here if it does not exist already. This forces, that the
149         // property is written to file in case an extrusion is newly created, and users of old
150         // documents, which usually do not have this property, can force the value to 100% by toggling
151         // the extrusion off and on.
152         if (bOn)
153         {
154             pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Diffusion"_ustr);
155             if (!pAny)
156             {
157                 css::beans::PropertyValue aPropValue;
158                 aPropValue.Name = u"Diffusion"_ustr;
159                 aPropValue.Value <<= 100.0;
160                 rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
161             }
162         }
163     }
164     break;
165 
166     case SID_EXTRUSION_TILT_DOWN:
167     case SID_EXTRUSION_TILT_UP:
168     case SID_EXTRUSION_TILT_LEFT:
169     case SID_EXTRUSION_TILT_RIGHT:
170     {
171         bool bHorizontal = ( nSID == SID_EXTRUSION_TILT_DOWN ) || ( nSID == SID_EXTRUSION_TILT_UP );
172         sal_Int32 nDiff = ( nSID == SID_EXTRUSION_TILT_LEFT ) || ( nSID == SID_EXTRUSION_TILT_UP ) ? 5 : -5;
173         EnhancedCustomShapeParameterPair aRotateAnglePropPair;
174         double fX = 0.0;
175         double fY = 0.0;
176         aRotateAnglePropPair.First.Value <<= fX;
177         aRotateAnglePropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
178         aRotateAnglePropPair.Second.Value <<= fY;
179         aRotateAnglePropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
180         css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, sRotateAngle );
181         if( pAny && ( *pAny >>= aRotateAnglePropPair ) )
182         {
183             aRotateAnglePropPair.First.Value >>= fX;
184             aRotateAnglePropPair.Second.Value >>= fY;
185         }
186         if ( bHorizontal )
187             fX += nDiff;
188         else
189             fY += nDiff;
190         aRotateAnglePropPair.First.Value <<= fX;
191         aRotateAnglePropPair.Second.Value <<= fY;
192         css::beans::PropertyValue aPropValue;
193         aPropValue.Name = sRotateAngle;
194         aPropValue.Value <<= aRotateAnglePropPair;
195         rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
196     }
197     break;
198 
199     case SID_EXTRUSION_DIRECTION:
200     {
201         const SfxInt32Item* pExtrusionItem = nullptr;
202         if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_DIRECTION, true, &pExtrusionItem ) == SfxItemState::SET )
203         {
204             sal_Int32 nSkew = pExtrusionItem->GetValue();
205 
206             Position3D  aViewPoint( 3472, -3472, 25000 );
207             double      fOriginX = 0.50;
208             double      fOriginY = -0.50;
209             double      fSkewAngle = nSkew;
210             double      fSkew = 50.0;
211 
212             switch( nSkew )
213             {
214             case 135:
215                 aViewPoint.PositionY = 3472;
216                 fOriginY = 0.50;
217                 break;
218             case 90:
219                 aViewPoint.PositionX = 0;
220                 aViewPoint.PositionY = 3472;
221                 fOriginX = 0;
222                 fOriginY = 0.50;
223                 break;
224             case 45:
225                 aViewPoint.PositionX = -3472;
226                 aViewPoint.PositionY = 3472;
227                 fOriginX = -0.50;
228                 fOriginY = 0.50;
229                 break;
230             case 180:
231                 aViewPoint.PositionY = 0;
232                 fOriginY = 0;
233                 break;
234             case 0:
235                 aViewPoint.PositionX = 0;
236                 aViewPoint.PositionY = 0;
237                 fOriginX = 0;
238                 fOriginY = 0;
239                 fSkew = 0.0;
240                 break;
241             case -360:
242                 aViewPoint.PositionX = -3472;
243                 aViewPoint.PositionY = 0;
244                 fOriginX = -0.50;
245                 fOriginY = 0;
246                 break;
247             case -90:
248                 aViewPoint.PositionX = 0;
249                 fOriginX = 0;
250                 break;
251             case -45:
252                 aViewPoint.PositionX = -3472;
253                 fOriginX = -0.50;
254                 break;
255             }
256 
257             css::beans::PropertyValue aPropValue;
258 
259             aPropValue.Name = "ViewPoint";
260             aPropValue.Value <<= aViewPoint;
261             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
262 
263 
264             EnhancedCustomShapeParameterPair aOriginPropPair;
265             aOriginPropPair.First.Value <<= fOriginX;
266             aOriginPropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
267             aOriginPropPair.Second.Value <<= fOriginY;
268             aOriginPropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
269             aPropValue.Name = "Origin";
270             aPropValue.Value <<= aOriginPropPair;
271             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
272 
273             EnhancedCustomShapeParameterPair aSkewPropPair;
274             aSkewPropPair.First.Value <<= fSkew;
275             aSkewPropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
276             aSkewPropPair.Second.Value <<= fSkewAngle;
277             aSkewPropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
278             aPropValue.Name = "Skew";
279             aPropValue.Value <<= aSkewPropPair;
280             rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
281         }
282     }
283     break;
284     case SID_EXTRUSION_PROJECTION:
285     {
286         const SfxInt32Item* pExtrusionItem = nullptr;
287         if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_PROJECTION, true, &pExtrusionItem ) == SfxItemState::SET )
288         {
289             sal_Int32 nProjection = pExtrusionItem->GetValue();
290             ProjectionMode eProjectionMode = nProjection == 1 ? ProjectionMode_PARALLEL : ProjectionMode_PERSPECTIVE;
291             css::beans::PropertyValue aPropValue;
292             aPropValue.Name = "ProjectionMode";
293             aPropValue.Value <<= eProjectionMode;
294             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
295         }
296     }
297     break;
298     case SID_EXTRUSION_DEPTH:
299     {
300         const SvxDoubleItem* pExtrusionItem = nullptr;
301         if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_DEPTH, true, &pExtrusionItem ) == SfxItemState::SET)
302         {
303             double fDepth = pExtrusionItem->GetValue();
304             EnhancedCustomShapeParameterPair aDepthPropPair;
305             aDepthPropPair.First.Value <<= fDepth;
306             aDepthPropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
307             aDepthPropPair.Second.Value <<= 0.0; // fraction
308             aDepthPropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
309 
310             css::beans::PropertyValue aPropValue;
311             aPropValue.Name = "Depth";
312             aPropValue.Value <<= aDepthPropPair;
313             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
314         }
315     }
316     break;
317     case SID_EXTRUSION_3D_COLOR:
318     {
319         if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_3D_COLOR ) == SfxItemState::SET)
320         {
321             Color aColor( static_cast<const SvxColorItem&>(rReq.GetArgs()->Get(SID_EXTRUSION_3D_COLOR)).GetValue() );
322 
323             const bool bAuto = aColor == COL_AUTO;
324 
325             css::beans::PropertyValue aPropValue;
326             aPropValue.Name = "Color";
327             aPropValue.Value <<= !bAuto;
328             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
329 
330             if( bAuto )
331             {
332                 pObj->ClearMergedItem( XATTR_SECONDARYFILLCOLOR );
333             }
334             else
335             {
336                 pObj->SetMergedItem( XSecondaryFillColorItem( u""_ustr, aColor ) );
337             }
338             pObj->BroadcastObjectChange();
339         }
340     }
341     break;
342     case SID_EXTRUSION_SURFACE:
343     {
344         const SfxInt32Item* pExtrusionItem = nullptr;
345         if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_SURFACE, true, &pExtrusionItem ) == SfxItemState::SET)
346         {
347             sal_Int32 nSurface = pExtrusionItem->GetValue();
348 
349             // Set ShadeMode only when changing from or to wireframe, otherwise keep existing value.
350             ShadeMode eOldShadeMode(ShadeMode_FLAT);
351             css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"ShadeMode"_ustr);
352             if (pAny)
353                 *pAny >>= eOldShadeMode;
354             ShadeMode eShadeMode(eOldShadeMode);
355             switch (nSurface)
356             {
357                 case 0: // wireframe
358                     eShadeMode = ShadeMode_DRAFT;
359                     break;
360                 case 1: // matte
361                 case 2: // plastic
362                 case 3: // metal ODF
363                 case 4: // metal MS Office
364                     if (eOldShadeMode == ShadeMode_DRAFT)
365                         eShadeMode = ShadeMode_FLAT; // ODF default
366                     break;
367             }
368 
369             // ODF has no dedicated property for 'surface'. MS Office binary format uses attribute
370             // c3DSpecularAmt to distinguish between 'matte' (=0) and 'plastic'.
371             // We do the same.
372             double fOldSpecularity = 0.0;
373             pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Specularity"_ustr);
374             if (pAny)
375                 *pAny >>= fOldSpecularity;
376             double fSpecularity = fOldSpecularity;
377             switch( nSurface )
378             {
379             case 0: // wireframe
380                 break;
381             case 1: // matte
382                 fSpecularity = 0.0;
383                 break;
384             case 2: // plastic
385             case 3: // metal ODF
386             case 4: // metal MS Office
387                 if (basegfx::fTools::equalZero(fOldSpecularity, 0.0001))
388                     // MS Office uses 80000/65536. That is currently not allowed in ODF.
389                     // But the ODF error will be caught in xmloff.
390                     fSpecularity = 80000.0 / 655.36; // interpreted as %
391                 break;
392             }
393 
394             // MS Office binary format uses attribute c3DDiffuseAmt with value =43712 (Fixed 16.16) in
395             // addition to the 'metal' flag. For other surface kinds default = 65536 is used.
396             // We toggle between 100 and 43712.0 / 655.36 here, to get better ODF -> MSO binary.
397             // We keep other values, those might be set outside regular UI, e.g by macro.
398             double fOldDiffusion = 100.0;
399             pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Diffusion"_ustr);
400             if (pAny)
401                 *pAny >>= fOldDiffusion;
402             double fDiffusion = fOldDiffusion;
403             if (nSurface == 4)
404             {
405                 if (fOldDiffusion == 100.0)
406                     fDiffusion = 43712.0 / 655.36; // interpreted as %
407             }
408             else
409             {
410                 if (basegfx::fTools::equalZero(fOldDiffusion - 43712.0 / 655.36, 0.0001))
411                     fDiffusion = 100.0;
412             }
413 
414             css::beans::PropertyValue aPropValue;
415             aPropValue.Name = "ShadeMode";
416             aPropValue.Value <<= eShadeMode;
417             rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
418 
419             aPropValue.Name = "Metal";
420             aPropValue.Value <<= nSurface == 3 || nSurface == 4;
421             rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
422 
423             if (nSurface == 3 || nSurface == 4)
424             {
425                 aPropValue.Name = "MetalType";
426                 aPropValue.Value <<= nSurface == 4
427                                          ? EnhancedCustomShapeMetalType::MetalMSCompatible
428                                          : EnhancedCustomShapeMetalType::MetalODF;
429                 rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
430             }
431 
432             if (!basegfx::fTools::equalZero(fOldSpecularity - fSpecularity, 0.0001))
433             {
434                 aPropValue.Name = "Specularity";
435                 aPropValue.Value <<= fSpecularity;
436                 rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
437             }
438 
439             if (!basegfx::fTools::equalZero(fOldDiffusion - fDiffusion, 0.0001))
440             {
441                 aPropValue.Name = "Diffusion";
442                 aPropValue.Value <<= fDiffusion;
443                 rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
444             }
445         }
446     }
447     break;
448     case SID_EXTRUSION_LIGHTING_INTENSITY:
449     {
450         const SfxInt32Item* pLightItem = nullptr;
451         if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_LIGHTING_INTENSITY, true, &pLightItem ) == SfxItemState::SET)
452         {
453             sal_Int32 nLevel = pLightItem->GetValue();
454 
455             double fBrightness; // c3DAmbientIntensity in MS Office
456             double fLevel1; // c3DKeyIntensity in MS Office
457             double fLevel2; // c3DFillIntensity in MS Office
458 
459             // ToDo: "bright" values are different from MS Office. Should they be kept?
460             switch( nLevel )
461             {
462             case 0: // bright
463                 fBrightness = 33.0; // ODF default.
464                 fLevel1 = 66.0; // ODF default
465                 fLevel2 = 66.0; // ODF default
466                 break;
467             case 1: // normal
468                 fBrightness = 15.0;
469                 fLevel1 = 67.0;
470                 fLevel2 = 37.0;
471                 break;
472             case 2: // dim
473                 fBrightness = 6.0;
474                 fLevel1 = 79.0;
475                 fLevel2 = 21.0;
476                 break;
477             }
478 
479             css::beans::PropertyValue aPropValue;
480             aPropValue.Name = "Brightness";
481             aPropValue.Value <<= fBrightness;
482             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
483 
484             aPropValue.Name = "FirstLightLevel";
485             aPropValue.Value <<= fLevel1;
486             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
487 
488             aPropValue.Name = "SecondLightLevel";
489             aPropValue.Value <<= fLevel2;
490             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
491 
492             // If a user sets light preset 'Dim' in MS Office, MS Office sets second light to harsh.
493             // In other cases it is soft.
494             aPropValue.Name = "SecondLightHarsh";
495             aPropValue.Value <<= nLevel == 2;
496             rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
497         }
498     }
499     break;
500     case SID_EXTRUSION_LIGHTING_DIRECTION:
501     {
502         const SfxInt32Item* pLightDirectionItem = nullptr;
503         if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_LIGHTING_DIRECTION, true, &pLightDirectionItem ) == SfxItemState::SET)
504         {
505             sal_Int32 nDirection = pLightDirectionItem->GetValue();
506 
507             if((nDirection >= 0) && (nDirection < 9))
508             {
509                 const Direction3D * pLighting1Defaults;
510                 const Direction3D * pLighting2Defaults;
511 
512                 getLightingDirectionDefaults( &pLighting1Defaults, &pLighting2Defaults );
513 
514                 css::beans::PropertyValue aPropValue;
515                 aPropValue.Name = "FirstLightDirection";
516                 aPropValue.Value <<= pLighting1Defaults[nDirection];
517                 rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
518 
519                 aPropValue.Name = "SecondLightDirection";
520                 aPropValue.Value <<= pLighting2Defaults[nDirection];
521                 rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
522             }
523         }
524     }
525     break;
526 
527     }
528 }
529 
execute(SdrView * pSdrView,SfxRequest const & rReq,SfxBindings & rBindings)530 void ExtrusionBar::execute( SdrView* pSdrView, SfxRequest const & rReq, SfxBindings& rBindings )
531 {
532     sal_uInt16 nSID = rReq.GetSlot();
533     TranslateId pStrResId;
534 
535     const bool bUndo = pSdrView && pSdrView->IsUndoEnabled();
536 
537     switch( nSID )
538     {
539         case SID_EXTRUSION_TOGGLE:
540         {
541             if ( !pStrResId )
542                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ON_OFF;
543             [[fallthrough]];
544         }
545         case SID_EXTRUSION_TILT_DOWN:
546         {
547             if ( !pStrResId )
548                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_DOWN;
549             [[fallthrough]];
550         }
551         case SID_EXTRUSION_TILT_UP:
552         {
553             if ( !pStrResId )
554                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_UP;
555             [[fallthrough]];
556         }
557         case SID_EXTRUSION_TILT_LEFT:
558         {
559             if ( !pStrResId )
560                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_LEFT;
561             [[fallthrough]];
562         }
563         case SID_EXTRUSION_TILT_RIGHT:
564         {
565             if ( !pStrResId )
566                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_RIGHT;
567             [[fallthrough]];
568         }
569         case SID_EXTRUSION_DIRECTION:
570         {
571             if ( !pStrResId )
572                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ORIENTATION;
573             [[fallthrough]];
574         }
575         case SID_EXTRUSION_PROJECTION:
576         {
577             if ( !pStrResId )
578                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_PROJECTION;
579             [[fallthrough]];
580         }
581         case SID_EXTRUSION_DEPTH:
582         {
583             if ( !pStrResId )
584                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_DEPTH;
585             [[fallthrough]];
586         }
587         case SID_EXTRUSION_3D_COLOR:
588         {
589             if ( !pStrResId )
590                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_COLOR;
591             [[fallthrough]];
592         }
593         case SID_EXTRUSION_SURFACE:
594         {
595             if ( !pStrResId )
596                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_SURFACE;
597             [[fallthrough]];
598         }
599         case SID_EXTRUSION_LIGHTING_INTENSITY:
600         {
601             if ( !pStrResId )
602                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_BRIGHTNESS;
603             [[fallthrough]];
604         }
605         case SID_EXTRUSION_LIGHTING_DIRECTION:
606         {
607             if ( !pStrResId )
608                 pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_LIGHTING;
609 
610             if (pSdrView)
611             {
612                 const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
613                 const size_t nCount = rMarkList.GetMarkCount();
614 
615                 for(size_t i=0; i<nCount; ++i)
616                 {
617                     SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
618                     if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
619                     {
620                         if( bUndo )
621                         {
622                             OUString aStr( SvxResId( pStrResId ) );
623                             pSdrView->BegUndo( aStr );
624                             pSdrView->AddUndo( pSdrView->GetModel().GetSdrUndoFactory().CreateUndoAttrObject( *pObj ) );
625                         }
626                         SdrCustomShapeGeometryItem aGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
627                         impl_execute( rReq, aGeometryItem, pObj );
628                         pObj->SetMergedItem( aGeometryItem );
629                         pObj->BroadcastObjectChange();
630                         if( bUndo )
631                             pSdrView->EndUndo();
632 
633                         // simulate a context change:
634                         // force SelectionHasChanged() being called
635                         // so that extrusion bar will be visible/hidden
636                         pSdrView->MarkListHasChanged();
637                     }
638                 }
639             }
640         }
641         break;
642 
643         case SID_EXTRUSION_DEPTH_DIALOG:
644         {
645             const SvxDoubleItem* pDepthItem = nullptr;
646             const SfxUInt16Item* pMetricItem = nullptr;
647             if( rReq.GetArgs() &&
648                 (rReq.GetArgs()->GetItemState( SID_EXTRUSION_DEPTH, true, &pDepthItem ) == SfxItemState::SET) &&
649                 (rReq.GetArgs()->GetItemState( SID_ATTR_METRIC, true, &pMetricItem ) == SfxItemState::SET))
650             {
651                 double fDepth = pDepthItem->GetValue();
652                 FieldUnit eUnit = static_cast<FieldUnit>(pMetricItem->GetValue());
653 
654                 ExtrusionDepthDialog aDlg(rReq.GetFrameWeld(), fDepth, eUnit);
655                 sal_uInt16 nRet = aDlg.run();
656                 if (nRet == RET_OK)
657                 {
658                     fDepth = aDlg.getDepth();
659 
660                     SvxDoubleItem aItem( fDepth, SID_EXTRUSION_DEPTH );
661                     const SfxPoolItem* aItems[] = { &aItem, nullptr };
662                     rBindings.Execute( SID_EXTRUSION_DEPTH, aItems );
663                 }
664             }
665             break;
666         }
667     }
668 
669     if( nSID != SID_EXTRUSION_TOGGLE )
670         return;
671 
672     static const sal_uInt16 SidArray[] = {
673             SID_EXTRUSION_TILT_DOWN,
674             SID_EXTRUSION_TILT_UP,
675             SID_EXTRUSION_TILT_LEFT,
676             SID_EXTRUSION_TILT_RIGHT,
677             SID_EXTRUSION_DEPTH_FLOATER,
678             SID_EXTRUSION_DIRECTION_FLOATER,
679             SID_EXTRUSION_LIGHTING_FLOATER,
680             SID_EXTRUSION_SURFACE_FLOATER,
681             SID_EXTRUSION_3D_COLOR,
682             SID_EXTRUSION_DEPTH,
683             SID_EXTRUSION_DIRECTION,
684             SID_EXTRUSION_PROJECTION,
685             SID_EXTRUSION_LIGHTING_DIRECTION,
686             SID_EXTRUSION_LIGHTING_INTENSITY,
687             SID_EXTRUSION_SURFACE,
688             0 };
689 
690     rBindings.Invalidate( SidArray );
691 }
692 
getExtrusionDirectionState(SdrView const * pSdrView,SfxItemSet & rSet)693 static void getExtrusionDirectionState( SdrView const * pSdrView, SfxItemSet& rSet )
694 {
695     const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
696     const size_t nCount = rMarkList.GetMarkCount();
697 
698     static constexpr OUString sExtrusion = u"Extrusion"_ustr;
699 
700     const css::uno::Any* pAny;
701 
702     double fFinalSkewAngle = -1;
703     bool bHasCustomShape = false;
704 
705     for(size_t i=0; i<nCount; ++i)
706     {
707         SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
708         if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
709         {
710             const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
711 
712             // see if this is an extruded customshape
713             if( !bHasCustomShape )
714             {
715                 const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
716                 if( pAny_ )
717                     *pAny_ >>= bHasCustomShape;
718 
719                 if( !bHasCustomShape )
720                     continue;
721             }
722 
723             bool        bParallel = true;
724             Position3D  aViewPoint( 3472, -3472, 25000 ); // MSO default
725             double      fSkewAngle = -135; // MSO default
726 
727             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"ProjectionMode"_ustr );
728             sal_Int16 nProjectionMode = sal_Int16();
729             if( pAny && ( *pAny >>= nProjectionMode ) )
730                 bParallel = static_cast<ProjectionMode>(nProjectionMode) == ProjectionMode_PARALLEL;
731 
732             if( bParallel )
733             {
734                 double      fSkew = 50.0;
735                 EnhancedCustomShapeParameterPair aSkewPropPair;
736                 pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Skew"_ustr );
737                 if( pAny && ( *pAny >>= aSkewPropPair ) )
738                 {
739                     aSkewPropPair.First.Value >>= fSkew;
740                     aSkewPropPair.Second.Value >>= fSkewAngle;
741                 }
742                 if ( fSkew == 0.0 )
743                     fSkewAngle = 0.0;
744                 else if ( fSkewAngle == 0.0 )
745                     fSkewAngle = -360.0;
746             }
747             else
748             {
749                 double      fOriginX = 0.50;
750                 double      fOriginY = -0.50;
751                 pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"ViewPoint"_ustr );
752                 if( pAny )
753                     *pAny >>= aViewPoint;
754 
755                 EnhancedCustomShapeParameterPair aOriginPropPair;
756                 pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Origin"_ustr );
757                 if( pAny && ( *pAny >>= aOriginPropPair ) )
758                 {
759                     aOriginPropPair.First.Value >>= fOriginX;
760                     aOriginPropPair.Second.Value >>= fOriginY;
761                 }
762                 fSkewAngle = -1;
763                 const double e = 0.0001;
764                 if( aViewPoint.PositionX > e )
765                 {
766                     if( aViewPoint.PositionY > e )
767                     {
768                         if( (fOriginX > e ) && ( fOriginY > e ) )
769                             fSkewAngle = 135.0;
770                     }
771                     else if( aViewPoint.PositionY < -e )
772                     {
773                         if( ( fOriginX > e ) && ( fOriginY < -e ) )
774                             fSkewAngle = -135.0;
775                     }
776                     else
777                     {
778                         if( ( fOriginX > e ) && ( fOriginY > -e ) && ( fOriginY < e ) )
779                             fSkewAngle = 180.0;
780                     }
781                 }
782                 else if( aViewPoint.PositionX < -e )
783                 {
784                     if( aViewPoint.PositionY < -e )
785                     {
786                         if( ( fOriginX < -e ) && ( fOriginY < -e ) )
787                             fSkewAngle = -45.0;
788                     }
789                     else if( aViewPoint.PositionY > e )
790                     {
791                         if( ( fOriginX < -e ) && ( fOriginY > e ) )
792                             fSkewAngle = 45.0;
793                     }
794                     else
795                     {
796                         if( ( fOriginX < e ) && ( fOriginY > -e ) && ( fOriginY < e ) )
797                             fSkewAngle = -360.0;
798                     }
799                 }
800                 else
801                 {
802                     if( aViewPoint.PositionY < -e )
803                     {
804                         if( ( fOriginX > -e ) && ( fOriginX < e ) && ( fOriginY < -e ) )
805                             fSkewAngle = -90.0;
806                     }
807                     else if( aViewPoint.PositionY > e )
808                     {
809                         if( ( fOriginX > -e ) && ( fOriginX < e ) && ( fOriginY > e ) )
810                             fSkewAngle = 90.0;
811                     }
812                     else
813                     {
814                         if( ( fOriginX > -e ) && ( fOriginX < e ) && ( fOriginY > -e ) && ( fOriginY < e ) )
815                             fSkewAngle = 0.0;
816                     }
817                 }
818             }
819 
820             if( rtl::math::approxEqual(fFinalSkewAngle, -1.0) )
821             {
822                 fFinalSkewAngle = fSkewAngle;
823             }
824             else if( !rtl::math::approxEqual(fSkewAngle, fFinalSkewAngle) )
825             {
826                 fFinalSkewAngle = -1.0;
827             }
828 
829             if( rtl::math::approxEqual(fFinalSkewAngle, -1.0) )
830                 break;
831         }
832     }
833 
834     if( bHasCustomShape )
835         rSet.Put( SfxInt32Item( SID_EXTRUSION_DIRECTION, static_cast<sal_Int32>(fFinalSkewAngle) ) );
836     else
837         rSet.DisableItem( SID_EXTRUSION_DIRECTION );
838 }
839 
getExtrusionProjectionState(SdrView const * pSdrView,SfxItemSet & rSet)840 static void getExtrusionProjectionState( SdrView const * pSdrView, SfxItemSet& rSet )
841 {
842     const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
843     const size_t nCount = rMarkList.GetMarkCount();
844 
845     static constexpr OUString sExtrusion = u"Extrusion"_ustr;
846 
847     const css::uno::Any* pAny;
848 
849     sal_Int32 nFinalProjection = -1;
850     bool bHasCustomShape = false;
851 
852     for(size_t i=0; i<nCount; ++i)
853     {
854         SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
855         if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
856         {
857             // see if this is an extruded customshape
858             if( !bHasCustomShape )
859             {
860                 const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
861                 const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
862                 if( pAny_ )
863                     *pAny_ >>= bHasCustomShape;
864 
865                 if( !bHasCustomShape )
866                     continue;
867             }
868 
869             const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
870 
871             bool    bParallel = true;
872             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"ProjectionMode"_ustr );
873             ProjectionMode eProjectionMode;
874             if( pAny && ( *pAny >>= eProjectionMode ) )
875                 bParallel = eProjectionMode == ProjectionMode_PARALLEL;
876 
877             if( nFinalProjection == -1 )
878             {
879                 nFinalProjection = bParallel ? 1 : 0;
880             }
881             else if( nFinalProjection != (bParallel ? 1 : 0) )
882             {
883                 nFinalProjection = -1;
884                 break;
885             }
886         }
887     }
888 
889     if( bHasCustomShape )
890         rSet.Put( SfxInt32Item( SID_EXTRUSION_PROJECTION, nFinalProjection ) );
891     else
892         rSet.DisableItem( SID_EXTRUSION_PROJECTION );
893 }
894 
getExtrusionSurfaceState(SdrView const * pSdrView,SfxItemSet & rSet)895 static void getExtrusionSurfaceState( SdrView const * pSdrView, SfxItemSet& rSet )
896 {
897     const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
898     const size_t nCount = rMarkList.GetMarkCount();
899 
900     static constexpr OUString sExtrusion = u"Extrusion"_ustr;
901 
902     const css::uno::Any* pAny;
903 
904     sal_Int32 nFinalSurface = -1;
905     bool bHasCustomShape = false;
906 
907     for(size_t i=0; i<nCount; ++i)
908     {
909         SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
910         if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
911         {
912             const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
913 
914             // see if this is an extruded customshape
915             if( !bHasCustomShape )
916             {
917                 const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
918                 if( pAny_ )
919                     *pAny_ >>= bHasCustomShape;
920 
921                 if( !bHasCustomShape )
922                     continue;
923             }
924 
925             sal_Int32 nSurface = 0; // wire frame
926 
927             ShadeMode eShadeMode( ShadeMode_FLAT );
928             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"ShadeMode"_ustr );
929             if( pAny )
930                 *pAny >>= eShadeMode;
931 
932             if (eShadeMode != ShadeMode_DRAFT)
933             {
934                 bool bMetal = false;
935                 pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Metal"_ustr );
936                 if( pAny )
937                     *pAny >>= bMetal;
938 
939                 if( bMetal )
940                 {
941                     nSurface = 3; // metal ODF
942                     sal_Int16 eMetalType = EnhancedCustomShapeMetalType::MetalODF;
943                     pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"MetalType"_ustr );
944                     if (pAny)
945                     {
946                         *pAny >>= eMetalType;
947                         if (eMetalType == EnhancedCustomShapeMetalType::MetalMSCompatible)
948                             nSurface = 4; // metal MS Office
949                     }
950                 }
951                 else
952                 {
953                     double fSpecularity = 0;
954                     pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Specularity"_ustr );
955                     if( pAny )
956                         *pAny >>= fSpecularity;
957 
958                     const double e = 0.0001;
959                     if( (fSpecularity > -e) && (fSpecularity < e) )
960                     {
961                         nSurface = 1; // matte
962                     }
963                     else
964                     {
965                         nSurface = 2; // plastic
966                     }
967                 }
968             }
969 
970             if( nFinalSurface == -1 )
971             {
972                 nFinalSurface = nSurface;
973             }
974             else if( nFinalSurface != nSurface )
975             {
976                 nFinalSurface = -1;
977                 break;
978             }
979         }
980     }
981 
982     if( bHasCustomShape )
983         rSet.Put( SfxInt32Item( SID_EXTRUSION_SURFACE, nFinalSurface ) );
984     else
985         rSet.DisableItem( SID_EXTRUSION_SURFACE );
986 }
987 
getExtrusionDepthState(SdrView const * pSdrView,SfxItemSet & rSet)988 static void getExtrusionDepthState( SdrView const * pSdrView, SfxItemSet& rSet )
989 {
990     const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
991     const size_t nCount = rMarkList.GetMarkCount();
992 
993     static constexpr OUString sExtrusion = u"Extrusion"_ustr;
994 
995     const css::uno::Any* pAny;
996 
997     double fFinalDepth = -1;
998     bool bHasCustomShape = false;
999 
1000     for(size_t i=0; i<nCount; ++i)
1001     {
1002         SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
1003         if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
1004         {
1005             const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
1006 
1007             // see if this is an extruded customshape
1008             if( !bHasCustomShape )
1009             {
1010                 const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
1011                 if( pAny_ )
1012                     *pAny_ >>= bHasCustomShape;
1013 
1014                 if( !bHasCustomShape )
1015                     continue;
1016             }
1017 
1018             double fDepth = 1270.0; // =36pt ODF default
1019             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Depth"_ustr );
1020             if( pAny )
1021             {
1022                 EnhancedCustomShapeParameterPair aDepthPropPair;
1023                 if ( *pAny >>= aDepthPropPair )
1024                     aDepthPropPair.First.Value >>= fDepth;
1025             }
1026 
1027             if( fFinalDepth == -1 )
1028             {
1029                 fFinalDepth = fDepth;
1030             }
1031             else if( !rtl::math::approxEqual(fFinalDepth, fDepth) )
1032             {
1033                 fFinalDepth = -1;
1034                 break;
1035             }
1036         }
1037     }
1038 
1039 
1040     FieldUnit eUnit = pSdrView->GetModel().GetUIUnit();
1041     rSet.Put( SfxUInt16Item( SID_ATTR_METRIC, static_cast<sal_uInt16>(eUnit) ) );
1042 
1043     if( bHasCustomShape )
1044         rSet.Put( SvxDoubleItem( fFinalDepth, SID_EXTRUSION_DEPTH ) );
1045     else
1046         rSet.DisableItem( SID_EXTRUSION_DEPTH );
1047 }
1048 
compare_direction(const Direction3D & d1,const Direction3D & d2)1049 static bool compare_direction( const Direction3D& d1, const Direction3D& d2 )
1050 {
1051     if( ((d1.DirectionX < 0) && (d2.DirectionX < 0)) || ((d1.DirectionX == 0) && (d2.DirectionX == 0)) || ((d1.DirectionX > 0) && (d2.DirectionX > 0)) )
1052     {
1053         if( ((d1.DirectionY < 0) && (d2.DirectionY < 0)) || ((d1.DirectionY == 0) && (d2.DirectionY == 0)) || ((d1.DirectionY > 0) && (d2.DirectionY > 0)) )
1054         {
1055             if( ((d1.DirectionZ < 0) && (d2.DirectionZ < 0)) || ((d1.DirectionZ == 0) && (d2.DirectionZ == 0)) || ((d1.DirectionZ > 0) && (d2.DirectionZ > 0)) )
1056             {
1057                 return true;
1058             }
1059         }
1060     }
1061 
1062     return false;
1063 }
1064 
getExtrusionLightingDirectionState(SdrView const * pSdrView,SfxItemSet & rSet)1065 static void getExtrusionLightingDirectionState( SdrView const * pSdrView, SfxItemSet& rSet )
1066 {
1067     const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
1068     const size_t nCount = rMarkList.GetMarkCount();
1069 
1070     static constexpr OUString sExtrusion = u"Extrusion"_ustr;
1071 
1072     const Direction3D * pLighting1Defaults;
1073     const Direction3D * pLighting2Defaults;
1074 
1075     getLightingDirectionDefaults( &pLighting1Defaults, &pLighting2Defaults );
1076 
1077     const css::uno::Any* pAny;
1078 
1079     int nFinalDirection = -1;
1080     bool bHasCustomShape = false;
1081 
1082     for(size_t i=0; i<nCount; ++i)
1083     {
1084         SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
1085         if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
1086         {
1087             const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
1088 
1089             // see if this is an extruded customshape
1090             if( !bHasCustomShape )
1091             {
1092                 const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
1093                 if( pAny_ )
1094                     *pAny_ >>= bHasCustomShape;
1095 
1096                 if( !bHasCustomShape )
1097                     continue;
1098             }
1099 
1100             Direction3D aFirstLightDirection( 50000, 0, 10000 );
1101             Direction3D aSecondLightDirection( -50000, 0, 10000 );
1102 
1103             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"FirstLightDirection"_ustr );
1104             if( pAny )
1105                 *pAny >>= aFirstLightDirection;
1106 
1107             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"SecondLightDirection"_ustr );
1108             if( pAny )
1109                 *pAny >>= aSecondLightDirection;
1110 
1111             int nDirection = -1;
1112 
1113             int j;
1114             for( j = 0; j < 9; j++ )
1115             {
1116                 if( compare_direction( aFirstLightDirection, pLighting1Defaults[j] ) &&
1117                     compare_direction( aSecondLightDirection, pLighting2Defaults[j] ))
1118                 {
1119                     nDirection = j;
1120                     break;
1121                 }
1122             }
1123 
1124             if( nFinalDirection == -1 )
1125             {
1126                 nFinalDirection = nDirection;
1127             }
1128             else if( nDirection != nFinalDirection )
1129             {
1130                 nFinalDirection = -1;
1131             }
1132 
1133             if( nFinalDirection == -1 )
1134                 break;
1135         }
1136     }
1137 
1138     if( bHasCustomShape )
1139         rSet.Put( SfxInt32Item( SID_EXTRUSION_LIGHTING_DIRECTION, static_cast<sal_Int32>(nFinalDirection) ) );
1140     else
1141         rSet.DisableItem( SID_EXTRUSION_LIGHTING_DIRECTION );
1142 }
1143 
getExtrusionLightingIntensityState(SdrView const * pSdrView,SfxItemSet & rSet)1144 static void getExtrusionLightingIntensityState( SdrView const * pSdrView, SfxItemSet& rSet )
1145 {
1146     const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
1147     const size_t nCount = rMarkList.GetMarkCount();
1148 
1149     static constexpr OUString sExtrusion = u"Extrusion"_ustr;
1150 
1151     const css::uno::Any* pAny;
1152 
1153     int nFinalLevel = -1;
1154     bool bHasCustomShape = false;
1155 
1156     for(size_t i=0; i<nCount; ++i)
1157     {
1158         SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
1159         if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
1160         {
1161             const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
1162 
1163             // see if this is an extruded customshape
1164             if( !bHasCustomShape )
1165             {
1166                 const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
1167                 if( pAny_ )
1168                     *pAny_ >>= bHasCustomShape;
1169 
1170                 if( !bHasCustomShape )
1171                     continue;
1172             }
1173 
1174             double fBrightness = 22178.0 / 655.36;
1175             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Brightness"_ustr );
1176             if( pAny )
1177                 *pAny >>= fBrightness;
1178 
1179             int nLevel;
1180             if( fBrightness >= 30.0 )
1181             {
1182                 nLevel = 0; // Bright
1183             }
1184             else if( fBrightness >= 10.0 )
1185             {
1186                 nLevel = 1; // Normal;
1187             }
1188             else
1189             {
1190                 nLevel = 2; // Dim
1191             }
1192 
1193             if( nFinalLevel == -1 )
1194             {
1195                 nFinalLevel = nLevel;
1196             }
1197             else if( nFinalLevel != nLevel )
1198             {
1199                 nFinalLevel = -1;
1200                 break;
1201             }
1202         }
1203     }
1204 
1205     if( bHasCustomShape )
1206         rSet.Put( SfxInt32Item( SID_EXTRUSION_LIGHTING_INTENSITY, nFinalLevel ) );
1207     else
1208         rSet.DisableItem( SID_EXTRUSION_LIGHTING_INTENSITY );
1209 }
1210 
getExtrusionColorState(SdrView const * pSdrView,SfxItemSet & rSet)1211 static void getExtrusionColorState( SdrView const * pSdrView, SfxItemSet& rSet )
1212 {
1213     const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
1214     const size_t nCount = rMarkList.GetMarkCount();
1215 
1216     static constexpr OUString sExtrusion = u"Extrusion"_ustr;
1217 
1218     const css::uno::Any* pAny;
1219 
1220     bool bInit = false;
1221     bool bAmbigius = false;
1222     Color aFinalColor;
1223     bool bHasCustomShape = false;
1224 
1225     for(size_t i=0; i<nCount; ++i)
1226     {
1227         SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
1228         if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
1229         {
1230             const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
1231 
1232             // see if this is an extruded customshape
1233             if( !bHasCustomShape )
1234             {
1235                 const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
1236                 if( pAny_ )
1237                     *pAny_ >>= bHasCustomShape;
1238 
1239                 if( !bHasCustomShape )
1240                     continue;
1241             }
1242 
1243             Color aColor;
1244 
1245             bool bUseColor = false;
1246             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Color"_ustr );
1247             if( pAny )
1248                 *pAny >>= bUseColor;
1249 
1250             if( bUseColor )
1251             {
1252                 const XSecondaryFillColorItem& rItem = pObj->GetMergedItem( XATTR_SECONDARYFILLCOLOR );
1253                 aColor = rItem.GetColorValue();
1254             }
1255             else
1256             {
1257                 aColor = COL_AUTO;
1258             }
1259 
1260             if( !bInit )
1261             {
1262                 aFinalColor = aColor;
1263                 bInit = true;
1264             }
1265             else if( aFinalColor != aColor )
1266             {
1267                 bAmbigius = true;
1268                 break;
1269             }
1270         }
1271     }
1272 
1273     if( bAmbigius )
1274         aFinalColor = COL_AUTO;
1275 
1276     if( bHasCustomShape )
1277         rSet.Put( SvxColorItem( aFinalColor, SID_EXTRUSION_3D_COLOR ) );
1278     else
1279         rSet.DisableItem( SID_EXTRUSION_3D_COLOR );
1280 }
1281 
1282 namespace svx {
checkForSelectedCustomShapes(SdrView const * pSdrView,bool bOnlyExtruded)1283 bool checkForSelectedCustomShapes( SdrView const * pSdrView, bool bOnlyExtruded )
1284 {
1285     static constexpr OUString sExtrusion = u"Extrusion"_ustr;
1286 
1287     const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
1288     const size_t nCount = rMarkList.GetMarkCount();
1289     bool bFound = false;
1290 
1291     for(size_t i=0;(i<nCount) && !bFound ; ++i)
1292     {
1293         SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
1294         if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
1295         {
1296             if( bOnlyExtruded )
1297             {
1298                 const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
1299                 const Any* pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
1300                 if( pAny )
1301                     *pAny >>= bFound;
1302             }
1303             else
1304             {
1305                 bFound = true;
1306             }
1307         }
1308     }
1309 
1310     return bFound;
1311 }
1312 }
1313 
getState(SdrView const * pSdrView,SfxItemSet & rSet)1314 void ExtrusionBar::getState( SdrView const * pSdrView, SfxItemSet& rSet )
1315 {
1316     getExtrusionDirectionState( pSdrView, rSet );
1317     getExtrusionProjectionState( pSdrView, rSet );
1318 
1319     const bool bOnlyExtrudedCustomShapes(checkForSelectedCustomShapes( pSdrView, true ));
1320 
1321     if (! bOnlyExtrudedCustomShapes)
1322     {
1323         rSet.DisableItem( SID_EXTRUSION_TILT_DOWN );
1324         rSet.DisableItem( SID_EXTRUSION_TILT_DOWN );
1325         rSet.DisableItem( SID_EXTRUSION_TILT_UP );
1326         rSet.DisableItem( SID_EXTRUSION_TILT_LEFT );
1327         rSet.DisableItem( SID_EXTRUSION_TILT_RIGHT );
1328         rSet.DisableItem( SID_EXTRUSION_3D_COLOR );
1329         rSet.DisableItem( SID_EXTRUSION_DEPTH_FLOATER );
1330         rSet.DisableItem( SID_EXTRUSION_DIRECTION_FLOATER );
1331         rSet.DisableItem( SID_EXTRUSION_LIGHTING_FLOATER );
1332         rSet.DisableItem( SID_EXTRUSION_SURFACE_FLOATER );
1333     }
1334 
1335     if( !checkForSelectedCustomShapes( pSdrView, false ) )
1336         rSet.DisableItem( SID_EXTRUSION_TOGGLE );
1337 
1338     getExtrusionDepthState( pSdrView, rSet );
1339     getExtrusionSurfaceState( pSdrView, rSet );
1340     getExtrusionLightingIntensityState( pSdrView, rSet );
1341     getExtrusionLightingDirectionState( pSdrView, rSet );
1342     getExtrusionColorState( pSdrView, rSet );
1343 }
1344 
1345 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1346