From 7de118051f046aa17f1061e09a5626f4ac4f2c3c Mon Sep 17 00:00:00 2001 From: Jehan Date: Thu, 16 Nov 2023 15:15:45 +0100 Subject: [PATCH] app: the Device Status dockable now shows context-sensitive colors. I moved the function to select a valid contextual RGBA format as a core API gimp_context_get_rgba_format(). This same API is now used in context actions, as well as in the GimpDeviceStatus widget. The latter now shows per-device fg/bg colors relatively to the active image's format. The tooltip will also display contextual information (i.e. either the image's name whose space is used, or sRGB). Of course, this all updates when switching images by connecting to the image-changed signal. --- app/actions/context-commands.c | 100 ++---------------------------- app/core/gimpcontext.c | 107 +++++++++++++++++++++++++++++++++ app/core/gimpcontext.h | 6 ++ app/widgets/gimpdevicestatus.c | 84 +++++++++++++++++++++----- 4 files changed, 187 insertions(+), 110 deletions(-) diff --git a/app/actions/context-commands.c b/app/actions/context-commands.c index d0c72c3d0e..b2d6467b39 100644 --- a/app/actions/context-commands.c +++ b/app/actions/context-commands.c @@ -30,8 +30,6 @@ #include "operations/layer-modes/gimp-layer-modes.h" -#include "gegl/gimp-babl.h" - #include "core/gimp.h" #include "core/gimpbrushgenerated.h" #include "core/gimpcontext.h" @@ -81,9 +79,6 @@ static gboolean context_set_color_index (gint index, static GimpPaletteEditor * context_get_palette_editor (void); static GimpColormapEditor * context_get_colormap_editor (void); -static const Babl * context_get_rgb_format (GimpContext *context, - GeglColor *color); - /* public functions */ @@ -151,7 +146,7 @@ context_foreground_red_cmd_callback (GimpAction *action, select_type = (GimpActionSelectType) g_variant_get_int32 (value); color = gegl_color_duplicate (gimp_context_get_foreground (context)); - format = context_get_rgb_format (context, color); + format = gimp_context_get_rgba_format (context, color, "double", NULL); gegl_color_get_pixel (color, format, pixel); /* TODO: if value was already out-of-gamut, say we want to decrease it @@ -183,7 +178,7 @@ context_foreground_green_cmd_callback (GimpAction *action, select_type = (GimpActionSelectType) g_variant_get_int32 (value); color = gegl_color_duplicate (gimp_context_get_foreground (context)); - format = context_get_rgb_format (context, color); + format = gimp_context_get_rgba_format (context, color, "double", NULL); gegl_color_get_pixel (color, format, pixel); pixel[1] = action_select_value (select_type, @@ -210,7 +205,7 @@ context_foreground_blue_cmd_callback (GimpAction *action, select_type = (GimpActionSelectType) g_variant_get_int32 (value); color = gegl_color_duplicate (gimp_context_get_foreground (context)); - format = context_get_rgb_format (context, color); + format = gimp_context_get_rgba_format (context, color, "double", NULL); gegl_color_get_pixel (color, format, pixel); pixel[2] = action_select_value (select_type, @@ -237,7 +232,7 @@ context_background_red_cmd_callback (GimpAction *action, select_type = (GimpActionSelectType) g_variant_get_int32 (value); color = gegl_color_duplicate (gimp_context_get_background (context)); - format = context_get_rgb_format (context, color); + format = gimp_context_get_rgba_format (context, color, "double", NULL); gegl_color_get_pixel (color, format, pixel); pixel[0] = action_select_value (select_type, @@ -264,7 +259,7 @@ context_background_green_cmd_callback (GimpAction *action, select_type = (GimpActionSelectType) g_variant_get_int32 (value); color = gegl_color_duplicate (gimp_context_get_background (context)); - format = context_get_rgb_format (context, color); + format = gimp_context_get_rgba_format (context, color, "double", NULL); gegl_color_get_pixel (color, format, pixel); pixel[1] = action_select_value (select_type, @@ -291,7 +286,7 @@ context_background_blue_cmd_callback (GimpAction *action, select_type = (GimpActionSelectType) g_variant_get_int32 (value); color = gegl_color_duplicate (gimp_context_get_background (context)); - format = context_get_rgb_format (context, color); + format = gimp_context_get_rgba_format (context, color, "double", NULL); gegl_color_get_pixel (color, format, pixel); pixel[2] = action_select_value (select_type, @@ -1096,86 +1091,3 @@ context_get_colormap_editor (void) return NULL; } - -/* The logic for the format to use in RGB color actions is as following: - * - The space we navigate through is the active image's space. - * - Increasing/decreasing follows the image TRC (in particular, if the image is - * linear or perceptual, we care about chromaticities yet don't follow the - * space TRC). - * - If there is no active image or if its space is non-sRGB, we use the context - * color's space. - * - We discard non-RGB spaces and fallback to sRGB. - */ -static const Babl * -context_get_rgb_format (GimpContext *context, - GeglColor *color) -{ - GimpImage *image = NULL; - const Babl *format = NULL; - const Babl *space = NULL; - GimpTRCType trc = GIMP_TRC_NON_LINEAR; - - g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); - - image = gimp_context_get_image (context); - if (image) - { - format = gimp_image_get_layer_format (image, FALSE); - space = babl_format_get_space (format); - } - - if (space == NULL || -#if BABL_MINOR_VERSION > 1 || (BABL_MINOR_VERSION == 1 && BABL_MICRO_VERSION >= 107) - ! babl_space_is_rgb (space) || -#else - babl_space_is_cmyk (space) || - babl_space_is_gray (space) || -#endif - FALSE) - { - format = gegl_color_get_format (color); - space = babl_format_get_space (format); - } - -#if BABL_MINOR_VERSION > 1 || (BABL_MINOR_VERSION == 1 && BABL_MICRO_VERSION >= 107) - if (! babl_space_is_rgb (space)) -#else - if (babl_space_is_cmyk (space) || babl_space_is_gray (space)) -#endif - { - format = NULL; - space = NULL; - } - - if (format != NULL) - { - if (image != NULL) - { - GimpPrecision precision; - - precision = gimp_image_get_precision (image); - trc = gimp_babl_trc (precision); - } - else - { - trc = gimp_babl_format_get_trc (format); - } - } - - switch (trc) - { - case GIMP_TRC_LINEAR: - format = babl_format_with_space ("RGBA double", space); - break; - case GIMP_TRC_NON_LINEAR: - format = babl_format_with_space ("R'G'B'A double", space); - break; - case GIMP_TRC_PERCEPTUAL: - format = babl_format_with_space ("R~G~B~A double", space); - break; - default: - g_return_val_if_reached (NULL); - } - - return format; -} diff --git a/app/core/gimpcontext.c b/app/core/gimpcontext.c index aeef7e1ad2..9042e55713 100644 --- a/app/core/gimpcontext.c +++ b/app/core/gimpcontext.c @@ -32,6 +32,8 @@ #include "config/gimpcoreconfig.h" +#include "gegl/gimp-babl.h" + #include "gimp.h" #include "gimp-memsize.h" #include "gimpbrush.h" @@ -1913,6 +1915,111 @@ gimp_context_image_changed (GimpContext *context) context->image); } +/* This is a utility function to share, across the program, some common logic of + * "which format to use when you are not sure and you need to give generic color + * information" in RGBA. + * @babl_type must be a valid babl type name such as "u8", "double", "float". + * If @space_image is not NULL, it will be used to return the GimpImage + * associated to the returned format (if the returned format is indeed using the + * image's space). + * + * The logic for the format to use in RGB color actions is as follows: + * - The space we navigate through is the active image's space. + * - Increasing/decreasing follows the image TRC (in particular, if the image is + * linear or perceptual, we care about chromaticities yet don't follow the + * space TRC). + * - If there is no active image or if its space is non-sRGB, we use the context + * color's space (if set). + * - We discard non-RGB spaces and fallback to sRGB. + */ +const Babl * +gimp_context_get_rgba_format (GimpContext *context, + GeglColor *color, + const gchar *babl_type, + GimpImage **space_image) +{ + GimpImage *image = NULL; + const Babl *format = NULL; + const Babl *space = NULL; + gchar *format_name; + GimpTRCType trc = GIMP_TRC_NON_LINEAR; + + g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); + g_return_val_if_fail (babl_type != NULL , NULL); + g_return_val_if_fail (space_image == NULL || *space_image == NULL, NULL); + + image = gimp_context_get_image (context); + if (image) + { + format = gimp_image_get_layer_format (image, FALSE); + space = babl_format_get_space (format); + if (space_image) + *space_image = image; + } + + if (color != NULL && + (space == NULL || +#if BABL_MINOR_VERSION > 1 || (BABL_MINOR_VERSION == 1 && BABL_MICRO_VERSION >= 107) + ! babl_space_is_rgb (space) || +#else + babl_space_is_cmyk (space) || + babl_space_is_gray (space) || +#endif + FALSE)) + { + format = gegl_color_get_format (color); + space = babl_format_get_space (format); + if (space_image) + *space_image = NULL; + } + +#if BABL_MINOR_VERSION > 1 || (BABL_MINOR_VERSION == 1 && BABL_MICRO_VERSION >= 107) + if (! babl_space_is_rgb (space)) +#else + if (babl_space_is_cmyk (space) || babl_space_is_gray (space)) +#endif + { + format = NULL; + space = NULL; + if (space_image) + *space_image = NULL; + } + + if (format != NULL) + { + if (image != NULL) + { + GimpPrecision precision; + + precision = gimp_image_get_precision (image); + trc = gimp_babl_trc (precision); + } + else + { + trc = gimp_babl_format_get_trc (format); + } + } + + switch (trc) + { + case GIMP_TRC_LINEAR: + format_name = g_strdup_printf ("RGBA %s", babl_type); + break; + case GIMP_TRC_NON_LINEAR: + format_name = g_strdup_printf ("R'G'B'A %s", babl_type); + break; + case GIMP_TRC_PERCEPTUAL: + format_name = g_strdup_printf ("R~G~B~A %s", babl_type); + break; + default: + g_return_val_if_reached (NULL); + } + format = babl_format_with_space (format_name, space); + g_free (format_name); + + return format; +} + static void gimp_context_image_disconnect (GimpImage *image, GimpContext *context) diff --git a/app/core/gimpcontext.h b/app/core/gimpcontext.h index ad3dcfc567..41fe283ea9 100644 --- a/app/core/gimpcontext.h +++ b/app/core/gimpcontext.h @@ -224,6 +224,12 @@ void gimp_context_set_image (GimpContext *context, void gimp_context_image_changed (GimpContext *context); +const Babl * gimp_context_get_rgba_format (GimpContext *context, + GeglColor *color, + const gchar *babl_type, + GimpImage **space_image); + + /* display */ GimpDisplay * gimp_context_get_display (GimpContext *context); void gimp_context_set_display (GimpContext *context, diff --git a/app/widgets/gimpdevicestatus.c b/app/widgets/gimpdevicestatus.c index cba7d4d9fe..cb88462ca4 100644 --- a/app/widgets/gimpdevicestatus.c +++ b/app/widgets/gimpdevicestatus.c @@ -36,6 +36,7 @@ #include "core/gimpcontext.h" #include "core/gimpdatafactory.h" #include "core/gimpgradient.h" +#include "core/gimpimage.h" #include "core/gimplist.h" #include "core/gimppattern.h" #include "core/gimptoolinfo.h" @@ -106,6 +107,9 @@ static void gimp_device_status_notify_device (GimpDeviceManager *manager, static void gimp_device_status_config_notify (GimpGuiConfig *config, const GParamSpec *pspec, GimpDeviceStatus *status); +static void gimp_device_status_image_changed (GimpContext *user_context, + GimpImage *image, + GimpDeviceStatus *status); static void gimp_device_status_notify_info (GimpDeviceInfo *device_info, const GParamSpec *pspec, GimpDeviceStatusEntry *entry); @@ -115,6 +119,10 @@ static void gimp_device_status_view_clicked (GtkWidget *widget, GdkModifierType state, const gchar *identifier); +static void + gimp_device_status_set_color_help_data (GimpDeviceStatusEntry *entry, + GimpContext *user_context); + G_DEFINE_TYPE (GimpDeviceStatus, gimp_device_status, GIMP_TYPE_EDITOR) @@ -191,6 +199,10 @@ gimp_device_status_constructed (GObject *object) gimp_device_status_config_notify (GIMP_GUI_CONFIG (status->gimp->config), NULL, status); + + g_signal_connect_object (gimp_get_user_context (status->gimp), "image-changed", + G_CALLBACK (gimp_device_status_image_changed), + status, 0); } static void @@ -492,6 +504,21 @@ gimp_device_status_config_notify (GimpGuiConfig *config, } } +static void +gimp_device_status_image_changed (GimpContext *user_context, + GimpImage *image, + GimpDeviceStatus *status) +{ + GList *list; + + for (list = status->devices; list; list = list->next) + { + GimpDeviceStatusEntry *entry = list->data; + + gimp_device_status_set_color_help_data (entry, user_context); + } +} + static void toggle_prop_visible (GtkWidget *widget, GtkWidget *widget_none, @@ -550,22 +577,8 @@ gimp_device_status_notify_info (GimpDeviceInfo *device_info, } if (! strcmp (pspec->name, "tool-options")) - { - GeglColor *color; - guchar rgb[3]; - gchar buf[64]; - - color = gimp_context_get_foreground (entry->context); - /* TODO: which space to use exactly to provide more useful info? */ - gegl_color_get_pixel (color, babl_format_with_space ("R'G'B' u8", NULL), rgb); - g_snprintf (buf, sizeof (buf), _("Foreground: %d, %d, %d"), rgb[0], rgb[1], rgb[2]); - gimp_help_set_help_data (entry->foreground, buf, NULL); - - color = gimp_context_get_background (entry->context); - gegl_color_get_pixel (color, babl_format_with_space ("R'G'B' u8", NULL), rgb); - g_snprintf (buf, sizeof (buf), _("Background: %d, %d, %d"), rgb[0], rgb[1], rgb[2]); - gimp_help_set_help_data (entry->background, buf, NULL); - } + gimp_device_status_set_color_help_data (entry, + gimp_get_user_context (entry->context->gimp)); } static void @@ -593,3 +606,42 @@ gimp_device_status_view_clicked (GtkWidget *widget, gimp_widget_get_monitor (widget), identifier); } + +static void +gimp_device_status_set_color_help_data (GimpDeviceStatusEntry *entry, + GimpContext *user_context) +{ + const Babl *format; + GimpImage *image = NULL; + GeglColor *color; + guchar rgb[4]; + gchar *buf; + + /* Note: we don't set the GeglColor on purpose. Whatever is the specific + * color space is too disconnected to this GUI usage and showing info in + * this space would only be confusing. + */ + format = gimp_context_get_rgba_format (user_context, NULL, "u8", &image); + + color = gimp_context_get_foreground (entry->context); + gegl_color_get_pixel (color, format, rgb); + if (image != NULL) + buf = g_strdup_printf (_("Foreground: %d, %d, %d (in color space of \"%s\")"), + rgb[0], rgb[1], rgb[2], + gimp_image_get_display_name (image)); + else + buf = g_strdup_printf (_("Foreground: %d, %d, %d (in sRGB)"), rgb[0], rgb[1], rgb[2]); + gimp_help_set_help_data (entry->foreground, buf, NULL); + g_free (buf); + + color = gimp_context_get_background (entry->context); + gegl_color_get_pixel (color, format, rgb); + if (image != NULL) + buf = g_strdup_printf (_("Background: %d, %d, %d (in color space of \"%s\")"), + rgb[0], rgb[1], rgb[2], + gimp_image_get_display_name (image)); + else + buf = g_strdup_printf (_("Background: %d, %d, %d (in sRGB)"), rgb[0], rgb[1], rgb[2]); + gimp_help_set_help_data (entry->background, buf, NULL); + g_free (buf); +}