1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <com/sun/star/presentation/EffectPresetClass.hpp>
21 #include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
22 #include <com/sun/star/animations/AnimationNodeType.hpp>
23 #include <com/sun/star/animations/ParallelTimeContainer.hpp>
24 #include <com/sun/star/view/XSelectionSupplier.hpp>
25 #include <com/sun/star/document/XActionLockable.hpp>
26 #include <com/sun/star/drawing/XDrawView.hpp>
27 #include <com/sun/star/drawing/XShape.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/presentation/EffectNodeType.hpp>
30 #include <com/sun/star/presentation/EffectCommands.hpp>
31 #include <com/sun/star/animations/AnimationTransformType.hpp>
32 #include <com/sun/star/text/XTextRangeCompare.hpp>
33 #include <com/sun/star/container/XEnumerationAccess.hpp>
34 #include <com/sun/star/container/XIndexAccess.hpp>
35 #include <com/sun/star/presentation/ParagraphTarget.hpp>
36 #include <com/sun/star/text/XText.hpp>
37 #include <com/sun/star/drawing/LineStyle.hpp>
38 #include <com/sun/star/drawing/FillStyle.hpp>
39 #include <comphelper/processfactory.hxx>
40 #include <comphelper/scopeguard.hxx>
41 #include <sfx2/dispatch.hxx>
42 #include <sfx2/viewfrm.hxx>
43 #include <tools/debug.hxx>
44 #include "STLPropertySet.hxx"
45 #include <CustomAnimationPane.hxx>
46 #include "CustomAnimationDialog.hxx"
47 #include <CustomAnimationList.hxx>
48 #include "motionpathtag.hxx"
49 #include <CustomAnimationPreset.hxx>
51 #include <comphelper/lok.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <sfx2/frame.hxx>
54 #include <comphelper/diagnose_ex.hxx>
56 #include <svx/svxids.hrc>
57 #include <DrawDocShell.hxx>
58 #include <ViewShellBase.hxx>
59 #include <DrawViewShell.hxx>
60 #include <DrawController.hxx>
61 #include <sdresid.hxx>
62 #include <drawview.hxx>
63 #include <slideshow.hxx>
64 #include <undoanim.hxx>
65 #include <optsitem.hxx>
67 #include <framework/FrameworkHelper.hxx>
69 #include <EventMultiplexer.hxx>
71 #include <strings.hrc>
75 #include <svx/strings.hrc>
76 #include <svx/dialmgr.hxx>
81 using namespace ::com::sun::star
;
82 using namespace ::com::sun::star::animations
;
83 using namespace ::com::sun::star::presentation
;
84 using namespace ::com::sun::star::text
;
86 using namespace ::com::sun::star::uno
;
87 using namespace ::com::sun::star::drawing
;
88 using ::com::sun::star::view::XSelectionSupplier
;
89 using ::com::sun::star::beans::XPropertySet
;
90 using ::com::sun::star::container::XIndexAccess
;
91 using ::com::sun::star::container::XEnumerationAccess
;
92 using ::com::sun::star::container::XEnumeration
;
93 using ::com::sun::star::text::XText
;
94 using ::sd::framework::FrameworkHelper
;
95 using ::com::sun::star::uno::UNO_QUERY
;
96 using ::com::sun::star::uno::UNO_QUERY_THROW
;
97 using ::com::sun::star::uno::Any
;
98 using ::com::sun::star::uno::Reference
;
99 using ::com::sun::star::uno::Exception
;
103 void fillRepeatComboBox(weld::ComboBox
& rBox
)
105 OUString
aNone( SdResId( STR_CUSTOMANIMATION_REPEAT_NONE
) );
106 rBox
.append_text(aNone
);
107 rBox
.append_text(OUString::number(2));
108 rBox
.append_text(OUString::number(3));
109 rBox
.append_text(OUString::number(4));
110 rBox
.append_text(OUString::number(5));
111 rBox
.append_text(OUString::number(10));
113 OUString
aUntilClick( SdResId( STR_CUSTOMANIMATION_REPEAT_UNTIL_NEXT_CLICK
) );
114 rBox
.append_text(aUntilClick
);
116 OUString
aEndOfSlide( SdResId( STR_CUSTOMANIMATION_REPEAT_UNTIL_END_OF_SLIDE
) );
117 rBox
.append_text(aEndOfSlide
);
120 CustomAnimationPane::CustomAnimationPane( weld::Widget
* pParent
, ViewShellBase
& rBase
)
121 : PanelLayout(pParent
, "CustomAnimationsPanel", "modules/simpress/ui/customanimationspanel.ui")
124 , mxFTAnimation(m_xBuilder
->weld_label("effectlabel"))
125 , mxCustomAnimationList(new CustomAnimationList(m_xBuilder
->weld_tree_view("custom_animation_list"),
126 m_xBuilder
->weld_label("custom_animation_label"),
127 m_xBuilder
->weld_widget("custom_animation_label_parent")))
128 , mxPBAddEffect(m_xBuilder
->weld_button("add_effect"))
129 , mxPBRemoveEffect(m_xBuilder
->weld_button("remove_effect"))
130 , mxPBMoveUp(m_xBuilder
->weld_button("move_up"))
131 , mxPBMoveDown(m_xBuilder
->weld_button("move_down"))
132 , mxFTCategory(m_xBuilder
->weld_label("categorylabel"))
133 , mxLBCategory(m_xBuilder
->weld_combo_box("categorylb"))
134 , mxFTEffect(m_xBuilder
->weld_label("effect_label"))
135 , mxLBAnimation(m_xBuilder
->weld_tree_view("effect_list"))
136 , mxFTStart(m_xBuilder
->weld_label("start_effect"))
137 , mxLBStart(m_xBuilder
->weld_combo_box("start_effect_list"))
138 , mxFTProperty(m_xBuilder
->weld_label("effect_property"))
139 , mxPlaceholderBox(m_xBuilder
->weld_container("placeholder"))
140 , mxPBPropertyMore(m_xBuilder
->weld_button("more_properties"))
141 , mxFTDuration(m_xBuilder
->weld_label("effect_duration"))
142 , mxCBXDuration(m_xBuilder
->weld_metric_spin_button("anim_duration", FieldUnit::SECOND
))
143 , mxFTStartDelay(m_xBuilder
->weld_label("delay_label"))
144 , mxMFStartDelay(m_xBuilder
->weld_metric_spin_button("delay_value", FieldUnit::SECOND
))
145 , mxCBAutoPreview(m_xBuilder
->weld_check_button("auto_preview"))
146 , mxPBPlay(m_xBuilder
->weld_button("play"))
147 , maIdle("sd idle treeview select")
148 , mnLastSelectedAnimation(-1)
149 , mnPropertyType(nPropertyTypeNone
)
151 , mnPolygonPathPos(-1)
152 , mnFreeformPathPos(-1)
153 , maLateInitTimer("sd CustomAnimationPane maLateInitTimer")
158 css::ui::LayoutSize
CustomAnimationPane::GetHeightForWidth(const sal_Int32
/*nWidth*/)
160 sal_Int32 nMinimumHeight
= get_preferred_size().Height();
161 return css::ui::LayoutSize(nMinimumHeight
, -1, nMinimumHeight
);
164 void CustomAnimationPane::initialize()
166 mxLBAnimation
->connect_changed(LINK(this, CustomAnimationPane
, AnimationSelectHdl
));
167 mxCustomAnimationList
->setController( static_cast<ICustomAnimationListController
*> ( this ) );
168 mxCustomAnimationList
->set_size_request(mxCustomAnimationList
->get_approximate_digit_width() * 15,
169 mxCustomAnimationList
->get_height_rows(4));
171 mxLBAnimation
->set_size_request(mxLBAnimation
->get_approximate_digit_width() * 15,
172 mxLBAnimation
->get_height_rows(4));
174 maStrProperty
= mxFTProperty
->get_label();
176 mxPBAddEffect
->connect_clicked( LINK( this, CustomAnimationPane
, implClickHdl
) );
177 mxPBRemoveEffect
->connect_clicked( LINK( this, CustomAnimationPane
, implClickHdl
) );
178 mxLBStart
->connect_changed( LINK( this, CustomAnimationPane
, implControlListBoxHdl
) );
179 mxCBXDuration
->connect_value_changed(LINK( this, CustomAnimationPane
, DurationModifiedHdl
));
180 mxPBPropertyMore
->connect_clicked( LINK( this, CustomAnimationPane
, implClickHdl
) );
181 mxPBMoveUp
->connect_clicked( LINK( this, CustomAnimationPane
, implClickHdl
) );
182 mxPBMoveDown
->connect_clicked( LINK( this, CustomAnimationPane
, implClickHdl
) );
183 mxPBPlay
->connect_clicked( LINK( this, CustomAnimationPane
, implClickHdl
) );
184 mxCBAutoPreview
->connect_toggled( LINK( this, CustomAnimationPane
, implToggleHdl
) );
185 mxLBCategory
->connect_changed( LINK(this, CustomAnimationPane
, UpdateAnimationLB
) );
186 mxMFStartDelay
->connect_value_changed( LINK(this, CustomAnimationPane
, DelayModifiedHdl
) );
187 mxMFStartDelay
->connect_focus_out(LINK( this, CustomAnimationPane
, DelayLoseFocusHdl
));
189 maIdle
.SetPriority(TaskPriority::DEFAULT
);
190 maIdle
.SetInvokeHandler(LINK(this, CustomAnimationPane
, SelectionHandler
));
192 maStrModify
= mxFTEffect
->get_label();
194 // get current controller and initialize listeners
197 mxView
.set(mrBase
.GetController(), UNO_QUERY
);
202 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::CustomAnimationPane()" );
205 // tdf#137637 keep user selection during initialization
206 ScopeLockGuard
aGuard(maSelectionLock
);
207 // get current page and update custom animation list
208 onChangeCurrentPage();
210 // Wait a short time before the presets list is created. This gives the
211 // system time to paint the control.
212 maLateInitTimer
.SetTimeout(100);
213 maLateInitTimer
.SetInvokeHandler(LINK(this, CustomAnimationPane
, lateInitCallback
));
214 maLateInitTimer
.Start();
217 CustomAnimationPane::~CustomAnimationPane()
219 maLateInitTimer
.Stop();
223 MotionPathTagVector aTags
;
224 aTags
.swap( maMotionPathTags
);
225 for (auto const& tag
: aTags
)
228 mxPBAddEffect
.reset();
229 mxPBRemoveEffect
.reset();
233 mxLBSubControl
.reset();
234 mxFTProperty
.reset();
235 mxPlaceholderBox
.reset();
236 mxPBPropertyMore
.reset();
237 mxFTDuration
.reset();
238 mxCBXDuration
.reset();
239 mxFTStartDelay
.reset();
240 mxMFStartDelay
.reset();
241 mxCustomAnimationList
.reset();
243 mxPBMoveDown
.reset();
245 mxCBAutoPreview
.reset();
246 mxFTCategory
.reset();
247 mxLBCategory
.reset();
248 mxFTAnimation
.reset();
249 mxLBAnimation
.reset();
252 void CustomAnimationPane::addUndo()
254 SfxUndoManager
* pManager
= mrBase
.GetDocShell()->GetUndoManager();
257 SdPage
* pPage
= SdPage::getImplementation( mxCurrentPage
);
259 pManager
->AddUndoAction( std::make_unique
<UndoAnimation
>( mrBase
.GetDocShell()->GetDoc(), pPage
) );
263 void CustomAnimationPane::addListener()
265 Link
<tools::EventMultiplexerEvent
&,void> aLink( LINK(this,CustomAnimationPane
,EventMultiplexerListener
) );
266 mrBase
.GetEventMultiplexer()->AddEventListener(aLink
);
269 void CustomAnimationPane::removeListener()
271 Link
<tools::EventMultiplexerEvent
&,void> aLink( LINK(this,CustomAnimationPane
,EventMultiplexerListener
) );
272 mrBase
.GetEventMultiplexer()->RemoveEventListener( aLink
);
275 IMPL_LINK(CustomAnimationPane
,EventMultiplexerListener
,
276 tools::EventMultiplexerEvent
&, rEvent
, void)
278 switch (rEvent
.meEventId
)
280 case EventMultiplexerEventId::EditViewSelection
:
281 onSelectionChanged();
284 case EventMultiplexerEventId::CurrentPageChanged
:
285 onChangeCurrentPage();
288 case EventMultiplexerEventId::MainViewAdded
:
289 // At this moment the controller may not yet been set at model
290 // or ViewShellBase. Take it from the view shell passed with
292 if (mrBase
.GetMainViewShell() != nullptr)
294 if( mrBase
.GetMainViewShell()->GetShellType() == ViewShell::ST_IMPRESS
)
296 mxView
= mrBase
.GetDrawController();
297 onSelectionChanged();
298 onChangeCurrentPage();
303 case EventMultiplexerEventId::MainViewRemoved
:
305 mxCurrentPage
= nullptr;
309 case EventMultiplexerEventId::Disposing
:
311 onSelectionChanged();
312 onChangeCurrentPage();
314 case EventMultiplexerEventId::EndTextEdit
:
315 if (mpMainSequence
&& rEvent
.mpUserData
)
316 mxCustomAnimationList
->update( mpMainSequence
);
322 static sal_Int32
getPropertyType( std::u16string_view rProperty
)
324 if ( rProperty
== u
"Direction" )
325 return nPropertyTypeDirection
;
327 if ( rProperty
== u
"Spokes" )
328 return nPropertyTypeSpokes
;
330 if ( rProperty
== u
"Zoom" )
331 return nPropertyTypeZoom
;
333 if ( rProperty
== u
"Accelerate" )
334 return nPropertyTypeAccelerate
;
336 if ( rProperty
== u
"Decelerate" )
337 return nPropertyTypeDecelerate
;
339 if ( rProperty
== u
"Color1" )
340 return nPropertyTypeFirstColor
;
342 if ( rProperty
== u
"Color2" )
343 return nPropertyTypeSecondColor
;
345 if ( rProperty
== u
"FillColor" )
346 return nPropertyTypeFillColor
;
348 if ( rProperty
== u
"ColorStyle" )
349 return nPropertyTypeColorStyle
;
351 if ( rProperty
== u
"AutoReverse" )
352 return nPropertyTypeAutoReverse
;
354 if ( rProperty
== u
"FontStyle" )
355 return nPropertyTypeFont
;
357 if ( rProperty
== u
"CharColor" )
358 return nPropertyTypeCharColor
;
360 if ( rProperty
== u
"CharHeight" )
361 return nPropertyTypeCharHeight
;
363 if ( rProperty
== u
"CharDecoration" )
364 return nPropertyTypeCharDecoration
;
366 if ( rProperty
== u
"LineColor" )
367 return nPropertyTypeLineColor
;
369 if ( rProperty
== u
"Rotate" )
370 return nPropertyTypeRotate
;
372 if ( rProperty
== u
"Transparency" )
373 return nPropertyTypeTransparency
;
375 if ( rProperty
== u
"Color" )
376 return nPropertyTypeColor
;
378 if ( rProperty
== u
"Scale" )
379 return nPropertyTypeScale
;
381 return nPropertyTypeNone
;
384 OUString
getPropertyName( sal_Int32 nPropertyType
)
386 switch( nPropertyType
)
388 case nPropertyTypeDirection
:
389 return SdResId(STR_CUSTOMANIMATION_DIRECTION_PROPERTY
);
391 case nPropertyTypeSpokes
:
392 return SdResId(STR_CUSTOMANIMATION_SPOKES_PROPERTY
);
394 case nPropertyTypeFirstColor
:
395 return SdResId(STR_CUSTOMANIMATION_FIRST_COLOR_PROPERTY
);
397 case nPropertyTypeSecondColor
:
398 return SdResId(STR_CUSTOMANIMATION_SECOND_COLOR_PROPERTY
);
400 case nPropertyTypeZoom
:
401 return SdResId(STR_CUSTOMANIMATION_ZOOM_PROPERTY
);
403 case nPropertyTypeFillColor
:
404 return SdResId(STR_CUSTOMANIMATION_FILL_COLOR_PROPERTY
);
406 case nPropertyTypeColorStyle
:
407 return SdResId(STR_CUSTOMANIMATION_STYLE_PROPERTY
);
409 case nPropertyTypeFont
:
410 return SdResId(STR_CUSTOMANIMATION_FONT_PROPERTY
);
412 case nPropertyTypeCharHeight
:
413 return SdResId(STR_CUSTOMANIMATION_SIZE_PROPERTY
);
415 case nPropertyTypeCharColor
:
416 return SdResId(STR_CUSTOMANIMATION_FONT_COLOR_PROPERTY
);
418 case nPropertyTypeCharHeightStyle
:
419 return SdResId(STR_CUSTOMANIMATION_FONT_SIZE_STYLE_PROPERTY
);
421 case nPropertyTypeCharDecoration
:
422 return SdResId(STR_CUSTOMANIMATION_FONT_STYLE_PROPERTY
);
424 case nPropertyTypeLineColor
:
425 return SdResId(STR_CUSTOMANIMATION_LINE_COLOR_PROPERTY
);
427 case nPropertyTypeRotate
:
428 return SdResId(STR_CUSTOMANIMATION_AMOUNT_PROPERTY
);
430 case nPropertyTypeColor
:
431 return SdResId(STR_CUSTOMANIMATION_COLOR_PROPERTY
);
433 case nPropertyTypeTransparency
:
434 return SdResId(STR_CUSTOMANIMATION_AMOUNT_PROPERTY
);
436 case nPropertyTypeScale
:
437 return SdResId(STR_CUSTOMANIMATION_SCALE_PROPERTY
);
443 void CustomAnimationPane::updateControls()
445 mxFTDuration
->set_sensitive(mxView
.is());
446 mxCBXDuration
->set_sensitive(mxView
.is());
447 mxCustomAnimationList
->set_sensitive(mxView
.is());
448 if (comphelper::LibreOfficeKit::isActive())
451 mxCBAutoPreview
->set_active(false);
452 mxCBAutoPreview
->hide();
456 mxPBPlay
->set_sensitive(mxView
.is());
457 mxCBAutoPreview
->set_sensitive(mxView
.is());
462 mxPBAddEffect
->set_sensitive(false);
463 mxPBRemoveEffect
->set_sensitive(false);
464 mxFTStart
->set_sensitive(false);
465 mxLBStart
->set_sensitive(false);
466 mxPBPropertyMore
->set_sensitive(false);
467 mxPlaceholderBox
->set_sensitive(false);
468 mxFTProperty
->set_sensitive(false);
469 mxFTCategory
->set_sensitive(false);
470 mxLBCategory
->set_sensitive(false);
471 mxFTAnimation
->set_sensitive(false);
472 mxLBAnimation
->set_sensitive(false);
473 mxFTStartDelay
->set_sensitive(false);
474 mxMFStartDelay
->set_sensitive(false);
475 mxLBAnimation
->clear();
476 mnLastSelectedAnimation
= -1;
477 mxCustomAnimationList
->clear();
481 const int nSelectionCount
= maListSelection
.size();
483 mxPBAddEffect
->set_sensitive( maViewSelection
.hasValue() );
484 mxPBRemoveEffect
->set_sensitive(nSelectionCount
!= 0);
485 bool bIsSelected
= (nSelectionCount
> 0);
489 mxFTAnimation
->set_sensitive(true);
490 mxLBAnimation
->set_sensitive(true);
494 mxFTAnimation
->set_sensitive(false);
495 mxLBAnimation
->set_sensitive(false);
496 mxLBAnimation
->clear();
497 mnLastSelectedAnimation
= -1;
500 mxLBCategory
->set_sensitive(bIsSelected
);
501 mxFTCategory
->set_sensitive(bIsSelected
);
503 mxFTStart
->set_sensitive(nSelectionCount
> 0);
504 mxLBStart
->set_sensitive(nSelectionCount
> 0);
505 mxPlaceholderBox
->set_sensitive(nSelectionCount
> 0);
506 mxPBPropertyMore
->set_sensitive(nSelectionCount
> 0);
507 mxFTStartDelay
->set_sensitive(nSelectionCount
> 0);
508 mxMFStartDelay
->set_sensitive(nSelectionCount
> 0);
510 mxFTProperty
->set_label(maStrProperty
);
512 sal_Int32 nOldPropertyType
= mnPropertyType
;
514 mnPropertyType
= nPropertyTypeNone
;
518 CustomAnimationEffectPtr pEffect
= maListSelection
.front();
520 OUString
aUIName( CustomAnimationPresets::getCustomAnimationPresets().getUINameForPresetId( pEffect
->getPresetId() ) );
522 OUString
aTemp( maStrModify
);
524 if( !aUIName
.isEmpty() )
526 aTemp
+= " " + aUIName
;
527 mxFTEffect
->set_label( aTemp
);
531 CustomAnimationPresetPtr pDescriptor
= CustomAnimationPresets::getCustomAnimationPresets().getEffectDescriptor( pEffect
->getPresetId() );
534 std::vector
<OUString
> aProperties( pDescriptor
->getProperties() );
535 if( !aProperties
.empty() )
537 mnPropertyType
= getPropertyType( aProperties
.front() );
539 mxFTProperty
->set_label( getPropertyName( mnPropertyType
) );
541 aValue
= getProperty1Value( mnPropertyType
, pEffect
);
545 sal_Int32 nNewPropertyType
= mnPropertyType
;
546 // if there is no value, then the control will be disabled, just show a disabled Direction box in that
547 // case to have something to fill the space
548 if (!aValue
.hasValue())
549 nNewPropertyType
= nPropertyTypeDirection
;
551 if (!mxLBSubControl
|| nOldPropertyType
!= nNewPropertyType
)
553 // for LOK destroy old widgets first
554 mxLBSubControl
.reset(nullptr);
555 // then create new control, to keep correct pointers for actions
556 mxLBSubControl
= SdPropertySubControl::create(nNewPropertyType
, mxFTProperty
.get(), mxPlaceholderBox
.get(), GetFrameWeld(), aValue
, pEffect
->getPresetId(), LINK(this, CustomAnimationPane
, implPropertyHdl
));
560 mxLBSubControl
->setValue(aValue
, pEffect
->getPresetId());
563 bool bEnable
= aValue
.hasValue();
564 mxPlaceholderBox
->set_sensitive( bEnable
);
565 mxFTProperty
->set_sensitive( bEnable
);
569 mxPBPropertyMore
->set_sensitive( false );
570 mxFTStartDelay
->set_sensitive( false );
571 mxMFStartDelay
->set_sensitive( false );
573 sal_Int32 nCategoryPos
= -1;
574 switch(pEffect
->getPresetClass())
576 case EffectPresetClass::ENTRANCE
: nCategoryPos
= 0; break;
577 case EffectPresetClass::EMPHASIS
: nCategoryPos
= 1; break;
578 case EffectPresetClass::EXIT
: nCategoryPos
= 2; break;
579 case EffectPresetClass::MOTIONPATH
: nCategoryPos
= 3; break;
583 switch(pEffect
->getCommand())
585 case EffectCommands::TOGGLEPAUSE
:
586 case EffectCommands::STOP
:
587 case EffectCommands::PLAY
:
588 nCategoryPos
= 4; break;
592 mxLBCategory
->set_active(nCategoryPos
);
594 fillAnimationLB( pEffect
->hasText() );
596 OUString rsPresetId
= pEffect
->getPresetId();
597 sal_Int32 nAnimationPos
= mxLBAnimation
->n_children();
598 while( nAnimationPos
-- )
600 auto pEntryData
= weld::fromId
<CustomAnimationPresetPtr
*>(mxLBAnimation
->get_id(nAnimationPos
));
603 CustomAnimationPresetPtr
& pPtr
= *pEntryData
;
604 if( pPtr
&& pPtr
->getPresetId() == rsPresetId
)
606 mxLBAnimation
->select( nAnimationPos
);
607 mnLastSelectedAnimation
= nAnimationPos
;
613 // If preset id is missing and category is motion path.
614 if (nAnimationPos
< 0 && nCategoryPos
== 3)
616 if (rsPresetId
== "libo-motionpath-curve")
618 mxLBAnimation
->select(mnCurvePathPos
);
619 mnLastSelectedAnimation
= mnCurvePathPos
;
621 else if (rsPresetId
== "libo-motionpath-polygon")
623 mxLBAnimation
->select(mnPolygonPathPos
);
624 mnLastSelectedAnimation
= mnPolygonPathPos
;
626 else if (rsPresetId
== "libo-motionpath-freeform-line")
628 mxLBAnimation
->select(mnFreeformPathPos
);
629 mnLastSelectedAnimation
= mnFreeformPathPos
;
633 sal_uInt16 nPos
= 0xffff;
635 sal_Int16 nNodeType
= pEffect
->getNodeType();
638 case EffectNodeType::ON_CLICK
: nPos
= 0; break;
639 case EffectNodeType::WITH_PREVIOUS
: nPos
= 1; break;
640 case EffectNodeType::AFTER_PREVIOUS
: nPos
= 2; break;
643 mxLBStart
->set_active( nPos
);
645 double fDuration
= pEffect
->getDuration();
646 const bool bHasSpeed
= fDuration
> 0.001;
648 mxFTDuration
->set_sensitive(bHasSpeed
);
649 mxCBXDuration
->set_sensitive(bHasSpeed
);
653 mxCBXDuration
->set_value(fDuration
*100.0, FieldUnit::NONE
);
656 mxPBPropertyMore
->set_sensitive(true);
658 mxFTStartDelay
->set_sensitive(true);
659 mxMFStartDelay
->set_sensitive(true);
660 double fBegin
= pEffect
->getBegin();
661 mxMFStartDelay
->set_value(fBegin
*10.0, FieldUnit::NONE
);
665 // use an empty direction box to fill the space
666 if (!mxLBSubControl
|| (nOldPropertyType
!= nPropertyTypeDirection
&& nOldPropertyType
!= nPropertyTypeNone
))
668 // for LOK destroy old widgets first
669 mxLBSubControl
.reset(nullptr);
670 // then create new control, to keep correct pointers for actions
671 mxLBSubControl
= SdPropertySubControl::create(nPropertyTypeDirection
, mxFTProperty
.get(), mxPlaceholderBox
.get(), GetFrameWeld(), uno::Any(), OUString(), LINK(this, CustomAnimationPane
, implPropertyHdl
));
674 mxLBSubControl
->setValue(uno::Any(), OUString());
676 mxPlaceholderBox
->set_sensitive(false);
677 mxFTProperty
->set_sensitive(false);
678 mxFTStartDelay
->set_sensitive(false);
679 mxMFStartDelay
->set_sensitive(false);
680 mxPBPropertyMore
->set_sensitive(false);
681 mxFTDuration
->set_sensitive(false);
682 mxCBXDuration
->set_sensitive(false);
683 mxCBXDuration
->set_text(OUString());
684 mxFTEffect
->set_label(maStrModify
);
687 bool bEnableUp
= true;
688 bool bEnableDown
= true;
689 if( nSelectionCount
== 0 )
696 if( mpMainSequence
->find( maListSelection
.front() ) == mpMainSequence
->getBegin() )
699 EffectSequence::iterator
aIter( mpMainSequence
->find( maListSelection
.back() ) );
700 if( aIter
== mpMainSequence
->getEnd() )
710 while( (aIter
!= mpMainSequence
->getEnd()) && !(mxCustomAnimationList
->isExpanded(*aIter
) ) );
712 if( aIter
== mpMainSequence
->getEnd() )
716 if( bEnableUp
|| bEnableDown
)
718 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
720 EffectSequenceHelper
* pSequence
= nullptr;
721 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
725 if( pSequence
== nullptr )
727 pSequence
= pEffect
->getEffectSequence();
731 if( pSequence
!= pEffect
->getEffectSequence() )
743 mxPBMoveUp
->set_sensitive(mxView
.is() && bEnableUp
);
744 mxPBMoveDown
->set_sensitive(mxView
.is() && bEnableDown
);
746 SdOptions
* pOptions
= SD_MOD()->GetSdOptions(DocumentType::Impress
);
747 mxCBAutoPreview
->set_active(pOptions
->IsPreviewChangedEffects());
749 updateMotionPathTags();
752 static bool updateMotionPathImpl( CustomAnimationPane
& rPane
, ::sd::View
& rView
, EffectSequence::iterator aIter
, const EffectSequence::iterator
& aEnd
, MotionPathTagVector
& rOldTags
, MotionPathTagVector
& rNewTags
)
754 bool bChanges
= false;
755 while( aIter
!= aEnd
)
757 CustomAnimationEffectPtr
pEffect( *aIter
++ );
758 if( pEffect
&& pEffect
->getPresetClass() == css::presentation::EffectPresetClass::MOTIONPATH
)
760 rtl::Reference
< MotionPathTag
> xMotionPathTag
;
761 // first try to find if there is already a tag for this
762 auto aMIter
= std::find_if(rOldTags
.begin(), rOldTags
.end(),
763 [&pEffect
](const rtl::Reference
<MotionPathTag
>& xTag
) { return xTag
->getEffect() == pEffect
; });
764 if (aMIter
!= rOldTags
.end())
766 rtl::Reference
< MotionPathTag
> xTag( *aMIter
);
767 if( !xTag
->isDisposed() )
769 xMotionPathTag
= xTag
;
770 rOldTags
.erase( aMIter
);
774 // if not found, create new one
775 if( !xMotionPathTag
.is() )
777 xMotionPathTag
.set( new MotionPathTag( rPane
, rView
, pEffect
) );
781 if( xMotionPathTag
.is() )
782 rNewTags
.push_back( xMotionPathTag
);
789 void CustomAnimationPane::updateMotionPathTags()
791 bool bChanges
= false;
793 MotionPathTagVector aTags
;
794 aTags
.swap( maMotionPathTags
);
796 ::sd::View
* pView
= nullptr;
800 std::shared_ptr
<ViewShell
> xViewShell( mrBase
.GetMainViewShell() );
802 pView
= xViewShell
->GetView();
805 if (mpMainSequence
&& pView
)
807 bChanges
= updateMotionPathImpl( *this, *pView
, mpMainSequence
->getBegin(), mpMainSequence
->getEnd(), aTags
, maMotionPathTags
);
809 auto rInteractiveSequenceVector
= mpMainSequence
->getInteractiveSequenceVector();
810 for (InteractiveSequencePtr
const& pIS
: rInteractiveSequenceVector
)
812 bChanges
|= updateMotionPathImpl( *this, *pView
, pIS
->getBegin(), pIS
->getEnd(), aTags
, maMotionPathTags
);
819 for( rtl::Reference
< MotionPathTag
>& xTag
: aTags
)
825 if( bChanges
&& pView
)
826 pView
->updateHandles();
829 void CustomAnimationPane::onSelectionChanged()
831 if( maSelectionLock
.isLocked() )
834 ScopeLockGuard
aGuard( maSelectionLock
);
836 if( mxView
.is() ) try
838 Reference
< XSelectionSupplier
> xSel( mxView
, UNO_QUERY_THROW
);
839 maViewSelection
= xSel
->getSelection();
840 mxCustomAnimationList
->onSelectionChanged( maViewSelection
);
845 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::onSelectionChanged()" );
849 void CustomAnimationPane::onDoubleClick()
854 void CustomAnimationPane::onContextMenu(const OUString
&rIdent
)
856 if (rIdent
== "onclick")
857 onChangeStart( EffectNodeType::ON_CLICK
);
858 else if (rIdent
== "withprev")
859 onChangeStart( EffectNodeType::WITH_PREVIOUS
);
860 else if (rIdent
== "afterprev")
861 onChangeStart( EffectNodeType::AFTER_PREVIOUS
);
862 else if (rIdent
== "options")
864 else if (rIdent
== "timing")
865 showOptions("timing");
866 else if (rIdent
== "remove")
868 else if (rIdent
== "create" && maViewSelection
.hasValue())
873 static void addValue( const std::unique_ptr
<STLPropertySet
>& pSet
, sal_Int32 nHandle
, const Any
& rValue
)
875 switch( pSet
->getPropertyState( nHandle
) )
877 case STLPropertyState::Ambiguous
:
878 // value is already ambiguous, do nothing
880 case STLPropertyState::Direct
:
881 // set to ambiguous if existing value is different
882 if( rValue
!= pSet
->getPropertyValue( nHandle
) )
883 pSet
->setPropertyState( nHandle
, STLPropertyState::Ambiguous
);
885 case STLPropertyState::Default
:
886 // just set new value
887 pSet
->setPropertyValue( nHandle
, rValue
);
892 static sal_Int32
calcMaxParaDepth( const Reference
< XShape
>& xTargetShape
)
894 sal_Int32 nMaxParaDepth
= -1;
896 if( xTargetShape
.is() )
898 Reference
< XEnumerationAccess
> xText( xTargetShape
, UNO_QUERY
);
901 Reference
< XPropertySet
> xParaSet
;
903 Reference
< XEnumeration
> xEnumeration( xText
->createEnumeration(), UNO_SET_THROW
);
904 while( xEnumeration
->hasMoreElements() )
906 xEnumeration
->nextElement() >>= xParaSet
;
909 sal_Int32 nParaDepth
= 0;
910 xParaSet
->getPropertyValue( "NumberingLevel" ) >>= nParaDepth
;
912 if( nParaDepth
> nMaxParaDepth
)
913 nMaxParaDepth
= nParaDepth
;
919 return nMaxParaDepth
+ 1;
922 Any
CustomAnimationPane::getProperty1Value( sal_Int32 nType
, const CustomAnimationEffectPtr
& pEffect
)
926 case nPropertyTypeDirection
:
927 case nPropertyTypeSpokes
:
928 case nPropertyTypeZoom
:
929 return Any( pEffect
->getPresetSubType() );
931 case nPropertyTypeColor
:
932 case nPropertyTypeFillColor
:
933 case nPropertyTypeFirstColor
:
934 case nPropertyTypeSecondColor
:
935 case nPropertyTypeCharColor
:
936 case nPropertyTypeLineColor
:
938 const sal_Int32 nIndex
= (nPropertyTypeFirstColor
== nType
) ? 0 : 1;
939 return pEffect
->getColor( nIndex
);
942 case nPropertyTypeFont
:
943 return pEffect
->getProperty( AnimationNodeType::SET
, u
"CharFontName" , EValue::To
);
945 case nPropertyTypeCharHeight
:
947 static const OUStringLiteral
aAttributeName( u
"CharHeight" );
948 Any
aValue( pEffect
->getProperty( AnimationNodeType::SET
, aAttributeName
, EValue::To
) );
949 if( !aValue
.hasValue() )
950 aValue
= pEffect
->getProperty( AnimationNodeType::ANIMATE
, aAttributeName
, EValue::To
);
954 case nPropertyTypeRotate
:
955 return pEffect
->getTransformationProperty( AnimationTransformType::ROTATE
, EValue::By
);
957 case nPropertyTypeTransparency
:
958 return pEffect
->getProperty( AnimationNodeType::SET
, u
"Opacity" , EValue::To
);
960 case nPropertyTypeScale
:
961 return pEffect
->getTransformationProperty( AnimationTransformType::SCALE
, EValue::By
);
963 case nPropertyTypeCharDecoration
:
965 Sequence
< Any
> aValues
{
966 pEffect
->getProperty( AnimationNodeType::SET
, u
"CharWeight" , EValue::To
),
967 pEffect
->getProperty( AnimationNodeType::SET
, u
"CharPosture" , EValue::To
),
968 pEffect
->getProperty( AnimationNodeType::SET
, u
"CharUnderline" , EValue::To
)
970 return Any( aValues
);
978 bool CustomAnimationPane::setProperty1Value( sal_Int32 nType
, const CustomAnimationEffectPtr
& pEffect
, const Any
& rValue
)
980 bool bEffectChanged
= false;
983 case nPropertyTypeDirection
:
984 case nPropertyTypeSpokes
:
985 case nPropertyTypeZoom
:
987 OUString aPresetSubType
;
988 rValue
>>= aPresetSubType
;
989 if( aPresetSubType
!= pEffect
->getPresetSubType() )
991 CustomAnimationPresets::getCustomAnimationPresets().changePresetSubType( pEffect
, aPresetSubType
);
992 bEffectChanged
= true;
997 case nPropertyTypeFillColor
:
998 case nPropertyTypeColor
:
999 case nPropertyTypeFirstColor
:
1000 case nPropertyTypeSecondColor
:
1001 case nPropertyTypeCharColor
:
1002 case nPropertyTypeLineColor
:
1004 const sal_Int32 nIndex
= (nPropertyTypeFirstColor
== nType
) ? 0 : 1;
1005 Any
aOldColor( pEffect
->getColor( nIndex
) );
1006 if( aOldColor
!= rValue
)
1008 pEffect
->setColor( nIndex
, rValue
);
1009 bEffectChanged
= true;
1014 case nPropertyTypeFont
:
1015 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::SET
, u
"CharFontName" , EValue::To
, rValue
);
1018 case nPropertyTypeCharHeight
:
1020 static const OUStringLiteral
aAttributeName( u
"CharHeight" );
1021 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::SET
, aAttributeName
, EValue::To
, rValue
);
1022 if( !bEffectChanged
)
1023 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::ANIMATE
, aAttributeName
, EValue::To
, rValue
);
1026 case nPropertyTypeRotate
:
1027 bEffectChanged
= pEffect
->setTransformationProperty( AnimationTransformType::ROTATE
, EValue::By
, rValue
);
1030 case nPropertyTypeTransparency
:
1031 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::SET
, u
"Opacity" , EValue::To
, rValue
);
1034 case nPropertyTypeScale
:
1035 bEffectChanged
= pEffect
->setTransformationProperty( AnimationTransformType::SCALE
, EValue::By
, rValue
);
1038 case nPropertyTypeCharDecoration
:
1040 Sequence
< Any
> aValues(3);
1042 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::SET
, u
"CharWeight" , EValue::To
, aValues
[0] );
1043 bEffectChanged
|= pEffect
->setProperty( AnimationNodeType::SET
, u
"CharPosture" , EValue::To
, aValues
[1] );
1044 bEffectChanged
|= pEffect
->setProperty( AnimationNodeType::SET
, u
"CharUnderline" , EValue::To
, aValues
[2] );
1050 return bEffectChanged
;
1053 static bool hasVisibleShape( const Reference
< XShape
>& xShape
)
1057 const OUString
sShapeType( xShape
->getShapeType() );
1059 if( sShapeType
== "com.sun.star.presentation.TitleTextShape" || sShapeType
== "com.sun.star.presentation.OutlinerShape" ||
1060 sShapeType
== "com.sun.star.presentation.SubtitleShape" || sShapeType
== "com.sun.star.drawing.TextShape" )
1062 Reference
< XPropertySet
> xSet( xShape
, UNO_QUERY_THROW
);
1064 FillStyle eFillStyle
;
1065 xSet
->getPropertyValue( "FillStyle" ) >>= eFillStyle
;
1067 css::drawing::LineStyle eLineStyle
;
1068 xSet
->getPropertyValue( "LineStyle" ) >>= eLineStyle
;
1070 return eFillStyle
!= FillStyle_NONE
|| eLineStyle
!= css::drawing::LineStyle_NONE
;
1079 std::unique_ptr
<STLPropertySet
> CustomAnimationPane::createSelectionSet()
1081 std::unique_ptr
<STLPropertySet
> pSet
= CustomAnimationDialog::createDefaultSet();
1083 pSet
->setPropertyValue( nHandleCurrentPage
, Any( mxCurrentPage
) );
1085 sal_Int32 nMaxParaDepth
= 0;
1087 // get options from selected effects
1088 const CustomAnimationPresets
& rPresets (CustomAnimationPresets::getCustomAnimationPresets());
1089 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
1091 EffectSequenceHelper
* pEffectSequence
= pEffect
->getEffectSequence();
1092 if( !pEffectSequence
)
1093 pEffectSequence
= mpMainSequence
.get();
1095 if( pEffect
->hasText() )
1097 sal_Int32 n
= calcMaxParaDepth(pEffect
->getTargetShape());
1098 if( n
> nMaxParaDepth
)
1102 addValue( pSet
, nHandleHasAfterEffect
, Any( pEffect
->hasAfterEffect() ) );
1103 addValue( pSet
, nHandleAfterEffectOnNextEffect
, Any( pEffect
->IsAfterEffectOnNext() ) );
1104 addValue( pSet
, nHandleDimColor
, pEffect
->getDimColor() );
1105 addValue( pSet
, nHandleIterateType
, Any( pEffect
->getIterateType() ) );
1107 // convert absolute time to percentage value
1108 // This calculation is done in float to avoid some rounding artifacts.
1109 float fIterateInterval
= static_cast<float>(pEffect
->getIterateInterval());
1110 if( pEffect
->getDuration() )
1111 fIterateInterval
= static_cast<float>(fIterateInterval
/ pEffect
->getDuration() );
1112 fIterateInterval
*= 100.0;
1113 addValue( pSet
, nHandleIterateInterval
, Any( static_cast<double>(fIterateInterval
) ) );
1115 addValue( pSet
, nHandleBegin
, Any( pEffect
->getBegin() ) );
1116 addValue( pSet
, nHandleDuration
, Any( pEffect
->getDuration() ) );
1117 addValue( pSet
, nHandleStart
, Any( pEffect
->getNodeType() ) );
1118 addValue( pSet
, nHandleRepeat
, pEffect
->getRepeatCount() );
1119 addValue( pSet
, nHandleEnd
, pEffect
->getEnd() );
1120 addValue( pSet
, nHandleRewind
, Any( pEffect
->getFill() ) );
1122 addValue( pSet
, nHandlePresetId
, Any( pEffect
->getPresetId() ) );
1124 addValue( pSet
, nHandleHasText
, Any( pEffect
->hasText() ) );
1126 addValue( pSet
, nHandleHasVisibleShape
, Any( hasVisibleShape( pEffect
->getTargetShape() ) ) );
1129 if( pEffect
->getAudio().is() )
1131 aSoundSource
= pEffect
->getAudio()->getSource();
1132 addValue( pSet
, nHandleSoundVolume
, Any( pEffect
->getAudio()->getVolume() ) );
1133 // todo addValue( pSet, nHandleSoundEndAfterSlide, makeAny( pEffect->getAudio()->getEndAfterSlide() ) );
1134 // this is now stored at the XCommand parameter sequence
1136 else if( pEffect
->getCommand() == EffectCommands::STOPAUDIO
)
1138 aSoundSource
<<= true;
1140 addValue( pSet
, nHandleSoundURL
, aSoundSource
);
1142 sal_Int32 nGroupId
= pEffect
->getGroupId();
1143 CustomAnimationTextGroupPtr pTextGroup
;
1144 if( nGroupId
!= -1 )
1145 pTextGroup
= pEffectSequence
->findGroup( nGroupId
);
1147 addValue( pSet
, nHandleTextGrouping
, Any( pTextGroup
? pTextGroup
->getTextGrouping() : sal_Int32(-1) ) );
1148 addValue( pSet
, nHandleAnimateForm
, Any( !pTextGroup
|| pTextGroup
->getAnimateForm() ) );
1149 addValue( pSet
, nHandleTextGroupingAuto
, Any( pTextGroup
? pTextGroup
->getTextGroupingAuto() : -1.0 ) );
1150 addValue( pSet
, nHandleTextReverse
, Any( pTextGroup
&& pTextGroup
->getTextReverse() ) );
1152 if( pEffectSequence
->getSequenceType() == EffectNodeType::INTERACTIVE_SEQUENCE
)
1154 InteractiveSequence
* pIS
= static_cast< InteractiveSequence
* >( pEffectSequence
);
1155 addValue( pSet
, nHandleTrigger
, Any( pIS
->getTriggerShape() ) );
1158 CustomAnimationPresetPtr pDescriptor
= rPresets
.getEffectDescriptor( pEffect
->getPresetId() );
1161 sal_Int32 nType
= nPropertyTypeNone
;
1163 std::vector
<OUString
> aProperties( pDescriptor
->getProperties() );
1164 if( !aProperties
.empty() )
1165 nType
= getPropertyType( aProperties
.front() );
1167 if( nType
!= nPropertyTypeNone
)
1169 addValue( pSet
, nHandleProperty1Type
, Any( nType
) );
1170 addValue( pSet
, nHandleProperty1Value
, getProperty1Value( nType
, pEffect
) );
1173 if( pDescriptor
->hasProperty( u
"Accelerate" ) )
1175 addValue( pSet
, nHandleAccelerate
, Any( pEffect
->getAcceleration() ) );
1178 if( pDescriptor
->hasProperty( u
"Decelerate" ) )
1180 addValue( pSet
, nHandleDecelerate
, Any( pEffect
->getDecelerate() ) );
1183 if( pDescriptor
->hasProperty( u
"AutoReverse" ) )
1185 addValue( pSet
, nHandleAutoReverse
, Any( pEffect
->getAutoReverse() ) );
1190 addValue( pSet
, nHandleMaxParaDepth
, Any( nMaxParaDepth
) );
1195 void CustomAnimationPane::changeSelection( STLPropertySet
const * pResultSet
, STLPropertySet
const * pOldSet
)
1197 // change selected effect
1198 bool bChanged
= false;
1200 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
1202 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
1204 DBG_ASSERT( pEffect
->getEffectSequence(), "sd::CustomAnimationPane::changeSelection(), dead effect in selection!" );
1205 if( !pEffect
->getEffectSequence() )
1208 double fDuration
= 0.0; // we might need this for iterate-interval
1209 if( pResultSet
->getPropertyState( nHandleDuration
) == STLPropertyState::Direct
)
1211 pResultSet
->getPropertyValue( nHandleDuration
) >>= fDuration
;
1215 fDuration
= pEffect
->getDuration();
1218 if( pResultSet
->getPropertyState( nHandleIterateType
) == STLPropertyState::Direct
)
1220 sal_Int16 nIterateType
= 0;
1221 pResultSet
->getPropertyValue( nHandleIterateType
) >>= nIterateType
;
1222 if( pEffect
->getIterateType() != nIterateType
)
1224 pEffect
->setIterateType( nIterateType
);
1229 if( pEffect
->getIterateType() )
1231 if( pResultSet
->getPropertyState( nHandleIterateInterval
) == STLPropertyState::Direct
)
1233 double fIterateInterval
= 0.0;
1234 pResultSet
->getPropertyValue( nHandleIterateInterval
) >>= fIterateInterval
;
1235 if( pEffect
->getIterateInterval() != fIterateInterval
)
1237 const double f
= fIterateInterval
* pEffect
->getDuration() / 100;
1238 pEffect
->setIterateInterval( f
);
1244 double fBegin
= 0.0;
1246 if( pResultSet
->getPropertyState( nHandleBegin
) == STLPropertyState::Direct
)
1247 pResultSet
->getPropertyValue( nHandleBegin
) >>= fBegin
;
1249 fBegin
= pEffect
->getBegin();
1251 if( pEffect
->getBegin() != fBegin
&& pResultSet
->getPropertyState( nHandleBegin
) == STLPropertyState::Direct
)
1253 pEffect
->setBegin( fBegin
);
1257 if( pResultSet
->getPropertyState( nHandleDuration
) == STLPropertyState::Direct
)
1259 if( pEffect
->getDuration() != fDuration
)
1261 pEffect
->setDuration( fDuration
);
1266 if( pResultSet
->getPropertyState( nHandleStart
) == STLPropertyState::Direct
)
1268 sal_Int16 nNodeType
= 0;
1269 pResultSet
->getPropertyValue( nHandleStart
) >>= nNodeType
;
1270 if( pEffect
->getNodeType() != nNodeType
)
1272 pEffect
->setNodeType( nNodeType
);
1277 if( pResultSet
->getPropertyState( nHandleRepeat
) == STLPropertyState::Direct
)
1279 Any
aRepeatCount( pResultSet
->getPropertyValue( nHandleRepeat
) );
1280 if( aRepeatCount
!= pEffect
->getRepeatCount() )
1282 pEffect
->setRepeatCount( aRepeatCount
);
1287 if( pResultSet
->getPropertyState( nHandleEnd
) == STLPropertyState::Direct
)
1289 Any
aEndValue( pResultSet
->getPropertyValue( nHandleEnd
) );
1290 if( pEffect
->getEnd() != aEndValue
)
1292 pEffect
->setEnd( aEndValue
);
1297 if( pResultSet
->getPropertyState( nHandleRewind
) == STLPropertyState::Direct
)
1299 sal_Int16 nFill
= 0;
1300 pResultSet
->getPropertyValue( nHandleRewind
) >>= nFill
;
1301 if( pEffect
->getFill() != nFill
)
1303 pEffect
->setFill( nFill
);
1308 if( pResultSet
->getPropertyState( nHandleHasAfterEffect
) == STLPropertyState::Direct
)
1310 bool bHasAfterEffect
= false;
1311 if( pResultSet
->getPropertyValue( nHandleHasAfterEffect
) >>= bHasAfterEffect
)
1313 if( pEffect
->hasAfterEffect() != bHasAfterEffect
)
1315 pEffect
->setHasAfterEffect( bHasAfterEffect
);
1321 if( pResultSet
->getPropertyState( nHandleAfterEffectOnNextEffect
) == STLPropertyState::Direct
)
1323 bool bAfterEffectOnNextEffect
= false;
1324 if( (pResultSet
->getPropertyValue( nHandleAfterEffectOnNextEffect
) >>= bAfterEffectOnNextEffect
)
1325 && (pEffect
->IsAfterEffectOnNext() != bAfterEffectOnNextEffect
) )
1327 pEffect
->setAfterEffectOnNext( bAfterEffectOnNextEffect
);
1332 if( pResultSet
->getPropertyState( nHandleDimColor
) == STLPropertyState::Direct
)
1334 Any
aDimColor( pResultSet
->getPropertyValue( nHandleDimColor
) );
1335 if( pEffect
->getDimColor() != aDimColor
)
1337 pEffect
->setDimColor( aDimColor
);
1342 if( pResultSet
->getPropertyState( nHandleAccelerate
) == STLPropertyState::Direct
)
1344 double fAccelerate
= 0.0;
1345 pResultSet
->getPropertyValue( nHandleAccelerate
) >>= fAccelerate
;
1346 if( pEffect
->getAcceleration() != fAccelerate
)
1348 pEffect
->setAcceleration( fAccelerate
);
1353 if( pResultSet
->getPropertyState( nHandleDecelerate
) == STLPropertyState::Direct
)
1355 double fDecelerate
= 0.0;
1356 pResultSet
->getPropertyValue( nHandleDecelerate
) >>= fDecelerate
;
1357 if( pEffect
->getDecelerate() != fDecelerate
)
1359 pEffect
->setDecelerate( fDecelerate
);
1364 if( pResultSet
->getPropertyState( nHandleAutoReverse
) == STLPropertyState::Direct
)
1366 bool bAutoReverse
= false;
1367 pResultSet
->getPropertyValue( nHandleAutoReverse
) >>= bAutoReverse
;
1368 if( pEffect
->getAutoReverse() != bAutoReverse
)
1370 pEffect
->setAutoReverse( bAutoReverse
);
1375 if( pResultSet
->getPropertyState( nHandleProperty1Value
) == STLPropertyState::Direct
)
1377 sal_Int32 nType
= 0;
1378 pOldSet
->getPropertyValue( nHandleProperty1Type
) >>= nType
;
1380 bChanged
|= setProperty1Value( nType
, pEffect
, pResultSet
->getPropertyValue( nHandleProperty1Value
) );
1383 if( pResultSet
->getPropertyState( nHandleSoundURL
) == STLPropertyState::Direct
)
1385 const Any
aSoundSource( pResultSet
->getPropertyValue( nHandleSoundURL
) );
1387 if( aSoundSource
.getValueType() == ::cppu::UnoType
<sal_Bool
>::get() )
1389 pEffect
->setStopAudio();
1395 aSoundSource
>>= aSoundURL
;
1397 if( !aSoundURL
.isEmpty() )
1399 if( !pEffect
->getAudio().is() )
1401 pEffect
->createAudio( aSoundSource
);
1406 if( pEffect
->getAudio()->getSource() != aSoundSource
)
1408 pEffect
->getAudio()->setSource( aSoundSource
);
1415 if( pEffect
->getAudio().is() || pEffect
->getStopAudio() )
1417 pEffect
->removeAudio();
1424 if( pResultSet
->getPropertyState( nHandleTrigger
) == STLPropertyState::Direct
)
1426 Reference
< XShape
> xTriggerShape
;
1427 pResultSet
->getPropertyValue( nHandleTrigger
) >>= xTriggerShape
;
1428 bChanged
|= mpMainSequence
->setTrigger( pEffect
, xTriggerShape
);
1432 const bool bHasTextGrouping
= pResultSet
->getPropertyState( nHandleTextGrouping
) == STLPropertyState::Direct
;
1433 const bool bHasAnimateForm
= pResultSet
->getPropertyState( nHandleAnimateForm
) == STLPropertyState::Direct
;
1434 const bool bHasTextGroupingAuto
= pResultSet
->getPropertyState( nHandleTextGroupingAuto
) == STLPropertyState::Direct
;
1435 const bool bHasTextReverse
= pResultSet
->getPropertyState( nHandleTextReverse
) == STLPropertyState::Direct
;
1437 if( bHasTextGrouping
|| bHasAnimateForm
|| bHasTextGroupingAuto
|| bHasTextReverse
)
1439 // we need to do a second pass for text grouping options
1440 // since changing them can cause effects to be removed
1441 // or replaced, we do this after we applied all other options
1444 sal_Int32 nTextGrouping
= 0;
1445 bool bAnimateForm
= true, bTextReverse
= false;
1446 double fTextGroupingAuto
= -1.0;
1448 if( bHasTextGrouping
)
1449 pResultSet
->getPropertyValue(nHandleTextGrouping
) >>= nTextGrouping
;
1451 pOldSet
->getPropertyValue(nHandleTextGrouping
) >>= nTextGrouping
;
1453 if( bHasAnimateForm
)
1454 pResultSet
->getPropertyValue(nHandleAnimateForm
) >>= bAnimateForm
;
1456 pOldSet
->getPropertyValue(nHandleAnimateForm
) >>= bAnimateForm
;
1458 if( bHasTextGroupingAuto
)
1459 pResultSet
->getPropertyValue(nHandleTextGroupingAuto
) >>= fTextGroupingAuto
;
1461 pOldSet
->getPropertyValue(nHandleTextGroupingAuto
) >>= fTextGroupingAuto
;
1463 if( bHasTextReverse
)
1464 pResultSet
->getPropertyValue(nHandleTextReverse
) >>= bTextReverse
;
1466 pOldSet
->getPropertyValue(nHandleTextReverse
) >>= bTextReverse
;
1468 EffectSequence
const aSelectedEffects( maListSelection
);
1469 for( CustomAnimationEffectPtr
const& pEffect
: aSelectedEffects
)
1471 EffectSequenceHelper
* pEffectSequence
= pEffect
->getEffectSequence();
1472 if( !pEffectSequence
)
1473 pEffectSequence
= mpMainSequence
.get();
1475 sal_Int32 nGroupId
= pEffect
->getGroupId();
1476 CustomAnimationTextGroupPtr pTextGroup
;
1477 if( nGroupId
!= -1 )
1479 // use existing group
1480 pTextGroup
= pEffectSequence
->findGroup( nGroupId
);
1484 // somethings changed so we need a group now
1485 pTextGroup
= pEffectSequence
->createTextGroup( pEffect
, nTextGrouping
, fTextGroupingAuto
, bAnimateForm
, bTextReverse
);
1490 /************************************************************************/
1492 Note, the setAnimateForm means set the animation from TextGroup to Object's Shape
1493 And on the UI in means "Animate attached shape" in "Effect Option" dialog
1494 The setTextGrouping means set animation to Object's Text,
1495 the nTextGrouping is Text Animation Type
1496 nTextGrouping = -1 is "As one Object", means no text animation.
1498 The previous call order first do the setTextGrouping and then do the setAnimateForm,
1499 that will cause such defect: in the setTextGrouping, the effect has been removed,
1500 but in setAnimateForm still need this effect, then a NULL pointer of that effect will
1501 be gotten, and cause crash.
1503 []bHasAnimateForm means the UI has changed, bAnimateForm is it value
1505 So if create a new textgroup animation, the following animation will never be run!
1506 Since the \A1\B0Animate attached shape\A1\B1 is default checked.
1507 And the bHasAnimateForm default is false, and if user uncheck it the value bAnimateForm will be false,
1508 it same as the TextGroup\A1\AFs default value, also could not be run setAnimateForm.
1509 if( bHasAnimateForm )
1511 if( pTextGroup->getAnimateForm() != bAnimateForm )
1513 pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1518 In setTextGrouping, there are three case:
1519 1. Create new text effects for empty TextGroup
1520 2. Remove all text effects of TextGroup (nTextGrouping == -1)
1521 3. Change all the text effects\A1\AF start type
1523 So here is the right logic:
1524 If set the animation from text to shape and remove text animation,
1525 should do setAnimateForm first, then do setTextGrouping.
1526 Other case,do setTextGrouping first, then do setAnimateForm.
1529 /************************************************************************/
1531 bool bDoSetAnimateFormFirst
= false;
1532 bool bNeedDoSetAnimateForm
= false;
1534 if( bHasAnimateForm
)
1536 if( pTextGroup
&& pTextGroup
->getAnimateForm() != bAnimateForm
)
1538 if( (pTextGroup
->getTextGrouping() >= 0) && (nTextGrouping
== -1 ) )
1540 bDoSetAnimateFormFirst
= true;
1542 bNeedDoSetAnimateForm
= true;
1546 if (bDoSetAnimateFormFirst
)
1548 pEffectSequence
->setAnimateForm( pTextGroup
, bAnimateForm
);
1552 if( bHasTextGrouping
)
1554 if( pTextGroup
&& pTextGroup
->getTextGrouping() != nTextGrouping
)
1556 pEffectSequence
->setTextGrouping( pTextGroup
, nTextGrouping
);
1558 // All the effects of the outline object is removed so we need to
1559 // put it back. OTOH, the shape object that still has effects
1560 // in the text group is fine.
1561 if (nTextGrouping
== -1 && pTextGroup
->getEffects().empty())
1563 pEffect
->setTarget(Any(pEffect
->getTargetShape()));
1564 pEffect
->setGroupId(-1);
1565 mpMainSequence
->append(pEffect
);
1572 if (!bDoSetAnimateFormFirst
&& bNeedDoSetAnimateForm
)
1576 pEffectSequence
->setAnimateForm( pTextGroup
, bAnimateForm
);
1581 if( bHasTextGroupingAuto
)
1583 if( pTextGroup
&& pTextGroup
->getTextGroupingAuto() != fTextGroupingAuto
)
1585 pEffectSequence
->setTextGroupingAuto( pTextGroup
, fTextGroupingAuto
);
1590 if( bHasTextReverse
)
1592 if( pTextGroup
&& pTextGroup
->getTextReverse() != bTextReverse
)
1594 pEffectSequence
->setTextReverse( pTextGroup
, bTextReverse
);
1603 mpMainSequence
->rebuild();
1605 mrBase
.GetDocShell()->SetModified();
1609 void CustomAnimationPane::showOptions(const OUString
& rPage
)
1611 std::unique_ptr
<STLPropertySet
> xSet
= createSelectionSet();
1613 auto xDlg
= std::make_shared
<CustomAnimationDialog
>(GetFrameWeld(), std::move(xSet
), rPage
);
1615 weld::DialogController::runAsync(xDlg
, [xDlg
, this](sal_Int32 nResult
){
1619 changeSelection(xDlg
->getResultSet(), xDlg
->getPropertySet());
1625 void CustomAnimationPane::onChangeCurrentPage()
1632 Reference
< XDrawPage
> xNewPage( mxView
->getCurrentPage() );
1633 if( xNewPage
!= mxCurrentPage
)
1635 mxCurrentPage
= xNewPage
;
1636 SdPage
* pPage
= SdPage::getImplementation( mxCurrentPage
);
1639 mpMainSequence
= pPage
->getMainSequence();
1640 mxCustomAnimationList
->update( mpMainSequence
);
1647 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::onChangeCurrentPage()" );
1651 static bool getTextSelection( const Any
& rSelection
, Reference
< XShape
>& xShape
, std::vector
< sal_Int16
>& rParaList
)
1653 Reference
< XTextRange
> xSelectedText
;
1654 rSelection
>>= xSelectedText
;
1655 if( xSelectedText
.is() ) try
1657 xShape
.set( xSelectedText
->getText(), UNO_QUERY_THROW
);
1659 css::uno::Reference
<css::document::XActionLockable
> xLockable(xShape
, css::uno::UNO_QUERY
);
1661 xLockable
->addActionLock();
1662 comphelper::ScopeGuard
aGuard([&xLockable
]()
1665 xLockable
->removeActionLock();
1668 Reference
< XTextRangeCompare
> xTextRangeCompare( xShape
, UNO_QUERY_THROW
);
1669 Reference
< XEnumerationAccess
> xParaEnumAccess( xShape
, UNO_QUERY_THROW
);
1670 Reference
< XEnumeration
> xParaEnum( xParaEnumAccess
->createEnumeration(), UNO_SET_THROW
);
1671 Reference
< XTextRange
> xRange
;
1672 Reference
< XTextRange
> xStart( xSelectedText
->getStart() );
1673 Reference
< XTextRange
> xEnd( xSelectedText
->getEnd() );
1675 if( xTextRangeCompare
->compareRegionEnds( xStart
, xEnd
) < 0 )
1677 Reference
< XTextRange
> xTemp( xStart
);
1682 sal_Int16 nPara
= 0;
1683 while( xParaEnum
->hasMoreElements() )
1685 xParaEnum
->nextElement() >>= xRange
;
1687 // break if start of selection is prior to end of current paragraph
1688 if( xRange
.is() && (xTextRangeCompare
->compareRegionEnds( xStart
, xRange
) >= 0 ) )
1694 while( xRange
.is() )
1696 if( xRange
.is() && !xRange
->getString().isEmpty() )
1697 rParaList
.push_back( nPara
);
1699 // break if end of selection is before or at end of current paragraph
1700 if( xRange
.is() && xTextRangeCompare
->compareRegionEnds( xEnd
, xRange
) >= 0 )
1705 if( xParaEnum
->hasMoreElements() )
1706 xParaEnum
->nextElement() >>= xRange
;
1715 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::getTextSelection()" );
1723 Reference
<XShape
> getTargetShape(const Any
& rTarget
)
1725 Reference
<XShape
> xShape
;
1729 ParagraphTarget aParaTarget
;
1730 if (rTarget
>>= aParaTarget
)
1731 xShape
= aParaTarget
.Shape
;
1737 void CustomAnimationPane::onAdd()
1739 bool bHasText
= true;
1741 // first create vector of targets for dialog preview
1742 std::vector
< Any
> aTargets
;
1744 // gather shapes from the selection
1745 Reference
< XSelectionSupplier
> xSel( mxView
, UNO_QUERY_THROW
);
1746 maViewSelection
= xSel
->getSelection();
1748 if( maViewSelection
.getValueType() == cppu::UnoType
<XShapes
>::get())
1750 Reference
< XIndexAccess
> xShapes
;
1751 maViewSelection
>>= xShapes
;
1753 sal_Int32 nCount
= xShapes
->getCount();
1754 aTargets
.reserve( nCount
);
1755 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; nIndex
++ )
1757 Any
aTarget( xShapes
->getByIndex( nIndex
) );
1758 aTargets
.push_back( aTarget
);
1761 Reference
< XText
> xText
;
1763 if( !xText
.is() || xText
->getString().isEmpty() )
1768 else if ( maViewSelection
.getValueType() == cppu::UnoType
<XShape
>::get())
1770 aTargets
.push_back( maViewSelection
);
1771 Reference
< XText
> xText
;
1772 maViewSelection
>>= xText
;
1773 if( !xText
.is() || xText
->getString().isEmpty() )
1776 else if ( maViewSelection
.getValueType() == cppu::UnoType
<XTextCursor
>::get())
1778 Reference
< XShape
> xShape
;
1779 std::vector
< sal_Int16
> aParaList
;
1780 if( getTextSelection( maViewSelection
, xShape
, aParaList
) )
1782 ParagraphTarget aParaTarget
;
1783 aParaTarget
.Shape
= xShape
;
1785 for( const auto& rPara
: aParaList
)
1787 aParaTarget
.Paragraph
= rPara
;
1788 aTargets
.push_back( Any( aParaTarget
) );
1794 OSL_FAIL("sd::CustomAnimationPane::onAdd(), unknown view selection!" );
1798 CustomAnimationPresetPtr pDescriptor
;
1799 mxFTCategory
->set_sensitive(true);
1800 mxFTAnimation
->set_sensitive(true);
1802 bool bCategoryReset
= false;
1804 if (!mxLBCategory
->get_sensitive() || mxLBCategory
->get_active() == -1)
1806 mxLBCategory
->set_sensitive(true);
1807 mxLBCategory
->set_active(0);
1808 bCategoryReset
= true;
1811 if (bCategoryReset
|| !mxLBAnimation
->get_sensitive() ||
1812 mxLBAnimation
->get_selected_index() == -1)
1814 mxLBAnimation
->set_sensitive(true);
1816 sal_Int32 nFirstEffect
= fillAnimationLB(bHasText
);
1817 if (nFirstEffect
== -1)
1820 mxLBAnimation
->select(nFirstEffect
);
1821 mnLastSelectedAnimation
= nFirstEffect
;
1824 auto pEntryData
= weld::fromId
<CustomAnimationPresetPtr
*>(mxLBAnimation
->get_selected_id());
1826 pDescriptor
= *pEntryData
;
1830 const double fDuration
= pDescriptor
->getDuration();
1831 mxCBXDuration
->set_value(fDuration
*100.0, FieldUnit::NONE
);
1832 bool bHasSpeed
= pDescriptor
->getDuration() > 0.001;
1833 mxCBXDuration
->set_sensitive( bHasSpeed
);
1834 mxFTDuration
->set_sensitive( bHasSpeed
);
1836 mxCustomAnimationList
->unselect_all();
1838 // gather shapes from the selection
1840 for( const auto& rTarget
: aTargets
)
1842 css::uno::Reference
<css::document::XActionLockable
> xLockable(getTargetShape(rTarget
), css::uno::UNO_QUERY
);
1844 xLockable
->addActionLock();
1845 comphelper::ScopeGuard
aGuard([&xLockable
]()
1848 xLockable
->removeActionLock();
1851 CustomAnimationEffectPtr pCreated
= mpMainSequence
->append( pDescriptor
, rTarget
, fDuration
);
1853 // if only one shape with text and no fill or outline is selected, animate only by first level paragraphs
1854 if( bHasText
&& (aTargets
.size() == 1) )
1856 Reference
< XShape
> xShape( rTarget
, UNO_QUERY
);
1857 if( xShape
.is() && !hasVisibleShape( xShape
) )
1859 mpMainSequence
->createTextGroup( pCreated
, 1, -1.0, false, false );
1866 pCreated
->setNodeType( EffectNodeType::WITH_PREVIOUS
);
1869 mxCustomAnimationList
->select( pCreated
);
1873 PathKind ePathKind
= getCreatePathKind();
1875 if (ePathKind
!= PathKind::NONE
)
1877 createPath( ePathKind
, aTargets
, 0.0 );
1878 updateMotionPathTags();
1882 mrBase
.GetDocShell()->SetModified();
1886 SlideShow::Stop( mrBase
);
1889 void CustomAnimationPane::onRemove()
1891 if( maListSelection
.empty() )
1896 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
1898 EffectSequence
aList( maListSelection
);
1900 for( CustomAnimationEffectPtr
& pEffect
: aList
)
1902 if( pEffect
->getEffectSequence() )
1903 pEffect
->getEffectSequence()->remove( pEffect
);
1906 maListSelection
.clear();
1907 mrBase
.GetDocShell()->SetModified();
1910 void CustomAnimationPane::remove( CustomAnimationEffectPtr
const & pEffect
)
1912 if( pEffect
->getEffectSequence() )
1915 pEffect
->getEffectSequence()->remove( pEffect
);
1916 mrBase
.GetDocShell()->SetModified();
1920 void CustomAnimationPane::onChangeStart()
1922 sal_Int16 nNodeType
;
1923 switch( mxLBStart
->get_active() )
1925 case 0: nNodeType
= EffectNodeType::ON_CLICK
; break;
1926 case 1: nNodeType
= EffectNodeType::WITH_PREVIOUS
; break;
1927 case 2: nNodeType
= EffectNodeType::AFTER_PREVIOUS
; break;
1932 onChangeStart( nNodeType
);
1935 void CustomAnimationPane::onChangeStart( sal_Int16 nNodeType
)
1939 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
1941 bool bNeedRebuild
= false;
1943 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
1945 if( pEffect
->getNodeType() != nNodeType
)
1947 pEffect
->setNodeType( nNodeType
);
1948 bNeedRebuild
= true;
1954 mpMainSequence
->rebuild();
1956 mrBase
.GetDocShell()->SetModified();
1960 void CustomAnimationPane::onChangeSpeed()
1962 double fDuration
= getDuration();
1970 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
1972 // change selected effect
1973 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
1975 pEffect
->setDuration( fDuration
);
1978 mpMainSequence
->rebuild();
1980 mrBase
.GetDocShell()->SetModified();
1984 double CustomAnimationPane::getDuration() const
1986 double fDuration
= 0;
1988 if (!mxCBXDuration
->get_text().isEmpty())
1989 fDuration
= mxCBXDuration
->get_value(FieldUnit::NONE
) / 100.0;
1994 PathKind
CustomAnimationPane::getCreatePathKind() const
1996 PathKind eKind
= PathKind::NONE
;
1998 if (mxLBAnimation
->count_selected_rows() == 1 &&
1999 mxLBCategory
->get_active() == gnMotionPathPos
)
2001 const sal_Int32 nPos
= mxLBAnimation
->get_selected_index();
2002 if( nPos
== mnCurvePathPos
)
2004 eKind
= PathKind::CURVE
;
2006 else if( nPos
== mnPolygonPathPos
)
2008 eKind
= PathKind::POLYGON
;
2010 else if( nPos
== mnFreeformPathPos
)
2012 eKind
= PathKind::FREEFORM
;
2019 void CustomAnimationPane::createPath( PathKind eKind
, std::vector
< Any
>& rTargets
, double fDuration
)
2021 sal_uInt16 nSID
= 0;
2025 case PathKind::CURVE
: nSID
= SID_DRAW_BEZIER_NOFILL
; break;
2026 case PathKind::POLYGON
: nSID
= SID_DRAW_POLYGON_NOFILL
; break;
2027 case PathKind::FREEFORM
: nSID
= SID_DRAW_FREELINE_NOFILL
; break;
2034 DrawViewShell
* pViewShell
= dynamic_cast< DrawViewShell
* >(
2035 FrameworkHelper::Instance(mrBase
)->GetViewShell(FrameworkHelper::msCenterPaneURL
).get());
2039 DrawView
* pView
= pViewShell
->GetDrawView();
2041 pView
->UnmarkAllObj();
2043 std::vector
< Any
> aTargets( 1, Any( fDuration
) );
2044 aTargets
.insert( aTargets
.end(), rTargets
.begin(), rTargets
.end() );
2045 Sequence
< Any
> aTargetSequence( comphelper::containerToSequence( aTargets
) );
2046 const SfxUnoAnyItem
aItem( SID_ADD_MOTION_PATH
, Any( aTargetSequence
) );
2047 pViewShell
->GetViewFrame()->GetDispatcher()->ExecuteList( nSID
, SfxCallMode::ASYNCHRON
, {&aItem
} );
2052 /// this link is called when the property box is modified by the user
2053 IMPL_LINK_NOARG(CustomAnimationPane
, implPropertyHdl
, LinkParamNone
*, void)
2055 if (!mxLBSubControl
)
2060 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2062 const Any
aValue(mxLBSubControl
->getValue());
2064 bool bNeedUpdate
= false;
2066 // change selected effect
2067 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2069 if( setProperty1Value( mnPropertyType
, pEffect
, aValue
) )
2075 mpMainSequence
->rebuild();
2077 mrBase
.GetDocShell()->SetModified();
2083 IMPL_LINK_NOARG(CustomAnimationPane
, DelayModifiedHdl
, weld::MetricSpinButton
&, void)
2088 IMPL_LINK_NOARG(CustomAnimationPane
, DelayLoseFocusHdl
, weld::Widget
&, void)
2090 double fBegin
= mxMFStartDelay
->get_value(FieldUnit::NONE
);
2092 //sequence rebuild only when the control loses focus
2093 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2095 // change selected effect
2096 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2098 pEffect
->setBegin( fBegin
/10.0 );
2101 mpMainSequence
->rebuild();
2103 mrBase
.GetDocShell()->SetModified();
2106 IMPL_LINK_NOARG(CustomAnimationPane
, AnimationSelectHdl
, weld::TreeView
&, void)
2111 IMPL_LINK_NOARG(CustomAnimationPane
, SelectionHandler
, Timer
*, void)
2113 if (mxLBAnimation
->has_grab()) // tdf#136474 try again later
2119 int nSelected
= mxLBAnimation
->get_selected_index();
2120 if (nSelected
== -1)
2123 // tdf#99137, the selected entry may also be a subcategory title, so not an effect
2124 // just skip it and move to the next one in this case
2125 if (mxLBAnimation
->get_text_emphasis(nSelected
, 0))
2127 if (nSelected
== 0 || nSelected
> mnLastSelectedAnimation
)
2128 mxLBAnimation
->select(++nSelected
);
2130 mxLBAnimation
->select(--nSelected
);
2133 mnLastSelectedAnimation
= nSelected
;
2135 CustomAnimationPresetPtr
* pPreset
= weld::fromId
<CustomAnimationPresetPtr
*>(mxLBAnimation
->get_id(nSelected
));
2136 PathKind ePathKind
= getCreatePathKind();
2138 if ( ePathKind
!= PathKind::NONE
)
2140 std::vector
< Any
> aTargets
;
2141 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2143 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2145 aTargets
.push_back( pEffect
->getTarget() );
2147 EffectSequenceHelper
* pEffectSequence
= pEffect
->getEffectSequence();
2148 if( !pEffectSequence
)
2149 pEffectSequence
= mpMainSequence
.get();
2151 // delete the old animation, new one will be appended
2152 // by createPath and SID_ADD_MOTION_PATH therein
2153 pEffectSequence
->remove( pEffect
);
2156 createPath( ePathKind
, aTargets
, 0.0 );
2157 updateMotionPathTags();
2161 CustomAnimationPresetPtr
pDescriptor(*pPreset
);
2162 const double fDuration
= (*pPreset
)->getDuration();
2163 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2165 // get selected effect
2166 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2168 // Dispose the deprecated motion path tag. It will be rebuilt later.
2169 if (pEffect
->getPresetClass() == css::presentation::EffectPresetClass::MOTIONPATH
)
2171 for (auto const& xTag
: maMotionPathTags
)
2173 if(xTag
->getEffect() == pEffect
&& !xTag
->isDisposed())
2178 EffectSequenceHelper
* pEffectSequence
= pEffect
->getEffectSequence();
2179 if( !pEffectSequence
)
2180 pEffectSequence
= mpMainSequence
.get();
2182 pEffectSequence
->replace( pEffect
, pDescriptor
, fDuration
);
2189 IMPL_LINK_NOARG(CustomAnimationPane
, UpdateAnimationLB
, weld::ComboBox
&, void)
2191 //FIXME: first effect only? what if there is more?
2192 CustomAnimationEffectPtr pEffect
= maListSelection
.front();
2193 fillAnimationLB( pEffect
->hasText() );
2196 IMPL_LINK_NOARG(CustomAnimationPane
, DurationModifiedHdl
, weld::MetricSpinButton
&, void)
2198 if (!mxCBXDuration
->get_text().isEmpty())
2200 double duration_value
= static_cast<double>(mxCBXDuration
->get_value(FieldUnit::NONE
));
2201 if(duration_value
<= 0.0)
2203 mxCBXDuration
->set_value(1, FieldUnit::NONE
);
2211 void InsertCategory(weld::TreeView
& rLBAnimation
, const OUString
& rMotionPathLabel
)
2213 int nRow
= rLBAnimation
.n_children();
2214 rLBAnimation
.append_text(rMotionPathLabel
);
2215 rLBAnimation
.set_text_emphasis(nRow
, true, 0);
2216 rLBAnimation
.set_text_align(nRow
, 0.5, 0);
2220 sal_Int32
CustomAnimationPane::fillAnimationLB( bool bHasText
)
2222 PresetCategoryList rCategoryList
;
2223 sal_uInt16 nPosition
= mxLBCategory
->get_active();
2224 const CustomAnimationPresets
& rPresets (CustomAnimationPresets::getCustomAnimationPresets());
2227 case 0:rCategoryList
= rPresets
.getEntrancePresets();break;
2228 case 1:rCategoryList
= rPresets
.getEmphasisPresets();break;
2229 case 2:rCategoryList
= rPresets
.getExitPresets();break;
2230 case 3:rCategoryList
= rPresets
.getMotionPathsPresets();break;
2231 case 4:rCategoryList
= rPresets
.getMiscPresets();break;
2234 sal_Int32 nFirstEffect
= -1;
2236 int nOldEntryCount
= mxLBAnimation
->n_children();
2237 int nOldScrollPos
= mxLBAnimation
->vadjustment_get_value();
2239 mxLBAnimation
->freeze();
2240 mxLBAnimation
->clear();
2241 mnLastSelectedAnimation
= -1;
2243 if (nPosition
== gnMotionPathPos
)
2245 OUString
sMotionPathLabel( SdResId( STR_CUSTOMANIMATION_USERPATH
) );
2246 InsertCategory(*mxLBAnimation
, sMotionPathLabel
);
2247 mnCurvePathPos
= mxLBAnimation
->n_children();
2248 mxLBAnimation
->append_text( SvxResId(STR_ObjNameSingulCOMBLINE
) );
2249 mxLBAnimation
->set_text_emphasis(mnCurvePathPos
, false, 0);
2250 mnPolygonPathPos
= mnCurvePathPos
+ 1;
2251 mxLBAnimation
->append_text( SvxResId(STR_ObjNameSingulPOLY
) );
2252 mxLBAnimation
->set_text_emphasis(mnPolygonPathPos
, false, 0);
2253 mnFreeformPathPos
= mnPolygonPathPos
+ 1;
2254 mxLBAnimation
->append_text( SvxResId(STR_ObjNameSingulFREELINE
) );
2255 mxLBAnimation
->set_text_emphasis(mnFreeformPathPos
, false, 0);
2258 for (const PresetCategoryPtr
& pCategory
: rCategoryList
)
2262 InsertCategory(*mxLBAnimation
, pCategory
->maLabel
);
2264 int nPos
= mxLBAnimation
->n_children();
2266 std::vector
< CustomAnimationPresetPtr
> aSortedVector
=
2267 pCategory
->maEffects
;
2269 for( const CustomAnimationPresetPtr
& pDescriptor
: aSortedVector
)
2271 // ( !isTextOnly || ( isTextOnly && bHasText ) ) <=> !isTextOnly || bHasText
2272 if( pDescriptor
&& ( !pDescriptor
->isTextOnly() || bHasText
) )
2274 auto pCustomPtr
= new CustomAnimationPresetPtr(pDescriptor
);
2275 OUString sId
= weld::toId(pCustomPtr
);
2276 mxLBAnimation
->append(sId
, pDescriptor
->getLabel());
2277 mxLBAnimation
->set_text_emphasis(nPos
, false, 0);
2279 if (nFirstEffect
== -1)
2280 nFirstEffect
= nPos
;
2288 mxLBAnimation
->thaw();
2290 if (mxLBAnimation
->n_children() == nOldEntryCount
)
2291 mxLBAnimation
->vadjustment_set_value(nOldScrollPos
);
2293 return nFirstEffect
;
2296 IMPL_LINK(CustomAnimationPane
, implToggleHdl
, weld::Toggleable
&, rBtn
, void)
2298 implControlHdl(&rBtn
);
2301 IMPL_LINK(CustomAnimationPane
, implClickHdl
, weld::Button
&, rBtn
, void)
2303 implControlHdl(&rBtn
);
2306 IMPL_LINK( CustomAnimationPane
, implControlListBoxHdl
, weld::ComboBox
&, rListBox
, void )
2308 implControlHdl(&rListBox
);
2311 /// this link is called when one of the controls is modified
2312 void CustomAnimationPane::implControlHdl(const weld::Widget
* pControl
)
2314 if (pControl
== mxPBAddEffect
.get())
2316 else if (pControl
== mxPBRemoveEffect
.get())
2318 else if (pControl
== mxLBStart
.get())
2320 else if (pControl
== mxPBPropertyMore
.get())
2322 else if (pControl
== mxPBMoveUp
.get())
2323 moveSelection( true );
2324 else if (pControl
== mxPBMoveDown
.get())
2325 moveSelection( false );
2326 else if (pControl
== mxPBPlay
.get())
2328 else if (pControl
== mxCBAutoPreview
.get())
2330 SdOptions
* pOptions
= SD_MOD()->GetSdOptions(DocumentType::Impress
);
2331 pOptions
->SetPreviewChangedEffects(mxCBAutoPreview
->get_active());
2335 IMPL_LINK_NOARG(CustomAnimationPane
, lateInitCallback
, Timer
*, void)
2337 // Call getPresets() to initiate the (expensive) construction of the
2339 CustomAnimationPresets::getCustomAnimationPresets();
2341 // update selection and control states
2342 onSelectionChanged();
2345 void CustomAnimationPane::moveSelection( bool bUp
)
2347 if( maListSelection
.empty() )
2350 EffectSequenceHelper
* pSequence
= maListSelection
.front()->getEffectSequence();
2351 if( pSequence
== nullptr )
2356 bool bChanged
= false;
2358 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2359 EffectSequence
& rEffectSequence
= pSequence
->getSequence();
2363 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2365 EffectSequence::iterator
aUpEffectPos( pSequence
->find( pEffect
) );
2366 // coverity[copy_paste_error : FALSE] - this is correct, checking if it exists
2367 if( aUpEffectPos
!= rEffectSequence
.end() )
2369 EffectSequence::iterator
aInsertPos( rEffectSequence
.erase( aUpEffectPos
) );
2371 if( aInsertPos
!= rEffectSequence
.begin() )
2374 while( (aInsertPos
!= rEffectSequence
.begin()) && !mxCustomAnimationList
->isExpanded(*aInsertPos
))
2376 rEffectSequence
.insert( aInsertPos
, pEffect
);
2380 rEffectSequence
.push_front( pEffect
);
2388 EffectSequence::reverse_iterator
aIter( maListSelection
.rbegin() );
2389 const EffectSequence::reverse_iterator
aEnd( maListSelection
.rend() );
2391 while( aIter
!= aEnd
)
2393 CustomAnimationEffectPtr pEffect
= *aIter
++;
2395 EffectSequence::iterator
aDownEffectPos( pSequence
->find( pEffect
) );
2396 // coverity[copy_paste_error : FALSE] - this is correct, checking if it exists
2397 if( aDownEffectPos
!= rEffectSequence
.end() )
2399 EffectSequence::iterator
aInsertPos( rEffectSequence
.erase( aDownEffectPos
) );
2401 if( aInsertPos
!= rEffectSequence
.end() )
2404 // Advance over rolled-up (un-expanded) items, unless we just moved it there.
2405 while( (aInsertPos
!= rEffectSequence
.end())
2406 && !mxCustomAnimationList
->isExpanded(*aInsertPos
)
2407 && (std::find(maListSelection
.begin(), maListSelection
.end(), *aInsertPos
)
2408 == maListSelection
.end())
2411 rEffectSequence
.insert( aInsertPos
, pEffect
);
2415 rEffectSequence
.push_back( pEffect
);
2424 mpMainSequence
->rebuild();
2426 mrBase
.GetDocShell()->SetModified();
2430 void CustomAnimationPane::onPreview( bool bForcePreview
)
2432 if (!bForcePreview
&& !mxCBAutoPreview
->get_active())
2435 // No preview in LOK.
2436 if (comphelper::LibreOfficeKit::isActive())
2439 if( maListSelection
.empty() )
2441 rtl::Reference
< MotionPathTag
> xMotionPathTag
;
2442 auto aIter
= std::find_if(maMotionPathTags
.begin(), maMotionPathTags
.end(),
2443 [](const MotionPathTagVector::value_type
& rxMotionPathTag
) { return rxMotionPathTag
->isSelected(); });
2444 if (aIter
!= maMotionPathTags
.end())
2445 xMotionPathTag
= *aIter
;
2447 if( xMotionPathTag
.is() )
2449 MainSequencePtr pSequence
= std::make_shared
<MainSequence
>();
2450 pSequence
->append( xMotionPathTag
->getEffect()->clone() );
2451 preview( pSequence
->getRootNode() );
2455 Reference
< XAnimationNodeSupplier
> xNodeSupplier( mxCurrentPage
, UNO_QUERY
);
2456 if( !xNodeSupplier
.is() )
2459 preview( xNodeSupplier
->getAnimationNode() );
2464 MainSequencePtr pSequence
= std::make_shared
<MainSequence
>();
2466 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2468 pSequence
->append( pEffect
->clone() );
2471 preview( pSequence
->getRootNode() );
2475 void CustomAnimationPane::preview( const Reference
< XAnimationNode
>& xAnimationNode
)
2477 Reference
< XParallelTimeContainer
> xRoot
= ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() );
2478 Sequence
< css::beans::NamedValue
> aUserData
2479 { { "node-type", css::uno::Any(css::presentation::EffectNodeType::TIMING_ROOT
) } };
2480 xRoot
->setUserData( aUserData
);
2481 xRoot
->appendChild( xAnimationNode
);
2483 SlideShow::StartPreview( mrBase
, mxCurrentPage
, xRoot
);
2486 // ICustomAnimationListController
2487 void CustomAnimationPane::onSelect()
2489 maListSelection
= mxCustomAnimationList
->getSelection();
2492 // mark shapes from selected effects
2493 if( maSelectionLock
.isLocked() )
2496 // tdf#145030 if nothing is selected in the effects list, leave the selection of
2497 // objects in the slide untouched
2498 if (maListSelection
.empty())
2501 ScopeLockGuard
aGuard( maSelectionLock
);
2502 DrawViewShell
* pViewShell
= dynamic_cast< DrawViewShell
* >(
2503 FrameworkHelper::Instance(mrBase
)->GetViewShell(FrameworkHelper::msCenterPaneURL
).get());
2504 DrawView
* pView
= pViewShell
? pViewShell
->GetDrawView() : nullptr;
2508 pView
->UnmarkAllObj();
2509 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2511 Reference
< XShape
> xShape( pEffect
->getTargetShape() );
2512 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(xShape
);
2514 pView
->MarkObj(pObj
, pView
->GetSdrPageView());
2519 // ICustomAnimationListController
2520 // pEffectInsertBefore may be null if moving to end of list.
2521 void CustomAnimationPane::onDragNDropComplete(std::vector
< CustomAnimationEffectPtr
> pEffectsDragged
, CustomAnimationEffectPtr pEffectInsertBefore
)
2523 if ( !mpMainSequence
)
2528 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2530 // Move all selected effects
2531 for( auto const& pEffectDragged
: pEffectsDragged
)
2533 // Move this dragged effect and any hidden sub-effects
2534 EffectSequence::iterator aIter
= mpMainSequence
->find( pEffectDragged
);
2535 const EffectSequence::iterator
aEnd( mpMainSequence
->getEnd() );
2537 while( aIter
!= aEnd
)
2539 CustomAnimationEffectPtr pEffect
= *aIter
++;
2541 // Update model with new location (function triggers a rebuild)
2542 // target may be null, which will insert at the end.
2543 mpMainSequence
->moveToBeforeEffect( pEffect
, pEffectInsertBefore
);
2544 // Done moving effect and its hidden sub-effects when *next* effect is visible.
2545 if (aIter
!= aEnd
&& mxCustomAnimationList
->isVisible(*aIter
))
2551 mrBase
.GetDocShell()->SetModified();
2554 void CustomAnimationPane::updatePathFromMotionPathTag( const rtl::Reference
< MotionPathTag
>& xTag
)
2556 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2560 SdrPathObj
* pPathObj
= xTag
->getPathObj();
2561 CustomAnimationEffectPtr pEffect
= xTag
->getEffect();
2562 if( (pPathObj
!= nullptr) && pEffect
)
2564 SfxUndoManager
* pManager
= mrBase
.GetDocShell()->GetUndoManager();
2567 SdPage
* pPage
= SdPage::getImplementation( mxCurrentPage
);
2569 pManager
->AddUndoAction( std::make_unique
<UndoAnimationPath
>( mrBase
.GetDocShell()->GetDoc(), pPage
, pEffect
->getNode() ) );
2572 pEffect
->updatePathFromSdrPathObj( *pPathObj
);
2578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */