summaryrefslogtreecommitdiff
path: root/src/gtkext
diff options
context:
space:
mode:
Diffstat (limited to 'src/gtkext')
-rw-r--r--src/gtkext/Makefile.am22
-rw-r--r--src/gtkext/area.c2
-rw-r--r--src/gtkext/bindings/Makefile.am42
-rw-r--r--src/gtkext/bindings/generated-enums.c.template41
-rw-r--r--src/gtkext/bindings/generated-enums.h.template23
-rw-r--r--src/gtkext/bufferview.c6
-rw-r--r--src/gtkext/dockstation-int.h18
-rw-r--r--src/gtkext/dockstation.c472
-rw-r--r--src/gtkext/dockstation.h11
-rw-r--r--src/gtkext/dockstation.ui80
-rw-r--r--src/gtkext/gresource.xml9
-rw-r--r--src/gtkext/grid-int.h42
-rw-r--r--src/gtkext/grid.c1310
-rw-r--r--src/gtkext/grid.h46
-rw-r--r--src/gtkext/grid.ui217
-rw-r--r--src/gtkext/hexview.c293
-rw-r--r--src/gtkext/hexview.h6
-rw-r--r--src/gtkext/hexview.ui52
-rw-r--r--src/gtkext/launcher-int.h56
-rw-r--r--src/gtkext/launcher.c211
-rw-r--r--src/gtkext/launcher.h45
-rw-r--r--src/gtkext/launcher.ui76
-rw-r--r--src/gtkext/panel-int.h10
-rw-r--r--src/gtkext/panel.c57
-rw-r--r--src/gtkext/panel.h7
-rw-r--r--src/gtkext/statusstack-int.h12
-rw-r--r--src/gtkext/statusstack.c310
-rw-r--r--src/gtkext/statusstack.h10
-rw-r--r--src/gtkext/statusstack.ui29
-rw-r--r--src/gtkext/tweak-int.h65
-rw-r--r--src/gtkext/tweak.c319
-rw-r--r--src/gtkext/tweak.h90
-rw-r--r--src/gtkext/tweak.ui46
33 files changed, 3173 insertions, 862 deletions
diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am
index fd6c575..c6908dd 100644
--- a/src/gtkext/Makefile.am
+++ b/src/gtkext/Makefile.am
@@ -26,10 +26,19 @@ libgtkext_la_LIBADD = \
libgtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)
+IMG_PATH = ../../data/images
+
RES_FILES = \
+ grid.ui \
+ dockstation.ui \
hexview.css \
hexview.ui \
- statusstack.ui
+ launcher.ui \
+ statusstack.ui \
+ $(IMG_PATH)/nolock-symbolic.svg \
+ $(IMG_PATH)/locked-symbolic.svg \
+ $(IMG_PATH)/unlocked-symbolic.svg \
+ tweak.ui
libgtkext4_la_SOURCES = \
area-int.h \
@@ -45,13 +54,21 @@ libgtkext4_la_SOURCES = \
helpers.h \
hexview-int.h \
hexview.h hexview.c \
+ launcher-int.h \
+ launcher.h launcher.c \
panel-int.h \
panel.h panel.c \
resources.h resources.c \
- statusstack.h statusstack.c
+ statusstack-int.h \
+ statusstack.h statusstack.c \
+ tweak-int.h \
+ tweak.h tweak.c
libgtkext4_la_CFLAGS = $(LIBGTK4_CFLAGS)
+libgtkext4_la_LIBADD = \
+ bindings/libgtkextbindings.la
+
devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
@@ -59,6 +76,7 @@ dev_HEADERS = $(libgtkext4_la_SOURCES:%c=)
#SUBDIRS = graph
+SUBDIRS = bindings
resources.c: gresource.xml $(RES_FILES)
diff --git a/src/gtkext/area.c b/src/gtkext/area.c
index 3c59a59..3c573b2 100644
--- a/src/gtkext/area.c
+++ b/src/gtkext/area.c
@@ -85,6 +85,8 @@ static void gtk_composing_area_class_init(GtkComposingAreaClass *class)
widget = GTK_WIDGET_CLASS(class);
+ gtk_widget_class_set_css_name(widget, "comparea");
+
widget->snapshot = gtk_composing_area_snapshot;
}
diff --git a/src/gtkext/bindings/Makefile.am b/src/gtkext/bindings/Makefile.am
new file mode 100644
index 0000000..71e770d
--- /dev/null
+++ b/src/gtkext/bindings/Makefile.am
@@ -0,0 +1,42 @@
+
+EXTRA_DIST = \
+ generated-enums.c.template \
+ generated-enums.h.template
+
+
+noinst_LTLIBRARIES = libgtkextbindings.la
+
+
+nodist_libgtkextbindings_la_SOURCES = \
+ grid-enums.h grid-enums.c
+
+libgtkextbindings_la_CFLAGS = $(LIBGTK4_CFLAGS)
+
+
+BUILT_SOURCES = $(nodist_libgtkextbindings_la_SOURCES)
+CLEANFILES = $(nodist_libgtkextbindings_la_SOURCES)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(nodist_libgtkextbindings_la_SOURCES:%c=)
+
+
+grid-enums.c: ../../gtkext/grid.h generated-enums.c.template
+ $(AM_V_GEN)$(GLIB_MKENUMS) \
+ --fhead "#include \"$(subst .c,.h,$@)\"\n" \
+ --template=$(srcdir)/generated-enums.c.template \
+ --output=$(srcdir)/$@ \
+ $<
+
+grid-enums.h: ../../gtkext/grid.h generated-enums.h.template
+ $(AM_V_GEN)$(GLIB_MKENUMS) \
+ --fhead "#ifndef _GTKEXT_BINDINGS_GRID_ENUM_H\n" \
+ --fhead "#define _GTKEXT_BINDINGS_GRID_ENUM_H\n" \
+ --fhead "\n" \
+ --fhead "#include \"$<\"\n" \
+ --fhead "\n" \
+ --ftail "#endif /* _GTKEXT_BINDINGS_GRID_ENUM_H */\n" \
+ --template=$(srcdir)/generated-enums.h.template \
+ --output=$(srcdir)/$@ \
+ $<
diff --git a/src/gtkext/bindings/generated-enums.c.template b/src/gtkext/bindings/generated-enums.c.template
new file mode 100644
index 0000000..8f54149
--- /dev/null
+++ b/src/gtkext/bindings/generated-enums.c.template
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/*** BEGIN file-header ***/
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* Enumerations de "@filename@" */
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+
+GType @enum_name@_get_type(void)
+{
+ static gsize static_g_@type@_type_id;
+
+ if (g_once_init_enter(&static_g_@type@_type_id)) {
+ static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ {@VALUENAME@, "@VALUENAME@", "@valuenick@"},
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+
+ GType g_@type@_type_id = g_@type@_register_static(
+ g_intern_static_string("@EnumName@"), values);
+
+ g_once_init_leave (&static_g_@type@_type_id, g_@type@_type_id);
+ }
+
+ return static_g_@type@_type_id;
+}
+
+/*** END value-tail ***/
diff --git a/src/gtkext/bindings/generated-enums.h.template b/src/gtkext/bindings/generated-enums.h.template
new file mode 100644
index 0000000..58c772d
--- /dev/null
+++ b/src/gtkext/bindings/generated-enums.h.template
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2023-2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+/*** BEGIN file-header ***/
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type(void) G_GNUC_CONST;
+#define @ENUMPREFIX@_@ENUMSHORT@_TYPE (@enum_name@_get_type())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+
+G_END_DECLS
+
+/*** END file-tail ***/
diff --git a/src/gtkext/bufferview.c b/src/gtkext/bufferview.c
index 6b8f17c..13c2632 100644
--- a/src/gtkext/bufferview.c
+++ b/src/gtkext/bufferview.c
@@ -279,9 +279,9 @@ GBufferView *gtk_buffer_view_get_view(const GtkBufferView *view)
/******************************************************************************
* *
-* Paramètres : widget = composant GTK à examiner. *
-* width = largeur affectée au composant graphique. *
-* height = hauteur affectée au composant graphique. *
+* Paramètres : widget = composant GTK à examiner. *
+* width = largeur affectée au composant graphique. *
+* height = hauteur affectée au composant graphique. *
* baseline = ligne de base affectée au composant graphique. *
* *
* Description : Prend acte de la taille allouée au composant d'affichage. *
diff --git a/src/gtkext/dockstation-int.h b/src/gtkext/dockstation-int.h
index a44371a..17ed828 100644
--- a/src/gtkext/dockstation-int.h
+++ b/src/gtkext/dockstation-int.h
@@ -32,19 +32,29 @@
/* Station de réception pour concentration d'éléments (instance) */
struct _GtkDockStation
{
- GtkWidget parent; /* A laisser en premier */
+ GtkBox parent; /* A laisser en premier */
+
+ GtkOrientation orientation; /* Spécification d'orientation */
+
+ GtkWidget *tabs; /* Bascule entre panneaux */
+ GtkWidget *toolbar; /* Boutons d'action */
+ GtkWidget *sep1; /* Séparateur #1 */
+ GtkStack *stack; /* Pile de panneaux affichés */
+ GtkWidget *sep2; /* Séparateur #2 */
+
+ GtkTiledPanel *def_panel; /* Eventuel panneau à maintenir*/
};
/* Station de réception pour concentration d'éléments (classe) */
struct _GtkDockStationClass
{
- GtkWidgetClass parent; /* A laisser en premier */
+ GtkBoxClass parent; /* A laisser en premier */
/* Signaux */
- void (* dock_widget) (GtkDockStation *, GtkWidget *);
- void (* undock_widget) (GtkDockStation *, GtkWidget *);
+ void (* panel_docked) (GtkDockStation *, GtkTiledPanel *);
+ void (* panel_undocked) (GtkDockStation *, GtkTiledPanel *);
void (* switch_widget) (GtkDockStation *, GtkWidget *);
diff --git a/src/gtkext/dockstation.c b/src/gtkext/dockstation.c
index 093f120..80bae75 100644
--- a/src/gtkext/dockstation.c
+++ b/src/gtkext/dockstation.c
@@ -28,6 +28,25 @@
+/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
+
+
+/* Liste des propriétés */
+
+typedef enum _DockStationProperty {
+
+ PROP_0, /* Réservé */
+
+ /* Interface GtkOrientable */
+ PROP_ORIENTATION,
+
+ N_PROPERTIES = PROP_ORIENTATION
+
+} DockStationProperty;
+
+//static GParamSpec *_dock_station_properties[N_PROPERTIES] = { NULL, };
+
+
/* Procède à l'initialisation de l'afficheur concentré. */
static void gtk_dock_station_class_init(GtkDockStationClass *);
@@ -35,16 +54,31 @@ static void gtk_dock_station_class_init(GtkDockStationClass *);
static void gtk_dock_station_init(GtkDockStation *);
/* Supprime toutes les références externes. */
-static void gtk_dock_station_dispose(GtkDockStation *);
+static void gtk_dock_station_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_dock_station_finalize(GtkDockStation *);
+static void gtk_dock_station_finalize(GObject *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Met à jour une propriété d'instance GObject. */
+static void gtk_dock_station_set_property(GObject *, guint, const GValue *, GParamSpec *);
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_dock_station_get_property(GObject *, guint, GValue *, GParamSpec *);
+/* ---------------------------------------------------------------------------------- */
+/* INTERFACE DU COMPOSANT GTK */
+/* ---------------------------------------------------------------------------------- */
+
+
/* Détermine le type du composant d'affichage concentré. */
-G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_WIDGET)
+G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_GRID)
/******************************************************************************
@@ -62,28 +96,47 @@ G_DEFINE_TYPE(GtkDockStation, gtk_dock_station, GTK_TYPE_WIDGET)
static void gtk_dock_station_class_init(GtkDockStationClass *class)
{
GObjectClass *object; /* Autre version de la classe */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_dock_station_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_dock_station_finalize;
+ object->dispose = gtk_dock_station_dispose;
+ object->finalize = gtk_dock_station_finalize;
+ object->set_property = gtk_dock_station_set_property;
+ object->get_property = gtk_dock_station_get_property;
- g_signal_new("dock-widget",
+ //g_object_class_install_properties(object, N_PROPERTIES, _dock_station_properties);
+ g_object_class_override_property(object, PROP_ORIENTATION, "orientation");
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/dockstation.ui");
+
+ //gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_status_stack_on_zoom_icon_press));
+
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, tabs);
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, toolbar);
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, sep1);
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, stack);
+ gtk_widget_class_bind_template_child(widget, GtkDockStation, sep2);
+
+ g_signal_new("panel-docked",
GTK_TYPE_DOCK_STATION,
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GtkDockStationClass, dock_widget),
+ G_STRUCT_OFFSET(GtkDockStationClass, panel_docked),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
- g_signal_new("undock-widget",
+ g_signal_new("panel-undocked",
GTK_TYPE_DOCK_STATION,
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GtkDockStationClass, undock_widget),
+ G_STRUCT_OFFSET(GtkDockStationClass, panel_undocked),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
+ /*
g_signal_new("switch-widget",
GTK_TYPE_DOCK_STATION,
G_SIGNAL_RUN_LAST,
@@ -107,6 +160,7 @@ static void gtk_dock_station_class_init(GtkDockStationClass *class)
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
+ */
}
@@ -125,57 +179,66 @@ static void gtk_dock_station_class_init(GtkDockStationClass *class)
static void gtk_dock_station_init(GtkDockStation *station)
{
-#if 0
+ gtk_widget_init_template(GTK_WIDGET(station));
- GtkNotebook *notebook; /* Autre version du composant */
- GtkWidget *hbox; /* Division supérieure */
- GtkWidget *button; /* Bouton de contrôle */
+ station->orientation = GTK_ORIENTATION_HORIZONTAL;
- notebook = GTK_NOTEBOOK(station);
+ station->def_panel = NULL;
- gtk_notebook_set_show_border(notebook, FALSE);
- gtk_notebook_set_scrollable(notebook, TRUE);
+}
- /* Définition de la zone de contrôle */
- hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_widget_set_valign(hbox, GTK_ALIGN_CENTER);
- gtk_widget_set_margin_end(hbox, 8);
- gtk_widget_show(hbox);
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- button = qck_create_toggle_button_with_named_img(G_OBJECT(station), "search",
- "edit-find-symbolic", GTK_ICON_SIZE_MENU, NULL,
- G_CALLBACK(on_toggle_revealer), station);
- gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+static void gtk_dock_station_dispose(GObject *object)
+{
+ GtkDockStation *station; /* Version spécialisée */
- button = qck_create_button_with_named_img(G_OBJECT(station), "menu",
- "go-down-symbolic", GTK_ICON_SIZE_MENU, NULL,
- G_CALLBACK(on_click_for_menu), station);
- gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ station = GTK_DOCK_STATION(object);
- button = qck_create_button_with_named_img(G_OBJECT(station), "close",
- "window-close-symbolic", GTK_ICON_SIZE_MENU, NULL,
- G_CALLBACK(on_click_for_close), station);
- gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_DOCK_STATION);
- gtk_notebook_set_action_widget(notebook, hbox, GTK_PACK_END);
+ g_clear_object(&station->def_panel);
- g_signal_connect(notebook, "switch-page",
- G_CALLBACK(gtk_dock_station_switch_panel), station);
+ G_OBJECT_CLASS(gtk_dock_station_parent_class)->dispose(object);
-#endif
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_dock_station_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_dock_station_parent_class)->finalize(object);
}
/******************************************************************************
* *
-* Paramètres : station = instance d'objet GLib à traiter. *
+* Paramètres : - *
* *
-* Description : Supprime toutes les références externes. *
+* Description : Crée un nouveau composant pour support d'affichage concentré.*
* *
* Retour : - *
* *
@@ -183,18 +246,23 @@ static void gtk_dock_station_init(GtkDockStation *station)
* *
******************************************************************************/
-static void gtk_dock_station_dispose(GtkDockStation *station)
+GtkWidget *gtk_dock_station_new(void)
{
- G_OBJECT_CLASS(gtk_dock_station_parent_class)->dispose(G_OBJECT(station));
+ GtkWidget *result; /* Instance à retourner */
+
+ result = g_object_new(GTK_TYPE_DOCK_STATION, NULL);
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : station = instance d'objet GLib à traiter. *
+* Paramètres : station = station d'accueil pour panneaux à compléter. *
+* panel = nouveau panneau à afficher. *
* *
-* Description : Procède à la libération totale de la mémoire. *
+* Description : Ajoute un panneau à un groupe de tuiles. *
* *
* Retour : - *
* *
@@ -202,18 +270,33 @@ static void gtk_dock_station_dispose(GtkDockStation *station)
* *
******************************************************************************/
-static void gtk_dock_station_finalize(GtkDockStation *station)
+void gtk_dock_station_add_panel(GtkDockStation *station, GtkTiledPanel *panel)
{
- G_OBJECT_CLASS(gtk_dock_station_parent_class)->finalize(G_OBJECT(station));
+ GtkStackPage *page; /* Nouvelle page insérée */
+
+ page = gtk_stack_add_child(station->stack, GTK_WIDGET(panel));
+
+ if (0) // TODO
+ gtk_stack_page_set_title(page, "settings");
+
+ else
+ gtk_stack_page_set_icon_name(page, "logs-symbolic");
+
+ gtk_stack_set_visible_child(station->stack, GTK_WIDGET(panel));
+
+
+ g_signal_emit_by_name(station, "panel-docked", panel);
+
}
/******************************************************************************
* *
-* Paramètres : - *
+* Paramètres : station = station d'accueil pour panneaux à compléter. *
+* panel = nouveau panneau à afficher. *
* *
-* Description : Crée un nouveau composant pour support d'affichage concentré.*
+* Description : Ajoute un panneau à conserver à un groupe de tuiles. *
* *
* Retour : - *
* *
@@ -221,17 +304,300 @@ static void gtk_dock_station_finalize(GtkDockStation *station)
* *
******************************************************************************/
-GtkWidget *gtk_dock_station_new(void)
+void gtk_dock_station_keep_panel(GtkDockStation *station, GtkTiledPanel *panel)
{
- GtkWidget *result; /* Instance à retourner */
+ bool visible; /* Visibilité des barres */
- result = g_object_new(GTK_TYPE_DOCK_STATION, NULL);
+ g_clear_object(&station->def_panel);
+
+ if (panel != NULL)
+ {
+ station->def_panel = panel;
+ ref_object(panel);
+
+ if (gtk_stack_get_page(station->stack, GTK_WIDGET(panel)) == NULL)
+ gtk_dock_station_add_panel(station, panel);
+
+ }
+
+ visible = (station->def_panel == NULL);
+
+ gtk_widget_set_visible(station->tabs, visible);
+ gtk_widget_set_visible(station->toolbar, visible);
+ gtk_widget_set_visible(station->sep1, visible);
+ gtk_widget_set_visible(station->sep2, visible && station->orientation == GTK_ORIENTATION_HORIZONTAL);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : station = station d'accueil pour panneaux à consulter. *
+* *
+* Description : Indique si la station d'accueil contient au moins un panneau.*
+* *
+* Retour : true si aucun panneau n'est intégré, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_dock_station_is_empty(const GtkDockStation *station)
+{
+ bool result; /* Bilan à retourner */
+ GtkSelectionModel *model; /* Modèle pour la pile */
+ guint count; /* Nombre de panneaux présents */
+
+ model = gtk_stack_get_pages(station->stack);
+
+ count = g_list_model_get_n_items(G_LIST_MODEL(model));
+
+ result = (count == 0);
+
+ unref_object(model);
return result;
}
+/******************************************************************************
+* *
+* Paramètres : station = station d'accueil pour panneaux à manipuler. *
+* main = panneau principal visé par l'opération. *
+* activated = nature du changement de statut : ajout, retrait ?*
+* *
+* Description : Note un ajout ou un retrait de panneau principal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_dock_station_notify_new_main_panel_state(const GtkDockStation *station, GtkTiledPanel *main, bool activated)
+{
+ GListModel *list; /* Liste de pages à parcourir */
+ guint count; /* Nombre de pages */
+ guint i; /* Boucle de parcours */
+ GtkStackPage *page; /* Page à consulter */
+ GtkWidget *panel; /* Panneau intégré */
+
+ list = G_LIST_MODEL(gtk_stack_get_pages(station->stack));
+
+ count = g_list_model_get_n_items(list);
+
+ for (i = 0; i < count; i++)
+ {
+ page = GTK_STACK_PAGE(g_list_model_get_object(list, i));
+ if (page == NULL) continue;
+
+ panel = gtk_stack_page_get_child(page);
+
+ gtk_tiled_panel_notify_new_main_panel_state(GTK_TILED_PANEL(panel), main, activated);
+
+ unref_object(page);
+
+ }
+
+ unref_object(list);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à prendre en compte. *
+* pspec = définition de la propriété. *
+* *
+* Description : Met à jour une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_dock_station_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GtkDockStation *station; /* Version spécialisée */
+ GtkOrientation orientation; /* Spécification d'orientation */
+ GtkLayoutManager *layout; /* Gestionnaire de disposition */
+ GtkLayoutChild *child_layout; /* Disposition de composant */
+
+ station = GTK_DOCK_STATION(object);
+
+ switch (prop_id)
+ {
+ case PROP_ORIENTATION:
+
+ orientation = g_value_get_enum(value);
+
+ if (station->orientation != orientation)
+ {
+ station->orientation = orientation;
+
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(station->tabs), orientation);
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(station->toolbar), orientation);
+
+ layout = gtk_widget_get_layout_manager(GTK_WIDGET(object));
+
+ if (orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ g_object_set(G_OBJECT(station->tabs),
+ "halign", GTK_ALIGN_START,
+ "valign", GTK_ALIGN_CENTER,
+ NULL);
+
+ g_object_set(G_OBJECT(station->toolbar),
+ "halign", GTK_ALIGN_END,
+ "valign", GTK_ALIGN_CENTER,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->toolbar);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 1,
+ "row", 0,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->sep1);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 0,
+ "row", 1,
+ "column-span", 2,
+ NULL);
+
+ gtk_widget_set_visible(station->sep2, FALSE);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, GTK_WIDGET(station->stack));
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 0,
+ "row", 2,
+ "column-span", 2,
+ NULL);
+
+ }
+ else
+ {
+ g_object_set(G_OBJECT(station->tabs),
+ "halign", GTK_ALIGN_START,
+ "valign", GTK_ALIGN_START,
+ NULL);
+
+ g_object_set(G_OBJECT(station->toolbar),
+ "halign", GTK_ALIGN_END,
+ "valign", GTK_ALIGN_START,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->sep1);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 1,
+ "row", 0,
+ "column-span", 1,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, GTK_WIDGET(station->stack));
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 2,
+ "row", 0,
+ "column-span", 1,
+ NULL);
+
+ gtk_widget_set_visible(station->sep2, TRUE);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->sep2);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 3,
+ "row", 0,
+ NULL);
+
+ child_layout = gtk_layout_manager_get_layout_child(layout, station->toolbar);
+
+ g_object_set(G_OBJECT(child_layout),
+ "column", 4,
+ "row", 0,
+ NULL);
+
+ }
+
+ g_object_notify_by_pspec(object, pspec);
+
+ }
+
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
+* *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_dock_station_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GtkDockStation *station; /* Version spécialisée */
+
+ station = GTK_DOCK_STATION(object);
+
+ switch (prop_id)
+ {
+ case PROP_ORIENTATION:
+ g_value_set_enum(value, station->orientation);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/gtkext/dockstation.h b/src/gtkext/dockstation.h
index a857626..e4c849f 100644
--- a/src/gtkext/dockstation.h
+++ b/src/gtkext/dockstation.h
@@ -28,6 +28,7 @@
#include <gtk/gtk.h>
+#include "panel.h"
#include "../glibext/helpers.h"
@@ -40,7 +41,17 @@ DECLARE_GTYPE(GtkDockStation, gtk_dock_station, GTK, DOCK_STATION);
/* Crée un nouveau composant pour support d'affichage concentré. */
GtkWidget *gtk_dock_station_new(void);
+/* Ajoute un panneau à un groupe de tuiles. */
+void gtk_dock_station_add_panel(GtkDockStation *, GtkTiledPanel *);
+/* Ajoute un panneau à conserver à un groupe de tuiles. */
+void gtk_dock_station_keep_panel(GtkDockStation *, GtkTiledPanel *);
+
+/* Indique si la station d'accueil contient au moins un panneau. */
+bool gtk_dock_station_is_empty(const GtkDockStation *);
+
+/* Note un ajout ou un retrait de panneau principal. */
+void gtk_dock_station_notify_new_main_panel_state(const GtkDockStation *, GtkTiledPanel *, bool);
diff --git a/src/gtkext/dockstation.ui b/src/gtkext/dockstation.ui
new file mode 100644
index 0000000..4d25134
--- /dev/null
+++ b/src/gtkext/dockstation.ui
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkDockStation" parent="GtkGrid">
+ <property name="orientation">horizontal</property>
+
+ <child>
+ <object class="GtkStackSwitcher" id="tabs">
+ <property name="orientation">horizontal</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="margin-start">2</property>
+ <property name="margin-top">2</property>
+ <property name="margin-end">2</property>
+ <property name="margin-bottom">2</property>
+ <property name="stack">stack</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkBox" id="toolbar">
+ <property name="orientation">horizontal</property>
+ <property name="halign">end</property>
+ <property name="valign">start</property>
+
+ <child>
+ <object class="GtkButton">
+ <property name="icon-name">window-close-symbolic</property>
+ <style>
+ <class name="circular"/>
+ <class name="flat"/>
+ <class name="control-button"/>
+ </style>
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">4</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator" id="sep1">
+ <property name="orientation">horizontal</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">0</property>
+ <property name="column-span">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkStack" id="stack">
+ <property name="hexpand">true</property>
+ <layout>
+ <property name="column">2</property>
+ <property name="row">0</property>
+ <property name="column-span">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator" id="sep2">
+ <property name="orientation">horizontal</property>
+ <layout>
+ <property name="column">3</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+
+ </template>
+</interface>
diff --git a/src/gtkext/gresource.xml b/src/gtkext/gresource.xml
index 3bfd8c5..26943a6 100644
--- a/src/gtkext/gresource.xml
+++ b/src/gtkext/gresource.xml
@@ -1,8 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/re/chrysalide/framework/gtkext">
+ <file compressed="true">dockstation.ui</file>
+ <file compressed="true">grid.ui</file>
<file compressed="true">hexview.css</file>
<file compressed="true">hexview.ui</file>
+ <file compressed="true">launcher.ui</file>
<file compressed="true">statusstack.ui</file>
+ <file compressed="true">tweak.ui</file>
+ </gresource>
+ <gresource prefix="/re/chrysalide/framework/gui/icons/scalable/actions">
+ <file compressed="true" alias="nolock-symbolic.svg">../../data/images/nolock-symbolic.svg</file>
+ <file compressed="true" alias="locked-symbolic.svg">../../data/images/locked-symbolic.svg</file>
+ <file compressed="true" alias="unlocked-symbolic.svg">../../data/images/unlocked-symbolic.svg</file>
</gresource>
</gresources>
diff --git a/src/gtkext/grid-int.h b/src/gtkext/grid-int.h
index 5ae48ad..8a2702b 100644
--- a/src/gtkext/grid-int.h
+++ b/src/gtkext/grid-int.h
@@ -25,46 +25,50 @@
#define _GTKEXT_GRID_INT_H
+#include "dockstation.h"
#include "grid.h"
-/* -------------------------- GESTION DES TUILES AFFICHEES -------------------------- */
-
-
-/* Informations concernant une tuile */
-typedef struct _grid_tile_t
+/* Conteneur pour un affichage en tuiles nommées (instance) */
+struct _GtkTilingGrid
{
- struct _grid_tile_t *parent; /* Tuile parente */
+ GtkGrid parent; /* A laisser en premier */
- GtkWidget *widget; /* Support d'affichage */
+ GSettings *settings; /* Configuration du conteneur */
- char *path; /* Chemin d'accès */
+ LayoutReachOptions layout; /* Disposition générale */
- struct _grid_tile_t *children[2]; /* Tuiles encastrées ou 2xNULL */
+ bool visible[TGB_COUNT]; /* Visibilités souhaitées */
-} grid_tile_t;
+ GtkRevealer *top; /* Zone d'accueil #1 */
+ GtkWidget *top_handle; /* Poignée de redimensionnement*/
+ GtkDockStation *top_station; /* Station entière */
+ GtkRevealer *left; /* Zone d'accueil #2 */
+ GtkWidget *left_handle; /* Poignée de redimensionnement*/
+ GtkDockStation *left_station; /* Station entière */
+ GtkDockStation *main_station; /* Zone d'accueil #3 */
-/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
+ GtkRevealer *right; /* Zone d'accueil #4 */
+ GtkWidget *right_handle; /* Poignée de redimensionnement*/
+ GtkDockStation *right_station; /* Station entière */
+ GtkRevealer *bottom; /* Zone d'accueil #5 */
+ GtkWidget *bottom_handle; /* Poignée de redimensionnement*/
+ GtkDockStation *bottom_station; /* Station entière */
-/* Conteneur pour un affichage en tuiles nommées (instance) */
-struct _GtkTilingGrid
-{
- GtkWidget parent; /* A laisser en premier */
-
- grid_tile_t *tiles; /* Tuiles représentées */
+ GtkGesture *tpad_gesture[TGB_COUNT]; /* Gestionnaires du touchpad */
- GtkTiledPanel *def_panel; /* Panneau principal par défaut*/
+ bool panning; /* Redimensionnement en cours */
};
/* Conteneur pour un affichage en tuiles nommées (classe) */
struct _GtkTilingGridClass
{
- GtkWidgetClass parent; /* A laisser en premier */
+ GtkGridClass parent; /* A laisser en premier */
/* Signaux */
diff --git a/src/gtkext/grid.c b/src/gtkext/grid.c
index 1b9c909..eb3cdf9 100644
--- a/src/gtkext/grid.c
+++ b/src/gtkext/grid.c
@@ -24,29 +24,43 @@
#include "grid.h"
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
#include "grid-int.h"
+#include "helpers.h"
+#include "bindings/grid-enums.h"
+
+/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
-/* -------------------------- GESTION DES TUILES AFFICHEES -------------------------- */
+/* Liste des propriétés */
+typedef enum _TilingGridProperty {
-#define IS_LEAF_TILE(t) \
- ({ \
- bool __result; \
- __result = GTK_IS_DOCK_STATION((t)->widget); \
- assert(__result || GTK_IS_PANED((t)->widget)); \
- __result; \
- })
+ PROP_0, /* Réservé */
+ PROP_LAYOUT, /* Disposition générale */
-/* Supprime une tuile de la mémoire. */
-static void delete_tile(grid_tile_t *);
+ PROP_EMPTY_TOP, /* Vide de la zone supérieure */
+ PROP_EMPTY_LEFT, /* Vide de la zone de gauche */
+ PROP_EMPTY_RIGHT, /* Vide de la zone de droite */
+ PROP_EMPTY_BOTTOM, /* Vide de la zone inférieure */
+ PROP_VISIBLE_TOP, /* Visibilité de zone sup. */
+ PROP_VISIBLE_LEFT, /* Visibilité de zone de gauche*/
+ PROP_VISIBLE_RIGHT, /* Visibilité de zone de droite*/
+ PROP_VISIBLE_BOTTOM, /* Visibilité de zone inf. */
+ N_PROPERTIES
-/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
+} TilingGridProperty;
+
+static GParamSpec *_tiling_grid_properties[N_PROPERTIES] = { NULL, };
/* Initialise la classe des conteneurs d'affichage en tuiles. */
@@ -56,48 +70,50 @@ static void gtk_tiling_grid_class_init(GtkTilingGridClass *);
static void gtk_tiling_grid_init(GtkTilingGrid *);
/* Supprime toutes les références externes. */
-static void gtk_tiling_grid_dispose(GtkTilingGrid *);
+static void gtk_tiling_grid_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_tiling_grid_finalize(GtkTilingGrid *);
+static void gtk_tiling_grid_finalize(GObject *);
+/* Réagit à une intégration ou à un retrait de panneau. */
+static void gtk_tiling_grid_on_panel_un_docked(GtkDockStation *, GtkTiledPanel *, GtkTilingGrid *);
+/* -------------------- REDIMENSIONNEMENT DE ZONES POUR PANNEAUX -------------------- */
-/* ---------------------------------------------------------------------------------- */
-/* GESTION DES TUILES AFFICHEES */
-/* ---------------------------------------------------------------------------------- */
+/* Initie un redimensionnement par drag-and-drop. */
+static void gtk_tiling_grid_on_gesture_drag_begin(GtkGestureDrag *, double, double, GtkTilingGrid *);
-/******************************************************************************
-* *
-* Paramètres : tile = tuile à supprimer. *
-* *
-* Description : Supprime une tuile de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+/* Applique l'effet d'un redimensionnement drag-and-drop donné. */
+static void gtk_tiling_grid_on_gesture_drag_update(GtkTilingGrid *, TilingGridBorder, double, double);
-static void delete_tile(grid_tile_t *tile)
-{
- if (!IS_LEAF_TILE(tile))
- {
- delete_tile(tile->children[0]);
- delete_tile(tile->children[1]);
- }
+/* Actualise l'effet d'un redimensionnement drag-and-drop. */
+static void gtk_tiling_grid_on_top_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *);
- else
- free(tile->path);
+/* Actualise l'effet d'un redimensionnement drag-and-drop. */
+static void gtk_tiling_grid_on_left_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *);
- unref_object(tile->widget);
+/* Actualise l'effet d'un redimensionnement drag-and-drop. */
+static void gtk_tiling_grid_on_right_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *);
- free(tile);
+/* Actualise l'effet d'un redimensionnement drag-and-drop. */
+static void gtk_tiling_grid_on_bottom_gesture_drag_update(GtkGestureDrag *, double, double, GtkTilingGrid *);
-}
+/* Clôture un drag-and-drop de redimensionnement. */
+static void gtk_tiling_grid_on_gesture_drag_end(GtkGestureDrag *, double, double, GtkTilingGrid *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Met à jour une propriété d'instance GObject. */
+static void gtk_tiling_grid_set_property(GObject *, guint, const GValue *, GParamSpec *);
+
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_tiling_grid_get_property(GObject *, guint, GValue *, GParamSpec *);
@@ -107,12 +123,12 @@ static void delete_tile(grid_tile_t *tile)
/* Détermine le type du conteneur d'affichage en tuiles nommées. */
-G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_WIDGET)
+G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_GRID)
/******************************************************************************
* *
-* Paramètres : klass = classe GTK à initialiser. *
+* Paramètres : class = classe GTK à initialiser. *
* *
* Description : Initialise la classe des conteneurs d'affichage en tuiles. *
* *
@@ -122,14 +138,101 @@ G_DEFINE_TYPE(GtkTilingGrid, gtk_tiling_grid, GTK_TYPE_WIDGET)
* *
******************************************************************************/
-static void gtk_tiling_grid_class_init(GtkTilingGridClass *klass)
+static void gtk_tiling_grid_class_init(GtkTilingGridClass *class)
{
GObjectClass *object; /* Autre version de la classe */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_tiling_grid_dispose;
+ object->finalize = gtk_tiling_grid_finalize;
+ object->set_property = gtk_tiling_grid_set_property;
+ object->get_property = gtk_tiling_grid_get_property;
+
+ _tiling_grid_properties[PROP_LAYOUT] =
+ g_param_spec_flags("layout", NULL, NULL,
+ LAYOUT_REACH_OPTIONS_TYPE,
+ LRO_NONE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_EMPTY_TOP] =
+ g_param_spec_boolean("empty-top", NULL, NULL,
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_EMPTY_LEFT] =
+ g_param_spec_boolean("empty-left", NULL, NULL,
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_EMPTY_RIGHT] =
+ g_param_spec_boolean("empty-right", NULL, NULL,
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_EMPTY_BOTTOM] =
+ g_param_spec_boolean("empty-bottom", NULL, NULL,
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * La valeur initiale des champs suivants est à maintenir synchronisée avec
+ * les initialisations de gtk_tiling_grid_init().
+ */
+
+ _tiling_grid_properties[PROP_VISIBLE_TOP] =
+ g_param_spec_boolean("visible-top", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_VISIBLE_LEFT] =
+ g_param_spec_boolean("visible-left", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_VISIBLE_RIGHT] =
+ g_param_spec_boolean("visible-right", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ _tiling_grid_properties[PROP_VISIBLE_BOTTOM] =
+ g_param_spec_boolean("visible-bottom", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties(object, N_PROPERTIES, _tiling_grid_properties);
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ g_type_ensure(GTK_TYPE_DOCK_STATION);
- object = G_OBJECT_CLASS(klass);
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/grid.ui");
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_tiling_grid_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_tiling_grid_finalize;
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_panel_un_docked));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_gesture_drag_begin));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_top_gesture_drag_update));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_left_gesture_drag_update));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_right_gesture_drag_update));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_bottom_gesture_drag_update));
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_tiling_grid_on_gesture_drag_end));
+
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top_handle);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, top_station);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left_handle);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, left_station);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, main_station);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right_handle);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, right_station);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom_handle);
+ gtk_widget_class_bind_template_child(widget, GtkTilingGrid, bottom_station);
+
+
+ /////////////
g_signal_new("station-created",
GTK_TYPE_TILING_GRID,
@@ -144,7 +247,7 @@ static void gtk_tiling_grid_class_init(GtkTilingGridClass *klass)
/******************************************************************************
* *
-* Paramètres : tgrid = instance GTK à initialiser. *
+* Paramètres : grid = instance GTK à initialiser. *
* *
* Description : Initialise une instance de conteneur d'affichage en tuiles. *
* *
@@ -154,18 +257,70 @@ static void gtk_tiling_grid_class_init(GtkTilingGridClass *klass)
* *
******************************************************************************/
-static void gtk_tiling_grid_init(GtkTilingGrid *tgrid)
+static void gtk_tiling_grid_init(GtkTilingGrid *grid)
{
- tgrid->tiles = NULL;
+ gtk_widget_init_template(GTK_WIDGET(grid));
+
+ grid->settings = g_settings_new_with_path("re.chrysalide.framework.tiledgrid",
+ "/re/chrysalide/framework/gui/tiles/");
+
+ g_settings_bind(grid->settings, "layout",
+ grid, "layout",
+ G_SETTINGS_BIND_DEFAULT);
+
+ /**
+ * L'initialisation des champs suivants est à maintenir synchronisée avec
+ * les valeurs initiales de gtk_tiling_grid_class_init().
+ */
+
+ grid->visible[TGB_TOP] = true;
+ grid->visible[TGB_LEFT] = true;
+ grid->visible[TGB_RIGHT] = true;
+ grid->visible[TGB_BOTTOM] = true;
+
+ g_settings_bind(grid->settings, "top-request",
+ grid->top_station, "height-request",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "top-visibility",
+ grid, "visible-top",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "left-request",
+ grid->left_station, "width-request",
+ G_SETTINGS_BIND_DEFAULT);
- tgrid->def_panel = NULL;
+ g_settings_bind(grid->settings, "left-visibility",
+ grid, "visible-left",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "right-request",
+ grid->right_station, "width-request",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "right-visibility",
+ grid, "visible-right",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "bottom-request",
+ grid->bottom_station, "height-request",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind(grid->settings, "bottom-visibility",
+ grid, "visible-bottom",
+ G_SETTINGS_BIND_DEFAULT);
+
+ gtk_widget_set_cursor_from_name(grid->top_handle, "row-resize");
+ gtk_widget_set_cursor_from_name(grid->left_handle, "col-resize");
+ gtk_widget_set_cursor_from_name(grid->right_handle, "col-resize");
+ gtk_widget_set_cursor_from_name(grid->bottom_handle, "row-resize");
}
/******************************************************************************
* *
-* Paramètres : grid = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -175,24 +330,24 @@ static void gtk_tiling_grid_init(GtkTilingGrid *tgrid)
* *
******************************************************************************/
-static void gtk_tiling_grid_dispose(GtkTilingGrid *grid)
+static void gtk_tiling_grid_dispose(GObject *object)
{
- if (grid->tiles != NULL)
- {
- delete_tile(grid->tiles);
- grid->tiles = NULL;
- }
+ GtkTilingGrid *grid; /* Version spécialisée */
+
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_DOCK_STATION);
+
+ grid = GTK_TILING_GRID(object);
- g_clear_object(&grid->def_panel);
+ g_clear_object(&grid->settings);
- G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->dispose(G_OBJECT(grid));
+ G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : grid = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -202,9 +357,9 @@ static void gtk_tiling_grid_dispose(GtkTilingGrid *grid)
* *
******************************************************************************/
-static void gtk_tiling_grid_finalize(GtkTilingGrid *grid)
+static void gtk_tiling_grid_finalize(GObject *object)
{
- G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->finalize(G_OBJECT(grid));
+ G_OBJECT_CLASS(gtk_tiling_grid_parent_class)->finalize(object);
}
@@ -232,142 +387,80 @@ GtkWidget *gtk_tiling_grid_new(void)
}
-
-
-
-
-#if 0
-
-
-#include <assert.h>
-#include <ctype.h>
-#include <malloc.h>
-#include <string.h>
-
-
-#include "../core/logs.h"
-
-
-
-/* Valide un chemin d'accès à une tuile. */
-static bool is_valid_tile_path(const char *);
-
-/* Crée une tuile finale d'affichage de panneaux. */
-static grid_tile_t *create_leaf_tile(const char *, GtkTiledGrid *);
-
-/* Crée une tuile intermédiaire d'affichage de panneaux. */
-static grid_tile_t *create_inter_tile(grid_tile_t *, bool, grid_tile_t *, grid_tile_t *);
-
-/* Supprime une tuile de la mémoire. */
-//static void delete_tile(grid_tile_t *);
-
-/* Calcule la taille comme entre un chemin et celui d'une tuile. */
-static size_t compute_tile_score(const grid_tile_t *, const char *);
-
-/* Indique la tuile adaptée pour un chemin donné. */
-static grid_tile_t *find_suitable_tile(grid_tile_t **, const char *, GtkTiledGrid *);
-
-/* Découpe une tuile pour y insérer une zone. */
-static grid_tile_t *split_tile(grid_tile_t **, const char *, char, GtkTiledGrid *);
-
-/* Tente de mettre la main sur une station d'accueil. */
-static grid_tile_t *find_tile_for_widget(grid_tile_t *, GtkWidget *);
-
-/* Retire une moitié de tuile vide au plein profit de l'autre. */
-static void collapse_tile(grid_tile_t *, grid_tile_t *);
-
-
-
-/* --------------------------- INTERFACE DU COMPOSANT GTK --------------------------- */
-
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* GESTION DES TUILES AFFICHEES */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : path = chemin destiné à sélectionner une tuile. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* border = sélection de la zone à considérer. *
+* visible = nouveau statut de visibilité à appliquer. *
* *
-* Description : Valide un chemin d'accès à une tuile. *
+* Description : Affiche ou masque une zone du conteneur en tuiles. *
* *
-* Retour : true si le chemin est utilisable, false sinon. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool is_valid_tile_path(const char *path)
+void gtk_tiling_grid_set_visible(GtkTilingGrid *grid, TilingGridBorder border, bool visible)
{
- bool result; /* Bilan à retourner */
- size_t len; /* Taille du chemin */
- size_t i; /* Boucle de parcours */
- char c; /* Caractère de chemin analysé */
-
- /**
- * M[NESWnesw]*
- */
-
- len = strlen(path);
+ GtkRevealer *revealer; /* Cible visée par l'opération */
+ GtkDockStation *station; /* Apport d'une contrainte */
- result = (len >= 1);
+ if (grid->visible[border] != visible)
+ {
+ grid->visible[border] = visible;
- if (result)
- result = (path[0] == 'M');
+ switch (border)
+ {
+ case TGB_TOP:
+ revealer = grid->top;
+ station = grid->top_station;
+ break;
+
+ case TGB_LEFT:
+ revealer = grid->left;
+ station = grid->left_station;
+ break;
+
+ case TGB_RIGHT:
+ revealer = grid->right;
+ station = grid->right_station;
+ break;
+
+ case TGB_BOTTOM:
+ revealer = grid->bottom;
+ station = grid->bottom_station;
+ break;
- for (i = 1; i < len && result; i++)
- {
- c = path[i];
+ }
- if (c == '\0')
- break;
+ gtk_revealer_set_reveal_child(revealer, visible && !gtk_dock_station_is_empty(station));
- result = (c == 'N' || c == 'n'
- || c == 'E' || c == 'e'
- || c == 'S' || c == 's'
- || c == 'W' || c == 'w');
+ g_object_notify_by_pspec(G_OBJECT(grid), _tiling_grid_properties[PROP_VISIBLE_TOP + border]);
}
- return result;
-
}
/******************************************************************************
* *
-* Paramètres : path = chemin d'accès à la future tuile. *
-* tgrid = conteneur d'affichage en tuiles à manipuler. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* border = sélection de la zone à considérer. *
* *
-* Description : Crée une tuile finale d'affichage de panneaux. *
+* Description : Fournit la visibilité d'une zone du conteneur en tuiles. *
* *
-* Retour : Structure mise en place. *
+* Retour : Visibilité de la zone considérée. *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *create_leaf_tile(const char *path, GtkTiledGrid *tgrid)
+bool gtk_tiling_grid_get_visible(GtkTilingGrid *grid, TilingGridBorder border)
{
- grid_tile_t *result; /* Structure à retourner */
-
- result = (grid_tile_t *)malloc(sizeof(grid_tile_t));
-
- result->parent = NULL;
-
- result->widget = gtk_dock_station_new();
- gtk_widget_show(result->widget);
+ bool result; /* Statut à retourner */
- result->path = strdup(path);
-
- result->children[0] = NULL;
- result->children[1] = NULL;
-
- g_signal_emit_by_name(tgrid, "station-created", result->widget);
+ result = grid->visible[border];
return result;
@@ -376,333 +469,307 @@ static grid_tile_t *create_leaf_tile(const char *path, GtkTiledGrid *tgrid)
/******************************************************************************
* *
-* Paramètres : parent = tuile parente ou NULL si aucune. *
-* horiz = indique le type d'orientation désiré. *
-* first = première tuile à intégrer. *
-* second = seconde tuile à intégrer. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* panel = nouveau panneau à afficher. *
+* keep = indique si le panneau est à conserver présent. *
* *
-* Description : Crée une tuile intermédiaire d'affichage de panneaux. *
+* Description : Ajoute un panneau à un conteneur en tuiles. *
* *
-* Retour : Structure mise en place. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *create_inter_tile(grid_tile_t *parent, bool horiz, grid_tile_t *first, grid_tile_t *second)
+void gtk_tiling_grid_add_panel(GtkTilingGrid *grid, GtkTiledPanel *panel, bool keep)
{
- grid_tile_t *result; /* Structure à retourner */
- GtkWidget *container; /* Conteneur à vider */
-
- result = (grid_tile_t *)malloc(sizeof(grid_tile_t));
-
- result->parent = parent;
-
- if (horiz)
- result->widget = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
- else
- result->widget = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
+ char *path; /* Chemin visé par le panneau */
+ bool static_path; /* Nature du chemin à traiter */
- gtk_widget_show(result->widget);
+ path = gtk_tiled_panel_get_path(panel);
- result->path = NULL;
+ static_path = (path == NULL);
- result->children[0] = first;
- result->children[1] = second;
+ if (static_path)
+ path = "";
- /* Changement de propriétaire */
+ switch (path[0])
+ {
+ case 'N':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->top_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->top_station, panel);
+ break;
- container = gtk_widget_get_parent(first->widget);
+ case 'W':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->left_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->left_station, panel);
+ break;
- if (container != NULL)
- gtk_container_remove(GTK_CONTAINER(container), first->widget);
+ case '\0':
+ case 'M':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->main_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->main_station, panel);
+ break;
- g_object_ref(G_OBJECT(first->widget));
- gtk_paned_pack1(GTK_PANED(result->widget), first->widget, TRUE, FALSE);
+ case 'E':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->right_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->right_station, panel);
+ break;
- container = gtk_widget_get_parent(second->widget);
+ case 'S':
+ if (keep)
+ gtk_dock_station_keep_panel(grid->bottom_station, panel);
+ else
+ gtk_dock_station_add_panel(grid->bottom_station, panel);
+ break;
- if (container != NULL)
- gtk_container_remove(GTK_CONTAINER(container), second->widget);
+ default:
+ break;
- g_object_ref(G_OBJECT(second->widget));
- gtk_paned_pack2(GTK_PANED(result->widget), second->widget, TRUE, FALSE);
+ }
- return result;
+ if (!static_path)
+ free(path);
}
-
/******************************************************************************
* *
-* Paramètres : tile = tuile à analyser. *
-* path = chemin final complet recherché. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* main = panneau principal visé par l'opération. *
+* activated = nature du changement de statut : ajout, retrait ?*
* *
-* Description : Calcule la taille comme entre un chemin et celui d'une tuile.*
+* Description : Note un ajout ou un retrait de panneau principal. *
* *
-* Retour : Quantité de caractères communs. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static size_t compute_tile_score(const grid_tile_t *tile, const char *path)
+void gtk_tiling_grid_notify_new_main_panel_state(const GtkTilingGrid *grid, GtkTiledPanel *main, bool activated)
{
- size_t result; /* Nombre de points à renvoyer */
- size_t max; /* Taille du chemin de la tuile*/
- size_t i; /* Boucle de parcours */
- size_t score_0; /* Score du sous-élément #1 */
- size_t score_1; /* Score du sous-élément #2 */
-
- if (IS_LEAF_TILE(tile))
- {
- max = strlen(tile->path);
-
- if (strlen(path) < max)
- result = 0;
-
- else
- {
- result = 0;
-
- for (i = 0; i < max; i++)
- {
- if (tolower((unsigned char)tile->path[i]) == tolower((unsigned char)path[i]))
- result++;
- else
- break;
- }
+ gtk_dock_station_notify_new_main_panel_state(grid->top_station, main, activated);
- }
-
- }
- else
- {
- score_0 = compute_tile_score(tile->children[0], path);
- score_1 = compute_tile_score(tile->children[1], path);
+ gtk_dock_station_notify_new_main_panel_state(grid->left_station, main, activated);
- result = score_0 > score_1 ? score_0 : score_1;
+ gtk_dock_station_notify_new_main_panel_state(grid->main_station, main, activated);
- }
+ gtk_dock_station_notify_new_main_panel_state(grid->right_station, main, activated);
- return result;
+ gtk_dock_station_notify_new_main_panel_state(grid->bottom_station, main, activated);
}
/******************************************************************************
* *
-* Paramètres : tile = tuile ou NULL si aucune. [OUT] *
-* path = chemin d'accès à la tuile visée. *
-* tgrid = conteneur d'affichage en tuiles à manipuler. *
+* Paramètres : station = plateforme GTK ayant connu un changement. *
+* widget = nouvel élément à intégrer. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Indique la tuile adaptée pour un chemin donné. *
+* Description : Réagit à une intégration ou à un retrait de panneau. *
* *
-* Retour : Structure d'acceuil à disposition. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *find_suitable_tile(grid_tile_t **tile, const char *path, GtkTiledGrid *tgrid)
+static void gtk_tiling_grid_on_panel_un_docked(GtkDockStation *station, GtkTiledPanel *panel, GtkTilingGrid *grid)
{
- grid_tile_t *result; /* Structure à renvoyer */
- size_t best_len; /* Taille du chemin associé */
- size_t score_0; /* Score du sous-élément #1 */
- size_t score_1; /* Score du sous-élément #2 */
- char *sub_path; /* Nouvelle tentative d'accès */
- grid_tile_t **best; /* Direction à prendre */
- unsigned char next; /* Prochaine étape */
-
- /* Cas d'école : appel initial */
- if (*tile == NULL)
- {
- assert(path[0] == 'M' && path[1] == '\0');
-
- result = create_leaf_tile("M", tgrid);
- *tile = result;
+ TilingGridBorder border; /* Aire concernée par l'action */
+ GtkRevealer *revealer; /* Cible visée par l'opération */
+ bool new_state; /* Nouveau statut d'affichage */
+ if (station == grid->top_station)
+ {
+ border = TGB_TOP;
+ revealer = grid->top;
}
- else
+ else if (station == grid->left_station)
{
- if (IS_LEAF_TILE(*tile))
- {
- best_len = compute_tile_score(*tile, path);
-
- assert(best_len > 0);
+ border = TGB_LEFT;
+ revealer = grid->left;
+ }
- if (path[best_len] == '\0')
- result = *tile;
+ else if (station == grid->right_station)
+ {
+ border = TGB_RIGHT;
+ revealer = grid->right;
+ }
- else
- result = split_tile(tile, path, path[best_len], tgrid);
+ else if (station == grid->bottom_station)
+ {
+ border = TGB_BOTTOM;
+ revealer = grid->bottom;
+ }
- }
+ else
+ assert(false);
- else
- {
- score_0 = compute_tile_score((*tile)->children[0], path);
- score_1 = compute_tile_score((*tile)->children[1], path);
+ new_state = grid->visible[border] && !gtk_dock_station_is_empty(station);
- assert(score_0 > 0 || score_0 > 0);
+ if (gtk_revealer_get_reveal_child(revealer) != new_state)
+ gtk_revealer_set_reveal_child(revealer, new_state);
- if (score_0 == score_1)
- {
- sub_path = strndup(path, score_0);
+ /**
+ * On ne sait pas si l'état a réellement changé, mais on avertit
+ * d'une mise à jour quand même, au cas où.
+ */
- score_0 = compute_tile_score((*tile)->children[0], sub_path);
- score_1 = compute_tile_score((*tile)->children[1], sub_path);
+ g_object_notify_by_pspec(G_OBJECT(grid), _tiling_grid_properties[PROP_EMPTY_TOP + border]);
- free(sub_path);
+}
- }
- if (score_0 == score_1)
- result = split_tile(tile, path, path[score_0], tgrid);
- else
- {
- if (score_0 > score_1)
- {
- best = &(*tile)->children[0];
- best_len = score_0;
- }
- else
- {
- best = &(*tile)->children[1];
- best_len = score_1;
- }
-
- /**
- * Si on vient de tomber une feuille, trois cas de figure :
- * - soit c'est elle qui est visée.
- * - soit on veut la diviser.
- * - soit on veut la diviser en englobant ses voisines.
- */
-
- if (IS_LEAF_TILE(*best))
- {
- assert(best_len <= strlen(path));
-
- next = path[best_len];
-
- /* Premier cas */
- if (next == '\0')
- result = *best;
-
- else
- {
- /* Second cas */
- if (islower(next))
- result = find_suitable_tile(best, path, tgrid);
-
- /* Troisième cas */
- else
- result = split_tile(tile, path, next, tgrid);
-
- }
-
- }
-
- else
- result = find_suitable_tile(best, path, tgrid);
-
- }
+/* ---------------------------------------------------------------------------------- */
+/* REDIMENSIONNEMENT DE ZONES POUR PANNEAUX */
+/* ---------------------------------------------------------------------------------- */
- }
- }
+/******************************************************************************
+* *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* start_x = pointe de départ sur l'axe des abscisses. *
+* start_y = pointe de départ sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
+* *
+* Description : Initie un redimensionnement par drag-and-drop. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- assert(IS_LEAF_TILE(result));
+static void gtk_tiling_grid_on_gesture_drag_begin(GtkGestureDrag *gesture, double start_x, double start_y, GtkTilingGrid *grid)
+{
+ gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_CLAIMED);
- return result;
+ grid->panning = true;
}
/******************************************************************************
* *
-* Paramètres : tile = tuile à découper en deux. [OUT] *
-* path = chemin d'accès à la future tuile. *
-* endpoint = désignation de la zone représentée. *
-* tgrid = conteneur d'affichage en tuiles à manipuler. *
+* Paramètres : grid = zone d'affichage en tuiles à manipuler. *
+* border = sélection de la zone à considérer. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
* *
-* Description : Découpe une tuile pour y insérer une zone. *
+* Description : Applique l'effet d'un redimensionnement drag-and-drop donné. *
* *
-* Retour : Structure fille mise en place. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *split_tile(grid_tile_t **tile, const char *path, char endpoint, GtkTiledGrid *tgrid)
+static void gtk_tiling_grid_on_gesture_drag_update(GtkTilingGrid *grid, TilingGridBorder border, double offset_x, double offset_y)
{
- grid_tile_t *result; /* Création à retourner */
- GtkWidget *container; /* Conteneur à vider */
- grid_tile_t *new; /* Nouvelle tuile intermédiaire*/
+ GtkDockStation *station; /* Station entière */
+ int request; /* Taille requise */
+
+ /* Sélection de la poignée adaptée */
+
+ switch (border)
+ {
+ case TGB_TOP:
+ station = grid->top_station;
+ break;
+
+ case TGB_LEFT:
+ station = grid->left_station;
+ break;
- container = gtk_widget_get_parent((*tile)->widget);
+ case TGB_RIGHT:
+ station = grid->right_station;
+ break;
- /* Création */
+ case TGB_BOTTOM:
+ station = grid->bottom_station;
+ break;
- result = create_leaf_tile(path, tgrid);
+ }
- /* Encapsulation */
+ /* Détermination d'une nouvelle position et application */
- switch (endpoint)
+ switch (border)
{
- case 'N':
- case 'n':
- new = create_inter_tile((*tile)->parent, false, result, *tile);
+ case TGB_TOP:
+ case TGB_BOTTOM:
+ g_object_get(G_OBJECT(station), "height-request", &request, NULL);
break;
- case 'E':
- case 'e':
- new = create_inter_tile((*tile)->parent, true, *tile, result);
+ case TGB_LEFT:
+ case TGB_RIGHT:
+ g_object_get(G_OBJECT(station), "width-request", &request, NULL);
break;
- case 'S':
- case 's':
- new = create_inter_tile((*tile)->parent, false, *tile, result);
+ }
+
+ switch (border)
+ {
+ case TGB_TOP:
+ request += offset_y;
break;
- case 'W':
- case 'w':
- new = create_inter_tile((*tile)->parent, true, result, *tile);
+ case TGB_LEFT:
+ request += offset_x;
break;
- default:
- assert(false);
- new = NULL;
+ case TGB_RIGHT:
+ request += -offset_x;
+ break;
+
+ case TGB_BOTTOM:
+ request += -offset_y;
break;
}
- /* Connexions */
+ if (request > 0)
+ {
+ switch (border)
+ {
+ case TGB_TOP:
+ case TGB_BOTTOM:
+ g_object_set(G_OBJECT(station), "height-request", request, NULL);
+ break;
- *tile = new;
+ case TGB_LEFT:
+ case TGB_RIGHT:
+ g_object_set(G_OBJECT(station), "width-request", request, NULL);
+ break;
- result->parent = new;
+ }
- if (container != NULL)
- {
- g_object_ref(G_OBJECT(new->widget));
- gtk_container_add(GTK_CONTAINER(container), new->widget);
}
- return result;
-
}
/******************************************************************************
* *
-* Paramètres : tile = tuile parente, prochaine victime de promotion. *
-* side = côté de tuile amené à disparaître. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Retire une moitié de tuile vide au plein profit de l'autre. *
+* Description : Actualise l'effet d'un redimensionnement drag-and-drop. *
* *
* Retour : - *
* *
@@ -710,114 +777,65 @@ static grid_tile_t *split_tile(grid_tile_t **tile, const char *path, char endpoi
* *
******************************************************************************/
-static void collapse_tile(grid_tile_t *tile, grid_tile_t *side)
+static void gtk_tiling_grid_on_top_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- grid_tile_t *promoted; /* Tuile à faire remonter */
- GtkWidget *container; /* Conteneur à vider */
-
- assert(!IS_LEAF_TILE(tile));
-
- /* Sélection du remplaçant */
-
- if (side == tile->children[0])
- promoted = tile->children[1];
- else
- promoted = tile->children[0];
-
- /* Etablissement d'une place nette */
-
- gtk_container_remove(GTK_CONTAINER(tile->widget), promoted->widget);
-
- container = gtk_widget_get_parent(tile->widget);
- gtk_container_remove(GTK_CONTAINER(container), tile->widget);
-
- delete_tile(side);
-
- /* Promotion effective */
-
- tile->widget = promoted->widget;
-
- tile->path = promoted->path;
-
- tile->children[0] = promoted->children[0];
- tile->children[1] = promoted->children[1];
-
- g_object_ref(G_OBJECT(promoted->widget));
- gtk_container_add(GTK_CONTAINER(container), tile->widget);
-
- free(promoted);
+ gtk_tiling_grid_on_gesture_drag_update(grid, TGB_TOP, offset_x, offset_y);
}
/******************************************************************************
* *
-* Paramètres : tile = point de départ des recherches locales. *
-* widget = composant graphique à retrouver. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Tente de mettre la main sur une station d'accueil. *
+* Description : Actualise l'effet d'un redimensionnement drag-and-drop. *
* *
-* Retour : Eventuelle tuile trouvée ou NULL. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static grid_tile_t *find_tile_for_widget(grid_tile_t *tile, GtkWidget *widget)
+static void gtk_tiling_grid_on_left_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- grid_tile_t *result; /* Tuile à retourner */
-
- if (IS_LEAF_TILE(tile))
- result = tile->widget == widget ? tile : NULL;
-
- else
- {
- result = find_tile_for_widget(tile->children[0], widget);
-
- if (result == NULL)
- result = find_tile_for_widget(tile->children[1], widget);
-
- }
-
- return result;
+ gtk_tiling_grid_on_gesture_drag_update(grid, TGB_LEFT, offset_x, offset_y);
}
-
-
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à consulter. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Donne le panneau fourni par défaut pour la zone principale. *
+* Description : Actualise l'effet d'un redimensionnement drag-and-drop. *
* *
-* Retour : Panneau d'affichage par défault ou NULL. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GPanelItem *gtk_tiled_grid_get_default_main_panel(const GtkTiledGrid *tgrid)
+static void gtk_tiling_grid_on_right_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- GPanelItem *result; /* Panneau à retourner */
-
- result = tgrid->def_panel;
-
- if (result != NULL)
- g_object_ref(G_OBJECT(result));
-
- return result;
+ gtk_tiling_grid_on_gesture_drag_update(grid, TGB_RIGHT, offset_x, offset_y);
}
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à modifier. *
-* panel = panneau d'affichage par défault ou NULL. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement sur l'axe des abscisses. *
+* offset_y = déplacement sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Fournit le panneau par défaut pour la zone principale. *
+* Description : Actualise l'effet d'un redimensionnement drag-and-drop. *
* *
* Retour : - *
* *
@@ -825,56 +843,21 @@ GPanelItem *gtk_tiled_grid_get_default_main_panel(const GtkTiledGrid *tgrid)
* *
******************************************************************************/
-void gtk_tiled_grid_set_default_main_panel(GtkTiledGrid *tgrid, GPanelItem *panel)
+static void gtk_tiling_grid_on_bottom_gesture_drag_update(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- GtkWidget *widget; /* Composant GTK à retirer */
- GtkWidget *parent; /* Conteneur à vider */
- grid_tile_t *tile; /* Première tuile d'accueil */
-
- if (tgrid->def_panel != NULL)
- {
- widget = gtk_dockable_build_widget(GTK_DOCKABLE(tgrid->def_panel));
-
- parent = gtk_widget_get_parent(widget);
-
- if (parent != NULL)
- gtk_container_remove(GTK_CONTAINER(parent), widget);
-
- g_object_unref(G_OBJECT(widget));
-
- g_object_unref(G_OBJECT(tgrid->def_panel));
-
- }
-
- tgrid->def_panel = panel;
-
- if (panel != NULL)
- {
- g_object_ref(G_OBJECT(panel));
-
- if (tgrid->tiles == NULL)
- gtk_tiled_grid_add(tgrid, panel);
-
- else
- {
- tile = find_suitable_tile(&tgrid->tiles, "M", tgrid);
-
- if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(tile->widget)) == 0)
- gtk_tiled_grid_add(tgrid, panel);
-
- }
-
- }
+ gtk_tiling_grid_on_gesture_drag_update(grid, TGB_BOTTOM, offset_x, offset_y);
}
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à modifier. *
-* panel = panneau d'affichage à intégrer. *
+* Paramètres : gesture = encadrement de déplacement à l'origine de l'appel. *
+* offset_x = déplacement final sur l'axe des abscisses. *
+* offset_y = déplacement final sur l'axe des ordonnées. *
+* grid = gestionnaire de placement en tuile concerné. *
* *
-* Description : Incorpore un nouveau panneau dans le conteneur en tuiles. *
+* Description : Clôture un drag-and-drop de redimensionnement. *
* *
* Retour : - *
* *
@@ -882,66 +865,30 @@ void gtk_tiled_grid_set_default_main_panel(GtkTiledGrid *tgrid, GPanelItem *pane
* *
******************************************************************************/
-void gtk_tiled_grid_add(GtkTiledGrid *tgrid, GPanelItem *panel)
+static void gtk_tiling_grid_on_gesture_drag_end(GtkGestureDrag *gesture, double offset_x, double offset_y, GtkTilingGrid *grid)
{
- char *path; /* Chemin d'accès */
- char *name; /* Nom à donner à l'onglet */
- grid_tile_t *tile; /* Tuile d'accueil */
-
- path = gtk_panel_item_class_get_path(G_PANEL_ITEM_GET_CLASS(panel));
-
- if (!is_valid_tile_path(path))
- {
- name = gtk_dockable_get_name(GTK_DOCKABLE(panel));
- log_variadic_message(LMT_ERROR, _("Invalid path '%s' for panel '%s'"), path, name);
- free(name);
- }
-
+ if (!grid->panning)
+ gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_DENIED);
else
- {
- tile = find_suitable_tile(&tgrid->tiles, path, tgrid);
- assert(tile != NULL);
-
- gtk_dock_station_add_dockable(GTK_DOCK_STATION(tile->widget), GTK_DOCKABLE(panel));
+ grid->panning = false;
- g_panel_item_set_dock_at_startup(panel, true);
-
- /* Si c'est la toute première fois... */
- if (gtk_widget_get_parent(tile->widget) == NULL)
- {
- assert(tile == tgrid->tiles);
- assert(tile->path[0] == 'M' && tile->path[1] == '\0');
- g_object_ref(G_OBJECT(tile->widget));
- gtk_container_add(GTK_CONTAINER(tgrid), tile->widget);
- }
-
- /* Si on n'a plus besoin du panneau par défaut */
- if (tgrid->def_panel != NULL && tile->path[0] == 'M' && tile->path[1] == '\0')
- {
- /* Si ce n'est pas le panneau qu'on vient de rajouter...*/
- if (panel != tgrid->def_panel)
- {
- /* Enfin : si ce panneau par défaut est réellement en place */
- if (g_panel_item_is_docked(tgrid->def_panel))
- gtk_tiled_grid_remove(tgrid, tgrid->def_panel);
-
- }
-
- }
+}
- }
- free(path);
-}
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à modifier. *
-* panel = panneau d'affichage à supprimer. *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à prendre en compte. *
+* pspec = définition de la propriété. *
* *
-* Description : Retire un panneau dans le conteneur en tuiles. *
+* Description : Met à jour une propriété d'instance GObject. *
* *
* Retour : - *
* *
@@ -949,90 +896,65 @@ void gtk_tiled_grid_add(GtkTiledGrid *tgrid, GPanelItem *panel)
* *
******************************************************************************/
-void gtk_tiled_grid_remove(GtkTiledGrid *tgrid, GPanelItem *panel)
+static void gtk_tiling_grid_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
- GtkWidget *station; /* Support courant */
- grid_tile_t *tile; /* Tuile d'accueil */
-
- assert(g_panel_item_is_docked(panel));
-
- gtk_dockable_decompose(GTK_DOCKABLE(panel), &station);
-
- tile = find_tile_for_widget(tgrid->tiles, station);
- assert(tile != NULL);
+ GtkTilingGrid *grid; /* Version spécialisée */
- gtk_dock_station_remove_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(panel));
+ grid = GTK_TILING_GRID(object);
- g_panel_item_set_dock_at_startup(panel, false);
-
- if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(station)) == 0)
+ switch (prop_id)
{
- /* Si le panneau par défaut devient nécessaire */
- if (tgrid->def_panel != NULL && tile->path[0] == 'M' && tile->path[1] == '\0')
- gtk_tiled_grid_add(tgrid, tgrid->def_panel);
-
- else
- {
- /* La racine est concernée ! */
- if (tile->parent == NULL)
+ case PROP_LAYOUT:
+ if (grid->layout != g_value_get_flags(value))
{
- assert(tile == tgrid->tiles);
+ grid->layout = g_value_get_flags(value);
- g_object_ref(G_OBJECT(tile->widget));
- gtk_container_remove(GTK_CONTAINER(tgrid), tile->widget);
+ apply_tiling_grid_layout(GTK_GRID(grid), grid->layout, (GtkWidget *[]) {
+ GTK_WIDGET(grid->top), GTK_WIDGET(grid->left),
+ GTK_WIDGET(grid->right), GTK_WIDGET(grid->bottom)
+ });
- delete_tile(tile);
- tgrid->tiles = NULL;
+ g_object_notify_by_pspec(object, pspec);
}
+ break;
- else
- collapse_tile(tile->parent, tile);
-
- }
-
- }
-
-}
-
+ gtk_tiling_grid_set_visible(grid, TGB_TOP, g_value_get_boolean(value));
+ break;
-/******************************************************************************
-* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à consulter. *
-* station = station d'accueil à retrouver. *
-* *
-* Description : Indique le chemin correspondant à une station intégrée. *
-* *
-* Retour : Copie de chemin trouvé, à libérer ensuite, ou NULL si échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ case PROP_VISIBLE_TOP:
+ gtk_tiling_grid_set_visible(grid, TGB_TOP, g_value_get_boolean(value));
+ break;
-char *gtk_tiled_grid_get_path_for_station(const GtkTiledGrid *tgrid, GtkDockStation *station)
-{
- char *result; /* Chemin d'accès à renvoyer */
- grid_tile_t *tile; /* Tuile d'accueil */
+ case PROP_VISIBLE_LEFT:
+ gtk_tiling_grid_set_visible(grid, TGB_LEFT, g_value_get_boolean(value));
+ break;
- tile = find_tile_for_widget(tgrid->tiles, GTK_WIDGET(station));
+ case PROP_VISIBLE_RIGHT:
+ gtk_tiling_grid_set_visible(grid, TGB_RIGHT, g_value_get_boolean(value));
+ break;
- if (tile == NULL)
- result = NULL;
+ case PROP_VISIBLE_BOTTOM:
+ gtk_tiling_grid_set_visible(grid, TGB_BOTTOM, g_value_get_boolean(value));
+ break;
- else
- result = strdup(tile->path);
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
- return result;
+ }
}
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à mettre à jour. *
-* config = configuration à consulter. *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
* *
-* Description : Replace les positions des séparateurs de tuiles. *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
* *
* Retour : - *
* *
@@ -1040,57 +962,68 @@ char *gtk_tiled_grid_get_path_for_station(const GtkTiledGrid *tgrid, GtkDockStat
* *
******************************************************************************/
-void gtk_tiled_grid_restore_positions(const GtkTiledGrid *tgrid, GGenConfig *config)
+static void gtk_tiling_grid_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
+ GtkTilingGrid *grid; /* Version spécialisée */
- void visit_tiles_for_restoring(grid_tile_t *tile, const char *vpath)
- {
- GtkOrientation orientation; /* Direction de la tuile */
- char hint; /* Inutile donc indispensable */
- char *key; /* Clef d'accès à un paramètre */
- gint position; /* Nouvelle position de barre */
- size_t i; /* Boucle de parcours */
- char *child_key; /* Clef d'accès des suivants */
-
- if (!IS_LEAF_TILE(tile))
- {
- orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(tile->widget));
+ grid = GTK_TILING_GRID(object);
- hint = orientation == GTK_ORIENTATION_HORIZONTAL ? 'h' : 'v';
+ switch (prop_id)
+ {
+ case PROP_EMPTY_TOP:
+ g_value_set_boolean(value, gtk_dock_station_is_empty(grid->top_station));
+ break;
- asprintf(&key, "%s%c", vpath, hint);
+ case PROP_EMPTY_LEFT:
+ g_value_set_boolean(value, gtk_dock_station_is_empty(grid->left_station));
+ break;
- if (g_generic_config_get_value(config, key, &position))
- gtk_paned_set_position(GTK_PANED(tile->widget), position);
+ case PROP_EMPTY_RIGHT:
+ g_value_set_boolean(value, gtk_dock_station_is_empty(grid->right_station));
+ break;
- for (i = 0; i < 2; i++)
- {
- asprintf(&child_key, "%s%zu", key, i);
+ case PROP_EMPTY_BOTTOM:
+ g_value_set_boolean(value, gtk_dock_station_is_empty(grid->bottom_station));
+ break;
- visit_tiles_for_restoring(tile->children[i], child_key);
+ case PROP_VISIBLE_TOP:
+ g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_TOP));
+ break;
- free(child_key);
+ case PROP_VISIBLE_LEFT:
+ g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_LEFT));
+ break;
- }
+ case PROP_VISIBLE_RIGHT:
+ g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_RIGHT));
+ break;
- free(key);
+ case PROP_VISIBLE_BOTTOM:
+ g_value_set_boolean(value, gtk_tiling_grid_get_visible(grid, TGB_BOTTOM));
+ break;
- }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
}
+}
- visit_tiles_for_restoring(tgrid->tiles, "gui.panels.positions.R");
-}
+
+/* ---------------------------------------------------------------------------------- */
+/* FORME GENERIQUE DE MISE EN DISPOSITION */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : tgrid = conteneur d'affichage en tuiles à consulter. *
-* config = configuration à mettre à jour. *
+* Paramètres : grid = composant GTK dont le contenu est à arranger. *
+* options = options de mise en place. *
+* panels = liste organisée de composants à déplacer. *
* *
-* Description : Sauvegarde les positions des séparateurs de tuiles. *
+* Description : Met en place une disposition particulière de panneaux. *
* *
* Retour : - *
* *
@@ -1098,49 +1031,98 @@ void gtk_tiled_grid_restore_positions(const GtkTiledGrid *tgrid, GGenConfig *con
* *
******************************************************************************/
-void gtk_tiled_grid_save_positions(const GtkTiledGrid *tgrid, GGenConfig *config)
+void apply_tiling_grid_layout(GtkGrid *grid, LayoutReachOptions options, GtkWidget *panels[TGB_COUNT])
{
-
- void visit_tiles_for_saving(grid_tile_t *tile, const char *vpath)
+ int top_panel_span; /* Etendue d'un composant #1 */
+ int left_panel_span; /* Etendue d'un composant #2 */
+ int right_panel_span; /* Etendue d'un composant #3 */
+ int bottom_panel_span; /* Etendue d'un composant #4 */
+ int top_panel_column; /* Position de composant #1 */
+ int left_panel_row; /* Position de composant #2 */
+ int right_panel_row; /* Position de composant #3 */
+ int bottom_panel_column; /* Position de composant #4 */
+ GtkLayoutManager *layout; /* Gestionnaire de disposition */
+ GtkGridLayoutChild *top_panel_layout; /* Disposition de composant #1 */
+ GtkGridLayoutChild *left_panel_layout; /* Disposition de composant #2 */
+ GtkGridLayoutChild *right_panel_layout; /* Disposition de composant #3 */
+ GtkGridLayoutChild *bottom_panel_layout;/* Disposition de composant #4 */
+
+ /* Calcul des placements */
+
+ top_panel_span = 3;
+ left_panel_span = 3;
+ right_panel_span = 3;
+ bottom_panel_span = 3;
+
+ if (options & LRO_LEFT_TOP_REACH)
{
- GtkOrientation orientation; /* Direction de la tuile */
- char hint; /* Inutile donc indispensable */
- char *key; /* Clef d'accès à un paramètre */
- gint position; /* Nouvelle position de barre */
- size_t i; /* Boucle de parcours */
- char *child_key; /* Clef d'accès des suivants */
-
- if (!IS_LEAF_TILE(tile))
- {
- orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(tile->widget));
-
- hint = orientation == GTK_ORIENTATION_HORIZONTAL ? 'h' : 'v';
+ top_panel_column = 1;
+ top_panel_span--;
+ left_panel_row = 0;
+ }
+ else
+ {
+ top_panel_column = 0;
+ left_panel_row = 1;
+ left_panel_span--;
+ }
- asprintf(&key, "%s%c", vpath, hint);
+ if (options & LRO_LEFT_BOTTOM_REACH)
+ {
+ bottom_panel_column = 1;
+ bottom_panel_span--;
+ }
+ else
+ {
+ left_panel_span--;
+ bottom_panel_column = 0;
+ }
- position = gtk_paned_get_position(GTK_PANED(tile->widget));
- g_generic_config_create_or_udpdate_param(config, key, CPT_INTEGER, -1, position);
+ if (options & LRO_RIGHT_TOP_REACH)
+ {
+ top_panel_span--;
+ right_panel_row = 0;
+ }
+ else
+ {
+ right_panel_row = 1;
+ right_panel_span--;
+ }
- for (i = 0; i < 2; i++)
- {
- asprintf(&child_key, "%s%zu", key, i);
+ if (options & LRO_RIGHT_BOTTOM_REACH)
+ bottom_panel_span--;
+ else
+ right_panel_span--;
- visit_tiles_for_saving(tile->children[i], child_key);
+ /* Mise en application des contraintes */
- free(child_key);
+ layout = gtk_widget_get_layout_manager(GTK_WIDGET(grid));
- }
+ top_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_TOP]));
+ left_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_LEFT]));
+ right_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_RIGHT]));
+ bottom_panel_layout = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(layout, panels[TGB_BOTTOM]));
- free(key);
+ g_object_set(G_OBJECT(top_panel_layout),
+ "column", top_panel_column,
+ "column-span", top_panel_span,
+ NULL);
- }
+ g_object_set(G_OBJECT(left_panel_layout),
+ "row", left_panel_row,
+ "row-span", left_panel_span,
+ NULL);
- }
+ g_object_set(G_OBJECT(right_panel_layout),
+ "row", right_panel_row,
+ "row-span", right_panel_span,
+ NULL);
+ g_object_set(G_OBJECT(bottom_panel_layout),
+ "column", bottom_panel_column,
+ "column-span", bottom_panel_span,
+ NULL);
- visit_tiles_for_saving(tgrid->tiles, "gui.panels.positions.R");
+ gtk_layout_manager_layout_changed(layout);
}
-
-
-#endif
diff --git a/src/gtkext/grid.h b/src/gtkext/grid.h
index d9b7ef1..fd98035 100644
--- a/src/gtkext/grid.h
+++ b/src/gtkext/grid.h
@@ -25,10 +25,10 @@
#define _GTKEXT_GRID_H
+#include <stdbool.h>
#include <gtk/gtk.h>
-#include "dockstation.h"
#include "panel.h"
#include "../glibext/helpers.h"
@@ -42,7 +42,51 @@ DECLARE_GTYPE(GtkTilingGrid, gtk_tiling_grid, GTK, TILING_GRID);
/* Crée une nouvelle instance de conteneur avec tuiles. */
GtkWidget *gtk_tiling_grid_new(void);
+/* Liste des zones de bordure */
+typedef enum _TilingGridBorder /*< skip (glib-mkenums) >*/
+{
+ TGB_TOP, /* Zone supérieure */
+ TGB_LEFT, /* Zone de gauche */
+ TGB_RIGHT, /* Zone de droite */
+ TGB_BOTTOM, /* Zone inférieure */
+} TilingGridBorder;
+
+/**
+ * Fixe le nombre de combinaisons sans le rendre visible dans l'énumération.
+ */
+#define TGB_COUNT (TGB_BOTTOM + 1)
+
+/* Affiche ou masque une zone du conteneur en tuiles. */
+void gtk_tiling_grid_set_visible(GtkTilingGrid *, TilingGridBorder, bool);
+
+/* Fournit la visibilité d'une zone du conteneur en tuiles. */
+bool gtk_tiling_grid_get_visible(GtkTilingGrid *, TilingGridBorder);
+
+/* Ajoute un panneau à un conteneur en tuiles. */
+void gtk_tiling_grid_add_panel(GtkTilingGrid *, GtkTiledPanel *, bool);
+
+/* Note un ajout ou un retrait de panneau principal. */
+void gtk_tiling_grid_notify_new_main_panel_state(const GtkTilingGrid *, GtkTiledPanel *, bool);
+
+
+
+/* --------------------- FORME GENERIQUE DE MISE EN DISPOSITION --------------------- */
+
+
+/* Options de dispositions cumulables */
+typedef enum _LayoutReachOptions /*< flags (glib-mkenums) >*/
+{
+ LRO_NONE = (0 << 0), /* Aucune atteinte des bords */
+ LRO_LEFT_TOP_REACH = (1 << 0), /* Atteinte du bord haut à G. */
+ LRO_LEFT_BOTTOM_REACH = (1 << 1), /* Atteinte du bord bas à G. */
+ LRO_RIGHT_TOP_REACH = (1 << 2), /* Atteinte du bord haut à D. */
+ LRO_RIGHT_BOTTOM_REACH = (1 << 3), /* Atteinte du bord bas à D. */
+
+} LayoutReachOptions;
+
+/* Met en place une disposition particulière de panneaux. */
+void apply_tiling_grid_layout(GtkGrid *, LayoutReachOptions, GtkWidget *[TGB_COUNT]);
diff --git a/src/gtkext/grid.ui b/src/gtkext/grid.ui
new file mode 100644
index 0000000..b14ced2
--- /dev/null
+++ b/src/gtkext/grid.ui
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkTilingGrid" parent="GtkGrid">
+
+ <!-- Zone supérieure -->
+
+ <child>
+ <object class="GtkRevealer" id="top">
+ <property name="transition-type">slide-up</property>
+ <property name="reveal-child">false</property>
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+
+ <child>
+ <object class="GtkDockStation" id="top_station">
+ <property name="orientation">vertical</property>
+ <property name="hexpand">true</property>
+ <property name="vexpand">false</property>
+ <property name="height-request">30</property>
+ <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator" id="top_handle">
+ <property name="orientation">vertical</property>
+ <property name="height-request">5</property>
+
+ <child>
+ <object class="GtkGestureDrag">
+ <property name="propagation-phase">capture</property>
+ <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/>
+ <signal name="drag-update" handler="gtk_tiling_grid_on_top_gesture_drag_update"/>
+ <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ <property name="column-span">3</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Zone de gauche -->
+
+ <child>
+ <object class="GtkRevealer" id="left">
+ <property name="transition-type">slide-right</property>
+ <property name="reveal-child">false</property>
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+
+ <child>
+ <object class="GtkDockStation" id="left_station">
+ <property name="orientation">vertical</property>
+ <property name="hexpand">false</property>
+ <property name="vexpand">true</property>
+ <property name="width-request">300</property>
+ <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator" id="left_handle">
+ <property name="orientation">horizontal</property>
+ <property name="width-request">5</property>
+
+ <child>
+ <object class="GtkGestureDrag">
+ <property name="propagation-phase">capture</property>
+ <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/>
+ <signal name="drag-update" handler="gtk_tiling_grid_on_left_gesture_drag_update"/>
+ <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">0</property>
+ <property name="row">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Zone centrale -->
+
+ <child>
+ <object class="GtkDockStation" id="main_station">
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Zone de droite -->
+
+ <child>
+ <object class="GtkRevealer" id="right">
+ <property name="transition-type">slide-left</property>
+ <property name="reveal-child">false</property>
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+
+ <child>
+ <object class="GtkSeparator" id="right_handle">
+ <property name="orientation">horizontal</property>
+ <property name="width-request">5</property>
+
+ <child>
+ <object class="GtkGestureDrag">
+ <property name="propagation-phase">capture</property>
+ <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/>
+ <signal name="drag-update" handler="gtk_tiling_grid_on_right_gesture_drag_update"/>
+ <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkDockStation" id="right_station">
+ <property name="orientation">vertical</property>
+ <property name="hexpand">false</property>
+ <property name="vexpand">true</property>
+ <property name="width-request">300</property>
+ <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">2</property>
+ <property name="row">1</property>
+ </layout>
+ </object>
+ </child>
+
+ <!-- Zone inférieure -->
+
+ <child>
+ <object class="GtkRevealer" id="bottom">
+ <property name="transition-type">slide-up</property>
+ <property name="reveal-child">false</property>
+
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+
+ <child>
+ <object class="GtkSeparator" id="bottom_handle">
+ <property name="orientation">vertical</property>
+ <property name="height-request">5</property>
+
+ <child>
+ <object class="GtkGestureDrag">
+ <property name="propagation-phase">capture</property>
+ <signal name="drag-begin" handler="gtk_tiling_grid_on_gesture_drag_begin"/>
+ <signal name="drag-update" handler="gtk_tiling_grid_on_bottom_gesture_drag_update"/>
+ <signal name="drag-end" handler="gtk_tiling_grid_on_gesture_drag_end"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkDockStation" id="bottom_station">
+ <property name="orientation">horizontal</property>
+ <property name="hexpand">true</property>
+ <property name="vexpand">false</property>
+ <property name="height-request">250</property>
+ <signal name="panel-docked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ <signal name="panel-undocked" handler="gtk_tiling_grid_on_panel_un_docked"/>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ <layout>
+ <property name="column">0</property>
+ <property name="row">2</property>
+ <property name="column-span">3</property>
+ </layout>
+ </object>
+ </child>
+
+ </template>
+</interface>
diff --git a/src/gtkext/hexview.c b/src/gtkext/hexview.c
index 6df1140..95b592e 100644
--- a/src/gtkext/hexview.c
+++ b/src/gtkext/hexview.c
@@ -37,6 +37,22 @@
/* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */
+/* Liste des propriétés */
+
+typedef enum _HexViewProperty {
+
+ PROP_0, /* Réservé */
+
+ PROP_SHOW_OFFSETS, /* Affichage des positions */
+ PROP_CONTENT, /* Contenu binaire affiché */
+
+ N_PROPERTIES
+
+} HexViewProperty;
+
+static GParamSpec *_hex_view_properties[N_PROPERTIES] = { NULL, };
+
+
/* Initialise la classe des afficheurs de tampons bruts. */
static void gtk_hex_view_class_init(GtkHexViewClass *);
@@ -44,10 +60,10 @@ static void gtk_hex_view_class_init(GtkHexViewClass *);
static void gtk_hex_view_init(GtkHexView *);
/* Supprime toutes les références externes. */
-static void gtk_hex_view_dispose(GtkHexView *);
+static void gtk_hex_view_dispose(GObject *);
/* Procède à la libération totale de la mémoire. */
-static void gtk_hex_view_finalize(GtkHexView *);
+static void gtk_hex_view_finalize(GObject *);
/* Procède à l'actualisation de l'affichage d'un sous-composant. */
static void gtk_hex_view_dispatch_sub_snapshot(GtkWidget *, GtkSnapshot *, GtkWidget *);
@@ -57,14 +73,14 @@ static void gtk_hex_view_populate_cache(GtkHexView *);
-void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent);
-
-
-
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+/* Met à jour une propriété d'instance GObject. */
+static void gtk_hex_view_set_property(GObject *, guint, const GValue *, GParamSpec *);
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_hex_view_get_property(GObject *, guint, GValue *, GParamSpec *);
/* Prend acte de la taille allouée au composant d'affichage. */
static void gtk_hex_view_size_allocate(GtkWidget *, int, int, int);
@@ -105,12 +121,26 @@ static void gtk_hex_view_class_init(GtkHexViewClass *class)
object = G_OBJECT_CLASS(class);
- object->dispose = (GObjectFinalizeFunc/* ! */)gtk_hex_view_dispose;
- object->finalize = (GObjectFinalizeFunc)gtk_hex_view_finalize;
+ object->dispose = gtk_hex_view_dispose;
+ object->finalize = gtk_hex_view_finalize;
+ object->set_property = gtk_hex_view_set_property;
+ object->get_property = gtk_hex_view_get_property;
+
+ _hex_view_properties[PROP_SHOW_OFFSETS] =
+ g_param_spec_boolean("show-offsets", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ _hex_view_properties[PROP_CONTENT] =
+ g_param_spec_object("content", NULL, NULL,
+ G_TYPE_BIN_CONTENT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties(object, N_PROPERTIES, _hex_view_properties);
widget = GTK_WIDGET_CLASS(class);
- // REMME gtk_widget_class_set_css_name(widget, "GtkHexView");
+ gtk_widget_class_set_css_name(widget, "hexview");
g_type_ensure(GTK_TYPE_COMPOSING_AREA);
@@ -167,12 +197,14 @@ static void gtk_hex_view_init(GtkHexView *view)
view->generator = NULL;
+ gtk_hex_view_create(view, NULL);
+
}
/******************************************************************************
* *
-* Paramètres : view = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -182,20 +214,24 @@ static void gtk_hex_view_init(GtkHexView *view)
* *
******************************************************************************/
-static void gtk_hex_view_dispose(GtkHexView *view)
+static void gtk_hex_view_dispose(GObject *object)
{
- gtk_widget_dispose_template(GTK_WIDGET(view), GTK_TYPE_HEX_VIEW);
+ GtkHexView *view; /* Version spécialisée */
+
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_HEX_VIEW);
+
+ view = GTK_HEX_VIEW(object);
g_clear_object(&view->generator);
- G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(G_OBJECT(view));
+ G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : view = instance d'objet GLib à traiter. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -205,9 +241,9 @@ static void gtk_hex_view_dispose(GtkHexView *view)
* *
******************************************************************************/
-static void gtk_hex_view_finalize(GtkHexView *view)
+static void gtk_hex_view_finalize(GObject *object)
{
- G_OBJECT_CLASS(gtk_hex_view_parent_class)->finalize(G_OBJECT(view));
+ G_OBJECT_CLASS(gtk_hex_view_parent_class)->finalize(object);
}
@@ -263,13 +299,43 @@ bool gtk_hex_view_create(GtkHexView *view, GBinContent *content)
parent = GTK_BUFFER_VIEW(view);
- cache = g_buffer_cache_new(1, 2);
+ cache = g_buffer_cache_new(1 /* opt_count */, 2 /* reg_count */);
parent->view = g_buffer_view_new(cache, parent->style);
unref_object(cache);
- view->generator = g_hex_generator_new(content);
+
+
+ gtk_hex_view_set_content(view, content);
+
+
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = composant d'affichage à consulter. *
+* *
+* Description : Fournit le contenu associé au composant d'affichage. *
+* *
+* Retour : Contenu dans lequel puise le générateur pour les lignes. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBinContent *gtk_hex_view_get_content(const GtkHexView *view)
+{
+ GBinContent *result; /* Référence à retourner */
+
+ if (view->generator != NULL)
+ result = g_hex_generator_get_content(view->generator);
+ else
+ result = NULL;
return result;
@@ -278,6 +344,61 @@ bool gtk_hex_view_create(GtkHexView *view, GBinContent *content)
/******************************************************************************
* *
+* Paramètres : view = composant d'affichage à modifier. *
+* content = nouveau contenu pour source de génération. *
+* *
+* Description : Définit le contenu associé au composant d'affichage. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_hex_view_set_content(GtkHexView *view, GBinContent *content)
+{
+ GBinContent *old; /* Ancienne valeur */
+ GBufferCache *cache; /* Tampon à représenter */
+
+ old = gtk_hex_view_get_content(view);
+
+ assert((old == NULL && view->generator == NULL) || (old != NULL && view->generator != NULL));
+
+ if (old != content)
+ {
+ if (view->generator != NULL)
+ {
+ cache = g_buffer_view_get_cache(GTK_BUFFER_VIEW(view)->view);
+
+ g_buffer_cache_wlock(cache);
+
+ g_buffer_cache_truncate(cache, 0);
+
+ g_buffer_cache_wunlock(cache);
+
+ unref_object(cache);
+
+ g_clear_object(&view->generator);
+
+ }
+
+ if (content != NULL)
+ view->generator = g_hex_generator_new(content);
+
+ g_object_notify_by_pspec(G_OBJECT(view), _hex_view_properties[PROP_CONTENT]);
+
+ assert(content != NULL);
+ gtk_widget_queue_resize(GTK_WIDGET(view));
+
+ }
+
+ g_clear_object(&old);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : widget = composant GTK à redessiner. *
* snapshot = gestionnaire de noeuds de rendu à solliciter. *
* parent = composant GTK parent et cadre de l'appel. *
@@ -380,67 +501,108 @@ static void gtk_hex_view_populate_cache(GtkHexView *view)
/* Mise à jour de l'affichage ? */
+ /*
if (needed != count)
gtk_widget_queue_resize(GTK_WIDGET(view));
+ */
}
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à prendre en compte. *
+* pspec = définition de la propriété. *
+* *
+* Description : Met à jour une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
-
-void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent)
+static void gtk_hex_view_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
- GdkRGBA red, green, yellow, blue;
- float w, h;
-
- gdk_rgba_parse (&red, "red");
- gdk_rgba_parse (&green, "green");
- gdk_rgba_parse (&yellow, "yellow");
- gdk_rgba_parse (&blue, "blue");
+ GtkHexView *view; /* Version spécialisée */
+ GObject *content; /* Contenu sous forme simple */
- w = gtk_widget_get_width (widget) / 2.0;
- h = gtk_widget_get_height (widget) / 2.0;
+ view = GTK_HEX_VIEW(object);
- h /= 2.0;
+ switch (prop_id)
+ {
+ case PROP_SHOW_OFFSETS:
+ g_display_options_set(GTK_CONTENT_VIEW(view)->options, HCO_OFFSET, g_value_get_boolean(value));
+ gtk_widget_set_visible(view->offsets, g_value_get_boolean(value));
+ break;
- gtk_snapshot_append_color (snapshot, &red,
- &GRAPHENE_RECT_INIT(0, 0, w, h));
- gtk_snapshot_append_color (snapshot, &green,
- &GRAPHENE_RECT_INIT(w, 0, w, h));
- gtk_snapshot_append_color (snapshot, &yellow,
- &GRAPHENE_RECT_INIT(0, h, w, h));
- gtk_snapshot_append_color (snapshot, &blue,
- &GRAPHENE_RECT_INIT(w, h, w, h));
+ case PROP_CONTENT:
+ content = g_value_get_object(value);
+ gtk_hex_view_set_content(view, G_BIN_CONTENT(content));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
}
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
+* *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+static void gtk_hex_view_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GtkHexView *view; /* Version spécialisée */
+ view = GTK_HEX_VIEW(object);
+ switch (prop_id)
+ {
+ case PROP_SHOW_OFFSETS:
+ g_value_set_boolean(value, gtk_widget_get_visible(view->offsets));
+ break;
+ case PROP_CONTENT:
+ g_value_take_object(value, gtk_hex_view_get_content(view));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
-/* ---------------------------------------------------------------------------------- */
+}
/******************************************************************************
* *
-* Paramètres : widget = composant GTK à examiner. *
-* width = largeur affectée au composant graphique. *
-* height = hauteur affectée au composant graphique. *
+* Paramètres : widget = composant GTK à examiner. *
+* width = largeur affectée au composant graphique. *
+* height = hauteur affectée au composant graphique. *
* baseline = ligne de base affectée au composant graphique. *
* *
* Description : Prend acte de la taille allouée au composant d'affichage. *
@@ -467,7 +629,13 @@ static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height,
final_widths = alloca(_CHILDREN_COUNT * sizeof(int));
for (i = 0; i < _CHILDREN_COUNT; i++)
- gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min_widths[i], NULL, NULL, NULL);
+ {
+ if (!gtk_widget_get_visible(view->children[i]))
+ min_widths[i] = 0;
+ else
+ gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min_widths[i], NULL, NULL, NULL);
+
+ }
/* Passe 1 : tentative sans défilement vertical */
@@ -491,7 +659,10 @@ static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height,
for (i = 0; i < _CHILDREN_COUNT; i++)
{
- final_widths[i] += min_widths[i];
+ if (!gtk_widget_get_visible(view->children[i]))
+ final_widths[i] = 0;
+ else
+ final_widths[i] += min_widths[i];
g_width_tracker_set_column_min_width(tracker, i, final_widths[i]);
@@ -531,17 +702,6 @@ static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *widget)
}
-
-
-
-
-
-
-
-
-
-
-
/******************************************************************************
* *
* Paramètres : widget = composant GTK à examiner. *
@@ -580,8 +740,12 @@ static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation,
for (i = 0; i < _CHILDREN_COUNT; i++)
{
+ if (!gtk_widget_get_visible(view->children[i]))
+ continue;
+
gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL);
requested += min;
+
}
for_size -= requested;
@@ -593,11 +757,14 @@ static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation,
GTK_BUFFER_VIEW(view)->style,
for_size);
- if (minimum != NULL) *minimum = 0;
+ if (minimum != NULL) *minimum = requested;
if (natural != NULL) *natural = requested;
for (i = 0; i < _CHILDREN_COUNT; i++)
{
+ if (!gtk_widget_get_visible(view->children[i]))
+ continue;
+
gtk_widget_measure(view->children[i], GTK_ORIENTATION_VERTICAL, -1, &min, &nat, NULL, NULL);
if (minimum != NULL && min > *minimum)
diff --git a/src/gtkext/hexview.h b/src/gtkext/hexview.h
index 2199786..0d2cd5a 100644
--- a/src/gtkext/hexview.h
+++ b/src/gtkext/hexview.h
@@ -41,6 +41,12 @@ DECLARE_GTYPE(GtkHexView, gtk_hex_view, GTK, HEX_VIEW);
/* Crée un composant d'affichage d'octets bruts et imprimables. */
GtkHexView *gtk_hex_view_new(GBinContent *);
+/* Fournit le contenu associé au composant d'affichage. */
+GBinContent *gtk_hex_view_get_content(const GtkHexView *);
+
+/* Définit le contenu associé au composant d'affichage. */
+void gtk_hex_view_set_content(GtkHexView *, GBinContent *);
+
#endif /* _GTKEXT_HEXVIEW_H */
diff --git a/src/gtkext/hexview.ui b/src/gtkext/hexview.ui
index ae4586c..9b42936 100644
--- a/src/gtkext/hexview.ui
+++ b/src/gtkext/hexview.ui
@@ -1,27 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="GtkHexView" parent="GtkBufferView">
- <property name="css-name">GtkHexView</property>
- <child>
- <object class="GtkComposingArea" id="offsets">
- <style>
- <class name="gutter"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkComposingArea" id="hex">
- <property name="hexpand">true</property>
- <style>
- <class name="custom-view"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkComposingArea" id="ascii">
- <style>
- <class name="custom-view"/>
- </style>
- </object>
- </child>
- </template>
+
+ <template class="GtkHexView" parent="GtkBufferView">
+ <child>
+ <object class="GtkComposingArea" id="offsets">
+ <style>
+ <class name="gutter"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkComposingArea" id="hex">
+ <property name="hexpand">true</property>
+ <style>
+ <class name="custom-view"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkComposingArea" id="ascii">
+ <style>
+ <class name="custom-view"/>
+ </style>
+ </object>
+ </child>
+ </template>
+
</interface>
diff --git a/src/gtkext/launcher-int.h b/src/gtkext/launcher-int.h
new file mode 100644
index 0000000..07152f0
--- /dev/null
+++ b/src/gtkext/launcher-int.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweak-int.h - définitions internes pour un lanceur de panneau majeur
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide 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.
+ *
+ * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_LAUNCHER_INT_H
+#define _GTKEXT_LAUNCHER_INT_H
+
+
+#include "launcher.h"
+
+
+
+/* Elément de lancement d'un panneau majeur pour l'interface (instance) */
+struct _GtkPanelLauncher
+{
+ GtkListBoxRow parent; /* A laisser en premier */
+
+ GtkImage *icon; /* Eventuelle image */
+ GtkLabel *title; /* Etiquette associée */
+ GtkLabel *desc; /* Description du panneau */
+
+};
+
+/* Elément de lancement d'un panneau majeur pour l'interface (classe) */
+struct _GtkPanelLauncherClass
+{
+ GtkListBoxRowClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un nouveau lanceur de panneau majeur. */
+bool gtk_panel_launcher_create(GtkPanelLauncher *, const char *, const char *, const char *);
+
+
+
+#endif /* _GTKEXT_LAUNCHER_INT_H */
diff --git a/src/gtkext/launcher.c b/src/gtkext/launcher.c
new file mode 100644
index 0000000..5bb850b
--- /dev/null
+++ b/src/gtkext/launcher.c
@@ -0,0 +1,211 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * launcher.c - lanceur de panneau majeur
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide 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.
+ *
+ * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "launcher.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "helpers.h"
+#include "launcher-int.h"
+#include "../common/extstr.h"
+
+
+
+/* Initialise la classe des sections d'éléments paramétrables. */
+static void gtk_panel_launcher_class_init(GtkPanelLauncherClass *);
+
+/* Initialise une instance de lanceur de panneau majeur. */
+static void gtk_panel_launcher_init(GtkPanelLauncher *);
+
+/* Supprime toutes les références externes. */
+static void gtk_panel_launcher_dispose(GObject *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_panel_launcher_finalize(GObject *);
+
+
+
+/* Détermine le type du composant d'affichage générique. */
+G_DEFINE_TYPE(GtkPanelLauncher, gtk_panel_launcher, GTK_TYPE_LIST_BOX_ROW);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Initialise la classe des sections d'éléments paramétrables. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_panel_launcher_class_init(GtkPanelLauncherClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = gtk_panel_launcher_dispose;
+ object->finalize = gtk_panel_launcher_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/launcher.ui");
+
+ gtk_widget_class_bind_template_child(widget, GtkPanelLauncher, icon);
+ gtk_widget_class_bind_template_child(widget, GtkPanelLauncher, title);
+ gtk_widget_class_bind_template_child(widget, GtkPanelLauncher, desc);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : launcher = composant GTK à initialiser. *
+* *
+* Description : Initialise une instance de lanceur de panneau majeur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_panel_launcher_init(GtkPanelLauncher *launcher)
+{
+ gtk_widget_init_template(GTK_WIDGET(launcher));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_panel_launcher_dispose(GObject *object)
+{
+ gtk_widget_dispose_template(GTK_WIDGET(object), GTK_TYPE_PANEL_LAUNCHER);
+
+ G_OBJECT_CLASS(gtk_panel_launcher_parent_class)->dispose(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_panel_launcher_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(gtk_panel_launcher_parent_class)->finalize(object);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : icon = désignation de l'image de représentation. *
+* title = titre principal à afficher. *
+* desc = description du panneau ciblé. *
+* *
+* Description : Crée un nouveau lanceur de panneau majeur. *
+* *
+* Retour : Composant GTK mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkPanelLauncher *gtk_panel_launcher_new(const char *icon, const char *title, const char *desc)
+{
+ GtkPanelLauncher *result; /* Instance à retourner */
+
+ result = g_object_new(GTK_TYPE_PANEL_LAUNCHER, NULL);
+
+ if (!gtk_panel_launcher_create(result, icon, title, desc))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : launcher = lanceur à initialiser pleinement. *
+* icon = désignation de l'image de représentation. *
+* title = titre principal à afficher. *
+* desc = description du panneau ciblé. *
+* *
+* Description : Met en place un nouveau lanceur de panneau majeur. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_panel_launcher_create(GtkPanelLauncher *launcher, const char *icon, const char *title, const char *desc)
+{
+ bool result; /* Bilan à retourner */
+ char *bold; /* Titre sublimé */
+
+ result = true;
+
+ gtk_image_set_from_icon_name(launcher->icon, icon);
+
+ bold = strdup(title);
+ bold = strprep(bold, "<b>");
+ bold = stradd(bold, "</b>");
+
+ gtk_label_set_label(launcher->title, bold);
+
+ free(bold);
+
+ gtk_label_set_label(launcher->desc, desc);
+
+ return result;
+
+}
diff --git a/src/gtkext/launcher.h b/src/gtkext/launcher.h
new file mode 100644
index 0000000..3857216
--- /dev/null
+++ b/src/gtkext/launcher.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * launcher.h - prototypes pour pour un lanceur de panneau majeur
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide 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.
+ *
+ * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_LAUNCHER_H
+#define _GTKEXT_LAUNCHER_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../glibext/helpers.h"
+
+
+
+#define GTK_TYPE_PANEL_LAUNCHER (gtk_panel_launcher_get_type())
+
+DECLARE_GTYPE(GtkPanelLauncher, gtk_panel_launcher, GTK, PANEL_LAUNCHER);
+
+
+/* Crée un nouveau lanceur de panneau majeur. */
+GtkPanelLauncher *gtk_panel_launcher_new(const char *, const char *, const char *);
+
+
+
+#endif /* _GTKEXT_LAUNCHER_H */
diff --git a/src/gtkext/launcher.ui b/src/gtkext/launcher.ui
new file mode 100644
index 0000000..f6f4fec
--- /dev/null
+++ b/src/gtkext/launcher.ui
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkPanelLauncher" parent="GtkListBoxRow">
+
+ <property name="child">
+
+ <object class="GtkGrid">
+ <property name="margin-bottom">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">12</property>
+ <property name="column-spacing">12</property>
+
+ <child>
+ <object class="GtkImage" id="icon">
+ <property name="icon-name"></property>
+ <property name="pixel-size">48</property>
+ <layout>
+ <property name="column">0</property>
+ <property name="row">0</property>
+ <property name="row-span">2</property>
+ </layout>
+ <style>
+ <class name="icon-dropshadow"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="title">
+ <property name="label"></property>
+ <property name="use-markup">TRUE</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="desc">
+ <property name="label"></property>
+ <property name="hexpand">true</property>
+ <property name="xalign">0</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">1</property>
+ </layout>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">go-next-symbolic</property>
+ <property name="margin-start">12</property>
+ <layout>
+ <property name="column">2</property>
+ <property name="row">0</property>
+ <property name="row-span">2</property>
+ </layout>
+ <style>
+ <class name="icon-dropshadow"/>
+ </style>
+ </object>
+ </child>
+
+ </object>
+
+ </property>
+
+ </template>
+</interface>
diff --git a/src/gtkext/panel-int.h b/src/gtkext/panel-int.h
index 07ade20..5398e51 100644
--- a/src/gtkext/panel-int.h
+++ b/src/gtkext/panel-int.h
@@ -30,9 +30,14 @@
+/* Indique l'emplacement par défaut pour un affichage. */
+typedef char * (* get_tiled_panel_path) (const GtkTiledPanel *);
+
/* Fournit les composants adaptés pour la barre de titre. */
-typedef GListStore * (* get_tiled_panel_widgets_cb) (GtkTiledPanel *, bool);
+typedef GListStore * (* get_tiled_panel_widgets_cb) (const GtkTiledPanel *, bool);
+/* Note un ajout ou un retrait de panneau principal. */
+typedef void (* notify_tiled_panel_state_cb) (GtkTiledPanel *, GtkTiledPanel *, bool);
/* Elément réactif pour panneaux de l'éditeur (instance) */
@@ -47,8 +52,11 @@ struct _GtkTiledPanelClass
{
GtkBoxClass parent; /* A laisser en premier */
+ get_tiled_panel_path get_default_path; /* Localisation de l'affichage */
get_tiled_panel_widgets_cb get_widgets; /* Récupération de composants */
+ notify_tiled_panel_state_cb notify; /* Note d'un ajout ou retrait */
+
};
diff --git a/src/gtkext/panel.c b/src/gtkext/panel.c
index de55917..f63cfa1 100644
--- a/src/gtkext/panel.c
+++ b/src/gtkext/panel.c
@@ -137,6 +137,35 @@ static void gtk_tiled_panel_finalize(GtkTiledPanel *panel)
/******************************************************************************
* *
* Paramètres : panel = panneau graphique à consulter. *
+* *
+* Description : Indique l'emplacement attendu pour un affichage. *
+* *
+* Retour : Chemin représenté ou NULL pour l'emplacement "M" par défaut. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *gtk_tiled_panel_get_path(const GtkTiledPanel *panel)
+{
+ char *result; /* Chemin à retourner */
+ GtkTiledPanelClass *class; /* Classe à actionner */
+
+ class = GTK_TILED_PANEL_GET_CLASS(panel);
+
+ if (class->get_default_path != NULL)
+ result = class->get_default_path(panel);
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau graphique à consulter. *
* left = indication quant au côté ciblé. *
* *
* Description : Fournit les composants adaptés pour la barre de titre. *
@@ -147,7 +176,7 @@ static void gtk_tiled_panel_finalize(GtkTiledPanel *panel)
* *
******************************************************************************/
-GListStore *gtk_tiled_panel_get_title_widgets(GtkTiledPanel *panel, bool left)
+GListStore *gtk_tiled_panel_get_title_widgets(const GtkTiledPanel *panel, bool left)
{
GListStore *result; /* Composant(s) à retourner */
GtkTiledPanelClass *class; /* Classe à actionner */
@@ -164,6 +193,32 @@ GListStore *gtk_tiled_panel_get_title_widgets(GtkTiledPanel *panel, bool left)
}
+/******************************************************************************
+* *
+* Paramètres : panel = panneau graphique à manipuler. *
+* main = panneau principal visé par l'opération. *
+* activated = nature du changement de statut : ajout, retrait ?*
+* *
+* Description : Note un ajout ou un retrait de panneau principal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_tiled_panel_notify_new_main_panel_state(GtkTiledPanel *panel, GtkTiledPanel *main, bool activated)
+{
+ GtkTiledPanelClass *class; /* Classe à actionner */
+
+ class = GTK_TILED_PANEL_GET_CLASS(panel);
+
+ if (class->notify != NULL)
+ class->notify(panel, main, activated);
+
+}
+
+
diff --git a/src/gtkext/panel.h b/src/gtkext/panel.h
index d2259ef..9b00657 100644
--- a/src/gtkext/panel.h
+++ b/src/gtkext/panel.h
@@ -38,9 +38,14 @@
DECLARE_GTYPE(GtkTiledPanel, gtk_tiled_panel, GTK, TILED_PANEL);
+/* Indique l'emplacement attendu pour un affichage. */
+char *gtk_tiled_panel_get_path(const GtkTiledPanel *);
+
/* Fournit les composants adaptés pour la barre de titre. */
-GListStore *gtk_tiled_panel_get_title_widgets(GtkTiledPanel *, bool);
+GListStore *gtk_tiled_panel_get_title_widgets(const GtkTiledPanel *, bool);
+/* Note un ajout ou un retrait de panneau principal. */
+void gtk_tiled_panel_notify_new_main_panel_state(GtkTiledPanel *, GtkTiledPanel *, bool);
diff --git a/src/gtkext/statusstack-int.h b/src/gtkext/statusstack-int.h
index facc5af..721b982 100644
--- a/src/gtkext/statusstack-int.h
+++ b/src/gtkext/statusstack-int.h
@@ -26,6 +26,7 @@
#include "statusstack.h"
+#include "../glibext/secstorage.h"
@@ -49,6 +50,12 @@ struct _GtkStatusStack
GSourceFunc def_source; /* Appel en fin d'activité */
+ /* Message simple par défaut */
+
+ GtkLabel *def_label; /* Afficheur de message */
+
+ char *msg; /* Contenu associé */
+
/* Navigation */
GtkLabel *nav_segment; /* Désignation du segment */
@@ -70,6 +77,9 @@ struct _GtkStatusStack
/* Tronc commun */
+ GSecretStorage *storage; /* Stockage des secrets */
+ GtkToggleButton *lock_update; /* Activation des accès */
+
GtkLabel *net_recv_speed; /* Débit en réception */
GtkLabel *net_send_speed; /* Débit en émission */
@@ -80,6 +90,8 @@ struct _GtkStatusStack
guint network_update_tag; /* Identifiant de mise à jour */
+ GtkToggleButton *bottom_toggler; /* Bascule de panneaux inf. */
+
};
/* Gestion de barre de statut adaptable (classe) */
diff --git a/src/gtkext/statusstack.c b/src/gtkext/statusstack.c
index 0d8ef62..92c296a 100644
--- a/src/gtkext/statusstack.c
+++ b/src/gtkext/statusstack.c
@@ -41,6 +41,25 @@
/* -------------------------- GESTION GENERALE DES STATUTS -------------------------- */
+/* Liste des propriétés */
+
+typedef enum _StatusStackProperty {
+
+ PROP_0, /* Réservé */
+
+ PROP_SHOW_BOTTOM, /* Affichage de la zone inf. */
+
+ N_PROPERTIES
+
+} StatusStackProperty;
+
+static GParamSpec *_status_stack_properties[N_PROPERTIES] = { NULL, };
+
+
+/* Source d'affichage par défaut */
+#define gtk_status_stack_default_source gtk_status_stack_show_simple_message
+
+
/* Initialise la classe des barres de statut améliorées. */
static void gtk_status_stack_class_init(GtkStatusStackClass *);
@@ -53,11 +72,33 @@ static void gtk_status_stack_dispose(GtkStatusStack *);
/* Procède à la libération totale de la mémoire. */
static void gtk_status_stack_finalize(GtkStatusStack *);
+/* Note le changement de verrouillage du stockage sécurisé. */
+static void gtk_status_stack_on_secret_storage_lock_update(GSecretStorage *, GtkStatusStack *);
+
/* Met à jour dans la barre les débits réseau observés. */
static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *);
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Met à jour une propriété d'instance GObject. */
+static void gtk_status_stack_set_property(GObject *, guint, const GValue *, GParamSpec *);
+
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_status_stack_get_property(GObject *, guint, GValue *, GParamSpec *);
+
+
+
+/* ----------------------- MISE EN AVANT DES MESSAGES SIMPLES ----------------------- */
+
+
+/* S'assure de l'affichage à jour de la partie "default". */
+static gboolean gtk_status_stack_show_simple_message(gpointer);
+
+
+
/* -------------------- STATUT DES INFORMATIONS DE DESASSEMBLAGE -------------------- */
@@ -86,7 +127,7 @@ static void init_navigation_info(navigation_info_t *);
static void fini_navigation_info(navigation_info_t *);
/* S'assure de l'affichage à jour de la partie "navigation". */
-static gboolean gtk_status_stack_show_current_location(GtkStatusStack *);
+static gboolean gtk_status_stack_show_current_location(gpointer);
/* Réagit à un clic sur l'icône de zoom. */
static void gtk_status_stack_on_zoom_icon_press(GtkEntry *, GtkEntryIconPosition, GtkStatusStack *);
@@ -136,7 +177,7 @@ static void fini_activity_info(activity_info_t *);
static activity_status_t *find_activity_status_by_id(activity_info_t *, activity_id_t);
/* S'assure de l'affichage à jour de la partie "activité". */
-static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *);
+static gboolean gtk_status_stack_show_current_activity(gpointer);
@@ -170,6 +211,15 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class)
object->dispose = (GObjectFinalizeFunc/* ! */)gtk_status_stack_dispose;
object->finalize = (GObjectFinalizeFunc)gtk_status_stack_finalize;
+ object->set_property = gtk_status_stack_set_property;
+ object->get_property = gtk_status_stack_get_property;
+
+ _status_stack_properties[PROP_SHOW_BOTTOM] =
+ g_param_spec_boolean("show-bottom", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(object, N_PROPERTIES, _status_stack_properties);
widget = GTK_WIDGET_CLASS(class);
@@ -179,6 +229,8 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class)
gtk_widget_class_bind_template_child(widget, GtkStatusStack, main);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, def_label);
+
gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_segment);
gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_phys);
gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_virt);
@@ -190,9 +242,13 @@ static void gtk_status_stack_class_init(GtkStatusStackClass *class)
gtk_widget_class_bind_template_child(widget, GtkStatusStack, activity_message);
gtk_widget_class_bind_template_child(widget, GtkStatusStack, activity_progress);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, lock_update);
+
gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_recv_speed);
gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_send_speed);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, bottom_toggler);
+
}
@@ -212,7 +268,9 @@ static void gtk_status_stack_init(GtkStatusStack *stack)
{
gtk_widget_init_template(GTK_WIDGET(stack));
- stack->def_source = NULL;
+ stack->def_source = gtk_status_stack_default_source;
+
+ stack->msg = NULL;
stack->nav_info = calloc(1, sizeof(navigation_info_t));
init_navigation_info(stack->nav_info);
@@ -220,11 +278,26 @@ static void gtk_status_stack_init(GtkStatusStack *stack)
stack->activity_info = calloc(1, sizeof(activity_info_t));
init_activity_info(stack->activity_info);
+ /* Suivi des évolutions relatives au stockage sécurisé */
+
+ stack->storage = get_secret_storage();
+
+ g_signal_connect(stack->storage, "lock-update",
+ G_CALLBACK(gtk_status_stack_on_secret_storage_lock_update), stack);
+
+ gtk_status_stack_on_secret_storage_lock_update(stack->storage, stack);
+
+ /* Suivi des débits de connexion */
+
stack->next_index = 0;
stack->network_update_tag = g_timeout_add(NETWORK_UPDATE_INTERVAL,
G_SOURCE_FUNC(gtk_status_stack_update_network_stats), stack);
+ /* Premier affichage... */
+
+ gtk_status_stack_reset_to_default(stack);
+
}
@@ -242,6 +315,12 @@ static void gtk_status_stack_init(GtkStatusStack *stack)
static void gtk_status_stack_dispose(GtkStatusStack *stack)
{
+ if (stack->storage != NULL)
+ g_signal_handlers_disconnect_by_func(stack->storage,
+ gtk_status_stack_on_secret_storage_lock_update, stack);
+
+ g_clear_object(&stack->storage);
+
g_source_remove(stack->network_update_tag);
gtk_widget_dispose_template(GTK_WIDGET(stack), GTK_TYPE_STATUS_STACK);
@@ -265,6 +344,9 @@ static void gtk_status_stack_dispose(GtkStatusStack *stack)
static void gtk_status_stack_finalize(GtkStatusStack *stack)
{
+ if (stack->msg != NULL)
+ free(stack->msg);
+
fini_navigation_info(stack->nav_info);
free(stack->nav_info);
@@ -311,11 +393,49 @@ GtkStatusStack *gtk_status_stack_new(void)
* *
******************************************************************************/
-void gtk_status_stack_reset(GtkStatusStack *stack)
+void gtk_status_stack_reset_to_default(GtkStatusStack *stack)
{
- gtk_stack_set_visible_child_name(stack->main, "default");
+ /**
+ * Une amélioration possible serait de passer à g_idle_add_once(),
+ * et de s'affranchir des retours G_SOURCE_REMOVE systématiques,
+ * mais la fonction n'est disponible qu'à partir de la GLib 2.74.
+ */
- stack->def_source = NULL;
+ g_idle_add(stack->def_source, stack);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gardien des secrets impliqué. *
+* stack = barre de statut à actualiser. *
+* *
+* Description : Note le changement de verrouillage du stockage sécurisé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_on_secret_storage_lock_update(GSecretStorage *storage, GtkStatusStack *stack)
+{
+ if (!g_secret_storage_has_key(stack->storage))
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(stack->lock_update), false);
+ gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "nolock-symbolic");
+ }
+ else
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(stack->lock_update), true);
+
+ if (g_secret_storage_is_locked(stack->storage))
+ gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "locked-symbolic");
+ else
+ gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "unlocked-symbolic");
+
+ }
}
@@ -441,6 +561,148 @@ static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *stack)
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à prendre en compte. *
+* pspec = définition de la propriété. *
+* *
+* Description : Met à jour une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+
+ stack = GTK_STATUS_STACK(object);
+
+ switch (prop_id)
+ {
+ case PROP_SHOW_BOTTOM:
+ gtk_toggle_button_set_active(stack->bottom_toggler, g_value_get_boolean(value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
+* *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+
+ stack = GTK_STATUS_STACK(object);
+
+ switch (prop_id)
+ {
+ case PROP_SHOW_BOTTOM:
+ g_value_set_boolean(value, gtk_toggle_button_get_active(stack->bottom_toggler));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MISE EN AVANT DES MESSAGES SIMPLES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* msg = simple message à faire paraître. *
+* *
+* Description : Inscrit un message simple dans la barre de statut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_status_stack_display_message(GtkStatusStack *stack, const char *msg)
+{
+ if (stack->msg != NULL)
+ free(stack->msg);
+
+ if (msg != NULL)
+ stack->msg = strdup(msg);
+ else
+ stack->msg = NULL;
+
+ gtk_status_stack_show_simple_message(stack);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = pile de statuts à manipuler. *
+* *
+* Description : S'assure de l'affichage à jour de la partie "default". *
+* *
+* Retour : G_SOURCE_REMOVE pour une exécution unique. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_status_stack_show_simple_message(gpointer data)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+
+ stack = GTK_STATUS_STACK(data);
+
+ stack->def_source = gtk_status_stack_show_simple_message;
+
+ gtk_label_set_text(stack->def_label, stack->msg != NULL ? stack->msg : "");
+
+ gtk_stack_set_visible_child_name(stack->main, "default");
+
+ return G_SOURCE_REMOVE;
+
+}
+
+
+
/* ---------------------------------------------------------------------------------- */
/* STATUT DES INFORMATIONS DE DESASSEMBLAGE */
/* ---------------------------------------------------------------------------------- */
@@ -572,7 +834,7 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrang
/******************************************************************************
* *
-* Paramètres : stack = pile de statuts à manipuler. *
+* Paramètres : data = pile de statuts à manipuler. *
* *
* Description : S'assure de l'affichage à jour de la partie "navigation". *
* *
@@ -582,14 +844,15 @@ void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrang
* *
******************************************************************************/
-static gboolean gtk_status_stack_show_current_location(GtkStatusStack *stack)
+static gboolean gtk_status_stack_show_current_location(gpointer data)
{
+ GtkStatusStack *stack; /* Version spécialisée */
navigation_info_t *info; /* Informations à constituer */
char raw_pos[6 + VMPA_MAX_LEN + 1]; /* Formatage final en direct */
- stack->def_source = (GSourceFunc)gtk_status_stack_show_current_location;
+ stack = GTK_STATUS_STACK(data);
- gtk_stack_set_visible_child_name(stack->main, "navigation");
+ stack->def_source = gtk_status_stack_show_current_location;
info = stack->nav_info;
@@ -613,6 +876,10 @@ static gboolean gtk_status_stack_show_current_location(GtkStatusStack *stack)
gtk_label_set_text(stack->nav_details, info->details != NULL ? info->details : "");
+ /* Conclusion */
+
+ gtk_stack_set_visible_child_name(stack->main, "navigation");
+
return G_SOURCE_REMOVE;
}
@@ -813,7 +1080,7 @@ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *m
if (info->tag != 0)
g_source_remove(info->tag);
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
g_mutex_unlock(&info->access);
@@ -880,7 +1147,7 @@ void gtk_status_stack_update_activity_message(GtkStatusStack *stack, activity_id
if (info->tag != 0)
g_source_remove(info->tag);
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
}
@@ -937,7 +1204,7 @@ void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t
if (info->tag != 0)
g_source_remove(info->tag);
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
}
@@ -989,7 +1256,7 @@ void gtk_status_stack_extend_activity_max(GtkStatusStack *stack, activity_id_t i
if (info->tag != 0)
g_source_remove(info->tag);
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
}
@@ -1055,10 +1322,10 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id)
if (info->count == 0)
{
info->tag = 0;
- g_idle_add(stack->def_source, stack);
+ gtk_status_stack_reset_to_default(stack);
}
else if (is_last)
- info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
exit:
@@ -1069,7 +1336,7 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id)
/******************************************************************************
* *
-* Paramètres : stack = pile de statuts à manipuler. *
+* Paramètres : data = pile de statuts à manipuler. *
* *
* Description : S'assure de l'affichage à jour de la partie "activité". *
* *
@@ -1079,11 +1346,14 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id)
* *
******************************************************************************/
-static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *stack)
+static gboolean gtk_status_stack_show_current_activity(gpointer data)
{
+ GtkStatusStack *stack; /* Version spécialisée */
activity_info_t *info; /* Informations à consulter */
activity_status_t *last; /* Dernier statut à traiter */
+ stack = GTK_STATUS_STACK(data);
+
info = stack->activity_info;
g_mutex_lock(&info->access);
@@ -1092,14 +1362,14 @@ static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *stack)
{
if (info->count > 0)
{
- gtk_stack_set_visible_child_name(stack->main, "activity");
-
last = &info->statuses[info->count - 1];
gtk_label_set_text(stack->activity_message, last->message);
gtk_progress_bar_set_fraction(stack->activity_progress, (last->current * 1.0) / last->max);
+ gtk_stack_set_visible_child_name(stack->main, "activity");
+
}
info->tag = 0;
diff --git a/src/gtkext/statusstack.h b/src/gtkext/statusstack.h
index 66ad6db..96d008c 100644
--- a/src/gtkext/statusstack.h
+++ b/src/gtkext/statusstack.h
@@ -45,7 +45,15 @@ DECLARE_GTYPE(GtkStatusStack, gtk_status_stack, GTK, STATUS_STACK);
GtkStatusStack *gtk_status_stack_new(void);
/* Réinitialise la barre de statut à son stade par défaut. */
-void gtk_status_stack_reset(GtkStatusStack *);
+void gtk_status_stack_reset_to_default(GtkStatusStack *);
+
+
+
+/* ----------------------- MISE EN AVANT DES MESSAGES SIMPLES ----------------------- */
+
+
+/* Inscrit un message simple dans la barre de statut. */
+void gtk_status_stack_display_message(GtkStatusStack *, const char *);
diff --git a/src/gtkext/statusstack.ui b/src/gtkext/statusstack.ui
index 422f95d..0b7cd6d 100644
--- a/src/gtkext/statusstack.ui
+++ b/src/gtkext/statusstack.ui
@@ -1,6 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkStatusStack" parent="GtkBox">
+ <!--property name="show-bottom" bind-source="bottom_toggler" bind-property="active" bind-flags="bidirectional|sync-create"/-->
+
<child>
<object class="GtkStack" id="main">
<property name="margin-start">8</property>
@@ -9,16 +12,19 @@
<!-- Vide par défaut -->
<child>
- <object class="GtkStackPage" id="stack">
+ <object class="GtkStackPage">
<property name="name">default</property>
<property name="child">
- <object class="GtkLabel">
+ <object class="GtkLabel" id="def_label">
<property name="hexpand">true</property>
<property name="halign">fill</property>
- <property name="valign">center</property>
+ <property name="valign">baseline</property>
<property name="xalign">0</property>
<property name="label"></property>
+ <style>
+ <class name="dim-label"/>
+ </style>
</object>
</property>
@@ -148,6 +154,20 @@
</child>
<child>
+ <object class="GtkToggleButton" id="lock_update">
+ <property name="sensitive">false</property>
+ <property name="has-frame">false</property>
+ <property name="icon-name">nolock-symbolic</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkSeparator">
+ <property name="orientation">vertical</property>
+ </object>
+ </child>
+
+ <child>
<object class="GtkImage">
<property name="margin-start">8</property>
<property name="icon-name">pan-down-symbolic</property>
@@ -185,7 +205,8 @@
<child>
<object class="GtkToggleButton" id="bottom_toggler">
<property name="has-frame">false</property>
- <property name="icon-name">panel-bottom-symbolic</property>
+ <property name="icon-name">dock-station-bottom-symbolic</property>
+ <property name="action-name">win.toggle-bottom</property>
</object>
</child>
diff --git a/src/gtkext/tweak-int.h b/src/gtkext/tweak-int.h
new file mode 100644
index 0000000..0d2c213
--- /dev/null
+++ b/src/gtkext/tweak-int.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweak-int.h - définitions internes pour une section d'éléments à paramétrer
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide 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.
+ *
+ * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_TWEAK_INT_H
+#define _GTKEXT_TWEAK_INT_H
+
+
+#include "tweak.h"
+
+
+
+/* Section de paramétrage pour liste d'éléments à configurer (instance) */
+struct _GtkTweakSection
+{
+ GtkListBoxRow parent; /* A laisser en premier */
+
+ GtkImage *icon; /* Eventuelle image */
+ GtkLabel *label; /* Etiquette associée */
+ GtkWidget *next; /* Eventuelle progression */
+
+ char *category; /* Groupe de rassemblement */
+
+ union
+ {
+ GType panel; /* Accès à la page de config. */
+ char *sub; /* Sous-ensemble à presenter */
+ };
+ bool has_sub_section; /* Choix du champ valide */
+
+};
+
+/* Section de paramétrage pour liste d'éléments à configurer (classe) */
+struct _GtkTweakSectionClass
+{
+ GtkListBoxRowClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une nouvelle section de configuration. */
+bool gtk_tweak_section_create(GtkTweakSection *, const tweak_info_t *);
+
+
+
+#endif /* _GTKEXT_TWEAK_INT_H */
diff --git a/src/gtkext/tweak.c b/src/gtkext/tweak.c
new file mode 100644
index 0000000..b03cf17
--- /dev/null
+++ b/src/gtkext/tweak.c
@@ -0,0 +1,319 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweak.c - section d'éléments à paramétrer
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide 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.
+ *
+ * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "tweak.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include "helpers.h"
+#include "tweak-int.h"
+
+
+
+/* Initialise la classe des sections d'éléments paramétrables. */
+static void gtk_tweak_section_class_init(GtkTweakSectionClass *);
+
+/* Initialise une instance de section d'éléments paramétrables. */
+static void gtk_tweak_section_init(GtkTweakSection *);
+
+/* Supprime toutes les références externes. */
+static void gtk_tweak_section_dispose(GtkTweakSection *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_tweak_section_finalize(GtkTweakSection *);
+
+
+
+/* Détermine le type du composant d'affichage générique. */
+G_DEFINE_TYPE(GtkTweakSection, gtk_tweak_section, GTK_TYPE_LIST_BOX_ROW);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Initialise la classe des sections d'éléments paramétrables. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_tweak_section_class_init(GtkTweakSectionClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)gtk_tweak_section_dispose;
+ object->finalize = (GObjectFinalizeFunc)gtk_tweak_section_finalize;
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/tweak.ui");
+
+ gtk_widget_class_bind_template_child(widget, GtkTweakSection, icon);
+ gtk_widget_class_bind_template_child(widget, GtkTweakSection, label);
+ gtk_widget_class_bind_template_child(widget, GtkTweakSection, next);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = composant GTK à initialiser. *
+* *
+* Description : Initialise une instance de section d'éléments paramétrables. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_tweak_section_init(GtkTweakSection *section)
+{
+ gtk_widget_init_template(GTK_WIDGET(section));
+
+ section->category = NULL;
+
+ section->sub = NULL;
+ section->has_sub_section = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_tweak_section_dispose(GtkTweakSection *section)
+{
+ gtk_widget_dispose_template(GTK_WIDGET(section), GTK_TYPE_TWEAK_SECTION);
+
+ G_OBJECT_CLASS(gtk_tweak_section_parent_class)->dispose(G_OBJECT(section));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_tweak_section_finalize(GtkTweakSection *section)
+{
+ if (section->category != NULL)
+ free(section->category);
+
+ if (section->has_sub_section && section->sub != NULL)
+ free(section->sub);
+
+ G_OBJECT_CLASS(gtk_tweak_section_parent_class)->finalize(G_OBJECT(section));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations associées à la section. *
+* *
+* Description : Crée une nouvelle section de configuration. *
+* *
+* Retour : Composant GTK mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkTweakSection *gtk_tweak_section_new(const tweak_info_t *info)
+{
+ GtkTweakSection *result; /* Instance à retourner */
+
+ result = g_object_new(GTK_TYPE_TWEAK_SECTION, NULL);
+
+ if (!gtk_tweak_section_create(result, info))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à initialiser pleinement. *
+* info = informations associées à la section. *
+* *
+* Description : Met en place une nouvelle section de configuration. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_tweak_section_create(GtkTweakSection *section, const tweak_info_t *info)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ gtk_image_set_from_icon_name(section->icon, info->image);
+ gtk_label_set_label(section->label, info->label);
+
+ gtk_widget_set_visible(section->next, info->has_sub_section);
+
+ section->category = strdup(info->category);
+
+ if (info->has_sub_section)
+ {
+ section->sub = strdup(info->sub);
+ section->has_sub_section = true;
+ }
+ else
+ {
+ section->panel = info->panel;
+ section->has_sub_section = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à consulter. *
+* *
+* Description : Fournit l'étiquette associée à une section de configuration. *
+* *
+* Retour : Désignation humaine de la section. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *gtk_tweak_section_get_label(const GtkTweakSection *section)
+{
+ const char *result; /* Texte à retourner */
+
+ result = gtk_label_get_text(section->label);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à consulter. *
+* *
+* Description : Indique si la section renvoie vers une sous-section. *
+* *
+* Retour : Bilan de la consultation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_tweak_section_has_sub_section(const GtkTweakSection *section)
+{
+ bool result; /* Statut à retourner */
+
+ result = section->has_sub_section;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à consulter. *
+* *
+* Description : Fournit le type d'un éventuel panneau de configuration lié. *
+* *
+* Retour : Bilan de la consultation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GType gtk_tweak_section_get_panel(const GtkTweakSection *section)
+{
+ GType result; /* Type d'objet à retourner */
+
+ assert(!section->has_sub_section);
+
+ result = section->panel;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : section = section à consulter. *
+* *
+* Description : Fournit la désignation d'une éventuelle sous-section liée. *
+* *
+* Retour : Désignation associée à la sous-section. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *gtk_tweak_section_get_sub_section(const GtkTweakSection *section)
+{
+ const char *result; /* Désignation à renvoyer */
+
+ assert(section->has_sub_section);
+
+ result = section->sub;
+
+ return result;
+
+}
diff --git a/src/gtkext/tweak.h b/src/gtkext/tweak.h
new file mode 100644
index 0000000..8c44844
--- /dev/null
+++ b/src/gtkext/tweak.h
@@ -0,0 +1,90 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * tweak.h - prototypes pour pour une section d'éléments à paramétrer
+ *
+ * Copyright (C) 2025 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide 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.
+ *
+ * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_TWEAK_H
+#define _GTKEXT_TWEAK_H
+
+
+#include <stdbool.h>
+#include <gtk/gtk.h>
+
+
+#include "../glibext/helpers.h"
+
+
+
+/* Définition d'une section de configuration */
+typedef struct _tweak_info_t
+{
+ const char *parent; /* Ensemble d'appartenance */
+
+ const char *category; /* Groupe de rassemblement */
+
+ const char *image; /* Eventuelle image associée */
+ const char *key; /* Désignation de la section */
+ const char *label; /* Désignation humaine */
+
+ union
+ {
+ GType panel; /* Accès à la page de config. */
+ const char *sub; /* Sous-ensemble à presenter */
+ };
+ bool has_sub_section; /* Choix du champ valide */
+
+} tweak_info_t;
+
+
+#define TWEAK_SIMPLE_DEF(p, c, i, k, l, t) \
+ { \
+ .parent = p, \
+ .category = c, \
+ .image = i, \
+ .key = k, \
+ .label = l, \
+ .panel = t, \
+ .has_sub_section = false, \
+ }
+
+#define GTK_TYPE_TWEAK_SECTION (gtk_tweak_section_get_type())
+
+DECLARE_GTYPE(GtkTweakSection, gtk_tweak_section, GTK, TWEAK_SECTION);
+
+
+/* Crée une nouvelle section de configuration. */
+GtkTweakSection *gtk_tweak_section_new(const tweak_info_t *);
+
+/* Fournit l'étiquette associée à une section de configuration. */
+const char *gtk_tweak_section_get_label(const GtkTweakSection *);
+
+/* Indique si la section renvoie vers une sous-section. */
+bool gtk_tweak_section_has_sub_section(const GtkTweakSection *);
+
+/* Fournit le type d'un éventuel panneau de configuration lié. */
+GType gtk_tweak_section_get_panel(const GtkTweakSection *);
+
+/* Fournit la désignation d'une éventuelle sous-section liée. */
+const char *gtk_tweak_section_get_sub_section(const GtkTweakSection *);
+
+
+
+#endif /* _GTKEXT_TWEAK_H */
diff --git a/src/gtkext/tweak.ui b/src/gtkext/tweak.ui
new file mode 100644
index 0000000..576e25e
--- /dev/null
+++ b/src/gtkext/tweak.ui
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkTweakSection" parent="GtkListBoxRow">
+
+ <property name="child">
+
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="margin-top">14</property>
+ <property name="margin-bottom">14</property>
+
+ <child>
+ <object class="GtkImage" id="icon">
+ <property name="icon-name">security-high-symbolic</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <style>
+ <class name="icon-dropshadow"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Security</property>
+ <property name="hexpand">true</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkImage" id="next">
+ <property name="icon-name">go-next-symbolic</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <style>
+ <class name="icon-dropshadow"/>
+ </style>
+ </object>
+ </child>
+
+ </object>
+ </property>
+
+ </template>
+</interface>