1 /*
2 * this file is part of the oxygen gtk engine
3 * Copyright (c) 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
4 *
5 * This  library is free  software; you can  redistribute it and/or
6 * modify it  under  the terms  of the  GNU Lesser  General  Public
7 * License  as published  by the Free  Software  Foundation; either
8 * version 2 of the License, or(at your option ) any later version.
9 *
10 * This library is distributed  in the hope that it will be useful,
11 * but  WITHOUT ANY WARRANTY; without even  the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License  along  with  this library;  if not,  write to  the Free
17 * Software Foundation, Inc., 51  Franklin St, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
19 */
20 
21 #include "oxygentreeviewstatedata.h"
22 #include "../config.h"
23 
24 #include <iostream>
25 
26 namespace Oxygen
27 {
28 
29     //_____________________________________________
connect(GtkWidget * widget)30     void TreeViewStateData::connect( GtkWidget* widget )
31     {
32 
33         #if OXYGEN_DEBUG
34         std::cerr << "Oxygen::TreeViewStateData::connect - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl;
35         #endif
36 
37         _target = widget;
38 
39         // connect timeLines
40         _current._timeLine.connect( (GSourceFunc)delayedUpdate, this );
41         _previous._timeLine.connect( (GSourceFunc)delayedUpdate, this );
42 
43         // set directions
44         _current._timeLine.setDirection( TimeLine::Forward );
45         _previous._timeLine.setDirection( TimeLine::Backward );
46 
47     }
48 
49     //_____________________________________________
disconnect(GtkWidget * widget)50     void TreeViewStateData::disconnect( GtkWidget* widget )
51     {
52         #if OXYGEN_DEBUG
53         std::cerr << "Oxygen::TreeViewStateData::disconnect - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl;
54         #endif
55 
56         _current._timeLine.disconnect();
57         _current._info.clear();
58 
59         _previous._timeLine.disconnect();
60         _previous._info.clear();
61 
62         _target = 0L;
63 
64     }
65 
66     //_____________________________________________
updateState(const Gtk::CellInfo & info,bool state)67     bool TreeViewStateData::updateState( const Gtk::CellInfo& info, bool state )
68     {
69         if( state && info != _current._info )
70         {
71 
72             // stop current animation if running
73             if( _current._timeLine.isRunning() ) _current._timeLine.stop();
74 
75             // stop previous animation if running
76             if( _current._info.isValid() )
77             {
78                 if( _previous._timeLine.isRunning() ) _previous._timeLine.stop();
79 
80                 // update dirty rect, to make sure de-allocated cellInfo gets repainted
81                 if( _previous._info.isValid() && GTK_IS_TREE_VIEW( _target ) )
82                 { _dirtyRect = _previous._info.backgroundRect( GTK_TREE_VIEW( _target ) ); }
83 
84                 // move current tab info to previous
85                 _previous._info = _current._info;
86                 _previous._timeLine.start();
87             }
88 
89             // assign new info to current and start animation
90             _current._info = info;
91             if( _current._info.isValid() ) _current._timeLine.start();
92 
93             return true;
94 
95         } else if( (!state) && info == _current._info ) {
96 
97             // stop current animation if running
98             if( _current._timeLine.isRunning() ) _current._timeLine.stop();
99 
100             // stop previous animation if running
101             if( _previous._timeLine.isRunning() ) _previous._timeLine.stop();
102 
103             // update dirty rect, to make sure de-allocated cellInfo gets repainted
104             if( _previous._info.isValid() && GTK_IS_TREE_VIEW( _target ) )
105             { _dirtyRect = _previous._info.backgroundRect( GTK_TREE_VIEW( _target ) ); }
106 
107             // move current tab info to previous
108             _previous._info = _current._info;
109             if( _previous._info.isValid() ) _previous._timeLine.start();
110 
111             // assign invalid info to current
112             _current._info.clear();
113 
114             return true;
115 
116         } else return false;
117 
118     }
119 
120     //_____________________________________________
dirtyRect(void)121     GdkRectangle TreeViewStateData::dirtyRect( void )
122     {
123 
124         GdkRectangle rect( Gtk::gdk_rectangle() );
125         if( GTK_IS_TREE_VIEW( _target ) )
126         {
127             GtkTreeView* treeView( GTK_TREE_VIEW( _target ) );
128 
129             const GdkRectangle previousRect( _previous._info.backgroundRect( treeView ) );
130             const GdkRectangle currentRect( _current._info.backgroundRect( treeView ) );
131             if( Gtk::gdk_rectangle_is_valid( &previousRect ) && Gtk::gdk_rectangle_is_valid( &currentRect ) )
132             {
133 
134                 gdk_rectangle_union( &previousRect, &currentRect, &rect );
135 
136             } else if( Gtk::gdk_rectangle_is_valid( &previousRect ) ) {
137 
138                 rect = previousRect;
139 
140             } else if( Gtk::gdk_rectangle_is_valid( &currentRect ) ) {
141 
142                 rect = currentRect;
143 
144             }
145 
146             // also union with dirty rect
147             if( Gtk::gdk_rectangle_is_valid( &_dirtyRect ) )
148             {
149                 if( Gtk::gdk_rectangle_is_valid( &rect ) ) gdk_rectangle_union( &_dirtyRect, &rect, &rect );
150                 else rect = _dirtyRect;
151 
152                 _dirtyRect = Gtk::gdk_rectangle();
153 
154             }
155 
156             // finally convert to widget coordinated
157             gtk_tree_view_convert_bin_window_to_widget_coords(
158                 treeView, rect.x, rect.y,
159                 &rect.x, &rect.y );
160 
161 
162         }
163 
164         return rect;
165 
166     }
167 
168     //_____________________________________________
delayedUpdate(gpointer pointer)169     gboolean TreeViewStateData::delayedUpdate( gpointer pointer )
170     {
171 
172         TreeViewStateData& data( *static_cast<TreeViewStateData*>( pointer ) );
173 
174         if( data._target )
175         {
176             const GdkRectangle rect( data.dirtyRect() );
177             Gtk::gtk_widget_queue_draw( data._target, &rect );
178         }
179 
180         return FALSE;
181 
182     }
183 
184 }
185