How align three forms vertically in Elm?

320 views Asked by At

1) I don't really get for what purpose Element and Form are different classes. Probably, it causes the following problem.

2) My main function maps all signals to a assemble function, which assembles view on each update

assemble: Float -> Float -> Element
assemble screen_w screen_h =
    [
        background screen_w screen_h,
        header screen_w screen_h,
        info screen_w screen_h
    ] 
        |> collage (round screen_w)  (round screen_h) 

main: Signal Element
main = 
    assemble
        <~ (toFloat <~ Window.width)
        ~ (toFloat <~ Window.height)

This architecture requires header to return Form

3) header uses one form for text and two other forms to decorate it.

I need to position them one above other and merge into one form.

stripe: Float -> Element
stripe w = 
    rect w 10
        |> filled black
        |> show
header: Float -> Float -> Form
header screen_w screen_h =
    [
        stripe screen_w,
        fromString "My awesome header"
            |> height 64
            |> text
            |> show
        ,
        stripe screen_w
    ]
        |> flow down
        |> toForm
        |> move (0, screen_h/2 - header_size/2 - header_shift)

4) The code above displays

<internal structure> 
<internal structure>
<internal structure>

in place of header and stripes.

It seems that show is unable to inverse toForm

because the following

main = 
  show 42
    |> toForm
    |> show

also displays

<internal structure> 

Can I align three forms one above other, using Elm?

2

There are 2 answers

0
Apanatshka On BEST ANSWER

Difference between Forms and Elements

Forms are free-form graphics that can be displayed in a collage. Elements are rectangular things with a known width and height.

Purpose of Graphics.Element.show

The show function is more of a debugging tool than a function for turning Forms into Elements. All data you define yourself can probably be displayed by show, but some internal data from libraries are not displayable, which is why you get the <internal structure> output. To turn Forms into Elements, use the Graphics.Collage.collage function.

Alignment of Forms

Alignment and distribution of forms in an Element-like way is not well supported in the core libraries. You can try the 3rd party library align-distribute for it, which should make it easier. Another more powerful 3rd party library is diagrams, but I'm not sure it's as easy to use nor whether you need more power than the other lib I linked to.

1
Tony On

I am pretty new to Elm myself, but I think the way to go is to keep each part of the header as a form (don't pipe to show), and move each one individually. Then header could return a list of Forms, and that would be concatenated with the list in assemble.

So a working header function might look this:

import Graphics.Collage exposing (..)
import Graphics.Element exposing (..)
import Text exposing (..)
import Color exposing (..)

main = 
  collage 500 500 (header 500 500)

stripe: Float -> Form
stripe w = 
  rect w 10
    |> filled black


header: Float -> Float -> List Form
header screen_w screen_h =
[
    stripe screen_w
        |> move (0, 245) --calculate based on screen coords
    ,
    fromString "My awesome header"
        |> Text.height 64
        |> text
        |> move (50, 220) --calculate based on screen coords
    ,
    stripe screen_w
        |> move (0, 180) --calculate based on screen coords
]

So, in this case the assemble function would look like:

assemble: Float -> Float -> Element
assemble screen_w screen_h =
    [background screen_w screen_h] ++
     header screen_w screen_h ++
    [info screen_w screen_h] 
        |> collage (round screen_w)  (round screen_h)