2012-11-04 14 views
8

Wybieram bibliotekę do pisania GUI na wierzchu GLFW i OpenGL. Robię to, ponieważ jestem niezadowolony z typowych powiązań biblioteki UI, które uważam za zbyt konieczne, a także chciałbym ścisłej kontroli wyglądu i sposobu działania moich interfejsów. Chciałbym deklaratywne podejście do definiowania interfejsów użytkownika. Eksperymentuję z reaktywnym bananem (i tymczasowo reaktywnym bananem-wx), aby sprawdzić, czy spełnia on moje potrzeby. Mam problem z definiowaniem rekurencyjnych widgetów. Oto mój najprostszy przypadek testowy:Obsługa wzajemnie rekurencyjnych widgetów GUI z reaktywnym bananem

  • Widżet tekstowy wyświetlający licznik.
  • Widget przycisku, który zwiększa licznik.
  • Widget przycisk, który nie jest aktywny (a więc jest on nieaktywny i nie reaguje na wejście w ogóle), gdy licznik jest 0, a inaczej aktywne i resetuje licznik do 0.

Pierwszy i trzeci widget mieć relację rekurencyjną. Pierwszy widżet intuicyjnie jest stepper ze zdarzeń podanych z dwóch przycisków. Jednak przycisk resetowania to fmap licznika, a następnie strumień zdarzeń opiera się na przycisku resetowania! Co należy zrobić?

Poza tym pytaniem mam obawy dotyczące obsługi zdarzeń: ponieważ chcę obsługiwać wprowadzanie danych wejściowych urządzenia i wprowadzanie fokusów w ramach mojego kodu, zamiast polegać na strukturze, widzę trudności naprzód w prawidłowym rozsyłaniu zdarzeń w skalowalny sposób. Idealnie zdefiniowałbym data, który hermetyzuje strukturę hierarchiczną widgetu, sposób instalowania wywołań zdarzeń między elementami, a następnie zapisuje funkcję, która przechodzi przez tę strukturę danych w celu zdefiniowania przetwarzania wejściowego urządzenia i wyników graficznych. Nie wiem, jak wziąć strumień wydarzeń i podzielić go tak łatwo, jak można połączyć strumienie zdarzeń.

Odpowiedz

5

Rekursja jest dozwolona, ​​o ile jest to wzajemna rekurencja między Behavior i Event. Dobrą rzeczą w przypadku Behavior s jest to, że próbkowanie ich w czasie aktualizacji zwróci starą wartość.

Na przykład, Twój przykład można wyrazić następująco

eClick1, eClick2 :: Event t() 

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

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

Zobacz także zapytania "Can reactive-banana handle cycles in the network?"


Co do drugiego pytania, to wydaje się szuka funkcji filterE i jej kuzyni filterApply i whenE?


Co do ogólnego celu, myślę, że jest dość ambitny. Z dotychczasowych doświadczeń, wydaje mi się, że wiązanie się z istniejącymi ramami wydaje się zupełnie inne niż stworzenie "czystego stanu" w FRP. Najprawdopodobniej kryją się tam nieodkryte (ale ekscytujące!) Abstrakcje. Kiedyś zacząłem pisać aplikację o nazwie BlackBoard, która zawiera ładną abstrakcję na temat rysunków zmieniających się w czasie. Jeśli jednak zależy ci raczej na wyniku, a nie na przygodzie, poleciłbym konserwatywne podejście: stwórz zestaw narzędzi GUI w imperatywnym stylu i nałóż na niego reaktywny banan, aby uzyskać korzyści z FRP.

Jeśli chcesz tylko dowolny GUI, obecnie koncentruję się na przeglądarce jako GUI. Oto niektóre preliminary experiments with Ji. Główną korzyścią w stosunku do wxHaskell jest to, że o wiele łatwiej jest zacząć działać, a wszelkie działania projektowe interfejsu API przyniosą korzyści szerokiemu gronu odbiorców.

+0

Co zrobić, jeśli jesteś w monady wydarzenie? Byłem zaniepokojony, ponieważ nie ma MonadFix dla rekursji wartości, więc ta sama rekurencja nie mogła być wyrażona w obecności dynamicznego przełączania zdarzeń. To prawda, że ​​nadal nie do końca jestem zadowolony ze wszystkich publicznych przykładów. – danharaj

+0

Co do mojego drugiego pytania: 'filterE' et al. pracuję w niewłaściwym kierunku, jeśli chodzi o skalowalność, jak sądzę. Wyciągają z wydarzenia, a to wydaje się uciążliwe. Załóżmy na przykład, że mamy drzewiastą strukturę widżetów GUI z kursorem dla fokusa klawiatury. Chcemy zmienić zdarzenia 'eDeviceInput' na zdarzenia oparte na tym kursorze. Z 'filterE', każdy strumień zdarzeń odbiorca będzie musiał wykonać swój własny filtr na drzewie widget, a także wiedzieć, gdzie to jest w drzewie, dzięki przekształceniom układ i dynamiczne zdarzenie przełączania kłopotliwe. – danharaj

+0

Typ "zdarzenia" nie jest monadą. Prawdopodobnie masz na myśli monadę 'Moment'? Jest to instancja 'MonadFix', jak można się spodziewać. –

Powiązane problemy