/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pikaviewrenderergradient.c * Copyright (C) 2003 Michael Natterer * * 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 . */ #include "config.h" #include #include #include #include "libpikabase/pikabase.h" #include "libpikacolor/pikacolor.h" #include "libpikamath/pikamath.h" #include "libpikawidgets/pikawidgets.h" #include "widgets-types.h" #include "core/pikagradient.h" #include "pikaviewrenderergradient.h" static void pika_view_renderer_gradient_set_context (PikaViewRenderer *renderer, PikaContext *context); static void pika_view_renderer_gradient_invalidate (PikaViewRenderer *renderer); static void pika_view_renderer_gradient_render (PikaViewRenderer *renderer, GtkWidget *widget); G_DEFINE_TYPE (PikaViewRendererGradient, pika_view_renderer_gradient, PIKA_TYPE_VIEW_RENDERER); #define parent_class pika_view_renderer_gradient_parent_class static void pika_view_renderer_gradient_class_init (PikaViewRendererGradientClass *klass) { PikaViewRendererClass *renderer_class = PIKA_VIEW_RENDERER_CLASS (klass); renderer_class->set_context = pika_view_renderer_gradient_set_context; renderer_class->invalidate = pika_view_renderer_gradient_invalidate; renderer_class->render = pika_view_renderer_gradient_render; } static void pika_view_renderer_gradient_init (PikaViewRendererGradient *renderer) { renderer->left = 0.0; renderer->right = 1.0; } static void pika_view_renderer_gradient_fg_bg_changed (PikaContext *context, const PikaRGB *color, PikaViewRenderer *renderer) { #if 0 g_printerr ("%s: invalidating %s\n", G_STRFUNC, pika_object_get_name (renderer->viewable)); #endif pika_view_renderer_invalidate (renderer); } static void pika_view_renderer_gradient_set_context (PikaViewRenderer *renderer, PikaContext *context) { PikaViewRendererGradient *rendergrad; rendergrad = PIKA_VIEW_RENDERER_GRADIENT (renderer); if (renderer->context && rendergrad->has_fg_bg_segments) { g_signal_handlers_disconnect_by_func (renderer->context, pika_view_renderer_gradient_fg_bg_changed, renderer); } PIKA_VIEW_RENDERER_CLASS (parent_class)->set_context (renderer, context); if (renderer->context && rendergrad->has_fg_bg_segments) { g_signal_connect (renderer->context, "foreground-changed", G_CALLBACK (pika_view_renderer_gradient_fg_bg_changed), renderer); g_signal_connect (renderer->context, "background-changed", G_CALLBACK (pika_view_renderer_gradient_fg_bg_changed), renderer); pika_view_renderer_gradient_fg_bg_changed (renderer->context, NULL, renderer); } } static void pika_view_renderer_gradient_invalidate (PikaViewRenderer *renderer) { PikaViewRendererGradient *rendergrad; gboolean has_fg_bg_segments = FALSE; rendergrad = PIKA_VIEW_RENDERER_GRADIENT (renderer); if (renderer->viewable) has_fg_bg_segments = pika_gradient_has_fg_bg_segments (PIKA_GRADIENT (renderer->viewable)); if (rendergrad->has_fg_bg_segments != has_fg_bg_segments) { if (renderer->context) { if (rendergrad->has_fg_bg_segments) { g_signal_handlers_disconnect_by_func (renderer->context, pika_view_renderer_gradient_fg_bg_changed, renderer); } else { g_signal_connect (renderer->context, "foreground-changed", G_CALLBACK (pika_view_renderer_gradient_fg_bg_changed), renderer); g_signal_connect (renderer->context, "background-changed", G_CALLBACK (pika_view_renderer_gradient_fg_bg_changed), renderer); } } rendergrad->has_fg_bg_segments = has_fg_bg_segments; } PIKA_VIEW_RENDERER_CLASS (parent_class)->invalidate (renderer); } static void pika_view_renderer_gradient_render (PikaViewRenderer *renderer, GtkWidget *widget) { PikaViewRendererGradient *rendergrad = PIKA_VIEW_RENDERER_GRADIENT (renderer); PikaGradient *gradient = PIKA_GRADIENT (renderer->viewable); PikaGradientSegment *seg = NULL; PikaColorTransform *transform; guchar *buf; guchar *dest; gint dest_stride; gint x; gint y; gdouble dx, cur_x; PikaRGB color; buf = g_alloca (4 * renderer->width); dx = (rendergrad->right - rendergrad->left) / (renderer->width - 1); cur_x = rendergrad->left; for (x = 0, dest = buf; x < renderer->width; x++, dest += 4) { guchar r, g, b, a; seg = pika_gradient_get_color_at (gradient, renderer->context, seg, cur_x, rendergrad->reverse, rendergrad->blend_color_space, &color); cur_x += dx; pika_rgba_get_uchar (&color, &r, &g, &b, &a); PIKA_CAIRO_ARGB32_SET_PIXEL (dest, r, g, b, a); } if (! renderer->surface) renderer->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, renderer->width, renderer->height); cairo_surface_flush (renderer->surface); dest = cairo_image_surface_get_data (renderer->surface); dest_stride = cairo_image_surface_get_stride (renderer->surface); transform = pika_view_renderer_get_color_transform (renderer, widget, babl_format ("cairo-ARGB32"), babl_format ("cairo-ARGB32")); if (transform) pika_color_transform_process_pixels (transform, babl_format ("cairo-ARGB32"), buf, babl_format ("cairo-ARGB32"), buf, renderer->width); for (y = 0; y < renderer->height; y++, dest += dest_stride) { memcpy (dest, buf, renderer->width * 4); } cairo_surface_mark_dirty (renderer->surface); } void pika_view_renderer_gradient_set_offsets (PikaViewRendererGradient *renderer, gdouble left, gdouble right) { g_return_if_fail (PIKA_IS_VIEW_RENDERER_GRADIENT (renderer)); left = CLAMP (left, 0.0, 1.0); right = CLAMP (right, left, 1.0); if (left != renderer->left || right != renderer->right) { renderer->left = left; renderer->right = right; pika_view_renderer_invalidate (PIKA_VIEW_RENDERER (renderer)); } } void pika_view_renderer_gradient_set_reverse (PikaViewRendererGradient *renderer, gboolean reverse) { g_return_if_fail (PIKA_IS_VIEW_RENDERER_GRADIENT (renderer)); if (reverse != renderer->reverse) { renderer->reverse = reverse ? TRUE : FALSE; pika_view_renderer_invalidate (PIKA_VIEW_RENDERER (renderer)); pika_view_renderer_update (PIKA_VIEW_RENDERER (renderer)); } } void pika_view_renderer_gradient_set_blend_color_space (PikaViewRendererGradient *renderer, PikaGradientBlendColorSpace blend_color_space) { g_return_if_fail (PIKA_IS_VIEW_RENDERER_GRADIENT (renderer)); if (blend_color_space != renderer->blend_color_space) { renderer->blend_color_space = blend_color_space; pika_view_renderer_invalidate (PIKA_VIEW_RENDERER (renderer)); pika_view_renderer_update (PIKA_VIEW_RENDERER (renderer)); } }