-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLifeGUI.hs
173 lines (128 loc) · 4.44 KB
/
LifeGUI.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade
import Graphics.Rendering.Cairo
import Control.Monad.Trans ( liftIO )
import Control.Concurrent (threadDelay)
import Life
width, height :: Int
width = 500
height = 500
rows, columns :: Int
rows = 10
columns = 10
borderWidth :: Double
borderWidth = 1.0
cellWidth, cellHeight :: Double
cellWidth = (fromIntegral width) / (fromIntegral columns)
cellHeight = (fromIntegral height) / (fromIntegral rows)
run :: Render () -> IO ()
run act = do
initGUI
dia <- dialogNew
dialogAddButton dia stockClose ResponseClose
contain <- dialogGetUpper dia
canvas <- drawingAreaNew
canvas `onSizeRequest` return (Requisition (fromIntegral width) (fromIntegral height))
canvas `onExpose` updateCanvas canvas act
boxPackStartDefaults contain canvas
widgetShow canvas
dialogRun dia
widgetDestroy dia
-- Flush all commands that are waiting to be sent to the graphics server.
-- This ensures that the window is actually closed before ghci displays the
-- prompt again.
flush
where updateCanvas :: DrawingArea -> Render () -> Event -> IO Bool
updateCanvas canvas act (Expose {}) = do
win <- widgetGetDrawWindow canvas
renderWithDrawable win act
return True
updateCanvas canvas act _ = return False
setRed :: Render ()
setRed = do
setSourceRGB 1 0 0
setFat :: Render ()
setFat = do
setLineWidth 20
setLineCap LineCapRound
drawSquare :: Double -> Double -> Render ()
drawSquare width height = do
(x,y) <- getCurrentPoint
lineTo (x+width) y
lineTo (x+width) (y+height)
lineTo x (y+height)
closePath
stroke
drawHCirc :: Double -> Double -> Double -> Render ()
drawHCirc x y radius = do
arc x y radius 0 pi
stroke
drawStr :: String -> Render ()
drawStr txt = do
lay <- createLayout txt
showLayout lay
drawStr_ :: String -> Render ()
drawStr_ txt = do
lay <- liftIO $ do
ctxt <- cairoCreateContext Nothing
descr <- contextGetFontDescription ctxt
descr `fontDescriptionSetSize` 20
ctxt `contextSetFontDescription` descr
layoutText ctxt txt
showLayout lay
updateCanvas :: DrawingArea -> Render () -> Event -> IO Bool
updateCanvas canvas act (Expose {}) = do win <- widgetGetDrawWindow canvas
renderWithDrawable win act
return True
updateCanvas canvas act _ = return False
drawBoard :: Board -> Render ()
drawBoard board = do
setLineWidth borderWidth
drawBorder
drawVerticalLines
drawHorizontalLines
drawLife board
where
drawLife :: Board -> Render ()
drawLife board = sequenceMap drawLiveCell (map translate board)
translate :: Position -> (Double, Double)
translate (x, y) = ((fromIntegral x) * cellWidth,
(fromIntegral y) * cellHeight)
drawLiveCell :: (Double, Double) -> Render ()
drawLiveCell (x, y) = setRed >> (moveTo x y) >> (drawSquare cellWidth cellHeight)
drawBorder :: Render ()
drawBorder = do
moveTo 0 0
drawSquare (fromIntegral width) (fromIntegral height)
drawVerticalLines = sequenceMap drawVertical (finiteIterate columns cellWidth)
drawHorizontalLines = sequenceMap drawHorizontal (finiteIterate rows cellHeight)
finiteIterate :: Int -> Double -> [Double]
finiteIterate count size = take count (iterate (+ size) size)
drawVertical :: Double -> Render ()
drawVertical x = do
moveTo x 0
lineTo x (fromIntegral height)
closePath
stroke
drawHorizontal :: Double -> Render ()
drawHorizontal y = do
moveTo 0 y
lineTo (fromIntegral width) y
closePath
stroke
sequenceMap :: (a -> Render ()) -> [a] -> Render ()
sequenceMap f list = sequence_ (map f list)
glider :: Board
glider = [(4,2), (2,3), (4,3), (3,4), (4,4)]
main = do initGUI
Just xml <- xmlNew "LifeGUI.glade"
window <- xmlGetWidget xml castToWindow "window"
onDestroy window mainQuit
canvas <- xmlGetWidget xml castToDrawingArea "drawingArea"
canvas `onSizeRequest` return (Requisition (fromIntegral width) (fromIntegral height))
canvas `onExpose` updateCanvas canvas (drawBoard glider)
stepButton <- xmlGetWidget xml castToButton "button1"
onClicked stepButton $ do (updateCanvas canvas (drawBoard (nextGeneration glider)) (Expose {}))
return ()
widgetShowAll window
mainGUI