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