Logo Search packages:      
Sourcecode: nautilus version File versions  Download package

eel-image-table.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */

/* eel-image-table.c - An image table.

   Copyright (C) 2000 Eazel, Inc.

   The Gnome Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The Gnome 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Authors: Ramiro Estrugo <ramiro@eazel.com>
*/

#include <config.h>
#include "eel-image-table.h"

#include "eel-art-extensions.h"
#include "eel-art-gtk-extensions.h"
#include "eel-debug-drawing.h"
#include "eel-gtk-extensions.h"
#include "eel-gtk-macros.h"
#include "eel-labeled-image.h"
#include "eel-marshal.h"
#include <gtk/gtk.h>

/* Arguments */
enum
{
      ARG_0,
      ARG_CHILD_UNDER_POINTER
};

/* Detail member struct */
struct EelImageTableDetails
{
      GtkWidget *child_under_pointer;
      GtkWidget *child_being_pressed;
      GdkGC     *clear_gc;
};

/* Signals */
typedef enum
{
      CHILD_ENTER,
      CHILD_LEAVE,
      CHILD_PRESSED,
      CHILD_RELEASED,
      CHILD_CLICKED,
      LAST_SIGNAL
} ImageTableSignals;

/* Signals */
static guint image_table_signals[LAST_SIGNAL] = { 0 };

static void    eel_image_table_class_init     (EelImageTableClass *image_table_class);
static void    eel_image_table_init           (EelImageTable      *image);

/* GObjectClass methods */
static void    eel_image_table_finalize             (GObject            *object);

/* GtkWidgetClass methods */
static void    eel_image_table_realize              (GtkWidget          *widget);
static void    eel_image_table_unrealize            (GtkWidget          *widget);

/* GtkContainerClass methods */
static void    eel_image_table_remove               (GtkContainer       *container,
                                         GtkWidget          *widget);
static GType   eel_image_table_child_type           (GtkContainer       *container);

/* Private EelImageTable methods */
static void    image_table_emit_signal              (EelImageTable      *image_table,
                                         GtkWidget          *child,
                                         guint               signal_index,
                                         int                 x,
                                         int                 y,
                                         int                 button,
                                         guint               state,
                                         GdkEvent           *event);

/* Ancestor callbacks */
static int     ancestor_enter_notify_event          (GtkWidget          *widget,
                                         GdkEventCrossing   *event,
                                         gpointer            event_data);
static int     ancestor_leave_notify_event          (GtkWidget          *widget,
                                         GdkEventCrossing   *event,
                                         gpointer            event_data);
static int     ancestor_motion_notify_event         (GtkWidget          *widget,
                                         GdkEventMotion     *event,
                                         gpointer            event_data);
static int     ancestor_button_press_event          (GtkWidget          *widget,
                                         GdkEventButton     *event,
                                         gpointer            event_data);
static int     ancestor_button_release_event        (GtkWidget          *widget,
                                         GdkEventButton     *event,
                                         gpointer            event_data);

EEL_CLASS_BOILERPLATE (EelImageTable, eel_image_table, EEL_TYPE_WRAP_TABLE)

static void
eel_image_table_class_init (EelImageTableClass *image_table_class)
{
      GObjectClass *object_class = G_OBJECT_CLASS (image_table_class);
      GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (image_table_class);
      GtkContainerClass *container_class = GTK_CONTAINER_CLASS (image_table_class);

      /* GObjectClass */
      object_class->finalize = eel_image_table_finalize;
      
      /* GtkWidgetClass */
      widget_class->realize = eel_image_table_realize;
      widget_class->unrealize = eel_image_table_unrealize;

      /* GtkContainerClass */
      container_class->remove = eel_image_table_remove;
      container_class->child_type = eel_image_table_child_type;

      /* Signals */
      image_table_signals[CHILD_ENTER] = g_signal_new ("child_enter",
                                           G_TYPE_FROM_CLASS (object_class),
                                           G_SIGNAL_RUN_LAST,
                                           G_STRUCT_OFFSET (EelImageTableClass, child_enter),
                                           NULL, NULL,
                                           eel_marshal_VOID__OBJECT_POINTER,
                                           G_TYPE_NONE,
                                           2,
                                           GTK_TYPE_WIDGET,
                                           G_TYPE_POINTER);
      image_table_signals[CHILD_LEAVE] = g_signal_new ("child_leave",
                                           G_TYPE_FROM_CLASS (object_class),
                                           G_SIGNAL_RUN_LAST,
                                           G_STRUCT_OFFSET (EelImageTableClass, child_leave),
                                           NULL, NULL,
                                           eel_marshal_VOID__OBJECT_POINTER,
                                           G_TYPE_NONE,
                                           2,
                                           GTK_TYPE_WIDGET,
                                           G_TYPE_POINTER);
      image_table_signals[CHILD_PRESSED] = g_signal_new ("child_pressed",
                                             G_TYPE_FROM_CLASS (object_class),
                                             G_SIGNAL_RUN_LAST,
                                             G_STRUCT_OFFSET (EelImageTableClass, child_pressed),
                                             NULL, NULL,
                                             eel_marshal_VOID__OBJECT_POINTER,
                                             G_TYPE_NONE,
                                             2,
                                             GTK_TYPE_WIDGET,
                                             G_TYPE_POINTER);
      image_table_signals[CHILD_RELEASED] = g_signal_new ("child_released",
                                              G_TYPE_FROM_CLASS (object_class),
                                              G_SIGNAL_RUN_LAST,
                                              G_STRUCT_OFFSET (EelImageTableClass, child_released),
                                              NULL, NULL,
                                              eel_marshal_VOID__OBJECT_POINTER,
                                              G_TYPE_NONE,
                                              2,
                                              GTK_TYPE_WIDGET,
                                              G_TYPE_POINTER);
      image_table_signals[CHILD_CLICKED] = g_signal_new ("child_clicked",
                                             G_TYPE_FROM_CLASS (object_class),
                                             G_SIGNAL_RUN_LAST,
                                             G_STRUCT_OFFSET (EelImageTableClass, child_clicked),
                                             NULL, NULL,
                                             eel_marshal_VOID__OBJECT_POINTER,
                                             G_TYPE_NONE,
                                             2,
                                             GTK_TYPE_WIDGET,
                                             G_TYPE_POINTER);
}

static void
eel_image_table_init (EelImageTable *image_table)
{
      gtk_widget_set_has_window (GTK_WIDGET (image_table), FALSE);

      image_table->details = g_new0 (EelImageTableDetails, 1);
}

/* GObjectClass methods */
static void
eel_image_table_finalize (GObject *object)
{
      EelImageTable *image_table;
      
      image_table = EEL_IMAGE_TABLE (object);

      g_free (image_table->details);

      EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
}

static void
eel_image_table_realize (GtkWidget *widget)
{
      GtkWidget *windowed_ancestor;

      g_assert (EEL_IS_IMAGE_TABLE (widget));
      
      /* Chain realize */
      EEL_CALL_PARENT (GTK_WIDGET_CLASS, realize, (widget));

      windowed_ancestor = eel_gtk_widget_find_windowed_ancestor (widget);
      g_assert (GTK_IS_WIDGET (windowed_ancestor));
      
      gtk_widget_add_events (windowed_ancestor,
                         GDK_BUTTON_PRESS_MASK
                         | GDK_BUTTON_RELEASE_MASK
                         | GDK_BUTTON_MOTION_MASK
                         | GDK_ENTER_NOTIFY_MASK
                         | GDK_LEAVE_NOTIFY_MASK
                         | GDK_POINTER_MOTION_MASK);

      eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor),
                                     "enter_notify_event",
                                     G_CALLBACK (ancestor_enter_notify_event),
                                     widget,
                                     widget);
      
      eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor),
                                     "leave_notify_event",
                                     G_CALLBACK (ancestor_leave_notify_event),
                                     widget,
                                     widget);
      
      eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor),
                                     "motion_notify_event",
                                     G_CALLBACK (ancestor_motion_notify_event),
                                     widget,
                                     widget);
      
      eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor),
                                     "button_press_event",
                                     G_CALLBACK (ancestor_button_press_event),
                                     widget,
                                     widget);
      
      eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor),
                                     "button_release_event",
                                     G_CALLBACK (ancestor_button_release_event),
                                     widget,
                                     widget);
}

static void
eel_image_table_unrealize (GtkWidget *widget)
{
      EelImageTable *image_table;

      g_assert (EEL_IS_IMAGE_TABLE (widget));

      image_table = EEL_IMAGE_TABLE (widget);

      if (image_table->details->clear_gc != NULL) {
            g_object_unref (image_table->details->clear_gc);
            image_table->details->clear_gc = NULL;
      }

      /* Chain unrealize */
      EEL_CALL_PARENT (GTK_WIDGET_CLASS, unrealize, (widget));
}

/* GtkContainerClass methods */
static void
eel_image_table_remove (GtkContainer *container,
                  GtkWidget *child)
{
      EelImageTable *image_table;
      
      g_assert (EEL_IS_IMAGE_TABLE (container));
      g_assert (EEL_IS_LABELED_IMAGE (child));
      
      image_table = EEL_IMAGE_TABLE (container);

      if (child == image_table->details->child_under_pointer) {
            image_table->details->child_under_pointer = NULL;
      }

      if (child == image_table->details->child_being_pressed) {
            image_table->details->child_being_pressed = NULL;
      }

      EEL_CALL_PARENT (GTK_CONTAINER_CLASS, remove, (container, child));
}

static GType
eel_image_table_child_type (GtkContainer *container)
{
      return EEL_TYPE_LABELED_IMAGE;
}

/* Private EelImageTable methods */

static void
image_table_emit_signal (EelImageTable *image_table,
                   GtkWidget *child,
                   guint signal_index,
                   int x,
                   int y,
                   int button,
                   guint state,
                   GdkEvent *gdk_event)
{
      EelImageTableEvent event;

      g_assert (EEL_IS_IMAGE_TABLE (image_table));
      g_assert (GTK_IS_WIDGET (child));
      g_assert (signal_index < LAST_SIGNAL);

      event.x = x;
      event.y = y;
      event.button = button;
      event.state = state;
      event.event = gdk_event;
      
      g_signal_emit (image_table, 
                   image_table_signals[signal_index],
                   0,
                   child,
                   &event);
}

static void
image_table_handle_motion (EelImageTable *image_table,
                     int x,
                     int y,
                     GdkEvent *event)
{
      GtkWidget *child;
      GtkWidget *leave_emit_child = NULL;
      GtkWidget *enter_emit_child = NULL;

      g_assert (EEL_IS_IMAGE_TABLE (image_table));

      child = eel_wrap_table_find_child_at_event_point (EEL_WRAP_TABLE (image_table), x, y);

      if (child && !gtk_widget_get_sensitive (child)) {
            return;
      }

      if (child == image_table->details->child_under_pointer) {
            return;
      }

      if (child != NULL) {
            if (image_table->details->child_under_pointer != NULL) {
                  leave_emit_child = image_table->details->child_under_pointer;
            }

            image_table->details->child_under_pointer = child;
            enter_emit_child = image_table->details->child_under_pointer;
      } else {
            if (image_table->details->child_under_pointer != NULL) {
                  leave_emit_child = image_table->details->child_under_pointer;
            }

            image_table->details->child_under_pointer = NULL;
      }

      if (leave_emit_child != NULL) {
            image_table_emit_signal (image_table,
                               leave_emit_child,
                               CHILD_LEAVE,
                               x,
                               y,
                               0,
                               0,
                               (GdkEvent *)event);
      }

      if (enter_emit_child != NULL) {
            image_table_emit_signal (image_table,
                               enter_emit_child,
                               CHILD_ENTER,
                               x,
                               y,
                               0,
                               0,
                               (GdkEvent *)event);
      }
}

static int
ancestor_enter_notify_event (GtkWidget *widget,
                       GdkEventCrossing *event,
                       gpointer event_data)
{
      g_assert (GTK_IS_WIDGET (widget));
      g_assert (EEL_IS_IMAGE_TABLE (event_data));
      g_assert (event != NULL);

      image_table_handle_motion (EEL_IMAGE_TABLE (event_data), event->x, event->y, (GdkEvent *) event);

      return FALSE;
}

static int
ancestor_leave_notify_event (GtkWidget *widget,
                       GdkEventCrossing *event,
                       gpointer event_data)
{
      EelIRect bounds;
      int x = -1;
      int y = -1;
      
      g_assert (GTK_IS_WIDGET (widget));
      g_assert (EEL_IS_IMAGE_TABLE (event_data));
      g_assert (event != NULL);

      bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (event_data));
      
      if (eel_irect_contains_point (bounds, event->x, event->y)) {
            x = event->x;
            y = event->y;
      }

      image_table_handle_motion (EEL_IMAGE_TABLE (event_data), x, y, (GdkEvent *) event);
      
      return FALSE;
}

static int
ancestor_motion_notify_event (GtkWidget *widget,
                        GdkEventMotion *event,
                        gpointer event_data)
{
      g_assert (GTK_IS_WIDGET (widget));
      g_assert (EEL_IS_IMAGE_TABLE (event_data));
      g_assert (event != NULL);

      image_table_handle_motion (EEL_IMAGE_TABLE (event_data), (int) event->x, (int) event->y, (GdkEvent *) event);

      return FALSE;
}

static int
ancestor_button_press_event (GtkWidget *widget,
                       GdkEventButton *event,
                       gpointer event_data)
{
      EelImageTable *image_table;
      GtkWidget *child;

      g_assert (GTK_IS_WIDGET (widget));
      g_assert (EEL_IS_IMAGE_TABLE (event_data));
      g_assert (event != NULL);

      image_table = EEL_IMAGE_TABLE (event_data);

      child = eel_wrap_table_find_child_at_event_point (EEL_WRAP_TABLE (image_table), event->x, event->y);

      if (child && !gtk_widget_get_sensitive (child)) {
            return FALSE;
      }

      if (child != NULL) {
            if (child == image_table->details->child_under_pointer) {
                  image_table->details->child_being_pressed = child;
                  image_table_emit_signal (image_table,
                                     child,
                                     CHILD_PRESSED,
                                     event->x,
                                     event->y,
                                     event->button,
                                     event->state,
                                     (GdkEvent *)event);
            }
      }

      return FALSE;
}

static int
ancestor_button_release_event (GtkWidget *widget,
                         GdkEventButton *event,
                         gpointer event_data)
{
      EelImageTable *image_table;
      GtkWidget *child;
      GtkWidget *released_emit_child = NULL;
      GtkWidget *clicked_emit_child = NULL;

      g_assert (GTK_IS_WIDGET (widget));
      g_assert (EEL_IS_IMAGE_TABLE (event_data));
      g_assert (event != NULL);

      image_table = EEL_IMAGE_TABLE (event_data);

      child = eel_wrap_table_find_child_at_event_point (EEL_WRAP_TABLE (image_table), event->x, event->y);

      if (child && !gtk_widget_get_sensitive (child)) {
            return FALSE;
      }

      if (image_table->details->child_being_pressed != NULL) {
            released_emit_child = image_table->details->child_being_pressed;
      }

      if (child != NULL) {
            if (child == image_table->details->child_being_pressed) {
                  clicked_emit_child = child;
            }
      }
      
      image_table->details->child_being_pressed = NULL;

      if (released_emit_child != NULL) {
            image_table_emit_signal (image_table,
                               released_emit_child,
                               CHILD_RELEASED,
                               event->x,
                               event->y,
                               event->button,
                               event->state,
                               (GdkEvent *)event);
      }
      
      if (clicked_emit_child != NULL) {

            image_table_emit_signal (image_table,
                               clicked_emit_child,
                               CHILD_CLICKED,
                               event->x,
                               event->y,
                               event->button,
                               event->state,
                               (GdkEvent *)event);
      }
      
      return FALSE;
}

/**
 * eel_image_table_new:
 */
GtkWidget*
eel_image_table_new (gboolean homogeneous)
{
      EelImageTable *image_table;

      image_table = EEL_IMAGE_TABLE (gtk_widget_new (eel_image_table_get_type (), NULL));

      eel_wrap_table_set_homogeneous (EEL_WRAP_TABLE (image_table), homogeneous);
      
      return GTK_WIDGET (image_table);
}

/**
 * eel_image_table_add_empty_child:
 * @image_table: A EelImageTable.
 *
 * Add a "empty" child to the table.  Useful when you want to have
 * empty space between 2 children.
 *
 * Returns: The empty child - A EelLabeledImage widget with no label
 *          or pixbuf.
 */
GtkWidget *
eel_image_table_add_empty_image (EelImageTable *image_table)
{
      GtkWidget *empty;

      g_return_val_if_fail (EEL_IS_IMAGE_TABLE (image_table), NULL);

      empty = eel_labeled_image_new (NULL, NULL);
      gtk_container_add (GTK_CONTAINER (image_table), empty);
      gtk_widget_set_sensitive (empty, FALSE);

      return empty;
}

Generated by  Doxygen 1.6.0   Back to index