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 "libgimpwidgets/gimpwidgets.h"
24 
25 #include "widgets-types.h"
26 
27 #include "config/gimpguiconfig.h"
28 
29 #include "core/gimp.h"
30 #include "core/gimpcontext.h"
31 
32 #include "gimpaction.h"
33 #include "gimpcolordialog.h"
34 #include "gimpdialogfactory.h"
35 #include "gimpfgbgeditor.h"
36 #include "gimpsessioninfo.h"
37 #include "gimptoolbox.h"
38 #include "gimptoolbox-color-area.h"
39 #include "gimpuimanager.h"
40 
41 #include "gimp-intl.h"
42 
43 
44 /*  local function prototypes  */
45 
46 static void   color_area_foreground_changed (GimpContext          *context,
47                                              const GimpRGB        *color,
48                                              GimpColorDialog      *dialog);
49 static void   color_area_background_changed (GimpContext          *context,
50                                              const GimpRGB        *color,
51                                              GimpColorDialog      *dialog);
52 
53 static void   color_area_dialog_update      (GimpColorDialog      *dialog,
54                                              const GimpRGB        *color,
55                                              GimpColorDialogState  state,
56                                              GimpContext          *context);
57 
58 static void   color_area_color_clicked      (GimpFgBgEditor       *editor,
59                                              GimpActiveColor       active_color,
60                                              GimpContext          *context);
61 static void   color_area_tooltip            (GimpFgBgEditor       *editor,
62                                              GimpFgBgTarget        target,
63                                              GtkTooltip           *tooltip,
64                                              GimpToolbox          *toolbox);
65 
66 
67 /*  local variables  */
68 
69 static GtkWidget       *color_area          = NULL;
70 static GtkWidget       *color_dialog        = NULL;
71 static gboolean         color_dialog_active = FALSE;
72 static GimpActiveColor  edit_color          = GIMP_ACTIVE_COLOR_FOREGROUND;
73 static GimpRGB          revert_fg;
74 static GimpRGB          revert_bg;
75 
76 
77 /*  public functions  */
78 
79 GtkWidget *
gimp_toolbox_color_area_create(GimpToolbox * toolbox,gint width,gint height)80 gimp_toolbox_color_area_create (GimpToolbox *toolbox,
81                                 gint         width,
82                                 gint         height)
83 {
84   GimpContext *context;
85 
86   g_return_val_if_fail (GIMP_IS_TOOLBOX (toolbox), NULL);
87 
88   context = gimp_toolbox_get_context (toolbox);
89 
90   color_area = gimp_fg_bg_editor_new (context);
91   gtk_widget_set_size_request (color_area, width, height);
92   gtk_widget_add_events (color_area,
93                          GDK_ENTER_NOTIFY_MASK |
94                          GDK_LEAVE_NOTIFY_MASK);
95 
96   g_object_set (color_area, "has-tooltip", TRUE, NULL);
97 
98   g_signal_connect (color_area, "color-clicked",
99                     G_CALLBACK (color_area_color_clicked),
100                     context);
101 
102   g_signal_connect (color_area, "tooltip",
103                     G_CALLBACK (color_area_tooltip),
104                     toolbox);
105 
106   return color_area;
107 }
108 
109 
110 /*  private functions  */
111 
112 static void
color_area_foreground_changed(GimpContext * context,const GimpRGB * color,GimpColorDialog * dialog)113 color_area_foreground_changed (GimpContext     *context,
114                                const GimpRGB   *color,
115                                GimpColorDialog *dialog)
116 {
117   if (edit_color == GIMP_ACTIVE_COLOR_FOREGROUND)
118     {
119       g_signal_handlers_block_by_func (dialog,
120                                        color_area_dialog_update,
121                                        context);
122 
123       /* FIXME this should use GimpColorDialog API */
124       gimp_color_selection_set_color (GIMP_COLOR_SELECTION (dialog->selection),
125                                       color);
126 
127       g_signal_handlers_unblock_by_func (dialog,
128                                          color_area_dialog_update,
129                                          context);
130     }
131 }
132 
133 static void
color_area_background_changed(GimpContext * context,const GimpRGB * color,GimpColorDialog * dialog)134 color_area_background_changed (GimpContext     *context,
135                                const GimpRGB   *color,
136                                GimpColorDialog *dialog)
137 {
138   if (edit_color == GIMP_ACTIVE_COLOR_BACKGROUND)
139     {
140       g_signal_handlers_block_by_func (dialog,
141                                        color_area_dialog_update,
142                                        context);
143 
144       /* FIXME this should use GimpColorDialog API */
145       gimp_color_selection_set_color (GIMP_COLOR_SELECTION (dialog->selection),
146                                       color);
147 
148       g_signal_handlers_unblock_by_func (dialog,
149                                          color_area_dialog_update,
150                                          context);
151     }
152 }
153 
154 static void
color_area_dialog_update(GimpColorDialog * dialog,const GimpRGB * color,GimpColorDialogState state,GimpContext * context)155 color_area_dialog_update (GimpColorDialog      *dialog,
156                           const GimpRGB        *color,
157                           GimpColorDialogState  state,
158                           GimpContext          *context)
159 {
160   switch (state)
161     {
162     case GIMP_COLOR_DIALOG_OK:
163       gtk_widget_hide (color_dialog);
164       color_dialog_active = FALSE;
165       /* Fallthrough */
166 
167     case GIMP_COLOR_DIALOG_UPDATE:
168       if (edit_color == GIMP_ACTIVE_COLOR_FOREGROUND)
169         {
170           g_signal_handlers_block_by_func (context,
171                                            color_area_foreground_changed,
172                                            dialog);
173 
174           gimp_context_set_foreground (context, color);
175 
176           g_signal_handlers_unblock_by_func (context,
177                                              color_area_foreground_changed,
178                                              dialog);
179         }
180       else
181         {
182           g_signal_handlers_block_by_func (context,
183                                            color_area_background_changed,
184                                            dialog);
185 
186           gimp_context_set_background (context, color);
187 
188           g_signal_handlers_unblock_by_func (context,
189                                              color_area_background_changed,
190                                              dialog);
191         }
192       break;
193 
194     case GIMP_COLOR_DIALOG_CANCEL:
195       gtk_widget_hide (color_dialog);
196       color_dialog_active = FALSE;
197       gimp_context_set_foreground (context, &revert_fg);
198       gimp_context_set_background (context, &revert_bg);
199       break;
200     }
201 }
202 
203 static void
color_area_color_clicked(GimpFgBgEditor * editor,GimpActiveColor active_color,GimpContext * context)204 color_area_color_clicked (GimpFgBgEditor  *editor,
205                           GimpActiveColor  active_color,
206                           GimpContext     *context)
207 {
208   GimpRGB      color;
209   const gchar *title;
210 
211   if (! color_dialog_active)
212     {
213       gimp_context_get_foreground (context, &revert_fg);
214       gimp_context_get_background (context, &revert_bg);
215     }
216 
217   if (active_color == GIMP_ACTIVE_COLOR_FOREGROUND)
218     {
219       gimp_context_get_foreground (context, &color);
220       title = _("Change Foreground Color");
221     }
222   else
223     {
224       gimp_context_get_background (context, &color);
225       title = _("Change Background Color");
226     }
227 
228   edit_color = active_color;
229 
230   if (! color_dialog)
231     {
232       color_dialog = gimp_color_dialog_new (NULL, context,
233                                             NULL, NULL, NULL,
234                                             GTK_WIDGET (editor),
235                                             gimp_dialog_factory_get_singleton (),
236                                             "gimp-toolbox-color-dialog",
237                                             &color,
238                                             TRUE, FALSE);
239 
240       g_signal_connect_object (color_dialog, "update",
241                                G_CALLBACK (color_area_dialog_update),
242                                G_OBJECT (context), 0);
243 
244       g_signal_connect_object (context, "foreground-changed",
245                                G_CALLBACK (color_area_foreground_changed),
246                                G_OBJECT (color_dialog), 0);
247       g_signal_connect_object (context, "background-changed",
248                                G_CALLBACK (color_area_background_changed),
249                                G_OBJECT (color_dialog), 0);
250     }
251   else if (! gtk_widget_get_visible (color_dialog))
252     {
253       gimp_dialog_factory_position_dialog (gimp_dialog_factory_get_singleton (),
254                                            "gimp-toolbox-color-dialog",
255                                            color_dialog,
256                                            gtk_widget_get_screen (GTK_WIDGET (editor)),
257                                            gimp_widget_get_monitor (GTK_WIDGET (editor)));
258     }
259 
260   gtk_window_set_title (GTK_WINDOW (color_dialog), title);
261   gimp_color_dialog_set_color (GIMP_COLOR_DIALOG (color_dialog), &color);
262 
263   gtk_window_present (GTK_WINDOW (color_dialog));
264   color_dialog_active = TRUE;
265 }
266 
267 static gboolean
accel_find_func(GtkAccelKey * key,GClosure * closure,gpointer data)268 accel_find_func (GtkAccelKey *key,
269                  GClosure    *closure,
270                  gpointer     data)
271 {
272   return (GClosure *) data == closure;
273 }
274 
275 static void
color_area_tooltip(GimpFgBgEditor * editor,GimpFgBgTarget target,GtkTooltip * tooltip,GimpToolbox * toolbox)276 color_area_tooltip (GimpFgBgEditor *editor,
277                     GimpFgBgTarget  target,
278                     GtkTooltip     *tooltip,
279                     GimpToolbox    *toolbox)
280 {
281   GimpUIManager *manager = gimp_dock_get_ui_manager (GIMP_DOCK (toolbox));
282   GimpAction    *action  = NULL;
283   const gchar   *text    = NULL;
284 
285   switch (target)
286     {
287     case GIMP_FG_BG_TARGET_FOREGROUND:
288       text = _("The active foreground color.\n"
289                "Click to open the color selection dialog.");
290       break;
291 
292     case GIMP_FG_BG_TARGET_BACKGROUND:
293       text = _("The active background color.\n"
294                "Click to open the color selection dialog.");
295       break;
296 
297     case GIMP_FG_BG_TARGET_SWAP:
298       action = gimp_ui_manager_find_action (manager, "context",
299                                             "context-colors-swap");
300       text = gimp_action_get_tooltip (action);
301       break;
302 
303     case GIMP_FG_BG_TARGET_DEFAULT:
304       action = gimp_ui_manager_find_action (manager, "context",
305                                             "context-colors-default");
306       text = gimp_action_get_tooltip (action);
307       break;
308 
309     default:
310       break;
311     }
312 
313   if (text)
314     {
315       gchar *markup = NULL;
316 
317       if (action)
318         {
319           GtkAccelGroup *accel_group;
320           GClosure      *accel_closure;
321           GtkAccelKey   *accel_key;
322 
323           accel_closure = gimp_action_get_accel_closure (action);
324           accel_group   = gtk_accel_group_from_accel_closure (accel_closure);
325 
326           accel_key = gtk_accel_group_find (accel_group,
327                                             accel_find_func,
328                                             accel_closure);
329 
330           if (accel_key            &&
331               accel_key->accel_key &&
332               (accel_key->accel_flags & GTK_ACCEL_VISIBLE))
333             {
334               gchar *escaped = g_markup_escape_text (text, -1);
335               gchar *accel   = gtk_accelerator_get_label (accel_key->accel_key,
336                                                           accel_key->accel_mods);
337 
338               markup = g_strdup_printf ("%s  <b>%s</b>", escaped, accel);
339 
340               g_free (accel);
341               g_free (escaped);
342             }
343         }
344 
345       if (markup)
346         {
347           gtk_tooltip_set_markup (tooltip, markup);
348           g_free (markup);
349         }
350       else
351         {
352           gtk_tooltip_set_text (tooltip, text);
353         }
354     }
355 }
356