on b00a8cb help sign in
199 lines 7.4 kB history raw
1module Graphics.Input where
3{-| This module is for creating standard input widgets such as buttons and
4text boxes. In general, functions in this library return a signal representing
5events from the user.
7The simplest inputs are *one-way inputs*, meaning the user can update
8them, but the programmer cannot. If you need to update an input from
9within the program you want the slightly more complex *two-way inputs*.
10This document will always show the one-way inputs first, *then* the
11two-way inputs.
13# Buttons
14@docs button, customButton, buttons, customButtons
16# Fields
17@docs field, password, email, fields, FieldState, emptyFieldState
19# Checkboxes
20@docs checkbox, checkboxes
22# Drop Downs
23@docs stringDropDown, dropDown
25# Mouse Hover
26@docs hoverable, hoverables
27-}
29import Basics (String)
30import Signal (Signal,lift,dropRepeats)
31import Native.Graphics.Input
32import List
33import Graphics.Element (Element)
34import Maybe (Maybe)
35import JavaScript (JSString)
37id x = x
39{-| Create a group of buttons.
41 * The first argument is the default value of the `events` signal.
42 * The `events` signal represents all of the activity in this group
43 of buttons.
44 * The `button` function creates a button
45 with the given name, like “Submit” or “Cancel”.
46 The `a` value is sent to `events` whenever the button is pressed.
47-}
48buttons : a -> { events : Signal a,
49 button : a -> String -> Element }
50buttons = Native.Graphics.Input.buttons
52{-| Create a button with a given label. The result is an `Element` and
53a signal of units. This signal triggers whenever the button is pressed.
54-}
55button : String -> (Element, Signal ())
56button txt =
57 let pool = buttons ()
58 in (pool.button () txt, pool.events)
60{-| Create a group of custom buttons.
62 * The first argument is the default value of the `events` signal.
63 * The `events` signal represents all of the activity in this group
64 of custom buttons.
65 * The `customButton` function creates a button with three different visual
66 states, one for up, hovering, and down. The resulting button has dimensions
67 large enough to fit all three possible `Elements`.
68 The `a` value is sent to `events` whenever the button is pressed.
69-}
70customButtons : a -> { events : Signal a,
71 customButton : a -> Element -> Element -> Element -> Element }
72customButtons = Native.Graphics.Input.customButtons
74{-| Create a button with custom states for up, hovering, and down
75(given in that order). The result is an `Element` and a signal of
76units. This signal triggers whenever the button is pressed.
77-}
78customButton : Element -> Element -> Element -> (Element, Signal ())
79customButton up hover down =
80 let pool = customButtons ()
81 in (pool.customButton () up hover down, pool.events)
83{-| Create a group of checkboxes.
85 * The first argument is the default value of the `events` signal.
86 * The `events` signal represents all of the activity in this group
87 of checkboxes.
88 * The `checkbox` function creates a
89 checkbox with a given state. The `(Bool -> a)` function is used
90 when the checkbox is modified. It takes the new state and turns
91 it into a value that can be sent to `events`. For example, this
92 lets you add an ID to distinguish between checkboxes.
93-}
94checkboxes : a -> { events : Signal a,
95 checkbox : (Bool -> a) -> Bool -> Element }
96checkboxes = Native.Graphics.Input.checkboxes
98{-| Create a checkbox with a given start state. Unlike `button`, this
99result is a *signal* of elements. That is because a checkbox has state
100that updates based on user input. The boolean signal represents the
101current state of the checkbox.
102-}
103checkbox : Bool -> (Signal Element, Signal Bool)
104checkbox b =
105 let cbs = checkboxes b
106 in (lift (cbs.checkbox id) cbs.events, cbs.events)
108{-| Detect when the mouse is hovering over some elements. This
109allows you to create and destroy elements dynamically and still
110detect hover information.
111-}
112hoverables : a -> { events : Signal a,
113 hoverable : (Bool -> a) -> Element -> Element }
114hoverables = Native.Graphics.Input.hoverables
116{-| Detect when the mouse is hovering over a specific `Element`. -}
117hoverable : Element -> (Element, Signal Bool)
118hoverable elem =
119 let pool = hoverables False
120 in (pool.hoverable id elem, pool.events)
122{-| Represents the current state of a text field. The `string` represents the
123characters filling the text field. The `selectionStart` and `selectionEnd`
124values represent what the user has selected with their mouse or keyboard.
125For example:
127 { string="She sells sea shells", selectionStart=3, selectionEnd=0 }
129This means the user highlighted the substring `"She"` backwards.
130-}
131type FieldState = { string:String, selectionStart:Int, selectionEnd:Int }
133{-| Create a group of text input fields.
135 * The first argument is the default value of the `events` signal.
136 * The `events` signal represents all of the activity in this group
137 of text fields.
138 * The `field` function creates a
139 field with the given ghost text and initial field state.
140 When the field is modified, the `(FieldState -> a)` function
141 takes the new state and turns
142 it into a value that can be sent to `events`. For example, this
143 lets you add an ID to distinguish between input fields.
144-}
145fields : a -> { events : Signal a,
146 field : (FieldState -> a) -> String -> FieldState -> Element }
147fields = Native.Graphics.Input.fields
149{-| The empty field state:
151 { string="", selectionStart=0, selectionEnd=0 }
152-}
153emptyFieldState : FieldState
154emptyFieldState = { string="", selectionStart=0, selectionEnd=0 }
156{-| Create a field with the given default text. The output is an element
157that updates to match the user input and a signal of strings representing
158the content of the field.
159-}
160field : String -> (Signal Element, Signal String)
161field placeHolder =
162 let tfs = fields emptyFieldState
163 changes = dropRepeats tfs.events
164 in (lift (tfs.field id placeHolder) changes,
165 dropRepeats (lift .string changes))
167{-| Same as `field` but the UI element blocks out each characters. -}
168password : String -> (Signal Element, Signal String)
169password placeHolder =
170 let tfs = Native.Graphics.Input.passwords emptyFieldState
171 changes = dropRepeats tfs.events
172 in (lift (tfs.field id placeHolder) changes,
173 dropRepeats (lift .string changes))
175{-| Same as `field` but it adds an annotation that this field is for email
176addresses. This is helpful for auto-complete and for mobile users who may
177get a custom keyboard with an `@` and `.com` button.
178-}
179email : String -> (Signal Element, Signal String)
180email placeHolder =
181 let tfs = Native.Graphics.Input.emails emptyFieldState
182 changes = dropRepeats tfs.events
183 in (lift (tfs.field id placeHolder) changes,
184 dropRepeats (lift .string changes))
186{-| Create a drop-down menu. When the user selects a string,
187the current state of the drop-down is set to the associated
188value. This lets you avoid manually mapping the string onto
189functions and values.
190-}
191dropDown : [(String,a)] -> (Signal Element, Signal a)
192dropDown = Native.Graphics.Input.dropDown
194{-| Create a drop-down menu for selecting strings. The resulting
195signal of strings represents the string that is currently selected.
196-}
197stringDropDown : [String] -> (Signal Element, Signal String)
198stringDropDown strs =
199 dropDown (List.map (\s -> (s,s)) strs)