2012-11-04 1 views
8

Je recherche une librairie pour écrire une interface graphique sur GLFW et OpenGL. Je le fais parce que je suis insatisfait des liens de la bibliothèque de l'interface utilisateur commune qui me semblent trop impératifs, et je voudrais également un contrôle strict de l'aspect et de la convivialité de mes interfaces utilisateur. Je voudrais une approche déclarative pour définir les interfaces utilisateur. J'expérimente avec la banane réactive (et temporairement réactif-banane-wx) pour voir si elle répond à mes besoins. J'ai un problème avec la définition de widgets récursifs. Voici mon cas de test le plus simple:Gestion de widgets GUI récurrents avec Reactive-banana

  • Un widget de texte qui affiche un compteur.
  • Un widget de bouton qui incrémente le compteur.
  • Un widget bouton qui est inactif (de sorte qu'il est grisé et ne répond pas à l'entrée du tout) lorsque le compteur est égal à 0 et autrement actif et remet le compteur à 0.

Le premier et le troisième un widget avoir une relation récursive. Le premier widget est intuitivement un stepper d'un union d'événements alimentés à partir des deux boutons. Cependant, le bouton de réinitialisation est un fmap du compteur, puis le flux d'événements repose sur le bouton de réinitialisation! Qu'y a-t-il à faire? Au-delà de cette question, je m'inquiète de la gestion des événements: Puisque je veux gérer les entrées et les entrées de mon code au lieu de me fier à un framework, je vois des difficultés à répartir correctement les événements de manière échelonnable. Idéalement, je définirais un data qui encapsule la structure hiérarchique d'un widget, un moyen d'installer des rappels d'événements entre les éléments, puis d'écrire une fonction qui traverse cette structure de données afin de définir le traitement d'entrée du périphérique et la sortie graphique. Je ne suis pas sûr de savoir comment prendre un flux d'événements et le diviser aussi facilement que les flux d'événements peuvent être fusionnés.

Répondre

5

La récursivité est autorisée, à condition qu'elle soit récurrente entre Behavior et Event. La bonne chose à propos de Behavior s est que leur échantillonnage au moment d'une mise à jour va retourner l'ancienne valeur.

Par exemple, votre exemple peut être exprimée comme suit

eClick1, eClick2 :: Event t() 

bCounter :: Behavior t Int 
bCounter = accumB 0 $ mconcat [eIncrement, eReset] 

eIncrement = (+1)  <$ eClick1 
eReset  = (const 0) <$ whenE ((> 0) <$> bCounter) eClick2 

Voir aussi la question "Can reactive-banana handle cycles in the network?"


Quant à votre deuxième question, vous semblez être à la recherche de la fonction filterE et son cousins ​​ et whenE? En ce qui concerne votre objectif global, je pense que c'est assez ambitieux. De la petite expérience que j'ai acquise jusqu'à présent, il me semble que la liaison à un cadre existant est très différente de la création d'un cadre «d'état propre» dans le PRF. Très probablement, il y a encore des abstractions non découvertes (mais passionnantes!) Cachées là. J'ai une fois commencé à écrire une application appelée BlackBoard qui contient une belle abstraction sur les dessins variant dans le temps. Cependant, si vous vous souciez davantage du résultat plutôt que de l'aventure, je vous recommande une approche conservatrice: créez le toolkit GUI dans un style impératif et accrochez reactive-banana en plus de cela pour obtenir les avantages de FRP.

Dans le cas où vous souhaitez simplement toute interface graphique, je me concentre actuellement sur le navigateur Web en tant que GUI. Voici quelques preliminary experiments with Ji. Le principal avantage par rapport à wxHaskell est qu'il est beaucoup plus facile de démarrer et que tout effort de conception d'API bénéficiera à un très large public.

+0

Et si vous êtes dans la monade d'événement? Je m'inquiétais car il n'avait pas MonadFix pour la récursion de valeur, de sorte que cette même récursivité ne pouvait pas être exprimée en présence de changement d'événement dynamique. Certes, je ne suis toujours pas entièrement à l'aise avec tous les exemples publics. – danharaj

+0

Quant à ma deuxième question: 'filterE' et al. travailler dans la mauvaise direction pour l'évolutivité, je pense. Ils tirent d'un événement, et cela semble lourd. Dites, par exemple, nous avons une structure arborescente de widgets gui avec un curseur pour la mise au point du clavier. Nous voulons transformer les événements 'eDeviceInput' en événements basés sur ce curseur. Avec 'filterE', chaque flux d'événement destinataire devrait exécuter son propre filtre sur l'arbre des widgets et aussi savoir où il se trouve dans l'arbre, ce qui rend les transformations de disposition et la commutation d'événements dynamiques lourdes. – danharaj

+0

Le type 'Event' n'est pas une monade. Vous voulez probablement dire la monade 'Moment '? C'est une instance de 'MonadFix' comme vous pouvez vous y attendre. –

Questions connexes