File indexing completed on 2024-04-28 05:32:11

0001 /*
0002     this file is part of the oxygen gtk engine
0003     SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "oxygengtkcellinfo.h"
0009 #include "oxygengeometry.h"
0010 #include "oxygengtkutils.h"
0011 
0012 #include <iostream>
0013 #include <cassert>
0014 
0015 namespace Oxygen
0016 {
0017 
0018     //____________________________________________________________________________
0019     Gtk::CellInfo::CellInfo( GtkTreeView* treeView, int x, int y, int w, int h ):
0020         _path(0L),
0021         _column(-1)
0022     {
0023         GtkTreeViewColumn *column( 0L );
0024 
0025         /*
0026         four attempts are made to get the path from any corner of the rectangle passed in arguments.
0027         This is necessary to handle half-hidden cells
0028         */
0029         gtk_tree_view_get_path_at_pos( treeView, (gint)x+1, (gint)y+1, &_path, &column, 0L, 0L );
0030         if( !_path ) {
0031             gtk_tree_view_get_path_at_pos( treeView, (gint)x+1, (gint)y+h-1, &_path, &column, 0L, 0L );
0032             if( !_path ) {
0033                 gtk_tree_view_get_path_at_pos( treeView, (gint)x+w-1, (gint)y+1, &_path, &column, 0L, 0L );
0034                 if( !_path ) {
0035                     gtk_tree_view_get_path_at_pos( treeView, (gint)x+w-1, (gint)y+h-1, &_path, &column, 0L, 0L );
0036                     if( !_path ) return;
0037                 }
0038             }
0039         }
0040 
0041         _column = indexOfColumn( treeView, column );
0042     }
0043 
0044     //____________________________________________________________________________
0045     bool Gtk::CellInfo::isLastVisibleColumn( GtkTreeView* treeView ) const
0046     {
0047         bool isLast( true );
0048         GList* columns( gtk_tree_view_get_columns( treeView ) );
0049         for( GList *child = g_list_nth( columns, _column ); ( child = g_list_next( child ) ); )
0050         {
0051             if( !GTK_IS_TREE_VIEW_COLUMN( child->data ) ) continue;
0052             GtkTreeViewColumn* column( GTK_TREE_VIEW_COLUMN( child->data ) );
0053             if( gtk_tree_view_column_get_visible( column ) )
0054             {
0055                 isLast = false;
0056                 break;
0057             }
0058 
0059         }
0060 
0061         if( columns ) g_list_free( columns );
0062         return isLast;
0063     }
0064 
0065     //____________________________________________________________________________
0066     bool Gtk::CellInfo::isFirstVisibleColumn( GtkTreeView* treeView ) const
0067     {
0068         bool isFirst( true );
0069         GList* columns( gtk_tree_view_get_columns( treeView ) );
0070         for( GList *child = g_list_nth( columns, _column ); ( child = g_list_previous( child ) ); )
0071         {
0072             if( !GTK_IS_TREE_VIEW_COLUMN( child->data ) ) continue;
0073             GtkTreeViewColumn* column( GTK_TREE_VIEW_COLUMN( child->data ) );
0074             if( gtk_tree_view_column_get_visible( column ) )
0075             {
0076                 isFirst = false;
0077                 break;
0078             }
0079 
0080         }
0081 
0082         if( columns ) g_list_free( columns );
0083         return isFirst;
0084     }
0085 
0086     //____________________________________________________________________________
0087     bool Gtk::CellInfo::isLeftOfExpanderColumn( GtkTreeView* treeView ) const
0088     {
0089         // check expander column
0090         GtkTreeViewColumn* expanderColumn( gtk_tree_view_get_expander_column( treeView ) );
0091         return expanderColumn && _column < indexOfColumn( treeView, expanderColumn );
0092 
0093     }
0094 
0095     //____________________________________________________________________________
0096     bool Gtk::CellInfo::hasParent( GtkTreeView* treeView ) const
0097     {
0098         // check treeview and path
0099         if( !( treeView && _path ) ) return false;
0100 
0101         // get model
0102         GtkTreeModel* model( gtk_tree_view_get_model( treeView ) );
0103         if( !model ) return false;
0104 
0105         // get iterator
0106         GtkTreeIter iter;
0107         if( !gtk_tree_model_get_iter( model, &iter, _path ) ) return false;
0108 
0109         GtkTreeIter parent;
0110         return gtk_tree_model_iter_parent( model, &parent, &iter );
0111 
0112     }
0113 
0114     //____________________________________________________________________________
0115     Gtk::CellInfo Gtk::CellInfo::parent( void ) const
0116     {
0117         CellInfo out;
0118         out._column = _column;
0119 
0120         // check path
0121         if( !_path ) return out;
0122 
0123         GtkTreePath* parent( gtk_tree_path_copy( _path ) );
0124         if( gtk_tree_path_up( parent ) ) out._path = parent;
0125         else gtk_tree_path_free( parent );
0126 
0127         return out;
0128 
0129     }
0130 
0131     //____________________________________________________________________________
0132     bool Gtk::CellInfo::hasChildren( GtkTreeView* treeView ) const
0133     {
0134         // check treeview and path
0135         if( !( treeView && _path ) ) return false;
0136 
0137         // get model
0138         GtkTreeModel* model( gtk_tree_view_get_model( treeView ) );
0139         if( !model ) return false;
0140 
0141         // get iterator
0142         GtkTreeIter iter;
0143         if( !gtk_tree_model_get_iter( model, &iter, _path ) ) return false;
0144         return gtk_tree_model_iter_has_child( model, &iter );
0145 
0146     }
0147 
0148     //____________________________________________________________________________
0149     bool Gtk::CellInfo::isLast( GtkTreeView* treeView ) const
0150     {
0151        // check treeview and path
0152         if( !( treeView && _path ) ) return false;
0153 
0154         // get model
0155         GtkTreeModel* model( gtk_tree_view_get_model( treeView ) );
0156         if( !model ) return false;
0157 
0158         // get iterator
0159         GtkTreeIter iter;
0160         if( !gtk_tree_model_get_iter( model, &iter, _path ) ) return false;
0161         return !gtk_tree_model_iter_next( model, &iter );
0162     }
0163 
0164     //____________________________________________________________________________
0165     GdkRectangle Gtk::CellInfo::backgroundRect( GtkTreeView* treeView ) const
0166     {
0167         GdkRectangle out( Gtk::gdk_rectangle() );
0168         if( treeView && isValid() )
0169         { gtk_tree_view_get_background_area( treeView, _path, gtk_tree_view_get_column( treeView, _column ), &out ); }
0170 
0171         return out;
0172 
0173     }
0174 
0175     //____________________________________________________________________________
0176     gint Gtk::CellInfo::indexOfColumn( GtkTreeView* treeView, GtkTreeViewColumn* column )
0177     {
0178         GList* columns( gtk_tree_view_get_columns( treeView ) );
0179         if( !columns ) return -1;
0180         gint index( g_list_index( columns, column ) );
0181         g_list_free( columns );
0182         return index;
0183     }
0184 
0185     //____________________________________________________________________________
0186     Gtk::CellInfoFlags::CellInfoFlags( GtkTreeView* treeView, const CellInfo& cellInfo ):
0187         _depth( cellInfo.depth() ),
0188         _expanderSize(0),
0189         _levelIndent(gtk_tree_view_get_level_indentation(treeView))
0190     {
0191         if( cellInfo.hasParent( treeView ) ) _flags |= HasParent;
0192         if( cellInfo.hasChildren( treeView ) ) _flags |= HasChildren;
0193         if( cellInfo.isLast( treeView ) ) _flags |= IsLast;
0194 
0195         gtk_widget_style_get( GTK_WIDGET( treeView ), "expander-size", &_expanderSize, NULL );
0196 
0197         /*
0198         for every parent of the current cell, one needs to know whether or not
0199         it is the last one at its level, to render the tree lines properly
0200         */
0201         _isLast = std::vector<bool>(_depth, false);
0202 
0203         int index( _depth-1 );
0204         for( CellInfo parent = cellInfo; parent.isValid() && parent.depth() > 0; parent = parent.parent() )
0205         {
0206             assert( index >= 0 );
0207             _isLast[index] = parent.isLast( treeView );
0208             --index;
0209         }
0210 
0211     }
0212 
0213 }