1 #ifndef oxygencomboboxdata_h
2 #define oxygencomboboxdata_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 "oxygensignal.h"
24 
25 #include <gtk/gtk.h>
26 #include <algorithm>
27 #include <map>
28 #include <iostream>
29 
30 namespace Oxygen
31 {
32 
33     // handles focus and hover and pressed down state for comboboxes
34     class ComboBoxData
35     {
36 
37         public:
38 
39         //! constructor
ComboBoxData(void)40         ComboBoxData( void ):
41             _target( 0L ),
42             _list( 0L )
43         {}
44 
45         //! destructor
~ComboBoxData(void)46         virtual ~ComboBoxData( void )
47         { disconnect( _target ); }
48 
49         //! setup connections
50         /*! does nothing. Only kept here for consistency with other data */
51         void connect( GtkWidget* );
52 
53         //! disconnect
54         void disconnect( GtkWidget* );
55 
56         //!@name modifiers
57         //@{
58 
59         //! list
setList(GtkWidget * widget)60         void setList( GtkWidget* widget )
61         { _list = widget; }
62 
63         //! assign button
64         void setButton( GtkWidget* value );
65 
66         //! button focus
setButtonFocus(bool value)67         void setButtonFocus( bool value )
68         {
69             if( _button._focus == value ) return;
70             _button._focus = value;
71 
72             // trigger update
73             if( _target ) gtk_widget_queue_draw( _target );
74 
75             return;
76         }
77 
78         //! register child
79         void registerChild( GtkWidget*, bool recursive = true );
80 
81         //@}
82 
83         //!@name accessors
84         //@{
85 
86         //! list
list(void)87         GtkWidget* list( void ) const
88         { return _list; }
89 
90         //! pressed
pressed(void)91         bool pressed( void ) const
92         { return _button._pressed; }
93 
94         //! true if either button or entry has focus
hasFocus(void)95         bool hasFocus( void ) const
96         { return _button._focus; }
97 
98         //! true if either button or entry has hover
hovered(void)99         bool hovered( void ) const
100         { return std::find_if( _hoverData.begin(), _hoverData.end(), HoveredFTor() ) != _hoverData.end(); }
101 
102         //@}
103 
104         protected:
105 
106         //! initialize cell view
107         void initializeCellView( GtkWidget* value );
108 
109         //! update cell view color
110         void updateCellViewColor( void ) const;
111 
112         //! update button event window
113         /*!
114         the trick is to extend the button event window by 6 pixels to the left,
115         in order to fill a dead area created by the Combobox's GtkFrame's margin.
116         */
117         void updateButtonEventWindow( void ) const;
118 
119         //! set hover flag for given widget
120         void setPressed( GtkWidget*, bool );
121 
122         //! set hover flag for given widget
123         void setHovered( GtkWidget*, bool );
124 
125         //! disconnect child
126         void unregisterChild( GtkWidget* );
127 
128         //!@name callbacks
129         //@{
130 
131         static gboolean childDestroyNotifyEvent( GtkWidget*, gpointer );
132         static void childToggledEvent( GtkWidget*, gpointer );
133         static void childSizeAllocateEvent( GtkWidget*, GtkAllocation*, gpointer );
134 
135         static gboolean enterNotifyEvent( GtkWidget*, GdkEventCrossing*, gpointer );
136         static gboolean leaveNotifyEvent( GtkWidget*, GdkEventCrossing*, gpointer );
137         static void stateChangeEvent( GtkWidget*, GtkStateType, gpointer );
138         static void styleSetEvent( GtkWidget*, GtkStyle*, gpointer );
139 
140         //@}
141 
142         private:
143 
144         //! target widget
145         GtkWidget* _target;
146 
147         //! drop-down list, if set
148         GtkWidget* _list;
149 
150         //!@name signals
151         //@{
152 
153         //! state change signal
154         Signal _stateChangeId;
155 
156         //! style set
157         Signal _styleSetId;
158 
159         //@}
160 
161         // handle child registration
162         class ChildData
163         {
164 
165             public:
166 
167             //! constructor
ChildData(void)168             explicit ChildData( void ):
169                 _widget(0L)
170             {}
171 
172             //! destructor
~ChildData(void)173             virtual ~ChildData( void )
174             {}
175 
176             //! disconnect
177             virtual void disconnect( void );
178 
179             //! widget
180             GtkWidget* _widget;
181 
182             //!callback id
183             Signal _destroyId;
184 
185         };
186 
187         // handle focus and toggle state
188         class ButtonData: public ChildData
189         {
190 
191             public:
192 
193             //! constructor
ButtonData(void)194             explicit ButtonData( void ):
195                 _pressed( false ),
196                 _focus( false )
197             {}
198 
199             //! destructor
~ButtonData(void)200             virtual ~ButtonData( void )
201             {}
202 
203             //! disconnect
204             virtual void disconnect( void );
205 
206             //! true if widget is down
207             bool _pressed;
208 
209             //! true if widget has focus
210             bool _focus;
211 
212             //! toggled callback Id
213             Signal _toggledId;
214             Signal _sizeAllocateId;
215 
216         };
217 
218         class HoverData: public ChildData
219         {
220             public:
221 
222             //! constructor
HoverData(void)223             explicit HoverData( void ):
224                 _hovered( false )
225             {}
226 
227             //! destructor
~HoverData(void)228             virtual ~HoverData( void )
229             {}
230 
231             //! disconnect
232             virtual void disconnect( void );
233 
234             //! true if widget is hovered
235             bool _hovered;
236 
237             //!@name callback ids
238             //@{
239             Signal _enterId;
240             Signal _leaveId;
241             //@}
242 
243         };
244 
245         //! need to detect hovered child
246         class HoveredFTor
247         {
248             public:
249 
operator()250             bool operator () ( const std::pair<GtkWidget*, HoverData>& dataPair )
251             { return dataPair.second._hovered; }
252 
253         };
254 
255         typedef std::map<GtkWidget*, HoverData> HoverDataMap;
256         HoverDataMap _hoverData;
257 
258         //! true if cell layout has been initialized
259         bool _cellLayoutInitialized;
260 
261         //! cell data
262         ChildData _cell;
263 
264         //! button data
265         ButtonData _button;
266 
267     };
268 
269 }
270 
271 #endif
272