diff options
Diffstat (limited to 'Tools/MiniBrowser/gtk/BrowserCellRendererVariant.c')
-rw-r--r-- | Tools/MiniBrowser/gtk/BrowserCellRendererVariant.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/Tools/MiniBrowser/gtk/BrowserCellRendererVariant.c b/Tools/MiniBrowser/gtk/BrowserCellRendererVariant.c new file mode 100644 index 000000000..cb2caa35b --- /dev/null +++ b/Tools/MiniBrowser/gtk/BrowserCellRendererVariant.c @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BrowserCellRendererVariant.h" +#include "BrowserMarshal.h" +#include <errno.h> + +enum { + PROP_0, + + PROP_VALUE, + PROP_ADJUSTMENT +}; + +enum { + CHANGED, + + LAST_SIGNAL +}; + +struct _BrowserCellRendererVariant { + GtkCellRenderer parent; + + GValue *value; + + GtkCellRenderer *textRenderer; + GtkCellRenderer *toggleRenderer; + GtkCellRenderer *spinRenderer; +}; + +struct _BrowserCellRendererVariantClass { + GtkCellRendererClass parent; +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(BrowserCellRendererVariant, browser_cell_renderer_variant, GTK_TYPE_CELL_RENDERER) + +static void browserCellRendererVariantFinalize(GObject *object) +{ + BrowserCellRendererVariant *renderer = BROWSER_CELL_RENDERER_VARIANT(object); + + g_object_unref(renderer->toggleRenderer); + g_object_unref(renderer->spinRenderer); + g_object_unref(renderer->textRenderer); + if (renderer->value) + g_boxed_free(G_TYPE_VALUE, renderer->value); + + G_OBJECT_CLASS(browser_cell_renderer_variant_parent_class)->finalize(object); +} + +static void browserCellRendererVariantGetProperty(GObject *object, guint propId, GValue *value, GParamSpec *pspec) +{ + BrowserCellRendererVariant *renderer = BROWSER_CELL_RENDERER_VARIANT(object); + + switch (propId) { + case PROP_VALUE: + g_value_set_boxed(value, renderer->value); + break; + case PROP_ADJUSTMENT: { + GtkAdjustment *adjustment = NULL; + g_object_get(G_OBJECT(renderer->spinRenderer), "adjustment", &adjustment, NULL); + if (adjustment) { + g_value_set_object(value, adjustment); + g_object_unref(adjustment); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec); + } +} + +static void browserCellRendererVariantSetModeForValue(BrowserCellRendererVariant *renderer) +{ + if (!renderer->value) + return; + + GtkCellRendererMode mode; + if (G_VALUE_HOLDS_BOOLEAN(renderer->value)) + mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE; + else if (G_VALUE_HOLDS_STRING(renderer->value) || G_VALUE_HOLDS_UINT(renderer->value)) + mode = GTK_CELL_RENDERER_MODE_EDITABLE; + else + return; + + g_object_set(G_OBJECT(renderer), "mode", mode, NULL); +} + +static void browserCellRendererVariantSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec) +{ + BrowserCellRendererVariant *renderer = BROWSER_CELL_RENDERER_VARIANT(object); + + switch (propId) { + case PROP_VALUE: + if (renderer->value) + g_boxed_free(G_TYPE_VALUE, renderer->value); + renderer->value = g_value_dup_boxed(value); + browserCellRendererVariantSetModeForValue(renderer); + break; + case PROP_ADJUSTMENT: + g_object_set(G_OBJECT(renderer->spinRenderer), "adjustment", g_value_get_object(value), NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec); + } +} + +static GtkCellRenderer *browserCellRendererVariantGetRendererForValue(BrowserCellRendererVariant *renderer) +{ + if (!renderer->value) + return NULL; + + if (G_VALUE_HOLDS_BOOLEAN(renderer->value)) { + g_object_set(G_OBJECT(renderer->toggleRenderer), + "active", g_value_get_boolean(renderer->value), + NULL); + return renderer->toggleRenderer; + } + + if (G_VALUE_HOLDS_STRING(renderer->value)) { + g_object_set(G_OBJECT(renderer->textRenderer), + "text", g_value_get_string(renderer->value), + NULL); + return renderer->textRenderer; + } + + if (G_VALUE_HOLDS_UINT(renderer->value)) { + gchar *text = g_strdup_printf("%u", g_value_get_uint(renderer->value)); + g_object_set(G_OBJECT(renderer->spinRenderer), "text", text, NULL); + g_free(text); + return renderer->spinRenderer; + } + + return NULL; +} + +static void browserCellRendererVariantCellRendererTextEdited(BrowserCellRendererVariant *renderer, const gchar *path, const gchar *newText) +{ + if (!renderer->value) + return; + + if (!G_VALUE_HOLDS_STRING(renderer->value)) + return; + + g_value_set_string(renderer->value, newText); + g_signal_emit(renderer, signals[CHANGED], 0, path, renderer->value); +} + +static void browserCellRendererVariantCellRendererSpinEdited(BrowserCellRendererVariant *renderer, const gchar *path, const gchar *newText) +{ + if (!renderer->value) + return; + + if (!G_VALUE_HOLDS_UINT(renderer->value)) + return; + + GtkAdjustment *adjustment; + g_object_get(G_OBJECT(renderer->spinRenderer), "adjustment", &adjustment, NULL); + if (!adjustment) + return; + + errno = 0; + gchar *endPtr; + gdouble value = g_strtod(newText, &endPtr); + if (errno || value > gtk_adjustment_get_upper(adjustment) || value < gtk_adjustment_get_lower(adjustment) || endPtr == newText) { + g_warning("Invalid input for cell: %s\n", newText); + return; + } + + g_value_set_uint(renderer->value, (guint)value); + g_signal_emit(renderer, signals[CHANGED], 0, path, renderer->value); +} + +static gboolean browserCellRendererVariantCellRendererActivate(GtkCellRenderer *cell, GdkEvent *event, GtkWidget *widget, const gchar *path, const GdkRectangle *bgArea, const GdkRectangle *cellArea, GtkCellRendererState flags) +{ + BrowserCellRendererVariant *renderer = BROWSER_CELL_RENDERER_VARIANT(cell); + + if (!renderer->value) + return TRUE; + + if (!G_VALUE_HOLDS_BOOLEAN(renderer->value)) + return TRUE; + + g_value_set_boolean(renderer->value, !g_value_get_boolean(renderer->value)); + g_signal_emit(renderer, signals[CHANGED], 0, path, renderer->value); + + return TRUE; +} + +static void browserCellRendererVariantCellRendererRender(GtkCellRenderer *cell, cairo_t *cr, GtkWidget *widget, const GdkRectangle *bgArea, const GdkRectangle *cellArea, GtkCellRendererState flags) +{ + GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell)); + if (!renderer) + return; + + GTK_CELL_RENDERER_GET_CLASS(renderer)->render(renderer, cr, widget, bgArea, cellArea, flags); +} + +static GtkCellEditable *browserCellRendererVariantCellRendererStartEditing(GtkCellRenderer *cell, GdkEvent *event, GtkWidget *widget, const gchar *path, const GdkRectangle *bgArea, const GdkRectangle *cellArea, GtkCellRendererState flags) +{ + GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell)); + if (!renderer) + return NULL; + + if (!GTK_CELL_RENDERER_GET_CLASS(renderer)->start_editing) + return NULL; + + return GTK_CELL_RENDERER_GET_CLASS(renderer)->start_editing(renderer, event, widget, path, bgArea, cellArea, flags); +} + +static void browserCellRendererVariantCellRendererGetPreferredWidth(GtkCellRenderer *cell, GtkWidget *widget, gint *minimumWidth, gint *naturalWidth) +{ + GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell)); + if (!renderer) + return; + + GTK_CELL_RENDERER_GET_CLASS(renderer)->get_preferred_width(renderer, widget, minimumWidth, naturalWidth); +} + +static void browserCellRendererVariantCellRendererGetPreferredHeight(GtkCellRenderer *cell, GtkWidget *widget, gint *minimumHeight, gint *naturalHeight) +{ + GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell)); + if (!renderer) + return; + + GTK_CELL_RENDERER_GET_CLASS(renderer)->get_preferred_height(renderer, widget, minimumHeight, naturalHeight); +} + +static void browserCellRendererVariantCellRendererGetPreferredWidthForHeight(GtkCellRenderer *cell, GtkWidget *widget, gint height, gint *minimumWidth, gint *naturalWidth) +{ + GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell)); + if (!renderer) + return; + + GTK_CELL_RENDERER_GET_CLASS(renderer)->get_preferred_width_for_height(renderer, widget, height, minimumWidth, naturalWidth); +} + +static void browserCellRendererVariantCellRendererGetPreferredHeightForWidth(GtkCellRenderer *cell, GtkWidget *widget, gint width, gint *minimumHeight, gint *naturalHeight) +{ + GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell)); + if (!renderer) + return; + + GTK_CELL_RENDERER_GET_CLASS(renderer)->get_preferred_height_for_width(renderer, widget, width, minimumHeight, naturalHeight); +} + +static void browserCellRendererVariantCellRendererGetAlignedArea(GtkCellRenderer *cell, GtkWidget *widget, GtkCellRendererState flags, const GdkRectangle *cellArea, GdkRectangle *alignedArea) +{ + GtkCellRenderer *renderer = browserCellRendererVariantGetRendererForValue(BROWSER_CELL_RENDERER_VARIANT(cell)); + if (!renderer) + return; + + GTK_CELL_RENDERER_GET_CLASS(renderer)->get_aligned_area(renderer, widget, flags, cellArea, alignedArea); +} + +static void browser_cell_renderer_variant_init(BrowserCellRendererVariant *renderer) +{ + g_object_set(renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); + + renderer->toggleRenderer = gtk_cell_renderer_toggle_new(); + g_object_set(G_OBJECT(renderer->toggleRenderer), "xalign", 0.0, NULL); + g_object_ref_sink(renderer->toggleRenderer); + + renderer->textRenderer = gtk_cell_renderer_text_new(); + g_signal_connect_swapped(renderer->textRenderer, "edited", + G_CALLBACK(browserCellRendererVariantCellRendererTextEdited), renderer); + g_object_set(G_OBJECT(renderer->textRenderer), "editable", TRUE, NULL); + g_object_ref_sink(renderer->textRenderer); + + renderer->spinRenderer = gtk_cell_renderer_spin_new(); + g_signal_connect_swapped(renderer->spinRenderer, "edited", + G_CALLBACK(browserCellRendererVariantCellRendererSpinEdited), renderer); + g_object_set(G_OBJECT(renderer->spinRenderer), "editable", TRUE, NULL); +} + +static void browser_cell_renderer_variant_class_init(BrowserCellRendererVariantClass *klass) +{ + GObjectClass *gobjectClass = G_OBJECT_CLASS(klass); + GtkCellRendererClass *cellRendererClass = GTK_CELL_RENDERER_CLASS(klass); + + gobjectClass->get_property = browserCellRendererVariantGetProperty; + gobjectClass->set_property = browserCellRendererVariantSetProperty; + gobjectClass->finalize = browserCellRendererVariantFinalize; + + cellRendererClass->activate = browserCellRendererVariantCellRendererActivate; + cellRendererClass->render = browserCellRendererVariantCellRendererRender; + cellRendererClass->start_editing = browserCellRendererVariantCellRendererStartEditing; + cellRendererClass->get_preferred_width = browserCellRendererVariantCellRendererGetPreferredWidth; + cellRendererClass->get_preferred_height = browserCellRendererVariantCellRendererGetPreferredHeight; + cellRendererClass->get_preferred_width_for_height = browserCellRendererVariantCellRendererGetPreferredWidthForHeight; + cellRendererClass->get_preferred_height_for_width = browserCellRendererVariantCellRendererGetPreferredHeightForWidth; + cellRendererClass->get_aligned_area = browserCellRendererVariantCellRendererGetAlignedArea; + + g_object_class_install_property(gobjectClass, + PROP_VALUE, + g_param_spec_boxed("value", + "Value", + "The cell renderer value", + G_TYPE_VALUE, + G_PARAM_READWRITE)); + g_object_class_install_property(gobjectClass, + PROP_ADJUSTMENT, + g_param_spec_object("adjustment", + "Adjustment", + "The adjustment that holds the value of the spin button", + GTK_TYPE_ADJUSTMENT, + G_PARAM_READWRITE)); + + signals[CHANGED] = + g_signal_new("changed", + G_TYPE_FROM_CLASS(gobjectClass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + browser_marshal_VOID__STRING_BOXED, + G_TYPE_NONE, 2, + G_TYPE_STRING, G_TYPE_VALUE); +} + +GtkCellRenderer *browser_cell_renderer_variant_new(void) +{ + return GTK_CELL_RENDERER(g_object_new(BROWSER_TYPE_CELL_RENDERER_VARIANT, NULL)); +} + |