erGtkIconView.c

Go to the documentation of this file.
00001 /**
00002  * \file erGtkIconView.c
00003  * \brief ereader gtk library - GtkIconView object adapted for ereader system
00004  */
00005  
00006 /*
00007  * This file is part of libergtk.
00008  *
00009  * libergtk is free software: you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation, either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * libergtk is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00021  */
00022 
00023 /**
00024  * Copyright (C) 2008 iRex Technologies B.V.
00025  * All rights reserved.
00026  */
00027  
00028 // system include files
00029 #include <string.h>
00030 #include <ctype.h>
00031 #include <gtk/gtk.h>
00032 #include <math.h>
00033 #include <gdk/gdkkeysyms.h>
00034 #include <gtk/gtkprivate.h>
00035 
00036 // ereader library includes
00037 
00038 // local includes
00039 #include "ergtk_log.h"
00040 #include "eri18n.h"
00041 #include "erGtkIconView.h"
00042 #include "gtkiconview_private.h"
00043 
00044 #define UNUSED(x) (void)(x)
00045 
00046 
00047 // The type name of class.
00048 const gchar *type_name = "erGtkIconView";
00049 
00050 // class-specific properties
00051 typedef enum
00052 {
00053     PROP_NOT_USED = 0,   // not sure whether param_id zero is allowed
00054     PROP_NAVIGATE_MODE, // 
00055     NUM_PROPS
00056 } prop_t;
00057 
00058 // instance private data
00059 typedef struct
00060 {
00061     gchar *navigate_mode; // "normal-navigate-mode" doesn't translate.
00062                            // "simple-navigate-mode" translates up/down to left/right.
00063 } erGtkIconViewPrivate;
00064 
00065 static const gchar *PROPNAME_NAVIGATE_MODE = "navigate-mode";
00066 
00067 static const gchar *normal_navigate_mode = "normal-navigate-mode";
00068 static const gchar *simple_navigate_mode = "simple-navigate-mode";
00069 
00070 // local data
00071 static GtkIconViewClass* g_parent_class = NULL;
00072 static guint pre_move_signal = 0;
00073 static guint navigate_cursor_signal = 0;
00074 
00075 // implementation of virtual methods
00076 static void             add_move_bindings       (GtkBindingSet      *binding_set, 
00077                                                  const gchar *navigate_mode);
00078 static void             add_move_binding        (GtkBindingSet      *binding_set,
00079                                                  guint               keyval,
00080                                                  GdkModifierType     modmask,
00081                                                  erGtkIconViewKeyPress navigate);
00082 
00083 static void             remove_move_bindings(GtkBindingSet *binding_set);
00084 static void             remove_move_binding(GtkBindingSet         *binding_set,
00085                                             guint                 keyval,
00086                                             GdkModifierType       modmask);
00087 
00088 static void             force_cursor_present    (erGtkIconView      *er_iconview);
00089 
00090 static void             destroy_impl            (GtkObject          *object);
00091 
00092 // signal handlers
00093 static gboolean         on_pre_move_cursor      (erGtkIconView      *er_iconview,
00094                                                  erGtkIconViewKeyPress navigate);
00095 
00096 static void             on_style_set            (GtkWidget          *widget, 
00097                                                  GtkStyle           *previous_style);
00098 
00099 static void             on_size_allocate        (GtkWidget          *widget, 
00100                                                  GtkAllocation      *allocation);
00101 
00102 static gboolean         on_button_press_event   (GtkWidget          *widget,
00103                                                  GdkEventButton     *event);
00104 
00105 static gboolean         on_button_release_event (GtkWidget          *widget,
00106                                                  GdkEventButton     *event);
00107 
00108 static void             get_property_impl ( GObject    *object,
00109                                             guint       param_id,
00110                                             GValue     *value,
00111                                             GParamSpec *pspec );
00112 
00113 static void             set_property_impl ( GObject      *object,
00114                                             guint         param_id,
00115                                             const GValue *value,
00116                                             GParamSpec   *pspec );
00117 
00118 static void             finalize_impl (GObject *object);
00119 
00120 
00121 static void             on_model_row_changed    (GtkTreeModel       *model,
00122                                                  GtkTreePath        *path,
00123                                                  GtkTreeIter        *iter,
00124                                                  gpointer           user_data);
00125 
00126 static void             on_model_row_inserted   (GtkTreeModel       *model,
00127                                                  GtkTreePath        *path,
00128                                                  GtkTreeIter        *iter,
00129                                                  gpointer           user_data);
00130 
00131 static gboolean         on_focus_out            (GtkWidget          *widget, 
00132                                                  gpointer           data);
00133 /*
00134 static gboolean         on_focus_in             (GtkWidget          *widget, 
00135                                                  gpointer           data);
00136 */
00137 static void             scale_pixbuf            (erGtkIconView      *er_iconview,
00138                                                  GtkTreeModel       *model,
00139                                                  GtkTreeIter        *iter);
00140 
00141 
00142 //
00143 // Mandatory widget functions
00144 //
00145 
00146 static void ergtk_icon_view_class_init(erGtkIconViewClass* klass)
00147 {
00148     LOGPRINTF("entry");
00149 
00150     GObjectClass   *object_class     = (GObjectClass*  )klass;
00151     GtkObjectClass *gtk_object_class = (GtkObjectClass*)klass;
00152     GtkWidgetClass *widget_class     = (GtkWidgetClass*)klass;
00153 
00154     GParamSpec *pspec;
00155     
00156     GtkBindingSet *binding_set;
00157     binding_set = gtk_binding_set_by_class (klass);
00158 
00159     // remember parent class struct, needed for chaining up to parent class
00160     g_parent_class = g_type_class_peek_parent(klass);
00161 
00162     // overload virtual methods
00163     gtk_object_class->destroy = destroy_impl;
00164     widget_class->style_set            = on_style_set;
00165     widget_class->size_allocate        = on_size_allocate;
00166     widget_class->button_press_event   = on_button_press_event;
00167     widget_class->button_release_event = on_button_release_event;
00168     
00169     object_class->get_property = get_property_impl;
00170     object_class->set_property = set_property_impl;
00171     object_class->finalize = finalize_impl;
00172     
00173     // reserve space for instance private data
00174     g_type_class_add_private (klass, sizeof(erGtkIconViewPrivate));
00175 
00176     // install custom properties
00177     // navigate mode
00178     const gchar * default_navigate_mode = normal_navigate_mode;
00179     pspec = g_param_spec_string( PROPNAME_NAVIGATE_MODE,
00180                                  PROPNAME_NAVIGATE_MODE,
00181                                  "Normal or simple navigate mode?",
00182                                  default_navigate_mode,
00183                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
00184     g_object_class_install_property(object_class, PROP_NAVIGATE_MODE, pspec);
00185 
00186     // signal handlers
00187     klass->pre_move_cursor = on_pre_move_cursor;
00188 
00189     // install custom style properties
00190     gtk_widget_class_install_style_property (widget_class,
00191                                              g_param_spec_int ("item-width",
00192                                                                P_("Item width"),
00193                                                                P_("Width in pixels occupied by text and pixbuf"),
00194                                                                G_MININT, G_MAXINT, 0,
00195                                                                GTK_PARAM_READABLE));
00196 
00197     gtk_widget_class_install_style_property (widget_class,
00198                                              g_param_spec_int ("item-height",
00199                                                                P_("Item height"),
00200                                                                P_("Height in pixels occupied by text and pixbuf"),
00201                                                                G_MININT, G_MAXINT, 0,
00202                                                                GTK_PARAM_READABLE));
00203 
00204     gtk_widget_class_install_style_property (widget_class,
00205                                              g_param_spec_int ("item-n-textlines",
00206                                                                P_("Textlines for item"),
00207                                                                P_("Number of textlines in item"),
00208                                                                G_MININT, G_MAXINT, 0,
00209                                                                GTK_PARAM_READABLE));
00210 
00211     // install custom signals
00212     pre_move_signal = g_signal_new ("pre-move-cursor",
00213                                     G_TYPE_FROM_CLASS (object_class),
00214                                     G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
00215                                     G_STRUCT_OFFSET (erGtkIconViewClass, pre_move_cursor),
00216                                     NULL, NULL,
00217                                     gtk_marshal_VOID__ENUM,
00218                                     G_TYPE_NONE,  
00219                                     1,            
00220                                     G_TYPE_INT);
00221 
00222     navigate_cursor_signal = g_signal_new("navigate-cursor",
00223                                           G_TYPE_FROM_CLASS (object_class),
00224                                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
00225                                           0,
00226                                           NULL, NULL,
00227                                           gtk_marshal_VOID__ENUM,
00228                                           G_TYPE_NONE,  
00229                                           1,            
00230                                           G_TYPE_INT);
00231     
00232     // custom key bindings
00233     // add_move_bindings(binding_set, default_navigate_mode);
00234 }
00235 
00236 // init instance
00237 static void ergtk_icon_view_init(erGtkIconView *er_iconview)
00238 {
00239     LOGPRINTF("entry");
00240     g_return_if_fail(ERGTK_IS_ICON_VIEW(er_iconview));
00241 
00242     GtkIconView*  iconview = (GtkIconView*) er_iconview;
00243 //    GtkWidget*    widget = (GtkWidget*) er_iconview;
00244    
00245     er_iconview->previous = NULL;
00246     er_iconview->next     = NULL;
00247     er_iconview->num_rows = 0;
00248     er_iconview->num_cols = 0;
00249     
00250     // override defaults of GtkIconView
00251     gtk_icon_view_set_margin(iconview, 0);
00252     gtk_icon_view_set_row_spacing(iconview, 0);
00253     gtk_icon_view_set_column_spacing(iconview, 0);
00254 }
00255 
00256 
00257 GType ergtk_icon_view_get_type(void)
00258 {
00259     static GType class_type = 0;
00260 
00261     if (class_type == 0)
00262     {
00263         static const GTypeInfo class_info =
00264         {
00265             sizeof(erGtkIconViewClass),
00266             NULL,               /* base_init */
00267             NULL,               /* base_finalize */
00268             (GClassInitFunc) ergtk_icon_view_class_init,
00269             NULL,               /* class_finalize */
00270             NULL,               /* class_data */
00271             sizeof(erGtkIconView),
00272             0,                  /* n_preallocs */
00273             (GInstanceInitFunc) ergtk_icon_view_init,
00274             NULL                /* *value_table */
00275         };
00276         class_type = g_type_register_static(GTK_TYPE_ICON_VIEW, type_name, &class_info, 0);
00277     }
00278 
00279     return class_type;
00280 }
00281 
00282 
00283 GtkWidget *ergtk_icon_view_new()
00284 {
00285     LOGPRINTF("entry");
00286 
00287     return g_object_new (ERGTK_TYPE_ICON_VIEW, NULL);
00288 }
00289 
00290 
00291 GtkWidget *ergtk_icon_view_new_with_model (GtkTreeModel *model)
00292 {
00293     GtkWidget*      widget;
00294 
00295     LOGPRINTF("entry");
00296     g_return_val_if_fail(model, NULL);
00297 
00298     widget = g_object_new (ERGTK_TYPE_ICON_VIEW, NULL);
00299     ergtk_icon_view_set_model( ERGTK_ICON_VIEW(widget), model);
00300 
00301     return widget;
00302 }
00303 
00304 //
00305 // Public widget methods
00306 //
00307 
00308 void ergtk_icon_view_set_model (erGtkIconView *er_iconview, GtkTreeModel *model)
00309 {
00310     LOGPRINTF("entry");
00311     g_return_if_fail(ERGTK_IS_ICON_VIEW(er_iconview));
00312 
00313     GtkIconView         *iconview = (GtkIconView*) er_iconview;
00314     GtkTreeModel        *iconview_model = gtk_icon_view_get_model(iconview);
00315 
00316     // disconnect signal handlers to old model
00317     if (iconview_model)
00318     {
00319         g_signal_handlers_disconnect_by_func(iconview_model, on_model_row_changed,  er_iconview);
00320         g_signal_handlers_disconnect_by_func(iconview_model, on_model_row_inserted, er_iconview);
00321     }
00322 
00323     // chain to parent class
00324     gtk_icon_view_set_model(iconview, model);
00325     iconview_model = model;
00326 
00327     // connect signal handlers to new model
00328     if (iconview_model)
00329     {
00330         g_signal_connect_after(model, "row-changed",  G_CALLBACK(on_model_row_changed),  er_iconview);
00331         g_signal_connect_after(model, "row-inserted", G_CALLBACK(on_model_row_inserted), er_iconview);
00332     }
00333 }
00334 
00335 
00336 static void on_model_row_changed(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
00337 {
00338     UNUSED(path);
00339     LOGPRINTF("entry");
00340     g_return_if_fail(ERGTK_IS_ICON_VIEW(user_data));
00341 
00342     erGtkIconView   *er_iconview = (erGtkIconView *) user_data;
00343 
00344     // resize pixbuf as needed
00345     scale_pixbuf(er_iconview, model, iter);
00346 }
00347 
00348 
00349 static void on_model_row_inserted(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
00350 {
00351     UNUSED(path);
00352     LOGPRINTF("entry");
00353     g_return_if_fail(ERGTK_IS_ICON_VIEW(user_data));
00354 
00355     erGtkIconView   *er_iconview = (erGtkIconView *) user_data;
00356 
00357     // resize pixbuf as needed
00358     scale_pixbuf(er_iconview, model, iter);
00359 }
00360 
00361 
00362 static gboolean on_focus_out(GtkWidget *widget, gpointer data)
00363 {
00364     UNUSED(widget);
00365     UNUSED(data);
00366     LOGPRINTF("entry");
00367 
00368     // Return TRUE to stop other handlers from being invoked for the event 
00369     return  TRUE;
00370 }
00371 
00372 
00373 static gboolean on_focus_in(GtkWidget *widget, gpointer data)
00374 {
00375     UNUSED(widget);
00376     UNUSED(data);
00377     LOGPRINTF("entry");
00378 
00379     // Return TRUE to stop other handlers from being invoked for the event 
00380     return  TRUE;
00381 }
00382 
00383 
00384 static void scale_pixbuf(erGtkIconView *er_iconview, GtkTreeModel *model, GtkTreeIter *iter)
00385 {
00386     LOGPRINTF("entry");
00387 
00388     GtkIconView     *iconview    = (GtkIconView *) er_iconview;
00389     gint            pixbuf_column = gtk_icon_view_get_pixbuf_column(iconview);
00390     gint            pixbuf_width  = 0;
00391     gint            pixbuf_height = 0;
00392     gint            icon_width  = 0;
00393     gint            icon_height = 0;
00394     gint            x;
00395     gint            y;
00396     gint            w;
00397     gint            h;
00398     float           scale_horizontal;
00399     float           scale_vertical;
00400     GdkPixbuf       *pixbuf_old = NULL;
00401     GdkPixbuf       *pixbuf_new = NULL;
00402     GtkListStore    *list_store = NULL;
00403     GtkTreeStore    *tree_store = NULL;
00404 
00405     // resize pixbuf as needed
00406     LOGPRINTF("pixbuf_column [%d]", pixbuf_column);
00407     if (pixbuf_column >= 0)
00408     {
00409         // get icon size
00410         ergtk_icon_view_get_icon_size(er_iconview, &icon_width, &icon_height);
00411         if (icon_width > 0  &&  icon_height > 0)
00412         {
00413             // get pixbuf
00414             gtk_tree_model_get( model, iter,
00415                                 pixbuf_column, &pixbuf_old,
00416                                 -1 );
00417             if (pixbuf_old)
00418             {
00419                 pixbuf_width  = gdk_pixbuf_get_width(pixbuf_old);
00420                 pixbuf_height = gdk_pixbuf_get_height(pixbuf_old);
00421             }
00422 
00423             // update pixbuf as needed
00424             if (   pixbuf_width  <= icon_width
00425                 && pixbuf_height <= icon_height )
00426             {
00427                 // pixmap fits in icon: no conversion
00428             }
00429             else if (   10 * pixbuf_width  <= 12 * icon_width
00430                      && 10 * pixbuf_height <= 12 * icon_height )
00431             {
00432                 // pixmap max. 20% too large: crop to fit icon
00433                 if (pixbuf_width <= icon_width)
00434                 {
00435                     x = 0;
00436                     w = pixbuf_width;
00437                 }
00438                 else
00439                 {
00440                     x = (pixbuf_width - icon_width ) / 2;
00441                     w = icon_width;
00442                 }
00443                 if (pixbuf_height <= icon_height)
00444                 {
00445                     y = 0;
00446                     h = pixbuf_height;
00447                 }
00448                 else
00449                 {
00450                     y = (pixbuf_height - icon_height) / 2;
00451                     h = icon_height;
00452                 }
00453                 pixbuf_new = gdk_pixbuf_new_subpixbuf(pixbuf_old, x, y, w, h);
00454             }
00455             else
00456             {
00457                 // pixmap more than 20% too large: scale down to fit icon, keep aspect ratio
00458                 scale_horizontal = ((float) icon_width ) / ((float) pixbuf_width );
00459                 scale_vertical   = ((float) icon_height) / ((float) pixbuf_height);
00460                 if (scale_horizontal < scale_vertical)
00461                 {
00462                     w = ((float) pixbuf_width ) * scale_horizontal;
00463                     h = ((float) pixbuf_height) * scale_horizontal;
00464                 }
00465                 else
00466                 {
00467                     w = ((float) pixbuf_width ) * scale_vertical;
00468                     h = ((float) pixbuf_height) * scale_vertical;
00469                 }
00470                 pixbuf_new = gdk_pixbuf_scale_simple(pixbuf_old, w, h, GDK_INTERP_BILINEAR);
00471             }
00472 
00473             // update model with new pixbuf
00474             if (pixbuf_new)
00475             {
00476                 if ( GTK_IS_LIST_STORE(model) )
00477                 {
00478                     list_store = GTK_LIST_STORE(model);
00479                     g_assert(list_store);
00480                     gtk_list_store_set( list_store, iter,
00481                                         pixbuf_column, pixbuf_new,
00482                                         -1 );
00483                 }
00484                 else if ( GTK_IS_TREE_STORE(model) )
00485                 {
00486                     tree_store = GTK_TREE_STORE(model);
00487                     g_assert(tree_store);
00488                     gtk_tree_store_set( tree_store, iter,
00489                                         pixbuf_column, pixbuf_new,
00490                                         -1 );
00491                 }
00492                 else
00493                 {
00494                     ERRORPRINTF("unexpected model type, cannot set new pixbuf");
00495                 }
00496             }
00497         }
00498     }
00499 
00500     // clean up
00501     if (pixbuf_old) { g_object_unref(pixbuf_old); }
00502     if (pixbuf_new) { g_object_unref(pixbuf_new); }
00503 }
00504 
00505 
00506 static void destroy_impl(GtkObject *object)
00507 {
00508     LOGPRINTF("entry");
00509     g_return_if_fail(ERGTK_IS_ICON_VIEW(object));
00510 
00511     erGtkIconView*  er_iconview = (erGtkIconView*) object;
00512     GtkObjectClass* parent_object_class = GTK_OBJECT_CLASS(g_parent_class);
00513 
00514     // disconnect model, if any
00515     ergtk_icon_view_set_model(er_iconview, NULL);
00516 
00517     // chain to parent class
00518     if (parent_object_class->destroy)
00519     {
00520         parent_object_class->destroy(object);
00521     }
00522 }
00523 
00524 
00525 static void on_style_set(GtkWidget *widget, GtkStyle *previous_style)
00526 {
00527     LOGPRINTF("entry");
00528     g_return_if_fail(ERGTK_IS_ICON_VIEW(widget));
00529 
00530     GtkIconView         *iconview = (GtkIconView*) widget;
00531     GtkIconViewCellInfo *info;
00532 
00533     gint icon_width = 0;
00534     gint icon_height = 0;
00535     gint text_height = 0;
00536     gint spacing = 0;
00537     gint item_width = 0;
00538     gint item_height = 0;
00539     gint item_n_textlines = 0;        
00540 
00541     GtkWidgetClass* parent_widget_class = GTK_WIDGET_CLASS(g_parent_class);
00542         
00543     // chain to parent class
00544     if (parent_widget_class->style_set)
00545     {
00546         parent_widget_class->style_set(widget, previous_style);
00547     }
00548     
00549     gtk_widget_style_get(widget,
00550                          "item-width", &item_width,
00551                          "item-height", &item_height,
00552                          "item-n-textlines", &item_n_textlines,
00553                          NULL);
00554 
00555     // set icon view properties
00556     //
00557     if ((item_width > 0) && (item_height > 0))
00558     {
00559         gtk_icon_view_set_item_width(iconview, item_width);
00560     }
00561 
00562     // set text cell properties
00563     //
00564     info = g_list_nth_data (iconview->priv->cell_list, iconview->priv->text_cell);
00565     if (info != NULL)
00566     {
00567         // set text padding to zero
00568         gtk_object_set( GTK_OBJECT(info->cell),
00569                         "xpad", 0,
00570                         NULL       );
00571 
00572         // set text height
00573         if (item_n_textlines > 0)
00574         {
00575             gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(info->cell), item_n_textlines);
00576         }
00577         gtk_cell_renderer_get_size(GTK_CELL_RENDERER(info->cell), widget, NULL, NULL, NULL, NULL, &text_height);
00578     }
00579 
00580     // set pixbuf cell properties
00581     //
00582     info = g_list_nth_data (iconview->priv->cell_list, iconview->priv->pixbuf_cell);
00583     if ((info != NULL) && (item_width > 0) && (item_height > 0))
00584     {    
00585         spacing = gtk_icon_view_get_spacing(iconview);
00586         icon_width = item_width;
00587         icon_height = item_height - text_height - spacing;
00588 
00589         gtk_cell_renderer_set_fixed_size(GTK_CELL_RENDERER(info->cell), icon_width, icon_height);
00590     }
00591 }
00592 
00593 
00594 static void on_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
00595 {
00596     LOGPRINTF("entry");
00597     g_return_if_fail(ERGTK_IS_ICON_VIEW(widget));
00598 
00599     GtkWidgetClass *parent_widget_class = GTK_WIDGET_CLASS(g_parent_class);
00600 
00601     erGtkIconView  *er_iconview = (erGtkIconView*) widget;
00602     GtkIconView    *iconview    = (GtkIconView  *) widget;
00603     gint item_width = 0;
00604     gint item_height = 0;
00605     gint focus_line_width = 0;
00606     gint row_space = 0;
00607     gint col_space = 0;
00608     
00609     // chain to parent class
00610     if (parent_widget_class->size_allocate)
00611     {
00612         parent_widget_class->size_allocate(widget, allocation);
00613     }
00614    
00615     gtk_widget_style_get(widget,
00616                          "item-width", &item_width,
00617                          "item-height", &item_height,
00618                          "focus-line-width", &focus_line_width,
00619                          NULL);
00620 
00621     if ((item_width > 0) && (item_height > 0))
00622     {
00623         // adjust size for padding
00624         item_height += 2 * focus_line_width;
00625         item_width  += 2 * focus_line_width;
00626      
00627         // calculate available space for rows 
00628         row_space = gtk_icon_view_get_row_spacing(iconview);
00629         er_iconview->num_rows = (allocation->height + row_space) / (item_height + row_space);
00630         
00631         // calculate available space for columns
00632         col_space = gtk_icon_view_get_column_spacing(iconview);
00633         er_iconview->num_cols = (allocation->width + col_space) / (item_width + col_space);
00634     }
00635 }
00636 
00637 
00638 static gboolean on_button_press_event (GtkWidget      *widget,
00639                                        GdkEventButton *event)
00640 {
00641     LOGPRINTF("entry");
00642     g_return_val_if_fail(ERGTK_IS_ICON_VIEW(widget), FALSE);
00643 
00644     GtkWidgetClass  *parent_widget_class = GTK_WIDGET_CLASS(g_parent_class);
00645     GtkIconView     *iconview = (GtkIconView*) widget;
00646     
00647     // ignore double-/triple-clicks
00648     if ((event->button == 1) && (event->type != GDK_BUTTON_PRESS))
00649     {
00650         event->type = GDK_NOTHING;
00651         iconview->priv->last_single_clicked = NULL;
00652         iconview->priv->pressed_button = -1;
00653     }
00654     
00655     // chain to parent class
00656     if (parent_widget_class->button_press_event)
00657     {
00658         parent_widget_class->button_press_event(widget, event);
00659     }
00660 
00661     return TRUE;
00662 }
00663 
00664 
00665 static gboolean on_button_release_event(GtkWidget      *widget,
00666                                         GdkEventButton *event)
00667 {
00668     LOGPRINTF("entry");
00669     g_return_val_if_fail(ERGTK_IS_ICON_VIEW(widget), FALSE);
00670 
00671     GtkTreePath     *path = NULL;
00672     GtkIconViewItem *item = NULL;
00673     gint             index = 0;
00674     GtkWidgetClass  *parent_widget_class = GTK_WIDGET_CLASS(g_parent_class);
00675     GtkIconView     *iconview = (GtkIconView*) widget;
00676     
00677     // activate item when single clicked and multi-select (shift/control) is not pressed
00678     //
00679     if ( (iconview->priv->pressed_button == event->button) &&
00680          ((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == 0) )
00681     {
00682         // find path at the button release position
00683         path = gtk_icon_view_get_path_at_pos(iconview, event->x, event->y);
00684         if (path)
00685         {
00686             // find item in path
00687             index = gtk_tree_path_get_indices(path)[0];
00688             item = g_list_nth_data(iconview->priv->items, index);
00689             
00690             // check if this item was the last one single clicked
00691             if (item == iconview->priv->last_single_clicked)
00692             {
00693                 // activate this item
00694                 gtk_icon_view_item_activated(iconview, path);
00695             }
00696         }        
00697         
00698         iconview->priv->last_single_clicked = NULL;
00699     }
00700     
00701     // chain to parent class
00702     if (parent_widget_class->button_release_event)
00703     {
00704         parent_widget_class->button_release_event(widget, event);
00705     }
00706     
00707     // clean up
00708     if (path) { gtk_tree_path_free(path); }
00709     
00710     return TRUE;
00711 }
00712 
00713 
00714 void ergtk_icon_view_set_next(erGtkIconView *er_iconview, erGtkIconView *next)
00715 {
00716     LOGPRINTF("entry");
00717     g_return_if_fail(                ERGTK_IS_ICON_VIEW(er_iconview));
00718     g_return_if_fail(next == NULL || ERGTK_IS_ICON_VIEW(next       ));
00719     
00720     er_iconview->next = next;
00721 }
00722 
00723 
00724 void ergtk_icon_view_set_previous(erGtkIconView *er_iconview, erGtkIconView *previous)
00725 {
00726     LOGPRINTF("entry");
00727     g_return_if_fail(                    ERGTK_IS_ICON_VIEW(er_iconview));
00728     g_return_if_fail(previous == NULL || ERGTK_IS_ICON_VIEW(previous   ));
00729 
00730     er_iconview->previous = previous;
00731 }
00732 
00733 
00734 void ergtk_icon_view_get_cursor(erGtkIconView *er_iconview, gint *row, gint *col)
00735 {
00736     GtkIconView     *iconview = (GtkIconView*) er_iconview;
00737 
00738     gint    r = 0;
00739     gint    c = 0;
00740 
00741     LOGPRINTF("entry");
00742     g_return_if_fail(ERGTK_IS_ICON_VIEW(er_iconview));
00743 
00744     force_cursor_present(er_iconview);
00745 
00746     if (iconview->priv->cursor_item)
00747     {
00748         r = iconview->priv->cursor_item->row;
00749         c = iconview->priv->cursor_item->col;
00750     }
00751 
00752     if (row != NULL)
00753     {
00754         *row = r;
00755     }
00756 
00757     if (col != NULL)
00758     {
00759         *col = c;
00760     }
00761 }
00762 
00763 
00764 void ergtk_icon_view_get_view_size(erGtkIconView *er_iconview, gint *num_rows, gint *num_cols, gint *num_items)
00765 {
00766     LOGPRINTF("entry");
00767     g_return_if_fail(ERGTK_IS_ICON_VIEW(er_iconview));
00768 
00769     GtkIconView     *iconview = (GtkIconView*) er_iconview;
00770     
00771     if (num_rows != NULL)
00772     { 
00773         *num_rows = er_iconview->num_rows;
00774     }
00775     
00776     if (num_cols != NULL)
00777     { 
00778         *num_cols = er_iconview->num_cols;
00779     }
00780     
00781     if (num_items != NULL)
00782     { 
00783         *num_items = g_list_length(iconview->priv->items);
00784     }
00785 
00786     LOGPRINTF("leave");
00787 }
00788 
00789 
00790 void ergtk_icon_view_get_icon_size(erGtkIconView *er_iconview, gint *icon_width, gint *icon_height)
00791 {
00792     LOGPRINTF("entry");
00793     g_return_if_fail(ERGTK_IS_ICON_VIEW(er_iconview));
00794 
00795     GtkIconView         *iconview = (GtkIconView*) er_iconview;
00796     GtkIconViewCellInfo *info;
00797 
00798     // get pixbuf cell properties
00799     info = g_list_nth_data (iconview->priv->cell_list, iconview->priv->pixbuf_cell);
00800     if (info && info->cell)
00801     {    
00802         gtk_cell_renderer_get_fixed_size(GTK_CELL_RENDERER(info->cell), icon_width, icon_height);
00803     }
00804     else
00805     {
00806         if (icon_width)
00807         {
00808             *icon_width = 0;
00809         }
00810         if (icon_height)
00811         {
00812             *icon_height = 0;
00813         }
00814     }
00815 }
00816 
00817 
00818 // move cursor to specified position
00819 // row < 0           : move to last row present
00820 // col < 0           : move to last item present in requested row
00821 // row < 0, col < 0  : move to last item present
00822 // non-existing item : move to last item present in requested col or
00823 //                     move to last item present when requested col not present
00824 void ergtk_icon_view_set_cursor(erGtkIconView  *er_iconview, gint row, gint col)
00825 {
00826     LOGPRINTF("entry");
00827     g_return_if_fail(ERGTK_IS_ICON_VIEW(er_iconview));
00828 
00829     GtkIconView     *iconview = (GtkIconView*) er_iconview;
00830     GtkWidget       *widget   = (GtkWidget  *) er_iconview;
00831     
00832     GtkTreePath *path = NULL;  
00833     gint index = 0;
00834     gint num_rows = 0;
00835     gint num_cols = 0;
00836     gint num_items = 0;
00837     gint last_row;
00838     gint last_col;
00839     gint last_row_last_col;
00840     
00841     LOGPRINTF("entry: row [%d] col [%d]", row, col);
00842 
00843     ergtk_icon_view_get_view_size(er_iconview, &num_rows, &num_cols, &num_items); 
00844     LOGPRINTF("num_rows [%d] num_cols [%d] num_items [%d]", num_rows, num_cols, num_items);
00845 
00846     if (num_items <= 0)
00847     {
00848         WARNPRINTF("no items, quit");
00849         return;
00850     }
00851 
00852     if (num_rows <= 0  ||  num_cols <= 0)
00853     {
00854         WARNPRINTF("no space allocated, num_rows [%d] num_cols [%d]",
00855                    num_rows, num_cols );
00856         return;
00857     }
00858 
00859     last_row          = (num_items - 1) / num_cols;
00860     last_row_last_col = (num_items - 1) % num_cols;
00861 
00862     // correct row, if needed
00863     if (last_row == 0)
00864     {
00865         // only one row present: use this one
00866         row = 0;
00867     }
00868     else
00869     {
00870         // multiple rows present: decide which one to use
00871         if (row < 0)
00872         {
00873             // no row requested: use last row
00874             row = last_row;
00875         }
00876         else if (row > last_row)
00877         {
00878             // requested row not present: use last row or before-last row
00879             if (col <= last_row_last_col)
00880             {
00881                 // no col requested                  : use last row
00882                 // requested col present on last row : use last row
00883                 row = last_row;
00884             }
00885             else
00886             {
00887                 // col requested not present on last row: use before-last row
00888                 row = last_row - 1;
00889             }
00890         }
00891     }
00892 
00893     // correct column, if needed
00894     if (row == last_row)
00895     {
00896         last_col = last_row_last_col;
00897     }
00898     else
00899     {
00900         last_col = num_cols - 1;
00901     }
00902     if (col < 0  ||  col > last_col)
00903     {
00904         // col not requested: use last column on row
00905         // col not present  : use last column on row
00906         col = last_col;
00907     }
00908     LOGPRINTF("calculated: col [%d] row [%d]", col, row);
00909 
00910     // create path from index and set cursor
00911     index = (row * num_cols) + col;
00912     path = gtk_tree_path_new_from_indices(index, -1);
00913     gtk_widget_grab_focus (widget);
00914     gtk_icon_view_select_path(iconview, path);  
00915     gtk_icon_view_set_cursor(iconview, path, NULL, FALSE);
00916 
00917     // clean up
00918     if (path) { gtk_tree_path_free(path); }
00919 
00920     return;
00921 }
00922 
00923 
00924 void ergtk_icon_view_set_focus_mode(erGtkIconView          *er_iconview, 
00925                                     gboolean               focus_in,
00926                                     gboolean               focus_out)
00927 {
00928     if (!focus_in)
00929     {
00930         // block focus-in events 
00931         g_signal_connect(G_OBJECT(er_iconview), "focus-in-event", G_CALLBACK (on_focus_in), NULL);
00932     }
00933     if (!focus_out)
00934     {
00935         // block focus-out events 
00936         g_signal_connect(G_OBJECT(er_iconview), "focus-out-event", G_CALLBACK (on_focus_out), NULL);
00937     }
00938 }
00939 
00940 
00941 //
00942 // Internal functions
00943 //
00944 
00945 static void force_cursor_present (erGtkIconView *er_iconview)
00946 {
00947     LOGPRINTF("entry");
00948 
00949     GtkIconView     *iconview = (GtkIconView*) er_iconview;
00950 
00951     if ( !iconview->priv->cursor_item )
00952     {
00953         // no cursor: set cursor on first item
00954         WARNPRINTF("no cursor, force to (0,0)");
00955         ergtk_icon_view_set_cursor(er_iconview, 0, 0);
00956     }
00957 }
00958 
00959 
00960 static gboolean on_pre_move_cursor (erGtkIconView         *er_iconview,
00961                                     erGtkIconViewKeyPress navigate)
00962 {
00963     LOGPRINTF("entry");
00964 
00965     gboolean        ret = FALSE;  
00966     GtkIconView     *iconview = (GtkIconView*) er_iconview;
00967     GtkTreePath     *path = NULL;
00968 
00969     gint curcol = 0;
00970     gint currow = 0;
00971     gint num_rows = 0;
00972     gint num_cols = 0;
00973     gint num_items = 0;
00974     gint row_items = 0;
00975     gint last_row = 0;
00976     gint last_row_last_col = 0;
00977     gint step = 0;
00978     
00979     LOGPRINTF("entry: navigate [%d]", navigate);
00980     g_return_val_if_fail (ERGTK_ICON_VIEW (er_iconview), FALSE);
00981 
00982     if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (er_iconview)))
00983     {
00984         WARNPRINTF("widget has no focus");
00985         return FALSE;
00986     }
00987 
00988     force_cursor_present(er_iconview);
00989     
00990     ergtk_icon_view_get_cursor(er_iconview, &currow, &curcol);
00991     ergtk_icon_view_get_view_size(er_iconview, &num_rows, &num_cols, &num_items); 
00992 
00993     // calculate number of items in this row
00994     if (currow == num_rows)
00995     {
00996         row_items = num_items - (num_cols*(num_rows-1));
00997     }
00998     else
00999     {
01000         row_items = num_cols;
01001     }
01002     
01003     // number of items in last row
01004     if ((currow+1) == num_rows)
01005     {
01006         row_items = num_items - (num_cols*(num_rows-1));
01007     }
01008     
01009     last_row = (num_items - 1) / num_cols;
01010     last_row_last_col = (num_items - 1) % num_cols;
01011     
01012     LOGPRINTF("curcol [%d] currow [%d]",  curcol, currow);
01013     LOGPRINTF("num_cols [%d] num_rows [%d] num_items [%d] row_items [%d] last_row [%d] last_row_last_col [%d]", 
01014               num_cols, num_rows, num_items, row_items, last_row, last_row_last_col );
01015 
01016     switch (navigate)
01017     {
01018     case ERGTK_ICON_VIEW_PRESS_SHORT_UP:
01019         if (currow > 0)
01020         {
01021             // move up line in view
01022             g_signal_emit_by_name(er_iconview, "move-cursor", GTK_MOVEMENT_DISPLAY_LINES, -1, &ret);
01023         }
01024         else 
01025         {
01026             gint items_previous = 0;
01027             if (er_iconview->previous) 
01028             {
01029                 ergtk_icon_view_get_view_size(er_iconview->previous, NULL, NULL, &items_previous);
01030             }
01031             
01032             if (items_previous > 0)
01033             {                
01034                 // move up view
01035                 ergtk_icon_view_set_cursor(er_iconview->previous, -1, curcol);
01036             }
01037             else
01038             {
01039                 // no view above, emit signal
01040                 g_signal_emit_by_name(er_iconview, "navigate-cursor", ERGTK_ICON_VIEW_PRESS_SHORT_UP);
01041             }
01042         }
01043         break;
01044         
01045     case ERGTK_ICON_VIEW_PRESS_SHORT_DOWN:
01046         if (currow < last_row)
01047         {
01048             if (((currow+1)*row_items)+curcol < num_items)
01049             {
01050                 // move down line in view
01051                 g_signal_emit_by_name (er_iconview, "move-cursor", GTK_MOVEMENT_DISPLAY_LINES, 1, &ret);
01052             }
01053             else
01054             {
01055                 // no item directly below so move to end of view
01056                 g_signal_emit_by_name (er_iconview, "move-cursor", GTK_MOVEMENT_BUFFER_ENDS, 1, &ret);
01057             }
01058         }
01059         else
01060         {
01061             gint item_next = 0;
01062             if (er_iconview->next) 
01063             {
01064                 ergtk_icon_view_get_view_size(er_iconview->next, NULL, NULL, &item_next);
01065             }
01066 
01067             if (item_next > 0) 
01068             {
01069                 // move down view
01070                 ergtk_icon_view_set_cursor(er_iconview->next, 0, curcol);
01071             }
01072             else
01073             {
01074                 // no view below, emit signal
01075                 g_signal_emit_by_name(er_iconview, "navigate-cursor", ERGTK_ICON_VIEW_PRESS_SHORT_DOWN);
01076             }
01077         }
01078         break;
01079         
01080     case ERGTK_ICON_VIEW_PRESS_SHORT_LEFT:
01081         if (curcol > 0)
01082         {
01083             g_signal_emit_by_name (er_iconview, "move-cursor", GTK_MOVEMENT_VISUAL_POSITIONS, -1, &ret);
01084         }
01085         else
01086         {
01087             if (currow > 0)
01088             {
01089                 // already at start of the line, move to last item of previous line
01090                 ergtk_icon_view_set_cursor(er_iconview, currow-1, -1);
01091             }
01092             else if (er_iconview->previous)
01093             {
01094                 // already at start of line, move to the end of the previous row
01095                 ergtk_icon_view_set_cursor(er_iconview->previous, -1, -1);
01096             }
01097             else 
01098             {
01099                 // already at start of the first line, emit signal
01100                 g_signal_emit_by_name(er_iconview, "navigate-cursor", ERGTK_ICON_VIEW_PRESS_SHORT_LEFT);
01101             }
01102         }
01103         break;
01104         
01105     case ERGTK_ICON_VIEW_PRESS_SHORT_RIGHT:
01106         if ( ((curcol+1) < row_items) && !((currow == last_row) && (curcol == last_row_last_col)) )
01107         {
01108                 g_signal_emit_by_name (er_iconview, "move-cursor", GTK_MOVEMENT_VISUAL_POSITIONS, 1, &ret);
01109         }
01110         else 
01111         {
01112        if (currow < last_row)
01113             {
01114                 // already at end of the line, move to first item of next line
01115                 ergtk_icon_view_set_cursor(er_iconview, currow+1, 0);
01116             }
01117             else if (er_iconview->next)
01118             {
01119                 // already at end of line, move to first item of next row
01120                 ergtk_icon_view_set_cursor(er_iconview->next, 0, 0);
01121             }
01122             else 
01123             {
01124                 // already at end of the last line, emit signal
01125                 g_signal_emit_by_name(er_iconview, "navigate-cursor", ERGTK_ICON_VIEW_PRESS_SHORT_RIGHT);
01126             }
01127         }
01128         break;
01129         
01130     case ERGTK_ICON_VIEW_PRESS_LONG_UP:
01131         g_signal_emit_by_name(er_iconview, "navigate-cursor", ERGTK_ICON_VIEW_PRESS_LONG_UP);
01132         break;
01133         
01134     case ERGTK_ICON_VIEW_PRESS_LONG_DOWN:
01135         g_signal_emit_by_name(er_iconview, "navigate-cursor", ERGTK_ICON_VIEW_PRESS_LONG_DOWN);
01136         break;
01137         
01138     case ERGTK_ICON_VIEW_PRESS_LONG_LEFT:
01139         if (curcol > 0)
01140         {
01141             // move to first in line
01142             step = 1 - (curcol+1);
01143             g_signal_emit_by_name (er_iconview, "move-cursor", GTK_MOVEMENT_VISUAL_POSITIONS, step, &ret);
01144         }
01145         else
01146         {
01147             if (currow > 0)
01148             {
01149                 // already at start of line, move up one line
01150                 on_pre_move_cursor(er_iconview, ERGTK_ICON_VIEW_PRESS_SHORT_UP);
01151             }
01152             else if (er_iconview->previous)
01153             {
01154                 // already at start of line, move to the start of the previous row
01155                 ergtk_icon_view_set_cursor(er_iconview->previous, -1, 0);
01156             }
01157             else 
01158             {
01159                 // already at start of first line
01160                 g_signal_emit_by_name(er_iconview, "navigate-cursor", ERGTK_ICON_VIEW_PRESS_LONG_LEFT);
01161             }
01162         }
01163         break;
01164         
01165     case ERGTK_ICON_VIEW_PRESS_LONG_RIGHT:
01166         if ((curcol+1) < row_items)
01167         {
01168             // move to last in line
01169             if (currow == last_row)
01170             {
01171                 step = last_row_last_col - curcol;
01172             }
01173             else
01174             {
01175                 step = row_items - (curcol+1);
01176             }
01177             g_signal_emit_by_name (er_iconview, "move-cursor", GTK_MOVEMENT_VISUAL_POSITIONS, step, &ret);
01178         }
01179         else
01180         {
01181             if (currow < last_row)
01182             {
01183                 // already at end of line, move to next line
01184                 on_pre_move_cursor(er_iconview, ERGTK_ICON_VIEW_PRESS_SHORT_DOWN);
01185             }
01186             else if (er_iconview->next)
01187             {
01188                 // already at end of line, move to end of next row
01189                 ergtk_icon_view_set_cursor(er_iconview->next, 0, -1);
01190             }
01191             else 
01192             {
01193                 // already at end of last line
01194                 g_signal_emit_by_name(er_iconview, "navigate-cursor", ERGTK_ICON_VIEW_PRESS_LONG_RIGHT);
01195             }
01196         }
01197         break;
01198 
01199     case ERGTK_ICON_VIEW_PRESS_ACTIVATE:
01200         path = gtk_tree_path_new();
01201         gtk_icon_view_get_cursor(iconview, &path, NULL);
01202         gtk_icon_view_item_activated(iconview, path);
01203         gtk_tree_path_free(path);
01204         path = NULL;
01205         break;
01206 
01207     default:
01208         g_assert_not_reached();
01209         break;
01210     }
01211 
01212     LOGPRINTF("leave");
01213     return TRUE;
01214 }
01215 
01216 static void add_move_bindings(GtkBindingSet *binding_set, const gchar * navigate_mode)
01217 {
01218     LOGPRINTF("entry");
01219     g_return_if_fail(binding_set != NULL);
01220 
01221     gint n = strlen(simple_navigate_mode);
01222     if (g_strncasecmp(navigate_mode, simple_navigate_mode, n) == 0)
01223     {
01224         add_move_binding(binding_set, GDK_Up,           0, ERGTK_ICON_VIEW_PRESS_SHORT_LEFT);
01225         add_move_binding(binding_set, GDK_KP_Up,        0, ERGTK_ICON_VIEW_PRESS_SHORT_LEFT);
01226 
01227         add_move_binding(binding_set, GDK_Down,         0, ERGTK_ICON_VIEW_PRESS_SHORT_RIGHT);
01228         add_move_binding(binding_set, GDK_KP_Down,      0, ERGTK_ICON_VIEW_PRESS_SHORT_RIGHT);
01229 
01230         add_move_binding(binding_set, GDK_Page_Up,      0, ERGTK_ICON_VIEW_PRESS_LONG_UP);
01231         add_move_binding(binding_set, GDK_KP_Page_Up,   0, ERGTK_ICON_VIEW_PRESS_LONG_UP);
01232         
01233         add_move_binding(binding_set, GDK_Page_Down,    0, ERGTK_ICON_VIEW_PRESS_LONG_DOWN);
01234         add_move_binding(binding_set, GDK_KP_Page_Down, 0, ERGTK_ICON_VIEW_PRESS_LONG_DOWN);
01235     }
01236     else
01237     {
01238         add_move_binding(binding_set, GDK_Up,           0, ERGTK_ICON_VIEW_PRESS_SHORT_UP);
01239         add_move_binding(binding_set, GDK_KP_Up,        0, ERGTK_ICON_VIEW_PRESS_SHORT_UP);
01240 
01241         add_move_binding(binding_set, GDK_Down,         0, ERGTK_ICON_VIEW_PRESS_SHORT_DOWN);
01242         add_move_binding(binding_set, GDK_KP_Down,      0, ERGTK_ICON_VIEW_PRESS_SHORT_DOWN);
01243 
01244         add_move_binding(binding_set, GDK_Page_Up,      0, ERGTK_ICON_VIEW_PRESS_LONG_UP);
01245         add_move_binding(binding_set, GDK_KP_Page_Up,   0, ERGTK_ICON_VIEW_PRESS_LONG_UP);
01246         
01247         add_move_binding(binding_set, GDK_Page_Down,    0, ERGTK_ICON_VIEW_PRESS_LONG_DOWN);
01248         add_move_binding(binding_set, GDK_KP_Page_Down, 0, ERGTK_ICON_VIEW_PRESS_LONG_DOWN);
01249     }
01250 
01251     add_move_binding(binding_set, GDK_Left,         0, ERGTK_ICON_VIEW_PRESS_SHORT_LEFT);
01252     add_move_binding(binding_set, GDK_KP_Left,      0, ERGTK_ICON_VIEW_PRESS_SHORT_LEFT);
01253 
01254     add_move_binding(binding_set, GDK_Right,        0, ERGTK_ICON_VIEW_PRESS_SHORT_RIGHT);
01255     add_move_binding(binding_set, GDK_KP_Right,     0, ERGTK_ICON_VIEW_PRESS_SHORT_RIGHT);
01256 
01257     add_move_binding(binding_set, GDK_Home,         0, ERGTK_ICON_VIEW_PRESS_LONG_LEFT);
01258     add_move_binding(binding_set, GDK_KP_Home,      0, ERGTK_ICON_VIEW_PRESS_LONG_LEFT);
01259 
01260     add_move_binding(binding_set, GDK_End,          0, ERGTK_ICON_VIEW_PRESS_LONG_RIGHT);
01261     add_move_binding(binding_set, GDK_KP_End,       0, ERGTK_ICON_VIEW_PRESS_LONG_RIGHT);
01262 
01263     add_move_binding(binding_set, GDK_space,        0, ERGTK_ICON_VIEW_PRESS_ACTIVATE);
01264     add_move_binding(binding_set, GDK_Return,       0, ERGTK_ICON_VIEW_PRESS_ACTIVATE);
01265     add_move_binding(binding_set, GDK_ISO_Enter,    0, ERGTK_ICON_VIEW_PRESS_ACTIVATE);
01266     add_move_binding(binding_set, GDK_KP_Enter,     0, ERGTK_ICON_VIEW_PRESS_ACTIVATE);
01267 }
01268 
01269 static void add_move_binding(GtkBindingSet         *binding_set,
01270                              guint                 keyval,
01271                              GdkModifierType       modmask,
01272                              erGtkIconViewKeyPress navigate)
01273 {
01274     LOGPRINTF("entry");
01275 
01276     gtk_binding_entry_add_signal(binding_set, keyval, modmask,
01277                                  "pre-move-cursor", 1,
01278                                  G_TYPE_ENUM, navigate);
01279 
01280     gtk_binding_entry_add_signal(binding_set, keyval, GDK_SHIFT_MASK,
01281                                  "pre-move-cursor", 1,
01282                                  G_TYPE_ENUM, navigate);
01283 
01284     if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
01285     {
01286         return;
01287     }
01288 
01289     gtk_binding_entry_add_signal(binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
01290                                  "pre-move-cursor", 1,
01291                                  G_TYPE_ENUM, navigate);
01292 
01293     gtk_binding_entry_add_signal(binding_set, keyval, GDK_CONTROL_MASK,
01294                                  "pre-move-cursor", 1,
01295                                  G_TYPE_ENUM, navigate);
01296 }
01297 
01298 static void remove_move_bindings(GtkBindingSet *binding_set)
01299 {
01300     LOGPRINTF("entry");
01301     g_return_if_fail(binding_set != NULL);
01302 
01303     remove_move_binding(binding_set, GDK_Up,           0);
01304     remove_move_binding(binding_set, GDK_KP_Up,        0);
01305 
01306     remove_move_binding(binding_set, GDK_Down,         0);
01307     remove_move_binding(binding_set, GDK_KP_Down,      0);
01308 
01309     remove_move_binding(binding_set, GDK_Page_Up,      0);
01310     remove_move_binding(binding_set, GDK_KP_Page_Up,   0);
01311 
01312     remove_move_binding(binding_set, GDK_Page_Down,    0);
01313     remove_move_binding(binding_set, GDK_KP_Page_Down, 0);
01314       
01315     remove_move_binding(binding_set, GDK_Left,         0);
01316     remove_move_binding(binding_set, GDK_KP_Left,      0);
01317 
01318     remove_move_binding(binding_set, GDK_Right,        0);
01319     remove_move_binding(binding_set, GDK_KP_Right,     0);
01320     
01321     remove_move_binding(binding_set, GDK_Home,         0);
01322     remove_move_binding(binding_set, GDK_KP_Home,      0);
01323    
01324     remove_move_binding(binding_set, GDK_End,          0);
01325     remove_move_binding(binding_set, GDK_KP_End,       0);
01326 
01327     remove_move_binding(binding_set, GDK_space,        0);
01328     remove_move_binding(binding_set, GDK_Return,       0);
01329     remove_move_binding(binding_set, GDK_ISO_Enter,    0);
01330     remove_move_binding(binding_set, GDK_KP_Enter,     0);
01331 }
01332 
01333 static void remove_move_binding(GtkBindingSet         *binding_set,
01334                                 guint                 keyval,
01335                                 GdkModifierType       modmask)
01336 {
01337     LOGPRINTF("entry");
01338 
01339     gtk_binding_entry_remove(binding_set, keyval, modmask);
01340     gtk_binding_entry_remove(binding_set, keyval, GDK_SHIFT_MASK);
01341 
01342     if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
01343     {
01344         return;
01345     }
01346 
01347     gtk_binding_entry_remove(binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
01348     gtk_binding_entry_remove(binding_set, keyval, GDK_CONTROL_MASK);
01349 }
01350 
01351 // get class-specific property
01352 static void get_property_impl ( GObject    *object,
01353                                 guint       param_id,
01354                                 GValue     *value,
01355                                 GParamSpec *pspec )
01356 {
01357     g_return_if_fail( ERGTK_IS_ICON_VIEW(object) );
01358 
01359     erGtkIconViewPrivate *priv = ERGTK_ICON_VIEW_GET_PRIVATE(object);
01360 
01361     switch (param_id)
01362     {
01363         case PROP_NAVIGATE_MODE:
01364             g_value_set_string (value, priv->navigate_mode);
01365             break;
01366 
01367         default:
01368             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
01369     }
01370 }
01371 
01372 
01373 // set class-specific property
01374 static void set_property_impl ( GObject      *object,
01375                                 guint         param_id,
01376                                 const GValue *value,
01377                                 GParamSpec   *pspec )
01378 {
01379     g_return_if_fail( ERGTK_IS_ICON_VIEW(object) );
01380 
01381     erGtkIconViewPrivate *priv = ERGTK_ICON_VIEW_GET_PRIVATE(object);
01382 
01383     gchar        **cpp;
01384 
01385     switch (param_id)
01386     {
01387         case PROP_NAVIGATE_MODE:
01388             {
01389                 const gchar *navigate_mode = g_value_get_string(value);
01390                 if (g_strncasecmp(navigate_mode, normal_navigate_mode, strlen(normal_navigate_mode))
01391                  && g_strncasecmp(navigate_mode, simple_navigate_mode, strlen(simple_navigate_mode)))
01392                 {
01393                     WARNPRINTF("Invalid navigate mode: %s!", navigate_mode);
01394                 }
01395                 else
01396                 {
01397                     cpp = &(priv->navigate_mode);
01398                     g_free(*cpp);
01399                     *cpp = g_strdup(g_value_get_string(value));
01400                     LOGPRINTF("navigate-mode set to [%s]", *cpp);
01401                     GtkBindingSet *binding_set = gtk_binding_set_find(type_name);
01402                     remove_move_bindings(binding_set);
01403                     add_move_bindings(binding_set, navigate_mode);
01404                 }
01405             }
01406             break;
01407         default:
01408             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
01409     }
01410 }
01411 
01412 // finalize instance
01413 static void finalize_impl (GObject *obj)
01414 {
01415     g_return_if_fail( ERGTK_IS_ICON_VIEW(obj) );
01416 
01417     erGtkIconViewPrivate *priv = ERGTK_ICON_VIEW_GET_PRIVATE(obj);
01418 
01419     // destroy instance data
01420     //   private
01421     g_free(priv->navigate_mode);
01422     //   public: none
01423 
01424     // chain to parent class
01425     ((GObjectClass*)g_parent_class)->finalize( obj );
01426 }
01427 
Generated by  doxygen 1.6.2-20100208