bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / filter / ppt / ppt97animations.cxx
blobc2ec7c1bb4b6a5425f378063b207a9bd386a2fb8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "ppt97animations.hxx"
22 #include <svx/svdobj.hxx>
23 #include <sdpage.hxx>
24 #include <tools/stream.hxx>
25 #include <svx/unoapi.hxx>
26 #include <sal/log.hxx>
27 #include <CustomAnimationPreset.hxx>
28 #include <com/sun/star/presentation/TextAnimationType.hpp>
29 #include <com/sun/star/presentation/EffectNodeType.hpp>
30 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
32 using namespace ::com::sun::star;
34 void Ppt97AnimationInfoAtom::ReadStream( SvStream& rIn )
36 sal_uInt32 nTmp;
37 rIn.ReadUInt32( nTmp );
38 nDimColor = Color(nTmp);
39 rIn.ReadUInt32( nFlags );
40 rIn.ReadUInt32( nSoundRef );
41 rIn.ReadInt32( nDelayTime );
42 rIn.ReadUInt16( nOrderID );
43 rIn.ReadUInt16( nSlideCount );
44 rIn.ReadUChar( nBuildType );
45 rIn.ReadUChar( nFlyMethod );
46 rIn.ReadUChar( nFlyDirection );
47 rIn.ReadUChar( nAfterEffect );
48 rIn.ReadUChar( nSubEffect );
49 rIn.ReadUChar( nOLEVerb );
50 rIn.ReadUChar( nUnknown1 );
51 rIn.ReadUChar( nUnknown2 );
54 Ppt97Animation::Ppt97Animation( SvStream& rInputStream )
55 : m_aAtom()
56 , m_bDirtyCache(true)
57 , m_bHasSpecialDuration(false)
58 , m_fDurationInSeconds(0.001)
60 m_aAtom.ReadStream( rInputStream );
63 bool Ppt97Animation::operator < ( const Ppt97Animation& rAnimation ) const
65 return m_aAtom.nOrderID < rAnimation.m_aAtom.nOrderID;
67 bool Ppt97Animation::operator > ( const Ppt97Animation& rAnimation ) const
69 return m_aAtom.nOrderID > rAnimation.m_aAtom.nOrderID;
71 bool Ppt97Animation::HasEffect() const
73 return m_aAtom.nBuildType != 0;
75 bool Ppt97Animation::HasParagraphEffect() const
77 return m_aAtom.nBuildType > 1;
79 sal_Int32 Ppt97Animation::GetParagraphLevel() const
81 sal_Int32 nParagraphLevel = 0;
82 if(m_aAtom.nBuildType>1)
83 nParagraphLevel = m_aAtom.nBuildType-1;
84 return nParagraphLevel;
86 bool Ppt97Animation::HasSoundEffect() const
88 return m_aAtom.nSoundRef && m_aAtom.nFlags & 0x0010;
90 bool Ppt97Animation::HasStopPreviousSound() const
92 return m_aAtom.nFlags & 0x0040;
94 bool Ppt97Animation::HasReverseOrder() const
96 return m_aAtom.nFlags & 0x001;
98 bool Ppt97Animation::HasAnimateAssociatedShape() const
100 return m_aAtom.nFlags & 0x004000;
102 bool Ppt97Animation::HasAfterEffect() const
104 return m_aAtom.nAfterEffect != 0;
106 bool Ppt97Animation::HasAfterEffect_ChangeColor() const
108 return m_aAtom.nAfterEffect == 1;
110 bool Ppt97Animation::HasAfterEffect_DimAtNextEffect() const
112 return m_aAtom.nAfterEffect == 2;
114 #ifdef FUTURE
115 bool Ppt97Animation::HasAfterEffect_DimAfterEffect() const
117 return m_aAtom.nAfterEffect == 3;
119 #endif
120 void Ppt97Animation::SetSoundFileUrl( const OUString& rSoundFileUrl )
122 m_aSoundFileUrl = rSoundFileUrl;
125 double Ppt97Animation::GetDelayTimeInSeconds() const
127 return m_aAtom.nDelayTime != 0X7FFFFFFF ? m_aAtom.nDelayTime/1000.0 : 0.0;
130 bool Ppt97Animation::GetSpecialDuration( double& rfDurationInSeconds ) const
132 UpdateCacheData();
133 if( m_bHasSpecialDuration )
134 rfDurationInSeconds = m_fDurationInSeconds;
135 return m_bHasSpecialDuration;
138 bool Ppt97Animation::GetSpecialTextIterationDelay( double& rfTextIterationDelay ) const
140 bool bRet = false;
141 switch(GetTextAnimationType())
143 case presentation::TextAnimationType::BY_LETTER:
144 rfTextIterationDelay = 0.075;
145 bRet = true;
146 break;
147 case presentation::TextAnimationType::BY_WORD:
148 rfTextIterationDelay = 0.3;
149 bRet = true;
150 break;
151 default:
152 break;
154 return bRet;
157 void Ppt97Animation::SetDimColor( Color nDimColor )
159 m_aAtom.nDimColor = nDimColor;
161 void Ppt97Animation::SetAnimateAssociatedShape( bool bAnimate )
163 if( !bAnimate )
165 //the appear effect cannot be animated without text
166 if( GetPresetId() == "ooo-entrance-appear" )
167 return;
168 //the random effect may be the appear effect and than has the same problem
169 if( GetPresetId() == "ooo-entrance-random" )
171 //this case is not 100% correct -> feel free to complete
172 //i consider this case as seldom and not that problematic and a simple correct fix is not in sight
173 SAL_INFO("sd", "you tried to deselect the animation of the form for random animation-> this has been refused");
174 return;
179 if(bAnimate)
180 m_aAtom.nFlags = m_aAtom.nFlags | 0x004000;
181 else if( HasAnimateAssociatedShape() )
183 m_aAtom.nFlags = m_aAtom.nFlags ^ 0x004000;
187 sal_Int16 Ppt97Animation::GetEffectNodeType() const //see css::presentation::EffectNodeType
189 sal_Int16 nRet = presentation::EffectNodeType::ON_CLICK;
190 if( m_aAtom.nFlags & 0x04 )
192 nRet = presentation::EffectNodeType::AFTER_PREVIOUS;
194 return nRet;
197 sal_Int16 Ppt97Animation::GetTextAnimationType() const
199 sal_Int16 nRet = presentation::TextAnimationType::BY_PARAGRAPH;
200 switch( m_aAtom.nSubEffect )
202 case 0:
203 break;
204 case 2:
205 nRet = presentation::TextAnimationType::BY_LETTER;
206 break;
207 default:
208 nRet = presentation::TextAnimationType::BY_WORD;
209 break;
211 return nRet;
213 OUString const & Ppt97Animation::GetPresetId() const
215 UpdateCacheData();
216 return m_aPresetId;
218 OUString const & Ppt97Animation::GetPresetSubType() const
220 UpdateCacheData();
221 return m_aSubType;
224 void Ppt97Animation::ClearCacheData() const
226 m_aPresetId.clear();
227 m_aSubType.clear();
228 m_bHasSpecialDuration = false;
229 m_fDurationInSeconds = 0.001;
231 void Ppt97Animation::UpdateCacheData() const
233 if( !m_bDirtyCache )
234 return;
236 ClearCacheData();
238 if( !HasEffect() )
240 m_bDirtyCache = false;
241 return;
244 switch( m_aAtom.nFlyMethod )
246 case 0x0:
247 m_aPresetId = "ooo-entrance-appear"; // --- appear ---
248 break;
249 case 0x01:
250 m_aPresetId = "ooo-entrance-random"; // --- random ---
251 break;
252 case 0x02: // --- blinds effect ---
254 switch ( m_aAtom.nFlyDirection )
256 case 0x0:
257 m_aPresetId = "ooo-entrance-venetian-blinds";
258 m_aSubType = "horizontal"; // horizontal
259 break;
260 case 0x1:
261 m_aPresetId = "ooo-entrance-venetian-blinds";
262 m_aSubType = "vertical"; // vertical
263 break;
266 break;
267 case 0x03: // --- (hor/ver) shifted appear ---
269 switch ( m_aAtom.nFlyDirection )
271 case 0x0:
272 m_aPresetId = "ooo-entrance-checkerboard";
273 m_aSubType = "across"; // vertical ???
274 break;
275 case 0x1:
276 m_aPresetId = "ooo-entrance-checkerboard";
277 m_aSubType = "downward"; // horizontal ???
278 break;
281 break;
282 case 0x05:
283 m_aPresetId = "ooo-entrance-dissolve-in";
284 break;
285 case 0x08: // --- (hor/ver) lines ---
287 switch ( m_aAtom.nFlyDirection )
289 case 0x0:
290 m_aPresetId = "ooo-entrance-random-bars";
291 m_aSubType = "vertical"; // horizontal ???
292 break;
293 case 0x1:
294 m_aPresetId = "ooo-entrance-random-bars";
295 m_aSubType = "horizontal"; // vertical ???
296 break;
299 break;
300 case 0x09: // --- diagonal ---
302 switch ( m_aAtom.nFlyDirection )
304 case 0x4:
305 m_aPresetId = "ooo-entrance-diagonal-squares";
306 m_aSubType = "left-to-top"; // to left top
307 break;
308 case 0x5:
309 m_aPresetId = "ooo-entrance-diagonal-squares";
310 m_aSubType = "right-to-top"; // to right top
311 break;
312 case 0x6:
313 m_aPresetId = "ooo-entrance-diagonal-squares";
314 m_aSubType = "left-to-bottom"; // to left bottom
315 break;
316 case 0x7:
317 m_aPresetId = "ooo-entrance-diagonal-squares";
318 m_aSubType = "right-to-bottom"; // to right bottom
319 break;
322 break;
323 case 0x0a: // --- roll/wipe ---
325 switch ( m_aAtom.nFlyDirection )
327 case 0x0:
328 m_aPresetId = "ooo-entrance-wipe";
329 m_aSubType = "from-right"; // from right
330 break;
331 case 0x1:
332 m_aPresetId = "ooo-entrance-wipe";
333 m_aSubType = "from-bottom"; // from bottom
334 break;
335 case 0x2:
336 m_aPresetId = "ooo-entrance-wipe";
337 m_aSubType = "from-left"; // from left
338 break;
339 case 0x3:
340 m_aPresetId = "ooo-entrance-wipe";
341 m_aSubType = "from-top"; // from top
342 break;
345 break;
346 case 0x0b: //--- fade in ---
348 switch ( m_aAtom.nFlyDirection )
350 case 0x0:
351 m_aPresetId = "ooo-entrance-box";
352 m_aSubType = "out"; // from center
353 break;
354 case 0x1:
355 m_aPresetId = "ooo-entrance-box";
356 m_aSubType = "in"; // to center
357 break;
360 break;
361 case 0x0c: // --- text effects ---
363 switch ( m_aAtom.nFlyDirection )
365 case 0x0:
366 m_aPresetId = "ooo-entrance-fly-in";
367 m_aSubType = "from-left";
369 break;
370 case 0x1:
371 m_aPresetId = "ooo-entrance-fly-in";
372 m_aSubType = "from-top";
373 break;
374 case 0x2:
375 m_aPresetId = "ooo-entrance-fly-in";
376 m_aSubType = "from-right";
377 break;
378 case 0x3:
379 m_aPresetId = "ooo-entrance-fly-in";
380 m_aSubType = "from-bottom";
381 break;
382 case 0x4:
383 m_aPresetId = "ooo-entrance-fly-in";
384 m_aSubType = "from-top-left";
385 break;
386 case 0x5:
387 m_aPresetId = "ooo-entrance-fly-in";
388 m_aSubType = "from-top-right";
389 break;
390 case 0x6:
391 m_aPresetId = "ooo-entrance-fly-in";
392 m_aSubType = "from-bottom-left";
393 break;
394 case 0x7:
395 m_aPresetId = "ooo-entrance-fly-in";
396 m_aSubType = "from-bottom-right";
397 break;
398 case 0x8: // -- short text effects --
399 m_aPresetId = "ooo-entrance-peek-in";
400 m_aSubType = "from-left";
401 break;
402 case 0x9:
403 m_aPresetId = "ooo-entrance-peek-in";
404 m_aSubType = "from-bottom";
405 break;
406 case 0xa:
407 m_aPresetId = "ooo-entrance-peek-in";
408 m_aSubType = "from-right";
409 break;
410 case 0xb:
411 m_aPresetId = "ooo-entrance-peek-in";
412 m_aSubType = "from-top";
413 break;
414 case 0xc: // -- slow text effects --
416 m_aPresetId = "ooo-entrance-fly-in-slow";
417 m_aSubType = "from-left";
419 break;
420 case 0xd:
422 m_aPresetId = "ooo-entrance-fly-in-slow";
423 m_aSubType = "from-top";
425 break;
426 case 0xe:
428 m_aPresetId = "ooo-entrance-fly-in-slow";
429 m_aSubType = "from-right";
431 break;
432 case 0xf:
434 m_aPresetId = "ooo-entrance-fly-in-slow";
435 m_aSubType = "from-bottom";
437 break;
438 case 0x10: // --- zoom ---
439 m_aPresetId = "ooo-entrance-zoom";
440 m_aSubType = "in";
441 break;
442 case 0x11:
443 m_aPresetId = "ooo-entrance-zoom";
444 m_aSubType = "in-slightly";
445 break;
446 case 0x12:
447 m_aPresetId = "ooo-entrance-zoom";
448 m_aSubType = "out";
449 break;
450 case 0x13:
451 m_aPresetId = "ooo-entrance-zoom";
452 m_aSubType = "out-slightly";
453 break;
454 case 0x14:
455 m_aPresetId = "ooo-entrance-zoom";
456 m_aSubType = "in-from-screen-center";
457 break;
458 case 0x15:
459 m_aPresetId = "ooo-entrance-zoom";
460 m_aSubType = "out-from-screen-center";
461 break;
462 case 0x16: // --- stretch ---
463 m_aPresetId = "ooo-entrance-stretchy";
464 m_aSubType = "across";
465 break;
466 case 0x17:
467 m_aPresetId = "ooo-entrance-stretchy";
468 m_aSubType = "from-left";
469 break;
470 case 0x18:
471 m_aPresetId = "ooo-entrance-stretchy";
472 m_aSubType = "from-top";
473 break;
474 case 0x19:
475 m_aPresetId = "ooo-entrance-stretchy";
476 m_aSubType = "from-right";
477 break;
478 case 0x1a:
479 m_aPresetId = "ooo-entrance-stretchy";
480 m_aSubType = "from-bottom";
481 break;
482 case 0x1b: // --- rotate ---
483 m_aPresetId = "ooo-entrance-swivel";
484 m_aSubType = "vertical";
485 break;
486 case 0x1c: // --- spirale ---
487 m_aPresetId = "ooo-entrance-spiral-in";
488 break;
491 break;
492 case 0x0d: // --- open/close ---
494 switch ( m_aAtom.nFlyDirection )
496 case 0x0:
497 m_aPresetId = "ooo-entrance-split";
498 m_aSubType = "horizontal-out"; //horizontal open
499 break;
500 case 0x1:
501 m_aPresetId = "ooo-entrance-split";
502 m_aSubType = "horizontal-in"; //horizontal close
503 break;
504 case 0x2:
505 m_aPresetId = "ooo-entrance-split";
506 m_aSubType = "vertical-out"; // vertical open
507 break;
508 case 0x3:
509 m_aPresetId = "ooo-entrance-split";
510 m_aSubType = "vertical-in"; // vertical close
511 break;
514 break;
515 case 0x0e: // --- blink ---
517 m_aPresetId = "ooo-entrance-flash-once";
518 switch ( m_aAtom.nFlyDirection )
520 case 0x0: //fast
521 m_fDurationInSeconds = 0.075;
522 m_bHasSpecialDuration = true;
523 break;
524 case 0x1: //medium
525 m_fDurationInSeconds = 0.5;
526 m_bHasSpecialDuration = true;
527 break;
528 case 0x2: //slow
529 m_fDurationInSeconds = 1.0;
530 m_bHasSpecialDuration = true;
531 break;
534 break;
535 default:
537 m_aPresetId = "ooo-entrance-appear";
538 OSL_FAIL("no effect mapped");
540 break;
542 m_bDirtyCache = false;
545 void Ppt97Animation::createAndSetCustomAnimationEffect( SdrObject* pObj )
548 if( !HasEffect() )
549 return;
550 if( !pObj || !pObj->getSdrPageFromSdrObject() )
552 OSL_FAIL("no valid SdrObject or page found for ppt import");
553 return;
556 uno::Reference< drawing::XShape > xShape = GetXShapeForSdrObject( pObj );
557 if( !xShape.is() )
559 OSL_FAIL("no XShape interface found for ppt import");
560 return;
562 ::sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
563 if( !pMainSequence.get() )
565 OSL_FAIL("no MainSequence found for ppt import");
566 return;
569 const ::sd::CustomAnimationPresets& rPresets( ::sd::CustomAnimationPresets::getCustomAnimationPresets() );
570 ::sd::CustomAnimationPresetPtr pPreset( rPresets.getEffectDescriptor( GetPresetId() ) );
571 if( !pPreset.get() )
573 OSL_FAIL("no suitable preset found for ppt import");
574 return;
577 //--------------start doing something
579 //1. ------ create an effect from the presets ------
580 ::sd::CustomAnimationEffectPtr pEffect( new ::sd::CustomAnimationEffect( pPreset->create( GetPresetSubType() ) ) );
582 //2. ------ adapt the created effect ------
584 // set the shape targeted by this effect
585 pEffect->setTarget( makeAny( xShape ) );
587 pEffect->setBegin( GetDelayTimeInSeconds() );
589 // some effects need a different duration than that of the mapped preset effect
590 double fDurationInSeconds = 1.0; //in seconds
591 if( GetSpecialDuration( fDurationInSeconds ) )
592 pEffect->setDuration( fDurationInSeconds );
594 // set after effect
595 if( HasAfterEffect() )
597 pEffect->setHasAfterEffect( true );
598 if( HasAfterEffect_ChangeColor() )
599 pEffect->setDimColor( uno::makeAny( GetDimColor() ) );
600 else
601 pEffect->setAfterEffectOnNext( HasAfterEffect_DimAtNextEffect() );
604 // set sound effect
605 if( HasSoundEffect() )
606 pEffect->createAudio( uno::makeAny( m_aSoundFileUrl ) );
608 // text iteration
609 pEffect->setIterateType( GetTextAnimationType() );
611 // some effects need a different delay between text iteration than that of the mapped preset effect
612 double fTextIterationDelay = 1.0;
613 if( GetSpecialTextIterationDelay( fTextIterationDelay ) )
614 pEffect->setIterateInterval( fTextIterationDelay );
616 // is the effect started on click or after the last effect (Another possible value is EffectNodeType::WITH_PREVIOUS )
617 pEffect->setNodeType( GetEffectNodeType() );
619 //set stop sound effect
620 if( HasStopPreviousSound() )
621 pEffect->setStopAudio();
623 // append the effect to the main sequence
624 if( !HasParagraphEffect() )
626 // TODO: !HasAnimateAssociatedShape() can possibly have this set to ONLY_TEXT - see i#42737
627 pEffect->setTargetSubItem( presentation::ShapeAnimationSubType::AS_WHOLE );
630 //3. ------ put the created effect to the model and do some last changes fro paragraph effects ------
631 pMainSequence->append( pEffect );
632 if( HasParagraphEffect() )
634 sal_Int32 nParagraphLevel = GetParagraphLevel();
635 double fDelaySeconds = GetDelayTimeInSeconds();
636 bool bAnimateAssociatedShape = HasAnimateAssociatedShape();//or only text
637 bool bTextReverse = HasReverseOrder();
639 // now create effects for each paragraph
640 ::sd::CustomAnimationTextGroupPtr pGroup = pMainSequence->
641 createTextGroup( pEffect, nParagraphLevel, fDelaySeconds, bAnimateAssociatedShape, bTextReverse );
643 if( pGroup )
645 const ::sd::EffectSequence& rEffects = pGroup->getEffects();
647 ::sd::CustomAnimationEffectPtr pLastEffect;
648 sal_Int32 nIndex = 0;
649 for( const auto& rxEffect : rEffects )
651 ::sd::CustomAnimationEffectPtr pGroupEffect(rxEffect);
653 ////todo? if( nIndex > 1 && pLastEffect && HasSoundEffect() )
654 //// pLastEffect->setStopAudio();
655 if( nIndex < 2 )
657 pGroupEffect->setNodeType( GetEffectNodeType() );
659 else if( nIndex > 0 )
661 bool bAtParagraphBegin = false;
662 if(!bTextReverse)
663 bAtParagraphBegin = pGroupEffect->getParaDepth() < nParagraphLevel;
664 else
665 bAtParagraphBegin = !pLastEffect || pLastEffect->getParaDepth() < nParagraphLevel;
666 if( bAtParagraphBegin )
667 pGroupEffect->setNodeType( GetEffectNodeType() );
668 else if( GetTextAnimationType() == presentation::TextAnimationType::BY_PARAGRAPH )
669 pGroupEffect->setNodeType( presentation::EffectNodeType::WITH_PREVIOUS );
670 else
671 pGroupEffect->setNodeType( presentation::EffectNodeType::AFTER_PREVIOUS );
673 pLastEffect = pGroupEffect;
674 nIndex++;
678 pMainSequence->rebuild();
681 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */