LibreOffice Module sd (master) 1
CustomAnimationList.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <com/sun/star/document/XActionLockable.hpp>
21#include <com/sun/star/drawing/XDrawPage.hpp>
22#include <com/sun/star/drawing/XShapes.hpp>
23#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
24#include <com/sun/star/presentation/EffectNodeType.hpp>
25#include <com/sun/star/presentation/ParagraphTarget.hpp>
26#include <com/sun/star/container/XEnumerationAccess.hpp>
27#include <com/sun/star/presentation/EffectPresetClass.hpp>
28#include <com/sun/star/presentation/EffectCommands.hpp>
29#include <com/sun/star/text/XTextRange.hpp>
30#include <com/sun/star/beans/XPropertySet.hpp>
34#include <utility>
35#include <vcl/commandevent.hxx>
36#include <vcl/event.hxx>
37#include <vcl/image.hxx>
38#include <vcl/settings.hxx>
39#include <vcl/svapp.hxx>
40#include <vcl/weldutils.hxx>
41#include <tools/debug.hxx>
42#include <tools/gen.hxx>
44
45#include <sdresid.hxx>
46
47#include <strings.hrc>
48#include <bitmaps.hlst>
49
50#include <algorithm>
51#include <memory>
52
53using namespace ::com::sun::star;
54using namespace ::com::sun::star::presentation;
55
56using ::com::sun::star::uno::UNO_QUERY;
57using ::com::sun::star::uno::UNO_QUERY_THROW;
58using ::com::sun::star::uno::Any;
59using ::com::sun::star::uno::Reference;
60using ::com::sun::star::uno::Exception;
61using ::com::sun::star::uno::XInterface;
62using ::com::sun::star::text::XTextRange;
63using ::com::sun::star::drawing::XShape;
64using ::com::sun::star::drawing::XShapes;
65using ::com::sun::star::drawing::XDrawPage;
66using ::com::sun::star::container::XChild;
67using ::com::sun::star::container::XIndexAccess;
68using ::com::sun::star::container::XEnumerationAccess;
69using ::com::sun::star::container::XEnumeration;
70using ::com::sun::star::beans::XPropertySet;
71using ::com::sun::star::beans::XPropertySetInfo;
72
73namespace sd {
74
75// go recursively through all shapes in the given XShapes collection and return true as soon as the
76// given shape is found. nIndex is incremented for each shape with the same shape type as the given
77// shape is found until the given shape is found.
78static bool getShapeIndex( const Reference< XShapes >& xShapes, const Reference< XShape >& xShape, sal_Int32& nIndex )
79{
80 const sal_Int32 nCount = xShapes->getCount();
81 sal_Int32 n;
82 for( n = 0; n < nCount; n++ )
83 {
84 Reference< XShape > xChild;
85 xShapes->getByIndex( n ) >>= xChild;
86 if( xChild == xShape )
87 return true;
88
89 if( xChild->getShapeType() == xShape->getShapeType() )
90 nIndex++;
91
92 Reference< XShapes > xChildContainer( xChild, UNO_QUERY );
93 if( xChildContainer.is() )
94 {
95 if( getShapeIndex( xChildContainer, xShape, nIndex ) )
96 return true;
97 }
98 }
99
100 return false;
101}
102
103// returns the index of the shape type from the given shape
104static sal_Int32 getShapeIndex( const Reference< XShape >& xShape )
105{
106 Reference< XChild > xChild( xShape, UNO_QUERY );
107 Reference< XShapes > xPage;
108
109 while( xChild.is() && !xPage.is() )
110 {
111 Reference< XInterface > x( xChild->getParent() );
112 xChild.set( x, UNO_QUERY );
113 Reference< XDrawPage > xTestPage( x, UNO_QUERY );
114 if( xTestPage.is() )
115 xPage.set( x, UNO_QUERY );
116 }
117
118 sal_Int32 nIndex = 1;
119
120 if( xPage.is() && getShapeIndex( xPage, xShape, nIndex ) )
121 return nIndex;
122 else
123 return -1;
124}
125
126OUString getShapeDescription( const Reference< XShape >& xShape, bool bWithText )
127{
128 OUString aDescription;
129 Reference< XPropertySet > xSet( xShape, UNO_QUERY );
130 bool bAppendIndex = true;
131
132 if(xSet.is()) try
133 {
134 Reference<XPropertySetInfo> xInfo(xSet->getPropertySetInfo());
135 if (xInfo.is())
136 {
137 static constexpr OUStringLiteral aPropName1(u"Name");
138 if(xInfo->hasPropertyByName(aPropName1))
139 xSet->getPropertyValue(aPropName1) >>= aDescription;
140
141 bAppendIndex = aDescription.isEmpty();
142
143 static constexpr OUStringLiteral aPropName2(u"UINameSingular");
144 if(xInfo->hasPropertyByName(aPropName2))
145 xSet->getPropertyValue(aPropName2) >>= aDescription;
146 }
147 }
148 catch( Exception& )
149 {
150 TOOLS_WARN_EXCEPTION( "sd", "sd::getShapeDescription()" );
151 }
152
153 if (bAppendIndex)
154 {
155 aDescription += " " + OUString::number(getShapeIndex(xShape));
156 }
157
158 if( bWithText )
159 {
160 Reference< XTextRange > xText( xShape, UNO_QUERY );
161 if( xText.is() )
162 {
163 OUString aText( xText->getString() );
164 if( !aText.isEmpty() )
165 {
166 aDescription += ": ";
167
168 aText = aText.replace( '\n', ' ' );
169 aText = aText.replace( '\r', ' ' );
170
171 aDescription += aText;
172 }
173 }
174 }
175 return aDescription;
176}
177
178static OUString getDescription( const Any& rTarget, bool bWithText )
179{
180 OUString aDescription;
181
182 if( rTarget.getValueType() == ::cppu::UnoType<ParagraphTarget>::get() )
183 {
184 ParagraphTarget aParaTarget;
185 rTarget >>= aParaTarget;
186
187 css::uno::Reference<css::document::XActionLockable> xLockable(aParaTarget.Shape, css::uno::UNO_QUERY);
188 if (xLockable.is())
189 xLockable->addActionLock();
190 comphelper::ScopeGuard aGuard([&xLockable]()
191 {
192 if (xLockable.is())
193 xLockable->removeActionLock();
194 });
195
196 Reference< XEnumerationAccess > xText( aParaTarget.Shape, UNO_QUERY_THROW );
197 Reference< XEnumeration > xEnumeration( xText->createEnumeration(), css::uno::UNO_SET_THROW );
198 sal_Int32 nPara = aParaTarget.Paragraph;
199
200 while( xEnumeration->hasMoreElements() && nPara )
201 {
202 xEnumeration->nextElement();
203 nPara--;
204 }
205
206 DBG_ASSERT( xEnumeration->hasMoreElements(), "sd::CustomAnimationEffect::prepareText(), paragraph out of range!" );
207
208 if( xEnumeration->hasMoreElements() )
209 {
210 Reference< XTextRange > xParagraph;
211 xEnumeration->nextElement() >>= xParagraph;
212
213 if( xParagraph.is() )
214 aDescription = xParagraph->getString();
215 }
216 }
217 else
218 {
219 Reference< XShape > xShape;
220 rTarget >>= xShape;
221 if( xShape.is() )
222 aDescription = getShapeDescription( xShape, bWithText );
223 }
224
225 return aDescription;
226}
227
229{
230public:
231 CustomAnimationListEntryItem(OUString aDescription,
233 const CustomAnimationEffectPtr& getEffect() const { return mpEffect; }
234
235 Size GetSize(const vcl::RenderContext& rRenderContext);
236 void Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected);
237 void PaintEffect(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected);
238 void PaintTrigger(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect);
239
240private:
242 OUString msEffectName;
244
245public:
246 static const ::tools::Long nIconWidth = 19;
247 static const ::tools::Long nItemMinHeight = 38;
248};
249
251 : msDescription(std::move(aDescription))
252 , mpEffect(std::move(pEffect))
253{
254 if (!mpEffect)
255 return;
256 switch (mpEffect->getPresetClass())
257 {
258 case EffectPresetClass::ENTRANCE:
259 msEffectName = SdResId(STR_CUSTOMANIMATION_ENTRANCE); break;
260 case EffectPresetClass::EXIT:
261 msEffectName = SdResId(STR_CUSTOMANIMATION_EXIT); break;
262 case EffectPresetClass::EMPHASIS:
263 msEffectName = SdResId(STR_CUSTOMANIMATION_EMPHASIS); break;
264 case EffectPresetClass::MOTIONPATH:
265 msEffectName = SdResId(STR_CUSTOMANIMATION_MOTION_PATHS); break;
266 default:
267 msEffectName = SdResId(STR_CUSTOMANIMATION_MISC); break;
268 }
269 msEffectName = msEffectName.replaceFirst( "%1" , CustomAnimationPresets::getCustomAnimationPresets().getUINameForPresetId(mpEffect->getPresetId()));
270}
271
273{
274 vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
275 const ::tools::Rectangle& rRect = std::get<1>(aPayload);
276 bool bSelected = std::get<2>(aPayload);
277 const OUString& rId = std::get<3>(aPayload);
278
279 CustomAnimationListEntryItem* pItem = weld::fromId<CustomAnimationListEntryItem*>(rId);
280
281 pItem->Paint(rRenderContext, rRect, bSelected);
282}
283
285{
286 vcl::RenderContext& rRenderContext = aPayload.first;
287 const OUString& rId = aPayload.second;
288
289 CustomAnimationListEntryItem* pItem = weld::fromId<CustomAnimationListEntryItem*>(rId);
290 if (!pItem)
292 return pItem->GetSize(rRenderContext);
293}
294
296{
297 auto width = rRenderContext.GetTextWidth( msDescription ) + nIconWidth;
298 if (width < (rRenderContext.GetTextWidth( msEffectName ) + 2*nIconWidth))
299 width = rRenderContext.GetTextWidth( msEffectName ) + 2*nIconWidth;
300
301 Size aSize(width, rRenderContext.GetTextHeight());
302 if (aSize.Height() < nItemMinHeight)
304 return aSize;
305}
306
307void CustomAnimationListEntryItem::PaintTrigger(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect)
308{
309 Size aSize(rRect.GetSize());
310
311 ::tools::Rectangle aOutRect(rRect);
312
313 // fill the background
314 Color aColor(rRenderContext.GetSettings().GetStyleSettings().GetDialogColor());
315
316 rRenderContext.Push();
317 rRenderContext.SetFillColor(aColor);
318 rRenderContext.SetLineColor();
319 rRenderContext.DrawRect(aOutRect);
320
321 // Erase the four corner pixels to make the rectangle appear rounded.
322 rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetWindowColor());
323 rRenderContext.DrawPixel(aOutRect.TopLeft());
324 rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Top()));
325 rRenderContext.DrawPixel(Point(aOutRect.Left(), aOutRect.Bottom()));
326 rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Bottom()));
327
328 // draw the category title
329
330 int nVertBorder = ((aSize.Height() - rRenderContext.GetTextHeight()) >> 1);
331 int nHorzBorder = rRenderContext.LogicToPixel(Size(3, 3), MapMode(MapUnit::MapAppFont)).Width();
332
333 aOutRect.AdjustLeft(nHorzBorder );
334 aOutRect.AdjustRight( -nHorzBorder );
335 aOutRect.AdjustTop( nVertBorder );
336 aOutRect.AdjustBottom( -nVertBorder );
337
338 rRenderContext.DrawText(aOutRect, rRenderContext.GetEllipsisString(msDescription, aOutRect.GetWidth()));
339 rRenderContext.Pop();
340}
341
342void CustomAnimationListEntryItem::PaintEffect(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected)
343{
344 rRenderContext.Push(vcl::PushFlags::TEXTCOLOR);
345 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
346 if (bSelected)
347 rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
348 else
349 rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
350
351 Point aPos(rRect.TopLeft());
352 int nItemHeight = rRect.GetHeight();
353
354 sal_Int16 nNodeType = mpEffect->getNodeType();
355 if (nNodeType == EffectNodeType::ON_CLICK )
356 {
357 rRenderContext.DrawImage(aPos, Image(StockImage::Yes, BMP_CUSTOMANIMATION_ON_CLICK));
358 }
359 else if (nNodeType == EffectNodeType::AFTER_PREVIOUS)
360 {
361 rRenderContext.DrawImage(aPos, Image(StockImage::Yes, BMP_CUSTOMANIMATION_AFTER_PREVIOUS));
362 }
363 else if (nNodeType == EffectNodeType::WITH_PREVIOUS)
364 {
365 //FIXME With previous image not defined in CustomAnimation.src
366 }
367
368 aPos.AdjustX(nIconWidth);
369
370 //TODO, full width of widget ?
371 rRenderContext.DrawText(aPos, rRenderContext.GetEllipsisString(msDescription, rRect.GetWidth()));
372
373 aPos.AdjustY(nIconWidth);
374
375 OUString sImage;
376 switch (mpEffect->getPresetClass())
377 {
378 case EffectPresetClass::ENTRANCE:
379 sImage = BMP_CUSTOMANIMATION_ENTRANCE_EFFECT; break;
380 case EffectPresetClass::EXIT:
381 sImage = BMP_CUSTOMANIMATION_EXIT_EFFECT; break;
382 case EffectPresetClass::EMPHASIS:
383 sImage = BMP_CUSTOMANIMATION_EMPHASIS_EFFECT; break;
384 case EffectPresetClass::MOTIONPATH:
385 sImage = BMP_CUSTOMANIMATION_MOTION_PATH; break;
386 case EffectPresetClass::OLEACTION:
387 sImage = BMP_CUSTOMANIMATION_OLE; break;
388 case EffectPresetClass::MEDIACALL:
389 switch (mpEffect->getCommand())
390 {
391 case EffectCommands::TOGGLEPAUSE:
392 sImage = BMP_CUSTOMANIMATION_MEDIA_PAUSE; break;
393 case EffectCommands::STOP:
394 sImage = BMP_CUSTOMANIMATION_MEDIA_STOP; break;
395 case EffectCommands::PLAY:
396 default:
397 sImage = BMP_CUSTOMANIMATION_MEDIA_PLAY; break;
398 }
399 break;
400 default:
401 break;
402 }
403
404 if (!sImage.isEmpty())
405 {
406 Image aImage(StockImage::Yes, sImage);
407 Point aImagePos(aPos);
408 aImagePos.AdjustY((nItemHeight/2 - aImage.GetSizePixel().Height()) >> 1 );
409 rRenderContext.DrawImage(aImagePos, aImage);
410 }
411
412 aPos.AdjustX(nIconWidth );
413 aPos.AdjustY((nItemHeight/2 - rRenderContext.GetTextHeight()) >> 1 );
414
415 rRenderContext.DrawText(aPos, rRenderContext.GetEllipsisString(msEffectName, rRect.GetWidth()));
416 rRenderContext.Pop();
417}
418
419void CustomAnimationListEntryItem::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect, bool bSelected)
420{
421 if (mpEffect)
422 PaintEffect(rRenderContext, rRect, bSelected);
423 else
424 PaintTrigger(rRenderContext, rRect);
425}
426
427CustomAnimationList::CustomAnimationList(std::unique_ptr<weld::TreeView> xTreeView,
428 std::unique_ptr<weld::Label> xLabel,
429 std::unique_ptr<weld::Widget> xScrolledWindow)
430 : mxTreeView(std::move(xTreeView))
431 , maDropTargetHelper(*this)
432 , mxEmptyLabel(std::move(xLabel))
433 , mxEmptyLabelParent(std::move(xScrolledWindow))
434 , mbIgnorePaint(false)
435 , mpController(nullptr)
436 , mnLastGroupId(0)
437 , mnPostExpandEvent(nullptr)
438 , mnPostCollapseEvent(nullptr)
439{
440 mxEmptyLabel->set_stack_background();
441
442 mxTreeView->set_selection_mode(SelectionMode::Multiple);
443 mxTreeView->connect_changed(LINK(this, CustomAnimationList, SelectHdl));
444 mxTreeView->connect_key_press(LINK(this, CustomAnimationList, KeyInputHdl));
445 mxTreeView->connect_popup_menu(LINK(this, CustomAnimationList, CommandHdl));
446 mxTreeView->connect_row_activated(LINK(this, CustomAnimationList, DoubleClickHdl));
447 mxTreeView->connect_expanding(LINK(this, CustomAnimationList, ExpandHdl));
448 mxTreeView->connect_collapsing(LINK(this, CustomAnimationList, CollapseHdl));
449 mxTreeView->connect_drag_begin(LINK(this, CustomAnimationList, DragBeginHdl));
450 mxTreeView->connect_custom_get_size(LINK(this, CustomAnimationList, CustomGetSizeHdl));
451 mxTreeView->connect_custom_render(LINK(this, CustomAnimationList, CustomRenderHdl));
452 mxTreeView->set_column_custom_renderer(0, true);
453}
454
456 : DropTargetHelper(rTreeView.get_widget().get_drop_target())
457 , m_rTreeView(rTreeView)
458{
459}
460
462{
463 sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
464
465 if (nAccept != DND_ACTION_NONE)
466 {
467 // to enable the autoscroll when we're close to the edges
469 rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
470 }
471
472 return nAccept;
473}
474
476{
477 return m_rTreeView.ExecuteDrop(rEvt);
478}
479
480// D'n'D #1: Record selected effects for drag'n'drop.
481IMPL_LINK(CustomAnimationList, DragBeginHdl, bool&, rUnsetDragIcon, bool)
482{
483 rUnsetDragIcon = false;
484
485 // Record which effects are selected:
486 // Since NextSelected(..) iterates through the selected items in the order they
487 // were selected, create a sorted list for simpler drag'n'drop algorithms.
488 mDndEffectsSelected.clear();
489 mxTreeView->selected_foreach([this](weld::TreeIter& rEntry){
490 mDndEffectsSelected.emplace_back(mxTreeView->make_iterator(&rEntry));
491 return false;
492 });
493
494 // Note: pEntry is the effect with focus (if multiple effects are selected)
495 mxDndEffectDragging = mxTreeView->make_iterator();
496 if (!mxTreeView->get_cursor(mxDndEffectDragging.get()))
497 mxDndEffectDragging.reset();
498
499 // Allow normal processing.
500 return false;
501}
502
503// D'n'D #3: Called each time mouse moves during drag
505{
507
508 const bool bIsMove = DND_ACTION_MOVE == rEvt.mnAction;
509 if (mxDndEffectDragging && !rEvt.mbLeaving && bIsMove)
510 ret = DND_ACTION_MOVE;
511 return ret;
512}
513
514// D'n'D #5: Tell model to update effect order.
516{
517 std::unique_ptr<weld::TreeIter> xDndEffectInsertBefore(mxTreeView->make_iterator());
518 if (!mxTreeView->get_dest_row_at_pos(rEvt.maPosPixel, xDndEffectInsertBefore.get(), true))
519 xDndEffectInsertBefore.reset();
520
521 const bool bMovingEffect = ( mxDndEffectDragging != nullptr );
522 const bool bMoveNotSelf = !xDndEffectInsertBefore || (mxDndEffectDragging && mxTreeView->iter_compare(*xDndEffectInsertBefore, *mxDndEffectDragging) != 0);
523 const bool bHaveSequence(mpMainSequence);
524
525 if( bMovingEffect && bMoveNotSelf && bHaveSequence )
526 {
527 CustomAnimationListEntryItem* pTarget = xDndEffectInsertBefore ?
528 weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xDndEffectInsertBefore)) :
529 nullptr;
530
531 // Build list of effects
532 std::vector< CustomAnimationEffectPtr > aEffects;
533 for( const auto &pEntry : mDndEffectsSelected )
534 {
535 CustomAnimationListEntryItem* pCustomAnimationEffect = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*pEntry));
536 aEffects.push_back(pCustomAnimationEffect->getEffect());
537 }
538
539 // Callback to observer to have it update the model.
540 // If pTarget is null, pass nullptr to indicate end of list.
542 std::move(aEffects),
543 pTarget ? pTarget->getEffect() : nullptr );
544
545 // Reset selection
547 Select();
548 }
549
550 // NOTE: Don't call default handler because all required
551 // move operations have been completed here to update the model.
552 return DND_ACTION_NONE;
553}
554
556{
558 {
560 mnPostExpandEvent = nullptr;
561 }
562
564 {
566 mnPostCollapseEvent = nullptr;
567 }
568
569 if( mpMainSequence )
570 mpMainSequence->removeListener( this );
571
572 clear();
573}
574
575IMPL_LINK(CustomAnimationList, KeyInputHdl, const KeyEvent&, rKEvt, bool)
576{
577 const int nKeyCode = rKEvt.GetKeyCode().GetCode();
578 switch (nKeyCode)
579 {
580 case KEY_DELETE:
581 mpController->onContextMenu("remove");
582 return true;
583 case KEY_INSERT:
584 mpController->onContextMenu("create");
585 return true;
586 case KEY_SPACE:
587 {
588 std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
589 if (mxTreeView->get_cursor(xEntry.get()))
590 {
591 auto aRect = mxTreeView->get_row_area(*xEntry);
592 const Point aPos(aRect.getOpenWidth() / 2, aRect.getOpenHeight() / 2);
593 const CommandEvent aCEvt(aPos, CommandEventId::ContextMenu);
594 CommandHdl(aCEvt);
595 return true;
596 }
597 }
598 }
599 return false;
600}
601
605{
606 CustomAnimationListEntryItem* pEntry = nullptr;
607
608 std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
609 if (mxTreeView->get_iter_first(*xEntry))
610 {
611 do
612 {
613 CustomAnimationListEntryItem* pTestEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
614 if (pTestEntry->getEffect() == pEffect)
615 {
616 mxTreeView->select(*xEntry);
617 mxTreeView->scroll_to_row(*xEntry);
618 pEntry = pTestEntry;
619 break;
620 }
621 } while (mxTreeView->iter_next(*xEntry));
622 }
623
624 if( !pEntry )
625 {
626 append( pEffect );
627 select( pEffect );
628 }
629}
630
632{
633 mxEntries.clear();
634 mxTreeView->clear();
635
636 mxEmptyLabelParent->show();
637 mxTreeView->hide();
638
639 mxLastParentEntry.reset();
640 mxLastTargetShape = nullptr;
641}
642
644{
645 if( mpMainSequence )
646 mpMainSequence->removeListener( this );
647
648 mpMainSequence = pMainSequence;
649 update();
650
651 if( mpMainSequence )
652 mpMainSequence->addListener( this );
653}
654
656{
657 explicit stl_append_effect_func( CustomAnimationList& rList ) : mrList( rList ) {}
658 void operator()(const CustomAnimationEffectPtr& pEffect);
660};
661
663{
664 mrList.append( pEffect );
665}
666
668{
669 mbIgnorePaint = true;
670
671 std::vector< CustomAnimationEffectPtr > aVisible;
672 std::vector< CustomAnimationEffectPtr > aSelected;
674
675 CustomAnimationEffectPtr pFirstSelEffect;
676 CustomAnimationEffectPtr pLastSelEffect;
677 ::tools::Long nFirstVis = -1;
678 ::tools::Long nLastVis = -1;
679 ::tools::Long nFirstSelOld = -1;
680 ::tools::Long nLastSelOld = -1;
681
682 std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
683
684 if( mpMainSequence )
685 {
686 std::unique_ptr<weld::TreeIter> xLastSelectedEntry;
687 std::unique_ptr<weld::TreeIter> xLastVisibleEntry;
688
689 // save selection, current, and expand (visible) states
690 mxTreeView->all_foreach([this, &aVisible, &nFirstVis, &xLastVisibleEntry,
691 &aSelected, &nFirstSelOld, &pFirstSelEffect, &xLastSelectedEntry](weld::TreeIter& rEntry){
692 CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(rEntry));
693 CustomAnimationEffectPtr pEffect(pEntry->getEffect());
694 if (pEffect)
695 {
696 if (weld::IsEntryVisible(*mxTreeView, rEntry))
697 {
698 aVisible.push_back(pEffect);
699 // save scroll position
700 if (nFirstVis == -1)
701 nFirstVis = weld::GetAbsPos(*mxTreeView, rEntry);
702 if (!xLastVisibleEntry)
703 xLastVisibleEntry = mxTreeView->make_iterator(&rEntry);
704 else
705 mxTreeView->copy_iterator(rEntry, *xLastVisibleEntry);
706 }
707
708 if (mxTreeView->is_selected(rEntry))
709 {
710 aSelected.push_back(pEffect);
711 if (nFirstSelOld == -1)
712 {
713 pFirstSelEffect = pEffect;
714 nFirstSelOld = weld::GetAbsPos(*mxTreeView, rEntry);
715 }
716 if (!xLastSelectedEntry)
717 xLastSelectedEntry = mxTreeView->make_iterator(&rEntry);
718 else
719 mxTreeView->copy_iterator(rEntry, *xLastSelectedEntry);
720 }
721 }
722
723 return false;
724 });
725
726 if (xLastSelectedEntry)
727 {
728 CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xLastSelectedEntry));
729 pLastSelEffect = pEntry->getEffect();
730 nLastSelOld = weld::GetAbsPos(*mxTreeView, *xLastSelectedEntry);
731 }
732
733 if (xLastVisibleEntry)
734 nLastVis = weld::GetAbsPos(*mxTreeView, *xLastVisibleEntry);
735
736 if (mxTreeView->get_cursor(xEntry.get()))
737 {
738 CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
739 aCurrent = pEntry->getEffect();
740 }
741 }
742
743 // rebuild list
744
745 mxTreeView->freeze();
746
747 clear();
748
749 if (mpMainSequence)
750 {
751 std::for_each( mpMainSequence->getBegin(), mpMainSequence->getEnd(), stl_append_effect_func( *this ) );
752 mxLastParentEntry.reset();
753
754 auto rInteractiveSequenceVector = mpMainSequence->getInteractiveSequenceVector();
755
756 for (InteractiveSequencePtr const& pIS : rInteractiveSequenceVector)
757 {
758 Reference< XShape > xShape( pIS->getTriggerShape() );
759 if( xShape.is() )
760 {
761 OUString aDescription = SdResId(STR_CUSTOMANIMATION_TRIGGER) + ": " +
762 getShapeDescription( xShape, false );
763
764 mxEntries.emplace_back(std::make_unique<CustomAnimationListEntryItem>(aDescription, nullptr));
765
766 OUString sId(weld::toId(mxEntries.back().get()));
767 mxTreeView->insert(nullptr, -1, &aDescription, &sId, nullptr, nullptr, false, nullptr);
768 std::for_each( pIS->getBegin(), pIS->getEnd(), stl_append_effect_func( *this ) );
769 mxLastParentEntry.reset();
770 }
771 }
772 }
773
774 mxTreeView->thaw();
775
776 if (mxTreeView->n_children())
777 {
778 mxEmptyLabelParent->hide();
779 mxTreeView->show();
780 }
781
782 if (mpMainSequence)
783 {
784 ::tools::Long nFirstSelNew = -1;
785 ::tools::Long nLastSelNew = -1;
786
787 std::vector<std::unique_ptr<weld::TreeIter>> aNewSelection;
788
789 // restore selection state, expand state, and current-entry (under cursor)
790 if (mxTreeView->get_iter_first(*xEntry))
791 {
792 do
793 {
794 CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
795
796 CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
797 if (pEffect)
798 {
799 // Any effects that were visible should still be visible, so expand their parents.
800 // (a previously expanded parent may have moved leaving a child to now be the new parent to expand)
801 if( std::find( aVisible.begin(), aVisible.end(), pEffect ) != aVisible.end() )
802 {
803 if (mxTreeView->get_iter_depth(*xEntry))
804 {
805 std::unique_ptr<weld::TreeIter> xParentEntry = mxTreeView->make_iterator(xEntry.get());
806 mxTreeView->iter_parent(*xParentEntry);
807 mxTreeView->expand_row(*xParentEntry);
808 }
809 }
810
811 if( std::find( aSelected.begin(), aSelected.end(), pEffect ) != aSelected.end() )
812 aNewSelection.emplace_back(mxTreeView->make_iterator(xEntry.get()));
813
814 // Restore the cursor, as it may deselect other effects wait until
815 // after the loop to reset the selection
816 if( pEffect == aCurrent )
817 mxTreeView->set_cursor(*xEntry);
818
819 if (pEffect == pFirstSelEffect)
820 nFirstSelNew = weld::GetAbsPos(*mxTreeView, *xEntry);
821
822 if (pEffect == pLastSelEffect)
823 nLastSelNew = weld::GetAbsPos(*mxTreeView, *xEntry);
824 }
825 } while (mxTreeView->iter_next(*xEntry));
826 }
827
828 // tdf#147032 unselect what previous set_cursor may have caused to get selected as a side-effect
829 mxTreeView->unselect_all();
830 for (const auto& rEntry : aNewSelection)
831 mxTreeView->select(*rEntry);
832
833 // Scroll to a selected entry, depending on where the selection moved.
834 const bool bMoved = nFirstSelNew != nFirstSelOld;
835 const bool bMovedUp = nFirstSelNew < nFirstSelOld;
836 const bool bMovedDown = nFirstSelNew > nFirstSelOld;
837
838 if( bMoved && nLastSelOld < nFirstVis && nLastSelNew < nFirstVis )
839 {
840 // The selection is above the visible area.
841 // Scroll up to show the last few selected entries.
842 if( nLastSelNew - (nLastVis - nFirstVis) > nFirstSelNew)
843 {
844 // The entries in the selection range can't fit in view.
845 // Scroll so the last selected entry is last in view.
846 mxTreeView->vadjustment_set_value(nLastSelNew - (nLastVis - nFirstVis));
847 }
848 else
849 mxTreeView->vadjustment_set_value(nFirstSelNew);
850 }
851 else if( bMoved && nFirstSelOld > nLastVis && nFirstSelNew > nLastVis )
852 {
853 // The selection is below the visible area.
854 // Scroll down to the first few selected entries.
855 mxTreeView->vadjustment_set_value(nFirstSelNew);
856 }
857 else if( bMovedUp && nFirstSelOld <= nFirstVis )
858 {
859 // A visible entry has moved up out of view; scroll up one.
860 mxTreeView->vadjustment_set_value(nFirstVis - 1);
861 }
862 else if( bMovedDown && nLastSelOld >= nLastVis )
863 {
864 // An entry has moved down out of view; scroll down one.
865 mxTreeView->vadjustment_set_value(nFirstVis + 1);
866 }
867 else if ( nFirstVis != -1 )
868 {
869 // The selection is still in view, or it hasn't moved.
870 mxTreeView->vadjustment_set_value(nFirstVis);
871 }
872 }
873
874 mbIgnorePaint = false;
875
876 Select();
877}
878
880{
881 Any aTarget( pEffect->getTarget() );
882 if( !aTarget.hasValue() )
883 return;
884
885 try
886 {
887 // create a ui description
888 OUString aDescription = getDescription(aTarget, pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_BACKGROUND);
889
890 std::unique_ptr<weld::TreeIter> xParentEntry;
891
892 Reference< XShape > xTargetShape( pEffect->getTargetShape() );
893 sal_Int32 nGroupId = pEffect->getGroupId();
894
895 // if this effect has the same target and group-id as the last root effect,
896 // the last root effect is also this effects parent
897 if (mxLastParentEntry && nGroupId != -1 && mxLastTargetShape == xTargetShape && mnLastGroupId == nGroupId)
898 xParentEntry = mxTreeView->make_iterator(mxLastParentEntry.get());
899
900 // create an entry for the effect
901 std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
902
903 mxEntries.emplace_back(std::make_unique<CustomAnimationListEntryItem>(aDescription, pEffect));
904
905 OUString sId(weld::toId(mxEntries.back().get()));
906
907 if (xParentEntry)
908 {
909 // add a subentry
910 mxTreeView->insert(xParentEntry.get(), -1, &aDescription, &sId, nullptr, nullptr, false, xEntry.get());
911 }
912 else
913 {
914 // add a root entry
915 mxTreeView->insert(nullptr, -1, &aDescription, &sId, nullptr, nullptr, false, xEntry.get());
916
917 // and the new root entry becomes the possible next group header
918 mxLastTargetShape = xTargetShape;
919 mnLastGroupId = nGroupId;
920 mxLastParentEntry = std::move(xEntry);
921 }
922 }
923 catch (const Exception&)
924 {
925 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationList::append()" );
926 }
927}
928
929static void selectShape(weld::TreeView* pTreeList, const Reference< XShape >& xShape )
930{
931 std::unique_ptr<weld::TreeIter> xEntry = pTreeList->make_iterator();
932 if (!pTreeList->get_iter_first(*xEntry))
933 return;
934
935 bool bFirstEntry = true;
936
937 do
938 {
939 CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(pTreeList->get_id(*xEntry));
940 CustomAnimationEffectPtr pEffect(pEntry->getEffect());
941 if (pEffect)
942 {
943 if (pEffect->getTarget() == xShape)
944 {
945 pTreeList->select(*xEntry);
946 if (bFirstEntry)
947 {
948 pTreeList->scroll_to_row(*xEntry);
949 bFirstEntry = false;
950 }
951 }
952 }
953 } while (pTreeList->iter_next(*xEntry));
954}
955
957{
958 try
959 {
960 mxTreeView->unselect_all();
961
962 if (rSelection.hasValue())
963 {
964 Reference< XIndexAccess > xShapes(rSelection, UNO_QUERY);
965 if( xShapes.is() )
966 {
967 sal_Int32 nCount = xShapes->getCount();
968 sal_Int32 nIndex;
969 for( nIndex = 0; nIndex < nCount; nIndex++ )
970 {
971 Reference< XShape > xShape( xShapes->getByIndex( nIndex ), UNO_QUERY );
972 if( xShape.is() )
973 selectShape(mxTreeView.get(), xShape);
974 }
975 }
976 else
977 {
978 Reference< XShape > xShape(rSelection, UNO_QUERY);
979 if( xShape.is() )
980 selectShape(mxTreeView.get(), xShape);
981 }
982 }
983
984 Select();
985 }
986 catch( Exception& )
987 {
988 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationList::onSelectionChanged()" );
989 }
990}
991
993{
994 Select();
995}
996
997// Notify controller to refresh UI when we are notified of selection change from base class
999{
1000 if( mbIgnorePaint )
1001 return;
1003}
1004
1005IMPL_LINK_NOARG(CustomAnimationList, PostExpandHdl, void*, void)
1006{
1007 std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
1008 if (mxTreeView->get_selected(xEntry.get()))
1009 {
1010 for (bool bChild = mxTreeView->iter_children(*xEntry); bChild; bChild = mxTreeView->iter_next_sibling(*xEntry))
1011 {
1012 if (!mxTreeView->is_selected(*xEntry))
1013 mxTreeView->select(*xEntry);
1014 }
1015 }
1016
1017 // Notify controller that selection has changed (it should update the UI)
1018 mpController->onSelect();
1019
1020 mnPostExpandEvent = nullptr;
1021}
1022
1023IMPL_LINK(CustomAnimationList, ExpandHdl, const weld::TreeIter&, rParent, bool)
1024{
1025 // If expanded entry is selected, then select its children too afterwards.
1026 if (mxTreeView->is_selected(rParent) && !mnPostExpandEvent) {
1027 mnPostExpandEvent = Application::PostUserEvent(LINK(this, CustomAnimationList, PostExpandHdl));
1028 }
1029
1030 return true;
1031}
1032
1033IMPL_LINK_NOARG(CustomAnimationList, PostCollapseHdl, void*, void)
1034{
1035 // Deselect all entries as SvTreeListBox::Collapse selects the last
1036 // entry to have focus (or its parent), which is not desired
1037 mxTreeView->unselect_all();
1038
1039 // Restore selection state for entries which are still visible
1040 for (const auto &pEntry : lastSelectedEntries)
1041 {
1042 if (weld::IsEntryVisible(*mxTreeView, *pEntry))
1043 mxTreeView->select(*pEntry);
1044 }
1045
1046 lastSelectedEntries.clear();
1047
1048 // Notify controller that selection has changed (it should update the UI)
1049 mpController->onSelect();
1050
1051 mnPostCollapseEvent = nullptr;
1052}
1053
1055{
1056 if (!mnPostCollapseEvent)
1057 {
1058 // weld::TreeView::collapse() discards multi-selection state
1059 // of list entries, so first save current selection state
1060 mxTreeView->selected_foreach([this](weld::TreeIter& rEntry){
1061 lastSelectedEntries.emplace_back(mxTreeView->make_iterator(&rEntry));
1062 return false;
1063 });
1064
1065 mnPostCollapseEvent = Application::PostUserEvent(LINK(this, CustomAnimationList, PostCollapseHdl));
1066 }
1067
1068 // Execute collapse on base class
1069 return true;
1070}
1071
1073{
1074 bool bExpanded = true; // we assume expanded by default
1075
1076 std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
1077 if (mxTreeView->get_iter_first(*xEntry))
1078 {
1079 do
1080 {
1082 weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
1083 if (pEntry->getEffect() == pEffect)
1084 {
1085 if (mxTreeView->get_iter_depth(*xEntry)) // no parent, keep expanded default of true
1086 {
1087 std::unique_ptr<weld::TreeIter> xParentEntry = mxTreeView->make_iterator(xEntry.get());
1088 if (mxTreeView->iter_parent(*xParentEntry))
1089 bExpanded = mxTreeView->get_row_expanded(*xParentEntry);
1090 }
1091 break;
1092 }
1093 } while (mxTreeView->iter_next(*xEntry));
1094 }
1095
1096 return bExpanded;
1097}
1098
1100{
1101 std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
1102 if (mxTreeView->get_iter_first(*xEntry))
1103 {
1104 do
1105 {
1106 CustomAnimationListEntryItem* pTestEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
1107 if (pTestEntry->getEffect() == pEffect)
1108 return weld::IsEntryVisible(*mxTreeView, *xEntry);
1109 } while (mxTreeView->iter_next(*xEntry));
1110 }
1111 return true;
1112}
1113
1115{
1116 EffectSequence aSelection;
1117
1118 mxTreeView->selected_foreach([this, &aSelection](weld::TreeIter& rEntry){
1119 CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(rEntry));
1120 CustomAnimationEffectPtr pEffect(pEntry->getEffect());
1121 if (pEffect)
1122 aSelection.push_back(pEffect);
1123
1124 // if the selected effect is not expanded and has children
1125 // we say that the children are automatically selected
1126 if (!mxTreeView->get_row_expanded(rEntry) && mxTreeView->iter_has_child(rEntry))
1127 {
1128 std::unique_ptr<weld::TreeIter> xChild = mxTreeView->make_iterator(&rEntry);
1129 (void)mxTreeView->iter_children(*xChild);
1130
1131 do
1132 {
1133 if (!mxTreeView->is_selected(*xChild))
1134 {
1135 CustomAnimationListEntryItem* pChild = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xChild));
1136 const CustomAnimationEffectPtr& pChildEffect( pChild->getEffect() );
1137 if( pChildEffect )
1138 aSelection.push_back( pChildEffect );
1139 }
1140 } while (mxTreeView->iter_next_sibling(*xChild));
1141 }
1142
1143 return false;
1144 });
1145
1146 return aSelection;
1147}
1148
1150{
1151 mpController->onDoubleClick();
1152 return false;
1153}
1154
1155IMPL_LINK(CustomAnimationList, CommandHdl, const CommandEvent&, rCEvt, bool)
1156{
1157 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1158 return false;
1159
1160 if (rCEvt.IsMouseEvent())
1161 {
1162 ::Point aPos = rCEvt.GetMousePosPixel();
1163 std::unique_ptr<weld::TreeIter> xIter(mxTreeView->make_iterator());
1164 if (mxTreeView->get_dest_row_at_pos(aPos, xIter.get(), false) && !mxTreeView->is_selected(*xIter))
1165 {
1166 mxTreeView->unselect_all();
1167 mxTreeView->set_cursor(*xIter);
1168 mxTreeView->select(*xIter);
1169 SelectHdl(*mxTreeView);
1170 }
1171 }
1172
1173 if (!mxTreeView->get_selected(nullptr))
1174 return false;
1175
1176 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxTreeView.get(), "modules/simpress/ui/effectmenu.ui"));
1177 std::unique_ptr<weld::Menu> xMenu = xBuilder->weld_menu("menu");
1178
1179 sal_Int16 nNodeType = -1;
1180 sal_Int16 nEntries = 0;
1181
1182 mxTreeView->selected_foreach([this, &nNodeType, &nEntries](weld::TreeIter& rEntry){
1183 CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(rEntry));
1184 CustomAnimationEffectPtr pEffect(pEntry->getEffect());
1185
1186 nEntries++;
1187 if (pEffect)
1188 {
1189 if( nNodeType == -1 )
1190 {
1191 nNodeType = pEffect->getNodeType();
1192 }
1193 else
1194 {
1195 if( nNodeType != pEffect->getNodeType() )
1196 {
1197 nNodeType = -1;
1198 return true;
1199 }
1200 }
1201 }
1202
1203 return false;
1204 });
1205
1206 xMenu->set_active("onclick", nNodeType == EffectNodeType::ON_CLICK);
1207 xMenu->set_active("withprev", nNodeType == EffectNodeType::WITH_PREVIOUS);
1208 xMenu->set_active("afterprev", nNodeType == EffectNodeType::AFTER_PREVIOUS);
1209 xMenu->set_sensitive("options", nEntries == 1);
1210 xMenu->set_sensitive("timing", nEntries == 1);
1211
1212 OUString sCommand = xMenu->popup_at_rect(mxTreeView.get(), ::tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
1213 if (!sCommand.isEmpty())
1214 ExecuteContextMenuAction(sCommand);
1215
1216 return true;
1217}
1218
1220{
1221 mpController->onContextMenu(rIdent);
1222}
1223
1225{
1226 update();
1228}
1229
1230}
1231
1232/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
static std::unique_ptr< weld::Builder > CreateBuilder(weld::Widget *pParent, const OUString &rUIFile, bool bMobile=false, sal_uInt64 nLOKWindowId=0)
static void RemoveUserEvent(ImplSVEvent *nUserEvent)
Size GetSizePixel() const
void DrawRect(const tools::Rectangle &rRect)
void SetLineColor()
OUString GetEllipsisString(const OUString &rStr, tools::Long nMaxWidth, DrawTextFlags nStyle=DrawTextFlags::EndEllipsis) const
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
void SetTextColor(const Color &rColor)
void DrawPixel(const Point &rPt)
void DrawImage(const Point &rPos, const Image &rImage, DrawImageFlags nStyle=DrawImageFlags::NONE)
void SetFillColor()
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
tools::Long GetTextHeight() const
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
const AllSettings & GetSettings() const
tools::Long AdjustY(tools::Long nVertMove)
tools::Long AdjustX(tools::Long nHorzMove)
constexpr tools::Long Height() const
void setHeight(tools::Long nHeight)
const Color & GetWindowColor() const
const Color & GetDialogTextColor() const
const Color & GetDialogColor() const
const Color & GetHighlightTextColor() const
CustomAnimationListDropTarget(CustomAnimationList &rTreeView)
virtual sal_Int8 AcceptDrop(const AcceptDropEvent &rEvt) override
virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent &rEvt) override
CustomAnimationListEntryItem(OUString aDescription, CustomAnimationEffectPtr pEffect)
void PaintEffect(vcl::RenderContext &rRenderContext, const ::tools::Rectangle &rRect, bool bSelected)
static const ::tools::Long nItemMinHeight
Size GetSize(const vcl::RenderContext &rRenderContext)
const CustomAnimationEffectPtr & getEffect() const
void PaintTrigger(vcl::RenderContext &rRenderContext, const ::tools::Rectangle &rRect)
void Paint(vcl::RenderContext &rRenderContext, const ::tools::Rectangle &rRect, bool bSelected)
static const ::tools::Long nIconWidth
virtual void notify_change() override
void onSelectionChanged(const css::uno::Any &rSelection)
void select(const CustomAnimationEffectPtr &pEffect)
selects or deselects the given effect.
std::vector< std::unique_ptr< weld::TreeIter > > mDndEffectsSelected
void ExecuteContextMenuAction(const OUString &rSelectedPopupEntry)
bool isVisible(const CustomAnimationEffectPtr &pEffect) const
std::unique_ptr< weld::Label > mxEmptyLabel
sal_Int8 AcceptDrop(const AcceptDropEvent &rEvt)
std::unique_ptr< weld::TreeView > mxTreeView
std::vector< std::unique_ptr< CustomAnimationListEntryItem > > mxEntries
CustomAnimationList(std::unique_ptr< weld::TreeView > xTreeView, std::unique_ptr< weld::Label > xLabel, std::unique_ptr< weld::Widget > xScrolledWindow)
bool isExpanded(const CustomAnimationEffectPtr &pEffect) const
std::unique_ptr< weld::TreeIter > mxLastParentEntry
void append(CustomAnimationEffectPtr pEffect)
appends the given effect to the list
sal_Int8 ExecuteDrop(const ExecuteDropEvent &rEvt)
EffectSequence getSelection() const
std::unique_ptr< weld::TreeIter > mxDndEffectDragging
ICustomAnimationListController * mpController
css::uno::Reference< css::drawing::XShape > mxLastTargetShape
std::unique_ptr< weld::Widget > mxEmptyLabelParent
static const CustomAnimationPresets & getCustomAnimationPresets()
This method gets presets instance, which is localized for the current user's locale.
virtual void onContextMenu(const OUString &rIdent)=0
virtual void onDragNDropComplete(std::vector< CustomAnimationEffectPtr > pEffectsDragged, CustomAnimationEffectPtr pEffectInsertBefore)=0
constexpr tools::Long GetWidth() const
constexpr tools::Long Top() const
constexpr Point TopLeft() const
constexpr tools::Long Right() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
virtual void scroll_to_row(int row)=0
virtual std::unique_ptr< TreeIter > make_iterator(const TreeIter *pOrig=nullptr) const=0
std::tuple< vcl::RenderContext &, const tools::Rectangle &, bool, const OUString & > render_args
virtual bool get_dest_row_at_pos(const Point &rPos, weld::TreeIter *pResult, bool bDnDMode, bool bAutoScroll=true)=0
virtual bool get_iter_first(TreeIter &rIter) const=0
virtual void select(int pos)=0
virtual bool iter_next(TreeIter &rIter) const=0
std::pair< vcl::RenderContext &, const OUString & > get_size_args
virtual OUString get_id(int pos) const=0
int nCount
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
float u
float x
ESelection aNewSelection(GetSelection())
FilterGroup & rTarget
sal_Int32 nIndex
sal_Int64 n
constexpr sal_uInt16 KEY_DELETE
constexpr sal_uInt16 KEY_SPACE
constexpr sal_uInt16 KEY_INSERT
@ Exception
std::list< CustomAnimationEffectPtr > EffectSequence
static void selectShape(weld::TreeView *pTreeList, const Reference< XShape > &xShape)
static OUString getDescription(const Any &rTarget, bool bWithText)
IMPL_LINK_NOARG(MainSequence, onTimerHdl, Timer *, void)
std::shared_ptr< MainSequence > MainSequencePtr
std::shared_ptr< InteractiveSequence > InteractiveSequencePtr
IMPL_STATIC_LINK(CustomAnimationList, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
OUString getShapeDescription(const Reference< XShape > &xShape, bool bWithText)
IMPL_LINK(SdCharHeightPropertyBox, implMenuSelectHdl, const OUString &, rIdent, void)
std::shared_ptr< CustomAnimationEffect > CustomAnimationEffectPtr
static bool getShapeIndex(const Reference< XShapes > &xShapes, const Reference< XShape > &xShape, sal_Int32 &nIndex)
long Long
size_t GetAbsPos(const weld::TreeView &rTreeView, const weld::TreeIter &rIter)
OUString toId(const void *pValue)
bool IsEntryVisible(const weld::TreeView &rTreeView, const weld::TreeIter &rIter)
OUString SdResId(TranslateId aId)
Definition: sdmod.cxx:83
sal_Int8 mnAction
stl_append_effect_func(CustomAnimationList &rList)
void operator()(const CustomAnimationEffectPtr &pEffect)
SvxTableController * mpController
#define DND_ACTION_MOVE
#define DND_ACTION_NONE
signed char sal_Int8
OUString sId