1 {-# LANGUAGE FlexibleContexts, MultiParamTypeClasses, TupleSections #-}
3 module RMCA.GUI.MultiBoard where
5 import Control.Concurrent.MVar
7 import Control.Monad.IO.Class
9 import qualified Data.IntMap as M
12 import Data.ReactiveValue
13 import Graphics.UI.Gtk
14 import Graphics.UI.Gtk.Board.TiledBoard hiding (Board)
15 import Graphics.UI.Gtk.Layout.BackgroundContainer
16 import Graphics.UI.Gtk.Reactive.Gtk2
19 import RMCA.IOClockworks
20 import RMCA.Layer.LayerConf
23 import RMCA.Translator.Message
28 createNotebook :: ( ReactiveValueRead addLayer () IO
29 , ReactiveValueRead rmLayer () IO
30 , ReactiveValueReadWrite board (M.IntMap ([Note],[Message])) IO
36 -> MCBMVar StaticLayerConf
37 -> MCBMVar DynLayerConf
41 , ReactiveFieldRead IO (M.IntMap Board)
42 , ReactiveFieldRead IO (M.IntMap LayerConf)
43 , ReactiveFieldRead IO
44 (M.IntMap (ReactiveFieldWrite IO [PlayHead]))
46 createNotebook boardQueue tc addLayerRV rmLayerRV
47 statMCBMVar dynMCBMVar synthMCBMVar guiCellMCBMVar = do
49 let curPageRV = ReactiveFieldReadWrite setter getter notifier
50 where (ReactiveFieldRead getter _) = notebookGetCurrentPagePassive n
51 -- afterSwitchPage is deprecated but switchPage gets us
52 -- the old page number and not the new one and using
53 -- afterSwitchPage doesn't trigger a warning so…
54 setter = postGUIAsync . notebookSetCurrentPage n
55 notifier io = void $ afterSwitchPage n (const io)
57 pageChanRV <- newCBMVarRW []
58 let foundHole = let foundHole' [] = 0
59 foundHole' [x] = x + 1
60 foundHole' (x:y:xs) = if x + 1 /= y then x + 1 else foundHole (y:xs)
64 let curChanRV = liftR2 (!!) pageChanRV curPageRV
65 ------------------------------------------------------------------------------
67 ------------------------------------------------------------------------------
69 chanMapRV <- newCBMVarRW M.empty
70 guiCellHidMVar <- newEmptyMVar
71 let clickHandler ioBoard = do
74 (\iPos' -> liftIO $ do
75 let iPos = actualTile iPos'
76 postGUIAsync $ void $ tryPutMVar state iPos
79 boardOnRelease ioBoard
81 let fPos = actualTile fPos'
83 liftIO $ postGUIAsync $ do
84 mp <- boardGetPiece fPos ioBoard
85 mstate <- tryTakeMVar state
86 when (fPos `elem` validArea && isJust mp) $ do
87 let piece = snd $ fromJust mp
88 when (button == RightButton && maybe False (== fPos) mstate) $ do
89 let nCell = rotateGUICell piece
90 boardSetPiece fPos (Player,nCell) ioBoard
91 nmp <- boardGetPiece fPos ioBoard
92 when (button == LeftButton && isJust nmp) $ do
93 let nCell = snd $ fromJust nmp
94 mOHid <- tryTakeMVar guiCellHidMVar
95 forM_ mOHid $ removeCallbackMCBMVar guiCellMCBMVar
96 reactiveValueWrite guiCellMCBMVar nCell
97 nHid <- installCallbackMCBMVar guiCellMCBMVar $ do
98 cp <- reactiveValueRead curChanRV
99 guiVal <- reactiveValueRead guiCellMCBMVar
100 mChanRV <- M.lookup cp <$> reactiveValueRead chanMapRV
101 when (isNothing mChanRV) $ error "Can't get piece array!"
102 let (_,pieceArrRV,_) = fromJust mChanRV
103 reactiveValueWrite (pieceArrRV ! fPos) guiVal
104 putMVar guiCellHidMVar nHid
108 boardCont <- backgroundContainerNew
109 guiBoard <- attachGameRules =<< initGame
110 clickHandler guiBoard
111 centerBoard <- alignmentNew 0.5 0.5 0 0
112 containerAdd centerBoard guiBoard
113 containerAdd boardCont centerBoard
115 fstP <- notebookAppendPage n boardCont ""
116 notebookPageNumber <- newCBMVarRW (1 :: Int)
118 initBoardRV tc guiBoard >>=
119 \(boardRV, pieceArrRV, phRV) -> reactiveValueRead chanMapRV >>=
120 reactiveValueWrite chanMapRV . M.insert fstP (boardRV,pieceArrRV,phRV)
122 reactiveValueRead pageChanRV >>=
123 reactiveValueWrite pageChanRV . (\pc -> pc ++ [foundHole pc])
125 layerMapRV <- newCBMVarRW $ M.insert fstP defaultLayerConf M.empty
127 let updateDynLayer cp = do
128 nDyn <- reactiveValueRead dynMCBMVar
129 reactiveValueRead layerMapRV >>=
130 reactiveValueWrite layerMapRV .
131 M.adjust (\(stat,_,synth) -> (stat,nDyn,synth)) cp
133 synthState <- reactiveValueRead synthMCBMVar
134 reactiveValueAppend boardQueue $
135 M.singleton cp $ ([],) $ synthMessage cp synthState
136 updateStatLayer _ = return ()--undefined
138 statHidMVar <- newEmptyMVar
139 dynHidMVar <- newEmptyMVar
140 synthHidMVar <- newEmptyMVar
142 installCallbackMCBMVar statMCBMVar
143 (reactiveValueRead curChanRV >>= updateStatLayer) >>= putMVar statHidMVar
144 installCallbackMCBMVar dynMCBMVar
145 (reactiveValueRead curChanRV >>= updateDynLayer) >>= putMVar dynHidMVar
146 installCallbackMCBMVar synthMCBMVar
147 (reactiveValueRead curChanRV >>= updateSynth) >>= putMVar synthHidMVar
149 ------------------------------------------------------------------------------
151 ------------------------------------------------------------------------------
153 reactiveValueOnCanRead addLayerRV $ postGUIAsync $ do
154 np <- reactiveValueRead notebookPageNumber
155 unless (np >= maxLayers) $ do
156 reactiveValueWrite notebookPageNumber (np + 1)
157 nBoardCont <- backgroundContainerNew
159 nGuiBoard <- attachGameRules =<< initGame
160 clickHandler nGuiBoard
161 nCenterBoard <- alignmentNew 0.5 0.5 0 0
162 containerAdd nCenterBoard nGuiBoard
163 containerAdd nBoardCont nCenterBoard
165 notebookAppendPage n nBoardCont $ show np
166 pChan <- reactiveValueRead pageChanRV
167 let newCP = foundHole pChan
168 (nBoardRV, nPieceArrRV, nPhRV) <- initBoardRV tc nGuiBoard
170 reactiveValueRead chanMapRV >>=
171 reactiveValueWrite chanMapRV . M.insert newCP (nBoardRV,nPieceArrRV,nPhRV)
172 reactiveValueRead layerMapRV >>=
173 reactiveValueWrite layerMapRV . M.insert newCP defaultLayerConf
175 --reactiveValueWrite curPageRV newP
176 reactiveValueWrite pageChanRV (pChan ++ [newCP])
179 reactiveValueOnCanRead rmLayerRV $ postGUIAsync $ do
180 np <- reactiveValueRead notebookPageNumber
182 cp <- reactiveValueRead curPageRV
183 oldCP <- reactiveValueRead curChanRV
184 let rmIndex :: Int -> [a] -> [a]
185 rmIndex n l = take n l ++ drop (n + 1) l
186 notebookRemovePage n cp
188 reactiveValueRead pageChanRV >>=
189 reactiveValueWrite pageChanRV . rmIndex cp
191 reactiveValueRead notebookPageNumber >>=
192 reactiveValueWrite notebookPageNumber . subtract 1
194 reactiveValueRead chanMapRV >>=
195 reactiveValueWrite chanMapRV . M.delete oldCP
197 reactiveValueRead layerMapRV >>=
198 reactiveValueWrite layerMapRV . M.delete oldCP
203 reactiveValueOnCanRead curChanRV $ do
204 cp <- reactiveValueRead curChanRV
206 takeMVar dynHidMVar >>= removeCallbackMCBMVar dynMCBMVar
207 takeMVar statHidMVar >>= removeCallbackMCBMVar statMCBMVar
208 takeMVar synthHidMVar >>= removeCallbackMCBMVar synthMCBMVar
209 layerMap <- reactiveValueRead layerMapRV
210 let mSelLayer = M.lookup cp layerMap
211 when (isNothing mSelLayer) $ error "Not found selected layer!"
212 let selLayer = fromJust mSelLayer
213 reactiveValueWrite dynMCBMVar (dynConf selLayer)
214 installCallbackMCBMVar dynMCBMVar (updateDynLayer cp) >>=
216 reactiveValueWrite statMCBMVar (staticConf selLayer)
217 installCallbackMCBMVar statMCBMVar (updateStatLayer cp) >>=
219 reactiveValueWrite synthMCBMVar (synthConf selLayer)
220 installCallbackMCBMVar synthMCBMVar (updateSynth cp) >>=
224 oldCurChanRV <- newCBMVarRW =<< reactiveValueRead curChanRV
225 reactiveValueOnCanRead curChanRV $ do
226 oldC <- reactiveValueRead oldCurChanRV
227 newC <- reactiveValueRead curChanRV
228 when (oldC /= newC) $ do
229 reactiveValueWrite oldCurChanRV newC
230 tryTakeMVar guiCellHidMVar >>=
231 fromMaybeM_ . fmap (removeCallbackMCBMVar guiCellMCBMVar)
232 reactiveValueWrite guiCellMCBMVar inertCell
234 ------------------------------------------------------------------------------
236 ------------------------------------------------------------------------------
237 let phMapRV :: ReactiveFieldRead IO (M.IntMap (ReactiveFieldWrite IO [PlayHead]))
238 phMapRV = liftR (M.map (\(_,_,b) -> b)) chanMapRV
240 boardMapRV :: ReactiveFieldRead IO (M.IntMap Board)
241 boardMapRV = ReactiveFieldRead getter notifier
242 where notifier io = do
243 chanMap <- reactiveValueRead chanMapRV
244 mapM_ ((`reactiveValueOnCanRead` io) . \(b,_,_) -> b) chanMap
246 chanMap <- reactiveValueRead chanMapRV
247 mapM (reactiveValueRead . \(b,_,_) -> b) chanMap
249 return (n, boardMapRV, readOnly layerMapRV, phMapRV)