{-|
This is a dragboard which uses checkerboard with draggable images or
colored fillers. It needs to be provided with number of rows and
columns, lens to the board state of type '[[a]]' (each square of the
board would thus contain a list of items '[a]' and show only the
first item) and the function which converts item 'a' to either color
of a filler or path to the image.

@
dragboard 3 3 boardState getPath
@
-}

{-# LANGUAGE FlexibleContexts #-}

module Monomer.Dragboard
    ( -- * Re-exported modules
      module Monomer.Dragboard.DragboardCfg
      -- * Constructors
    , dragboard
    , dragboard_
    , dragboardV
    , dragboardV_
    , dragboardD_
    ) where

import Control.Lens
import Data.Default
import Data.Text (Text)
import Data.Typeable
import Monomer.Core.Combinators
import Monomer.Graphics.Types
import Monomer.Widgets.Composite

import Monomer.Dragboard.DragboardCfg
import Monomer.Dragboard.DragboardEvent
import Monomer.Dragboard.DragboardModel
import Monomer.Dragboard.UI

{-|
Creates a dragboard using the given lens, providing number of
columns and rows and the function to get image path or color from
the value.
-}
dragboard
    :: (WidgetModel s, WidgetEvent e, Eq a, Typeable a)
    => Int                       -- ^ Number of columns.
    -> Int                       -- ^ Number of rows.
    -> ALens' s [[a]]            -- ^ The lens into the model.
    -> (a -> Either Text Color)  -- ^ The path or color function.
    -> WidgetNode s e            -- ^ The created dragboard.
dragboard :: forall s e a.
(WidgetModel s, WidgetEvent e, Eq a, Typeable a) =>
Int
-> Int
-> ALens' s [[a]]
-> (a -> Either Text Color)
-> WidgetNode s e
dragboard Int
c Int
r ALens' s [[a]]
field a -> Either Text Color
f = forall s e a.
(WidgetModel s, WidgetEvent e, Eq a, Typeable a) =>
Int
-> Int
-> ALens' s [[a]]
-> (a -> Either Text Color)
-> [DragboardCfg s e a]
-> WidgetNode s e
dragboard_ Int
c Int
r ALens' s [[a]]
field a -> Either Text Color
f forall a. Default a => a
def

{-|
Creates a dragboard using the given lens, providing number of
columns and rows and the function to get image path or color from
the value. Accepts config.
-}
dragboard_
    :: (WidgetModel s, WidgetEvent e, Eq a, Typeable a)
    => Int                       -- ^ Number of columns.
    -> Int                       -- ^ Number of rows.
    -> ALens' s [[a]]            -- ^ The lens into the model.
    -> (a -> Either Text Color)  -- ^ The path or color function.
    -> [DragboardCfg s e a]      -- ^ The config options.
    -> WidgetNode s e            -- ^ The created dragboard.
dragboard_ :: forall s e a.
(WidgetModel s, WidgetEvent e, Eq a, Typeable a) =>
Int
-> Int
-> ALens' s [[a]]
-> (a -> Either Text Color)
-> [DragboardCfg s e a]
-> WidgetNode s e
dragboard_ Int
c Int
r ALens' s [[a]]
field a -> Either Text Color
f [DragboardCfg s e a]
configs = WidgetNode s e
node where
    node :: WidgetNode s e
node = forall s e a.
(WidgetModel s, WidgetEvent e, Eq a, Typeable a) =>
Int
-> Int
-> WidgetData s [[a]]
-> (a -> Either Text Color)
-> [DragboardCfg s e a]
-> [CompositeCfg (DragboardModel a) (DragboardEvent a) s e]
-> WidgetNode s e
dragboardD_ Int
c Int
r WidgetData s [[a]]
wlens a -> Either Text Color
f [DragboardCfg s e a]
configs []
    wlens :: WidgetData s [[a]]
wlens = forall s a. ALens' s a -> WidgetData s a
WidgetLens ALens' s [[a]]
field

{-|
Creates a dragboard using the given board state and 'onChange' event
handler, providing number of columns and rows and the function to
get image path or color from the value.
-}
dragboardV
    :: (WidgetModel s, WidgetEvent e, Eq a, Typeable a)
    => Int                       -- ^ Number of columns.
    -> Int                       -- ^ Number of rows.
    -> [[a]]                     -- ^ The current board state.
    -> (([[a]], Int, Int) -> e)  -- ^ The event to raise on change.
    -> (a -> Either Text Color)  -- ^ The path or color function.
    -> WidgetNode s e            -- ^ The created dragboard.
dragboardV :: forall s e a.
(WidgetModel s, WidgetEvent e, Eq a, Typeable a) =>
Int
-> Int
-> [[a]]
-> (([[a]], Int, Int) -> e)
-> (a -> Either Text Color)
-> WidgetNode s e
dragboardV Int
c Int
r [[a]]
v ([[a]], Int, Int) -> e
handler a -> Either Text Color
f = forall s e a.
(WidgetModel s, WidgetEvent e, Eq a, Typeable a) =>
Int
-> Int
-> [[a]]
-> (([[a]], Int, Int) -> e)
-> (a -> Either Text Color)
-> [DragboardCfg s e a]
-> WidgetNode s e
dragboardV_ Int
c Int
r [[a]]
v ([[a]], Int, Int) -> e
handler a -> Either Text Color
f forall a. Default a => a
def

{-|
Creates a dragboard using the given board state and 'onChange' event
handler, providing number of columns and rows and the function to
get image path or color from the value. Accepts config.
-}
dragboardV_
    :: (WidgetModel s, WidgetEvent e, Eq a, Typeable a)
    => Int                       -- ^ Number of columns.
    -> Int                       -- ^ Number of rows.
    -> [[a]]                     -- ^ The current board state.
    -> (([[a]], Int, Int) -> e)  -- ^ The event to raise on change.
    -> (a -> Either Text Color)  -- ^ The path or color function.
    -> [DragboardCfg s e a]      -- ^ The config options.
    -> WidgetNode s e            -- ^ The created dragboard.
dragboardV_ :: forall s e a.
(WidgetModel s, WidgetEvent e, Eq a, Typeable a) =>
Int
-> Int
-> [[a]]
-> (([[a]], Int, Int) -> e)
-> (a -> Either Text Color)
-> [DragboardCfg s e a]
-> WidgetNode s e
dragboardV_ Int
c Int
r [[a]]
v ([[a]], Int, Int) -> e
handler a -> Either Text Color
f [DragboardCfg s e a]
configs = WidgetNode s e
node where
    node :: WidgetNode s e
node = forall s e a.
(WidgetModel s, WidgetEvent e, Eq a, Typeable a) =>
Int
-> Int
-> WidgetData s [[a]]
-> (a -> Either Text Color)
-> [DragboardCfg s e a]
-> [CompositeCfg (DragboardModel a) (DragboardEvent a) s e]
-> WidgetNode s e
dragboardD_ Int
c Int
r (forall s a. a -> WidgetData s a
WidgetValue [[a]]
v) a -> Either Text Color
f [DragboardCfg s e a]
newConfigs []
    newConfigs :: [DragboardCfg s e a]
newConfigs = forall t a e. CmbOnChange t a e => (a -> e) -> t
onChange ([[a]], Int, Int) -> e
handler forall a. a -> [a] -> [a]
: [DragboardCfg s e a]
configs

{-|
Creates a dragboard providing a 'WidgetData' instance, number of
columns and rows, the function to get image path or color from the
value and config.
-}
dragboardD_
    :: (WidgetModel s, WidgetEvent e, Eq a, Typeable a)
    => Int
    -- ^ Number of columns.
    -> Int
    -- ^ Number of rows.
    -> WidgetData s [[a]]
    -- ^ The 'WidgetData' to retrieve the board state from.
    -> (a -> Either Text Color)
    -- ^ The path or color function.
    -> [DragboardCfg s e a]
    -- ^ The config options.
    -> [CompositeCfg (DragboardModel a) (DragboardEvent a) s e]
    -- ^ The composite config options.
    -> WidgetNode s e
    -- ^ The created dragboard.
dragboardD_ :: forall s e a.
(WidgetModel s, WidgetEvent e, Eq a, Typeable a) =>
Int
-> Int
-> WidgetData s [[a]]
-> (a -> Either Text Color)
-> [DragboardCfg s e a]
-> [CompositeCfg (DragboardModel a) (DragboardEvent a) s e]
-> WidgetNode s e
dragboardD_ Int
c Int
r WidgetData s [[a]]
wdata a -> Either Text Color
f [DragboardCfg s e a]
configs [CompositeCfg (DragboardModel a) (DragboardEvent a) s e]
cmpConfigs = WidgetNode s e
node where
    node :: WidgetNode s e
node = forall s e ep sp.
(CompositeModel s, CompositeEvent e, CompositeEvent ep,
 CompParentModel sp) =>
WidgetType
-> WidgetData sp s
-> UIBuilder s e
-> EventHandler s e sp ep
-> [CompositeCfg s e sp ep]
-> WidgetNode sp ep
compositeD_ WidgetType
wt forall {s} {a}. WidgetData s (DragboardModel a)
wdata' UIBuilder (DragboardModel a) (DragboardEvent a)
uiBuilder EventHandler (DragboardModel a) (DragboardEvent a) s e
eventHandler [CompositeCfg (DragboardModel a) (DragboardEvent a) s e]
cmpConfigs'
    wt :: WidgetType
wt = Text -> WidgetType
WidgetType Text
"dragboard"
    wdata' :: WidgetData s (DragboardModel a)
wdata' = forall s a. a -> WidgetData s a
WidgetValue forall a. DragboardModel a
initDragboardModel
    uiBuilder :: UIBuilder (DragboardModel a) (DragboardEvent a)
uiBuilder = forall a s e.
Typeable a =>
DragboardCfg s e a
-> Int
-> Int
-> (a -> Either Text Color)
-> UIBuilder (DragboardModel a) (DragboardEvent a)
buildUI DragboardCfg s e a
config Int
c Int
r a -> Either Text Color
f
    eventHandler :: EventHandler (DragboardModel a) (DragboardEvent a) s e
eventHandler = forall a sp ep.
Eq a =>
WidgetData sp [[a]]
-> DragboardCfg sp ep a
-> EventHandler (DragboardModel a) (DragboardEvent a) sp ep
handleEvent WidgetData s [[a]]
wdata DragboardCfg s e a
config
    config :: DragboardCfg s e a
config = forall a. Monoid a => [a] -> a
mconcat [DragboardCfg s e a]
configs
    cmpConfigs' :: [CompositeCfg (DragboardModel a) (DragboardEvent a) s e]
cmpConfigs' =
        [ forall t w s. CmbMergeRequired t w s => (w -> s -> s -> Bool) -> t
mergeRequired (\WidgetEnv (DragboardModel a) (DragboardEvent a)
_ DragboardModel a
_ DragboardModel a
_ -> Bool
True)
        , forall s e sp ep.
MergeModelHandler s e sp -> CompositeCfg s e sp ep
compositeMergeModel forall {b} {p} {p}. HasBoardState b [[a]] => p -> s -> b -> p -> b
mergeHandler
        , forall e s sp ep.
WidgetEvent e =>
MergeEventsHandler s e sp -> CompositeCfg s e sp ep
compositeMergeEvents forall a b. (a -> b) -> a -> b
$ \WidgetEnv (DragboardModel a) (DragboardEvent a)
_ WidgetNode (DragboardModel a) (DragboardEvent a)
_ WidgetNode (DragboardModel a) (DragboardEvent a)
_ s
_ DragboardModel a
m DragboardModel a
_ -> [forall a. DragboardModel a -> DragboardEvent a
EventMerge DragboardModel a
m]
        ] forall a. Semigroup a => a -> a -> a
<> [CompositeCfg (DragboardModel a) (DragboardEvent a) s e]
cmpConfigs
    mergeHandler :: p -> s -> b -> p -> b
mergeHandler p
_ s
pm b
m p
_ = b
m forall a b. a -> (a -> b) -> b
& forall s a. HasBoardState s a => Lens' s a
boardState forall s t a b. ASetter s t a b -> b -> s -> t
.~ forall s a. s -> WidgetData s a -> a
widgetDataGet s
pm WidgetData s [[a]]
wdata