aboutsummaryrefslogtreecommitdiff
path: root/tut11_3_2_stopwatch.icl
blob: 5d5a4519ed93854fad22d5897f40841071cd02b4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
implementation module tut11_3_2_stopwatch

// ********************************************************************************
// Clean tutorial example program.
//
// This program defines a stopwatch process component.
// It uses three timers to track the seconds, minutes, and hours separately.
// Message passing is used to reset, pause, and continue timing.
// The current time is displayed using a dialogue.
// ********************************************************************************

import StdEnv,StdIO

:: DialogIds = {secondsId :: Id, minutesId :: Id, hoursId :: Id}
:: TimerInfo = {timerId :: Id, timerRId :: RId StopwatchCommands, timerInterval :: TimerInterval}
:: StopwatchCommands = Reset | Pause | Continue | Close

second :== ticksPerSecond
minute :== 60 * second
hour   :== 60 * minute

openDialogIds :: *env -> (DialogIds,*env) | Ids env
openDialogIds env
# ([secondsId, minutesId, hoursId:_],env) = openIds 3 env
= ({secondsId=secondsId, minutesId=minutesId, hoursId=hoursId}, env)

openTimerInfos :: *env -> ([TimerInfo], *env) | Ids env
openTimerInfos env
# (tids, env)       = openIds 3 env
# (rids, env)       = openRIds 3 env
# intervals         = [second, minute, hour]
= ([{timerId=tid, timerRId=rid, timerInterval=i} \\ tid <- tids & rid <- rids & i <- intervals], env)

stopwatch :: (RId StopwatchCommands) -> Process
stopwatch rid = Process NDI Void initialise` []
where
    initialise` pst
    # (dialogIds, pst)  = accPIO openDialogIds pst
    # (timerInfos, pst) = accPIO openTimerInfos pst
    = initialise rid dialogIds timerInfos pst

initialise :: (RId StopwatchCommands) DialogIds [TimerInfo] (PSt .l) -> PSt .l
initialise rid {secondsId, minutesId, hoursId} timerInfos pst
# (errors, pst)     = seqList [openTimer 0 (tdef timerInfo) \\ timerInfo <- timerInfos] pst
| any ((<>) NoError) errors = closeProcess pst
# (error, pst)      = openDialog Void ddef pst
| error <> NoError  = closeProcess pst
# (error, pst)      = openReceiver Void rdef pst
| error <> NoError  = closeProcess pst
| otherwise         = pst
where
    tdef {timerId, timerRId, timerInterval} = Timer timerInterval (Receiver timerRId receive []) [TimerId timerId, TimerFunction tick]
    where
        tick nrElapsed (time, pst=:{io})
        # time      = (time + nrElapsed) rem maxunit
        # io        = setControlText textId (toString time) io
        = (time, {pst & io = io})

        receive Reset (time, pst=:{io})
        # io        = disableTimer timerId io
        # io        = enableTimer timerId io
        # io        = setControlText textId "00" io
        = (0, {pst & io = io})
        receive Pause (time, pst=:{io}) = (time, {pst & io = disableTimer timerId io})
        receive Continue (time, pst=:{io}) = (time, {pst & io = enableTimer timerId io})

        (textId, maxunit) = if (timerInterval == second) (secondsId, 60)
                           (if (timerInterval == minute) (minutesId, 60)
                                                         (hoursId, 24))

    ddef = Dialog "Stopwatch" (LayoutControl (ListLS [TextControl text [ControlPos (Left, zero)] \\ text <- ["Hours:","Minutes:","Second:"]]) [] :+:
                                LayoutControl (ListLS [TextControl "0" [ControlPos (Left, zero), ControlId id, ControlWidth (ContentWidth "00")] \\ id <- [hoursId, minutesId, secondsId]]) []) [WindowClose (noLS closeProcess)]

    rdef = Receiver rid (noLS1 receive) []
    where
        receive Close pst = closeProcess pst
        receive msg pst = snd (seqList [syncSend timerRId msg \\ {timerRId} <- timerInfos] pst)