From 6c751d40ab1b84a6979c143ed47702207edebed8 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 14 Jul 2020 15:06:20 +0200
Subject: Updated the Python bindings for the loaded panel interface.

---
 plugins/pychrysalide/analysis/storage/serialize.c |   1 -
 plugins/pychrysalide/glibext/constants.c          | 135 +++++++++++++--
 plugins/pychrysalide/glibext/constants.h          |  14 +-
 plugins/pychrysalide/glibext/loadedpanel.c        | 191 +++++++++++++++++-----
 4 files changed, 277 insertions(+), 64 deletions(-)

diff --git a/plugins/pychrysalide/analysis/storage/serialize.c b/plugins/pychrysalide/analysis/storage/serialize.c
index 3e94271..eeab8f5 100644
--- a/plugins/pychrysalide/analysis/storage/serialize.c
+++ b/plugins/pychrysalide/analysis/storage/serialize.c
@@ -56,7 +56,6 @@ static bool py_serializable_object_store_wrapper(const GSerializableObject *, GO
 /* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
 
 
-
 /* Charge un objet depuis une mémoire tampon. */
 static bool py_serializable_object_load(PyObject *, PyObject *);
 
diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c
index 47bd00d..a7938cb 100644
--- a/plugins/pychrysalide/glibext/constants.c
+++ b/plugins/pychrysalide/glibext/constants.c
@@ -25,9 +25,11 @@
 #include "constants.h"
 
 
+#include <i18n.h>
 #include <glibext/linesegment.h>
 #include <glibext/gbinportion.h>
 #include <glibext/gbufferline.h>
+#include <glibext/gloadedpanel.h>
 
 
 #include "../helpers.h"
@@ -148,6 +150,105 @@ int convert_to_portion_access_rights(PyObject *arg, void *dst)
 *                                                                             *
 *  Paramètres  : type = type dont le dictionnaire est à compléter.            *
 *                                                                             *
+*  Description : Définit les constantes relatives aux lignes de tampon.       *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool define_buffer_line_constants(PyTypeObject *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *values;                       /* Groupe de valeurs à établir */
+
+    values = PyDict_New();
+
+    result = add_const_to_group(values, "NONE", BLF_NONE);
+    if (result) result = add_const_to_group(values, "HAS_CODE", BLF_HAS_CODE);
+    if (result) result = add_const_to_group(values, "IS_LABEL", BLF_IS_LABEL);
+    if (result) result = add_const_to_group(values, "ENTRYPOINT", BLF_ENTRYPOINT);
+    if (result) result = add_const_to_group(values, "BOOKMARK", BLF_BOOKMARK);
+    if (result) result = add_const_to_group(values, "WIDTH_MANAGER", BLF_WIDTH_MANAGER);
+    if (result) result = add_const_to_group(values, "ALL", BLF_ALL);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group_to_type(type, true, "BufferLineFlags", values,
+                                            "Optional flags linked to a rendering line.");
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en constante BufferLineFlags.             *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_buffer_line_flags(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+    unsigned long value;                    /* Valeur transcrite           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type);
+
+    switch (result)
+    {
+        case -1:
+            /* L'exception est déjà fixée par Python */
+            result = 0;
+            break;
+
+        case 0:
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to BufferLineFlags");
+            break;
+
+        case 1:
+            value = PyLong_AsUnsignedLong(arg);
+
+            if ((value & BLF_ALL) != value)
+            {
+                PyErr_SetString(PyExc_TypeError, "invalid value for BufferLineFlags");
+                result = 0;
+            }
+
+            else
+                *((BufferLineFlags *)dst) = value;
+
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type dont le dictionnaire est à compléter.            *
+*                                                                             *
 *  Description : Définit les constantes relatives aux segments de ligne.      *
 *                                                                             *
 *  Retour      : true en cas de succès de l'opération, false sinon.           *
@@ -258,7 +359,7 @@ int convert_to_rendering_tag_type(PyObject *arg, void *dst)
 *                                                                             *
 *  Paramètres  : type = type dont le dictionnaire est à compléter.            *
 *                                                                             *
-*  Description : Définit les constantes relatives aux lignes de tampon.       *
+*  Description : Définit les constantes relatives aux panneaux de chargement. *
 *                                                                             *
 *  Retour      : true en cas de succès de l'opération, false sinon.           *
 *                                                                             *
@@ -266,20 +367,17 @@ int convert_to_rendering_tag_type(PyObject *arg, void *dst)
 *                                                                             *
 ******************************************************************************/
 
-bool define_buffer_line_constants(PyTypeObject *type)
+bool define_loaded_panel_constants(PyTypeObject *type)
 {
     bool result;                            /* Bilan à retourner           */
     PyObject *values;                       /* Groupe de valeurs à établir */
 
     values = PyDict_New();
 
-    result = add_const_to_group(values, "NONE", BLF_NONE);
-    if (result) result = add_const_to_group(values, "HAS_CODE", BLF_HAS_CODE);
-    if (result) result = add_const_to_group(values, "IS_LABEL", BLF_IS_LABEL);
-    if (result) result = add_const_to_group(values, "ENTRYPOINT", BLF_ENTRYPOINT);
-    if (result) result = add_const_to_group(values, "BOOKMARK", BLF_BOOKMARK);
-    if (result) result = add_const_to_group(values, "WIDTH_MANAGER", BLF_WIDTH_MANAGER);
-    if (result) result = add_const_to_group(values, "ALL", BLF_ALL);
+    result = add_const_to_group(values, "RAW", SPT_RAW);
+    if (result) result = add_const_to_group(values, "TOP", SPT_TOP);
+    if (result) result = add_const_to_group(values, "CENTER", SPT_CENTER);
+    if (result) result = add_const_to_group(values, "BOTTOM", SPT_BOTTOM);
 
     if (!result)
     {
@@ -287,8 +385,8 @@ bool define_buffer_line_constants(PyTypeObject *type)
         goto exit;
     }
 
-    result = attach_constants_group_to_type(type, true, "BufferLineFlags", values,
-                                            "Optional flags linked to a rendering line.");
+    result = attach_constants_group_to_type(type, false, "ScrollPositionTweak", values,
+                                            "Details for adjusting the displayed position while scrolling.");
 
  exit:
 
@@ -302,7 +400,7 @@ bool define_buffer_line_constants(PyTypeObject *type)
 *  Paramètres  : arg = argument quelconque à tenter de convertir.             *
 *                dst = destination des valeurs récupérées en cas de succès.   *
 *                                                                             *
-*  Description : Tente de convertir en constante BufferLineFlags.             *
+*  Description : Tente de convertir en constante ScrollPositionTweak.         *
 *                                                                             *
 *  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
 *                                                                             *
@@ -310,10 +408,10 @@ bool define_buffer_line_constants(PyTypeObject *type)
 *                                                                             *
 ******************************************************************************/
 
-int convert_to_buffer_line_flags(PyObject *arg, void *dst)
+int convert_to_scroll_position_tweak(PyObject *arg, void *dst)
 {
     int result;                             /* Bilan à retourner           */
-    unsigned long value;                    /* Valeur transcrite           */
+    unsigned long value;                    /* Valeur récupérée            */
 
     result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type);
 
@@ -325,20 +423,21 @@ int convert_to_buffer_line_flags(PyObject *arg, void *dst)
             break;
 
         case 0:
-            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to BufferLineFlags");
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ScrollPositionTweak");
             break;
 
         case 1:
+
             value = PyLong_AsUnsignedLong(arg);
 
-            if ((value & BLF_ALL) != value)
+            if (!IS_VALID_STP(value))
             {
-                PyErr_SetString(PyExc_TypeError, "invalid value for BufferLineFlags");
                 result = 0;
+                PyErr_SetString(PyExc_ValueError, _("invalid position tweak"));
             }
 
             else
-                *((BufferLineFlags *)dst) = value;
+                *((ScrollPositionTweak *)dst) = value;
 
             break;
 
diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h
index b815586..f509866 100644
--- a/plugins/pychrysalide/glibext/constants.h
+++ b/plugins/pychrysalide/glibext/constants.h
@@ -37,17 +37,23 @@ bool define_binary_portion_constants(PyTypeObject *);
 /* Tente de convertir en constante PortionAccessRights. */
 int convert_to_portion_access_rights(PyObject *, void *);
 
+/* Définit les constantes relatives aux lignes de tampon. */
+bool define_buffer_line_constants(PyTypeObject *);
+
+/* Tente de convertir en constante BufferLineFlags. */
+int convert_to_buffer_line_flags(PyObject *, void *);
+
 /* Définit les constantes relatives aux segments de ligne. */
 bool define_line_segment_constants(PyTypeObject *);
 
 /* Tente de convertir en constante RenderingTagType. */
 int convert_to_rendering_tag_type(PyObject *, void *);
 
-/* Définit les constantes relatives aux lignes de tampon. */
-bool define_buffer_line_constants(PyTypeObject *);
+/* Définit les constantes relatives aux panneaux de chargement. */
+bool define_loaded_panel_constants(PyTypeObject *);
 
-/* Tente de convertir en constante BufferLineFlags. */
-int convert_to_buffer_line_flags(PyObject *, void *);
+/* Tente de convertir en constante ScrollPositionTweak. */
+int convert_to_scroll_position_tweak(PyObject *, void *);
 
 
 
diff --git a/plugins/pychrysalide/glibext/loadedpanel.c b/plugins/pychrysalide/glibext/loadedpanel.c
index d6b743b..6e87cde 100644
--- a/plugins/pychrysalide/glibext/loadedpanel.c
+++ b/plugins/pychrysalide/glibext/loadedpanel.c
@@ -30,29 +30,46 @@
 
 
 #include <i18n.h>
-#include <glibext/gloadedpanel.h>
+#include <glibext/gloadedpanel-int.h>
 
 
+#include "constants.h"
 #include "linecursor.h"
 #include "../access.h"
 #include "../helpers.h"
 
 
 
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Procède à l'initialisation de l'interface de génération. */
+static void py_loaded_panel_interface_init(GLoadedPanelIface *, gpointer *);
+
+/* S'assure qu'un emplacement donné est visible à l'écran. */
+static void py_loaded_panel_scroll_to_cursor_wrapper(GLoadedPanel *, const GLineCursor *, ScrollPositionTweak, bool);
+
+
+
+/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */
+
+
 /* S'assure qu'un emplacement donné est visible à l'écran. */
 static PyObject *py_loaded_panel_scroll_to_cursor(PyObject *, PyObject *);
 
-/* Définit les constantes pour l'affichage des contenus chargés. */
-static bool py_loaded_panel_define_constants(PyTypeObject *);
 
 
+/* ---------------------------------------------------------------------------------- */
+/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
+/* ---------------------------------------------------------------------------------- */
+
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = classe représentant un tampon de code.                *
-*                args = arguments fournis à l'appel.                          *
+*  Paramètres  : iface  = interface GLib à initialiser.                       *
+*                unused = adresse non utilisée ici.                           *
 *                                                                             *
-*  Description : S'assure qu'un emplacement donné est visible à l'écran.      *
+*  Description : Procède à l'initialisation de l'interface de génération.     *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -60,56 +77,143 @@ static bool py_loaded_panel_define_constants(PyTypeObject *);
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_loaded_panel_scroll_to_cursor(PyObject *self, PyObject *args)
+static void py_loaded_panel_interface_init(GLoadedPanelIface *iface, gpointer *unused)
 {
-    GLineCursor *cursor;                    /* Emplacement à cibler        */
-    unsigned long tweak;                    /* Adapation à effectuer       */
-    int move;                               /* Déplacement à l'écran ?     */
-    int ret;                                /* Bilan de lecture des args.  */
-    GLoadedPanel *panel;                    /* Panneau à manipuler         */
 
-    ret = PyArg_ParseTuple(args, "O&kp", convert_to_line_cursor, &cursor, &tweak, &move);
-    if (!ret) return NULL;
+#define LOADED_PANEL_DOC                                                    \
+    "LoadPanel defines an interface for all panels which can be included"   \
+    " inside the main graphical window.\n"                                  \
+    "\n"                                                                    \
+    "A typical class declaration for a new implementation looks like:\n"    \
+    "\n"                                                                    \
+    "    class NewImplem(GObject.Object, LoadedPanel():\n"                  \
+    "        ...\n"                                                         \
+    "\n"                                                                    \
+    "The following methods have to be defined for new implementations:\n"   \
+    "* pychrysalide.glibext.LoadedPanel._scroll_to_cursor();\n"
+
+    iface->scroll = py_loaded_panel_scroll_to_cursor_wrapper;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : panel  = composant GTK à manipuler.                          *
+*                cursor = emplacement à présenter à l'écran.                  *
+*                tweak  = adaptation finale à effectuer.                      *
+*                move   = doit-on déplacer le curseur à l'adresse indiquée ?  *
+*                                                                             *
+*  Description : S'assure qu'un emplacement donné est visible à l'écran.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    if (!IS_VALID_STP(tweak))
+static void py_loaded_panel_scroll_to_cursor_wrapper(GLoadedPanel *panel, const GLineCursor *cursor, ScrollPositionTweak tweak, bool move)
+{
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *tweak_obj;                    /* Détails en versionPython    */
+    PyObject *move_obj;                     /* Consigne de déplacement     */
+    PyObject *args;                         /* Arguments pour l'appel      */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *pyret;                        /* Bilan de consultation       */
+
+#define LOADED_PANEL_SCROLL_TO_CURSOR_WRAPPER PYTHON_WRAPPER_DEF                \
+(                                                                               \
+    _scroll_to_cursor, "$self, cursor, tweak, move, /",                         \
+    METH_VARARGS,                                                               \
+    "Abstract method used to ensure a given address is displayed in the view"   \
+    " panel.\n"                                                                 \
+    "\n"                                                                        \
+    "The *cursor* argument is a pychrysalide.glibext.LineCursor location. The"  \
+    " *tweak* parameter defines the final adjustment for new location and the"  \
+    " *move* order is a boolean value which implies a scroll operation if"      \
+    " requiered."                                                               \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(panel));
+
+    if (has_python_method(pyobj, "_scroll_to_cursor"))
     {
-        PyErr_SetString(PyExc_ValueError, _("invalid position tweak"));
-        return NULL;
-    }
+        tweak_obj = cast_with_constants_group_from_type(get_python_loaded_panel_type(),
+                                                        "ScrollPositionTweak", tweak);
 
-    panel = G_LOADED_PANEL(pygobject_get(self));
+        move_obj = (move ? Py_True : Py_False);
+        Py_INCREF(move_obj);
 
-    g_loaded_panel_scroll_to_cursor(panel, cursor, tweak, move);
+        args = PyTuple_New(3);
+        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(cursor)));
+        PyTuple_SetItem(args, 1, tweak_obj);
+        PyTuple_SetItem(args, 2, move_obj);
 
-    Py_RETURN_NONE;
+        pyret = run_python_method(pyobj, "_scroll_to_cursor", args);
+
+        Py_XDECREF(pyret);
+
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
 
 }
 
 
+
+/* ---------------------------------------------------------------------------------- */
+/*                           CONNEXION AVEC L'API DE PYTHON                           */
+/* ---------------------------------------------------------------------------------- */
+
+
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : obj_type = type dont le dictionnaire est à compléter.        *
+*  Paramètres  : self = classe représentant un tampon de code.                *
+*                args = arguments fournis à l'appel.                          *
 *                                                                             *
-*  Description : Définit les constantes pour l'affichage des contenus chargés.*
+*  Description : S'assure qu'un emplacement donné est visible à l'écran.      *
 *                                                                             *
-*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool py_loaded_panel_define_constants(PyTypeObject *obj_type)
+static PyObject *py_loaded_panel_scroll_to_cursor(PyObject *self, PyObject *args)
 {
-    bool result;                            /* Bilan à retourner           */
+    GLineCursor *cursor;                    /* Emplacement à cibler        */
+    ScrollPositionTweak tweak;              /* Adapation à effectuer       */
+    int move;                               /* Déplacement à l'écran ?     */
+    int ret;                                /* Bilan de lecture des args.  */
+    GLoadedPanel *panel;                    /* Panneau à manipuler         */
+
+#define LOADED_PANEL_SCROLL_TO_CURSOR_METHOD PYTHON_METHOD_DEF                  \
+(                                                                               \
+    scroll_to_cursor, "$self, cursor, tweak, move, /",                          \
+    METH_VARARGS, py_loaded_panel,                                              \
+    "Ensure a given address is displayed in the view panel.\n"                  \
+    "\n"                                                                        \
+    "The *cursor* argument is a pychrysalide.glibext.LineCursor location. The"  \
+    " *tweak* parameter defines the final adjustment for new location and the"  \
+    " *move* order is a boolean value which implies a scroll operation if"      \
+    " requiered."                                                               \
+)
+
+    ret = PyArg_ParseTuple(args, "O&O&p", convert_to_line_cursor, &cursor,
+                           convert_to_scroll_position_tweak, &tweak, &move);
+    if (!ret) return NULL;
 
-    result = true;
+    panel = G_LOADED_PANEL(pygobject_get(self));
 
-    result &= PyDict_AddULongMacro(obj_type, SPT_RAW);
-    result &= PyDict_AddULongMacro(obj_type, SPT_TOP);
-    result &= PyDict_AddULongMacro(obj_type, SPT_CENTER);
-    result &= PyDict_AddULongMacro(obj_type, SPT_BOTTOM);
+    g_loaded_panel_scroll_to_cursor(panel, cursor, tweak, move);
 
-    return result;
+    Py_RETURN_NONE;
 
 }
 
@@ -129,11 +233,8 @@ static bool py_loaded_panel_define_constants(PyTypeObject *obj_type)
 PyTypeObject *get_python_loaded_panel_type(void)
 {
     static PyMethodDef py_loaded_panel_methods[] = {
-        {
-            "scroll_to_cursor", py_loaded_panel_scroll_to_cursor,
-            METH_VARARGS,
-            "scroll_to_cursor($self, cursor, tweak, move, /)\n--\n\nEnsure a given address is displayed in the view panel."
-        },
+        LOADED_PANEL_SCROLL_TO_CURSOR_WRAPPER,
+        LOADED_PANEL_SCROLL_TO_CURSOR_METHOD,
         { NULL }
     };
 
@@ -146,11 +247,11 @@ PyTypeObject *get_python_loaded_panel_type(void)
         PyVarObject_HEAD_INIT(NULL, 0)
 
         .tp_name        = "pychrysalide.glibext.LoadedPanel",
-        //.tp_basicsize   = sizeof(PyGObject),
+        .tp_basicsize   = sizeof(PyObject),
 
         .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 
-        .tp_doc         = "PyChrysalide loaded panel",
+        .tp_doc         = LOADED_PANEL_DOC,
 
         .tp_methods     = py_loaded_panel_methods,
         .tp_getset      = py_loaded_panel_getseters,
@@ -180,6 +281,14 @@ bool ensure_python_loaded_panel_is_registered(void)
     PyObject *module;                       /* Module à recompléter        */
     PyObject *dict;                         /* Dictionnaire du module      */
 
+    static GInterfaceInfo info = {          /* Paramètres d'inscription    */
+
+        .interface_init = (GInterfaceInitFunc)py_loaded_panel_interface_init,
+        .interface_finalize = NULL,
+        .interface_data = NULL,
+
+    };
+
     type = get_python_loaded_panel_type();
 
     if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
@@ -188,10 +297,10 @@ bool ensure_python_loaded_panel_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
-        if (!register_interface_for_pygobject(dict, G_TYPE_LOADED_PANEL, type))
+        if (!register_interface_for_pygobject_2(dict, G_TYPE_LOADED_PANEL, type, &info))
             return false;
 
-        if (!py_loaded_panel_define_constants(type))
+        if (!define_loaded_panel_constants(type))
             return false;
 
     }
-- 
cgit v0.11.2-87-g4458