summaryrefslogtreecommitdiff
path: root/Tools/MiniBrowser/gtk/BrowserCellRendererVariant.c
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/MiniBrowser/gtk/BrowserCellRendererVariant.c')
-rw-r--r--Tools/MiniBrowser/gtk/BrowserCellRendererVariant.c346
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));
+}
+