1 #ifndef oxygenmenustatedata_h
2 #define oxygenmenustatedata_h
3 /*
4 * this file is part of the oxygen gtk engine
5 * Copyright (c) 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
6 *
7 * This  library is free  software; you can  redistribute it and/or
8 * modify it  under  the terms  of the  GNU Lesser  General  Public
9 * License  as published  by the Free  Software  Foundation; either
10 * version 2 of the License, or(at your option ) any later version.
11 *
12 * This library is distributed  in the hope that it will be useful,
13 * but  WITHOUT ANY WARRANTY; without even  the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License  along  with  this library;  if not,  write to  the Free
19 * Software Foundation, Inc., 51  Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
21 */
22 
23 #include "../oxygenanimationdata.h"
24 #include "../oxygenanimationmodes.h"
25 #include "../oxygengtkutils.h"
26 #include "oxygenfollowmousedata.h"
27 #include "oxygensignal.h"
28 #include "oxygentimer.h"
29 #include "oxygentimeline.h"
30 
31 #include <gtk/gtk.h>
32 
33 #include <map>
34 
35 namespace Oxygen
36 {
37     //! handles menu items animations
38     class MenuStateData: public FollowMouseData
39     {
40 
41         public:
42 
43         //! constructor
MenuStateData(void)44         MenuStateData( void ):
45             _target( 0L ),
46             _dirtyRect( Gtk::gdk_rectangle() ),
47             _xPadding(0),
48             _yPadding(0)
49             {}
50 
51         //! destructor
~MenuStateData(void)52         virtual ~MenuStateData( void )
53         { disconnect( _target ); }
54 
55         //! setup connections
56         using FollowMouseData::connect;
57         virtual void connect( GtkWidget* );
58 
59         //! disconnect
60         using FollowMouseData::disconnect;
61         virtual void disconnect( GtkWidget* );
62 
63         //!@name modifiers
64         //@{
65 
66         //! enable state
setEnabled(bool value)67         void setEnabled( bool value )
68         {
69 
70             // base class
71             FollowMouseData::setEnabled( value );
72 
73             _current._timeLine.setEnabled( value );
74             _previous._timeLine.setEnabled( value );
75 
76             if( !value )
77             {
78                 _current.clear();
79                 _previous.clear();
80             }
81 
82         }
83 
84         //! duration
setDuration(int value)85         void setDuration( int value )
86         {
87             _current._timeLine.setDuration( value );
88             _previous._timeLine.setDuration( value );
89         }
90 
91         //@}
92 
93         //!@name accessors
94         //@{
95 
96         //! true if animated
isAnimated(void)97         bool isAnimated( void ) const
98         { return isAnimated( AnimationCurrent ) || isAnimated( AnimationPrevious ); }
99 
100         //! true if given animation type is animated
isAnimated(const WidgetType & type)101         bool isAnimated( const WidgetType& type ) const
102         { return data( type )._timeLine.isRunning(); }
103 
104         //! widget for current animation type
widget(const WidgetType & type)105         GtkWidget* widget( const WidgetType& type ) const
106         { return data( type )._widget; }
107 
108         //! rect for given animation type
rectangle(const WidgetType & type)109         const GdkRectangle& rectangle( const WidgetType& type ) const
110         { return data( type )._rect; }
111 
112         //! animation data
animationData(const WidgetType & type)113         AnimationData animationData( const WidgetType& type ) const
114         {
115             const Data& data( this->data( type ) );
116             return data._timeLine.isRunning() ?
117                 AnimationData( data._timeLine.value(), AnimationHover ):
118                 AnimationData();
119         }
120 
121         //! true when fade out animation is locked (delayed)
isLocked(void)122         virtual bool isLocked( void ) const
123         { return _timer.isRunning(); }
124 
125         //@}
126 
127         protected:
128 
129         //! register child
130         void registerChild( GtkWidget* );
131 
132         //! disconnect child
133         void unregisterChild( GtkWidget* );
134 
135         //! update items
136         void updateItems( void );
137 
138         //! update state for given widget
139         bool updateState( GtkWidget*, const GdkRectangle&, int, int, bool state, bool delayed = false );
140 
141         //! true if menu item is active (pressed down)
142         bool menuItemIsActive( GtkWidget* ) const;
143 
144         //! return dirty rect (for update)
145         GdkRectangle dirtyRect( void );
146 
147         //! animations data
148         class Data
149         {
150 
151             public:
152 
153             //! constructor
Data(void)154             explicit Data( void ):
155                 _widget( 0L ),
156                 _rect( Gtk::gdk_rectangle() ),
157                 _xOffset( 0 ),
158                 _yOffset( 0 )
159             {}
160 
161             //! update data
copy(const Data & other)162             void copy( const Data& other )
163             {
164                 _widget = other._widget;
165                 _rect = other._rect;
166                 _xOffset = other._xOffset;
167                 _yOffset = other._yOffset;
168             }
169 
170             //! update data
update(GtkWidget * widget,const GdkRectangle & rect,int xOffset,int yOffset)171             void update( GtkWidget* widget, const GdkRectangle& rect, int xOffset, int yOffset )
172             {
173                 _widget = widget;
174                 _rect = rect;
175                 _xOffset = xOffset;
176                 _yOffset = yOffset;
177             }
178 
179             //! true if valid
isValid(void)180             bool isValid( void ) const
181             { return _widget && Gtk::gdk_rectangle_is_valid( &_rect ); }
182 
183             //! clear
clear(void)184             void clear( void )
185             {
186                 if( _timeLine.isRunning() ) _timeLine.stop();
187                 _widget = 0L;
188                 _rect = Gtk::gdk_rectangle();
189             }
190 
191             //! dirty rect
192             /*! properly adds offsets between widget window and painting window */
dirtyRect(void)193             GdkRectangle dirtyRect( void ) const
194             {
195                 GdkRectangle rect( _rect );
196                 rect.x += _xOffset;
197                 rect.y += _yOffset;
198                 return rect;
199             }
200 
201             //! timeline
202             TimeLine _timeLine;
203 
204             //! widget
205             GtkWidget* _widget;
206 
207             //! rectangle
208             GdkRectangle _rect;
209 
210             //! offset between paint window and menu window
211             int _xOffset;
212             int _yOffset;
213 
214         };
215 
216         //! get data for given animation type
data(const WidgetType & type)217         Data& data( const WidgetType& type )
218         {
219             switch( type )
220             {
221                 default:
222                 case AnimationCurrent: return _current;
223                 case AnimationPrevious: return _previous;
224             }
225         }
226 
227         //! get data for given animation type
data(const WidgetType & type)228         const Data& data( const WidgetType& type ) const
229         {
230             switch( type )
231             {
232                 default:
233                 case AnimationCurrent: return _current;
234                 case AnimationPrevious: return _previous;
235             }
236         }
237 
238         //!@name callbacks
239         //@{
240 
241         //! child is destroyed
242         static gboolean childDestroyNotifyEvent( GtkWidget*, gpointer );
243 
244         //! mouse motion events
245         static gboolean motionNotifyEvent( GtkWidget*, GdkEventMotion*, gpointer);
246 
247         //! mouse leave events
248         static gboolean leaveNotifyEvent( GtkWidget*, GdkEventCrossing*, gpointer);
249 
250         //! update widget for fade-in/fade-out animation
251         static gboolean delayedUpdate( gpointer );
252 
253         //! update widget for follow-mouse animation
254         static gboolean followMouseUpdate( gpointer );
255 
256         //! start delayed fade-out animation
257         static gboolean delayedAnimate( gpointer );
258 
259         //@}
260 
261         private:
262 
263         //! target
264         GtkWidget* _target;
265 
266         //!@name signals
267         //@{
268         Signal _motionId;
269         Signal _leaveId;
270         //@}
271 
272         //!@name animation data
273         //@{
274 
275         //! additional dirty rect
276         GdkRectangle _dirtyRect;
277 
278         Data _previous;
279         Data _current;
280 
281         //@}
282 
283         //!@name follow mouse animated data
284         //@{
285 
286         //! padding
287         gint _xPadding;
288         gint _yPadding;
289 
290         //! delayed animation timeOut
291         static const int _timeOut;
292 
293         //! timer of delayed animation
294         Timer _timer;
295 
296         //@}
297 
298         //! map children to destroy signal
299         typedef std::map<GtkWidget*, Signal> ChildrenMap;
300         ChildrenMap _children;
301 
302     };
303 
304 }
305 
306 #endif
307