[gimp] Issue #2938: Painting on indexed images counter-intuitive.



commit 94043529c87235b5b0edc0f4fe9f667129c4bfa6
Author: Jehan <jehan girinstud io>
Date:   Sat Mar 16 22:08:51 2019 +0100

    Issue #2938: Painting on indexed images counter-intuitive.
    
    When loading indexed images, the image type is not obvious at all
    (basically only reference is in the title bar). The main issue is that
    if you don't realize it when editing, GIMP appear broken when the
    expected colors don't appear on canvas.
    Commit e48c239459 was a first step by showing various color widgets with
    out-of-gamut warnings contextually. This additional commits will also
    allows color selection for painting tools (i.e. foreground and
    background colors) to be done within the image palette by default. This
    way, the fact that this image impose working with limited color palette
    is obvious as soon as you try to edit colors.

 app/actions/view-commands.c          |   1 +
 app/dialogs/dialogs.c                |   1 +
 app/widgets/Makefile.am              |   2 +
 app/widgets/gimpcolordialog.c        | 437 ++++++++++++++++++--
 app/widgets/gimpcolordialog.h        |   7 +
 app/widgets/gimpcolormapeditor.c     |   1 +
 app/widgets/gimpcolormapselection.c  | 758 +++++++++++++++++++++++++++++++++++
 app/widgets/gimpcolormapselection.h  |  81 ++++
 app/widgets/gimpcolorpanel.c         |   2 +-
 app/widgets/gimpgradienteditor.c     |   2 +
 app/widgets/gimppaletteeditor.c      |   1 +
 app/widgets/gimptoolbox-color-area.c |   2 +-
 app/widgets/widgets-types.h          |   1 +
 13 files changed, 1267 insertions(+), 29 deletions(-)
---
diff --git a/app/actions/view-commands.c b/app/actions/view-commands.c
index ccd185a1bd..3d50635584 100644
--- a/app/actions/view-commands.c
+++ b/app/actions/view-commands.c
@@ -1011,6 +1011,7 @@ view_padding_color_cmd_callback (GtkAction *action,
             dialog =
               gimp_color_dialog_new (GIMP_VIEWABLE (image),
                                      action_data_get_context (data),
+                                     FALSE,
                                      _("Set Canvas Padding Color"),
                                      GIMP_ICON_FONT,
                                      _("Set Custom Canvas Padding Color"),
diff --git a/app/dialogs/dialogs.c b/app/dialogs/dialogs.c
index 30ee47362f..259ce15394 100644
--- a/app/dialogs/dialogs.c
+++ b/app/dialogs/dialogs.c
@@ -249,6 +249,7 @@ static const GimpDialogFactoryEntry entries[] =
   FOREIGN ("gimp-gradient-editor-color-dialog",    TRUE,  FALSE),
   FOREIGN ("gimp-palette-editor-color-dialog",     TRUE,  FALSE),
   FOREIGN ("gimp-colormap-editor-color-dialog",    TRUE,  FALSE),
+  FOREIGN ("gimp-colormap-selection-color-dialog", TRUE,  FALSE),
 
   FOREIGN ("gimp-controller-editor-dialog",        FALSE, TRUE),
   FOREIGN ("gimp-controller-action-dialog",        FALSE, TRUE),
diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am
index fff6a2b9a1..6b7767ba89 100644
--- a/app/widgets/Makefile.am
+++ b/app/widgets/Makefile.am
@@ -84,6 +84,8 @@ libappwidgets_a_sources = \
        gimpcolorhistory.h              \
        gimpcolormapeditor.c            \
        gimpcolormapeditor.h            \
+       gimpcolormapselection.c         \
+       gimpcolormapselection.h         \
        gimpcolorpanel.c                \
        gimpcolorpanel.h                \
        gimpcolorselectorpalette.c      \
diff --git a/app/widgets/gimpcolordialog.c b/app/widgets/gimpcolordialog.c
index 01f6c3fda5..efa6b87fed 100644
--- a/app/widgets/gimpcolordialog.c
+++ b/app/widgets/gimpcolordialog.c
@@ -32,11 +32,16 @@
 #include "core/gimp.h"
 #include "core/gimp-palettes.h"
 #include "core/gimpcontext.h"
+#include "core/gimpimage.h"
+#include "core/gimpimage-colormap.h"
 #include "core/gimpmarshal.h"
 #include "core/gimppalettemru.h"
+#include "core/gimpprojection.h"
 
+#include "gimpactiongroup.h"
 #include "gimpcolordialog.h"
 #include "gimpcolorhistory.h"
+#include "gimpcolormapselection.h"
 #include "gimpdialogfactory.h"
 #include "gimphelp-ids.h"
 #include "gimpwidgets-constructors.h"
@@ -55,14 +60,34 @@ enum
   LAST_SIGNAL
 };
 
+enum
+{
+  PROP_0,
+  PROP_CONTEXT_AWARE
+};
 
 static void   gimp_color_dialog_constructed      (GObject            *object);
+static void   gimp_color_dialog_set_property     (GObject            *object,
+                                                  guint               property_id,
+                                                  const GValue       *value,
+                                                  GParamSpec         *pspec);
+static void   gimp_color_dialog_get_property     (GObject            *object,
+                                                  guint               property_id,
+                                                  GValue             *value,
+                                                  GParamSpec         *pspec);
 
 static void   gimp_color_dialog_response         (GtkDialog          *dialog,
                                                   gint                response_id);
 
 static void   gimp_color_dialog_help_func        (const gchar        *help_id,
                                                   gpointer            help_data);
+
+static void   gimp_color_dialog_colormap_clicked (GimpColorDialog    *dialog,
+                                                  GimpPaletteEntry   *entry,
+                                                  GdkModifierType     state);
+static void
+        gimp_color_dialog_colormap_edit_activate (GimpColorDialog    *dialog);
+
 static void   gimp_color_dialog_color_changed    (GimpColorSelection *selection,
                                                   GimpColorDialog    *dialog);
 
@@ -73,6 +98,15 @@ static void   gimp_color_dialog_history_selected (GimpColorHistory   *history,
                                                   const GimpRGB      *rgb,
                                                   GimpColorDialog    *dialog);
 
+static void   gimp_color_dialog_context_notify   (GimpColorDialog    *dialog,
+                                                  const GParamSpec   *pspec);
+static void   gimp_color_dialog_image_changed    (GimpContext        *context,
+                                                  GimpImage          *image,
+                                                  GimpColorDialog    *dialog);
+static void   gimp_color_dialog_update           (GimpColorDialog    *dialog);
+static void   gimp_color_dialog_show             (GimpColorDialog    *dialog);
+static void   gimp_color_dialog_hide             (GimpColorDialog    *dialog);
+
 
 G_DEFINE_TYPE (GimpColorDialog, gimp_color_dialog, GIMP_TYPE_VIEWABLE_DIALOG)
 
@@ -87,9 +121,11 @@ gimp_color_dialog_class_init (GimpColorDialogClass *klass)
   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
   GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
 
-  object_class->constructed = gimp_color_dialog_constructed;
+  object_class->constructed  = gimp_color_dialog_constructed;
+  object_class->set_property = gimp_color_dialog_set_property;
+  object_class->get_property = gimp_color_dialog_get_property;
 
-  dialog_class->response    = gimp_color_dialog_response;
+  dialog_class->response     = gimp_color_dialog_response;
 
   color_dialog_signals[UPDATE] =
     g_signal_new ("update",
@@ -101,24 +137,17 @@ gimp_color_dialog_class_init (GimpColorDialogClass *klass)
                   G_TYPE_NONE, 2,
                   GIMP_TYPE_RGB,
                   GIMP_TYPE_COLOR_DIALOG_STATE);
-}
 
-static void
-gimp_color_dialog_init (GimpColorDialog *dialog)
-{
+  g_object_class_install_property (object_class, PROP_CONTEXT_AWARE,
+                                   g_param_spec_boolean ("context-aware",
+                                                        NULL, NULL, FALSE,
+                                                        GIMP_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY));
 }
 
 static void
-gimp_color_dialog_constructed (GObject *object)
+gimp_color_dialog_init (GimpColorDialog *dialog)
 {
-  GimpColorDialog    *dialog          = GIMP_COLOR_DIALOG (object);
-  GimpViewableDialog *viewable_dialog = GIMP_VIEWABLE_DIALOG (object);
-  GtkWidget          *hbox;
-  GtkWidget          *history;
-  GtkWidget          *button;
-
-  G_OBJECT_CLASS (parent_class)->constructed (object);
-
   gimp_dialog_add_buttons (GIMP_DIALOG (dialog),
 
                            _("_Reset"),  RESPONSE_RESET,
@@ -133,10 +162,111 @@ gimp_color_dialog_constructed (GObject *object)
                                             GTK_RESPONSE_CANCEL,
                                             -1);
 
+  dialog->stack = gtk_notebook_new ();
+  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+                      dialog->stack, TRUE, TRUE, 0);
+  gtk_notebook_set_show_tabs (GTK_NOTEBOOK (dialog->stack), FALSE);
+  gtk_notebook_set_show_border (GTK_NOTEBOOK (dialog->stack), FALSE);
+  gtk_widget_show (dialog->stack);
+}
+
+static void
+gimp_color_dialog_constructed (GObject *object)
+{
+  GimpColorDialog    *dialog          = GIMP_COLOR_DIALOG (object);
+  GimpViewableDialog *viewable_dialog = GIMP_VIEWABLE_DIALOG (object);
+  GtkWidget          *hbox;
+  GtkWidget          *history;
+  GtkWidget          *arrow;
+  GtkWidget          *button;
+  GList              *list;
+
+  G_OBJECT_CLASS (parent_class)->constructed (object);
+
+  /** Tab: colormap selection. **/
+  dialog->colormap_selection = gimp_colormap_selection_new (viewable_dialog->context);
+  gtk_notebook_append_page (GTK_NOTEBOOK (dialog->stack),
+                            dialog->colormap_selection, NULL);
+  g_signal_connect_swapped (dialog->colormap_selection, "color-clicked",
+                            G_CALLBACK (gimp_color_dialog_colormap_clicked),
+                            dialog);
+  g_signal_connect_swapped (dialog->colormap_selection, "color-activated",
+                            G_CALLBACK (gimp_color_dialog_colormap_edit_activate),
+                            dialog);
+  gtk_widget_show (dialog->colormap_selection);
+
+  list = gimp_action_groups_from_name ("colormap");
+  if (list)
+    {
+      GtkWidget       *image;
+      GimpActionGroup *group;
+      GtkAction       *action;
+      const gchar     *icon_name;
+      const gchar     *help_id;
+      gchar           *tooltip;
+
+      group = list->data;
+
+      /* Edit color */
+      action = gtk_action_group_get_action (GTK_ACTION_GROUP (group),
+                                            "colormap-edit-color");
+
+      button = gimp_button_new ();
+      gtk_button_set_relief (GTK_BUTTON (button), FALSE);
+
+      icon_name = gtk_action_get_icon_name (action);
+      image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
+      gtk_container_add (GTK_CONTAINER (button), image);
+      gtk_widget_show (image);
+
+      tooltip = g_strdup (gtk_action_get_tooltip (action));
+      help_id = g_object_get_qdata (G_OBJECT (action), GIMP_HELP_ID);
+      gimp_help_set_help_data_with_markup (button, tooltip, help_id);
+      g_free (tooltip);
+
+      /* Note: I only use the "colormap-edit-color" action for icon, and
+       * tooltip, but don't actually run it because it would create yet
+       * another dialog. Instead we switch the stack view.
+       */
+      g_signal_connect_swapped (button, "clicked",
+                                G_CALLBACK (gimp_color_dialog_colormap_edit_activate),
+                                dialog);
+      gtk_widget_show (button);
+      gtk_box_pack_start (GTK_BOX (GIMP_COLORMAP_SELECTION (dialog->colormap_selection)->right_vbox), button,
+                          FALSE, FALSE, 0);
+
+      /* Add Color */
+      action = gtk_action_group_get_action (GTK_ACTION_GROUP (group),
+                                            "colormap-add-color-from-fg");
+
+      button = gimp_button_new ();
+      gtk_button_set_relief (GTK_BUTTON (button), FALSE);
+
+      icon_name = gtk_action_get_icon_name (action);
+      image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
+      gtk_container_add (GTK_CONTAINER (button), image);
+      gtk_widget_show (image);
+
+      tooltip = g_strdup (gtk_action_get_tooltip (action));
+      help_id = g_object_get_qdata (G_OBJECT (action), GIMP_HELP_ID);
+      gimp_help_set_help_data_with_markup (button, tooltip, help_id);
+      g_free (tooltip);
+
+      gtk_activatable_set_related_action (GTK_ACTIVATABLE (button), action);
+      gtk_widget_show (button);
+      gtk_box_pack_start (GTK_BOX (GIMP_COLORMAP_SELECTION (dialog->colormap_selection)->right_vbox), button,
+                          FALSE, FALSE, 0);
+    }
+  else
+    {
+      g_warning ("%s: 'colormap' action group not found", G_STRFUNC);
+    }
+
+  /** Tab: color selection. **/
   dialog->selection = gimp_color_selection_new ();
   gtk_container_set_border_width (GTK_CONTAINER (dialog->selection), 12);
-  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
-                      dialog->selection, TRUE, TRUE, 0);
+  gtk_notebook_append_page (GTK_NOTEBOOK (dialog->stack),
+                            dialog->selection, NULL);
   gtk_widget_show (dialog->selection);
 
   g_signal_connect (dialog->selection, "color-changed",
@@ -169,14 +299,72 @@ gimp_color_dialog_constructed (GObject *object)
   g_signal_connect (history, "color-selected",
                     G_CALLBACK (gimp_color_dialog_history_selected),
                     dialog);
+
+  g_signal_connect (dialog, "show",
+                    G_CALLBACK (gimp_color_dialog_show),
+                    NULL);
+  g_signal_connect (dialog, "hide",
+                    G_CALLBACK (gimp_color_dialog_hide),
+                    NULL);
+  gimp_color_dialog_show (dialog);
+}
+
+static void
+gimp_color_dialog_set_property (GObject      *object,
+                                guint         property_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  GimpColorDialog *dialog = GIMP_COLOR_DIALOG (object);
+
+  switch (property_id)
+    {
+    case PROP_CONTEXT_AWARE:
+      dialog->context_aware = g_value_get_boolean (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_color_dialog_get_property (GObject    *object,
+                                guint       property_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  GimpColorDialog *dialog = GIMP_COLOR_DIALOG (object);
+
+  switch (property_id)
+    {
+    case PROP_CONTEXT_AWARE:
+      g_value_set_boolean (value, dialog->context_aware);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
 }
 
 static void
 gimp_color_dialog_response (GtkDialog *gtk_dialog,
                             gint       response_id)
 {
-  GimpColorDialog *dialog = GIMP_COLOR_DIALOG (gtk_dialog);
-  GimpRGB          color;
+  GimpColorDialog       *dialog          = GIMP_COLOR_DIALOG (gtk_dialog);
+  GimpViewableDialog    *viewable_dialog = GIMP_VIEWABLE_DIALOG (dialog);
+  GimpImage             *image           = NULL;
+  GimpColormapSelection *colormap_selection;
+  gint                   col_index;
+  GimpRGB                color;
+
+  colormap_selection = GIMP_COLORMAP_SELECTION (dialog->colormap_selection);
+  col_index = gimp_colormap_selection_get_index (colormap_selection, NULL);
+
+  if (dialog->colormap_editing && viewable_dialog->context)
+    image = gimp_context_get_image (viewable_dialog->context);
 
   switch (response_id)
     {
@@ -188,16 +376,53 @@ gimp_color_dialog_response (GtkDialog *gtk_dialog,
       gimp_color_selection_get_color (GIMP_COLOR_SELECTION (dialog->selection),
                                       &color);
 
-      g_signal_emit (dialog, color_dialog_signals[UPDATE], 0,
-                     &color, GIMP_COLOR_DIALOG_OK);
+      if (dialog->colormap_editing && image)
+        {
+          GimpRGB old_color;
+
+          dialog->colormap_editing = FALSE;
+
+          /* Restore old color for undo */
+          gimp_color_selection_get_old_color (GIMP_COLOR_SELECTION (dialog->selection), &old_color);
+          gimp_image_set_colormap_entry (image, col_index, &old_color, FALSE);
+          gimp_image_set_colormap_entry (image, col_index, &color, TRUE);
+          gimp_image_flush (image);
+
+          gtk_notebook_set_current_page (GTK_NOTEBOOK (dialog->stack),
+                                         gtk_notebook_page_num (GTK_NOTEBOOK (dialog->stack),
+                                                                dialog->colormap_selection));
+          g_signal_emit (dialog, color_dialog_signals[UPDATE], 0,
+                         &color, GIMP_COLOR_DIALOG_UPDATE);
+        }
+      else
+        {
+          g_signal_emit (dialog, color_dialog_signals[UPDATE], 0,
+                         &color, GIMP_COLOR_DIALOG_OK);
+        }
       break;
 
     default:
       gimp_color_selection_get_old_color (GIMP_COLOR_SELECTION (dialog->selection),
                                           &color);
 
-      g_signal_emit (dialog, color_dialog_signals[UPDATE], 0,
-                     &color, GIMP_COLOR_DIALOG_CANCEL);
+      if (dialog->colormap_editing && image)
+        {
+          dialog->colormap_editing = FALSE;
+
+          gimp_image_set_colormap_entry (image, col_index, &color, FALSE);
+          gimp_projection_flush (gimp_image_get_projection (image));
+
+          gtk_notebook_set_current_page (GTK_NOTEBOOK (dialog->stack),
+                                         gtk_notebook_page_num (GTK_NOTEBOOK (dialog->stack),
+                                                                dialog->colormap_selection));
+          g_signal_emit (dialog, color_dialog_signals[UPDATE], 0,
+                         &color, GIMP_COLOR_DIALOG_UPDATE);
+        }
+      else
+        {
+          g_signal_emit (dialog, color_dialog_signals[UPDATE], 0,
+                         &color, GIMP_COLOR_DIALOG_CANCEL);
+        }
       break;
     }
 }
@@ -208,6 +433,7 @@ gimp_color_dialog_response (GtkDialog *gtk_dialog,
 GtkWidget *
 gimp_color_dialog_new (GimpViewable      *viewable,
                        GimpContext       *context,
+                       gboolean           context_aware,
                        const gchar       *title,
                        const gchar       *icon_name,
                        const gchar       *desc,
@@ -245,6 +471,7 @@ gimp_color_dialog_new (GimpViewable      *viewable,
                          "icon-name",      icon_name,
                          "description",    desc,
                          "context",        context,
+                         "context-aware",  context_aware,
                          "parent",         gtk_widget_get_toplevel (parent),
                          "use-header-bar", use_header_bar,
                          NULL);
@@ -347,15 +574,83 @@ gimp_color_dialog_help_func (const gchar *help_id,
 }
 
 static void
-gimp_color_dialog_color_changed (GimpColorSelection *selection,
-                                 GimpColorDialog    *dialog)
+gimp_color_dialog_colormap_clicked (GimpColorDialog  *dialog,
+                                    GimpPaletteEntry *entry,
+                                    GdkModifierType   state)
 {
+  gimp_color_dialog_set_color (dialog, &entry->color);
+
   if (dialog->wants_updates)
     {
-      GimpRGB color;
+      g_signal_emit (dialog, color_dialog_signals[UPDATE], 0,
+                     &entry->color, GIMP_COLOR_DIALOG_UPDATE);
+    }
+}
+
+static void
+gimp_color_dialog_colormap_edit_activate (GimpColorDialog *dialog)
+{
+  GimpColormapSelection *colormap_selection;
+  GimpRGB                color;
+  gint                   col_index;
 
-      gimp_color_selection_get_color (selection, &color);
+  dialog->colormap_editing = TRUE;
 
+  colormap_selection = GIMP_COLORMAP_SELECTION (dialog->colormap_selection);
+  col_index = gimp_colormap_selection_get_index (colormap_selection, NULL);
+  gimp_image_get_colormap_entry (dialog->active_image, col_index, &color);
+  gimp_color_dialog_set_color (dialog, &color);
+
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (dialog->stack),
+                                 gtk_notebook_page_num (GTK_NOTEBOOK (dialog->stack),
+                                                        dialog->selection));
+}
+
+static void
+gimp_color_dialog_color_changed (GimpColorSelection *selection,
+                                 GimpColorDialog    *dialog)
+{
+  GimpViewableDialog *viewable_dialog = GIMP_VIEWABLE_DIALOG (dialog);
+  GimpRGB             color;
+
+  gimp_color_selection_get_color (selection, &color);
+
+  if (dialog->colormap_editing && viewable_dialog->context)
+    {
+      GimpImage *image;
+
+      image = gimp_context_get_image (viewable_dialog->context);
+      if (image)
+        {
+          GimpColormapSelection *colormap_selection;
+          gboolean               push_undo = FALSE;
+          gint                   col_index;
+
+          colormap_selection = GIMP_COLORMAP_SELECTION (dialog->colormap_selection);
+          col_index = gimp_colormap_selection_get_index (colormap_selection, NULL);
+          if (push_undo)
+            {
+              GimpRGB old_color;
+
+              gimp_color_selection_get_old_color (GIMP_COLOR_SELECTION (dialog->selection), &old_color);
+
+              /* Restore old color for undo */
+              gimp_image_set_colormap_entry (image, col_index, &old_color,
+                                             FALSE);
+            }
+
+          gimp_image_set_colormap_entry (image, col_index, &color,
+                                         push_undo);
+
+          if (push_undo)
+            gimp_image_flush (image);
+          else
+            gimp_projection_flush (gimp_image_get_projection (image));
+        }
+    }
+
+  if (dialog->wants_updates)
+    {
       g_signal_emit (dialog, color_dialog_signals[UPDATE], 0,
                      &color, GIMP_COLOR_DIALOG_UPDATE);
     }
@@ -390,3 +685,91 @@ gimp_color_dialog_history_selected (GimpColorHistory *history,
   gimp_color_selection_set_color (GIMP_COLOR_SELECTION (dialog->selection),
                                   rgb);
 }
+
+/* Context-related callbacks */
+
+static void
+gimp_color_dialog_context_notify (GimpColorDialog  *dialog,
+                                  const GParamSpec *pspec)
+{
+  GimpViewableDialog *viewable_dialog = GIMP_VIEWABLE_DIALOG (dialog);
+  GimpImage          *image;
+
+  if (viewable_dialog->context)
+    {
+      image = gimp_context_get_image (viewable_dialog->context);
+
+      g_signal_connect (viewable_dialog->context, "image-changed",
+                        G_CALLBACK (gimp_color_dialog_image_changed),
+                        dialog);
+
+      gimp_color_dialog_image_changed (viewable_dialog->context,
+                                       image, dialog);
+    }
+}
+
+static void
+gimp_color_dialog_image_changed (GimpContext     *context,
+                                 GimpImage       *image,
+                                 GimpColorDialog *dialog)
+{
+  if (dialog->active_image != image)
+    {
+      if (dialog->active_image)
+        {
+          g_signal_handlers_disconnect_by_func (dialog->active_image,
+                                                G_CALLBACK (gimp_color_dialog_update),
+                                                dialog);
+        }
+      dialog->active_image = image;
+      if (image)
+        {
+          g_signal_connect_swapped (image, "notify::base-type",
+                                    G_CALLBACK (gimp_color_dialog_update),
+                                    dialog);
+        }
+      gimp_color_dialog_update (dialog);
+    }
+}
+
+static void
+gimp_color_dialog_update (GimpColorDialog *dialog)
+{
+  if (dialog->active_image &&
+      gimp_image_get_base_type (dialog->active_image) == GIMP_INDEXED)
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (dialog->stack),
+                                   gtk_notebook_page_num (GTK_NOTEBOOK (dialog->stack),
+                                                          dialog->colormap_selection));
+  else
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (dialog->stack),
+                                   gtk_notebook_page_num (GTK_NOTEBOOK (dialog->stack),
+                                                          dialog->selection));
+}
+
+static void
+gimp_color_dialog_show (GimpColorDialog *dialog)
+{
+  dialog->colormap_editing = FALSE;
+
+  if (dialog->context_aware)
+    {
+      g_signal_connect (dialog, "notify::context",
+                        G_CALLBACK (gimp_color_dialog_context_notify),
+                        NULL);
+      gimp_color_dialog_update (dialog);
+    }
+  else
+    {
+      gtk_notebook_set_current_page (GTK_NOTEBOOK (dialog->stack),
+                                     gtk_notebook_page_num (GTK_NOTEBOOK (dialog->stack),
+                                                            dialog->selection));
+    }
+}
+
+static void
+gimp_color_dialog_hide (GimpColorDialog *dialog)
+{
+  g_signal_handlers_disconnect_by_func (dialog,
+                                        G_CALLBACK (gimp_color_dialog_context_notify),
+                                        NULL);
+}
diff --git a/app/widgets/gimpcolordialog.h b/app/widgets/gimpcolordialog.h
index a60c010056..8fdb35ad20 100644
--- a/app/widgets/gimpcolordialog.h
+++ b/app/widgets/gimpcolordialog.h
@@ -42,8 +42,14 @@ struct _GimpColorDialog
   GimpViewableDialog   parent_instance;
 
   gboolean             wants_updates;
+  gboolean             context_aware;
 
+  GtkWidget           *stack;
   GtkWidget           *selection;
+  GtkWidget           *colormap_selection;
+
+  GimpImage           *active_image;
+  gboolean             colormap_editing;
 };
 
 struct _GimpColorDialogClass
@@ -60,6 +66,7 @@ GType       gimp_color_dialog_get_type  (void) G_GNUC_CONST;
 
 GtkWidget * gimp_color_dialog_new       (GimpViewable      *viewable,
                                          GimpContext       *context,
+                                         gboolean           context_aware,
                                          const gchar       *title,
                                          const gchar       *icon_name,
                                          const gchar       *desc,
diff --git a/app/widgets/gimpcolormapeditor.c b/app/widgets/gimpcolormapeditor.c
index 85dec288b0..084f4211e3 100644
--- a/app/widgets/gimpcolormapeditor.c
+++ b/app/widgets/gimpcolormapeditor.c
@@ -405,6 +405,7 @@ gimp_colormap_editor_edit_color (GimpColormapEditor *editor)
       editor->color_dialog =
         gimp_color_dialog_new (GIMP_VIEWABLE (image),
                                GIMP_IMAGE_EDITOR (editor)->context,
+                               FALSE,
                                _("Edit Colormap Entry"),
                                GIMP_ICON_COLORMAP,
                                desc,
diff --git a/app/widgets/gimpcolormapselection.c b/app/widgets/gimpcolormapselection.c
new file mode 100644
index 0000000000..f07bf53edb
--- /dev/null
+++ b/app/widgets/gimpcolormapselection.c
@@ -0,0 +1,758 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpmath/gimpmath.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "core/gimp.h"
+#include "core/gimpcontext.h"
+#include "core/gimpcontainer.h"
+#include "core/gimpimage.h"
+#include "core/gimpimage-colormap.h"
+#include "core/gimpmarshal.h"
+#include "core/gimppalette.h"
+#include "core/gimpprojection.h"
+
+#include "gimpcolordialog.h"
+#include "gimpcolormapselection.h"
+#include "gimpdialogfactory.h"
+#include "gimpdnd.h"
+#include "gimpdocked.h"
+#include "gimpmenufactory.h"
+#include "gimppaletteview.h"
+#include "gimpuimanager.h"
+#include "gimpviewrendererpalette.h"
+#include "gimpwidgets-utils.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_CONTEXT
+};
+
+enum
+{
+  COLOR_CONTEXT,
+  COLOR_CLICKED,
+  COLOR_ACTIVATED,
+  LAST_SIGNAL
+};
+
+#define BORDER      6
+#define RGB_EPSILON 1e-6
+
+#define HAVE_COLORMAP(image) \
+        (image != NULL && \
+         gimp_image_get_base_type (image) == GIMP_INDEXED && \
+         gimp_image_get_colormap (image) != NULL)
+
+
+static void   gimp_colormap_selection_set_property    (GObject               *object,
+                                                       guint                  property_id,
+                                                       const GValue          *value,
+                                                       GParamSpec            *pspec);
+static void   gimp_colormap_selection_get_property    (GObject               *object,
+                                                       guint                  property_id,
+                                                       GValue                *value,
+                                                       GParamSpec            *pspec);
+static void   gimp_colormap_selection_dispose         (GObject               *object);
+static void   gimp_colormap_selection_finalize        (GObject               *object);
+
+static void   gimp_colormap_selection_unmap           (GtkWidget             *widget);
+
+static PangoLayout *
+              gimp_colormap_selection_create_layout   (GtkWidget             *widget);
+
+static void   gimp_colormap_selection_update_entries  (GimpColormapSelection *selection);
+
+static gboolean
+              gimp_colormap_selection_preview_draw    (GtkWidget             *widget,
+                                                       cairo_t               *cr,
+                                                       GimpColormapSelection *selection);
+
+static void   gimp_colormap_selection_entry_clicked   (GimpPaletteView       *view,
+                                                       GimpPaletteEntry      *entry,
+                                                       GdkModifierType       state,
+                                                       GimpColormapSelection *selection);
+static void   gimp_colormap_selection_entry_selected  (GimpPaletteView       *view,
+                                                       GimpPaletteEntry      *entry,
+                                                       GimpColormapSelection *selection);
+static void   gimp_colormap_selection_entry_activated (GimpPaletteView       *view,
+                                                       GimpPaletteEntry      *entry,
+                                                       GimpColormapSelection *selection);
+static void   gimp_colormap_selection_entry_context   (GimpPaletteView       *view,
+                                                       GimpPaletteEntry      *entry,
+                                                       GimpColormapSelection *selection);
+static void   gimp_colormap_selection_color_dropped   (GimpPaletteView       *view,
+                                                       GimpPaletteEntry      *entry,
+                                                       const GimpRGB         *color,
+                                                       GimpColormapSelection *selection);
+
+static void   gimp_colormap_adjustment_changed        (GtkAdjustment         *adjustment,
+                                                       GimpColormapSelection *selection);
+static void   gimp_colormap_hex_entry_changed         (GimpColorHexEntry     *entry,
+                                                       GimpColormapSelection *selection);
+
+static void   gimp_colormap_selection_set_context     (GimpColormapSelection *selection,
+                                                       GimpContext           *context);
+static void   gimp_colormap_selection_image_changed   (GimpColormapSelection *selection,
+                                                       GimpImage             *image);
+static void   gimp_colormap_selection_set_palette     (GimpColormapSelection *selection);
+
+G_DEFINE_TYPE (GimpColormapSelection, gimp_colormap_selection, GTK_TYPE_BOX)
+
+#define parent_class gimp_colormap_selection_parent_class
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+gimp_colormap_selection_class_init (GimpColormapSelectionClass* klass)
+{
+  GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  signals[COLOR_CONTEXT] =
+    g_signal_new ("color-context",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GimpColormapSelectionClass, color_context),
+                  NULL, NULL,
+                  gimp_marshal_VOID__POINTER,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_POINTER);
+  signals[COLOR_CLICKED] =
+    g_signal_new ("color-clicked",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GimpColormapSelectionClass, color_clicked),
+                  NULL, NULL,
+                  gimp_marshal_VOID__POINTER_ENUM,
+                  G_TYPE_NONE, 2,
+                  G_TYPE_POINTER,
+                  GDK_TYPE_MODIFIER_TYPE);
+  signals[COLOR_ACTIVATED] =
+    g_signal_new ("color-activated",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GimpColormapSelectionClass, color_activated),
+                  NULL, NULL,
+                  gimp_marshal_VOID__POINTER,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_POINTER);
+
+  object_class->set_property    = gimp_colormap_selection_set_property;
+  object_class->get_property    = gimp_colormap_selection_get_property;
+  object_class->dispose         = gimp_colormap_selection_dispose;
+  object_class->finalize        = gimp_colormap_selection_finalize;
+
+  widget_class->unmap           = gimp_colormap_selection_unmap;
+
+  g_object_class_install_property (object_class, PROP_CONTEXT,
+                                   g_param_spec_object ("context",
+                                                        NULL, NULL,
+                                                        GIMP_TYPE_CONTEXT,
+                                                        GIMP_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
+}
+
+static void
+gimp_colormap_selection_init (GimpColormapSelection *selection)
+{
+  GtkWidget *frame;
+  GtkWidget *grid;
+
+  gtk_box_set_homogeneous (GTK_BOX (selection), FALSE);
+
+  /* Main colormap frame. */
+  frame = gtk_frame_new (NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+  gtk_box_pack_start (GTK_BOX (selection), frame, TRUE, TRUE, 0);
+  gtk_widget_show (frame);
+
+  selection->view = gimp_view_new_full_by_types (NULL,
+                                                 GIMP_TYPE_PALETTE_VIEW,
+                                                 GIMP_TYPE_PALETTE,
+                                                 1, 1, 0,
+                                                 FALSE, TRUE, FALSE);
+  gimp_view_set_expand (GIMP_VIEW (selection->view), TRUE);
+  gtk_container_add (GTK_CONTAINER (frame), selection->view);
+  gtk_widget_show (selection->view);
+
+  g_signal_connect (selection->view, "draw",
+                    G_CALLBACK (gimp_colormap_selection_preview_draw),
+                    selection);
+
+  g_signal_connect (selection->view, "entry-clicked",
+                    G_CALLBACK (gimp_colormap_selection_entry_clicked),
+                    selection);
+  g_signal_connect (selection->view, "entry-selected",
+                    G_CALLBACK (gimp_colormap_selection_entry_selected),
+                    selection);
+  g_signal_connect (selection->view, "entry-activated",
+                    G_CALLBACK (gimp_colormap_selection_entry_activated),
+                    selection);
+  g_signal_connect (selection->view, "entry-context",
+                    G_CALLBACK (gimp_colormap_selection_entry_context),
+                    selection);
+  g_signal_connect (selection->view, "color-dropped",
+                    G_CALLBACK (gimp_colormap_selection_color_dropped),
+                    selection);
+
+  /* Bottom horizontal box for additional widgets. */
+  selection->right_vbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
+  gtk_box_set_homogeneous (GTK_BOX (selection->right_vbox), TRUE);
+  gtk_box_pack_end (GTK_BOX (selection), selection->right_vbox,
+                    FALSE, FALSE, 0);
+  gtk_widget_show (selection->right_vbox);
+
+  /*  Some helpful hints  */
+  grid = gtk_grid_new ();
+  gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
+  gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
+  gtk_box_pack_end (GTK_BOX (selection), grid, FALSE, FALSE, 0);
+  gtk_widget_show (grid);
+
+  selection->index_adjustment = (GtkAdjustment *)
+    gtk_adjustment_new (0, 0, 0, 1, 10, 0);
+  selection->index_spinbutton = gimp_spin_button_new (selection->index_adjustment,
+                                                      1.0, 0);
+  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (selection->index_spinbutton),
+                               TRUE);
+
+  gimp_grid_attach_aligned (GTK_GRID (grid), 0, 0,
+                            _("Color index:"), 0.0, 0.5,
+                            selection->index_spinbutton, 1);
+
+  g_signal_connect (selection->index_adjustment, "value-changed",
+                    G_CALLBACK (gimp_colormap_adjustment_changed),
+                    selection);
+
+  selection->color_entry = gimp_color_hex_entry_new ();
+  gimp_grid_attach_aligned (GTK_GRID (grid), 0, 1,
+                            _("HTML notation:"), 0.0, 0.5,
+                            selection->color_entry, 1);
+
+  g_signal_connect (selection->color_entry, "color-changed",
+                    G_CALLBACK (gimp_colormap_hex_entry_changed),
+                    selection);
+}
+
+static void
+gimp_colormap_selection_set_property (GObject      *object,
+                                      guint         property_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+  GimpColormapSelection *selection = GIMP_COLORMAP_SELECTION (object);
+
+  switch (property_id)
+    {
+    case PROP_CONTEXT:
+      gimp_colormap_selection_set_context (selection, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_colormap_selection_get_property (GObject    *object,
+                                      guint       property_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+  GimpColormapSelection *selection = GIMP_COLORMAP_SELECTION (object);
+
+  switch (property_id)
+    {
+    case PROP_CONTEXT:
+      g_value_set_object (value, selection->context);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_colormap_selection_dispose (GObject *object)
+{
+  GimpColormapSelection *selection = GIMP_COLORMAP_SELECTION (object);
+
+  g_clear_pointer (&selection->color_dialog, gtk_widget_destroy);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gimp_colormap_selection_finalize (GObject *object)
+{
+  GimpColormapSelection *selection = GIMP_COLORMAP_SELECTION (object);
+
+  g_clear_object (&selection->layout);
+  g_clear_object (&selection->context);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_colormap_selection_unmap (GtkWidget *widget)
+{
+  GimpColormapSelection *selection = GIMP_COLORMAP_SELECTION (widget);
+
+  if (selection->color_dialog)
+    gtk_widget_hide (selection->color_dialog);
+
+  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+}
+
+/*  public functions  */
+
+GtkWidget *
+gimp_colormap_selection_new (GimpContext *context)
+{
+  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
+
+  return g_object_new (GIMP_TYPE_COLORMAP_SELECTION,
+                       "context",     context,
+                       "orientation", GTK_ORIENTATION_VERTICAL,
+                       NULL);
+}
+
+gint
+gimp_colormap_selection_get_index (GimpColormapSelection *selection,
+                                   const GimpRGB         *search)
+{
+  GimpImage *image;
+  gint       index;
+
+  g_return_val_if_fail (GIMP_IS_COLORMAP_SELECTION (selection), 0);
+
+  image = gimp_context_get_image (selection->context);
+
+  if (! HAVE_COLORMAP (image))
+    return -1;
+
+  index = selection->col_index;
+
+  if (search)
+    {
+      GimpRGB temp;
+
+      gimp_image_get_colormap_entry (image, index, &temp);
+
+      if (gimp_rgb_distance (&temp, search) > RGB_EPSILON)
+        {
+          gint n_colors = gimp_image_get_colormap_size (image);
+          gint i;
+
+          for (i = 0; i < n_colors; i++)
+            {
+              gimp_image_get_colormap_entry (image, i, &temp);
+
+              if (gimp_rgb_distance (&temp, search) < RGB_EPSILON)
+                {
+                  index = i;
+                  break;
+                }
+            }
+        }
+    }
+
+  return index;
+}
+
+gboolean
+gimp_colormap_selection_set_index (GimpColormapSelection *selection,
+                                   gint                   index,
+                                   GimpRGB               *color)
+{
+  GimpImage *image;
+  gint       size;
+
+  g_return_val_if_fail (GIMP_IS_COLORMAP_SELECTION (selection), FALSE);
+
+  image = gimp_context_get_image (selection->context);
+
+  if (! HAVE_COLORMAP (image))
+    return FALSE;
+
+  size = gimp_image_get_colormap_size (image);
+
+  if (size < 1)
+    return FALSE;
+
+  index = CLAMP (index, 0, size - 1);
+
+  if (index != selection->col_index)
+    {
+      GimpPalette *palette = gimp_image_get_colormap_palette (image);
+
+      selection->col_index = index;
+
+      gimp_palette_view_select_entry (GIMP_PALETTE_VIEW (selection->view),
+                                      gimp_palette_get_entry (palette, index));
+
+      gimp_colormap_selection_update_entries (selection);
+    }
+
+  if (color)
+    gimp_image_get_colormap_entry (image, index, color);
+
+  return TRUE;
+}
+
+gint
+gimp_colormap_selection_max_index (GimpColormapSelection *selection)
+{
+  GimpImage *image;
+
+  g_return_val_if_fail (GIMP_IS_COLORMAP_SELECTION (selection), -1);
+
+  image = gimp_context_get_image (selection->context);
+
+  if (! HAVE_COLORMAP (image))
+    return -1;
+
+  return MAX (0, gimp_image_get_colormap_size (image) - 1);
+}
+
+
+/*  private functions  */
+
+static PangoLayout *
+gimp_colormap_selection_create_layout (GtkWidget *widget)
+{
+  PangoLayout    *layout;
+  PangoAttrList  *attrs;
+  PangoAttribute *attr;
+
+  layout = gtk_widget_create_pango_layout (widget,
+                                           _("Only indexed images have "
+                                             "a colormap."));
+
+  pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
+
+  attrs = pango_attr_list_new ();
+
+  attr = pango_attr_style_new (PANGO_STYLE_ITALIC);
+  attr->start_index = 0;
+  attr->end_index   = -1;
+  pango_attr_list_insert (attrs, attr);
+
+  pango_layout_set_attributes (layout, attrs);
+  pango_attr_list_unref (attrs);
+
+  return layout;
+}
+
+static gboolean
+gimp_colormap_selection_preview_draw (GtkWidget             *widget,
+                                      cairo_t               *cr,
+                                      GimpColormapSelection *selection)
+{
+  GtkStyleContext *style = gtk_widget_get_style_context (widget);
+  GimpImage       *image;
+  GtkAllocation    allocation;
+  GdkRGBA          color;
+  gint             width, height;
+  gint             y;
+
+  image = gimp_context_get_image (selection->context);
+
+  if (image == NULL || gimp_image_get_base_type (image) == GIMP_INDEXED)
+    return FALSE;
+
+  gtk_style_context_get_color (style, gtk_widget_get_state_flags (widget),
+                               &color);
+  gdk_cairo_set_source_rgba (cr, &color);
+
+  gtk_widget_get_allocation (widget, &allocation);
+
+  if (! selection->layout)
+    selection->layout = gimp_colormap_selection_create_layout (selection->view);
+
+  pango_layout_set_width (selection->layout,
+                          PANGO_SCALE * (allocation.width - 2 * BORDER));
+
+  pango_layout_get_pixel_size (selection->layout, &width, &height);
+
+  y = (allocation.height - height) / 2;
+
+  cairo_move_to (cr, BORDER, MAX (y, 0));
+  pango_cairo_show_layout (cr, selection->layout);
+
+  return TRUE;
+}
+
+static void
+gimp_colormap_selection_update_entries (GimpColormapSelection *selection)
+{
+  GimpImage *image = gimp_context_get_image (selection->context);
+
+  if (! HAVE_COLORMAP (image) ||
+      ! gimp_image_get_colormap_size (image))
+    {
+      gtk_widget_set_sensitive (selection->index_spinbutton, FALSE);
+      gtk_widget_set_sensitive (selection->color_entry, FALSE);
+
+      gtk_adjustment_set_value (selection->index_adjustment, 0);
+      gtk_entry_set_text (GTK_ENTRY (selection->color_entry), "");
+    }
+  else
+    {
+      const guchar *colormap = gimp_image_get_colormap (image);
+      const guchar *col;
+      gchar        *string;
+
+      gtk_adjustment_set_value (selection->index_adjustment, selection->col_index);
+
+      col = colormap + selection->col_index * 3;
+
+      string = g_strdup_printf ("%02x%02x%02x", col[0], col[1], col[2]);
+      gtk_entry_set_text (GTK_ENTRY (selection->color_entry), string);
+      g_free (string);
+
+      gtk_widget_set_sensitive (selection->index_spinbutton, TRUE);
+      gtk_widget_set_sensitive (selection->color_entry, TRUE);
+    }
+}
+
+static void
+gimp_colormap_selection_entry_clicked (GimpPaletteView       *view,
+                                       GimpPaletteEntry      *entry,
+                                       GdkModifierType        state,
+                                       GimpColormapSelection *selection)
+{
+  gimp_colormap_selection_set_index (selection, entry->position, NULL);
+
+  g_signal_emit (selection, signals[COLOR_CLICKED], 0, entry, state);
+}
+
+static void
+gimp_colormap_selection_entry_selected (GimpPaletteView       *view,
+                                        GimpPaletteEntry      *entry,
+                                        GimpColormapSelection *selection)
+{
+  gint index = entry ? entry->position : 0;
+
+  gimp_colormap_selection_set_index (selection, index, NULL);
+}
+
+static void
+gimp_colormap_selection_entry_activated (GimpPaletteView       *view,
+                                         GimpPaletteEntry      *entry,
+                                         GimpColormapSelection *selection)
+{
+  gimp_colormap_selection_set_index (selection, entry->position, NULL);
+
+  g_signal_emit (selection, signals[COLOR_ACTIVATED], 0, entry);
+}
+
+static void
+gimp_colormap_selection_entry_context (GimpPaletteView       *view,
+                                       GimpPaletteEntry      *entry,
+                                       GimpColormapSelection *selection)
+{
+  gimp_colormap_selection_set_index (selection, entry->position, NULL);
+
+  g_signal_emit (selection, signals[COLOR_CONTEXT], 0, entry);
+}
+
+static void
+gimp_colormap_selection_color_dropped (GimpPaletteView       *view,
+                                       GimpPaletteEntry      *entry,
+                                       const GimpRGB         *color,
+                                       GimpColormapSelection *selection)
+{
+}
+
+static void
+gimp_colormap_adjustment_changed (GtkAdjustment         *adjustment,
+                                  GimpColormapSelection *selection)
+{
+  GimpImage *image = gimp_context_get_image (selection->context);
+
+  if (HAVE_COLORMAP (image))
+    {
+      gint index = ROUND (gtk_adjustment_get_value (adjustment));
+
+      gimp_colormap_selection_set_index (selection, index, NULL);
+
+      gimp_colormap_selection_update_entries (selection);
+    }
+}
+
+static void
+gimp_colormap_hex_entry_changed (GimpColorHexEntry     *entry,
+                                 GimpColormapSelection *selection)
+{
+  GimpImage *image = gimp_context_get_image (selection->context);
+
+  if (image)
+    {
+      GimpRGB color;
+
+      gimp_color_hex_entry_get_color (entry, &color);
+
+      gimp_image_set_colormap_entry (image, selection->col_index, &color, TRUE);
+      gimp_image_flush (image);
+    }
+}
+
+static void
+gimp_colormap_selection_set_context (GimpColormapSelection *selection,
+                                     GimpContext           *context)
+{
+  g_return_if_fail (GIMP_IS_COLORMAP_SELECTION (selection));
+  g_return_if_fail (context == NULL || GIMP_IS_CONTEXT (context));
+
+  if (context != selection->context)
+    {
+      if (selection->context)
+        {
+          g_signal_handlers_disconnect_by_func (selection->context,
+                                                gtk_widget_queue_draw,
+                                                selection);
+          g_signal_handlers_disconnect_by_func (selection->context,
+                                                G_CALLBACK (gimp_colormap_selection_image_changed),
+                                                selection);
+          g_object_unref (selection->context);
+        }
+
+      selection->context = context;
+
+      if (context)
+        {
+          g_object_ref (context);
+
+          g_signal_connect_swapped (context, "foreground-changed",
+                                    G_CALLBACK (gtk_widget_queue_draw),
+                                    selection);
+          g_signal_connect_swapped (context, "background-changed",
+                                    G_CALLBACK (gtk_widget_queue_draw),
+                                    selection);
+          g_signal_connect_swapped (context, "image-changed",
+                                    G_CALLBACK (gimp_colormap_selection_image_changed),
+                                    selection);
+          gimp_colormap_selection_image_changed (selection, gimp_context_get_image (context));
+        }
+
+      gimp_view_renderer_set_context (GIMP_VIEW (selection->view)->renderer,
+                                      context);
+      g_object_notify (G_OBJECT (selection), "context");
+    }
+}
+
+static void
+gimp_colormap_selection_image_changed (GimpColormapSelection *selection,
+                                       GimpImage             *image)
+{
+  if (selection->active_image)
+    {
+      g_signal_handlers_disconnect_by_func (selection->active_image,
+                                            G_CALLBACK (gtk_widget_queue_draw),
+                                            selection);
+      if (gimp_image_get_base_type (selection->active_image) == GIMP_INDEXED)
+        {
+          GimpPalette *palette;
+
+          palette = gimp_image_get_colormap_palette (selection->active_image);
+          g_signal_handlers_disconnect_by_func (palette,
+                                                G_CALLBACK (gtk_widget_queue_draw),
+                                                selection);
+        }
+
+      if (selection->color_dialog)
+        gtk_widget_hide (selection->color_dialog);
+
+      if (! HAVE_COLORMAP (image))
+        {
+          gtk_adjustment_set_upper (selection->index_adjustment, 0);
+
+          if (gtk_widget_get_mapped (GTK_WIDGET (selection)))
+            {
+              if (selection->active_palette)
+                g_signal_handlers_disconnect_by_func (selection->active_palette,
+                                                      G_CALLBACK (gtk_widget_queue_draw),
+                                                      selection);
+              gimp_view_set_viewable (GIMP_VIEW (selection->view), NULL);
+              gtk_adjustment_set_upper (selection->index_adjustment, 0);
+              selection->active_palette = NULL;
+            }
+        }
+    }
+  selection->active_image = image;
+  if (image)
+    {
+      g_signal_connect_swapped (image, "colormap-changed",
+                                G_CALLBACK (gtk_widget_queue_draw),
+                                selection);
+      g_signal_connect_swapped (image, "mode-changed",
+                                G_CALLBACK (gimp_colormap_selection_set_palette),
+                                selection);
+
+      if (HAVE_COLORMAP (image))
+        gimp_colormap_selection_set_palette (selection);
+    }
+  gtk_widget_queue_draw (GTK_WIDGET (selection));
+}
+
+static void
+gimp_colormap_selection_set_palette (GimpColormapSelection *selection)
+{
+  GimpPalette *palette;
+
+  palette = gimp_image_get_colormap_palette (selection->active_image);
+  if (palette != selection->active_palette)
+    {
+      if (selection->active_palette)
+        {
+          g_signal_handlers_disconnect_by_func (selection->active_palette,
+                                                G_CALLBACK (gtk_widget_queue_draw),
+                                                selection);
+          gimp_view_set_viewable (GIMP_VIEW (selection->view), NULL);
+          gtk_adjustment_set_upper (selection->index_adjustment, 0);
+        }
+      selection->active_palette = palette;
+      if (palette)
+        {
+          g_signal_connect_swapped (palette, "dirty",
+                                    G_CALLBACK (gtk_widget_queue_draw),
+                                    selection);
+          gimp_view_set_viewable (GIMP_VIEW (selection->view),
+                                  GIMP_VIEWABLE (palette));
+
+          gtk_adjustment_set_upper (selection->index_adjustment,
+                                    gimp_image_get_colormap_size (selection->active_image) - 1);
+        }
+    }
+}
diff --git a/app/widgets/gimpcolormapselection.h b/app/widgets/gimpcolormapselection.h
new file mode 100644
index 0000000000..e524d1b42f
--- /dev/null
+++ b/app/widgets/gimpcolormapselection.h
@@ -0,0 +1,81 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_COLORMAP_SELECTION_H__
+#define __GIMP_COLORMAP_SELECTION_H__
+
+
+#define GIMP_TYPE_COLORMAP_SELECTION            (gimp_colormap_selection_get_type ())
+#define GIMP_COLORMAP_SELECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GIMP_TYPE_COLORMAP_SELECTION, GimpColormapSelection))
+#define GIMP_COLORMAP_SELECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
GIMP_TYPE_COLORMAP_SELECTION, GimpColormapSelectionClass))
+#define GIMP_IS_COLORMAP_SELECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GIMP_TYPE_COLORMAP_SELECTION))
+#define GIMP_IS_COLORMAP_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GIMP_TYPE_COLORMAP_SELECTION))
+#define GIMP_COLORMAP_SELECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GIMP_TYPE_COLORMAP_SELECTION, GimpColormapSelectionClass))
+
+
+typedef struct _GimpColormapSelectionClass GimpColormapSelectionClass;
+
+struct _GimpColormapSelection
+{
+  GtkBox  parent_instance;
+
+  GimpContext     *context;
+  GimpImage       *active_image;
+  GimpPalette     *active_palette;
+
+  GtkWidget       *view;
+  gint             col_index;
+
+  PangoLayout     *layout;
+
+  GtkAdjustment   *index_adjustment;
+  GtkWidget       *index_spinbutton;
+  GtkWidget       *color_entry;
+
+  GtkWidget       *color_dialog;
+  GtkWidget       *right_vbox;
+};
+
+struct _GimpColormapSelectionClass
+{
+  GtkBoxClass  parent_class;
+
+  void (* color_context)   (GimpColormapSelection *selection,
+                            GimpPaletteEntry      *entry);
+  void (* color_clicked)   (GimpColormapSelection *selection,
+                            GimpPaletteEntry      *entry,
+                            GdkModifierType        state);
+  void (* color_activated) (GimpColormapSelection *selection,
+                            GimpPaletteEntry      *entry);
+};
+
+
+GType       gimp_colormap_selection_get_type   (void) G_GNUC_CONST;
+
+GtkWidget * gimp_colormap_selection_new        (GimpContext *context);
+
+gint        gimp_colormap_selection_get_index  (GimpColormapSelection *selection,
+                                                const GimpRGB         *search);
+gboolean    gimp_colormap_selection_set_index  (GimpColormapSelection *selection,
+                                                gint                   index,
+                                                GimpRGB               *color);
+
+gint        gimp_colormap_selection_max_index  (GimpColormapSelection *selection);
+
+
+#endif /* __GIMP_COLORMAP_SELECTION_H__ */
+
diff --git a/app/widgets/gimpcolorpanel.c b/app/widgets/gimpcolorpanel.c
index 4bf15b20fd..f76f8a346a 100644
--- a/app/widgets/gimpcolorpanel.c
+++ b/app/widgets/gimpcolorpanel.c
@@ -187,7 +187,7 @@ gimp_color_panel_clicked (GtkButton *button)
       GimpColorButton *color_button = GIMP_COLOR_BUTTON (button);
 
       panel->color_dialog =
-        gimp_color_dialog_new (NULL, panel->context,
+        gimp_color_dialog_new (NULL, panel->context, TRUE,
                                gimp_color_button_get_title (color_button),
                                NULL, NULL,
                                GTK_WIDGET (button),
diff --git a/app/widgets/gimpgradienteditor.c b/app/widgets/gimpgradienteditor.c
index dec420103f..754a167333 100644
--- a/app/widgets/gimpgradienteditor.c
+++ b/app/widgets/gimpgradienteditor.c
@@ -581,6 +581,7 @@ gimp_gradient_editor_edit_left_color (GimpGradientEditor *editor)
   editor->color_dialog =
     gimp_color_dialog_new (GIMP_VIEWABLE (gradient),
                            GIMP_DATA_EDITOR (editor)->context,
+                           TRUE,
                            _("Left Endpoint Color"),
                            GIMP_ICON_GRADIENT,
                            _("Gradient Segment's Left Endpoint Color"),
@@ -625,6 +626,7 @@ gimp_gradient_editor_edit_right_color (GimpGradientEditor *editor)
   editor->color_dialog =
     gimp_color_dialog_new (GIMP_VIEWABLE (gradient),
                            GIMP_DATA_EDITOR (editor)->context,
+                           TRUE,
                            _("Right Endpoint Color"),
                            GIMP_ICON_GRADIENT,
                            _("Gradient Segment's Right Endpoint Color"),
diff --git a/app/widgets/gimppaletteeditor.c b/app/widgets/gimppaletteeditor.c
index d9c334bf0a..9e9b67688c 100644
--- a/app/widgets/gimppaletteeditor.c
+++ b/app/widgets/gimppaletteeditor.c
@@ -481,6 +481,7 @@ gimp_palette_editor_edit_color (GimpPaletteEditor *editor)
       editor->color_dialog =
         gimp_color_dialog_new (GIMP_VIEWABLE (palette),
                                data_editor->context,
+                               FALSE,
                                _("Edit Palette Color"),
                                GIMP_ICON_PALETTE,
                                _("Edit Color Palette Entry"),
diff --git a/app/widgets/gimptoolbox-color-area.c b/app/widgets/gimptoolbox-color-area.c
index feea1b5f77..88943980bb 100644
--- a/app/widgets/gimptoolbox-color-area.c
+++ b/app/widgets/gimptoolbox-color-area.c
@@ -228,7 +228,7 @@ color_area_color_clicked (GimpFgBgEditor  *editor,
 
   if (! color_dialog)
     {
-      color_dialog = gimp_color_dialog_new (NULL, context,
+      color_dialog = gimp_color_dialog_new (NULL, context, TRUE,
                                             NULL, NULL, NULL,
                                             GTK_WIDGET (editor),
                                             gimp_dialog_factory_get_singleton (),
diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h
index 331fea54e4..1fb3910bb8 100644
--- a/app/widgets/widgets-types.h
+++ b/app/widgets/widgets-types.h
@@ -175,6 +175,7 @@ typedef struct _GimpColorBar                 GimpColorBar;
 typedef struct _GimpColorDisplayEditor       GimpColorDisplayEditor;
 typedef struct _GimpColorFrame               GimpColorFrame;
 typedef struct _GimpColorHistory             GimpColorHistory;
+typedef struct _GimpColormapSelection        GimpColormapSelection;
 typedef struct _GimpColorPanel               GimpColorPanel;
 typedef struct _GimpComboTagEntry            GimpComboTagEntry;
 typedef struct _GimpControllerEditor         GimpControllerEditor;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]