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 "gtkcolorswatchprivate.h" |
21 | |
22 | #include "gtkbox.h" |
23 | #include "gtkcolorchooserprivate.h" |
24 | #include "gtkdragsource.h" |
25 | #include "gtkdroptarget.h" |
26 | #include "gtkgesturelongpress.h" |
27 | #include "gtkgestureclick.h" |
28 | #include "gtkgesturesingle.h" |
29 | #include "gtkicontheme.h" |
30 | #include "gtkimage.h" |
31 | #include "gtkintl.h" |
32 | #include "gtkmain.h" |
33 | #include "gtkmodelbuttonprivate.h" |
34 | #include "gtkpopovermenu.h" |
35 | #include "gtkprivate.h" |
36 | #include "gtksnapshot.h" |
37 | #include "gtkwidgetprivate.h" |
38 | #include "gtkeventcontrollerkey.h" |
39 | #include "gtknative.h" |
40 | |
41 | /* |
42 | * GtkColorSwatch has two CSS nodes, the main one named colorswatch |
43 | * and a subnode named overlay. The main node gets the .light or .dark |
44 | * style classes added depending on the brightness of the color that |
45 | * the swatch is showing. |
46 | * |
47 | * The color swatch has the .activatable style class by default. It can |
48 | * be removed for non-activatable swatches. |
49 | */ |
50 | |
51 | typedef struct _GtkColorSwatchClass GtkColorSwatchClass; |
52 | |
53 | struct _GtkColorSwatch |
54 | { |
55 | GtkWidget parent_instance; |
56 | |
57 | GdkRGBA color; |
58 | char *icon; |
59 | guint has_color : 1; |
60 | guint use_alpha : 1; |
61 | guint selectable : 1; |
62 | guint : 1; |
63 | |
64 | GtkWidget *overlay_widget; |
65 | |
66 | GtkWidget *popover; |
67 | GtkDropTarget *dest; |
68 | GtkDragSource *source; |
69 | }; |
70 | |
71 | struct _GtkColorSwatchClass |
72 | { |
73 | GtkWidgetClass parent_class; |
74 | |
75 | void ( * activate) (GtkColorSwatch *swatch); |
76 | void ( * customize) (GtkColorSwatch *swatch); |
77 | }; |
78 | |
79 | enum |
80 | { |
81 | PROP_ZERO, |
82 | PROP_RGBA, |
83 | PROP_SELECTABLE, |
84 | , |
85 | PROP_CAN_DROP, |
86 | PROP_CAN_DRAG |
87 | }; |
88 | |
89 | G_DEFINE_TYPE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET) |
90 | |
91 | #define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11) |
92 | static void |
93 | swatch_snapshot (GtkWidget *widget, |
94 | GtkSnapshot *snapshot) |
95 | { |
96 | GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); |
97 | const int width = gtk_widget_get_width (widget); |
98 | const int height = gtk_widget_get_height (widget); |
99 | const GdkRGBA *color; |
100 | |
101 | color = &swatch->color; |
102 | if (swatch->dest) |
103 | { |
104 | const GValue *value = gtk_drop_target_get_value (self: swatch->dest); |
105 | |
106 | if (value) |
107 | color = g_value_get_boxed (value); |
108 | } |
109 | |
110 | if (swatch->has_color) |
111 | { |
112 | if (swatch->use_alpha && !gdk_rgba_is_opaque (rgba: color)) |
113 | { |
114 | _gtk_color_chooser_snapshot_checkered_pattern (snapshot, width, height); |
115 | |
116 | gtk_snapshot_append_color (snapshot, |
117 | color, |
118 | bounds: &GRAPHENE_RECT_INIT (0, 0, width, height)); |
119 | } |
120 | else |
121 | { |
122 | GdkRGBA opaque = *color; |
123 | |
124 | opaque.alpha = 1.0; |
125 | |
126 | gtk_snapshot_append_color (snapshot, |
127 | color: &opaque, |
128 | bounds: &GRAPHENE_RECT_INIT (0, 0, width, height)); |
129 | } |
130 | } |
131 | |
132 | gtk_widget_snapshot_child (widget, child: swatch->overlay_widget, snapshot); |
133 | } |
134 | |
135 | static gboolean |
136 | swatch_drag_drop (GtkDropTarget *dest, |
137 | const GValue *value, |
138 | double x, |
139 | double y, |
140 | GtkColorSwatch *swatch) |
141 | |
142 | { |
143 | gtk_color_swatch_set_rgba (swatch, color: g_value_get_boxed (value)); |
144 | |
145 | return TRUE; |
146 | } |
147 | |
148 | void |
149 | gtk_color_swatch_activate (GtkColorSwatch *swatch) |
150 | { |
151 | double red, green, blue, alpha; |
152 | |
153 | red = swatch->color.red; |
154 | green = swatch->color.green; |
155 | blue = swatch->color.blue; |
156 | alpha = swatch->color.alpha; |
157 | |
158 | gtk_widget_activate_action (GTK_WIDGET (swatch), |
159 | name: "color.select" , format_string: "(dddd)" , red, green, blue, alpha); |
160 | } |
161 | |
162 | void |
163 | gtk_color_swatch_customize (GtkColorSwatch *swatch) |
164 | { |
165 | double red, green, blue, alpha; |
166 | |
167 | red = swatch->color.red; |
168 | green = swatch->color.green; |
169 | blue = swatch->color.blue; |
170 | alpha = swatch->color.alpha; |
171 | |
172 | gtk_widget_activate_action (GTK_WIDGET (swatch), |
173 | name: "color.customize" , format_string: "(dddd)" , red, green, blue, alpha); |
174 | } |
175 | |
176 | void |
177 | gtk_color_swatch_select (GtkColorSwatch *swatch) |
178 | { |
179 | gtk_widget_set_state_flags (GTK_WIDGET (swatch), flags: GTK_STATE_FLAG_SELECTED, FALSE); |
180 | } |
181 | |
182 | static gboolean |
183 | gtk_color_swatch_is_selected (GtkColorSwatch *swatch) |
184 | { |
185 | return (gtk_widget_get_state_flags (GTK_WIDGET (swatch)) & GTK_STATE_FLAG_SELECTED) != 0; |
186 | } |
187 | |
188 | static gboolean |
189 | key_controller_key_pressed (GtkEventControllerKey *controller, |
190 | guint keyval, |
191 | guint keycode, |
192 | GdkModifierType state, |
193 | GtkWidget *widget) |
194 | { |
195 | GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); |
196 | |
197 | if (keyval == GDK_KEY_space || |
198 | keyval == GDK_KEY_Return || |
199 | keyval == GDK_KEY_ISO_Enter|| |
200 | keyval == GDK_KEY_KP_Enter || |
201 | keyval == GDK_KEY_KP_Space) |
202 | { |
203 | if (swatch->has_color && |
204 | swatch->selectable && |
205 | !gtk_color_swatch_is_selected (swatch)) |
206 | gtk_color_swatch_select (swatch); |
207 | else |
208 | gtk_color_swatch_customize (swatch); |
209 | |
210 | return TRUE; |
211 | } |
212 | |
213 | return FALSE; |
214 | } |
215 | |
216 | static GMenuModel * |
217 | (GtkColorSwatch *swatch) |
218 | { |
219 | GMenu *, *section; |
220 | GMenuItem *item; |
221 | double red, green, blue, alpha; |
222 | |
223 | menu = g_menu_new (); |
224 | |
225 | red = swatch->color.red; |
226 | green = swatch->color.green; |
227 | blue = swatch->color.blue; |
228 | alpha = swatch->color.alpha; |
229 | |
230 | section = g_menu_new (); |
231 | item = g_menu_item_new (_("Customize" ), NULL); |
232 | g_menu_item_set_action_and_target_value (menu_item: item, action: "color.customize" , |
233 | target_value: g_variant_new (format_string: "(dddd)" , red, green, blue, alpha)); |
234 | |
235 | g_menu_append_item (menu: section, item); |
236 | g_menu_append_section (menu, NULL, G_MENU_MODEL (section)); |
237 | g_object_unref (object: item); |
238 | g_object_unref (object: section); |
239 | |
240 | return G_MENU_MODEL (menu); |
241 | } |
242 | |
243 | static void |
244 | (GtkColorSwatch *swatch) |
245 | { |
246 | GMenuModel *model; |
247 | |
248 | g_clear_pointer (&swatch->popover, gtk_widget_unparent); |
249 | |
250 | model = gtk_color_swatch_get_menu_model (swatch); |
251 | swatch->popover = gtk_popover_menu_new_from_model (model); |
252 | gtk_widget_set_parent (widget: swatch->popover, GTK_WIDGET (swatch)); |
253 | g_object_unref (object: model); |
254 | |
255 | gtk_popover_popup (GTK_POPOVER (swatch->popover)); |
256 | } |
257 | |
258 | static gboolean |
259 | swatch_primary_action (GtkColorSwatch *swatch) |
260 | { |
261 | if (!swatch->has_color) |
262 | { |
263 | gtk_color_swatch_customize (swatch); |
264 | return TRUE; |
265 | } |
266 | else if (swatch->selectable && |
267 | !gtk_color_swatch_is_selected (swatch)) |
268 | { |
269 | gtk_color_swatch_select (swatch); |
270 | return TRUE; |
271 | } |
272 | |
273 | return FALSE; |
274 | } |
275 | |
276 | static void |
277 | hold_action (GtkGestureLongPress *gesture, |
278 | double x, |
279 | double y, |
280 | GtkColorSwatch *swatch) |
281 | { |
282 | do_popup (swatch); |
283 | gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_CLAIMED); |
284 | } |
285 | |
286 | static void |
287 | tap_action (GtkGestureClick *gesture, |
288 | int n_press, |
289 | double x, |
290 | double y, |
291 | GtkColorSwatch *swatch) |
292 | { |
293 | guint button; |
294 | |
295 | button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)); |
296 | |
297 | if (button == GDK_BUTTON_PRIMARY) |
298 | { |
299 | if (n_press == 1) |
300 | swatch_primary_action (swatch); |
301 | else if (n_press > 1) |
302 | gtk_color_swatch_activate (swatch); |
303 | } |
304 | else if (button == GDK_BUTTON_SECONDARY) |
305 | { |
306 | if (swatch->has_color && swatch->has_menu) |
307 | do_popup (swatch); |
308 | } |
309 | } |
310 | |
311 | static void |
312 | swatch_size_allocate (GtkWidget *widget, |
313 | int width, |
314 | int height, |
315 | int baseline) |
316 | { |
317 | GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); |
318 | |
319 | gtk_widget_size_allocate (widget: swatch->overlay_widget, |
320 | allocation: &(GtkAllocation) { |
321 | 0, 0, |
322 | width, height |
323 | }, baseline: -1); |
324 | |
325 | if (swatch->popover) |
326 | gtk_popover_present (GTK_POPOVER (swatch->popover)); |
327 | } |
328 | |
329 | static void |
330 | gtk_color_swatch_measure (GtkWidget *widget, |
331 | GtkOrientation orientation, |
332 | int for_size, |
333 | int *minimum, |
334 | int *natural, |
335 | int *minimum_baseline, |
336 | int *natural_baseline) |
337 | { |
338 | GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); |
339 | int w, h, min; |
340 | |
341 | gtk_widget_measure (widget: swatch->overlay_widget, |
342 | orientation, |
343 | for_size: -1, |
344 | minimum, natural, |
345 | NULL, NULL); |
346 | |
347 | gtk_widget_get_size_request (widget, width: &w, height: &h); |
348 | if (orientation == GTK_ORIENTATION_HORIZONTAL) |
349 | min = w < 0 ? 48 : w; |
350 | else |
351 | min = h < 0 ? 32 : h; |
352 | |
353 | *minimum = MAX (*minimum, min); |
354 | *natural = MAX (*natural, min); |
355 | } |
356 | |
357 | static void |
358 | (GtkWidget *widget, |
359 | const char *action_name, |
360 | GVariant *parameters) |
361 | { |
362 | do_popup (GTK_COLOR_SWATCH (widget)); |
363 | } |
364 | |
365 | static void |
366 | update_icon (GtkColorSwatch *swatch) |
367 | { |
368 | GtkImage *image = GTK_IMAGE (swatch->overlay_widget); |
369 | |
370 | if (swatch->icon) |
371 | gtk_image_set_from_icon_name (image, icon_name: swatch->icon); |
372 | else if (gtk_color_swatch_is_selected (swatch)) |
373 | gtk_image_set_from_icon_name (image, icon_name: "object-select-symbolic" ); |
374 | else |
375 | gtk_image_clear (image); |
376 | } |
377 | |
378 | static void |
379 | update_accessible_properties (GtkColorSwatch *swatch) |
380 | { |
381 | if (swatch->selectable) |
382 | { |
383 | gboolean selected = gtk_color_swatch_is_selected (swatch); |
384 | |
385 | gtk_accessible_update_state (self: GTK_ACCESSIBLE (ptr: swatch), |
386 | first_state: GTK_ACCESSIBLE_STATE_CHECKED, selected, |
387 | -1); |
388 | } |
389 | else |
390 | { |
391 | gtk_accessible_reset_state (self: GTK_ACCESSIBLE (ptr: swatch), |
392 | state: GTK_ACCESSIBLE_STATE_CHECKED); |
393 | } |
394 | } |
395 | |
396 | static void |
397 | swatch_state_flags_changed (GtkWidget *widget, |
398 | GtkStateFlags previous_state) |
399 | { |
400 | GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); |
401 | |
402 | update_icon (swatch); |
403 | update_accessible_properties (swatch); |
404 | |
405 | GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->state_flags_changed (widget, previous_state); |
406 | } |
407 | |
408 | /* GObject implementation {{{1 */ |
409 | |
410 | static void |
411 | swatch_get_property (GObject *object, |
412 | guint prop_id, |
413 | GValue *value, |
414 | GParamSpec *pspec) |
415 | { |
416 | GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object); |
417 | GdkRGBA color; |
418 | |
419 | switch (prop_id) |
420 | { |
421 | case PROP_RGBA: |
422 | gtk_color_swatch_get_rgba (swatch, color: &color); |
423 | g_value_set_boxed (value, v_boxed: &color); |
424 | break; |
425 | case PROP_SELECTABLE: |
426 | g_value_set_boolean (value, v_boolean: gtk_color_swatch_get_selectable (swatch)); |
427 | break; |
428 | case PROP_HAS_MENU: |
429 | g_value_set_boolean (value, v_boolean: swatch->has_menu); |
430 | break; |
431 | case PROP_CAN_DROP: |
432 | g_value_set_boolean (value, v_boolean: swatch->dest != NULL); |
433 | break; |
434 | case PROP_CAN_DRAG: |
435 | g_value_set_boolean (value, v_boolean: swatch->source != NULL); |
436 | break; |
437 | default: |
438 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
439 | break; |
440 | } |
441 | } |
442 | |
443 | static void |
444 | swatch_set_property (GObject *object, |
445 | guint prop_id, |
446 | const GValue *value, |
447 | GParamSpec *pspec) |
448 | { |
449 | GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object); |
450 | |
451 | switch (prop_id) |
452 | { |
453 | case PROP_RGBA: |
454 | gtk_color_swatch_set_rgba (swatch, color: g_value_get_boxed (value)); |
455 | break; |
456 | case PROP_SELECTABLE: |
457 | gtk_color_swatch_set_selectable (swatch, selectable: g_value_get_boolean (value)); |
458 | break; |
459 | case PROP_HAS_MENU: |
460 | swatch->has_menu = g_value_get_boolean (value); |
461 | break; |
462 | case PROP_CAN_DROP: |
463 | gtk_color_swatch_set_can_drop (swatch, can_drop: g_value_get_boolean (value)); |
464 | break; |
465 | case PROP_CAN_DRAG: |
466 | gtk_color_swatch_set_can_drag (swatch, can_drag: g_value_get_boolean (value)); |
467 | break; |
468 | default: |
469 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
470 | break; |
471 | } |
472 | } |
473 | |
474 | static void |
475 | swatch_finalize (GObject *object) |
476 | { |
477 | GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object); |
478 | |
479 | g_free (mem: swatch->icon); |
480 | gtk_widget_unparent (widget: swatch->overlay_widget); |
481 | |
482 | G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object); |
483 | } |
484 | |
485 | static void |
486 | swatch_dispose (GObject *object) |
487 | { |
488 | GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object); |
489 | |
490 | g_clear_pointer (&swatch->popover, gtk_widget_unparent); |
491 | |
492 | G_OBJECT_CLASS (gtk_color_swatch_parent_class)->dispose (object); |
493 | } |
494 | |
495 | static void |
496 | gtk_color_swatch_class_init (GtkColorSwatchClass *class) |
497 | { |
498 | GtkWidgetClass *widget_class = (GtkWidgetClass *)class; |
499 | GObjectClass *object_class = (GObjectClass *)class; |
500 | |
501 | object_class->get_property = swatch_get_property; |
502 | object_class->set_property = swatch_set_property; |
503 | object_class->finalize = swatch_finalize; |
504 | object_class->dispose = swatch_dispose; |
505 | |
506 | widget_class->measure = gtk_color_swatch_measure; |
507 | widget_class->snapshot = swatch_snapshot; |
508 | widget_class->size_allocate = swatch_size_allocate; |
509 | widget_class->state_flags_changed = swatch_state_flags_changed; |
510 | |
511 | g_object_class_install_property (oclass: object_class, property_id: PROP_RGBA, |
512 | pspec: g_param_spec_boxed (name: "rgba" , P_("RGBA Color" ), P_("Color as RGBA" ), |
513 | GDK_TYPE_RGBA, GTK_PARAM_READWRITE)); |
514 | g_object_class_install_property (oclass: object_class, property_id: PROP_SELECTABLE, |
515 | pspec: g_param_spec_boolean (name: "selectable" , P_("Selectable" ), P_("Whether the swatch is selectable" ), |
516 | TRUE, GTK_PARAM_READWRITE)); |
517 | g_object_class_install_property (oclass: object_class, property_id: PROP_HAS_MENU, |
518 | pspec: g_param_spec_boolean (name: "has-menu" , P_("Has Menu" ), P_("Whether the swatch should offer customization" ), |
519 | TRUE, GTK_PARAM_READWRITE)); |
520 | g_object_class_install_property (oclass: object_class, property_id: PROP_CAN_DROP, |
521 | pspec: g_param_spec_boolean (name: "can-drop" , P_("Can Drop" ), P_("Whether the swatch should accept drops" ), |
522 | FALSE, GTK_PARAM_READWRITE)); |
523 | g_object_class_install_property (oclass: object_class, property_id: PROP_CAN_DRAG, |
524 | pspec: g_param_spec_boolean (name: "can-drag" , P_("Can Drag" ), P_("Whether the swatch should allow drags" ), |
525 | TRUE, GTK_PARAM_READWRITE)); |
526 | |
527 | /** |
528 | * GtkColorSwatch|menu.popup: |
529 | * |
530 | * Opens the context menu. |
531 | */ |
532 | gtk_widget_class_install_action (widget_class, action_name: "menu.popup" , NULL, activate: swatch_popup_menu); |
533 | |
534 | gtk_widget_class_add_binding_action (widget_class, |
535 | GDK_KEY_F10, mods: GDK_SHIFT_MASK, |
536 | action_name: "menu.popup" , |
537 | NULL); |
538 | gtk_widget_class_add_binding_action (widget_class, |
539 | GDK_KEY_Menu, mods: 0, |
540 | action_name: "menu.popup" , |
541 | NULL); |
542 | |
543 | gtk_widget_class_set_css_name (widget_class, I_("colorswatch" )); |
544 | gtk_widget_class_set_accessible_role (widget_class, accessible_role: GTK_ACCESSIBLE_ROLE_RADIO); |
545 | } |
546 | |
547 | static void |
548 | gtk_color_swatch_init (GtkColorSwatch *swatch) |
549 | { |
550 | GtkEventController *controller; |
551 | GtkGesture *gesture; |
552 | |
553 | swatch->use_alpha = TRUE; |
554 | swatch->selectable = TRUE; |
555 | swatch->has_menu = TRUE; |
556 | swatch->color.red = 0.75; |
557 | swatch->color.green = 0.25; |
558 | swatch->color.blue = 0.25; |
559 | swatch->color.alpha = 1.0; |
560 | |
561 | gtk_widget_set_focusable (GTK_WIDGET (swatch), TRUE); |
562 | gtk_widget_set_overflow (GTK_WIDGET (swatch), overflow: GTK_OVERFLOW_HIDDEN); |
563 | |
564 | gesture = gtk_gesture_long_press_new (); |
565 | gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), |
566 | TRUE); |
567 | g_signal_connect (gesture, "pressed" , |
568 | G_CALLBACK (hold_action), swatch); |
569 | gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (gesture)); |
570 | |
571 | gesture = gtk_gesture_click_new (); |
572 | gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), button: 0); |
573 | g_signal_connect (gesture, "pressed" , |
574 | G_CALLBACK (tap_action), swatch); |
575 | gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (gesture)); |
576 | |
577 | controller = gtk_event_controller_key_new (); |
578 | g_signal_connect (controller, "key-pressed" , |
579 | G_CALLBACK (key_controller_key_pressed), swatch); |
580 | gtk_widget_add_controller (GTK_WIDGET (swatch), controller); |
581 | |
582 | gtk_color_swatch_set_can_drag (swatch, TRUE); |
583 | |
584 | gtk_widget_add_css_class (GTK_WIDGET (swatch), css_class: "activatable" ); |
585 | |
586 | swatch->overlay_widget = g_object_new (GTK_TYPE_IMAGE, |
587 | first_property_name: "accessible-role" , GTK_ACCESSIBLE_ROLE_NONE, |
588 | "css-name" , "overlay" , |
589 | NULL); |
590 | gtk_widget_set_parent (widget: swatch->overlay_widget, GTK_WIDGET (swatch)); |
591 | } |
592 | |
593 | /* Public API {{{1 */ |
594 | |
595 | GtkWidget * |
596 | gtk_color_swatch_new (void) |
597 | { |
598 | return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_SWATCH, NULL); |
599 | } |
600 | |
601 | static GdkContentProvider * |
602 | gtk_color_swatch_drag_prepare (GtkDragSource *source, |
603 | double x, |
604 | double y, |
605 | GtkColorSwatch *swatch) |
606 | { |
607 | return gdk_content_provider_new_typed (GDK_TYPE_RGBA, &swatch->color); |
608 | } |
609 | |
610 | void |
611 | gtk_color_swatch_set_rgba (GtkColorSwatch *swatch, |
612 | const GdkRGBA *color) |
613 | { |
614 | swatch->has_color = TRUE; |
615 | swatch->color = *color; |
616 | if (swatch->source) |
617 | gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (swatch->source), phase: GTK_PHASE_CAPTURE); |
618 | |
619 | if (INTENSITY (swatch->color.red, swatch->color.green, swatch->color.blue) > 0.5) |
620 | { |
621 | gtk_widget_add_css_class (GTK_WIDGET (swatch), css_class: "light" ); |
622 | gtk_widget_remove_css_class (GTK_WIDGET (swatch), css_class: "dark" ); |
623 | } |
624 | else |
625 | { |
626 | gtk_widget_add_css_class (GTK_WIDGET (swatch), css_class: "dark" ); |
627 | gtk_widget_remove_css_class (GTK_WIDGET (swatch), css_class: "light" ); |
628 | } |
629 | |
630 | gtk_widget_queue_draw (GTK_WIDGET (swatch)); |
631 | g_object_notify (G_OBJECT (swatch), property_name: "rgba" ); |
632 | } |
633 | |
634 | gboolean |
635 | gtk_color_swatch_get_rgba (GtkColorSwatch *swatch, |
636 | GdkRGBA *color) |
637 | { |
638 | if (swatch->has_color) |
639 | { |
640 | color->red = swatch->color.red; |
641 | color->green = swatch->color.green; |
642 | color->blue = swatch->color.blue; |
643 | color->alpha = swatch->color.alpha; |
644 | return TRUE; |
645 | } |
646 | else |
647 | { |
648 | color->red = 1.0; |
649 | color->green = 1.0; |
650 | color->blue = 1.0; |
651 | color->alpha = 1.0; |
652 | return FALSE; |
653 | } |
654 | } |
655 | |
656 | void |
657 | gtk_color_swatch_set_icon (GtkColorSwatch *swatch, |
658 | const char *icon) |
659 | { |
660 | swatch->icon = g_strdup (str: icon); |
661 | update_icon (swatch); |
662 | gtk_widget_queue_draw (GTK_WIDGET (swatch)); |
663 | } |
664 | |
665 | void |
666 | gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch, |
667 | gboolean can_drop) |
668 | { |
669 | if (can_drop == (swatch->dest != NULL)) |
670 | return; |
671 | |
672 | if (can_drop && !swatch->dest) |
673 | { |
674 | swatch->dest = gtk_drop_target_new (GDK_TYPE_RGBA, actions: GDK_ACTION_COPY); |
675 | gtk_drop_target_set_preload (self: swatch->dest, TRUE); |
676 | g_signal_connect (swatch->dest, "drop" , G_CALLBACK (swatch_drag_drop), swatch); |
677 | g_signal_connect_swapped (swatch->dest, "notify::value" , G_CALLBACK (gtk_widget_queue_draw), swatch); |
678 | gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (swatch->dest)); |
679 | } |
680 | if (!can_drop && swatch->dest) |
681 | { |
682 | gtk_widget_remove_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (swatch->dest)); |
683 | swatch->dest = NULL; |
684 | } |
685 | |
686 | g_object_notify (G_OBJECT (swatch), property_name: "can-drop" ); |
687 | } |
688 | |
689 | void |
690 | gtk_color_swatch_set_can_drag (GtkColorSwatch *swatch, |
691 | gboolean can_drag) |
692 | { |
693 | if (can_drag == (swatch->source != NULL)) |
694 | return; |
695 | |
696 | if (can_drag && !swatch->source) |
697 | { |
698 | swatch->source = gtk_drag_source_new (); |
699 | g_signal_connect (swatch->source, "prepare" , G_CALLBACK (gtk_color_swatch_drag_prepare), swatch); |
700 | gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (swatch->source), |
701 | phase: swatch->has_color ? GTK_PHASE_CAPTURE : GTK_PHASE_NONE); |
702 | gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (swatch->source)); |
703 | } |
704 | if (!can_drag && swatch->source) |
705 | { |
706 | gtk_widget_remove_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (swatch->source)); |
707 | swatch->source = NULL; |
708 | } |
709 | |
710 | g_object_notify (G_OBJECT (swatch), property_name: "can-drag" ); |
711 | } |
712 | |
713 | void |
714 | gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch, |
715 | gboolean use_alpha) |
716 | { |
717 | swatch->use_alpha = use_alpha; |
718 | gtk_widget_queue_draw (GTK_WIDGET (swatch)); |
719 | } |
720 | |
721 | void |
722 | gtk_color_swatch_set_selectable (GtkColorSwatch *swatch, |
723 | gboolean selectable) |
724 | { |
725 | if (selectable == swatch->selectable) |
726 | return; |
727 | |
728 | swatch->selectable = selectable; |
729 | |
730 | update_accessible_properties (swatch); |
731 | g_object_notify (G_OBJECT (swatch), property_name: "selectable" ); |
732 | } |
733 | |
734 | gboolean |
735 | gtk_color_swatch_get_selectable (GtkColorSwatch *swatch) |
736 | { |
737 | return swatch->selectable; |
738 | } |
739 | |
740 | /* vim:set foldmethod=marker: */ |
741 | |