Author: paobac
Date: Mon Jan  7 20:10:42 2008
New Revision: 2091
URL: http://svn.gnome.org/viewvc/file-roller?rev=2091&view=rev

Log:
2008-01-07  Paolo Bacchilega  <[EMAIL PROTECTED]>

        * src/sexy-icon-entry.h: new file
        * src/sexy-icon-entry.c: new file
        * src/fr-list-model.c: 
        * src/fr-window.h: 
        * src/fr-window.c: 
        * src/Makefile.am: 
        
        Started work an a list filter.

Added:
   branches/filter/src/sexy-icon-entry.c
   branches/filter/src/sexy-icon-entry.h
Modified:
   branches/filter/ChangeLog

Added: branches/filter/src/sexy-icon-entry.c
==============================================================================
--- (empty file)
+++ branches/filter/src/sexy-icon-entry.c       Mon Jan  7 20:10:42 2008
@@ -0,0 +1,1046 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  File-Roller
+ *
+ *  Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+/* Based on libsexy 0.1.11.  Original copyright note follows:
+ *  
+ * 
+ * @file libsexy/sexy-icon-entry.c Entry widget
+ *
+ * @Copyright (C) 2004-2006 Christian Hammond.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+  
+#include <libsexy/sexy-icon-entry.h>
+#include <string.h>
+#include <gtk/gtk.h>
+
+#define ICON_MARGIN 2
+#define MAX_ICONS 2
+
+#define IS_VALID_ICON_ENTRY_POSITION(pos) \
+       ((pos) == SEXY_ICON_ENTRY_PRIMARY || \
+        (pos) == SEXY_ICON_ENTRY_SECONDARY)
+
+typedef struct
+{
+       GtkImage *icon;
+       gboolean highlight;
+       gboolean hovered;
+       gboolean hide_if_empty;
+       GdkWindow *window;
+
+} SexyIconInfo;
+
+struct _SexyIconEntryPriv
+{
+       SexyIconInfo icons[MAX_ICONS];
+
+       gulong icon_released_id;
+       gboolean empty;
+};
+
+enum
+{
+       ICON_PRESSED,
+       ICON_RELEASED,
+       LAST_SIGNAL
+};
+
+static void sexy_icon_entry_class_init(SexyIconEntryClass *klass);
+static void sexy_icon_entry_editable_init(GtkEditableClass *iface);
+static void sexy_icon_entry_init(SexyIconEntry *entry);
+static void sexy_icon_entry_finalize(GObject *obj);
+static void sexy_icon_entry_destroy(GtkObject *obj);
+static void sexy_icon_entry_map(GtkWidget *widget);
+static void sexy_icon_entry_unmap(GtkWidget *widget);
+static void sexy_icon_entry_realize(GtkWidget *widget);
+static void sexy_icon_entry_unrealize(GtkWidget *widget);
+static void sexy_icon_entry_size_request(GtkWidget *widget,
+                                                                               
  GtkRequisition *requisition);
+static void sexy_icon_entry_size_allocate(GtkWidget *widget,
+                                                                               
   GtkAllocation *allocation);
+static gint sexy_icon_entry_expose(GtkWidget *widget, GdkEventExpose *event);
+static gint sexy_icon_entry_enter_notify(GtkWidget *widget,
+                                                                               
           GdkEventCrossing *event);
+static gint sexy_icon_entry_leave_notify(GtkWidget *widget,
+                                                                               
           GdkEventCrossing *event);
+static gint sexy_icon_entry_button_press(GtkWidget *widget,
+                                                                               
           GdkEventButton *event);
+static gint sexy_icon_entry_button_release(GtkWidget *widget,
+                                                                               
                 GdkEventButton *event);
+
+static void sexy_icon_entry_changed (GtkEditable *editable);
+
+static GtkEntryClass *parent_class = NULL;
+static guint signals[LAST_SIGNAL] = {0};
+
+G_DEFINE_TYPE_EXTENDED(SexyIconEntry, sexy_icon_entry, GTK_TYPE_ENTRY,
+                                          0,
+                                          
G_IMPLEMENT_INTERFACE(GTK_TYPE_EDITABLE,
+                                                                               
         sexy_icon_entry_editable_init));
+
+static void
+sexy_icon_entry_class_init(SexyIconEntryClass *klass)
+{
+       GObjectClass *gobject_class;
+       GtkObjectClass *object_class;
+       GtkWidgetClass *widget_class;
+       GtkEntryClass *entry_class;
+
+       parent_class = g_type_class_peek_parent(klass);
+
+       gobject_class  = G_OBJECT_CLASS(klass);
+       object_class   = GTK_OBJECT_CLASS(klass);
+       widget_class   = GTK_WIDGET_CLASS(klass);
+       entry_class    = GTK_ENTRY_CLASS(klass);
+       
+       gobject_class->finalize = sexy_icon_entry_finalize;
+
+       object_class->destroy = sexy_icon_entry_destroy;
+
+       widget_class->map = sexy_icon_entry_map;
+       widget_class->unmap = sexy_icon_entry_unmap;
+       widget_class->realize = sexy_icon_entry_realize;
+       widget_class->unrealize = sexy_icon_entry_unrealize;
+       widget_class->size_request = sexy_icon_entry_size_request;
+       widget_class->size_allocate = sexy_icon_entry_size_allocate;
+       widget_class->expose_event = sexy_icon_entry_expose;
+       widget_class->enter_notify_event = sexy_icon_entry_enter_notify;
+       widget_class->leave_notify_event = sexy_icon_entry_leave_notify;
+       widget_class->button_press_event = sexy_icon_entry_button_press;
+       widget_class->button_release_event = sexy_icon_entry_button_release;
+
+       /**
+        * SexyIconEntry::icon-pressed:
+        * @entry: The entry on which the signal is emitted.
+        * @icon_pos: The position of the clicked icon.
+        * @button: The mouse button clicked.
+        *
+        * The ::icon-pressed signal is emitted when an icon is clicked.
+        */
+       signals[ICON_PRESSED] =
+               g_signal_new("icon_pressed",
+                                        G_TYPE_FROM_CLASS(gobject_class),
+                                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                                        G_STRUCT_OFFSET(SexyIconEntryClass, 
icon_pressed),
+                                        NULL, NULL,
+                                        gtk_marshal_VOID__INT_INT,
+                                        G_TYPE_NONE, 2,
+                                        G_TYPE_INT,
+                                        G_TYPE_INT);
+
+       /**
+        * SexyIconEntry::icon-released:
+        * @entry: The entry on which the signal is emitted.
+        * @icon_pos: The position of the clicked icon.
+        * @button: The mouse button clicked.
+        *
+        * The ::icon-released signal is emitted on the button release from a
+        * mouse click.
+        */
+       signals[ICON_RELEASED] =
+               g_signal_new("icon_released",
+                                        G_TYPE_FROM_CLASS(gobject_class),
+                                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                                        G_STRUCT_OFFSET(SexyIconEntryClass, 
icon_released),
+                                        NULL, NULL,
+                                        gtk_marshal_VOID__INT_INT,
+                                        G_TYPE_NONE, 2,
+                                        G_TYPE_INT,
+                                        G_TYPE_INT);
+}
+
+static void
+sexy_icon_entry_editable_init(GtkEditableClass *iface)
+{
+               iface->changed = sexy_icon_entry_changed;
+}
+
+static void
+sexy_icon_entry_init(SexyIconEntry *entry)
+{
+       entry->priv = g_new0(SexyIconEntryPriv, 1);
+       entry->priv->empty = TRUE;
+}
+
+static void
+sexy_icon_entry_finalize(GObject *obj)
+{
+       SexyIconEntry *entry;
+
+       g_return_if_fail(obj != NULL);
+       g_return_if_fail(SEXY_IS_ICON_ENTRY(obj));
+
+       entry = SEXY_ICON_ENTRY(obj);
+
+       g_free(entry->priv);
+
+       if (G_OBJECT_CLASS(parent_class)->finalize)
+               G_OBJECT_CLASS(parent_class)->finalize(obj);
+}
+
+static void
+sexy_icon_entry_destroy(GtkObject *obj)
+{
+       SexyIconEntry *entry;
+
+       entry = SEXY_ICON_ENTRY(obj);
+
+       sexy_icon_entry_set_icon(entry, SEXY_ICON_ENTRY_PRIMARY, NULL);
+       sexy_icon_entry_set_icon(entry, SEXY_ICON_ENTRY_SECONDARY, NULL);
+
+       if (GTK_OBJECT_CLASS(parent_class)->destroy)
+               GTK_OBJECT_CLASS(parent_class)->destroy(obj);
+}
+
+static void
+sexy_icon_entry_map(GtkWidget *widget)
+{
+       if (GTK_WIDGET_REALIZED(widget) && !GTK_WIDGET_MAPPED(widget))
+       {
+               SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+               int i;
+
+               GTK_WIDGET_CLASS(parent_class)->map(widget);
+
+               for (i = 0; i < MAX_ICONS; i++)
+               {
+                       if (entry->priv->icons[i].icon != NULL)
+                               gdk_window_show(entry->priv->icons[i].window);
+               }
+       }
+}
+
+static void
+sexy_icon_entry_unmap(GtkWidget *widget)
+{
+       if (GTK_WIDGET_MAPPED(widget))
+       {
+               SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+               int i;
+
+               for (i = 0; i < MAX_ICONS; i++)
+               {
+                       if (entry->priv->icons[i].icon != NULL)
+                               gdk_window_hide(entry->priv->icons[i].window);
+               }
+
+               GTK_WIDGET_CLASS(parent_class)->unmap(widget);
+       }
+}
+
+static gint
+get_icon_width(SexyIconEntry *entry, SexyIconEntryPosition icon_pos)
+{
+       GtkRequisition requisition;
+       gint menu_icon_width;
+       gint width;
+       SexyIconInfo *icon_info = &entry->priv->icons[icon_pos];
+
+       if (icon_info->icon == NULL)
+               return 0;
+
+       gtk_widget_size_request(GTK_WIDGET(icon_info->icon), &requisition);
+       gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &menu_icon_width, NULL);
+
+       width = MAX(requisition.width, menu_icon_width);
+
+       return width;
+}
+
+static void
+get_borders(SexyIconEntry *entry, gint *xborder, gint *yborder)
+{
+       GtkWidget *widget = GTK_WIDGET(entry);
+       gint focus_width;
+       gboolean interior_focus;
+
+       gtk_widget_style_get(widget,
+                                                "interior-focus", 
&interior_focus,
+                                                "focus-line-width", 
&focus_width,
+                                                NULL);
+
+       if (gtk_entry_get_has_frame(GTK_ENTRY(entry)))
+       {
+               *xborder = widget->style->xthickness;
+               *yborder = widget->style->ythickness;
+       }
+       else
+       {
+               *xborder = 0;
+               *yborder = 0;
+       }
+
+       if (!interior_focus)
+       {
+               *xborder += focus_width;
+               *yborder += focus_width;
+       }
+}
+
+static void
+get_text_area_size(SexyIconEntry *entry, GtkAllocation *alloc)
+{
+       GtkWidget *widget = GTK_WIDGET(entry);
+       GtkRequisition requisition;
+       gint xborder, yborder;
+
+       gtk_widget_get_child_requisition(widget, &requisition);
+       get_borders(entry, &xborder, &yborder);
+
+       alloc->x      = xborder;
+       alloc->y      = yborder;
+       alloc->width  = widget->allocation.width - xborder * 2;
+       alloc->height = requisition.height       - yborder * 2;
+}
+
+static void
+get_icon_allocation(SexyIconEntry *icon_entry,
+                                       gboolean left,
+                                       GtkAllocation *widget_alloc,
+                                       GtkAllocation *text_area_alloc,
+                                       GtkAllocation *allocation,
+                                       SexyIconEntryPosition *icon_pos)
+{
+       gboolean rtl;
+
+       rtl = (gtk_widget_get_direction(GTK_WIDGET(icon_entry)) ==
+                  GTK_TEXT_DIR_RTL);
+
+       if (left)
+               *icon_pos = (rtl ? SEXY_ICON_ENTRY_SECONDARY : 
SEXY_ICON_ENTRY_PRIMARY);
+       else
+               *icon_pos = (rtl ? SEXY_ICON_ENTRY_PRIMARY : 
SEXY_ICON_ENTRY_SECONDARY);
+
+       allocation->y = text_area_alloc->y;
+       allocation->width = get_icon_width(icon_entry, *icon_pos);
+       allocation->height = text_area_alloc->height;
+
+       if (left)
+               allocation->x = text_area_alloc->x + ICON_MARGIN;
+       else
+       {
+               allocation->x = text_area_alloc->x + text_area_alloc->width -
+                               allocation->width - ICON_MARGIN;
+       }
+}
+
+static void
+sexy_icon_entry_realize(GtkWidget *widget)
+{
+       SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+       GdkWindowAttr attributes;
+       gint attributes_mask;
+       int i;
+
+       GTK_WIDGET_CLASS(parent_class)->realize(widget);
+
+       attributes.x = 0;
+       attributes.y = 0;
+       attributes.width = 1;
+       attributes.height = 1;
+       attributes.window_type = GDK_WINDOW_CHILD;
+       attributes.wclass = GDK_INPUT_OUTPUT;
+       attributes.visual = gtk_widget_get_visual(widget);
+       attributes.colormap = gtk_widget_get_colormap(widget);
+       attributes.event_mask = gtk_widget_get_events(widget);
+       attributes.event_mask |=
+               (GDK_EXPOSURE_MASK
+                | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+                | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+
+       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+       for (i = 0; i < MAX_ICONS; i++)
+       {
+               SexyIconInfo *icon_info;
+
+               icon_info = &entry->priv->icons[i];
+               icon_info->window = gdk_window_new(widget->window, &attributes,
+                                                                               
   attributes_mask);
+               gdk_window_set_user_data(icon_info->window, widget);
+
+               gdk_window_set_background(icon_info->window,
+                       &widget->style->base[GTK_WIDGET_STATE(widget)]);
+       }
+
+       gtk_widget_queue_resize(widget);
+}
+
+static void
+sexy_icon_entry_unrealize(GtkWidget *widget)
+{
+       SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+       int i;
+
+       GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
+
+       for (i = 0; i < MAX_ICONS; i++)
+       {
+               SexyIconInfo *icon_info = &entry->priv->icons[i];
+
+               gdk_window_destroy(icon_info->window);
+               icon_info->window = NULL;
+       }
+}
+
+static void
+sexy_icon_entry_size_request(GtkWidget *widget, GtkRequisition *requisition)
+{
+       GtkEntry *gtkentry;
+       SexyIconEntry *entry;
+       gint icon_widths = 0;
+       int i;
+
+       gtkentry = GTK_ENTRY(widget);
+       entry    = SEXY_ICON_ENTRY(widget);
+
+       for (i = 0; i < MAX_ICONS; i++)
+       {
+               int icon_width = get_icon_width(entry, i);
+
+               if (icon_width > 0)
+                       icon_widths += icon_width + ICON_MARGIN;
+       }
+
+       GTK_WIDGET_CLASS(parent_class)->size_request(widget, requisition);
+
+       if (icon_widths > requisition->width)
+               requisition->width += icon_widths;
+}
+
+static void
+place_windows(SexyIconEntry *icon_entry, GtkAllocation *widget_alloc)
+{
+       SexyIconEntryPosition left_icon_pos;
+       SexyIconEntryPosition right_icon_pos;
+       GtkAllocation left_icon_alloc;
+       GtkAllocation right_icon_alloc;
+       GtkAllocation text_area_alloc;
+
+       get_text_area_size(icon_entry, &text_area_alloc);
+       get_icon_allocation(icon_entry, TRUE, widget_alloc, &text_area_alloc,
+                                               &left_icon_alloc, 
&left_icon_pos);
+       get_icon_allocation(icon_entry, FALSE, widget_alloc, &text_area_alloc,
+                                               &right_icon_alloc, 
&right_icon_pos);
+
+       if (left_icon_alloc.width > 0)
+       {
+               text_area_alloc.x = left_icon_alloc.x + left_icon_alloc.width +
+                                   ICON_MARGIN;
+       }
+
+       if (right_icon_alloc.width > 0)
+               text_area_alloc.width -= right_icon_alloc.width + ICON_MARGIN;
+
+       text_area_alloc.width -= text_area_alloc.x;
+
+       gdk_window_move_resize(icon_entry->priv->icons[left_icon_pos].window,
+                                                  left_icon_alloc.x, 
left_icon_alloc.y,
+                                                  left_icon_alloc.width, 
left_icon_alloc.height);
+
+       gdk_window_move_resize(icon_entry->priv->icons[right_icon_pos].window,
+                                                  right_icon_alloc.x, 
right_icon_alloc.y,
+                                                  right_icon_alloc.width, 
right_icon_alloc.height);
+
+       gdk_window_move_resize(GTK_ENTRY(icon_entry)->text_area,
+                                                  text_area_alloc.x, 
text_area_alloc.y,
+                                                  text_area_alloc.width, 
text_area_alloc.height);
+}
+
+static void
+sexy_icon_entry_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
+{
+       g_return_if_fail(SEXY_IS_ICON_ENTRY(widget));
+       g_return_if_fail(allocation != NULL);
+
+       widget->allocation = *allocation;
+
+       GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation);
+
+       if (GTK_WIDGET_REALIZED(widget))
+               place_windows(SEXY_ICON_ENTRY(widget), allocation);
+}
+
+static GdkPixbuf *
+get_pixbuf_from_icon(SexyIconEntry *entry, SexyIconEntryPosition icon_pos)
+{
+       GdkPixbuf *pixbuf = NULL;
+       gchar *stock_id;
+       SexyIconInfo *icon_info = &entry->priv->icons[icon_pos];
+       GtkIconSize size;
+
+       switch (gtk_image_get_storage_type(GTK_IMAGE(icon_info->icon)))
+       {
+               case GTK_IMAGE_PIXBUF:
+                       pixbuf = 
gtk_image_get_pixbuf(GTK_IMAGE(icon_info->icon));
+                       g_object_ref(pixbuf);
+                       break;
+
+               case GTK_IMAGE_STOCK:
+                       gtk_image_get_stock(GTK_IMAGE(icon_info->icon), 
&stock_id, &size);
+                       pixbuf = gtk_widget_render_icon(GTK_WIDGET(entry),
+                                                                               
        stock_id, size, NULL);
+                       break;
+
+               default:
+                       return NULL;
+       }
+
+       return pixbuf;
+}
+
+/* Kudos to the gnome-panel guys. */
+static void
+colorshift_pixbuf(GdkPixbuf *dest, GdkPixbuf *src, int shift)
+{
+       gint i, j;
+       gint width, height, has_alpha, src_rowstride, dest_rowstride;
+       guchar *target_pixels;
+       guchar *original_pixels;
+       guchar *pix_src;
+       guchar *pix_dest;
+       int val;
+       guchar r, g, b;
+
+       has_alpha       = gdk_pixbuf_get_has_alpha(src);
+       width           = gdk_pixbuf_get_width(src);
+       height          = gdk_pixbuf_get_height(src);
+       src_rowstride   = gdk_pixbuf_get_rowstride(src);
+       dest_rowstride  = gdk_pixbuf_get_rowstride(dest);
+       original_pixels = gdk_pixbuf_get_pixels(src);
+       target_pixels   = gdk_pixbuf_get_pixels(dest);
+
+       for (i = 0; i < height; i++)
+       {
+               pix_dest = target_pixels   + i * dest_rowstride;
+               pix_src  = original_pixels + i * src_rowstride;
+
+               for (j = 0; j < width; j++)
+               {
+                       r = *(pix_src++);
+                       g = *(pix_src++);
+                       b = *(pix_src++);
+
+                       val = r + shift;
+                       *(pix_dest++) = CLAMP(val, 0, 255);
+
+                       val = g + shift;
+                       *(pix_dest++) = CLAMP(val, 0, 255);
+
+                       val = b + shift;
+                       *(pix_dest++) = CLAMP(val, 0, 255);
+
+                       if (has_alpha)
+                               *(pix_dest++) = *(pix_src++);
+               }
+       }
+}
+
+static void
+draw_icon(GtkWidget *widget, SexyIconEntryPosition icon_pos)
+{
+       SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+       SexyIconInfo *icon_info = &entry->priv->icons[icon_pos];
+       GdkPixbuf *pixbuf;
+       gint x, y, width, height;
+
+       if (icon_info->icon == NULL || !GTK_WIDGET_REALIZED(widget))
+               return;
+
+       if (entry->priv->empty && icon_info->hide_if_empty)
+               return;
+
+       if ((pixbuf = get_pixbuf_from_icon(entry, icon_pos)) == NULL)
+               return;
+
+       gdk_drawable_get_size(icon_info->window, &width, &height);
+
+       if (width == 1 || height == 1)
+       {
+               /*
+                * size_allocate hasn't been called yet. These are the default 
values.
+                */
+               return;
+       }
+
+       if (gdk_pixbuf_get_height(pixbuf) > height)
+       {
+               GdkPixbuf *temp_pixbuf;
+               int scale;
+
+               scale = height - (2 * ICON_MARGIN);
+
+               temp_pixbuf = gdk_pixbuf_scale_simple(pixbuf, scale, scale,
+                                                                               
          GDK_INTERP_BILINEAR);
+
+               g_object_unref(pixbuf);
+
+               pixbuf = temp_pixbuf;
+       }
+
+       x = (width  - gdk_pixbuf_get_width(pixbuf)) / 2;
+       y = (height - gdk_pixbuf_get_height(pixbuf)) / 2;
+
+       if (icon_info->hovered)
+       {
+               GdkPixbuf *temp_pixbuf;
+
+               temp_pixbuf = gdk_pixbuf_copy(pixbuf);
+
+               colorshift_pixbuf(temp_pixbuf, pixbuf, 30);
+
+               g_object_unref(pixbuf);
+
+               pixbuf = temp_pixbuf;
+       }
+
+       gdk_draw_pixbuf(icon_info->window, widget->style->black_gc, pixbuf,
+                                       0, 0, x, y, -1, -1,
+                                       GDK_RGB_DITHER_NORMAL, 0, 0);
+
+       g_object_unref(pixbuf);
+}
+
+static gint
+sexy_icon_entry_expose(GtkWidget *widget, GdkEventExpose *event)
+{
+       SexyIconEntry *entry;
+
+       g_return_val_if_fail(SEXY_IS_ICON_ENTRY(widget), FALSE);
+       g_return_val_if_fail(event != NULL, FALSE);
+
+       entry = SEXY_ICON_ENTRY(widget);
+
+       if (GTK_WIDGET_DRAWABLE(widget))
+       {
+               gboolean found = FALSE;
+               int i;
+
+               for (i = 0; i < MAX_ICONS && !found; i++)
+               {
+                       SexyIconInfo *icon_info = &entry->priv->icons[i];
+
+                       if (event->window == icon_info->window)
+                       {
+                               gint width;
+                               GtkAllocation text_area_alloc;
+
+                               get_text_area_size(entry, &text_area_alloc);
+                               gdk_drawable_get_size(icon_info->window, 
&width, NULL);
+
+                               gtk_paint_flat_box(widget->style, 
icon_info->window,
+                                                                  
GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
+                                                                  NULL, 
widget, "entry_bg",
+                                                                  0, 0, width, 
text_area_alloc.height);
+
+                               draw_icon(widget, i);
+
+                               found = TRUE;
+                       }
+               }
+
+               if (!found)
+                       GTK_WIDGET_CLASS(parent_class)->expose_event(widget, 
event);
+       }
+
+       return FALSE;
+}
+
+static void
+update_icon(GObject *obj, GParamSpec *param, SexyIconEntry *entry)
+{
+       if (param != NULL)
+       {
+               const char *name = g_param_spec_get_name(param);
+
+               if (strcmp(name, "pixbuf")   && strcmp(name, "stock")  &&
+                       strcmp(name, "image")    && strcmp(name, "pixmap") &&
+                       strcmp(name, "icon_set") && strcmp(name, 
"pixbuf_animation"))
+               {
+                       return;
+               }
+       }
+
+       gtk_widget_queue_resize(GTK_WIDGET(entry));
+}
+
+static gint
+sexy_icon_entry_enter_notify(GtkWidget *widget, GdkEventCrossing *event)
+{
+       SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+       int i;
+
+       for (i = 0; i < MAX_ICONS; i++)
+       {
+               if (event->window == entry->priv->icons[i].window)
+               {
+                       if (sexy_icon_entry_get_icon_highlight(entry, i))
+                       {
+                               entry->priv->icons[i].hovered = TRUE;
+
+                               update_icon(NULL, NULL, entry);
+
+                               break;
+                       }
+               }
+       }
+
+       return FALSE;
+}
+
+static gint
+sexy_icon_entry_leave_notify(GtkWidget *widget, GdkEventCrossing *event)
+{
+       SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+       int i;
+
+       for (i = 0; i < MAX_ICONS; i++)
+       {
+               if (event->window == entry->priv->icons[i].window)
+               {
+                       if (sexy_icon_entry_get_icon_highlight(entry, i))
+                       {
+                               entry->priv->icons[i].hovered = FALSE;
+
+                               update_icon(NULL, NULL, entry);
+
+                               break;
+                       }
+               }
+       }
+
+       return FALSE;
+}
+
+static gint
+sexy_icon_entry_button_press(GtkWidget *widget, GdkEventButton *event)
+{
+       SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+       int i;
+
+       for (i = 0; i < MAX_ICONS; i++)
+       {
+               if (event->window == entry->priv->icons[i].window)
+               {
+                       if (event->button == 1 &&
+                               sexy_icon_entry_get_icon_highlight(entry, i))
+                       {
+                               entry->priv->icons[i].hovered = FALSE;
+
+                               update_icon(NULL, NULL, entry);
+                       }
+
+                       g_signal_emit(entry, signals[ICON_PRESSED], 0, i, 
event->button);
+
+                       return TRUE;
+               }
+       }
+
+       if (GTK_WIDGET_CLASS(parent_class)->button_press_event)
+               return 
GTK_WIDGET_CLASS(parent_class)->button_press_event(widget,
+                                                                               
                                                  event);
+
+       return FALSE;
+}
+
+static gint
+sexy_icon_entry_button_release(GtkWidget *widget, GdkEventButton *event)
+{
+       SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+       int i;
+
+       for (i = 0; i < MAX_ICONS; i++)
+       {
+               GdkWindow *icon_window = entry->priv->icons[i].window;
+
+               if (event->window == icon_window)
+               {
+                       int width, height;
+                       gdk_drawable_get_size(icon_window, &width, &height);
+
+                       if (event->button == 1 &&
+                               sexy_icon_entry_get_icon_highlight(entry, i) &&
+                               event->x >= 0     && event->y >= 0 &&
+                               event->x <= width && event->y <= height)
+                       {
+                               entry->priv->icons[i].hovered = TRUE;
+
+                               update_icon(NULL, NULL, entry);
+                       }
+
+                       g_signal_emit(entry, signals[ICON_RELEASED], 0, i, 
event->button);
+
+                       return TRUE;
+               }
+       }
+
+       if (GTK_WIDGET_CLASS(parent_class)->button_release_event)
+               return 
GTK_WIDGET_CLASS(parent_class)->button_release_event(widget,
+                                                                               
                                                        event);
+
+       return FALSE;
+}
+
+
+static void
+sexy_icon_entry_changed (GtkEditable *editable)
+{
+       SexyIconEntry *entry = SEXY_ICON_ENTRY(editable);
+       char          *value;
+       gboolean       empty;
+       
+       value = gtk_editable_get_chars (editable, 0, -1);
+       empty = (value == NULL) || (*value == '\0');
+       if (empty != entry->priv->empty) {
+               entry->priv->empty = empty;
+               gtk_widget_queue_resize (GTK_WIDGET (entry));
+       }       
+       g_free (value);
+}
+
+
+/**
+ * sexy_icon_entry_new
+ *
+ * Creates a new SexyIconEntry widget.
+ *
+ * Returns a new #SexyIconEntry.
+ */
+GtkWidget *
+sexy_icon_entry_new(void)
+{
+       return GTK_WIDGET(g_object_new(SEXY_TYPE_ICON_ENTRY, NULL));
+}
+
+/**
+ * sexy_icon_entry_set_icon
+ * @entry: A #SexyIconEntry.
+ * @position: Icon position.
+ * @icon: A #GtkImage to set as the icon.
+ *
+ * Sets the icon shown in the entry
+ */
+void
+sexy_icon_entry_set_icon(SexyIconEntry *entry, SexyIconEntryPosition icon_pos,
+                                                GtkImage *icon)
+{
+       SexyIconInfo *icon_info;
+
+       g_return_if_fail(entry != NULL);
+       g_return_if_fail(SEXY_IS_ICON_ENTRY(entry));
+       g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos));
+       g_return_if_fail(icon == NULL || GTK_IS_IMAGE(icon));
+
+       icon_info = &entry->priv->icons[icon_pos];
+
+       if (icon == icon_info->icon)
+               return;
+
+       icon_info->hide_if_empty = FALSE;
+
+       if (icon_pos == SEXY_ICON_ENTRY_SECONDARY &&
+               entry->priv->icon_released_id != 0)
+       {
+               g_signal_handler_disconnect(entry, 
entry->priv->icon_released_id);
+               entry->priv->icon_released_id = 0;
+       }
+
+       if (icon == NULL)
+       {
+               if (icon_info->icon != NULL)
+               {
+                       gtk_widget_destroy(GTK_WIDGET(icon_info->icon));
+                       icon_info->icon = NULL;
+
+                       /*
+                        * Explicitly check, as the pointer may become 
invalidated
+                        * during destruction.
+                        */
+                       if (icon_info->window != NULL && 
GDK_IS_WINDOW(icon_info->window))
+                               gdk_window_hide(icon_info->window);
+               }
+       }
+       else
+       {
+               if (icon_info->window != NULL && icon_info->icon == NULL)
+                       gdk_window_show(icon_info->window);
+
+               g_signal_connect(G_OBJECT(icon), "notify",
+                                                G_CALLBACK(update_icon), 
entry);
+
+               icon_info->icon = icon;
+               g_object_ref(icon);
+       }
+
+       update_icon(NULL, NULL, entry);
+}
+
+/**
+ * sexy_icon_entry_set_icon_highlight
+ * @entry: A #SexyIconEntry;
+ * @position: Icon position.
+ * @highlight: TRUE if the icon should highlight on mouse-over
+ *
+ * Determines whether the icon will highlight on mouse-over.
+ */
+void
+sexy_icon_entry_set_icon_highlight(SexyIconEntry *entry,
+                                                                  
SexyIconEntryPosition icon_pos,
+                                                                  gboolean 
highlight)
+{
+       SexyIconInfo *icon_info;
+
+       g_return_if_fail(entry != NULL);
+       g_return_if_fail(SEXY_IS_ICON_ENTRY(entry));
+       g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos));
+
+       icon_info = &entry->priv->icons[icon_pos];
+
+       if (icon_info->highlight == highlight)
+               return;
+
+       icon_info->highlight = highlight;
+}
+
+/**
+ * sexy_icon_entry_set_hide_if_empty
+ * @entry: A #SexyIconEntry;
+ * @position: Icon position.
+ * @hide: TRUE if the icon should hidden when the entry is empty
+ *
+ * Determines whether the icon will be hidden when the entry is empty.
+ */
+void 
+sexy_icon_entry_set_hide_if_empty (SexyIconEntry *entry,
+                                  SexyIconEntryPosition icon_pos,
+                                  gboolean hide)
+{
+       SexyIconInfo *icon_info;
+
+       g_return_if_fail(entry != NULL);
+       g_return_if_fail(SEXY_IS_ICON_ENTRY(entry));
+       g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos));
+
+       icon_info = &entry->priv->icons[icon_pos];
+       icon_info->hide_if_empty = hide;
+}
+
+/**
+ * sexy_icon_entry_get_icon
+ * @entry: A #SexyIconEntry.
+ * @position: Icon position.
+ *
+ * Retrieves the image used for the icon
+ *
+ * Returns: A #GtkImage.
+ */
+GtkImage *
+sexy_icon_entry_get_icon(const SexyIconEntry *entry,
+                                                SexyIconEntryPosition icon_pos)
+{
+       g_return_val_if_fail(entry != NULL, NULL);
+       g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry), NULL);
+       g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos), NULL);
+
+       return entry->priv->icons[icon_pos].icon;
+}
+
+/**
+ * sexy_icon_entry_get_icon_highlight
+ * @entry: A #SexyIconEntry.
+ * @position: Icon position.
+ *
+ * Retrieves whether entry will highlight the icon on mouseover.
+ *
+ * Returns: TRUE if icon highlights.
+ */
+gboolean
+sexy_icon_entry_get_icon_highlight(const SexyIconEntry *entry,
+                                                                  
SexyIconEntryPosition icon_pos)
+{
+       g_return_val_if_fail(entry != NULL, FALSE);
+       g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry), FALSE);
+       g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos), FALSE);
+
+       return entry->priv->icons[icon_pos].highlight;
+}
+
+static void
+clear_button_clicked_cb(SexyIconEntry *icon_entry,
+                                               SexyIconEntryPosition icon_pos,
+                                               int button)
+{
+       if (icon_pos != SEXY_ICON_ENTRY_SECONDARY || button != 1)
+               return;
+
+       gtk_entry_set_text(GTK_ENTRY(icon_entry), "");
+}
+
+/**
+ * sexy_icon_entry_add_clear_button
+ * @icon_entry: A #SexyIconEntry.
+ *
+ * A convenience function to add a clear button to the end of the entry.
+ * This is useful for search boxes.
+ */
+void
+sexy_icon_entry_add_clear_button(SexyIconEntry *icon_entry)
+{
+       GtkWidget *icon;
+
+       g_return_if_fail(icon_entry != NULL);
+       g_return_if_fail(SEXY_IS_ICON_ENTRY(icon_entry));
+
+       icon = gtk_image_new_from_stock(GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU);
+       gtk_widget_show(icon);
+       sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(icon_entry),
+                                                        
SEXY_ICON_ENTRY_SECONDARY,
+                                                        GTK_IMAGE(icon));
+       sexy_icon_entry_set_icon_highlight(SEXY_ICON_ENTRY(icon_entry),
+                                                                          
SEXY_ICON_ENTRY_SECONDARY, TRUE);
+       sexy_icon_entry_set_hide_if_empty(SEXY_ICON_ENTRY(icon_entry),
+                                                                          
SEXY_ICON_ENTRY_SECONDARY, TRUE);
+
+       if (icon_entry->priv->icon_released_id != 0)
+       {
+               g_signal_handler_disconnect(icon_entry,
+                                                                       
icon_entry->priv->icon_released_id);
+       }
+
+       icon_entry->priv->icon_released_id =
+               g_signal_connect(G_OBJECT(icon_entry), "icon_released",
+                                                
G_CALLBACK(clear_button_clicked_cb), NULL);
+}

Added: branches/filter/src/sexy-icon-entry.h
==============================================================================
--- (empty file)
+++ branches/filter/src/sexy-icon-entry.h       Mon Jan  7 20:10:42 2008
@@ -0,0 +1,105 @@
+/*
+ * @file libsexy/sexy-icon-entry.h Entry widget
+ *
+ * @Copyright (C) 2004-2006 Christian Hammond.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+#ifndef _SEXY_ICON_ENTRY_H_
+#define _SEXY_ICON_ENTRY_H_
+
+typedef struct _SexyIconEntry      SexyIconEntry;
+typedef struct _SexyIconEntryClass SexyIconEntryClass;
+typedef struct _SexyIconEntryPriv  SexyIconEntryPriv;
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtkimage.h>
+
+#define SEXY_TYPE_ICON_ENTRY (sexy_icon_entry_get_type())
+#define SEXY_ICON_ENTRY(obj) \
+               (G_TYPE_CHECK_INSTANCE_CAST((obj), SEXY_TYPE_ICON_ENTRY, 
SexyIconEntry))
+#define SEXY_ICON_ENTRY_CLASS(klass) \
+               (G_TYPE_CHECK_CLASS_CAST((klass), SEXY_TYPE_ICON_ENTRY, 
SexyIconEntryClass))
+#define SEXY_IS_ICON_ENTRY(obj) \
+               (G_TYPE_CHECK_INSTANCE_TYPE((obj), SEXY_TYPE_ICON_ENTRY))
+#define SEXY_IS_ICON_ENTRY_CLASS(klass) \
+               (G_TYPE_CHECK_CLASS_TYPE((klass), SEXY_TYPE_ICON_ENTRY))
+#define SEXY_ICON_ENTRY_GET_CLASS(obj) \
+               (G_TYPE_INSTANCE_GET_CLASS ((obj), SEXY_TYPE_ICON_ENTRY, 
SexyIconEntryClass))
+
+typedef enum
+{
+       SEXY_ICON_ENTRY_PRIMARY,
+       SEXY_ICON_ENTRY_SECONDARY
+
+} SexyIconEntryPosition;
+
+struct _SexyIconEntry
+{
+       GtkEntry parent_object;
+
+       SexyIconEntryPriv *priv;
+
+       void (*gtk_reserved1)(void);
+       void (*gtk_reserved2)(void);
+       void (*gtk_reserved3)(void);
+       void (*gtk_reserved4)(void);
+};
+
+struct _SexyIconEntryClass
+{
+       GtkEntryClass parent_class;
+
+       /* Signals */
+       void (*icon_pressed)(SexyIconEntry *entry, SexyIconEntryPosition 
icon_pos,
+                                                int button);
+       void (*icon_released)(SexyIconEntry *entry, SexyIconEntryPosition 
icon_pos,
+                                                 int button);
+
+       void (*gtk_reserved1)(void);
+       void (*gtk_reserved2)(void);
+       void (*gtk_reserved3)(void);
+       void (*gtk_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType sexy_icon_entry_get_type(void);
+
+GtkWidget *sexy_icon_entry_new(void);
+
+void sexy_icon_entry_set_icon(SexyIconEntry *entry,
+                                                         SexyIconEntryPosition 
position,
+                                                         GtkImage *icon);
+
+void sexy_icon_entry_set_icon_highlight(SexyIconEntry *entry,
+                                                                               
SexyIconEntryPosition position,
+                                                                               
gboolean highlight);
+
+void sexy_icon_entry_set_hide_if_empty(SexyIconEntry *entry,
+                                                                               
SexyIconEntryPosition position,
+                                                                               
gboolean hide);
+
+GtkImage *sexy_icon_entry_get_icon(const SexyIconEntry *entry,
+                                                                  
SexyIconEntryPosition position);
+
+gboolean sexy_icon_entry_get_icon_highlight(const SexyIconEntry *entry,
+                                                                               
        SexyIconEntryPosition position);
+void sexy_icon_entry_add_clear_button(SexyIconEntry *icon_entry);
+
+G_END_DECLS
+
+#endif /* _SEXY_ICON_ENTRY_H_ */
_______________________________________________
SVN-commits-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/svn-commits-list

Reply via email to