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 "gtkcoloreditorprivate.h" |
21 | |
22 | #include "gtkcolorchooserprivate.h" |
23 | #include "gtkcolorplaneprivate.h" |
24 | #include "gtkcolorscaleprivate.h" |
25 | #include "gtkcolorswatchprivate.h" |
26 | #include "gtkcolorutils.h" |
27 | #include "gtkcolorpickerprivate.h" |
28 | #include "gtkgrid.h" |
29 | #include "gtkbutton.h" |
30 | #include "gtkintl.h" |
31 | #include "gtkorientable.h" |
32 | #include "gtkentry.h" |
33 | #include "gtkoverlay.h" |
34 | #include "gtkadjustment.h" |
35 | #include "gtklabel.h" |
36 | #include "gtkspinbutton.h" |
37 | #include "gtkeventcontrollerkey.h" |
38 | #include "gtkroot.h" |
39 | |
40 | #include <math.h> |
41 | |
42 | typedef struct _GtkColorEditorClass GtkColorEditorClass; |
43 | |
44 | struct _GtkColorEditor |
45 | { |
46 | GtkBox parent_instance; |
47 | |
48 | GtkWidget *overlay; |
49 | GtkWidget *grid; |
50 | GtkWidget *swatch; |
51 | GtkWidget *entry; |
52 | GtkWidget *h_slider; |
53 | GtkWidget *; |
54 | GtkWidget *h_entry; |
55 | GtkWidget *a_slider; |
56 | GtkWidget *; |
57 | GtkWidget *a_entry; |
58 | GtkWidget *sv_plane; |
59 | GtkWidget *; |
60 | GtkWidget *s_entry; |
61 | GtkWidget *v_entry; |
62 | GtkWidget *; |
63 | GtkWidget *popdown_focus; |
64 | |
65 | GtkAdjustment *h_adj; |
66 | GtkAdjustment *s_adj; |
67 | GtkAdjustment *v_adj; |
68 | GtkAdjustment *a_adj; |
69 | |
70 | GtkWidget *picker_button; |
71 | GtkColorPicker *picker; |
72 | |
73 | int ; |
74 | |
75 | guint text_changed : 1; |
76 | guint use_alpha : 1; |
77 | }; |
78 | |
79 | struct _GtkColorEditorClass |
80 | { |
81 | GtkBoxClass parent_class; |
82 | }; |
83 | |
84 | enum |
85 | { |
86 | PROP_ZERO, |
87 | PROP_RGBA, |
88 | PROP_USE_ALPHA |
89 | }; |
90 | |
91 | static void gtk_color_editor_iface_init (GtkColorChooserInterface *iface); |
92 | |
93 | G_DEFINE_TYPE_WITH_CODE (GtkColorEditor, gtk_color_editor, GTK_TYPE_BOX, |
94 | G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER, |
95 | gtk_color_editor_iface_init)) |
96 | |
97 | static guint |
98 | scale_round (double value, double scale) |
99 | { |
100 | value = floor (x: value * scale + 0.5); |
101 | value = MAX (value, 0); |
102 | value = MIN (value, scale); |
103 | return (guint)value; |
104 | } |
105 | |
106 | static void |
107 | entry_set_rgba (GtkColorEditor *editor, |
108 | const GdkRGBA *color) |
109 | { |
110 | char *text; |
111 | |
112 | text = g_strdup_printf (format: "#%02X%02X%02X" , |
113 | scale_round (value: color->red, scale: 255), |
114 | scale_round (value: color->green, scale: 255), |
115 | scale_round (value: color->blue, scale: 255)); |
116 | gtk_editable_set_text (GTK_EDITABLE (editor->entry), text); |
117 | editor->text_changed = FALSE; |
118 | g_free (mem: text); |
119 | } |
120 | |
121 | static void |
122 | entry_apply (GtkWidget *entry, |
123 | GtkColorEditor *editor) |
124 | { |
125 | GdkRGBA color; |
126 | char *text; |
127 | |
128 | if (!editor->text_changed) |
129 | return; |
130 | |
131 | text = gtk_editable_get_chars (GTK_EDITABLE (editor->entry), start_pos: 0, end_pos: -1); |
132 | if (gdk_rgba_parse (rgba: &color, spec: text)) |
133 | { |
134 | color.alpha = gtk_adjustment_get_value (adjustment: editor->a_adj); |
135 | gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (editor), color: &color); |
136 | } |
137 | |
138 | editor->text_changed = FALSE; |
139 | |
140 | g_free (mem: text); |
141 | } |
142 | |
143 | static void |
144 | entry_focus_changed (GtkWidget *entry, |
145 | GParamSpec *pspec, |
146 | GtkColorEditor *editor) |
147 | { |
148 | if (!gtk_widget_has_focus (widget: entry)) |
149 | entry_apply (entry, editor); |
150 | } |
151 | |
152 | static void |
153 | entry_text_changed (GtkWidget *entry, |
154 | GParamSpec *pspec, |
155 | GtkColorEditor *editor) |
156 | { |
157 | editor->text_changed = TRUE; |
158 | } |
159 | |
160 | static void |
161 | hsv_changed (GtkColorEditor *editor) |
162 | { |
163 | GdkRGBA color; |
164 | double h, s, v, a; |
165 | |
166 | h = gtk_adjustment_get_value (adjustment: editor->h_adj); |
167 | s = gtk_adjustment_get_value (adjustment: editor->s_adj); |
168 | v = gtk_adjustment_get_value (adjustment: editor->v_adj); |
169 | a = gtk_adjustment_get_value (adjustment: editor->a_adj); |
170 | |
171 | gtk_hsv_to_rgb (h, s, v, r: &color.red, g: &color.green, b: &color.blue); |
172 | color.alpha = a; |
173 | |
174 | gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (editor->swatch), color: &color); |
175 | gtk_color_scale_set_rgba (GTK_COLOR_SCALE (editor->a_slider), color: &color); |
176 | entry_set_rgba (editor, color: &color); |
177 | |
178 | g_object_notify (G_OBJECT (editor), property_name: "rgba" ); |
179 | } |
180 | |
181 | static void |
182 | (GtkColorEditor *editor) |
183 | { |
184 | if (editor->current_popup) |
185 | { |
186 | gtk_widget_hide (widget: editor->current_popup); |
187 | editor->current_popup = NULL; |
188 | editor->popup_position = 0; |
189 | if (editor->popdown_focus) |
190 | { |
191 | if (gtk_widget_is_visible (widget: editor->popdown_focus)) |
192 | gtk_widget_grab_focus (widget: editor->popdown_focus); |
193 | g_clear_object (&editor->popdown_focus); |
194 | } |
195 | } |
196 | } |
197 | |
198 | static void |
199 | (GtkWidget *widget, |
200 | const char *action_name, |
201 | GVariant *parameters) |
202 | { |
203 | GtkColorEditor *editor = GTK_COLOR_EDITOR (widget); |
204 | GtkWidget * = NULL; |
205 | GtkRoot *root; |
206 | GtkWidget *focus; |
207 | int position; |
208 | int s, e; |
209 | const char *param; |
210 | |
211 | param = g_variant_get_string (value: parameters, NULL); |
212 | |
213 | if (strcmp (s1: param, s2: "sv" ) == 0) |
214 | { |
215 | popup = editor->sv_popup; |
216 | focus = editor->s_entry; |
217 | position = 0; |
218 | } |
219 | else if (strcmp (s1: param, s2: "h" ) == 0) |
220 | { |
221 | popup = editor->h_popup; |
222 | focus = editor->h_entry; |
223 | gtk_range_get_slider_range (GTK_RANGE (editor->h_slider), slider_start: &s, slider_end: &e); |
224 | position = (s + e) / 2; |
225 | } |
226 | else if (strcmp (s1: param, s2: "a" ) == 0) |
227 | { |
228 | popup = editor->a_popup; |
229 | focus = editor->a_entry; |
230 | gtk_range_get_slider_range (GTK_RANGE (editor->a_slider), slider_start: &s, slider_end: &e); |
231 | position = (s + e) / 2; |
232 | } |
233 | else |
234 | { |
235 | g_warning ("unsupported popup_edit parameter %s" , param); |
236 | } |
237 | |
238 | if (popup == editor->current_popup) |
239 | dismiss_current_popup (editor); |
240 | else if (popup) |
241 | { |
242 | dismiss_current_popup (editor); |
243 | root = gtk_widget_get_root (GTK_WIDGET (editor)); |
244 | g_set_object (&editor->popdown_focus, gtk_root_get_focus (root)); |
245 | editor->current_popup = popup; |
246 | editor->popup_position = position; |
247 | gtk_widget_show (widget: popup); |
248 | gtk_widget_grab_focus (widget: focus); |
249 | } |
250 | } |
251 | |
252 | static gboolean |
253 | (GtkEventController *controller, |
254 | guint keyval, |
255 | guint keycode, |
256 | GdkModifierType state, |
257 | GtkColorEditor *editor) |
258 | { |
259 | if (keyval == GDK_KEY_Escape) |
260 | { |
261 | dismiss_current_popup (editor); |
262 | return TRUE; |
263 | } |
264 | |
265 | return FALSE; |
266 | } |
267 | |
268 | static gboolean |
269 | get_child_position (GtkOverlay *overlay, |
270 | GtkWidget *widget, |
271 | GtkAllocation *allocation, |
272 | GtkColorEditor *editor) |
273 | { |
274 | GtkRequisition req; |
275 | GtkAllocation alloc; |
276 | int s, e; |
277 | double x, y; |
278 | |
279 | gtk_widget_get_preferred_size (widget, minimum_size: &req, NULL); |
280 | |
281 | allocation->x = 0; |
282 | allocation->y = 0; |
283 | allocation->width = req.width; |
284 | allocation->height = req.height; |
285 | |
286 | if (widget == editor->sv_popup) |
287 | { |
288 | gtk_widget_translate_coordinates (src_widget: editor->sv_plane, |
289 | dest_widget: gtk_widget_get_parent (widget: editor->grid), |
290 | src_x: 0, src_y: -6, |
291 | dest_x: &x, dest_y: &y); |
292 | if (gtk_widget_get_direction (GTK_WIDGET (overlay)) == GTK_TEXT_DIR_RTL) |
293 | x = 0; |
294 | else |
295 | x = gtk_widget_get_width (GTK_WIDGET (overlay)) - req.width; |
296 | } |
297 | else if (widget == editor->h_popup) |
298 | { |
299 | gtk_widget_get_allocation (widget: editor->h_slider, allocation: &alloc); |
300 | gtk_range_get_slider_range (GTK_RANGE (editor->h_slider), slider_start: &s, slider_end: &e); |
301 | |
302 | if (gtk_widget_get_direction (GTK_WIDGET (overlay)) == GTK_TEXT_DIR_RTL) |
303 | gtk_widget_translate_coordinates (src_widget: editor->h_slider, |
304 | dest_widget: gtk_widget_get_parent (widget: editor->grid), |
305 | src_x: - req.width - 6, src_y: editor->popup_position - req.height / 2, |
306 | dest_x: &x, dest_y: &y); |
307 | else |
308 | gtk_widget_translate_coordinates (src_widget: editor->h_slider, |
309 | dest_widget: gtk_widget_get_parent (widget: editor->grid), |
310 | src_x: alloc.width + 6, src_y: editor->popup_position - req.height / 2, |
311 | dest_x: &x, dest_y: &y); |
312 | } |
313 | else if (widget == editor->a_popup) |
314 | { |
315 | gtk_widget_get_allocation (widget: editor->a_slider, allocation: &alloc); |
316 | gtk_range_get_slider_range (GTK_RANGE (editor->a_slider), slider_start: &s, slider_end: &e); |
317 | |
318 | gtk_widget_translate_coordinates (src_widget: editor->a_slider, |
319 | dest_widget: gtk_widget_get_parent (widget: editor->grid), |
320 | src_x: editor->popup_position - req.width / 2, src_y: - req.height - 6, |
321 | dest_x: &x, dest_y: &y); |
322 | } |
323 | else |
324 | return FALSE; |
325 | |
326 | allocation->x = CLAMP (x, 0, gtk_widget_get_width (GTK_WIDGET (overlay)) - req.width); |
327 | allocation->y = CLAMP (y, 0, gtk_widget_get_height (GTK_WIDGET (overlay)) - req.height); |
328 | |
329 | return TRUE; |
330 | } |
331 | |
332 | static void |
333 | value_changed (GtkAdjustment *a, |
334 | GtkAdjustment *as) |
335 | { |
336 | double scale; |
337 | |
338 | scale = gtk_adjustment_get_upper (adjustment: as) / gtk_adjustment_get_upper (adjustment: a); |
339 | g_signal_handlers_block_by_func (as, value_changed, a); |
340 | gtk_adjustment_set_value (adjustment: as, value: gtk_adjustment_get_value (adjustment: a) * scale); |
341 | g_signal_handlers_unblock_by_func (as, value_changed, a); |
342 | } |
343 | |
344 | static GtkAdjustment * |
345 | scaled_adjustment (GtkAdjustment *a, |
346 | double scale) |
347 | { |
348 | GtkAdjustment *as; |
349 | |
350 | as = gtk_adjustment_new (value: gtk_adjustment_get_value (adjustment: a) * scale, |
351 | lower: gtk_adjustment_get_lower (adjustment: a) * scale, |
352 | upper: gtk_adjustment_get_upper (adjustment: a) * scale, |
353 | step_increment: gtk_adjustment_get_step_increment (adjustment: a) * scale, |
354 | page_increment: gtk_adjustment_get_page_increment (adjustment: a) * scale, |
355 | page_size: gtk_adjustment_get_page_size (adjustment: a) * scale); |
356 | |
357 | g_signal_connect (a, "value-changed" , G_CALLBACK (value_changed), as); |
358 | g_signal_connect (as, "value-changed" , G_CALLBACK (value_changed), a); |
359 | |
360 | return as; |
361 | } |
362 | |
363 | static void |
364 | color_picked (GObject *source, |
365 | GAsyncResult *res, |
366 | gpointer data) |
367 | { |
368 | GtkColorPicker *picker = GTK_COLOR_PICKER (source); |
369 | GtkColorEditor *editor = data; |
370 | GError *error = NULL; |
371 | GdkRGBA *color; |
372 | |
373 | color = gtk_color_picker_pick_finish (picker, res, error: &error); |
374 | if (color == NULL) |
375 | { |
376 | g_error_free (error); |
377 | } |
378 | else |
379 | { |
380 | gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (editor), color); |
381 | gdk_rgba_free (rgba: color); |
382 | } |
383 | } |
384 | |
385 | static void |
386 | pick_color (GtkButton *button, |
387 | GtkColorEditor *editor) |
388 | { |
389 | gtk_color_picker_pick (picker: editor->picker, callback: color_picked, user_data: editor); |
390 | } |
391 | |
392 | static void |
393 | gtk_color_editor_init (GtkColorEditor *editor) |
394 | { |
395 | GtkEventController *controller; |
396 | |
397 | editor->use_alpha = TRUE; |
398 | |
399 | g_type_ensure (GTK_TYPE_COLOR_SCALE); |
400 | g_type_ensure (GTK_TYPE_COLOR_PLANE); |
401 | g_type_ensure (GTK_TYPE_COLOR_SWATCH); |
402 | gtk_widget_init_template (GTK_WIDGET (editor)); |
403 | |
404 | if (gtk_widget_get_direction (widget: editor->h_slider) == GTK_TEXT_DIR_RTL) |
405 | gtk_widget_add_css_class (widget: editor->h_slider, css_class: "marks-before" ); |
406 | else |
407 | gtk_widget_add_css_class (widget: editor->h_slider, css_class: "marks-after" ); |
408 | |
409 | /* Create the scaled popup adjustments manually here because connecting user data is not |
410 | * supported by template GtkBuilder xml (it would be possible to set this up in the xml |
411 | * but require 4 separate callbacks and would be rather ugly). |
412 | */ |
413 | gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (editor->h_entry), adjustment: scaled_adjustment (a: editor->h_adj, scale: 360)); |
414 | gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (editor->s_entry), adjustment: scaled_adjustment (a: editor->s_adj, scale: 100)); |
415 | gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (editor->v_entry), adjustment: scaled_adjustment (a: editor->v_adj, scale: 100)); |
416 | gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (editor->a_entry), adjustment: scaled_adjustment (a: editor->a_adj, scale: 100)); |
417 | |
418 | /* This can be setup in the .ui file, but requires work in Glade otherwise it cannot be edited there */ |
419 | gtk_overlay_add_overlay (GTK_OVERLAY (editor->overlay), widget: editor->sv_popup); |
420 | gtk_overlay_add_overlay (GTK_OVERLAY (editor->overlay), widget: editor->h_popup); |
421 | gtk_overlay_add_overlay (GTK_OVERLAY (editor->overlay), widget: editor->a_popup); |
422 | |
423 | controller = gtk_event_controller_key_new (); |
424 | g_signal_connect (controller, "key-pressed" , G_CALLBACK (popup_key_pressed), editor); |
425 | gtk_widget_add_controller (widget: editor->h_entry, controller); |
426 | controller = gtk_event_controller_key_new (); |
427 | g_signal_connect (controller, "key-pressed" , G_CALLBACK (popup_key_pressed), editor); |
428 | gtk_widget_add_controller (widget: editor->s_entry, controller); |
429 | controller = gtk_event_controller_key_new (); |
430 | g_signal_connect (controller, "key-pressed" , G_CALLBACK (popup_key_pressed), editor); |
431 | gtk_widget_add_controller (widget: editor->v_entry, controller); |
432 | controller = gtk_event_controller_key_new (); |
433 | g_signal_connect (controller, "key-pressed" , G_CALLBACK (popup_key_pressed), editor); |
434 | gtk_widget_add_controller (widget: editor->a_entry, controller); |
435 | |
436 | gtk_widget_remove_css_class (widget: editor->swatch, css_class: "activatable" ); |
437 | |
438 | editor->picker = gtk_color_picker_new (); |
439 | if (editor->picker == NULL) |
440 | gtk_widget_hide (widget: editor->picker_button); |
441 | } |
442 | |
443 | static void |
444 | gtk_color_editor_dispose (GObject *object) |
445 | { |
446 | GtkColorEditor *editor = GTK_COLOR_EDITOR (object); |
447 | |
448 | dismiss_current_popup (editor); |
449 | g_clear_object (&editor->picker); |
450 | |
451 | G_OBJECT_CLASS (gtk_color_editor_parent_class)->dispose (object); |
452 | } |
453 | |
454 | static void |
455 | gtk_color_editor_get_property (GObject *object, |
456 | guint prop_id, |
457 | GValue *value, |
458 | GParamSpec *pspec) |
459 | { |
460 | GtkColorEditor *ce = GTK_COLOR_EDITOR (object); |
461 | GtkColorChooser *cc = GTK_COLOR_CHOOSER (object); |
462 | |
463 | switch (prop_id) |
464 | { |
465 | case PROP_RGBA: |
466 | { |
467 | GdkRGBA color; |
468 | gtk_color_chooser_get_rgba (chooser: cc, color: &color); |
469 | g_value_set_boxed (value, v_boxed: &color); |
470 | } |
471 | break; |
472 | case PROP_USE_ALPHA: |
473 | g_value_set_boolean (value, v_boolean: gtk_widget_get_visible (widget: ce->a_slider)); |
474 | break; |
475 | default: |
476 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
477 | break; |
478 | } |
479 | } |
480 | |
481 | static void |
482 | gtk_color_editor_set_use_alpha (GtkColorEditor *editor, |
483 | gboolean use_alpha) |
484 | { |
485 | if (editor->use_alpha != use_alpha) |
486 | { |
487 | editor->use_alpha = use_alpha; |
488 | gtk_widget_set_visible (widget: editor->a_slider, visible: use_alpha); |
489 | gtk_color_swatch_set_use_alpha (GTK_COLOR_SWATCH (editor->swatch), use_alpha); |
490 | } |
491 | } |
492 | |
493 | static void |
494 | gtk_color_editor_set_property (GObject *object, |
495 | guint prop_id, |
496 | const GValue *value, |
497 | GParamSpec *pspec) |
498 | { |
499 | GtkColorEditor *ce = GTK_COLOR_EDITOR (object); |
500 | GtkColorChooser *cc = GTK_COLOR_CHOOSER (object); |
501 | |
502 | switch (prop_id) |
503 | { |
504 | case PROP_RGBA: |
505 | gtk_color_chooser_set_rgba (chooser: cc, color: g_value_get_boxed (value)); |
506 | break; |
507 | case PROP_USE_ALPHA: |
508 | gtk_color_editor_set_use_alpha (editor: ce, use_alpha: g_value_get_boolean (value)); |
509 | break; |
510 | default: |
511 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
512 | break; |
513 | } |
514 | } |
515 | |
516 | static void |
517 | gtk_color_editor_class_init (GtkColorEditorClass *class) |
518 | { |
519 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
520 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); |
521 | |
522 | object_class->dispose = gtk_color_editor_dispose; |
523 | object_class->get_property = gtk_color_editor_get_property; |
524 | object_class->set_property = gtk_color_editor_set_property; |
525 | |
526 | g_object_class_override_property (oclass: object_class, property_id: PROP_RGBA, name: "rgba" ); |
527 | g_object_class_override_property (oclass: object_class, property_id: PROP_USE_ALPHA, name: "use-alpha" ); |
528 | |
529 | /* Bind class to template |
530 | */ |
531 | gtk_widget_class_set_template_from_resource (widget_class, |
532 | resource_name: "/org/gtk/libgtk/ui/gtkcoloreditor.ui" ); |
533 | |
534 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, overlay); |
535 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, grid); |
536 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, swatch); |
537 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, entry); |
538 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, h_slider); |
539 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, h_popup); |
540 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, h_entry); |
541 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, a_slider); |
542 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, a_popup); |
543 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, a_entry); |
544 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, sv_plane); |
545 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, sv_popup); |
546 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, s_entry); |
547 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, v_entry); |
548 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, h_adj); |
549 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, s_adj); |
550 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, v_adj); |
551 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, a_adj); |
552 | gtk_widget_class_bind_template_child (widget_class, GtkColorEditor, picker_button); |
553 | |
554 | gtk_widget_class_bind_template_callback (widget_class, hsv_changed); |
555 | gtk_widget_class_bind_template_callback (widget_class, dismiss_current_popup); |
556 | gtk_widget_class_bind_template_callback (widget_class, get_child_position); |
557 | gtk_widget_class_bind_template_callback (widget_class, entry_text_changed); |
558 | gtk_widget_class_bind_template_callback (widget_class, entry_apply); |
559 | gtk_widget_class_bind_template_callback (widget_class, entry_focus_changed); |
560 | gtk_widget_class_bind_template_callback (widget_class, pick_color); |
561 | |
562 | /** |
563 | * GtkColorEditor|color.edit: |
564 | * @component: the component to edit, "h", "sv" or "a" |
565 | * |
566 | * Opens the edit popup for one of the color components. |
567 | */ |
568 | gtk_widget_class_install_action (widget_class, action_name: "color.edit" , parameter_type: "s" , activate: popup_edit); |
569 | } |
570 | |
571 | static void |
572 | gtk_color_editor_get_rgba (GtkColorChooser *chooser, |
573 | GdkRGBA *color) |
574 | { |
575 | GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser); |
576 | float h, s, v; |
577 | |
578 | h = gtk_adjustment_get_value (adjustment: editor->h_adj); |
579 | s = gtk_adjustment_get_value (adjustment: editor->s_adj); |
580 | v = gtk_adjustment_get_value (adjustment: editor->v_adj); |
581 | gtk_hsv_to_rgb (h, s, v, r: &color->red, g: &color->green, b: &color->blue); |
582 | color->alpha = gtk_adjustment_get_value (adjustment: editor->a_adj); |
583 | } |
584 | |
585 | static void |
586 | gtk_color_editor_set_rgba (GtkColorChooser *chooser, |
587 | const GdkRGBA *color) |
588 | { |
589 | GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser); |
590 | float h, s, v; |
591 | |
592 | gtk_rgb_to_hsv (r: color->red, g: color->green, b: color->blue, h: &h, s: &s, v: &v); |
593 | |
594 | gtk_adjustment_set_value (adjustment: editor->h_adj, value: h); |
595 | gtk_adjustment_set_value (adjustment: editor->s_adj, value: s); |
596 | gtk_adjustment_set_value (adjustment: editor->v_adj, value: v); |
597 | gtk_adjustment_set_value (adjustment: editor->a_adj, value: color->alpha); |
598 | |
599 | gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (editor->swatch), color); |
600 | gtk_color_scale_set_rgba (GTK_COLOR_SCALE (editor->a_slider), color); |
601 | entry_set_rgba (editor, color); |
602 | |
603 | g_object_notify (G_OBJECT (editor), property_name: "rgba" ); |
604 | } |
605 | |
606 | static void |
607 | gtk_color_editor_iface_init (GtkColorChooserInterface *iface) |
608 | { |
609 | iface->get_rgba = gtk_color_editor_get_rgba; |
610 | iface->set_rgba = gtk_color_editor_set_rgba; |
611 | } |
612 | |
613 | GtkWidget * |
614 | gtk_color_editor_new (void) |
615 | { |
616 | return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_EDITOR, NULL); |
617 | } |
618 | |