aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-cell-toggle.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2012-12-10 21:09:59 +0800
committerMatthew Barnes <mbarnes@redhat.com>2012-12-13 03:33:43 +0800
commitd09d8de870b6697c8a8b262e7e077b871a69b315 (patch)
tree3b718882e7a0bb0a996daf2967a033d91714c9b5 /e-util/e-cell-toggle.c
parentb61331ed03ac1c7a9b8614e25510040b9c60ae02 (diff)
downloadgsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar
gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.gz
gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.bz2
gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.lz
gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.xz
gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.zst
gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.zip
Consolidate base utility libraries into libeutil.
Evolution consists of entirely too many small utility libraries, which increases linking and loading time, places a burden on higher layers of the application (e.g. modules) which has to remember to link to all the small in-tree utility libraries, and makes it difficult to generate API documentation for these utility libraries in one Gtk-Doc module. Merge the following utility libraries under the umbrella of libeutil, and enforce a single-include policy on libeutil so we can reorganize the files as desired without disrupting its pseudo-public API. libemail-utils/libemail-utils.la libevolution-utils/libevolution-utils.la filter/libfilter.la widgets/e-timezone-dialog/libetimezonedialog.la widgets/menus/libmenus.la widgets/misc/libemiscwidgets.la widgets/table/libetable.la widgets/text/libetext.la This also merges libedataserverui from the Evolution-Data-Server module, since Evolution is its only consumer nowadays, and I'd like to make some improvements to those APIs without concern for backward-compatibility. And finally, start a Gtk-Doc module for libeutil. It's going to be a project just getting all the symbols _listed_ much less _documented_. But the skeletal structure is in place and I'm off to a good start.
Diffstat (limited to 'e-util/e-cell-toggle.c')
-rw-r--r--e-util/e-cell-toggle.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/e-util/e-cell-toggle.c b/e-util/e-cell-toggle.c
new file mode 100644
index 0000000000..2f2bcd359c
--- /dev/null
+++ b/e-util/e-cell-toggle.c
@@ -0,0 +1,469 @@
+/*
+ * e-cell-toggle.c - Multi-state image toggle cell object.
+ *
+ * This program 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) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Miguel de Icaza <miguel@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <libgnomecanvas/libgnomecanvas.h>
+
+#include "art/empty.xpm"
+
+#include "gal-a11y-e-cell-toggle.h"
+#include "gal-a11y-e-cell-registry.h"
+
+#include "e-cell-toggle.h"
+#include "e-table-item.h"
+
+#define E_CELL_TOGGLE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CELL_TOGGLE, ECellTogglePrivate))
+
+struct _ECellTogglePrivate {
+ gchar **icon_names;
+ guint n_icon_names;
+
+ GdkPixbuf *empty;
+ GPtrArray *pixbufs;
+ gint height;
+};
+
+G_DEFINE_TYPE (ECellToggle, e_cell_toggle, E_TYPE_CELL)
+
+typedef struct {
+ ECellView cell_view;
+ GnomeCanvas *canvas;
+} ECellToggleView;
+
+static void
+cell_toggle_load_icons (ECellToggle *cell_toggle)
+{
+ GtkIconTheme *icon_theme;
+ gint width, height;
+ gint max_height = 0;
+ guint ii;
+ GError *error = NULL;
+
+ icon_theme = gtk_icon_theme_get_default ();
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height);
+
+ g_ptr_array_set_size (cell_toggle->priv->pixbufs, 0);
+
+ for (ii = 0; ii < cell_toggle->priv->n_icon_names; ii++) {
+ const gchar *icon_name = cell_toggle->priv->icon_names[ii];
+ GdkPixbuf *pixbuf = NULL;
+
+ if (icon_name != NULL)
+ pixbuf = gtk_icon_theme_load_icon (
+ icon_theme, icon_name, height, 0, &error);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ if (pixbuf == NULL)
+ pixbuf = g_object_ref (cell_toggle->priv->empty);
+
+ g_ptr_array_add (cell_toggle->priv->pixbufs, pixbuf);
+ max_height = MAX (max_height, gdk_pixbuf_get_height (pixbuf));
+ }
+
+ cell_toggle->priv->height = max_height;
+}
+
+static void
+cell_toggle_dispose (GObject *object)
+{
+ ECellTogglePrivate *priv;
+
+ priv = E_CELL_TOGGLE_GET_PRIVATE (object);
+
+ if (priv->empty != NULL) {
+ g_object_unref (priv->empty);
+ priv->empty = NULL;
+ }
+
+ /* This unrefs all the elements. */
+ g_ptr_array_set_size (priv->pixbufs, 0);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_cell_toggle_parent_class)->dispose (object);
+}
+
+static void
+cell_toggle_finalize (GObject *object)
+{
+ ECellTogglePrivate *priv;
+ guint ii;
+
+ priv = E_CELL_TOGGLE_GET_PRIVATE (object);
+
+ /* The array is not NULL-terminated,
+ * so g_strfreev() will not work. */
+ for (ii = 0; ii < priv->n_icon_names; ii++)
+ g_free (priv->icon_names[ii]);
+ g_free (priv->icon_names);
+
+ g_ptr_array_free (priv->pixbufs, TRUE);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_cell_toggle_parent_class)->finalize (object);
+}
+
+static ECellView *
+cell_toggle_new_view (ECell *ecell,
+ ETableModel *table_model,
+ gpointer e_table_item_view)
+{
+ ECellToggleView *toggle_view = g_new0 (ECellToggleView, 1);
+ ETableItem *eti = E_TABLE_ITEM (e_table_item_view);
+ GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas;
+
+ toggle_view->cell_view.ecell = ecell;
+ toggle_view->cell_view.e_table_model = table_model;
+ toggle_view->cell_view.e_table_item_view = e_table_item_view;
+ toggle_view->cell_view.kill_view_cb = NULL;
+ toggle_view->cell_view.kill_view_cb_data = NULL;
+ toggle_view->canvas = canvas;
+
+ return (ECellView *) toggle_view;
+}
+
+static void
+cell_toggle_kill_view (ECellView *ecell_view)
+{
+ ECellToggleView *toggle_view = (ECellToggleView *) ecell_view;
+
+ if (toggle_view->cell_view.kill_view_cb)
+ toggle_view->cell_view.kill_view_cb (
+ ecell_view, toggle_view->cell_view.kill_view_cb_data);
+
+ if (toggle_view->cell_view.kill_view_cb_data)
+ g_list_free (toggle_view->cell_view.kill_view_cb_data);
+
+ g_free (ecell_view);
+}
+
+static void
+cell_toggle_draw (ECellView *ecell_view,
+ cairo_t *cr,
+ gint model_col,
+ gint view_col,
+ gint row,
+ ECellFlags flags,
+ gint x1,
+ gint y1,
+ gint x2,
+ gint y2)
+{
+ ECellTogglePrivate *priv;
+ GdkPixbuf *image;
+ gint x, y;
+
+ const gint value = GPOINTER_TO_INT (
+ e_table_model_value_at (ecell_view->e_table_model, model_col, row));
+
+ priv = E_CELL_TOGGLE_GET_PRIVATE (ecell_view->ecell);
+
+ if (value < 0 || value >= priv->pixbufs->len)
+ return;
+
+ image = g_ptr_array_index (priv->pixbufs, value);
+
+ if ((x2 - x1) < gdk_pixbuf_get_width (image))
+ x = x1;
+ else
+ x = x1 + ((x2 - x1) - gdk_pixbuf_get_width (image)) / 2;
+
+ if ((y2 - y1) < gdk_pixbuf_get_height (image))
+ y = y1;
+ else
+ y = y1 + ((y2 - y1) - gdk_pixbuf_get_height (image)) / 2;
+
+ cairo_save (cr);
+ gdk_cairo_set_source_pixbuf (cr, image, x, y);
+ cairo_paint_with_alpha (cr, 1);
+ cairo_restore (cr);
+}
+
+static void
+etog_set_value (ECellToggleView *toggle_view,
+ gint model_col,
+ gint view_col,
+ gint row,
+ gint value)
+{
+ ECellTogglePrivate *priv;
+
+ priv = E_CELL_TOGGLE_GET_PRIVATE (toggle_view->cell_view.ecell);
+
+ if (value >= priv->pixbufs->len)
+ value = 0;
+
+ e_table_model_set_value_at (
+ toggle_view->cell_view.e_table_model,
+ model_col, row, GINT_TO_POINTER (value));
+}
+
+static gint
+cell_toggle_event (ECellView *ecell_view,
+ GdkEvent *event,
+ gint model_col,
+ gint view_col,
+ gint row,
+ ECellFlags flags,
+ ECellActions *actions)
+{
+ ECellToggleView *toggle_view = (ECellToggleView *) ecell_view;
+ gpointer _value = e_table_model_value_at (
+ ecell_view->e_table_model, model_col, row);
+ const gint value = GPOINTER_TO_INT (_value);
+
+ switch (event->type) {
+ case GDK_KEY_PRESS:
+ if (event->key.keyval != GDK_KEY_space)
+ return FALSE;
+ /* Fall through */
+ case GDK_BUTTON_PRESS:
+ if (!e_table_model_is_cell_editable (
+ ecell_view->e_table_model, model_col, row))
+ return FALSE;
+
+ etog_set_value (
+ toggle_view, model_col, view_col, row, value + 1);
+
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+static gint
+cell_toggle_height (ECellView *ecell_view,
+ gint model_col,
+ gint view_col,
+ gint row)
+{
+ ECellTogglePrivate *priv;
+
+ priv = E_CELL_TOGGLE_GET_PRIVATE (ecell_view->ecell);
+
+ return priv->height;
+}
+
+static void
+cell_toggle_print (ECellView *ecell_view,
+ GtkPrintContext *context,
+ gint model_col,
+ gint view_col,
+ gint row,
+ gdouble width,
+ gdouble height)
+{
+ ECellTogglePrivate *priv;
+ GdkPixbuf *image;
+ gdouble image_width, image_height;
+ const gint value = GPOINTER_TO_INT (
+ e_table_model_value_at (ecell_view->e_table_model, model_col, row));
+
+ cairo_t *cr;
+
+ priv = E_CELL_TOGGLE_GET_PRIVATE (ecell_view->ecell);
+
+ if (value >= priv->pixbufs->len)
+ return;
+
+ image = g_ptr_array_index (priv->pixbufs, value);
+ if (image) {
+ cr = gtk_print_context_get_cairo_context (context);
+ cairo_save (cr);
+ cairo_translate (cr, 0 , 0);
+ image = gdk_pixbuf_add_alpha (image, TRUE, 255, 255, 255);
+ image_width = (gdouble) gdk_pixbuf_get_width (image);
+ image_height = (gdouble) gdk_pixbuf_get_height (image);
+ cairo_rectangle (
+ cr,
+ image_width / 7,
+ image_height / 3,
+ image_width - image_width / 4,
+ image_width - image_height / 7);
+ cairo_clip (cr);
+ gdk_cairo_set_source_pixbuf (cr, image, 0, image_height / 4);
+ cairo_paint (cr);
+ cairo_restore (cr);
+ }
+}
+
+static gdouble
+cell_toggle_print_height (ECellView *ecell_view,
+ GtkPrintContext *context,
+ gint model_col,
+ gint view_col,
+ gint row,
+ gdouble width)
+{
+ ECellTogglePrivate *priv;
+
+ priv = E_CELL_TOGGLE_GET_PRIVATE (ecell_view->ecell);
+
+ return priv->height;
+}
+
+static gint
+cell_toggle_max_width (ECellView *ecell_view,
+ gint model_col,
+ gint view_col)
+{
+ ECellTogglePrivate *priv;
+ gint max_width = 0;
+ gint number_of_rows;
+ gint row;
+
+ priv = E_CELL_TOGGLE_GET_PRIVATE (ecell_view->ecell);
+
+ number_of_rows = e_table_model_row_count (ecell_view->e_table_model);
+ for (row = 0; row < number_of_rows; row++) {
+ GdkPixbuf *pixbuf;
+ gpointer value;
+
+ value = e_table_model_value_at (
+ ecell_view->e_table_model, model_col, row);
+ pixbuf = g_ptr_array_index (
+ priv->pixbufs, GPOINTER_TO_INT (value));
+
+ max_width = MAX (max_width, gdk_pixbuf_get_width (pixbuf));
+ }
+
+ return max_width;
+}
+
+static void
+e_cell_toggle_class_init (ECellToggleClass *class)
+{
+ GObjectClass *object_class;
+ ECellClass *cell_class;
+
+ g_type_class_add_private (class, sizeof (ECellTogglePrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = cell_toggle_dispose;
+ object_class->finalize = cell_toggle_finalize;
+
+ cell_class = E_CELL_CLASS (class);
+ cell_class->new_view = cell_toggle_new_view;
+ cell_class->kill_view = cell_toggle_kill_view;
+ cell_class->draw = cell_toggle_draw;
+ cell_class->event = cell_toggle_event;
+ cell_class->height = cell_toggle_height;
+ cell_class->print = cell_toggle_print;
+ cell_class->print_height = cell_toggle_print_height;
+ cell_class->max_width = cell_toggle_max_width;
+
+ gal_a11y_e_cell_registry_add_cell_type (
+ NULL, E_TYPE_CELL_TOGGLE, gal_a11y_e_cell_toggle_new);
+}
+
+static void
+e_cell_toggle_init (ECellToggle *cell_toggle)
+{
+ cell_toggle->priv = E_CELL_TOGGLE_GET_PRIVATE (cell_toggle);
+
+ cell_toggle->priv->empty =
+ gdk_pixbuf_new_from_xpm_data (empty_xpm);
+
+ cell_toggle->priv->pixbufs =
+ g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+/**
+ * e_cell_toggle_construct:
+ * @cell_toggle: a fresh ECellToggle object
+ * @icon_names: array of icon names, some of which may be %NULL
+ * @n_icon_names: length of the @icon_names array
+ *
+ * Constructs the @cell_toggle object with the @icon_names and @n_icon_names
+ * arguments.
+ */
+void
+e_cell_toggle_construct (ECellToggle *cell_toggle,
+ const gchar **icon_names,
+ guint n_icon_names)
+{
+ guint ii;
+
+ g_return_if_fail (E_IS_CELL_TOGGLE (cell_toggle));
+ g_return_if_fail (icon_names != NULL);
+ g_return_if_fail (n_icon_names > 0);
+
+ cell_toggle->priv->icon_names = g_new (gchar *, n_icon_names);
+ cell_toggle->priv->n_icon_names = n_icon_names;
+
+ for (ii = 0; ii < n_icon_names; ii++)
+ cell_toggle->priv->icon_names[ii] = g_strdup (icon_names[ii]);
+
+ cell_toggle_load_icons (cell_toggle);
+}
+
+/**
+ * e_cell_toggle_new:
+ * @icon_names: array of icon names, some of which may be %NULL
+ * @n_icon_names: length of the @icon_names array
+ *
+ * Creates a new ECell renderer that can be used to render toggle
+ * buttons with the icons specified in @icon_names. The value returned
+ * by ETableModel::get_value is typecast into an integer and clamped
+ * to the [0..n_icon_names) range. That will select the image rendered.
+ *
+ * %NULL elements in @icon_names will show no icon for the corresponding
+ * integer value.
+ *
+ * Returns: an ECell object that can be used to render multi-state
+ * toggle cells.
+ */
+ECell *
+e_cell_toggle_new (const gchar **icon_names,
+ guint n_icon_names)
+{
+ ECellToggle *cell_toggle;
+
+ g_return_val_if_fail (icon_names != NULL, NULL);
+ g_return_val_if_fail (n_icon_names > 0, NULL);
+
+ cell_toggle = g_object_new (E_TYPE_CELL_TOGGLE, NULL);
+ e_cell_toggle_construct (cell_toggle, icon_names, n_icon_names);
+
+ return (ECell *) cell_toggle;
+}
+
+GPtrArray *
+e_cell_toggle_get_pixbufs (ECellToggle *cell_toggle)
+{
+ g_return_val_if_fail (E_IS_CELL_TOGGLE (cell_toggle), NULL);
+
+ return cell_toggle->priv->pixbufs;
+}