/
widgets.py
332 lines (312 loc) · 11.8 KB
/
widgets.py
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
from harmless7drl import Widget
import string
import time
from textwrap import TextWrapper
import sys
MovementKeys = { # authoritative in gamewidget.py
'h': (-1, 0),
'l': (1, 0),
'j': (0, 1),
'k': (0, -1),
'y': (-1, -1),
'u': (1, -1),
'b': (-1, 1),
'n': (1, 1),
'west': (-1, 0),
'east': (1, 0),
'south': (0, 1),
'north': (0, -1),
'northwest': (-1, -1),
'northeast': (1, -1),
'southwest': (-1, 1),
'southeast': (1, 1),
}
def blinkphase(n = 2, phaselength = 0.5):
import time
return int( (time.time() % (n * phaselength)) / phaselength )
from harmless7drl import getCfg
prettymenu = getCfg( "tcod", "prettymenu" ) == "yes"
if prettymenu:
PrimaryColour = 'tcod-primary'
SecondaryColour = 'tcod-secondary'
BorderColour = 'tcod-border'
HighlightPrimaryColour = 'tcod-primary-hl'
HighlightSecondaryColour = 'tcod-secondary-hl'
else:
PrimaryColour = 'white'
SecondaryColour = 'blue'
BorderColour = SecondaryColour
HighlightPrimaryColour, HighlightSecondaryColour = SecondaryColour, PrimaryColour
PrimaryColourRGB = 158, 0, 156
BorderColourRGB = 106, 0, 105
SecondaryColourRGB = 182,151,91
HighlightPrimaryColourRGB = PrimaryColourRGB
HighlightSecondaryColourRGB = 255, 255, 255
class ClippedException: pass
class Subwindow:
def __init__(self, ui, x0, y0, w, h):
self.ui = ui
self.x0, self.y0 = x0, y0
self.w, self.h = w, h
def transform(self, x, y):
if x < 0 or y < 0 or x >= self.w or y >= self.h:
raise ClippedException()
x, y = x + self.x0, y + self.y0
return x,y
def put(self, x, y, *args, **kwargs):
try:
x, y = self.transform(x, y)
self.ui.put( x, y, *args, **kwargs )
except ClippedException:
pass
def putString(self, x, y, s, *args, **kwargs):
for ch in s:
self.put( x, y, ch, *args, **kwargs)
x += 1
return x
def decorate(self, borderColour, insideColour):
for x in range( self.w ):
for y in range( self.h ):
col = insideColour
if x == 0 or y == 0 or x+1 == self.w or y+1 == self.h:
col = borderColour
self.put( x, y, ' ', col, col )
def centeredSubwindow( ui, w, h ):
wid, hei = ui.dimensions()
x0 = int( (wid-w) / 2 + 0.5 )
y0 = int( (hei-h) / 2 + 0.5 )
x0 = max( 0, x0 )
y0 = max( 0, y0 )
w = min( w, wid - x0 )
h = min( h, hei - y0 )
return Subwindow( ui, x0, y0, w, h )
class DelayWidget (Widget):
def __init__(self, dt = 0.1, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.t = time.time() + dt
def draw(self):
if time.time() >= self.t:
self.done = True
class DirectionWidget (Widget):
def __init__(self, acceptZ = False, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.movementKeys = MovementKeys
self.acceptZ = acceptZ
def keyboard(self, key):
try:
self.result = self.movementKeys[key]
self.done = True
except KeyError:
if key == '>' or key == '<' and self.acceptZ:
self.result = key
self.done = True
class HitEnterWidget (Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
def keyboard(self, key):
if key == '\n' or key == ' ':
self.done = True
class TextInputWidget (Widget):
def __init__(self, width, okay = string.printable, query = None, acceptEmpty = False, centered = False, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.width = width
self.okay = list( okay )
self.data = []
self.query = query
self.centered = centered
self.height = 4
self.resize()
def resize(self, w = None, h = None):
self.dialog = centeredSubwindow( self.ui, self.width + 3, self.height )
def draw(self):
bg = PrimaryColour
fg = SecondaryColour
self.dialog.decorate( BorderColour, bg )
y = 1
if self.query:
x = self.dialog.putString( 1, y, self.query.center( self.width + 1 ) if self.centered else self.query, fg, bg )
y += 1
x = 1
if self.centered:
x = int( (self.width + 3 - len(self.data)) / 2 )
x = self.dialog.putString( x, y, "".join( self.data ), fg, bg )
if blinkphase(2) == 0:
self.dialog.put( x, y, "_", fg, bg )
def keyboard(self, key):
if key == '\n':
if self.data:
self.done = True
self.result = "".join( self.data )
elif not self.done:
if key == 'backspace':
if self.data:
self.data.pop()
elif key in self.okay:
if len( self.data ) < self.width:
self.data.append( key )
class WallOfTextWidget (HitEnterWidget):
def __init__(self, text, width, center = False, *args, **kwargs):
HitEnterWidget.__init__(self, *args, **kwargs)
self.width = width
self.center = center
self.text = text
def draw(self):
bg = PrimaryColour
fg = SecondaryColour
screenw, screenh = self.ui.dimensions()
tw = TextWrapper( self.width - 2 )
tw.feed( self.text )
height = min( tw.numberOfLines() + 2, screenh )
dialog = centeredSubwindow( self.ui, self.width, height )
dialog.decorate( BorderColour, bg )
i = 0
for i in range(1, height-1):
s = tw.line(i-1)
if self.center:
s = s.center( self.width - 2 )
dialog.putString( 1, i, s, fg, bg )
class CursorWidget (Widget):
def __init__(self, game, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.game = game
self.game.cursor = self.game.player.tile.x, self.game.player.tile.y
self.visibility = game.playerVisibility( game.player.fov() )
self.description = ""
def draw(self):
screenw, screenh = self.game.ui.dimensions()
tw = TextWrapper( screenw, self.game.textfieldheight )
tw.feed( self.description )
if tw.pages:
page = tw.popPage()
else:
lines = [ tw.line(0), tw.line(1) ]
for i in range(2):
try:
self.game.ui.putString( 0, i, " " * screenw, 'bold-white' )
self.game.ui.putString( 0, i, lines[i], 'bold-white' )
except IndexError:
pass
def keyboard(self, key):
try:
dx, dy = MovementKeys[ key ]
x, y = self.game.cursor
self.game.cursor = x+dx,y+dy
try:
tile = self.game.player.tile.level.tiles[ self.game.cursor ]
except KeyError:
tile = None
if tile and self.visibility( tile ):
self.description = self.game.player.tile.level.tiles[ self.game.cursor ].describe()
else:
self.description = ""
try:
if self.game.player.tile.level.tiles[ self.game.cursor ].rememberedAs:
self.description = self.game.player.tile.level.tiles[ self.game.cursor ].describeRemembered()
except IndexError:
pass
except KeyError:
if key == '\n' or key == ' ':
self.result = self.game.cursor
self.game.cursor = None
self.done = True
class SelectionMenuWidget (Widget):
def __init__(self, choices = [], title = None, centered = False, noInvert = False, padding = 0, cancelable = False, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.title = title
self.cancelable = cancelable
self.choices = choices # symbol, description
self.selection = 0
self.noInvert = noInvert
self.width = max( map( lambda syde : len(syde[1]) + 2 + 2, self.choices ) )
self.centered = centered
self.xoffset = 2 if not self.centered else 1
if self.title:
self.yoffset = 2
self.width = max( len(self.title), self.width )
else:
self.yoffset = 1
self.width += self.xoffset + 1
self.width += padding
self.height = len( self.choices ) + 1 + self.yoffset
self.resize()
def resize(self, w = None, h = None):
self.dialog = centeredSubwindow( self.ui, self.width, self.height )
def keyboard(self, key):
if key == 'escape' and self.cancelable:
self.result = None
self.done = True
elif key == '\n':
sym, desc = self.choices[ self.selection ]
self.result = sym
self.done = True
else:
try:
translated = MovementKeys[key]
if translated == (0,-1):
self.selection = max( 0, self.selection - 1 )
elif translated == (0,1):
self.selection = min( len(self.choices) - 1, self.selection + 1 )
except KeyError:
pass
def draw(self):
bg = PrimaryColour
fg = SecondaryColour
self.dialog.decorate( BorderColour, bg )
i = 0
if self.title:
self.dialog.putString( 1, 1, self.title.center( self.width - 2 ), fg, bg )
for sym, desc in self.choices:
bga, fga = bg, fg
if i == self.selection:
if not self.noInvert:
bga = HighlightPrimaryColour
fga = HighlightSecondaryColour
desc = " ".join( [ ">", desc, "<" ] )
if self.centered:
desc = desc.center( self.width - 2)
self.dialog.putString( self.xoffset, i + self.yoffset, desc, fga, bga )
i += 1
class SpellSelectionMenuWidget (SelectionMenuWidget):
def __init__(self, hotkeys = {}, *args, **kwargs):
SelectionMenuWidget.__init__(self, *args, **kwargs)
self.hotkeys = hotkeys
def keyboard(self, key):
try:
self.result = self.hotkeys[key]
self.done = True
except KeyError:
SelectionMenuWidget.keyboard( self, key )
class RootMenuWidget(Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
def draw(self):
# display a splash screen
from harmless7drl import Signature, Version, Date, Author, Email
lines = [ Signature, Version, Date, "", "by %s" % Author, Email, "", "Originally created for the 2010 7DRL challenge", "", "Press any key to continue" ]
screenw, screenh = self.ui.dimensions()
y = ( screenh-len(lines) ) // 2
for line in lines[:-1]:
self.ui.putString( 0, y, line.center( screenw ), "bold-white", "black" )
y += 1
self.ui.putString( 0, y, lines[-1].center( screenw ), "bold-white", "black" )
def keyboard(self, key):
from gamewidget import GameWidget
self.hidden = True # remember: that's the _splash_ screen
while True:
result = self.main.query( SelectionMenuWidget, choices = [
('new', "Play Harmless7DRL"),
('instructions', "Instructions"),
('about', "About"),
('quit', "Quit"),
], padding = 5, centered = True, noInvert = True )
if result == 'quit':
self.done = True
break
elif result == 'new':
self.main.query( GameWidget )
elif result == 'instructions':
from plot import displayInstructions
displayInstructions( self.main )
elif result == 'about':
from plot import displayAbout
displayAbout( self.main )