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.
This commit is contained in:
Jehan 2023-11-16 15:15:45 +01:00
parent cd09634dc2
commit 7de118051f
4 changed files with 187 additions and 110 deletions

View File

@ -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;
}

View File

@ -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)

View File

@ -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,

View File

@ -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);
}