diff options
Diffstat (limited to 'tdegtk/tdegtk-tabwidgetdata.cpp')
-rw-r--r-- | tdegtk/tdegtk-tabwidgetdata.cpp | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/tdegtk/tdegtk-tabwidgetdata.cpp b/tdegtk/tdegtk-tabwidgetdata.cpp new file mode 100644 index 0000000..19d70b8 --- /dev/null +++ b/tdegtk/tdegtk-tabwidgetdata.cpp @@ -0,0 +1,308 @@ +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa <[email protected]> +* +* the tabwidget data code is largely inspired from the gtk redmond engine +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or(at your option ) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free +* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301, USA. +*/ + +#include "tdegtk-tabwidgetdata.h" +#include "tdegtk-utils.h" +#include "config.h" + +#include <gtk/gtk.h> +#include <cassert> +#include <iostream> + + //________________________________________________________________________________ + void TabWidgetData::connect( GtkWidget* widget ) + { + + #if TDEGTK_DEBUG + std::cerr << "TDEGTK::TabWidgetData::connect - " << widget << std::endl; + #endif + + _target = widget; + _motionId.connect( G_OBJECT(widget), "motion-notify-event", G_CALLBACK( motionNotifyEvent ), this ); + _leaveId.connect( G_OBJECT(widget), "leave-notify-event", G_CALLBACK( leaveNotifyEvent ), this ); + _pageAddedId.connect( G_OBJECT(widget), "page-added", G_CALLBACK( pageAddedEvent ), this ); + + updateRegisteredChildren( widget ); + + } + + //________________________________________________________________________________ + void TabWidgetData::disconnect( GtkWidget* widget ) + { + + #if TDEGTK_DEBUG + std::cerr << "TDEGTK::TabWidgetData::disconnect - " << widget << std::endl; + #endif + + _target = 0L; + _motionId.disconnect(); + _leaveId.disconnect(); + _pageAddedId.disconnect(); + + // disconnect all children + for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter ) + { iter->second.disconnect(); } + _childrenData.clear(); + + } + + //________________________________________________________________________________ + void TabWidgetData::updateHoveredTab( GtkWidget* widget ) + { + + if( !widget ) widget = _target; + if( !widget ) return; + + // get pointer position + int xPointer(0), yPointer(0); + + GdkDeviceManager* manager( gdk_display_get_device_manager( gtk_widget_get_display( widget ) ) ); + GdkDevice* pointer( gdk_device_manager_get_client_pointer( manager ) ); + if( !pointer ) return; + + gdk_window_get_device_position( gtk_widget_get_window( widget ), pointer, &xPointer, &yPointer, 0L ); + + + // loop over tabs and check matching + for( unsigned int i = (unsigned int)Gtk::gtk_notebook_find_first_tab( widget ); i < _tabRects.size(); i++ ) + { + if( Gtk::gdk_rectangle_contains( &_tabRects[i], xPointer, yPointer ) ) + { setHoveredTab( widget, i ); return; } + } + + // reset hovered tab + setHoveredTab( widget, -1 ); + return; + + } + + //________________________________________________________________________________ + void TabWidgetData::updateTabRect( GtkWidget* widget, int index, const GdkRectangle& r ) + { + // make sure the vector has the right size + if( !GTK_IS_NOTEBOOK( widget ) ) return; + GtkNotebook* notebook = GTK_NOTEBOOK( widget ); + _tabRects.resize( gtk_notebook_get_n_pages( notebook ), defaultRect() ); + + // check index against number of tabs + if( index < 0 || index >= (int)_tabRects.size() ) + { return; } + + // store rectangle + _tabRects[index]=r; + } + + //________________________________________________________________________________ + void TabWidgetData::setDirty( bool value ) + { + if( _dirty == value ) return; + _dirty = value; + if( _dirty && _target ) + { + + // we should only update the tabbar rect here + GdkRectangle updateRect; + Gtk::gtk_notebook_get_tabbar_rect( GTK_NOTEBOOK( _target ), &updateRect ); + Gtk::gtk_widget_queue_draw( _target, &updateRect ); + + #if TDEGTK_DEBUG + std::cerr << "TDEGTK::TabWidgetData::setDirty - update: " << updateRect << std::endl; + #endif + + } + + } + + //________________________________________________________________________________ + bool TabWidgetData::isInTab( int x, int y ) const + { + + // loop over tab rectangles and check. + for( RectangleList::const_iterator iter = _tabRects.begin(); iter != _tabRects.end(); ++iter ) + { if( Gtk::gdk_rectangle_contains( &(*iter), x, y ) ) return true; } + + return false; + + } + + //________________________________________________________________________________ + void TabWidgetData::setHoveredTab( GtkWidget* widget, int index ) + { + + if( _hoveredTab == index ) return; + + _hoveredTab = index; + + GdkRectangle updateRect( Gtk::gdk_rectangle() ); + for( RectangleList::const_iterator iter = _tabRects.begin(); iter != _tabRects.end(); ++iter ) + { gdk_rectangle_union( &(*iter), &updateRect, &updateRect ); } + + gtk_widget_queue_draw_area( widget, updateRect.x-4, updateRect.y-4, updateRect.width+8, updateRect.height+8 ); + + return; + } + + //________________________________________________________________________________ + gboolean TabWidgetData::motionNotifyEvent(GtkWidget* widget, GdkEventMotion*, gpointer data ) + { + + static_cast<TabWidgetData*>( data )->updateHoveredTab( widget ); + return FALSE; + + } + + //________________________________________________________________________________ + gboolean TabWidgetData::leaveNotifyEvent( GtkWidget* widget, GdkEventCrossing*, gpointer data ) + { + // reset hovered tab + static_cast<TabWidgetData*>( data )->setHoveredTab( widget, -1 ); + return FALSE; + } + + //________________________________________________________________________________ + void TabWidgetData::pageAddedEvent( GtkNotebook* parent, GtkWidget* child, guint, gpointer data) + { + #if TDEGTK_DEBUG + std::cerr << "TDEGTK::TabWidgetData::pageAddedEvent - " << child << std::endl; + #endif + static_cast<TabWidgetData*>(data)->updateRegisteredChildren( GTK_WIDGET( parent ) ); + } + + //________________________________________________________________________________ + void TabWidgetData::updateRegisteredChildren( GtkWidget* widget ) + { + + if( !widget ) widget = _target; + if( !widget ) return; + + // cast to notebook and check against number of pages + if( GTK_IS_NOTEBOOK( widget ) ) + { + GtkNotebook* notebook( GTK_NOTEBOOK( widget ) ); + for( int i = 0; i < gtk_notebook_get_n_pages( notebook ); ++i ) + { + + // retrieve page and tab label + GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) ); + registerChild( gtk_notebook_get_tab_label( notebook, page ) ); + } + } + } + + //________________________________________________________________________________ + void TabWidgetData::registerChild( GtkWidget* widget ) + { + + // do nothing if child is invalid (might happen: not checked at calling stage) + if( !widget ) return; + + // make sure widget is not already in map + if( _childrenData.find( widget ) == _childrenData.end() ) + { + + #if TDEGTK_DEBUG + std::cerr << "TDEGTK::TabWidgetData::registerChild - " << widget << std::endl; + #endif + + // allocate new ChildData + ChildData data; + data._destroyId.connect( G_OBJECT(widget), "destroy", G_CALLBACK( childDestroyNotifyEvent ), this ); + data._enterId.connect( G_OBJECT(widget), "enter-notify-event", G_CALLBACK( childCrossingNotifyEvent ), this ); + data._leaveId.connect( G_OBJECT(widget), "leave-notify-event", G_CALLBACK( childCrossingNotifyEvent ), this ); + + if( GTK_IS_CONTAINER( widget ) ) + { data._addId.connect( G_OBJECT(widget), "add", G_CALLBACK( childAddedEvent ), this ); } + + // and insert in map + _childrenData.insert( std::make_pair( widget, data ) ); + + } + + /* + also insert widget's children, recursively. + that should take care of buttons in tabs and other fancy stuff that applications mght do + */ + if( GTK_IS_CONTAINER( widget ) ) + { + + GList *children( gtk_container_get_children( GTK_CONTAINER(widget) ) ); + for( GList* child = g_list_first(children); child; child = g_list_next(child) ) + { registerChild( GTK_WIDGET( child->data ) ); } + + if( children ) g_list_free( children ); + } + + } + + //________________________________________________________________________________ + void TabWidgetData::unregisterChild( GtkWidget* widget ) + { + + ChildDataMap::iterator iter( _childrenData.find( widget ) ); + if( iter == _childrenData.end() ) return; + + #if TDEGTK_DEBUG + std::cerr << "TDEGTK::TabWidgetData::unregisterChild - " << widget << std::endl; + #endif + + iter->second.disconnect(); + _childrenData.erase( iter ); + + } + + //____________________________________________________________________________________________ + gboolean TabWidgetData::childDestroyNotifyEvent( GtkWidget* widget, gpointer data ) + { + static_cast<TabWidgetData*>(data)->unregisterChild( widget ); + return FALSE; + } + + //____________________________________________________________________________________________ + void TabWidgetData::childAddedEvent( GtkContainer* parent, GtkWidget*, gpointer data ) + { + static_cast<TabWidgetData*>(data)->updateRegisteredChildren(); + return; + } + + + //____________________________________________________________________________________________ + gboolean TabWidgetData::childCrossingNotifyEvent( GtkWidget* widget, GdkEventCrossing*, gpointer data ) + { + + // retrieve widget's parent and check type + static_cast<TabWidgetData*>(data)->updateHoveredTab(); + return FALSE; + + } + + //____________________________________________________________________________________________ + void TabWidgetData::ChildData::disconnect( void ) + { + + _destroyId.disconnect(); + _enterId.disconnect(); + _leaveId.disconnect(); + _addId.disconnect(); + + } + + |