Et salut à tous !
J'avais envie de présenter ce projet depuis un moment sans en trouver le temps; je me suis lancé dans un petit projet pour progresser un peut en rust, un genre de QML.
Je l'ai appelé RML avec beaucoup d'humidité.
Le rendu est fait grâce à macroquad (que je recommande, c'est vraiment ultra complet comme lib de rendu 2D [et même 3D]).
Pour le cœur j'ai fait un arena tree pour stocker les noeuds de mon ihm, avec quelques méthodes métiers, un système de propriétés abstraites, un système d'events (je remap d'ailleurs les events système dedans) et enfin une bonne grosse macro pour parser mon DSL.
Le DSL supporte la déclaration d'élements (Rectangle, Text, Node, MouseArea), la définitions de signaux, de callback, de fonctions et de propriétés (qui peuvent être initialisées par des fonctions ou par des valeurs). On peut aussi importer des composants depuis un répertoire contenant des .rml .
Pour les callback et les fonctions, je n'ai pas implémenté de langage interprété, c'est du rust natif, avec une petite transformation (un peu bancale) pour passer d'une notation $noeud.propriété.
Pour positionner les éléments, on a le choix entre du positionnement relatif au parent (en modifiant x et y), ou bien via un système d'ancre et de marges.
C'est très loin de ce que propose Slint, Ribir, ou bien son inspiration, le QML bien sur.
Mais je me suis presque étonné de voir qu'avec au final assez peu de code, on pouvait obtenir un truc relativement fonctionnel.
Voilà ce que ça donne :
let mut engine = rml!(
import "components" as UI
Node {
id: root
anchors: fill
text: "Please don't hit my button!"
signal click
on_click: {
$.root.text = "outch!".to_string();
}
Rectangle {
anchors: fill
margins: 10
color: { GRAY }
}
Text {
anchors: center
text: { $.root.text }
color: { WHITE }
font_size: 16
}
UI::Button {
id: test_btn
anchors: center | bottom
margins: 20
text: "Click me!"
on_click: {
emit!(engine, root, click);
}
}
}
);
Bref, voilà le lien : https://github.com/aldebaranzbradaradjan/rml
Si une bonne âme qui s'y connaît en DSL et macro Rust veut bien me donner un coup de main c'est là dessus que j'ai fait le code le plus sale.
La macro en elle même est relativement propre, mais je passe par des phases de transformation en chaîne de caractères et il y a pas mal de limitations.
J'espère que vous trouverez le projet sympa, moi je me suis bien amusé à le développer !
+++
# Application
Posté par abriotde (site web personnel, Mastodon) . Évalué à 3 (+2/-0).
Je préfère l'intro de ton Readme : "RML is a simple DSL for creating 2D GUIs in Rust" parce que Markup Langage ça sert a rien ;)
Mais sinon, certes le projet est aujourd'hui très basique (peu puissant) mais au fond si je comprends bien c'est une ré-implémentation en Rust de QML (Sans toutes les fonctionnalités pour le moment bien sûr), ce que ne propose pas les alternatives que tu cite non? Si c'est le cas, il pourrait avoir un bel avenir. Je suis sûr qu'il y a des applications Qt/QML à porter en Rust. Aujourd'hui le plus simple c'est le binding de QML depuis Rust mais c'est sans la sécurité de Rust. C'est un peu comme mettre une super alarme mais laisser ton or dans une caisse en bois (ou l'inverse un super coffre fort mais sans surveillance). Tout le travail de migration pour un résultat en mi-teinte.
Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.
[^] # Re: Application
Posté par Aldebaran (site web personnel) . Évalué à 2 (+1/-0).
Salut; oui je suis pas au point sur le nom on est d'accord ;)
Alors pour répondre à ta question, oui et non, c'est fortement inspiré du QML, mais la syntaxe est différente et il n'y a pas de js.
À la limite ça peut servir de base pour une qml en rust, mais c'est un taf terrible pour la compatibilité.
Slint par exemple de mon point de vue, remplis vachement mieux cet objectif. Là non plus on est pas sur du QML, mais ça reste proche, et surtout ça fonctionne bien.
[^] # Re: Application
Posté par abriotde (site web personnel, Mastodon) . Évalué à 3 (+2/-0).
Le nom est plutôt pas mal (avec le jeu de mot). C'est l'introduction que je trouves peu explicite, pour quelqu'un qui ne connaitrais pas QML. Un Markup Language, pourquoi faire?
Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.
[^] # Re: Application
Posté par Aldebaran (site web personnel) . Évalué à 1 (+0/-0).
Bah à la base j'y pensais comme au markup language dans HTML;
Et je pensais que QML venait de là (Qt Markup Language), mais en fait c'est Qt Meta-object Language… Donc bon…
QML reste un langage à balise après, DSL c'est un peu plus ouvert encore, ça peut englober tout et n'importe quoi.
Mais si tu as des propositions de nom ou de signification de l’acronyme je suis ouvert au truc ;)
# Voir aussi
Posté par nud . Évalué à 5 (+3/-0).
Le langage Slint créé pour la librairie du même nom, écrite en Rust aussi par un autre linuxfrien.
[^] # Re: Voir aussi
Posté par Gof (site web personnel) . Évalué à 5 (+3/-0).
Oui c'est moi! Je suis un des créateurs de Slint.
Slint est effectivement très similaire.
Bon travail, j’applaudis.
En effet c'est assez limitant car cela signifie que quand il y a une erreur dans la macro RML, le message d'erreur ne pointe pas à la ligne en question.
Il faut essayer de ne pas sérialiser dans un string mais de garder les token d'origin avec leur Span associé. En particulier pour le code en Rust incrusté dans la macro.
[^] # Re: Voir aussi
Posté par Aldebaran (site web personnel) . Évalué à 2 (+1/-0).
Ah merci Gof ;)
En passant et si ça n'est pas clair, je ne veux en aucun cas faire une concurrence de quoi que ce soit avec Slint (de toute façon Slint est à des années lumière de mon machin), c'est vraiment par jeu et pour comprendre comment ça marche que je fais ça.
En fait la macro s'occupe de 99% du parsing et je la trouve assez lisible; mais je n'ai pas trouvé mieux que de faire une opération en string pour traduire ma notation $element.property en rust classique;
J'ai une méthode transform_dollar_notation(), qui essaye de faire le taf, mais comme elle est appliquée avant la macro elle doit "deviner" le type des propriété concernées, pour les cas limites (l'initialisation par callback par exemple) ou je n'arrive pas à deviner facilement le type, j'ai une notation :
$root.value = $test.testValue:f32; <= ça permet à ma méthode de déterminer que testValue doit être castée en f32.
C'est un peu dommage, parce que mon abstract value "sait" de quel type elle est, mais je ne pense pas qu'il me soit possible de faire une fonction get qui retourne des type différents, même pas une proc macro; et ça se comprend hein.
Sinon j'ai pensé à générer des structures à la fin de mon code de macro (une par noeud d'ihm) pour servir d'accesseur / setter et remplacer ma notation, avec des champs correspondants à mes propriétés, et des getter / setter.
Genre :
struct root {
value : f32
}
struct test {
testValue: f32
}
Pour pouvoir écrire :
root.value = test.testValue; <= et ça reste du rust classique au final
Mais la partie synchro avec mon engine est un peu lourdingue; soit je passe par des méthodes prégénérées (get / set; et du coup la syntaxe devient root.set_value(test.get_testValue); classique) soit je trouve le moyen de redéfinir le comportement de l'accesseur et du = en rust; soit je resynchronise toutes mes structs avec mon back à chaque boucle d’évènement.
Et je pense que je dois toujours déterminer au préalable le type de mes propriétés, et du coup je me tate à rendre leur type obligatoire à la déclaration.
Comme ça :
Node {
id: root
number value: 0.
}
Ça serait le plus simple pour s'assurer du type de mes propriétés.
J'ai bien essayé de lire le code de Slint, pour voir comment ça fonctionne, mais le code de macro doit être trop bien écrit, ça a l'air tellement simple et naturel que je ne rencontre aucunes des problématiques qui sont les miennes :)
Si tu as des idées ou des pistes concernant mes interrogations je serais ravi de les entendre, ça me ferait plaisir d'avoir l'avis de quelqu'un qui sait ce qu'il fait !
Et sinon pas de soucis, je comprend si tu as autre chose à faire, comme par exemple t'occuper de Slint ;)
Envoyer un commentaire
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.