diff options
Diffstat (limited to 'src/gtkext')
33 files changed, 3174 insertions, 863 deletions
diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am index 2a2738a..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,20 +54,29 @@ 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/%) -dev_HEADERS = $(libgtkext_la_SOURCES:%c=) +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> |