on 9df2eac help sign in
231 lines 7.5 kB history raw
1module Graphics.Input where
2{-| This module is for creating standard input widgets such as buttons and
3text fields. All functions in this library follow a general pattern in which
4you create an `Input` that many elements can report to:
6```haskell
7clicks : Input ()
8clicks = input ()
10clickableYogi : Element
11clickableYogi = clickable clicks.handle () (image 40 40 "/yogi.jpg")
12```
14Whenever the user clicks on the resulting `clickableYogi` element, it sends an
15update to the `clicks` input. You will see this pattern again and again in
16examples in this library, so just read on to get a better idea of how it works!
18# Creating Inputs
19@docs Input, input
21# Basic Input Elements
22Text fields come later.
23@docs button, customButton, checkbox, dropDown
25# Clicks and Hovers
26@docs clickable, hoverable
28# Text Fields
29@docs field, password, email, noContent, FieldContent, Selection, Direction
30-}
32import Signal (Signal)
33import Graphics.Element (Element)
34import Native.Graphics.Input
36{-| This is the key abstraction of this library. An `Input` is a record
37of two fields:
39 1. `signal` — all values coming to this input from “the world”
40 2. `handle` — a way to refer to this particular input and send it values
42This will make more sense as you see more examples.
43-}
44type Input a = { signal : Signal a, handle : Handle a }
46data Handle a = Handle
48{-| This creates a new `Input`. You provide a single argument that will serve
49as the initial value of the input’s `signal`. For example:
51 numbers : Input Int
52 numbers = input 42
54The initial value of `numbers.signal` is 42, and you will be able
55to pipe updates to the input using `numbers.handle`.
57Note: This is an inherently impure function. Specifically, `(input ())` and
58`(input ())` are actually two different inputs with different signals and handles.
59-}
60input : a -> Input a
61input = Native.Graphics.Input.input
63{-| Create a standard button. The following example begins making a basic
64calculator:
66 data Keys = Number Int | Plus | Minus | Clear
68 keys : Input Keys
69 keys = input Clear
71 calculator : Element
72 calculator =
73 flow right [ button keys.handle (Number 1) "1"
74 , button keys.handle (Number 2) "2"
75 , button keys.handle Plus "+"
76 ]
78If the user presses the "+" button, `keys.signal` will update to `Plus`. If the
79users presses "2", `keys.signal` will update to `(Number 2)`.
80-}
81button : Handle a -> a -> String -> Element
82button = Native.Graphics.Input.button
84{-| Same as `button` but lets you customize buttons to look however you want.
86 click : Input ()
87 click = input ()
89 prettyButton : Element
90 prettyButton =
91 customButton click.handle
92 (image 100 40 "/button_up.jpg")
93 (image 100 40 "/button_hover.jpg")
94 (image 100 40 "/button_down.jpg")
95-}
96customButton : Handle a -> a -> Element -> Element -> Element -> Element
97customButton = Native.Graphics.Input.customButton
99{-| Create a checkbox. The following example creates three synced checkboxes:
101 check : Input Bool
102 check = input False
104 boxes : Bool -> Element
105 boxes checked =
106 let box = container 40 40 middle (checkbox check.handle id checked)
107 in flow right [ box, box, box ]
109 main : Signal Element
110 main = boxes <~ check.signal
111-}
112checkbox : Handle a -> (Bool -> a) -> Bool -> Element
113checkbox = Native.Graphics.Input.checkbox
115{-| Create a drop-down menu. The following drop-down lets you choose your
116favorite British sport:
118 data Sport = Football | Cricket | Snooker
120 sport : Input Sport
121 sport = input Nothing
123 sportDropDown : Element
124 sportDropDown =
125 dropDown sport.handle
126 [ ("" , Nothing)
127 , ("Football", Just Football)
128 , ("Cricket" , Just Cricket)
129 , ("Snooker" , Just Snooker)
130 ]
132If the user selects "Football" from the drop down menue, `sport.signal`
133will update to `Just Football`.
134-}
135dropDown : Handle a -> [(String,a)] -> Element
136dropDown = Native.Graphics.Input.dropDown
138{-| Detect mouse hovers over a specific `Element`. In the following example,
139we will create a hoverable picture called `cat`.
141 hover : Input Bool
142 hover = input False
144 cat : Element
145 cat = image 30 30 "/cat.jpg"
146 |> hoverable hover.handle id
148When the mouse hovers above the `cat` element, `hover.signal` will become
149`True`. When the mouse leaves it, `hover.signal` will become `False`.
150-}
151hoverable : Handle a -> (Bool -> a) -> Element -> Element
152hoverable = Native.Graphics.Input.hoverable
154{-| Detect mouse clicks on a specific `Element`. In the following example,
155we will create a clickable picture called `cat`.
157 data Picture = Cat | Hat
159 picture : Input Picture
160 picture = input Cat
162 cat : Element
163 cat = image 30 30 "/cat.jpg"
164 |> clickable picture.handle Cat
166 hat : Element
167 hat = image 30 30 "/hat.jpg"
168 |> clickable picture.handle Hat
170When the user clicks on the `cat` element, `picture.signal` receives
171an update containing the value `Cat`. When the user clicks on the `hat` element,
172`picture.signal` receives an update containing the value `Hat`. This lets you
173distinguish which element was clicked. In a more complex example, they could be
174distinguished with IDs or more complex data structures.
175-}
176clickable : Handle a -> a -> Element -> Element
177clickable = Native.Graphics.Input.clickable
179{-| Represents the current content of a text field. For example:
181 FieldContent "She sells sea shells" (Selection 0 3 Backward)
183This means the user highlighted the substring `"She"` backwards.
184-}
185type FieldContent = { string:String, selection:Selection }
187{-| The selection within a text field. `start` is never greater than `end`:
189 Selection 0 0 Forward -- cursor precedes all characters
191 Selection 5 9 Backward -- highlighting characters starting after
192 -- the 5th and ending after the 9th
193-}
194type Selection = { start:Int, end:Int, direction:Direction }
196{-| The direction of selection.-}
197data Direction = Forward | Backward
199{-| A field with no content:
201 FieldContent "" (Selection 0 0 Forward)
202-}
203noContent : FieldContent
204noContent = FieldContent "" (Selection 0 0 Forward)
206{-| Create a text field. The following example creates a time-varying element
207called `nameField`. As the user types their name, the field will be updated
208to match what they have entered.
210 name : Input FieldContent
211 name = input noContent
213 nameField : Signal Element
214 nameField = field name.handle id "Name" <~ name.signal
215-}
216field : Handle a -> (FieldContent -> a) -> String -> FieldContent -> Element
217field = Native.Graphics.Input.field
219{-| Same as `field` but the UI element blocks out each characters. -}
220password : Handle a -> (FieldContent -> a) -> String -> FieldContent -> Element
221password = Native.Graphics.Input.password
223{-| Same as `field` but it adds an annotation that this field is for email
224addresses. This is helpful for auto-complete and for mobile users who may
225get a custom keyboard with an `@` and `.com` button.
226-}
227email : Handle a -> (FieldContent -> a) -> String -> FieldContent -> Element
228email = Native.Graphics.Input.email
230-- area : Handle a -> (FieldContent -> a) -> Handle b -> ((Int,Int) -> b) -> (Int,Int) -> String -> FieldContent -> Element
231-- area = Native.Graphics.Input.area