--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Sure.
Try this program:
import Html exposing (div, button, text, fromElement)
import Html.Events exposing (onClick)
import StartApp
import Effects
import DragAndDrop exposing (..)
import Graphics.Input
import Text exposing (fromString)
import Graphics.Element exposing (layers, leftAligned, sizeOf)
import Graphics.Collage exposing (collage, outlined, rect, solid, toForm)
import Color exposing (black)
hover = Signal.mailbox False
box = Graphics.Input.hoverable (Signal.message hover.address)
(putInBox (leftAligned (fromString "drag-and-drop me")))
putInBox e =
let (sx,sy) = sizeOf e
in layers [e, collage sx sy [outlined (solid black) (rect (toFloat sx) (toFloat sy))]]
moveBy (dx,dy) (x,y) = (x + toFloat dx, y - toFloat dy)
main =
(StartApp.start { init = (model, Effects.none)
, update = update
, view = view
, inputs = [ Signal.map DnD (track False hover.signal) ] }).html
model = (0,0)
type Action = DnD (Maybe DragAndDrop.Action) | ToOrigin
update action model =
case action of
DnD (Just (MoveBy (dx,dy))) -> (moveBy (dx,dy) model, Effects.none)
ToOrigin -> ((0,0), Effects.none)
_ -> (model, Effects.none)
view address model =
div []
[ fromElement (collage 200 200 [Graphics.Collage.move model (toForm box)])
, button [ onClick address ToOrigin ] [ text "back to center" ] ]
with this elm-package.json
:
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.1 <= v < 3.0.0",
"evancz/elm-html": "4.0.2 <= v < 5.0.0",
"evancz/start-app": "2.0.2 <= v < 3.0.0",
"jvoigtlaender/elm-drag-and-drop": "1.0.3 <= v < 2.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
}
Maybe something like below would work for you. Some notes:
track
-functions. Instead, the mouseEvents
/automaton
version of the API is used.Main
module does not “reach down” for a hover-signal.Main
does need to bring in the mouseEvents
signal, though.MyWidget
module in any way. Moreover, it needs to be connected only once, even if there are several subwidgets that use mouse dragging.Main
module uses MyWidget
is essentially following the usual architecture (so not depending on internals of MyWidget
), except that Main
needs to explicitly “notify” a MyWidget
component of mouse events (see the line with MyWidget.notifyMouseEvent
). That would have to happen for each subcomponent that uses mouse dragging. It might be the main weakness of this approach, in particular if MyWidget
is a grandchild as in your scenario, not a direct child as in my simplified example.MyWidget
, the model needs to be enriched by a “drag state”. The way that is handled is rather canonical (see the updateDragState
function) and would repeat itself across other widget types.module Main (main) where
import MyWidget
import Html exposing (div, button, text, fromElement)
import Html.Events exposing (onClick)
import StartApp
import Effects
import Drag
main =
(StartApp.start { init = (model, Effects
.none)
, update = update
, view = view
, inputs = [ Signal.map MouseEvent Drag.mouseEvents ] }).html
model = { counter = 0, widget = MyWidget.model }
type Action = Increase | Widget MyWidget.Action | MouseEvent Drag.MouseEvent
update action ({ counter, widget } as model) =
case action of
Increase -> ({ model | counter = counter + 1 }, Effects.none)
Widget action -> ({ model | widget = MyWidget.update action widget }, Effects.none)
MouseEvent event -> ({ model | widget = MyWidget.notifyMouseEvent event widget }, Effects.none)
view address { counter, widget } =
div []
[ fromElement (MyWidget.view (Signal.forwardTo address Widget) widget)
, text (toString counter)
, button [ onClick address Increase ] [ text "increase counter" ] ]
module MyWidget (model, Action, update, notifyMouseEvent, view) where
import Drag
import Automaton
import Graphics.Input
import Text exposing (fromString)
import Graphics.Element exposing (layers, leftAligned, sizeOf)
import Graphics.Collage exposing (collage, outlined, rect, solid, toForm)
import Color exposing (black)
box address = Graphics.Input.hoverable (\b -> Signal.message address (Hover (if b then Just () else Nothing)))
(putInBox (leftAligned (fromString "drag-and-drop me")))
putInBox e =
let (sx,sy) = sizeOf e
in layers [e, collage sx sy [outlined (solid black) (rect (toFloat sx) (toFloat sy))]]
moveBy (dx,dy) (x,y) = (x + toFloat dx, y - toFloat dy)
model = { pos = (0,0), dragState = Drag.automaton Nothing }
type Action = Drag (Maybe ((), Drag.Action)) | Hover (Maybe ())
update action ({ pos } as model) =
case action of
Drag (Just (_, Drag.MoveBy (dx,dy))) -> { model | pos = moveBy (dx,dy) pos }
Hover which -> updateDragState (Drag.Hover which) model
_ -> model
updateDragState input ({ dragState } as model) = let ( dragState', output ) = Automaton.step input dragState
in update (Drag output) { model | dragState = dragState' }
notifyMouseEvent = updateDragState << Drag.Mouse
view address { pos } = collage 200 200 [Graphics.Collage.move pos (toForm (box address))]
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"."
],
"exposed-modules": [],
"dependencies":
{
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/automaton": "1.1.0 <= v < 2.0.0",
"evancz/elm-effects": "2.0.1 <= v < 3.0.0",
"evancz/elm-html": "4.0.2 <= v < 5.0.0",
"evancz/start-app": "2.0.2 <= v < 3.0.0",
"jvoigtlaender/elm-drag": "1.0.0 <= v < 2.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
}