1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /**
3  * A simple gradient preview
4  *
5  * Author:
6  *   Lauris Kaplinski <lauris@kaplinski.com>
7  *
8  * Copyright (C) 2001-2002 Lauris Kaplinski
9  * Copyright (C) 2001 Ximian, Inc.
10  *
11  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
12  */
13 
14 #include <sigc++/sigc++.h>
15 
16 #include <glibmm/refptr.h>
17 #include <gdkmm/pixbuf.h>
18 
19 #include <cairomm/surface.h>
20 
21 #include "gradient-image.h"
22 
23 #include "display/cairo-utils.h"
24 
25 #include "object/sp-gradient.h"
26 #include "object/sp-stop.h"
27 
28 namespace Inkscape {
29 namespace UI {
30 namespace Widget {
GradientImage(SPGradient * gradient)31 GradientImage::GradientImage(SPGradient *gradient)
32     : _gradient(nullptr)
33 {
34     set_has_window(false);
35     set_gradient(gradient);
36 }
37 
~GradientImage()38 GradientImage::~GradientImage()
39 {
40     if (_gradient) {
41         _release_connection.disconnect();
42         _modified_connection.disconnect();
43         _gradient = nullptr;
44     }
45 }
46 
47 void
size_request(GtkRequisition * requisition) const48 GradientImage::size_request(GtkRequisition *requisition) const
49 {
50     requisition->width = 54;
51     requisition->height = 12;
52 }
53 
54 void
get_preferred_width_vfunc(int & minimal_width,int & natural_width) const55 GradientImage::get_preferred_width_vfunc(int &minimal_width, int &natural_width) const
56 {
57     GtkRequisition requisition;
58     size_request(&requisition);
59     minimal_width = natural_width = requisition.width;
60 }
61 
62 void
get_preferred_height_vfunc(int & minimal_height,int & natural_height) const63 GradientImage::get_preferred_height_vfunc(int &minimal_height, int &natural_height) const
64 {
65     GtkRequisition requisition;
66     size_request(&requisition);
67     minimal_height = natural_height = requisition.height;
68 }
69 
70 bool
on_draw(const Cairo::RefPtr<Cairo::Context> & cr)71 GradientImage::on_draw(const Cairo::RefPtr<Cairo::Context> &cr)
72 {
73     auto allocation = get_allocation();
74 
75     cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard();
76     auto ct = cr->cobj();
77 
78     cairo_set_source(ct, check);
79     cairo_paint(ct);
80     cairo_pattern_destroy(check);
81 
82     if (_gradient) {
83         auto p = _gradient->create_preview_pattern(allocation.get_width());
84         cairo_set_source(ct, p);
85         cairo_paint(ct);
86         cairo_pattern_destroy(p);
87     }
88 
89     return true;
90 }
91 
92 void
set_gradient(SPGradient * gradient)93 GradientImage::set_gradient(SPGradient *gradient)
94 {
95     if (_gradient) {
96         _release_connection.disconnect();
97         _modified_connection.disconnect();
98     }
99 
100     _gradient = gradient;
101 
102     if (gradient) {
103         _release_connection = gradient->connectRelease(sigc::mem_fun(this, &GradientImage::gradient_release));
104         _modified_connection = gradient->connectModified(sigc::mem_fun(this, &GradientImage::gradient_modified));
105     }
106 
107     update();
108 }
109 
110 void
gradient_release(SPObject *)111 GradientImage::gradient_release(SPObject *)
112 {
113     if (_gradient) {
114         _release_connection.disconnect();
115         _modified_connection.disconnect();
116     }
117 
118     _gradient = nullptr;
119 
120     update();
121 }
122 
123 void
gradient_modified(SPObject *,guint)124 GradientImage::gradient_modified(SPObject *, guint /*flags*/)
125 {
126     update();
127 }
128 
129 void
update()130 GradientImage::update()
131 {
132     if (get_is_drawable()) {
133         queue_draw();
134     }
135 }
136 
137 } // namespace Widget
138 } // namespace UI
139 } // namespace Inkscape
140 
141 GdkPixbuf*
sp_gradient_to_pixbuf(SPGradient * gr,int width,int height)142 sp_gradient_to_pixbuf (SPGradient *gr, int width, int height)
143 {
144     cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
145     cairo_t *ct = cairo_create(s);
146 
147     cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard();
148     cairo_set_source(ct, check);
149     cairo_paint(ct);
150     cairo_pattern_destroy(check);
151 
152     if (gr) {
153         cairo_pattern_t *p = gr->create_preview_pattern(width);
154         cairo_set_source(ct, p);
155         cairo_paint(ct);
156         cairo_pattern_destroy(p);
157     }
158 
159     cairo_destroy(ct);
160     cairo_surface_flush(s);
161 
162     // no need to free s - the call below takes ownership
163     GdkPixbuf *pixbuf = ink_pixbuf_create_from_cairo_surface(s);
164     return pixbuf;
165 }
166 
167 
168 Glib::RefPtr<Gdk::Pixbuf>
sp_gradient_to_pixbuf_ref(SPGradient * gr,int width,int height)169 sp_gradient_to_pixbuf_ref (SPGradient *gr, int width, int height)
170 {
171     cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
172     cairo_t *ct = cairo_create(s);
173 
174     cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard();
175     cairo_set_source(ct, check);
176     cairo_paint(ct);
177     cairo_pattern_destroy(check);
178 
179     if (gr) {
180         cairo_pattern_t *p = gr->create_preview_pattern(width);
181         cairo_set_source(ct, p);
182         cairo_paint(ct);
183         cairo_pattern_destroy(p);
184     }
185 
186     cairo_destroy(ct);
187     cairo_surface_flush(s);
188 
189     Cairo::RefPtr<Cairo::Surface> sref = Cairo::RefPtr<Cairo::Surface>(new Cairo::Surface(s));
190     Glib::RefPtr<Gdk::Pixbuf> pixbuf =
191         Gdk::Pixbuf::create(sref, 0, 0, width, height);
192 
193     cairo_surface_destroy(s);
194 
195     return pixbuf;
196 }
197 
198 
199 Glib::RefPtr<Gdk::Pixbuf>
sp_gradstop_to_pixbuf_ref(SPStop * stop,int width,int height)200 sp_gradstop_to_pixbuf_ref (SPStop *stop, int width, int height)
201 {
202     cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
203     cairo_t *ct = cairo_create(s);
204 
205     /* Checkerboard background */
206     cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard();
207     cairo_rectangle(ct, 0, 0, width, height);
208     cairo_set_source(ct, check);
209     cairo_fill_preserve(ct);
210     cairo_pattern_destroy(check);
211 
212     if (stop) {
213         /* Alpha area */
214         cairo_rectangle(ct, 0, 0, width/2, height);
215         ink_cairo_set_source_rgba32(ct, stop->get_rgba32());
216         cairo_fill(ct);
217 
218         /* Solid area */
219         cairo_rectangle(ct, width/2, 0, width, height);
220         ink_cairo_set_source_rgba32(ct, stop->get_rgba32() | 0xff);
221         cairo_fill(ct);
222     }
223 
224     cairo_destroy(ct);
225     cairo_surface_flush(s);
226 
227     Cairo::RefPtr<Cairo::Surface> sref = Cairo::RefPtr<Cairo::Surface>(new Cairo::Surface(s));
228     Glib::RefPtr<Gdk::Pixbuf> pixbuf =
229         Gdk::Pixbuf::create(sref, 0, 0, width, height);
230 
231     cairo_surface_destroy(s);
232 
233     return pixbuf;
234 }
235 
236 
237 
238 /*
239   Local Variables:
240   mode:c++
241   c-file-style:"stroustrup"
242   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
243   indent-tabs-mode:nil
244   fill-column:99
245   End:
246 */
247 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 :
248