File indexing completed on 2024-05-12 05:34:35

0001 #ifndef oxygenmenustatedata_h
0002 #define oxygenmenustatedata_h
0003 /*
0004 * this file is part of the oxygen gtk engine
0005 * SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0006 *
0007 * SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "../oxygenanimationdata.h"
0011 #include "../oxygenanimationmodes.h"
0012 #include "../oxygengtkutils.h"
0013 #include "oxygenfollowmousedata.h"
0014 #include "oxygensignal.h"
0015 #include "oxygentimer.h"
0016 #include "oxygentimeline.h"
0017 
0018 #include <gtk/gtk.h>
0019 
0020 #include <map>
0021 
0022 namespace Oxygen
0023 {
0024     //! handles menu items animations
0025     class MenuStateData: public FollowMouseData
0026     {
0027 
0028         public:
0029 
0030         //! constructor
0031         MenuStateData( void ):
0032             _target( 0L ),
0033             _dirtyRect( Gtk::gdk_rectangle() ),
0034             _xPadding(0),
0035             _yPadding(0)
0036             {}
0037 
0038         //! destructor
0039         virtual ~MenuStateData( void )
0040         { disconnect( _target ); }
0041 
0042         //! setup connections
0043         using FollowMouseData::connect;
0044         virtual void connect( GtkWidget* );
0045 
0046         //! disconnect
0047         using FollowMouseData::disconnect;
0048         virtual void disconnect( GtkWidget* );
0049 
0050         //!@name modifiers
0051         //@{
0052 
0053         //! enable state
0054         void setEnabled( bool value )
0055         {
0056 
0057             // base class
0058             FollowMouseData::setEnabled( value );
0059 
0060             _current._timeLine.setEnabled( value );
0061             _previous._timeLine.setEnabled( value );
0062 
0063             if( !value )
0064             {
0065                 _current.clear();
0066                 _previous.clear();
0067             }
0068 
0069         }
0070 
0071         //! duration
0072         void setDuration( int value )
0073         {
0074             _current._timeLine.setDuration( value );
0075             _previous._timeLine.setDuration( value );
0076         }
0077 
0078         //@}
0079 
0080         //!@name accessors
0081         //@{
0082 
0083         //! true if animated
0084         bool isAnimated( void ) const
0085         { return isAnimated( AnimationCurrent ) || isAnimated( AnimationPrevious ); }
0086 
0087         //! true if given animation type is animated
0088         bool isAnimated( const WidgetType& type ) const
0089         { return data( type )._timeLine.isRunning(); }
0090 
0091         //! widget for current animation type
0092         GtkWidget* widget( const WidgetType& type ) const
0093         { return data( type )._widget; }
0094 
0095         //! rect for given animation type
0096         const GdkRectangle& rectangle( const WidgetType& type ) const
0097         { return data( type )._rect; }
0098 
0099         //! animation data
0100         AnimationData animationData( const WidgetType& type ) const
0101         {
0102             const Data& data( this->data( type ) );
0103             return data._timeLine.isRunning() ?
0104                 AnimationData( data._timeLine.value(), AnimationHover ):
0105                 AnimationData();
0106         }
0107 
0108         //! true when fade out animation is locked (delayed)
0109         virtual bool isLocked( void ) const
0110         { return _timer.isRunning(); }
0111 
0112         //@}
0113 
0114         protected:
0115 
0116         //! register child
0117         void registerChild( GtkWidget* );
0118 
0119         //! disconnect child
0120         void unregisterChild( GtkWidget* );
0121 
0122         //! update items
0123         void updateItems( void );
0124 
0125         //! update state for given widget
0126         bool updateState( GtkWidget*, const GdkRectangle&, int, int, bool state, bool delayed = false );
0127 
0128         //! true if menu item is active (pressed down)
0129         bool menuItemIsActive( GtkWidget* ) const;
0130 
0131         //! return dirty rect (for update)
0132         GdkRectangle dirtyRect( void );
0133 
0134         //! animations data
0135         class Data
0136         {
0137 
0138             public:
0139 
0140             //! constructor
0141             explicit Data( void ):
0142                 _widget( 0L ),
0143                 _rect( Gtk::gdk_rectangle() ),
0144                 _xOffset( 0 ),
0145                 _yOffset( 0 )
0146             {}
0147 
0148             //! update data
0149             void copy( const Data& other )
0150             {
0151                 _widget = other._widget;
0152                 _rect = other._rect;
0153                 _xOffset = other._xOffset;
0154                 _yOffset = other._yOffset;
0155             }
0156 
0157             //! update data
0158             void update( GtkWidget* widget, const GdkRectangle& rect, int xOffset, int yOffset )
0159             {
0160                 _widget = widget;
0161                 _rect = rect;
0162                 _xOffset = xOffset;
0163                 _yOffset = yOffset;
0164             }
0165 
0166             //! true if valid
0167             bool isValid( void ) const
0168             { return _widget && Gtk::gdk_rectangle_is_valid( &_rect ); }
0169 
0170             //! clear
0171             void clear( void )
0172             {
0173                 if( _timeLine.isRunning() ) _timeLine.stop();
0174                 _widget = 0L;
0175                 _rect = Gtk::gdk_rectangle();
0176             }
0177 
0178             //! dirty rect
0179             /*! properly adds offsets between widget window and painting window */
0180             GdkRectangle dirtyRect( void ) const
0181             {
0182                 GdkRectangle rect( _rect );
0183                 rect.x += _xOffset;
0184                 rect.y += _yOffset;
0185                 return rect;
0186             }
0187 
0188             //! timeline
0189             TimeLine _timeLine;
0190 
0191             //! widget
0192             GtkWidget* _widget;
0193 
0194             //! rectangle
0195             GdkRectangle _rect;
0196 
0197             //! offset between paint window and menu window
0198             int _xOffset;
0199             int _yOffset;
0200 
0201         };
0202 
0203         //! get data for given animation type
0204         Data& data( const WidgetType& type )
0205         {
0206             switch( type )
0207             {
0208                 default:
0209                 case AnimationCurrent: return _current;
0210                 case AnimationPrevious: return _previous;
0211             }
0212         }
0213 
0214         //! get data for given animation type
0215         const Data& data( const WidgetType& type ) const
0216         {
0217             switch( type )
0218             {
0219                 default:
0220                 case AnimationCurrent: return _current;
0221                 case AnimationPrevious: return _previous;
0222             }
0223         }
0224 
0225         //!@name callbacks
0226         //@{
0227 
0228         //! child is destroyed
0229         static gboolean childDestroyNotifyEvent( GtkWidget*, gpointer );
0230 
0231         //! mouse motion events
0232         static gboolean motionNotifyEvent( GtkWidget*, GdkEventMotion*, gpointer);
0233 
0234         //! mouse leave events
0235         static gboolean leaveNotifyEvent( GtkWidget*, GdkEventCrossing*, gpointer);
0236 
0237         //! update widget for fade-in/fade-out animation
0238         static gboolean delayedUpdate( gpointer );
0239 
0240         //! update widget for follow-mouse animation
0241         static gboolean followMouseUpdate( gpointer );
0242 
0243         //! start delayed fade-out animation
0244         static gboolean delayedAnimate( gpointer );
0245 
0246         //@}
0247 
0248         private:
0249 
0250         //! target
0251         GtkWidget* _target;
0252 
0253         //!@name signals
0254         //@{
0255         Signal _motionId;
0256         Signal _leaveId;
0257         //@}
0258 
0259         //!@name animation data
0260         //@{
0261 
0262         //! additional dirty rect
0263         GdkRectangle _dirtyRect;
0264 
0265         Data _previous;
0266         Data _current;
0267 
0268         //@}
0269 
0270         //!@name follow mouse animated data
0271         //@{
0272 
0273         //! padding
0274         gint _xPadding;
0275         gint _yPadding;
0276 
0277         //! delayed animation timeOut
0278         static const int _timeOut;
0279 
0280         //! timer of delayed animation
0281         Timer _timer;
0282 
0283         //@}
0284 
0285         //! map children to destroy signal
0286         typedef std::map<GtkWidget*, Signal> ChildrenMap;
0287         ChildrenMap _children;
0288 
0289     };
0290 
0291 }
0292 
0293 #endif