File indexing completed on 2024-05-12 17:05:47

0001 #ifndef oxygencomboboxdata_h
0002 #define oxygencomboboxdata_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 "oxygensignal.h"
0011 
0012 #include <gtk/gtk.h>
0013 #include <algorithm>
0014 #include <map>
0015 #include <iostream>
0016 
0017 namespace Oxygen
0018 {
0019 
0020     // handles focus and hover and pressed down state for comboboxes
0021     class ComboBoxData
0022     {
0023 
0024         public:
0025 
0026         //! constructor
0027         ComboBoxData( void ):
0028             _target( 0L ),
0029             _list( 0L )
0030         {}
0031 
0032         //! destructor
0033         virtual ~ComboBoxData( void )
0034         { disconnect( _target ); }
0035 
0036         //! setup connections
0037         /*! does nothing. Only kept here for consistency with other data */
0038         void connect( GtkWidget* );
0039 
0040         //! disconnect
0041         void disconnect( GtkWidget* );
0042 
0043         //!@name modifiers
0044         //@{
0045 
0046         //! list
0047         void setList( GtkWidget* widget )
0048         { _list = widget; }
0049 
0050         //! assign button
0051         void setButton( GtkWidget* value );
0052 
0053         //! button focus
0054         void setButtonFocus( bool value )
0055         {
0056             if( _button._focus == value ) return;
0057             _button._focus = value;
0058 
0059             // trigger update
0060             if( _target ) gtk_widget_queue_draw( _target );
0061 
0062             return;
0063         }
0064 
0065         //! register child
0066         void registerChild( GtkWidget*, bool recursive = true );
0067 
0068         //@}
0069 
0070         //!@name accessors
0071         //@{
0072 
0073         //! list
0074         GtkWidget* list( void ) const
0075         { return _list; }
0076 
0077         //! pressed
0078         bool pressed( void ) const
0079         { return _button._pressed; }
0080 
0081         //! true if either button or entry has focus
0082         bool hasFocus( void ) const
0083         { return _button._focus; }
0084 
0085         //! true if either button or entry has hover
0086         bool hovered( void ) const
0087         { return std::find_if( _hoverData.begin(), _hoverData.end(), HoveredFTor() ) != _hoverData.end(); }
0088 
0089         //@}
0090 
0091         protected:
0092 
0093         //! initialize cell view
0094         void initializeCellView( GtkWidget* value );
0095 
0096         //! update cell view color
0097         void updateCellViewColor( void ) const;
0098 
0099         //! update button event window
0100         /*!
0101         the trick is to extend the button event window by 6 pixels to the left,
0102         in order to fill a dead area created by the Combobox's GtkFrame's margin.
0103         */
0104         void updateButtonEventWindow( void ) const;
0105 
0106         //! set hover flag for given widget
0107         void setPressed( GtkWidget*, bool );
0108 
0109         //! set hover flag for given widget
0110         void setHovered( GtkWidget*, bool );
0111 
0112         //! disconnect child
0113         void unregisterChild( GtkWidget* );
0114 
0115         //!@name callbacks
0116         //@{
0117 
0118         static gboolean childDestroyNotifyEvent( GtkWidget*, gpointer );
0119         static void childToggledEvent( GtkWidget*, gpointer );
0120         static void childSizeAllocateEvent( GtkWidget*, GtkAllocation*, gpointer );
0121 
0122         static gboolean enterNotifyEvent( GtkWidget*, GdkEventCrossing*, gpointer );
0123         static gboolean leaveNotifyEvent( GtkWidget*, GdkEventCrossing*, gpointer );
0124         static void stateChangeEvent( GtkWidget*, GtkStateType, gpointer );
0125         static void styleSetEvent( GtkWidget*, GtkStyle*, gpointer );
0126 
0127         //@}
0128 
0129         private:
0130 
0131         //! target widget
0132         GtkWidget* _target;
0133 
0134         //! drop-down list, if set
0135         GtkWidget* _list;
0136 
0137         //!@name signals
0138         //@{
0139 
0140         //! state change signal
0141         Signal _stateChangeId;
0142 
0143         //! style set
0144         Signal _styleSetId;
0145 
0146         //@}
0147 
0148         // handle child registration
0149         class ChildData
0150         {
0151 
0152             public:
0153 
0154             //! constructor
0155             explicit ChildData( void ):
0156                 _widget(0L)
0157             {}
0158 
0159             //! destructor
0160             virtual ~ChildData( void )
0161             {}
0162 
0163             //! disconnect
0164             virtual void disconnect( void );
0165 
0166             //! widget
0167             GtkWidget* _widget;
0168 
0169             //!callback id
0170             Signal _destroyId;
0171 
0172         };
0173 
0174         // handle focus and toggle state
0175         class ButtonData: public ChildData
0176         {
0177 
0178             public:
0179 
0180             //! constructor
0181             explicit ButtonData( void ):
0182                 _pressed( false ),
0183                 _focus( false )
0184             {}
0185 
0186             //! destructor
0187             virtual ~ButtonData( void )
0188             {}
0189 
0190             //! disconnect
0191             virtual void disconnect( void );
0192 
0193             //! true if widget is down
0194             bool _pressed;
0195 
0196             //! true if widget has focus
0197             bool _focus;
0198 
0199             //! toggled callback Id
0200             Signal _toggledId;
0201             Signal _sizeAllocateId;
0202 
0203         };
0204 
0205         class HoverData: public ChildData
0206         {
0207             public:
0208 
0209             //! constructor
0210             explicit HoverData( void ):
0211                 _hovered( false )
0212             {}
0213 
0214             //! destructor
0215             virtual ~HoverData( void )
0216             {}
0217 
0218             //! disconnect
0219             virtual void disconnect( void );
0220 
0221             //! true if widget is hovered
0222             bool _hovered;
0223 
0224             //!@name callback ids
0225             //@{
0226             Signal _enterId;
0227             Signal _leaveId;
0228             //@}
0229 
0230         };
0231 
0232         //! need to detect hovered child
0233         class HoveredFTor
0234         {
0235             public:
0236 
0237             bool operator () ( const std::pair<GtkWidget*, HoverData>& dataPair )
0238             { return dataPair.second._hovered; }
0239 
0240         };
0241 
0242         typedef std::map<GtkWidget*, HoverData> HoverDataMap;
0243         HoverDataMap _hoverData;
0244 
0245         //! true if cell layout has been initialized
0246         bool _cellLayoutInitialized;
0247 
0248         //! cell data
0249         ChildData _cell;
0250 
0251         //! button data
0252         ButtonData _button;
0253 
0254     };
0255 
0256 }
0257 
0258 #endif