file-roller r2091 - in branches/filter: . src
- From: paobac svn gnome org
- To: svn-commits-list gnome org
- Subject: file-roller r2091 - in branches/filter: . src
- Date: Mon, 7 Jan 2008 20:10:42 +0000 (GMT)
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 <paobac svn gnome org>
* 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_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]