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.BoardLink
15 import Graphics.UI.Gtk.Board.TiledBoard hiding (Board)
16 import Graphics.UI.Gtk.Layout.BackgroundContainer
17 import Graphics.UI.Gtk.Reactive.Gtk2
20 import RMCA.Layer.Layer
24 createNotebook :: ( ReactiveValueRead addLayer () IO
25 , ReactiveValueRead rmLayer () IO
32 , ReactiveFieldRead IO (M.IntMap Board)
33 , ReactiveFieldRead IO (M.IntMap Layer)
34 , ReactiveFieldRead IO
35 (M.IntMap (ReactiveFieldWrite IO [PlayHead]))
37 createNotebook addLayerRV rmLayerRV layerMCBMVar guiCellMCBMVar = do
39 let curPageRV = ReactiveFieldReadWrite setter getter notifier
40 where (ReactiveFieldRead getter _) = notebookGetCurrentPagePassive n
41 -- afterSwitchPage is deprecated but switchPage gets us
42 -- the old page number and not the new one and using
43 -- afterSwitchPage doesn't trigger a warning.
44 setter = postGUIAsync . notebookSetCurrentPage n
45 notifier io = void $ afterSwitchPage n (const io)
47 pageChanRV <- newCBMVarRW []
48 let foundHole = let foundHole' [] = 0
49 foundHole' [x] = x + 1
50 foundHole' (x:y:xs) = if x + 1 /= y then x + 1 else foundHole (y:xs)
54 let curChanRV = liftR2 (!!) pageChanRV curPageRV
55 ------------------------------------------------------------------------------
57 ------------------------------------------------------------------------------
59 chanMapRV <- newCBMVarRW M.empty
60 guiCellHidMVar <- newEmptyMVar
61 let clickHandler ioBoard = do
65 postGUIAsync $ void $ tryPutMVar state iPos
68 boardOnRelease ioBoard
71 liftIO $ postGUIAsync $ do
72 mp <- boardGetPiece fPos ioBoard
73 mstate <- tryTakeMVar state
74 when (fPos `elem` validArea && isJust mp) $ do
75 let piece = snd $ fromJust mp
76 when (button == RightButton && maybe False (== fPos) mstate) $ do
77 let nCell = rotateGUICell piece
78 boardSetPiece fPos (Player,nCell) ioBoard
79 nmp <- boardGetPiece fPos ioBoard
80 when (button == LeftButton && isJust nmp) $ do
81 let nCell = snd $ fromJust nmp
82 mOHid <- tryTakeMVar guiCellHidMVar
83 forM_ mOHid $ removeCallbackMCBMVar guiCellMCBMVar
84 reactiveValueWrite guiCellMCBMVar nCell
85 nHid <- installCallbackMCBMVar guiCellMCBMVar $ do
86 cp <- reactiveValueRead curChanRV
87 guiVal <- reactiveValueRead guiCellMCBMVar
88 mChanRV <- M.lookup cp <$> reactiveValueRead chanMapRV
89 when (isNothing mChanRV) $ error "Can't get piece array!"
90 let (_,pieceArrRV,_) = fromJust mChanRV
91 reactiveValueWrite (pieceArrRV ! fPos) guiVal
92 putMVar guiCellHidMVar nHid
96 boardCont <- backgroundContainerNew
97 guiBoard <- attachGameRules =<< initGame
99 centerBoard <- alignmentNew 0.5 0.5 0 0
100 containerAdd centerBoard guiBoard
101 containerAdd boardCont centerBoard
103 fstP <- notebookAppendPage n boardCont "Lol first"
104 notebookPageNumber <- newCBMVarRW (1 :: Int)
106 initBoardRV guiBoard >>=
107 \(boardRV, pieceArrRV, phRV) -> reactiveValueRead chanMapRV >>=
108 reactiveValueWrite chanMapRV . M.insert fstP (boardRV,pieceArrRV,phRV)
110 reactiveValueRead pageChanRV >>=
111 reactiveValueWrite pageChanRV . (\pc -> pc ++ [foundHole pc])
112 layerMapRV <- newCBMVarRW $ M.insert fstP defaultLayer M.empty
114 let updateLayer cp = do
115 nLayer <- reactiveValueRead layerMCBMVar
116 reactiveValueRead layerMapRV >>=
117 reactiveValueWrite layerMapRV . M.insert cp nLayer
119 layerHidMVar <- newEmptyMVar
121 installCallbackMCBMVar layerMCBMVar
122 (reactiveValueRead curChanRV >>= updateLayer) >>= putMVar layerHidMVar
124 ------------------------------------------------------------------------------
126 ------------------------------------------------------------------------------
128 reactiveValueOnCanRead addLayerRV $ postGUIAsync $ do
129 np <- reactiveValueRead notebookPageNumber
130 unless (np >= 16) $ do
131 reactiveValueWrite notebookPageNumber (np + 1)
132 nBoardCont <- backgroundContainerNew
134 nGuiBoard <- attachGameRules =<< initGame
135 clickHandler nGuiBoard
136 nCenterBoard <- alignmentNew 0.5 0.5 0 0
137 containerAdd nCenterBoard nGuiBoard
138 containerAdd nBoardCont nCenterBoard
140 notebookAppendPage n nBoardCont $ show np
141 pChan <- reactiveValueRead pageChanRV
142 let newCP = foundHole pChan
143 (nBoardRV, nPieceArrRV, nPhRV) <- initBoardRV nGuiBoard
145 reactiveValueRead chanMapRV >>=
146 reactiveValueWrite chanMapRV . M.insert newCP (nBoardRV,nPieceArrRV,nPhRV)
147 reactiveValueRead layerMapRV >>=
148 reactiveValueWrite layerMapRV . M.insert newCP defaultLayer
150 --reactiveValueWrite curPageRV newP
151 reactiveValueWrite pageChanRV (pChan ++ [newCP])
154 reactiveValueOnCanRead rmLayerRV $ postGUIAsync $ do
155 np <- reactiveValueRead notebookPageNumber
157 cp <- reactiveValueRead curPageRV
158 oldCP <- reactiveValueRead curChanRV
159 let rmIndex :: Int -> [a] -> [a]
160 rmIndex n l = take n l ++ drop (n + 1) l
161 notebookRemovePage n cp
163 reactiveValueRead pageChanRV >>=
164 reactiveValueWrite pageChanRV . rmIndex cp
166 reactiveValueRead notebookPageNumber >>=
167 reactiveValueWrite notebookPageNumber . subtract 1
169 reactiveValueRead chanMapRV >>=
170 reactiveValueWrite chanMapRV . M.delete oldCP
171 reactiveValueRead layerMapRV >>=
172 reactiveValueWrite layerMapRV . M.delete oldCP
179 reactiveValueOnCanRead curChanRV $ do
180 cp <- reactiveValueRead curChanRV
182 takeMVar layerHidMVar >>= removeCallbackMCBMVar layerMCBMVar
183 layerMap <- reactiveValueRead layerMapRV
184 let mSelLayer = M.lookup cp layerMap
185 when (isNothing mSelLayer) $ error "Not found selected layer!"
186 let selLayer = fromJust mSelLayer
187 reactiveValueWrite layerMCBMVar selLayer
188 installCallbackMCBMVar layerMCBMVar (updateLayer cp) >>=
192 oldCurChanRV <- newCBMVarRW =<< reactiveValueRead curChanRV
193 reactiveValueOnCanRead curChanRV $ do
194 oldC <- reactiveValueRead oldCurChanRV
195 newC <- reactiveValueRead curChanRV
196 when (oldC /= newC) $ do
197 reactiveValueWrite oldCurChanRV newC
198 tryTakeMVar guiCellHidMVar >>=
199 fromMaybeM_ . fmap (removeCallbackMCBMVar guiCellMCBMVar)
200 reactiveValueWrite guiCellMCBMVar inertCell
202 ------------------------------------------------------------------------------
204 ------------------------------------------------------------------------------
205 let {-phMapRV :: ReactiveFieldWrite IO (M.IntMap [PlayHead])
206 phMapRV = ReactiveFieldWrite setter
207 where setter phM = sequence_ $ M.mapWithKey writePhs phM
208 writePhs :: Int -> [PlayHead] -> IO ()
209 writePhs k phs = do chanMap <- reactiveValueRead chanMapRV
210 let mselChan = M.lookup k chanMap
211 when (isNothing mselChan) $
212 error "Can't find layer!"
213 let (_,_,phsRV) = fromJust mselChan
214 reactiveValueWrite phsRV phs
216 phMapRV :: ReactiveFieldRead IO (M.IntMap (ReactiveFieldWrite IO [PlayHead]))
217 phMapRV = liftR (M.map (\(_,_,b) -> b)) chanMapRV
219 boardMapRV :: ReactiveFieldRead IO (M.IntMap Board)
220 boardMapRV = ReactiveFieldRead getter notifier
221 where notifier io = do
222 chanMap <- reactiveValueRead chanMapRV
223 mapM_ ((`reactiveValueOnCanRead` io) . \(b,_,_) -> b) chanMap
225 chanMap <- reactiveValueRead chanMapRV
226 mapM (reactiveValueRead . \(b,_,_) -> b) chanMap
228 return (n, boardMapRV, readOnly layerMapRV, phMapRV)