Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible bug: Updating visibility of dynamically created content #143

Open
archaephyrryx opened this issue Jan 2, 2017 · 2 comments
Open

Comments

@archaephyrryx
Copy link

This may be just a usage error on my part, but I am noticing a strange phenomenon when trying to set up conditional visibility/layout for dynamically created UI elements (in WX of course). As somewhat of a toy-example, I tried to create a widget that created StaticText elements on the fly and allowed the user to "browse" through these elements through '<' '>' buttons. Here is the code I have at this point, which exhibits the problem.

{-# LANGUAGE RecursiveDo #-}

module Test.Adder where

import Reactive.Banana
import Reactive.Banana.WX
import Graphics.UI.WX.Attributes
import Graphics.UI.WX hiding (Event, newEvent, empty, Identity)
import Graphics.UI.WXCore hiding (Event, Timer, empty, Identity, newEvent)
import Graphics.UI.WXCore.Frame

-- | Combine Unit-Events
anyEvent :: [Event ()] -> Event ()
anyEvent = foldl1 (unionWith (\_ _ -> ()))

-- | Unsugared if-then-else function
if_ :: Bool -> a -> a -> a
if_ True x _ = x
if_ False _ y = y

-- | Apply a function to the value at an index, or return a default value
-- if the index is out of range
(!?) :: (a -> b) -> b -> Int -> ([a] -> b)
(f!? ~y) n xs
  | n < 0 = y
  | otherwise = case drop n xs of
                  x:_ -> f x
                  [] -> y

main :: IO ()
main = start test


create :: Window w -> Int -> Behavior Int -> Event Int -> Event () -> MomentIO (StaticText ())
create t i bi ei eRef = do
  let tx = replicate i '\t' ++ show i

  x <- liftIO $ staticText t [ text := tx ]

  let beq = (==i) <$> bi

  let eMe = filterE (==i) ei

  sink x [ visible :== beq ]
  reactimate (refresh x <$ anyEvent [ eRef, () <$ eMe ])
  return x

test :: IO ()
test = do
    f <- frame [text := "Test"]

    add <- button f [ text := "+" ]

    prv <- button f [ text := "<" ]
    cur <- staticText f []
    nxt <- button f [ text := ">" ]

    tab <- panel f [ clientSize := sz 200 300 ]
    deb <- staticText f []
    ref <- button f [ text := "refresh" ]


    let networkDescription :: MomentIO ()
        networkDescription = mdo
                eAdd <- event0 add command
                eRef <- event0 ref command

                let bNotFirst = (>0) <$> bCur
                    bNotLast  = (<) <$> bCur <*> bNext

                sink prv [ enabled :== bNotFirst ]
                sink cur [ text :== show <$> bCur ]
                sink nxt [ enabled :== bNotLast ]

                ePrev <- event0 prv command
                eNext <- event0 nxt command

                let eDelta :: Enum n => Event (n -> n)
                    eDelta = unions [ pred <$ whenE bNotFirst ePrev
                                    , succ <$ whenE bNotLast  eNext ]
                    eChange = flip ($) <$> bCur <@> eDelta

                bCur <- stepper 0 $ eChange

                (eIndex, bCount) <- mapAccum 0 ((\x -> (x, succ x)) <$ eAdd)

                let bView = (\n i -> if_ (n==0) (0) i) <$> bCount <*> bCur
                    bNext = pred <$> bCount
                    eCreate = (\n -> create tab n bView eChange $ anyEvent [eRef,eAdd]) <$> eIndex

                reCreate <- execute eCreate

                bItemer <- accumB id $ flip (.) . (:) <$> reCreate
                let bItems = ($[]) <$> bItemer
                    bThis = (widget!?(nullLayouts!!0)) <$> bCur <*> bItems

                sink tab [ layout :== bThis ]
                liftIO $ set f [ layout := column 5 [ margin 10 $ row 5 [ widget add
                                                                        , widget prv
                                                                        , widget cur
                                                                        , widget nxt
                                                                        , widget ref
                                                                        ]
                                                    , fill $ widget tab
                                                    ]
                               ]

    network <- compile networkDescription
    actuate network


The problem I am noting is that all labels are invisible until a new one is created, at which point the current widget in focus becomes visible. Whether this is a bug or just a paradigm I am misusing, or a subtlety with reactive frameworks, I am unsure as to how to resolve this.

@HeinrichApfelmus
Copy link
Owner

(Sorry for taking so long to respond. I'll take a look, but I'm a bit swamped right now. If you post it on StackOverflow. tag reactive-banana, somebody else may chime in as well.)

@mitchellwrosen
Copy link
Collaborator

I'm not familiar with wx code, so I can't really read this example, but I do have a hunch =)

Is it possible you are rendering a frame at the moment you expect a "visible" behavior to change, when actually the behavior changes slightly after the event that triggered its change a la stepper/accumB?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants