1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2012 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include "gtkcolorscaleprivate.h"
21
22 #include "gtkcolorchooserprivate.h"
23 #include "gtkgesturelongpress.h"
24 #include "gtkcolorutils.h"
25 #include "gtkorientable.h"
26 #include "gtkrangeprivate.h"
27 #include "gtkstylecontext.h"
28 #include "gtkaccessible.h"
29 #include "gtkprivate.h"
30 #include "gtkintl.h"
31 #include "gtkrenderprivate.h"
32
33 #include <math.h>
34
35 struct _GtkColorScalePrivate
36 {
37 GdkRGBA color;
38 GtkColorScaleType type;
39
40 GtkGesture *long_press_gesture;
41 };
42
43 enum
44 {
45 PROP_ZERO,
46 PROP_SCALE_TYPE
47 };
48
49 static void hold_action (GtkGestureLongPress *gesture,
50 gdouble x,
51 gdouble y,
52 GtkColorScale *scale);
53
G_DEFINE_TYPE_WITH_PRIVATE(GtkColorScale,gtk_color_scale,GTK_TYPE_SCALE)54 G_DEFINE_TYPE_WITH_PRIVATE (GtkColorScale, gtk_color_scale, GTK_TYPE_SCALE)
55
56 void
57 gtk_color_scale_draw_trough (GtkColorScale *scale,
58 cairo_t *cr,
59 int x,
60 int y,
61 int width,
62 int height)
63 {
64 GtkWidget *widget;
65
66 if (width <= 1 || height <= 1)
67 return;
68
69 cairo_save (cr);
70 cairo_translate (cr, x, y);
71
72 widget = GTK_WIDGET (scale);
73 cairo_rectangle (cr, 0, 0, width, height);
74 cairo_clip (cr);
75
76 if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_HORIZONTAL &&
77 gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
78 {
79 cairo_translate (cr, width, 0);
80 cairo_scale (cr, -1, 1);
81 }
82
83 if (scale->priv->type == GTK_COLOR_SCALE_HUE)
84 {
85 gint stride;
86 cairo_surface_t *tmp;
87 guint red, green, blue;
88 guint32 *data, *p;
89 gdouble h;
90 gdouble r, g, b;
91 gdouble f;
92 gint x, y;
93
94 stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
95
96 data = g_malloc (height * stride);
97
98 f = 1.0 / (height - 1);
99 for (y = 0; y < height; y++)
100 {
101 h = CLAMP (y * f, 0.0, 1.0);
102 p = data + y * (stride / 4);
103 for (x = 0; x < width; x++)
104 {
105 gtk_hsv_to_rgb (h, 1, 1, &r, &g, &b);
106 red = CLAMP (r * 255, 0, 255);
107 green = CLAMP (g * 255, 0, 255);
108 blue = CLAMP (b * 255, 0, 255);
109 p[x] = (red << 16) | (green << 8) | blue;
110 }
111 }
112
113 tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24,
114 width, height, stride);
115
116 cairo_set_source_surface (cr, tmp, 0, 0);
117 cairo_paint (cr);
118
119 cairo_surface_destroy (tmp);
120 g_free (data);
121 }
122 else if (scale->priv->type == GTK_COLOR_SCALE_ALPHA)
123 {
124 cairo_pattern_t *pattern;
125 cairo_matrix_t matrix;
126 GdkRGBA *color;
127
128 cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
129 cairo_paint (cr);
130 cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
131
132 pattern = _gtk_color_chooser_get_checkered_pattern ();
133 cairo_matrix_init_scale (&matrix, 0.125, 0.125);
134 cairo_pattern_set_matrix (pattern, &matrix);
135 cairo_mask (cr, pattern);
136 cairo_pattern_destroy (pattern);
137
138 color = &scale->priv->color;
139
140 pattern = cairo_pattern_create_linear (0, 0, width, 0);
141 cairo_pattern_add_color_stop_rgba (pattern, 0, color->red, color->green, color->blue, 0);
142 cairo_pattern_add_color_stop_rgba (pattern, width, color->red, color->green, color->blue, 1);
143 cairo_set_source (cr, pattern);
144 cairo_paint (cr);
145 cairo_pattern_destroy (pattern);
146 }
147
148 cairo_restore (cr);
149 }
150
151 static void
gtk_color_scale_init(GtkColorScale * scale)152 gtk_color_scale_init (GtkColorScale *scale)
153 {
154 GtkStyleContext *context;
155
156 scale->priv = gtk_color_scale_get_instance_private (scale);
157
158 gtk_widget_add_events (GTK_WIDGET (scale), GDK_TOUCH_MASK);
159
160 scale->priv->long_press_gesture = gtk_gesture_long_press_new (GTK_WIDGET (scale));
161 g_signal_connect (scale->priv->long_press_gesture, "pressed",
162 G_CALLBACK (hold_action), scale);
163 gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (scale->priv->long_press_gesture),
164 GTK_PHASE_TARGET);
165
166 context = gtk_widget_get_style_context (GTK_WIDGET (scale));
167 gtk_style_context_add_class (context, "color");
168 }
169
170 static void
scale_finalize(GObject * object)171 scale_finalize (GObject *object)
172 {
173 GtkColorScale *scale = GTK_COLOR_SCALE (object);
174
175 g_clear_object (&scale->priv->long_press_gesture);
176
177 G_OBJECT_CLASS (gtk_color_scale_parent_class)->finalize (object);
178 }
179
180 static void
scale_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)181 scale_get_property (GObject *object,
182 guint prop_id,
183 GValue *value,
184 GParamSpec *pspec)
185 {
186 GtkColorScale *scale = GTK_COLOR_SCALE (object);
187
188 switch (prop_id)
189 {
190 case PROP_SCALE_TYPE:
191 g_value_set_int (value, scale->priv->type);
192 break;
193 default:
194 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
195 break;
196 }
197 }
198
199 static void
scale_set_type(GtkColorScale * scale,GtkColorScaleType type)200 scale_set_type (GtkColorScale *scale,
201 GtkColorScaleType type)
202 {
203 AtkObject *atk_obj;
204
205 scale->priv->type = type;
206
207 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (scale));
208 if (GTK_IS_ACCESSIBLE (atk_obj))
209 {
210 if (type == GTK_COLOR_SCALE_HUE)
211 atk_object_set_name (atk_obj, C_("Color channel", "Hue"));
212 else if (type == GTK_COLOR_SCALE_ALPHA)
213 atk_object_set_name (atk_obj, C_("Color channel", "Alpha"));
214 atk_object_set_role (atk_obj, ATK_ROLE_COLOR_CHOOSER);
215 }
216 }
217
218 static void
scale_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)219 scale_set_property (GObject *object,
220 guint prop_id,
221 const GValue *value,
222 GParamSpec *pspec)
223 {
224 GtkColorScale *scale = GTK_COLOR_SCALE (object);
225
226 switch (prop_id)
227 {
228 case PROP_SCALE_TYPE:
229 scale_set_type (scale, (GtkColorScaleType)g_value_get_int (value));
230 break;
231 default:
232 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
233 break;
234 }
235 }
236
237 static void
hold_action(GtkGestureLongPress * gesture,gdouble x,gdouble y,GtkColorScale * scale)238 hold_action (GtkGestureLongPress *gesture,
239 gdouble x,
240 gdouble y,
241 GtkColorScale *scale)
242 {
243 gboolean handled;
244
245 g_signal_emit_by_name (scale, "popup-menu", &handled);
246 }
247
248 static void
gtk_color_scale_class_init(GtkColorScaleClass * class)249 gtk_color_scale_class_init (GtkColorScaleClass *class)
250 {
251 GObjectClass *object_class = G_OBJECT_CLASS (class);
252
253 object_class->finalize = scale_finalize;
254 object_class->get_property = scale_get_property;
255 object_class->set_property = scale_set_property;
256
257 g_object_class_install_property (object_class, PROP_SCALE_TYPE,
258 g_param_spec_int ("scale-type", P_("Scale type"), P_("Scale type"),
259 0, 1, 0,
260 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
261 }
262
263 void
gtk_color_scale_set_rgba(GtkColorScale * scale,const GdkRGBA * color)264 gtk_color_scale_set_rgba (GtkColorScale *scale,
265 const GdkRGBA *color)
266 {
267 scale->priv->color = *color;
268 gtk_widget_queue_draw (GTK_WIDGET (scale));
269 }
270
271 GtkWidget *
gtk_color_scale_new(GtkAdjustment * adjustment,GtkColorScaleType type)272 gtk_color_scale_new (GtkAdjustment *adjustment,
273 GtkColorScaleType type)
274 {
275 return g_object_new (GTK_TYPE_COLOR_SCALE,
276 "adjustment", adjustment,
277 "draw-value", FALSE,
278 "scale-type", type,
279 NULL);
280 }
281