diff options
Diffstat (limited to 'svx/source/toolbars')
-rw-r--r-- | svx/source/toolbars/extrusionbar.cxx | 1338 | ||||
-rw-r--r-- | svx/source/toolbars/fontworkbar.cxx | 566 |
2 files changed, 1904 insertions, 0 deletions
diff --git a/svx/source/toolbars/extrusionbar.cxx b/svx/source/toolbars/extrusionbar.cxx new file mode 100644 index 000000000..3e0273c28 --- /dev/null +++ b/svx/source/toolbars/extrusionbar.cxx @@ -0,0 +1,1338 @@ +/* -*- 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 ::cppu; +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, nullptr } +}; + +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 OUStringLiteral sExtrusion = u"Extrusion"; + static constexpr OUStringLiteral sRotateAngle = u"RotateAngle"; + + 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"); + if (!pAny) + { + css::beans::PropertyValue aPropValue; + aPropValue.Name = u"Diffusion"; + 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: + { + if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_DIRECTION ) == SfxItemState::SET ) + { + sal_Int32 nSkew = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_DIRECTION)->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: + { + if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_PROJECTION ) == SfxItemState::SET ) + { + sal_Int32 nProjection = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_PROJECTION)->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: + { + if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_DEPTH ) == SfxItemState::SET) + { + double fDepth = rReq.GetArgs()->GetItem<SvxDoubleItem>(SID_EXTRUSION_DEPTH)->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( "", aColor ) ); + } + pObj->BroadcastObjectChange(); + } + } + break; + case SID_EXTRUSION_SURFACE: + { + if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_SURFACE ) == SfxItemState::SET) + { + sal_Int32 nSurface = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_SURFACE)->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"); + 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"); + 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"); + 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: + { + if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_LIGHTING_INTENSITY ) == SfxItemState::SET) + { + sal_Int32 nLevel = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_LIGHTING_INTENSITY)->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: + { + if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_LIGHTING_DIRECTION ) == SfxItemState::SET) + { + sal_Int32 nDirection = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_LIGHTING_DIRECTION)->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: + if( rReq.GetArgs() && + (rReq.GetArgs()->GetItemState( SID_EXTRUSION_DEPTH ) == SfxItemState::SET) && + (rReq.GetArgs()->GetItemState( SID_ATTR_METRIC ) == SfxItemState::SET)) + { + double fDepth = rReq.GetArgs()->GetItem<SvxDoubleItem>(SID_EXTRUSION_DEPTH)->GetValue(); + FieldUnit eUnit = static_cast<FieldUnit>(rReq.GetArgs()->GetItem<SfxUInt16Item>(SID_ATTR_METRIC)->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 OUStringLiteral sExtrusion = u"Extrusion"; + + 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, "ProjectionMode" ); + 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, "Skew" ); + 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, "ViewPoint" ); + if( pAny ) + *pAny >>= aViewPoint; + + EnhancedCustomShapeParameterPair aOriginPropPair; + pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "Origin" ); + 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 OUStringLiteral sExtrusion = u"Extrusion"; + + 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, "ProjectionMode" ); + 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 OUStringLiteral sExtrusion = u"Extrusion"; + + 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" ); + if( pAny ) + *pAny >>= eShadeMode; + + if (eShadeMode != ShadeMode_DRAFT) + { + bool bMetal = false; + pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Metal" ); + if( pAny ) + *pAny >>= bMetal; + + if( bMetal ) + { + nSurface = 3; // metal ODF + sal_Int16 eMetalType = EnhancedCustomShapeMetalType::MetalODF; + pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"MetalType" ); + if (pAny) + { + *pAny >>= eMetalType; + if (eMetalType == EnhancedCustomShapeMetalType::MetalMSCompatible) + nSurface = 4; // metal MS Office + } + } + else + { + double fSpecularity = 0; + pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Specularity" ); + 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 OUStringLiteral sExtrusion = u"Extrusion"; + + 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, "Depth" ); + 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; + } + } + } + + if( pSdrView->GetModel() ) + { + 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 OUStringLiteral sExtrusion = u"Extrusion"; + + 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, "FirstLightDirection" ); + if( pAny ) + *pAny >>= aFirstLightDirection; + + pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "SecondLightDirection" ); + 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 OUStringLiteral sExtrusion = u"Extrusion"; + + 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, "Brightness" ); + 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 OUStringLiteral sExtrusion = u"Extrusion"; + + 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, "Color" ); + 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 OUStringLiteral sExtrusion = u"Extrusion"; + + 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: */ diff --git a/svx/source/toolbars/fontworkbar.cxx b/svx/source/toolbars/fontworkbar.cxx new file mode 100644 index 000000000..7b2e8653b --- /dev/null +++ b/svx/source/toolbars/fontworkbar.cxx @@ -0,0 +1,566 @@ +/* -*- 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 <svx/svdundo.hxx> +#include <sfx2/request.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/viewsh.hxx> +#include <svx/unoapi.hxx> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> +#include <sal/log.hxx> +#include <svx/dialmgr.hxx> +#include <svx/svdoashp.hxx> +#include <svx/strings.hrc> +#include <svx/svdpage.hxx> +#include <svx/svdview.hxx> +#include <svx/sdasitm.hxx> +#include <svx/gallery.hxx> +#include <svx/fmmodel.hxx> +#include <svx/sdtfsitm.hxx> +#include <svl/itempool.hxx> +#include <svl/stritem.hxx> +#include <sfx2/bindings.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/kernitem.hxx> + +#include <svx/svxids.hrc> +#include <svx/fontworkbar.hxx> +#include <svx/fontworkgallery.hxx> + + +using namespace ::svx; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; + +static void SetAlignmentState( SdrView const * pSdrView, SfxItemSet& rSet ) +{ + const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); + const size_t nCount = rMarkList.GetMarkCount(); + + sal_Int32 nAlignment = -1; + for( size_t i = 0; i < nCount; ++i ) + { + SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj(); + if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr ) + { + sal_Int32 nOldAlignment = nAlignment; + const SdrTextHorzAdjustItem& rTextHorzAdjustItem = pObj->GetMergedItem( SDRATTR_TEXT_HORZADJUST ); + const SdrTextFitToSizeTypeItem& rTextFitToSizeTypeItem = pObj->GetMergedItem( SDRATTR_TEXT_FITTOSIZE ); + switch ( rTextHorzAdjustItem.GetValue() ) + { + case SDRTEXTHORZADJUST_LEFT : nAlignment = 0; break; + case SDRTEXTHORZADJUST_CENTER : nAlignment = 1; break; + case SDRTEXTHORZADJUST_RIGHT : nAlignment = 2; break; + case SDRTEXTHORZADJUST_BLOCK : + { + auto const fit(rTextFitToSizeTypeItem.GetValue()); + if (fit == drawing::TextFitToSizeType_NONE) + { + nAlignment = 3; + } + else if (fit == drawing::TextFitToSizeType_ALLLINES || + fit == drawing::TextFitToSizeType_PROPORTIONAL) + { + nAlignment = 4; + } + } + } + if ( ( nOldAlignment != -1 ) && ( nOldAlignment != nAlignment ) ) + { + nAlignment = -1; + break; + } + } + } + rSet.Put( SfxInt32Item( SID_FONTWORK_ALIGNMENT, nAlignment ) ); +} + +static void SetCharacterSpacingState( SdrView const * pSdrView, SfxItemSet& rSet ) +{ + const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); + const size_t nCount = rMarkList.GetMarkCount(); + + sal_Int32 nCharacterSpacing = -1; + for( size_t i = 0; i < nCount; ++i ) + { + SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj(); + if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr ) + { + sal_Int32 nOldCharacterSpacing = nCharacterSpacing; + const SvxCharScaleWidthItem& rCharScaleWidthItem = pObj->GetMergedItem( EE_CHAR_FONTWIDTH ); + nCharacterSpacing = rCharScaleWidthItem.GetValue(); + if ( ( nOldCharacterSpacing != -1 ) && ( nOldCharacterSpacing != nCharacterSpacing ) ) + { + nCharacterSpacing = -1; + break; + } + } + } + rSet.Put( SfxInt32Item( SID_FONTWORK_CHARACTER_SPACING, nCharacterSpacing ) ); +} + + +static void SetKernCharacterPairsState( SdrView const * pSdrView, SfxItemSet& rSet ) +{ + const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); + const size_t nCount = rMarkList.GetMarkCount(); + + bool bChecked = false; + for( size_t i = 0; i < nCount; ++i ) + { + SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj(); + if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr ) + { + const SvxKerningItem& rKerningItem = pObj->GetMergedItem( EE_CHAR_KERNING ); + if ( rKerningItem.GetValue() ) + bChecked = true; + } + } + rSet.Put( SfxBoolItem( SID_FONTWORK_KERN_CHARACTER_PAIRS, bChecked ) ); +} + +static void SetFontWorkShapeTypeState( SdrView const * pSdrView, SfxItemSet& rSet ) +{ + const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); + const size_t nCount = rMarkList.GetMarkCount(); + + OUString aFontWorkShapeType; + + 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 ) ); + const Any* pAny = rGeometryItem.GetPropertyValueByName( "Type" ); + if( pAny ) + { + OUString aType; + if ( *pAny >>= aType ) + { + if ( !aFontWorkShapeType.isEmpty() ) + { + if ( aFontWorkShapeType != aType ) // different FontWorkShapeTypes selected ? + { + aFontWorkShapeType.clear(); + break; + } + } + aFontWorkShapeType = aType; + } + } + } + } + rSet.Put( SfxStringItem( SID_FONTWORK_SHAPE_TYPE, aFontWorkShapeType ) ); +} + +// Declare the default interface. (The slotmap must not be empty, so +// we enter something which never occurs here (hopefully).) +static SfxSlot aFontworkBarSlots_Impl[] = +{ + { 0, SfxGroupId::NONE, SfxSlotMode::NONE, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, 0, SfxDisableFlags::NONE, nullptr } +}; + +SFX_IMPL_INTERFACE(FontworkBar, SfxShell) + +void FontworkBar::InitInterface_Impl() +{ + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Invisible, ToolbarId::Svx_Fontwork_Bar); +} + + +FontworkBar::FontworkBar(SfxViewShell* pViewShell ) +: SfxShell(pViewShell) +{ + DBG_ASSERT( pViewShell, "svx::FontworkBar::FontworkBar(), I need a viewshell!" ); + if( pViewShell ) + SetPool(&pViewShell->GetPool()); + + SetName( SvxResId( RID_SVX_FONTWORK_BAR )); +} + +FontworkBar::~FontworkBar() +{ + SetRepeatTarget(nullptr); +} + +namespace svx { +bool checkForFontWork( const SdrObject* pObj ) +{ + static constexpr OUStringLiteral sTextPath = u"TextPath"; + bool bFound = false; + + if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr ) + { + const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) ); + const Any* pAny = rGeometryItem.GetPropertyValueByName( sTextPath, sTextPath ); + if( pAny ) + *pAny >>= bFound; + } + + return bFound; +} + +bool checkForSelectedFontWork( SdrView const * pSdrView ) +{ + 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(); + bFound = checkForFontWork(pObj); + } + return bFound; +} + +static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& rGeometryItem, SdrObject* pObj ) +{ + sal_uInt16 nSID = rReq.GetSlot(); + switch( nSID ) + { + case SID_FONTWORK_SAME_LETTER_HEIGHTS: + { + css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "TextPath", "SameLetterHeights" ); + if( pAny ) + { + bool bOn = false; + (*pAny) >>= bOn; + bOn = !bOn; + css::beans::PropertyValue aPropValue; + aPropValue.Name = "SameLetterHeights"; + aPropValue.Value <<= bOn; + rGeometryItem.SetPropertyValue("TextPath", aPropValue); + } + } + break; + + case SID_FONTWORK_ALIGNMENT: + { + if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_FONTWORK_ALIGNMENT ) == SfxItemState::SET ) + { + sal_Int32 nValue = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_FONTWORK_ALIGNMENT)->GetValue(); + if ( ( nValue >= 0 ) && ( nValue < 5 ) ) + { + drawing::TextFitToSizeType eFTS = drawing::TextFitToSizeType_NONE; + SdrTextHorzAdjust eHorzAdjust; + switch ( nValue ) + { + case 4 : eFTS = drawing::TextFitToSizeType_ALLLINES; [[fallthrough]]; + case 3 : eHorzAdjust = SDRTEXTHORZADJUST_BLOCK; break; + default: eHorzAdjust = SDRTEXTHORZADJUST_LEFT; break; + case 1 : eHorzAdjust = SDRTEXTHORZADJUST_CENTER; break; + case 2 : eHorzAdjust = SDRTEXTHORZADJUST_RIGHT; break; + } + pObj->SetMergedItem( SdrTextHorzAdjustItem( eHorzAdjust ) ); + pObj->SetMergedItem( SdrTextFitToSizeTypeItem( eFTS ) ); + pObj->BroadcastObjectChange(); + } + } + } + break; + + case SID_FONTWORK_CHARACTER_SPACING: + { + if( rReq.GetArgs() && ( rReq.GetArgs()->GetItemState( SID_FONTWORK_CHARACTER_SPACING ) == SfxItemState::SET ) ) + { + sal_Int32 nCharSpacing = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_FONTWORK_CHARACTER_SPACING)->GetValue(); + pObj->SetMergedItem( SvxCharScaleWidthItem( static_cast<sal_uInt16>(nCharSpacing), EE_CHAR_FONTWIDTH ) ); + pObj->BroadcastObjectChange(); + } + } + break; + + case SID_FONTWORK_KERN_CHARACTER_PAIRS: + { + if( rReq.GetArgs() && ( rReq.GetArgs()->GetItemState( SID_FONTWORK_KERN_CHARACTER_PAIRS ) == SfxItemState::SET ) ) + { + // sal_Bool bKernCharacterPairs = ((const SfxBoolItem*)rReq.GetArgs()->GetItem(SID_FONTWORK_KERN_CHARACTER_PAIRS))->GetValue(); +//TODO: pObj->SetMergedItem( SvxCharScaleWidthItem( (sal_uInt16)nCharSpacing, EE_CHAR_FONTWIDTH ) ); + pObj->BroadcastObjectChange(); + } + } + break; + } +} + +static void GetGeometryForCustomShape( SdrCustomShapeGeometryItem& rGeometryItem, const OUString& rCustomShape ) +{ + static const OUStringLiteral sType( u"Type" ); + + css::beans::PropertyValue aPropVal; + aPropVal.Name = sType; + aPropVal.Value <<= rCustomShape; + rGeometryItem.SetPropertyValue( aPropVal ); + + static const OUStringLiteral sAdjustmentValues( u"AdjustmentValues" ); + static const OUStringLiteral sCoordinateOrigin( u"CoordinateOrigin" ); + static const OUStringLiteral sCoordinateSize( u"CoordinateSize" ); + static const OUStringLiteral sEquations( u"Equations" ); + static const OUStringLiteral sHandles( u"Handles" ); + static const OUStringLiteral sPath( u"Path" ); + rGeometryItem.ClearPropertyValue( sAdjustmentValues ); + rGeometryItem.ClearPropertyValue( sCoordinateOrigin ); + rGeometryItem.ClearPropertyValue( sCoordinateSize ); + rGeometryItem.ClearPropertyValue( sEquations ); + rGeometryItem.ClearPropertyValue( sHandles ); + rGeometryItem.ClearPropertyValue( sPath ); + + /* SJ: CustomShapes that are available in the gallery are having the highest + priority, so we will take a look there before taking the internal default */ + + if ( !GalleryExplorer::GetSdrObjCount( GALLERY_THEME_POWERPOINT ) ) + return; + + std::vector< OUString > aObjList; + if ( !GalleryExplorer::FillObjListTitle( GALLERY_THEME_POWERPOINT, aObjList ) ) + return; + + for ( std::vector<OUString>::size_type i = 0; i < aObjList.size(); i++ ) + { + if ( aObjList[ i ].equalsIgnoreAsciiCase( rCustomShape ) ) + { + FmFormModel aFormModel; + SfxItemPool& rPool(aFormModel.GetItemPool()); + rPool.FreezeIdRanges(); + + if ( GalleryExplorer::GetSdrObj( GALLERY_THEME_POWERPOINT, i, &aFormModel ) ) + { + const SdrObject* pSourceObj = nullptr; + if (aFormModel.GetPageCount() > 0) + pSourceObj = aFormModel.GetPage( 0 )->GetObj( 0 ); + SAL_WARN_IF(!pSourceObj, "svx.form", "No content in gallery custom shape '" << rCustomShape << "'" ); + if( pSourceObj ) + { + PropertyValue aPropVal_; + const SdrCustomShapeGeometryItem& rSourceGeometry = pSourceObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ); + const css::uno::Any* pAny = rSourceGeometry.GetPropertyValueByName( sType ); + if ( pAny ) + { + aPropVal_.Name = sType; + aPropVal_.Value = *pAny; + rGeometryItem.SetPropertyValue( aPropVal_ ); + } + pAny = rSourceGeometry.GetPropertyValueByName( sAdjustmentValues ); + if ( pAny ) + { + aPropVal_.Name = sAdjustmentValues; + aPropVal_.Value = *pAny; + rGeometryItem.SetPropertyValue( aPropVal_ ); + } + pAny = rSourceGeometry.GetPropertyValueByName( sCoordinateOrigin ); + if ( pAny ) + { + aPropVal_.Name = sCoordinateOrigin; + aPropVal_.Value = *pAny; + rGeometryItem.SetPropertyValue( aPropVal_ ); + } + pAny = rSourceGeometry.GetPropertyValueByName( sCoordinateSize ); + if ( pAny ) + { + aPropVal_.Name = sCoordinateSize; + aPropVal_.Value = *pAny; + rGeometryItem.SetPropertyValue( aPropVal_ ); + } + pAny = rSourceGeometry.GetPropertyValueByName( sEquations ); + if ( pAny ) + { + aPropVal_.Name = sEquations; + aPropVal_.Value = *pAny; + rGeometryItem.SetPropertyValue( aPropVal_ ); + } + pAny = rSourceGeometry.GetPropertyValueByName( sHandles ); + if ( pAny ) + { + aPropVal_.Name = sHandles; + aPropVal_.Value = *pAny; + rGeometryItem.SetPropertyValue( aPropVal_ ); + } + pAny = rSourceGeometry.GetPropertyValueByName( sPath ); + if ( pAny ) + { + aPropVal_.Name = sPath; + aPropVal_.Value = *pAny; + rGeometryItem.SetPropertyValue( aPropVal_ ); + } + } + } + } + } +} + + +void FontworkBar::execute( SdrView& rSdrView, SfxRequest const & rReq, SfxBindings& rBindings ) +{ + TranslateId pStrResId; + + sal_uInt16 nSID = rReq.GetSlot(); + switch( nSID ) + { + case SID_FONTWORK_GALLERY_FLOATER: + { + std::shared_ptr<FontWorkGalleryDialog> pDlg = std::make_shared<FontWorkGalleryDialog>(rReq.GetFrameWeld(), rSdrView); + weld::DialogController::runAsync(pDlg, [](int){}); + } + break; + + case SID_FONTWORK_SHAPE_TYPE: + { + OUString aCustomShape; + const SfxItemSet* pArgs = rReq.GetArgs(); + if ( pArgs ) + { + const SfxStringItem& rItm = static_cast<const SfxStringItem&>(pArgs->Get( rReq.GetSlot() )); + aCustomShape = rItm.GetValue(); + } + if ( !aCustomShape.isEmpty() ) + { + const SdrMarkList& rMarkList = rSdrView.GetMarkedObjectList(); + const size_t nCount = rMarkList.GetMarkCount(); + for( size_t i = 0; i < nCount; ++i ) + { + SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj(); + if( auto pCustomShape = dynamic_cast<SdrObjCustomShape*>( pObj) ) + { + const bool bUndo = rSdrView.IsUndoEnabled(); + + if( bUndo ) + { + OUString aStr( SvxResId( RID_SVXSTR_UNDO_APPLY_FONTWORK_SHAPE ) ); + rSdrView.BegUndo(aStr); + rSdrView.AddUndo(rSdrView.GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj)); + } + SdrCustomShapeGeometryItem aGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) ); + GetGeometryForCustomShape( aGeometryItem, aCustomShape ); + pObj->SetMergedItem( aGeometryItem ); + + Reference< drawing::XShape > aXShape = GetXShapeForSdrObject( pCustomShape ); + if ( aXShape.is() ) + { + Reference< drawing::XEnhancedCustomShapeDefaulter > xDefaulter( aXShape, UNO_QUERY ); + if( xDefaulter.is() ) + xDefaulter->createCustomShapeDefaults( aCustomShape ); + } + + pObj->BroadcastObjectChange(); + if (bUndo) + rSdrView.EndUndo(); + rSdrView.AdjustMarkHdl(); //HMH sal_True ); + rBindings.Invalidate( SID_FONTWORK_SHAPE_TYPE ); + } + } + } + } + break; + + case SID_FONTWORK_CHARACTER_SPACING_DIALOG : + { + if( rReq.GetArgs() && ( rReq.GetArgs()->GetItemState( SID_FONTWORK_CHARACTER_SPACING ) == SfxItemState::SET ) ) + { + sal_Int32 nCharSpacing = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_FONTWORK_CHARACTER_SPACING)->GetValue(); + FontworkCharacterSpacingDialog aDlg(rReq.GetFrameWeld(), nCharSpacing); + sal_uInt16 nRet = aDlg.run(); + if (nRet != RET_CANCEL) + { + SfxInt32Item aItem(SID_FONTWORK_CHARACTER_SPACING, aDlg.getScale()); + SfxPoolItem* aItems[] = { &aItem, nullptr }; + rBindings.Execute( SID_FONTWORK_CHARACTER_SPACING, const_cast<const SfxPoolItem**>(aItems) ); + } + } + } + break; + + case SID_FONTWORK_SHAPE: + case SID_FONTWORK_ALIGNMENT: + { + if ( !pStrResId ) + pStrResId = RID_SVXSTR_UNDO_APPLY_FONTWORK_ALIGNMENT; + [[fallthrough]]; + } + case SID_FONTWORK_CHARACTER_SPACING: + { + if ( !pStrResId ) + pStrResId = RID_SVXSTR_UNDO_APPLY_FONTWORK_CHARACTER_SPACING; + [[fallthrough]]; + } + case SID_FONTWORK_KERN_CHARACTER_PAIRS: + { + if ( !pStrResId ) + pStrResId = RID_SVXSTR_UNDO_APPLY_FONTWORK_CHARACTER_SPACING; + [[fallthrough]]; + } + case SID_FONTWORK_SAME_LETTER_HEIGHTS: + { + if ( !pStrResId ) + pStrResId = RID_SVXSTR_UNDO_APPLY_FONTWORK_SAME_LETTER_HEIGHT; + + const SdrMarkList& rMarkList = rSdrView.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 ) + { + const bool bUndo = rSdrView.IsUndoEnabled(); + if( bUndo ) + { + OUString aStr( SvxResId( pStrResId ) ); + rSdrView.BegUndo(aStr); + rSdrView.AddUndo(rSdrView.GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj)); + } + SdrCustomShapeGeometryItem aGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) ); + impl_execute( rReq, aGeometryItem, pObj ); + pObj->SetMergedItem( aGeometryItem ); + pObj->BroadcastObjectChange(); + if (bUndo) + rSdrView.EndUndo(); + } + } + } + break; + } +} + +void FontworkBar::getState( SdrView const * pSdrView, SfxItemSet& rSet ) +{ + if ( checkForSelectedFontWork( pSdrView ) ) + { + SetAlignmentState( pSdrView, rSet ); + SetCharacterSpacingState( pSdrView, rSet ); + SetKernCharacterPairsState( pSdrView, rSet ); + SetFontWorkShapeTypeState( pSdrView, rSet ); + } + else + { + rSet.DisableItem( SID_FONTWORK_ALIGNMENT_FLOATER ); + rSet.DisableItem( SID_FONTWORK_ALIGNMENT ); + rSet.DisableItem( SID_FONTWORK_CHARACTER_SPACING_FLOATER ); + rSet.DisableItem( SID_FONTWORK_CHARACTER_SPACING ); + rSet.DisableItem( SID_FONTWORK_KERN_CHARACTER_PAIRS ); + rSet.DisableItem( SID_FONTWORK_SAME_LETTER_HEIGHTS ); + rSet.DisableItem( SID_FONTWORK_SHAPE_TYPE ); + } +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |