From f3578d35758ac47991806233ceba8d566160260b Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 24 Dec 2020 17:29:08 +0100 Subject: Added a way to retrieve RGBA colors from the current GTK style. --- plugins/pychrysalide/gtkext/easygtk.c | 85 ++++++++++++++++++++++++ src/gtkext/easygtk.c | 117 ++++++++++++++++++++++++++++++++++ src/gtkext/easygtk.h | 5 ++ 3 files changed, 207 insertions(+) diff --git a/plugins/pychrysalide/gtkext/easygtk.c b/plugins/pychrysalide/gtkext/easygtk.c index fe57c7e..a489cd1 100644 --- a/plugins/pychrysalide/gtkext/easygtk.c +++ b/plugins/pychrysalide/gtkext/easygtk.c @@ -41,6 +41,9 @@ " useful features GTK is missing." +/* Identifie la couleur de base associée à un style GTK. */ +static PyObject *py_easygtk_get_color_from_style(PyObject *, PyObject *); + /* Détermine l'indice d'un composant dans un conteneur GTK. */ static PyObject *py_easygtk_find_contained_child_index(PyObject *, PyObject *); @@ -54,6 +57,87 @@ static PyObject *py_easygtk_get_nth_contained_child(PyObject *, PyObject *); * Paramètres : self = NULL car méthode statique. * * args = paramètres à transmettre à l'appel natif. * * * +* Description : Identifie la couleur de base associée à un style GTK. * +* * +* Retour : Bilan présumé de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_easygtk_get_color_from_style(PyObject *self, PyObject *args) +{ + PyObject *result; /* Désignation à retourner */ + const char *class; /* Classe de style GTK */ + int background; /* Nature du traitement */ + int ret; /* Bilan de lecture des args. */ + GdkRGBA color; /* Couleur obtenue */ + bool status; /* Bilan de la récupération */ + PyObject *gdk_mod; /* Module Python Gdk */ + PyObject *rgba_type; /* Classe "GtkRGBA" */ + PyObject *rgba_args; /* Arguments pour l'appel */ + +#define EASYGTK_GET_COLOR_FROM_STYLE_METHOD PYTHON_METHOD_DEF \ +( \ + get_color_from_style, "cls, background, /", \ + METH_VARARGS | METH_STATIC, py_easygtk, \ + "Find the index of a given child widget inside a GTK container" \ + " children.\n" \ + "\n" \ + "The *containter* argument must be a Gtk.Container instance and" \ + " *child* a Gtk.Widget instance.\n" \ + "\n" \ + "The result is the found index or -1 in case of error." \ +) + + ret = PyArg_ParseTuple(args, "sp", &class, &background); + if (!ret) return NULL; + + status = get_color_from_style(class, background, &color); + + if (status) + { + gdk_mod = PyImport_ImportModule("gi.repository.Gdk"); + + if (gdk_mod == NULL) + { + PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module"); + goto done; + } + + rgba_type = PyObject_GetAttrString(gdk_mod, "RGBA"); + + Py_DECREF(gdk_mod); + + rgba_args = PyTuple_New(4); + PyTuple_SetItem(rgba_args, 0, PyFloat_FromDouble(color.red)); + PyTuple_SetItem(rgba_args, 1, PyFloat_FromDouble(color.green)); + PyTuple_SetItem(rgba_args, 2, PyFloat_FromDouble(color.blue)); + PyTuple_SetItem(rgba_args, 3, PyFloat_FromDouble(color.alpha)); + + result = PyObject_CallObject(rgba_type, rgba_args); + + Py_DECREF(rgba_args); + + } + + else + { + done: + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = NULL car méthode statique. * +* args = paramètres à transmettre à l'appel natif. * +* * * Description : Détermine l'indice d'un composant dans un conteneur GTK. * * * * Retour : Indice du composant dans le conteneur ou -1 si non trouvé. * @@ -165,6 +249,7 @@ static PyObject *py_easygtk_get_nth_contained_child(PyObject *self, PyObject *ar PyTypeObject *get_python_easygtk_type(void) { static PyMethodDef py_easygtk_methods[] = { + EASYGTK_GET_COLOR_FROM_STYLE_METHOD, EASYGTK_FIND_CONTAINED_CHILD_INDEX_METHOD, EASYGTK_GET_NTH_CONTAINED_CHILD_METHOD, { NULL } diff --git a/src/gtkext/easygtk.c b/src/gtkext/easygtk.c index 6e42556..3a17a72 100644 --- a/src/gtkext/easygtk.c +++ b/src/gtkext/easygtk.c @@ -25,6 +25,7 @@ #include +#include #include "support.h" @@ -757,9 +758,125 @@ GtkWidget *qck_create_menu_separator(void) +/****************************************************************************** +* * +* Paramètres : class = classe de style à appliquer. * +* background = indique la nature de la couleur à relever. * +* color = couleur associée au style indiqué. [OUT] * +* * +* Description : Identifie la couleur de base associée à un style GTK. * +* * +* Retour : Bilan présumé de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool get_color_from_style(const char *class, bool background, GdkRGBA *color) +{ + bool result; /* Bilan à retourner */ + GtkWidget *area; /* Composant pour le contexte */ + GtkStyleContext *context; /* Contexte de style GTK */ + cairo_surface_t *surface; /* Surface de dessin temporaire*/ + cairo_t *cr; /* Pinceau pour le dessin */ + uint32_t *pixel; /* Valeurs pour un pixel choisi*/ + int a; /* Valeur du canal alpha */ + int r; /* Valeur du canal rouge */ + int g; /* Valeur du canal vert */ + int b; /* Valeur du canal bleu */ + + result = false; + + /* Mise en place de l'environnement */ + + area = gtk_drawing_area_new(); + g_object_ref_sink(G_OBJECT(area)); + + context = gtk_widget_get_style_context (area); + + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 20, 20); + + if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) + goto empty_surface; + + cr = cairo_create(surface); + + if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) + goto bad_cairo; + + /* Dessin */ + + gtk_style_context_add_class(context, class); + + if (background) + gtk_render_background(context, cr, 0, 0, 20, 20); + else + gtk_render_line(context, cr, -0.5, -0.5, 19.5, 19.5); + cairo_surface_flush(surface); + /* Récupération du pixel (0 ; 0) */ + pixel = (uint32_t *)cairo_image_surface_get_data(surface); + + /* Récupération des valeurs de couleur */ + + a = (*pixel & 0xff000000) >> 24; + r = (*pixel & 0x00ff0000) >> 16; + g = (*pixel & 0x0000ff00) >> 8; + b = (*pixel & 0x000000ff); + + if (a == 0) + { + r = 0; + g = 0; + b = 0; + + } + else + { + /** + * Utilisation de la méthode employée dans la fonction + * _cairo_image_analyze_color() de cairo-image-surface.c. + * + * La documentation pour CAIRO_FORMAT_ARGB32 précise en effet : + * + * """ + * each pixel is a 32-bit quantity, with alpha in the upper 8 bits, + * then red, then green, then blue. The 32-bit quantities are + * native-endian. Pre-multiplied alpha is used. (That is, 50% + * transparent red is 0x80800000, not 0x80ff0000.) + * """ + */ + + r = (r * 255 + a / 2) / a; + g = (g * 255 + a / 2) / a; + b = (b * 255 + a / 2) / a; + + } + + color->alpha = (1.0 * a) / 0xff; + color->red = (1.0 * r) / 0xff; + color->green = (1.0 * g) / 0xff; + color->blue = (1.0 * b) / 0xff; + + result = true; + + /* Renvoi des conclusions */ + + bad_cairo: + + cairo_destroy(cr); + + empty_surface: + + cairo_surface_destroy(surface); + + g_object_unref(G_OBJECT(area)); + + return result; + +} /****************************************************************************** diff --git a/src/gtkext/easygtk.h b/src/gtkext/easygtk.h index f8c2212..f181d43 100644 --- a/src/gtkext/easygtk.h +++ b/src/gtkext/easygtk.h @@ -25,6 +25,7 @@ #define _GTKEXT_EASYGTK_H +#include #include @@ -92,6 +93,10 @@ GtkWidget *qck_create_menu_separator(void); + +/* Identifie la couleur de base associée à un style GTK. */ +bool get_color_from_style(const char *, bool, GdkRGBA *); + /* Détermine l'indice d'un composant dans un conteneur GTK. */ gint find_contained_child_index(GtkContainer *, GtkWidget *); -- cgit v0.11.2-87-g4458