1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2010-09-20
7  * Description : Managing visibility state with animations
8  *
9  * Copyright (C) 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10  * Copyright (C) 2012-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  *
12  * This program is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation;
15  * either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "itemvisibilitycontroller.h"
26 
27 // Qt includes
28 
29 #include <QParallelAnimationGroup>
30 #include <QPropertyAnimation>
31 
32 // Local includes
33 
34 #include "digikam_debug.h"
35 
36 namespace Digikam
37 {
38 
ItemVisibilityControllerPropertyObject(QObject * const parent)39 ItemVisibilityControllerPropertyObject::ItemVisibilityControllerPropertyObject(QObject* const parent)
40     : QObject  (parent),
41       m_opacity(0),
42       m_visible(false)
43 {
44 }
45 
opacity() const46 qreal ItemVisibilityControllerPropertyObject::opacity() const
47 {
48     return m_opacity;
49 }
50 
setOpacity(qreal opacity)51 void ItemVisibilityControllerPropertyObject::setOpacity(qreal opacity)
52 {
53     m_opacity = opacity;
54 
55     emit opacityChanged();
56 }
57 
isVisible() const58 bool ItemVisibilityControllerPropertyObject::isVisible() const
59 {
60     return m_visible;
61 }
62 
setVisible(bool visible)63 void ItemVisibilityControllerPropertyObject::setVisible(bool visible)
64 {
65     m_visible = visible;
66 
67     emit visibleChanged();
68 }
69 
70 // ---------------------------------------------------------------------------------
71 
AnimatedVisibility(QObject * const parent)72 AnimatedVisibility::AnimatedVisibility(QObject* const parent)
73     : ItemVisibilityControllerPropertyObject(parent)
74 {
75     m_controller = new ItemVisibilityController(this);
76     m_controller->addItem(this);
77 }
78 
controller() const79 ItemVisibilityController* AnimatedVisibility::controller() const
80 {
81     return m_controller;
82 }
83 
84 // ---------------------------------------------------------------------------------
85 
HidingStateChanger(QObject * const parent)86 HidingStateChanger::HidingStateChanger(QObject* const parent)
87     : ItemVisibilityController(parent),
88       m_object                (nullptr)
89 {
90     connect(this, SIGNAL(propertiesAssigned(bool)),
91             this, SLOT(slotPropertiesAssigned(bool)));
92 }
93 
HidingStateChanger(QObject * const target,const QByteArray & property,QObject * const parent)94 HidingStateChanger::HidingStateChanger(QObject* const target, const QByteArray& property, QObject* const parent)
95     : ItemVisibilityController(parent)
96 {
97     connect(this, SIGNAL(propertiesAssigned(bool)),
98             this, SLOT(slotPropertiesAssigned(bool)));
99 
100     setTargetObject(target);
101     setPropertyName(property);
102 
103     // here, we assume to start with a visible item
104 
105     setVisible(true);
106 }
107 
setTargetObject(QObject * const object)108 void HidingStateChanger::setTargetObject(QObject* const object)
109 {
110     m_object = object;
111 }
112 
setPropertyName(const QByteArray & propertyName)113 void HidingStateChanger::setPropertyName(const QByteArray& propertyName)
114 {
115     m_property = propertyName;
116 }
117 
changeValue(const QVariant & value)118 void HidingStateChanger::changeValue(const QVariant& value)
119 {
120     m_value = value;
121 
122     if (!hasVisibleItems())
123     {
124         // shortcut
125 
126         slotPropertiesAssigned(false);
127         slotPropertiesAssigned(true);
128     }
129     else
130     {
131         hide();
132     }
133 }
134 
slotPropertiesAssigned(bool visible)135 void HidingStateChanger::slotPropertiesAssigned(bool visible)
136 {
137     if (!visible)
138     {
139         if (m_object)
140         {
141             m_object->setProperty(m_property.constData(), m_value);
142         }
143 
144         emit stateChanged();
145         show();
146     }
147     else
148     {
149         emit finished();
150     }
151 }
152 
153 // ---------------------------------------------------------------------------------
154 
155 class Q_DECL_HIDDEN AnimationControl
156 {
157 public:
158 
159     enum Situation
160     {
161         MainControl,
162         IndependentControl,
163         RemovingControl
164     };
165 
166 public:
167 
168     explicit AnimationControl(ItemVisibilityController* const q);
169     AnimationControl(AnimationControl* const other, QObject* const item);
170     ~AnimationControl();
171 
172     void clear();
173 
174     void addItem(QAbstractAnimation* const animation, QObject* const item);
175     QAbstractAnimation* takeItem(QObject* const item);
176     void moveTo(AnimationControl* const other, QObject* const item);
177     void moveAllTo(AnimationControl* const other);
178 
179     bool hasItem(QObject* const o) const;
180     bool hasVisibleItems(ItemVisibilityController::IncludeFadingOutMode mode) const;
181 
182     void transitionToVisible(bool show, bool immediately = false);
183     void animationFinished();
184 
185     void syncProperties(QObject* const o);
186     void connect(QObject* const item);
187     void disconnect(QObject* const item);
188 
189     void setEasingCurve(const QEasingCurve& easing);
190     void setAnimationDuration(int msecs);
191 
192 public:
193 
194     QList<QObject*>                 m_items;
195     QAbstractAnimation*             m_animation;
196     ItemVisibilityController::State m_state;
197     Situation                       m_situation;
198 
199 private:
200 
201     void setVisibleProperty(bool value);
202     void connect(QAbstractAnimation* const anim);
203     void disconnect(QAbstractAnimation* const anim);
204     void moveToGroup();
205 
206 private:
207 
208     QParallelAnimationGroup*        m_animationGroup;
209     ItemVisibilityController* const m_q;
210 };
211 
AnimationControl(ItemVisibilityController * const q)212 AnimationControl::AnimationControl(ItemVisibilityController* const q)
213     : m_animation     (nullptr),
214       m_state         (ItemVisibilityController::Hidden),
215       m_situation     (MainControl),
216       m_animationGroup(nullptr),
217       m_q             (q)
218 {
219 }
220 
AnimationControl(AnimationControl * const other,QObject * const object)221 AnimationControl::AnimationControl(AnimationControl* const other, QObject* const object)
222     : m_animation     (nullptr),
223       m_state         (other->m_state),
224       m_situation     (IndependentControl),
225       m_animationGroup(nullptr),
226       m_q             (other->m_q)
227 {
228     other->moveTo(this, object);
229 }
230 
~AnimationControl()231 AnimationControl::~AnimationControl()
232 {
233     clear();
234     delete m_animation;
235 }
236 
clear()237 void AnimationControl::clear()
238 {
239     m_state = ItemVisibilityController::Hidden;
240 
241     if (m_animation)
242     {
243         disconnect(m_animation);
244     }
245 
246     delete m_animation;
247     m_animation      = nullptr;
248     m_animationGroup = nullptr; // the same pointer as animation
249 
250     foreach (QObject* const item, m_items)
251     {
252         disconnect(item);
253     }
254 
255     m_items.clear();
256 }
257 
connect(QObject * const item)258 void AnimationControl::connect(QObject* const item)
259 {
260     m_q->connect(item, SIGNAL(destroyed(QObject*)),
261                  m_q, SLOT(objectDestroyed(QObject*)));
262 }
263 
disconnect(QObject * const item)264 void AnimationControl::disconnect(QObject* const item)
265 {
266     m_q->disconnect(item, SIGNAL(destroyed(QObject*)),
267                     m_q, SLOT(objectDestroyed(QObject*)));
268 }
269 
connect(QAbstractAnimation * const anim)270 void AnimationControl::connect(QAbstractAnimation* const anim)
271 {
272     m_q->connect(anim, SIGNAL(finished()),
273                  m_q, SLOT(animationFinished()));
274 }
275 
disconnect(QAbstractAnimation * const anim)276 void AnimationControl::disconnect(QAbstractAnimation* const anim)
277 {
278     m_q->disconnect(anim, SIGNAL(finished()),
279                     m_q, SLOT(animationFinished()));
280 }
281 
moveToGroup()282 void AnimationControl::moveToGroup()
283 {
284     if (!m_animationGroup)
285     {
286         m_animationGroup = new QParallelAnimationGroup;
287         connect(m_animationGroup);
288 
289         if (m_animation)
290         {
291             disconnect(m_animation);
292             m_animationGroup->addAnimation(m_animation);
293         }
294 
295         m_animation = m_animationGroup;
296     }
297 }
298 
addItem(QAbstractAnimation * const anim,QObject * const item)299 void AnimationControl::addItem(QAbstractAnimation* const anim, QObject* const item)
300 {
301     // Either there is no group but now for the first time two items,
302     // or the control got empty intermittently, but still has the group installed
303 
304     if (!m_items.isEmpty() || m_animationGroup)
305     {
306         moveToGroup();
307         m_animationGroup->addAnimation(anim);
308     }
309     else
310     {
311         connect(anim);
312         m_animation = anim;
313     }
314 
315     m_items << item;
316 }
317 
takeItem(QObject * const item)318 QAbstractAnimation* AnimationControl::takeItem(QObject* const item)
319 {
320     int index = m_items.indexOf(item);
321 
322     if (index == -1)
323     {
324         return nullptr;
325     }
326 
327     m_items.removeAt(index);
328 
329     if (m_animationGroup)
330     {
331         return m_animationGroup->takeAnimation(index);
332     }
333     else
334     {
335         QAbstractAnimation* const anim = m_animation;
336         disconnect(m_animation);
337         m_animation = nullptr;
338         return anim;
339     }
340 }
341 
moveTo(AnimationControl * const other,QObject * const item)342 void AnimationControl::moveTo(AnimationControl* const other, QObject* const item)
343 {
344     QAbstractAnimation* const anim = takeItem(item);
345 
346     if (anim)
347     {
348         other->addItem(anim, item);
349     }
350 }
351 
moveAllTo(AnimationControl * const other)352 void AnimationControl::moveAllTo(AnimationControl* const other)
353 {
354     foreach (QObject* const item, m_items)
355     {
356         moveTo(other, item);
357     }
358 }
359 
hasItem(QObject * const o) const360 bool AnimationControl::hasItem(QObject* const o) const
361 {
362     return m_items.contains(o);
363 }
364 
hasVisibleItems(ItemVisibilityController::IncludeFadingOutMode mode) const365 bool AnimationControl::hasVisibleItems(ItemVisibilityController::IncludeFadingOutMode mode) const
366 {
367     if (m_items.isEmpty())
368     {
369         return false;
370     }
371 
372     if (mode == ItemVisibilityController::IncludeFadingOut)
373     {
374         return (m_state != ItemVisibilityController::Hidden);
375     }
376     else
377     {
378         return ((m_state != ItemVisibilityController::Hidden) && (m_state != ItemVisibilityController::FadingOut));
379     }
380 }
381 
setVisibleProperty(bool value)382 void AnimationControl::setVisibleProperty(bool value)
383 {
384     foreach (QObject* const o, m_items)
385     {
386         o->setProperty("visible", value);
387     }
388 }
389 
syncProperties(QObject * const o)390 void AnimationControl::syncProperties(QObject* const o)
391 {
392     if (m_state == ItemVisibilityController::Visible || m_state == ItemVisibilityController::FadingIn)
393     {
394         o->setProperty("visible", true);
395         o->setProperty("opacity", 1.0);
396     }
397     else
398     {
399         o->setProperty("visible", false);
400         o->setProperty("opacity", 0);
401     }
402 }
403 
transitionToVisible(bool show,bool immediately)404 void AnimationControl::transitionToVisible(bool show, bool immediately)
405 {
406     //qCDebug(DIGIKAM_WIDGETS_LOG) << "state" << state << "show" << show << items.size();
407 
408     if (show)
409     {
410         if ((m_state == ItemVisibilityController::Visible) || (m_state == ItemVisibilityController::FadingIn))
411         {
412             return;
413         }
414 
415         if (m_state == ItemVisibilityController::Hidden)
416         {
417             setVisibleProperty(true);
418         }
419 
420         m_state = ItemVisibilityController::FadingIn;
421     }
422     else
423     {
424         if ((m_state == ItemVisibilityController::Hidden) || (m_state == ItemVisibilityController::FadingOut))
425         {
426             return;
427         }
428 
429         m_state = ItemVisibilityController::FadingOut;
430     }
431 
432     if (m_animation)
433     {
434         QAbstractAnimation::Direction direction = show ? QAbstractAnimation::Forward
435                                                        : QAbstractAnimation::Backward;
436         m_animation->setDirection(direction);
437 
438         if (immediately)
439         {
440             m_animation->setCurrentTime(show ? m_animation->totalDuration() : 0);
441         }
442 
443         m_animation->start();
444     }
445 }
446 
animationFinished()447 void AnimationControl::animationFinished()
448 {
449     if      (m_state == ItemVisibilityController::FadingOut)
450     {
451         setVisibleProperty(false);
452         m_state = ItemVisibilityController::Hidden;
453     }
454     else if (m_state == ItemVisibilityController::FadingIn)
455     {
456         m_state = ItemVisibilityController::Visible;
457     }
458 }
459 
setEasingCurve(const QEasingCurve & easing)460 void AnimationControl::setEasingCurve(const QEasingCurve& easing)
461 {
462     if      (m_animationGroup)
463     {
464         for (int i = 0 ; i < m_animationGroup->animationCount() ; ++i)
465         {
466             QVariantAnimation* const anim = static_cast<QVariantAnimation*>(m_animationGroup->animationAt(i));
467 
468             if (anim)
469             {
470                 anim->setEasingCurve(easing);
471             }
472         }
473     }
474     else if (m_animation)
475     {
476         QVariantAnimation* const anim = static_cast<QVariantAnimation*>(m_animation);
477 
478         if (anim)
479         {
480             anim->setEasingCurve(easing);
481         }
482     }
483 }
484 
setAnimationDuration(int msecs)485 void AnimationControl::setAnimationDuration(int msecs)
486 {
487     if      (m_animationGroup)
488     {
489         for (int i = 0 ; i < m_animationGroup->animationCount() ; ++i)
490         {
491             QVariantAnimation* const anim = static_cast<QVariantAnimation*>(m_animationGroup->animationAt(i));
492 
493             if (anim)
494             {
495                 anim->setDuration(msecs);
496             }
497         }
498     }
499     else if (m_animation)
500     {
501         QVariantAnimation* const anim = static_cast<QVariantAnimation*>(m_animation);
502 
503         if (anim)
504         {
505             anim->setDuration(msecs);
506         }
507     }
508 }
509 
510 // ---------------------------------------------------------------------------------
511 
512 class Q_DECL_HIDDEN ItemVisibilityController::Private
513 {
514 public:
515 
Private(ItemVisibilityController * const qq)516     explicit Private(ItemVisibilityController* const qq)
517         : visible          (false),
518           shallBeShown     (true),
519           itemShallBeShown (nullptr),
520           animationDuration(75),
521           easingCurve      (QEasingCurve::InOutQuad),
522           control          (nullptr),
523           q                (qq)
524     {
525     }
526 
527 public:
528 
529     void              setVisible(bool v, bool immediately);
530     void              setItemVisible(QObject* const item, bool visible, bool immediately);
531 
532     AnimationControl* findInChildren(QObject* const item) const;
533     AnimationControl* getChild(QObject* const item);
534     void              cleanupChildren(QAbstractAnimation* const finishedAnimation);
535 
536 public:
537 
538     bool                            visible;
539     bool                            shallBeShown;
540     QObject*                        itemShallBeShown;
541 
542     int                             animationDuration;
543     QEasingCurve                    easingCurve;
544 
545     AnimationControl*               control;
546     QList<AnimationControl*>        childControls;
547     ItemVisibilityController* const q;
548 };
549 
findInChildren(QObject * const item) const550 AnimationControl* ItemVisibilityController::Private::findInChildren(QObject* const item) const
551 {
552     foreach (AnimationControl* const child, childControls)
553     {
554         if (child->hasItem(item))
555         {
556             return child;
557         }
558     }
559 
560     return nullptr;
561 }
562 
getChild(QObject * const item)563 AnimationControl* ItemVisibilityController::Private::getChild(QObject* const item)
564 {
565     if (!control)
566     {
567         return nullptr;
568     }
569 
570     if (control->hasItem(item))
571     {
572         AnimationControl* const child = new AnimationControl(control, item);
573         childControls << child;
574 
575         return child;
576     }
577     else
578     {
579         return findInChildren(item);
580     }
581 }
582 
cleanupChildren(QAbstractAnimation * const finishedAnimation)583 void ItemVisibilityController::Private::cleanupChildren(QAbstractAnimation* const finishedAnimation)
584 {
585     QList<AnimationControl*>::iterator it;
586 
587     for (it = childControls.begin() ; it != childControls.end() ; )
588     {
589         AnimationControl* child = *it;
590 
591         if      ((child->m_state == control->m_state) && (child->m_situation == AnimationControl::IndependentControl))
592         {
593             // merge back to main control
594 
595             child->moveAllTo(control);
596             delete child;
597             it = childControls.erase(it);
598         }
599         else if ((child->m_animation == finishedAnimation) && (child->m_situation == AnimationControl::RemovingControl))
600         {
601             foreach (QObject* const item, child->m_items)
602             {
603                 emit q->hiddenAndRemoved(item);
604             }
605 
606             delete child;
607             it = childControls.erase(it);
608         }
609         else
610         {
611             ++it;
612         }
613     }
614 }
615 
setVisible(bool v,bool immediately)616 void ItemVisibilityController::Private::setVisible(bool v, bool immediately)
617 {
618     // no check d->visible == visible
619 
620     visible = v;
621 
622     if (control)
623     {
624         control->transitionToVisible(shallBeShown && visible, immediately);
625     }
626 
627     foreach (AnimationControl* const child, childControls)
628     {
629         if (child->m_situation == AnimationControl::IndependentControl)
630         {
631             child->transitionToVisible(shallBeShown && visible, immediately);
632         }
633     }
634 
635     if (itemShallBeShown)
636     {
637         setItemVisible(itemShallBeShown, visible, immediately);
638     }
639 }
640 
setItemVisible(QObject * const item,bool visible,bool immediately)641 void ItemVisibilityController::Private::setItemVisible(QObject* const item, bool visible, bool immediately)
642 {
643     AnimationControl* const child = getChild(item);
644 
645     if (child)
646     {
647         child->transitionToVisible(visible, immediately);
648     }
649 }
650 
651 // ---------------------------------------------------------------------------------
652 
ItemVisibilityController(QObject * const parent)653 ItemVisibilityController::ItemVisibilityController(QObject* const parent)
654     : QObject(parent),
655       d      (new Private(this))
656 {
657 }
658 
~ItemVisibilityController()659 ItemVisibilityController::~ItemVisibilityController()
660 {
661     clear();
662     delete d->control;
663     delete d;
664 }
665 
createAnimation(QObject *)666 QPropertyAnimation* ItemVisibilityController::createAnimation(QObject*)
667 {
668     QPropertyAnimation* const anim = new QPropertyAnimation(this);
669     anim->setPropertyName("opacity");
670     anim->setStartValue(0);
671     anim->setEndValue(1.0);
672     anim->setDuration(d->animationDuration);
673     anim->setEasingCurve(d->easingCurve);
674 
675     return anim;
676 }
677 
addItem(QObject * item)678 void ItemVisibilityController::addItem(QObject* item)
679 {
680     if (!item)
681     {
682         return;
683     }
684 
685     if (!d->control)
686     {
687         // initialize main control
688 
689         d->control = new AnimationControl(this);
690         d->control->transitionToVisible(d->shallBeShown && d->visible);
691     }
692 
693     QPropertyAnimation* const anim = createAnimation(item);
694     anim->setTargetObject(item);
695     d->control->connect(item);
696     d->control->syncProperties(item);
697     d->control->addItem(anim, item);
698 }
699 
removeItem(QObject * item)700 void ItemVisibilityController::removeItem(QObject* item)
701 {
702     if (!item || !d->control)
703     {
704         return;
705     }
706 
707     if (d->control->hasItem(item))
708     {
709         d->control->disconnect(item);
710         delete d->control->takeItem(item);
711     }
712     else
713     {
714         AnimationControl* child = d->findInChildren(item);
715 
716         if (child)
717         {
718             child->disconnect(item);
719             d->childControls.removeOne(child);
720             delete child;
721         }
722     }
723 }
724 
clear()725 void ItemVisibilityController::clear()
726 {
727     if (d->control)
728     {
729         d->control->clear();
730     }
731 
732     foreach (AnimationControl* const child, d->childControls)
733     {
734         child->clear();
735     }
736 
737     d->childControls.clear();
738 
739     d->visible = false;
740 }
741 
items() const742 QList<QObject*> ItemVisibilityController::items() const
743 {
744     QList<QObject*> items;
745 
746     if (d->control)
747     {
748         items = d->control->m_items;
749     }
750 
751     foreach (AnimationControl* const child, d->childControls)
752     {
753         items += child->m_items;
754     }
755 
756     return items;
757 }
758 
visibleItems(IncludeFadingOutMode mode) const759 QList<QObject*> ItemVisibilityController::visibleItems(IncludeFadingOutMode mode) const
760 {
761     QList<QObject*> items;
762 
763     if (d->control && d->control->hasVisibleItems(mode))
764     {
765         items = d->control->m_items;
766     }
767 
768     foreach (AnimationControl* const child, d->childControls)
769     {
770         if (child->hasVisibleItems(mode))
771         {
772             items += child->m_items;
773         }
774     }
775 
776     return items;
777 }
778 
shallBeShown() const779 bool ItemVisibilityController::shallBeShown() const
780 {
781     return d->shallBeShown;
782 }
783 
isVisible() const784 bool ItemVisibilityController::isVisible() const
785 {
786     return d->visible;
787 }
788 
state() const789 ItemVisibilityController::State ItemVisibilityController::state() const
790 {
791     return (d->control ? d->control->m_state : Hidden);
792 }
793 
hasVisibleItems(IncludeFadingOutMode mode) const794 bool ItemVisibilityController::hasVisibleItems(IncludeFadingOutMode mode) const
795 {
796     if (d->control && d->control->hasVisibleItems(mode))
797     {
798         return true;
799     }
800 
801     foreach (AnimationControl* const child, d->childControls)
802     {
803         if (child->hasVisibleItems(mode))
804         {
805             return true;
806         }
807     }
808 
809     return false;
810 }
811 
setEasingCurve(const QEasingCurve & easing)812 void ItemVisibilityController::setEasingCurve(const QEasingCurve& easing)
813 {
814     d->easingCurve = easing;
815 
816     if (d->control)
817     {
818         d->control->setEasingCurve(easing);
819     }
820 
821     foreach (AnimationControl* const child, d->childControls)
822     {
823         child->setEasingCurve(easing);
824     }
825 }
826 
setAnimationDuration(int msecs)827 void ItemVisibilityController::setAnimationDuration(int msecs)
828 {
829     d->animationDuration = msecs;
830 
831     if (d->control)
832     {
833         d->control->setAnimationDuration(msecs);
834     }
835 
836     foreach (AnimationControl* const child, d->childControls)
837     {
838         child->setAnimationDuration(msecs);
839     }
840 }
841 
setShallBeShown(bool shallBeShown)842 void ItemVisibilityController::setShallBeShown(bool shallBeShown)
843 {
844     // no check d->shallBeShown == shallBeShown
845 
846     d->shallBeShown     = shallBeShown;
847     d->itemShallBeShown = nullptr;
848 
849     // apply
850 
851     setVisible(d->visible);
852 }
853 
setShallBeShownDirectly(bool shallBeShown)854 void ItemVisibilityController::setShallBeShownDirectly(bool shallBeShown)
855 {
856     // no check d->shallBeShown == shallBeShown
857 
858     d->shallBeShown     = shallBeShown;
859     d->itemShallBeShown = nullptr;
860 
861     // apply
862 
863     setDirectlyVisible(d->visible);
864 }
865 
setItemThatShallBeShown(QObject * item)866 void ItemVisibilityController::setItemThatShallBeShown(QObject* item)
867 {
868     d->itemShallBeShown = item;
869     d->shallBeShown     = false;
870     setVisible(d->visible);
871 }
872 
show()873 void ItemVisibilityController::show()
874 {
875     setVisible(true);
876 }
877 
hide()878 void ItemVisibilityController::hide()
879 {
880     setVisible(false);
881 }
882 
setVisible(bool visible)883 void ItemVisibilityController::setVisible(bool visible)
884 {
885     d->setVisible(visible, false);
886 }
887 
setDirectlyVisible(bool visible)888 void ItemVisibilityController::setDirectlyVisible(bool visible)
889 {
890     d->setVisible(visible, true);
891 }
892 
showItem(QObject * item)893 void ItemVisibilityController::showItem(QObject* item)
894 {
895     setItemVisible(item, true);
896 }
897 
hideItem(QObject * item)898 void ItemVisibilityController::hideItem(QObject* item)
899 {
900     setItemVisible(item, false);
901 }
902 
setItemVisible(QObject * item,bool visible)903 void ItemVisibilityController::setItemVisible(QObject* item, bool visible)
904 {
905     d->setItemVisible(item, visible, false);
906 }
907 
setItemDirectlyVisible(QObject * item,bool visible)908 void ItemVisibilityController::setItemDirectlyVisible(QObject* item, bool visible)
909 {
910     d->setItemVisible(item, visible, true);
911 }
912 
hideAndRemoveItem(QObject * item)913 void ItemVisibilityController::hideAndRemoveItem(QObject* item)
914 {
915     AnimationControl* const child = d->getChild(item);
916 
917     if (child)
918     {
919         child->m_situation = AnimationControl::RemovingControl;
920         child->transitionToVisible(false);
921     }
922 }
923 
animationFinished()924 void ItemVisibilityController::animationFinished()
925 {
926     QAbstractAnimation* const animation = static_cast<QAbstractAnimation*>(sender());
927 
928     if (d->control && (d->control->m_animation == animation))
929     {
930         d->control->animationFinished();
931         emit propertiesAssigned(d->control->m_state == Visible);
932     }
933 
934     foreach (AnimationControl* const child, d->childControls)
935     {
936         if (child->m_animation == animation)
937         {
938             child->animationFinished();
939 
940             foreach (QObject* const item, child->m_items)
941             {
942                 if (d->control)
943                 {
944                     emit propertiesAssigned(item, (d->control->m_state == Visible));
945                 }
946             }
947         }
948     }
949 
950     // if a child is now in main state, move again to main control
951 
952     d->cleanupChildren(animation);
953 }
954 
objectDestroyed(QObject * item)955 void ItemVisibilityController::objectDestroyed(QObject* item)
956 {
957     removeItem(item);
958 }
959 
960 } // namespace Digikam
961