summaryrefslogtreecommitdiffstats
path: root/app/widgets/gimpcellrendererviewable.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/widgets/gimpcellrendererviewable.c')
-rw-r--r--app/widgets/gimpcellrendererviewable.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/app/widgets/gimpcellrendererviewable.c b/app/widgets/gimpcellrendererviewable.c
new file mode 100644
index 0000000..2155567
--- /dev/null
+++ b/app/widgets/gimpcellrendererviewable.c
@@ -0,0 +1,416 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpcellrendererviewable.c
+ * Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
+ *
+ * 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 3 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "widgets-types.h"
+
+#include "core/gimpmarshal.h"
+#include "core/gimpviewable.h"
+
+#include "gimpcellrendererviewable.h"
+#include "gimpview-popup.h"
+#include "gimpviewrenderer.h"
+
+
+enum
+{
+ PRE_CLICKED,
+ CLICKED,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_RENDERER
+};
+
+
+static void gimp_cell_renderer_viewable_finalize (GObject *object);
+static void gimp_cell_renderer_viewable_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gimp_cell_renderer_viewable_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_cell_renderer_viewable_get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *rectangle,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height);
+static void gimp_cell_renderer_viewable_render (GtkCellRenderer *cell,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags);
+static gboolean gimp_cell_renderer_viewable_activate (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags);
+
+
+G_DEFINE_TYPE (GimpCellRendererViewable, gimp_cell_renderer_viewable,
+ GTK_TYPE_CELL_RENDERER)
+
+#define parent_class gimp_cell_renderer_viewable_parent_class
+
+static guint viewable_cell_signals[LAST_SIGNAL] = { 0 };
+
+
+static void
+gimp_cell_renderer_viewable_class_init (GimpCellRendererViewableClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
+
+ /**
+ * GimpCellRendererViewable::pre-clicked:
+ * @cell:
+ * @path:
+ * @state:
+ *
+ * Called early on a viewable cell when it is clicked, typically
+ * before selection code is invoked for example.
+ *
+ * Returns: %TRUE if the signal handled the event and event
+ * propagation should stop, for example preventing a
+ * selection from happening, %FALSE to continue as normal
+ **/
+ viewable_cell_signals[PRE_CLICKED] =
+ g_signal_new ("pre-clicked",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GimpCellRendererViewableClass, pre_clicked),
+ g_signal_accumulator_true_handled, NULL,
+ gimp_marshal_BOOLEAN__STRING_FLAGS,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_STRING,
+ GDK_TYPE_MODIFIER_TYPE);
+
+ /**
+ * GimpCellRendererViewable::clicked:
+ * @cell:
+ * @path:
+ * @state:
+ *
+ * Called late on a viewable cell when it is clicked, typically
+ * after selection code has been invoked for example.
+ **/
+ viewable_cell_signals[CLICKED] =
+ g_signal_new ("clicked",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GimpCellRendererViewableClass, clicked),
+ NULL, NULL,
+ gimp_marshal_VOID__STRING_FLAGS,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ GDK_TYPE_MODIFIER_TYPE);
+
+ object_class->finalize = gimp_cell_renderer_viewable_finalize;
+ object_class->get_property = gimp_cell_renderer_viewable_get_property;
+ object_class->set_property = gimp_cell_renderer_viewable_set_property;
+
+ cell_class->get_size = gimp_cell_renderer_viewable_get_size;
+ cell_class->render = gimp_cell_renderer_viewable_render;
+ cell_class->activate = gimp_cell_renderer_viewable_activate;
+
+ klass->clicked = NULL;
+
+ g_object_class_install_property (object_class, PROP_RENDERER,
+ g_param_spec_object ("renderer",
+ NULL, NULL,
+ GIMP_TYPE_VIEW_RENDERER,
+ GIMP_PARAM_READWRITE));
+}
+
+static void
+gimp_cell_renderer_viewable_init (GimpCellRendererViewable *cellviewable)
+{
+ g_object_set (cellviewable,
+ "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
+ NULL);
+}
+
+static void
+gimp_cell_renderer_viewable_finalize (GObject *object)
+{
+ GimpCellRendererViewable *cell = GIMP_CELL_RENDERER_VIEWABLE (object);
+
+ g_clear_object (&cell->renderer);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_cell_renderer_viewable_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpCellRendererViewable *cell = GIMP_CELL_RENDERER_VIEWABLE (object);
+
+ switch (param_id)
+ {
+ case PROP_RENDERER:
+ g_value_set_object (value, cell->renderer);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_cell_renderer_viewable_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpCellRendererViewable *cell = GIMP_CELL_RENDERER_VIEWABLE (object);
+
+ switch (param_id)
+ {
+ case PROP_RENDERER:
+ {
+ GimpViewRenderer *renderer = g_value_dup_object (value);
+
+ if (cell->renderer)
+ g_object_unref (cell->renderer);
+
+ cell->renderer = renderer;
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_cell_renderer_viewable_get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height)
+{
+ GimpCellRendererViewable *cellviewable;
+ gfloat xalign, yalign;
+ gint xpad, ypad;
+ gint view_width = 0;
+ gint view_height = 0;
+ gint calc_width;
+ gint calc_height;
+
+ gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
+ gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
+
+ cellviewable = GIMP_CELL_RENDERER_VIEWABLE (cell);
+
+ if (cellviewable->renderer)
+ {
+ view_width = (cellviewable->renderer->width +
+ 2 * cellviewable->renderer->border_width);
+ view_height = (cellviewable->renderer->height +
+ 2 * cellviewable->renderer->border_width);
+ }
+
+ calc_width = (gint) xpad * 2 + view_width;
+ calc_height = (gint) ypad * 2 + view_height;
+
+ if (x_offset) *x_offset = 0;
+ if (y_offset) *y_offset = 0;
+
+ if (cell_area && view_width > 0 && view_height > 0)
+ {
+ if (x_offset)
+ {
+ *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
+ 1.0 - xalign : xalign) *
+ (cell_area->width - calc_width - 2 * xpad));
+ *x_offset = (MAX (*x_offset, 0) + xpad);
+ }
+ if (y_offset)
+ {
+ *y_offset = (yalign * (cell_area->height - calc_height - 2 * ypad));
+ *y_offset = (MAX (*y_offset, 0) + ypad);
+ }
+ }
+
+ if (width) *width = calc_width;
+ if (height) *height = calc_height;
+}
+
+static void
+gimp_cell_renderer_viewable_render (GtkCellRenderer *cell,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags)
+{
+ GimpCellRendererViewable *cellviewable;
+
+ cellviewable = GIMP_CELL_RENDERER_VIEWABLE (cell);
+
+ if (cellviewable->renderer)
+ {
+ cairo_t *cr;
+
+ if (! (flags & GTK_CELL_RENDERER_SELECTED))
+ {
+ /* this is an ugly hack. The cell state should be passed to
+ * the view renderer, so that it can adjust its border.
+ * (or something like this) */
+ if (cellviewable->renderer->border_type == GIMP_VIEW_BORDER_WHITE)
+ gimp_view_renderer_set_border_type (cellviewable->renderer,
+ GIMP_VIEW_BORDER_BLACK);
+
+ gimp_view_renderer_remove_idle (cellviewable->renderer);
+ }
+
+ cr = gdk_cairo_create (window);
+ gdk_cairo_rectangle (cr, expose_area);
+ cairo_clip (cr);
+
+ cairo_translate (cr, cell_area->x, cell_area->y);
+
+ gimp_view_renderer_draw (cellviewable->renderer, widget, cr,
+ cell_area->width,
+ cell_area->height);
+
+ cairo_destroy (cr);
+ }
+}
+
+static gboolean
+gimp_cell_renderer_viewable_activate (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags)
+{
+ GimpCellRendererViewable *cellviewable;
+
+ cellviewable = GIMP_CELL_RENDERER_VIEWABLE (cell);
+
+ if (cellviewable->renderer)
+ {
+ GdkModifierType state = 0;
+
+ if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS)
+ state = ((GdkEventButton *) event)->state;
+
+ if (! event ||
+ (((GdkEventAny *) event)->type == GDK_BUTTON_PRESS &&
+ ((GdkEventButton *) event)->button == 1))
+ {
+ gimp_cell_renderer_viewable_clicked (cellviewable, path, state);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+GtkCellRenderer *
+gimp_cell_renderer_viewable_new (void)
+{
+ return g_object_new (GIMP_TYPE_CELL_RENDERER_VIEWABLE, NULL);
+}
+
+gboolean
+gimp_cell_renderer_viewable_pre_clicked (GimpCellRendererViewable *cell,
+ const gchar *path,
+ GdkModifierType state)
+{
+ gboolean handled = FALSE;
+
+ g_return_val_if_fail (GIMP_IS_CELL_RENDERER_VIEWABLE (cell), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ g_signal_emit (cell,
+ viewable_cell_signals[PRE_CLICKED],
+ 0 /*detail*/,
+ path, state,
+ &handled);
+
+ return handled;
+}
+
+void
+gimp_cell_renderer_viewable_clicked (GimpCellRendererViewable *cell,
+ const gchar *path,
+ GdkModifierType state)
+{
+
+ g_return_if_fail (GIMP_IS_CELL_RENDERER_VIEWABLE (cell));
+ g_return_if_fail (path != NULL);
+
+ if (cell->renderer)
+ {
+ GdkEvent *event = gtk_get_current_event ();
+
+ if (event)
+ {
+ GdkEventButton *bevent = (GdkEventButton *) event;
+
+ if (bevent->type == GDK_BUTTON_PRESS &&
+ (bevent->button == 1 || bevent->button == 2))
+ {
+ gimp_view_popup_show (gtk_get_event_widget (event),
+ bevent,
+ cell->renderer->context,
+ cell->renderer->viewable,
+ cell->renderer->width,
+ cell->renderer->height,
+ cell->renderer->dot_for_dot);
+ }
+
+ gdk_event_free (event);
+ }
+ }
+
+ /* emit the signal last so no callback effects can set
+ * cell->renderer to NULL.
+ */
+ g_signal_emit (cell, viewable_cell_signals[CLICKED], 0, path, state);
+}