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
, u
"CustomAnimationsPanel"_ustr
, u
"modules/simpress/ui/customanimationspanel.ui"_ustr
)
124 , mxFTAnimation(m_xBuilder
->weld_label(u
"effectlabel"_ustr
))
125 , mxCustomAnimationList(new CustomAnimationList(m_xBuilder
->weld_tree_view(u
"custom_animation_list"_ustr
),
126 m_xBuilder
->weld_label(u
"custom_animation_label"_ustr
),
127 m_xBuilder
->weld_widget(u
"custom_animation_label_parent"_ustr
)))
128 , mxPBAddEffect(m_xBuilder
->weld_button(u
"add_effect"_ustr
))
129 , mxPBRemoveEffect(m_xBuilder
->weld_button(u
"remove_effect"_ustr
))
130 , mxPBMoveUp(m_xBuilder
->weld_button(u
"move_up"_ustr
))
131 , mxPBMoveDown(m_xBuilder
->weld_button(u
"move_down"_ustr
))
132 , mxFTCategory(m_xBuilder
->weld_label(u
"categorylabel"_ustr
))
133 , mxLBCategory(m_xBuilder
->weld_combo_box(u
"categorylb"_ustr
))
134 , mxFTEffect(m_xBuilder
->weld_label(u
"effect_label"_ustr
))
135 , mxLBAnimation(m_xBuilder
->weld_tree_view(u
"effect_list"_ustr
))
136 , mxFTStart(m_xBuilder
->weld_label(u
"start_effect"_ustr
))
137 , mxLBStart(m_xBuilder
->weld_combo_box(u
"start_effect_list"_ustr
))
138 , mxFTProperty(m_xBuilder
->weld_label(u
"effect_property"_ustr
))
139 , mxPlaceholderBox(m_xBuilder
->weld_container(u
"placeholder"_ustr
))
140 , mxPBPropertyMore(m_xBuilder
->weld_button(u
"more_properties"_ustr
))
141 , mxFTDuration(m_xBuilder
->weld_label(u
"effect_duration"_ustr
))
142 , mxCBXDuration(m_xBuilder
->weld_metric_spin_button(u
"anim_duration"_ustr
, FieldUnit::SECOND
))
143 , mxFTStartDelay(m_xBuilder
->weld_label(u
"delay_label"_ustr
))
144 , mxMFStartDelay(m_xBuilder
->weld_metric_spin_button(u
"delay_value"_ustr
, FieldUnit::SECOND
))
145 , mxCBAutoPreview(m_xBuilder
->weld_check_button(u
"auto_preview"_ustr
))
146 , mxPBPlay(m_xBuilder
->weld_button(u
"play"_ustr
))
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_selection_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
= mrBase
.GetDrawController();
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 (auto pMainViewShell
= mrBase
.GetMainViewShell().get())
294 if( pMainViewShell
->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
= SdModule::get()->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
= std::move(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 maViewSelection
= mxView
->getSelection();
839 mxCustomAnimationList
->onSelectionChanged( maViewSelection
);
844 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::onSelectionChanged()" );
848 void CustomAnimationPane::onDoubleClick()
853 void CustomAnimationPane::onContextMenu(const OUString
&rIdent
)
855 if (rIdent
== "onclick")
856 onChangeStart( EffectNodeType::ON_CLICK
);
857 else if (rIdent
== "withprev")
858 onChangeStart( EffectNodeType::WITH_PREVIOUS
);
859 else if (rIdent
== "afterprev")
860 onChangeStart( EffectNodeType::AFTER_PREVIOUS
);
861 else if (rIdent
== "options")
863 else if (rIdent
== "timing")
864 showOptions(u
"timing"_ustr
);
865 else if (rIdent
== "remove")
867 else if (rIdent
== "create" && maViewSelection
.hasValue())
872 static void addValue( const std::unique_ptr
<STLPropertySet
>& pSet
, sal_Int32 nHandle
, const Any
& rValue
)
874 switch( pSet
->getPropertyState( nHandle
) )
876 case STLPropertyState::Ambiguous
:
877 // value is already ambiguous, do nothing
879 case STLPropertyState::Direct
:
880 // set to ambiguous if existing value is different
881 if( rValue
!= pSet
->getPropertyValue( nHandle
) )
882 pSet
->setPropertyState( nHandle
, STLPropertyState::Ambiguous
);
884 case STLPropertyState::Default
:
885 // just set new value
886 pSet
->setPropertyValue( nHandle
, rValue
);
891 static sal_Int32
calcMaxParaDepth( const Reference
< XShape
>& xTargetShape
)
893 sal_Int32 nMaxParaDepth
= -1;
895 if( xTargetShape
.is() )
897 Reference
< XEnumerationAccess
> xText( xTargetShape
, UNO_QUERY
);
900 Reference
< XPropertySet
> xParaSet
;
902 Reference
< XEnumeration
> xEnumeration( xText
->createEnumeration(), UNO_SET_THROW
);
903 while( xEnumeration
->hasMoreElements() )
905 xEnumeration
->nextElement() >>= xParaSet
;
908 sal_Int32 nParaDepth
= 0;
909 xParaSet
->getPropertyValue( u
"NumberingLevel"_ustr
) >>= nParaDepth
;
911 if( nParaDepth
> nMaxParaDepth
)
912 nMaxParaDepth
= nParaDepth
;
918 return nMaxParaDepth
+ 1;
921 Any
CustomAnimationPane::getProperty1Value( sal_Int32 nType
, const CustomAnimationEffectPtr
& pEffect
)
925 case nPropertyTypeDirection
:
926 case nPropertyTypeSpokes
:
927 case nPropertyTypeZoom
:
928 return Any( pEffect
->getPresetSubType() );
930 case nPropertyTypeColor
:
931 case nPropertyTypeFillColor
:
932 case nPropertyTypeFirstColor
:
933 case nPropertyTypeSecondColor
:
934 case nPropertyTypeCharColor
:
935 case nPropertyTypeLineColor
:
937 const sal_Int32 nIndex
= (nPropertyTypeFirstColor
== nType
) ? 0 : 1;
938 return pEffect
->getColor( nIndex
);
941 case nPropertyTypeFont
:
942 return pEffect
->getProperty( AnimationNodeType::SET
, u
"CharFontName" , EValue::To
);
944 case nPropertyTypeCharHeight
:
946 static constexpr OUString
aAttributeName( u
"CharHeight"_ustr
);
947 Any
aValue( pEffect
->getProperty( AnimationNodeType::SET
, aAttributeName
, EValue::To
) );
948 if( !aValue
.hasValue() )
949 aValue
= pEffect
->getProperty( AnimationNodeType::ANIMATE
, aAttributeName
, EValue::To
);
953 case nPropertyTypeRotate
:
954 return pEffect
->getTransformationProperty( AnimationTransformType::ROTATE
, EValue::By
);
956 case nPropertyTypeTransparency
:
957 return pEffect
->getProperty( AnimationNodeType::SET
, u
"Opacity" , EValue::To
);
959 case nPropertyTypeScale
:
960 return pEffect
->getTransformationProperty( AnimationTransformType::SCALE
, EValue::By
);
962 case nPropertyTypeCharDecoration
:
964 Sequence
< Any
> aValues
{
965 pEffect
->getProperty( AnimationNodeType::SET
, u
"CharWeight" , EValue::To
),
966 pEffect
->getProperty( AnimationNodeType::SET
, u
"CharPosture" , EValue::To
),
967 pEffect
->getProperty( AnimationNodeType::SET
, u
"CharUnderline" , EValue::To
)
969 return Any( aValues
);
977 bool CustomAnimationPane::setProperty1Value( sal_Int32 nType
, const CustomAnimationEffectPtr
& pEffect
, const Any
& rValue
)
979 bool bEffectChanged
= false;
982 case nPropertyTypeDirection
:
983 case nPropertyTypeSpokes
:
984 case nPropertyTypeZoom
:
986 OUString aPresetSubType
;
987 rValue
>>= aPresetSubType
;
988 if( aPresetSubType
!= pEffect
->getPresetSubType() )
990 CustomAnimationPresets::getCustomAnimationPresets().changePresetSubType( pEffect
, aPresetSubType
);
991 bEffectChanged
= true;
996 case nPropertyTypeFillColor
:
997 case nPropertyTypeColor
:
998 case nPropertyTypeFirstColor
:
999 case nPropertyTypeSecondColor
:
1000 case nPropertyTypeCharColor
:
1001 case nPropertyTypeLineColor
:
1003 const sal_Int32 nIndex
= (nPropertyTypeFirstColor
== nType
) ? 0 : 1;
1004 Any
aOldColor( pEffect
->getColor( nIndex
) );
1005 if( aOldColor
!= rValue
)
1007 pEffect
->setColor( nIndex
, rValue
);
1008 bEffectChanged
= true;
1013 case nPropertyTypeFont
:
1014 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::SET
, u
"CharFontName" , EValue::To
, rValue
);
1017 case nPropertyTypeCharHeight
:
1019 static constexpr OUString
aAttributeName( u
"CharHeight"_ustr
);
1020 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::SET
, aAttributeName
, EValue::To
, rValue
);
1021 if( !bEffectChanged
)
1022 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::ANIMATE
, aAttributeName
, EValue::To
, rValue
);
1025 case nPropertyTypeRotate
:
1026 bEffectChanged
= pEffect
->setTransformationProperty( AnimationTransformType::ROTATE
, EValue::By
, rValue
);
1029 case nPropertyTypeTransparency
:
1030 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::SET
, u
"Opacity" , EValue::To
, rValue
);
1033 case nPropertyTypeScale
:
1034 bEffectChanged
= pEffect
->setTransformationProperty( AnimationTransformType::SCALE
, EValue::By
, rValue
);
1037 case nPropertyTypeCharDecoration
:
1039 Sequence
< Any
> aValues(3);
1041 bEffectChanged
= pEffect
->setProperty( AnimationNodeType::SET
, u
"CharWeight" , EValue::To
, aValues
[0] );
1042 bEffectChanged
|= pEffect
->setProperty( AnimationNodeType::SET
, u
"CharPosture" , EValue::To
, aValues
[1] );
1043 bEffectChanged
|= pEffect
->setProperty( AnimationNodeType::SET
, u
"CharUnderline" , EValue::To
, aValues
[2] );
1049 return bEffectChanged
;
1052 static bool hasVisibleShape( const Reference
< XShape
>& xShape
)
1056 const OUString
sShapeType( xShape
->getShapeType() );
1058 if( sShapeType
== "com.sun.star.presentation.TitleTextShape" || sShapeType
== "com.sun.star.presentation.OutlinerShape" ||
1059 sShapeType
== "com.sun.star.presentation.SubtitleShape" || sShapeType
== "com.sun.star.drawing.TextShape" )
1061 Reference
< XPropertySet
> xSet( xShape
, UNO_QUERY_THROW
);
1063 FillStyle eFillStyle
;
1064 xSet
->getPropertyValue( u
"FillStyle"_ustr
) >>= eFillStyle
;
1066 css::drawing::LineStyle eLineStyle
;
1067 xSet
->getPropertyValue( u
"LineStyle"_ustr
) >>= eLineStyle
;
1069 return eFillStyle
!= FillStyle_NONE
|| eLineStyle
!= css::drawing::LineStyle_NONE
;
1078 std::unique_ptr
<STLPropertySet
> CustomAnimationPane::createSelectionSet()
1080 std::unique_ptr
<STLPropertySet
> pSet
= CustomAnimationDialog::createDefaultSet();
1082 pSet
->setPropertyValue( nHandleCurrentPage
, Any( mxCurrentPage
) );
1084 sal_Int32 nMaxParaDepth
= 0;
1086 // get options from selected effects
1087 const CustomAnimationPresets
& rPresets (CustomAnimationPresets::getCustomAnimationPresets());
1088 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
1090 EffectSequenceHelper
* pEffectSequence
= pEffect
->getEffectSequence();
1091 if( !pEffectSequence
)
1092 pEffectSequence
= mpMainSequence
.get();
1094 if( pEffect
->hasText() )
1096 sal_Int32 n
= calcMaxParaDepth(pEffect
->getTargetShape());
1097 if( n
> nMaxParaDepth
)
1101 addValue( pSet
, nHandleHasAfterEffect
, Any( pEffect
->hasAfterEffect() ) );
1102 addValue( pSet
, nHandleAfterEffectOnNextEffect
, Any( pEffect
->IsAfterEffectOnNext() ) );
1103 addValue( pSet
, nHandleDimColor
, pEffect
->getDimColor() );
1104 addValue( pSet
, nHandleIterateType
, Any( pEffect
->getIterateType() ) );
1106 // convert absolute time to percentage value
1107 // This calculation is done in float to avoid some rounding artifacts.
1108 float fIterateInterval
= static_cast<float>(pEffect
->getIterateInterval());
1109 if( pEffect
->getDuration() )
1110 fIterateInterval
= static_cast<float>(fIterateInterval
/ pEffect
->getDuration() );
1111 fIterateInterval
*= 100.0;
1112 addValue( pSet
, nHandleIterateInterval
, Any( static_cast<double>(fIterateInterval
) ) );
1114 addValue( pSet
, nHandleBegin
, Any( pEffect
->getBegin() ) );
1115 addValue( pSet
, nHandleDuration
, Any( pEffect
->getDuration() ) );
1116 addValue( pSet
, nHandleStart
, Any( pEffect
->getNodeType() ) );
1117 addValue( pSet
, nHandleRepeat
, pEffect
->getRepeatCount() );
1118 addValue( pSet
, nHandleEnd
, pEffect
->getEnd() );
1119 addValue( pSet
, nHandleRewind
, Any( pEffect
->getFill() ) );
1121 addValue( pSet
, nHandlePresetId
, Any( pEffect
->getPresetId() ) );
1123 addValue( pSet
, nHandleHasText
, Any( pEffect
->hasText() ) );
1125 addValue( pSet
, nHandleHasVisibleShape
, Any( hasVisibleShape( pEffect
->getTargetShape() ) ) );
1128 if( pEffect
->getAudio().is() )
1130 aSoundSource
= pEffect
->getAudio()->getSource();
1131 addValue( pSet
, nHandleSoundVolume
, Any( pEffect
->getAudio()->getVolume() ) );
1132 // todo addValue( pSet, nHandleSoundEndAfterSlide, makeAny( pEffect->getAudio()->getEndAfterSlide() ) );
1133 // this is now stored at the XCommand parameter sequence
1135 else if( pEffect
->getCommand() == EffectCommands::STOPAUDIO
)
1137 aSoundSource
<<= true;
1139 addValue( pSet
, nHandleSoundURL
, aSoundSource
);
1141 sal_Int32 nGroupId
= pEffect
->getGroupId();
1142 CustomAnimationTextGroupPtr pTextGroup
;
1143 if( nGroupId
!= -1 )
1144 pTextGroup
= pEffectSequence
->findGroup( nGroupId
);
1146 addValue( pSet
, nHandleTextGrouping
, Any( pTextGroup
? pTextGroup
->getTextGrouping() : sal_Int32(-1) ) );
1147 addValue( pSet
, nHandleAnimateForm
, Any( !pTextGroup
|| pTextGroup
->getAnimateForm() ) );
1148 addValue( pSet
, nHandleTextGroupingAuto
, Any( pTextGroup
? pTextGroup
->getTextGroupingAuto() : -1.0 ) );
1149 addValue( pSet
, nHandleTextReverse
, Any( pTextGroup
&& pTextGroup
->getTextReverse() ) );
1151 if( pEffectSequence
->getSequenceType() == EffectNodeType::INTERACTIVE_SEQUENCE
)
1153 InteractiveSequence
* pIS
= static_cast< InteractiveSequence
* >( pEffectSequence
);
1154 addValue( pSet
, nHandleTrigger
, Any( pIS
->getTriggerShape() ) );
1157 CustomAnimationPresetPtr pDescriptor
= rPresets
.getEffectDescriptor( pEffect
->getPresetId() );
1160 sal_Int32 nType
= nPropertyTypeNone
;
1162 std::vector
<OUString
> aProperties( pDescriptor
->getProperties() );
1163 if( !aProperties
.empty() )
1164 nType
= getPropertyType( aProperties
.front() );
1166 if( nType
!= nPropertyTypeNone
)
1168 addValue( pSet
, nHandleProperty1Type
, Any( nType
) );
1169 addValue( pSet
, nHandleProperty1Value
, getProperty1Value( nType
, pEffect
) );
1172 if( pDescriptor
->hasProperty( u
"Accelerate" ) )
1174 addValue( pSet
, nHandleAccelerate
, Any( pEffect
->getAcceleration() ) );
1177 if( pDescriptor
->hasProperty( u
"Decelerate" ) )
1179 addValue( pSet
, nHandleDecelerate
, Any( pEffect
->getDecelerate() ) );
1182 if( pDescriptor
->hasProperty( u
"AutoReverse" ) )
1184 addValue( pSet
, nHandleAutoReverse
, Any( pEffect
->getAutoReverse() ) );
1189 addValue( pSet
, nHandleMaxParaDepth
, Any( nMaxParaDepth
) );
1194 void CustomAnimationPane::changeSelection( STLPropertySet
const * pResultSet
, STLPropertySet
const * pOldSet
)
1196 // change selected effect
1197 bool bChanged
= false;
1199 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
1201 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
1203 DBG_ASSERT( pEffect
->getEffectSequence(), "sd::CustomAnimationPane::changeSelection(), dead effect in selection!" );
1204 if( !pEffect
->getEffectSequence() )
1207 double fDuration
= 0.0; // we might need this for iterate-interval
1208 if( pResultSet
->getPropertyState( nHandleDuration
) == STLPropertyState::Direct
)
1210 pResultSet
->getPropertyValue( nHandleDuration
) >>= fDuration
;
1214 fDuration
= pEffect
->getDuration();
1217 if( pResultSet
->getPropertyState( nHandleIterateType
) == STLPropertyState::Direct
)
1219 sal_Int16 nIterateType
= 0;
1220 pResultSet
->getPropertyValue( nHandleIterateType
) >>= nIterateType
;
1221 if( pEffect
->getIterateType() != nIterateType
)
1223 pEffect
->setIterateType( nIterateType
);
1228 if( pEffect
->getIterateType() )
1230 if( pResultSet
->getPropertyState( nHandleIterateInterval
) == STLPropertyState::Direct
)
1232 double fIterateInterval
= 0.0;
1233 pResultSet
->getPropertyValue( nHandleIterateInterval
) >>= fIterateInterval
;
1234 if( pEffect
->getIterateInterval() != fIterateInterval
)
1236 const double f
= fIterateInterval
* pEffect
->getDuration() / 100;
1237 pEffect
->setIterateInterval( f
);
1243 double fBegin
= 0.0;
1245 if( pResultSet
->getPropertyState( nHandleBegin
) == STLPropertyState::Direct
)
1246 pResultSet
->getPropertyValue( nHandleBegin
) >>= fBegin
;
1248 fBegin
= pEffect
->getBegin();
1250 if( pEffect
->getBegin() != fBegin
&& pResultSet
->getPropertyState( nHandleBegin
) == STLPropertyState::Direct
)
1252 pEffect
->setBegin( fBegin
);
1256 if( pResultSet
->getPropertyState( nHandleDuration
) == STLPropertyState::Direct
)
1258 if( pEffect
->getDuration() != fDuration
)
1260 pEffect
->setDuration( fDuration
);
1265 if( pResultSet
->getPropertyState( nHandleStart
) == STLPropertyState::Direct
)
1267 sal_Int16 nNodeType
= 0;
1268 pResultSet
->getPropertyValue( nHandleStart
) >>= nNodeType
;
1269 if( pEffect
->getNodeType() != nNodeType
)
1271 pEffect
->setNodeType( nNodeType
);
1276 if( pResultSet
->getPropertyState( nHandleRepeat
) == STLPropertyState::Direct
)
1278 Any
aRepeatCount( pResultSet
->getPropertyValue( nHandleRepeat
) );
1279 if( aRepeatCount
!= pEffect
->getRepeatCount() )
1281 pEffect
->setRepeatCount( aRepeatCount
);
1286 if( pResultSet
->getPropertyState( nHandleEnd
) == STLPropertyState::Direct
)
1288 Any
aEndValue( pResultSet
->getPropertyValue( nHandleEnd
) );
1289 if( pEffect
->getEnd() != aEndValue
)
1291 pEffect
->setEnd( aEndValue
);
1296 if( pResultSet
->getPropertyState( nHandleRewind
) == STLPropertyState::Direct
)
1298 sal_Int16 nFill
= 0;
1299 pResultSet
->getPropertyValue( nHandleRewind
) >>= nFill
;
1300 if( pEffect
->getFill() != nFill
)
1302 pEffect
->setFill( nFill
);
1307 if( pResultSet
->getPropertyState( nHandleHasAfterEffect
) == STLPropertyState::Direct
)
1309 bool bHasAfterEffect
= false;
1310 if( pResultSet
->getPropertyValue( nHandleHasAfterEffect
) >>= bHasAfterEffect
)
1312 if( pEffect
->hasAfterEffect() != bHasAfterEffect
)
1314 pEffect
->setHasAfterEffect( bHasAfterEffect
);
1320 if( pResultSet
->getPropertyState( nHandleAfterEffectOnNextEffect
) == STLPropertyState::Direct
)
1322 bool bAfterEffectOnNextEffect
= false;
1323 if( (pResultSet
->getPropertyValue( nHandleAfterEffectOnNextEffect
) >>= bAfterEffectOnNextEffect
)
1324 && (pEffect
->IsAfterEffectOnNext() != bAfterEffectOnNextEffect
) )
1326 pEffect
->setAfterEffectOnNext( bAfterEffectOnNextEffect
);
1331 if( pResultSet
->getPropertyState( nHandleDimColor
) == STLPropertyState::Direct
)
1333 Any
aDimColor( pResultSet
->getPropertyValue( nHandleDimColor
) );
1334 if( pEffect
->getDimColor() != aDimColor
)
1336 pEffect
->setDimColor( aDimColor
);
1341 if( pResultSet
->getPropertyState( nHandleAccelerate
) == STLPropertyState::Direct
)
1343 double fAccelerate
= 0.0;
1344 pResultSet
->getPropertyValue( nHandleAccelerate
) >>= fAccelerate
;
1345 if( pEffect
->getAcceleration() != fAccelerate
)
1347 pEffect
->setAcceleration( fAccelerate
);
1352 if( pResultSet
->getPropertyState( nHandleDecelerate
) == STLPropertyState::Direct
)
1354 double fDecelerate
= 0.0;
1355 pResultSet
->getPropertyValue( nHandleDecelerate
) >>= fDecelerate
;
1356 if( pEffect
->getDecelerate() != fDecelerate
)
1358 pEffect
->setDecelerate( fDecelerate
);
1363 if( pResultSet
->getPropertyState( nHandleAutoReverse
) == STLPropertyState::Direct
)
1365 bool bAutoReverse
= false;
1366 pResultSet
->getPropertyValue( nHandleAutoReverse
) >>= bAutoReverse
;
1367 if( pEffect
->getAutoReverse() != bAutoReverse
)
1369 pEffect
->setAutoReverse( bAutoReverse
);
1374 if( pResultSet
->getPropertyState( nHandleProperty1Value
) == STLPropertyState::Direct
)
1376 sal_Int32 nType
= 0;
1377 pOldSet
->getPropertyValue( nHandleProperty1Type
) >>= nType
;
1379 bChanged
|= setProperty1Value( nType
, pEffect
, pResultSet
->getPropertyValue( nHandleProperty1Value
) );
1382 if( pResultSet
->getPropertyState( nHandleSoundURL
) == STLPropertyState::Direct
)
1384 const Any
aSoundSource( pResultSet
->getPropertyValue( nHandleSoundURL
) );
1386 if( aSoundSource
.getValueType() == ::cppu::UnoType
<sal_Bool
>::get() )
1388 pEffect
->setStopAudio();
1394 aSoundSource
>>= aSoundURL
;
1396 if( !aSoundURL
.isEmpty() )
1398 if( !pEffect
->getAudio().is() )
1400 pEffect
->createAudio( aSoundSource
);
1405 if( pEffect
->getAudio()->getSource() != aSoundSource
)
1407 pEffect
->getAudio()->setSource( aSoundSource
);
1414 if( pEffect
->getAudio().is() || pEffect
->getStopAudio() )
1416 pEffect
->removeAudio();
1423 if( pResultSet
->getPropertyState( nHandleTrigger
) == STLPropertyState::Direct
)
1425 Reference
< XShape
> xTriggerShape
;
1426 pResultSet
->getPropertyValue( nHandleTrigger
) >>= xTriggerShape
;
1427 bChanged
|= mpMainSequence
->setTrigger( pEffect
, xTriggerShape
);
1431 const bool bHasTextGrouping
= pResultSet
->getPropertyState( nHandleTextGrouping
) == STLPropertyState::Direct
;
1432 const bool bHasAnimateForm
= pResultSet
->getPropertyState( nHandleAnimateForm
) == STLPropertyState::Direct
;
1433 const bool bHasTextGroupingAuto
= pResultSet
->getPropertyState( nHandleTextGroupingAuto
) == STLPropertyState::Direct
;
1434 const bool bHasTextReverse
= pResultSet
->getPropertyState( nHandleTextReverse
) == STLPropertyState::Direct
;
1436 if( bHasTextGrouping
|| bHasAnimateForm
|| bHasTextGroupingAuto
|| bHasTextReverse
)
1438 // we need to do a second pass for text grouping options
1439 // since changing them can cause effects to be removed
1440 // or replaced, we do this after we applied all other options
1443 sal_Int32 nTextGrouping
= 0;
1444 bool bAnimateForm
= true, bTextReverse
= false;
1445 double fTextGroupingAuto
= -1.0;
1447 if( bHasTextGrouping
)
1448 pResultSet
->getPropertyValue(nHandleTextGrouping
) >>= nTextGrouping
;
1450 pOldSet
->getPropertyValue(nHandleTextGrouping
) >>= nTextGrouping
;
1452 if( bHasAnimateForm
)
1453 pResultSet
->getPropertyValue(nHandleAnimateForm
) >>= bAnimateForm
;
1455 pOldSet
->getPropertyValue(nHandleAnimateForm
) >>= bAnimateForm
;
1457 if( bHasTextGroupingAuto
)
1458 pResultSet
->getPropertyValue(nHandleTextGroupingAuto
) >>= fTextGroupingAuto
;
1460 pOldSet
->getPropertyValue(nHandleTextGroupingAuto
) >>= fTextGroupingAuto
;
1462 if( bHasTextReverse
)
1463 pResultSet
->getPropertyValue(nHandleTextReverse
) >>= bTextReverse
;
1465 pOldSet
->getPropertyValue(nHandleTextReverse
) >>= bTextReverse
;
1467 EffectSequence
const aSelectedEffects( maListSelection
);
1468 for( CustomAnimationEffectPtr
const& pEffect
: aSelectedEffects
)
1470 EffectSequenceHelper
* pEffectSequence
= pEffect
->getEffectSequence();
1471 if( !pEffectSequence
)
1472 pEffectSequence
= mpMainSequence
.get();
1474 sal_Int32 nGroupId
= pEffect
->getGroupId();
1475 CustomAnimationTextGroupPtr pTextGroup
;
1476 if( nGroupId
!= -1 )
1478 // use existing group
1479 pTextGroup
= pEffectSequence
->findGroup( nGroupId
);
1483 // somethings changed so we need a group now
1484 pTextGroup
= pEffectSequence
->createTextGroup( pEffect
, nTextGrouping
, fTextGroupingAuto
, bAnimateForm
, bTextReverse
);
1489 /************************************************************************/
1491 Note, the setAnimateForm means set the animation from TextGroup to Object's Shape
1492 And on the UI in means "Animate attached shape" in "Effect Option" dialog
1493 The setTextGrouping means set animation to Object's Text,
1494 the nTextGrouping is Text Animation Type
1495 nTextGrouping = -1 is "As one Object", means no text animation.
1497 The previous call order first do the setTextGrouping and then do the setAnimateForm,
1498 that will cause such defect: in the setTextGrouping, the effect has been removed,
1499 but in setAnimateForm still need this effect, then a NULL pointer of that effect will
1500 be gotten, and cause crash.
1502 []bHasAnimateForm means the UI has changed, bAnimateForm is it value
1504 So if create a new textgroup animation, the following animation will never be run!
1505 Since the \A1\B0Animate attached shape\A1\B1 is default checked.
1506 And the bHasAnimateForm default is false, and if user uncheck it the value bAnimateForm will be false,
1507 it same as the TextGroup\A1\AFs default value, also could not be run setAnimateForm.
1508 if( bHasAnimateForm )
1510 if( pTextGroup->getAnimateForm() != bAnimateForm )
1512 pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1517 In setTextGrouping, there are three case:
1518 1. Create new text effects for empty TextGroup
1519 2. Remove all text effects of TextGroup (nTextGrouping == -1)
1520 3. Change all the text effects\A1\AF start type
1522 So here is the right logic:
1523 If set the animation from text to shape and remove text animation,
1524 should do setAnimateForm first, then do setTextGrouping.
1525 Other case,do setTextGrouping first, then do setAnimateForm.
1528 /************************************************************************/
1530 bool bDoSetAnimateFormFirst
= false;
1531 bool bNeedDoSetAnimateForm
= false;
1533 if( bHasAnimateForm
)
1535 if( pTextGroup
&& pTextGroup
->getAnimateForm() != bAnimateForm
)
1537 if( (pTextGroup
->getTextGrouping() >= 0) && (nTextGrouping
== -1 ) )
1539 bDoSetAnimateFormFirst
= true;
1541 bNeedDoSetAnimateForm
= true;
1545 if (bDoSetAnimateFormFirst
)
1547 pEffectSequence
->setAnimateForm( pTextGroup
, bAnimateForm
);
1551 if( bHasTextGrouping
)
1553 if( pTextGroup
&& pTextGroup
->getTextGrouping() != nTextGrouping
)
1555 pEffectSequence
->setTextGrouping( pTextGroup
, nTextGrouping
);
1557 // All the effects of the outline object is removed so we need to
1558 // put it back. OTOH, the shape object that still has effects
1559 // in the text group is fine.
1560 if (nTextGrouping
== -1 && pTextGroup
->getEffects().empty())
1562 pEffect
->setTarget(Any(pEffect
->getTargetShape()));
1563 pEffect
->setGroupId(-1);
1564 mpMainSequence
->append(pEffect
);
1571 if (!bDoSetAnimateFormFirst
&& bNeedDoSetAnimateForm
)
1575 pEffectSequence
->setAnimateForm( pTextGroup
, bAnimateForm
);
1580 if( bHasTextGroupingAuto
)
1582 if( pTextGroup
&& pTextGroup
->getTextGroupingAuto() != fTextGroupingAuto
)
1584 pEffectSequence
->setTextGroupingAuto( pTextGroup
, fTextGroupingAuto
);
1589 if( bHasTextReverse
)
1591 if( pTextGroup
&& pTextGroup
->getTextReverse() != bTextReverse
)
1593 pEffectSequence
->setTextReverse( pTextGroup
, bTextReverse
);
1602 mpMainSequence
->rebuild();
1604 mrBase
.GetDocShell()->SetModified();
1608 void CustomAnimationPane::showOptions(const OUString
& rPage
)
1610 std::unique_ptr
<STLPropertySet
> xSet
= createSelectionSet();
1612 auto xDlg
= std::make_shared
<CustomAnimationDialog
>(GetFrameWeld(), std::move(xSet
), rPage
);
1614 weld::DialogController::runAsync(xDlg
, [xDlg
, this](sal_Int32 nResult
){
1618 changeSelection(xDlg
->getResultSet(), xDlg
->getPropertySet());
1624 void CustomAnimationPane::onChangeCurrentPage()
1631 Reference
< XDrawPage
> xNewPage( mxView
->getCurrentPage() );
1632 if( xNewPage
!= mxCurrentPage
)
1634 mxCurrentPage
= std::move(xNewPage
);
1635 SdPage
* pPage
= SdPage::getImplementation( mxCurrentPage
);
1638 mpMainSequence
= pPage
->getMainSequence();
1639 mxCustomAnimationList
->update( mpMainSequence
);
1646 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::onChangeCurrentPage()" );
1650 static bool getTextSelection(const Reference
< XTextRange
>& xSelectedText
, Reference
< XShape
>& xShape
, std::vector
< sal_Int16
>& rParaList
)
1652 if( xSelectedText
.is() ) try
1654 xShape
.set( xSelectedText
->getText(), UNO_QUERY_THROW
);
1656 css::uno::Reference
<css::document::XActionLockable
> xLockable(xShape
, css::uno::UNO_QUERY
);
1658 xLockable
->addActionLock();
1659 comphelper::ScopeGuard
aGuard([&xLockable
]()
1662 xLockable
->removeActionLock();
1665 Reference
< XTextRangeCompare
> xTextRangeCompare( xShape
, UNO_QUERY_THROW
);
1666 Reference
< XEnumerationAccess
> xParaEnumAccess( xShape
, UNO_QUERY_THROW
);
1667 Reference
< XEnumeration
> xParaEnum( xParaEnumAccess
->createEnumeration(), UNO_SET_THROW
);
1668 Reference
< XTextRange
> xRange
;
1669 Reference
< XTextRange
> xStart( xSelectedText
->getStart() );
1670 Reference
< XTextRange
> xEnd( xSelectedText
->getEnd() );
1672 if (xTextRangeCompare
->compareRegionEnds(xStart
, xEnd
) < 0)
1673 std::swap(xStart
, xEnd
);
1675 sal_Int16 nPara
= 0;
1676 while( xParaEnum
->hasMoreElements() )
1678 xParaEnum
->nextElement() >>= xRange
;
1680 // break if start of selection is prior to end of current paragraph
1681 if( xRange
.is() && (xTextRangeCompare
->compareRegionEnds( xStart
, xRange
) >= 0 ) )
1687 while( xRange
.is() )
1689 if( xRange
.is() && !xRange
->getString().isEmpty() )
1690 rParaList
.push_back( nPara
);
1692 // break if end of selection is before or at end of current paragraph
1693 if( xRange
.is() && xTextRangeCompare
->compareRegionEnds( xEnd
, xRange
) >= 0 )
1698 if( xParaEnum
->hasMoreElements() )
1699 xParaEnum
->nextElement() >>= xRange
;
1708 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::getTextSelection()" );
1716 Reference
<XShape
> getTargetShape(const Any
& rTarget
)
1718 Reference
<XShape
> xShape
;
1722 ParagraphTarget aParaTarget
;
1723 if (rTarget
>>= aParaTarget
)
1724 xShape
= aParaTarget
.Shape
;
1730 void CustomAnimationPane::onAdd()
1732 bool bHasText
= true;
1734 // first create vector of targets for dialog preview
1735 std::vector
< Any
> aTargets
;
1737 // gather shapes from the selection
1738 maViewSelection
= mxView
->getSelection();
1740 if (Reference
<XIndexAccess
> xShapes
; maViewSelection
>>= xShapes
)
1742 sal_Int32 nCount
= xShapes
->getCount();
1743 aTargets
.reserve( nCount
);
1744 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; nIndex
++ )
1746 Any
aTarget( xShapes
->getByIndex( nIndex
) );
1747 aTargets
.push_back( aTarget
);
1750 Reference
< XText
> xText
;
1752 if( !xText
.is() || xText
->getString().isEmpty() )
1757 else if (Reference
<XText
> xText
; maViewSelection
>>= xText
)
1759 aTargets
.push_back( maViewSelection
);
1760 if( !xText
.is() || xText
->getString().isEmpty() )
1763 else if (Reference
<XTextCursor
> xCursor
; maViewSelection
>>= xCursor
)
1765 Reference
< XShape
> xShape
;
1766 std::vector
< sal_Int16
> aParaList
;
1767 if (getTextSelection(xCursor
, xShape
, aParaList
))
1769 ParagraphTarget aParaTarget
;
1770 aParaTarget
.Shape
= std::move(xShape
);
1772 for( const auto& rPara
: aParaList
)
1774 aParaTarget
.Paragraph
= rPara
;
1775 aTargets
.push_back( Any( aParaTarget
) );
1781 OSL_FAIL("sd::CustomAnimationPane::onAdd(), unknown view selection!" );
1785 CustomAnimationPresetPtr pDescriptor
;
1786 mxFTCategory
->set_sensitive(true);
1787 mxFTAnimation
->set_sensitive(true);
1789 bool bCategoryReset
= false;
1791 if (!mxLBCategory
->get_sensitive() || mxLBCategory
->get_active() == -1)
1793 mxLBCategory
->set_sensitive(true);
1794 mxLBCategory
->set_active(0);
1795 bCategoryReset
= true;
1798 if (bCategoryReset
|| !mxLBAnimation
->get_sensitive() ||
1799 mxLBAnimation
->get_selected_index() == -1)
1801 mxLBAnimation
->set_sensitive(true);
1803 sal_Int32 nFirstEffect
= fillAnimationLB(bHasText
);
1804 if (nFirstEffect
== -1)
1807 mxLBAnimation
->select(nFirstEffect
);
1808 mnLastSelectedAnimation
= nFirstEffect
;
1811 auto pEntryData
= weld::fromId
<CustomAnimationPresetPtr
*>(mxLBAnimation
->get_selected_id());
1813 pDescriptor
= *pEntryData
;
1817 const double fDuration
= pDescriptor
->getDuration();
1818 mxCBXDuration
->set_value(fDuration
*100.0, FieldUnit::NONE
);
1819 bool bHasSpeed
= pDescriptor
->getDuration() > 0.001;
1820 mxCBXDuration
->set_sensitive( bHasSpeed
);
1821 mxFTDuration
->set_sensitive( bHasSpeed
);
1823 mxCustomAnimationList
->unselect_all();
1825 // gather shapes from the selection
1827 for( const auto& rTarget
: aTargets
)
1829 css::uno::Reference
<css::document::XActionLockable
> xLockable(getTargetShape(rTarget
), css::uno::UNO_QUERY
);
1831 xLockable
->addActionLock();
1832 comphelper::ScopeGuard
aGuard([&xLockable
]()
1835 xLockable
->removeActionLock();
1838 CustomAnimationEffectPtr pCreated
= mpMainSequence
->append( pDescriptor
, rTarget
, fDuration
);
1840 // if only one shape with text and no fill or outline is selected, animate only by first level paragraphs
1841 if( bHasText
&& (aTargets
.size() == 1) )
1843 Reference
< XShape
> xShape( rTarget
, UNO_QUERY
);
1844 if( xShape
.is() && !hasVisibleShape( xShape
) )
1846 mpMainSequence
->createTextGroup( pCreated
, 1, -1.0, false, false );
1853 pCreated
->setNodeType( EffectNodeType::WITH_PREVIOUS
);
1856 mxCustomAnimationList
->select( pCreated
);
1860 PathKind ePathKind
= getCreatePathKind();
1862 if (ePathKind
!= PathKind::NONE
)
1864 createPath( ePathKind
, aTargets
, 0.0 );
1865 updateMotionPathTags();
1869 mrBase
.GetDocShell()->SetModified();
1873 if (!SlideShow::IsInteractiveSlideshow(&mrBase
)) // IASS
1874 SlideShow::Stop( mrBase
);
1877 void CustomAnimationPane::onRemove()
1879 if( maListSelection
.empty() )
1884 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
1886 EffectSequence
aList( maListSelection
);
1888 for( CustomAnimationEffectPtr
& pEffect
: aList
)
1890 if( pEffect
->getEffectSequence() )
1891 pEffect
->getEffectSequence()->remove( pEffect
);
1894 maListSelection
.clear();
1895 mrBase
.GetDocShell()->SetModified();
1898 void CustomAnimationPane::remove( CustomAnimationEffectPtr
const & pEffect
)
1900 if( pEffect
->getEffectSequence() )
1903 pEffect
->getEffectSequence()->remove( pEffect
);
1904 mrBase
.GetDocShell()->SetModified();
1908 void CustomAnimationPane::onChangeStart()
1910 sal_Int16 nNodeType
;
1911 switch( mxLBStart
->get_active() )
1913 case 0: nNodeType
= EffectNodeType::ON_CLICK
; break;
1914 case 1: nNodeType
= EffectNodeType::WITH_PREVIOUS
; break;
1915 case 2: nNodeType
= EffectNodeType::AFTER_PREVIOUS
; break;
1920 onChangeStart( nNodeType
);
1923 void CustomAnimationPane::onChangeStart( sal_Int16 nNodeType
)
1927 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
1929 bool bNeedRebuild
= false;
1931 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
1933 if( pEffect
->getNodeType() != nNodeType
)
1935 pEffect
->setNodeType( nNodeType
);
1936 bNeedRebuild
= true;
1942 mpMainSequence
->rebuild();
1944 mrBase
.GetDocShell()->SetModified();
1948 void CustomAnimationPane::onChangeSpeed()
1950 double fDuration
= getDuration();
1958 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
1960 // change selected effect
1961 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
1963 pEffect
->setDuration( fDuration
);
1966 mpMainSequence
->rebuild();
1968 mrBase
.GetDocShell()->SetModified();
1972 double CustomAnimationPane::getDuration() const
1974 double fDuration
= 0;
1976 if (!mxCBXDuration
->get_text().isEmpty())
1977 fDuration
= mxCBXDuration
->get_value(FieldUnit::NONE
) / 100.0;
1982 PathKind
CustomAnimationPane::getCreatePathKind() const
1984 PathKind eKind
= PathKind::NONE
;
1986 if (mxLBAnimation
->count_selected_rows() == 1 &&
1987 mxLBCategory
->get_active() == gnMotionPathPos
)
1989 const sal_Int32 nPos
= mxLBAnimation
->get_selected_index();
1990 if( nPos
== mnCurvePathPos
)
1992 eKind
= PathKind::CURVE
;
1994 else if( nPos
== mnPolygonPathPos
)
1996 eKind
= PathKind::POLYGON
;
1998 else if( nPos
== mnFreeformPathPos
)
2000 eKind
= PathKind::FREEFORM
;
2007 void CustomAnimationPane::createPath( PathKind eKind
, std::vector
< Any
>& rTargets
, double fDuration
)
2009 sal_uInt16 nSID
= 0;
2013 case PathKind::CURVE
: nSID
= SID_DRAW_BEZIER_NOFILL
; break;
2014 case PathKind::POLYGON
: nSID
= SID_DRAW_POLYGON_NOFILL
; break;
2015 case PathKind::FREEFORM
: nSID
= SID_DRAW_FREELINE_NOFILL
; break;
2022 DrawViewShell
* pViewShell
= dynamic_cast< DrawViewShell
* >(
2023 FrameworkHelper::Instance(mrBase
)->GetViewShell(FrameworkHelper::msCenterPaneURL
).get());
2027 DrawView
* pView
= pViewShell
->GetDrawView();
2029 pView
->UnmarkAllObj();
2031 std::vector
< Any
> aTargets( 1, Any( fDuration
) );
2032 aTargets
.insert( aTargets
.end(), rTargets
.begin(), rTargets
.end() );
2033 Sequence
< Any
> aTargetSequence( comphelper::containerToSequence( aTargets
) );
2034 const SfxUnoAnyItem
aItem( SID_ADD_MOTION_PATH
, Any( aTargetSequence
) );
2035 pViewShell
->GetViewFrame()->GetDispatcher()->ExecuteList( nSID
, SfxCallMode::ASYNCHRON
, {&aItem
} );
2040 /// this link is called when the property box is modified by the user
2041 IMPL_LINK_NOARG(CustomAnimationPane
, implPropertyHdl
, LinkParamNone
*, void)
2043 if (!mxLBSubControl
)
2048 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2050 const Any
aValue(mxLBSubControl
->getValue());
2052 bool bNeedUpdate
= false;
2054 // change selected effect
2055 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2057 if( setProperty1Value( mnPropertyType
, pEffect
, aValue
) )
2063 mpMainSequence
->rebuild();
2065 mrBase
.GetDocShell()->SetModified();
2071 IMPL_LINK_NOARG(CustomAnimationPane
, DelayModifiedHdl
, weld::MetricSpinButton
&, void)
2076 IMPL_LINK_NOARG(CustomAnimationPane
, DelayLoseFocusHdl
, weld::Widget
&, void)
2078 double fBegin
= mxMFStartDelay
->get_value(FieldUnit::NONE
);
2080 //sequence rebuild only when the control loses focus
2081 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2083 // change selected effect
2084 for( CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2086 pEffect
->setBegin( fBegin
/10.0 );
2089 mpMainSequence
->rebuild();
2091 mrBase
.GetDocShell()->SetModified();
2094 IMPL_LINK_NOARG(CustomAnimationPane
, AnimationSelectHdl
, weld::TreeView
&, void)
2099 IMPL_LINK_NOARG(CustomAnimationPane
, SelectionHandler
, Timer
*, void)
2101 if (mxLBAnimation
->has_grab()) // tdf#136474 try again later
2107 int nSelected
= mxLBAnimation
->get_selected_index();
2108 if (nSelected
== -1)
2111 // tdf#99137, the selected entry may also be a subcategory title, so not an effect
2112 // just skip it and move to the next one in this case
2113 if (mxLBAnimation
->get_text_emphasis(nSelected
, 0))
2115 if (nSelected
== 0 || nSelected
> mnLastSelectedAnimation
)
2116 mxLBAnimation
->select(++nSelected
);
2118 mxLBAnimation
->select(--nSelected
);
2121 mnLastSelectedAnimation
= nSelected
;
2123 CustomAnimationPresetPtr
* pPreset
= weld::fromId
<CustomAnimationPresetPtr
*>(mxLBAnimation
->get_id(nSelected
));
2124 PathKind ePathKind
= getCreatePathKind();
2126 if ( ePathKind
!= PathKind::NONE
)
2128 std::vector
< Any
> aTargets
;
2129 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2131 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2133 aTargets
.push_back( pEffect
->getTarget() );
2135 EffectSequenceHelper
* pEffectSequence
= pEffect
->getEffectSequence();
2136 if( !pEffectSequence
)
2137 pEffectSequence
= mpMainSequence
.get();
2139 // delete the old animation, new one will be appended
2140 // by createPath and SID_ADD_MOTION_PATH therein
2141 pEffectSequence
->remove( pEffect
);
2144 createPath( ePathKind
, aTargets
, 0.0 );
2145 updateMotionPathTags();
2149 CustomAnimationPresetPtr
pDescriptor(*pPreset
);
2150 const double fDuration
= (*pPreset
)->getDuration();
2151 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2153 // get selected effect
2154 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2156 // Dispose the deprecated motion path tag. It will be rebuilt later.
2157 if (pEffect
->getPresetClass() == css::presentation::EffectPresetClass::MOTIONPATH
)
2159 for (auto const& xTag
: maMotionPathTags
)
2161 if(xTag
->getEffect() == pEffect
&& !xTag
->isDisposed())
2166 EffectSequenceHelper
* pEffectSequence
= pEffect
->getEffectSequence();
2167 if( !pEffectSequence
)
2168 pEffectSequence
= mpMainSequence
.get();
2170 pEffectSequence
->replace( pEffect
, pDescriptor
, fDuration
);
2177 IMPL_LINK_NOARG(CustomAnimationPane
, UpdateAnimationLB
, weld::ComboBox
&, void)
2179 //FIXME: first effect only? what if there is more?
2180 bool bHasText
= false;
2181 if (!maListSelection
.empty())
2183 CustomAnimationEffectPtr pEffect
= maListSelection
.front();
2184 bHasText
= pEffect
&& pEffect
->hasText();
2186 fillAnimationLB(bHasText
);
2189 IMPL_LINK_NOARG(CustomAnimationPane
, DurationModifiedHdl
, weld::MetricSpinButton
&, void)
2191 if (!mxCBXDuration
->get_text().isEmpty())
2193 double duration_value
= static_cast<double>(mxCBXDuration
->get_value(FieldUnit::NONE
));
2194 if(duration_value
<= 0.0)
2196 mxCBXDuration
->set_value(1, FieldUnit::NONE
);
2204 void InsertCategory(weld::TreeView
& rLBAnimation
, const OUString
& rMotionPathLabel
)
2206 int nRow
= rLBAnimation
.n_children();
2207 rLBAnimation
.append_text(rMotionPathLabel
);
2208 rLBAnimation
.set_text_emphasis(nRow
, true, 0);
2209 rLBAnimation
.set_text_align(nRow
, 0.5, 0);
2213 sal_Int32
CustomAnimationPane::fillAnimationLB( bool bHasText
)
2215 PresetCategoryList rCategoryList
;
2216 sal_uInt16 nPosition
= mxLBCategory
->get_active();
2217 const CustomAnimationPresets
& rPresets (CustomAnimationPresets::getCustomAnimationPresets());
2220 case 0:rCategoryList
= rPresets
.getEntrancePresets();break;
2221 case 1:rCategoryList
= rPresets
.getEmphasisPresets();break;
2222 case 2:rCategoryList
= rPresets
.getExitPresets();break;
2223 case 3:rCategoryList
= rPresets
.getMotionPathsPresets();break;
2224 case 4:rCategoryList
= rPresets
.getMiscPresets();break;
2227 sal_Int32 nFirstEffect
= -1;
2229 int nOldEntryCount
= mxLBAnimation
->n_children();
2230 int nOldScrollPos
= mxLBAnimation
->vadjustment_get_value();
2232 mxLBAnimation
->freeze();
2233 mxLBAnimation
->clear();
2234 mnLastSelectedAnimation
= -1;
2236 if (nPosition
== gnMotionPathPos
)
2238 OUString
sMotionPathLabel( SdResId( STR_CUSTOMANIMATION_USERPATH
) );
2239 InsertCategory(*mxLBAnimation
, sMotionPathLabel
);
2240 mnCurvePathPos
= mxLBAnimation
->n_children();
2241 mxLBAnimation
->append_text( SvxResId(STR_ObjNameSingulCOMBLINE
) );
2242 mxLBAnimation
->set_text_emphasis(mnCurvePathPos
, false, 0);
2243 mnPolygonPathPos
= mnCurvePathPos
+ 1;
2244 mxLBAnimation
->append_text( SvxResId(STR_ObjNameSingulPOLY
) );
2245 mxLBAnimation
->set_text_emphasis(mnPolygonPathPos
, false, 0);
2246 mnFreeformPathPos
= mnPolygonPathPos
+ 1;
2247 mxLBAnimation
->append_text( SvxResId(STR_ObjNameSingulFREELINE
) );
2248 mxLBAnimation
->set_text_emphasis(mnFreeformPathPos
, false, 0);
2251 for (const PresetCategoryPtr
& pCategory
: rCategoryList
)
2255 InsertCategory(*mxLBAnimation
, pCategory
->maLabel
);
2257 int nPos
= mxLBAnimation
->n_children();
2259 std::vector
< CustomAnimationPresetPtr
> aSortedVector
=
2260 pCategory
->maEffects
;
2262 for( const CustomAnimationPresetPtr
& pDescriptor
: aSortedVector
)
2264 // ( !isTextOnly || ( isTextOnly && bHasText ) ) <=> !isTextOnly || bHasText
2265 if( pDescriptor
&& ( !pDescriptor
->isTextOnly() || bHasText
) )
2267 auto pCustomPtr
= new CustomAnimationPresetPtr(pDescriptor
);
2268 OUString sId
= weld::toId(pCustomPtr
);
2269 mxLBAnimation
->append(sId
, pDescriptor
->getLabel());
2270 mxLBAnimation
->set_text_emphasis(nPos
, false, 0);
2272 if (nFirstEffect
== -1)
2273 nFirstEffect
= nPos
;
2281 mxLBAnimation
->thaw();
2283 if (mxLBAnimation
->n_children() == nOldEntryCount
)
2284 mxLBAnimation
->vadjustment_set_value(nOldScrollPos
);
2286 return nFirstEffect
;
2289 IMPL_LINK(CustomAnimationPane
, implToggleHdl
, weld::Toggleable
&, rBtn
, void)
2291 implControlHdl(&rBtn
);
2294 IMPL_LINK(CustomAnimationPane
, implClickHdl
, weld::Button
&, rBtn
, void)
2296 implControlHdl(&rBtn
);
2299 IMPL_LINK( CustomAnimationPane
, implControlListBoxHdl
, weld::ComboBox
&, rListBox
, void )
2301 implControlHdl(&rListBox
);
2304 /// this link is called when one of the controls is modified
2305 void CustomAnimationPane::implControlHdl(const weld::Widget
* pControl
)
2307 if (pControl
== mxPBAddEffect
.get())
2309 else if (pControl
== mxPBRemoveEffect
.get())
2311 else if (pControl
== mxLBStart
.get())
2313 else if (pControl
== mxPBPropertyMore
.get())
2315 else if (pControl
== mxPBMoveUp
.get())
2316 moveSelection( true );
2317 else if (pControl
== mxPBMoveDown
.get())
2318 moveSelection( false );
2319 else if (pControl
== mxPBPlay
.get())
2321 else if (pControl
== mxCBAutoPreview
.get())
2323 SdOptions
* pOptions
= SdModule::get()->GetSdOptions(DocumentType::Impress
);
2324 pOptions
->SetPreviewChangedEffects(mxCBAutoPreview
->get_active());
2328 IMPL_LINK_NOARG(CustomAnimationPane
, lateInitCallback
, Timer
*, void)
2330 // Call getPresets() to initiate the (expensive) construction of the
2332 CustomAnimationPresets::getCustomAnimationPresets();
2334 // update selection and control states
2335 onSelectionChanged();
2338 void CustomAnimationPane::moveSelection( bool bUp
)
2340 if( maListSelection
.empty() )
2343 EffectSequenceHelper
* pSequence
= maListSelection
.front()->getEffectSequence();
2344 if( pSequence
== nullptr )
2349 bool bChanged
= false;
2351 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2352 EffectSequence
& rEffectSequence
= pSequence
->getSequence();
2356 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2358 EffectSequence::iterator
aUpEffectPos( pSequence
->find( pEffect
) );
2359 // coverity[copy_paste_error : FALSE] - this is correct, checking if it exists
2360 if( aUpEffectPos
!= rEffectSequence
.end() )
2362 EffectSequence::iterator
aInsertPos( rEffectSequence
.erase( aUpEffectPos
) );
2364 if( aInsertPos
!= rEffectSequence
.begin() )
2367 while( (aInsertPos
!= rEffectSequence
.begin()) && !mxCustomAnimationList
->isExpanded(*aInsertPos
))
2369 rEffectSequence
.insert( aInsertPos
, pEffect
);
2373 rEffectSequence
.push_front( pEffect
);
2381 EffectSequence::reverse_iterator
aIter( maListSelection
.rbegin() );
2382 const EffectSequence::reverse_iterator
aEnd( maListSelection
.rend() );
2384 while( aIter
!= aEnd
)
2386 CustomAnimationEffectPtr pEffect
= *aIter
++;
2388 EffectSequence::iterator
aDownEffectPos( pSequence
->find( pEffect
) );
2389 // coverity[copy_paste_error : FALSE] - this is correct, checking if it exists
2390 if( aDownEffectPos
!= rEffectSequence
.end() )
2392 EffectSequence::iterator
aInsertPos( rEffectSequence
.erase( aDownEffectPos
) );
2394 if( aInsertPos
!= rEffectSequence
.end() )
2397 // Advance over rolled-up (un-expanded) items, unless we just moved it there.
2398 while( (aInsertPos
!= rEffectSequence
.end())
2399 && !mxCustomAnimationList
->isExpanded(*aInsertPos
)
2400 && (std::find(maListSelection
.begin(), maListSelection
.end(), *aInsertPos
)
2401 == maListSelection
.end())
2404 rEffectSequence
.insert( aInsertPos
, pEffect
);
2408 rEffectSequence
.push_back( pEffect
);
2417 mpMainSequence
->rebuild();
2419 mrBase
.GetDocShell()->SetModified();
2423 void CustomAnimationPane::onPreview( bool bForcePreview
)
2425 if (!bForcePreview
&& !mxCBAutoPreview
->get_active())
2428 // No preview in LOK.
2429 if (comphelper::LibreOfficeKit::isActive())
2432 if( maListSelection
.empty() )
2434 rtl::Reference
< MotionPathTag
> xMotionPathTag
;
2435 auto aIter
= std::find_if(maMotionPathTags
.begin(), maMotionPathTags
.end(),
2436 [](const MotionPathTagVector::value_type
& rxMotionPathTag
) { return rxMotionPathTag
->isSelected(); });
2437 if (aIter
!= maMotionPathTags
.end())
2438 xMotionPathTag
= *aIter
;
2440 if( xMotionPathTag
.is() )
2442 MainSequencePtr pSequence
= std::make_shared
<MainSequence
>();
2443 pSequence
->append( xMotionPathTag
->getEffect()->clone() );
2444 preview( pSequence
->getRootNode() );
2448 Reference
< XAnimationNodeSupplier
> xNodeSupplier( mxCurrentPage
, UNO_QUERY
);
2449 if( !xNodeSupplier
.is() )
2452 preview( xNodeSupplier
->getAnimationNode() );
2457 MainSequencePtr pSequence
= std::make_shared
<MainSequence
>();
2459 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2461 pSequence
->append( pEffect
->clone() );
2464 preview( pSequence
->getRootNode() );
2468 void CustomAnimationPane::preview( const Reference
< XAnimationNode
>& xAnimationNode
)
2470 Reference
< XParallelTimeContainer
> xRoot
= ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() );
2471 Sequence
< css::beans::NamedValue
> aUserData
2472 { { u
"node-type"_ustr
, css::uno::Any(css::presentation::EffectNodeType::TIMING_ROOT
) } };
2473 xRoot
->setUserData( aUserData
);
2474 xRoot
->appendChild( xAnimationNode
);
2476 SlideShow::StartPreview( mrBase
, mxCurrentPage
, xRoot
);
2479 // ICustomAnimationListController
2480 void CustomAnimationPane::onSelect()
2482 maListSelection
= mxCustomAnimationList
->getSelection();
2485 // mark shapes from selected effects
2486 if( maSelectionLock
.isLocked() )
2489 // tdf#145030 if nothing is selected in the effects list, leave the selection of
2490 // objects in the slide untouched
2491 if (maListSelection
.empty())
2494 ScopeLockGuard
aGuard( maSelectionLock
);
2495 DrawViewShell
* pViewShell
= dynamic_cast< DrawViewShell
* >(
2496 FrameworkHelper::Instance(mrBase
)->GetViewShell(FrameworkHelper::msCenterPaneURL
).get());
2497 DrawView
* pView
= pViewShell
? pViewShell
->GetDrawView() : nullptr;
2501 pView
->UnmarkAllObj();
2502 for( const CustomAnimationEffectPtr
& pEffect
: maListSelection
)
2504 Reference
< XShape
> xShape( pEffect
->getTargetShape() );
2505 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(xShape
);
2507 pView
->MarkObj(pObj
, pView
->GetSdrPageView());
2512 // ICustomAnimationListController
2513 // pEffectInsertBefore may be null if moving to end of list.
2514 void CustomAnimationPane::onDragNDropComplete(std::vector
< CustomAnimationEffectPtr
> pEffectsDragged
, CustomAnimationEffectPtr pEffectInsertBefore
)
2516 if ( !mpMainSequence
)
2521 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2523 // Move all selected effects
2524 for( auto const& pEffectDragged
: pEffectsDragged
)
2526 // Move this dragged effect and any hidden sub-effects
2527 EffectSequence::iterator aIter
= mpMainSequence
->find( pEffectDragged
);
2528 const EffectSequence::iterator
aEnd( mpMainSequence
->getEnd() );
2530 while( aIter
!= aEnd
)
2532 CustomAnimationEffectPtr pEffect
= *aIter
++;
2534 // Update model with new location (function triggers a rebuild)
2535 // target may be null, which will insert at the end.
2536 mpMainSequence
->moveToBeforeEffect( pEffect
, pEffectInsertBefore
);
2537 // Done moving effect and its hidden sub-effects when *next* effect is visible.
2538 if (aIter
!= aEnd
&& mxCustomAnimationList
->isVisible(*aIter
))
2544 mrBase
.GetDocShell()->SetModified();
2547 void CustomAnimationPane::updatePathFromMotionPathTag( const rtl::Reference
< MotionPathTag
>& xTag
)
2549 MainSequenceRebuildGuard
aGuard( mpMainSequence
);
2553 SdrPathObj
* pPathObj
= xTag
->getPathObj();
2554 CustomAnimationEffectPtr pEffect
= xTag
->getEffect();
2555 if( (pPathObj
!= nullptr) && pEffect
)
2557 SfxUndoManager
* pManager
= mrBase
.GetDocShell()->GetUndoManager();
2560 SdPage
* pPage
= SdPage::getImplementation( mxCurrentPage
);
2562 pManager
->AddUndoAction( std::make_unique
<UndoAnimationPath
>( mrBase
.GetDocShell()->GetDoc(), pPage
, pEffect
->getNode() ) );
2565 pEffect
->updatePathFromSdrPathObj( *pPathObj
);
2571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */