496 lines
15 KiB
C
496 lines
15 KiB
C
|
/*
|
||
|
Copyright (C) 2008-2013 Christian Dywan <christian@twotoasts.de>
|
||
|
|
||
|
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.1 of the License, or (at your option) any later version.
|
||
|
|
||
|
See the file COPYING for the full license text.
|
||
|
*/
|
||
|
|
||
|
#include "katze-cellrenderercomboboxtext.h"
|
||
|
|
||
|
#include "marshal.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <gdk/gdk.h>
|
||
|
|
||
|
#define P_(String) (String)
|
||
|
#define I_(String) (String)
|
||
|
#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
|
||
|
#define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
|
||
|
#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
|
||
|
|
||
|
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_finalize (GObject* object);
|
||
|
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_get_property (GObject* object,
|
||
|
guint param_id,
|
||
|
GValue* value,
|
||
|
GParamSpec* pspec);
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_set_property (GObject* object,
|
||
|
guint param_id,
|
||
|
const GValue* value,
|
||
|
GParamSpec* pspec);
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_get_size (GtkCellRenderer* cell,
|
||
|
GtkWidget* widget,
|
||
|
#if GTK_CHECK_VERSION(3,0,0)
|
||
|
const GdkRectangle* cell_area,
|
||
|
#else
|
||
|
GdkRectangle* cell_area,
|
||
|
#endif
|
||
|
gint* x_offset,
|
||
|
gint* y_offset,
|
||
|
gint* width,
|
||
|
gint* height);
|
||
|
#if GTK_CHECK_VERSION(3,0,0)
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_render (GtkCellRenderer *cell,
|
||
|
cairo_t* cr,
|
||
|
GtkWidget *widget,
|
||
|
const GdkRectangle *background_area,
|
||
|
const GdkRectangle *cell_area,
|
||
|
GtkCellRendererState flags);
|
||
|
#else
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_render (GtkCellRenderer *cell,
|
||
|
GdkDrawable *window,
|
||
|
GtkWidget *widget,
|
||
|
GdkRectangle *background_area,
|
||
|
GdkRectangle *cell_area,
|
||
|
GdkRectangle *expose_area,
|
||
|
GtkCellRendererState flags);
|
||
|
#endif
|
||
|
|
||
|
enum {
|
||
|
PROP_0,
|
||
|
|
||
|
PROP_FOLDED_TEXT,
|
||
|
PROP_FOLDED_MARKUP,
|
||
|
PROP_FOLDED_ATTRIBUTES,
|
||
|
PROP_UNFOLDED_TEXT,
|
||
|
PROP_UNFOLDED_MARKUP,
|
||
|
PROP_UNFOLDED_ATTRIBUTES,
|
||
|
};
|
||
|
|
||
|
#define KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT, KatzeCellRendererComboBoxTextPrivate))
|
||
|
|
||
|
typedef struct _KatzeCellRendererComboBoxTextPrivate KatzeCellRendererComboBoxTextPrivate;
|
||
|
struct _KatzeCellRendererComboBoxTextPrivate
|
||
|
{
|
||
|
struct _Properties {
|
||
|
PangoAttrList* extra_attrs;
|
||
|
|
||
|
gchar* text;
|
||
|
|
||
|
guint markup_set : 1;
|
||
|
} props[2];
|
||
|
};
|
||
|
|
||
|
G_DEFINE_TYPE (KatzeCellRendererComboBoxText, katze_cell_renderer_combobox_text, GTK_TYPE_CELL_RENDERER_TEXT)
|
||
|
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_init (KatzeCellRendererComboBoxText *celltext)
|
||
|
{
|
||
|
guint prop_index;
|
||
|
KatzeCellRendererComboBoxTextPrivate *priv;
|
||
|
|
||
|
priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (celltext);
|
||
|
|
||
|
for (prop_index = 0 ; prop_index < 2; prop_index++)
|
||
|
{
|
||
|
priv->props[prop_index].text = NULL;
|
||
|
priv->props[prop_index].extra_attrs = NULL;
|
||
|
priv->props[prop_index].markup_set = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_class_init (KatzeCellRendererComboBoxTextClass *class)
|
||
|
{
|
||
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||
|
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
|
||
|
|
||
|
object_class->finalize = katze_cell_renderer_combobox_text_finalize;
|
||
|
|
||
|
object_class->get_property = katze_cell_renderer_combobox_text_get_property;
|
||
|
object_class->set_property = katze_cell_renderer_combobox_text_set_property;
|
||
|
|
||
|
cell_class->get_size = katze_cell_renderer_combobox_text_get_size;
|
||
|
cell_class->render = katze_cell_renderer_combobox_text_render;
|
||
|
|
||
|
g_object_class_install_property (object_class,
|
||
|
PROP_FOLDED_TEXT,
|
||
|
g_param_spec_string ("folded-text",
|
||
|
P_("Folded text"),
|
||
|
P_("Text to render if combobox_text is closed. The string [text] is replaced by default text"),
|
||
|
NULL,
|
||
|
GTK_PARAM_READWRITE));
|
||
|
|
||
|
g_object_class_install_property (object_class,
|
||
|
PROP_FOLDED_MARKUP,
|
||
|
g_param_spec_string ("folded-markup",
|
||
|
P_("Folded markup"),
|
||
|
P_("Marked up text to render if combobox_text is closed. The string [text] is replaced by default text"),
|
||
|
NULL,
|
||
|
GTK_PARAM_WRITABLE));
|
||
|
|
||
|
g_object_class_install_property (object_class,
|
||
|
PROP_FOLDED_ATTRIBUTES,
|
||
|
g_param_spec_boxed ("folded-attributes",
|
||
|
P_("Folded attributes"),
|
||
|
P_("A list of style attributes to apply to the text of the renderer if combobox_text is closed"),
|
||
|
PANGO_TYPE_ATTR_LIST,
|
||
|
GTK_PARAM_READWRITE));
|
||
|
|
||
|
g_object_class_install_property (object_class,
|
||
|
PROP_UNFOLDED_TEXT,
|
||
|
g_param_spec_string ("unfolded-text",
|
||
|
P_("Unfolded text"),
|
||
|
P_("Text to render if combobox_text is opened"),
|
||
|
NULL,
|
||
|
GTK_PARAM_READWRITE));
|
||
|
|
||
|
g_object_class_install_property (object_class,
|
||
|
PROP_UNFOLDED_MARKUP,
|
||
|
g_param_spec_string ("unfolded-markup",
|
||
|
P_("Unfolded markup"),
|
||
|
P_("Marked up text to render if combobox_text is opened"),
|
||
|
NULL,
|
||
|
GTK_PARAM_WRITABLE));
|
||
|
|
||
|
g_object_class_install_property (object_class,
|
||
|
PROP_UNFOLDED_ATTRIBUTES,
|
||
|
g_param_spec_boxed ("unfolded-attributes",
|
||
|
P_("Unfolded attributes"),
|
||
|
P_("A list of style attributes to apply to the text of the renderer if combobox_text is opened"),
|
||
|
PANGO_TYPE_ATTR_LIST,
|
||
|
GTK_PARAM_READWRITE));
|
||
|
|
||
|
|
||
|
g_type_class_add_private (object_class, sizeof (KatzeCellRendererComboBoxTextPrivate));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_finalize (GObject *object)
|
||
|
{
|
||
|
guint prop_index;
|
||
|
KatzeCellRendererComboBoxTextPrivate *priv;
|
||
|
|
||
|
priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (object);
|
||
|
|
||
|
for (prop_index = 0 ; prop_index < 2; prop_index++)
|
||
|
{
|
||
|
g_free (priv->props[prop_index].text);
|
||
|
if (priv->props[prop_index].extra_attrs)
|
||
|
pango_attr_list_unref (priv->props[prop_index].extra_attrs);
|
||
|
}
|
||
|
|
||
|
G_OBJECT_CLASS (katze_cell_renderer_combobox_text_parent_class)->finalize (object);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_get_property (GObject* object,
|
||
|
guint param_id,
|
||
|
GValue* value,
|
||
|
GParamSpec* pspec)
|
||
|
{
|
||
|
KatzeCellRendererComboBoxTextPrivate *priv;
|
||
|
|
||
|
priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (object);
|
||
|
|
||
|
switch (param_id)
|
||
|
{
|
||
|
case PROP_FOLDED_TEXT:
|
||
|
g_value_set_string (value, priv->props[0].text);
|
||
|
break;
|
||
|
|
||
|
case PROP_FOLDED_ATTRIBUTES:
|
||
|
g_value_set_boxed (value, priv->props[0].extra_attrs);
|
||
|
break;
|
||
|
|
||
|
case PROP_UNFOLDED_TEXT:
|
||
|
g_value_set_string (value, priv->props[1].text);
|
||
|
break;
|
||
|
|
||
|
case PROP_UNFOLDED_ATTRIBUTES:
|
||
|
g_value_set_boxed (value, priv->props[1].extra_attrs);
|
||
|
break;
|
||
|
|
||
|
case PROP_FOLDED_MARKUP:
|
||
|
case PROP_UNFOLDED_MARKUP:
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_set_property (GObject* object,
|
||
|
guint param_id,
|
||
|
const GValue* value,
|
||
|
GParamSpec* pspec)
|
||
|
{
|
||
|
guint prop_index = 0;
|
||
|
KatzeCellRendererComboBoxTextPrivate *priv;
|
||
|
|
||
|
priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (object);
|
||
|
|
||
|
switch (param_id)
|
||
|
{
|
||
|
case PROP_FOLDED_TEXT:
|
||
|
prop_text:
|
||
|
g_free (priv->props[prop_index].text);
|
||
|
|
||
|
if (priv->props[prop_index].markup_set)
|
||
|
{
|
||
|
if (priv->props[prop_index].extra_attrs)
|
||
|
{
|
||
|
pango_attr_list_unref (priv->props[prop_index].extra_attrs);
|
||
|
priv->props[prop_index].extra_attrs = NULL;
|
||
|
}
|
||
|
priv->props[prop_index].markup_set = FALSE;
|
||
|
}
|
||
|
|
||
|
priv->props[prop_index].text = g_value_dup_string (value);
|
||
|
break;
|
||
|
|
||
|
case PROP_FOLDED_ATTRIBUTES:
|
||
|
prop_attributes:
|
||
|
if (priv->props[prop_index].extra_attrs)
|
||
|
pango_attr_list_unref (priv->props[prop_index].extra_attrs);
|
||
|
|
||
|
priv->props[prop_index].extra_attrs = g_value_get_boxed (value);
|
||
|
if (priv->props[prop_index].extra_attrs)
|
||
|
pango_attr_list_ref (priv->props[prop_index].extra_attrs);
|
||
|
break;
|
||
|
|
||
|
case PROP_FOLDED_MARKUP:
|
||
|
prop_markup:
|
||
|
{
|
||
|
const gchar *str;
|
||
|
gchar *text = NULL;
|
||
|
GError *error = NULL;
|
||
|
PangoAttrList *attrs = NULL;
|
||
|
|
||
|
str = g_value_get_string (value);
|
||
|
if (str && !pango_parse_markup (str,
|
||
|
-1,
|
||
|
0,
|
||
|
&attrs,
|
||
|
&text,
|
||
|
NULL,
|
||
|
&error))
|
||
|
{
|
||
|
g_warning ("Failed to set text from markup due to error parsing markup: %s",
|
||
|
error->message);
|
||
|
g_error_free (error);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
g_free (priv->props[prop_index].text);
|
||
|
|
||
|
if (priv->props[prop_index].extra_attrs)
|
||
|
pango_attr_list_unref (priv->props[prop_index].extra_attrs);
|
||
|
|
||
|
priv->props[prop_index].text = text;
|
||
|
priv->props[prop_index].extra_attrs = attrs;
|
||
|
priv->props[prop_index].markup_set = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case PROP_UNFOLDED_TEXT:
|
||
|
prop_index = 1;
|
||
|
goto prop_text;
|
||
|
|
||
|
case PROP_UNFOLDED_ATTRIBUTES:
|
||
|
prop_index = 1;
|
||
|
goto prop_attributes;
|
||
|
|
||
|
case PROP_UNFOLDED_MARKUP:
|
||
|
prop_index = 1;
|
||
|
goto prop_markup;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* katze_cell_renderer_combobox_text_new:
|
||
|
*
|
||
|
* Creates a new #KatzeCellRendererComboBoxText. Adjust how text is drawn using
|
||
|
* object properties. Object properties can be
|
||
|
* set globally (with g_object_set()). Also, with #GtkTreeViewColumn,
|
||
|
* you can bind a property to a value in a #GtkTreeModel. For example,
|
||
|
* you can bind the "text" property on the cell renderer to a string
|
||
|
* value in the model, thus rendering a different string in each row
|
||
|
* of the #GtkTreeView
|
||
|
*
|
||
|
* Return value: (transfer full): the new cell renderer
|
||
|
**/
|
||
|
GtkCellRenderer *
|
||
|
katze_cell_renderer_combobox_text_new (void)
|
||
|
{
|
||
|
return g_object_new (KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT, NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
set_text(KatzeCellRendererComboBoxText* cell,
|
||
|
GtkWidget* widget,
|
||
|
const gchar* repl)
|
||
|
{
|
||
|
const gchar *text = NULL;
|
||
|
PangoAttrList* extra_attrs = NULL;
|
||
|
GtkWidget* pwidget = gtk_widget_get_parent (widget);
|
||
|
gboolean unfolded = FALSE;
|
||
|
KatzeCellRendererComboBoxTextPrivate *priv;
|
||
|
|
||
|
priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (cell);
|
||
|
|
||
|
if (GTK_IS_MENU_ITEM (pwidget))
|
||
|
{
|
||
|
GtkWidget* menu = gtk_widget_get_parent (pwidget);
|
||
|
GList* items;
|
||
|
|
||
|
if (menu
|
||
|
&& (GTK_IS_MENU (menu))
|
||
|
&& (items = gtk_container_get_children (GTK_CONTAINER (menu)))
|
||
|
&& (GTK_WIDGET (items->data) == pwidget)
|
||
|
&& (g_list_length (items) > 1)
|
||
|
&& (GTK_IS_SEPARATOR_MENU_ITEM (g_list_next (items)->data)))
|
||
|
{
|
||
|
unfolded = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (unfolded)
|
||
|
{
|
||
|
text = priv->props[1].text;
|
||
|
extra_attrs = priv->props[1].extra_attrs;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
text = priv->props[0].text;
|
||
|
extra_attrs = priv->props[0].extra_attrs;
|
||
|
}
|
||
|
|
||
|
if (!text)
|
||
|
{
|
||
|
text = g_strdup (repl ? repl : "");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GString* string = g_string_new ("");
|
||
|
const gchar* src = text;
|
||
|
const guint skip = sizeof ("[text]") - 1;
|
||
|
guint len;
|
||
|
|
||
|
while (0 != (len = strlen(src)))
|
||
|
{
|
||
|
const gchar* found = strstr (src, "[text]");
|
||
|
|
||
|
if (!found)
|
||
|
{
|
||
|
g_string_append (string, src);
|
||
|
src += len;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_string_append_len (string, src, found-src);
|
||
|
if (repl)
|
||
|
g_string_append (string, repl);
|
||
|
src = found + skip;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
text = g_string_free (string, FALSE);
|
||
|
}
|
||
|
|
||
|
g_object_set (G_OBJECT (cell),
|
||
|
"text", text,
|
||
|
"attributes", extra_attrs,
|
||
|
NULL);
|
||
|
|
||
|
g_free ((gpointer)text);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
katze_cell_renderer_combobox_text_get_size (GtkCellRenderer *cell,
|
||
|
GtkWidget *widget,
|
||
|
#if GTK_CHECK_VERSION(3,0,0)
|
||
|
const GdkRectangle* cell_area,
|
||
|
#else
|
||
|
GdkRectangle* cell_area,
|
||
|
#endif
|
||
|
gint *x_offset,
|
||
|
gint *y_offset,
|
||
|
gint *width,
|
||
|
gint *height)
|
||
|
{
|
||
|
const gchar *text = NULL;
|
||
|
|
||
|
g_object_get (G_OBJECT (cell), "text", &text, NULL);
|
||
|
|
||
|
set_text (KATZE_CELL_RENDERER_COMBOBOX_TEXT (cell), widget, text);
|
||
|
|
||
|
GTK_CELL_RENDERER_CLASS (katze_cell_renderer_combobox_text_parent_class)->get_size (cell,
|
||
|
widget, cell_area,
|
||
|
x_offset, y_offset, width, height);
|
||
|
|
||
|
g_object_set (G_OBJECT (cell), "text", text, NULL);
|
||
|
g_free ((gpointer)text);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
#if GTK_CHECK_VERSION(3,0,0)
|
||
|
katze_cell_renderer_combobox_text_render (GtkCellRenderer *cell,
|
||
|
cairo_t* cr,
|
||
|
GtkWidget *widget,
|
||
|
const GdkRectangle *background_area,
|
||
|
const GdkRectangle *cell_area,
|
||
|
GtkCellRendererState flags)
|
||
|
#else
|
||
|
katze_cell_renderer_combobox_text_render (GtkCellRenderer *cell,
|
||
|
GdkDrawable *window,
|
||
|
GtkWidget *widget,
|
||
|
GdkRectangle *background_area,
|
||
|
GdkRectangle *cell_area,
|
||
|
GdkRectangle *expose_area,
|
||
|
GtkCellRendererState flags)
|
||
|
#endif
|
||
|
{
|
||
|
const gchar *text = NULL;
|
||
|
|
||
|
g_object_get (G_OBJECT (cell), "text", &text, NULL);
|
||
|
|
||
|
set_text (KATZE_CELL_RENDERER_COMBOBOX_TEXT (cell), widget, text);
|
||
|
|
||
|
#if GTK_CHECK_VERSION(3,0,0)
|
||
|
GTK_CELL_RENDERER_CLASS (katze_cell_renderer_combobox_text_parent_class)->render (cell,
|
||
|
cr,
|
||
|
widget,
|
||
|
background_area,
|
||
|
cell_area,
|
||
|
flags);
|
||
|
#else
|
||
|
GTK_CELL_RENDERER_CLASS (katze_cell_renderer_combobox_text_parent_class)->render (cell,
|
||
|
window,
|
||
|
widget,
|
||
|
background_area,
|
||
|
cell_area,
|
||
|
expose_area,
|
||
|
flags);
|
||
|
#endif
|
||
|
|
||
|
g_object_set (G_OBJECT (cell), "text", text, NULL);
|
||
|
g_free ((gpointer)text);
|
||
|
}
|