1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <gegl.h>
21 #include <gtk/gtk.h>
22 
23 #include "libgimpcolor/gimpcolor.h"
24 #include "libgimpwidgets/gimpwidgets.h"
25 
26 #include "widgets-types.h"
27 
28 #include "config/gimpcoreconfig.h"
29 
30 #include "core/gimp.h"
31 #include "core/gimpcontext.h"
32 #include "core/gimpmarshal.h"
33 
34 #include "gimpaction.h"
35 #include "gimpactiongroup.h"
36 #include "gimpactionimpl.h"
37 #include "gimpcolordialog.h"
38 #include "gimpcolorpanel.h"
39 
40 
41 #define RGBA_EPSILON 1e-6
42 
43 enum
44 {
45   RESPONSE,
46   LAST_SIGNAL
47 };
48 
49 
50 /*  local function prototypes  */
51 
52 static void       gimp_color_panel_dispose         (GObject            *object);
53 
54 static gboolean   gimp_color_panel_button_press    (GtkWidget          *widget,
55                                                     GdkEventButton     *bevent);
56 
57 static void       gimp_color_panel_clicked         (GtkButton          *button);
58 
59 static void       gimp_color_panel_color_changed   (GimpColorButton    *button);
60 static GType      gimp_color_panel_get_action_type (GimpColorButton    *button);
61 
62 static void       gimp_color_panel_dialog_update   (GimpColorDialog    *dialog,
63                                                     const GimpRGB      *color,
64                                                     GimpColorDialogState state,
65                                                     GimpColorPanel     *panel);
66 
67 
68 G_DEFINE_TYPE (GimpColorPanel, gimp_color_panel, GIMP_TYPE_COLOR_BUTTON)
69 
70 #define parent_class gimp_color_panel_parent_class
71 
72 static guint color_panel_signals[LAST_SIGNAL] = { 0, };
73 
74 
75 static void
gimp_color_panel_class_init(GimpColorPanelClass * klass)76 gimp_color_panel_class_init (GimpColorPanelClass *klass)
77 {
78   GObjectClass         *object_class       = G_OBJECT_CLASS (klass);
79   GtkWidgetClass       *widget_class       = GTK_WIDGET_CLASS (klass);
80   GtkButtonClass       *button_class       = GTK_BUTTON_CLASS (klass);
81   GimpColorButtonClass *color_button_class = GIMP_COLOR_BUTTON_CLASS (klass);
82 
83   object_class->dispose               = gimp_color_panel_dispose;
84 
85   widget_class->button_press_event    = gimp_color_panel_button_press;
86 
87   button_class->clicked               = gimp_color_panel_clicked;
88 
89   color_button_class->color_changed   = gimp_color_panel_color_changed;
90   color_button_class->get_action_type = gimp_color_panel_get_action_type;
91 
92   color_panel_signals[RESPONSE] =
93     g_signal_new ("response",
94                   G_TYPE_FROM_CLASS (klass),
95                   G_SIGNAL_RUN_LAST,
96                   G_STRUCT_OFFSET (GimpColorPanelClass, response),
97                   NULL, NULL,
98                   gimp_marshal_VOID__ENUM,
99                   G_TYPE_NONE, 1,
100                   GIMP_TYPE_COLOR_DIALOG_STATE);
101 }
102 
103 static void
gimp_color_panel_init(GimpColorPanel * panel)104 gimp_color_panel_init (GimpColorPanel *panel)
105 {
106   panel->context      = NULL;
107   panel->color_dialog = NULL;
108 }
109 
110 static void
gimp_color_panel_dispose(GObject * object)111 gimp_color_panel_dispose (GObject *object)
112 {
113   GimpColorPanel *panel = GIMP_COLOR_PANEL (object);
114 
115   if (panel->color_dialog)
116     {
117       gtk_widget_destroy (panel->color_dialog);
118       panel->color_dialog = NULL;
119     }
120 
121   G_OBJECT_CLASS (parent_class)->dispose (object);
122 }
123 
124 static gboolean
gimp_color_panel_button_press(GtkWidget * widget,GdkEventButton * bevent)125 gimp_color_panel_button_press (GtkWidget      *widget,
126                                GdkEventButton *bevent)
127 {
128   if (gdk_event_triggers_context_menu ((GdkEvent *) bevent))
129     {
130       GimpColorButton *color_button;
131       GimpColorPanel  *color_panel;
132       GtkUIManager    *ui_manager;
133       GimpActionGroup *group;
134       GimpAction      *action;
135       GimpRGB          color;
136 
137       color_button = GIMP_COLOR_BUTTON (widget);
138       color_panel  = GIMP_COLOR_PANEL (widget);
139       ui_manager   = gimp_color_button_get_ui_manager (color_button);
140 
141       group = gtk_ui_manager_get_action_groups (ui_manager)->data;
142 
143       action = gimp_action_group_get_action (group,
144                                              "color-button-use-foreground");
145       gimp_action_set_visible (action, color_panel->context != NULL);
146 
147       action = gimp_action_group_get_action (group,
148                                              "color-button-use-background");
149       gimp_action_set_visible (action, color_panel->context != NULL);
150 
151       if (color_panel->context)
152         {
153           action = gimp_action_group_get_action (group,
154                                                  "color-button-use-foreground");
155           gimp_context_get_foreground (color_panel->context, &color);
156           g_object_set (action, "color", &color, NULL);
157 
158           action = gimp_action_group_get_action (group,
159                                                  "color-button-use-background");
160           gimp_context_get_background (color_panel->context, &color);
161           g_object_set (action, "color", &color, NULL);
162         }
163 
164       action = gimp_action_group_get_action (group, "color-button-use-black");
165       gimp_rgba_set (&color, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE);
166       g_object_set (action, "color", &color, NULL);
167 
168       action = gimp_action_group_get_action (group, "color-button-use-white");
169       gimp_rgba_set (&color, 1.0, 1.0, 1.0, GIMP_OPACITY_OPAQUE);
170       g_object_set (action, "color", &color, NULL);
171     }
172 
173   if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
174     return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, bevent);
175 
176   return FALSE;
177 }
178 
179 static void
gimp_color_panel_clicked(GtkButton * button)180 gimp_color_panel_clicked (GtkButton *button)
181 {
182   GimpColorPanel *panel = GIMP_COLOR_PANEL (button);
183   GimpRGB         color;
184 
185   gimp_color_button_get_color (GIMP_COLOR_BUTTON (button), &color);
186 
187   if (! panel->color_dialog)
188     {
189       GimpColorButton *color_button = GIMP_COLOR_BUTTON (button);
190 
191       panel->color_dialog =
192         gimp_color_dialog_new (NULL, panel->context,
193                                gimp_color_button_get_title (color_button),
194                                NULL, NULL,
195                                GTK_WIDGET (button),
196                                NULL, NULL,
197                                &color,
198                                gimp_color_button_get_update (color_button),
199                                gimp_color_button_has_alpha (color_button));
200 
201       g_signal_connect (panel->color_dialog, "destroy",
202                         G_CALLBACK (gtk_widget_destroyed),
203                         &panel->color_dialog);
204 
205       g_signal_connect (panel->color_dialog, "update",
206                         G_CALLBACK (gimp_color_panel_dialog_update),
207                         panel);
208     }
209   else
210     {
211       gimp_color_dialog_set_color (GIMP_COLOR_DIALOG (panel->color_dialog),
212                                    &color);
213     }
214 
215   gtk_window_present (GTK_WINDOW (panel->color_dialog));
216 }
217 
218 static GType
gimp_color_panel_get_action_type(GimpColorButton * button)219 gimp_color_panel_get_action_type (GimpColorButton *button)
220 {
221   return GIMP_TYPE_ACTION_IMPL;
222 }
223 
224 
225 /*  public functions  */
226 
227 GtkWidget *
gimp_color_panel_new(const gchar * title,const GimpRGB * color,GimpColorAreaType type,gint width,gint height)228 gimp_color_panel_new (const gchar       *title,
229                       const GimpRGB     *color,
230                       GimpColorAreaType  type,
231                       gint               width,
232                       gint               height)
233 {
234   g_return_val_if_fail (title != NULL, NULL);
235   g_return_val_if_fail (color != NULL, NULL);
236   g_return_val_if_fail (width > 0, NULL);
237   g_return_val_if_fail (height > 0, NULL);
238 
239   return g_object_new (GIMP_TYPE_COLOR_PANEL,
240                        "title",       title,
241                        "type",        type,
242                        "color",       color,
243                        "area-width",  width,
244                        "area-height", height,
245                        NULL);
246 }
247 
248 static void
gimp_color_panel_color_changed(GimpColorButton * button)249 gimp_color_panel_color_changed (GimpColorButton *button)
250 {
251   GimpColorPanel *panel = GIMP_COLOR_PANEL (button);
252   GimpRGB         color;
253 
254   if (panel->color_dialog)
255     {
256       GimpRGB dialog_color;
257 
258       gimp_color_button_get_color (GIMP_COLOR_BUTTON (button), &color);
259       gimp_color_dialog_get_color (GIMP_COLOR_DIALOG (panel->color_dialog),
260                                    &dialog_color);
261 
262       if (gimp_rgba_distance (&color, &dialog_color) > RGBA_EPSILON ||
263           color.a != dialog_color.a)
264         {
265           gimp_color_dialog_set_color (GIMP_COLOR_DIALOG (panel->color_dialog),
266                                        &color);
267         }
268     }
269 }
270 
271 void
gimp_color_panel_set_context(GimpColorPanel * panel,GimpContext * context)272 gimp_color_panel_set_context (GimpColorPanel *panel,
273                               GimpContext    *context)
274 {
275   g_return_if_fail (GIMP_IS_COLOR_PANEL (panel));
276   g_return_if_fail (context == NULL || GIMP_IS_CONTEXT (context));
277 
278   panel->context = context;
279 
280   if (context)
281     gimp_color_button_set_color_config (GIMP_COLOR_BUTTON (panel),
282                                         context->gimp->config->color_management);
283 }
284 
285 void
gimp_color_panel_dialog_response(GimpColorPanel * panel,GimpColorDialogState state)286 gimp_color_panel_dialog_response (GimpColorPanel       *panel,
287                                   GimpColorDialogState  state)
288 {
289   g_return_if_fail (GIMP_IS_COLOR_PANEL (panel));
290   g_return_if_fail (state == GIMP_COLOR_DIALOG_OK ||
291                     state == GIMP_COLOR_DIALOG_CANCEL);
292 
293   if (panel->color_dialog && gtk_widget_get_visible (panel->color_dialog))
294     gimp_color_panel_dialog_update (NULL, NULL, state, panel);
295 }
296 
297 
298 /*  private functions  */
299 
300 static void
gimp_color_panel_dialog_update(GimpColorDialog * dialog,const GimpRGB * color,GimpColorDialogState state,GimpColorPanel * panel)301 gimp_color_panel_dialog_update (GimpColorDialog      *dialog,
302                                 const GimpRGB        *color,
303                                 GimpColorDialogState  state,
304                                 GimpColorPanel       *panel)
305 {
306   switch (state)
307     {
308     case GIMP_COLOR_DIALOG_UPDATE:
309       if (gimp_color_button_get_update (GIMP_COLOR_BUTTON (panel)))
310         gimp_color_button_set_color (GIMP_COLOR_BUTTON (panel), color);
311       break;
312 
313     case GIMP_COLOR_DIALOG_OK:
314       if (! gimp_color_button_get_update (GIMP_COLOR_BUTTON (panel)))
315         gimp_color_button_set_color (GIMP_COLOR_BUTTON (panel), color);
316       gtk_widget_hide (panel->color_dialog);
317 
318       g_signal_emit (panel, color_panel_signals[RESPONSE], 0,
319                      state);
320       break;
321 
322     case GIMP_COLOR_DIALOG_CANCEL:
323       if (gimp_color_button_get_update (GIMP_COLOR_BUTTON (panel)))
324         gimp_color_button_set_color (GIMP_COLOR_BUTTON (panel), color);
325       gtk_widget_hide (panel->color_dialog);
326 
327       g_signal_emit (panel, color_panel_signals[RESPONSE], 0,
328                      state);
329       break;
330     }
331 }
332