shamansir / tron-gui / WithTron

WithTron is the set of functions which wrap Elm Browser.* helpers and so let you easily add your GUI to the usual Elm-driven flow.

See Tutorial for the details on how to use it.

Here is the OneKnob example:

The only things that is different from usual Elm application is for function which allows you to build the Tron GUI using current state of the model:

import WithTron
import Tron.Tree exposing (Tree)

type alias Amount = Float

type Msg
    = AmountChanged Amount

type alias Model = Amount

for : Tree () -> Model -> Tron Msg
for _ amount =
    Build.root
        [
            ( "amount"
            , Build.float
                { min = 0, max = 1, step = 0.01 }
                amount
                AmountChanged
            )
        ]

init _ =
    ( 0, Cmd.none )

view _ amount =
    Html.text
        <| String.fromFloat amount

update msg _ curAmount =
    case msg of

        AmountChanged newAmount ->
            ( newAmount
            , Cmd.none
            )

subscriptions _ = Sub.none

main : WithTron.Program () Model Msg
main =
    WithTron.element
        (Render.toHtml Dock.center Theme.dark)
        Communication.none
        { for = for
        , init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }

NB: Please don't forget to add a copy of src/Tron.css to your application, or refer to one hosted at GitHub.

For help on how to define your interface with for function, see the detailed Tron.Build documentation.

More examples are in the README, and in the example/*/Main.elm modules.

See also: Tron.Option.Render, Tron.Option.Communication, Tron.Build.

Program


type alias Program flags model msg =
Platform.Program flags ( model
, Tron.Core.State
, Tree ) (Architecture.WithTronMsg msg
}

Adds Model msg to the Elm Program and so controls all the required communication between usual App and GUI.

Browser.* Wrappers

sandbox : Tron.Option.Render.Target -> { for : model -> Tron msg, init : model, view : model -> Html msg, update : msg -> model -> model } -> Program () model msg

Wrapper for Program.sandbox with for function and Tron options.

For example:

import Tron.Style.Theme as Theme exposing (Theme(..))
import Tron.Style.Dock as Dock
import Tron.Option.Render as Render
import Tron.Option.Communication as Communication
import WithTron

main : WithTron.Program () Example.Model Example.Msg
main =
    WithTron.sandbox
        (Render.toHtml Dock.center Theme.dark)
        Communication.none
        { for = ExampleGui.for
        , init = Example.init
        , view = Example.view
        , update = Example.update
        }

element : Tron.Option.Render.Target -> Tron.Option.Communication.Ports msg -> { for : Tree -> model -> Tron msg, init : flags -> ( model, Platform.Cmd.Cmd msg ), subscriptions : Tree -> model -> Platform.Sub.Sub msg, view : Tree -> model -> Html msg, update : msg -> Tree -> model -> ( model, Platform.Cmd.Cmd msg ) } -> Program flags model msg

Wrapper for Program.element with for function and Tron options.

Example from Basic/Main.elm

import Tron.Style.Theme as Theme exposing (Theme(..))
import Tron.Style.Dock as Dock
import Tron.Option.Render as Render
import Tron.Option.Communication as Communication
import WithTron

import Example.Goose.Main as Example
import Example.Goose.Model as Example
import Example.Goose.Msg as Example
import Example.Goose.Gui as ExampleGui

main : WithTron.Program () Example.Model Example.Msg
main =
    WithTron.element
        (Render.toHtml Dock.center Theme.dark)
        Communication.none
        { for = ExampleGui.for
        , init = always Example.init
        , view = Example.view
        , update = Example.update
        , subscriptions = always Sub.none
        }

document : Tron.Option.Render.Target -> Tron.Option.Communication.Ports msg -> { init : flags -> ( model, Platform.Cmd.Cmd msg ), for : Tree -> model -> Tron msg, subscriptions : Tree -> model -> Platform.Sub.Sub msg, view : Tree -> model -> Browser.Document msg, update : msg -> Tree -> model -> ( model, Platform.Cmd.Cmd msg ) } -> Program flags model msg

Wrapper for Program.document with for function and Tron options.

For example:

import WithTron
import Tron.Style.Theme as Theme exposing (Theme(..))
import Tron.Style.Dock as Dock
import Tron.Expose.Data as Exp
import Tron.Option.Render as Render
import Tron.Option.Communication as Communication
import WithTron

main : WithTron.Program () Example.Model Example.Msg
main =
    WithTron.document
        (Render.toHtml Dock.center Theme.light)
        (Communication.detachable
            { ack = ackToWs
            , transmit = sendUpdateToWs
            , receive = receieveUpdateFromWs identity
            }
        )
        { for = ExampleGui.for
        , init = always Example.init
        , view =
            \model ->
                { title = "Detachable Tron"
                , body = [ Example.view model ]
                }
        , update = Example.update
        , subscriptions = always Sub.none
        }

application : Tron.Option.Render.Target -> Tron.Option.Communication.Ports msg -> { init : flags -> Url -> Browser.Navigation.Key -> ( model, Platform.Cmd.Cmd msg ), for : Tree -> model -> Tron msg, subscriptions : Tree -> model -> Platform.Sub.Sub msg, view : Tree -> model -> Browser.Document msg, update : msg -> Tree -> model -> ( model, Platform.Cmd.Cmd msg ), onUrlChange : Url -> msg, onUrlRequest : Browser.UrlRequest -> msg } -> Program flags model msg

Wrapper for Program.application with for function and Tron options.

Example from Detachable/Main.elm:

import WithTron exposing (ProgramWithTron)
import Tron.Style.Theme as Theme exposing (Theme(..))
import Tron.Style.Dock as Dock
import Tron.Expose.Data as Exp
import Tron.Option.Render as Render
import Tron.Option.Communication as Communication
import WithTron

import Example.Goose.Main as Example
import Example.Goose.Model as Example
import Example.Goose.Msg as Example
import Example.Goose.Gui as ExampleGui

main : WithTron.Program () Example.Model Example.Msg
main =
    WithTron.application
        (Render.toHtml Dock.center Theme.light)
        (Communication.detachable
            { ack = ackToWs
            , transmit = sendUpdateToWs
            , receive = receieveUpdateFromWs identity
            }
        )
        { for = ExampleGui.for
        , init = always Example.init
        , view =
            \model ->
                { title = "Detachable Tron"
                , body = [ Example.view model ]
                }
        , update = Example.update
        , subscriptions = always Sub.none
        , onUrlChange = always Example.NoOp
        , onUrlRequest = always Example.NoOp
        }

port receieveUpdateFromWs : (Exp.RawInUpdate -> msg) -> Sub msg

port sendUpdateToWs : Exp.RawOutUpdate -> Cmd msg

port ackToWs : Exp.Ack -> Cmd msg

Helpers to create configurations for Browser.*

overElement : Tron.Option.Render.Target -> Tron.Option.Communication.Ports msg -> { for : model -> Tron msg, init : flags -> ( model, Platform.Cmd.Cmd msg ), subscriptions : model -> Platform.Sub.Sub msg, view : model -> Html msg, update : msg -> model -> ( model, Platform.Cmd.Cmd msg ) } -> ElementDef flags model msg

Create the configuration that fits Browser.element.

Browser.element
    <| WithTron.overElement
        { ... }

overDocument : Tron.Option.Render.Target -> Tron.Option.Communication.Ports msg -> { init : flags -> ( model, Platform.Cmd.Cmd msg ), for : model -> Tron msg, subscriptions : model -> Platform.Sub.Sub msg, view : model -> Browser.Document msg, update : msg -> model -> ( model, Platform.Cmd.Cmd msg ) } -> DocumentDef flags model msg

Create the configuration that fits Browser.document.

Browser.document
    <| WithTron.overDocument
        { ... }

overApplication : Tron.Option.Render.Target -> Tron.Option.Communication.Ports msg -> { init : flags -> Url -> Browser.Navigation.Key -> ( model, Platform.Cmd.Cmd msg ), for : model -> Tron msg, subscriptions : model -> Platform.Sub.Sub msg, view : model -> Browser.Document msg, update : msg -> model -> ( model, Platform.Cmd.Cmd msg ), onUrlChange : Url -> msg, onUrlRequest : Browser.UrlRequest -> msg } -> ApplicationDef flags model msg

Create the configuration that fits Browser.application.

Browser.application
    <| WithTron.overApplication
        { ... }

Past dependent helpers

pastDependentOverElement : Tron.Option.Render.Target -> Tron.Option.Communication.Ports msg -> { for : Tree -> model -> Tron msg, init : flags -> ( model, Platform.Cmd.Cmd msg ), subscriptions : Tree -> model -> Platform.Sub.Sub msg, view : Tree -> model -> Html msg, update : msg -> Tree -> model -> ( model, Platform.Cmd.Cmd msg ) } -> ElementDef flags model msg

Create the configuration that fits Browser.element with the ability to track the previous state of the values in the GUI (see WithTron.ValueAt).

Browser.element
    <| WithTron.pastDependentOverElement
        { ... }

pastDependentOverDocument : Tron.Option.Render.Target -> Tron.Option.Communication.Ports msg -> { init : flags -> ( model, Platform.Cmd.Cmd msg ), for : Tree -> model -> Tron msg, subscriptions : Tree -> model -> Platform.Sub.Sub msg, view : Tree -> model -> Browser.Document msg, update : msg -> Tree -> model -> ( model, Platform.Cmd.Cmd msg ) } -> DocumentDef flags model msg

Create the configuration that fits Browser.application with the ability to track the previous state of the values in the GUI (see WithTron.ValueAt).

Browser.document
    <| WithTron.pastDependentOverDocument
        { ... }

pastDependentOverApplication : Tron.Option.Render.Target -> Tron.Option.Communication.Ports msg -> { init : flags -> Url -> Browser.Navigation.Key -> ( model, Platform.Cmd.Cmd msg ), for : Tree -> model -> Tron msg, subscriptions : Tree -> model -> Platform.Sub.Sub msg, view : Tree -> model -> Browser.Document msg, update : msg -> Tree -> model -> ( model, Platform.Cmd.Cmd msg ), onUrlChange : Url -> msg, onUrlRequest : Browser.UrlRequest -> msg } -> ApplicationDef flags model msg

Create the configuration that fits Browser.application with the ability to track the previous state of the values in the GUI (see WithTron.ValueAt).

Browser.element
    <| WithTron.pastDependentOverElement
        { ... }

Just UI

justUi : Tron.Option.Render.Target -> (Tree -> Tree) -> ElementDef () () ()

justUiAndCommunication : Tron.Option.Render.Target -> Tron.Option.Communication.Ports () -> (Tree -> Tree) -> ElementDef () () ()