bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / dlg / animobjs.cxx
blob49f98e184bf33fd7e47d08e1148756489782d6cf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <time.h>
21 #include <svl/eitem.hxx>
22 #include <svl/intitem.hxx>
23 #include <svx/svdograf.hxx>
24 #include <svx/svdogrp.hxx>
25 #include <sfx2/dispatch.hxx>
26 #include <sfx2/progress.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/weld.hxx>
29 #include <vcl/virdev.hxx>
31 #include <anminfo.hxx>
32 #include <animobjs.hxx>
33 #include <app.hrc>
34 #include <strings.hrc>
35 #include <sdresid.hxx>
36 #include <View.hxx>
37 #include <drawdoc.hxx>
38 #include <sdpage.hxx>
40 #include <ViewShell.hxx>
42 #include <vcl/settings.hxx>
44 #include <EffectMigration.hxx>
46 #include <algorithm>
48 using namespace ::com::sun::star;
50 namespace sd {
52 /**
53 * SdDisplay - Control
55 SdDisplay::SdDisplay(vcl::Window* pWin)
56 : Control(pWin, 0)
57 , aScale(1, 1)
59 SetMapMode(MapMode(MapUnit::MapPixel));
60 const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
61 SetBackground( Wallpaper( rStyles.GetFieldColor() ) );
64 SdDisplay::~SdDisplay()
68 void SdDisplay::SetBitmapEx( BitmapEx const * pBmpEx )
70 if( pBmpEx )
72 aBitmapEx = *pBmpEx;
74 else
76 const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
77 const Color aFillColor = rStyles.GetFieldColor();
78 aBitmapEx.Erase(aFillColor);
82 void SdDisplay::Paint( vcl::RenderContext& /*rRenderContext*/, const ::tools::Rectangle& )
84 Point aPt;
85 Size aSize = GetOutputSize();
86 Size aBmpSize = aBitmapEx.GetBitmap().GetSizePixel();
87 aBmpSize.setWidth( static_cast<long>( static_cast<double>(aBmpSize.Width()) * static_cast<double>(aScale) ) );
88 aBmpSize.setHeight( static_cast<long>( static_cast<double>(aBmpSize.Height()) * static_cast<double>(aScale) ) );
90 if( aBmpSize.Width() < aSize.Width() )
91 aPt.setX( ( aSize.Width() - aBmpSize.Width() ) / 2 );
92 if( aBmpSize.Height() < aSize.Height() )
93 aPt.setY( ( aSize.Height() - aBmpSize.Height() ) / 2 );
95 aBitmapEx.Draw( this, aPt, aBmpSize );
98 void SdDisplay::SetScale( const Fraction& rFrac )
100 aScale = rFrac;
103 Size SdDisplay::GetOptimalSize() const
105 return LogicToPixel(Size(147, 87), MapMode(MapUnit::MapAppFont));
108 void SdDisplay::DataChanged( const DataChangedEvent& rDCEvt )
110 Control::DataChanged( rDCEvt );
112 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
114 const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
115 SetBackground( Wallpaper( rStyles.GetFieldColor() ) );
116 SetDrawMode( GetSettings().GetStyleSettings().GetHighContrastMode()
117 ? sd::OUTPUT_DRAWMODE_CONTRAST
118 : sd::OUTPUT_DRAWMODE_COLOR );
122 const size_t AnimationWindow::EMPTY_FRAMELIST = std::numeric_limits<size_t>::max();
125 * AnimationWindow - FloatingWindow
127 AnimationWindow::AnimationWindow(SfxBindings* pInBindings, SfxChildWindow *pCW, vcl::Window* pParent)
128 : SfxDockingWindow(pInBindings, pCW, pParent,
129 "DockingAnimation", "modules/simpress/ui/dockinganimation.ui")
130 , m_nCurrentFrame(EMPTY_FRAMELIST)
131 , bMovie(false)
132 , bAllObjects(false)
134 get(m_pBtnFirst, "first");
135 get(m_pBtnReverse, "prev");
136 get(m_pBtnStop, "stop");
137 get(m_pBtnPlay, "next");
138 get(m_pBtnLast, "last");
139 get(m_pNumFldBitmap, "numbitmap");
140 get(m_pTimeField, "duration");
141 m_pTimeField->SetDuration(true);
142 m_pTimeField->EnforceValidValue(true);
143 m_pTimeField->SetMax(tools::Time(0, 0, 59, 99*tools::Time::nanoPerCenti));
144 get(m_pLbLoopCount, "loopcount");
145 get(m_pBtnGetOneObject, "getone");
146 get(m_pBtnGetAllObjects, "getall");
147 get(m_pBtnRemoveBitmap, "delone");
148 get(m_pBtnRemoveAll, "delall");
149 get(m_pFiCount, "count");
150 get(m_pRbtGroup, "group");
151 get(m_pRbtBitmap, "bitmap");
152 get(m_pFtAdjustment, "alignmentft");
153 get(m_pLbAdjustment, "alignment");
154 get(m_pBtnCreateGroup, "create");
156 m_pCtlDisplay = VclPtr<SdDisplay>::Create(get<Window>("box"));
157 m_pCtlDisplay->set_hexpand(true);
158 m_pCtlDisplay->set_vexpand(true);
159 m_pCtlDisplay->Show();
161 // create new document with page
162 pMyDoc.reset( new SdDrawDocument(DocumentType::Impress, nullptr) );
163 SdPage* pPage = pMyDoc->AllocSdPage(false);
164 pMyDoc->InsertPage(pPage);
166 pControllerItem.reset( new AnimationControllerItem( SID_ANIMATOR_STATE, this, pInBindings ) );
168 // as long as not in the resource
169 m_pTimeField->SetFormat( TimeFieldFormat::F_SEC_CS );
171 m_pBtnFirst->SetClickHdl( LINK( this, AnimationWindow, ClickFirstHdl ) );
172 m_pBtnReverse->SetClickHdl( LINK( this, AnimationWindow, ClickPlayHdl ) );
173 m_pBtnStop->SetClickHdl( LINK( this, AnimationWindow, ClickStopHdl ) );
174 m_pBtnPlay->SetClickHdl( LINK( this, AnimationWindow, ClickPlayHdl ) );
175 m_pBtnLast->SetClickHdl( LINK( this, AnimationWindow, ClickLastHdl ) );
177 m_pBtnGetOneObject->SetClickHdl( LINK( this, AnimationWindow, ClickGetObjectHdl ) );
178 m_pBtnGetAllObjects->SetClickHdl( LINK( this, AnimationWindow, ClickGetObjectHdl ) );
179 m_pBtnRemoveBitmap->SetClickHdl( LINK( this, AnimationWindow, ClickRemoveBitmapHdl ) );
180 m_pBtnRemoveAll->SetClickHdl( LINK( this, AnimationWindow, ClickRemoveBitmapHdl ) );
182 m_pRbtGroup->SetClickHdl( LINK( this, AnimationWindow, ClickRbtHdl ) );
183 m_pRbtBitmap->SetClickHdl( LINK( this, AnimationWindow, ClickRbtHdl ) );
184 m_pBtnCreateGroup->SetClickHdl( LINK( this, AnimationWindow, ClickCreateGroupHdl ) );
185 m_pNumFldBitmap->SetModifyHdl( LINK( this, AnimationWindow, ModifyBitmapHdl ) );
186 m_pTimeField->SetModifyHdl( LINK( this, AnimationWindow, ModifyTimeHdl ) );
188 // disable 3D border
189 m_pCtlDisplay->SetBorderStyle(WindowBorderStyle::MONO);
191 SetMinOutputSizePixel(GetOptimalSize());
193 ResetAttrs();
195 // the animator is empty; no animation group can be created
196 m_pBtnCreateGroup->Disable();
199 AnimationWindow::~AnimationWindow()
201 disposeOnce();
204 void AnimationWindow::dispose()
206 pControllerItem.reset();
208 m_FrameList.clear();
209 m_nCurrentFrame = EMPTY_FRAMELIST;
211 // delete the clones
212 pMyDoc.reset();
214 m_pCtlDisplay.disposeAndClear();
215 m_pBtnFirst.clear();
216 m_pBtnReverse.clear();
217 m_pBtnStop.clear();
218 m_pBtnPlay.clear();
219 m_pBtnLast.clear();
220 m_pNumFldBitmap.clear();
221 m_pTimeField.clear();
222 m_pLbLoopCount.clear();
223 m_pBtnGetOneObject.clear();
224 m_pBtnGetAllObjects.clear();
225 m_pBtnRemoveBitmap.clear();
226 m_pBtnRemoveAll.clear();
227 m_pFiCount.clear();
228 m_pRbtGroup.clear();
229 m_pRbtBitmap.clear();
230 m_pFtAdjustment.clear();
231 m_pLbAdjustment.clear();
232 m_pBtnCreateGroup.clear();
233 SfxDockingWindow::dispose();
236 IMPL_LINK_NOARG(AnimationWindow, ClickFirstHdl, Button*, void)
238 m_nCurrentFrame = (m_FrameList.empty()) ? EMPTY_FRAMELIST : 0;
239 UpdateControl();
242 IMPL_LINK_NOARG(AnimationWindow, ClickStopHdl, Button*, void)
244 bMovie = false;
247 IMPL_LINK( AnimationWindow, ClickPlayHdl, Button *, p, void )
249 ScopeLockGuard aGuard( maPlayLock );
251 bMovie = true;
252 bool bDisableCtrls = false;
253 size_t const nCount = m_FrameList.size();
254 bool bReverse = p == m_pBtnReverse;
256 // it is difficult to find it later on
257 bool bRbtGroupEnabled = m_pRbtGroup->IsEnabled();
258 bool bBtnGetAllObjectsEnabled = m_pBtnGetAllObjects->IsEnabled();
259 bool bBtnGetOneObjectEnabled = m_pBtnGetOneObject->IsEnabled();
261 // calculate overall time
262 tools::Time aTime( 0 );
263 long nFullTime;
264 if( m_pRbtBitmap->IsChecked() )
266 for (size_t i = 0; i < nCount; ++i)
268 aTime += m_FrameList[i].second;
270 nFullTime = aTime.GetMSFromTime();
272 else
274 nFullTime = nCount * 100;
275 aTime.MakeTimeFromMS( nFullTime );
278 // StatusBarManager from 1 second
279 std::unique_ptr<SfxProgress> pProgress;
280 if( nFullTime >= 1000 )
282 bDisableCtrls = true;
283 m_pBtnStop->Enable();
284 m_pBtnStop->Update();
285 OUString const aStr("Animator:"); // here we should think about something smart
286 pProgress.reset(new SfxProgress( nullptr, aStr, nFullTime ));
289 sal_uLong nTmpTime = 0;
290 size_t i = 0;
291 bool bCount = i < nCount;
292 if( bReverse )
294 i = nCount - 1;
296 while( bCount && bMovie )
298 // make list and view consistent
299 assert(i < m_FrameList.size());
300 m_nCurrentFrame = i;
302 UpdateControl(bDisableCtrls);
304 if( m_pRbtBitmap->IsChecked() )
306 tools::Time const & rTime = m_FrameList[i].second;
308 m_pTimeField->SetTime( rTime );
309 sal_uLong nTime = rTime.GetMSFromTime();
311 WaitInEffect( nTime, nTmpTime, pProgress.get() );
312 nTmpTime += nTime;
314 else
316 WaitInEffect( 100, nTmpTime, pProgress.get() );
317 nTmpTime += 100;
319 if( bReverse )
321 if (i == 0)
323 // Terminate loop.
324 bCount = false;
326 else
328 --i;
331 else
333 i++;
334 if (i >= nCount)
336 // Terminate loop.
337 bCount = false;
338 // Move i back into valid range.
339 i = nCount - 1;
344 // to re-enable the controls
345 bMovie = false;
346 if (nCount > 0)
348 assert(i == m_nCurrentFrame);
349 UpdateControl();
352 if( pProgress )
354 pProgress.reset();
355 m_pBtnStop->Disable();
358 m_pRbtGroup->Enable( bRbtGroupEnabled );
359 m_pBtnGetAllObjects->Enable( bBtnGetAllObjectsEnabled );
360 m_pBtnGetOneObject->Enable( bBtnGetOneObjectEnabled );
363 IMPL_LINK_NOARG(AnimationWindow, ClickLastHdl, Button*, void)
365 m_nCurrentFrame =
366 (m_FrameList.empty()) ? EMPTY_FRAMELIST : m_FrameList.size() - 1 ;
367 UpdateControl();
370 IMPL_LINK( AnimationWindow, ClickRbtHdl, Button*, p, void )
372 if (m_FrameList.empty() || p == m_pRbtGroup || m_pRbtGroup->IsChecked())
374 m_pTimeField->SetText( OUString() );
375 m_pTimeField->Enable( false );
376 m_pLbLoopCount->Enable( false );
378 else if( p == m_pRbtBitmap || m_pRbtBitmap->IsChecked() )
380 sal_uLong n = static_cast<sal_uLong>(m_pNumFldBitmap->GetValue());
381 if( n > 0 )
383 tools::Time const & rTime = m_FrameList[n - 1].second;
384 m_pTimeField->SetTime( rTime );
386 m_pTimeField->Enable();
387 m_pLbLoopCount->Enable();
391 IMPL_LINK( AnimationWindow, ClickGetObjectHdl, Button*, pBtn, void )
393 bAllObjects = pBtn == m_pBtnGetAllObjects;
395 // Code now in AddObj()
396 SfxBoolItem aItem( SID_ANIMATOR_ADD, true );
398 GetBindings().GetDispatcher()->ExecuteList(
399 SID_ANIMATOR_ADD, SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
402 IMPL_LINK( AnimationWindow, ClickRemoveBitmapHdl, Button*, pBtn, void )
404 SdPage* pPage = pMyDoc->GetSdPage(0, PageKind::Standard);
405 SdrObject* pObject;
407 // tdf#95298 check m_nCurrentFrame for EMPTY_FRAMELIST to avoid out-of-bound array access
408 if (pBtn == m_pBtnRemoveBitmap && EMPTY_FRAMELIST != m_nCurrentFrame)
410 m_FrameList.erase(m_FrameList.begin() + m_nCurrentFrame);
412 pObject = pPage->GetObj(m_nCurrentFrame);
413 // Through acquisition of the AnimatedGIFs, objects does not need to
414 // exist.
415 if( pObject )
417 pObject = pPage->RemoveObject(m_nCurrentFrame);
418 DBG_ASSERT(pObject, "Clone not found during deletion");
419 SdrObject::Free( pObject );
420 pPage->RecalcObjOrdNums();
423 if (m_nCurrentFrame >= m_FrameList.size())
425 // tdf#95298 last frame was deleted, try to use the one before it or go on empty state
426 m_nCurrentFrame = m_FrameList.empty() ? EMPTY_FRAMELIST : m_FrameList.size() - 1;
429 else // delete everything
431 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(),
432 VclMessageType::Warning, VclButtonsType::YesNo,
433 SdResId(STR_ASK_DELETE_ALL_PICTURES)));
434 short nReturn = xWarn->run();
436 if( nReturn == RET_YES )
438 // clear frame list
439 for (size_t i = m_FrameList.size(); i > 0; )
441 --i;
442 pObject = pPage->GetObj( i );
443 if( pObject )
445 pObject = pPage->RemoveObject( i );
446 DBG_ASSERT(pObject, "Clone not found during deletion");
447 SdrObject::Free( pObject );
448 //pPage->RecalcObjOrdNums();
451 m_FrameList.clear();
452 m_nCurrentFrame = EMPTY_FRAMELIST;
456 // can we create a animation group
457 if (m_FrameList.empty())
459 m_pBtnCreateGroup->Disable();
460 // if previous disabled by acquisition of AnimatedGIFs:
461 //m_pRbtBitmap->Enable();
462 m_pRbtGroup->Enable();
465 // calculate and set zoom for DisplayWin
466 Fraction aFrac(GetScale());
467 m_pCtlDisplay->SetScale(aFrac);
469 UpdateControl();
472 IMPL_LINK_NOARG(AnimationWindow, ClickCreateGroupHdl, Button*, void)
474 // Code now in CreatePresObj()
475 SfxBoolItem aItem( SID_ANIMATOR_CREATE, true );
477 GetBindings().GetDispatcher()->ExecuteList(SID_ANIMATOR_CREATE,
478 SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
481 IMPL_LINK_NOARG(AnimationWindow, ModifyBitmapHdl, Edit&, void)
483 sal_uLong nBmp = static_cast<sal_uLong>(m_pNumFldBitmap->GetValue());
485 if (nBmp > m_FrameList.size())
487 nBmp = m_FrameList.size();
490 m_nCurrentFrame = nBmp - 1;
492 UpdateControl();
495 IMPL_LINK_NOARG(AnimationWindow, ModifyTimeHdl, Edit&, void)
497 sal_uLong nPos = static_cast<sal_uLong>(m_pNumFldBitmap->GetValue() - 1);
499 tools::Time & rTime = m_FrameList[nPos].second;
501 rTime = m_pTimeField->GetTime();
504 void AnimationWindow::UpdateControl(bool const bDisableCtrls)
506 // tdf#95298 check m_nCurrentFrame for EMPTY_FRAMELIST to avoid out-of-bound array access
507 if (!m_FrameList.empty() && EMPTY_FRAMELIST != m_nCurrentFrame)
509 BitmapEx & rBmp(m_FrameList[m_nCurrentFrame].first);
511 SdPage* pPage = pMyDoc->GetSdPage(0, PageKind::Standard);
512 SdrObject *const pObject = pPage->GetObj(m_nCurrentFrame);
513 if( pObject )
515 ScopedVclPtrInstance< VirtualDevice > pVD;
516 ::tools::Rectangle aObjRect( pObject->GetCurrentBoundRect() );
517 Size aObjSize( aObjRect.GetSize() );
518 Point aOrigin( Point( -aObjRect.Left(), -aObjRect.Top() ) );
519 MapMode aMap( pVD->GetMapMode() );
520 aMap.SetMapUnit( MapUnit::Map100thMM );
521 aMap.SetOrigin( aOrigin );
522 pVD->SetMapMode( aMap );
523 pVD->SetOutputSize( aObjSize );
524 const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
525 pVD->SetBackground( Wallpaper( rStyles.GetFieldColor() ) );
526 pVD->SetDrawMode( rStyles.GetHighContrastMode()
527 ? sd::OUTPUT_DRAWMODE_CONTRAST
528 : sd::OUTPUT_DRAWMODE_COLOR );
529 pVD->Erase();
530 pObject->SingleObjectPainter( *pVD );
531 rBmp = pVD->GetBitmapEx( aObjRect.TopLeft(), aObjSize );
534 m_pCtlDisplay->SetBitmapEx(&rBmp);
536 else
538 m_pCtlDisplay->SetBitmapEx(nullptr);
540 m_pCtlDisplay->Invalidate();
541 m_pCtlDisplay->Update();
543 m_pFiCount->SetText(OUString::number(
544 m_FrameList.size()));
546 if (!m_FrameList.empty() && !bMovie)
548 size_t nIndex = m_nCurrentFrame + 1;
549 m_pNumFldBitmap->SetValue(nIndex);
551 // if there is at least 1 object in the list
552 m_pBtnFirst->Enable();
553 m_pBtnReverse->Enable();
554 m_pBtnPlay->Enable();
555 m_pBtnLast->Enable();
556 m_pNumFldBitmap->Enable();
557 m_pTimeField->Enable();
558 m_pLbLoopCount->Enable();
559 m_pBtnRemoveBitmap->Enable();
560 m_pBtnRemoveAll->Enable();
562 else
564 // if no object is in the list
565 m_pBtnFirst->Enable( false );
566 m_pBtnReverse->Enable( false );
567 m_pBtnPlay->Enable( false );
568 m_pBtnLast->Enable( false );
569 m_pNumFldBitmap->Enable( false );
570 m_pTimeField->Enable( false );
571 m_pLbLoopCount->Enable( false );
572 m_pBtnRemoveBitmap->Enable( false );
573 m_pBtnRemoveAll->Enable( false );
576 if( bMovie && bDisableCtrls )
578 m_pBtnGetOneObject->Enable( false );
579 m_pBtnGetAllObjects->Enable( false );
580 m_pRbtGroup->Enable( false );
581 m_pRbtBitmap->Enable( false );
582 m_pBtnCreateGroup->Enable( false );
583 m_pFtAdjustment->Enable( false );
584 m_pLbAdjustment->Enable( false );
586 else
588 // enable 'group object' only if it is not a Animated GIF
589 if (m_FrameList.empty())
591 m_pRbtGroup->Enable();
594 m_pRbtBitmap->Enable();
595 m_pBtnCreateGroup->Enable(!m_FrameList.empty());
596 m_pFtAdjustment->Enable();
597 m_pLbAdjustment->Enable();
600 ClickRbtHdl( nullptr );
603 void AnimationWindow::ResetAttrs()
605 m_pRbtGroup->Check();
606 m_pLbAdjustment->SelectEntryPos( BA_CENTER );
607 // LoopCount
608 m_pLbLoopCount->SelectEntryPos( m_pLbLoopCount->GetEntryCount() - 1);
610 UpdateControl();
613 void AnimationWindow::WaitInEffect( sal_uLong nMilliSeconds, sal_uLong nTime,
614 SfxProgress* pProgress ) const
616 sal_uInt64 aEnd = tools::Time::GetSystemTicks() + nMilliSeconds;
617 sal_uInt64 aCurrent = tools::Time::GetSystemTicks();
618 while (aCurrent < aEnd)
620 aCurrent = tools::Time::GetSystemTicks();
622 if( pProgress )
623 pProgress->SetState( nTime + nMilliSeconds + aCurrent - aEnd );
625 Application::Reschedule();
627 if( !bMovie )
628 return;
632 Fraction AnimationWindow::GetScale()
634 Fraction aFrac;
635 size_t const nCount = m_FrameList.size();
636 if (nCount > 0)
638 Size aBmpSize(0, 0);
639 for (size_t i = 0; i < nCount; i++)
641 BitmapEx const & rBitmap = m_FrameList[i].first;
642 Size aTempSize( rBitmap.GetBitmap().GetSizePixel() );
643 aBmpSize.setWidth( std::max( aBmpSize.Width(), aTempSize.Width() ) );
644 aBmpSize.setHeight( std::max( aBmpSize.Height(), aTempSize.Height() ) );
647 aBmpSize.AdjustWidth(10 );
648 aBmpSize.AdjustHeight(10 );
650 Size aDisplaySize(m_pCtlDisplay->GetOutputSize());
652 aFrac = Fraction( std::min( static_cast<double>(aDisplaySize.Width()) / static_cast<double>(aBmpSize.Width()),
653 static_cast<double>(aDisplaySize.Height()) / static_cast<double>(aBmpSize.Height()) ) );
655 return aFrac;
658 void AnimationWindow::Resize()
660 SfxDockingWindow::Resize();
661 Fraction aFrac(GetScale());
662 m_pCtlDisplay->SetScale(aFrac);
665 bool AnimationWindow::Close()
667 if( maPlayLock.isLocked() )
669 return false;
671 else
673 SfxBoolItem aItem( SID_ANIMATION_OBJECTS, false );
675 GetBindings().GetDispatcher()->ExecuteList(
676 SID_ANIMATION_OBJECTS, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
677 { &aItem });
679 SfxDockingWindow::Close();
681 return true;
685 void AnimationWindow::AddObj (::sd::View& rView )
687 // finish text entry mode to ensure that bitmap is identical with object
688 if( rView.IsTextEdit() )
689 rView.SdrEndTextEdit();
691 // clone object(s) and insert the clone(s) into the list
692 const SdrMarkList& rMarkList = rView.GetMarkedObjectList();
693 const size_t nMarkCount = rMarkList.GetMarkCount();
694 SdPage* pPage = pMyDoc->GetSdPage(0, PageKind::Standard);
695 const size_t nCloneCount = pPage->GetObjCount();
697 if (nMarkCount <= 0)
698 return;
700 // If it is ONE animation object or one group object, which was
701 // 'individually taken', we insert the objects separately
702 bool bAnimObj = false;
703 if( nMarkCount == 1 )
705 SdrMark* pMark = rMarkList.GetMark(0);
706 SdrObject* pObject = pMark->GetMarkedSdrObj();
707 SdAnimationInfo* pAnimInfo = SdDrawDocument::GetAnimationInfo( pObject );
708 SdrInventor nInv = pObject->GetObjInventor();
709 sal_uInt16 nId = pObject->GetObjIdentifier();
711 // Animated Bitmap (GIF)
712 if( nInv == SdrInventor::Default && nId == OBJ_GRAF && static_cast<SdrGrafObj*>( pObject )->IsAnimated() )
714 const SdrGrafObj* pGrafObj = static_cast<SdrGrafObj*>(pObject);
715 Graphic aGraphic( pGrafObj->GetTransformedGraphic() );
716 sal_uInt16 nCount = 0;
718 if( aGraphic.IsAnimated() )
719 nCount = aGraphic.GetAnimation().Count();
721 if( nCount > 0 )
723 const Animation aAnimation( aGraphic.GetAnimation() );
725 for( sal_uInt16 i = 0; i < nCount; i++ )
727 const AnimationBitmap& rAnimationBitmap = aAnimation.Get( i );
729 // LoopCount
730 if( i == 0 )
732 sal_uInt32 nLoopCount = aAnimation.GetLoopCount();
734 if( !nLoopCount ) // endless
735 m_pLbLoopCount->SelectEntryPos( m_pLbLoopCount->GetEntryCount() - 1);
736 else
737 m_pLbLoopCount->SelectEntry(OUString::number( nLoopCount ) );
740 long nTime = rAnimationBitmap.mnWait;
741 ::tools::Time aTime( 0, 0, nTime / 100, nTime % 100 );
742 size_t nIndex = m_nCurrentFrame + 1;
743 m_FrameList.insert(
744 m_FrameList.begin() + nIndex,
745 ::std::make_pair(rAnimationBitmap.maBitmapEx, aTime));
747 // increment => next one inserted after this one
748 ++m_nCurrentFrame;
750 // if a animated GIF is taken, only such one can be created
751 m_pRbtBitmap->Check();
752 m_pRbtGroup->Enable( false );
753 bAnimObj = true;
756 else if( bAllObjects || ( pAnimInfo && pAnimInfo->mbIsMovie ) )
758 // several objects
759 SdrObjList* pObjList = static_cast<SdrObjGroup*>(pObject)->GetSubList();
761 for( size_t nObject = 0; nObject < pObjList->GetObjCount(); ++nObject )
763 SdrObject* pSnapShot(pObjList->GetObj(nObject));
764 BitmapEx aBitmapEx(SdrExchangeView::GetObjGraphic(*pSnapShot).GetBitmapEx());
765 size_t nIndex = m_nCurrentFrame + 1;
766 m_FrameList.insert(
767 m_FrameList.begin() + nIndex,
768 ::std::make_pair(aBitmapEx, m_pTimeField->GetTime()));
770 // increment => next one inserted after this one
771 ++m_nCurrentFrame;
773 // Clone
774 pPage->InsertObject(
775 pSnapShot->CloneSdrObject(pPage->getSdrModelFromSdrPage()),
776 m_nCurrentFrame);
778 bAnimObj = true;
781 // also one single animated object
782 if( !bAnimObj && !( bAllObjects && nMarkCount > 1 ) )
784 BitmapEx aBitmapEx(rView.GetAllMarkedGraphic().GetBitmapEx());
786 ::tools::Time aTime( m_pTimeField->GetTime() );
788 size_t nIndex = m_nCurrentFrame + 1;
789 m_FrameList.insert(
790 m_FrameList.begin() + nIndex,
791 ::std::make_pair(aBitmapEx, aTime));
794 // one single object
795 if( nMarkCount == 1 && !bAnimObj )
797 SdrMark* pMark = rMarkList.GetMark(0);
798 SdrObject* pObject = pMark->GetMarkedSdrObj();
799 SdrObject* pClone(pObject->CloneSdrObject(pPage->getSdrModelFromSdrPage()));
800 size_t nIndex = m_nCurrentFrame + 1;
801 pPage->InsertObject(pClone, nIndex);
803 // several objects: group the clones
804 else if (nMarkCount > 1)
806 // take objects separately
807 if( bAllObjects )
809 for( size_t nObject= 0; nObject < nMarkCount; ++nObject )
811 // Clone
812 SdrObject* pObject(rMarkList.GetMark(nObject)->GetMarkedSdrObj());
813 BitmapEx aBitmapEx(SdrExchangeView::GetObjGraphic(*pObject).GetBitmapEx());
814 size_t nIndex = m_nCurrentFrame + 1;
815 m_FrameList.insert(
816 m_FrameList.begin() + nIndex,
817 ::std::make_pair(aBitmapEx, m_pTimeField->GetTime()));
819 // increment => next one inserted after this one
820 ++m_nCurrentFrame;
822 pPage->InsertObject(
823 pObject->CloneSdrObject(pPage->getSdrModelFromSdrPage()),
824 m_nCurrentFrame);
826 bAnimObj = true; // that we don't change again
828 else
830 SdrObjGroup* pCloneGroup = new SdrObjGroup(rView.getSdrModelFromSdrView());
831 SdrObjList* pObjList = pCloneGroup->GetSubList();
833 for (size_t nObject= 0; nObject < nMarkCount; ++nObject)
835 pObjList->InsertObject(
836 rMarkList.GetMark(nObject)->GetMarkedSdrObj()->CloneSdrObject(
837 pPage->getSdrModelFromSdrPage()));
840 size_t nIndex = m_nCurrentFrame + 1;
841 pPage->InsertObject(pCloneGroup, nIndex);
845 if( !bAnimObj )
847 ++m_nCurrentFrame;
850 // if there was nothing in the animator before but now is something
851 // there, we can create a animation group
852 if (nCloneCount == 0 && !m_FrameList.empty())
854 m_pBtnCreateGroup->Enable();
857 // calculate and set zoom for DisplayWin
858 Fraction aFrac( GetScale() );
859 m_pCtlDisplay->SetScale(aFrac);
861 UpdateControl();
864 void AnimationWindow::CreateAnimObj (::sd::View& rView )
866 vcl::Window* pOutWin = static_cast< vcl::Window*>(rView.GetFirstOutputDevice()); // GetWin( 0 );
867 DBG_ASSERT( pOutWin, "Window does not exist!" );
869 // find window center
870 const MapMode aMap100( MapUnit::Map100thMM );
871 Size aMaxSizeLog;
872 Size aMaxSizePix;
873 Size aTemp( pOutWin->GetOutputSizePixel() );
874 const Point aWindowCenter( pOutWin->PixelToLogic( Point( aTemp.Width() >> 1, aTemp.Height() >> 1 ) ) );
875 const OutputDevice* pDefDev = Application::GetDefaultDevice();
876 const size_t nCount = m_FrameList.size();
877 BitmapAdjustment eBA = static_cast<BitmapAdjustment>(m_pLbAdjustment->GetSelectedEntryPos());
879 // find biggest bitmap
880 for (size_t i = 0; i < nCount; ++i)
882 const BitmapEx& rBmpEx = m_FrameList[i].first;
883 const Graphic aGraphic( rBmpEx );
884 Size aTmpSizeLog;
885 const Size aTmpSizePix( rBmpEx.GetSizePixel() );
887 if ( aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
888 aTmpSizeLog = pDefDev->PixelToLogic( aGraphic.GetPrefSize(), aMap100 );
889 else
890 aTmpSizeLog = OutputDevice::LogicToLogic( aGraphic.GetPrefSize(), aGraphic.GetPrefMapMode(), aMap100 );
892 aMaxSizeLog.setWidth( std::max( aMaxSizeLog.Width(), aTmpSizeLog.Width() ) );
893 aMaxSizeLog.setHeight( std::max( aMaxSizeLog.Height(), aTmpSizeLog.Height() ) );
895 aMaxSizePix.setWidth( std::max( aMaxSizePix.Width(), aTmpSizePix.Width() ) );
896 aMaxSizePix.setHeight( std::max( aMaxSizePix.Height(), aTmpSizePix.Height() ) );
899 SdrPageView* pPV = rView.GetSdrPageView();
901 if( m_pRbtBitmap->IsChecked() )
903 // create bitmap group (Animated GIF)
904 Animation aAnimation;
905 Point aPt;
907 for (size_t i = 0; i < nCount; ++i)
909 tools::Time const & rTime = m_FrameList[i].second;
910 long nTime = rTime.GetNanoSec();
911 nTime += rTime.GetSec() * 100;
913 BitmapEx const & rBitmapEx = m_FrameList[i].first;
915 // calculate offset for the specified direction
916 const Size aBitmapSize( rBitmapEx.GetSizePixel() );
918 switch( eBA )
920 case BA_LEFT_UP:
921 break;
923 case BA_LEFT:
924 aPt.setY( (aMaxSizePix.Height() - aBitmapSize.Height()) >> 1 );
925 break;
927 case BA_LEFT_DOWN:
928 aPt.setY( aMaxSizePix.Height() - aBitmapSize.Height() );
929 break;
931 case BA_UP:
932 aPt.setX( (aMaxSizePix.Width() - aBitmapSize.Width()) >> 1 );
933 break;
935 case BA_CENTER:
936 aPt.setX( (aMaxSizePix.Width() - aBitmapSize.Width()) >> 1 );
937 aPt.setY( (aMaxSizePix.Height() - aBitmapSize.Height()) >> 1 );
938 break;
940 case BA_DOWN:
941 aPt.setX( (aMaxSizePix.Width() - aBitmapSize.Width()) >> 1 );
942 aPt.setY( aMaxSizePix.Height() - aBitmapSize.Height() );
943 break;
945 case BA_RIGHT_UP:
946 aPt.setX( aMaxSizePix.Width() - aBitmapSize.Width() );
947 break;
949 case BA_RIGHT:
950 aPt.setX( aMaxSizePix.Width() - aBitmapSize.Width() );
951 aPt.setY( (aMaxSizePix.Height() - aBitmapSize.Height()) >> 1 );
952 break;
954 case BA_RIGHT_DOWN:
955 aPt.setX( aMaxSizePix.Width() - aBitmapSize.Width() );
956 aPt.setY( aMaxSizePix.Height() - aBitmapSize.Height() );
957 break;
961 // find LoopCount (number of passes)
962 AnimationBitmap aAnimationBitmap;
963 sal_uInt32 nLoopCount = 0;
964 sal_Int32 nPos = m_pLbLoopCount->GetSelectedEntryPos();
966 if( nPos != LISTBOX_ENTRY_NOTFOUND && nPos != m_pLbLoopCount->GetEntryCount() - 1 ) // endless
967 nLoopCount = m_pLbLoopCount->GetSelectedEntry().toUInt32();
969 aAnimationBitmap.maBitmapEx = rBitmapEx;
970 aAnimationBitmap.maPositionPixel = aPt;
971 aAnimationBitmap.maSizePixel = aBitmapSize;
972 aAnimationBitmap.mnWait = nTime;
973 aAnimationBitmap.meDisposal = Disposal::Back;
974 aAnimationBitmap.mbUserInput = false;
976 aAnimation.Insert( aAnimationBitmap );
977 aAnimation.SetDisplaySizePixel( aMaxSizePix );
978 aAnimation.SetLoopCount( nLoopCount );
981 SdrGrafObj* pGrafObj = new SdrGrafObj(
982 rView.getSdrModelFromSdrView(),
983 Graphic(aAnimation));
984 const Point aOrg( aWindowCenter.X() - ( aMaxSizeLog.Width() >> 1 ), aWindowCenter.Y() - ( aMaxSizeLog.Height() >> 1 ) );
986 pGrafObj->SetLogicRect( ::tools::Rectangle( aOrg, aMaxSizeLog ) );
987 rView.InsertObjectAtView( pGrafObj, *pPV, SdrInsertFlags::SETDEFLAYER);
989 else
991 // calculate offset for the specified direction
992 Size aOffset;
993 SdrObject * pClone = nullptr;
994 SdPage* pPage = pMyDoc->GetSdPage(0, PageKind::Standard);
996 for (size_t i = 0; i < nCount; ++i)
998 pClone = pPage->GetObj(i);
999 ::tools::Rectangle aRect( pClone->GetSnapRect() );
1001 switch( eBA )
1003 case BA_LEFT_UP:
1004 break;
1006 case BA_LEFT:
1007 aOffset.setHeight( (aMaxSizeLog.Height() - aRect.GetHeight()) / 2 );
1008 break;
1010 case BA_LEFT_DOWN:
1011 aOffset.setHeight( aMaxSizeLog.Height() - aRect.GetHeight() );
1012 break;
1014 case BA_UP:
1015 aOffset.setWidth( (aMaxSizeLog.Width() - aRect.GetWidth()) / 2 );
1016 break;
1018 case BA_CENTER:
1019 aOffset.setWidth( (aMaxSizeLog.Width() - aRect.GetWidth()) / 2 );
1020 aOffset.setHeight( (aMaxSizeLog.Height() - aRect.GetHeight()) / 2 );
1021 break;
1023 case BA_DOWN:
1024 aOffset.setWidth( (aMaxSizeLog.Width() - aRect.GetWidth()) / 2 );
1025 aOffset.setHeight( aMaxSizeLog.Height() - aRect.GetHeight() );
1026 break;
1028 case BA_RIGHT_UP:
1029 aOffset.setWidth( aMaxSizeLog.Width() - aRect.GetWidth() );
1030 break;
1032 case BA_RIGHT:
1033 aOffset.setWidth( aMaxSizeLog.Width() - aRect.GetWidth() );
1034 aOffset.setHeight( (aMaxSizeLog.Height() - aRect.GetHeight()) / 2 );
1035 break;
1037 case BA_RIGHT_DOWN:
1038 aOffset.setWidth( aMaxSizeLog.Width() - aRect.GetWidth() );
1039 aOffset.setHeight( aMaxSizeLog.Height() - aRect.GetHeight() );
1040 break;
1043 // Unfortunately, SetSnapRect is not implemented for ellipses !!!
1044 Point aMovePt( aWindowCenter + Point( aOffset.Width(), aOffset.Height() ) - aRect.TopLeft() );
1045 Size aMoveSize( aMovePt.X(), aMovePt.Y() );
1046 pClone->NbcMove( aMoveSize );
1049 // #i42894# Caution(!) variable pPage looks right, but it is a page from the local
1050 // document the dialog is using (!), so get the target page from the target view
1051 SdPage* pTargetSdPage = dynamic_cast< SdPage* >(rView.GetSdrPageView() ? rView.GetSdrPageView()->GetPage() : nullptr);
1053 if(pTargetSdPage)
1055 // create animation group
1056 SdrObjGroup* pGroup = new SdrObjGroup(rView.getSdrModelFromSdrView());
1057 SdrObjList* pObjList = pGroup->GetSubList();
1059 for (size_t i = 0; i < nCount; ++i)
1061 // the clone remains in the animation; we insert a clone of the
1062 // clone into the group
1063 pClone = pPage->GetObj(i);
1064 SdrObject* pCloneOfClone(pClone->CloneSdrObject(pPage->getSdrModelFromSdrPage()));
1065 //SdrObject* pCloneOfClone = pPage->GetObj(i)->Clone();
1066 pObjList->InsertObject(pCloneOfClone);
1069 // until now the top left corner of the group is in the window center;
1070 // correct the position by half of the size of the group
1071 aTemp = aMaxSizeLog;
1072 aTemp.setHeight( - aTemp.Height() / 2 );
1073 aTemp.setWidth( - aTemp.Width() / 2 );
1074 pGroup->NbcMove(aTemp);
1076 // #i42894# create needed SMIL stuff and move child objects to page directly (see
1077 // comments at EffectMigration::CreateAnimatedGroup why this has to be done).
1078 EffectMigration::CreateAnimatedGroup(*pGroup, *pTargetSdPage);
1080 // #i42894# if that worked, delete the group again
1081 if(!pGroup->GetSubList()->GetObjCount())
1083 // always use SdrObject::Free(...) for SdrObjects (!)
1084 SdrObject* pTemp(pGroup);
1085 SdrObject::Free(pTemp);
1090 ClickFirstHdl( nullptr );
1093 void AnimationWindow::DataChanged( const DataChangedEvent& rDCEvt )
1095 SfxDockingWindow::DataChanged( rDCEvt );
1097 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1099 UpdateControl();
1104 * ControllerItem for Animator
1106 AnimationControllerItem::AnimationControllerItem(
1107 sal_uInt16 _nId,
1108 AnimationWindow* pAnimWin,
1109 SfxBindings* _pBindings)
1110 : SfxControllerItem( _nId, *_pBindings ),
1111 pAnimationWin( pAnimWin )
1115 void AnimationControllerItem::StateChanged( sal_uInt16 nSId,
1116 SfxItemState eState, const SfxPoolItem* pItem )
1118 if( eState >= SfxItemState::DEFAULT && nSId == SID_ANIMATOR_STATE )
1120 const SfxUInt16Item* pStateItem = dynamic_cast< const SfxUInt16Item*>( pItem );
1121 assert(pStateItem); //SfxUInt16Item expected
1122 if (pStateItem)
1124 sal_uInt16 nState = pStateItem->GetValue();
1125 pAnimationWin->m_pBtnGetOneObject->Enable( nState & 1 );
1126 pAnimationWin->m_pBtnGetAllObjects->Enable( nState & 2 );
1131 } // end of namespace sd
1133 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */