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

0001 /*
0002     this file is part of the oxygen gtk engine
0003     SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0004     SPDX-FileCopyrightText: 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "oxygenscrolledwindowdata.h"
0010 #include "../oxygengtkutils.h"
0011 #include "../config.h"
0012 #include "../oxygencairocontext.h"
0013 #include "oxygenanimations.h"
0014 
0015 #include <cassert>
0016 #include <iostream>
0017 
0018 namespace Oxygen
0019 {
0020 
0021     //_____________________________________________
0022     void ScrolledWindowData::connect( GtkWidget* widget )
0023     {
0024         assert( GTK_IS_SCROLLED_WINDOW( widget ) );
0025         assert( !_target );
0026 
0027         // store target
0028         _target = widget;
0029 
0030         // register scrollbars
0031         GtkScrolledWindow* scrolledWindow( GTK_SCROLLED_WINDOW( widget ) );
0032 
0033         if( GtkWidget* hScrollBar = gtk_scrolled_window_get_hscrollbar( scrolledWindow ) )
0034         { registerChild( hScrollBar ); }
0035 
0036         if( GtkWidget* vScrollBar = gtk_scrolled_window_get_vscrollbar( scrolledWindow ) )
0037         { registerChild( vScrollBar ); }
0038 
0039         // check child
0040         GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
0041         if( !child ) return;
0042 
0043         #if OXYGEN_DEBUG
0044         std::cerr
0045             << "Oxygen::ScrolledWindowData::connect -"
0046             << " child: " << child << " (" << G_OBJECT_TYPE_NAME( child ) << ")"
0047             << std::endl;
0048         #endif
0049 
0050         if( GTK_IS_TREE_VIEW( child ) || GTK_IS_TEXT_VIEW( child ) || GTK_IS_ICON_VIEW( child ) )
0051         {
0052 
0053             registerChild( child );
0054 
0055         } else {
0056 
0057             // list widget types for which scrolled window needs register
0058             static const char* widgetTypes[] = { "ExoIconView", "FMIconContainer", 0L };
0059             for( unsigned int i = 0; widgetTypes[i]; i++ )
0060             {
0061                 if( Gtk::g_object_is_a( G_OBJECT( child ), widgetTypes[i] ) )
0062                 {
0063                     registerChild( child );
0064                     break;
0065                 }
0066             }
0067 
0068         }
0069 
0070     }
0071 
0072     //_____________________________________________
0073     void ScrolledWindowData::disconnect( GtkWidget* )
0074     {
0075         _target = 0;
0076         for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter )
0077         { iter->second.disconnect( iter->first ); }
0078 
0079         _childrenData.clear();
0080     }
0081 
0082     //________________________________________________________________________________
0083     void ScrolledWindowData::setHovered( GtkWidget* widget, bool value )
0084     {
0085 
0086         bool oldHover( hovered() );
0087         ChildDataMap::iterator iter( _childrenData.find( widget ) );
0088         if( iter != _childrenData.end() ) iter->second._hovered = value;
0089         else return;
0090 
0091         // need to schedule repaint of the whole widget
0092         if( oldHover != hovered() && _target ) gtk_widget_queue_draw( _target );
0093 
0094     }
0095 
0096     //________________________________________________________________________________
0097     void ScrolledWindowData::setFocused( GtkWidget* widget, bool value )
0098     {
0099 
0100         bool oldFocus( focused() );
0101         ChildDataMap::iterator iter( _childrenData.find( widget ) );
0102         if( iter != _childrenData.end() ) iter->second._focused = value;
0103         else return;
0104 
0105         // need to schedule repaint of the whole widget
0106         if( oldFocus != focused() && _target ) gtk_widget_queue_draw( _target );
0107 
0108     }
0109 
0110     //_____________________________________________
0111     void ScrolledWindowData::registerChild( GtkWidget* widget )
0112     {
0113         // make sure widget is not already in map
0114         if( _childrenData.find( widget ) == _childrenData.end() )
0115         {
0116 
0117             #if OXYGEN_DEBUG
0118             std::cerr
0119                 << "Oxygen::ScrolledWindowData::registerChild -"
0120                 << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
0121                 << std::endl;
0122             #endif
0123 
0124             // adjust event mask
0125             gtk_widget_add_events( widget, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|GDK_FOCUS_CHANGE_MASK );
0126 
0127             // allocate new Hover data
0128             ChildData data;
0129             data._destroyId.connect( G_OBJECT(widget), "destroy", G_CALLBACK( childDestroyNotifyEvent ), this );
0130             data._enterId.connect( G_OBJECT(widget), "enter-notify-event", G_CALLBACK( enterNotifyEvent ), this );
0131             data._leaveId.connect( G_OBJECT(widget), "leave-notify-event", G_CALLBACK( leaveNotifyEvent ), this );
0132             data._focusInId.connect( G_OBJECT(widget), "focus-in-event", G_CALLBACK( focusInNotifyEvent ), this );
0133             data._focusOutId.connect( G_OBJECT(widget), "focus-out-event", G_CALLBACK( focusOutNotifyEvent ), this );
0134 
0135             // and insert in map
0136             _childrenData.insert( std::make_pair( widget, data ) );
0137 
0138             // set initial focus
0139             setFocused( widget, gtk_widget_has_focus( widget ) );
0140 
0141             // set initial hover
0142             const bool enabled( gtk_widget_get_state( widget ) != GTK_STATE_INSENSITIVE );
0143 
0144             // on connection, needs to check whether mouse pointer is in widget or not
0145             // to have the proper initial value of the hover flag
0146             if( enabled && gtk_widget_get_window( widget ) )
0147             {
0148 
0149                 gint xPointer,yPointer;
0150                 gdk_window_get_pointer( gtk_widget_get_window( widget ), &xPointer, &yPointer, 0L );
0151                 const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( widget ) );
0152                 const GdkRectangle rect( Gtk::gdk_rectangle( 0, 0, allocation.width, allocation.height ) );
0153                 setHovered( widget, Gtk::gdk_rectangle_contains( &rect, xPointer, yPointer ) );
0154 
0155             } else setHovered( widget, false );
0156 
0157         }
0158 
0159     }
0160 
0161     //________________________________________________________________________________
0162     void ScrolledWindowData::unregisterChild( GtkWidget* widget )
0163     {
0164 
0165         // loopup in hover map
0166         ChildDataMap::iterator iter( _childrenData.find( widget ) );
0167         if( iter == _childrenData.end() ) return;
0168 
0169         #if OXYGEN_DEBUG
0170         std::cerr
0171             << "Oxygen::ScrolledWindowData::unregisterChild -"
0172             << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
0173             << std::endl;
0174         #endif
0175 
0176         iter->second.disconnect( widget );
0177         _childrenData.erase( iter );
0178 
0179     }
0180 
0181     //________________________________________________________________________________
0182     #if OXYGEN_DEBUG
0183     void ScrolledWindowData::ChildData::disconnect( GtkWidget* widget )
0184     #else
0185     void ScrolledWindowData::ChildData::disconnect( GtkWidget* )
0186     #endif
0187     {
0188 
0189         #if OXYGEN_DEBUG
0190         std::cerr
0191             << "Oxygen::ScrolledWindowData::ChildData::disconnect -"
0192             << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
0193             << std::endl;
0194         #endif
0195 
0196         _destroyId.disconnect();
0197         _enterId.disconnect();
0198         _leaveId.disconnect();
0199         _focusInId.disconnect();
0200         _focusOutId.disconnect();
0201         _hovered = false;
0202         _focused = false;
0203 
0204     }
0205 
0206     //____________________________________________________________________________________________
0207     gboolean ScrolledWindowData::childDestroyNotifyEvent( GtkWidget* widget, gpointer data )
0208     {
0209         #if OXYGEN_DEBUG
0210         std::cerr
0211             << "Oxygen::ScrolledWindowData::childDestroyNotifyEvent -"
0212             << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
0213             << std::endl;
0214         #endif
0215         static_cast<ScrolledWindowData*>(data)->unregisterChild( widget );
0216         return FALSE;
0217     }
0218 
0219     //________________________________________________________________________________
0220     gboolean ScrolledWindowData::enterNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data )
0221     {
0222 
0223         #if OXYGEN_DEBUG
0224         std::cerr << "Oxygen::ScrolledWindowData::enterNotifyEvent -"
0225             << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
0226             << std::endl;
0227         #endif
0228 
0229         if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) )
0230         { static_cast<ScrolledWindowData*>( data )->setHovered( widget, true ); }
0231 
0232         return FALSE;
0233     }
0234 
0235     //________________________________________________________________________________
0236     gboolean ScrolledWindowData::leaveNotifyEvent( GtkWidget* widget, GdkEventCrossing* event, gpointer data )
0237     {
0238 
0239         #if OXYGEN_DEBUG
0240         std::cerr << "Oxygen::ScrolledWindowData::leaveNotifyEvent -"
0241             << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
0242             << std::endl;
0243         #endif
0244 
0245         if( !(event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK) ) )
0246         { static_cast<ScrolledWindowData*>( data )->setHovered( widget, false ); }
0247 
0248         return FALSE;
0249     }
0250 
0251     //________________________________________________________________________________
0252     gboolean ScrolledWindowData::focusInNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data )
0253     {
0254 
0255         #if OXYGEN_DEBUG
0256         std::cerr << "Oxygen::ScrolledWindowData::focusInNotifyEvent -"
0257             << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
0258             << std::endl;
0259         #endif
0260 
0261         static_cast<ScrolledWindowData*>( data )->setFocused( widget, true );
0262         return FALSE;
0263     }
0264 
0265     //________________________________________________________________________________
0266     gboolean ScrolledWindowData::focusOutNotifyEvent( GtkWidget* widget, GdkEvent*, gpointer data )
0267     {
0268 
0269         #if OXYGEN_DEBUG
0270         std::cerr << "Oxygen::ScrolledWindowData::focusOutNotifyEvent -"
0271             << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
0272             << std::endl;
0273         #endif
0274 
0275         static_cast<ScrolledWindowData*>( data )->setFocused( widget, false );
0276         return FALSE;
0277     }
0278 
0279 }