1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2012 Red Hat, Inc.
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.
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.
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/>.
20 #include "gtkcolorscaleprivate.h"
22 #include "gtkcolorchooserprivate.h"
23 #include "gtkcolorutils.h"
24 #include "gtkorientable.h"
25 #include "gtkstylecontext.h"
26 #include "gtkaccessible.h"
27 #include "gtkpressandholdprivate.h"
28 #include "gtkprivate.h"
33 struct _GtkColorScalePrivate
35 cairo_surface_t *surface;
38 GtkColorScaleType type;
40 GtkPressAndHold *press_and_hold;
49 G_DEFINE_TYPE (GtkColorScale, gtk_color_scale, GTK_TYPE_SCALE)
52 gtk_color_scale_get_trough_size (GtkColorScale *scale,
58 GtkWidget *widget = GTK_WIDGET (scale);
59 gint width, height, focus_line_width, focus_padding;
60 gint x_offset, y_offset;
61 gint slider_width, slider_height;
63 gtk_widget_style_get (widget,
64 "focus-line-width", &focus_line_width,
65 "focus-padding", &focus_padding,
66 "slider-width", &slider_width,
67 "slider-length", &slider_height,
70 width = gtk_widget_get_allocated_width (widget) - 2 * (focus_line_width + focus_padding);
71 height = gtk_widget_get_allocated_height (widget) - 2 * (focus_line_width + focus_padding);
73 x_offset = focus_line_width + focus_padding;
74 y_offset = focus_line_width + focus_padding;
76 /* if the slider has a vertical shape, draw the trough asymmetric */
77 if (slider_width > slider_height)
79 if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_VERTICAL)
81 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
82 x_offset += (gint) floor (slider_width / 2.0);
84 width = (gint) floor (slider_width / 2.0);
88 height = (gint) floor (slider_width / 2.0);
97 *x_offset_out = x_offset;
99 *y_offset_out = y_offset;
103 create_surface (GtkColorScale *scale)
105 GtkWidget *widget = GTK_WIDGET (scale);
106 cairo_surface_t *surface;
109 if (!gtk_widget_get_realized (widget))
112 gtk_color_scale_get_trough_size (scale,
116 if (!scale->priv->surface ||
117 width != scale->priv->width ||
118 height != scale->priv->height)
120 surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
123 if (scale->priv->surface)
124 cairo_surface_destroy (scale->priv->surface);
125 scale->priv->surface = surface;
126 scale->priv->width = width;
127 scale->priv->height= height;
130 surface = scale->priv->surface;
132 if (width == 1 || height == 1)
135 if (scale->priv->type == GTK_COLOR_SCALE_HUE)
139 cairo_surface_t *tmp;
140 guint red, green, blue;
147 stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
149 data = g_malloc (height * stride);
151 f = 1.0 / (height - 1);
152 for (y = 0; y < height; y++)
154 h = CLAMP (y * f, 0.0, 1.0);
155 p = data + y * (stride / 4);
156 for (x = 0; x < width; x++)
158 gtk_hsv_to_rgb (h, 1, 1, &r, &g, &b);
159 red = CLAMP (r * 255, 0, 255);
160 green = CLAMP (g * 255, 0, 255);
161 blue = CLAMP (b * 255, 0, 255);
162 p[x] = (red << 16) | (green << 8) | blue;
166 tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24,
167 width, height, stride);
168 cr = cairo_create (surface);
170 cairo_set_source_surface (cr, tmp, 0, 0);
174 cairo_surface_destroy (tmp);
177 else if (scale->priv->type == GTK_COLOR_SCALE_ALPHA)
180 cairo_pattern_t *pattern;
181 cairo_matrix_t matrix;
184 cr = cairo_create (surface);
186 cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
188 cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
190 pattern = _gtk_color_chooser_get_checkered_pattern ();
191 cairo_matrix_init_scale (&matrix, 0.125, 0.125);
192 cairo_pattern_set_matrix (pattern, &matrix);
193 cairo_mask (cr, pattern);
194 cairo_pattern_destroy (pattern);
196 color = &scale->priv->color;
198 pattern = cairo_pattern_create_linear (0, 0, width, 0);
199 cairo_pattern_add_color_stop_rgba (pattern, 0, color->red, color->green, color->blue, 0);
200 cairo_pattern_add_color_stop_rgba (pattern, width, color->red, color->green, color->blue, 1);
201 cairo_set_source (cr, pattern);
203 cairo_pattern_destroy (pattern);
210 scale_draw (GtkWidget *widget,
213 GtkColorScale *scale = GTK_COLOR_SCALE (widget);
214 gint width, height, x_offset, y_offset;
215 cairo_pattern_t *pattern;
217 create_surface (scale);
218 gtk_color_scale_get_trough_size (scale,
219 &x_offset, &y_offset,
223 cairo_translate (cr, x_offset, y_offset);
224 cairo_rectangle (cr, 0, 0, width, height);
226 pattern = cairo_pattern_create_for_surface (scale->priv->surface);
227 if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_HORIZONTAL &&
228 gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
230 cairo_matrix_t matrix;
232 cairo_matrix_init_scale (&matrix, -1, 1);
233 cairo_matrix_translate (&matrix, -width, 0);
234 cairo_pattern_set_matrix (pattern, &matrix);
236 cairo_set_source (cr, pattern);
239 cairo_pattern_destroy (pattern);
243 GTK_WIDGET_CLASS (gtk_color_scale_parent_class)->draw (widget, cr);
249 gtk_color_scale_init (GtkColorScale *scale)
251 scale->priv = G_TYPE_INSTANCE_GET_PRIVATE (scale,
252 GTK_TYPE_COLOR_SCALE,
253 GtkColorScalePrivate);
254 gtk_widget_add_events (GTK_WIDGET (scale), GDK_TOUCH_MASK);
258 scale_finalize (GObject *object)
260 GtkColorScale *scale = GTK_COLOR_SCALE (object);
262 if (scale->priv->surface)
263 cairo_surface_destroy (scale->priv->surface);
265 g_clear_object (&scale->priv->press_and_hold);
267 G_OBJECT_CLASS (gtk_color_scale_parent_class)->finalize (object);
271 scale_get_property (GObject *object,
276 GtkColorScale *scale = GTK_COLOR_SCALE (object);
280 case PROP_SCALE_TYPE:
281 g_value_set_int (value, scale->priv->type);
284 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
290 scale_set_type (GtkColorScale *scale,
291 GtkColorScaleType type)
295 scale->priv->type = type;
297 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (scale));
298 if (GTK_IS_ACCESSIBLE (atk_obj))
300 if (type == GTK_COLOR_SCALE_HUE)
301 atk_object_set_name (atk_obj, C_("Color channel", "Hue"));
302 else if (type == GTK_COLOR_SCALE_ALPHA)
303 atk_object_set_name (atk_obj, C_("Color channel", "Alpha"));
304 atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (scale)), ATK_ROLE_COLOR_CHOOSER);
309 scale_set_property (GObject *object,
314 GtkColorScale *scale = GTK_COLOR_SCALE (object);
318 case PROP_SCALE_TYPE:
319 scale_set_type (scale, (GtkColorScaleType)g_value_get_int (value));
322 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
328 hold_action (GtkPressAndHold *pah,
331 GtkColorScale *scale)
335 g_signal_emit_by_name (scale, "popup-menu", &handled);
339 scale_touch (GtkWidget *widget,
340 GdkEventTouch *event)
342 GtkColorScale *scale = GTK_COLOR_SCALE (widget);
344 if (!scale->priv->press_and_hold)
348 g_object_get (gtk_widget_get_settings (widget),
349 "gtk-dnd-drag-threshold", &drag_threshold,
352 scale->priv->press_and_hold = gtk_press_and_hold_new ();
354 g_object_set (scale->priv->press_and_hold,
355 "drag-threshold", drag_threshold,
359 g_signal_connect (scale->priv->press_and_hold, "hold",
360 G_CALLBACK (hold_action), scale);
363 gtk_press_and_hold_process_event (scale->priv->press_and_hold, (GdkEvent *)event);
365 return GTK_WIDGET_CLASS (gtk_color_scale_parent_class)->touch_event (widget, event);
370 gtk_color_scale_class_init (GtkColorScaleClass *class)
372 GObjectClass *object_class = G_OBJECT_CLASS (class);
373 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
375 object_class->finalize = scale_finalize;
376 object_class->get_property = scale_get_property;
377 object_class->set_property = scale_set_property;
379 widget_class->draw = scale_draw;
380 widget_class->touch_event = scale_touch;
382 g_object_class_install_property (object_class, PROP_SCALE_TYPE,
383 g_param_spec_int ("scale-type", P_("Scale type"), P_("Scale type"),
385 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
387 g_type_class_add_private (class, sizeof (GtkColorScalePrivate));
391 gtk_color_scale_set_rgba (GtkColorScale *scale,
392 const GdkRGBA *color)
394 scale->priv->color = *color;
395 scale->priv->width = -1; /* force surface refresh */
396 create_surface (scale);
397 gtk_widget_queue_draw (GTK_WIDGET (scale));
401 gtk_color_scale_new (GtkAdjustment *adjustment,
402 GtkColorScaleType type)
404 return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_SCALE,
405 "adjustment", adjustment,