1 {-# LANGUAGE FlexibleContexts, MultiParamTypeClasses #-}
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
18 import RMCA.Global.Clock
20 import RMCA.Layer.Layer
24 createNotebook :: ( ReactiveValueRead addLayer () IO
25 , ReactiveValueRead rmLayer () IO
33 , ReactiveFieldRead IO (M.IntMap Board)
34 , ReactiveFieldRead IO (M.IntMap Layer)
35 , ReactiveFieldRead IO
36 (M.IntMap (ReactiveFieldWrite IO [PlayHead]))
38 createNotebook tc addLayerRV rmLayerRV layerMCBMVar guiCellMCBMVar = do
40 let curPageRV = ReactiveFieldReadWrite setter getter notifier
41 where (ReactiveFieldRead getter _) = notebookGetCurrentPagePassive n
42 -- afterSwitchPage is deprecated but switchPage gets us
43 -- the old page number and not the new one and using
44 -- afterSwitchPage doesn't trigger a warning.
45 setter = postGUIAsync . notebookSetCurrentPage n
46 notifier io = void $ afterSwitchPage n (const io)
48 pageChanRV <- newCBMVarRW []
49 let foundHole = let foundHole' [] = 0
50 foundHole' [x] = x + 1
51 foundHole' (x:y:xs) = if x + 1 /= y then x + 1 else foundHole (y:xs)
55 let curChanRV = liftR2 (!!) pageChanRV curPageRV
56 ------------------------------------------------------------------------------
58 ------------------------------------------------------------------------------
60 chanMapRV <- newCBMVarRW M.empty
61 guiCellHidMVar <- newEmptyMVar
62 let clickHandler ioBoard = do
65 (\iPos' -> liftIO $ do
66 let iPos = actualTile iPos'
67 postGUIAsync $ void $ tryPutMVar state iPos
70 boardOnRelease ioBoard
72 let fPos = actualTile fPos'
74 liftIO $ postGUIAsync $ do
75 mp <- boardGetPiece fPos ioBoard
76 mstate <- tryTakeMVar state
77 when (fPos `elem` validArea && isJust mp) $ do
78 let piece = snd $ fromJust mp
79 when (button == RightButton && maybe False (== fPos) mstate) $ do
80 let nCell = rotateGUICell piece
81 boardSetPiece fPos (Player,nCell) ioBoard
82 nmp <- boardGetPiece fPos ioBoard
83 when (button == LeftButton && isJust nmp) $ do
84 let nCell = snd $ fromJust nmp
85 mOHid <- tryTakeMVar guiCellHidMVar
86 forM_ mOHid $ removeCallbackMCBMVar guiCellMCBMVar
87 reactiveValueWrite guiCellMCBMVar nCell
88 nHid <- installCallbackMCBMVar guiCellMCBMVar $ do
89 cp <- reactiveValueRead curChanRV
90 guiVal <- reactiveValueRead guiCellMCBMVar
91 mChanRV <- M.lookup cp <$> reactiveValueRead chanMapRV
92 when (isNothing mChanRV) $ error "Can't get piece array!"
93 let (_,pieceArrRV,_) = fromJust mChanRV
94 reactiveValueWrite (pieceArrRV ! fPos) guiVal
95 putMVar guiCellHidMVar nHid
99 boardCont <- backgroundContainerNew
100 guiBoard <- attachGameRules =<< initGame
101 clickHandler guiBoard
102 centerBoard <- alignmentNew 0.5 0.5 0 0
103 containerAdd centerBoard guiBoard
104 containerAdd boardCont centerBoard
106 fstP <- notebookAppendPage n boardCont "Lol first"
107 notebookPageNumber <- newCBMVarRW (1 :: Int)
109 initBoardRV tc guiBoard >>=
110 \(boardRV, pieceArrRV, phRV) -> reactiveValueRead chanMapRV >>=
111 reactiveValueWrite chanMapRV . M.insert fstP (boardRV,pieceArrRV,phRV)
113 reactiveValueRead pageChanRV >>=
114 reactiveValueWrite pageChanRV . (\pc -> pc ++ [foundHole pc])
115 layerMapRV <- newCBMVarRW $ M.insert fstP defaultLayer M.empty
117 let updateLayer cp = do
118 nLayer <- reactiveValueRead layerMCBMVar
119 reactiveValueRead layerMapRV >>=
120 reactiveValueWrite layerMapRV . M.insert cp nLayer
122 layerHidMVar <- newEmptyMVar
124 installCallbackMCBMVar layerMCBMVar
125 (reactiveValueRead curChanRV >>= updateLayer) >>= putMVar layerHidMVar
127 ------------------------------------------------------------------------------
129 ------------------------------------------------------------------------------
131 reactiveValueOnCanRead addLayerRV $ postGUIAsync $ do
132 np <- reactiveValueRead notebookPageNumber
133 unless (np >= 16) $ do
134 reactiveValueWrite notebookPageNumber (np + 1)
135 nBoardCont <- backgroundContainerNew
137 nGuiBoard <- attachGameRules =<< initGame
138 clickHandler nGuiBoard
139 nCenterBoard <- alignmentNew 0.5 0.5 0 0
140 containerAdd nCenterBoard nGuiBoard
141 containerAdd nBoardCont nCenterBoard
143 notebookAppendPage n nBoardCont $ show np
144 pChan <- reactiveValueRead pageChanRV
145 let newCP = foundHole pChan
146 (nBoardRV, nPieceArrRV, nPhRV) <- initBoardRV tc nGuiBoard
148 reactiveValueRead chanMapRV >>=
149 reactiveValueWrite chanMapRV . M.insert newCP (nBoardRV,nPieceArrRV,nPhRV)
150 reactiveValueRead layerMapRV >>=
151 reactiveValueWrite layerMapRV . M.insert newCP defaultLayer
153 --reactiveValueWrite curPageRV newP
154 reactiveValueWrite pageChanRV (pChan ++ [newCP])
157 reactiveValueOnCanRead rmLayerRV $ postGUIAsync $ do
158 np <- reactiveValueRead notebookPageNumber
160 cp <- reactiveValueRead curPageRV
161 oldCP <- reactiveValueRead curChanRV
162 let rmIndex :: Int -> [a] -> [a]
163 rmIndex n l = take n l ++ drop (n + 1) l
164 notebookRemovePage n cp
166 reactiveValueRead pageChanRV >>=
167 reactiveValueWrite pageChanRV . rmIndex cp
169 reactiveValueRead notebookPageNumber >>=
170 reactiveValueWrite notebookPageNumber . subtract 1
172 reactiveValueRead chanMapRV >>=
173 reactiveValueWrite chanMapRV . M.delete oldCP
174 reactiveValueRead layerMapRV >>=
175 reactiveValueWrite layerMapRV . M.delete oldCP
182 reactiveValueOnCanRead curChanRV $ do
183 cp <- reactiveValueRead curChanRV
185 takeMVar layerHidMVar >>= removeCallbackMCBMVar layerMCBMVar
186 layerMap <- reactiveValueRead layerMapRV
187 let mSelLayer = M.lookup cp layerMap
188 when (isNothing mSelLayer) $ error "Not found selected layer!"
189 let selLayer = fromJust mSelLayer
190 reactiveValueWrite layerMCBMVar selLayer
191 installCallbackMCBMVar layerMCBMVar (updateLayer cp) >>=
195 oldCurChanRV <- newCBMVarRW =<< reactiveValueRead curChanRV
196 reactiveValueOnCanRead curChanRV $ do
197 oldC <- reactiveValueRead oldCurChanRV
198 newC <- reactiveValueRead curChanRV
199 when (oldC /= newC) $ do
200 reactiveValueWrite oldCurChanRV newC
201 tryTakeMVar guiCellHidMVar >>=
202 fromMaybeM_ . fmap (removeCallbackMCBMVar guiCellMCBMVar)
203 reactiveValueWrite guiCellMCBMVar inertCell
205 ------------------------------------------------------------------------------
207 ------------------------------------------------------------------------------
208 let {-phMapRV :: ReactiveFieldWrite IO (M.IntMap [PlayHead])
209 phMapRV = ReactiveFieldWrite setter
210 where setter phM = sequence_ $ M.mapWithKey writePhs phM
211 writePhs :: Int -> [PlayHead] -> IO ()
212 writePhs k phs = do chanMap <- reactiveValueRead chanMapRV
213 let mselChan = M.lookup k chanMap
214 when (isNothing mselChan) $
215 error "Can't find layer!"
216 let (_,_,phsRV) = fromJust mselChan
217 reactiveValueWrite phsRV phs
219 phMapRV :: ReactiveFieldRead IO (M.IntMap (ReactiveFieldWrite IO [PlayHead]))
220 phMapRV = liftR (M.map (\(_,_,b) -> b)) chanMapRV
222 boardMapRV :: ReactiveFieldRead IO (M.IntMap Board)
223 boardMapRV = ReactiveFieldRead getter notifier
224 where notifier io = do
225 chanMap <- reactiveValueRead chanMapRV
226 mapM_ ((`reactiveValueOnCanRead` io) . \(b,_,_) -> b) chanMap
228 chanMap <- reactiveValueRead chanMapRV
229 mapM (reactiveValueRead . \(b,_,_) -> b) chanMap
231 return (n, boardMapRV, readOnly layerMapRV, phMapRV)