2013-03-24 18:08:48 +00:00
|
|
|
module Graphics.Input where
|
2013-09-03 03:37:39 +00:00
|
|
|
{-| This module is for creating standard input widgets such as buttons and
|
2014-02-17 16:38:37 +00:00
|
|
|
text fields. All functions in this library follow this general pattern:
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
-- (Signal (), SignalID ())
|
|
|
|
(clicks, clickID) = input ()
|
2013-09-03 02:28:52 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
clickableYogi : Element
|
|
|
|
clickableYogi = clickable clickID () (image 40 40 "/yogi.jpg")
|
|
|
|
```
|
2013-09-03 02:28:52 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
Whenever the user clicks on the resulting `clickableYogi` element, it sends a
|
|
|
|
`()` to the `clicks` signal. Typically, you would create all your input signals
|
|
|
|
when setting up the signal graph, so then your graphics code can refer to them
|
|
|
|
easily.
|
2013-09-03 02:28:52 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
# Creating Inputs
|
|
|
|
@docs input
|
2013-09-03 02:28:52 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
# Basic Input Elements
|
|
|
|
Text fields come later.
|
|
|
|
@docs button, customButton, checkbox, dropDown
|
2013-09-03 02:28:52 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
# Clicks and Hovers
|
|
|
|
@docs clickable, hoverable
|
2013-09-03 02:28:52 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
# Text Fields
|
|
|
|
@docs field, password, email, noContent, FieldContent, Selection, Direction
|
2013-09-03 02:28:52 +00:00
|
|
|
-}
|
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
import Signal (Signal)
|
2013-09-03 03:37:39 +00:00
|
|
|
import Graphics.Element (Element)
|
2014-02-17 19:58:10 +00:00
|
|
|
import Native.Graphics.Input
|
2013-09-03 03:37:39 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
data SignalID a = SignalID
|
2013-03-25 02:29:32 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
{-| This function is the key to using this library. It creates a signal that
|
|
|
|
input elements (buttens, checkboxes, etc.) can report to. It also create a
|
|
|
|
unique `SignalID` that allows input elements to refer to this particular
|
|
|
|
signal. It may be best to look at examples in the rest of the docs and return
|
|
|
|
to this function.
|
2013-09-03 02:28:52 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
Note: creating an input signal is an inherently imperative action, so this is
|
|
|
|
one of very few impure functions in Elm. It is designed such that it can only
|
|
|
|
be used as you build your signal graph at startup, keeping Elm pure at runtime.
|
2013-09-03 02:28:52 +00:00
|
|
|
-}
|
2014-02-17 16:38:37 +00:00
|
|
|
input : a -> (Signal a, SignalID a)
|
|
|
|
input = Native.Graphics.Input.input
|
2013-03-24 18:08:48 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
{-| Create a standard button. The following example begins making a basic
|
|
|
|
calculator:
|
2013-03-24 18:08:48 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
data Input = Number Int | Plus | Minus | Clear
|
|
|
|
|
|
|
|
-- (Signal Input, SignalID Input)
|
|
|
|
(calcInput, pressID) = input Clear
|
|
|
|
|
|
|
|
buttons : Element
|
|
|
|
buttons =
|
|
|
|
flow right [ button pressID (Number 1) "1"
|
|
|
|
, button pressID (Number 2) "2"
|
|
|
|
, button pressID Plus "+"
|
|
|
|
]
|
|
|
|
|
|
|
|
If the user presses the "plus" button, the `calcInput` signal will update to
|
|
|
|
`Plus`. If the users presses "2", `calcInput` will update to `(Number 2)`.
|
2013-09-03 02:28:52 +00:00
|
|
|
-}
|
2014-02-17 16:38:37 +00:00
|
|
|
button : SignalID a -> a -> String -> Element
|
|
|
|
button = Native.Graphics.Input.button
|
|
|
|
|
|
|
|
customButton : SignalID a -> a -> Element -> Element -> Element -> Element
|
|
|
|
customButton = Native.Graphics.Input.customButton
|
|
|
|
|
|
|
|
checkbox : SignalID a -> (Bool -> a) -> Bool -> Element
|
2014-02-17 19:58:10 +00:00
|
|
|
checkbox = Native.Graphics.Input.checkbox
|
2014-02-17 16:38:37 +00:00
|
|
|
|
|
|
|
{-| Create a drop-down menu. The following drop-down lets you choose your
|
|
|
|
favorite British sport:
|
|
|
|
|
|
|
|
data Sport = Football | Cricket | Snooker
|
|
|
|
|
|
|
|
-- (Signal (Maybe Sport), SignalID (Maybe Sport))
|
|
|
|
(dropStatus, dropID) = input Nothing
|
|
|
|
|
|
|
|
sportDropDown : Element
|
|
|
|
sportDropDown =
|
|
|
|
dropDown dropID
|
|
|
|
[ ("" , Nothing)
|
|
|
|
, ("Football", Just Football)
|
|
|
|
, ("Cricket" , Just Cricket)
|
|
|
|
, ("Snooker" , Just Snooker)
|
|
|
|
]
|
|
|
|
|
|
|
|
If the user selects "Football" from the drop down menue, the `dropStatus`
|
|
|
|
signal will update to `Just Football`.
|
2013-09-03 02:28:52 +00:00
|
|
|
-}
|
2014-02-17 16:38:37 +00:00
|
|
|
dropDown : SignalID a -> [(String,a)] -> Element
|
|
|
|
dropDown = Native.Graphics.Input.dropDown
|
|
|
|
|
|
|
|
{-| Detect mouse hovers over a specific `Element`. In the following example,
|
|
|
|
we will create a hoverable picture called `cat`.
|
|
|
|
|
|
|
|
-- (Signal Bool, SignalID Bool)
|
|
|
|
(hover, hoverID) = input False
|
|
|
|
|
|
|
|
cat : Element
|
|
|
|
cat = image 30 30 "/cat.jpg"
|
|
|
|
|> hoverable hoverID (\hover -> hover)
|
|
|
|
|
|
|
|
When the mouse hovers above the `cat` element, the `hover` signal will become
|
|
|
|
`True`. When the mouse leaves it, `hover` will become `False`.
|
2013-09-03 02:28:52 +00:00
|
|
|
-}
|
2014-02-17 16:38:37 +00:00
|
|
|
hoverable : SignalID a -> (Bool -> a) -> Element -> Element
|
|
|
|
hoverable = Native.Graphics.Input.hoverable
|
|
|
|
|
|
|
|
{-| Detect mouse clicks on a specific `Element`. In the following example,
|
|
|
|
we will create a clickable picture called `cat`.
|
2013-06-15 07:49:22 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
data Picture = Cat | Hat
|
2013-06-15 07:49:22 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
-- (Signal Picture, SignalID Picture)
|
|
|
|
(click, clickID) = input Cat
|
2013-09-03 02:28:52 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
cat : Element
|
|
|
|
cat = image 30 30 "/cat.jpg"
|
|
|
|
|> clickable clickID Cat
|
|
|
|
|
|
|
|
hat : Element
|
|
|
|
hat = image 30 30 "/hat.jpg"
|
|
|
|
|> clickable clickID Hat
|
|
|
|
|
|
|
|
When the user clicks on the `cat` element, the `click` signal receives
|
|
|
|
an update containing the value `Cat`. When the user clicks on the `hat` element,
|
|
|
|
the `click` signal receives an update containing the value `Hat`. This lets you
|
|
|
|
distinguish which element was clicked. In a more complex example, they could be
|
|
|
|
distinguished with IDs or more complex data structures.
|
|
|
|
-}
|
|
|
|
clickable : SignalID a -> a -> Element -> Element
|
|
|
|
clickable = Native.Graphics.Input.clickable
|
|
|
|
|
|
|
|
{-| Represents the current content of a text field. For example:
|
|
|
|
|
|
|
|
FieldContent "She sells sea shells" (Selection 0 3 Backward)
|
2013-09-03 02:28:52 +00:00
|
|
|
|
|
|
|
This means the user highlighted the substring `"She"` backwards.
|
|
|
|
-}
|
2014-02-17 16:38:37 +00:00
|
|
|
type FieldContent = { string:String, selection:Selection }
|
|
|
|
|
|
|
|
{-| The selection within a text field. `start` is never greater than `end`:
|
|
|
|
|
|
|
|
Selection 0 0 Forward -- cursor precedes all characters
|
|
|
|
|
|
|
|
Selection 5 9 Backward -- highlighting characters starting after
|
|
|
|
-- the 5th and ending after the 9th
|
2013-09-03 02:28:52 +00:00
|
|
|
-}
|
2014-02-17 16:38:37 +00:00
|
|
|
type Selection = { start:Int, end:Int, direction:Direction }
|
2013-03-24 18:42:17 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
{-| The direction of selection.-}
|
|
|
|
data Direction = Forward | Backward
|
2013-09-03 02:28:52 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
{-| A field with no content:
|
|
|
|
|
|
|
|
FieldContent "" (Selection 0 0 Forward)
|
2013-09-03 02:28:52 +00:00
|
|
|
-}
|
2014-02-17 16:38:37 +00:00
|
|
|
noContent : FieldContent
|
|
|
|
noContent = FieldContent "" (Selection 0 0 Forward)
|
|
|
|
|
|
|
|
{-| Create a text field. The following example creates a time-varying element
|
|
|
|
called `nameField`. As the user types their name, the field will be updated
|
|
|
|
to match what they have entered.
|
2013-05-06 09:30:11 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
-- (Signal FieldContent, SignalID FieldContent)
|
|
|
|
(nameContent,nameID) = input noContent
|
|
|
|
|
|
|
|
nameField : Signal Element
|
|
|
|
nameField = field nameID (\content -> content) "Name" <~ nameContent
|
2013-09-03 02:28:52 +00:00
|
|
|
-}
|
2014-02-17 16:38:37 +00:00
|
|
|
field : SignalID a -> (FieldContent -> a) -> String -> FieldContent -> Element
|
|
|
|
field = Native.Graphics.Input.field
|
2013-03-24 18:42:17 +00:00
|
|
|
|
2013-09-03 02:28:52 +00:00
|
|
|
{-| Same as `field` but the UI element blocks out each characters. -}
|
2014-02-17 16:38:37 +00:00
|
|
|
password : SignalID a -> (FieldContent -> a) -> String -> FieldContent -> Element
|
|
|
|
password = Native.Graphics.Input.password
|
2013-04-01 07:35:18 +00:00
|
|
|
|
2013-09-03 02:28:52 +00:00
|
|
|
{-| Same as `field` but it adds an annotation that this field is for email
|
|
|
|
addresses. This is helpful for auto-complete and for mobile users who may
|
|
|
|
get a custom keyboard with an `@` and `.com` button.
|
|
|
|
-}
|
2014-02-17 16:38:37 +00:00
|
|
|
email : SignalID a -> (FieldContent -> a) -> String -> FieldContent -> Element
|
|
|
|
email = Native.Graphics.Input.email
|
2013-05-23 10:44:57 +00:00
|
|
|
|
2014-02-17 16:38:37 +00:00
|
|
|
-- area : SignalID a -> (FieldContent -> a) -> SignalID b -> ((Int,Int) -> b) -> (Int,Int) -> String -> FieldContent -> Element
|
|
|
|
-- area = Native.Graphics.Input.area
|