270 lines
9.3 KiB
C
270 lines
9.3 KiB
C
/* 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 <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 <string.h>
|
|
|
|
#include <gegl.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#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));
|
|
}
|
|
}
|