]> gitweb.factorcode.org Git - factor.git/blob - extra/ui/frp/signals/signals.factor
"<$" made generic + moved to monads
[factor.git] / extra / ui / frp / signals / signals.factor
1 USING: accessors arrays kernel models models.product monads
2 sequences sequences.extras ;
3 FROM: models.product => product ;
4 IN: ui.frp.signals
5
6 GENERIC: null-val ( gadget -- model )
7 M: model null-val drop f ;
8
9 TUPLE: multi-model < model important? ;
10 GENERIC: (model-changed) ( model observer -- )
11 : <multi-model> ( models kind -- model ) f swap new-model [ [ add-dependency ] curry each ] keep ;
12 M: multi-model model-changed over value>> [ (model-changed) ] [ 2drop ] if ;
13 M: multi-model model-activated dup dependencies>> [ value>> ] find nip
14    [ swap model-changed ] [ drop ] if* ;
15
16 : #1 ( model -- model' ) t >>important? ;
17
18 IN: models
19 : notify-connections ( model -- )
20     dup connections>> dup [ dup multi-model? [ important?>> ] [ drop f ] if ] find-all
21     [ second tuck [ remove ] dip prefix ] each
22     [ model-changed ] with each ;
23 IN: ui.frp.signals
24
25 TUPLE: basic-model < multi-model ;
26 M: basic-model (model-changed) [ value>> ] dip set-model ;
27 : <merge> ( models -- signal ) basic-model <multi-model> ;
28 : <2merge> ( model1 model2 -- signal ) 2array <merge> ;
29 : <basic> ( value -- signal ) basic-model new-model ;
30
31 TUPLE: filter-model < multi-model quot ;
32 M: filter-model (model-changed) [ value>> ] dip 2dup quot>> call( a -- ? )
33    [ set-model ] [ 2drop ] if ;
34 : <filter> ( model quot -- filter-signal ) [ 1array filter-model <multi-model> ] dip >>quot ;
35
36 TUPLE: fold-model < multi-model quot base values ;
37 M: fold-model (model-changed) 2dup base>> =
38     [ [ [ value>> ] [ [ values>> ] [ quot>> ] bi ] bi* swapd reduce* ] keep set-model ]
39     [ [ [ value>> ] [ values>> ] bi* push ]
40       [ [ [ value>> ] [ [ value>> ] [ quot>> ] bi ] bi* call( val oldval -- newval ) ] keep set-model ] 2bi
41     ] if ;
42 M: fold-model model-activated drop ;
43 : new-fold-model ( deps -- model ) fold-model <multi-model> V{ } clone >>values ;
44 : <fold> ( model oldval quot -- signal ) rot 1array new-fold-model swap >>quot
45    swap >>value ;
46 : <fold*> ( model oldmodel quot -- signal ) over [ [ 2array new-fold-model ] dip >>quot ]
47     dip [ >>base ] [ value>> >>value ] bi ;
48
49 TUPLE: updater-model < multi-model values updates ;
50 M: updater-model (model-changed) tuck updates>> =
51    [ [ values>> value>> ] keep set-model ]
52    [ drop ] if ;
53 : <updates> ( values updates -- signal ) [ 2array updater-model <multi-model> ] 2keep
54    [ >>values ] [ >>updates ] bi* ;
55
56 SYMBOL: switch
57 TUPLE: switch-model < multi-model original switcher on ;
58 M: switch-model (model-changed) 2dup switcher>> =
59    [ [ value>> ] dip over switch = [ nip [ original>> ] keep f >>on model-changed ] [ t >>on set-model ] if ]
60    [ dup on>> [ 2drop ] [ [ value>> ] dip over [ set-model ] [ 2drop ] if ] if ] if ;
61 : <switch> ( signal1 signal2 -- signal' ) swap [ 2array switch-model <multi-model> ] 2keep
62    [ [ value>> >>value ] [ >>original ] bi ] [ >>switcher ] bi* ;
63 M: switch-model model-activated [ original>> ] keep model-changed ;
64 : >behavior ( event -- behavior ) t <model> <switch> ;
65
66 TUPLE: mapped-model < multi-model model quot ;
67 : new-mapped-model ( model quot class -- mapped-model ) [ over 1array ] dip
68    <multi-model> swap >>quot swap >>model ;
69 : <mapped> ( model quot -- signal ) mapped-model new-mapped-model ;
70 M: mapped-model (model-changed)
71     [ [ value>> ] [ quot>> ] bi* call( old -- new ) ] [ nip ] 2bi
72     set-model ;
73
74 TUPLE: side-effect-model < mapped-model ;
75 M: side-effect-model (model-changed) [ value>> ] dip [ quot>> call( old -- ) ] 2keep set-model ;
76
77 : $> ( model quot -- signal ) side-effect-model new-mapped-model ;
78
79 TUPLE: quot-model < mapped-model ;
80 M: quot-model (model-changed) nip [ quot>> call( -- b ) ] keep set-model ;
81 M: model <$ quot-model new-mapped-model ;
82
83 TUPLE: action-value < basic-model parent ;
84 : <action-value> ( parent value -- model ) action-value new-model swap >>parent ;
85 M: action-value model-activated dup parent>> dup activate-model model-changed ; ! a fake dependency of sorts
86
87 TUPLE: action < multi-model quot ;
88 M: action (model-changed) [ [ value>> ] [ quot>> ] bi* call( a -- b ) ] keep value>>
89    [ swap add-connection ] 2keep model-changed ;
90 : <action> ( model quot -- action-signal ) [ 1array action <multi-model> ] dip >>quot dup f <action-value> >>value value>> ;
91
92 TUPLE: | < multi-model ;
93 : <|> ( models -- product ) | <multi-model> ;
94 GENERIC: models-changed ( product -- )
95 M: | models-changed drop ;
96 M: | model-changed
97     nip
98     dup dependencies>> [ value>> ] all?
99     [ [ dup [ value>> ] product-value swap set-model ] keep models-changed ]
100     [ drop ] if ;
101 M: | model-activated dup model-changed ;
102
103 TUPLE: & < | ;
104 : <&> ( models -- product ) & <multi-model> ;
105 M: & models-changed dependencies>> [ [ null-val ] keep (>>value) ] each ;
106
107 ! for side effects
108 TUPLE: (frp-when) < multi-model quot cond ;
109 : frp-when ( model quot cond -- model ) rot 1array (frp-when) <multi-model> swap >>cond swap >>quot ;
110 M: (frp-when) (model-changed) [ quot>> ] 2keep
111     [ value>> ] [ cond>> ] bi* call( a -- ? ) [ call( model -- ) ] [ 2drop ] if ;
112
113 M: model fmap <mapped> ;
114 USE: ui.frp.functors
115 FMAPS: $> <$ fmap FOR & | product ;
116
117 ! only used in construction
118 : with-self ( quot: ( model -- model ) -- model ) [ f <basic> dup ] dip call swap [ add-dependency ] keep ; inline