aboutsummaryrefslogblamecommitdiffstats
path: root/libempathy-gtk/gossip-cell-renderer-text.c
blob: 2b54eedf5299ce40f94d27579f45066df350a8ee (plain) (tree)















































































































































































































































































































































































                                                                                                                       
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Copyright (C) 2004-2007 Imendio AB
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 * 
 * Authors: Mikael Hallendal <micke@imendio.com>
 */

#include "config.h"

#include <string.h>

#include "gossip-cell-renderer-text.h"

#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CELL_RENDERER_TEXT, GossipCellRendererTextPriv))

struct _GossipCellRendererTextPriv {
    gchar    *name;
    gchar    *status;
    gboolean  is_group;

    gboolean  is_valid;
    gboolean  is_selected;

    gboolean  show_status;
};

static void gossip_cell_renderer_text_class_init (GossipCellRendererTextClass *klass);
static void gossip_cell_renderer_text_init       (GossipCellRendererText      *cell);
static void cell_renderer_text_finalize          (GObject                     *object);
static void cell_renderer_text_get_property      (GObject                     *object,
                          guint                        param_id,
                          GValue                      *value,
                          GParamSpec                  *pspec);
static void cell_renderer_text_set_property      (GObject                     *object,
                          guint                        param_id,
                          const GValue                *value,
                          GParamSpec                  *pspec);
static void cell_renderer_text_get_size          (GtkCellRenderer             *cell,
                          GtkWidget                   *widget,
                          GdkRectangle                *cell_area,
                          gint                        *x_offset,
                          gint                        *y_offset,
                          gint                        *width,
                          gint                        *height);
static void cell_renderer_text_render            (GtkCellRenderer             *cell,
                          GdkDrawable                 *window,
                          GtkWidget                   *widget,
                          GdkRectangle                *background_area,
                          GdkRectangle                *cell_area,
                          GdkRectangle                *expose_area,
                          GtkCellRendererState         flags);
static void cell_renderer_text_update_text       (GossipCellRendererText      *cell,
                          GtkWidget                   *widget,
                          gboolean                     selected);

/* Properties */
enum {
    PROP_0,
    PROP_NAME,
    PROP_STATUS,
    PROP_IS_GROUP,
    PROP_SHOW_STATUS,
};

G_DEFINE_TYPE (GossipCellRendererText, gossip_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);

static void
gossip_cell_renderer_text_class_init (GossipCellRendererTextClass *klass)
{
    GObjectClass         *object_class;
    GtkCellRendererClass *cell_class;

    object_class = G_OBJECT_CLASS (klass);
    cell_class = GTK_CELL_RENDERER_CLASS (klass);

    object_class->finalize = cell_renderer_text_finalize;

    object_class->get_property = cell_renderer_text_get_property;
    object_class->set_property = cell_renderer_text_set_property;

    cell_class->get_size = cell_renderer_text_get_size;
    cell_class->render = cell_renderer_text_render;

    g_object_class_install_property (object_class,
                     PROP_NAME,
                     g_param_spec_string ("name",
                                  "Name",
                                  "Contact name",
                                  NULL,
                                  G_PARAM_READWRITE));
    g_object_class_install_property (object_class,
                     PROP_STATUS,
                     g_param_spec_string ("status",
                                  "Status",
                                  "Contact status string",
                                  NULL,
                                  G_PARAM_READWRITE));
    g_object_class_install_property (object_class,
                     PROP_IS_GROUP,
                     g_param_spec_boolean ("is_group",
                                   "Is group",
                                   "Whether this cell is a group",
                                   FALSE,
                                   G_PARAM_READWRITE));
    g_object_class_install_property (object_class,
                     PROP_SHOW_STATUS,
                     g_param_spec_boolean ("show-status",
                                   "Show status",
                                   "Whether to show the status line",
                                   TRUE,
                                   G_PARAM_READWRITE));

    g_type_class_add_private (object_class, sizeof (GossipCellRendererTextPriv));
}

static void
gossip_cell_renderer_text_init (GossipCellRendererText *cell)
{
    GossipCellRendererTextPriv *priv;

    priv = GET_PRIV (cell);

    g_object_set (cell,
              "ellipsize", PANGO_ELLIPSIZE_END,
              NULL);

    priv->name = g_strdup ("");
    priv->status = g_strdup ("");
    priv->show_status = TRUE;
}

static void
cell_renderer_text_finalize (GObject *object)
{
    GossipCellRendererText     *cell;
    GossipCellRendererTextPriv *priv;

    cell = GOSSIP_CELL_RENDERER_TEXT (object);
    priv = GET_PRIV (cell);

    g_free (priv->name);
    g_free (priv->status);

    (G_OBJECT_CLASS (gossip_cell_renderer_text_parent_class)->finalize) (object);
}

static void
cell_renderer_text_get_property (GObject    *object,
                 guint       param_id,
                 GValue     *value,
                 GParamSpec *pspec)
{
    GossipCellRendererText     *cell;
    GossipCellRendererTextPriv *priv;

    cell = GOSSIP_CELL_RENDERER_TEXT (object);
    priv = GET_PRIV (cell);

    switch (param_id) {
    case PROP_NAME:
        g_value_set_string (value, priv->name);
        break;
    case PROP_STATUS:
        g_value_set_string (value, priv->status);
        break;
    case PROP_IS_GROUP:
        g_value_set_boolean (value, priv->is_group);
        break;
    case PROP_SHOW_STATUS:
        g_value_set_boolean (value, priv->show_status);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
        break;
    }
}

static void
cell_renderer_text_set_property (GObject      *object,
                 guint         param_id,
                 const GValue *value,
                 GParamSpec   *pspec)
{
    GossipCellRendererText     *cell;
    GossipCellRendererTextPriv *priv;
    const gchar                *str;

    cell = GOSSIP_CELL_RENDERER_TEXT (object);
    priv = GET_PRIV (cell);

    switch (param_id) {
    case PROP_NAME:
        g_free (priv->name);
        str = g_value_get_string (value);
        priv->name = g_strdup (str ? str : "");
        g_strdelimit (priv->name, "\n\r\t", ' ');
        priv->is_valid = FALSE;
        break;
    case PROP_STATUS:
        g_free (priv->status);
        str = g_value_get_string (value);
        priv->status = g_strdup (str ? str : "");
        g_strdelimit (priv->status, "\n\r\t", ' ');
        priv->is_valid = FALSE;
        break;
    case PROP_IS_GROUP:
        priv->is_group = g_value_get_boolean (value);
        priv->is_valid = FALSE;
        break;
    case PROP_SHOW_STATUS:
        priv->show_status = g_value_get_boolean (value);
        priv->is_valid = FALSE;
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
        break;
    }
}

static void
cell_renderer_text_get_size (GtkCellRenderer *cell,
                 GtkWidget       *widget,
                 GdkRectangle    *cell_area,
                 gint            *x_offset,
                 gint            *y_offset,
                 gint            *width,
                 gint            *height)
{
    GossipCellRendererText     *celltext;
    GossipCellRendererTextPriv *priv;

    celltext = GOSSIP_CELL_RENDERER_TEXT (cell);
    priv = GET_PRIV (cell);

    /* Only update if not already valid so we get the right size. */
    cell_renderer_text_update_text (celltext, widget, priv->is_selected);

    (GTK_CELL_RENDERER_CLASS (gossip_cell_renderer_text_parent_class)->get_size) (cell, widget,
                                              cell_area,
                                              x_offset, y_offset,
                                              width, height);
}

static void
cell_renderer_text_render (GtkCellRenderer      *cell,
               GdkWindow            *window,
               GtkWidget            *widget,
               GdkRectangle         *background_area,
               GdkRectangle         *cell_area,
               GdkRectangle         *expose_area,
               GtkCellRendererState  flags)
{
    GossipCellRendererText *celltext;

    celltext = GOSSIP_CELL_RENDERER_TEXT (cell);

    cell_renderer_text_update_text (celltext,
                    widget,
                    (flags & GTK_CELL_RENDERER_SELECTED));

    (GTK_CELL_RENDERER_CLASS (gossip_cell_renderer_text_parent_class)->render) (
        cell, window,
        widget,
        background_area,
        cell_area,
        expose_area, flags);
}

static void
cell_renderer_text_update_text (GossipCellRendererText *cell,
                GtkWidget              *widget,
                gboolean                selected)
{
    GossipCellRendererTextPriv *priv;
    PangoAttrList              *attr_list;
    PangoAttribute             *attr_color, *attr_style, *attr_size;
    GtkStyle                   *style;
    gchar                      *str;

    priv = GET_PRIV (cell);

    if (priv->is_valid && priv->is_selected == selected) {
        return;
    }

    if (priv->is_group) {
        g_object_set (cell,
                  "visible", TRUE,
                  "weight", PANGO_WEIGHT_BOLD,
                  "text", priv->name,
                  "attributes", NULL,
                  "xpad", 1,
                  "ypad", 1,
                  NULL);

        priv->is_selected = selected;
        priv->is_valid = TRUE;
        return;
    }

    style = gtk_widget_get_style (widget);

    attr_list = pango_attr_list_new ();

    attr_style = pango_attr_style_new (PANGO_STYLE_ITALIC);
    attr_style->start_index = strlen (priv->name) + 1;
    attr_style->end_index = -1;
    pango_attr_list_insert (attr_list, attr_style);

    if (!selected) {
        GdkColor color;

        color = style->text_aa[GTK_STATE_NORMAL];

        attr_color = pango_attr_foreground_new (color.red, color.green, color.blue);
        attr_color->start_index = attr_style->start_index;
        attr_color->end_index = -1;
        pango_attr_list_insert (attr_list, attr_color);
    }

    attr_size = pango_attr_size_new (pango_font_description_get_size (style->font_desc) / 1.2);

    attr_size->start_index = attr_style->start_index;
    attr_size->end_index = -1;
    pango_attr_list_insert (attr_list, attr_size);

    if (!priv->status || !priv->status[0] || !priv->show_status) {
        str = g_strdup (priv->name);
    } else {
        str = g_strdup_printf ("%s\n%s", priv->name, priv->status);
    }

    g_object_set (cell,
              "visible", TRUE,
              "weight", PANGO_WEIGHT_NORMAL,
              "text", str,
              "attributes", attr_list,
              "xpad", 0,
              "ypad", 1,
              NULL);

    g_free (str);
    pango_attr_list_unref (attr_list);

    priv->is_selected = selected;
    priv->is_valid = TRUE;
}

GtkCellRenderer *
gossip_cell_renderer_text_new (void)
{
    return g_object_new (GOSSIP_TYPE_CELL_RENDERER_TEXT, NULL);
}