1 {-# LANGUAGE GADTs, BangPatterns #-}
13 import qualified Graphics
.UI
.Gtk
as G
14 import System
.Glib
.Attributes
(AttrOp
(..))
16 import Control
.Monad
.Prompt
22 backgroundColor
:: G
.Color
23 backgroundColor
= G
.Color
0xE0E0 0xE0E0 0xE0E0
26 frameColor
= G
.Color
0x4040 0x4040 0x4040
28 mainGUI
:: [Strategy
] -> IO ()
30 G
.unsafeInitGUIForThreadedRTS
34 mkMainWindow
:: [Strategy
] -> IO ()
35 mkMainWindow strats
= do
37 win `G
.set`
[G
.windowTitle
:= "Haskell PGMS"]
38 win `G
.onDestroy` G
.mainQuit
40 vbox
<- G
.vBoxNew
False 0
41 win `G
.containerAdd` vbox
43 menubar
<- G
.menuBarNew
44 vbox `G
.containerAdd` menubar
46 board
<- G
.drawingAreaNew
47 vbox `G
.containerAdd` board
49 statusbar
<- G
.statusbarNew
50 vbox `G
.containerAdd` statusbar
52 state
<- newIORef
(initState strats
)
54 let globals
= Globals
{ gBoard
= board
,
55 gStatusbar
= statusbar
,
58 configureBoard globals
60 runItem
<- G
.menuItemNewWithLabel
"Run"
61 menubar `G
.menuShellAppend` runItem
63 runItem `G
.menuItemSetSubmenu` runMenu
65 runRunItem
<- G
.menuItemNewWithLabel
"Run"
66 runMenu `G
.menuShellAppend` runRunItem
67 runRunItem `G
.onActivateLeaf` runGame globals
69 runStatsItem
<- G
.menuItemNewWithLabel
"Statistics..."
70 runMenu `G
.menuShellAppend` runStatsItem
71 runStatsItem `G
.onActivateLeaf` runStats globals
73 G
.separatorMenuItemNew
>>= G
.menuShellAppend runMenu
75 runQuitItem
<- G
.menuItemNewWithLabel
"Quit"
76 runMenu `G
.menuShellAppend` runQuitItem
77 runQuitItem `G
.onActivateLeaf` G
.widgetDestroy win
79 difficultyItem
<- G
.menuItemNewWithLabel
"Difficulty"
80 menubar `G
.menuShellAppend` difficultyItem
81 difficultyMenu
<- G
.menuNew
82 difficultyItem `G
.menuItemSetSubmenu` difficultyMenu
83 Just prev
<- foldM (\prev
(name
, cfg
) -> do
84 item <- maybe G
.radioMenuItemNewWithLabel
85 G
.radioMenuItemNewWithLabelFromWidget
87 item `G
.onActivateLeaf` selectConfig
item cfg globals
88 difficultyMenu `G
.menuShellAppend`
item
91 G
.separatorMenuItemNew
>>= G
.menuShellAppend difficultyMenu
92 customItem
<- G
.radioMenuItemNewWithLabelFromWidget prev
"Custom..."
93 customItem `G
.onActivateLeaf` customConfig customItem globals
94 difficultyMenu `G
.menuShellAppend` customItem
96 strategyItem
<- G
.menuItemNewWithLabel
"Strategy"
97 menubar `G
.menuShellAppend` strategyItem
98 strategyMenu
<- G
.menuNew
99 strategyItem `G
.menuItemSetSubmenu` strategyMenu
100 foldM (\prev strat
-> do
101 item <- maybe G
.radioMenuItemNewWithLabel
102 G
.radioMenuItemNewWithLabelFromWidget
104 strategyMenu `G
.menuShellAppend`
item
105 item `G
.onActivateLeaf` selectStrategy strat globals
111 configureBoard
:: Globals
-> IO ()
112 configureBoard g
= do
115 iconFile
<- findFile
"icons.png"
116 icons
<- G
.pixbufNewFromFile iconFile
117 iconSize
<- G
.pixbufGetWidth icons
118 G
.widgetSetSizeRequest area
(pX maxSize
* iconSize
+ 2)
119 (pY maxSize
* iconSize
+ 2)
121 area `G
.onExpose`
\_
-> do
122 s
<- readIORef
(gState g
)
123 let board
= maybe empty id (sBoard s
)
124 makeArray
= listArray (Pos
1 1, cSize
(sConfig s
)) . repeat
127 bMines
= makeArray
False,
128 bView
= makeArray Hidden
,
130 drawBoard iconSize icons area
(sConfig s
) board
134 drawBoard
:: Int -> G
.Pixbuf
-> G
.DrawingArea
-> Config
-> Board
-> IO ()
135 drawBoard iconSize icons area cfg board
= do
136 (w
, h
) <- G
.widgetGetSize area
137 let Pos sx sy
= cSize cfg
138 ox
= (w
- sx
* iconSize
) `
div`
2
139 oy
= (h
- sy
* iconSize
) `
div`
2
140 draw
<- G
.widgetGetDrawWindow area
142 gc
<- G
.gcNewWithValues draw G
.newGCValues
143 let drawCell
(Pos x y
) n
= G
.drawPixbuf draw gc icons
144 0 (n
* iconSize
) (ox
+ (x
-1)*iconSize
) (oy
+ (y
-1)*iconSize
)
145 iconSize iconSize G
.RgbDitherNone
0 0
147 forM_
(assocs (bView board
)) $ \(p
, cell
) -> case cell
of
148 Exposed n
-> drawCell p n
149 Hidden
-> drawCell p
(9 + fromEnum (bMines board
! p
))
150 Marked
-> drawCell p
(11 + fromEnum (bMines board
! p
))
151 Exploded
-> drawCell p
13
153 G
.gcSetValues gc G
.newGCValues
{ G
.foreground
= backgroundColor
}
154 G
.drawRectangle draw gc
False (ox
- 1) (oy
- 1)
155 (sx
* iconSize
+ 1) (sy
* iconSize
+ 1)
156 G
.gcSetValues gc G
.newGCValues
{ G
.foreground
= frameColor
}
157 G
.drawRectangle draw gc
False (ox
- 2) (oy
- 2)
158 (sx
* iconSize
+ 3) (sy
* iconSize
+ 3)
160 runGame
:: Globals
-> IO ()
162 s
<- readIORef
(gState g
)
163 maybe runGame
' (\_
-> return False) (sStop s
)
170 s
<- readIORef
(gState g
)
171 runPromptC finish handle
(playGameP
(sConfig s
) gen1
172 (sRun
(sStrategy s
) gen2
))
174 handle
:: Play a
-> (a
-> IO Bool) -> IO Bool
175 handle
(Start b
) c
= do
179 handle
(Update p b
) c
= do
182 handle
(Trace s b
) c
= do
187 finish
:: (Result
String, Board
) -> IO Bool
191 finish
(Lost
, b
) = do
194 finish
(Unfinished s
, b
) = do
195 msg
("Unfinished: " ++ s
)
198 cont
:: (a
-> IO Bool) -> a
-> IO ()
200 hdl
<- flip G
.timeoutAdd
120 $ do
201 modifyIORef
(gState g
) $ \s
-> s
{ sStop
= Nothing
}
203 modifyIORef
(gState g
) $ \s
-> s
{ sStop
= Just
(G
.timeoutRemove hdl
) }
205 setBoard
:: Board
-> IO Bool
207 modifyIORef
(gState g
) $ \s
-> s
{ sBoard
= Just b
}
208 G
.widgetQueueDraw
(gBoard g
)
211 msg
:: String -> IO G
.MessageId
213 G
.statusbarPush
(gStatusbar g
) 1 s