From a66a6bbf0a4c7dc521f03a3473fb3f550a4990c9 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Mon, 29 Oct 2012 16:17:27 -0500 Subject: [PATCH] Add tab prelighting support --- tdegtk/Makefile.am | 9 + tdegtk/tdegtk-animations.cpp | 436 ++++++++++++++++++++++++++++++++ tdegtk/tdegtk-animations.h | 337 ++++++++++++++++++++++++ tdegtk/tdegtk-baseengine.cpp | 27 ++ tdegtk/tdegtk-baseengine.h | 83 ++++++ tdegtk/tdegtk-datamap.h | 170 +++++++++++++ tdegtk/tdegtk-draw.cpp | 12 +- tdegtk/tdegtk-genericengine.h | 112 ++++++++ tdegtk/tdegtk-tabwidgetdata.cpp | 308 ++++++++++++++++++++++ tdegtk/tdegtk-tabwidgetdata.h | 189 ++++++++++++++ tdegtk/tdegtk-tabwidgetengine.h | 109 ++++++++ 11 files changed, 1788 insertions(+), 4 deletions(-) create mode 100644 tdegtk/tdegtk-animations.cpp create mode 100644 tdegtk/tdegtk-animations.h create mode 100644 tdegtk/tdegtk-baseengine.cpp create mode 100644 tdegtk/tdegtk-baseengine.h create mode 100644 tdegtk/tdegtk-datamap.h create mode 100644 tdegtk/tdegtk-genericengine.h create mode 100644 tdegtk/tdegtk-tabwidgetdata.cpp create mode 100644 tdegtk/tdegtk-tabwidgetdata.h create mode 100644 tdegtk/tdegtk-tabwidgetengine.h diff --git a/tdegtk/Makefile.am b/tdegtk/Makefile.am index 26f45dd..4d18449 100644 --- a/tdegtk/Makefile.am +++ b/tdegtk/Makefile.am @@ -11,6 +11,12 @@ source_h = \ $(srcdir)/tdegtk-signals.h \ $(srcdir)/tdegtk-widgetlookup.h \ $(srcdir)/tdegtk-utils.h \ + $(srcdir)/tdegtk-tabwidgetdata.h \ + $(srcdir)/tdegtk-animations.h \ + $(srcdir)/tdegtk-datamap.h \ + $(srcdir)/tdegtk-baseengine.h \ + $(srcdir)/tdegtk-genericengine.h \ + $(srcdir)/tdegtk-tabwidgetengine.h \ $(srcdir)/tdegtk-types.h source_c = \ @@ -25,6 +31,9 @@ source_c = \ $(srcdir)/tdegtk-signals.cpp \ $(srcdir)/tdegtk-widgetlookup.cpp \ $(srcdir)/tdegtk-utils.cpp \ + $(srcdir)/tdegtk-tabwidgetdata.cpp \ + $(srcdir)/tdegtk-animations.cpp \ + $(srcdir)/tdegtk-baseengine.cpp \ $(srcdir)/tdegtk-theme.cpp enginedir = $(libdir)/gtk-3.0/$(GTK_VERSION)/theming-engines diff --git a/tdegtk/tdegtk-animations.cpp b/tdegtk/tdegtk-animations.cpp new file mode 100644 index 0000000..54aea87 --- /dev/null +++ b/tdegtk/tdegtk-animations.cpp @@ -0,0 +1,436 @@ +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa +* Copyright (c) 2010 Ruslan Kabatsayev +* +* 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-animations.h" +#include "tdegtk-utils.h" +#include "../config.h" + +#include +#include + + //_________________________________________ + Animations::Animations( void ): + _innerShadowsEnabled( true ), + _hooksInitialized( false ) + { + #if OXYGEN_DEBUG + std::cerr << "Oxygen::Animations::Animations" << std::endl; + #endif + + // create engines +#if 0 + registerEngine( _backgroundHintEngine = new BackgroundHintEngine( this ) ); + registerEngine( _comboBoxEngine = new ComboBoxEngine( this ) ); + registerEngine( _comboBoxEntryEngine = new ComboBoxEntryEngine( this ) ); + registerEngine( _dialogEngine = new DialogEngine( this ) ); + registerEngine( _groupBoxEngine = new GroupBoxEngine( this ) ); + registerEngine( _groupBoxLabelEngine = new GroupBoxLabelEngine( this ) ); + registerEngine( _hoverEngine = new HoverEngine( this ) ); + registerEngine( _mainWindowEngine = new MainWindowEngine( this ) ); + registerEngine( _menuItemEngine = new MenuItemEngine( this ) ); + registerEngine( _panedEngine = new PanedEngine( this ) ); + registerEngine( _scrollBarEngine = new ScrollBarEngine( this ) ); + registerEngine( _scrolledWindowEngine = new ScrolledWindowEngine( this ) ); + registerEngine( _innerShadowEngine = new InnerShadowEngine( this ) ); +#endif + registerEngine( _tabWidgetEngine = new TabWidgetEngine( this ) ); +#if 0 + registerEngine( _treeViewEngine = new TreeViewEngine( this ) ); + registerEngine( _widgetSizeEngine = new WidgetSizeEngine( this ) ); + + // animations specific engines + registerEngine( _widgetStateEngine = new WidgetStateEngine( this ) ); + registerEngine( _arrowStateEngine = new ArrowStateEngine( this ) ); + registerEngine( _scrollBarStateEngine = new ScrollBarStateEngine( this ) ); + registerEngine( _tabWidgetStateEngine = new TabWidgetStateEngine( this ) ); + registerEngine( _treeViewStateEngine = new TreeViewStateEngine( this ) ); + registerEngine( _menuBarStateEngine = new MenuBarStateEngine( this ) ); + registerEngine( _menuStateEngine = new MenuStateEngine( this ) ); + registerEngine( _toolBarStateEngine = new ToolBarStateEngine( this ) ); +#endif + + } + + //____________________________________________________________________________________________ + Animations::~Animations( void ) + { + #if OXYGEN_DEBUG + std::cerr << "Oxygen::Animations::~Animations" << std::endl; + #endif + + // delete all engines + for( BaseEngine::List::iterator iter = _engines.begin(); iter != _engines.end(); ++iter ) + { delete *iter; } + + // disconnect all signals from map + for( WidgetMap::iterator iter = _allWidgets.begin(); iter != _allWidgets.end(); iter++ ) + { iter->second.disconnect(); } + + // clear hooks + _backgroundHintHook.disconnect(); + _sizeAllocationHook.disconnect(); + _realizationHook.disconnect(); + _innerShadowHook.disconnect(); + + } + +#if 0 + //_________________________________________ + void Animations::initialize( const QtSettings& settings ) + { + + const bool animationsEnabled( settings.animationsEnabled() ); + + // pass animations configuration to engines + widgetStateEngine().setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); + widgetStateEngine().setDuration( settings.genericAnimationsDuration() ); + + arrowStateEngine().setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); + arrowStateEngine().setDuration( settings.genericAnimationsDuration() ); + + scrollBarStateEngine().setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); + scrollBarStateEngine().setDuration( settings.genericAnimationsDuration() ); + + tabWidgetStateEngine().setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); + tabWidgetStateEngine().setDuration( settings.genericAnimationsDuration() ); + + treeViewStateEngine().setEnabled( animationsEnabled && settings.genericAnimationsEnabled() ); + treeViewStateEngine().setDuration( settings.genericAnimationsDuration() ); + + menuBarStateEngine().setAnimationsEnabled( animationsEnabled && (settings.menuBarAnimationType() != None) ); + menuBarStateEngine().setFollowMouse( settings.menuBarAnimationType() == FollowMouse ); + menuBarStateEngine().setDuration( settings.menuBarAnimationsDuration() ); + menuBarStateEngine().setFollowMouseAnimationsDuration( settings.menuBarFollowMouseAnimationsDuration() ); + + menuStateEngine().setEnabled( animationsEnabled && (settings.menuAnimationType() != None) ); + menuStateEngine().setFollowMouse( settings.menuAnimationType() == FollowMouse ); + menuStateEngine().setDuration( settings.menuAnimationsDuration() ); + menuStateEngine().setFollowMouseAnimationsDuration( settings.menuFollowMouseAnimationsDuration() ); + + // for now, only Fade animations mode is supported for toolbar animations + toolBarStateEngine().setEnabled( animationsEnabled && (settings.toolBarAnimationType() != None) ); + toolBarStateEngine().setFollowMouse( settings.toolBarAnimationType() == FollowMouse ); + toolBarStateEngine().setDuration( settings.genericAnimationsDuration() ); + toolBarStateEngine().setFollowMouseAnimationsDuration( settings.toolBarAnimationsDuration() ); + + } +#endif + + //____________________________________________________________________________________________ + void Animations::initializeHooks( void ) + { + if( _hooksInitialized ) return; + +#if 0 + _backgroundHintHook.connect( "realize", (GSignalEmissionHook)backgroundHintHook, this ); + + #if ENABLE_INNER_SHADOWS_HACK + if(!getenv("OXYGEN_DISABLE_INNER_SHADOWS_HACK")) + { _innerShadowHook.connect( "realize", (GSignalEmissionHook)innerShadowHook, this ); } + #endif + +#endif + + _sizeAllocationHook.connect( "size-allocate", (GSignalEmissionHook)sizeAllocationHook, this ); + _realizationHook.connect( "realize", (GSignalEmissionHook)realizationHook, this ); + + _hooksInitialized = true; + } + + //____________________________________________________________________________________________ + bool Animations::registerWidget( GtkWidget* widget ) + { + + if( _allWidgets.find( widget ) != _allWidgets.end() ) return false; + + #if OXYGEN_DEBUG + std::cerr << "Oxygen::Animations::registerWidget - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; + #endif + + Signal destroyId; + destroyId.connect( G_OBJECT( widget ), "destroy", G_CALLBACK( destroyNotifyEvent ), this ); + _allWidgets.insert( std::make_pair( widget, destroyId ) ); + return true; + + } + + //____________________________________________________________________________________________ + void Animations::unregisterWidget( GtkWidget* widget ) + { + + #if OXYGEN_DEBUG + std::cerr << "Oxygen::Animations::unregisterWidget - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; + #endif + + // find in map + WidgetMap::iterator iter( _allWidgets.find( widget ) ); + assert( iter != _allWidgets.end() ); + + // disconnect signal + iter->second.disconnect(); + + // erase from map + _allWidgets.erase( widget ); + + // erase from all maps + for( BaseEngine::List::iterator iter = _engines.begin(); iter != _engines.end(); ++iter ) + { (*iter)->unregisterWidget( widget ); } + + } + + //____________________________________________________________________________________________ + void Animations::setEnabled( bool value ) + { + + for( BaseEngine::List::iterator iter = _engines.begin(); iter != _engines.end(); ++iter ) + { (*iter)->setEnabled( value ); } + + } + + //____________________________________________________________________________________________ + gboolean Animations::destroyNotifyEvent( GtkWidget* widget, gpointer data ) + { + static_cast(data)->unregisterWidget( widget ); + return FALSE; + } + + //____________________________________________________________________________________________ + gboolean Animations::sizeAllocationHook( GSignalInvocationHint*, guint, const GValue* params, gpointer data ) + { + + // get widget from params + GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); + + // check type + if( !GTK_IS_WIDGET( widget ) ) return FALSE; + + // comboboxes + /* + need to force the wrap-width property to 0, + otherwise the "appears-as-list" flag is not respected, which additionally breaks the widget rendering. + This has to be done soon enoug to avoid crash with latest gtk3 versions + */ + if( + GTK_IS_COMBO_BOX( widget ) && + Gtk::gtk_combobox_appears_as_list( widget ) && + !gtk_combo_box_get_has_entry( GTK_COMBO_BOX( widget ) ) ) + { + gtk_combo_box_set_wrap_width( GTK_COMBO_BOX( widget ), 0 ); + return TRUE; + } + + #if GTK_CHECK_VERSION( 3, 5, 0 ) + /* + HACK: Somehow, style_updated method for GtkRange widgets is not called anymore + as soon as we (oxygen-gtk) install our hooks. This prevents some settings to be + properly initialized, such as the slider length, or the arrows for scrollbars. + Therefore we explicitly call the styleUpdated function ourselves. + */ + if( GTK_IS_RANGE( widget ) ) + { + // get class + GtkWidgetClass* widgetClass = GTK_WIDGET_GET_CLASS( widget ); + if( widgetClass && widgetClass->style_updated ) + { (*widgetClass->style_updated)(widget); } + } + #endif + + // groupbox labels + #if ENABLE_GROUPBOX_HACK + if( static_cast( data )->groupBoxLabelEngine().contains( widget ) ) + { + static_cast( data )->groupBoxLabelEngine().adjustSize( widget ); + return TRUE; + } + #endif + + #if ENABLE_COMBOBOX_LIST_RESIZE + // comboboxes + if( !GTK_IS_WINDOW( widget ) ) return TRUE; + + GtkWindow* window( GTK_WINDOW( widget ) ); + if( gtk_window_get_type_hint( window ) != GDK_WINDOW_TYPE_HINT_COMBO ) return TRUE; + + Animations& animations( *static_cast(data) ); + GtkWidget* combobox = animations.comboBoxEngine().find( widget ); + if( !combobox ) combobox = animations.comboBoxEntryEngine().find( widget ); + if( !combobox ) return true; + + int w, h; + gtk_window_get_size( window, &w, &h ); + + gint sourceX, sourceY; + gint targetX, targetY; + gtk_window_get_position( window, &sourceX, &sourceY ); + gdk_window_get_origin( gtk_widget_get_window( combobox ), &targetX, &targetY ); + + // store allocations + const GtkAllocation comboAllocation( Gtk::gtk_widget_get_allocation( combobox ) ); + const GtkAllocation widgetAllocation( Gtk::gtk_widget_get_allocation( widget ) ); + + const bool widthChanged( widgetAllocation.width != comboAllocation.width - 6 ); + const bool positionChanged( sourceX != targetX + comboAllocation.x + 3 ); + + #if OXYGEN_DEBUG + std::cerr + << "Animations::comboBoxHook -" + << " widget: " << widget + << " widthChanged: " << widthChanged + << " positionChanged: " << positionChanged + << std::endl; + #endif + + int uglyShadowWidth=!Gtk::gdk_default_screen_is_composited(); + + // perform move-resize + if( widthChanged && positionChanged ) + { + + gdk_window_move_resize( + gtk_widget_get_window( widget ), + targetX + comboAllocation.x + 3 - uglyShadowWidth, sourceY, + comboAllocation.width - 6 + 2*uglyShadowWidth, widgetAllocation.height ); + + } else if( widthChanged ) { + + gdk_window_resize( + gtk_widget_get_window( widget ), + comboAllocation.width - 6 + 2*uglyShadowWidth, widgetAllocation.height ); + + } else if( positionChanged ) { + + gdk_window_move( + gtk_widget_get_window( widget ), + targetX + comboAllocation.x + 3 - uglyShadowWidth, sourceY ); + + } + + #endif + + return true; + + } + +#if 0 + //____________________________________________________________________________________________ + gboolean Animations::backgroundHintHook( GSignalInvocationHint*, guint, const GValue* params, gpointer data ) + { + // get widget from params + GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); + + // check type + if( !GTK_IS_WIDGET( widget ) ) return FALSE; + if( !GTK_IS_WINDOW( widget ) ) return TRUE; + + Animations& animations( *static_cast(data) ); + animations.backgroundHintEngine().registerWidget( widget ); + + return TRUE; + } + + //____________________________________________________________________________________________ + gboolean Animations::innerShadowHook( GSignalInvocationHint*, guint, const GValue* params, gpointer data ) + { + + // get widget from params + GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); + + // check type + if( !GTK_IS_WIDGET( widget ) ) return FALSE; + + // check enabled state + Animations& animations( *static_cast(data) ); + if( !animations.innerShadowsEnabled() ) return TRUE; + + // blacklist + if( Gtk::g_object_is_a( G_OBJECT( widget ), "SwtFixed" ) ) return TRUE; + if( Gtk::g_object_is_a( G_OBJECT( widget ), "GtkPizza" ) ) return TRUE; + if( Gtk::g_object_is_a( G_OBJECT( widget ), "MessageList") ) return TRUE; + + GtkWidget* parent(gtk_widget_get_parent(widget)); + if( !GTK_IS_SCROLLED_WINDOW( parent ) ) return TRUE; + + GtkWidget* child(gtk_bin_get_child(GTK_BIN(parent))); + if(child!=widget) return TRUE; + + #if OXYGEN_DEBUG + std::cerr + << "Oxygen::Animations::innerShadowHook -" + << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME(widget) << ")" + << " parent: " << parent << " (" << G_OBJECT_TYPE_NAME(parent) << ")" + << " widget path: " << Gtk::gtk_widget_path( widget ) + << " isTreeView: " << (GTK_IS_TREE_VIEW(widget)?"true":"false") + << " isTextView: " << (GTK_IS_TEXT_VIEW(widget)?"true":"false") + << std::endl; + #endif + + animations.innerShadowEngine().registerWidget( parent ); + animations.innerShadowEngine().registerChild( parent, widget ); + + return TRUE; + + } +#endif + + //____________________________________________________________________________________________ + gboolean Animations::realizationHook( GSignalInvocationHint*, guint, const GValue* params, gpointer data ) + { + + // get widget from params + GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); + + // check type + if( !GTK_IS_WIDGET( widget ) ) return FALSE; + + if( GTK_IS_NOTEBOOK( widget ) ) + { gtk_notebook_set_show_border( GTK_NOTEBOOK(widget), FALSE ); } + + #if ENABLE_GROUPBOX_HACK + if( GTK_IS_LABEL( widget ) && GTK_IS_FRAME( gtk_widget_get_parent( widget ) ) ) + { + + GtkFrame *frame( GTK_FRAME( gtk_widget_get_parent( widget ) ) ); + if( widget == gtk_frame_get_label_widget( frame ) && !Gtk::gtk_widget_find_parent( widget, "GtkPizza" ) ) + { + #if OXYGEN_DEBUG + std::cout + << "Oxygen::Animations::realizationHook -" + << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" + << " parent: " << frame << " (" << G_OBJECT_TYPE_NAME( frame ) << ")" + << std::endl; + #endif + + // modify alignment + gtk_frame_set_label_align( frame, 0.5, 0.0 ); + gtk_frame_set_shadow_type( frame, GTK_SHADOW_OUT ); + + // register to engine + static_cast( data )->groupBoxLabelEngine().registerWidget( widget ); + static_cast( data )->groupBoxLabelEngine().adjustSize( widget ); + + } + + } + #endif + + return TRUE; + + } diff --git a/tdegtk/tdegtk-animations.h b/tdegtk/tdegtk-animations.h new file mode 100644 index 0000000..17fc873 --- /dev/null +++ b/tdegtk/tdegtk-animations.h @@ -0,0 +1,337 @@ +#ifndef tdegtk_animations_h +#define tdegtk_animations_h + +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa +* +* 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-arrowstateengine.h" +// #include "tdegtk-backgroundhintengine.h" +#include "tdegtk-baseengine.h" +// #include "tdegtk-comboboxengine.h" +// #include "tdegtk-comboboxentryengine.h" +// #include "tdegtk-dialogengine.h" +// #include "tdegtk-groupboxengine.h" +// #include "tdegtk-groupboxlabelengine.h" +#include "tdegtk-hooks.h" +// #include "tdegtk-hoverengine.h" +// #include "tdegtk-mainwindowengine.h" +// #include "tdegtk-menubarstateengine.h" +// #include "tdegtk-menuitemengine.h" +// #include "tdegtk-menustateengine.h" +// #include "tdegtk-panedengine.h" +// #include "tdegtk-scrollbarengine.h" +// #include "tdegtk-scrollbarstateengine.h" +// #include "tdegtk-scrolledwindowengine.h" +// #include "tdegtk-innershadowengine.h" +#include "tdegtk-signals.h" +#include "tdegtk-tabwidgetengine.h" +// #include "tdegtk-tabwidgetstateengine.h" +// #include "tdegtk-toolbarstateengine.h" +// #include "tdegtk-treeviewengine.h" +// #include "tdegtk-treeviewstateengine.h" +// #include "tdegtk-widgetsizeengine.h" +// #include "tdegtk-widgetstateengine.h" + +#include +#include +#include + + //! keeps track of all animation engines + class Animations + { + + public: + + //! constructor + Animations( void ); + + //! destructor + virtual ~Animations( void ); + + //! initialize settings +// void initialize( const QtSettings& ); + + //! initialize hooks + void initializeHooks( void ); + + //! unregister widget + bool registerWidget( GtkWidget* ); + + //! unregister widget + void unregisterWidget( GtkWidget* ); + + //! enabled state + void setEnabled( bool value ); + +#if 0 + //! inner shadow enabled state + void setInnerShadowsEnabled( bool value ) + { _innerShadowsEnabled = value; } + + //! inner shadow enabled state + bool innerShadowsEnabled( void ) const + { return _innerShadowsEnabled; } + + //! combobox engine + ComboBoxEngine& comboBoxEngine( void ) const + { return *_comboBoxEngine; } + + //! comboboxentry engine + ComboBoxEntryEngine& comboBoxEntryEngine( void ) const + { return *_comboBoxEntryEngine; } + + //! dialog engine + DialogEngine& dialogEngine( void ) const + { return *_dialogEngine; } + + //! groupbox engine + GroupBoxEngine& groupBoxEngine( void ) const + { return *_groupBoxEngine; } + + //! background hint + BackgroundHintEngine& backgroundHintEngine( void ) const + { return *_backgroundHintEngine; } + + //! main window engine + MainWindowEngine& mainWindowEngine( void ) const + { return *_mainWindowEngine; } + + //! menu item engine + MenuItemEngine& menuItemEngine( void ) const + { return *_menuItemEngine; } + + //! hover engine + HoverEngine& hoverEngine( void ) const + { return *_hoverEngine; } + + //! paned (splitter) engine + PanedEngine& panedEngine( void ) const + { return *_panedEngine; } + + //! scrollbar engine + ScrollBarEngine& scrollBarEngine( void ) const + { return *_scrollBarEngine; } + + //! scrolled window engine + ScrolledWindowEngine& scrolledWindowEngine( void ) const + { return *_scrolledWindowEngine; } + + //! inner shadow engine + InnerShadowEngine& innerShadowEngine( void ) const + { return *_innerShadowEngine; } +#endif + + //! tab widget engine + TabWidgetEngine& tabWidgetEngine( void ) const + { return *_tabWidgetEngine; } + +#if 0 + //! tree view engine + TreeViewEngine& treeViewEngine( void ) const + { return *_treeViewEngine; } + + //! window size engine + WidgetSizeEngine& widgetSizeEngine( void ) const + { return *_widgetSizeEngine; } + + //!@name animations specific engines + //@{ + + //! widget mouse-over and focus animations engine + WidgetStateEngine& widgetStateEngine( void ) const + { return *_widgetStateEngine; } + + //! arrow mouse-over animations engine + ArrowStateEngine& arrowStateEngine( void ) const + { return *_arrowStateEngine; } + + //! scrollbar arrow mouse-over animations engine + ScrollBarStateEngine& scrollBarStateEngine( void ) const + { return *_scrollBarStateEngine; } + + //! notebook tabs mouse-over animations engine + TabWidgetStateEngine& tabWidgetStateEngine( void ) const + { return *_tabWidgetStateEngine; } + + //! tree view mouse-over animation engine + TreeViewStateEngine& treeViewStateEngine( void ) const + { return *_treeViewStateEngine; } + + //! menubar mouse-over animation engine + MenuBarStateEngine& menuBarStateEngine( void ) const + { return *_menuBarStateEngine; } + + //! menu mouse-over animation engine + MenuStateEngine& menuStateEngine( void ) const + { return *_menuStateEngine; } + + //! toolbar mouse-over animation engine + ToolBarStateEngine& toolBarStateEngine( void ) const + { return *_toolBarStateEngine; } +#endif + + //@} + + protected: + + //! register new engine + void registerEngine( BaseEngine* engine ) + { _engines.push_back( engine ); } + +#if 0 + //! groupbox engine + GroupBoxLabelEngine& groupBoxLabelEngine( void ) const + { return *_groupBoxLabelEngine; } +#endif + + //! destruction callback + static gboolean destroyNotifyEvent( GtkWidget*, gpointer ); + + //! combobox list size adjustment hook + static gboolean sizeAllocationHook( GSignalInvocationHint*, guint, const GValue*, gpointer ); + +#if 0 + //! background hint setting hook + static gboolean backgroundHintHook( GSignalInvocationHint*, guint, const GValue*, gpointer ); + + //! inner shadow composited mode enabling hook + static gboolean innerShadowHook( GSignalInvocationHint*, guint, const GValue*, gpointer ); +#endif + + //! widget realize hook + static gboolean realizationHook( GSignalInvocationHint*, guint, const GValue*, gpointer ); + + private: + + //! inner shadow enabled state + bool _innerShadowsEnabled; + + //! list of engines + BaseEngine::List _engines; + +#if 0 + //! background hint engine + BackgroundHintEngine* _backgroundHintEngine; + + //! combobox engine + ComboBoxEngine* _comboBoxEngine; + + //! combobox entry engine + ComboBoxEntryEngine* _comboBoxEntryEngine; + + //! dialog engine + DialogEngine* _dialogEngine; + + //! groupbox engine + GroupBoxEngine* _groupBoxEngine; + + //! groupbox engine + GroupBoxLabelEngine* _groupBoxLabelEngine; + + //! hover engine + HoverEngine* _hoverEngine; + + //! main window engine + MainWindowEngine* _mainWindowEngine; + + //! menu item engine + MenuItemEngine* _menuItemEngine; + + //! paned engine + PanedEngine* _panedEngine; + + //! scrollbar engine + ScrollBarEngine* _scrollBarEngine; + + //! scrolled window engine + ScrolledWindowEngine* _scrolledWindowEngine; + + //! inner shadow engine + InnerShadowEngine* _innerShadowEngine; +#endif + + //! tab widget engine + TabWidgetEngine* _tabWidgetEngine; + +#if 0 + //! tree view engine + TreeViewEngine* _treeViewEngine; + + //! widget size engine + WidgetSizeEngine* _widgetSizeEngine; + + //!@name Animation specific engines + //@{ + + //! widget mouse-over and focus animations engine + WidgetStateEngine* _widgetStateEngine; + + //! arrow mouse-over animations engine + ArrowStateEngine* _arrowStateEngine; + + //! scrollbar arrow mouse-over animations engine + ScrollBarStateEngine* _scrollBarStateEngine; + + //! notebook tabs mouse-over animations engine + TabWidgetStateEngine* _tabWidgetStateEngine; + + //! tree view mouse-over animation engine + TreeViewStateEngine* _treeViewStateEngine; + + //! menubar mouse-over animation engine + MenuBarStateEngine* _menuBarStateEngine; + + //! menu mouse-over animation engine + MenuStateEngine* _menuStateEngine; + + //! toolbar mouse-over animation engine + ToolBarStateEngine* _toolBarStateEngine; +#endif + + //@} + + //!@name hooks + //@{ + + //! true when hooks are initialized + bool _hooksInitialized; + + //! realization hook + Hook _realizationHook; + + //! size allocation hook + Hook _sizeAllocationHook; + + //! background hint hook + Hook _backgroundHintHook; + + //! inner shadows hook + Hook _innerShadowHook; + + //@} + + //! keep track of all registered widgets, and associated destroy callback + typedef std::map< GtkWidget*, Signal > WidgetMap; + WidgetMap _allWidgets; + + }; + +#endif + diff --git a/tdegtk/tdegtk-baseengine.cpp b/tdegtk/tdegtk-baseengine.cpp new file mode 100644 index 0000000..c6eb4de --- /dev/null +++ b/tdegtk/tdegtk-baseengine.cpp @@ -0,0 +1,27 @@ +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa +* +* 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-baseengine.h" +#include "tdegtk-animations.h" + + + //______________________________________________________ + bool BaseEngine::registerWidget( GtkWidget* widget ) + { return parent().registerWidget( widget ); } diff --git a/tdegtk/tdegtk-baseengine.h b/tdegtk/tdegtk-baseengine.h new file mode 100644 index 0000000..85c28d2 --- /dev/null +++ b/tdegtk/tdegtk-baseengine.h @@ -0,0 +1,83 @@ +#ifndef tdegtk_baseengine_h +#define tdegtk_baseengine_h +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa +* +* 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 +#include + + //! forward declaration + class Animations; + + //! base class for all engines + /*! engines map pointers to GtkWidget to some data, needed for animations */ + class BaseEngine + { + public: + + //! constructor + BaseEngine( Animations* parent ): + _parent( parent ), + _enabled( true ) + {} + + virtual ~BaseEngine() + {} + + //! register widget + virtual bool registerWidget( GtkWidget* widget ); + + //! unregister widget + virtual void unregisterWidget( GtkWidget* ) = 0; + + //! engine list + typedef std::vector< BaseEngine* > List; + + //! enable state + /*! returns true if changed */ + virtual bool setEnabled( bool value ) + { + if( _enabled == value ) return false; + _enabled = value; + return true; + } + + //! enable state + bool enabled( void ) const + { return _enabled; } + + protected: + + //! returns parent + virtual Animations& parent( void ) const + { return *_parent; } + + private: + + //! parent + Animations* _parent; + + //! enable flag + bool _enabled; + + }; + +#endif + diff --git a/tdegtk/tdegtk-datamap.h b/tdegtk/tdegtk-datamap.h new file mode 100644 index 0000000..e82cdc0 --- /dev/null +++ b/tdegtk/tdegtk-datamap.h @@ -0,0 +1,170 @@ +#ifndef oxygendatamap_h +#define oxygendatamap_h +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa +* +* 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 +#include +#include + + //! generic class to map data to widgets + /* + Note: I'm not sure about memory management. At some point one might need to allocate the registered + data on the heap rather than on the stack, to be able to safely pass the data pointer around via callbacks. + The current implementation should make that possible without external code change, provided that the map + content is properly deleted (as opposed to erased) in destructor and 'unregister' method. + */ + template + class DataMap + { + + public: + + //! constructor + DataMap( void ): + _lastWidget( 0L ), + _lastData( 0L ) + {} + + virtual ~DataMap(){} + + //! insert new widget + inline T& registerWidget( GtkWidget* widget ) + { + T& data( _map.insert( std::make_pair( widget, T() ) ).first->second ); + _lastWidget = widget; + _lastData = &data; + return data; + } + + //! true if widget is in list + virtual bool contains( GtkWidget* widget ) + { + + // check against last widget + if( widget == _lastWidget ) return true; + + // find in map, returns false if not found + typename Map::iterator iter = _map.find( widget ); + if( iter == _map.end() ) return false; + + // store as last widget/last data, to speed up lookup. + _lastWidget = widget; + _lastData = &iter->second; + return true; + + } + + //! return value + virtual T& value( GtkWidget* widget ) + { + + // check against last widget + if( widget == _lastWidget ) return *_lastData; + + // find in map, abort if not found + typename Map::iterator iter( _map.find( widget ) ); + assert( iter != _map.end() ); + + // store as last widget/last data, to speed up lookup. + _lastWidget = widget; + _lastData = &iter->second; + return iter->second; + + } + + //! erase + virtual void erase( GtkWidget* widget ) + { + + // clear last widget and data, if match + if( _lastWidget == widget ) + { + _lastWidget = 0L; + _lastData = 0L; + } + + // erase from map + _map.erase( widget ); + + } + + //! connect all widgets in map + void connectAll( void ) + { + for( typename Map::iterator iter = _map.begin(); iter != _map.end(); iter++ ) + { iter->second.connect( iter->first ); } + } + + + //! connect all widgets in map + void disconnectAll( void ) + { + for( typename Map::iterator iter = _map.begin(); iter != _map.end(); iter++ ) + { iter->second.disconnect( iter->first ); } + } + + //! erase + virtual void clear( void ) + { + + _lastWidget = 0L; + _lastData = 0L; + _map.clear(); + + } + + //! retrieve internal map + typedef std::map Map; + Map& map( void ) + { return _map; } + + //! retrieve internal map + const Map& map( void ) const + { return _map; } + + protected: + + //! copy constructor is private + DataMap( const DataMap& ) + { assert( false ); } + + //! assignment operator + DataMap& operator = ( const DataMap& ) + { + assert( false ); + return *this; + } + + private: + + //! pointer to last inquired widget + GtkWidget* _lastWidget; + + //! pointer to last retrieved data + T* _lastData; + + //! internal map between widget and data + Map _map; + + }; + +#endif + diff --git a/tdegtk/tdegtk-draw.cpp b/tdegtk/tdegtk-draw.cpp index 77c0b7c..a4788f2 100644 --- a/tdegtk/tdegtk-draw.cpp +++ b/tdegtk/tdegtk-draw.cpp @@ -32,6 +32,7 @@ #include "tdegtk-types.h" #include "tdegtk-widgetlookup.h" #include "tdegtk-utils.h" +#include "tdegtk-animations.h" #include "tqtcairopainter.h" @@ -49,6 +50,7 @@ p.drawRect(x, y, w, h); WidgetLookup m_widgetLookup; +Animations m_animations; // Keep this in sync with gtkToTQPaletteColorGroup() below static TQColorGroup gtkToTQtColorGroup(GtkThemingEngine* engine, GtkStateFlags state) { @@ -662,11 +664,13 @@ tdegtk_draw_extension (DRAW_ARGS, widget = m_widgetLookup.find(cr, path); if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_NOTEBOOK)) { + // Register tabbar with animation engine + m_animations.tabWidgetEngine().registerWidget(widget); + // Check tab properties const int tabIndex = Gtk::gtk_notebook_find_tab(widget, x+width/2, y+height/2); -// Style::instance().animations().tabWidgetEngine().updateTabRect(widget, tabIndex, x, y, width, height); -// bool prelight = (tabIndex == Style::instance().animations().tabWidgetEngine().hoveredTab(widget)); - bool prelight = false; + m_animations.tabWidgetEngine().updateTabRect(widget, tabIndex, x, y, width, height); + bool prelight = (tabIndex == m_animations.tabWidgetEngine().hoveredTab(widget)); GtkNotebook* notebook = GTK_NOTEBOOK(widget); // bool firstTab = (tabIndex == 0); // bool lastTab = (tabIndex == gtk_notebook_get_n_pages(notebook)-1); @@ -725,7 +729,7 @@ tdegtk_draw_extension (DRAW_ARGS, DRAW_FILLED_RECTANGLE_OVER_SPECIFIC_AREA(p2, brush, 0, 0, width, height) // Draw tab - tqApp->style().drawControl(TQStyle::CE_TabBarTab, &p2, ceData, elementFlags, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE) | ((tabIndex==currentPage)?TQStyle::Style_Selected:TQStyle::Style_Default), tabOpt); + tqApp->style().drawControl(TQStyle::CE_TabBarTab, &p2, ceData, elementFlags, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE) | ((tabIndex==currentPage)?TQStyle::Style_Selected:TQStyle::Style_Default) | ((prelight)?TQStyle::Style_MouseOver:TQStyle::Style_Default), tabOpt); cairo_restore(cr); } diff --git a/tdegtk/tdegtk-genericengine.h b/tdegtk/tdegtk-genericengine.h new file mode 100644 index 0000000..236ab60 --- /dev/null +++ b/tdegtk/tdegtk-genericengine.h @@ -0,0 +1,112 @@ +#ifndef tdegtk_genericengine_h +#define tdegtk_genericengine_h +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa +* +* 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-baseengine.h" +#include "tdegtk-datamap.h" + +#include + + //! forward declaration + class Animations; + + //! associates widgets with some type of data + template< typename T> + class GenericEngine: public BaseEngine + { + + public: + + //! constructor + GenericEngine( Animations* widget ): + BaseEngine( widget ) + {} + + //! destructor + virtual ~GenericEngine( void ) + {} + + //! register widget + virtual bool registerWidget( GtkWidget* widget ) + { + if( _data.contains( widget ) ) return false; + if( enabled() ) + { + + T& data( _data.registerWidget( widget ) ); + data.connect( widget ); + + } else _data.registerWidget( widget ); + + BaseEngine::registerWidget( widget ); + return true; + + } + + //! unregister widget + virtual void unregisterWidget( GtkWidget* widget ) + { + if( !_data.contains( widget ) ) return; + _data.value( widget ).disconnect( widget ); + _data.erase( widget ); + } + + //! enabled state + /*! returns true if changed */ + inline virtual bool setEnabled( bool value ); + + //! true if widget is included + virtual bool contains( GtkWidget* widget ) + { return _data.contains( widget ); } + + protected: + + //! return refence to data + virtual DataMap& data( void ) + { return _data; } + + //! return refence to data + virtual const DataMap& data( void ) const + { return _data; } + + private: + + //! map widgets to data + DataMap _data; + + }; + + //________________________________________________________________________ + template< typename T> bool GenericEngine::setEnabled( bool value ) + { + if( enabled() == value ) return false; + + BaseEngine::setEnabled( value ); + if( enabled() ) _data.connectAll(); + else _data.disconnectAll(); + + return true; + + } + +#endif + 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 +* +* 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 +#include +#include + + //________________________________________________________________________________ + 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( data )->updateHoveredTab( widget ); + return FALSE; + + } + + //________________________________________________________________________________ + gboolean TabWidgetData::leaveNotifyEvent( GtkWidget* widget, GdkEventCrossing*, gpointer data ) + { + // reset hovered tab + static_cast( 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(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(data)->unregisterChild( widget ); + return FALSE; + } + + //____________________________________________________________________________________________ + void TabWidgetData::childAddedEvent( GtkContainer* parent, GtkWidget*, gpointer data ) + { + static_cast(data)->updateRegisteredChildren(); + return; + } + + + //____________________________________________________________________________________________ + gboolean TabWidgetData::childCrossingNotifyEvent( GtkWidget* widget, GdkEventCrossing*, gpointer data ) + { + + // retrieve widget's parent and check type + static_cast(data)->updateHoveredTab(); + return FALSE; + + } + + //____________________________________________________________________________________________ + void TabWidgetData::ChildData::disconnect( void ) + { + + _destroyId.disconnect(); + _enterId.disconnect(); + _leaveId.disconnect(); + _addId.disconnect(); + + } + + diff --git a/tdegtk/tdegtk-tabwidgetdata.h b/tdegtk/tdegtk-tabwidgetdata.h new file mode 100644 index 0000000..e7284bf --- /dev/null +++ b/tdegtk/tdegtk-tabwidgetdata.h @@ -0,0 +1,189 @@ +#ifndef tdegtk_tabwidgetdata_h +#define tdegtk_widgetdata_h +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa +* +* 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-signals.h" + +#include +#include +#include + + //! detects and stores tab widget hovered tab + class TabWidgetData + { + + public: + + //! constructor + TabWidgetData( void ): + _target(0L), + _hoveredTab(-1), + _dragInProgress( false ), + _dirty( false ) + {} + + //! destructor + virtual ~TabWidgetData( void ) + { disconnect( _target ); } + + //! setup connections + void connect( GtkWidget* ); + + //! disconnect + void disconnect( GtkWidget* ); + + //!@name modifiers + //@{ + + //! update tab rectangle + /* this is used to decide when a tab is hovered or not */ + void updateTabRect( GtkWidget*, int, const GdkRectangle& ); + + //! update hovered tab + void updateHoveredTab( GtkWidget* = 0L ); + + //! true when drag is in progress + void setDragInProgress( bool value ) + { _dragInProgress = value; } + + //! toggle dirty state + void toggleDirty( void ) + { setDirty( !isDirty() ); } + + //! mark as dirty + void setDirty( bool ); + + //@} + + //@name accessors + //@{ + + //! true if hovered + int hoveredTab( void ) const + { return _hoveredTab; } + + //! true when drag is in progress + bool dragInProgress( void ) const + { return _dragInProgress; } + + //! true if is dirty + bool isDirty( void ) const + { return _dirty; } + + //! returns true if provided point is in one tab of the widget + bool isInTab( int x, int y ) const; + + //@] + + protected: + + //! set current tab + void setHoveredTab( GtkWidget*, int ); + + //! child registration + //@{ + + void updateRegisteredChildren( GtkWidget* = 0L ); + void registerChild( GtkWidget* ); + void unregisterChild( GtkWidget* ); + + //@} + + //!@name static callbacks + //@{ + static gboolean motionNotifyEvent( GtkWidget*, GdkEventMotion*, gpointer ); + static gboolean leaveNotifyEvent( GtkWidget*, GdkEventCrossing*, gpointer ); + static void pageAddedEvent( GtkNotebook*, GtkWidget*, guint, gpointer ); + static gboolean childDestroyNotifyEvent( GtkWidget*, gpointer ); + static gboolean childCrossingNotifyEvent( GtkWidget*, GdkEventCrossing*, gpointer ); + static void childAddedEvent( GtkContainer*, GtkWidget*, gpointer ); + //@} + + private: + + //! default tabRect size + GdkRectangle defaultRect( void ) const + { + GdkRectangle out = {0, 0, -1, -1}; + return out; + } + + //! target widget + GtkWidget* _target; + + //!@name callbacks IDs + //@{ + Signal _motionId; + Signal _leaveId; + Signal _pageAddedId; + //@} + + //! index of currently hovered tab + int _hoveredTab; + + //! true when there is a drag in progress + bool _dragInProgress; + + //! true when tabbar is dirty + /*! a repaint is triggered of the full tabbar when set to true. + This forces the tabbar base to be redrawn event if the selected tab + has not been primarily damaged */ + bool _dirty; + + //! store rectangles matching tabs + typedef std::vector RectangleList; + RectangleList _tabRects; + + //! child data + /*! + one must keep track of the tab widgets children enter/leave event + to properly update tab hover because some tabs have embedded children. + This is notably the case for gimp, nautilus (in tabbed mode), etc. + */ + class ChildData + { + public: + + //! constructor + ChildData( void ) + {} + + //! destructor + virtual ~ChildData( void ) + {} + + //! disconnect all signals + void disconnect( void ); + + Signal _destroyId; + Signal _addId; + Signal _enterId; + Signal _leaveId; + }; + + //! map registered children and corresponding data + typedef std::map ChildDataMap; + ChildDataMap _childrenData; + + }; + +#endif + diff --git a/tdegtk/tdegtk-tabwidgetengine.h b/tdegtk/tdegtk-tabwidgetengine.h new file mode 100644 index 0000000..6ec74d9 --- /dev/null +++ b/tdegtk/tdegtk-tabwidgetengine.h @@ -0,0 +1,109 @@ +#ifndef tdegtk_tabwidgetengine_h +#define tdegtk_tabwidgetengine_h +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa +* +* 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-genericengine.h" +#include "tdegtk-datamap.h" +#include "tdegtk-tabwidgetdata.h" + +#include + + //! forward declaration + class Animations; + + //! stores data associated to editable tabwidgetes + /*! + ensures that the text entry and the button of editable tabwidgetes + gets hovered and focus flags at the same time + */ + class TabWidgetEngine: public GenericEngine + { + + public: + + //! constructor + TabWidgetEngine( Animations* widget ): + GenericEngine( widget ) + {} + + //! destructor + virtual ~TabWidgetEngine( void ) + {} + + //!@name modifiers + //@{ + + //! returns hovered tab, if any + void updateTabRect( GtkWidget* widget, int index, int x, int y, int w, int h ) + { + GdkRectangle local = { x, y, w, h }; + return data().value( widget ).updateTabRect( widget, index, local ); + } + + //! returns hovered tab, if any + void updateTabRect( GtkWidget* widget, int index, const GdkRectangle& r ) + { return data().value( widget ).updateTabRect( widget, index, r ); } + + //! returns hovered tab, if any + void updateHoveredTab( GtkWidget* widget ) + { return data().value( widget ).updateHoveredTab( widget ); } + + //! true when drag is in progress + void setDragInProgress( GtkWidget* widget, bool value ) + { data().value( widget ).setDragInProgress( value ); } + + //! toggle dirty state + void toggleDirty( GtkWidget* widget ) + { data().value( widget ).toggleDirty(); } + + //! true when tabbar is dirty + void setDirty( GtkWidget* widget, bool value ) + { data().value( widget ).setDirty( value ); } + + //@} + + //!@name accessors + //@{ + + //! returns hovered tab, if any + int hoveredTab( GtkWidget* widget ) + { return data().value( widget ).hoveredTab(); } + + //! returns true if provided point is in one tab of the widget + bool isInTab( GtkWidget* widget, int x, int y ) + { return data().value( widget ).isInTab( x, y ); } + + //! true when drag is in progress + bool dragInProgress( GtkWidget* widget ) + { return data().value( widget ).dragInProgress(); } + + //! true when tabbar is dirty + bool isDirty( GtkWidget* widget ) + { return data().value( widget ).isDirty(); } + + //@} + + }; + + +#endif +