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