on fa132ea help sign in
elk/libraries/Graphics/Element.elm
267 lines 9.3 kB history raw
2module Graphics.Element (widthOf, heightOf, sizeOf,
3 width, height, size, opacity, color, tag, link,
4 image, fittedImage, croppedImage, tiledImage,
5 flow, up, down, left, right, inward, outward,
6 above, below, beside, layers,
7 container, absolute, relative,
8 middle, topLeft, topRight, bottomLeft, bottomRight,
9 midLeft, midRight, midTop, midBottom, middleAt,
10 topLeftAt, topRightAt, bottomLeftAt, bottomRightAt,
11 midLeftAt, midRightAt, midTopAt, midBottomAt,
12 spacer, newElement, Three, Pos, ElementPrim, Properties
13 ) where
15import open Basics
16import Native.Utils as Native
17import open JavaScript
18import List as List
19import Color (Color)
20import Maybe (Maybe, Just, Nothing)
22type Properties = {
23 id : Int,
24 width : Int,
25 height : Int,
26 opacity : Float,
27 color : Maybe Color,
28 href : JSString,
29 tag : JSString,
30 hover : ()
31 }
33type Element = { props : Properties, element : ElementPrim }
35-- Get the width of an Element
36widthOf : Element -> Int
37widthOf e = e.props.width
39-- Get the height of an Element
40heightOf : Element -> Int
41heightOf e = e.props.height
43-- Get the width and height of an Element
44sizeOf : Element -> (Int,Int)
45sizeOf e = (e.props.width, e.props.height)
47-- Create an `Element` with a given width.
48width : Int -> Element -> Element
49width nw e = let p = e.props
50 props = case e.element of
51 Image _ w h _ -> {p| height <- h `div` w * nw }
52 RawHtml html -> {p| height <- let (w,h) = Native.htmlHeight nw html in h}
53 _ -> p
54 in { element=e.element, props={ props | width <- nw } }
56-- Create an `Element` with a given height.
57height : Int -> Element -> Element
58height nh e = let p = e.props
59 props = case e.element of
60 Image _ w h _ -> {p| width <- w `div` h * nh }
61 _ -> p
62 in { element=e.element, props={p| height <- nh} }
64-- Create an `Element` with a new width and height.
65size : Int -> Int -> Element -> Element
66size w h e = height h (width w e)
68-- Create an `Element` with a given opacity. Opacity is a number between 0 and 1
69-- where 0 means totally clear.
70opacity : Float -> Element -> Element
71opacity o e = let p = e.props in { element=e.element, props={p| opacity <- o} }
73-- Create an `Element` with a given background color.
74color : Color -> Element -> Element
75color c e = let p = e.props in
76 { element = e.element
77 , props = { p | color <- Just c}
78 }
80-- Create an `Element` with a tag. This lets you link directly to it.
81-- The element `(tag "all-about-badgers" thirdParagraph)` can be reached
82-- with a link lik this: `/facts-about-animals.elm#all-about-badgers`
83tag : String -> Element -> Element
84tag name e = let p = e.props in
85 { element=e.element, props={p | tag <- fromString name} }
87-- Create an `Element` that is a hyper-link.
88link : String -> Element -> Element
89link href e = let p = e.props in
90 { element=e.element, props={p | href <- fromString href} }
92emptyStr = fromString ""
93newElement w h e =
94 { props = Properties (Native.guid ()) w h 1 Nothing emptyStr emptyStr (), element = e }
96data ElementPrim
97 = Image ImageStyle Int Int JSString
98 | Container Position Element
99 | Flow Direction [Element]
100 | Spacer
101 | RawHtml JSString
102 | Custom -- for custom Elements implemented in JS, see collage for example
104data ImageStyle = Plain | Fitted | Cropped (Int,Int) | Tiled
106-- Create an image given a width, height, and image source.
107image : Int -> Int -> String -> Element
108image w h src = newElement w h (Image Plain w h (fromString src))
110-- Create a fitted image given a width, height, and image source.
111-- This will crop the picture to best fill the given dimensions.
112fittedImage : Int -> Int -> String -> Element
113fittedImage w h src = newElement w h (Image Fitted w h (fromString src))
115-- Create a cropped image. Take a rectangle out of the picture starting
116-- at the given top left coordinate. If you have a 140-by-140 image,
117-- the following will cut a 100-by-100 square out of the middle of it.
118--
119-- croppedImage (20,20) 100 100 "yogi.jpg"
120croppedImage : (Int,Int) -> Int -> Int -> String -> Element
121croppedImage pos w h src =
122 newElement w h (Image (Cropped pos) w h (fromString src))
124tiledImage : Int -> Int -> String -> Element
125tiledImage w h src =
126 newElement w h (Image Tiled w h (fromString src))
128data Three = P | Z | N
129data Pos = Absolute Int | Relative Float
130type Position = { horizontal : Three, vertical : Three, x : Pos, y : Pos }
132-- Put an element in a container. This lets you position the element really
133-- easily, and there are tons of ways to set the `Position`.
134-- To center `element` exactly in a 300-by-300 square you would say:
135--
136-- container 300 300 middle element
137--
138-- By setting the color of the container, you can create borders.
139container : Int -> Int -> Position -> Element -> Element
140container w h pos e = newElement w h (Container pos e)
142-- Create an empty box. This is useful for getting your spacing right and
143-- for making borders.
144spacer : Int -> Int -> Element
145spacer w h = newElement w h Spacer
147data Direction = DUp | DDown | DLeft | DRight | DIn | DOut
149-- Have a list of elements flow in a particular direction.
150-- The `Direction` starts from the first element in the list.
151--
152-- flow right [a,b,c]
153--
154-- +---+---+---+
155-- | a | b | c |
156-- +---+---+---+
157flow : Direction -> [Element] -> Element
158flow dir es =
159 let ws = List.map widthOf es
160 hs = List.map heightOf es
161 newFlow w h = newElement w h (Flow dir es)
162 in
163 if es == [] then spacer 0 0 else
164 case dir of
165 DUp -> newFlow (List.maximum ws) (List.sum hs)
166 DDown -> newFlow (List.maximum ws) (List.sum hs)
167 DLeft -> newFlow (List.sum ws) (List.maximum hs)
168 DRight -> newFlow (List.sum ws) (List.maximum hs)
169 DIn -> newFlow (List.maximum ws) (List.maximum hs)
170 DOut -> newFlow (List.maximum ws) (List.maximum hs)
172-- Stack elements vertically. To put `a` above `b` you would say:
173--
174-- a `above` b
175above : Element -> Element -> Element
176above hi lo =
177 newElement (max (widthOf hi) (widthOf lo))
178 (heightOf hi + heightOf lo)
179 (Flow DDown [hi,lo])
181-- Stack elements vertically. To put `a` below `b` you would say:
182--
183-- a `below` b
184below : Element -> Element -> Element
185below lo hi =
186 newElement (max (widthOf hi) (widthOf lo))
187 (heightOf hi + heightOf lo)
188 (Flow DDown [hi,lo])
190-- Put elements beside each other horizontally.
191beside : Element -> Element -> Element
192beside lft rht =
193 newElement (widthOf lft + widthOf rht)
194 (max (heightOf lft) (heightOf rht))
195 (Flow right [lft,rht])
197-- Layer elements on top of each other, starting from the bottom.
198-- `(layers == flow outward)`
199layers : [Element] -> Element
200layers es =
201 let ws = List.map widthOf es
202 hs = List.map heightOf es
203 in newElement (List.maximum ws) (List.maximum hs) (Flow DOut es)
206-- Repetitive things --
208absolute : Int -> Pos
209absolute = Absolute
210relative : Float -> Pos
211relative = Relative
213middle : Position
214middle = { horizontal=Z, vertical=Z, x=Relative 0.5, y=Relative 0.5 }
215topLeft : Position
216topLeft = { horizontal=N, vertical=P, x=Absolute 0, y=Absolute 0 }
217topRight : Position
218topRight = { topLeft | horizontal <- P }
219bottomLeft : Position
220bottomLeft = { topLeft | vertical <- N }
221bottomRight : Position
222bottomRight = { bottomLeft | horizontal <- P }
223midLeft : Position
224midLeft = { middle | horizontal <- N, x <- Absolute 0 }
225midRight : Position
226midRight = { midLeft | horizontal <- P }
227midTop : Position
228midTop = { middle | vertical <- P, y <- Absolute 0 }
229midBottom : Position
230midBottom = { midTop | vertical <- N }
232middleAt : Pos -> Pos -> Position
233middleAt x y = { horizontal = Z, vertical = Z, x = x, y = y }
234topLeftAt : Pos -> Pos -> Position
235topLeftAt x y = { horizontal = N, vertical = P, x = x, y = y }
236topRightAt : Pos -> Pos -> Position
237topRightAt x y = { horizontal = P, vertical = P, x = x, y = y }
238bottomLeftAt : Pos -> Pos -> Position
239bottomLeftAt x y = { horizontal = N, vertical = N, x = x, y = y }
240bottomRightAt : Pos -> Pos -> Position
241bottomRightAt x y = { horizontal = P, vertical = N, x = x, y = y }
242midLeftAt : Pos -> Pos -> Position
243midLeftAt x y = { horizontal = N, vertical = Z, x = x, y = y }
244midRightAt : Pos -> Pos -> Position
245midRightAt x y = { horizontal = P, vertical = Z, x = x, y = y }
246midTopAt : Pos -> Pos -> Position
247midTopAt x y = { horizontal = Z, vertical = P, x = x, y = y }
248midBottomAt : Pos -> Pos -> Position
249midBottomAt x y = { horizontal = Z, vertical = N, x = x, y = y }
251up : Direction
252up = DUp
254down : Direction
255down = DDown
257left : Direction
258left = DLeft
260right : Direction
261right = DRight
263inward : Direction
264inward = DIn
266outward : Direction
267outward = DOut