Bac à sable

This commit is contained in:
Adrien Bourmault 2023-09-21 12:03:53 +02:00
parent 1a780bd8f3
commit 71d7d30664
No known key found for this signature in database
GPG Key ID: 6EB408FE0ACEC664
14 changed files with 52 additions and 1974 deletions

View File

@ -1,2 +0,0 @@
# Gem-graph Client

View File

@ -1,46 +0,0 @@
L'utilisation d'OpenGL fait que la première version de Gem-graph sera tout naturellement en 3D. Le modèle de marche aléatoire de dimères sera aussi facile à y réaliser que dans un modèle 1D (on pourrait même se servir d'une seule règle au lieu de deux !) (mais deux règles permettront un meilleur rendu).
Modifier la forme des flèches ?
Pour cette première version, la forme "central star" + "cône" a l'avantage de la simplicité.
La "central star" de chaque cube est commune aux six flèches possibles qui sont orientées chacune vers une face différente.
Dans la version actuelle, elle est redessinée si plusieurs flèches sont dans le même cube.
Ce dessin est peu coûteux (deux lignes superposées pour chaque nouvelle flèche)
et ce cas (plusieurs flèches dans le même cube) sera peu fréquent dans les premiers modèles développés. Mais... TODO
Le plus simple serait un trait allant du centre d'un cube au centre d'une de ses faces. Ce serait peu lisible pour des objets mais pourrait avoir un intérêt pour les tags (balises) éventuellement associés aux objets ou situations. Ces tags seraient machine-readable. Nécessairement. Seraient-ils human-readable aussi ? Ce serait idéal ! A inventer ou essayer, en tout cas.
Un seul trait aurait sûrement un intérêt dans la représentation de voisinages de Moore 3D (Je préfère ne pas imaginer ça pour l'instant ! Il va falloir choisir de ne représenter ou de ne visualiser qu'une partie des connexions à la fois...).
Le premier objectif des versions à venir est l'extension du voisinage. Un voisinage type von Neumann 3D - le plus simple possible si on le veut symétrique par rapport aux axes de l'espace - est tout à fait indiqué pour cette première version. Mais les versions à venir devraient travailler en priorité avec des voisinages type Moore 3D approximativement spériques de rayon proche de celui de l'espace local.
Par ailleurs, Gem-graph ne peut avoir sa puissance théorique maximale que s'il peut utiliser un voisinage étendu à tout l'espace. Mais cette puissance est vraisemblablement inutile, sauf pour les démonstrations mathématiques d'équivalence avec les automates cellulaires, par exemple, ou d'autres formalismes.
Par ailleurs, il est d'ores et déjà possible d'utiliser pleinement le "poids" (weight) ou la "charge" (load) des flèches.
! WARNING ! J'ai inversé pôle Nord et pôle Sud. Et c'est à corriger, je pense. 👀️
Ce sera une convention, bien sûr. Mais comment la choisir ? J'ai imaginé superposer repère orthonormé et repère géodésique.
Si je regarde un repère orthonormé 3D:
les +x sont à ma droite, les -x à ma gauche (Est - Ouest)
les +y en haut, les -y en bas (Zénith - Nadir) et... si l'axe des z vient vers moi,
les +z sont derrière moi et les -z devant. Donc les -z sont au Nord (que je regarde) et les +z sont au Sud.
Les vertex situés aux intersections des "grilles" (X-X, Y-Y et Z-Z) sont-ils utiles ?
Ils le seraient si ses cubes individuels étaient coloriés ou soulignés pour mettre en valeur des flèches qu'ils contiennent ou d'autres particularités.
Mais tant qu'il n'est pas possible de rendre sélectivement transparentes les parois de cubes individuels (ou de tel ou tel objet dessiné par les flèches), cette fonction est inutilisable et les vertex situés aux intersections des grilles sont donc inutiles.
On pourrait ne garder que ceux situés sur les faces de l'espace qui, eux, servent à tracer les grilles X-X, Y-Y et Z-Z.
Le nombre de vertex de l'espace serait alors de 12 par cube-unité (soit 12 * x * y * z) plus les vertex intersections des seules faces de l'espace (soit (x * y + x * z + y * z) * 2).
A raison, bien sûr de trois nombres par vertex plus les couleurs.
Je comprends (maintenant seulement !) que si des régions du buffer lignes (idem pour le buffer triangles) sont laissées vides (occupées par des zéros) elles seront néanmoins redessinées en permanence et que le seul moyen d'éviter cela est de réallouer la taille du buffer à chaque délétion ou chaque ajout de flèche.
Néanmoins, lorsque le nombre de flèches présent dans l'espace est invariant, - cas de mes premiers modèles - il peut être avantageux de travailler dans un buffer de taille fixe. Il faut, pour cela, fixer une "densité maximale de flèches dans l'espace" nécessairement arbitraire.
Bien que ce nombre reste toujours arbitraire, on peut estimer que certaines de ses valeurs seront plus utiles/utilisables que d'autres :
- un espace totalement vide ou totalement saturé ne pourrait rien représenter
- un espace trop vide ou trop plein (à définir - c'est intuitif) aurait peu de chances de représenter des phénomènes intéressants. La marche aléatoire d'un seul ou de quelques dimères dans un grand espace, par exemple, servira plus de test pour le bon fonctionnement de Gem-graph que de modèle d'étude.
- on peut considérer un espace rempli de flèches aux 2/3 comme équivalent à un espace repli au tiers (1/3) mais où les flèches seraient écrites "en creux" et, par conséquent, moins lisibles. Inutile, donc, de remplir plus de la moitié de l'espace.
D'expérience,
- les densités de l'ordre du tiers (1/3 des unités de l'espace occupées par au moins une flèche) suffisent à représenter un nombre de phénomènes tel qu'il n'est pas nécessaire, au moins dans un premier temps, de prévoir davantage (mais des réalloc sont toujours possibles) et les densités trop fortes sont peu lisibles.
Un buffer lignes pourrait donc avoir une taille fixe qui serait calculée selon les paramètres suivants :
- x * y * z = nombre de cubes
- nombre de flèches moyen par cube = 2 (il s'agit d'un nombre "moyen" qui surestime très probablement le nombre de flèches utilisé par la plupart des modèles)
- dessin d'une flèche seule dans un cube = 3 + 4 traits (soit 14 nombres)
Faut-il coder cette option ?

View File

@ -1,118 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gem-graph-model version="0.2.1">
<identity>
<name>Modèle de test</name>
<owner>Léontine Patinette</owner>
<owner_id>2</owner_id>
<date>1630000000</date>
<version>1.0</version>
<g_ref id="Cause" date="1630000000" author="toujours" lang="en">Ref</g_ref>
</identity>
<parameters id="texte" date="0" author="Léontine Trottine.">
<simulation>
<max_thread>0</max_thread>
<max_cycles>9</max_cycles>
</simulation>
<space-param>
<!-- loop_on_zero="true" anything moved before zero reenters at the end of space-->
<!-- loop_on_zero="false" anything moved before zero is lost-->
<!-- loop_on_max="true" anything moved beyond max reenters at the zero of space-->
<!-- loop_on_max="false" anything moved beyond max is lost-->
<dimension x="29"/>
<!-- Site_multiplicity = number of sites in a space unit. -->
<!-- Each site points towards a neighbouring space unit. -->
<!-- Several arrows can be stacked in the same site. -->
<site_multiplicity>3</site_multiplicity>
</space-param>
</parameters>
<!-- Model objects definition -->
<objects id="only dimers in this model" date="1630000000" author="inanimés,... âme ?">
<object id="a dimer" date="1630000000" author="Alphonse">
<arrow site="1" weight="1" x="0"/>
<arrow site="2" weight="1" x="1"/>
</object>
</objects>
<!-- Saved space description (initial space is sequence 0) -->
<savedstates id="texte" date="1630000000" author="Qui courrait dans l'herbe'">
<state id="initial" date="1630000000" author="Une souris verte">
<arrow site="1" weight="1" x="0"/>
<arrow site="2" weight="1" x="1"/>
<arrow site="1" weight="1" x="10"/>
<arrow site="2" weight="1" x="11"/>
<arrow site="1" weight="1" x="20"/>
<arrow site="2" weight="1" x="21"/>
<!-- Three dimers 1-1 are drawn in the global space
at locations (0,1) (10,11) and (20,21) -->
</state>
</savedstates>
<!-- Model transitions definition (rules) -->
<!-- In this version : <xs:sequence minOccurs="0" maxOccurs="unbounded">-->
<!-- Transitions should be edited by hand and written in a 'human-readable' format -->
<conditions id="random walk of dimers" date="1630000000" author="Zazard le lézard !">
<condition site="1" weight="1" node_id="1" parent="0" x="0"/>
<condition site="2" weight="1" node_id="2" parent="1" x="1"/>
<!-- as soon as conditions 1 and 2 are satisfied, a dimer is identified at atation (0,1). -->
<condition site="1" weight="0" node_id="3" parent="2" x="2"/>
<!-- as soon as condition 3 is satisfied,
the neighbouring space unit to East of the dimer is empty
and the dimer identified by conditions (1,2) can be moved to East. -->
<condition site="2" weight="0" node_id="4" parent="2" x="-1"/>
<!-- as soon as condition 4 is satisfied,
the neighbouring space unit to West of the dimer is empty
and the dimer identified by conditions (1,2) can be moved to West. -->
</conditions>
<transitions>
<transition id="move_a_dimer_to_east" date="1630000000" author="Pas moi..."
parent="3" probability="1">
<arrow site="1" weight="0" x="0"/>
<arrow site="2" weight="0" x="1"/>
<arrow site="1" weight="1" x="1"/>
<arrow site="2" weight="1" x="2"/>
</transition>
<transition id="move_a_dimer_to_west" date="1630000000" author="Ni moi !"
parent="4" probability="1">
<arrow site="1" weight="0" x="0"/>
<arrow site="2" weight="0" x="1"/>
<arrow site="2" weight="1" x="0"/>
<arrow site="1" weight="1" x="1"/>
</transition>
</transitions>
</gem-graph-model>

View File

@ -1,145 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gem-graph-model version="0.2.1">
<identity>
<name>Test 21-03-2023</name>
<owner>J</owner>
<owner_id>J</owner_id>
<date>time_stamp</date>
<version>1.0</version>
<g_ref id="Cause" date="time_stamp" author="J" lang="en">Ref</g_ref>
</identity>
<parameters id="texte" date="0" author="J">
<simulation>
<max_thread>0</max_thread>
<max_cycles>9</max_cycles>
</simulation>
<space-param>
<!-- loop_on_zero="true" anything moved before zero reenters at the end of space-->
<!-- loop_on_zero="false" anything moved before zero is lost-->
<!-- loop_on_max="true" anything moved beyond max reenters at the zero of space-->
<!-- loop_on_max="false" anything moved beyond max is lost-->
<dimension x="22" y="4" z="8"/>
<!-- Site_multiplicity = number of sites in a space unit. -->
<!-- Each site points towards a neighbouring space unit. -->
<!-- Several arrows can be stacked in the same site. -->
<site_multiplicity>3</site_multiplicity>
</space-param>
</parameters>
<!-- Model objects definition -->
<objects id="only dimers in this model" date="time_stamp" author="J">
<object id="a dimer" date="time_stamp" author="J">
<arrow site="1" weight="1" x="0"/>
<arrow site="2" weight="1" x="1"/>
</object>
</objects>
<!-- Saved space description (initial space is sequence 0) -->
<savedstates id="texte" date="time_stamp" author="J">
<state id="initial" date="time_stamp" author="J">
<arrow site="1" weight="1" x="0"/>
<arrow site="2" weight="1" x="1"/>
<arrow site="1" weight="1" x="10"/>
<arrow site="2" weight="1" x="11"/>
<arrow site="1" weight="1" x="20"/>
<arrow site="2" weight="1" x="21"/>
<!-- Three dimers 1-1 are drawn in the global space
at locations (0,1) (10,11) and (20,21) -->
</state>
</savedstates>
<!-- Model transitions definition (rules) -->
<!-- In this version : <xs:sequence minOccurs="0" maxOccurs="unbounded">-->
<!-- Transitions should be edited by hand and written in a 'human-readable' format -->
<conditions_tree>
<condition_anonym site="1" weight="1" x="0">
<condition_anonym site="2" weight="1" x="1">
<condition_anonym site="1" weight="0" x="2">
<transition_anonym id="move_a_dimer_to_east"
date="time_stamp"
author="J"
probability="0.5"/>
<arrow site="1" weight="0" x="0"/>
<arrow site="2" weight="0" x="1"/>
<arrow site="1" weight="1" x="1"/>
<arrow site="2" weight="1" x="2"/>
</condition_anonym>
<condition_anonym site="2" weight="0" x="-1">
<transition_anonym id="move_a_dimer_to_west"
date="time_stamp"
author="J"
probability="0.5"/>
<arrow site="1" weight="0" x="0"/>
<arrow site="2" weight="0" x="1"/>
<arrow site="2" weight="1" x="0"/>
<arrow site="1" weight="1" x="1"/>
</condition_anonym>
</condition_anonym>
</condition_anonym>
</conditions_tree>
<conditionslist id="random walk of dimers" date="time_stamp" author="J">
<condition site="1" weight="1" node_id="1" parent="0" x="0"/>
<condition site="2" weight="1" node_id="2" parent="1" x="1"/>
<!-- as soon as conditions 1 and 2 are satisfied, a dimer is identified at atation (0,1). -->
<condition site="1" weight="0" node_id="3" parent="2" x="2"/>
<!-- as soon as condition 3 is satisfied,
the neighbouring space unit to East of the dimer is empty
and the dimer identified by conditions (1,2) can be moved to East. -->
<condition site="2" weight="0" node_id="4" parent="2" x="-1"/>
<!-- as soon as condition 4 is satisfied,
the neighbouring space unit to West of the dimer is empty
and the dimer identified by conditions (1,2) can be moved to West. -->
</conditionslist>
<transitionslist>
<transition id="move_a_dimer_to_east" date="time_stamp" author="J"
parent="3" probability="1">
<arrow site="1" weight="0" x="0"/>
<arrow site="2" weight="0" x="1"/>
<arrow site="1" weight="1" x="1"/>
<arrow site="2" weight="1" x="2"/>
</transition>
<transition id="move_a_dimer_to_west" date="time_stamp" author="J"
parent="4" probability="1">
<arrow site="1" weight="0" x="0"/>
<arrow site="2" weight="0" x="1"/>
<arrow site="2" weight="1" x="0"/>
<arrow site="1" weight="1" x="1"/>
</transition>
</transitionslist>
</gem-graph-model>

View File

@ -1,194 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- https://www.freeformatter.com/xml-validator-xsd.html -->
<xs:attribute name="id" type="xs:string"/>
<xs:attribute name="node_id" type="xs:integer"/>
<xs:attribute name="parent" type="xs:integer"/>
<xs:attribute name="date" type="xs:integer"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="lang" type="xs:string"/>
<xs:attribute name="owner" type="xs:string"/>
<xs:attribute name="owner_id" type="xs:integer"/>
<xs:attribute name="author" type="xs:string"/>
<xs:attribute name="version" type="xs:float"/>
<xs:attribute name="probability" type="xs:integer"/>
<xs:attribute name="site" type="xs:integer" default="0"/>
<xs:attribute name="weight" type="xs:integer" default="0"/>
<xs:attribute name="u" type="xs:integer"/>
<xs:attribute name="v" type="xs:integer"/>
<xs:attribute name="w" type="xs:integer"/>
<xs:attribute name="x" type="xs:integer"/>
<xs:attribute name="y" type="xs:integer"/>
<xs:attribute name="z" type="xs:integer"/>
<xs:attribute name="t" type="xs:integer"/>
<xs:attributeGroup name="id_date_author">
<xs:attribute ref="id"/>
<xs:attribute ref="date"/>
<xs:attribute ref="author"/>
</xs:attributeGroup>
<xs:element name="g_ref">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attributeGroup ref="id_date_author"/>
<xs:attribute ref="lang" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="quote" substitutionGroup="g_ref"/>
<xs:element name="dimension">
<xs:complexType>
<xs:attribute ref="u" use="optional"/>
<xs:attribute ref="v" use="optional"/>
<xs:attribute ref="w" use="optional"/>
<xs:attribute ref="x" use="optional"/>
<xs:attribute ref="y" use="optional"/>
<xs:attribute ref="z" use="optional"/>
<xs:attribute ref="t" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="arrow">
<xs:complexType>
<xs:attribute ref="site" use="required"/>
<xs:attribute ref="weight" use="required"/>
<xs:attribute ref="u" use="optional"/>
<xs:attribute ref="v" use="optional"/>
<xs:attribute ref="w" use="optional"/>
<xs:attribute ref="x" use="optional"/>
<xs:attribute ref="y" use="optional"/>
<xs:attribute ref="z" use="optional"/>
<xs:attribute ref="t" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="condition">
<xs:complexType>
<xs:attribute ref="site" use="required"/>
<xs:attribute ref="weight" use="required"/>
<xs:attribute ref="node_id" use="required"/>
<xs:attribute ref="parent" use="required"/>
<xs:attribute ref="u" use="optional"/>
<xs:attribute ref="v" use="optional"/>
<xs:attribute ref="w" use="optional"/>
<xs:attribute ref="x" use="optional"/>
<xs:attribute ref="y" use="optional"/>
<xs:attribute ref="z" use="optional"/>
<xs:attribute ref="t" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="state">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element ref="arrow"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="object" substitutionGroup="state"/>
<xs:element name="transition">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element minOccurs="0" ref="quote"/>
<xs:element ref="arrow"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
<xs:attribute ref="parent" use="required"/>
<xs:attribute ref="probability" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="gem-graph-model">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="identity">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="name" type="xs:string"/>
<xs:element name="owner" type="xs:string"/>
<xs:element name="owner_id" type="xs:integer"/>
<xs:element name="date" type="xs:integer"/>
<xs:element name="version" type="xs:float"/>
<xs:element ref="g_ref" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="parameters">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="simulation">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="max_thread" type="xs:integer"/>
<xs:element name="max_cycles" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="space-param">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element ref="dimension"/>
<xs:element name="site_multiplicity" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="objects">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element ref="object"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="savedstates">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element ref="state"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="conditions">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element minOccurs="0" ref="quote"/>
<xs:element ref="condition"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="transitions">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element ref="transition"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute ref="version" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -1,235 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- https://www.freeformatter.com/xml-validator-xsd.html -->
<xs:attribute name="id" type="xs:string"/>
<xs:attribute name="node_id" type="xs:integer"/>
<xs:attribute name="parent" type="xs:integer"/>
<xs:attribute name="date" type="xs:integer"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="lang" type="xs:string"/>
<xs:attribute name="owner" type="xs:string"/>
<xs:attribute name="owner_id" type="xs:integer"/>
<xs:attribute name="author" type="xs:string"/>
<xs:attribute name="version" type="xs:float"/>
<xs:attribute name="probability" type="xs:integer"/>
<xs:attribute name="site" type="xs:integer" default="0"/>
<xs:attribute name="weight" type="xs:integer" default="0"/>
<xs:attribute name="u" type="xs:integer"/>
<xs:attribute name="v" type="xs:integer"/>
<xs:attribute name="w" type="xs:integer"/>
<xs:attribute name="x" type="xs:integer"/>
<xs:attribute name="y" type="xs:integer"/>
<xs:attribute name="z" type="xs:integer"/>
<xs:attribute name="t" type="xs:integer"/>
<xs:attributeGroup name="id_date_author">
<xs:attribute ref="id"/>
<xs:attribute ref="date"/>
<xs:attribute ref="author"/>
</xs:attributeGroup>
<xs:element name="g_ref">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attributeGroup ref="id_date_author"/>
<xs:attribute ref="lang" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="quote" substitutionGroup="g_ref"/>
<xs:element name="dimension">
<xs:complexType>
<xs:attribute ref="u" use="optional"/>
<xs:attribute ref="v" use="optional"/>
<xs:attribute ref="w" use="optional"/>
<xs:attribute ref="x" use="optional"/>
<xs:attribute ref="y" use="optional"/>
<xs:attribute ref="z" use="optional"/>
<xs:attribute ref="t" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="arrow">
<xs:complexType>
<xs:attribute ref="site" use="required"/>
<xs:attribute ref="weight" use="required"/>
<xs:attribute ref="u" use="optional"/>
<xs:attribute ref="v" use="optional"/>
<xs:attribute ref="w" use="optional"/>
<xs:attribute ref="x" use="required"/>
<xs:attribute ref="y" use="optional"/>
<xs:attribute ref="z" use="optional"/>
<xs:attribute ref="t" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="condition">
<xs:complexType>
<xs:attribute ref="site" use="required"/>
<xs:attribute ref="weight" use="required"/>
<xs:attribute ref="node_id" use="required"/>
<xs:attribute ref="parent" use="required"/>
<xs:attribute ref="u" use="optional"/>
<xs:attribute ref="v" use="optional"/>
<xs:attribute ref="w" use="optional"/>
<xs:attribute ref="x" use="required"/>
<xs:attribute ref="y" use="optional"/>
<xs:attribute ref="z" use="optional"/>
<xs:attribute ref="t" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="condition_anonym">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element ref="condition_anonym"/>
</xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element ref="arrow"/>
</xs:sequence>
<xs:attribute ref="site" use="required"/>
<xs:attribute ref="weight" use="required"/>
<xs:attribute ref="u" use="optional"/>
<xs:attribute ref="v" use="optional"/>
<xs:attribute ref="w" use="optional"/>
<xs:attribute ref="x" use="required"/>
<xs:attribute ref="y" use="optional"/>
<xs:attribute ref="z" use="optional"/>
<xs:attribute ref="t" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="state">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element ref="arrow"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="object" substitutionGroup="state"/>
<xs:element name="transition">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element minOccurs="0" ref="quote"/>
<xs:element ref="arrow"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
<xs:attribute ref="parent" use="required"/>
<xs:attribute ref="probability" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="transition_anonym">
<xs:complexType>
<xs:attributeGroup ref="id_date_author"/>
<xs:attribute ref="probability" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="gem-graph-model">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="identity">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="name" type="xs:string"/>
<xs:element name="owner" type="xs:string"/>
<xs:element name="owner_id" type="xs:integer"/>
<xs:element name="date" type="xs:integer"/>
<xs:element name="version" type="xs:float"/>
<xs:element ref="g_ref" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="parameters">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="simulation">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="max_thread" type="xs:integer"/>
<xs:element name="max_cycles" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="space-param">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element ref="dimension"/>
<xs:element name="site_multiplicity" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="objects">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element ref="object"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="savedstates">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element ref="state"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="conditionslist">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element minOccurs="0" ref="quote"/>
<xs:element ref="condition"/>
</xs:sequence>
<xs:attributeGroup ref="id_date_author"/>
</xs:complexType>
</xs:element>
<xs:element name="transitionslist">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element ref="transition"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="conditionstree">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element ref="condition_anonym"/>
</xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element ref="transition_anonym"/>
</xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element ref="arrow"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute ref="version" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -1,32 +0,0 @@
Home:
- Pas de sidebar (inutile)
- Récemment ouverts
- Permettre d'ouvrir directement sans validation (par un "ne pas redemander")
- Logo en grand au centre
Edit:
- Sidebar présente
- Bibliothèques (par stack)
- objets
- conditions/transitions (liées)
- états sauvegardés
- Zone principale
- vue état globale 3D (en haut ou en bas) avec zoom sur localité
- vue édition (avec split) -> vue 3D aussi ? vue schématique ?
- conditions/transitions
- objets
- états
Run:
- Sidebar
- Contrôles
- Vitesse
- Pas à pas
- Avance/Recul/Run/Pause (avec vue buffer)
- Bibliothèques (par stack)
- objets
- conditions/transitions (liées)
- états sauvegardés
- Zone principale
- Vue globale 3D (en haut ou bas)
- Mesures (stats par exemple)

View File

@ -67,76 +67,15 @@ void ui_disable_action(const char *name);
//
// Actions
//
void on_about_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_quit_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_preferences_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_togglesidebar_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_editmode_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_runmode_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_presentmode_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_openfile_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_closefile_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_savefile_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
void on_toast_close_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
static const GActionEntry app_actions[] = {
{ "quit", on_quit_action, NULL, NULL, NULL },
{ "about", on_about_action, NULL, NULL, NULL },
{ "preferences", on_preferences_action, NULL, NULL, NULL },
{ "togglesidebar", on_togglesidebar_action, NULL, NULL, NULL },
{ "editmode", on_editmode_action, NULL, NULL, NULL },
{ "runmode", on_runmode_action, NULL, NULL, NULL },
{ "presentmode", on_presentmode_action, NULL, NULL, NULL },
{ "openfile", on_openfile_action, NULL, NULL, NULL },
{ "closefile", on_closefile_action, NULL, NULL, NULL },
{ "savefile", on_savefile_action, NULL, NULL, NULL },
{ "toastclose", on_toast_close_action, NULL, NULL, NULL },
};
//
// Actions responses
//
void on_openfile_response(GtkNativeDialog *native,
int response,
GemGraphClientWindow *self);
void on_openfile_response_complete(GObject *source_object,
GAsyncResult *result,
GemGraphClientWindow *self);
//
// General events
//

View File

@ -1,402 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xmlreader.h> // http://xmlsoft.org/examples/#parse1.c
#define VRB0 0
#define VRB1 0
#define VRB2 0
#define VRB3 0
#define VRB4 1
// https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/general.html
// make && bin/learning ./data/dimers\ random\ walk.xml
/****** WARNING ! VARIABLES GLOBALES !! ÇA PAS BON !!! > TODO < **********/
xmlDocPtr doc; // ! WARNING ! I TAKE FOR GRANTED THAT xmlDocPtr doc != NULL
xmlHashTable *my_table;
/******************************************************************************/
bool model_init(char *docname)
{
xmlNodePtr node;
doc = xmlParseFile(docname);
if (doc == NULL ) {
fprintf(stderr,"Document not parsed successfully.\n");
return false;
}
node = xmlDocGetRootElement(doc);
if (node == NULL) {
fprintf(stderr,"empty document\n");
xmlFreeDoc(doc);
return false;
}
if (xmlStrcmp(node->name, (xmlChar *) "gem-graph-model")) {
fprintf(stderr,"document of the wrong type, root node != gem-graph-model\n");
xmlFreeDoc(doc);
return false;
}
my_table = xmlHashCreate(10);
printf("-------------------- model_init(%s) -----------------------\n", docname);
/* xmlDocPtr my_tree = xmlReadIO, */
/* xmlInputReadCallback ioread, */
/* xmlInputCloseCallback ioclose, */
/* void * ioctx, */
/* const char * URL, */
/* const char * encoding, */
/* int options); */
return true;
}
/******************************************************************************/
bool model_shutdown(char *docname){
xmlFreeDoc(doc);
printf("-------------------- model_shutdown(%s) -------------------\n", docname);
return false;
}
/******************************************************************************/
static 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 xmlChar* splitStrAtSlash(xmlChar *toSplit){
toSplit = (xmlChar *)xmlStrchr(toSplit, '/');
toSplit = xmlStrsub (toSplit, 1, xmlStrlen(toSplit));
return toSplit;
}
static 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 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;
// Lookup for node from path in hash table
node = xmlHashLookup(my_table, path);
// Found a node in hash table
if(node){
if (VRB0) printf("xmlHashLookup (my_table, path: <%s>, tag: <%s> @>%p)\n",
path, node->name, node);
assert(node > (xmlNodePtr)2048);
return node;
// no node found in hash table
} else {
xmlChar *reste = path, *last = reste, *affich = reste;
last = getLastTag(last);
xmlNodePtr node = xmlDocGetRootElement(doc);
if (VRB1) printf("line n° %lu : tag <%s> reste = %s\n",\
xmlGetLineNo(node), (xmlChar *)node->name, (xmlChar *)affich);
xmlChar *extrait;
while ((ulong)xmlStrchr (reste, '/')){
extrait = getFirstTag(reste); //printf("extrait = %s\n", extrait);
reste = splitStrAtSlash((xmlChar *)reste);//printf("reste = %s\n", reste);
node = node->xmlChildrenNode;
node = getNextChild(node, extrait);
if (VRB1) printf("line n°%lu : tag <%s> reste = %s\n",\
xmlGetLineNo(node), (xmlChar *)extrait, (xmlChar *)reste);
}
if(node != NULL && xmlStrcmp(node->name, last)) {
node = node->xmlChildrenNode;
while (node != NULL && xmlStrcmp(node->name, last)) {
node = node->next;
}
if (VRB1) printf("line n°%lu : tag <%s>\n",\
xmlGetLineNo(node), (xmlChar *)node->name);
xmlHashAddEntry (my_table, path, node);
}
if (VRB0) printf("VRB0 xmlHashAddEntry (my_table, path: <%s>, tag: <%s> @>%p)\n",\
path, node->name, node);
return node;
}
return NULL; // ?
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
static long model_get_node_attrib(xmlNodePtr node)
{
long value = 0;
if (node && node->properties) {
xmlAttr* attribute = node->properties;
xmlChar* value_txt = NULL;
char *ptr;
while(attribute && attribute->name && attribute->children)
{
value_txt = xmlNodeListGetString(node->doc, attribute->children, 1);
value = strtol((char *)value_txt, &ptr, 10);
if (VRB3) printf ("model_get_node_attrib <%s> = %s = %ld\n",\
attribute->name, value_txt, value);
attribute = attribute->next;
}
}
return value;
}
static long model_get_state_arrows_nb(xmlNodePtr node)
{
long arrows_nb= 0;
if (VRB0) printf ("VRB0 model_get_state_arrows_nb <%s> start at line %ld\n",\
node->name, xmlGetLineNo(node));
while (node && node->next){
if (VRB2) printf ("%s %ld >", (xmlChar *)node->name, arrows_nb);
if (!xmlStrcmp(node->name, (xmlChar *)"arrow")) ++arrows_nb;
if (VRB2) printf (" %ld ", arrows_nb);
node = node->next;
}
if (VRB2) printf ("\n");
if (VRB0) printf ("VRB0 model_get_state_arrows_nb = %ld end at line %ld\n",\
arrows_nb, xmlGetLineNo(node));
return arrows_nb;
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
char model_get_dim(xmlChar *path){
xmlNodePtr node = model_get_node(path); if (VRB2) printf("@node = %p ", node);
if (node && node->properties) {
xmlAttr* attribute = node->properties;
while(attribute && attribute->name && attribute->children)
{
xmlChar* value = xmlNodeListGetString(node->doc, attribute->children, 1);
// printf ("model_get_dim %s = %s\n", attribute->name, value);
xmlFree(value);
attribute = attribute->next;
}
}
if (xmlHasProp (node, (xmlChar *) "z")) return 3;
if (xmlHasProp (node, (xmlChar *) "y")) return 2;
if (xmlHasProp (node, (xmlChar *) "x")) return 1;
return 0;
}
int model_get_dim_value(xmlChar *path, xmlChar *axis){
xmlNodePtr node = model_get_node(path);
//xmlNodePtr node= xmlTextReadernoderentNode(reader);
if (node && node->properties) {
xmlAttr* attribute = node->properties;
while(attribute && attribute->name && attribute->children)
{
xmlChar* value = xmlNodeListGetString(node->doc, attribute->children, 1);
if (!xmlStrcmp(attribute->name, axis))
return (int)strtol((char *)value, NULL, 0);
}
}
return 0;
}
char model_get_cond_tree (xmlChar *path){
xmlNodePtr node = model_get_node(path);
node = node->xmlChildrenNode;
node = getNextChild(node, (xmlChar *)"condition");
node = xmlCopyNodeList (node->xmlChildrenNode);
printf("model_get_cond_tree(\"%s\") > line n°%ld\n", path, xmlGetLineNo(node));
return 0;
}
int model_get_cond (xmlChar *path, xmlChar *node_id){
xmlNodePtr node = model_get_node(path);
printf("model_get_cond(...) {...node->name = %s...}\n", node->name);
node = getNextChild(node->next, (xmlChar *)"condition");
node = getNextChild(node->next, (xmlChar *)"condition");
if (xmlHasProp (node, (xmlChar *) "site")) {
printf(" node %s has attribute site\n", node->name);
}
if (xmlHasProp (node, (xmlChar *) "node_id")) {
printf(" node %s has attribute %s with value %hhn %s %s\n",\
node->name,\
xmlHasProp (node, (xmlChar *) "node_id")->name,\
xmlGetProp (node, (xmlChar *) "node_id"),\
(xmlChar *)"?! xmlGetProp is deprecated !",\
(xmlChar *)"");
}
node = getNextChild(node->next, (xmlChar *)"condition");
return 0;
}
long model_get_dim_X (xmlChar *path){
xmlNodePtr node = xmlHashLookup(my_table, (xmlChar *)"get_X");
if(node){
//if (VRB1){
printf("get_X > tag <%s> found in hash table\n",\
node->name); // node->name = "x"
//}
return (long)xmlHashLookup(my_table, (xmlChar *)"get_X"); //TODO
}else{
xmlNodePtr node = model_get_node(path); // node = dimension
if (node && node->properties) {
xmlAttr* attribute = node->properties;
while(attribute && attribute->name && attribute->children)
{
xmlChar* value = xmlNodeListGetString(node->doc, attribute->children, 1);
if (!xmlStrcmp(attribute->name, (xmlChar *)"x")) {
xmlHashAddEntry (my_table, (xmlChar *)"get_X", attribute);
return (int)strtol((char *)value, NULL, 0);
}
}
}
}
return 0;
}
int model_get_dim_Y (xmlChar *path){
printf("model_get_dim_Y(%s)\n", path);
return 0;
}
int model_get_dim_Z (xmlChar *path){
printf("model_get_dim_Z(%s)\n", path);
return 0;
}
int model_get_multiplicity (xmlChar *path){
xmlNodePtr node = model_get_node(path);
if(node) return (int)strtol((char *)xmlNodeGetContent(node), NULL, 0);
return 0;
}
int model_get_objects_list(xmlChar *path){
return xmlGetLineNo(model_get_node(path));
}
xmlChar *model_get_states_list(xmlChar *path){
xmlNodePtr node = model_get_node(path);
return (xmlChar *)xmlNodeGetContent(node);
}
long model_get_state_arrows_count(xmlChar *path, long n){
// Ici, je sais que c'est le 'PREMIER' état qui est demandé car n == 0
char compl[] = "/state/arrow";
char *new_p = calloc(1, (sizeof(compl) + strlen((char *)path)) * sizeof(char));
strcat(new_p, (char *)path);
strcat(new_p + strlen((char *)path), compl); // printf("%s\n", new_p);
xmlNodePtr node = model_get_node((xmlChar *)new_p);
long size = model_get_state_arrows_nb(node);
int dim = model_get_dim((xmlChar *)"parameters/space-param/dimension");
if (VRB0) printf("VRB0 model_get_saved_state(size = %ld)->%p<-attrib dim = %d size = %ld\n",\
size, (xmlNodePtr)model_get_node_attrib(node), dim, size * ( 2 + dim ) * sizeof(int));
int c = 0;
int *t = calloc(1, (size * ( 2 + dim ) * sizeof(int)));
// int rk = 0;
// int *s = calloc(1, ( 2 + dim ) * sizeof(int));
if(1)
{
long arrows_nb= 0;
if (VRB4) printf ("VRB4 model_get_state_arrows_nb <%s> start at line %ld\n",\
node->name, xmlGetLineNo(node));
while (node && node->next){
if (!xmlStrcmp(node->name, (xmlChar *)"arrow")) ++arrows_nb;
if (VRB4 && !xmlStrcmp(node->name, (xmlChar *)"arrow")) printf ("VRB4 %s-%ld ",\
(xmlChar *)node->name, arrows_nb);
if (node && node->properties) {
xmlAttr* attribute = node->properties;
while(attribute)
{
xmlChar* value = xmlNodeListGetString(node->doc, attribute->children, 1);
if (VRB4) printf("v=%s ", value);
*(t + c) = strtol((char*)value, NULL, 0);
++c;
xmlFree(value);
attribute = attribute->next;
}
if (VRB4) printf("\n");
}
node = node->next;
}
if (VRB4) printf ("VRB4 model_get_state_arrows_nb = %ld end at line %ld\n",\
arrows_nb, xmlGetLineNo(node));
if (VRB4) for(int k = 0; k < c; k++) printf("%d ", *(t + k)); printf("\n");
return arrows_nb;
}
return (long) size * ( 2 + dim ) * sizeof(int);
}
int model_get_state(xmlChar *path, xmlChar *state_id){
printf("model_get_state (%s -> %s state)\n", path, state_id);
return 0;
}
int model_get_conditions_list(xmlChar *path){
printf("model_get_conditions_list(%s)\n", path);
return 0;
}
int model_get_transitions_list(xmlChar *path){
printf("model_get_transitions_list(%s)\n", path);
return 0;
}

View File

@ -38,23 +38,6 @@ G_DEFINE_TYPE (GemGraphClientApplication,
static GemGraphClientApplication *application;
/* -------------------------------------------------------------------------- */
void ui_enable_action(const char *name) {
g_simple_action_set_enabled(
(GSimpleAction *)g_action_map_lookup_action(
G_ACTION_MAP(application),
name),
true);
}
void ui_disable_action(const char *name) {
g_simple_action_set_enabled(
(GSimpleAction *)g_action_map_lookup_action(
G_ACTION_MAP(application),
name),
false);
}
/*
* Window actual presentation on screen
*
@ -71,8 +54,6 @@ static void gem_graph_client_application_activate(GApplication *app)
"application", app,
NULL);
ui_set_stack("home");
gtk_window_present(window);
}
@ -91,40 +72,8 @@ static void gem_graph_client_application_init(GemGraphClientApplication *self)
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
"app.quit",
(const char *[]) { "<primary>q", NULL });
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
"app.editmode",
(const char *[]) { "<primary>e", NULL });
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
"app.runmode",
(const char *[]) { "<primary>r", NULL });
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
"app.presentmode",
(const char *[]) { "<primary>p", NULL });
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
"app.savefile",
(const char *[]) { "<primary>s", NULL });
application = self;
//
// Disable unneeded/inoperant actions
//
ui_disable_action("savefile");
ui_disable_action("closefile");
ui_disable_action("editmode");
ui_disable_action("runmode");
ui_disable_action("presentmode");
ui_disable_action("togglesidebar");
}
void ui_send_notification(const char *message)
{
g_print("NOTIFICATION: %s\n", message);
g_application_send_notification(G_APPLICATION(application),
"notification",
g_notification_new(message)
);
}
/* -------------------------------------------------------------------------- */

37
src/ui/bac_a_sable.ui Normal file
View File

@ -0,0 +1,37 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.14.0 -->
<interface>
<!-- interface-name gem-graph.ui -->
<requires lib="gtk" version="4.6"/>
<template class="GemGraphClientWindow" parent="GtkApplicationWindow">
<property name="icon-name">application-x-executable</property>
<property name="title">Bac à sable</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkBox">
<child>
<object class="GtkGLArea" id="run_glarea"/>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="run_controls">
<property name="margin-bottom">50</property>
<property name="margin-top">50</property>
<property name="orientation">horizontal</property>
</object>
</child>
<child>
<object class="GtkBox" id="glarea_controls"/>
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar" id="main_titlebar"/>
</child>
<style>
<class name="devel"/>
</style>
</template>
</interface>

View File

@ -29,163 +29,6 @@
#include "../../include/ui.h"
void on_about_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
static const char *authors[] = { "Adrien Bourmault (neox@a-lec.org)",
"Jean Sirmai (jean@a-lec.org)",
"Arthur Menges (arthur.menges@a-lec.org)",
NULL};
GemGraphClientApplication *self = user_data;
GtkWindow *window = NULL;
g_assert (GEM_GRAPH_CLIENT_IS_APPLICATION(self));
window = gtk_application_get_active_window(GTK_APPLICATION (self));
gtk_show_about_dialog(window,
"program-name", "Gem-graph",
"logo-icon-name", "application-x-executable",
"authors", authors,
"version", "0.1.0",
"copyright", "Copyright © 2023 Libre en Communs",
NULL);
}
void on_quit_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
g_application_quit(G_APPLICATION(self));
}
void on_preferences_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
ui_send_internal_notification("Not implemented !");
}
void on_togglesidebar_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
ui_toggle_sidebar();
}
void on_editmode_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
ui_set_stack("edition");
}
void on_runmode_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
ui_set_stack("run");
}
void on_presentmode_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
ui_set_stack("presentation");
}
void on_openfile_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
// Create a new file selection dialog, using the "open" mode
GtkFileChooserNative *native =
gtk_file_chooser_native_new("Open File",
GTK_WINDOW(self),
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Open",
"_Cancel");
// Connect the "response" signal of the file selection dialog;
// this signal is emitted when the user selects a file, or when
// they cancel the operation
g_signal_connect (native,
"response",
G_CALLBACK(on_openfile_response),
self);
// Present the dialog to the user
gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
}
void on_closefile_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
ui_disable_action("closefile");
ui_disable_action("savefile");
ui_disable_action("runmode");
ui_disable_action("editmode");
ui_disable_action("presentmode");
ui_disable_action("togglesidebar");
ui_set_stack("home");
}
void on_savefile_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
}
void on_toast_close_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
ui_close_internal_notification();
}
/* -------------------------------------------------------------------------- */
/*
@ -228,7 +71,7 @@ void on_realize(GtkWidget *widget)
return;
if (graphics_init(gtk_widget_get_name(widget)) == false) {
ui_send_internal_notification("Failed to allocate GLArea !");
printf("Failed to allocate GLArea !");
}
}
@ -241,10 +84,21 @@ void on_unrealize(GtkWidget *widget)
return;
if (graphics_shutdown(gtk_widget_get_name(widget))) {
ui_send_internal_notification("Failed to allocate GLArea !");
printf("Failed to allocate GLArea !");
}
}
void on_quit_action(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GemGraphClientApplication *self = user_data;
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
g_application_quit(G_APPLICATION(self));
}
void on_close_window(GtkWidget *widget)
{
/* Reset the state */
@ -259,67 +113,3 @@ void on_close_window(GtkWidget *widget)
}
/* -------------------------------------------------------------------------- */
/*
* Responses
*/
void on_openfile_response(GtkNativeDialog *native,
int response,
GemGraphClientWindow *self)
{
g_autoptr(GFile) file;
GtkFileChooser *chooser;
if (response == GTK_RESPONSE_ACCEPT) {
chooser = GTK_FILE_CHOOSER(native);
file = gtk_file_chooser_get_file(chooser);
// Load asynchroneously not to block control flow
g_file_load_contents_async (file,
NULL,
(GAsyncReadyCallback)on_openfile_response_complete,
self);
}
g_object_unref(native);
}
void on_openfile_response_complete(GObject *source_object,
GAsyncResult *result,
GemGraphClientWindow *self)
{
GFile *file = G_FILE(source_object);
g_autofree char *contents = NULL;
gsize length = 0;
g_autoptr(GError) error = NULL;
// Gives you the contents of the file as a byte array, or
// set the error argument
g_file_load_contents_finish(file,
result,
&contents,
&length,
NULL,
&error);
// In case of error, print a warning to the standard error output
if (error != NULL)
{
g_printerr("Unable to open “%s”: %s\n",
g_file_peek_path(file),
error->message);
return;
}
//g_print("File content is :\n%s\n", contents);
ui_enable_action("closefile");
ui_enable_action("savefile");
ui_enable_action("runmode");
ui_enable_action("editmode");
ui_enable_action("presentmode");
ui_enable_action("togglesidebar");
ui_set_stack("run");
}

View File

@ -1,343 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.10.2 -->
<interface>
<!-- interface-name gem-graph.ui -->
<requires lib="gtk" version="4.6"/>
<template class="GemGraphClientWindow" parent="GtkApplicationWindow">
<property name="default-height">900</property>
<property name="default-width">1400</property>
<property name="icon-name">application-x-executable</property>
<property name="title">GemGraph 0.1.0</property>
<style>
<class name="devel"/>
</style>
<child type="titlebar">
<object class="GtkHeaderBar" id="main_titlebar">
<child type="end">
<object class="GtkMenuButton" id="main_button_menu">
<property name="direction">none</property>
<property name="menu-model">main_menu</property>
</object>
</child>
<child type="start">
<object class="GtkMenuButton" id="main_button_mode">
<property name="always-show-arrow">True</property>
<property name="use-underline">True</property>
<property name="tooltip-text" translatable="yes">Change session mode</property>
<property name="icon-name">document-edit-symbolic</property>
<property name="menu-model">mode_menu</property>
</object>
</child>
<child>
<object class="GtkToggleButton" id="main_button_sidebar">
<property name="icon-name">sidebar-show-symbolic</property>
<property name="tooltip-text" translatable="yes">Display/hide sidebar</property>
<property name="action-name">app.togglesidebar</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkOverlay" id="toast_overlay">
<child>
<object class="GtkPaned" id="main_paned">
<property name="position">300</property>
<child>
<object class="GtkStack" id="side_stack">
<child>
<object class="GtkStackPage">
<property name="name">run</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="run_controls">
<property name="margin-top">50</property>
<property name="margin-bottom">50</property>
<property name="orientation">horizontal</property>
<child>
<object class="GtkToggleButton" id="run_play_control">
<property name="icon-name"></property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkStackSwitcher">
<property name="visible">True</property>
<property name="stack">runlib_stack</property>
</object>
</child>
<child>
<object class="GtkStack" id="runlib_stack">
<child>
<object class="GtkStackPage">
<property name="name">runlib_objects</property>
<property name="title" translatable="yes">Objects</property>
<property name="visible">True</property>
<property name="child">
<object class="GtkLabel" id="label_runlib_objects">
<property name="justify">center</property>
<property name="label" translatable="yes">&lt;b&gt;runlib_objects&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="margin-top">50</property>
<property name="margin-bottom">50</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">runlib_conditions_and_rules</property>
<property name="title" translatable="yes">Rules &amp; Conds</property>
<property name="visible">True</property>
<property name="child">
<object class="GtkLabel" id="label_runlib_conditions_and_rules">
<property name="justify">center</property>
<property name="label" translatable="yes">&lt;b&gt;runlib_conditions_and_rules&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="margin-top">50</property>
<property name="margin-bottom">50</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">runlib_states</property>
<property name="title" translatable="yes">Savedstates</property>
<property name="visible">True</property>
<property name="child">
<object class="GtkLabel" id="label_runlib_states">
<property name="justify">center</property>
<property name="label" translatable="yes">&lt;b&gt;runlib_states&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="margin-top">50</property>
<property name="margin-bottom">50</property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">home</property>
<property name="child">
<object class="GtkLabel" id="labelhome">
<property name="justify">center</property>
<property name="label" translatable="yes">&lt;b&gt;Sidebar: home&lt;/b&gt;</property>
<property name="use-markup">True</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">presentation</property>
<property name="child">
<object class="GtkLabel" id="labelsidepresentation">
<property name="justify">center</property>
<property name="label" translatable="yes">&lt;b&gt;Sidebar: presentation mode&lt;/b&gt;</property>
<property name="use-markup">True</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">edition</property>
<property name="child">
<object class="GtkLabel" id="labelsideedit">
<property name="justify">center</property>
<property name="label" translatable="yes">&lt;b&gt;Sidebar: edition mode&lt;/b&gt;</property>
<property name="use-markup">True</property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkStack" id="main_stack">
<child>
<object class="GtkStackPage">
<property name="name">run</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkGlArea" id="run_glarea">
</object>
</child>
<child>
<object class="GtkBox" id="glarea_controls">
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">home</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="vexpand">True</property>
<property name="file">data/hicolor/apps/scalable/gemgraph_désaturé.png</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="margin-bottom">50</property>
<property name="margin-top">00</property>
<property name="justify">center</property>
<property name="valign">center</property>
<property name="label" translatable="yes">&lt;b&gt;Welcome to the Gem-graph client.&lt;/b&gt;</property>
<property name="use-markup">True</property>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">presentation</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkGlArea" id="presentation_glarea">
</object>
</child>
<child>
<object class="GtkBox" id="presentation_controls">
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">edition</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkGlArea" id="edition_glarea">
</object>
</child>
<child>
<object class="GtkBox" id="edition_controls">
</object>
</child>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child type="overlay">
<object class="GtkRevealer" id="toast_revealer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="transition-type">GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN</property>
<child>
<object class="GtkBox" id="toast_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="spacing">20</property>
<child>
<object class="GtkLabel" id="toast_text">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">(null)</property>
</object>
</child>
<child>
<object class="GtkToggleButton" id="toast_close_button">
<property name="icon-name">window-close-symbolic</property>
<property name="action-name">app.toastclose</property>
</object>
</child>
<style>
<class name="app-notification"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
<menu id="main_menu">
<section>
<item>
<attribute name="label" translatable="yes">_Open...</attribute>
<attribute name="action">app.openfile</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Close</attribute>
<attribute name="action">app.closefile</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Save</attribute>
<attribute name="action">app.savefile</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Preferences</attribute>
<attribute name="action">app.preferences</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
<attribute name="action">win.show-help-overlay</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_About GemGraph</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
</menu>
<menu id="mode_menu">
<section>
<attribute name="label" translatable="yes">Switch session mode</attribute>
<item>
<attribute name="icon">document-edit-symbolic</attribute>
<attribute name="label" translatable="yes">_Edition</attribute>
<attribute name="action">app.editmode</attribute>
<attribute name="use-icon">True</attribute>
</item>
<item>
<attribute name="icon">system-run-symbolic</attribute>
<attribute name="label" translatable="yes">_Run</attribute>
<attribute name="action">app.runmode</attribute>
<attribute name="use-icon">True</attribute>
</item>
<item>
<attribute name="icon">video-display-symbolic</attribute>
<attribute name="label" translatable="yes">_Presentation</attribute>
<attribute name="action">app.presentmode</attribute>
<attribute name="use-icon">True</attribute>
</item>
</section>
</menu>
</interface>

View File

@ -45,14 +45,6 @@ struct _GemGraphClientWindow
/* Template widgets */
GtkHeaderBar *main_titlebar;
GtkStack *main_stack;
GtkStack *side_stack;
GtkPaned *main_paned;
GtkMenuButton *main_button_mode;
GtkToggleButton *main_button_sidebar;
GtkRevealer *toast_revealer;
GtkToggleButton *toast_close_button;
GtkLabel *toast_text;
GtkGLArea *run_glarea;
GtkBox *run_controls;
};
@ -70,8 +62,8 @@ static void gem_graph_client_window_class_init(GemGraphClientWindowClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
if (g_file_get_contents("src/ui/gemgraph.ui", &contents, &len, &err) == FALSE)
g_error("error reading gemgraph.ui: %s", err->message);
if (g_file_get_contents("src/ui/bac_a_sable.ui", &contents, &len, &err) == FALSE)
g_error("error reading bac_a_sable.ui: %s", err->message);
bytes = g_bytes_new_take(contents, len);
gtk_widget_class_set_template(GTK_WIDGET_CLASS(klass), bytes);
@ -79,30 +71,6 @@ static void gem_graph_client_window_class_init(GemGraphClientWindowClass *klass)
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
main_titlebar);
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
main_stack);
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
side_stack);
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
main_paned);
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
main_button_mode);
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
main_button_sidebar);
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
toast_revealer);
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
toast_close_button);
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
toast_text);
gtk_widget_class_bind_template_child(widget_class,
GemGraphClientWindow,
run_glarea);
@ -116,88 +84,12 @@ static void gem_graph_client_window_init(GemGraphClientWindow *self)
gtk_widget_init_template(GTK_WIDGET(self));
window = self;
// Launch with sidebar off
ui_toggle_sidebar();
// Setup GLArea
ui_setup_glarea(window->run_glarea, window->run_controls);
}
/* -------------------------------------------------------------------------- */
void ui_set_stack(const char *mode)
{
if (window->main_stack == NULL) {
g_printerr("Can't find self->main_stack !\n");
return;
}
if (window->side_stack == NULL) {
g_printerr("Can't find self->side_stack !\n");
return;
}
gtk_stack_set_visible_child_full(window->main_stack,
mode,
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
gtk_stack_set_visible_child_full(window->side_stack,
mode,
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
// Switch on the first letter of the mode, because switch is soooo simple :)
switch(mode[0]) {
case 'e':
gtk_menu_button_set_icon_name(window->main_button_mode,
"document-edit-symbolic");
break;
case 'r':
gtk_menu_button_set_icon_name(window->main_button_mode,
"system-run-symbolic");
break;
case 'p':
gtk_menu_button_set_icon_name(window->main_button_mode,
"x-office-presentation-symbolic");
break;
case 'h':
gtk_paned_set_position(window->main_paned, 0);
gtk_menu_button_set_icon_name(window->main_button_mode,
"user-home-symbolic");
break;
default:
break;
}
}
void ui_send_internal_notification(const char *message)
{
if (window->toast_revealer == NULL) {
g_printerr("Can't find self->toast_overlay !\n");
return;
}
if (window->toast_text == NULL) {
g_printerr("Can't find self->toast_overlay !\n");
return;
}
gtk_label_set_label(window->toast_text, message);
gtk_revealer_set_reveal_child(window->toast_revealer, true);
}
void ui_close_internal_notification(void)
{
if (window->toast_revealer == NULL) {
g_printerr("Can't find self->toast_overlay !\n");
return;
}
if (window->toast_text == NULL) {
g_printerr("Can't find self->toast_overlay !\n");
return;
}
gtk_revealer_set_reveal_child(window->toast_revealer, false);
}
static inline GtkWidget *create_axis_slider(int axis)
{
GtkWidget *box, *label, *slider;
@ -275,15 +167,3 @@ void ui_setup_glarea(GtkGLArea *target, GtkBox *target_controls)
gtk_gl_area_set_required_version( GTK_GL_AREA(gl_area), minor, major);
gtk_gl_area_get_required_version( GTK_GL_AREA(gl_area), &minor, &major);
}
void ui_toggle_sidebar(void)
{
int position = gtk_paned_get_position(window->main_paned);
if (position != 0) {
gtk_paned_set_position(window->main_paned, 0);
} else {
gtk_paned_set_position(window->main_paned, 400);
}
}