diff --git a/(notes) b/(notes)
new file mode 100644
index 0000000..930caee
--- /dev/null
+++ b/(notes)
@@ -0,0 +1,239 @@
+
+contain.c: (136) gtk_box_append (middle_box, GTK_WIDGET (get_GLArea()));
+
+graph_area.h: (177) static inline GLuint create_shader(const int stack_id, int type, const char *src) {...}
+
+graph_area.c: (153) graphics_draw (stack_index[i].stack_id);
+
+graph_area.c: (233) g_signal_connect (adj, "value-changed", G_CALLBACK(on_axis_value_change), (gpointer) label);
+graph_area.c: (289) g_signal_connect(GTK_GL_AREA(gl_area), "render", G_CALLBACK(on_glarea_render), NULL);
+graph_area.c: g_signal_connect(gl_area, "realize", G_CALLBACK(on_glarea_realize), NULL);
+graph_area.c: g_signal_connect(gl_area, "unrealize", G_CALLBACK(on_glarea_unrealize), NULL);
+
+graph_stack.c: (149) if (!graphics_init_shaders(cur_id)) return -1;
+graph_stack.c: (153) graphics_init_buffers(cur_id);
+
+graph_stack.c: (288) draw_space_ridges_vertex (stack_id, stack->buffer_vertex_size, space_X, space_Y, space_Z);
+graph_stack.c: draw_space_ridges_lines (stack_id);
+graph_stack.c: draw_grids_on_space_faces_vertex (stack_id, space_X, space_Y, space_Z);
+graph_stack.c: draw_grids_on_space_faces_lines (stack_id, stack->buffer_lines_size, space_X, space_Y, space_Z);
+
+graph_stack.c: (316) stack->arrows_nb = set_arrow (stack_id, stack->arrows_nb, space_X, space_Y, space_Z, arrow.load, arrow.site, arrow.x, arrow.y, arrow.z);
+
+--------------------------------------------------------------------------------
+
+contain is called (#included) in : callback, display, tree, graph_stack, graph_area, init,
+
+--------------------------------------------------------------------------------
+
+// https://docs.gtk.org/gtk4/visual_index.html < widgets gallery
+// https://docs.gtk.org/gtk4/section-text-widget.html
+// https://docs.gtk.org/gtk4/class.Widget.html#height-for-width-geometry-management
+// GTK_ORIENTATION_VERTICAL GTK_ORIENTATION_HORIZONTAL
+
+
+
+
+
+
+
+
+
+
+
+
+https://docs.gtk.org/gtk4/visual_index.html widgets gallery
+https://forge.a-lec.org/gem-graph/gem-graph-client/src/branch/devel/Makefile
+https://docs.gtk.org/gtk4/class.Widget.html#height-for-width-geometry-management
+// GtkSizeRequestMode get_request_mode (GtkWidget* widget);
+// gtk_window_set_default_size (GTK_WINDOW (a_box), 30, 400); < TO STUDY
+https://docs.gtk.org/gtk4/section-text-widget.html texts
+https://docs.gtk.org/gtk4/drag-and-drop.html drag-and-drop
+https://docs.gtk.org/gtk4/class.GestureZoom.html GtkGestureZoom
+https://docs.gtk.org/gtk4/class.ListView.html
+https://blog.gtk.org/2020/09/08/on-list-models/ < TODO
+https://docs.gtk.org/gio/method.ActionMap.add_action_entries.html
+--------------------------------------------------------------------------------
+
+
+GTK_ORIENTATION_VERTICAL GTK_ORIENTATION_HORIZONTAL
+
+GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT GTK_SIZE_REQUEST_CONSTANT_SIZE
+
+g_signal_connect (button, "clicked", G_CALLBACK (printf("%s\n", text)), text);
+g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window);
+
+--------------------------------------------------------------------------------
+
+GtkBox GtkGrid GtkRevealer GtkStack
+GtkOverlay GtkPaned GtkExpander GtkFixed
+
+box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+gtk_widget_set_halign (box, GTK_ALIGN_FILL);
+gtk_widget_set_valign (box, GTK_ALIGN_CENTER); // START CENTER END FILL
+gtk_window_set_child (GTK_WINDOW (window), box);
+puis, après déclaration du bouton, gtk_box_append (GTK_BOX (box), button);
+
+grid = gtk_grid_new ();
+gtk_window_set_child (GTK_WINDOW (window), grid);
+button = gtk_button_new_with_label (" I "); n fois
+gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1); n fois
+
+--------------------------------------------------------------------------------
+
+TODO (or NOT TODO)
+
+GtkWidget *get_text_view(){ // WTF ?!& @Grr #~!
+ // https://docs.gtk.org/gtk4/section-text-widget.html
+ GtkWidget *my_view = gtk_text_view_new ();
+ GtkTextTagTable *my_table = gtk_text_tag_table_new ();
+ GtkTextBuffer *my_buffer = gtk_text_buffer_new (my_table);
+
+ gtk_text_buffer_set_text (my_buffer, "Hello, this is some text", -1);
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (my_view), my_buffer);
+
+ /* Now you might put the view in a container and display it on the
+ * screen; when the user edits the text, signals on the buffer
+ * will be emitted, such as "changed", "insert_text", and so on.
+ */
+ return my_view;
+}
+
+
+
+
+
+
+/*
+https://docs.gtk.org/gtk4/class.ApplicationWindow.html
+
+GtkApplication *app = gtk_application_new ("org.gtk.test", 0);
+
+GtkBuilder *builder = gtk_builder_new_from_string (
+ ""
+ " "
+ "",
+ -1);
+
+GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"));
+gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
+g_object_unref (builder);
+
+// ...
+
+GtkWidget *window = gtk_application_window_new (app);
+
+*/
+//------------------------------------------------------------------------------
+
+GtkScrolledWindow *get_scrolled_gl_area(){
+ GtkScrolledWindow *scrolled = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new());
+ gtk_scrolled_window_set_min_content_width (scrolled, W_IMAGE);
+ gtk_scrolled_window_set_min_content_height (scrolled, H_IMAGE);
+// GtkAdjustment *width = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000);
+// GtkAdjustment *height = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000);
+ // (value, lower, upper, step_increment, page_increment, page_size)
+// GtkWidget *GLarea = gtk_gl_area_new();
+// gtk_scrolled_window_set_child (scrolled, GLarea);
+// https://docs.gtk.org/gtk4/class.GLArea.html
+ return scrolled;
+}
+
+
+
+
+// https://docs.gtk.org/gtk4/getting_started.html (m'aura bien servi, quand même !)
+
+
+
+//typedef anytype = {(int)(*fnct) {printf("typedef {(int)(*fnct) {printf("");}");} GtkModelFnct;
+
+
+
+
+
+
+
+
+
+
+
+/*
+ essai run-stop, speed et step by step dans une seule box controls
+ -----------------------------------------------------------------
+
+
+#include
+#include
+#include "cold.h"
+
+void print_text(GtkWidget *widget, gpointer data) {g_print (data);}
+
+GtkWidget *get_a_space_test_image(){
+ GtkWidget *image;
+ image = GTK_WIDGET(get_scrolled_gl_area());
+ image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/images/aXoris.png");
+ image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/images/gg sketch.png");
+ image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/images/E coli.png");
+ image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/images/E coli resized.png");
+ image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/E coli by David S. Goodsell (2009).png");
+ return image;
+}
+
+GtkWidget *get_scroll_speed(){
+ GtkAdjustment *speed_adjust = gtk_adjustment_new (0, 0, 100, 1, 0, 0);
+ GtkWidget *scroll_speed = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, speed_adjust);
+ return scroll_speed;
+}
+
+// TODO cliquer sur "RUN" --> affiche "STOP" (et inversement)
+GtkBox *get_RUN_STOP_box(){
+ GtkBox *RUN_STOP_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); // spacing = 2
+
+ GtkWidget *RUN_Label = GTK_WIDGET (gtk_label_new (NULL)); // "RUN"));
+ const char *str = " RUN\n STOP";
+ const char *format = "\%s";
+ char *markup;
+
+ markup = g_markup_printf_escaped (format, str);
+ gtk_label_set_markup (GTK_LABEL (RUN_Label), markup); // Sets the labels text and attributes from markup.
+ g_free (markup);
+
+ gtk_label_set_max_width_chars (GTK_LABEL(RUN_Label), 12);
+ gtk_label_set_wrap (GTK_LABEL(RUN_Label), TRUE);
+ gtk_label_set_xalign (GTK_LABEL(RUN_Label), 0.5); // xalign value, between 0 and 1
+ gtk_label_set_yalign (GTK_LABEL(RUN_Label), 0.5);
+ gtk_label_set_selectable (GTK_LABEL(RUN_Label), FALSE); // default = FALSE
+ gtk_label_set_single_line_mode (GTK_LABEL(RUN_Label), TRUE); // default = TRUE
+ //
+ gtk_box_append (RUN_STOP_box, RUN_Label);
+ return RUN_STOP_box;
+}
+
+GtkBox *get_STEP_by_STEP_box(){
+ GtkBox *STEP_by_STEP_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0));
+ GtkWidget *STEP_by_STEP_Label = GTK_WIDGET (gtk_label_new ("ONE\nSTEP"));
+ gtk_box_append (STEP_by_STEP_box, STEP_by_STEP_Label);
+ return STEP_by_STEP_box;
+}
+
+GtkBox *get_CONTROL_box(){
+ GtkBox *CONTROL_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_VERTICAL, 0));
+ gtk_box_append (CONTROL_box, GTK_WIDGET (get_RUN_STOP_box()));
+ gtk_box_append (CONTROL_box, GTK_WIDGET (get_scroll_speed()));
+ gtk_box_append (CONTROL_box, GTK_WIDGET (get_STEP_by_STEP_box()));
+ return CONTROL_box;
+}
+*/
diff --git a/Makefile b/Makefile
index ed08dd6..18f51cb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,24 +1,158 @@
-all: Getting_Started_with_GTK
+.PHONY: run clean install all
+.DELETE_ON_ERROR: $(BINDIR)/Getting_Started_with_GTK
+.DEFAULT_GOAL: all
+NTHREADS= $(shell nproc)
+CC=gcc
+CFLAGS=`pkg-config --cflags gtk4 gl glib-2.0 libxml-2.0`
+LDFLAGS=`pkg-config --libs gtk4 gl glib-2.0 libxml-2.0` -lGL -lGLU -lm -lepoxy -lX11 -lGLEW
WARNINGS = -Wall
-DEBUG = -ggdb -fno-omit-frame-pointer
-OPTIMIZE = -O2
+DEBUG = -ggdb -fno-omit-frame-pointer #-fdiagnostics-color=always -fsanitize=bounds -fstack-check
+OPTIMIZE = -O3
+BINDIR=bin
+BUILDDIR=build
+SRCDIR=src
-Getting_Started_with_GTK: Makefile main.c
- $(CC) -o $@ $(WARNINGS) $(DEBUG) $(OPTIMIZE) main.c
+sources = $(shell find . -maxdepth 1 -type f -name "*.c")
+objects = $(patsubst %.c,%.o,$(sources))
+dependencies = $(patsubst %.c,%.d,$(sources))
-clean:
- rm -f Getting_Started_with_GTK
+all: myprogram
+
+-include $(dependencies)
+
+myprogram: $(objects)
+ $(CC) $(LDFLAGS) $(WARNINGS) $(DEBUG) $(OPTIMIZE) $^ -o $@
+
+%.o: %.c Makefile
+ $(CC) $(CFLAGS) $(WARNINGS) $(DEBUG) $(OPTIMIZE) -c $< -o $@
+
+%.d: %.c Makefile
+ $(CC) $(CFLAGS) -MM -MT $(@:%.d=%.o) -MF $@ $<
-# Builder will call this to install the application before running.
install:
echo "Installing is not supported"
-# Builder uses this target to run your application.
-run:
- ./main
+run: myprogram
+ ./myprogram
-# gcc $( pkg-config --cflags gtk4 ) -o main main.c $( pkg-config --libs gtk4 )
+clean:
+ rm -f myprogram
+ rm -f *.o
+ rm -f *.d
+
+# /!\ erreur fatale: GL/glu.h >
+# gcc -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -g -Wall -Wextra
+# -std=c99 -lm *.c -o formattage `pkg-config --cflags --libs glib-2.0`
+
+#------------------------------------------------------------------------------#
+# 'make' has an implicit rule for updating a ‘.o’ file #
+# from a correspondingly named ‘.c’ file #
+# using a ‘cc -c’ command. #
+# Implicit rules are listed and applied in a predefined order (C before P...) #
+# Predefined implicit rules are implemented in make as suffix rules #
+# The default suffix list is: .out, .a, .ln, .o, .c, .cc, .C, .cpp, .p,... #
+# Rules whose suffixes fail to be on the list are disabled. #
+# You can define your own implicit rules by writing pattern rules. #
+#------------------------------------------------------------------------------#
+
+# If there are many implicit rules with the same target pattern,
+# the rule that actually applies is the one whose prerequisites exist or can be made
+# ex: a .o can be made from a .c (C compiler) or a .p (Pascal compiler)
+
+# Variables allow a text string to be defined once
+# and substituted in multiple places later.
+# (see Chapter 6 [How to Use Variables], page 65)
+
+
+
+#------------------------------------------------------------------------------#
+# To study : how can the following commands be modified ? #
+#------------------------------------------------------------------------------#
+
+#SHELL = /bin/sh
+#.SUFFIXES:
+#.SUFFIXES: .c .o .h # is .h useful ?
+#.PHONY = run
+#.PHONY = clean
+#.PHONY: Makefile
+
+#CC=gcc
+#CFLAGS=`pkg-config --cflags gtk4 --libs gtk4`
+#WARNINGS = -Wall
+#DEBUG = -ggdb -fno-omit-frame-pointer
+#OPTIMIZE = -O2
+
+# in exec.o:
+# $(WARNINGS) $(DEBUG) $(OPTIMIZE) < ne sont pas indispensables
+# si le $@ est supprimé, main.cest modifié
+#all:
+# exec
+
+#install:
+# echo "Installing is not supported"
+
+
+
+
+
+
+#------------------------------------------------------------------------------#
+# Personnal notes & links #
+#------------------------------------------------------------------------------#
+
+
+# gcc $( pkg-config --cflags gtk4 ) -o exec main.c $( pkg-config --libs gtk4 )
+
+# https://www.gnu.org/software/make/manual/
+
+# Makefiles contain five kinds of things:
+# explicit rules, implicit rules, variable definitions, directives and comments.
+
+
+# Variables automatiques --------------------------------------------------
+# $@ fait référence à la cible de la règle (au nom de la cible).
+# $< fait référence à la première dépendance.
+# $? fait référence aux noms de touess les dépendances plus récentes que la cible.
+# = les fichiers qui ont été modifiés après la compilation de code la plus récente
+# $^ fait référence aux noms de touess les dépendances avec des espaces entre eux.
+
+# Variables implicites -------------------------------------------------
+# VPATH Équivalent utilitaire de la variable PATH de Bash. Vide par défaut.
+# Les chemins sont séparés par le signe deux-points (:).
+# CC Le programme pour compiler des fichiers C.
+# La valeur par défaut est cc. (Habituellement, cc pointe vers gcc.)
+# CPP Le programme qui exécute le préprocesseur C.
+# La valeur par défaut est $ (CC) -E.
+# LEX Le programme qui transforme les grammaires lexicales en code source.
+# La valeur par défaut est lex. (Vous devriez remplacer cela par flex.)
+# LINT Le programme qui lint votre code source. La valeur par défaut est lint.
+# RM La commande pour supprimer un fichier. La valeur par défaut est rm -f.
+# CFLAGS Contient tous les indicateurs du compilateur C (cc).
+# CPPFLAGS tous les indicateurs du préprocesseur C.
+# .PHONY Spécifie des cibles qui ne ressemblent pas au nom d'un fichier.
+# Un exemple est la cible "make clean" ; où clean est une valeur de .PHONY
+
+# Syntaxe de Base
+# Règles : Une règle se compose d'une cible, des dépendances et des commandes.
+# Elle est généralement structurée comme suit :
+# cible: dépendances
+# commande
+#
+# La cible (target) est le fichier à générer,
+# les dépendances (prerequisites) sont les fichiers requis pour construire la cible
+# et les commandes (recipe) sont les instructions exécutées pour créer la cible.
+#
+# A simple makefile consists of “rules” with the following shape:
+# target ... : prerequisites ...
+# recipe
+# ...
+# A target is usually the name of a file that is generated by a program;
+# examples of targets are executable or object files.
+# A target can also be the name of an action to carry out, such as ‘clean’
+
+
+# accessoirement : https://blog.stephane-robert.info/docs/makefile/ & /docs/task/
diff --git a/Makefile de gem-graph-client b/Makefile de gem-graph-client
deleted file mode 100644
index 7012b2b..0000000
--- a/Makefile de gem-graph-client
+++ /dev/null
@@ -1,132 +0,0 @@
-##
-## Gem-graph OpenGL experiments
-##
-## Desc: Makefile
-##
-## Copyright (C) 2023 Arthur Menges
-## Copyright (C) 2023 Adrien Bourmault
-##
-## This file is part of Gem-graph.
-##
-## This program is free software: you can redistribute it and/or modify
-## it under the terms of the GNU Affero General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## This program 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 Affero General Public License for more details.
-##
-## You should have received a copy of the GNU Affero General Public License
-## along with this program. If not, see .
-##
-
-.PHONY: all clean install run build_system
-.DELETE_ON_ERROR: $(BINDIR)/gem-graph-client
-.DEFAULT_GOAL := all
-
-#
-# Color codes
-#
-CL='\033[0;32m'
-CL2='\033[1;36m'
-CL3='\033[0m'
-NC='\033[1;37m'
-
-#
-# Variables & constants
-#
-NTHREADS= $(shell nproc)
-
-CC=gcc
-WARNINGS= -Wall
-DEBUG= -ggdb -fno-omit-frame-pointer -fdiagnostics-color=always -fsanitize=bounds -fstack-check
- #-fsanitize=address \
- #-fsanitize=pointer-compare -fsanitize=pointer-subtract \
- #-fsanitize=leak -fsanitize=undefined -fsanitize=null -fsanitize=bounds
-OPTIMIZE= -O3
-INCLUDE= $(shell pkg-config --cflags glib-2.0 libxml-2.0 gtk4)
-LIBS= $(shell pkg-config --libs glib-2.0 libxml-2.0 gtk4) -lGL -lGLU -lm -lepoxy -lX11 -lGLEW
-
-BINDIR=bin
-BUILDDIR=build
-SRCDIR=src
-#vpath %.c $(SRCDIR)
-
-SOURCES= $(shell find $(SRCDIR) -type f -name "*.c")
-BUILDBINS=$(patsubst %.c,$(BUILDDIR)/%.o,$(SOURCES))
-BUILDDEPS=$(patsubst %.c,$(BUILDDIR)/%.d,$(SOURCES))
-
--include /etc/os-release
-
-#
-# Directories
-#
-$(BUILDDIR):
- @mkdir -p $@
- @echo -e ${CL2}[$@] ${CL}folder generated.${CL3}
-
-$(BINDIR):
- @mkdir -p $@
- @echo -e ${CL2}[$@] ${CL}folder generated.${CL3}
-
-#
-# Dependencies
-#
--include $(BUILDDEPS)
-
-$(BUILDDIR)/%.d: %.c | $(BUILDDIR)
- @mkdir -p $(shell dirname $@)
- @$(CC) -MM -MT $(@:%.d=%.o) -MF $@ $<
- @echo -e ${CL2}[$@] ${CL}dependencies generated.${CL3}
-
-#
-# Compilation
-#
-$(BINDIR)/gem-graph-client: $(BUILDBINS) | $(BINDIR)
- @$(CC) -o $@ $(WARNINGS) $(DEBUG) $(OPTIMIZE) $^ $(INCLUDE) $(LIBS)
- @echo -e ${CL2}[$@] ${CL}built.${CL3}
-
-
-$(BUILDDIR)/%.o: %.c | $(BUILDDIR)
- @mkdir -p $(shell dirname $@)
- @$(CC) $(WARNINGS) $(DEBUG) $(OPTIMIZE) $(INCLUDE) -c $< -o $@
- @echo -e ${CL2}[$@] ${CL}compiled.${CL3}
-
-
-#
-# Virtual recipes
-#
-clean:
- @rm -rf $(BINDIR)
- @rm -rf $(BUILDDIR)
- @echo -e ${CL2}[$@] ${CL}done.${CL3}
-
-install:
- echo "Installing is not supported"
-
-build_system:
- @echo -e ${CL2}[$@] ${CL}building...${CL3}
- @make $(BINDIR)/gem-graph-client -j $(NTHREADS)
- @echo -e ${CL2}[$@] ${CL}done.${CL3}
-
-run: build_system
- @echo -e ${CL2}[$@] ${CL}executing...${CL3}
- @$(BINDIR)/gem-graph-client
- @echo -e ${CL2}[$@] ${CL}done.${CL3}
-
-debug: build_system
- @echo -e ${CL2}[$@] ${CL}executing...${CL3}
- @gdb $(BINDIR)/gem-graph-client
- @echo -e ${CL2}[$@] ${CL}done.${CL3}
-
-valgrind: build_system
- @echo -e ${CL2}[$@] ${CL}executing...${CL3}
- @valgrind $(BINDIR)/gem-graph-client
- @echo -e ${CL2}[$@] ${CL}done.${CL3}
-
-all: build_system
- @echo -e ${CL2}[$@] ${CL}done.${CL3}
-
-
diff --git a/automaton.c b/automaton.c
new file mode 100644
index 0000000..4f4f6fa
--- /dev/null
+++ b/automaton.c
@@ -0,0 +1,79 @@
+#include
+#include
+#include "callback.h"
+#include "automaton.h"
+
+
+/******************************************************************************/
+/* S T A T E S */
+/******************************************************************************/
+
+static int choice_EXEC_EDIT = EXEC;
+static int choice_STATE_RULES_DATA = STATE;
+
+
+/******************************************************************************/
+/* T R A N S I T I O N S */
+/******************************************************************************/
+
+static void debug_printing (int prescribed, int sub_automaton);
+
+void set_EXEC_EDIT (int prescribed) {
+ if (choice_EXEC_EDIT != prescribed) {
+ debug_printing (prescribed, 0); // EXEC_EDIT is sub_automaton 0
+ choice_EXEC_EDIT = prescribed;
+ }
+}
+
+void set_STATE_RULES_DATA (int prescribed) {
+ if (choice_STATE_RULES_DATA != prescribed) {
+ debug_printing (prescribed, 1); // STATE_RULES_DATA is sub_automaton 1
+ choice_STATE_RULES_DATA = prescribed;
+ }
+}
+
+
+/******************************************************************************/
+/* G E T T E R S & D E B U G G E R S */
+/******************************************************************************/
+
+int get_EXEC_EDIT () {return choice_EXEC_EDIT;}
+int get_STATE_RULES_DATA () {return choice_STATE_RULES_DATA;}
+
+static char *get_str_EXEC_EDIT (int value) {
+ switch (value) {
+ case (EXEC) : return "EXEC";
+ case (EDIT) : return "EDIT";
+ default : printf("default in automaton.get_EXEC_EDIT ()\n"); return NULL;
+ }
+}
+
+static char *get_str_STATE_RULES_DATA (int value) {
+ switch (value) {
+ case (STATE) : return "STATE";
+ case (RULES) : return "RULES";
+ case (DATA) : return "DATA";
+ default : printf("default in automaton.get_STATE_RULES_DATA ()\n"); return NULL;
+ }
+}
+
+static void debug_printing (int prescribed, int sub_automaton) {
+ switch (sub_automaton) { // sub_automaton 0 is EXEC_EDIT and
+ // sub_automaton 1 is STATE_RULES_DATA
+ case (0) : printf("switch > %5s X %5s <> %5s X %5s\n",
+ get_str_EXEC_EDIT (choice_EXEC_EDIT),
+ get_str_STATE_RULES_DATA (choice_STATE_RULES_DATA),
+ get_str_EXEC_EDIT (prescribed),
+ get_str_STATE_RULES_DATA (choice_STATE_RULES_DATA));
+ break;
+ case (1) : printf("switch > %5s X %5s <> %5s X %5s\n",
+ get_str_EXEC_EDIT (choice_EXEC_EDIT),
+ get_str_STATE_RULES_DATA (choice_STATE_RULES_DATA),
+ get_str_EXEC_EDIT (choice_EXEC_EDIT),
+ get_str_STATE_RULES_DATA (prescribed));
+ break;
+ default : printf("default in automaton.debug_printing()\n");
+ }
+}
+
+
diff --git a/automaton.h b/automaton.h
new file mode 100644
index 0000000..48e5517
--- /dev/null
+++ b/automaton.h
@@ -0,0 +1,16 @@
+#include
+#include
+
+enum choice_EXEC_EDIT { EXEC, EDIT };
+enum choice_STATE_RULES_DATA { STATE, RULES, DATA };
+ // MEASURE, OBSERVE, INTERPRET, HELP, CONFIGURE }; ?
+
+void set_EXEC_EDIT (int prescribed);
+void set_STATE_RULES_DATA (int prescribed);
+
+int get_EXEC_EDIT ();
+int get_STATE_RULES_DATA ();
+
+// char *get_str_EXEC_EDIT (int value);
+// char *get_str_STATE_RULES_DATA (int value);
+
diff --git a/base.h b/base.h
new file mode 100644
index 0000000..365d60f
--- /dev/null
+++ b/base.h
@@ -0,0 +1,91 @@
+/*
+ * Gem-graph OpenGL experiments
+ *
+ * Desc: Base header
+ *
+ * Copyright (C) 2023 Arthur Menges
+ * Copyright (C) 2023 Adrien Bourmault
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+//#define G_APPLICATION_DEFAULT_FLAGS 0
+
+enum { X_AXIS, Y_AXIS, Z_AXIS, N_AXIS }; // < used by : graph_area.h
+enum { HOME_MODE, RUN_MODE, EDIT_MODE, PRESENTATION_MODE, N_MODE }; // Gem-graph modes
+struct arrow_t { uint load; uint site; uint x; uint y; uint z; }; // describes an arrow
+static inline char *read_file(char *filename); // < used by : init.c
+
+/* I'm standing on Earth (or any spinning spheroid) and looking towards its North pole, then :
+ X - X = EAST - WEST = rouge - cyan
+ Y - Y = ZENITH - NADIR = vert - magenta (fuschia)
+ Z - Z = NORTH - SOUTH = bleu - jaune */
+
+#define EAST 0 // + x rouge
+#define WEST 1 // - x cyan
+#define ZENITH 2 // + y vert
+#define NADIR 3 // - y magenta
+#define SOUTH 4 // + z bleu
+#define NORTH 5 // - z jaune
+
+
+/*
+ * char *read_file(char *filename) reads a file from filename into a provided buffer
+ *
+ * @param filename, file name
+ * contents, target ptr
+ *
+ * @return void
+ */
+static inline char *read_file(char *filename)
+{
+ int fd;
+ int filesize;
+ char *contents;
+
+ fd = open(filename, O_RDONLY);
+ if(fd < 0) {
+ printf("Couldn't read file: %s\n",filename);
+ return NULL;
+ }
+
+ filesize = lseek(fd, 0, SEEK_END) + 1 ;
+ contents = g_malloc(filesize * sizeof(char));
+ assert (contents);
+
+ lseek(fd, 0, SEEK_SET);
+ read(fd,contents,filesize);
+
+ contents[filesize-1] = '\0';
+
+ close(fd);
+
+ return contents;
+}
+
diff --git a/callback.c b/callback.c
new file mode 100644
index 0000000..f42cd4a
--- /dev/null
+++ b/callback.c
@@ -0,0 +1,219 @@
+#include
+#include
+
+#include "callback.h"
+#include "contain.h"
+#include "tree.h"
+#include "contain.h"
+#include "dialog.h"
+#include "texts.h"
+#include "automaton.h"
+#include "parsing.h"
+#include "graph_area.h"
+
+/******************************************************************************/
+/* W I N D O W S A C T I V A T I O N */
+/******************************************************************************/
+
+static GtkWindow *main_window, *dialog_window;
+
+void on_main_window_activation (GtkApplication *app, gpointer no_user_data)
+{
+ main_window = GTK_WINDOW (gtk_application_window_new (app));
+ main_window_design (main_window);
+ g_signal_connect (app, "activate", G_CALLBACK (on_dialog_window_activation), main_window);
+}
+
+void on_dialog_window_activation (GtkApplication *app, gpointer no_user_data)
+{
+ dialog_window = GTK_WINDOW (gtk_application_window_new (app));
+ dialog_window_design (main_window, dialog_window);
+}
+
+
+void on_auto_notification (const char *message)
+{
+ /* Ignored (2024-06-06) because I don't know how to get "main_window" easily
+
+ if (window->toast_revealer == NULL) {
+ g_printerr("Can't find app->toast_overlay !\n");
+ return;
+ }
+
+ if (window->toast_text == NULL) {
+ g_printerr("Can't find app->toast_overlay !\n");
+ return;
+ }
+
+ gtk_label_set_label(window->toast_text, message);
+ gtk_revealer_set_reveal_child(window->toast_revealer, true);
+ */
+ g_printerr("%s\n", message);
+}
+
+/******************************************************************************/
+/* T R E E */
+/******************************************************************************/
+void on_user_tree_expander_toggled (GtkExpander *expander, gpointer user_data)
+{
+ GtkTreeListRow *row = GTK_TREE_LIST_ROW (user_data);
+ gboolean is_expanded = gtk_tree_list_row_get_expanded(row);
+ gtk_tree_list_row_set_expanded (row, !is_expanded);
+}
+
+void on_bind_user_tree_factory (GtkSignalListItemFactory *factory, GObject* object, gpointer user_data)
+{
+ GtkListItem *list_item = GTK_LIST_ITEM (object); assert (list_item);
+ GtkTreeListRow *row = gtk_list_item_get_item (list_item); assert (row); // if (row != NULL) {...} ?
+ const gchar *text = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_tree_list_row_get_item (row)));
+ GtkWidget *expander = gtk_list_item_get_child (list_item);
+ gtk_expander_set_label (GTK_EXPANDER (expander), text);
+ g_signal_handlers_disconnect_by_func(expander, G_CALLBACK (on_user_tree_expander_toggled), row);
+ g_signal_connect(expander, "activate", G_CALLBACK (on_user_tree_expander_toggled), row);
+ gtk_widget_set_margin_start(expander, gtk_tree_list_row_get_depth(row) * 20);
+}
+
+/******************************************************************************/
+/* G L A R E A */
+/******************************************************************************/
+gboolean on_glarea_render(GtkGLArea *area, GdkGLContext *context)
+{
+ // Check if the widget is a glarea
+ if(gtk_gl_area_get_error(area) != NULL) {
+ on_auto_notification("An OpenGL error occured !");
+ return false;
+ }
+
+ if (ui_render_stack(gtk_widget_get_parent(GTK_WIDGET(area))) == false) {
+ on_auto_notification("Failed to render corresponding graphic stack !");
+ return false;
+ }
+
+ return true;
+}
+
+
+/* We need to set up our state when we realize the GtkGLArea widget */
+void on_glarea_realize(GtkWidget *widget)
+{
+ GError *internal_error = NULL;
+
+ // Make the GL context current to be able to call the GL API
+ gtk_gl_area_make_current(GTK_GL_AREA(widget));
+
+ // Check if the widget is a glarea
+ if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) {
+ on_auto_notification("An OpenGL error occured !");
+ return;
+ }
+
+ // Link graphical stack to widget
+ if (ui_init_graphic_stack(gtk_widget_get_parent(widget),
+ internal_error) == false) {
+ on_auto_notification(
+ "Failed to link the graphic stack to widgets !");
+ return;
+ }
+
+ gtk_gl_area_set_auto_render(GTK_GL_AREA(widget), true);
+}
+
+/* We should tear down the state when unrealizing */
+void on_glarea_unrealize(GtkWidget *widget)
+{
+ GError *internal_error = NULL;
+
+ // Make the GL context current to be able to call the GL API
+ gtk_gl_area_make_current(GTK_GL_AREA(widget));
+
+ // Check if the widget is a glarea
+ if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) {
+ on_auto_notification("An OpenGL error occured !");
+ return;
+ }
+
+ // Destroy graphic stack
+ if (ui_shutdown_graphic_stack(gtk_widget_get_parent(widget),
+ internal_error) == false) {
+ on_auto_notification(
+ "Failed to shutdown the graphic stack !");
+ return;
+ }
+}
+
+void on_axis_value_change(GtkAdjustment *adjustment, gpointer data)
+{
+
+ GtkWidget *slider = gtk_widget_get_parent(GTK_WIDGET(data));
+ GtkWidget *container_widget = gtk_widget_get_parent(GTK_WIDGET(slider));
+
+ const gchar *label_text = gtk_label_get_label(GTK_LABEL(data));
+
+ // THANKS ASCIIIII/Unicode/Whateverrr !
+ int axis = label_text[0] - 'X';
+
+ g_assert(axis >= 0 && axis < N_AXIS);
+
+ /* Update the rotation angle */
+ ui_update_axis_stack(container_widget,
+ axis,
+ gtk_adjustment_get_value(adjustment));
+
+ /* Update the contents of the GL drawing area */
+}
+
+
+/******************************************************************************/
+/* B U T T O N S */
+/******************************************************************************/
+
+void on_toggle_EXEC_EDIT (GtkWidget *toggled_button, gpointer user_data) {
+
+ if (get_EXEC_EDIT ()) {
+ gtk_button_set_icon_name (GTK_BUTTON (toggled_button), "power-profile-balanced-rtl-symbolic");
+ set_EXEC_EDIT (EXEC);
+ } else {
+ gtk_button_set_icon_name (GTK_BUTTON (toggled_button), "text-editor-symbolic");
+ set_EXEC_EDIT (EDIT);
+ }
+ switch (get_STATE_RULES_DATA()) {
+ case (STATE) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_STATE())); break;
+ case (RULES) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_RULES())); break;
+ case (DATA) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_DATA())); break;
+ default : printf("default in callback.on_toggle_STATE_RULES_DATA()\n");
+ }
+}
+
+void on_toggle_STATE_RULES_DATA (GtkWidget *toggled_button, gpointer user_data) {
+
+ const char *toggled_button_name = gtk_check_button_get_label (GTK_CHECK_BUTTON (toggled_button));
+ int is_active = gtk_check_button_get_active (GTK_CHECK_BUTTON (toggled_button));
+
+ if (! strcmp (toggled_button_name, "state")) set_STATE_RULES_DATA (STATE);
+ if (! strcmp (toggled_button_name, "rules")) set_STATE_RULES_DATA (RULES);
+ if (! strcmp (toggled_button_name, "data analysis")) set_STATE_RULES_DATA (DATA);
+
+ if (is_active)
+ switch (get_STATE_RULES_DATA()) {
+ case (STATE) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_STATE())); break;
+ case (RULES) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_RULES())); break;
+ case (DATA) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_DATA())); break;
+ default : printf("default in callback.on_toggle_STATE_RULES_DATA()\n");
+ }
+}
+
+void on_SAVE_CURRENT_MODEL_BEFORE_EDITING (GtkWidget *btt_SAVE_CURRENT_MODEL, gpointer data) {
+ gtk_widget_set_sensitive (GTK_WIDGET (data), TRUE);
+ printf ("callback.c (line 201) - SAVE_CURRENT_MODEL_BEFORE_EDITING\n");
+}
+
+void on_DISCARD_CURRENT_MODEL_AND_START_EDITING (GtkWidget *btt_SAVE_CURRENT_MODEL, gpointer data) {
+ gtk_window_close (GTK_WINDOW (data));
+ printf ("callback.c (line 206) - DISCARD_CURRENT_MODEL_AND_START_EDITING\n");
+}
+
+void on_WRITE_CURRENT_MODEL (GtkWidget *btt_WRITE_CURRENT_MODEL, gpointer data) {
+ gtk_window_close (GTK_WINDOW (data));
+ printf ("callback.c (line 211) - WRITE_CURRENT_MODEL\n");
+}
+
diff --git a/callback.h b/callback.h
new file mode 100644
index 0000000..678c9ba
--- /dev/null
+++ b/callback.h
@@ -0,0 +1,27 @@
+#include
+
+
+void on_main_window_activation (GtkApplication *app, gpointer user_data);
+void on_dialog_window_activation (GtkApplication *app, gpointer user_data);
+void on_auto_notification (const char *message);
+
+void on_user_tree_expander_toggled (GtkExpander *expander, gpointer user_data);
+void on_bind_user_tree_factory (GtkSignalListItemFactory *factory, GObject* object, gpointer user_data);
+
+gboolean on_glarea_render (GtkGLArea *area, GdkGLContext *context);
+void on_glarea_realize (GtkWidget *widget);
+void on_glarea_unrealize (GtkWidget *widget);
+
+void on_axis_value_change (GtkAdjustment *adjustment, gpointer data);
+
+void on_toggle_EXEC_EDIT (GtkWidget *btt_XOR_EXEC_EDIT, gpointer user_data);
+void on_toggle_MODEL_RUN_STOP (GtkWidget *btt_MODEL_RUN_STOP, gpointer data);
+
+void on_open_STATE (GtkWidget *btt_open_STATE, gpointer data);
+void on_open_RULES (GtkWidget *btt_open_RULES, gpointer data);
+void on_open_DATA (GtkWidget *btt_open_DATA, gpointer data);
+
+void on_SAVE_CURRENT_MODEL_BEFORE_EDITING (GtkWidget *btt_SAVE_CURRENT_MODEL, gpointer data);
+void on_DISCARD_CURRENT_MODEL_AND_START_EDITING (GtkWidget *btt_SAVE_CURRENT_MODEL, gpointer data);
+void on_WRITE_CURRENT_MODEL (GtkWidget *btt_WRITE_CURRENT_MODEL, gpointer data);
+void on_toggle_STATE_RULES_DATA (GtkWidget *btt, gpointer user_data);
diff --git a/contain.c b/contain.c
new file mode 100644
index 0000000..3f0a463
--- /dev/null
+++ b/contain.c
@@ -0,0 +1,426 @@
+#include
+#include
+
+#include "graph_area.h"
+#include "callback.h"
+#include "automaton.h"
+#include "display.h"
+#include "tree.h"
+#include "texts.h"
+
+// https://blog.gtk.org/2020/09/08/on-list-models/ < TODO
+// https://docs.gtk.org/gtk4/visual_index.html < widgets gallery
+
+
+GtkFrame *get_frame_with_label(){ // EN ATTENDANT DE SAVOIR UTILISER : GtkTextTagTable , GtkTextBuffer
+ GtkFrame *space_specif = GTK_FRAME(gtk_frame_new ("Space (run / edit) specifications"));
+ GtkWidget *any_Label = GTK_WIDGET (gtk_label_new (get_space_run_edit_specif()));
+ gtk_frame_set_child (GTK_FRAME (space_specif), GTK_WIDGET (any_Label));
+ return space_specif;
+}
+
+GtkWidget *get_edit_rules_page_new(){
+ GtkPaned *hpaned = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL));
+
+ GtkWidget *arbre_des_règles = gtk_frame_new ("Arbre des règles");
+ GtkWidget *édition_de_la_règle_sélectionnée = gtk_frame_new ("Édition de la règle sélectionnée");
+
+ gtk_paned_set_start_child (hpaned, GTK_WIDGET (arbre_des_règles));
+ gtk_paned_set_end_child (hpaned, GTK_WIDGET (édition_de_la_règle_sélectionnée));
+ // gtk_widget_set_size_request (GTK_WIDGET (hpaned), W, H);
+ gtk_paned_set_wide_handle (hpaned, TRUE);
+
+ return GTK_WIDGET (hpaned);
+}
+
+GtkWidget *get_edit_measures_page_new(){
+ GtkWidget *measures_grid = gtk_grid_new();
+ return measures_grid;
+}
+
+GtkWidget *get_edit_results_page_new(){
+ GtkWidget *xxx_grid = gtk_grid_new();
+ return xxx_grid;
+}
+
+GtkWidget *get_edit_discuss_page_new(){
+ GtkWidget *xxx_grid = gtk_grid_new();
+ return xxx_grid;
+}
+
+GtkWidget *get_edit_help_page_new(){
+ GtkWidget *edit_help_grid = gtk_grid_new();
+ gtk_grid_attach (GTK_GRID(edit_help_grid), GTK_WIDGET(get_frame_with_label()), 0, 0, 1, 1);
+ return edit_help_grid;
+}
+
+GtkWidget *get_measures_page_new(){
+ GtkWidget *measures_grid = gtk_grid_new();
+ gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("movements"), 0, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("transports"), 1, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("transformations"), 2, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("objects"), 0, 1, 1, 1);
+ gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("situations"), 1, 1, 1, 1);
+ return measures_grid;
+}
+
+GtkWidget *get_results_page_new(){
+ GtkWidget *results_grid = gtk_grid_new();
+ gtk_grid_attach (GTK_GRID(results_grid), gtk_button_new_with_label ("Repartitions"), 0, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID(results_grid), gtk_button_new_with_label ("Correlations"), 0, 1, 1, 1);
+ gtk_grid_attach (GTK_GRID(results_grid), gtk_button_new_with_label ("Evolutions"), 0, 2, 1, 1);
+ return results_grid;
+}
+
+GtkWidget *get_discuss_page_new(){
+ GtkWidget *discuss_grid = gtk_grid_new();
+ gtk_grid_attach (GTK_GRID (discuss_grid), gtk_button_new_with_label ("Interpretations"), 0, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID (discuss_grid), gtk_button_new_with_label ("Discussions"), 0, 1, 1, 1);
+ return discuss_grid;
+}
+
+GtkWidget *get_help_page_new(){
+ GtkWidget *run_help_grid = gtk_grid_new();
+ gtk_grid_attach (GTK_GRID(run_help_grid), GTK_WIDGET(get_frame_with_label()), 0, 0, 1, 1);
+ return run_help_grid;
+}
+
+GtkWidget *get_edit_space_page_new(){
+ GtkWidget *space_grid = gtk_grid_new();
+ gtk_grid_attach (GTK_GRID(space_grid), get_image_ALL_SPACE(), 0, 0, 1, 3);
+ gtk_grid_attach (GTK_GRID(space_grid), get_OBJECTS_and_SITUATIONS(), 0, 4, 1, 1);
+ gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET (get_XYZ_box()), 1, 0, 1, 2);
+ gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET (get_ZOOM_box()), 1, 2, 1, 2);
+ gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET (get_edit_TOOL_box()), 1, 3, 1, 2);
+ gtk_widget_set_size_request (space_grid, W, H);
+ return space_grid;
+}
+
+//------------------------------------------------------------------------------
+
+GtkWidget *get_selected_rules_vpaned_new(){
+ GtkPaned *V_selected_1_vs_2 = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_VERTICAL));
+
+ GtkBox *up_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2));
+ gtk_box_append (up_box, GTK_WIDGET (get_image_GLUTAMATE()));
+ gtk_box_append (up_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_VERTICAL)));
+ gtk_box_append (up_box, GTK_WIDGET (get_image_GLUTAMINE()));
+
+ GtkBox *bottom_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2));
+ gtk_box_append (bottom_box, GTK_WIDGET (get_image_ATP()));
+ gtk_box_append (bottom_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_VERTICAL)));
+ gtk_box_append (bottom_box, GTK_WIDGET (get_image_AMP()));
+
+ gtk_paned_set_start_child (V_selected_1_vs_2, GTK_WIDGET (up_box));
+ gtk_paned_set_end_child (V_selected_1_vs_2, GTK_WIDGET (bottom_box));
+
+ return GTK_WIDGET (V_selected_1_vs_2);
+}
+
+
+
+GtkWidget *get_TIME_EXEC_controls_box(){
+ GtkBox *top_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2));
+ gtk_box_append (top_box, GTK_WIDGET (get_ELAPSED_TIME_ProgressBar()));
+ gtk_box_append (top_box, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_VERTICAL)));
+ gtk_box_append (top_box, GTK_WIDGET (get_RUN_STOP_box()));
+ return GTK_WIDGET (top_box);
+}
+
+GtkWidget *get_SPACE_VIEW_box(){
+ GtkBox *right_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 2));
+ gtk_box_append (right_box, GTK_WIDGET (get_XYZ_box()));
+ gtk_box_append (right_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (right_box, GTK_WIDGET (get_ZOOM_box()));
+
+ GtkBox *middle_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2));
+ gtk_box_append (middle_box, GTK_WIDGET (get_image_ALL_SPACE()));
+// ui_setup_glarea (0, GTK_WIDGET (middle_box));
+
+ gtk_box_append (middle_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_VERTICAL)));
+ gtk_box_append (middle_box, GTK_WIDGET (right_box));
+ return GTK_WIDGET (middle_box);
+}
+
+GtkWidget *get_SPACE_EDIT_controls_box() {
+ GtkWidget *label_ad_hoc = gtk_label_new ("_____________\n\
+ SPACE EDIT\n controls\n_____________");
+ return GTK_WIDGET (label_ad_hoc);
+}
+
+
+static void icons_for_fun (GtkHeaderBar *header_bar);
+
+static GtkButton *btt_open_STATE;
+static GtkButton *btt_open_RULES;
+static GtkButton *btt_open_DATA;
+
+GtkButton *get_GtkButton (char *btt_name) {
+ if (strcmp (btt_name, "state")) return btt_open_STATE;
+ if (strcmp (btt_name, "rules")) return btt_open_RULES;
+ if (strcmp (btt_name, "data analysis")) return btt_open_DATA;
+ return NULL;
+}
+
+void set_check_button_active (GtkButton *button, int active){
+ const char *lab = gtk_button_get_label (button);
+ if (strcmp (lab, "state")) printf("set_check_button_active > %s\n", lab);
+}
+
+
+void window_header_bar (GtkWindow *window, char *title){
+ GtkWidget *header_bar = GTK_WIDGET (gtk_header_bar_new ());
+ gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header_bar), gtk_label_new (title));
+ gtk_window_set_titlebar (window, header_bar);
+
+ gpointer no_local_data = NULL;
+
+ GtkButton *btt_XOR_EXEC_EDIT = GTK_BUTTON (gtk_toggle_button_new ());
+ gtk_button_set_icon_name (btt_XOR_EXEC_EDIT, "system-run-symbolic");
+ gtk_button_set_icon_name (btt_XOR_EXEC_EDIT, "process-stop-symbolic");
+ gtk_button_set_icon_name (btt_XOR_EXEC_EDIT, "power-profile-balanced-rtl-symbolic");
+ g_signal_connect (btt_XOR_EXEC_EDIT, "clicked", G_CALLBACK (on_toggle_EXEC_EDIT), no_local_data);
+
+ GtkWidget *any_Label = GTK_WIDGET (gtk_label_new (" | "));
+
+ GtkCheckButton *group_STATE_RULES_DATA = GTK_CHECK_BUTTON (gtk_check_button_new ());
+
+ btt_open_STATE = GTK_BUTTON (gtk_check_button_new_with_label ("state"));
+ g_signal_connect (btt_open_STATE, "toggled", G_CALLBACK (on_toggle_STATE_RULES_DATA), no_local_data);
+ gtk_check_button_set_group (GTK_CHECK_BUTTON (btt_open_STATE), group_STATE_RULES_DATA);
+
+ btt_open_RULES = GTK_BUTTON (gtk_check_button_new_with_label ("rules"));
+ g_signal_connect (btt_open_RULES, "toggled", G_CALLBACK (on_toggle_STATE_RULES_DATA), no_local_data);
+ gtk_check_button_set_group (GTK_CHECK_BUTTON (btt_open_RULES), group_STATE_RULES_DATA);
+
+ btt_open_DATA = GTK_BUTTON (gtk_check_button_new_with_label ("data analysis"));
+ g_signal_connect (btt_open_DATA, "toggled", G_CALLBACK (on_toggle_STATE_RULES_DATA), no_local_data);
+ gtk_check_button_set_group (GTK_CHECK_BUTTON (btt_open_DATA), group_STATE_RULES_DATA);
+
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (btt_XOR_EXEC_EDIT));
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (any_Label));
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (btt_open_STATE));
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (btt_open_RULES));
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (btt_open_DATA));
+
+
+ icons_for_fun (GTK_HEADER_BAR (header_bar)); // https://iconduck.com/sets/adwaita-icon-theme
+// https://iconduck.com/sets/carbon-icons < pas mal ...
+// https://thenounproject.com/icon/train-134324/
+// ma préférée : Transport Steam Engine Icon mais : [ process icon ] semble un bon choix...
+}
+
+void main_window_design (GtkWindow *main_window){
+ window_header_bar (main_window,
+ "E coli (with permission from David S. Goodsell, 2009)");
+ gtk_check_button_set_active (GTK_CHECK_BUTTON (btt_open_STATE), TRUE);
+ gtk_window_present (GTK_WINDOW (main_window));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+GtkWidget *get_window_child_STATE() {
+ if (0) printf("contain.get_window_child_STATE (line 235)\n");
+ GtkBox *page_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 2));
+ gtk_box_append (page_box, GTK_WIDGET (get_OBJECTS_and_SITUATIONS()));
+ gtk_box_append (page_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (page_box, GTK_WIDGET (get_SPACE_VIEW_box()));
+ gtk_box_append (page_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ if (get_EXEC_EDIT ()) gtk_box_append (page_box, GTK_WIDGET (get_SPACE_EDIT_controls_box()));
+ else gtk_box_append (page_box, GTK_WIDGET (get_TIME_EXEC_controls_box()));
+ return GTK_WIDGET (page_box);
+}
+
+GtkWidget *get_window_child_RULES(){
+ if (0) printf("contain.get_window_child_RULES (line 246)\n");
+ GtkPaned *H_tree_vs_selected = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL));
+// GtkWidget *arbre_des_règles = gtk_frame_new ("Arbre des règles");
+// GtkWidget *édition_de_la_règle_sélectionnée_n_1 = gtk_frame_new ("Inspection");
+ gtk_paned_set_start_child (H_tree_vs_selected, GTK_WIDGET (get_rules_tree_hpaned_new()));
+ gtk_paned_set_end_child (H_tree_vs_selected, GTK_WIDGET (get_selected_rules_vpaned_new()));
+ gtk_paned_set_position (H_tree_vs_selected, 400); // WARNING : c'est une position "absolue"
+ gtk_paned_set_wide_handle (H_tree_vs_selected, TRUE);
+ return GTK_WIDGET (H_tree_vs_selected);
+}
+
+GtkWidget *get_window_child_DATA (){
+ if (0) printf("contain.get_window_child_DATA (line 259)\n");
+ GtkBox *data_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 32));
+
+ GtkWidget* frame_rule_effect = gtk_frame_new ("rule effect\n-----------");
+ gtk_frame_set_label_align (GTK_FRAME (frame_rule_effect), 0.5);
+ GtkBox *rule_effect_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8));
+ gtk_frame_set_child (GTK_FRAME (frame_rule_effect), GTK_WIDGET (rule_effect_box));
+
+ GtkWidget* frame_rule_topic = gtk_frame_new ("rule topic\n----------");
+ gtk_frame_set_label_align (GTK_FRAME (frame_rule_topic), 0.5);
+ GtkBox *rule_topic_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8));
+ gtk_frame_set_child (GTK_FRAME (frame_rule_topic), GTK_WIDGET (rule_topic_box));
+
+ GtkWidget* frame_data_type = gtk_frame_new ("data type\n----------");
+ gtk_frame_set_label_align (GTK_FRAME (frame_data_type), 0.5);
+ GtkBox *data_type_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8));
+ gtk_frame_set_child (GTK_FRAME (frame_data_type), GTK_WIDGET (data_type_box));
+
+ GtkWidget* frame_interpretations = gtk_frame_new ("interpretation\n---------------");
+ gtk_frame_set_label_align (GTK_FRAME (frame_interpretations), 0.5);
+ GtkBox *interpretations_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8));
+ gtk_frame_set_child (GTK_FRAME (frame_interpretations), GTK_WIDGET (interpretations_box));
+
+ GtkWidget* frame_discussions = gtk_frame_new ("discussion\n------------");
+ gtk_frame_set_label_align (GTK_FRAME (frame_discussions), 0.5);
+ GtkBox *discussions_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8));
+ gtk_frame_set_child (GTK_FRAME (frame_discussions), GTK_WIDGET (discussions_box));
+
+ GtkWidget* frame_separator = gtk_frame_new ("\n");
+
+ GtkWidget* frame_game = gtk_frame_new ("game\n------");
+ gtk_frame_set_label_align (GTK_FRAME (frame_game), 0.5);
+ GtkBox *game_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8));
+ gtk_frame_set_child (GTK_FRAME (frame_game), GTK_WIDGET (game_box));
+
+ GtkWidget* frame_help = gtk_frame_new ("help\n-----");
+ gtk_frame_set_label_align (GTK_FRAME (frame_help), 0.5);
+ GtkBox *help_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8));
+ gtk_frame_set_child (GTK_FRAME (frame_help), GTK_WIDGET (help_box));
+
+ gtk_box_append (data_box, GTK_WIDGET (frame_rule_effect));
+ gtk_box_append (data_box, GTK_WIDGET (frame_rule_topic));
+ gtk_box_append (data_box, GTK_WIDGET (frame_data_type));
+ gtk_box_append (data_box, GTK_WIDGET (frame_interpretations));
+ gtk_box_append (data_box, GTK_WIDGET (frame_discussions));
+ gtk_box_append (data_box, GTK_WIDGET (frame_separator));
+ gtk_box_append (data_box, GTK_WIDGET (frame_game));
+ gtk_box_append (data_box, GTK_WIDGET (frame_help));
+
+ gtk_box_append (rule_effect_box, gtk_button_new_with_label ("movement"));
+ gtk_box_append (rule_effect_box, gtk_button_new_with_label ("transport"));
+ gtk_box_append (rule_effect_box, gtk_button_new_with_label ("transformation"));
+
+ gtk_box_append (rule_topic_box, gtk_button_new_with_label ("objects"));
+ gtk_box_append (rule_topic_box, gtk_button_new_with_label ("situations"));
+
+ gtk_box_append (rule_topic_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (rule_topic_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (rule_topic_box, gtk_button_new_with_label ("accuracy"));
+ gtk_box_append (rule_topic_box, gtk_button_new_with_label ("pattern recognition"));
+
+ gtk_box_append (data_type_box, gtk_button_new_with_label ("repartitions"));
+ gtk_box_append (data_type_box, gtk_button_new_with_label ("evolutions"));
+ gtk_box_append (data_type_box, gtk_button_new_with_label ("correlations"));
+
+ gtk_box_append (interpretations_box, gtk_button_new_with_label ("stochastic"));
+ gtk_box_append (interpretations_box, gtk_button_new_with_label ("deterministic"));
+
+ gtk_box_append (interpretations_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (interpretations_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (interpretations_box, gtk_button_new_with_label ("physical"));
+ gtk_box_append (interpretations_box, gtk_button_new_with_label ("chemical"));
+ gtk_box_append (interpretations_box, gtk_button_new_with_label ("biological"));
+ gtk_box_append (interpretations_box, gtk_button_new_with_label ("social"));
+ gtk_box_append (interpretations_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+
+ gtk_box_append (discussions_box, gtk_button_new_with_label ("context"));
+ gtk_box_append (discussions_box, gtk_button_new_with_label ("methodology"));
+ gtk_box_append (discussions_box, gtk_button_new_with_label ("comparisons"));
+ gtk_box_append (discussions_box, gtk_button_new_with_label ("to improve"));
+ gtk_box_append (discussions_box, gtk_button_new_with_label ("summary"));
+
+ gtk_box_append (game_box, gtk_button_new_with_label ("single player"));
+ gtk_box_append (game_box, gtk_button_new_with_label ("multiple players"));
+ gtk_box_append (game_box, gtk_button_new_with_label ("edition facilities"));
+
+ gtk_box_append (help_box, gtk_button_new_with_label ("modelization"));
+ gtk_box_append (help_box, gtk_button_new_with_label ("measurements"));
+ gtk_box_append (help_box, gtk_button_new_with_label ("results"));
+ gtk_box_append (help_box, gtk_button_new_with_label ("data analysis"));
+
+ gtk_box_append (help_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (help_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (help_box, gtk_button_new_with_label ("preferences"));
+
+ //SWITCH_TO (DATA);
+ return GTK_WIDGET (data_box);
+}
+
+static void icons_for_fun (GtkHeaderBar *header_bar)
+{
+ GtkButton *go_home = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (go_home, "go-home-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (go_home));
+
+ GtkButton *user_trash = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (user_trash, "user-trash-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (user_trash));
+
+ GtkButton *help_biblio = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (help_biblio, "accessories-dictionary-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (help_biblio));
+
+ GtkButton *help_doc = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (help_doc, "emblem-documents-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (help_doc));
+
+ GtkButton *help_about = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (help_about, "help-about-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (help_about));
+
+ GtkButton *help_faq = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (help_faq, "help-faq-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (help_faq));
+
+ GtkButton *terminal = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (terminal, "utilities-terminal-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (terminal));
+
+ GtkButton *search = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (search, "folder-saved-search-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (search));
+
+ GtkButton *preferences_desktop_appearance = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (preferences_desktop_appearance, "preferences-desktop-appearance-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (preferences_desktop_appearance));
+
+ GtkButton *preferences_system = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (preferences_system, "preferences-system-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (preferences_system));
+
+ GtkButton *document_properties = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (document_properties, "document-properties-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (document_properties));
+
+ GtkButton *text_edit = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (text_edit, "text-editor-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (text_edit));
+
+ GtkButton *applications_utilities = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (applications_utilities, "applications-utilities-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (applications_utilities));
+
+ GtkButton *open_menu = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (open_menu, "open-menu-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (open_menu));
+
+ GtkButton *power_max = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (power_max, "power-profile-performance-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (power_max));
+
+ GtkButton *power_middle = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (power_middle, "power-profile-balanced-rtl-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (power_middle));
+
+ GtkButton *power_low = GTK_BUTTON (gtk_button_new ());
+ gtk_button_set_icon_name (power_low, "power-profile-power-saver-symbolic");
+ gtk_header_bar_pack_end (header_bar, GTK_WIDGET (power_low));
+}
+
diff --git a/contain.h b/contain.h
new file mode 100644
index 0000000..23364c8
--- /dev/null
+++ b/contain.h
@@ -0,0 +1,44 @@
+//******************************************************************************/
+/* */
+/* E coli by David S. Goodsell (2009) */
+/* --- */
+/* Let this freeze frame guide us towards the model */
+/* that alone can account for the phenomenon ! */
+/* */
+/******************************************************************************/
+
+#include
+
+#define W 1920
+#define H 960
+#define W_IMAGE W - 320
+#define H_IMAGE H - 126
+#define H_STYLES_PANE 30
+#define W_IMAGE_LOCAL W / 16
+#define H_IMAGE_LOCAL H / 16
+
+/*
+G_BEGIN_DECLS
+#define MY_TYPE_WINDOW (my_window_get_type())
+G_DECLARE_FINAL_TYPE (MyWindow, my_window, MY, WINDOW, GtkApplicationWindow)
+G_END_DECLS
+
+G_BEGIN_DECLS
+#define MY_TYPE_APPLICATION (my_application_get_type())
+G_DECLARE_FINAL_TYPE (MyApplication, my_application, MY, APPLICATION, GtkApplication)
+MyApplication *my_application_new (const char *application_id, GApplicationFlags flags);
+G_END_DECLS
+*/
+
+void main_window_design (GtkWindow *main_window);
+void set_check_button_active (GtkButton *button, int active);
+void two_notebooks_in_two_panes (GtkWindow *window);
+
+GtkFrame *get_frame_with_label();
+GtkWidget *get_selected_rules_vpaned_new();
+GtkWidget *get_TIME_EXEC_controls_box();
+GtkWidget *get_SPACE_EDIT_controls_box();
+GtkButton *get_GtkButton (char *btt_name);
+GtkWidget *get_window_child_STATE();
+GtkWidget *get_window_child_RULES();
+GtkWidget *get_window_child_DATA();
diff --git a/dialog.c b/dialog.c
new file mode 100644
index 0000000..a872962
--- /dev/null
+++ b/dialog.c
@@ -0,0 +1,37 @@
+#include "callback.h"
+
+void dialog_window_design (GtkWindow *main_window, GtkWindow *dialog_window){
+ char *title = " Save the current model before modifying it? ";
+ GtkWidget *header_bar = GTK_WIDGET (gtk_header_bar_new ());
+ gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header_bar), gtk_label_new (title));
+ gtk_window_set_titlebar (dialog_window, header_bar);
+
+ GtkWidget *dialog_window_grid = gtk_grid_new ();
+
+ const char *txt = " SAVE CURRENT MODEL ";
+ GtkButton *action_save_current_model = GTK_BUTTON (gtk_button_new_with_label (txt));
+ gtk_widget_set_sensitive (GTK_WIDGET (action_save_current_model), FALSE);
+ g_signal_connect (action_save_current_model, "clicked",
+ G_CALLBACK (on_WRITE_CURRENT_MODEL), dialog_window);
+
+ GtkButton *click_yes = GTK_BUTTON (gtk_button_new_with_label ("YES"));
+ g_signal_connect (click_yes, "clicked",
+ G_CALLBACK (on_SAVE_CURRENT_MODEL_BEFORE_EDITING), action_save_current_model);
+
+ GtkButton *click_no = GTK_BUTTON (gtk_button_new_with_label ("NO"));
+ g_signal_connect (click_no, "clicked",
+ G_CALLBACK (on_DISCARD_CURRENT_MODEL_AND_START_EDITING), dialog_window);
+
+ gtk_grid_attach (GTK_GRID (dialog_window_grid), GTK_WIDGET (click_yes), 0, 0, 1, 1) ;
+ gtk_grid_attach (GTK_GRID (dialog_window_grid), GTK_WIDGET (click_no), 1, 0, 1, 1) ;
+ gtk_grid_attach (GTK_GRID (dialog_window_grid), GTK_WIDGET (action_save_current_model), 0, 2, 2, 1) ;
+ gtk_window_set_child (GTK_WINDOW (dialog_window), GTK_WIDGET (dialog_window_grid));
+
+ gtk_window_set_transient_for (GTK_WINDOW (dialog_window), GTK_WINDOW (main_window));
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog_window), TRUE);
+ gtk_window_set_deletable (GTK_WINDOW (dialog_window), FALSE); // FALSE
+ gtk_window_set_modal (GTK_WINDOW (dialog_window), TRUE);
+// gtk_window_present (GTK_WINDOW (dialog_window)); see button...
+}
+
+
diff --git a/dialog.h b/dialog.h
new file mode 100644
index 0000000..3cbf6a2
--- /dev/null
+++ b/dialog.h
@@ -0,0 +1,2 @@
+void dialog_window_design (GtkWindow *main_window, GtkWindow *dialog_window);
+
diff --git a/dimers random walk.xml b/dimers random walk.xml
new file mode 100644
index 0000000..12ae465
--- /dev/null
+++ b/dimers random walk.xml
@@ -0,0 +1,118 @@
+
+
+
+
+ Modèle de test
+
+ Léontine Patinette
+
+ 2
+
+ 1630000000
+
+ 1.0
+
+ Ref
+
+
+
+
+ 0
+ 9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/display.c b/display.c
new file mode 100644
index 0000000..439ad62
--- /dev/null
+++ b/display.c
@@ -0,0 +1,280 @@
+#include
+#include
+
+#include "contain.h"
+#include "tree.h"
+#include "texts.h"
+
+//------------------------------------------------------------------------------
+
+GtkWidget *get_image_ALL_SPACE(){
+ GtkWidget *image;
+ // forget > GTK_WIDGET(get_scrolled_gl_area());
+ // Use GtkImage if you want to display a fixed-size icon
+ // and GtkPicture if you want to display a (maybe) scaled picture.
+ image = gtk_image_new_from_file("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/aXoris.png");
+ image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/gg sketch.png");
+ image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/E coli (Goodsell) 2.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE, H_IMAGE);
+ return image;
+}
+
+GtkWidget *get_image_GLUTAMATE(){
+ GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/glutamate.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL);
+ return image;
+}
+
+GtkWidget *get_image_GLUTAMINE(){
+ GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/glutamine.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL);
+ return image;
+}
+
+GtkWidget *get_image_HISTIDINE(){
+ GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/histidine.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL);
+ return image;
+}
+
+GtkWidget *get_image_HISTAMINE(){
+ GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/histamine.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL);
+ return image;
+}
+
+GtkWidget *get_image_PHENYLALANINE(){
+ GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/phénylalanine.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL);
+ return image;
+}
+
+GtkWidget *get_image_DOPAMINE(){
+ GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/dopamine.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL);
+ return image;
+}
+
+GtkWidget *get_image_ATP(){
+ GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/ATP.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL);
+ return image;
+}
+
+GtkWidget *get_image_AMP(){
+ GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/AMP.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL);
+ return image;
+}
+
+GtkWidget *get_user_tree(){
+ GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/arbre utilisateur.png");
+ gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL);
+ return image;
+}
+
+//------------------------------------------------------------------------------
+
+// TODO cliquer sur "RUN" --> affiche "STOP" (et inversement)
+static GtkWidget *get_scroll_speed(){
+ GtkAdjustment *speed_adjust = gtk_adjustment_new (100, 0, 100, 1, 0, 0);
+ GtkWidget *scroll_speed = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, speed_adjust);
+ gtk_widget_set_size_request (GTK_WIDGET (scroll_speed), 120, 2);
+ return scroll_speed;
+}
+
+static GtkBox *get_UNDO_SPEED_box(){
+ GtkBox *SPEED_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0));
+ gtk_box_append (SPEED_box, GTK_WIDGET(gtk_label_new ("< UNDO <\n")));
+ gtk_box_append (SPEED_box, get_scroll_speed());
+ return SPEED_box;
+}
+
+static GtkBox *get_DO_SPEED_box(){
+ GtkBox *SPEED_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0));
+ gtk_box_append (SPEED_box, GTK_WIDGET(gtk_label_new ("> DO >\n")));
+ gtk_box_append (SPEED_box, get_scroll_speed());
+ return SPEED_box;
+}
+
+GtkBox *get_RUN_STOP_box(){
+ GtkBox *RUN_STOP_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 20));
+ gtk_box_append (RUN_STOP_box, GTK_WIDGET (get_UNDO_SPEED_box()));
+ gtk_box_append (RUN_STOP_box, GTK_WIDGET(gtk_label_new (" STEP\n(show active rule) ")));
+ gtk_box_append (RUN_STOP_box, GTK_WIDGET (get_DO_SPEED_box()));
+ gtk_box_append (RUN_STOP_box, GTK_WIDGET(gtk_label_new (" R U N\n S T O P")));
+ return RUN_STOP_box;
+}
+//------------------------------------------------------------------------------
+
+GtkBox *get_ZOOM_box(){
+ GtkBox *ZOOM_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0));
+ GtkWidget *ZOOM_Label = GTK_WIDGET (gtk_label_new (\
+ "\n TOOLS\n ---\n zoom\n ---\n space\n struct.\n\
+ ---\n arrows\n struct.\n ---\n orient\n state\n in space\n"));
+ gtk_widget_set_size_request (GTK_WIDGET (ZOOM_box), 10, 80);
+ gtk_box_append (ZOOM_box, ZOOM_Label);
+ return ZOOM_box;
+}
+
+//------------------------------------------------------------------------------
+
+GtkBox *get_edit_TOOL_box(){
+ GtkBox *TOOL_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0));
+ GtkWidget *ZOOM_Label = GTK_WIDGET (gtk_label_new ("TOOLS\n ---\n(space\nstruct.)"));
+ gtk_widget_set_size_request (GTK_WIDGET (TOOL_box), 10, 120);
+ gtk_box_append (TOOL_box, ZOOM_Label);
+ return TOOL_box;
+}
+
+//------------------------------------------------------------------------------
+
+GtkBox *get_XYZ_box(){
+ GtkBox *XYZ_labels_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 2)); // spacing = 2
+ GtkBox *XYZ_scrollbar_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); // spacing = 2q
+ // GtkWidget *scale_X = gtk_scale_button_new (0, 360, 10, NULL); < à étudier
+ // (double min, double max, double step, const char** icons)
+ GtkAdjustment *X_adjust = gtk_adjustment_new (0, 0, 380, 1, 0, 0);
+ GtkAdjustment *Y_adjust = gtk_adjustment_new (0, 0, 380, 1, 0, 0);
+ GtkAdjustment *Z_adjust = gtk_adjustment_new (0, 0, 380, 1, 0, 0);
+ GtkWidget *scroll_X = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, X_adjust);
+ GtkWidget *scroll_Y = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, Y_adjust);
+ GtkWidget *scroll_Z = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, Z_adjust);
+ gtk_widget_set_size_request (GTK_WIDGET (scroll_X), 1, 500);
+
+ gtk_box_append (XYZ_scrollbar_box, GTK_WIDGET (gtk_label_new (" "))); // AD HOC (pour "centrer")
+ gtk_box_append (XYZ_scrollbar_box, scroll_X);
+ gtk_box_append (XYZ_scrollbar_box, scroll_Y);
+ gtk_box_append (XYZ_scrollbar_box, scroll_Z);
+
+ gtk_box_append (XYZ_labels_box, GTK_WIDGET (gtk_label_new ("\nX Y Z")));
+ gtk_box_append (XYZ_labels_box, GTK_WIDGET (XYZ_scrollbar_box));
+ gtk_box_append (XYZ_labels_box, GTK_WIDGET (gtk_label_new ("")));
+ return XYZ_labels_box;
+}
+
+//------------------------------------------------------------------------------
+
+GtkProgressBar *get_ELAPSED_TIME_ProgressBar(){ // To rename : DO - UNDO - REDO ?
+ GtkProgressBar *buffer = GTK_PROGRESS_BAR (gtk_progress_bar_new ());
+ gtk_progress_bar_set_text (buffer,\
+ "\n<--- [buffer] (simulation extensive time) --->\n\
+ supports DO - UNDO - REDO functions\n");
+ gtk_progress_bar_set_show_text (buffer, TRUE);
+ gtk_widget_set_size_request (GTK_WIDGET (buffer), W - 560, 0);
+ return buffer;
+}
+
+//------------------------------------------------------------------------------
+
+// Chaque label "objet" ou "situation" sera remplacé par un curseur "transparence" (vertical)
+
+static GtkBox *get_objects_box(){
+ GtkBox *objects_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0));
+ GtkAdjustment *adjust = gtk_adjustment_new (0, 0, 255, 1, 0, 0);
+ if (0) for (int i = 0; i < 10; i++)
+ gtk_box_append (objects_box, gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, adjust));
+ char string[7];
+ for (int i = 0; i < 16; i++){
+ sprintf(string, "[%d] ", i);
+ if (0) printf("%s\n", string); // répété deux fois ! pourquoi ?
+ gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (string)));
+ }
+ gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (" membrane ")));
+ gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (" co-enzyme A ")));
+ gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (" ribosome ")));
+ gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (" ATP synthase ")));
+ return objects_box;
+}
+
+static GtkBox *get_situations_box(){
+ GtkBox *situations_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0));
+ char string[7];
+ for (int i = 0; i < 64; i++){
+ sprintf(string, "[%d] ", i);
+ if (0) printf("%s\n", string); // répété deux fois ! pourquoi ?
+ gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (string)));
+ }
+ gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (" transcription ")));
+ gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (" transport Na/K ")));
+ gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (" ubiquitination ")));
+ gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (" rotation moteur flagellaire ")));
+ return situations_box;
+}
+
+static GtkWidget *get_frame_objects(){
+ GtkWidget *scroll = gtk_scrolled_window_new ();
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
+ GtkWidget *frame_objects = gtk_frame_new (" Objects"); // defines each class of object transparence
+ gtk_widget_set_size_request (frame_objects, 0, H_STYLES_PANE); // < utile seulement pour la largeur min/max
+ gtk_frame_set_child (GTK_FRAME (frame_objects), GTK_WIDGET (get_objects_box()));
+ gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scroll), frame_objects);
+ return scroll;
+}
+
+static GtkWidget *get_frame_situations(){
+ GtkWidget *scroll = gtk_scrolled_window_new ();
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
+ GtkWidget *frame_situations = gtk_frame_new (" Situations"); // facilitates each situation identification
+ gtk_widget_set_size_request (GTK_WIDGET (frame_situations), 0, H_STYLES_PANE); // < utile seulement pour la largeur min/max
+ gtk_frame_set_child (GTK_FRAME (frame_situations), GTK_WIDGET (get_situations_box()));
+ gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scroll), frame_situations);
+ return scroll;
+}
+
+GtkWidget *get_OBJECTS_and_SITUATIONS(){
+ GtkWidget *objects_and_situations_horizontal_pane = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_paned_set_start_child (GTK_PANED(objects_and_situations_horizontal_pane), GTK_WIDGET (get_frame_objects()));
+ gtk_paned_set_end_child (GTK_PANED(objects_and_situations_horizontal_pane), GTK_WIDGET (get_frame_situations()));
+ return objects_and_situations_horizontal_pane;
+}
+
+
+GtkBox *get_rules_comparator_new(){
+ GtkBox *comparator = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 2));
+ gtk_box_append (comparator, GTK_WIDGET (get_image_ATP()));
+ gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (comparator, GTK_WIDGET (get_image_AMP()));
+ gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (comparator, GTK_WIDGET (get_image_GLUTAMATE()));
+ gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (comparator, GTK_WIDGET (get_image_GLUTAMINE()));
+ gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (comparator, GTK_WIDGET (get_image_HISTIDINE()));
+ gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (comparator, GTK_WIDGET (get_image_PHENYLALANINE()));
+ gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ gtk_box_append (comparator, GTK_WIDGET (get_image_DOPAMINE()));
+ gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL)));
+ return comparator;
+}
+
+GtkWidget *get_rules_tree_hpaned_new(){
+ GtkPaned *H_tree_vs_comparison = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL));
+
+// GtkWidget *arbre_des_règles = gtk_frame_new ("Arbre");
+// GtkWidget *comparaison_des_règles_sélectionnées = gtk_frame_new ("Sélection");
+
+ gtk_paned_set_start_child (H_tree_vs_comparison, GTK_WIDGET (get_user_rules_tree()));
+ gtk_paned_set_end_child (H_tree_vs_comparison, GTK_WIDGET (get_rules_comparator_new()));
+ gtk_paned_set_position (H_tree_vs_comparison, 300);
+ gtk_paned_set_wide_handle (H_tree_vs_comparison, TRUE);
+ gtk_paned_set_shrink_start_child (H_tree_vs_comparison, FALSE);
+ gtk_paned_set_shrink_end_child (H_tree_vs_comparison, FALSE);
+ return GTK_WIDGET (H_tree_vs_comparison);
+}
+
+GtkWidget *get_rules_page_new(){
+ GtkPaned *H_tree_vs_selected = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL));
+
+// GtkWidget *arbre_des_règles = gtk_frame_new ("Arbre des règles");
+// GtkWidget *édition_de_la_règle_sélectionnée_n_1 = gtk_frame_new ("Inspection");
+
+ gtk_paned_set_start_child (H_tree_vs_selected, GTK_WIDGET (get_rules_tree_hpaned_new()));
+ gtk_paned_set_end_child (H_tree_vs_selected, GTK_WIDGET (get_selected_rules_vpaned_new()));
+ gtk_paned_set_position (H_tree_vs_selected, 600); // WARNING : c'est une position "absolue"
+ gtk_paned_set_wide_handle (H_tree_vs_selected, TRUE);
+ // gtk_widget_set_size_request (GTK_WIDGET (H_tree_vs_selected), W, H); // inutile... ?
+ return GTK_WIDGET (H_tree_vs_selected);
+}
+
diff --git a/display.h b/display.h
new file mode 100644
index 0000000..157190b
--- /dev/null
+++ b/display.h
@@ -0,0 +1,38 @@
+/******************************************************************************/
+/* */
+/* E coli by David S. Goodsell (2009) */
+/* --- */
+/* Let this freeze frame guide us towards the model */
+/* that alone can account for the phenomenon ! */
+/* */
+/******************************************************************************/
+
+GtkWidget *get_text_view();
+GtkFrame *get_frame_with_label();
+GtkWidget *get_rules_page_new();
+GtkBox *get_rules_user_tree_new();
+
+GtkWidget *get_image_ALL_SPACE();
+GtkWidget *get_image_GLUTAMATE();
+GtkWidget *get_image_GLUTAMINE();
+GtkWidget *get_image_HISTIDINE();
+GtkWidget *get_image_HISTAMINE();
+GtkWidget *get_image_PHENYLALANINE();
+GtkWidget *get_image_DOPAMINE();
+GtkWidget *get_image_ATP();
+GtkWidget *get_image_AMP();
+GtkWidget *get_rules_tree_hpaned_new();
+
+GtkProgressBar *get_ELAPSED_TIME_ProgressBar();
+GtkBox *get_RUN_STOP_box();
+GtkBox *get_ZOOM_box();
+GtkBox *get_edit_TOOL_box();
+GtkBox *get_XYZ_box();
+GtkWidget *get_OBJECTS_and_SITUATIONS();
+GtkBox *get_ELAPSED_TIME_box();
+
+GtkButton *get_btt_run_xor_edit();
+
+void window_bar(GtkWindow *window, char *title);
+
+
diff --git a/draw.c b/draw.c
new file mode 100644
index 0000000..fea1ca7
--- /dev/null
+++ b/draw.c
@@ -0,0 +1,207 @@
+/*
+ * Gem-graph OpenGL experiments
+ *
+ * Desc: GL functions
+ *
+ * Copyright (C) 2023 Adrien Bourmault
+ * Copyright (C) 2023 Jean Sirmai
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/*
+ * Writes values to describe a vertex at (x,y,z) intoq the vertex buffer
+ *
+ * @param coords GLfloat(x,y,z)
+ *
+ * @return void
+ */
+
+#include
+#include
+#include
+#include "base.h"
+//#include "ui.h"
+#include "graph_area.h"
+
+void graphics_draw_vertex (const int stack_id,
+ GLfloat x,
+ GLfloat y,
+ GLfloat z)
+{
+ //g_printerr("stack_id is %d\n", stack_id);
+ //g_printerr("stack_id is %d\n", stack_id);
+ //g_printerr("graphic_stack is at %p\n", graphic_stack);
+ //g_printerr("graphic_stack[stack_id] is at %p\n", graphic_stack + stack_id);
+ volatile struct graphic_stack_t *stack = &graphic_stack[stack_id];
+
+ //g_printerr("Currently stack->buffer_vertex_origin @ %p\n", stack->buffer_vertex_origin);
+
+ //assert (stack->buffer_vertex_origin);
+
+ stack->buffer_vertex_origin =
+ g_realloc (stack->buffer_vertex_origin,
+ (stack->buffer_vertex_size + 3) * sizeof(GLfloat));
+ //print_stack(stack_id);
+
+ stack->buffer_vertex_origin[stack->buffer_vertex_size + 0] = x;
+ stack->buffer_vertex_origin[stack->buffer_vertex_size + 1] = y;
+ stack->buffer_vertex_origin[stack->buffer_vertex_size + 2] = z;
+
+ stack->buffer_vertex_size += 3;
+}
+
+/*
+ * Writes values to describe a color (r,g,b) into the color buffer
+ *
+ * @param color GLfloat(r,g,b)
+ *
+ * @return void
+ */
+void graphics_draw_color (const int stack_id,
+ GLfloat r,
+ GLfloat g,
+ GLfloat b)
+{
+ struct graphic_stack_t *stack = &graphic_stack[stack_id];
+
+ stack->buffer_colors_origin = g_realloc (stack->buffer_colors_origin,
+ (stack->buffer_colors_size + 3) * sizeof(GLfloat));
+
+ assert (stack->buffer_colors_origin);
+
+ stack->buffer_colors_origin[stack->buffer_colors_size + 0] = r;
+ stack->buffer_colors_origin[stack->buffer_colors_size + 1] = g;
+ stack->buffer_colors_origin[stack->buffer_colors_size + 2] = b;
+
+ stack->buffer_colors_size += 3;
+}
+
+/*
+ * Writes values to describe a line from a to b into the line buffer
+ *
+ * @param coords GLuint (a,b)
+ *
+ * @return void
+ */
+void graphics_draw_line (const int stack_id,
+ GLuint a,
+ GLuint b)
+{
+ struct graphic_stack_t *stack = &graphic_stack[stack_id];
+
+ stack->buffer_lines_origin = g_realloc (stack->buffer_lines_origin,
+ (stack->buffer_lines_size + 2) * sizeof(GLuint));
+
+ assert (stack->buffer_lines_origin);
+
+ stack->buffer_lines_origin[stack->buffer_lines_size + 0] = a;
+ stack->buffer_lines_origin[stack->buffer_lines_size + 1] = b;
+
+ stack->buffer_lines_size += 2;
+}
+
+/*
+ * Writes values to describe an (a,b,c) plan (triangle) into the plan buffer
+ *
+ * @param coords GLuint (a,b,c)
+ *
+ * @return void
+ */
+void graphics_draw_plan (const int stack_id,
+ GLuint a,
+ GLuint b,
+ GLuint c)
+{
+ struct graphic_stack_t *stack = &graphic_stack[stack_id];
+
+ stack->buffer_plans_origin = g_realloc (stack->buffer_plans_origin,
+ (stack->buffer_plans_size + 3) * sizeof(GLuint));
+
+ assert (stack->buffer_plans_origin);
+
+ stack->buffer_plans_origin[stack->buffer_plans_size + 0] = a;
+ stack->buffer_plans_origin[stack->buffer_plans_size + 1] = b;
+ stack->buffer_plans_origin[stack->buffer_plans_size + 2] = c;
+
+ stack->buffer_plans_size += 3;
+}
+
+/*
+ * Draws the current buffer to a gl_area
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return void
+ */
+void graphics_draw(const int stack_id)
+{
+ struct graphic_stack_t *stack = &graphic_stack[stack_id];
+
+ g_printerr("[debug] graphics_draw() started\n");
+
+ print_stack(stack_id);
+
+ GLint cur_viewport[4];
+ glGetIntegerv(GL_VIEWPORT, cur_viewport);
+
+ mat4 m = GLM_MAT4_IDENTITY_INIT;
+ glm_rotate_x(m, glm_rad(stack->rotation_angles[X_AXIS]), m);
+ glm_rotate_y(m, glm_rad(stack->rotation_angles[Y_AXIS]), m);
+ glm_rotate_z(m, glm_rad(stack->rotation_angles[Z_AXIS]), m);
+
+ mat4 v = GLM_MAT4_IDENTITY_INIT; // XXX define zoom and translations here ?
+
+ mat4 p = GLM_MAT4_IDENTITY_INIT;
+ glm_ortho(-1.0f, +1.0f, -1.0f, +1.0f, -1.0f, +1.0f, p);
+ glm_ortho_default((float)cur_viewport[2] / (float)cur_viewport[3], p);
+ glm_perspective_default((float)cur_viewport[2] / (float)cur_viewport[3], p);
+
+ /* Use our shaders */
+ glUseProgram(stack->program);
+
+ glClearColor(0, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ /* Update the "mvp" matrix we use in the shader */
+ glUniformMatrix4fv(stack->m, 1, GL_FALSE, (float *)m);
+ glUniformMatrix4fv(stack->v, 1, GL_FALSE, (float *)v);
+ glUniformMatrix4fv(stack->p, 1, GL_FALSE, (float *)p);
+
+ /* Use the vertices in our buffer */
+ glEnableVertexAttribArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, stack->position_buffer);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0,(void*)0);
+
+ // couleurs
+ glEnableVertexAttribArray(1);
+ glBindBuffer(GL_ARRAY_BUFFER, stack->color_buffer);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0,(void*)0);
+
+ glEnable(GL_DEPTH_TEST);
+
+ glDrawElements(GL_LINES, stack->buffer_lines_size, GL_UNSIGNED_INT, stack->buffer_lines_origin);
+ glDrawElements(GL_TRIANGLES, stack->buffer_plans_size, GL_UNSIGNED_INT, stack->buffer_plans_origin);
+
+ /* We finished using the buffers and program */
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(1);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glUseProgram(0);
+
+ glFlush();
+ g_printerr("[debug] graphics_draw() ended\n");
+}
diff --git a/graph_area.c b/graph_area.c
new file mode 100644
index 0000000..2732cf3
--- /dev/null
+++ b/graph_area.c
@@ -0,0 +1,332 @@
+/*
+ * Gem-graph OpenGL experiments
+ *
+ * Desc: User interface functions
+ *
+ * Copyright (C) 2023 Adrien Bourmault
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+
+#include "contain.h"
+#include "graph_area.h"
+#include "callback.h"
+
+struct stack_index_t {
+ long stack_id;
+ void *container_widget;
+ void *gl_area;
+};
+
+static struct stack_index_t *stack_index = NULL;
+size_t stack_index_size = 0;
+
+
+int set_arrow (int stack_id, // 2024-06-27 DEBUG !
+ int arrows_nb,
+ int space_X,
+ int space_Y,
+ int space_Z,
+ int requested_weight,
+ int site,
+ int arrow_x,
+ int arrow_y,
+ int arrow_z) {
+ printf("graph_area.c > int set_arrow (...) 2024-06-27 DEBUG\n");
+ return 0;
+
+} // 2024-06-27 DEBUG !
+
+
+
+/*
+ * Look for stack entry and returns stack_id
+ *
+ * @params container_widget, generally the GtkBox that contains the GLArea
+ *
+ * @returns stack_id
+ */
+long ui_get_graphic_stack(void *container_widget)
+{
+ // look for stack_index entry
+ for (int i = 0; i < stack_index_size; i++) {
+ if (stack_index[i].container_widget == (void *)container_widget) {
+ return stack_index[i].stack_id;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Look for stack entry and returns stack_id
+ *
+ * @params container_widget, generally the GtkBox that contains the GLArea
+ *
+ * @returns stack_id
+ */
+long ui_is_graphic_stack_ready(void *container_widget)
+{
+ // look for stack_index entry
+ for (int i = 0; i < stack_index_size; i++) {
+ if (stack_index[i].container_widget == (void *)container_widget) {
+ return stack_index[i].stack_id;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Look for stack entry and initializes OpenGL for it
+ *
+ * @params container_widget, generally the GtkBox that contains the GLArea
+ *
+ * @returns bool, true if success
+ */
+bool ui_init_graphic_stack(void *container_widget, GError *error_buffer)
+{
+ g_printerr("[debug] ui_init_graphic_stack()\n");
+
+ g_printerr("[debug] ui_init_graphic_stack() : target is %p\n", container_widget);
+
+ // look for stack_index entry
+ for (int i = 0; i < stack_index_size; i++) {
+ g_printerr("[debug] ui_init_graphic_stack() : i is %d\n", i);
+ g_printerr("[debug] ui_init_graphic_stack() : target would be %p\n",
+ stack_index[i].container_widget);
+ if (stack_index[i].container_widget == (void *)container_widget) {
+ stack_index[i].stack_id = graphics_init(&error_buffer);
+ g_printerr("[debug] ui_init_graphic_stack() : stack_id is %ld\n",
+ stack_index[i].stack_id);
+ if (stack_index[i].stack_id >= 0)
+ return true;
+ else
+ return false;
+ }
+ }
+ return false;
+}
+
+/*
+ * Look for stack entry and shutdowns OpenGL for it
+ *
+ * @params container_widget, generally the GtkBox that contains the GLArea
+ *
+ * @returns bool, true if success
+ */
+bool ui_shutdown_graphic_stack(void *container_widget, GError *error_buffer)
+{
+ // look for stack_index entry
+ for (int i = 0; i < stack_index_size; i++) {
+ if (stack_index[i].container_widget == (void *)container_widget) {
+ if (graphics_shutdown(stack_index[i].stack_id,
+ &error_buffer) == false) {
+ return false;
+ }
+ stack_index[i].stack_id = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void ui_clean_stack_index(void)
+{
+ // look for stack_index entry
+ for (int i = 0; i < stack_index_size; i++) {
+ stack_index[i].stack_id = 0;
+ }
+ return;
+}
+
+/*
+ * Look for stack entry and triggers OpenGL for drawing
+ *
+ * @params container_widget, generally the GtkBox that contains the GLArea
+ *
+ * @returns bool, true if success
+ */
+bool ui_render_stack(GtkWidget *container_widget)
+{
+ // look for stack_index entry
+ for (int i = 0; i < stack_index_size; i++) {
+ if (stack_index[i].container_widget == (void *)container_widget) {
+ graphics_draw (stack_index[i].stack_id);
+ return true;
+ }
+ }
+ return false;
+}
+
+//void graphics_draw(const int stack_id) {printf("graph_area.c > void graphics_draw(const int stack_id) (161)\n");}
+
+/*
+ * Look for stack entry and triggers OpenGL for drawing
+ *
+ * @params container_widget, generally the GtkBox that contains the GLArea
+ *
+ * @returns bool, true if success
+ */
+bool ui_update_axis_stack(GtkWidget *container_widget, int axis, int value)
+{
+ // look for stack_index entry
+ for (int i = 0; i < stack_index_size; i++) {
+ if (stack_index[i].container_widget == (void *)container_widget) {
+ graphic_stack[stack_index[i].stack_id].rotation_angles[axis] = value;
+ gtk_widget_queue_draw((GtkWidget*)(stack_index[i].gl_area));
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * Look for every stack entry and shutdowns OpenGL for it
+ *
+ * @params void
+ *
+ * @returns bool, true if success
+ */
+void ui_shutdown_all_graphic_stacks(void)
+{
+ // look for stack_index entry
+ for (int i = 0; i < stack_index_size; i++) {
+ graphics_shutdown(stack_index[i].stack_id, NULL);
+ }
+ return;
+}
+
+/*
+ * Creates a slider widget
+ *
+ * @params axis, meaning which axis we're building (for label)
+ *
+ * @returns GtkWidget*, pointer to the new widget
+ */
+GtkWidget *create_axis_slider(int axis)
+{
+ GtkWidget *box, *label, *slider;
+ GtkAdjustment *adj;
+ const char *text;
+
+ box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+
+ switch (axis) {
+ case X_AXIS:
+ text = "X";
+ break;
+
+ case Y_AXIS:
+ text = "Y";
+ break;
+
+ case Z_AXIS:
+ text = "Z";
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ label = gtk_label_new(text);
+ gtk_box_append(GTK_BOX(box), label);
+ gtk_widget_set_visible (label, TRUE);
+
+ adj = gtk_adjustment_new(0.0, 0.0, 360.0, 1.0, 12.0, 0.0);
+ g_signal_connect (adj, "value-changed", G_CALLBACK(on_axis_value_change), (gpointer) label);
+ slider = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, adj);
+ gtk_box_append(GTK_BOX(box), slider);
+ gtk_widget_set_hexpand(slider, TRUE);
+ gtk_widget_set_visible (slider, TRUE);
+
+ gtk_widget_set_visible (box, TRUE);
+
+ return box;
+}
+
+/*
+ * Creates GLArea and indexes it
+ *
+ * @params target_mode, meaning which ui_stack we're on
+ * target_widget, meaning the box that will host the GLArea
+ *
+ * @returns bool, true if success
+ */
+bool ui_setup_glarea(int target_mode, GtkWidget *target_widget)
+{
+ GtkWidget *gl_area;
+
+ g_printerr("[debug] ui_setup_glarea()\n");
+
+ assert(target_widget);
+
+ g_printerr("[debug] ui_setup_glarea() : target is %p\n", target_widget);
+
+ if (stack_index == NULL) {
+ stack_index = g_malloc(sizeof(struct stack_index_t));
+ stack_index_size = 1;
+ } else {
+ // look for stack_index entry
+ for (int i = 0; i < stack_index_size; i++) {
+ if (stack_index[i].container_widget == (void *)target_widget) {
+ return false;
+ }
+ }
+ // create entry
+ stack_index =
+ g_realloc(stack_index,
+ ++stack_index_size * sizeof(struct stack_index_t));
+ }
+
+ gl_area = GTK_WIDGET(gtk_gl_area_new());
+ assert(gl_area);
+
+ gtk_widget_set_size_request(gl_area, 1000, 1000);
+ gtk_gl_area_set_auto_render(GTK_GL_AREA(gl_area), true);
+ gtk_widget_set_hexpand(gl_area, TRUE);
+ gtk_widget_set_vexpand(gl_area, TRUE);
+ gtk_widget_set_halign(gl_area, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign(gl_area, GTK_ALIGN_CENTER);
+
+ // The main "draw" call for GtkGLArea
+ g_signal_connect(GTK_GL_AREA(gl_area), "render", G_CALLBACK(on_glarea_render), NULL);
+ g_signal_connect(gl_area, "realize", G_CALLBACK(on_glarea_realize), NULL);
+ g_signal_connect(gl_area, "unrealize", G_CALLBACK(on_glarea_unrealize), NULL);
+
+ stack_index[stack_index_size-1].container_widget =
+ (void*)target_widget;
+
+ stack_index[stack_index_size-1].gl_area = (void*)gl_area;
+
+ g_printerr("[debug] ui_setup_glarea() : set target to %p\n", target_widget);
+
+ g_printerr("[debug] ui_setup_glarea() : stack_index (@0x%p) had %ld elements\n",
+ stack_index,
+ stack_index_size);
+
+ gtk_box_append (GTK_BOX (target_widget), gl_area);
+ gtk_widget_set_visible (GTK_WIDGET (gl_area), TRUE);
+
+ // Create sliders
+ for(int i = 0; i < N_AXIS; i++)
+ gtk_box_append(GTK_BOX(target_widget), create_axis_slider(i));
+
+ return true;
+}
diff --git a/graph_area.h b/graph_area.h
new file mode 100644
index 0000000..e492cc6
--- /dev/null
+++ b/graph_area.h
@@ -0,0 +1,328 @@
+/*
+ * Gem-graph OpenGL experiments
+ *
+ * Desc: OpenGL utils header
+ *
+ * Copyright (C) 2023 Arthur Menges
+ * Copyright (C) 2023 Adrien Bourmault
+ * Copyright (C) 2023 Jean Sirmai
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "base.h"
+//#include "draw.c"
+
+// #define VERTEX_SHADER_FILE "src/graphics/shaders/shader.vert"
+// #define FRAG_SHADER_FILE "src/graphics/shaders/shader.frag"
+#define VERTEX_SHADER_FILE "shader.vert"
+#define FRAG_SHADER_FILE "shader.frag"
+#define GL_TARGET_MAJOR_VERSION 0
+#define GL_TARGET_MINOR_VERSION 4
+
+/*
+ * Structure describing a gl_area and its parameters, used to create a table
+ * of Gem-graph client current gl_areas
+ */
+struct graphic_stack_t {
+
+ int id;
+ int mode;
+
+ float rotation_angles[N_AXIS]; // Rotation angles on each axis
+
+ GLuint vao; // init_buffers
+ GLuint position_buffer; // shutdown, draw
+ GLuint color_buffer; // shutdown, draw
+ GLuint program; // shutdown, init_shaders, draw
+ GLuint m; // init_shaders, draw
+ GLuint v; // init_shaders, draw
+ GLuint p; // init_shaders, draw
+
+ struct arrow_t *arrows_ptr;
+ long arrows_nb;
+
+ GLfloat *buffer_vertex_origin;
+ GLfloat *buffer_colors_origin;
+ GLuint *buffer_lines_origin;
+ GLuint *buffer_plans_origin;
+
+ long buffer_vertex_size;
+ long buffer_colors_size;
+ long buffer_lines_size;
+ long buffer_plans_size;
+
+ long buffer_vertex_0_arrow;
+ long buffer_colors_0_arrow;
+ long buffer_lines_0_arrow;
+ long buffer_plans_0_arrow;
+};
+
+bool ui_render_stack(GtkWidget *container_widget);
+
+bool ui_setup_glarea(int target_mode, GtkWidget *target_widget);
+
+/*
+ * Dynamic array of ptrs to dynamically allocated gl_area_entry
+ */
+extern struct graphic_stack_t *graphic_stack;
+
+/*
+ * Initializes a gl_area
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return true if initialized
+ */
+int graphics_init(void *error_buffer);
+
+/*
+ * Draws the current buffer to a gl_area
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return void
+ */
+void graphics_draw(const int stack_id);
+
+/*
+ * Shutdowns a gl_area
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return true if success
+ */
+bool graphics_shutdown(const int stack_id, void *error_buffer);
+
+/*
+ * Initializes the shaders of a gl_area and link them to a program
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return true if initialized
+ */
+bool graphics_init_shaders(const int stack_id);
+
+bool ui_init_graphic_stack(void *container_widget, GError *error_buffer);
+bool ui_shutdown_graphic_stack(void *container_widget, GError *error_buffer);
+bool ui_update_axis_stack(GtkWidget *container_widget, int axis, int value);
+
+/* Initializes the buffer of a gl_area
+ * Calls according to the user preferences
+ * @param gl_area, ptr to the gl_area widget
+ * @return void
+ */
+void graphics_init_buffers(const int stack_id);
+
+/*
+ * Draws a vertex (x, y, z)
+ * if (console) prints (x, y, z) values to console
+ *
+ * @param GLfloat x, GLfloat y, GLfloat z
+ *
+ * @return void
+ */
+void graphics_draw_vertex (const int stack_id,
+ GLfloat x,
+ GLfloat y,
+ GLfloat z);
+
+/*
+ * Draws the color (r, g, b) associated to a vertex
+ * if (console) prints (r, g, b) values to console
+ *
+ * @param GLfloat r, GLfloat g, GLfloat b
+ *
+ * @return void
+ */
+void graphics_draw_color (const int stack_id, GLfloat r, GLfloat g, GLfloat b);
+
+/*
+ * Writes values to describe a line from a to b into the line buffer
+ *
+ * @param coords GLuint (a,b)
+ *
+ * @return void
+ */
+void graphics_draw_line (const int stack_id, GLuint a, GLuint b);
+
+/*
+ * Writes values to describe an (a,b,c) plan (triangle) into the plan buffer
+ *
+ * @param coords GLuint (a,b,c)
+ *
+ * @return void
+ */
+void graphics_draw_plan (const int stack_id, GLuint a, GLuint b, GLuint c);
+
+/*
+ * Created and compile a shader
+ *
+ * @param type, shader type
+ * src, source code of shader
+ *
+ * @return shader id
+ */
+static inline GLuint create_shader(const int stack_id, int type, const char *src)
+{
+ GLuint shader;
+ int status;
+
+ shader = glCreateShader(type);
+ glShaderSource(shader, 1, &src, NULL);
+ glCompileShader(shader);
+
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if(status == GL_FALSE) {
+ int log_len;
+ char *buffer;
+
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len);
+
+ buffer = g_malloc(log_len + 1);
+ assert (buffer);
+ glGetShaderInfoLog(shader, log_len, NULL, buffer);
+
+ g_warning("Compile failure in %s shader:\n%s",
+ type == GL_VERTEX_SHADER ? "vertex" : "fragment",
+ buffer);
+
+ g_free(buffer);
+
+ glDeleteShader(shader);
+
+ return 0;
+ }
+
+ return shader;
+}
+
+static inline void print_stack(int stack_id)
+{
+ static int n = 0;
+
+ printf("\n[n=%d]***************", n);
+
+ printf("id = %d\tmode = %d\n",
+ graphic_stack[stack_id].id,
+ graphic_stack[stack_id].mode);
+
+ printf("rotation_angles = ");
+ for (int i = 0; i < N_AXIS; i++) {
+ printf("%f\t", graphic_stack[stack_id].rotation_angles[i]); // Rotation angles on each axis
+ }
+ printf("\n");
+
+ printf("vao = %d\n", graphic_stack[stack_id].vao);
+ printf("position_buffer = %d\n", graphic_stack[stack_id].position_buffer);
+ printf("color_buffer = %d\n", graphic_stack[stack_id].color_buffer);
+ printf("program = %d\n", graphic_stack[stack_id].program);
+ printf("m = %d\n", graphic_stack[stack_id].m);
+ printf("v = %d\n", graphic_stack[stack_id].v);
+ printf("p = %d\n", graphic_stack[stack_id].p);
+
+ printf("arrows_ptr = %p\n", graphic_stack[stack_id].arrows_ptr);
+ printf("arrows_nb = %ld\n", graphic_stack[stack_id].arrows_nb);
+
+ printf("buffer_vertex_origin = %p\n", graphic_stack[stack_id].buffer_vertex_origin);
+ printf("buffer_colors_origin = %p\n", graphic_stack[stack_id].buffer_colors_origin);
+ printf("buffer_lines_origin = %p\n", graphic_stack[stack_id].buffer_lines_origin);
+ printf("buffer_plans_origin = %p\n", graphic_stack[stack_id].buffer_plans_origin);
+
+ printf("buffer_vertex_size = %ld\n", graphic_stack[stack_id].buffer_vertex_size);
+ printf("buffer_colors_size = %ld\n", graphic_stack[stack_id].buffer_colors_size);
+ printf("buffer_lines_size = %ld\n", graphic_stack[stack_id].buffer_lines_size);
+ printf("buffer_plans_size = %ld\n", graphic_stack[stack_id].buffer_plans_size);
+
+ printf("buffer_vertex_0_arrow = %ld\n", graphic_stack[stack_id].buffer_vertex_0_arrow);
+ printf("buffer_colors_0_arrow = %ld\n", graphic_stack[stack_id].buffer_colors_0_arrow);
+ printf("buffer_lines_0_arrow = %ld\n", graphic_stack[stack_id].buffer_lines_0_arrow);
+ printf("buffer_plans_0_arrow = %ld\n", graphic_stack[stack_id].buffer_plans_0_arrow);
+
+ printf("********************\n");
+ n++;
+}
+
+
+void graphics_model_setup (const int stack_id);
+
+int draw_one_arrow_vertex (const int stack_id,
+ int space_X,
+ int space_Y,
+ int space_Z,
+ int weight,
+ int site,
+ int x,
+ int y,
+ int z);
+
+int draw_one_arrow_line(const int stack_id,
+ int offset_vertex);
+
+/*
+ * Writes grid ridges to vertex and color buffers
+ *
+ * @param coords long (x,y,z), step_x, step_y, step_z
+ *
+ * @return void
+ */
+int draw_space_ridges_vertex (const int stack_id,
+ long offset_vertex,
+ long x,
+ long y,
+ long z);
+
+int draw_space_ridges_lines (const int stack_id);
+
+/*
+ * Writes grid lines on space faces
+ *
+ * @param coords long (x,y,z)
+ *
+ * @return void
+ */
+long draw_grids_on_space_faces_vertex (const int stack_id,
+ long x,
+ long y,
+ long z);
+
+long draw_grids_on_space_faces_lines (const int stack_id,
+ long offset_vertex,
+ long x,
+ long y,
+ long z);
+
+int set_arrow (int stack_id,
+ int arrows_nb,
+ int space_X,
+ int space_Y,
+ int space_Z,
+ int requested_weight,
+ int site,
+ int arrow_x,
+ int arrow_y,
+ int arrow_z);
+
diff --git a/graph_stack.c b/graph_stack.c
new file mode 100644
index 0000000..6d77b9e
--- /dev/null
+++ b/graph_stack.c
@@ -0,0 +1,323 @@
+/*
+ * Gem-graph OpenGL experiments
+ *
+ * Desc: GL functions
+ *
+ * Copyright (C) 2023 Arthur Menges
+ * Copyright (C) 2023 Adrien Bourmault
+ * Copyright (C) 2023 Jean Sirmai
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include "contain.h"
+#include "graph_area.h"
+#include "parsing.h"
+
+#define TEST 0
+
+struct graphic_stack_t *graphic_stack = NULL;
+size_t graphic_stack_size = 0;
+int *free_stack_slot = NULL;
+size_t free_stack_slot_size = 0;
+
+/*
+ * Prints verbose human-readable debug messages
+ *
+ * @param source, XXX
+ * type, XXX
+ * id, XXX
+ * severity, XXX
+ * length, XXX
+ * msg, XXX
+ * data, XXX
+ *
+ * @return void
+ */
+
+static void graphics_debug_callback(GLenum source, GLenum type, GLuint id,
+ GLenum severity, GLsizei length,
+ const GLchar *msg, const void *data)
+{
+ const char *errsource;
+ const char *errtype;
+ const char *errseverity;
+ const GLubyte *string;
+ GLenum code;
+
+ switch (source) {
+ case GL_DEBUG_SOURCE_API: errsource = "API"; break;
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM: errsource = "WINDOW SYSTEM"; break;
+ case GL_DEBUG_SOURCE_SHADER_COMPILER: errsource = "SHADER COMPILER"; break;
+ case GL_DEBUG_SOURCE_THIRD_PARTY: errsource = "THIRD PARTY"; break;
+ case GL_DEBUG_SOURCE_APPLICATION: errsource = "APPLICATION"; break;
+ case GL_DEBUG_SOURCE_OTHER: errsource = "UNKNOWN"; break;
+ default: errsource = "UNKNOWN"; break;
+ }
+
+ switch (type) {
+ case GL_DEBUG_TYPE_ERROR: errtype = "ERROR"; break;
+ case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: errtype = "DEPRECATED BEHAVIOR";break;
+ case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: errtype = "UNDEFINED BEHAVIOR"; break;
+ case GL_DEBUG_TYPE_PORTABILITY: errtype = "PORTABILITY"; break;
+ case GL_DEBUG_TYPE_PERFORMANCE: errtype = "PERFORMANCE"; break;
+ case GL_DEBUG_TYPE_OTHER: errtype = "OTHER"; break;
+ case GL_DEBUG_TYPE_MARKER: errtype = "MARKER"; break;
+ default: errtype = "UNKNOWN"; break;
+ }
+
+ switch (severity) {
+ case GL_DEBUG_SEVERITY_HIGH: errseverity = "CRITICAL"; break;
+ case GL_DEBUG_SEVERITY_MEDIUM: errseverity = "ERROR"; break;
+ case GL_DEBUG_SEVERITY_LOW: errseverity = "WARNING"; break;
+ case GL_DEBUG_SEVERITY_NOTIFICATION: errseverity = "INFO"; break;
+ default: errseverity = "UNKNOWN"; break;
+ }
+
+ code = glGetError();
+ string = gluErrorString(code);
+
+ g_printerr("[%s] %s (%s) from %s: %s\n",
+ errseverity, string, errtype, errsource, msg);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Initializes graphical stack
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return id if initialized
+ */
+int graphics_init(void *error_buffer)
+{
+ int cur_id = 0;
+ struct graphic_stack_t *stack;
+
+ g_printerr("[debug] graphics_init()\n");
+
+ if (graphic_stack == NULL) {
+ graphic_stack = g_malloc0(sizeof(struct graphic_stack_t));
+ graphic_stack_size = 1;
+ g_printerr("[debug] graphics_init(): init graphic_stack @ %p\n", graphic_stack);
+ } else {
+ // Check if there are free slots
+ if (free_stack_slot_size) {
+ // We get the last free slot registered
+ cur_id = free_stack_slot[free_stack_slot_size-1];
+ // Unregister it (ofc)
+ free_stack_slot = g_realloc(free_stack_slot,
+ free_stack_slot_size-- *
+ sizeof(int));
+ } else {
+ cur_id = graphic_stack_size;
+ graphic_stack = g_realloc(graphic_stack,
+ ++graphic_stack_size *
+ sizeof(struct graphic_stack_t));
+ }
+ }
+
+ memset(&graphic_stack[cur_id], 0, sizeof(struct graphic_stack_t));
+
+ g_printerr("[debug] graphics_init() : graphic_stack (@0x%p) has %ld elements\n",
+ graphic_stack,
+ graphic_stack_size);
+
+ stack = &graphic_stack[cur_id];
+ stack->id = cur_id;
+
+ glEnable(GL_DEBUG_OUTPUT);
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
+ glEnable(GL_MULTISAMPLE);
+
+ if (!graphics_init_shaders(cur_id)) return -1;
+
+ print_stack(cur_id);
+
+ graphics_init_buffers(cur_id);
+
+ glDebugMessageCallback(graphics_debug_callback, NULL);
+
+ //print_stack(cur_id);
+
+ return cur_id;
+}
+
+/*
+ * Shutdowns a gl_area
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return true if success
+ */
+bool graphics_shutdown(const int id, void *error_buffer)
+{
+ struct graphic_stack_t *stack;
+
+ if (id >= graphic_stack_size ||
+ graphic_stack_size == 0 ||
+ graphic_stack == NULL)
+ return false;
+
+ stack = &graphic_stack[id];
+
+ //XXX
+ free(stack->arrows_ptr);
+ stack->arrows_ptr = NULL;
+ stack->arrows_nb = 0;
+
+ glDeleteBuffers(1, &stack->position_buffer);
+ glDeleteBuffers(1, &stack->color_buffer);
+ glDeleteProgram(stack->program);
+
+ g_free(stack->buffer_vertex_origin);
+ g_free(stack->buffer_colors_origin);
+ g_free(stack->buffer_lines_origin);
+ g_free(stack->buffer_plans_origin);
+
+ if (graphic_stack_size == 1) {
+ free(graphic_stack);
+ graphic_stack = NULL;
+ graphic_stack_size = 0;
+ } else {
+ memset(&graphic_stack[id], 0, sizeof(struct graphic_stack_t));
+ free_stack_slot = g_realloc(free_stack_slot,
+ ++free_stack_slot_size *
+ sizeof(int));
+ free_stack_slot[free_stack_slot_size-1] = id;
+ }
+
+ return true;
+}
+
+/* TODO
+ * #pragma omp parallel schedule(static, 12)
+ * void __attribute__((optimize("no-unroll-loops"))) main_test_graphics (void) {}
+ *
+// assert : space dimensions (x,y,z) > 0
+// assert : arrows localization within space and sites
+// assert : no more than one arrow per address
+// notify : weights are replaced, NOT added (could be !)
+ *
+ * Init space and arrows (= initial state)
+ * and allows ulterior creations, suppressions or modifications of the arrows[] array
+ *
+ * draws the space()
+ * triggers set_arrows() that modifies the list () and draws arrows
+ *
+ * Initialisation du générateur pseudo-aléatoire
+ * Attention, les vertex centraux de chaque unité d'espace (cube)
+ * peuvent être redondants (max 6)
+*/
+void graphics_model_setup (const int stack_id)
+{
+ /*------------------------------------------------------------------------*/
+
+ /* I N I T I A L D A T A S P E C I F I C A T I O N */
+
+ /*------------------------------------------------------------------------*/
+
+ struct graphic_stack_t *stack = &graphic_stack[stack_id];
+ char dimension;
+ long space_X;
+ long space_Y;
+ long space_Z;
+ long announced_arrows_nb;
+ int density_max;
+ char multiplicity;
+
+ dimension = model_get_dim();
+
+ g_print("[GRAPH DEBUG] dim = %d\n", dimension);
+
+ space_X = 1;
+ space_Y = 1;
+ space_Z = 1;
+
+ switch(dimension) {
+ case 3:
+ space_Z = model_get_dim_value("z");
+;
+ case 2:
+ space_Y = model_get_dim_value("y");
+;
+ // even in 1D, we must be able to see a grid (or not !)
+ if (!space_Y)
+ space_Y = 1;
+ case 1:
+ space_X = model_get_dim_value("x");
+;
+ if (!space_X)
+ space_X = 1;
+ default:
+ break;
+ }
+
+ g_print("[GRAPH DEBUG] x = %ld\n", space_X);
+ g_print("[GRAPH DEBUG] y = %ld\n", space_Y);
+ g_print("[GRAPH DEBUG] z = %ld\n", space_Z);
+
+ density_max = space_X * space_Y * space_Z;
+ stack->arrows_nb = 0;
+
+ multiplicity = model_get_multiplicity();
+ g_print("[GRAPH DEBUG] site_multiplicity = %d, density_max = %d\n", multiplicity, density_max);
+
+ /*------------------------------------------------------------------------*/
+
+ /* S P A C E D R A W I N G */
+
+ /*------------------------------------------------------------------------*/
+
+ draw_space_ridges_vertex (stack_id, stack->buffer_vertex_size, space_X, space_Y, space_Z);
+ draw_space_ridges_lines (stack_id);
+ draw_grids_on_space_faces_vertex (stack_id, space_X, space_Y, space_Z);
+ draw_grids_on_space_faces_lines (stack_id, stack->buffer_lines_size, space_X, space_Y, space_Z);
+
+ stack->buffer_vertex_0_arrow = stack->buffer_vertex_size;
+ stack->buffer_colors_0_arrow = stack->buffer_colors_size;
+ stack->buffer_lines_0_arrow = stack->buffer_lines_size;
+
+ /*------------------------------------------------------------------------*/
+
+ /* A R R O W S D R A W I N G */
+
+ /*------------------------------------------------------------------------*/
+
+ char state_id[30] = {0};
+ struct arrow_t arrow = {0};
+
+ assert(model_get_next_state((char *)&state_id));
+
+ g_print("[GRAPH DEBUG] first state is = %s\n", state_id);
+
+ announced_arrows_nb = model_get_state_arrows_count(state_id);
+
+ g_print("[GRAPH DEBUG] announced_arrows_nb is = %ld\n", announced_arrows_nb);
+
+ while (model_get_next_arrow(&arrow, (char *)&state_id, dimension)) {
+ g_print("[GRAPH DEBUG] cur arrow has x = %d\n", arrow.x);
+ stack->arrows_nb = set_arrow (stack_id, stack->arrows_nb, space_X, space_Y, space_Z, arrow.load, arrow.site, arrow.x, arrow.y, arrow.z);
+ }
+
+ if (stack->arrows_nb != announced_arrows_nb)
+ g_printerr("ARGH : not all arrows have been parsed !\n");
+}
+
diff --git a/graphics.h b/graphics.h
new file mode 100644
index 0000000..c83b60c
--- /dev/null
+++ b/graphics.h
@@ -0,0 +1,314 @@
+/*
+ * Gem-graph OpenGL experiments
+ *
+ * Desc: OpenGL utils header
+ *
+ * Copyright (C) 2023 Arthur Menges
+ * Copyright (C) 2023 Adrien Bourmault
+ * Copyright (C) 2023 Jean Sirmai
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include "base.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define VERTEX_SHADER_FILE "src/graphics/shaders/shader.vert"
+#define FRAG_SHADER_FILE "src/graphics/shaders/shader.frag"
+#define GL_TARGET_MAJOR_VERSION 0
+#define GL_TARGET_MINOR_VERSION 4
+
+/*
+ * Structure describing a gl_area and its parameters, used to create a table
+ * of Gem-graph client current gl_areas
+ */
+struct graphic_stack_t {
+
+ int id;
+ int mode;
+
+ float rotation_angles[N_AXIS]; // Rotation angles on each axis
+
+ GLuint vao; // init_buffers
+ GLuint position_buffer; // shutdown, draw
+ GLuint color_buffer; // shutdown, draw
+ GLuint program; // shutdown, init_shaders, draw
+ GLuint m; // init_shaders, draw
+ GLuint v; // init_shaders, draw
+ GLuint p; // init_shaders, draw
+
+ struct arrow_t *arrows_ptr;
+ long arrows_nb;
+
+ GLfloat *buffer_vertex_origin;
+ GLfloat *buffer_colors_origin;
+ GLuint *buffer_lines_origin;
+ GLuint *buffer_plans_origin;
+
+ long buffer_vertex_size;
+ long buffer_colors_size;
+ long buffer_lines_size;
+ long buffer_plans_size;
+
+ long buffer_vertex_0_arrow;
+ long buffer_colors_0_arrow;
+ long buffer_lines_0_arrow;
+ long buffer_plans_0_arrow;
+};
+
+/*
+ * Dynamic array of ptrs to dynamically allocated gl_area_entry
+ */
+extern struct graphic_stack_t *graphic_stack;
+
+/*
+ * Initializes a gl_area
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return true if initialized
+ */
+int graphics_init(void *error_buffer);
+
+/*
+ * Draws the current buffer to a gl_area
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return void
+ */
+//void graphics_draw(const int stack_id);
+
+/*
+ * Shutdowns a gl_area
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return true if success
+ */
+bool graphics_shutdown(const int stack_id, void *error_buffer);
+
+/*
+ * Initializes the shaders of a gl_area and link them to a program
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return true if initialized
+ */
+bool graphics_init_shaders(const int stack_id);
+
+/* Initializes the buffer of a gl_area
+ * Calls according to the user preferences
+ * @param gl_area, ptr to the gl_area widget
+ * @return void
+ */
+void graphics_init_buffers(const int stack_id);
+
+/*
+ * Draws a vertex (x, y, z)
+ * if (console) prints (x, y, z) values to console
+ *
+ * @param GLfloat x, GLfloat y, GLfloat z
+ *
+ * @return void
+ */
+void graphics_draw_vertex (const int stack_id,
+ GLfloat x,
+ GLfloat y,
+ GLfloat z);
+
+/*
+ * Draws the color (r, g, b) associated to a vertex
+ * if (console) prints (r, g, b) values to console
+ *
+ * @param GLfloat r, GLfloat g, GLfloat b
+ *
+ * @return void
+ */
+void graphics_draw_color (const int stack_id, GLfloat r, GLfloat g, GLfloat b);
+
+/*
+ * Writes values to describe a line from a to b into the line buffer
+ *
+ * @param coords GLuint (a,b)
+ *
+ * @return void
+ */
+void graphics_draw_line (const int stack_id, GLuint a, GLuint b);
+
+/*
+ * Writes values to describe an (a,b,c) plan (triangle) into the plan buffer
+ *
+ * @param coords GLuint (a,b,c)
+ *
+ * @return void
+ */
+void graphics_draw_plan (const int stack_id, GLuint a, GLuint b, GLuint c);
+
+/*
+ * Created and compile a shader
+ *
+ * @param type, shader type
+ * src, source code of shader
+ *
+ * @return shader id
+ */
+static inline GLuint create_shader(const int stack_id, int type, const char *src)
+{
+ GLuint shader;
+ int status;
+
+ shader = glCreateShader(type);
+ glShaderSource(shader, 1, &src, NULL);
+ glCompileShader(shader);
+
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if(status == GL_FALSE) {
+ int log_len;
+ char *buffer;
+
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len);
+
+ buffer = g_malloc(log_len + 1);
+ assert (buffer);
+ glGetShaderInfoLog(shader, log_len, NULL, buffer);
+
+ g_warning("Compile failure in %s shader:\n%s",
+ type == GL_VERTEX_SHADER ? "vertex" : "fragment",
+ buffer);
+
+ g_free(buffer);
+
+ glDeleteShader(shader);
+
+ return 0;
+ }
+
+ return shader;
+}
+
+static inline void print_stack(int stack_id)
+{
+ static int n = 0;
+
+ printf("\n[n=%d]***************", n);
+
+ printf("id = %d\tmode = %d\n",
+ graphic_stack[stack_id].id,
+ graphic_stack[stack_id].mode);
+
+ printf("rotation_angles = ");
+ for (int i = 0; i < N_AXIS; i++) {
+ printf("%f\t", graphic_stack[stack_id].rotation_angles[i]); // Rotation angles on each axis
+ }
+ printf("\n");
+
+ printf("vao = %d\n", graphic_stack[stack_id].vao);
+ printf("position_buffer = %d\n", graphic_stack[stack_id].position_buffer);
+ printf("color_buffer = %d\n", graphic_stack[stack_id].color_buffer);
+ printf("program = %d\n", graphic_stack[stack_id].program);
+ printf("m = %d\n", graphic_stack[stack_id].m);
+ printf("v = %d\n", graphic_stack[stack_id].v);
+ printf("p = %d\n", graphic_stack[stack_id].p);
+
+ printf("arrows_ptr = %p\n", graphic_stack[stack_id].arrows_ptr);
+ printf("arrows_nb = %ld\n", graphic_stack[stack_id].arrows_nb);
+
+ printf("buffer_vertex_origin = %p\n", graphic_stack[stack_id].buffer_vertex_origin);
+ printf("buffer_colors_origin = %p\n", graphic_stack[stack_id].buffer_colors_origin);
+ printf("buffer_lines_origin = %p\n", graphic_stack[stack_id].buffer_lines_origin);
+ printf("buffer_plans_origin = %p\n", graphic_stack[stack_id].buffer_plans_origin);
+
+ printf("buffer_vertex_size = %ld\n", graphic_stack[stack_id].buffer_vertex_size);
+ printf("buffer_colors_size = %ld\n", graphic_stack[stack_id].buffer_colors_size);
+ printf("buffer_lines_size = %ld\n", graphic_stack[stack_id].buffer_lines_size);
+ printf("buffer_plans_size = %ld\n", graphic_stack[stack_id].buffer_plans_size);
+
+ printf("buffer_vertex_0_arrow = %ld\n", graphic_stack[stack_id].buffer_vertex_0_arrow);
+ printf("buffer_colors_0_arrow = %ld\n", graphic_stack[stack_id].buffer_colors_0_arrow);
+ printf("buffer_lines_0_arrow = %ld\n", graphic_stack[stack_id].buffer_lines_0_arrow);
+ printf("buffer_plans_0_arrow = %ld\n", graphic_stack[stack_id].buffer_plans_0_arrow);
+
+ printf("********************\n");
+ n++;
+}
+
+
+void graphics_model_setup (const int stack_id);
+
+int draw_one_arrow_vertex (const int stack_id,
+ int space_X,
+ int space_Y,
+ int space_Z,
+ int weight,
+ int site,
+ int x,
+ int y,
+ int z);
+
+int draw_one_arrow_line(const int stack_id,
+ int offset_vertex);
+
+/*
+ * Writes grid ridges to vertex and color buffers
+ *
+ * @param coords long (x,y,z), step_x, step_y, step_z
+ *
+ * @return void
+ */
+int draw_space_ridges_vertex (const int stack_id,
+ long offset_vertex,
+ long x,
+ long y,
+ long z);
+
+int draw_space_ridges_lines (const int stack_id);
+
+/*
+ * Writes grid lines on space faces
+ *
+ * @param coords long (x,y,z)
+ *
+ * @return void
+ */
+long draw_grids_on_space_faces_vertex (const int stack_id,
+ long x,
+ long y,
+ long z);
+
+long draw_grids_on_space_faces_lines (const int stack_id,
+ long offset_vertex,
+ long x,
+ long y,
+ long z);
+
+int set_arrow (int stack_id,
+ int arrows_nb,
+ int space_X,
+ int space_Y,
+ int space_Z,
+ int requested_weight,
+ int site,
+ int arrow_x,
+ int arrow_y,
+ int arrow_z);
+
diff --git a/grid.c b/grid.c
new file mode 100644
index 0000000..0947d80
--- /dev/null
+++ b/grid.c
@@ -0,0 +1,162 @@
+/*
+ * Gem-graph
+ *
+ * Desc: OpenGL grid functions
+ *
+ * Copyright (C) 2023 Jean Sirmai
+ * Copyright (C) 2023 Adrien Bourmault
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include "base.h"
+//#include "ui.h"
+#include "graphics.h"
+
+int draw_space_ridges_vertex (const int stack_id,
+ long offset_vertex,
+ long x,
+ long y,
+ long z)
+{
+ GLfloat max = fmax(x, y); max = fmax(max, z);
+
+ graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex - y / max, - z / max);
+
+ graphics_draw_vertex (stack_id, offset_vertex + x / max, offset_vertex - y / max, - z / max);
+ graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex + y / max, - z / max);
+ graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex - y / max, + z / max);
+
+ graphics_draw_vertex (stack_id, offset_vertex + x / max, offset_vertex + y / max, - z / max);
+ graphics_draw_vertex (stack_id, offset_vertex + x / max, offset_vertex - y / max, + z / max);
+ graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex + y / max, + z / max);
+
+ graphics_draw_vertex (stack_id, offset_vertex + x / max, + y / max, + z / max);
+
+ graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
+ graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
+ graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
+ graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
+ graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
+ graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
+ graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
+ graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
+
+ return 8;
+}
+
+int draw_space_ridges_lines (const int stack_id)
+{
+ graphics_draw_line (stack_id, 0, 1); graphics_draw_line (stack_id, 7, 4);
+ graphics_draw_line (stack_id, 0, 2); graphics_draw_line (stack_id, 7, 5);
+ graphics_draw_line (stack_id, 0, 3); graphics_draw_line (stack_id, 7, 6);
+
+ graphics_draw_line (stack_id, 1, 4); graphics_draw_line (stack_id, 2, 4);
+ graphics_draw_line (stack_id, 1, 5); graphics_draw_line (stack_id, 3, 5);
+ graphics_draw_line (stack_id, 2, 6); graphics_draw_line (stack_id, 3, 6);
+
+ return 12;
+}
+
+long draw_grids_on_space_faces_vertex (const int stack_id,
+ long x,
+ long y,
+ long z)
+{
+ float i, max = fmax(x, y); max = fmax(max, z);
+
+ for (i = 1; i < x; i++) {
+
+ graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, - y / max, - z / max);
+ graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, - y / max, z / max);
+ graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, y / max, z / max);
+ graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, y / max, - z / max);
+
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ }
+
+ /* offset_vertex += (x - 1) * 4; */ /* offset_colors += (x - 1) * 4; */
+
+ for (i = 1; i < y; i++) {
+
+ graphics_draw_vertex (stack_id, - x / max, (2 * i / y - 1) * y / max, - z / max);
+ graphics_draw_vertex (stack_id, - x / max, (2 * i / y - 1) * y / max, z / max);
+ graphics_draw_vertex (stack_id, x / max, (2 * i / y - 1) * y / max, z / max);
+ graphics_draw_vertex (stack_id, x / max, (2 * i / y - 1) * y / max, - z / max);
+
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ }
+
+ /* offset_vertex += (y - 1) * 4; */ /* offset_colors += (y - 1) * 4; */
+
+ for (i = 1; i < z; i++) {
+
+ graphics_draw_vertex (stack_id, - x / max, - y / max, (2 * i / z - 1) * z / max);
+ graphics_draw_vertex (stack_id, - x / max, y / max, (2 * i / z - 1) * z / max);
+ graphics_draw_vertex (stack_id, x / max, y / max, (2 * i / z - 1) * z / max);
+ graphics_draw_vertex (stack_id, x / max, - y / max, (2 * i / z - 1) * z / max);
+
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
+ }
+
+ return (x + y + z - 3) * 3;
+}
+
+
+long draw_grids_on_space_faces_lines (const int stack_id,
+ long offset_vertex,
+ long x,
+ long y,
+ long z)
+{
+ offset_vertex = offset_vertex / 3;
+
+ for (int i = 0; i < x - 1; i ++) {
+
+ graphics_draw_line (stack_id, offset_vertex + i * 4 + 1, offset_vertex + i * 4 + 2);
+ graphics_draw_line (stack_id, offset_vertex + i * 4 + 2, offset_vertex + i * 4 + 3);
+ }
+
+ offset_vertex += (x - 1) * 4;
+
+ for (int i = 0; i < y - 1; i ++) {
+
+ graphics_draw_line (stack_id, offset_vertex + i * 4 + 2, offset_vertex + i * 4 + 3);
+ graphics_draw_line (stack_id, offset_vertex + i * 4 + 3, offset_vertex + i * 4 + 0);
+ }
+
+ offset_vertex += (y - 1) * 4;
+
+ for (int i = 0; i < z - 1; i ++) {
+
+ graphics_draw_line (stack_id, offset_vertex + i * 4 + 0, offset_vertex + i * 4 + 1);
+ graphics_draw_line (stack_id, offset_vertex + i * 4 + 3, offset_vertex + i * 4 + 0);
+ }
+
+ return (x + y + z - 3) * 4;
+}
+
diff --git a/image/AMP.png b/image/AMP.png
new file mode 100644
index 0000000..450dfb7
Binary files /dev/null and b/image/AMP.png differ
diff --git a/image/ATP.png b/image/ATP.png
new file mode 100644
index 0000000..ba106d3
Binary files /dev/null and b/image/ATP.png differ
diff --git a/image/E coli (Goodsell) 2.png b/image/E coli (Goodsell) 2.png
new file mode 100644
index 0000000..b2eb7d7
Binary files /dev/null and b/image/E coli (Goodsell) 2.png differ
diff --git a/image/E coli (Goodsell).png b/image/E coli (Goodsell).png
new file mode 100644
index 0000000..55b14b8
Binary files /dev/null and b/image/E coli (Goodsell).png differ
diff --git a/image/aXoris.png b/image/aXoris.png
new file mode 100644
index 0000000..1994d91
Binary files /dev/null and b/image/aXoris.png differ
diff --git a/image/catécholamines.png b/image/catécholamines.png
new file mode 100644
index 0000000..4878e2f
Binary files /dev/null and b/image/catécholamines.png differ
diff --git a/image/dopamine.png b/image/dopamine.png
new file mode 100644
index 0000000..5360f44
Binary files /dev/null and b/image/dopamine.png differ
diff --git a/image/glutamate.png b/image/glutamate.png
new file mode 100644
index 0000000..dc474be
Binary files /dev/null and b/image/glutamate.png differ
diff --git a/image/glutamine.png b/image/glutamine.png
new file mode 100644
index 0000000..7ac3bb7
Binary files /dev/null and b/image/glutamine.png differ
diff --git a/image/hb.png b/image/hb.png
new file mode 100644
index 0000000..a010e57
Binary files /dev/null and b/image/hb.png differ
diff --git a/image/insuline Zn.png b/image/insuline Zn.png
new file mode 100644
index 0000000..9f7dd18
Binary files /dev/null and b/image/insuline Zn.png differ
diff --git a/image/insuline.png b/image/insuline.png
new file mode 100644
index 0000000..ea1c2a7
Binary files /dev/null and b/image/insuline.png differ
diff --git a/image/phénylalanine.png b/image/phénylalanine.png
new file mode 100644
index 0000000..10498bf
Binary files /dev/null and b/image/phénylalanine.png differ
diff --git a/init.c b/init.c
new file mode 100644
index 0000000..12756a4
--- /dev/null
+++ b/init.c
@@ -0,0 +1,191 @@
+/*
+ * Gem-graph OpenGL experiments
+ *
+ * Desc: GL functions
+ *
+ * Copyright (C) 2023 Arthur Menges
+ * Copyright (C) 2023 Adrien Bourmault
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/* -------------------------------------------------------------------------- */
+
+#include
+#include
+#include "base.h"
+#include "contain.h" // instead of "ui.h"
+#include "graph_area.h"
+
+/* Initializes the buffer of a gl_area
+ * Calls according to the user preferences
+ * @param gl_area, ptr to the gl_area widget
+ * @return void
+ */
+void graphics_init_buffers(const int stack_id)
+{
+ struct graphic_stack_t *stack = &graphic_stack[stack_id];
+
+ //XXX
+ graphics_model_setup(stack_id);
+
+ GLuint vao, vertex_buffer, color_buffer;
+
+ glGenBuffers(1, &vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER,
+ stack->buffer_vertex_size *
+ sizeof(stack->buffer_vertex_origin[0]),
+ stack->buffer_vertex_origin,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+
+ // colors
+ glGenBuffers(1, &color_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, color_buffer);
+ glBufferData(GL_ARRAY_BUFFER, stack->buffer_colors_size *
+ sizeof(stack->buffer_colors_origin[0]),
+ stack->buffer_colors_origin,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ // We only use one VAO, so we always keep it bound
+ glGenVertexArrays(1, &vao);
+ glBindVertexArray(vao);
+
+ stack->vao = vao;
+ stack->position_buffer = vertex_buffer;
+ stack->color_buffer = color_buffer;
+}
+
+/*
+ * Initializes the shaders of a gl_area and link them to a program
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return true if initialized
+ */
+bool graphics_init_shaders(const int stack_id)
+{
+ struct graphic_stack_t *stack = &graphic_stack[stack_id];
+ char *vertex_shader;
+ char *fragment_shader;
+ int status;
+ GLuint vertex = 0, fragment; // 2024-06-05 j'initialise vertex à 0 (au pif !)
+ GLuint program = 0;
+ GLuint m = 0;
+ GLuint v = 0;
+ GLuint p = 0;
+
+ // Load vertex shader file
+ vertex_shader = read_file(VERTEX_SHADER_FILE);
+ if (vertex_shader == NULL)
+ return false;
+ vertex = create_shader(stack_id, GL_VERTEX_SHADER, vertex_shader);
+
+ if(vertex == 0) {
+ stack->program = 0;
+ g_free(vertex_shader);
+ return false;
+ }
+
+ // Load fragment shader file
+ fragment_shader = read_file(FRAG_SHADER_FILE);
+ if (fragment_shader == NULL)
+ return false;
+ fragment = create_shader(stack_id, GL_FRAGMENT_SHADER, fragment_shader);
+
+ if(fragment == 0) {
+ glDeleteShader(vertex);
+ stack->program = 0;
+ g_free(vertex_shader);
+ g_free(fragment_shader);
+ return false;
+ }
+
+ // Link shaders to program
+ program = glCreateProgram();
+ printf("\n------------------------------------------------------------------------------------------\n");
+ printf("[debug] graphics_init_shaders() : program = %d, vertex = %d, fragment = %d\n\
+ exec > ** (myprogram:-----): WARNING ** : --:--:--:---: Linking failure: (address)\n",
+ program, vertex, fragment);
+
+ /* (myprogram:11732): WARNING **: 10:37:34.233: v plusieurs 'run' successifs
+ * (myprogram:11883): WARNING **: 10:38:22.979: glLinkProgram(program); < commenté
+ * (myprogram:11953): WARNING **: 10:38:46.170:
+ * (myprogram:12034): WARNING **: 10:39:14.709:
+ * (myprogram:12182): WARNING **: 10:40:49.788:
+ * > probablement la même adresse dans la librairie 'mesa' d'OpenGL (?) */
+
+ glAttachShader(program, vertex);
+ glAttachShader(program, fragment);
+
+ printf("Failed to link the graphic stack to widgets ! <> see init.c graphics_init_shaders()\n");
+ printf("the error in not : vertex shader lacks `main' but : failed to link... (comment line 140)\n");
+ // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glLinkProgram.xhtml
+ // glLinkProgram(program); // Linking failure: (address)
+ printf("------------------------------------------------------------------------------------------\n");
+
+ glGetProgramiv(program, GL_LINK_STATUS, &status); // Linking failure: (address)
+
+ if(status == GL_FALSE) {
+ int log_len;
+ char *buffer;
+
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len);
+
+ buffer = g_malloc(log_len + 1);
+ assert(buffer);
+ glGetProgramInfoLog(program, log_len, NULL, buffer);
+
+ g_warning("Linking failure:\n%s", buffer);
+
+ g_free(buffer);
+
+ glDeleteProgram(program);
+ program = 0;
+
+ glDeleteShader(vertex);
+ glDeleteShader(fragment);
+
+ g_free(vertex_shader);
+ g_free(fragment_shader);
+
+ return false;
+ }
+
+ /* Get the location of the "mvp" uniform */
+ m = glGetUniformLocation(program, "model_matrix");
+ v = glGetUniformLocation(program, "view_matrix");
+ p = glGetUniformLocation(program, "projection_matrix");
+
+ glDetachShader(program, vertex);
+ glDetachShader(program, fragment);
+
+ glDeleteShader(vertex);
+ glDeleteShader(fragment);
+
+ stack->program = program;
+ stack->m = m;
+ stack->v = v;
+ stack->p = p;
+
+ g_free(vertex_shader);
+ g_free(fragment_shader);
+
+ return true;
+}
diff --git a/init.c.todo b/init.c.todo
new file mode 100644
index 0000000..7789ec0
--- /dev/null
+++ b/init.c.todo
@@ -0,0 +1,175 @@
+/*
+ * Gem-graph OpenGL experiments
+ *
+ * Desc: GL functions
+ *
+ * Copyright (C) 2023 Arthur Menges
+ * Copyright (C) 2023 Adrien Bourmault
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/* -------------------------------------------------------------------------- */
+
+#include
+#include
+#include "base.h"
+#include "contain.h" // instead of "ui.h"
+#include "graph_area.h"
+
+/* Initializes the buffer of a gl_area
+ * Calls according to the user preferences
+ * @param gl_area, ptr to the gl_area widget
+ * @return void
+ */
+void graphics_init_buffers(const int stack_id)
+{
+ struct graphic_stack_t *stack = &graphic_stack[stack_id];
+
+ //XXX
+ graphics_model_setup(stack_id);
+
+ GLuint vao, vertex_buffer, color_buffer;
+
+ glGenBuffers(1, &vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER,
+ stack->buffer_vertex_size *
+ sizeof(stack->buffer_vertex_origin[0]),
+ stack->buffer_vertex_origin,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+
+ // colors
+ glGenBuffers(1, &color_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, color_buffer);
+ glBufferData(GL_ARRAY_BUFFER, stack->buffer_colors_size *
+ sizeof(stack->buffer_colors_origin[0]),
+ stack->buffer_colors_origin,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ // We only use one VAO, so we always keep it bound
+ glGenVertexArrays(1, &vao);
+ glBindVertexArray(vao);
+
+ stack->vao = vao;
+ stack->position_buffer = vertex_buffer;
+ stack->color_buffer = color_buffer;
+}
+
+/*
+ * Initializes the shaders of a gl_area and link them to a program
+ *
+ * @param gl_area, ptr to the gl_area widget
+ *
+ * @return true if initialized
+ */
+bool graphics_init_shaders(const int stack_id)
+{
+ struct graphic_stack_t *stack = &graphic_stack[stack_id];
+ char *vertex_shader;
+ char *fragment_shader;
+ int status;
+ GLuint vertex = 0, fragment; // 2024-06-05 j'initialise vertex à 0 (au pif !)
+ GLuint program = 0;
+ GLuint m = 0;
+ GLuint v = 0;
+ GLuint p = 0;
+
+ // Load vertex shader file
+ vertex_shader = read_file(VERTEX_SHADER_FILE);
+ if (vertex_shader == NULL)
+ return false;
+ vertex = create_shader(stack_id, GL_VERTEX_SHADER, vertex_shader);
+
+ if(vertex == 0) {
+ stack->program = 0;
+ g_free(vertex_shader);
+ return false;
+ }
+
+ // Load fragment shader file
+ fragment_shader = read_file(FRAG_SHADER_FILE);
+ if (fragment_shader == NULL)
+ return false;
+ fragment = create_shader(stack_id, GL_FRAGMENT_SHADER, fragment_shader);
+
+ if(fragment == 0) {
+ glDeleteShader(vertex);
+ stack->program = 0;
+ g_free(vertex_shader);
+ g_free(fragment_shader);
+ return false;
+ }
+
+ // Link shaders to program
+ program = glCreateProgram();
+ glAttachShader(program, vertex);
+ glAttachShader(program, fragment);
+
+ glLinkProgram(program);
+
+ glGetProgramiv(program, GL_LINK_STATUS, &status);
+
+ if(status == GL_FALSE) {
+ int log_len;
+ char *buffer;
+
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len);
+
+ buffer = g_malloc(log_len + 1);
+ assert(buffer);
+ glGetProgramInfoLog(program, log_len, NULL, buffer);
+
+ g_warning("Linking failure:\n%s", buffer);
+
+ g_free(buffer);
+
+ glDeleteProgram(program);
+ program = 0;
+
+ glDeleteShader(vertex);
+ glDeleteShader(fragment);
+
+ g_free(vertex_shader);
+ g_free(fragment_shader);
+
+ return false;
+ }
+
+ /* Get the location of the "mvp" uniform */
+ m = glGetUniformLocation(program, "model_matrix");
+ v = glGetUniformLocation(program, "view_matrix");
+ p = glGetUniformLocation(program, "projection_matrix");
+
+ glDetachShader(program, vertex);
+ glDetachShader(program, fragment);
+
+ glDeleteShader(vertex);
+ glDeleteShader(fragment);
+
+ stack->program = program;
+ stack->m = m;
+ stack->v = v;
+ stack->p = p;
+
+ g_free(vertex_shader);
+ g_free(fragment_shader);
+
+ return true;
+}
diff --git a/main b/main
deleted file mode 100755
index 8a5e7d6..0000000
Binary files a/main and /dev/null differ
diff --git a/main.c b/main.c
old mode 100755
new mode 100644
index 6edfd95..a5f9b0c
--- a/main.c
+++ b/main.c
@@ -1,73 +1,26 @@
-/* main.c
- *
- * Copyright 2024 Jean
- *
- * This program 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.
- *
- * This program 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 this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
+/******************************************************************************/
+/* */
+/* E coli by David S. Goodsell (2009) */
+/* --- */
+/* Let this freeze frame guide us towards the model */
+/* that alone can account for the phenomenon ! */
+/* */
+/******************************************************************************/
-#include
+#include "callback.h"
-static void
-print_hello (GtkWidget *widget,
- gpointer data)
-{
- g_print ("Hello World\n");
-}
-
-static void
-activate (GtkApplication *app,
- gpointer user_data)
-{
- GtkWidget *window;
- GtkWidget *button;
- GtkWidget *box;
-
- window = gtk_application_window_new (app);
- gtk_window_set_title (GTK_WINDOW (window), "Window");
- gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
-
- box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
- gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
- gtk_widget_set_valign (box, GTK_ALIGN_CENTER);
-
- gtk_window_set_child (GTK_WINDOW (window), box);
-
- button = gtk_button_new_with_label ("Hello World");
-
- g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
- g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window);
-
- gtk_box_append (GTK_BOX (box), button);
-
- gtk_window_present (GTK_WINDOW (window));
-}
-
-int
-main (int argc,
- char **argv)
+int main (int argc, char **argv)
{
GtkApplication *app;
int status;
- app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
- g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
+ app = gtk_application_new ("org.jean.GTK4_GG_hack", G_APPLICATION_DEFAULT_FLAGS);
+ g_signal_connect (app, "activate", G_CALLBACK (on_main_window_activation), NULL);
+ g_signal_connect (app, "activate", G_CALLBACK (on_dialog_window_activation), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
+ printf("in contain.get_SPACE_VIEW_box() (line 138) > ui_setup_glarea (0, GTK_WIDGET (middle_box)); < commented 2024/06/27 > TODO\n");
+
return status;
}
-
-
diff --git a/manifest.scm b/manifest.scm
new file mode 100644
index 0000000..c1ac365
--- /dev/null
+++ b/manifest.scm
@@ -0,0 +1,30 @@
+;;
+;; Dépendances sous GNU Guix
+;;
+
+
+(specifications->manifest
+ (list
+ "bash"
+ "coreutils"
+ "gcc-toolchain"
+ "pkg-config"
+ "valgrind"
+ "findutils"
+ "gdb"
+ "make"
+ "gtk"
+ "libxml2"
+ "glu"
+ "glew"
+ "glfw"
+ "cglm"
+ "libepoxy"
+ "pango@1.90.0"
+ "xorgproto"
+ "glib"
+ "mesa-headers"
+ "mesa"
+ "libadwaita"
+ )
+)
diff --git a/parsing.c b/parsing.c
new file mode 100644
index 0000000..b618d5b
--- /dev/null
+++ b/parsing.c
@@ -0,0 +1,481 @@
+/*
+ * Gem-graph client
+ *
+ * Desc: Model parsing functions
+ *
+ * Copyright (C) 2023 Jean Sirmai
+ * Copyright (C) 2024 Adrien Bourmault
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include // http://xmlsoft.org/examples/#parse1.c
+ // https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/general.html
+
+#include "base.h"
+
+#define READ_SITE 1 << 0
+#define READ_WEIGHT 1 << 1
+#define READ_X 1 << 2
+#define READ_Y 1 << 3
+#define READ_Z 1 << 4
+#define SUCCESSFUL_READ_ARROW_X (READ_SITE | READ_WEIGHT | READ_X)
+#define SUCCESSFUL_READ_ARROW_XY (READ_SITE | READ_WEIGHT | READ_X | READ_Y)
+#define SUCCESSFUL_READ_ARROW_XYZ (READ_SITE | READ_WEIGHT | READ_X | READ_Y | READ_Z)
+
+static xmlDocPtr model;
+static xmlHashTablePtr model_hashtable;
+
+bool model_init(const char *content, size_t length, const char *basename)
+{
+ xmlNode *node;
+
+ /*
+ * this initialize the library and check potential ABI mismatches
+ * between the version it was compiled for and the actual shared
+ * library used.
+ */
+ LIBXML_TEST_VERSION
+
+ model = xmlReadMemory(content, length, basename, NULL, 0);
+
+ if (model == NULL ) {
+ return false;
+ }
+
+ node = xmlDocGetRootElement(model);
+
+ if (node == NULL) {
+ g_printerr("Empty XML model !\n");
+ xmlFreeDoc(model);
+ return false;
+ }
+
+ if (xmlStrcmp(node->name, (xmlChar *) "gem-graph-model")) {
+ g_printerr("document of the wrong type, root node != gem-graph-model\n");
+ xmlFreeDoc(model);
+ return false;
+ }
+
+ model_hashtable = xmlHashCreate(0);
+
+ if (model_hashtable == NULL) {
+ g_printerr("Can't create model hash table !\n");
+ xmlFreeDoc(model);
+ return false;
+ }
+
+ return true;
+}
+
+bool model_shutdown(void)
+{
+ xmlFreeDoc(model);
+ xmlHashFree(model_hashtable, NULL);
+
+ // Cleanup function for the XML library
+ xmlCleanupParser();
+
+ // This is to debug memory for regression tests
+ xmlMemoryDump();
+
+ return true;
+}
+
+/******************************************************************************/
+
+static inline xmlNodePtr getNextChild(xmlNodePtr node, xmlChar *last)
+{
+ while (node != NULL && xmlStrcmp(node->name, last)) {
+ // //printf(" <>--- line n°%lu <%s>\n", xmlGetLineNo(node), node->name);
+ node = node->next;
+ }
+ return node;
+}
+
+static inline xmlChar* splitStrAtSlash(xmlChar *toSplit)
+{
+ toSplit = (xmlChar *)xmlStrchr(toSplit, '/');
+ toSplit = xmlStrsub (toSplit, 1, xmlStrlen(toSplit));
+ return toSplit;
+}
+
+static inline xmlChar* getFirstTag(xmlChar *path)
+{
+ xmlChar *preop = path;
+ path = (xmlChar *)xmlStrchr(path, '/');
+ path = xmlStrsub (path, 1, xmlStrlen(path));
+
+ //printf("%s = %s + / + %s\n", preop, xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1), path);
+
+ return xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1);
+}
+
+static inline xmlChar* getLastTag(xmlChar *path)
+{
+ while ((ulong)xmlStrchr (path, '/'))
+ path = splitStrAtSlash((xmlChar *)path);
+
+ // //printf("last tag in the path = <%s>\n", path);
+ return path; // which is no more the given path but only its last tag !
+}
+
+/******************************************************************************/
+
+static xmlNodePtr model_get_node(xmlChar *path)
+{
+ xmlNodePtr node;
+ xmlChar *extrait;
+ xmlChar *reste, *last;
+
+ // Lookup for node from path in hash table
+ node = xmlHashLookup(model_hashtable, path);
+
+ // Found a node in hash table
+ if (node) {
+ return node;
+
+ // no node found in hash table
+ } else {
+ reste = path;
+ last = getLastTag(reste);
+ node = xmlDocGetRootElement(model);
+
+ while (xmlStrchr (reste, '/')) {
+ extrait = getFirstTag(reste);
+ reste = splitStrAtSlash((xmlChar *)reste);
+ node = node->xmlChildrenNode;
+ node = getNextChild(node, extrait);
+ }
+
+ if(node && xmlStrcmp(node->name, last)) {
+ node = node->xmlChildrenNode;
+
+ while (node && xmlStrcmp(node->name, last)) {
+ node = node->next;
+ }
+ xmlHashAddEntry (model_hashtable, path, node);
+ }
+
+ return node;
+
+ }
+
+ return NULL;
+}
+
+/******************************************************************************/
+
+static inline long model_get_node_long_attrib(xmlNodePtr node, char *id)
+{
+ xmlAttr *attribute;
+ xmlChar* value;
+ long ret_value;
+
+ if (node && node->properties) {
+ attribute = node->properties;
+ while(attribute && attribute->name && attribute->children) {
+ if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) {
+ value = xmlNodeListGetString(node->doc, attribute->children, 1);
+ ret_value = strtol((char *)value, NULL, 0);
+ xmlFree(value);
+ return ret_value;
+ }
+ attribute = attribute->next;
+ }
+ }
+ return 0;
+}
+
+static inline bool model_get_node_str_attrib(xmlNodePtr node,
+ char *id,
+ char *dest)
+{
+ xmlAttr *attribute;
+ xmlChar* value;
+
+ if (node && node->properties) {
+ attribute = node->properties;
+ while(attribute && attribute->name && attribute->children) {
+ if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) {
+ value = xmlNodeListGetString(node->doc, attribute->children, 1);
+ strcpy(dest, (char *)value);
+ xmlFree(value);
+ return true;
+ }
+ attribute = attribute->next;
+ }
+ }
+ return false;
+}
+
+/******************************************************************************/
+
+char model_get_dim(void)
+{
+ // xmlAttr *attribute;
+ // xmlChar* value;
+ xmlNodePtr node = model_get_node(
+ (xmlChar *)"parameters/space-param/dimension");
+
+ if (xmlHasProp (node, (xmlChar *) "z")) return 3;
+ if (xmlHasProp (node, (xmlChar *) "y")) return 2;
+ if (xmlHasProp (node, (xmlChar *) "x")) return 1;
+ return 0;
+}
+
+long model_get_dim_value(const char *axis)
+{
+ // xmlAttr *attribute;
+ // xmlChar *value;
+ // long ret_value;
+ xmlNodePtr node = model_get_node(
+ (xmlChar *)"parameters/space-param/dimension");
+
+ return model_get_node_long_attrib(node, (char *)axis);
+}
+
+char model_get_multiplicity(void)
+{
+ // xmlAttr *attribute;
+ // xmlChar* value;
+ xmlNodePtr node = model_get_node(
+ (xmlChar *)"parameters/space-param/site_multiplicity");
+
+ if (node->children)
+ if (node->children->content)
+ return (char)strtol((char *)node->children->content, NULL, 0);
+
+ return 0;
+}
+
+bool model_get_next_state(char *new_state_id)
+{
+ static xmlNodePtr cur_node = NULL;
+ // xmlAttr *attribute;
+ // xmlChar *value;
+
+ if (cur_node == NULL) {
+ // Get first state
+ cur_node = model_get_node((xmlChar *)"savedstates/state");
+
+ } else {
+ // Get next state
+ if (cur_node->next)
+ cur_node = cur_node->next;
+ else
+ return false;
+ }
+
+ // Lookup in properties
+ if (model_get_node_str_attrib(cur_node, "id", new_state_id))
+ return true;
+
+ cur_node = NULL;
+ return false;
+}
+
+long model_get_state_arrows_count(const char *state_id)
+{
+ xmlNodePtr cur_node = NULL;
+ // xmlAttr *attribute;
+ long value = 0;
+ bool found = false;
+ char temp_char[25];
+ // uint check = 0; // bit field checker
+
+ //printf("NEW CALL : cur_node = %p\n", cur_node);
+
+ assert(state_id);
+
+ // Get first state node
+ cur_node = model_get_node((xmlChar *)"savedstates/state");
+
+ // Lookup in properties
+ while (cur_node && cur_node->properties) {
+ // attribute = cur_node->properties; < usage ?
+
+ // Look for the id attribute
+ if (model_get_node_str_attrib(cur_node, "id", (char *)&temp_char)) {
+ if (!xmlStrcmp((const xmlChar *)temp_char, (const xmlChar *)state_id)) {
+ found = true;
+ break;
+ }
+ }
+ cur_node = cur_node->next;
+ }
+
+ // Check if the state has been found
+ if (!found) {
+ cur_node = NULL;
+ return -1;
+ }
+
+
+ // Count arrows
+ if (cur_node->children) {
+ cur_node = cur_node->children;
+ while (cur_node) {
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow"))
+ value++;
+ cur_node = cur_node->next;
+ }
+ } else {
+ return -1;
+ }
+ return value;
+}
+
+bool model_get_next_arrow(struct arrow_t *new_arrow,
+ const char *state_id,
+ char dimension)
+{
+ static xmlNodePtr cur_node = NULL;
+ xmlAttr *attribute;
+ xmlChar *value;
+ bool found = false;
+ char temp_char[25];
+ uint check = 0; // bit field checker
+
+ //printf("NEW CALL : cur_node = %p\n", cur_node);
+
+ assert(new_arrow);
+ assert(state_id);
+
+ if (cur_node == NULL) {
+ // Get first state node
+ cur_node = model_get_node((xmlChar *)"savedstates/state");
+
+ // Lookup in properties
+ while (cur_node && cur_node->properties) {
+ attribute = cur_node->properties;
+
+ // Look for the id attribute
+ if (model_get_node_str_attrib(cur_node, "id", (char *)&temp_char)) {
+ if (!xmlStrcmp((xmlChar *)temp_char, (const xmlChar *)state_id)) {
+ found = true;
+ break;
+ }
+ }
+ cur_node = cur_node->next;
+ }
+
+ // Check if the state has been found
+ if (!found) {
+ cur_node = NULL;
+ return false;
+ }
+
+ // Get first arrow
+ if (cur_node->children) {
+ cur_node = cur_node->children;
+
+ found = false;
+ while (cur_node && cur_node->name) {
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) {
+ found = true;
+ break;
+ }
+ cur_node = cur_node->next;
+ }
+ }
+
+ // Check if the state has been found
+ if (!found) {
+ cur_node = NULL;
+ return false;
+ }
+
+ } else {
+ // Get next arrow
+ found = false;
+ while (cur_node->next) {
+ cur_node = cur_node->next;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) {
+ found = true;
+ break;
+ }
+ }
+
+ // Check if the state has been found
+ if (!found) {
+ cur_node = NULL;
+ return false;
+ }
+ }
+
+ //printf("DURING CALL : cur_node = %p\n", cur_node);
+ //printf("DURING CALL : cur_node->name = %s\n", cur_node->name);
+
+ // Lookup in properties
+ if (cur_node && cur_node->properties) {
+ attribute = cur_node->properties;
+
+ while(attribute && attribute->name && attribute->children) {
+ //printf("attr name : %s\n", attribute->name);
+ if (!xmlStrcmp(attribute->name, (const xmlChar *)"site")) {
+ value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
+ new_arrow->site = strtol((char *)value, NULL, 0);
+ xmlFree(value);
+ check |= READ_SITE;
+ }
+ if (!xmlStrcmp(attribute->name, (const xmlChar *)"weight")) {
+ value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
+ new_arrow->load = strtol((char *)value, NULL, 0);
+ xmlFree(value);
+ check |= READ_WEIGHT;
+ }
+ if (!xmlStrcmp(attribute->name, (const xmlChar *)"x")) {
+ value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
+ new_arrow->x = strtol((char *)value, NULL, 0);
+ xmlFree(value);
+ check |= READ_X;
+ }
+ if (!xmlStrcmp(attribute->name, (const xmlChar *)"y")) {
+ value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
+ new_arrow->y = strtol((char *)value, NULL, 0);
+ xmlFree(value);
+ check |= READ_Y;
+ }
+ if (!xmlStrcmp(attribute->name, (const xmlChar *)"z")) {
+ value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
+ new_arrow->z = strtol((char *)value, NULL, 0);
+ xmlFree(value);
+ check |= READ_Z;
+ }
+ attribute = attribute->next;
+ }
+
+ switch(dimension) {
+ case 3:
+ return (bool)(check & SUCCESSFUL_READ_ARROW_XYZ);
+ case 2:
+ return (bool)(check & SUCCESSFUL_READ_ARROW_XY);
+ case 1:
+ return (bool)(check & SUCCESSFUL_READ_ARROW_X);
+ }
+ }
+ cur_node = NULL;
+ return false;
+}
diff --git a/parsing.h b/parsing.h
new file mode 100644
index 0000000..1cf7ff8
--- /dev/null
+++ b/parsing.h
@@ -0,0 +1,43 @@
+/*
+ * Gem-graph OpenGL experiments
+ *
+ * Desc: Model parsing header
+ *
+ * Copyright (C) 2023 Arthur Menges
+ * Copyright (C) 2023 Adrien Bourmault
+ *
+ * This file is part of Gem-graph.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+#include "base.h"
+
+bool model_init(const char *content, size_t length, const char *basename);
+bool model_shutdown(void);
+
+char model_get_dim(void);
+long model_get_dim_value(const char *axis);
+char model_get_multiplicity(void);
+bool model_get_next_state(char *new_state_id);
+bool model_get_next_arrow(struct arrow_t *new_arrow,
+ const char *state_id,
+ char dimension);
+
+long model_get_state_arrows_count(const char *state_id);
+bool model_get_next_arrow(struct arrow_t *new_arrow,
+ const char *state_id,
+ char dimension);
diff --git a/shader.frag b/shader.frag
new file mode 100644
index 0000000..fb8a76c
--- /dev/null
+++ b/shader.frag
@@ -0,0 +1,9 @@
+#version 330 core
+
+in vec4 color;
+out vec4 out_frag_color;
+
+void main(void)
+{
+ out_frag_color = color;
+}
\ No newline at end of file
diff --git a/shader.vert b/shader.vert
new file mode 100644
index 0000000..09e953c
--- /dev/null
+++ b/shader.vert
@@ -0,0 +1,20 @@
+#version 330 core
+
+uniform mat4 projection_matrix;
+uniform mat4 model_matrix;
+uniform mat4 view_matrix;
+
+layout(location=0) in vec3 in_position;
+layout(location=1) in vec3 in_color;
+
+out vec4 color;
+
+void main(void)
+{
+ float zoom = 1.1f, chrominance = 1, luminance = 1;
+ gl_Position =
+ projection_matrix * view_matrix * model_matrix * vec4(in_position, zoom);
+ color = vec4 (chrominance * in_color.rgb, luminance);
+}
+
+// https://learnopengl.com/Getting-started/Shaders
\ No newline at end of file
diff --git a/texts.c b/texts.c
new file mode 100644
index 0000000..f14fdf9
--- /dev/null
+++ b/texts.c
@@ -0,0 +1,48 @@
+/******************************************************************************/
+/* */
+/* E coli by David S. Goodsell (2009) */
+/* --- */
+/* Let this freeze frame guide us towards the model */
+/* that alone can account for the phenomenon ! */
+/* */
+/******************************************************************************/
+
+char *get_space_run_edit_specif(){ return "\n\
+>>> Dans : [space_page - mode RUN] doivent être : ------------------------------------------------------\n\n\
+(1) les commandes de mouvement:\n\
+ - run/stop, slow down/speed up, step by step, do/undo/redo\n\
+ + le buffer [elapsed time] qui montre le temps de simulation écoulé\n\n\
+(2) les commandes qui modifient la perception de l'espace (la caméra)\n\
+ - son orientation (X,Y,Z),\n\
+ + l'orientation (X,Y,Z) de l'état dans l'espace (six possibilités),\n\
+ + le zoom,\n\
+ + les paramètres qui définissent la perspective (distances oeil/écran, écran/objet virtuel) \n\n\
+(3) les commandes qui modifient les apparences des objets et des situations d'intérêt\n\
+ (+/- transparents, colorés, etc.)\n\n\
+(4) les commandes qui modifient l'apparence de l'espace (grilles, +/- surfaces, aspect des flèches, etc.)\n\n\
+(0) NB >>> AUCUNE COMMANDE NE DOIT PERMETTRE D'ÉDITER L'ESPACE ! <<<\n\n\n\
+>>> Dans : [space_page - mode EDIT] doivent être : ------------------------------------------------------\n\n\
+(1) les commandes qui modifient la perception de l'espace (la caméra)\n\
+ - son orientation (X,Y,Z),\n\
+ + l'orientation (X,Y,Z) de l'état dans l'espace (six possibilités),\n\
+ + le zoom,\n\
+ + les paramètres qui définissent la perspective (distances oeil/écran, écran/objet virtuel) \n\n\
+(2) les commandes qui modifient les apparences des objets et des situations d'intérêt\n\
+ (+/- transparents, colorés, etc.)\n\n\
+(3) les commandes qui modifient l'apparence de l'espace (grilles, +/- surfaces, aspect des flèches, etc.)\n\n\
+(4) les commandes d'édition locales (drag and drop une flèche)\n\
+ ('faire de la place' pour insérer)\n\
+ (sélectionner pour déplacer ou enlever...)\n\
+ NB ces commandes doivent être graphiques et/ou accessibles par raccourcis ou en ligne\n\n\
+(5) les commandes d'édition globales\n\
+ (ex: introduire, retirer, transformer +/-aléatoirement (n) objets dans l'espace)\n\n\n\
+ NB une action effectuée sur une zone d'intérêt devrait pouvoir être automatiquement appliquée\n\
+ à d'autres zones d'intérêt identifiées comme similaires\n\n\
+(0) NB >>> AUCUNE COMMANDE NE DOIT PERMETTRE D'EXÉCUTER UN RUN ! <<<\n\n\n\
+>>> L'objectif est que l'utilisateur ait accès à une organsisation aussi ergonomique que possible -----\n\n\
+ i.e : chaque utilisateur devrait disposer de 'préférences'\n\
+ c'est-à-dire avoir la possiblité de faire des choix ergonomiques personnalisés.\n\
+";}
+
+char *get_rules_run_edit_specif(){ return "\n\
+";}
diff --git a/texts.h b/texts.h
new file mode 100644
index 0000000..43a7437
--- /dev/null
+++ b/texts.h
@@ -0,0 +1,39 @@
+char *get_space_run_edit_specif();
+char *get_rules_run_edit_specif();
+
+/*
+>>> Dans : [space_page - mode RUN] doivent être : ------------------------------------------------------
+
+(1) les commandes de mouvement:
+ - run/stop, slow down/speed up, step by step, do/undo/redo
+ + le buffer [elapsed time] qui montre le temps de simulation écoulé
+(2) les commandes qui modifient la perception de l'espace (la caméra)
+ - son orientation (X,Y,Z),
+ + le zoom,
+ + les paramètres qui définissent la perspective (distances oeil/écran, écran/objet virtuel)
+(3) les commandes qui modifient les apparences des objets et des situations d'intérêt
+ (+/- transparents, colorés, etc.)
+(4) les commandes qui modifient l'apparence de l'espace (grilles, +/- surfaces, aspect des flèches, etc.)
+(0) NB >>> AUCUNE COMMANDE NE DOIT PERMETTRE D'ÉDITER L'ESPACE ! <<<
+>>> Dans : [space_page - mode EDIT] doivent être : ------------------------------------------------------
+(1) les commandes qui modifient la perception de l'espace (la caméra)
+ - son orientation (X,Y,Z),
+ + le zoom,
+ + les paramètres qui définissent la perspective (distances oeil/écran, écran/objet virtuel)
+(2) les commandes qui modifient les apparences des objets et des situations d'intérêt
+ (+/- transparents, colorés, etc.)
+(3) les commandes qui modifient l'apparence de l'espace (grilles, +/- surfaces, aspect des flèches, etc.)
+(4) les commandes d'édition locales (drag and drop une flèche)
+ ('faire de la place' pour insérer)
+ (sélectionner pour déplacer ou enlever...)
+ NB ces commandes doivent être graphiques et/ou accessibles par raccourcis ou en ligne
+(5) les commandes d'édition globales
+ (ex: introduire, retirer, transformer +/-aléatoirement (n) objets dans l'espace)
+ NB une action effectuée sur une zone d'intérêt devrait pouvoir être automatiquement appliquée
+ à d'autres zones d'intérêt identifiées comme similaires
+(0) NB >>> AUCUNE COMMANDE NE DOIT PERMETTRE D'EXÉCUTER UN RUN ! <<<
+>>> L'objectif est que l'utilisateur ait accès à une organsisation aussi ergonomique que possible -----
+ i.e : chaque utilisateur devrait disposer de 'préférences'
+ c'est-à-dire avoir la possiblité de faire des choix ergonomiques personnalisés.
+*/
+
diff --git a/tree.c b/tree.c
new file mode 100644
index 0000000..99c6fbb
--- /dev/null
+++ b/tree.c
@@ -0,0 +1,135 @@
+#include
+#include
+
+#include
+
+#include "contain.h"
+#include "texts.h"
+#include "callback.h"
+
+// https://docs.gtk.org/gtk4/visual_index.html < widgets gallery
+// https://docs.gtk.org/gtk4/section-text-widget.html
+// https://docs.gtk.org/gtk4/class.Widget.html#height-for-width-geometry-management
+// GTK_ORIENTATION_VERTICAL GTK_ORIENTATION_HORIZONTAL
+
+struct TreeNode_t {gchar *text; struct TreeNode_t *child, *next;};
+
+static void add_child_node (struct TreeNode_t *parent, struct TreeNode_t *child){
+ if (parent->child) {
+ struct TreeNode_t *cur = parent->child;
+ while (cur && cur->next) {cur = cur->next;}
+ cur->next = child;
+ } else parent->child = child;
+}
+
+static struct TreeNode_t *create_user_tree_node (const gchar* text){
+ struct TreeNode_t *node = g_malloc0 (sizeof(struct TreeNode_t));
+ node->text = g_strdup (text);
+ node->child = NULL; // if (0) printf("create_user_tree_node %s\n", text);
+ return node;
+}
+
+static void let_us_create_a_complex_useless_and_expensive_tree (struct TreeNode_t *tree_root) {
+ struct TreeNode_t *a = create_user_tree_node("We, the people");add_child_node(tree_root, a);
+ struct TreeNode_t *b = create_user_tree_node("in Order to"); add_child_node(tree_root, b);
+ struct TreeNode_t *c = create_user_tree_node("do establish"); add_child_node(tree_root, c);
+ struct TreeNode_t *aa = create_user_tree_node("aware of"); add_child_node(a, aa);
+ struct TreeNode_t *aaa = create_user_tree_node("our rights"); add_child_node(aa, aaa);
+ struct TreeNode_t *aab = create_user_tree_node("our duties"); add_child_node(aa, aab);
+ struct TreeNode_t *aaaa = create_user_tree_node("read"); add_child_node(aaa, aaaa);
+ struct TreeNode_t *aaab = create_user_tree_node("write"); add_child_node(aaa, aaab);
+ struct TreeNode_t *aaac = create_user_tree_node("copy"); add_child_node(aaa, aaac);
+ struct TreeNode_t *aaad = create_user_tree_node("edit"); add_child_node(aaa, aaad);
+ struct TreeNode_t *aaaba= create_user_tree_node("code"); add_child_node(aaab, aaaba);
+ struct TreeNode_t *aaabb= create_user_tree_node("language"); add_child_node(aaab, aaabb);
+ struct TreeNode_t *aaabc= create_user_tree_node("any art..."); add_child_node(aaab, aaabc);
+ struct TreeNode_t *aaadb= create_user_tree_node("publish"); add_child_node(aaac, aaadb);
+ struct TreeNode_t *aaada= create_user_tree_node("create"); add_child_node(aaad, aaada);
+ struct TreeNode_t *aaba = create_user_tree_node("learn"); add_child_node(aab, aaba);
+ struct TreeNode_t *aabb = create_user_tree_node("help"); add_child_node(aab, aabb);
+ struct TreeNode_t *ba = create_user_tree_node("promote"); add_child_node(b, ba);
+ struct TreeNode_t *bb = create_user_tree_node("individual"); add_child_node(b, bb);
+ struct TreeNode_t *bc = create_user_tree_node("and common"); add_child_node(b, bc);
+ struct TreeNode_t *bca = create_user_tree_node("education"); add_child_node(bc, bca);
+ struct TreeNode_t *bcb = create_user_tree_node("mutual"); add_child_node(bc, bcb);
+ struct TreeNode_t *bcc = create_user_tree_node("support"); add_child_node(bc, bcc);
+ struct TreeNode_t *bcd = create_user_tree_node("health"); add_child_node(bc, bcd);
+ struct TreeNode_t *bcda = create_user_tree_node("mental"); add_child_node(bcd, bcda);
+ struct TreeNode_t *bcdb = create_user_tree_node("physical"); add_child_node(bcd, bcdb);
+ struct TreeNode_t *ca = create_user_tree_node("free"); add_child_node(c, ca);
+ struct TreeNode_t *cb = create_user_tree_node("code"); add_child_node(c, cb);
+ struct TreeNode_t *cc = create_user_tree_node("access"); add_child_node(c, cc);
+}
+
+void on_setup_user_tree_factory (GtkSignalListItemFactory *factory,
+ GObject* object, gpointer user_data){
+ GtkWidget* expander = gtk_expander_new (NULL);
+ gtk_list_item_set_child (GTK_LIST_ITEM (object), expander);
+ if (0) printf("[on_setup_user_tree_factory] here is an expander\n");
+}
+
+static GListModel* get_user_tree_model_child (struct TreeNode_t *parent){
+ GtkStringList *list = NULL;
+ if (parent) {
+ if (0) printf("[get_user_tree_model_child] here is %s content : ", parent->text);
+ struct TreeNode_t *child = parent->child;
+ if (child) {list = gtk_string_list_new(NULL);}
+ while(child) {
+ gtk_string_list_append(list, child->text);
+ if (0) printf("%s ", child->text);
+ child = child->next;
+ }
+ } // else printf("hot.c GListModel* get_user_tree_model_child (struct TreeNode_t *parent) child = %d \n", parent);
+ if (0) printf("\n");
+ return G_LIST_MODEL(list);
+}
+
+GListModel* get_user_tree_model (GObject *item, gpointer root){
+ struct TreeNode_t *cur = (struct TreeNode_t *)root;
+ struct TreeNode_t *parent = root;
+ const gchar *string = gtk_string_object_get_string (GTK_STRING_OBJECT (item));
+ while (cur) {
+ if (strcmp(string, cur->text) == 0) break;
+ cur = cur->next;
+ if (cur == NULL) {cur = parent->child; parent = cur;}
+ }
+ if (0) printf("[get_user_user_tree_model] looked for %s in %s item\n", cur->text, string);
+// ! WARNING ! TODO CUR EST L'ENFANT, MAINTENANT DONC, SI CUR EST UNE FEUILLE, JE N'ATTEINDRAI PAS SON ENFANT
+ return get_user_tree_model_child (cur);
+}
+
+GtkScrolledWindow *get_user_rules_tree ()
+{
+ struct TreeNode_t *tree_root = create_user_tree_node("root");
+ let_us_create_a_complex_useless_and_expensive_tree (tree_root);
+
+ GtkStringList *model = gtk_string_list_new(NULL);
+ gtk_string_list_append (model, tree_root->text);
+ GtkSignalListItemFactory *factory = GTK_SIGNAL_LIST_ITEM_FACTORY (gtk_signal_list_item_factory_new());
+ g_signal_connect (factory, "setup", G_CALLBACK(on_setup_user_tree_factory), NULL);
+ g_signal_connect (factory, "bind", G_CALLBACK(on_bind_user_tree_factory), NULL);
+
+ GtkTreeListModel *tree_model = gtk_tree_list_model_new(
+ G_LIST_MODEL (model),
+ FALSE, // Passthrough - False in actual usage with dynamic children retrieval
+ TRUE, // FALSE, // autoexpand
+ (GtkTreeListModelCreateModelFunc) &get_user_tree_model,
+ tree_root,
+ NULL // (GDestroyNotify) free_user_tree_node
+ );
+
+ GtkSingleSelection *selection_model = gtk_single_selection_new (G_LIST_MODEL (tree_model));
+ gtk_single_selection_set_autoselect (selection_model, FALSE);
+ gtk_single_selection_set_can_unselect (selection_model, TRUE);
+ GtkWidget *list_view = gtk_list_view_new (GTK_SELECTION_MODEL (selection_model), GTK_LIST_ITEM_FACTORY (factory));
+ GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new());
+// Allocation height too small. Tried to allocate 1922x1030, but GtkNotebook 0x25cd4c0 needs at least 1922x1064.
+// even if I remove (comment) the next line :
+ gtk_scrolled_window_set_child (scrolled_window, list_view);
+ gtk_scrolled_window_set_policy (scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_vexpand (GTK_WIDGET (scrolled_window), TRUE);
+ gtk_widget_set_visible (GTK_WIDGET (scrolled_window), TRUE);
+ gtk_widget_set_visible (GTK_WIDGET (list_view), TRUE);
+ return scrolled_window;
+}
+
diff --git a/tree.h b/tree.h
new file mode 100644
index 0000000..880cf7b
--- /dev/null
+++ b/tree.h
@@ -0,0 +1,40 @@
+/******************************************************************************/
+/* */
+/* E coli by David S. Goodsell (2009) */
+/* --- */
+/* Let this freeze frame guide us towards the model */
+/* that alone can account for the phenomenon ! */
+/* */
+/******************************************************************************/
+
+#pragma once // < WTF !?
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+//#include "cold.h"
+#include "display.h"
+#include "contain.h"
+
+
+// https://blog.gtk.org/2020/09/08/on-list-models/ < TODO
+
+GtkScrolledWindow *get_user_rules_tree ();
+void set_run_edit_mode(int prescribed_mode);
+int get_run_edit_mode();
+GListModel* get_user_tree_model (GObject *item, gpointer root);
+void on_setup_user_tree_factory (GtkSignalListItemFactory *factory,
+ GObject* object, gpointer user_data);
+