shamansir / tron-gui / Tron

This is the Tron msg, which is, similarly to Html msg or Svg msg, may send your messages into the lifecycle of your application. In this case, it represents the tree of your components with the associated handlers that produce messages.

See Tutorial for the details on how to use it.

To use Tron in your application, you'll need to specify this function:

for : Model -> Tron Msg

See Tron.Build for the helpers to define your own interface.

See WithTron for the ways to add Tron to your applcation.

Tron msg is the same as Tron.Tree (Control.Value -> Maybe msg), so it stores the value handler together with every control.

Tron


type alias Tron a =
Tree.Internals.Tree (Control.Value.Value -> Maybe a)

Tron a is the tree of your controls or, recursively, any control in such tree.

To build your interface, use the helpers from the Tron.Builder module or any of its variants like Tron.Build.Proxy, Tron.Build.Unit or Tron.Build.String


type alias Set a =
List ( Path.Label
, Tron a 
}

Set msg is just the list of controls' definitions together with their labels.

Convert from and to

lift : Tree.Internals.Tree a -> Tron a

lift Tree a to Tree (Control.Value -> Maybe a), which is the alias of Tron a.

toUnit : Tron a -> Tron ()

Store nothing, but values.

pathify : Tron a -> Tron Path

Add the path representing the label-based way to reach the particular control in the GUI tree.

Tip: to get Tron (Path, a), use:

pathify1 : Tron a -> Tron (Path, a)
pathify1 tron =
    Tron.map2
        Tuple.pair
        (Tron.pathify tron)
        tron

To get Tron (Path, Value), use:

pathify2 : Tron a -> Tron (Path, Value)
pathify2 tron =
    Tron.map2
        Tuple.pair
        (Tron.pathify tron)
        (Tron.proxify tron)

proxify : Tron a -> Tron Control.Value.Value

Make all the controls in the Tron tree return the current value, projected to Control.Value, themselves. In combination with perform and map, this helps to send values or ports of fire them as messages.

Under the hood, since Tron a == Tree (Control.Value -> Maybe a), it becomes Tree (Control.Value -> Maybe Control.Value) where it always Just with the same value given as argument.

expose : Tron a -> Tron Tree.Expose.Data.Value

Make all the controls in the Tron tree return the current value, converted to the exposed JSON Expose.Value, themselves. In combination with perform, this helps to send values to ports or fire them as messages.

Under the hood, since Tron a == Tree (Control.Value -> Maybe a), it becomes Tree (Control.Value -> Maybe Exp.Value) where it always Just with the same value, converted to JSON, given as argument.

Common helpers

map : (a -> b) -> Tron a -> Tron b

The usual map function which allows you to substitute the messages sent through the components.

mapSet : (a -> b) -> Set a -> Set b

The usual map function which allows you to substitute the messages sent through the components in a Set. For example, implementation of Tron.Build.palette:

Tron.choiceBy
    (options
        |> Tron.buttons
        |> List.map (Tron.with (Tron.face << Tron.useColor << Tuple.second))
        |> Tron.toSet Tuple.first
        |> Tron.mapSet Tuple.second
    )
    current
    (\cv1 cv2 ->
        case ( cv1 |> Color.toRgba, cv2 |> Color.toRgba ) of
            ( c1, c2 ) ->
                (c1.red == c2.red) &&
                (c1.blue == c2.blue) &&
                (c1.green == c2.green) &&
                (c1.alpha == c2.alpha)
    )
    toMsg
|> cells CS.half

andThen : (a -> Tron b) -> Tron a -> Tron b

The usual andThen function which allows you to change the message type

with : (a -> Tron a -> Tron a) -> Tron a -> Tron a

Same as andThen, but also gets current component as argument, it gets useful in mapping Sets or lists of controls:

Tron.choiceBy
    (Product.all
        |> List.filter Product.hasIcon
        |> Tron.buttons
        |> List.map (Tron.with (Tron.face << productIcon))
        |> Tron.toSet Product.getName
    )
    Product.default
    Product.compare
|> Tron.shape (rows 3)

looseMap2 : (a -> b -> c) -> Tron a -> Tron b -> Tron c

maps two GUI trees with given fn; If some control exists only in one tree at the specific compared place, it is removed; NB: The control state is always taken from the second (right) variant, that's why this map is loose :).

looseMap3 : (a -> b -> c -> d) -> Tron a -> Tron b -> Tron c -> Tron d

maps three GUI trees with given fn; If one of the trees lacks the control at the specific compared place, this place is empty in the resulting tree; NB: The control state is always taken from the most right variant, that's why this map is loose :).

looseMap4 : (a -> b -> c -> d -> e) -> Tron a -> Tron b -> Tron c -> Tron d -> Tron e

maps four GUI trees with given fn; If one of the trees lacks the control at the specific compared place, this place is empty in the resulting tree; NB: The control state is always taken from the most right variant, that's why this map is loose :).

looseMap5 : (a -> b -> c -> d -> e -> f) -> Tron a -> Tron b -> Tron c -> Tron d -> Tron e -> Tron f

maps five GUI trees with given fn; If one of the trees lacks the control at the specific compared place, this place is empty in the resulting tree; NB: The control state is always taken from the most right variant, that's why this map is loose :).

Special

perform : Tron msg -> Platform.Cmd.Cmd msg

Apply the value of the given control (at the current level, no going deep) to the handler it holds (Tron msg is Tree (Control.Value -> Maybe msg)), and this way get the current msg. Then fire it using Cmd as the side-effect, at least if it was determined.