3 -- Copyright : (c) 2008 Bertram Felgenhauer
6 -- Maintainer : Bertram Felgenhauer <int-e@gmx.de>
7 -- Stability : experimental
8 -- Portability : portable
10 -- This module is part of Haskell PGMS.
23 import qualified Graphics
.UI
.Gtk
as G
24 import System
.Glib
.Attributes
(AttrOp
(..))
26 import Control
.Monad
.Prompt
29 import Data
.Array.IArray
32 backgroundColor
:: G
.Color
33 backgroundColor
= G
.Color
0xE0E0 0xE0E0 0xE0E0
36 frameColor
= G
.Color
0x4040 0x4040 0x4040
38 mainGUI
:: [Strategy
] -> IO ()
40 G
.unsafeInitGUIForThreadedRTS
44 mkMainWindow
:: [Strategy
] -> IO ()
45 mkMainWindow strats
= do
47 win `G
.set`
[G
.windowTitle
:= "Haskell PGMS"]
48 win `G
.onDestroy` G
.mainQuit
50 vbox
<- G
.vBoxNew
False 0
51 win `G
.containerAdd` vbox
53 menubar
<- G
.menuBarNew
54 vbox `G
.containerAdd` menubar
56 board
<- G
.drawingAreaNew
57 vbox `G
.containerAdd` board
59 statusbar
<- G
.statusbarNew
60 vbox `G
.containerAdd` statusbar
62 state
<- newIORef
(initState strats
)
64 let globals
= Globals
{ gBoard
= board
,
65 gStatusbar
= statusbar
,
68 configureBoard globals
70 runItem
<- G
.menuItemNewWithLabel
"Run"
71 menubar `G
.menuShellAppend` runItem
73 runItem `G
.menuItemSetSubmenu` runMenu
75 runRunItem
<- G
.menuItemNewWithLabel
"Run"
76 runMenu `G
.menuShellAppend` runRunItem
77 runRunItem `G
.onActivateLeaf` runGame globals
79 runStatsItem
<- G
.menuItemNewWithLabel
"Statistics..."
80 runMenu `G
.menuShellAppend` runStatsItem
81 runStatsItem `G
.onActivateLeaf` runStats globals
83 G
.separatorMenuItemNew
>>= G
.menuShellAppend runMenu
85 runQuitItem
<- G
.menuItemNewWithLabel
"Quit"
86 runMenu `G
.menuShellAppend` runQuitItem
87 runQuitItem `G
.onActivateLeaf` G
.widgetDestroy win
89 difficultyItem
<- G
.menuItemNewWithLabel
"Difficulty"
90 menubar `G
.menuShellAppend` difficultyItem
91 difficultyMenu
<- G
.menuNew
92 difficultyItem `G
.menuItemSetSubmenu` difficultyMenu
93 Just prev
<- foldM (\prev
(name
, cfg
) -> do
94 item <- maybe G
.radioMenuItemNewWithLabel
95 G
.radioMenuItemNewWithLabelFromWidget
97 item `G
.onActivateLeaf` selectConfig
item cfg globals
98 difficultyMenu `G
.menuShellAppend`
item
101 G
.separatorMenuItemNew
>>= G
.menuShellAppend difficultyMenu
102 customItem
<- G
.radioMenuItemNewWithLabelFromWidget prev
"Custom..."
103 customItem `G
.onActivateLeaf` customConfig customItem globals
104 difficultyMenu `G
.menuShellAppend` customItem
106 strategyItem
<- G
.menuItemNewWithLabel
"Strategy"
107 menubar `G
.menuShellAppend` strategyItem
108 strategyMenu
<- G
.menuNew
109 strategyItem `G
.menuItemSetSubmenu` strategyMenu
110 foldM (\prev strat
-> do
111 item <- maybe G
.radioMenuItemNewWithLabel
112 G
.radioMenuItemNewWithLabelFromWidget
114 strategyMenu `G
.menuShellAppend`
item
115 item `G
.onActivateLeaf` selectStrategy strat globals
121 configureBoard
:: Globals
-> IO ()
122 configureBoard g
= do
125 iconFile
<- findFile
"icons.png"
126 icons
<- G
.pixbufNewFromFile iconFile
127 iconSize
<- G
.pixbufGetWidth icons
128 G
.widgetSetSizeRequest area
(pX maxSize
* iconSize
+ 2)
129 (pY maxSize
* iconSize
+ 2)
131 area `G
.onExpose`
\_
-> do
132 s
<- readIORef
(gState g
)
133 let board
= maybe empty id (sBoard s
)
134 makeArray e
= listArray (Pos
1 1, cSize
(sConfig s
)) (repeat e
)
137 bMines
= makeArray
False,
138 bView
= makeArray Hidden
,
140 drawBoard iconSize icons area
(sConfig s
) board
144 drawBoard
:: Int -> G
.Pixbuf
-> G
.DrawingArea
-> Config
-> Board
-> IO ()
145 drawBoard iconSize icons area cfg board
= do
146 (w
, h
) <- G
.widgetGetSize area
147 let Pos sX sY
= cSize cfg
148 ox
= (w
- sX
* iconSize
) `
div`
2
149 oy
= (h
- sY
* iconSize
) `
div`
2
150 draw
<- G
.widgetGetDrawWindow area
152 gc
<- G
.gcNewWithValues draw G
.newGCValues
153 let drawCell
(Pos x y
) n
= G
.drawPixbuf draw gc icons
154 0 (n
* iconSize
) (ox
+ (x
-1)*iconSize
) (oy
+ (y
-1)*iconSize
)
155 iconSize iconSize G
.RgbDitherNone
0 0
157 forM_
(assocs (bView board
)) $ \(p
, cell
) -> case cell
of
158 Exposed n
-> drawCell p n
159 Hidden
-> drawCell p
(9 + fromEnum (bMines board
! p
))
160 Marked
-> drawCell p
(11 + fromEnum (bMines board
! p
))
161 Exploded
-> drawCell p
13
163 G
.gcSetValues gc G
.newGCValues
{ G
.foreground
= backgroundColor
}
164 G
.drawRectangle draw gc
False (ox
- 1) (oy
- 1)
165 (sX
* iconSize
+ 1) (sY
* iconSize
+ 1)
166 G
.gcSetValues gc G
.newGCValues
{ G
.foreground
= frameColor
}
167 G
.drawRectangle draw gc
False (ox
- 2) (oy
- 2)
168 (sX
* iconSize
+ 3) (sY
* iconSize
+ 3)
170 runGame
:: Globals
-> IO ()
172 s
<- readIORef
(gState g
)
173 maybe runGame
' (\_
-> return False) (sStop s
)
180 s
<- readIORef
(gState g
)
181 runPromptC finish handle
(playGameP
(sConfig s
) gen1
182 (sRun
(sStrategy s
) gen2
))
184 handle
:: Play a
-> (a
-> IO Bool) -> IO Bool
185 handle
(Start b
) c
= do
189 handle
(Update p b
) c
= do
192 handle
(Trace s b
) c
= do
197 finish
:: (Result
String, Board
) -> IO Bool
201 finish
(Lost
, b
) = do
204 finish
(Unfinished s
, b
) = do
205 msg
("Unfinished: " ++ s
)
208 cont
:: (a
-> IO Bool) -> a
-> IO ()
210 hdl
<- flip G
.timeoutAdd
120 $ do
211 modifyIORef
(gState g
) $ \s
-> s
{ sStop
= Nothing
}
213 modifyIORef
(gState g
) $ \s
-> s
{ sStop
= Just
(G
.timeoutRemove hdl
) }
215 setBoard
:: Board
-> IO Bool
217 modifyIORef
(gState g
) $ \s
-> s
{ sBoard
= Just b
}
218 G
.widgetQueueDraw
(gBoard g
)
221 msg
:: String -> IO G
.MessageId
223 G
.statusbarPush
(gStatusbar g
) 1 s