File indexing completed on 2025-04-27 03:58:24

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2010-09-20
0007  * Description : Managing visibility state with animations
0008  *
0009  * SPDX-FileCopyrightText: 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #ifndef DIGIKAM_ITEM_VISIBILITY_CONTROLLER_H
0017 #define DIGIKAM_ITEM_VISIBILITY_CONTROLLER_H
0018 
0019 // Qt includes
0020 
0021 #include <QAbstractAnimation>
0022 #include <QVariant>
0023 
0024 // Local includes
0025 
0026 #include "digikam_export.h"
0027 
0028 class QEasingCurve;
0029 class QPropertyAnimation;
0030 
0031 namespace Digikam
0032 {
0033 
0034 class DIGIKAM_EXPORT ItemVisibilityController : public QObject
0035 {
0036     Q_OBJECT
0037     Q_PROPERTY(bool  shallBeShown READ shallBeShown WRITE setShallBeShown)
0038     Q_PROPERTY(bool  visible      READ isVisible    WRITE setVisible)
0039 
0040 public:
0041 
0042     /**
0043      *  This class handles complex visibility situations for items.
0044      *  There is a 3-tiered approach:
0045      *  1) shallBeShown determines if the items shall at any time be shown.
0046      *     If it is false, items will never be shown.
0047      *     Default is true, so you can ignore this setting.
0048      *  2) visible determines if the items shall be shown now.
0049      *     Only takes effect if shallBeShown is true.
0050      *     Default is false: Initially, controlled items are hidden.
0051      *  3) Opacity and individual item visibility:
0052      *     When showing, items are first set to individually visible,
0053      *     then their opacity is increased from 0 to 1.
0054      *     When hiding, opacity is first decreased from 1 to 0,
0055      *     then they are set individually to hidden.
0056      *  Different types of items can be handled:
0057      *  - a group of items with an "opacity" and "visible" property
0058      *  - a single item with an "opacity" and "visible" property
0059      *  - a proxy object with these properties (see above)
0060      */
0061 
0062     enum State
0063     {
0064         Hidden,
0065         FadingIn,
0066         Visible,
0067         FadingOut
0068     };
0069     Q_ENUM(State)
0070 
0071     enum IncludeFadingOutMode
0072     {
0073         /// In addition to items visible or fading in, return those fading out
0074         IncludeFadingOut,
0075 
0076         /// Do not return those items currently fading out (soon to be hidden)
0077         ExcludeFadingOut
0078     };
0079 
0080 public:
0081 
0082     explicit ItemVisibilityController(QObject* const parent = nullptr);
0083     ~ItemVisibilityController() override;
0084 
0085     bool  shallBeShown()                                                        const;
0086     bool  isVisible()                                                           const;
0087     State state()                                                               const;
0088 
0089     /**
0090      *  This returns the "result" of isVisible and shallBeShown:
0091      *  Something is indeed visible on the scene.
0092      *  Also returns false if no items are available.
0093      */
0094     bool  hasVisibleItems(IncludeFadingOutMode mode = IncludeFadingOut)         const;
0095 
0096     /**
0097      * Remove all animations
0098      */
0099     void clear();
0100 
0101     /**
0102      * Add and remove objects. The given objects shall provide
0103      * an "opacity" and a "visible" property.
0104      * You can, for convenience, use a ItemVisibilityControllerPropertyObject
0105      * as a value container, if your items do not provide these properties directly.
0106      * No ownership is taken, so the objects should live as long as this object
0107      * is used.
0108      */
0109     void addItem(QObject* object);
0110     void removeItem(QObject* object);
0111 
0112     /**
0113      * Returns all items under control
0114      */
0115     QList<QObject*> items()                                                     const;
0116 
0117     /**
0118      * Returns all currently visible items.
0119      */
0120     QList<QObject*> visibleItems(IncludeFadingOutMode mode = IncludeFadingOut)  const;
0121 
0122     /**
0123      * Allows to change the default parameters of all animations.
0124      */
0125     void setEasingCurve(const QEasingCurve& easing);
0126     void setAnimationDuration(int msecs);
0127 
0128 Q_SIGNALS:
0129 
0130     /**
0131      * Emitted when the (main) transition has finished
0132      */
0133     void propertiesAssigned(bool visible);
0134 
0135     /**
0136      * Emitted when a transition for a single item finished
0137      * (see setItemVisible())
0138      */
0139     void propertiesAssigned(QObject* item, bool visible);
0140 
0141     /**
0142      * Emitted when hideAndRemoveItem has finished
0143      */
0144     void hiddenAndRemoved(QObject* item);
0145 
0146 public Q_SLOTS:
0147 
0148     /**
0149      * Adjusts the first condition - the items are shown if shallBeShown is true and isVisible is true
0150      */
0151     void setShallBeShown(bool shallBeShown);
0152     void setShallBeShownDirectly(bool shallBeShown);
0153 
0154     /**
0155      * Sets a single item to be shown. Calling setVisible() will effectively
0156      * effect only this single item, as if calling setItemVisible().
0157      * Reset by calling with 0 or setShallBeShown().
0158      */
0159     void setItemThatShallBeShown(QObject* item);
0160 
0161     /**
0162      * Adjusts the main condition.
0163      * All items are affected.
0164      * If any items were shown or hidden separately, they will be resynchronized.
0165      * "Directly" means no animation is employed.
0166      */
0167     void show();
0168     void hide();
0169     void setVisible(bool visible);
0170     void setDirectlyVisible(bool visible);
0171 
0172     /**
0173      * Shows or hides a single item.
0174      * The item's status is changed individually.
0175      * The next call to the "global" method will take precedence again.
0176      * "Directly" means no animation is employed.
0177      */
0178     void showItem(QObject* item);
0179     void hideItem(QObject* item);
0180     void setItemVisible(QObject* item, bool visible);
0181     void setItemDirectlyVisible(QObject* item, bool visible);
0182 
0183     /**
0184      * Hide the item, and then remove it.
0185      * When finished, hiddenAndRemoved() is emitted.
0186      */
0187     void hideAndRemoveItem(QObject* item);
0188 
0189 protected:
0190 
0191     /**
0192      * Creates the animation for showing and hiding the given item.
0193      * The item is given for information only, you do not need to use it.
0194      * The default implementation creates and animation for "opacity"
0195      * from 0.0 to 1.0, using default easing curve and duration,
0196      * which can and will be changed by setEasingCurve and setAnimationDuration.
0197      */
0198     virtual QPropertyAnimation* createAnimation(QObject* item);
0199 
0200 protected Q_SLOTS:
0201 
0202     void animationFinished();
0203     void objectDestroyed(QObject*);
0204 
0205 private:
0206 
0207     class Private;
0208     Private* const d;
0209 };
0210 
0211 // ------------------------------------------------------------------------------------------
0212 
0213 class DIGIKAM_EXPORT ItemVisibilityControllerPropertyObject : public QObject
0214 {
0215     Q_OBJECT
0216     Q_PROPERTY(qreal opacity READ opacity   WRITE setOpacity NOTIFY opacityChanged)
0217     Q_PROPERTY(bool  visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
0218 
0219 public:
0220 
0221     /**
0222      *  You can use this object as a container providing the properties
0223      *  set by ItemVisibilityController.
0224      *  Connect to the signals accordingly, e.g. to trigger a repaint.
0225      */
0226 
0227     explicit ItemVisibilityControllerPropertyObject(QObject* const parent = nullptr);
0228 
0229     qreal opacity()                 const;
0230     void setOpacity(qreal opacity);
0231 
0232     bool isVisible()                const;
0233     void setVisible(bool visible);
0234 
0235 Q_SIGNALS:
0236 
0237     void opacityChanged();
0238     void visibleChanged();
0239 
0240 protected:
0241 
0242     qreal m_opacity;
0243     bool  m_visible;
0244 };
0245 
0246 // ------------------------------------------------------------------------------------------
0247 
0248 class DIGIKAM_EXPORT AnimatedVisibility : public ItemVisibilityControllerPropertyObject
0249 {
0250     Q_OBJECT
0251 
0252 public:
0253 
0254     /** A convenience class:
0255      *  The property object brings its own controller.
0256      *  Ready to use: Just construct an object and connect to the signals.
0257      *  Please note the difference between controller()->setVisible() and setVisible():
0258      *  You want to call the controller's method!
0259      */
0260 
0261     explicit AnimatedVisibility(QObject* const parent = nullptr);
0262 
0263     ItemVisibilityController* controller() const;
0264 
0265 protected:
0266 
0267     ItemVisibilityController* m_controller;
0268 };
0269 
0270 // ------------------------------------------------------------------------------------------
0271 
0272 class DIGIKAM_EXPORT HidingStateChanger : public ItemVisibilityController
0273 {
0274     Q_OBJECT
0275 
0276 public:
0277 
0278     /**
0279      * This class provides a state change while fading in and out:
0280      * When changeValue is called, first the items are hidden,
0281      * when this is finished, the property is assigned to the object.
0282      * Afterwards, the items are shown again.
0283      * Note that the targetObject is not necessarily a controlled item!
0284      */
0285 
0286     explicit HidingStateChanger(QObject* const parent = nullptr);
0287 
0288     /**
0289      * Convenience constructor: Sets target and property name
0290      */
0291     HidingStateChanger(QObject* const target, const QByteArray& property, QObject* const parent = nullptr);
0292 
0293     void setTargetObject(QObject* const object);
0294     void setPropertyName(const QByteArray& propertyName);
0295 
0296 public Q_SLOTS:
0297 
0298     void changeValue(const QVariant& value);
0299 
0300 Q_SIGNALS:
0301 
0302     /**
0303      * Emitted when the items were hidden and the target object's property changed
0304      */
0305     void stateChanged();
0306 
0307     /**
0308      * Emitted when the items were hidden, the target object's property changed, and the items shown again
0309      */
0310     void finished();
0311 
0312 protected Q_SLOTS:
0313 
0314     void slotPropertiesAssigned(bool);
0315 
0316 protected:
0317 
0318     QObject*   m_object;
0319     QByteArray m_property;
0320     QVariant   m_value;
0321 };
0322 
0323 } // namespace Digikam
0324 
0325 #endif // DIGIKAM_ITEM_VISIBILITY_CONTROLLER_H