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

0001 #ifndef oxygenmenubarstatedata_h
0002 #define oxygenmenubarstatedata_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 * SPDX-FileCopyrightText: 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
0007 *
0008 * MenuBarState prelight effect is based on
0009 * Redmond95 - a cairo based GTK+ engine
0010 * SPDX-FileCopyrightText: 2001 Red Hat Inc. <@redhat.com>
0011 * SPDX-FileCopyrightText: 2006 Andrew Johnson <acjgenius@earthlink.net>
0012 * SPDX-FileCopyrightText: 2006-2007 Benjamin Berg <benjamin@sipsolutions.net>
0013 *
0014 * SPDX-License-Identifier: LGPL-2.0-or-later
0015 */
0016 
0017 #include "../oxygenanimationdata.h"
0018 #include "../oxygenanimationmodes.h"
0019 #include "../oxygengtkutils.h"
0020 #include "oxygenfollowmousedata.h"
0021 #include "oxygensignal.h"
0022 #include "oxygentimeline.h"
0023 
0024 #include <gtk/gtk.h>
0025 
0026 #include <map>
0027 
0028 namespace Oxygen
0029 {
0030     class MenuBarStateData: public FollowMouseData
0031     {
0032 
0033         public:
0034 
0035         //! constructor
0036         MenuBarStateData( void ):
0037             _target( 0L ),
0038             _animationsEnabled( true ),
0039             _dirtyRect( Gtk::gdk_rectangle() )
0040             {}
0041 
0042         //! destructor
0043         virtual ~MenuBarStateData( void )
0044         { disconnect( _target ); }
0045 
0046         //! setup connections
0047         using FollowMouseData::connect;
0048         virtual void connect( GtkWidget* );
0049 
0050         //! disconnect
0051         using FollowMouseData::disconnect;
0052         virtual void disconnect( GtkWidget* );
0053 
0054         //! enable state
0055         void setAnimationsEnabled( bool value )
0056         {
0057 
0058             // base class
0059             FollowMouseData::setEnabled( value );
0060 
0061             _animationsEnabled = value;
0062             _current._timeLine.setEnabled( value );
0063             _previous._timeLine.setEnabled( value );
0064 
0065             if( !value )
0066             {
0067                 _current.clear();
0068                 _previous.clear();
0069             }
0070 
0071         }
0072 
0073         //! duration
0074         void setDuration( int value )
0075         {
0076             _current._timeLine.setDuration( value );
0077             _previous._timeLine.setDuration( value );
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         //@}
0109 
0110         protected:
0111 
0112         //! register child
0113         void registerChild( GtkWidget* );
0114 
0115         //! disconnect child
0116         void unregisterChild( GtkWidget* );
0117 
0118         //! update items
0119         void updateItems( GdkEventType );
0120 
0121         //! update state for given widget
0122         bool updateState( GtkWidget*, const GdkRectangle&, bool );
0123 
0124         //! true if menu item is active (pressed down)
0125         bool menuItemIsActive( GtkWidget* ) const;
0126 
0127         //! return dirty rect (for update)
0128         GdkRectangle dirtyRect( void );
0129 
0130         //@}
0131 
0132         //! animations data
0133         class Data
0134         {
0135 
0136             public:
0137 
0138             //! constructor
0139             explicit Data( void ):
0140                 _widget( 0L ),
0141                 _rect( Gtk::gdk_rectangle() )
0142             {}
0143 
0144             //! update data
0145             void copy( const Data& other )
0146             {
0147                 _widget = other._widget;
0148                 _rect = other._rect;
0149             }
0150 
0151             //! update data
0152             void update( GtkWidget* widget, const GdkRectangle& rect )
0153             {
0154                 _widget = widget;
0155                 _rect = rect;
0156             }
0157 
0158             //! true if valid
0159             bool isValid( void ) const
0160             { return _widget && Gtk::gdk_rectangle_is_valid( &_rect ); }
0161 
0162             //! clear
0163             void clear( void )
0164             {
0165                 if( _timeLine.isRunning() ) _timeLine.stop();
0166                 _widget = 0L;
0167                 _rect = Gtk::gdk_rectangle();
0168             }
0169 
0170             //! timeline
0171             TimeLine _timeLine;
0172 
0173             //! widget
0174             GtkWidget* _widget;
0175 
0176             //! rectangle
0177             GdkRectangle _rect;
0178 
0179         };
0180 
0181         //! get data for given animation type
0182         Data& data( const WidgetType& type )
0183         {
0184             switch( type )
0185             {
0186                 default:
0187                 case AnimationCurrent: return _current;
0188                 case AnimationPrevious: return _previous;
0189             }
0190         }
0191 
0192         //! get data for given animation type
0193         const Data& data( const WidgetType& type ) const
0194         {
0195             switch( type )
0196             {
0197                 default:
0198                 case AnimationCurrent: return _current;
0199                 case AnimationPrevious: return _previous;
0200             }
0201         }
0202 
0203         //!@name callbacks
0204         //@{
0205 
0206         //! child is destroyed
0207         static gboolean childDestroyNotifyEvent( GtkWidget*, gpointer );
0208 
0209         //! mouse motion events
0210         static gboolean motionNotifyEvent( GtkWidget*, GdkEventMotion*, gpointer);
0211 
0212         //! mouse leave events
0213         static gboolean leaveNotifyEvent( GtkWidget*, GdkEventCrossing*, gpointer);
0214 
0215         //! update widget for fade-in/fade-out animation
0216         static gboolean delayedUpdate( gpointer );
0217 
0218         //! update widget for follow-mouse animation
0219         static gboolean followMouseUpdate( gpointer );
0220 
0221         //@}
0222 
0223         private:
0224 
0225         //! target
0226         GtkWidget* _target;
0227 
0228         //!@name signals
0229         //@{
0230         Signal _motionId;
0231         Signal _leaveId;
0232         //@}
0233 
0234         //!@name animation data
0235         //@{
0236 
0237         //! true if menubar item mouse-over is animated
0238         bool _animationsEnabled;
0239 
0240         //! additional dirty rect
0241         GdkRectangle _dirtyRect;
0242 
0243         Data _previous;
0244         Data _current;
0245 
0246         //@}
0247 
0248         //! map children to destroy signal
0249         typedef std::map<GtkWidget*, Signal> ChildrenMap;
0250         ChildrenMap _children;
0251 
0252     };
0253 
0254 }
0255 
0256 #endif