

Almost every application needs to communicate with the user in some way.
Therefore, a substantial part of the code deals with the interaction
of program logic with GUI components.

Typically, the following is needed:

 put values into input fields under program control
 read and check input from the user
 pop up dialogs to query the user for further information


Task

For a minimal "application", write a program that presents a form with three components to the user:

 a numeric input field ("Value") 
 a button ("increment")
 a button ("random")


The field is initialized to zero.

The user may manually enter a new value into the field,
or increment its value with the "increment" button.

Entering a non-numeric value should be either impossible,
or issue an error message.

Pressing the "random" button presents a confirmation dialog,
and resets the field's value to a random value if the answer is "Yes".

(This task may be regarded as an extension of the task Simple windowed application).



import Graphics.UI.WX
import System.Random
 
main :: IO ()
main = start $ do
    frm   <- frame [text := "Interact"]
    fld   <- textEntry frm [text := "0", on keyboard := checkKeys]
    inc   <- button frm [text := "increment", on command := increment fld]
    ran   <- button frm [text := "random", on command := (randReplace fld frm)]
    set frm [layout := margin 5 $ floatCentre $ column 2
            [centre $ widget fld, row 2 [widget inc, widget ran]]]
 
increment :: Textual w => w -> IO ()
increment field = do
    val <- get field text
    when ((not . null) val) $ set field [text := show $ 1 + read val]
 
checkKeys :: EventKey -> IO ()
checkKeys (EventKey key _ _) =
    when (elem (show key) $ "Backspace" : map show [0..9]) propagateEvent
 
randReplace :: Textual w => w -> Window a -> IO ()
randReplace field frame = do
    answer <- confirmDialog frame "Random" "Generate a random number?" True
    when answer $ getStdRandom (randomR (1,100)) >>= \num ->
                  set field [text := show (num :: Int)]