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 "libgimpmath/gimpmath.h"
25 #include "libgimpwidgets/gimpwidgets.h"
26 
27 #include "widgets-types.h"
28 
29 #include "core/gimp.h"
30 #include "core/gimpcontext.h"
31 #include "core/gimpcontainer.h"
32 #include "core/gimpimage.h"
33 #include "core/gimpimage-colormap.h"
34 #include "core/gimpmarshal.h"
35 #include "core/gimppalette.h"
36 #include "core/gimpprojection.h"
37 
38 #include "gimpcolordialog.h"
39 #include "gimpcolormapeditor.h"
40 #include "gimpdialogfactory.h"
41 #include "gimpdnd.h"
42 #include "gimpdocked.h"
43 #include "gimpmenufactory.h"
44 #include "gimppaletteview.h"
45 #include "gimpuimanager.h"
46 #include "gimpviewrendererpalette.h"
47 #include "gimpwidgets-utils.h"
48 
49 #include "gimp-intl.h"
50 
51 
52 #define BORDER      6
53 #define RGB_EPSILON 1e-6
54 
55 #define HAVE_COLORMAP(image) \
56         (image != NULL && \
57          gimp_image_get_base_type (image) == GIMP_INDEXED && \
58          gimp_image_get_colormap (image) != NULL)
59 
60 
61 static void gimp_colormap_editor_docked_iface_init (GimpDockedInterface *face);
62 
63 static void   gimp_colormap_editor_constructed     (GObject            *object);
64 static void   gimp_colormap_editor_dispose         (GObject            *object);
65 static void   gimp_colormap_editor_finalize        (GObject            *object);
66 
67 static void   gimp_colormap_editor_unmap           (GtkWidget          *widget);
68 
69 static void   gimp_colormap_editor_set_image       (GimpImageEditor    *editor,
70                                                     GimpImage          *image);
71 
72 static void   gimp_colormap_editor_set_context     (GimpDocked        *docked,
73                                                     GimpContext       *context);
74 
75 static PangoLayout *
76               gimp_colormap_editor_create_layout   (GtkWidget          *widget);
77 
78 static void   gimp_colormap_editor_update_entries  (GimpColormapEditor *editor);
79 
80 static gboolean gimp_colormap_preview_expose       (GtkWidget          *widget,
81                                                     GdkEventExpose     *event,
82                                                     GimpColormapEditor *editor);
83 
84 static void   gimp_colormap_editor_entry_clicked   (GimpPaletteView    *view,
85                                                     GimpPaletteEntry   *entry,
86                                                     GdkModifierType    state,
87                                                     GimpColormapEditor *editor);
88 static void   gimp_colormap_editor_entry_selected  (GimpPaletteView    *view,
89                                                     GimpPaletteEntry   *entry,
90                                                     GimpColormapEditor *editor);
91 static void   gimp_colormap_editor_entry_activated (GimpPaletteView    *view,
92                                                     GimpPaletteEntry   *entry,
93                                                     GimpColormapEditor *editor);
94 static void   gimp_colormap_editor_entry_context   (GimpPaletteView    *view,
95                                                     GimpPaletteEntry   *entry,
96                                                     GimpColormapEditor *editor);
97 static void   gimp_colormap_editor_color_dropped   (GimpPaletteView    *view,
98                                                     GimpPaletteEntry   *entry,
99                                                     const GimpRGB      *color,
100                                                     GimpColormapEditor *editor);
101 
102 static void   gimp_colormap_adjustment_changed     (GtkAdjustment      *adjustment,
103                                                     GimpColormapEditor *editor);
104 static void   gimp_colormap_hex_entry_changed      (GimpColorHexEntry  *entry,
105                                                     GimpColormapEditor *editor);
106 
107 static void   gimp_colormap_image_mode_changed     (GimpImage          *image,
108                                                     GimpColormapEditor *editor);
109 static void   gimp_colormap_image_colormap_changed (GimpImage          *image,
110                                                     gint                ncol,
111                                                     GimpColormapEditor *editor);
112 
113 static void   gimp_colormap_editor_edit_color_update
114                                                     (GimpColorDialog    *dialog,
115                                                      const GimpRGB      *color,
116                                                      GimpColorDialogState state,
117                                                      GimpColormapEditor *editor);
118 
119 
120 G_DEFINE_TYPE_WITH_CODE (GimpColormapEditor, gimp_colormap_editor,
121                          GIMP_TYPE_IMAGE_EDITOR,
122                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
123                                                 gimp_colormap_editor_docked_iface_init))
124 
125 #define parent_class gimp_colormap_editor_parent_class
126 
127 static GimpDockedInterface *parent_docked_iface = NULL;
128 
129 
130 static void
gimp_colormap_editor_class_init(GimpColormapEditorClass * klass)131 gimp_colormap_editor_class_init (GimpColormapEditorClass* klass)
132 {
133   GObjectClass         *object_class       = G_OBJECT_CLASS (klass);
134   GtkWidgetClass       *widget_class       = GTK_WIDGET_CLASS (klass);
135   GimpImageEditorClass *image_editor_class = GIMP_IMAGE_EDITOR_CLASS (klass);
136 
137   object_class->constructed     = gimp_colormap_editor_constructed;
138   object_class->dispose         = gimp_colormap_editor_dispose;
139   object_class->finalize        = gimp_colormap_editor_finalize;
140 
141   widget_class->unmap           = gimp_colormap_editor_unmap;
142 
143   image_editor_class->set_image = gimp_colormap_editor_set_image;
144 }
145 
146 static void
gimp_colormap_editor_docked_iface_init(GimpDockedInterface * iface)147 gimp_colormap_editor_docked_iface_init (GimpDockedInterface *iface)
148 {
149   parent_docked_iface = g_type_interface_peek_parent (iface);
150 
151   if (! parent_docked_iface)
152     parent_docked_iface = g_type_default_interface_peek (GIMP_TYPE_DOCKED);
153 
154   iface->set_context = gimp_colormap_editor_set_context;
155 }
156 
157 static void
gimp_colormap_editor_init(GimpColormapEditor * editor)158 gimp_colormap_editor_init (GimpColormapEditor *editor)
159 {
160   GtkWidget *frame;
161   GtkWidget *table;
162 
163   frame = gtk_frame_new (NULL);
164   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
165   gtk_box_pack_start (GTK_BOX (editor), frame, TRUE, TRUE, 0);
166   gtk_widget_show (frame);
167 
168   editor->view = gimp_view_new_full_by_types (NULL,
169                                               GIMP_TYPE_PALETTE_VIEW,
170                                               GIMP_TYPE_PALETTE,
171                                               1, 1, 0,
172                                               FALSE, TRUE, FALSE);
173   gimp_view_set_expand (GIMP_VIEW (editor->view), TRUE);
174   gtk_container_add (GTK_CONTAINER (frame), editor->view);
175   gtk_widget_show (editor->view);
176 
177   g_signal_connect (editor->view, "expose-event",
178                     G_CALLBACK (gimp_colormap_preview_expose),
179                     editor);
180 
181   g_signal_connect (editor->view, "entry-clicked",
182                     G_CALLBACK (gimp_colormap_editor_entry_clicked),
183                     editor);
184   g_signal_connect (editor->view, "entry-selected",
185                     G_CALLBACK (gimp_colormap_editor_entry_selected),
186                     editor);
187   g_signal_connect (editor->view, "entry-activated",
188                     G_CALLBACK (gimp_colormap_editor_entry_activated),
189                     editor);
190   g_signal_connect (editor->view, "entry-context",
191                     G_CALLBACK (gimp_colormap_editor_entry_context),
192                     editor);
193   g_signal_connect (editor->view, "color-dropped",
194                     G_CALLBACK (gimp_colormap_editor_color_dropped),
195                     editor);
196 
197   /*  Some helpful hints  */
198   table = gtk_table_new (2, 2, FALSE);
199   gtk_table_set_col_spacing (GTK_TABLE (table), 0, 4);
200   gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
201   gtk_box_pack_end (GTK_BOX (editor), table, FALSE, FALSE, 0);
202   gtk_widget_show (table);
203 
204   editor->index_adjustment = (GtkAdjustment *)
205     gtk_adjustment_new (0, 0, 0, 1, 10, 0);
206   editor->index_spinbutton = gimp_spin_button_new (editor->index_adjustment,
207                                                    1.0, 0);
208   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (editor->index_spinbutton),
209                                TRUE);
210 
211   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
212                              _("Color index:"), 0.0, 0.5,
213                              editor->index_spinbutton, 1, TRUE);
214 
215   g_signal_connect (editor->index_adjustment, "value-changed",
216                     G_CALLBACK (gimp_colormap_adjustment_changed),
217                     editor);
218 
219   editor->color_entry = gimp_color_hex_entry_new ();
220   gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
221                              _("HTML notation:"), 0.0, 0.5,
222                              editor->color_entry, 1, TRUE);
223 
224   g_signal_connect (editor->color_entry, "color-changed",
225                     G_CALLBACK (gimp_colormap_hex_entry_changed),
226                     editor);
227 }
228 
229 static void
gimp_colormap_editor_constructed(GObject * object)230 gimp_colormap_editor_constructed (GObject *object)
231 {
232   GimpColormapEditor *editor = GIMP_COLORMAP_EDITOR (object);
233   GdkModifierType     extend_mask;
234   GdkModifierType     modify_mask;
235 
236   G_OBJECT_CLASS (parent_class)->constructed (object);
237 
238   extend_mask = gtk_widget_get_modifier_mask (GTK_WIDGET (object),
239                                               GDK_MODIFIER_INTENT_EXTEND_SELECTION);
240   modify_mask = gtk_widget_get_modifier_mask (GTK_WIDGET (object),
241                                               GDK_MODIFIER_INTENT_MODIFY_SELECTION);
242 
243   gimp_editor_add_action_button (GIMP_EDITOR (editor), "colormap",
244                                  "colormap-edit-color",
245                                  NULL);
246 
247   gimp_editor_add_action_button (GIMP_EDITOR (editor), "colormap",
248                                  "colormap-add-color-from-fg",
249                                  "colormap-add-color-from-bg",
250                                  gimp_get_toggle_behavior_mask (),
251                                  NULL);
252 
253   gimp_editor_add_action_button (GIMP_EDITOR (editor), "colormap",
254                                  "colormap-selection-replace",
255                                  "colormap-selection-add",
256                                  extend_mask,
257                                  "colormap-selection-subtract",
258                                  modify_mask,
259                                  "colormap-selection-intersect",
260                                  extend_mask | modify_mask,
261                                  NULL);
262 }
263 
264 static void
gimp_colormap_editor_dispose(GObject * object)265 gimp_colormap_editor_dispose (GObject *object)
266 {
267   GimpColormapEditor *editor = GIMP_COLORMAP_EDITOR (object);
268 
269   g_clear_pointer (&editor->color_dialog, gtk_widget_destroy);
270 
271   G_OBJECT_CLASS (parent_class)->dispose (object);
272 }
273 
274 static void
gimp_colormap_editor_finalize(GObject * object)275 gimp_colormap_editor_finalize (GObject *object)
276 {
277   GimpColormapEditor *editor = GIMP_COLORMAP_EDITOR (object);
278 
279   g_clear_object (&editor->layout);
280 
281   G_OBJECT_CLASS (parent_class)->finalize (object);
282 }
283 
284 static void
gimp_colormap_editor_unmap(GtkWidget * widget)285 gimp_colormap_editor_unmap (GtkWidget *widget)
286 {
287   GimpColormapEditor *editor = GIMP_COLORMAP_EDITOR (widget);
288 
289   if (editor->color_dialog)
290     gtk_widget_hide (editor->color_dialog);
291 
292   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
293 }
294 
295 static void
gimp_colormap_editor_set_image(GimpImageEditor * image_editor,GimpImage * image)296 gimp_colormap_editor_set_image (GimpImageEditor *image_editor,
297                                 GimpImage       *image)
298 {
299   GimpColormapEditor *editor = GIMP_COLORMAP_EDITOR (image_editor);
300 
301   if (image_editor->image)
302     {
303       g_signal_handlers_disconnect_by_func (image_editor->image,
304                                             gimp_colormap_image_mode_changed,
305                                             editor);
306       g_signal_handlers_disconnect_by_func (image_editor->image,
307                                             gimp_colormap_image_colormap_changed,
308                                             editor);
309 
310       if (editor->color_dialog)
311         gtk_widget_hide (editor->color_dialog);
312 
313       if (! HAVE_COLORMAP (image))
314         {
315           gtk_adjustment_set_upper (editor->index_adjustment, 0);
316 
317           if (gtk_widget_get_mapped (GTK_WIDGET (editor)))
318             gimp_view_set_viewable (GIMP_VIEW (editor->view), NULL);
319         }
320     }
321 
322   GIMP_IMAGE_EDITOR_CLASS (parent_class)->set_image (image_editor, image);
323 
324   editor->col_index = 0;
325 
326   if (image)
327     {
328       g_signal_connect (image, "mode-changed",
329                         G_CALLBACK (gimp_colormap_image_mode_changed),
330                         editor);
331       g_signal_connect (image, "colormap-changed",
332                         G_CALLBACK (gimp_colormap_image_colormap_changed),
333                         editor);
334 
335       if (HAVE_COLORMAP (image))
336         {
337           gimp_view_set_viewable (GIMP_VIEW (editor->view),
338                                   GIMP_VIEWABLE (gimp_image_get_colormap_palette (image)));
339 
340           gtk_adjustment_set_upper (editor->index_adjustment,
341                                     gimp_image_get_colormap_size (image) - 1);
342         }
343     }
344 
345   gimp_colormap_editor_update_entries (editor);
346 }
347 
348 static void
gimp_colormap_editor_set_context(GimpDocked * docked,GimpContext * context)349 gimp_colormap_editor_set_context (GimpDocked  *docked,
350                                   GimpContext *context)
351 {
352   GimpColormapEditor *editor = GIMP_COLORMAP_EDITOR (docked);
353 
354   parent_docked_iface->set_context (docked, context);
355 
356   gimp_view_renderer_set_context (GIMP_VIEW (editor->view)->renderer,
357                                   context);
358 }
359 
360 
361 /*  public functions  */
362 
363 GtkWidget *
gimp_colormap_editor_new(GimpMenuFactory * menu_factory)364 gimp_colormap_editor_new (GimpMenuFactory *menu_factory)
365 {
366   g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
367 
368   return g_object_new (GIMP_TYPE_COLORMAP_EDITOR,
369                        "menu-factory",    menu_factory,
370                        "menu-identifier", "<Colormap>",
371                        "ui-path",         "/colormap-popup",
372                        NULL);
373 }
374 
375 void
gimp_colormap_editor_edit_color(GimpColormapEditor * editor)376 gimp_colormap_editor_edit_color (GimpColormapEditor *editor)
377 {
378   GimpImage    *image;
379   const guchar *colormap;
380   GimpRGB       color;
381   gchar        *desc;
382   gint         index;
383 
384   g_return_if_fail (GIMP_IS_COLORMAP_EDITOR (editor));
385 
386   image = GIMP_IMAGE_EDITOR (editor)->image;
387 
388   if (! HAVE_COLORMAP (image))
389     return;
390 
391   index = editor->col_index;
392 
393   colormap = gimp_image_get_colormap (image);
394 
395   gimp_rgba_set_uchar (&color,
396                        colormap[index * 3],
397                        colormap[index * 3 + 1],
398                        colormap[index * 3 + 2],
399                        255);
400 
401   desc = g_strdup_printf (_("Edit colormap entry #%d"), index);
402 
403   if (! editor->color_dialog)
404     {
405       editor->color_dialog =
406         gimp_color_dialog_new (GIMP_VIEWABLE (image),
407                                GIMP_IMAGE_EDITOR (editor)->context,
408                                _("Edit Colormap Entry"),
409                                GIMP_ICON_COLORMAP,
410                                desc,
411                                GTK_WIDGET (editor),
412                                gimp_dialog_factory_get_singleton (),
413                                "gimp-colormap-editor-color-dialog",
414                                (const GimpRGB *) &color,
415                                TRUE, FALSE);
416 
417       g_signal_connect (editor->color_dialog, "destroy",
418                         G_CALLBACK (gtk_widget_destroyed),
419                         &editor->color_dialog);
420 
421       g_signal_connect (editor->color_dialog, "update",
422                         G_CALLBACK (gimp_colormap_editor_edit_color_update),
423                         editor);
424     }
425   else
426     {
427       gimp_viewable_dialog_set_viewable (GIMP_VIEWABLE_DIALOG (editor->color_dialog),
428                                          GIMP_VIEWABLE (image),
429                                          GIMP_IMAGE_EDITOR (editor)->context);
430       g_object_set (editor->color_dialog, "description", desc, NULL);
431       gimp_color_dialog_set_color (GIMP_COLOR_DIALOG (editor->color_dialog),
432                                    &color);
433 
434       if (! gtk_widget_get_visible (editor->color_dialog))
435         gimp_dialog_factory_position_dialog (gimp_dialog_factory_get_singleton (),
436                                              "gimp-colormap-editor-color-dialog",
437                                              editor->color_dialog,
438                                              gtk_widget_get_screen (GTK_WIDGET (editor)),
439                                              gimp_widget_get_monitor (GTK_WIDGET (editor)));
440     }
441 
442   g_free (desc);
443 
444   gtk_window_present (GTK_WINDOW (editor->color_dialog));
445 }
446 
447 gint
gimp_colormap_editor_get_index(GimpColormapEditor * editor,const GimpRGB * search)448 gimp_colormap_editor_get_index (GimpColormapEditor *editor,
449                                 const GimpRGB      *search)
450 {
451   GimpImage *image;
452   gint       index;
453 
454   g_return_val_if_fail (GIMP_IS_COLORMAP_EDITOR (editor), 0);
455 
456   image = GIMP_IMAGE_EDITOR (editor)->image;
457 
458   if (! HAVE_COLORMAP (image))
459     return -1;
460 
461   index = editor->col_index;
462 
463   if (search)
464     {
465       GimpRGB temp;
466 
467       gimp_image_get_colormap_entry (image, index, &temp);
468 
469       if (gimp_rgb_distance (&temp, search) > RGB_EPSILON)
470         {
471           gint n_colors = gimp_image_get_colormap_size (image);
472           gint i;
473 
474           for (i = 0; i < n_colors; i++)
475             {
476               gimp_image_get_colormap_entry (image, i, &temp);
477 
478               if (gimp_rgb_distance (&temp, search) < RGB_EPSILON)
479                 {
480                   index = i;
481                   break;
482                 }
483             }
484         }
485     }
486 
487   return index;
488 }
489 
490 gboolean
gimp_colormap_editor_set_index(GimpColormapEditor * editor,gint index,GimpRGB * color)491 gimp_colormap_editor_set_index (GimpColormapEditor *editor,
492                                 gint                index,
493                                 GimpRGB            *color)
494 {
495   GimpImage *image;
496   gint       size;
497 
498   g_return_val_if_fail (GIMP_IS_COLORMAP_EDITOR (editor), FALSE);
499 
500   image = GIMP_IMAGE_EDITOR (editor)->image;
501 
502   if (! HAVE_COLORMAP (image))
503     return FALSE;
504 
505   size = gimp_image_get_colormap_size (image);
506 
507   if (size < 1)
508     return FALSE;
509 
510   index = CLAMP (index, 0, size - 1);
511 
512   if (index != editor->col_index)
513     {
514       GimpPalette *palette = gimp_image_get_colormap_palette (image);
515 
516       editor->col_index = index;
517 
518       gimp_palette_view_select_entry (GIMP_PALETTE_VIEW (editor->view),
519                                       gimp_palette_get_entry (palette, index));
520 
521       gimp_colormap_editor_update_entries (editor);
522     }
523 
524   if (color)
525     gimp_image_get_colormap_entry (GIMP_IMAGE_EDITOR (editor)->image,
526                                    index, color);
527 
528   return TRUE;
529 }
530 
531 gint
gimp_colormap_editor_max_index(GimpColormapEditor * editor)532 gimp_colormap_editor_max_index (GimpColormapEditor *editor)
533 {
534   GimpImage *image;
535 
536   g_return_val_if_fail (GIMP_IS_COLORMAP_EDITOR (editor), -1);
537 
538   image = GIMP_IMAGE_EDITOR (editor)->image;
539 
540   if (! HAVE_COLORMAP (image))
541     return -1;
542 
543   return MAX (0, gimp_image_get_colormap_size (image) - 1);
544 }
545 
546 
547 /*  private functions  */
548 
549 static PangoLayout *
gimp_colormap_editor_create_layout(GtkWidget * widget)550 gimp_colormap_editor_create_layout (GtkWidget *widget)
551 {
552   PangoLayout    *layout;
553   PangoAttrList  *attrs;
554   PangoAttribute *attr;
555 
556   layout = gtk_widget_create_pango_layout (widget,
557                                            _("Only indexed images have "
558                                              "a colormap."));
559 
560   pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
561 
562   attrs = pango_attr_list_new ();
563 
564   attr = pango_attr_style_new (PANGO_STYLE_ITALIC);
565   attr->start_index = 0;
566   attr->end_index   = -1;
567   pango_attr_list_insert (attrs, attr);
568 
569   pango_layout_set_attributes (layout, attrs);
570   pango_attr_list_unref (attrs);
571 
572   return layout;
573 }
574 
575 static gboolean
gimp_colormap_preview_expose(GtkWidget * widget,GdkEventExpose * event,GimpColormapEditor * editor)576 gimp_colormap_preview_expose (GtkWidget          *widget,
577                               GdkEventExpose     *event,
578                               GimpColormapEditor *editor)
579 {
580   GimpImageEditor *image_editor = GIMP_IMAGE_EDITOR (editor);
581   GtkStyle        *style;
582   cairo_t         *cr;
583   GtkAllocation    allocation;
584   gint             width, height;
585   gint             y;
586 
587   if (image_editor->image == NULL ||
588       gimp_image_get_base_type (image_editor->image) == GIMP_INDEXED)
589     return FALSE;
590 
591   cr = gdk_cairo_create (event->window);
592   gdk_cairo_region (cr, event->region);
593   cairo_clip (cr);
594 
595   style = gtk_widget_get_style (widget);
596   gdk_cairo_set_source_color (cr, &style->fg[gtk_widget_get_state (widget)]);
597 
598   gtk_widget_get_allocation (widget, &allocation);
599 
600   if (! gtk_widget_get_has_window (widget))
601     cairo_translate (cr, allocation.x, allocation.y);
602 
603   if (! editor->layout)
604     editor->layout = gimp_colormap_editor_create_layout (editor->view);
605 
606   pango_layout_set_width (editor->layout,
607                           PANGO_SCALE * (allocation.width - 2 * BORDER));
608 
609   pango_layout_get_pixel_size (editor->layout, &width, &height);
610 
611   y = (allocation.height - height) / 2;
612 
613   cairo_move_to (cr, BORDER, MAX (y, 0));
614   pango_cairo_show_layout (cr, editor->layout);
615 
616   cairo_destroy (cr);
617 
618   return TRUE;
619 }
620 
621 static void
gimp_colormap_editor_update_entries(GimpColormapEditor * editor)622 gimp_colormap_editor_update_entries (GimpColormapEditor *editor)
623 {
624   GimpImage *image = GIMP_IMAGE_EDITOR (editor)->image;
625 
626   if (! HAVE_COLORMAP (image) ||
627       ! gimp_image_get_colormap_size (image))
628     {
629       gtk_widget_set_sensitive (editor->index_spinbutton, FALSE);
630       gtk_widget_set_sensitive (editor->color_entry, FALSE);
631 
632       gtk_adjustment_set_value (editor->index_adjustment, 0);
633       gtk_entry_set_text (GTK_ENTRY (editor->color_entry), "");
634     }
635   else
636     {
637       const guchar *colormap = gimp_image_get_colormap (image);
638       const guchar *col;
639       gchar        *string;
640 
641       gtk_adjustment_set_value (editor->index_adjustment, editor->col_index);
642 
643       col = colormap + editor->col_index * 3;
644 
645       string = g_strdup_printf ("%02x%02x%02x", col[0], col[1], col[2]);
646       gtk_entry_set_text (GTK_ENTRY (editor->color_entry), string);
647       g_free (string);
648 
649       gtk_widget_set_sensitive (editor->index_spinbutton, TRUE);
650       gtk_widget_set_sensitive (editor->color_entry, TRUE);
651     }
652 }
653 
654 static void
gimp_colormap_editor_entry_clicked(GimpPaletteView * view,GimpPaletteEntry * entry,GdkModifierType state,GimpColormapEditor * editor)655 gimp_colormap_editor_entry_clicked (GimpPaletteView    *view,
656                                     GimpPaletteEntry   *entry,
657                                     GdkModifierType     state,
658                                     GimpColormapEditor *editor)
659 {
660   GimpImageEditor *image_editor = GIMP_IMAGE_EDITOR (editor);
661 
662   gimp_colormap_editor_set_index (editor, entry->position, NULL);
663 
664   if (state & gimp_get_toggle_behavior_mask ())
665     gimp_context_set_background (image_editor->context, &entry->color);
666   else
667     gimp_context_set_foreground (image_editor->context, &entry->color);
668 }
669 
670 static void
gimp_colormap_editor_entry_selected(GimpPaletteView * view,GimpPaletteEntry * entry,GimpColormapEditor * editor)671 gimp_colormap_editor_entry_selected (GimpPaletteView    *view,
672                                      GimpPaletteEntry   *entry,
673                                      GimpColormapEditor *editor)
674 {
675   gint index = entry ? entry->position : 0;
676 
677   gimp_colormap_editor_set_index (editor, index, NULL);
678 }
679 
680 static void
gimp_colormap_editor_entry_activated(GimpPaletteView * view,GimpPaletteEntry * entry,GimpColormapEditor * editor)681 gimp_colormap_editor_entry_activated (GimpPaletteView    *view,
682                                       GimpPaletteEntry   *entry,
683                                       GimpColormapEditor *editor)
684 {
685   gimp_colormap_editor_set_index (editor, entry->position, NULL);
686 
687   gimp_ui_manager_activate_action (gimp_editor_get_ui_manager (GIMP_EDITOR (editor)),
688                                    "colormap",
689                                    "colormap-edit-color");
690 }
691 
692 static void
gimp_colormap_editor_entry_context(GimpPaletteView * view,GimpPaletteEntry * entry,GimpColormapEditor * editor)693 gimp_colormap_editor_entry_context (GimpPaletteView    *view,
694                                     GimpPaletteEntry   *entry,
695                                     GimpColormapEditor *editor)
696 {
697   gimp_colormap_editor_set_index (editor, entry->position, NULL);
698 
699   gimp_editor_popup_menu (GIMP_EDITOR (editor), NULL, NULL);
700 }
701 
702 static void
gimp_colormap_editor_color_dropped(GimpPaletteView * view,GimpPaletteEntry * entry,const GimpRGB * color,GimpColormapEditor * editor)703 gimp_colormap_editor_color_dropped (GimpPaletteView    *view,
704                                     GimpPaletteEntry   *entry,
705                                     const GimpRGB      *color,
706                                     GimpColormapEditor *editor)
707 {
708 }
709 
710 static void
gimp_colormap_adjustment_changed(GtkAdjustment * adjustment,GimpColormapEditor * editor)711 gimp_colormap_adjustment_changed (GtkAdjustment      *adjustment,
712                                   GimpColormapEditor *editor)
713 {
714   GimpImage *image = GIMP_IMAGE_EDITOR (editor)->image;
715 
716   if (HAVE_COLORMAP (image))
717     {
718       gint index = ROUND (gtk_adjustment_get_value (adjustment));
719 
720       gimp_colormap_editor_set_index (editor, index, NULL);
721 
722       gimp_colormap_editor_update_entries (editor);
723     }
724 }
725 
726 static void
gimp_colormap_hex_entry_changed(GimpColorHexEntry * entry,GimpColormapEditor * editor)727 gimp_colormap_hex_entry_changed (GimpColorHexEntry  *entry,
728                                  GimpColormapEditor *editor)
729 {
730   GimpImage *image = GIMP_IMAGE_EDITOR (editor)->image;
731 
732   if (image)
733     {
734       GimpRGB color;
735 
736       gimp_color_hex_entry_get_color (entry, &color);
737 
738       gimp_image_set_colormap_entry (image, editor->col_index, &color, TRUE);
739       gimp_image_flush (image);
740     }
741 }
742 
743 static void
gimp_colormap_image_mode_changed(GimpImage * image,GimpColormapEditor * editor)744 gimp_colormap_image_mode_changed (GimpImage          *image,
745                                   GimpColormapEditor *editor)
746 {
747   if (editor->color_dialog)
748     gtk_widget_hide (editor->color_dialog);
749 
750   gimp_colormap_image_colormap_changed (image, -1, editor);
751 }
752 
753 static void
gimp_colormap_image_colormap_changed(GimpImage * image,gint ncol,GimpColormapEditor * editor)754 gimp_colormap_image_colormap_changed (GimpImage          *image,
755                                       gint                ncol,
756                                       GimpColormapEditor *editor)
757 {
758   if (HAVE_COLORMAP (image))
759     {
760       gimp_view_set_viewable (GIMP_VIEW (editor->view),
761                               GIMP_VIEWABLE (gimp_image_get_colormap_palette (image)));
762 
763       gtk_adjustment_set_upper (editor->index_adjustment,
764                                 gimp_image_get_colormap_size (image) - 1);
765     }
766   else
767     {
768       gimp_view_set_viewable (GIMP_VIEW (editor->view), NULL);
769     }
770 
771   if (ncol == editor->col_index || ncol == -1)
772     gimp_colormap_editor_update_entries (editor);
773 }
774 
775 static void
gimp_colormap_editor_edit_color_update(GimpColorDialog * dialog,const GimpRGB * color,GimpColorDialogState state,GimpColormapEditor * editor)776 gimp_colormap_editor_edit_color_update (GimpColorDialog      *dialog,
777                                         const GimpRGB        *color,
778                                         GimpColorDialogState  state,
779                                         GimpColormapEditor   *editor)
780 {
781   GimpImageEditor *image_editor = GIMP_IMAGE_EDITOR (editor);
782   GimpImage       *image        = image_editor->image;
783   gboolean         push_undo    = FALSE;
784 
785   switch (state)
786     {
787     case GIMP_COLOR_DIALOG_OK:
788       push_undo = TRUE;
789 
790       if (state & gimp_get_toggle_behavior_mask ())
791         gimp_context_set_background (image_editor->context, color);
792       else
793         gimp_context_set_foreground (image_editor->context, color);
794       /* Fall through */
795 
796     case GIMP_COLOR_DIALOG_CANCEL:
797       gtk_widget_hide (editor->color_dialog);
798       break;
799 
800     case GIMP_COLOR_DIALOG_UPDATE:
801       break;
802     }
803 
804   if (image)
805     {
806       if (push_undo)
807         {
808           GimpRGB old_color;
809 
810           gimp_color_selection_get_old_color (
811             GIMP_COLOR_SELECTION (dialog->selection), &old_color);
812 
813           /* Restore old color for undo */
814           gimp_image_set_colormap_entry (image, editor->col_index, &old_color,
815                                          FALSE);
816         }
817 
818       gimp_image_set_colormap_entry (image, editor->col_index, color,
819                                      push_undo);
820 
821       if (push_undo)
822         gimp_image_flush (image);
823       else
824         gimp_projection_flush (gimp_image_get_projection (image));
825     }
826 }
827