/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
 
 
#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
#include <com/sun/star/drawing/ShadeMode.hpp>
#include <com/sun/star/drawing/Position3D.hpp>
#include <com/sun/star/drawing/Direction3D.hpp>
#include <com/sun/star/drawing/ProjectionMode.hpp>
#include <svx/svxids.hrc>
#include <svx/svdundo.hxx>
#include <sfx2/request.hxx>
#include <sfx2/objface.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/bindings.hxx>
#include <svx/xsflclit.hxx>
#include <svx/dialmgr.hxx>
#include <svx/svdoashp.hxx>
#include <svx/strings.hrc>
#include <svx/svdview.hxx>
#include <editeng/colritem.hxx>
#include <svx/chrtitem.hxx>
#include <svx/sdasitm.hxx>
#include <svl/intitem.hxx>
#include <rtl/math.hxx>
#include <basegfx/numeric/ftools.hxx>
 
#include <svx/extrusionbar.hxx>
#include <extrusiondepthdialog.hxx>
 
using namespace ::svx;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::uno;
 
// Declare the default interface. (The slotmap must not be empty, so
// we enter something which never occurs here (hopefully).)
static SfxSlot aExtrusionBarSlots_Impl[] =
{
    { 0, SfxGroupId::NONE, SfxSlotMode::NONE, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, 0, SfxDisableFlags::NONE, u""_ustr }
};
 
SFX_IMPL_INTERFACE(ExtrusionBar, SfxShell)
 
void ExtrusionBar::InitInterface_Impl()
{
    GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Invisible, ToolbarId::Svx_Extrusion_Bar);
}
 
 
ExtrusionBar::ExtrusionBar(SfxViewShell* pViewShell )
: SfxShell(pViewShell)
{
    DBG_ASSERT( pViewShell, "svx::ExtrusionBar::ExtrusionBar(), I need a viewshell!" );
    if( pViewShell )
        SetPool(&pViewShell->GetPool());
 
    SetName(SvxResId(RID_SVX_EXTRUSION_BAR));
}
 
ExtrusionBar::~ExtrusionBar()
{
    SetRepeatTarget(nullptr);
}
 
static void getLightingDirectionDefaults( const Direction3D **pLighting1Defaults, const Direction3D **pLighting2Defaults )
{
 
    static const Direction3D aLighting1Defaults[9] =
    {
        Direction3D( -50000, -50000, 10000 ),
        Direction3D( 0, -50000, 10000 ),
        Direction3D( 50000, -50000, 10000 ),
        Direction3D( -50000, 0, 10000 ),
        Direction3D( 0, 0, 10000 ),
        Direction3D( 50000, 0, 10000 ),
        Direction3D( -50000, 50000, 10000 ),
        Direction3D( 0, 50000, 10000 ),
        Direction3D( 50000, 50000, 10000 )
    };
 
    static const Direction3D aLighting2Defaults[9] =
    {
        Direction3D( 50000,0, 10000 ),
        Direction3D( 0, 50000, 10000 ),
        Direction3D( -50000, 0, 10000 ),
        Direction3D( 50000, 0, 10000 ),
        Direction3D( 0, 0, 10000 ),
        Direction3D( -50000, 0, 10000 ),
        Direction3D( 50000, 0, 10000 ),
        Direction3D( 0, -50000, 10000 ),
        Direction3D( -50000, 0, 10000 )
    };
 
    *pLighting1Defaults = aLighting1Defaults;
    *pLighting2Defaults = aLighting2Defaults;
};
 
static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& rGeometryItem, SdrObject* pObj )
{
    static constexpr OUString sExtrusion = u"Extrusion"_ustr;
    static constexpr OUString sRotateAngle = u"RotateAngle"_ustr;
 
    sal_uInt16 nSID = rReq.GetSlot();
    switch( nSID )
    {
    case SID_EXTRUSION_TOGGLE:
    {
        bool bOn(false);
        css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
        if ( pAny )
        {
            (*pAny) >>= bOn;
            bOn = !bOn;
            css::beans::PropertyValue aPropValue;
            aPropValue.Name = sExtrusion;
            aPropValue.Value <<= bOn;
            rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
        }
        else
        {
            css::beans::PropertyValue aPropValue;
            aPropValue.Name = sExtrusion;
            aPropValue.Value <<= true;
            rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
            bOn = true;
        }
 
        // draw:extrusion-diffusion has default 0% and c3DDiffuseAmt has default 100%. We set property
        // "Diffusion" with value 100% here if it does not exist already. This forces, that the
        // property is written to file in case an extrusion is newly created, and users of old
        // documents, which usually do not have this property, can force the value to 100% by toggling
        // the extrusion off and on.
        if (bOn)
        {
            pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Diffusion"_ustr);
            if (!pAny)
            {
                css::beans::PropertyValue aPropValue;
                aPropValue.Name = u"Diffusion"_ustr;
                aPropValue.Value <<= 100.0;
                rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
            }
        }
    }
    break;
 
    case SID_EXTRUSION_TILT_DOWN:
    case SID_EXTRUSION_TILT_UP:
    case SID_EXTRUSION_TILT_LEFT:
    case SID_EXTRUSION_TILT_RIGHT:
    {
        bool bHorizontal = ( nSID == SID_EXTRUSION_TILT_DOWN ) || ( nSID == SID_EXTRUSION_TILT_UP );
        sal_Int32 nDiff = ( nSID == SID_EXTRUSION_TILT_LEFT ) || ( nSID == SID_EXTRUSION_TILT_UP ) ? 5 : -5;
        EnhancedCustomShapeParameterPair aRotateAnglePropPair;
        double fX = 0.0;
        double fY = 0.0;
        aRotateAnglePropPair.First.Value <<= fX;
        aRotateAnglePropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
        aRotateAnglePropPair.Second.Value <<= fY;
        aRotateAnglePropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
        css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, sRotateAngle );
        if( pAny && ( *pAny >>= aRotateAnglePropPair ) )
        {
            aRotateAnglePropPair.First.Value >>= fX;
            aRotateAnglePropPair.Second.Value >>= fY;
        }
        if ( bHorizontal )
            fX += nDiff;
        else
            fY += nDiff;
        aRotateAnglePropPair.First.Value <<= fX;
        aRotateAnglePropPair.Second.Value <<= fY;
        css::beans::PropertyValue aPropValue;
        aPropValue.Name = sRotateAngle;
        aPropValue.Value <<= aRotateAnglePropPair;
        rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
    }
    break;
 
    case SID_EXTRUSION_DIRECTION:
    {
        const SfxInt32Item* pExtrusionItem = nullptr;
        if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_DIRECTION, true, &pExtrusionItem ) == SfxItemState::SET )
        {
            sal_Int32 nSkew = pExtrusionItem->GetValue();
 
            Position3D  aViewPoint( 3472, -3472, 25000 );
            double      fOriginX = 0.50;
            double      fOriginY = -0.50;
            double      fSkewAngle = nSkew;
            double      fSkew = 50.0;
 
            switch( nSkew )
            {
            case 135:
                aViewPoint.PositionY = 3472;
                fOriginY = 0.50;
                break;
            case 90:
                aViewPoint.PositionX = 0;
                aViewPoint.PositionY = 3472;
                fOriginX = 0;
                fOriginY = 0.50;
                break;
            case 45:
                aViewPoint.PositionX = -3472;
                aViewPoint.PositionY = 3472;
                fOriginX = -0.50;
                fOriginY = 0.50;
                break;
            case 180:
                aViewPoint.PositionY = 0;
                fOriginY = 0;
                break;
            case 0:
                aViewPoint.PositionX = 0;
                aViewPoint.PositionY = 0;
                fOriginX = 0;
                fOriginY = 0;
                fSkew = 0.0;
                break;
            case -360:
                aViewPoint.PositionX = -3472;
                aViewPoint.PositionY = 0;
                fOriginX = -0.50;
                fOriginY = 0;
                break;
            case -90:
                aViewPoint.PositionX = 0;
                fOriginX = 0;
                break;
            case -45:
                aViewPoint.PositionX = -3472;
                fOriginX = -0.50;
                break;
            }
 
            css::beans::PropertyValue aPropValue;
 
            aPropValue.Name = "ViewPoint";
            aPropValue.Value <<= aViewPoint;
            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
 
 
            EnhancedCustomShapeParameterPair aOriginPropPair;
            aOriginPropPair.First.Value <<= fOriginX;
            aOriginPropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
            aOriginPropPair.Second.Value <<= fOriginY;
            aOriginPropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
            aPropValue.Name = "Origin";
            aPropValue.Value <<= aOriginPropPair;
            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
 
            EnhancedCustomShapeParameterPair aSkewPropPair;
            aSkewPropPair.First.Value <<= fSkew;
            aSkewPropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
            aSkewPropPair.Second.Value <<= fSkewAngle;
            aSkewPropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
            aPropValue.Name = "Skew";
            aPropValue.Value <<= aSkewPropPair;
            rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
        }
    }
    break;
    case SID_EXTRUSION_PROJECTION:
    {
        const SfxInt32Item* pExtrusionItem = nullptr;
        if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_PROJECTION, true, &pExtrusionItem ) == SfxItemState::SET )
        {
            sal_Int32 nProjection = pExtrusionItem->GetValue();
            ProjectionMode eProjectionMode = nProjection == 1 ? ProjectionMode_PARALLEL : ProjectionMode_PERSPECTIVE;
            css::beans::PropertyValue aPropValue;
            aPropValue.Name = "ProjectionMode";
            aPropValue.Value <<= eProjectionMode;
            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
        }
    }
    break;
    case SID_EXTRUSION_DEPTH:
    {
        const SvxDoubleItem* pExtrusionItem = nullptr;
        if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_DEPTH, true, &pExtrusionItem ) == SfxItemState::SET)
        {
            double fDepth = pExtrusionItem->GetValue();
            EnhancedCustomShapeParameterPair aDepthPropPair;
            aDepthPropPair.First.Value <<= fDepth;
            aDepthPropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
            aDepthPropPair.Second.Value <<= 0.0; // fraction
            aDepthPropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
 
            css::beans::PropertyValue aPropValue;
            aPropValue.Name = "Depth";
            aPropValue.Value <<= aDepthPropPair;
            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
        }
    }
    break;
    case SID_EXTRUSION_3D_COLOR:
    {
        if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_3D_COLOR ) == SfxItemState::SET)
        {
            Color aColor( static_cast<const SvxColorItem&>(rReq.GetArgs()->Get(SID_EXTRUSION_3D_COLOR)).GetValue() );
 
            const bool bAuto = aColor == COL_AUTO;
 
            css::beans::PropertyValue aPropValue;
            aPropValue.Name = "Color";
            aPropValue.Value <<= !bAuto;
            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
 
            if( bAuto )
            {
                pObj->ClearMergedItem( XATTR_SECONDARYFILLCOLOR );
            }
            else
            {
                pObj->SetMergedItem( XSecondaryFillColorItem( u""_ustr, aColor ) );
            }
            pObj->BroadcastObjectChange();
        }
    }
    break;
    case SID_EXTRUSION_SURFACE:
    {
        const SfxInt32Item* pExtrusionItem = nullptr;
        if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_SURFACE, true, &pExtrusionItem ) == SfxItemState::SET)
        {
            sal_Int32 nSurface = pExtrusionItem->GetValue();
 
            // Set ShadeMode only when changing from or to wireframe, otherwise keep existing value.
            ShadeMode eOldShadeMode(ShadeMode_FLAT);
            css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"ShadeMode"_ustr);
            if (pAny)
                *pAny >>= eOldShadeMode;
            ShadeMode eShadeMode(eOldShadeMode);
            switch (nSurface)
            {
                case 0: // wireframe
                    eShadeMode = ShadeMode_DRAFT;
                    break;
                case 1: // matte
                case 2: // plastic
                case 3: // metal ODF
                case 4: // metal MS Office
                    if (eOldShadeMode == ShadeMode_DRAFT)
                        eShadeMode = ShadeMode_FLAT; // ODF default
                    break;
            }
 
            // ODF has no dedicated property for 'surface'. MS Office binary format uses attribute
            // c3DSpecularAmt to distinguish between 'matte' (=0) and 'plastic'.
            // We do the same.
            double fOldSpecularity = 0.0;
            pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Specularity"_ustr);
            if (pAny)
                *pAny >>= fOldSpecularity;
            double fSpecularity = fOldSpecularity;
            switch( nSurface )
            {
            case 0: // wireframe
                break;
            case 1: // matte
                fSpecularity = 0.0;
                break;
            case 2: // plastic
            case 3: // metal ODF
            case 4: // metal MS Office
                if (basegfx::fTools::equalZero(fOldSpecularity, 0.0001))
                    // MS Office uses 80000/65536. That is currently not allowed in ODF.
                    // But the ODF error will be caught in xmloff.
                    fSpecularity = 80000.0 / 655.36; // interpreted as %
                break;
            }
 
            // MS Office binary format uses attribute c3DDiffuseAmt with value =43712 (Fixed 16.16) in
            // addition to the 'metal' flag. For other surface kinds default = 65536 is used.
            // We toggle between 100 and 43712.0 / 655.36 here, to get better ODF -> MSO binary.
            // We keep other values, those might be set outside regular UI, e.g by macro.
            double fOldDiffusion = 100.0;
            pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Diffusion"_ustr);
            if (pAny)
                *pAny >>= fOldDiffusion;
            double fDiffusion = fOldDiffusion;
            if (nSurface == 4)
            {
                if (fOldDiffusion == 100.0)
                    fDiffusion = 43712.0 / 655.36; // interpreted as %
            }
            else
            {
                if (basegfx::fTools::equalZero(fOldDiffusion - 43712.0 / 655.36, 0.0001))
                    fDiffusion = 100.0;
            }
 
            css::beans::PropertyValue aPropValue;
            aPropValue.Name = "ShadeMode";
            aPropValue.Value <<= eShadeMode;
            rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
 
            aPropValue.Name = "Metal";
            aPropValue.Value <<= nSurface == 3 || nSurface == 4;
            rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
 
            if (nSurface == 3 || nSurface == 4)
            {
                aPropValue.Name = "MetalType";
                aPropValue.Value <<= nSurface == 4
                                         ? EnhancedCustomShapeMetalType::MetalMSCompatible
                                         : EnhancedCustomShapeMetalType::MetalODF;
                rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
            }
 
            if (!basegfx::fTools::equalZero(fOldSpecularity - fSpecularity, 0.0001))
            {
                aPropValue.Name = "Specularity";
                aPropValue.Value <<= fSpecularity;
                rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
            }
 
            if (!basegfx::fTools::equalZero(fOldDiffusion - fDiffusion, 0.0001))
            {
                aPropValue.Name = "Diffusion";
                aPropValue.Value <<= fDiffusion;
                rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
            }
        }
    }
    break;
    case SID_EXTRUSION_LIGHTING_INTENSITY:
    {
        const SfxInt32Item* pLightItem = nullptr;
        if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_LIGHTING_INTENSITY, true, &pLightItem ) == SfxItemState::SET)
        {
            sal_Int32 nLevel = pLightItem->GetValue();
 
            double fBrightness; // c3DAmbientIntensity in MS Office
            double fLevel1; // c3DKeyIntensity in MS Office
            double fLevel2; // c3DFillIntensity in MS Office
 
            // ToDo: "bright" values are different from MS Office. Should they be kept?
            switch( nLevel )
            {
            case 0: // bright
                fBrightness = 33.0; // ODF default.
                fLevel1 = 66.0; // ODF default
                fLevel2 = 66.0; // ODF default
                break;
            case 1: // normal
                fBrightness = 15.0;
                fLevel1 = 67.0;
                fLevel2 = 37.0;
                break;
            case 2: // dim
                fBrightness = 6.0;
                fLevel1 = 79.0;
                fLevel2 = 21.0;
                break;
            }
 
            css::beans::PropertyValue aPropValue;
            aPropValue.Name = "Brightness";
            aPropValue.Value <<= fBrightness;
            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
 
            aPropValue.Name = "FirstLightLevel";
            aPropValue.Value <<= fLevel1;
            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
 
            aPropValue.Name = "SecondLightLevel";
            aPropValue.Value <<= fLevel2;
            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
 
            // If a user sets light preset 'Dim' in MS Office, MS Office sets second light to harsh.
            // In other cases it is soft.
            aPropValue.Name = "SecondLightHarsh";
            aPropValue.Value <<= nLevel == 2;
            rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
        }
    }
    break;
    case SID_EXTRUSION_LIGHTING_DIRECTION:
    {
        const SfxInt32Item* pLightDirectionItem = nullptr;
        if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_LIGHTING_DIRECTION, true, &pLightDirectionItem ) == SfxItemState::SET)
        {
            sal_Int32 nDirection = pLightDirectionItem->GetValue();
 
            if((nDirection >= 0) && (nDirection < 9))
            {
                const Direction3D * pLighting1Defaults;
                const Direction3D * pLighting2Defaults;
 
                getLightingDirectionDefaults( &pLighting1Defaults, &pLighting2Defaults );
 
                css::beans::PropertyValue aPropValue;
                aPropValue.Name = "FirstLightDirection";
                aPropValue.Value <<= pLighting1Defaults[nDirection];
                rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
 
                aPropValue.Name = "SecondLightDirection";
                aPropValue.Value <<= pLighting2Defaults[nDirection];
                rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
            }
        }
    }
    break;
 
    }
}
 
void ExtrusionBar::execute( SdrView* pSdrView, SfxRequest const & rReq, SfxBindings& rBindings )
{
    sal_uInt16 nSID = rReq.GetSlot();
    TranslateId pStrResId;
 
    const bool bUndo = pSdrView && pSdrView->IsUndoEnabled();
 
    switch( nSID )
    {
        case SID_EXTRUSION_TOGGLE:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ON_OFF;
            [[fallthrough]];
        }
        case SID_EXTRUSION_TILT_DOWN:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_DOWN;
            [[fallthrough]];
        }
        case SID_EXTRUSION_TILT_UP:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_UP;
            [[fallthrough]];
        }
        case SID_EXTRUSION_TILT_LEFT:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_LEFT;
            [[fallthrough]];
        }
        case SID_EXTRUSION_TILT_RIGHT:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_RIGHT;
            [[fallthrough]];
        }
        case SID_EXTRUSION_DIRECTION:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ORIENTATION;
            [[fallthrough]];
        }
        case SID_EXTRUSION_PROJECTION:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_PROJECTION;
            [[fallthrough]];
        }
        case SID_EXTRUSION_DEPTH:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_DEPTH;
            [[fallthrough]];
        }
        case SID_EXTRUSION_3D_COLOR:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_COLOR;
            [[fallthrough]];
        }
        case SID_EXTRUSION_SURFACE:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_SURFACE;
            [[fallthrough]];
        }
        case SID_EXTRUSION_LIGHTING_INTENSITY:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_BRIGHTNESS;
            [[fallthrough]];
        }
        case SID_EXTRUSION_LIGHTING_DIRECTION:
        {
            if ( !pStrResId )
                pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_LIGHTING;
 
            if (pSdrView)
            {
                const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
                const size_t nCount = rMarkList.GetMarkCount();
 
                for(size_t i=0; i<nCount; ++i)
                {
                    SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
                    if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
                    {
                        if( bUndo )
                        {
                            OUString aStr( SvxResId( pStrResId ) );
                            pSdrView->BegUndo( aStr );
                            pSdrView->AddUndo( pSdrView->GetModel().GetSdrUndoFactory().CreateUndoAttrObject( *pObj ) );
                        }
                        SdrCustomShapeGeometryItem aGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
                        impl_execute( rReq, aGeometryItem, pObj );
                        pObj->SetMergedItem( aGeometryItem );
                        pObj->BroadcastObjectChange();
                        if( bUndo )
                            pSdrView->EndUndo();
 
                        // simulate a context change:
                        // force SelectionHasChanged() being called
                        // so that extrusion bar will be visible/hidden
                        pSdrView->MarkListHasChanged();
                    }
                }
            }
        }
        break;
 
        case SID_EXTRUSION_DEPTH_DIALOG:
        {
            const SvxDoubleItem* pDepthItem = nullptr;
            const SfxUInt16Item* pMetricItem = nullptr;
            if( rReq.GetArgs() &&
                (rReq.GetArgs()->GetItemState( SID_EXTRUSION_DEPTH, true, &pDepthItem ) == SfxItemState::SET) &&
                (rReq.GetArgs()->GetItemState( SID_ATTR_METRIC, true, &pMetricItem ) == SfxItemState::SET))
            {
                double fDepth = pDepthItem->GetValue();
                FieldUnit eUnit = static_cast<FieldUnit>(pMetricItem->GetValue());
 
                ExtrusionDepthDialog aDlg(rReq.GetFrameWeld(), fDepth, eUnit);
                sal_uInt16 nRet = aDlg.run();
                if (nRet == RET_OK)
                {
                    fDepth = aDlg.getDepth();
 
                    SvxDoubleItem aItem( fDepth, SID_EXTRUSION_DEPTH );
                    SfxPoolItem* aItems[] = { &aItem, nullptr };
                    rBindings.Execute( SID_EXTRUSION_DEPTH, const_cast<const SfxPoolItem**>(aItems) );
                }
            }
            break;
        }
    }
 
    if( nSID != SID_EXTRUSION_TOGGLE )
        return;
 
    static const sal_uInt16 SidArray[] = {
            SID_EXTRUSION_TILT_DOWN,
            SID_EXTRUSION_TILT_UP,
            SID_EXTRUSION_TILT_LEFT,
            SID_EXTRUSION_TILT_RIGHT,
            SID_EXTRUSION_DEPTH_FLOATER,
            SID_EXTRUSION_DIRECTION_FLOATER,
            SID_EXTRUSION_LIGHTING_FLOATER,
            SID_EXTRUSION_SURFACE_FLOATER,
            SID_EXTRUSION_3D_COLOR,
            SID_EXTRUSION_DEPTH,
            SID_EXTRUSION_DIRECTION,
            SID_EXTRUSION_PROJECTION,
            SID_EXTRUSION_LIGHTING_DIRECTION,
            SID_EXTRUSION_LIGHTING_INTENSITY,
            SID_EXTRUSION_SURFACE,
            0 };
 
    rBindings.Invalidate( SidArray );
}
 
static void getExtrusionDirectionState( SdrView const * pSdrView, SfxItemSet& rSet )
{
    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
    const size_t nCount = rMarkList.GetMarkCount();
 
    static constexpr OUString sExtrusion = u"Extrusion"_ustr;
 
    const css::uno::Any* pAny;
 
    double fFinalSkewAngle = -1;
    bool bHasCustomShape = false;
 
    for(size_t i=0; i<nCount; ++i)
    {
        SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
        if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
        {
            const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
 
            // see if this is an extruded customshape
            if( !bHasCustomShape )
            {
                const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
                if( pAny_ )
                    *pAny_ >>= bHasCustomShape;
 
                if( !bHasCustomShape )
                    continue;
            }
 
            bool        bParallel = true;
            Position3D  aViewPoint( 3472, -3472, 25000 ); // MSO default
            double      fSkewAngle = -135; // MSO default
 
            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"ProjectionMode"_ustr );
            sal_Int16 nProjectionMode = sal_Int16();
            if( pAny && ( *pAny >>= nProjectionMode ) )
                bParallel = static_cast<ProjectionMode>(nProjectionMode) == ProjectionMode_PARALLEL;
 
            if( bParallel )
            {
                double      fSkew = 50.0;
                EnhancedCustomShapeParameterPair aSkewPropPair;
                pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Skew"_ustr );
                if( pAny && ( *pAny >>= aSkewPropPair ) )
                {
                    aSkewPropPair.First.Value >>= fSkew;
                    aSkewPropPair.Second.Value >>= fSkewAngle;
                }
                if ( fSkew == 0.0 )
                    fSkewAngle = 0.0;
                else if ( fSkewAngle == 0.0 )
                    fSkewAngle = -360.0;
            }
            else
            {
                double      fOriginX = 0.50;
                double      fOriginY = -0.50;
                pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"ViewPoint"_ustr );
                if( pAny )
                    *pAny >>= aViewPoint;
 
                EnhancedCustomShapeParameterPair aOriginPropPair;
                pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Origin"_ustr );
                if( pAny && ( *pAny >>= aOriginPropPair ) )
                {
                    aOriginPropPair.First.Value >>= fOriginX;
                    aOriginPropPair.Second.Value >>= fOriginY;
                }
                fSkewAngle = -1;
                const double e = 0.0001;
                if( aViewPoint.PositionX > e )
                {
                    if( aViewPoint.PositionY > e )
                    {
                        if( (fOriginX > e ) && ( fOriginY > e ) )
                            fSkewAngle = 135.0;
                    }
                    else if( aViewPoint.PositionY < -e )
                    {
                        if( ( fOriginX > e ) && ( fOriginY < -e ) )
                            fSkewAngle = -135.0;
                    }
                    else
                    {
                        if( ( fOriginX > e ) && ( fOriginY > -e ) && ( fOriginY < e ) )
                            fSkewAngle = 180.0;
                    }
                }
                else if( aViewPoint.PositionX < -e )
                {
                    if( aViewPoint.PositionY < -e )
                    {
                        if( ( fOriginX < -e ) && ( fOriginY < -e ) )
                            fSkewAngle = -45.0;
                    }
                    else if( aViewPoint.PositionY > e )
                    {
                        if( ( fOriginX < -e ) && ( fOriginY > e ) )
                            fSkewAngle = 45.0;
                    }
                    else
                    {
                        if( ( fOriginX < e ) && ( fOriginY > -e ) && ( fOriginY < e ) )
                            fSkewAngle = -360.0;
                    }
                }
                else
                {
                    if( aViewPoint.PositionY < -e )
                    {
                        if( ( fOriginX > -e ) && ( fOriginX < e ) && ( fOriginY < -e ) )
                            fSkewAngle = -90.0;
                    }
                    else if( aViewPoint.PositionY > e )
                    {
                        if( ( fOriginX > -e ) && ( fOriginX < e ) && ( fOriginY > e ) )
                            fSkewAngle = 90.0;
                    }
                    else
                    {
                        if( ( fOriginX > -e ) && ( fOriginX < e ) && ( fOriginY > -e ) && ( fOriginY < e ) )
                            fSkewAngle = 0.0;
                    }
                }
            }
 
            if( rtl::math::approxEqual(fFinalSkewAngle, -1.0) )
            {
                fFinalSkewAngle = fSkewAngle;
            }
            else if( !rtl::math::approxEqual(fSkewAngle, fFinalSkewAngle) )
            {
                fFinalSkewAngle = -1.0;
            }
 
            if( rtl::math::approxEqual(fFinalSkewAngle, -1.0) )
                break;
        }
    }
 
    if( bHasCustomShape )
        rSet.Put( SfxInt32Item( SID_EXTRUSION_DIRECTION, static_cast<sal_Int32>(fFinalSkewAngle) ) );
    else
        rSet.DisableItem( SID_EXTRUSION_DIRECTION );
}
 
static void getExtrusionProjectionState( SdrView const * pSdrView, SfxItemSet& rSet )
{
    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
    const size_t nCount = rMarkList.GetMarkCount();
 
    static constexpr OUString sExtrusion = u"Extrusion"_ustr;
 
    const css::uno::Any* pAny;
 
    sal_Int32 nFinalProjection = -1;
    bool bHasCustomShape = false;
 
    for(size_t i=0; i<nCount; ++i)
    {
        SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
        if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
        {
            // see if this is an extruded customshape
            if( !bHasCustomShape )
            {
                const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
                const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
                if( pAny_ )
                    *pAny_ >>= bHasCustomShape;
 
                if( !bHasCustomShape )
                    continue;
            }
 
            const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
 
            bool    bParallel = true;
            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"ProjectionMode"_ustr );
            ProjectionMode eProjectionMode;
            if( pAny && ( *pAny >>= eProjectionMode ) )
                bParallel = eProjectionMode == ProjectionMode_PARALLEL;
 
            if( nFinalProjection == -1 )
            {
                nFinalProjection = bParallel ? 1 : 0;
            }
            else if( nFinalProjection != (bParallel ? 1 : 0) )
            {
                nFinalProjection = -1;
                break;
            }
        }
    }
 
    if( bHasCustomShape )
        rSet.Put( SfxInt32Item( SID_EXTRUSION_PROJECTION, nFinalProjection ) );
    else
        rSet.DisableItem( SID_EXTRUSION_PROJECTION );
}
 
static void getExtrusionSurfaceState( SdrView const * pSdrView, SfxItemSet& rSet )
{
    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
    const size_t nCount = rMarkList.GetMarkCount();
 
    static constexpr OUString sExtrusion = u"Extrusion"_ustr;
 
    const css::uno::Any* pAny;
 
    sal_Int32 nFinalSurface = -1;
    bool bHasCustomShape = false;
 
    for(size_t i=0; i<nCount; ++i)
    {
        SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
        if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
        {
            const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
 
            // see if this is an extruded customshape
            if( !bHasCustomShape )
            {
                const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
                if( pAny_ )
                    *pAny_ >>= bHasCustomShape;
 
                if( !bHasCustomShape )
                    continue;
            }
 
            sal_Int32 nSurface = 0; // wire frame
 
            ShadeMode eShadeMode( ShadeMode_FLAT );
            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"ShadeMode"_ustr );
            if( pAny )
                *pAny >>= eShadeMode;
 
            if (eShadeMode != ShadeMode_DRAFT)
            {
                bool bMetal = false;
                pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Metal"_ustr );
                if( pAny )
                    *pAny >>= bMetal;
 
                if( bMetal )
                {
                    nSurface = 3; // metal ODF
                    sal_Int16 eMetalType = EnhancedCustomShapeMetalType::MetalODF;
                    pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"MetalType"_ustr );
                    if (pAny)
                    {
                        *pAny >>= eMetalType;
                        if (eMetalType == EnhancedCustomShapeMetalType::MetalMSCompatible)
                            nSurface = 4; // metal MS Office
                    }
                }
                else
                {
                    double fSpecularity = 0;
                    pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Specularity"_ustr );
                    if( pAny )
                        *pAny >>= fSpecularity;
 
                    const double e = 0.0001;
                    if( (fSpecularity > -e) && (fSpecularity < e) )
                    {
                        nSurface = 1; // matte
                    }
                    else
                    {
                        nSurface = 2; // plastic
                    }
                }
            }
 
            if( nFinalSurface == -1 )
            {
                nFinalSurface = nSurface;
            }
            else if( nFinalSurface != nSurface )
            {
                nFinalSurface = -1;
                break;
            }
        }
    }
 
    if( bHasCustomShape )
        rSet.Put( SfxInt32Item( SID_EXTRUSION_SURFACE, nFinalSurface ) );
    else
        rSet.DisableItem( SID_EXTRUSION_SURFACE );
}
 
static void getExtrusionDepthState( SdrView const * pSdrView, SfxItemSet& rSet )
{
    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
    const size_t nCount = rMarkList.GetMarkCount();
 
    static constexpr OUString sExtrusion = u"Extrusion"_ustr;
 
    const css::uno::Any* pAny;
 
    double fFinalDepth = -1;
    bool bHasCustomShape = false;
 
    for(size_t i=0; i<nCount; ++i)
    {
        SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
        if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
        {
            const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
 
            // see if this is an extruded customshape
            if( !bHasCustomShape )
            {
                const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
                if( pAny_ )
                    *pAny_ >>= bHasCustomShape;
 
                if( !bHasCustomShape )
                    continue;
            }
 
            double fDepth = 1270.0; // =36pt ODF default
            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Depth"_ustr );
            if( pAny )
            {
                EnhancedCustomShapeParameterPair aDepthPropPair;
                if ( *pAny >>= aDepthPropPair )
                    aDepthPropPair.First.Value >>= fDepth;
            }
 
            if( fFinalDepth == -1 )
            {
                fFinalDepth = fDepth;
            }
            else if( !rtl::math::approxEqual(fFinalDepth, fDepth) )
            {
                fFinalDepth = -1;
                break;
            }
        }
    }
 
 
    FieldUnit eUnit = pSdrView->GetModel().GetUIUnit();
    rSet.Put( SfxUInt16Item( SID_ATTR_METRIC, static_cast<sal_uInt16>(eUnit) ) );
 
    if( bHasCustomShape )
        rSet.Put( SvxDoubleItem( fFinalDepth, SID_EXTRUSION_DEPTH ) );
    else
        rSet.DisableItem( SID_EXTRUSION_DEPTH );
}
 
static bool compare_direction( const Direction3D& d1, const Direction3D& d2 )
{
    if( ((d1.DirectionX < 0) && (d2.DirectionX < 0)) || ((d1.DirectionX == 0) && (d2.DirectionX == 0)) || ((d1.DirectionX > 0) && (d2.DirectionX > 0)) )
    {
        if( ((d1.DirectionY < 0) && (d2.DirectionY < 0)) || ((d1.DirectionY == 0) && (d2.DirectionY == 0)) || ((d1.DirectionY > 0) && (d2.DirectionY > 0)) )
        {
            if( ((d1.DirectionZ < 0) && (d2.DirectionZ < 0)) || ((d1.DirectionZ == 0) && (d2.DirectionZ == 0)) || ((d1.DirectionZ > 0) && (d2.DirectionZ > 0)) )
            {
                return true;
            }
        }
    }
 
    return false;
}
 
static void getExtrusionLightingDirectionState( SdrView const * pSdrView, SfxItemSet& rSet )
{
    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
    const size_t nCount = rMarkList.GetMarkCount();
 
    static constexpr OUString sExtrusion = u"Extrusion"_ustr;
 
    const Direction3D * pLighting1Defaults;
    const Direction3D * pLighting2Defaults;
 
    getLightingDirectionDefaults( &pLighting1Defaults, &pLighting2Defaults );
 
    const css::uno::Any* pAny;
 
    int nFinalDirection = -1;
    bool bHasCustomShape = false;
 
    for(size_t i=0; i<nCount; ++i)
    {
        SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
        if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
        {
            const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
 
            // see if this is an extruded customshape
            if( !bHasCustomShape )
            {
                const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
                if( pAny_ )
                    *pAny_ >>= bHasCustomShape;
 
                if( !bHasCustomShape )
                    continue;
            }
 
            Direction3D aFirstLightDirection( 50000, 0, 10000 );
            Direction3D aSecondLightDirection( -50000, 0, 10000 );
 
            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"FirstLightDirection"_ustr );
            if( pAny )
                *pAny >>= aFirstLightDirection;
 
            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"SecondLightDirection"_ustr );
            if( pAny )
                *pAny >>= aSecondLightDirection;
 
            int nDirection = -1;
 
            int j;
            for( j = 0; j < 9; j++ )
            {
                if( compare_direction( aFirstLightDirection, pLighting1Defaults[j] ) &&
                    compare_direction( aSecondLightDirection, pLighting2Defaults[j] ))
                {
                    nDirection = j;
                    break;
                }
            }
 
            if( nFinalDirection == -1 )
            {
                nFinalDirection = nDirection;
            }
            else if( nDirection != nFinalDirection )
            {
                nFinalDirection = -1;
            }
 
            if( nFinalDirection == -1 )
                break;
        }
    }
 
    if( bHasCustomShape )
        rSet.Put( SfxInt32Item( SID_EXTRUSION_LIGHTING_DIRECTION, static_cast<sal_Int32>(nFinalDirection) ) );
    else
        rSet.DisableItem( SID_EXTRUSION_LIGHTING_DIRECTION );
}
 
static void getExtrusionLightingIntensityState( SdrView const * pSdrView, SfxItemSet& rSet )
{
    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
    const size_t nCount = rMarkList.GetMarkCount();
 
    static constexpr OUString sExtrusion = u"Extrusion"_ustr;
 
    const css::uno::Any* pAny;
 
    int nFinalLevel = -1;
    bool bHasCustomShape = false;
 
    for(size_t i=0; i<nCount; ++i)
    {
        SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
        if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
        {
            const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
 
            // see if this is an extruded customshape
            if( !bHasCustomShape )
            {
                const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
                if( pAny_ )
                    *pAny_ >>= bHasCustomShape;
 
                if( !bHasCustomShape )
                    continue;
            }
 
            double fBrightness = 22178.0 / 655.36;
            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Brightness"_ustr );
            if( pAny )
                *pAny >>= fBrightness;
 
            int nLevel;
            if( fBrightness >= 30.0 )
            {
                nLevel = 0; // Bright
            }
            else if( fBrightness >= 10.0 )
            {
                nLevel = 1; // Normal;
            }
            else
            {
                nLevel = 2; // Dim
            }
 
            if( nFinalLevel == -1 )
            {
                nFinalLevel = nLevel;
            }
            else if( nFinalLevel != nLevel )
            {
                nFinalLevel = -1;
                break;
            }
        }
    }
 
    if( bHasCustomShape )
        rSet.Put( SfxInt32Item( SID_EXTRUSION_LIGHTING_INTENSITY, nFinalLevel ) );
    else
        rSet.DisableItem( SID_EXTRUSION_LIGHTING_INTENSITY );
}
 
static void getExtrusionColorState( SdrView const * pSdrView, SfxItemSet& rSet )
{
    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
    const size_t nCount = rMarkList.GetMarkCount();
 
    static constexpr OUString sExtrusion = u"Extrusion"_ustr;
 
    const css::uno::Any* pAny;
 
    bool bInit = false;
    bool bAmbigius = false;
    Color aFinalColor;
    bool bHasCustomShape = false;
 
    for(size_t i=0; i<nCount; ++i)
    {
        SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
        if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
        {
            const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
 
            // see if this is an extruded customshape
            if( !bHasCustomShape )
            {
                const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
                if( pAny_ )
                    *pAny_ >>= bHasCustomShape;
 
                if( !bHasCustomShape )
                    continue;
            }
 
            Color aColor;
 
            bool bUseColor = false;
            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Color"_ustr );
            if( pAny )
                *pAny >>= bUseColor;
 
            if( bUseColor )
            {
                const XSecondaryFillColorItem& rItem = pObj->GetMergedItem( XATTR_SECONDARYFILLCOLOR );
                aColor = rItem.GetColorValue();
            }
            else
            {
                aColor = COL_AUTO;
            }
 
            if( !bInit )
            {
                aFinalColor = aColor;
                bInit = true;
            }
            else if( aFinalColor != aColor )
            {
                bAmbigius = true;
                break;
            }
        }
    }
 
    if( bAmbigius )
        aFinalColor = COL_AUTO;
 
    if( bHasCustomShape )
        rSet.Put( SvxColorItem( aFinalColor, SID_EXTRUSION_3D_COLOR ) );
    else
        rSet.DisableItem( SID_EXTRUSION_3D_COLOR );
}
 
namespace svx {
bool checkForSelectedCustomShapes( SdrView const * pSdrView, bool bOnlyExtruded )
{
    static constexpr OUString sExtrusion = u"Extrusion"_ustr;
 
    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
    const size_t nCount = rMarkList.GetMarkCount();
    bool bFound = false;
 
    for(size_t i=0;(i<nCount) && !bFound ; ++i)
    {
        SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
        if( dynamic_cast<const SdrObjCustomShape*>( pObj) !=  nullptr )
        {
            if( bOnlyExtruded )
            {
                const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
                const Any* pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
                if( pAny )
                    *pAny >>= bFound;
            }
            else
            {
                bFound = true;
            }
        }
    }
 
    return bFound;
}
}
 
void ExtrusionBar::getState( SdrView const * pSdrView, SfxItemSet& rSet )
{
    getExtrusionDirectionState( pSdrView, rSet );
    getExtrusionProjectionState( pSdrView, rSet );
 
    const bool bOnlyExtrudedCustomShapes(checkForSelectedCustomShapes( pSdrView, true ));
 
    if (! bOnlyExtrudedCustomShapes)
    {
        rSet.DisableItem( SID_EXTRUSION_TILT_DOWN );
        rSet.DisableItem( SID_EXTRUSION_TILT_DOWN );
        rSet.DisableItem( SID_EXTRUSION_TILT_UP );
        rSet.DisableItem( SID_EXTRUSION_TILT_LEFT );
        rSet.DisableItem( SID_EXTRUSION_TILT_RIGHT );
        rSet.DisableItem( SID_EXTRUSION_3D_COLOR );
        rSet.DisableItem( SID_EXTRUSION_DEPTH_FLOATER );
        rSet.DisableItem( SID_EXTRUSION_DIRECTION_FLOATER );
        rSet.DisableItem( SID_EXTRUSION_LIGHTING_FLOATER );
        rSet.DisableItem( SID_EXTRUSION_SURFACE_FLOATER );
    }
 
    if( !checkForSelectedCustomShapes( pSdrView, false ) )
        rSet.DisableItem( SID_EXTRUSION_TOGGLE );
 
    getExtrusionDepthState( pSdrView, rSet );
    getExtrusionSurfaceState( pSdrView, rSet );
    getExtrusionLightingIntensityState( pSdrView, rSet );
    getExtrusionLightingDirectionState( pSdrView, rSet );
    getExtrusionColorState( pSdrView, rSet );
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V1019 Compound assignment expression '* pAny >>= aRotateAnglePropPair' is used inside condition.