bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / dlg / animobjs.cxx
blob5c66014ffc7c9406619694577e6a4c29c4cb676e
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 <com/sun/star/presentation/AnimationEffect.hpp>
21 #include <com/sun/star/presentation/AnimationSpeed.hpp>
22 #include <svx/xoutbmp.hxx>
23 #include <time.h>
24 #include <svl/eitem.hxx>
25 #include <svx/svdograf.hxx>
26 #include <svx/svdogrp.hxx>
27 #include <sfx2/basedlgs.hxx>
28 #include <sfx2/dispatch.hxx>
29 #include <sfx2/progress.hxx>
30 #include <vcl/msgbox.hxx>
32 #include "anminfo.hxx"
33 #include "animobjs.hxx"
34 #include "app.hrc"
35 #include "strings.hrc"
36 #include "sdresid.hxx"
37 #include "View.hxx"
38 #include "drawdoc.hxx"
39 #include "sdpage.hxx"
40 #include "res_bmp.hrc"
41 #include "ViewShell.hxx"
43 #include <vcl/svapp.hxx>
44 #include <vcl/settings.hxx>
46 #include <EffectMigration.hxx>
48 #include <string>
49 #include <algorithm>
51 using namespace ::com::sun::star;
53 namespace sd {
55 /**
56 * SdDisplay - Control
58 SdDisplay::SdDisplay(vcl::Window* pWin)
59 : Control(pWin, 0)
60 , aScale(1, 1)
62 SetMapMode( MAP_PIXEL );
63 const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
64 SetBackground( Wallpaper( Color( rStyles.GetFieldColor() ) ) );
67 SdDisplay::~SdDisplay()
71 void SdDisplay::SetBitmapEx( BitmapEx* pBmpEx )
73 if( pBmpEx )
75 aBitmapEx = *pBmpEx;
77 else
79 const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
80 const Color aFillColor = rStyles.GetFieldColor();
81 aBitmapEx.Erase(aFillColor);
85 void SdDisplay::Paint( vcl::RenderContext& /*rRenderContext*/, const Rectangle& )
87 Point aPt;
88 Size aSize = GetOutputSize();
89 Size aBmpSize = aBitmapEx.GetBitmap().GetSizePixel();
90 aBmpSize.Width() = (long) ( (double) aBmpSize.Width() * (double) aScale );
91 aBmpSize.Height() = (long) ( (double) aBmpSize.Height() * (double) aScale );
93 if( aBmpSize.Width() < aSize.Width() )
94 aPt.X() = ( aSize.Width() - aBmpSize.Width() ) / 2;
95 if( aBmpSize.Height() < aSize.Height() )
96 aPt.Y() = ( aSize.Height() - aBmpSize.Height() ) / 2;
98 aBitmapEx.Draw( this, aPt, aBmpSize );
101 void SdDisplay::SetScale( const Fraction& rFrac )
103 aScale = rFrac;
106 Size SdDisplay::GetOptimalSize() const
108 return LogicToPixel(Size(147, 87), MAP_APPFONT);
111 void SdDisplay::DataChanged( const DataChangedEvent& rDCEvt )
113 Control::DataChanged( rDCEvt );
115 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
117 const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
118 SetBackground( Wallpaper( Color( rStyles.GetFieldColor() ) ) );
119 SetDrawMode( GetSettings().GetStyleSettings().GetHighContrastMode()
120 ? sd::OUTPUT_DRAWMODE_CONTRAST
121 : sd::OUTPUT_DRAWMODE_COLOR );
125 const size_t AnimationWindow::EMPTY_FRAMELIST = std::numeric_limits<size_t>::max();
128 * AnimationWindow - FloatingWindow
130 AnimationWindow::AnimationWindow(SfxBindings* pInBindings, SfxChildWindow *pCW, vcl::Window* pParent)
131 : SfxDockingWindow(pInBindings, pCW, pParent,
132 "DockingAnimation", "modules/simpress/ui/dockinganimation.ui")
133 , pWin(pParent)
134 , m_nCurrentFrame(EMPTY_FRAMELIST)
135 , bMovie(false)
136 , bAllObjects(false)
137 , pBindings(pInBindings)
139 get(m_pBtnFirst, "first");
140 get(m_pBtnReverse, "prev");
141 get(m_pBtnStop, "stop");
142 get(m_pBtnPlay, "next");
143 get(m_pBtnLast, "last");
144 get(m_pNumFldBitmap, "numbitmap");
145 get(m_pTimeField, "duration");
146 m_pTimeField->SetDuration(true);
147 m_pTimeField->EnforceValidValue(true);
148 m_pTimeField->SetMax(tools::Time(0, 0, 59, 99*tools::Time::nanoPerCenti));
149 get(m_pLbLoopCount, "loopcount");
150 get(m_pBtnGetOneObject, "getone");
151 get(m_pBtnGetAllObjects, "getall");
152 get(m_pBtnRemoveBitmap, "delone");
153 get(m_pBtnRemoveAll, "delall");
154 get(m_pFiCount, "count");
155 get(m_pRbtGroup, "group");
156 get(m_pRbtBitmap, "bitmap");
157 get(m_pFtAdjustment, "alignmentft");
158 get(m_pLbAdjustment, "alignment");
159 get(m_pBtnCreateGroup, "create");
161 m_pCtlDisplay = VclPtr<SdDisplay>::Create(get<Window>("box"));
162 m_pCtlDisplay->set_hexpand(true);
163 m_pCtlDisplay->set_vexpand(true);
164 m_pCtlDisplay->Show();
166 //undo SfxDockingWindow HelpId clear hack
167 reverseUniqueHelpIdHack(*this);
169 // create new document with page
170 pMyDoc = new SdDrawDocument(DOCUMENT_TYPE_IMPRESS, NULL);
171 SdPage* pPage = pMyDoc->AllocSdPage(false);
172 pMyDoc->InsertPage(pPage);
174 pControllerItem = new AnimationControllerItem( SID_ANIMATOR_STATE, this, pBindings );
176 // as long as not in the resource
177 m_pTimeField->SetFormat( TimeFieldFormat::F_SEC_CS );
179 m_pBtnFirst->SetClickHdl( LINK( this, AnimationWindow, ClickFirstHdl ) );
180 m_pBtnReverse->SetClickHdl( LINK( this, AnimationWindow, ClickPlayHdl ) );
181 m_pBtnStop->SetClickHdl( LINK( this, AnimationWindow, ClickStopHdl ) );
182 m_pBtnPlay->SetClickHdl( LINK( this, AnimationWindow, ClickPlayHdl ) );
183 m_pBtnLast->SetClickHdl( LINK( this, AnimationWindow, ClickLastHdl ) );
185 m_pBtnGetOneObject->SetClickHdl( LINK( this, AnimationWindow, ClickGetObjectHdl ) );
186 m_pBtnGetAllObjects->SetClickHdl( LINK( this, AnimationWindow, ClickGetObjectHdl ) );
187 m_pBtnRemoveBitmap->SetClickHdl( LINK( this, AnimationWindow, ClickRemoveBitmapHdl ) );
188 m_pBtnRemoveAll->SetClickHdl( LINK( this, AnimationWindow, ClickRemoveBitmapHdl ) );
190 m_pRbtGroup->SetClickHdl( LINK( this, AnimationWindow, ClickRbtHdl ) );
191 m_pRbtBitmap->SetClickHdl( LINK( this, AnimationWindow, ClickRbtHdl ) );
192 m_pBtnCreateGroup->SetClickHdl( LINK( this, AnimationWindow, ClickCreateGroupHdl ) );
193 m_pNumFldBitmap->SetModifyHdl( LINK( this, AnimationWindow, ModifyBitmapHdl ) );
194 m_pTimeField->SetModifyHdl( LINK( this, AnimationWindow, ModifyTimeHdl ) );
196 // disable 3D border
197 m_pCtlDisplay->SetBorderStyle(WindowBorderStyle::MONO);
199 SetMinOutputSizePixel(GetOptimalSize());
201 ResetAttrs();
203 // the animator is empty; no animation group can be created
204 m_pBtnCreateGroup->Disable();
207 AnimationWindow::~AnimationWindow()
209 disposeOnce();
212 void AnimationWindow::dispose()
214 DELETEZ( pControllerItem );
216 for (size_t i = 0; i < m_FrameList.size(); ++i)
218 delete m_FrameList[i].first;
219 delete m_FrameList[i].second;
221 m_FrameList.clear();
222 m_nCurrentFrame = EMPTY_FRAMELIST;
224 // delete the clones
225 delete pMyDoc;
227 m_pCtlDisplay.disposeAndClear();
228 m_pBtnFirst.clear();
229 m_pBtnReverse.clear();
230 m_pBtnStop.clear();
231 m_pBtnPlay.clear();
232 m_pBtnLast.clear();
233 m_pNumFldBitmap.clear();
234 m_pTimeField.clear();
235 m_pLbLoopCount.clear();
236 m_pBtnGetOneObject.clear();
237 m_pBtnGetAllObjects.clear();
238 m_pBtnRemoveBitmap.clear();
239 m_pBtnRemoveAll.clear();
240 m_pFiCount.clear();
241 m_pRbtGroup.clear();
242 m_pRbtBitmap.clear();
243 m_pFtAdjustment.clear();
244 m_pLbAdjustment.clear();
245 m_pBtnCreateGroup.clear();
246 pWin.clear();
247 SfxDockingWindow::dispose();
250 IMPL_LINK_NOARG(AnimationWindow, ClickFirstHdl)
252 m_nCurrentFrame = (m_FrameList.empty()) ? EMPTY_FRAMELIST : 0;
253 UpdateControl();
255 return 0L;
258 IMPL_LINK_NOARG(AnimationWindow, ClickStopHdl)
260 bMovie = false;
261 return 0L;
264 IMPL_LINK( AnimationWindow, ClickPlayHdl, void *, p )
266 ScopeLockGuard aGuard( maPlayLock );
268 bMovie = true;
269 bool bDisableCtrls = false;
270 size_t const nCount = m_FrameList.size();
271 bool bReverse = p == m_pBtnReverse;
273 // it is difficult to find it later on
274 bool bRbtGroupEnabled = m_pRbtGroup->IsEnabled();
275 bool bBtnGetAllObjectsEnabled = m_pBtnGetAllObjects->IsEnabled();
276 bool bBtnGetOneObjectEnabled = m_pBtnGetOneObject->IsEnabled();
278 // calculate overall time
279 tools::Time aTime( 0 );
280 long nFullTime;
281 if( m_pRbtBitmap->IsChecked() )
283 for (size_t i = 0; i < nCount; ++i)
285 aTime += *m_FrameList[i].second;
287 nFullTime = aTime.GetMSFromTime();
289 else
291 nFullTime = nCount * 100;
292 aTime.MakeTimeFromMS( nFullTime );
295 // StatusBarManager from 1 second
296 SfxProgress* pProgress = NULL;
297 if( nFullTime >= 1000 )
299 bDisableCtrls = true;
300 m_pBtnStop->Enable();
301 m_pBtnStop->Update();
302 OUString aStr("Animator:"); // here we should think about something smart
303 pProgress = new SfxProgress( NULL, aStr, nFullTime );
306 sal_uLong nTmpTime = 0;
307 size_t i = 0;
308 bool bCount = i < nCount;
309 if( bReverse )
311 i = nCount - 1;
313 while( bCount && bMovie )
315 // make list and view consistent
316 assert(i < m_FrameList.size());
317 m_nCurrentFrame = i;
319 UpdateControl(bDisableCtrls);
321 if( m_pRbtBitmap->IsChecked() )
323 tools::Time *const pTime = m_FrameList[i].second;
324 assert(pTime);
326 m_pTimeField->SetTime( *pTime );
327 sal_uLong nTime = pTime->GetMSFromTime();
329 WaitInEffect( nTime, nTmpTime, pProgress );
330 nTmpTime += nTime;
332 else
334 WaitInEffect( 100, nTmpTime, pProgress );
335 nTmpTime += 100;
337 if( bReverse )
339 if (i == 0)
341 // Terminate loop.
342 bCount = false;
344 else
346 --i;
349 else
351 i++;
352 if (i >= nCount)
354 // Terminate loop.
355 bCount = false;
356 // Move i back into valid range.
357 i = nCount - 1;
362 // to re-enable the controls
363 bMovie = false;
364 if (nCount > 0)
366 assert(i == m_nCurrentFrame);
367 UpdateControl();
370 if( pProgress )
372 delete pProgress;
373 m_pBtnStop->Disable();
376 m_pRbtGroup->Enable( bRbtGroupEnabled );
377 m_pBtnGetAllObjects->Enable( bBtnGetAllObjectsEnabled );
378 m_pBtnGetOneObject->Enable( bBtnGetOneObjectEnabled );
380 return 0L;
383 IMPL_LINK_NOARG(AnimationWindow, ClickLastHdl)
385 m_nCurrentFrame =
386 (m_FrameList.empty()) ? EMPTY_FRAMELIST : m_FrameList.size() - 1 ;
387 UpdateControl();
389 return 0L;
392 IMPL_LINK( AnimationWindow, ClickRbtHdl, void *, p )
394 if (m_FrameList.empty() || p == m_pRbtGroup || m_pRbtGroup->IsChecked())
396 m_pTimeField->SetText( OUString() );
397 m_pTimeField->Enable( false );
398 m_pLbLoopCount->Enable( false );
400 else if( p == m_pRbtBitmap || m_pRbtBitmap->IsChecked() )
402 sal_uLong n = static_cast<sal_uLong>(m_pNumFldBitmap->GetValue());
403 if( n > 0 )
405 tools::Time *const pTime = m_FrameList[n - 1].second;
406 if( pTime )
407 m_pTimeField->SetTime( *pTime );
409 m_pTimeField->Enable();
410 m_pLbLoopCount->Enable();
413 return 0L;
416 IMPL_LINK( AnimationWindow, ClickGetObjectHdl, void *, pBtn )
418 bAllObjects = pBtn == m_pBtnGetAllObjects;
420 // Code now in AddObj()
421 SfxBoolItem aItem( SID_ANIMATOR_ADD, true );
423 GetBindings().GetDispatcher()->Execute(
424 SID_ANIMATOR_ADD, SfxCallMode::SLOT | SfxCallMode::RECORD, &aItem, 0L );
425 return 0L;
428 IMPL_LINK( AnimationWindow, ClickRemoveBitmapHdl, void *, pBtn )
430 SdPage* pPage = pMyDoc->GetSdPage(0, PK_STANDARD);
431 SdrObject* pObject;
433 // tdf#95298 check m_nCurrentFrame for EMPTY_FRAMELIST to avoid out-of-bound array access
434 if (pBtn == m_pBtnRemoveBitmap && EMPTY_FRAMELIST != m_nCurrentFrame)
436 delete m_FrameList[m_nCurrentFrame].first;
437 delete m_FrameList[m_nCurrentFrame].second;
438 m_FrameList.erase(m_FrameList.begin() + m_nCurrentFrame);
440 pObject = pPage->GetObj(m_nCurrentFrame);
441 // Through acquisition of the AnimatedGIFs, objects does not need to
442 // exist.
443 if( pObject )
445 pObject = pPage->RemoveObject(m_nCurrentFrame);
446 DBG_ASSERT(pObject, "Clone not found during deletion");
447 SdrObject::Free( pObject );
448 pPage->RecalcObjOrdNums();
451 if (m_nCurrentFrame >= m_FrameList.size())
453 // tdf#95298 last frame was deleted, try to use the one before it or go on empty state
454 m_nCurrentFrame = m_FrameList.empty() ? EMPTY_FRAMELIST : m_FrameList.size() - 1;
457 else // delete everything
459 ScopedVclPtrInstance< WarningBox > aWarnBox( this, WB_YES_NO, SD_RESSTR( STR_ASK_DELETE_ALL_PICTURES ) );
460 short nReturn = aWarnBox->Execute();
462 if( nReturn == RET_YES )
464 // clear frame list
465 for (size_t i = m_FrameList.size(); i > 0; )
467 --i;
468 delete m_FrameList[i].first;
470 pObject = pPage->GetObj( i );
471 if( pObject )
473 pObject = pPage->RemoveObject( i );
474 DBG_ASSERT(pObject, "Clone not found during deletion");
475 SdrObject::Free( pObject );
476 //pPage->RecalcObjOrdNums();
479 delete m_FrameList[i].second;
481 m_FrameList.clear();
482 m_nCurrentFrame = EMPTY_FRAMELIST;
486 // can we create a animation group
487 if (m_FrameList.empty())
489 m_pBtnCreateGroup->Disable();
490 // if previous disabled by acquisition of AnimatedGIFs:
491 //m_pRbtBitmap->Enable();
492 m_pRbtGroup->Enable();
495 // calculate and set zoom for DisplayWin
496 Fraction aFrac(GetScale());
497 m_pCtlDisplay->SetScale(aFrac);
499 UpdateControl();
501 return 0L;
504 IMPL_LINK_NOARG(AnimationWindow, ClickCreateGroupHdl)
506 // Code now in CreatePresObj()
507 SfxBoolItem aItem( SID_ANIMATOR_CREATE, true );
509 GetBindings().GetDispatcher()->Execute(
510 SID_ANIMATOR_CREATE, SfxCallMode::SLOT | SfxCallMode::RECORD, &aItem, 0L );
511 return 0L;
514 IMPL_LINK_NOARG(AnimationWindow, ModifyBitmapHdl)
516 sal_uLong nBmp = static_cast<sal_uLong>(m_pNumFldBitmap->GetValue());
518 if (nBmp > m_FrameList.size())
520 nBmp = m_FrameList.size();
523 m_nCurrentFrame = nBmp - 1;
525 UpdateControl();
527 return 0L;
530 IMPL_LINK_NOARG(AnimationWindow, ModifyTimeHdl)
532 sal_uLong nPos = static_cast<sal_uLong>(m_pNumFldBitmap->GetValue() - 1);
534 tools::Time *const pTime = m_FrameList[nPos].second;
536 *pTime = m_pTimeField->GetTime();
538 return 0L;
541 void AnimationWindow::UpdateControl(bool const bDisableCtrls)
543 // tdf#95298 check m_nCurrentFrame for EMPTY_FRAMELIST to avoid out-of-bound array access
544 if (!m_FrameList.empty() && EMPTY_FRAMELIST != m_nCurrentFrame)
546 BitmapEx aBmp(*m_FrameList[m_nCurrentFrame].first);
548 SdPage* pPage = pMyDoc->GetSdPage(0, PK_STANDARD);
549 SdrObject *const pObject =
550 static_cast<SdrObject*>(pPage->GetObj(m_nCurrentFrame));
551 if( pObject )
553 ScopedVclPtrInstance< VirtualDevice > pVD;
554 Rectangle aObjRect( pObject->GetCurrentBoundRect() );
555 Size aObjSize( aObjRect.GetSize() );
556 Point aOrigin( Point( -aObjRect.Left(), -aObjRect.Top() ) );
557 MapMode aMap( pVD->GetMapMode() );
558 aMap.SetMapUnit( MAP_100TH_MM );
559 aMap.SetOrigin( aOrigin );
560 pVD->SetMapMode( aMap );
561 pVD->SetOutputSize( aObjSize );
562 const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
563 pVD->SetBackground( Wallpaper( rStyles.GetFieldColor() ) );
564 pVD->SetDrawMode( rStyles.GetHighContrastMode()
565 ? sd::OUTPUT_DRAWMODE_CONTRAST
566 : sd::OUTPUT_DRAWMODE_COLOR );
567 pVD->Erase();
568 pObject->SingleObjectPainter( *pVD.get() );
569 aBmp = BitmapEx( pVD->GetBitmap( aObjRect.TopLeft(), aObjSize ) );
572 m_pCtlDisplay->SetBitmapEx(&aBmp);
574 else
576 m_pCtlDisplay->SetBitmapEx(0);
578 m_pCtlDisplay->Invalidate();
579 m_pCtlDisplay->Update();
581 m_pFiCount->SetText(OUString::number(
582 m_FrameList.size()));
584 if (!m_FrameList.empty() && !bMovie)
586 size_t nIndex = m_nCurrentFrame + 1;
587 m_pNumFldBitmap->SetValue(nIndex);
589 // if there is at least 1 object in the list
590 m_pBtnFirst->Enable();
591 m_pBtnReverse->Enable();
592 m_pBtnPlay->Enable();
593 m_pBtnLast->Enable();
594 m_pNumFldBitmap->Enable();
595 m_pTimeField->Enable();
596 m_pLbLoopCount->Enable();
597 m_pBtnRemoveBitmap->Enable();
598 m_pBtnRemoveAll->Enable();
600 else
602 // if no object is in the list
603 m_pBtnFirst->Enable( false );
604 m_pBtnReverse->Enable( false );
605 m_pBtnPlay->Enable( false );
606 m_pBtnLast->Enable( false );
607 m_pNumFldBitmap->Enable( false );
608 m_pTimeField->Enable( false );
609 m_pLbLoopCount->Enable( false );
610 m_pBtnRemoveBitmap->Enable( false );
611 m_pBtnRemoveAll->Enable( false );
614 if( bMovie && bDisableCtrls )
616 m_pBtnGetOneObject->Enable( false );
617 m_pBtnGetAllObjects->Enable( false );
618 m_pRbtGroup->Enable( false );
619 m_pRbtBitmap->Enable( false );
620 m_pBtnCreateGroup->Enable( false );
621 m_pFtAdjustment->Enable( false );
622 m_pLbAdjustment->Enable( false );
624 else
626 // enable 'group object' only if it is not a Animated GIF
627 if (m_FrameList.empty())
629 m_pRbtGroup->Enable();
632 m_pRbtBitmap->Enable();
633 m_pBtnCreateGroup->Enable(!m_FrameList.empty());
634 m_pFtAdjustment->Enable( true );
635 m_pLbAdjustment->Enable( true );
638 ClickRbtHdl( NULL );
641 void AnimationWindow::ResetAttrs()
643 m_pRbtGroup->Check();
644 m_pLbAdjustment->SelectEntryPos( BA_CENTER );
645 // LoopCount
646 m_pLbLoopCount->SelectEntryPos( m_pLbLoopCount->GetEntryCount() - 1);
648 UpdateControl();
651 void AnimationWindow::WaitInEffect( sal_uLong nMilliSeconds, sal_uLong nTime,
652 SfxProgress* pProgress ) const
654 sal_uInt64 aEnd = tools::Time::GetSystemTicks() + nMilliSeconds;
655 sal_uInt64 aCurrent = tools::Time::GetSystemTicks();
656 while (aCurrent < aEnd)
658 aCurrent = tools::Time::GetSystemTicks();
660 if( pProgress )
661 pProgress->SetState( nTime + nMilliSeconds + aCurrent - aEnd );
663 Application::Reschedule();
665 if( !bMovie )
666 return;
670 Fraction AnimationWindow::GetScale()
672 Fraction aFrac;
673 size_t const nCount = m_FrameList.size();
674 if (nCount > 0)
676 Size aBmpSize(0, 0);
677 for (size_t i = 0; i < nCount; i++)
679 BitmapEx *const pBitmap = m_FrameList[i].first;
680 Size aTempSize( pBitmap->GetBitmap().GetSizePixel() );
681 aBmpSize.Width() = std::max( aBmpSize.Width(), aTempSize.Width() );
682 aBmpSize.Height() = std::max( aBmpSize.Height(), aTempSize.Height() );
685 aBmpSize.Width() += 10;
686 aBmpSize.Height() += 10;
688 Size aDisplaySize(m_pCtlDisplay->GetOutputSize());
690 aFrac = Fraction( std::min( (double)aDisplaySize.Width() / (double)aBmpSize.Width(),
691 (double)aDisplaySize.Height() / (double)aBmpSize.Height() ) );
693 return aFrac;
696 void AnimationWindow::Resize()
698 SfxDockingWindow::Resize();
699 Fraction aFrac(GetScale());
700 m_pCtlDisplay->SetScale(aFrac);
703 bool AnimationWindow::Close()
705 if( maPlayLock.isLocked() )
707 return false;
709 else
711 SfxBoolItem aItem( SID_ANIMATION_OBJECTS, false );
713 GetBindings().GetDispatcher()->Execute(
714 SID_ANIMATION_OBJECTS, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, &aItem, 0L );
716 SfxDockingWindow::Close();
718 return true;
722 void AnimationWindow::FillInfo( SfxChildWinInfo& rInfo ) const
724 SfxDockingWindow::FillInfo( rInfo ) ;
727 void AnimationWindow::AddObj (::sd::View& rView )
729 // finish text entry mode to ensure that bitmap is identical with object
730 if( rView.IsTextEdit() )
731 rView.SdrEndTextEdit();
733 // clone object(s) and insert the clone(s) into the list
734 const SdrMarkList& rMarkList = rView.GetMarkedObjectList();
735 const size_t nMarkCount = rMarkList.GetMarkCount();
736 SdPage* pPage = pMyDoc->GetSdPage(0, PK_STANDARD);
737 const size_t nCloneCount = pPage->GetObjCount();
739 if (nMarkCount > 0)
741 // If it is ONE animation object or one group object, which was
742 // 'individually taken', we insert the objects separately
743 bool bAnimObj = false;
744 if( nMarkCount == 1 )
746 SdrMark* pMark = rMarkList.GetMark(0);
747 SdrObject* pObject = pMark->GetMarkedSdrObj();
748 SdAnimationInfo* pAnimInfo = rView.GetDoc().GetAnimationInfo( pObject );
749 sal_uInt32 nInv = pObject->GetObjInventor();
750 sal_uInt16 nId = pObject->GetObjIdentifier();
752 // Animated Bitmap (GIF)
753 if( nInv == SdrInventor && nId == OBJ_GRAF && static_cast<SdrGrafObj*>( pObject )->IsAnimated() )
755 const SdrGrafObj* pGrafObj = static_cast<SdrGrafObj*>(pObject);
756 Graphic aGraphic( pGrafObj->GetTransformedGraphic() );
757 sal_uInt16 nCount = 0;
759 if( aGraphic.IsAnimated() )
760 nCount = aGraphic.GetAnimation().Count();
762 if( nCount > 0 )
764 const Animation aAnimation( aGraphic.GetAnimation() );
766 for( sal_uInt16 i = 0; i < nCount; i++ )
768 const AnimationBitmap& rAnimBmp = aAnimation.Get( i );
770 BitmapEx *const pBitmapEx =
771 new BitmapEx(rAnimBmp.aBmpEx);
773 // LoopCount
774 if( i == 0 )
776 long nLoopCount = aAnimation.GetLoopCount();
778 if( !nLoopCount ) // endless
779 m_pLbLoopCount->SelectEntryPos( m_pLbLoopCount->GetEntryCount() - 1);
780 else
781 m_pLbLoopCount->SelectEntry(OUString::number( nLoopCount ) );
784 long nTime = rAnimBmp.nWait;
785 ::tools::Time* pTime = new ::tools::Time( 0, 0, nTime / 100, nTime % 100 );
786 size_t nIndex = m_nCurrentFrame + 1;
787 m_FrameList.insert(
788 m_FrameList.begin() + nIndex,
789 ::std::make_pair(pBitmapEx, pTime));
791 // increment => next one inserted after this one
792 ++m_nCurrentFrame;
794 // if a animated GIF is taken, only such one can be created
795 m_pRbtBitmap->Check();
796 m_pRbtGroup->Enable( false );
797 bAnimObj = true;
800 else if( bAllObjects || ( pAnimInfo && pAnimInfo->mbIsMovie ) )
802 // several objects
803 SdrObjList* pObjList = static_cast<SdrObjGroup*>(pObject)->GetSubList();
805 for( size_t nObject = 0; nObject < pObjList->GetObjCount(); ++nObject )
807 SdrObject* pSnapShot = pObjList->GetObj( nObject );
809 BitmapEx *const pBitmapEx = new BitmapEx(
810 SdrExchangeView::GetObjGraphic(
811 pSnapShot->GetModel(), pSnapShot).GetBitmapEx() );
813 ::tools::Time* pTime = new ::tools::Time( m_pTimeField->GetTime() );
814 size_t nIndex = m_nCurrentFrame + 1;
815 m_FrameList.insert(
816 m_FrameList.begin() + nIndex,
817 ::std::make_pair(pBitmapEx, pTime));
819 // increment => next one inserted after this one
820 ++m_nCurrentFrame;
822 // Clone
823 pPage->InsertObject(pSnapShot->Clone(), m_nCurrentFrame);
825 bAnimObj = true;
828 // also one single animated object
829 if( !bAnimObj && !( bAllObjects && nMarkCount > 1 ) )
831 BitmapEx *const pBitmapEx =
832 new BitmapEx(rView.GetAllMarkedGraphic().GetBitmapEx());
834 ::tools::Time* pTime = new ::tools::Time( m_pTimeField->GetTime() );
836 size_t nIndex = m_nCurrentFrame + 1;
837 m_FrameList.insert(
838 m_FrameList.begin() + nIndex,
839 ::std::make_pair(pBitmapEx, pTime));
842 // one single object
843 if( nMarkCount == 1 && !bAnimObj )
845 SdrMark* pMark = rMarkList.GetMark(0);
846 SdrObject* pObject = pMark->GetMarkedSdrObj();
847 SdrObject* pClone = pObject->Clone();
848 size_t nIndex = m_nCurrentFrame + 1;
849 pPage->InsertObject(pClone, nIndex);
851 // several objects: group the clones
852 else if (nMarkCount > 1)
854 // take objects separately
855 if( bAllObjects )
857 for( size_t nObject= 0; nObject < nMarkCount; ++nObject )
859 // Clone
860 SdrObject* pObject = rMarkList.GetMark( nObject )->GetMarkedSdrObj();
862 BitmapEx *const pBitmapEx = new BitmapEx(
863 SdrExchangeView::GetObjGraphic(
864 pObject->GetModel(), pObject).GetBitmapEx() );
866 ::tools::Time* pTime = new ::tools::Time( m_pTimeField->GetTime() );
868 size_t nIndex = m_nCurrentFrame + 1;
869 m_FrameList.insert(
870 m_FrameList.begin() + nIndex,
871 ::std::make_pair(pBitmapEx, pTime));
873 // increment => next one inserted after this one
874 ++m_nCurrentFrame;
876 pPage->InsertObject(pObject->Clone(), m_nCurrentFrame);
878 bAnimObj = true; // that we don't change again
880 else
882 SdrObjGroup* pCloneGroup = new SdrObjGroup;
883 SdrObjList* pObjList = pCloneGroup->GetSubList();
885 for (size_t nObject= 0; nObject < nMarkCount; ++nObject)
886 pObjList->InsertObject(rMarkList.GetMark(nObject)->GetMarkedSdrObj()->Clone());
888 size_t nIndex = m_nCurrentFrame + 1;
889 pPage->InsertObject(pCloneGroup, nIndex);
893 if( !bAnimObj )
895 ++m_nCurrentFrame;
898 // if there was nothing in the animator before but now is something
899 // there, we can create a animation group
900 if (nCloneCount == 0 && !m_FrameList.empty())
902 m_pBtnCreateGroup->Enable();
905 // calculate and set zoom for DisplayWin
906 Fraction aFrac( GetScale() );
907 m_pCtlDisplay->SetScale(aFrac);
909 UpdateControl();
913 void AnimationWindow::CreateAnimObj (::sd::View& rView )
915 vcl::Window* pOutWin = static_cast< vcl::Window*>(rView.GetFirstOutputDevice()); // GetWin( 0 );
916 DBG_ASSERT( pOutWin, "Window does not exist!" );
918 // find window center
919 const MapMode aMap100( MAP_100TH_MM );
920 Size aMaxSizeLog;
921 Size aMaxSizePix;
922 Size aTemp( pOutWin->GetOutputSizePixel() );
923 const Point aWindowCenter( pOutWin->PixelToLogic( Point( aTemp.Width() >> 1, aTemp.Height() >> 1 ) ) );
924 const OutputDevice* pDefDev = Application::GetDefaultDevice();
925 const size_t nCount = m_FrameList.size();
926 BitmapAdjustment eBA = (BitmapAdjustment) m_pLbAdjustment->GetSelectEntryPos();
928 // find biggest bitmap
929 for (size_t i = 0; i < nCount; ++i)
931 const BitmapEx& rBmpEx = *m_FrameList[i].first;
932 const Graphic aGraphic( rBmpEx );
933 Size aTmpSizeLog;
934 const Size aTmpSizePix( rBmpEx.GetSizePixel() );
936 if ( aGraphic.GetPrefMapMode().GetMapUnit() == MAP_PIXEL )
937 aTmpSizeLog = pDefDev->PixelToLogic( aGraphic.GetPrefSize(), aMap100 );
938 else
939 aTmpSizeLog = OutputDevice::LogicToLogic( aGraphic.GetPrefSize(), aGraphic.GetPrefMapMode(), aMap100 );
941 aMaxSizeLog.Width() = std::max( aMaxSizeLog.Width(), aTmpSizeLog.Width() );
942 aMaxSizeLog.Height() = std::max( aMaxSizeLog.Height(), aTmpSizeLog.Height() );
944 aMaxSizePix.Width() = std::max( aMaxSizePix.Width(), aTmpSizePix.Width() );
945 aMaxSizePix.Height() = std::max( aMaxSizePix.Height(), aTmpSizePix.Height() );
948 SdrPageView* pPV = rView.GetSdrPageView();
950 if( m_pRbtBitmap->IsChecked() )
952 // create bitmap group (Animated GIF)
953 Animation aAnimation;
954 Point aPt;
956 for (size_t i = 0; i < nCount; ++i)
958 tools::Time *const pTime = m_FrameList[i].second;
959 long nTime = pTime->GetNanoSec();
960 nTime += pTime->GetSec() * 100;
962 BitmapEx const*const pBitmapEx = m_FrameList[i].first;
964 // calculate offset for the specified direction
965 const Size aBitmapSize( pBitmapEx->GetSizePixel() );
967 switch( eBA )
969 case BA_LEFT_UP:
970 break;
972 case BA_LEFT:
973 aPt.Y() = (aMaxSizePix.Height() - aBitmapSize.Height()) >> 1;
974 break;
976 case BA_LEFT_DOWN:
977 aPt.Y() = aMaxSizePix.Height() - aBitmapSize.Height();
978 break;
980 case BA_UP:
981 aPt.X() = (aMaxSizePix.Width() - aBitmapSize.Width()) >> 1;
982 break;
984 case BA_CENTER:
985 aPt.X() = (aMaxSizePix.Width() - aBitmapSize.Width()) >> 1;
986 aPt.Y() = (aMaxSizePix.Height() - aBitmapSize.Height()) >> 1;
987 break;
989 case BA_DOWN:
990 aPt.X() = (aMaxSizePix.Width() - aBitmapSize.Width()) >> 1;
991 aPt.Y() = aMaxSizePix.Height() - aBitmapSize.Height();
992 break;
994 case BA_RIGHT_UP:
995 aPt.X() = aMaxSizePix.Width() - aBitmapSize.Width();
996 break;
998 case BA_RIGHT:
999 aPt.X() = aMaxSizePix.Width() - aBitmapSize.Width();
1000 aPt.Y() = (aMaxSizePix.Height() - aBitmapSize.Height()) >> 1;
1001 break;
1003 case BA_RIGHT_DOWN:
1004 aPt.X() = aMaxSizePix.Width() - aBitmapSize.Width();
1005 aPt.Y() = aMaxSizePix.Height() - aBitmapSize.Height();
1006 break;
1010 // find LoopCount (number of passes)
1011 AnimationBitmap aAnimBmp;
1012 long nLoopCount = 0L;
1013 sal_Int32 nPos = m_pLbLoopCount->GetSelectEntryPos();
1015 if( nPos != LISTBOX_ENTRY_NOTFOUND && nPos != m_pLbLoopCount->GetEntryCount() - 1 ) // endless
1016 nLoopCount = (long) m_pLbLoopCount->GetSelectEntry().toInt32();
1018 aAnimBmp.aBmpEx = *pBitmapEx;
1019 aAnimBmp.aPosPix = aPt;
1020 aAnimBmp.aSizePix = aBitmapSize;
1021 aAnimBmp.nWait = nTime;
1022 aAnimBmp.eDisposal = DISPOSE_BACK;
1023 aAnimBmp.bUserInput = false;
1025 aAnimation.Insert( aAnimBmp );
1026 aAnimation.SetDisplaySizePixel( aMaxSizePix );
1027 aAnimation.SetLoopCount( nLoopCount );
1030 SdrGrafObj* pGrafObj = new SdrGrafObj( Graphic( aAnimation ) );
1031 const Point aOrg( aWindowCenter.X() - ( aMaxSizeLog.Width() >> 1 ), aWindowCenter.Y() - ( aMaxSizeLog.Height() >> 1 ) );
1033 pGrafObj->SetLogicRect( Rectangle( aOrg, aMaxSizeLog ) );
1034 rView.InsertObjectAtView( pGrafObj, *pPV, SdrInsertFlags::SETDEFLAYER);
1036 else
1038 // calculate offset for the specified direction
1039 Size aOffset;
1040 SdrObject * pClone = NULL;
1041 SdPage* pPage = pMyDoc->GetSdPage(0, PK_STANDARD);
1043 for (size_t i = 0; i < nCount; ++i)
1045 pClone = pPage->GetObj(i);
1046 Rectangle aRect( pClone->GetSnapRect() );
1048 switch( eBA )
1050 case BA_LEFT_UP:
1051 break;
1053 case BA_LEFT:
1054 aOffset.Height() = (aMaxSizeLog.Height() - aRect.GetHeight()) / 2;
1055 break;
1057 case BA_LEFT_DOWN:
1058 aOffset.Height() = aMaxSizeLog.Height() - aRect.GetHeight();
1059 break;
1061 case BA_UP:
1062 aOffset.Width() = (aMaxSizeLog.Width() - aRect.GetWidth()) / 2;
1063 break;
1065 case BA_CENTER:
1066 aOffset.Width() = (aMaxSizeLog.Width() - aRect.GetWidth()) / 2;
1067 aOffset.Height() = (aMaxSizeLog.Height() - aRect.GetHeight()) / 2;
1068 break;
1070 case BA_DOWN:
1071 aOffset.Width() = (aMaxSizeLog.Width() - aRect.GetWidth()) / 2;
1072 aOffset.Height() = aMaxSizeLog.Height() - aRect.GetHeight();
1073 break;
1075 case BA_RIGHT_UP:
1076 aOffset.Width() = aMaxSizeLog.Width() - aRect.GetWidth();
1077 break;
1079 case BA_RIGHT:
1080 aOffset.Width() = aMaxSizeLog.Width() - aRect.GetWidth();
1081 aOffset.Height() = (aMaxSizeLog.Height() - aRect.GetHeight()) / 2;
1082 break;
1084 case BA_RIGHT_DOWN:
1085 aOffset.Width() = aMaxSizeLog.Width() - aRect.GetWidth();
1086 aOffset.Height() = aMaxSizeLog.Height() - aRect.GetHeight();
1087 break;
1090 // Unfortunately, SetSnapRect is not implemented for ellipses !!!
1091 Point aMovePt( aWindowCenter + Point( aOffset.Width(), aOffset.Height() ) - aRect.TopLeft() );
1092 Size aMoveSize( aMovePt.X(), aMovePt.Y() );
1093 pClone->NbcMove( aMoveSize );
1096 // #i42894# Caution(!) variable pPage looks right, but it is a page from the local
1097 // document the dialog is using (!), so get the target page from the target view
1098 SdPage* pTargetSdPage = dynamic_cast< SdPage* >(rView.GetSdrPageView() ? rView.GetSdrPageView()->GetPage() : 0);
1100 if(pTargetSdPage)
1102 // create animation group
1103 SdrObjGroup* pGroup = new SdrObjGroup;
1104 SdrObjList* pObjList = pGroup->GetSubList();
1106 for (size_t i = 0; i < nCount; ++i)
1108 // the clone remains in the animatior; we insert a clone of the
1109 // clone into the group
1110 pClone = pPage->GetObj(i);
1111 SdrObject* pCloneOfClone = pClone->Clone();
1112 //SdrObject* pCloneOfClone = pPage->GetObj(i)->Clone();
1113 pObjList->InsertObject(pCloneOfClone);
1116 // until now the top left corner of the group is in the window center;
1117 // correct the position by half of the size of the group
1118 aTemp = aMaxSizeLog;
1119 aTemp.Height() = - aTemp.Height() / 2;
1120 aTemp.Width() = - aTemp.Width() / 2;
1121 pGroup->NbcMove(aTemp);
1123 // #i42894# create needed SMIL stuff and move child objects to page directly (see
1124 // comments at EffectMigration::CreateAnimatedGroup why this has to be done).
1125 EffectMigration::CreateAnimatedGroup(*pGroup, *pTargetSdPage);
1127 // #i42894# if that worked, delete the group again
1128 if(!pGroup->GetSubList()->GetObjCount())
1130 delete pGroup;
1135 ClickFirstHdl( this );
1138 void AnimationWindow::DataChanged( const DataChangedEvent& rDCEvt )
1140 SfxDockingWindow::DataChanged( rDCEvt );
1142 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1144 UpdateControl();
1149 * ControllerItem for Animator
1151 AnimationControllerItem::AnimationControllerItem(
1152 sal_uInt16 _nId,
1153 AnimationWindow* pAnimWin,
1154 SfxBindings* _pBindings)
1155 : SfxControllerItem( _nId, *_pBindings ),
1156 pAnimationWin( pAnimWin )
1160 void AnimationControllerItem::StateChanged( sal_uInt16 nSId,
1161 SfxItemState eState, const SfxPoolItem* pItem )
1163 if( eState >= SfxItemState::DEFAULT && nSId == SID_ANIMATOR_STATE )
1165 const SfxUInt16Item* pStateItem = PTR_CAST( SfxUInt16Item, pItem );
1166 assert(pStateItem); //SfxUInt16Item expected
1167 if (pStateItem)
1169 sal_uInt16 nState = pStateItem->GetValue();
1170 pAnimationWin->m_pBtnGetOneObject->Enable( nState & 1 );
1171 pAnimationWin->m_pBtnGetAllObjects->Enable( nState & 2 );
1176 } // end of namespace sd
1178 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */