1
|
|
|
""" |
2
|
|
|
libtcod works with a special 'root' console. You create this console using |
3
|
|
|
the :any:`tcod.console_init_root` function. Usually after setting the font |
4
|
|
|
with :any:`console_set_custom_font` first. |
5
|
|
|
|
6
|
|
|
Example:: |
7
|
|
|
|
8
|
|
|
# Make sure 'arial10x10.png' is in the same directory as this script. |
9
|
|
|
import time |
10
|
|
|
|
11
|
|
|
import tcod |
12
|
|
|
|
13
|
|
|
# Setup the font. |
14
|
|
|
tcod.console_set_custom_font( |
15
|
|
|
'arial10x10.png', |
16
|
|
|
tcod.FONT_LAYOUT_ASCII_INROW | tcod.FONT_LAYOUT_TCOD, |
17
|
|
|
) |
18
|
|
|
# Initialize the root console in a context. |
19
|
|
|
with tcod.console_init_root(80, 60, 'title') as root_console: |
20
|
|
|
root_console.print_(x=0, y=0, string='Hello World!') |
21
|
|
|
tcod.console_flush() # Show the console. |
22
|
|
|
time.sleep(3) # Wait 3 seconds. |
23
|
|
|
# The window is closed here, after the above context exits. |
24
|
|
|
""" |
25
|
|
|
|
26
|
|
|
from __future__ import absolute_import |
27
|
|
|
|
28
|
|
|
import sys |
29
|
|
|
|
30
|
|
|
import warnings |
31
|
|
|
|
32
|
|
|
import numpy as np |
|
|
|
|
33
|
|
|
|
34
|
|
|
import tcod.libtcod |
35
|
|
|
from tcod.libtcod import ffi, lib |
36
|
|
|
import tcod._internal |
37
|
|
|
|
38
|
|
|
if sys.version_info[0] == 2: # Python 2 |
39
|
|
|
def _fmt(string): |
|
|
|
|
40
|
|
|
if not isinstance(string, unicode): |
|
|
|
|
41
|
|
|
string = string.decode('latin-1') |
42
|
|
|
return string.replace(u'%', u'%%') |
43
|
|
|
else: |
44
|
|
|
def _fmt(string): |
45
|
|
|
"""Return a string that escapes 'C printf' side effects.""" |
46
|
|
|
return string.replace('%', '%%') |
47
|
|
|
|
48
|
|
|
|
49
|
|
|
class Console(object): |
50
|
|
|
"""A console object containing a grid of characters with |
51
|
|
|
foreground/background colors. |
52
|
|
|
|
53
|
|
|
.. versionchanged:: 4.3 |
54
|
|
|
Added `order` parameter. |
55
|
|
|
|
56
|
|
|
Args: |
57
|
|
|
width (int): Width of the new Console. |
58
|
|
|
height (int): Height of the new Console. |
59
|
|
|
order (str): Which numpy memory order to use. |
60
|
|
|
|
61
|
|
|
Attributes: |
62
|
|
|
console_c (CData): A cffi pointer to a TCOD_console_t object. |
63
|
|
|
""" |
64
|
|
|
|
65
|
|
|
def __init__(self, width, height, order='C'): |
66
|
|
|
self._key_color = None |
67
|
|
|
self._ch = np.zeros((height, width), dtype=np.intc) |
68
|
|
|
self._fg = np.zeros((height, width), dtype='(3,)u1') |
69
|
|
|
self._bg = np.zeros((height, width), dtype='(3,)u1') |
70
|
|
|
self._order = tcod._internal.verify_order(order) |
71
|
|
|
|
72
|
|
|
# libtcod uses the root console for defaults. |
73
|
|
|
bkgnd_flag = alignment = 0 |
74
|
|
|
if lib.TCOD_ctx.root != ffi.NULL: |
75
|
|
|
bkgnd_flag = lib.TCOD_ctx.root.bkgnd_flag |
76
|
|
|
alignment = lib.TCOD_ctx.root.alignment |
77
|
|
|
|
78
|
|
|
self._console_data = self.console_c = ffi.new( |
79
|
|
|
'TCOD_console_data_t*', |
80
|
|
|
{ |
81
|
|
|
'w': width, 'h': height, |
82
|
|
|
'ch_array': ffi.cast('int*', self._ch.ctypes.data), |
83
|
|
|
'fg_array': ffi.cast('TCOD_color_t*', self._fg.ctypes.data), |
84
|
|
|
'bg_array': ffi.cast('TCOD_color_t*', self._bg.ctypes.data), |
85
|
|
|
'bkgnd_flag': bkgnd_flag, |
86
|
|
|
'alignment': alignment, |
87
|
|
|
'fore': (255, 255, 255), |
88
|
|
|
'back': (0, 0, 0), |
89
|
|
|
}, |
90
|
|
|
) |
91
|
|
|
|
92
|
|
|
@classmethod |
93
|
|
|
def _from_cdata(cls, cdata, order='C'): |
|
|
|
|
94
|
|
|
if isinstance(cdata, cls): |
95
|
|
|
return cdata |
96
|
|
|
self = object.__new__(cls) |
97
|
|
|
self.console_c = cdata |
98
|
|
|
self._init_setup_console_data(order) |
99
|
|
|
return self |
100
|
|
|
|
101
|
|
|
def _init_setup_console_data(self, order='C'): |
102
|
|
|
"""Setup numpy arrays over libtcod data buffers.""" |
103
|
|
|
self._key_color = None |
104
|
|
|
if self.console_c == ffi.NULL: |
105
|
|
|
self._console_data = lib.TCOD_ctx.root |
106
|
|
|
else: |
107
|
|
|
self._console_data = ffi.cast('TCOD_console_data_t *', self.console_c) |
|
|
|
|
108
|
|
|
|
109
|
|
|
def unpack_color(color_data): |
110
|
|
|
"""return a (height, width, 3) shaped array from an image struct""" |
111
|
|
|
color_buffer = ffi.buffer(color_data[0:self.width * self.height]) |
112
|
|
|
array = np.frombuffer(color_buffer, np.uint8) |
113
|
|
|
return array.reshape((self.height, self.width, 3)) |
114
|
|
|
|
115
|
|
|
self._fg = unpack_color(self._console_data.fg_array) |
116
|
|
|
self._bg = unpack_color(self._console_data.bg_array) |
117
|
|
|
|
118
|
|
|
buf = self._console_data.ch_array |
119
|
|
|
buf = ffi.buffer(buf[0:self.width * self.height]) |
120
|
|
|
self._ch = np.frombuffer(buf, np.intc).reshape((self.height, |
121
|
|
|
self.width)) |
122
|
|
|
|
123
|
|
|
self._order = tcod._internal.verify_order(order) |
124
|
|
|
|
125
|
|
|
@property |
126
|
|
|
def width(self): |
127
|
|
|
"""int: The width of this Console. (read-only)""" |
128
|
|
|
return lib.TCOD_console_get_width(self.console_c) |
129
|
|
|
|
130
|
|
|
@property |
131
|
|
|
def height(self): |
132
|
|
|
"""int: The height of this Console. (read-only)""" |
133
|
|
|
return lib.TCOD_console_get_height(self.console_c) |
134
|
|
|
|
135
|
|
|
@property |
136
|
|
|
def bg(self): |
|
|
|
|
137
|
|
|
"""A uint8 array with the shape (height, width, 3). |
138
|
|
|
|
139
|
|
|
You can change the consoles background colors by using this array. |
140
|
|
|
|
141
|
|
|
Index this array with ``console.bg[y, x, channel]`` |
142
|
|
|
""" |
143
|
|
|
return self._bg.transpose(1, 0, 2) if self._order == 'F' else self._bg |
144
|
|
|
|
145
|
|
|
@property |
146
|
|
|
def fg(self): |
|
|
|
|
147
|
|
|
"""A uint8 array with the shape (height, width, 3). |
148
|
|
|
|
149
|
|
|
You can change the consoles foreground colors by using this array. |
150
|
|
|
|
151
|
|
|
Index this array with ``console.fg[y, x, channel]`` |
152
|
|
|
""" |
153
|
|
|
return self._fg.transpose(1, 0, 2) if self._order == 'F' else self._fg |
154
|
|
|
|
155
|
|
|
@property |
156
|
|
|
def ch(self): |
|
|
|
|
157
|
|
|
"""An integer array with the shape (height, width). |
158
|
|
|
|
159
|
|
|
You can change the consoles character codes by using this array. |
160
|
|
|
|
161
|
|
|
Index this array with ``console.ch[y, x]`` |
162
|
|
|
""" |
163
|
|
|
return self._ch.T if self._order == 'F' else self._ch |
164
|
|
|
|
165
|
|
|
@property |
166
|
|
|
def default_bg(self): |
167
|
|
|
"""Tuple[int, int, int]: The default background color.""" |
168
|
|
|
color = self._console_data.back |
169
|
|
|
return color.r, color.g, color.b |
170
|
|
|
@default_bg.setter |
171
|
|
|
def default_bg(self, color): |
|
|
|
|
172
|
|
|
self._console_data.back = color |
173
|
|
|
|
174
|
|
|
@property |
175
|
|
|
def default_fg(self): |
176
|
|
|
"""Tuple[int, int, int]: The default foreground color.""" |
177
|
|
|
color = self._console_data.fore |
178
|
|
|
return color.r, color.g, color.b |
179
|
|
|
@default_fg.setter |
180
|
|
|
def default_fg(self, color): |
|
|
|
|
181
|
|
|
self._console_data.fore = color |
182
|
|
|
|
183
|
|
|
@property |
184
|
|
|
def default_bg_blend(self): |
185
|
|
|
"""int: The default blending mode.""" |
186
|
|
|
return self._console_data.bkgnd_flag |
187
|
|
|
@default_bg_blend.setter |
188
|
|
|
def default_bg_blend(self, value): |
|
|
|
|
189
|
|
|
self._console_data.bkgnd_flag = value |
190
|
|
|
|
191
|
|
|
@property |
192
|
|
|
def default_alignment(self): |
193
|
|
|
"""int: The default text alignment.""" |
194
|
|
|
return self._console_data.alignment |
195
|
|
|
@default_alignment.setter |
196
|
|
|
def default_alignment(self, value): |
|
|
|
|
197
|
|
|
self._console_data.alignment = value |
198
|
|
|
|
199
|
|
|
def clear(self): |
200
|
|
|
"""Reset this console to its default colors and the space character. |
201
|
|
|
""" |
202
|
|
|
lib.TCOD_console_clear(self.console_c) |
203
|
|
|
|
204
|
|
|
def put_char(self, x, y, ch, bg_blend=tcod.libtcod.BKGND_DEFAULT): |
|
|
|
|
205
|
|
|
"""Draw the character c at x,y using the default colors and a blend mode. |
|
|
|
|
206
|
|
|
|
207
|
|
|
Args: |
208
|
|
|
x (int): The x coordinate from the left. |
209
|
|
|
y (int): The y coordinate from the top. |
210
|
|
|
ch (int): Character code to draw. Must be in integer form. |
211
|
|
|
bg_blend (int): Blending mode to use, defaults to BKGND_DEFAULT. |
212
|
|
|
""" |
213
|
|
|
lib.TCOD_console_put_char(self.console_c, x, y, ch, bg_blend) |
214
|
|
|
|
215
|
|
|
def print_(self, x, y, string, bg_blend=tcod.libtcod.BKGND_DEFAULT, |
|
|
|
|
216
|
|
|
alignment=None): |
217
|
|
|
"""Print a color formatted string on a console. |
218
|
|
|
|
219
|
|
|
Args: |
220
|
|
|
x (int): The x coordinate from the left. |
221
|
|
|
y (int): The y coordinate from the top. |
222
|
|
|
string (Text): A Unicode string optionaly using color codes. |
223
|
|
|
bg_blend (int): Blending mode to use, defaults to BKGND_DEFAULT. |
224
|
|
|
alignment (Optinal[int]): Text alignment. |
225
|
|
|
""" |
226
|
|
|
alignment = self.default_alignment if alignment is None else alignment |
227
|
|
|
|
228
|
|
|
lib.TCOD_console_print_ex_utf(self.console_c, x, y, |
229
|
|
|
bg_blend, alignment, _fmt(string)) |
230
|
|
|
|
231
|
|
|
def print_rect(self, x, y, width, height, string, |
|
|
|
|
232
|
|
|
bg_blend=tcod.libtcod.BKGND_DEFAULT, alignment=None): |
|
|
|
|
233
|
|
|
"""Print a string constrained to a rectangle. |
234
|
|
|
|
235
|
|
|
If h > 0 and the bottom of the rectangle is reached, |
236
|
|
|
the string is truncated. If h = 0, |
237
|
|
|
the string is only truncated if it reaches the bottom of the console. |
238
|
|
|
|
239
|
|
|
Args: |
240
|
|
|
x (int): The x coordinate from the left. |
241
|
|
|
y (int): The y coordinate from the top. |
242
|
|
|
width (int): Maximum width to render the text. |
243
|
|
|
height (int): Maximum lines to render the text. |
244
|
|
|
string (Text): A Unicode string. |
245
|
|
|
bg_blend (int): Background blending flag. |
246
|
|
|
alignment (Optional[int]): Alignment flag. |
247
|
|
|
|
248
|
|
|
Returns: |
249
|
|
|
int: The number of lines of text once word-wrapped. |
250
|
|
|
""" |
251
|
|
|
alignment = self.default_alignment if alignment is None else alignment |
252
|
|
|
return lib.TCOD_console_print_rect_ex_utf(self.console_c, |
253
|
|
|
x, y, width, height, bg_blend, alignment, _fmt(string)) |
254
|
|
|
|
255
|
|
|
def get_height_rect(self, x, y, width, height, string): |
|
|
|
|
256
|
|
|
"""Return the height of this text word-wrapped into this rectangle. |
257
|
|
|
|
258
|
|
|
Args: |
259
|
|
|
x (int): The x coordinate from the left. |
260
|
|
|
y (int): The y coordinate from the top. |
261
|
|
|
width (int): Maximum width to render the text. |
262
|
|
|
height (int): Maximum lines to render the text. |
263
|
|
|
string (Text): A Unicode string. |
264
|
|
|
|
265
|
|
|
Returns: |
266
|
|
|
int: The number of lines of text once word-wrapped. |
267
|
|
|
""" |
268
|
|
|
return lib.TCOD_console_get_height_rect_utf( |
269
|
|
|
self.console_c, x, y, width, height, _fmt(string)) |
270
|
|
|
|
271
|
|
|
def rect(self, x, y, width, height, clear, |
|
|
|
|
272
|
|
|
bg_blend=tcod.libtcod.BKGND_DEFAULT): |
|
|
|
|
273
|
|
|
"""Draw a the background color on a rect optionally clearing the text. |
274
|
|
|
|
275
|
|
|
If clr is True the affected tiles are changed to space character. |
276
|
|
|
|
277
|
|
|
Args: |
278
|
|
|
x (int): The x coordinate from the left. |
279
|
|
|
y (int): The y coordinate from the top. |
280
|
|
|
width (int): Maximum width to render the text. |
281
|
|
|
height (int): Maximum lines to render the text. |
282
|
|
|
clear (bool): If True all text in the affected area will be |
283
|
|
|
removed. |
284
|
|
|
bg_blend (int): Background blending flag. |
285
|
|
|
""" |
286
|
|
|
lib.TCOD_console_rect(self.console_c, x, y, width, height, clear, |
287
|
|
|
bg_blend) |
288
|
|
|
|
289
|
|
|
def hline(self, x, y, width, bg_blend=tcod.libtcod.BKGND_DEFAULT): |
|
|
|
|
290
|
|
|
"""Draw a horizontal line on the console. |
291
|
|
|
|
292
|
|
|
This always uses the character 196, the horizontal line character. |
293
|
|
|
|
294
|
|
|
Args: |
295
|
|
|
x (int): The x coordinate from the left. |
296
|
|
|
y (int): The y coordinate from the top. |
297
|
|
|
width (int): The horozontal length of this line. |
298
|
|
|
bg_blend (int): The background blending flag. |
299
|
|
|
""" |
300
|
|
|
lib.TCOD_console_hline(self.console_c, x, y, width, bg_blend) |
301
|
|
|
|
302
|
|
|
def vline(self, x, y, height, bg_blend=tcod.libtcod.BKGND_DEFAULT): |
|
|
|
|
303
|
|
|
"""Draw a vertical line on the console. |
304
|
|
|
|
305
|
|
|
This always uses the character 179, the vertical line character. |
306
|
|
|
|
307
|
|
|
Args: |
308
|
|
|
x (int): The x coordinate from the left. |
309
|
|
|
y (int): The y coordinate from the top. |
310
|
|
|
height (int): The horozontal length of this line. |
311
|
|
|
bg_blend (int): The background blending flag. |
312
|
|
|
""" |
313
|
|
|
lib.TCOD_console_vline(self.console_c, x, y, height, bg_blend) |
314
|
|
|
|
315
|
|
|
def print_frame(self, x, y, width, height, string='', |
|
|
|
|
316
|
|
|
clear=True, bg_blend=tcod.libtcod.BKGND_DEFAULT): |
|
|
|
|
317
|
|
|
"""Draw a framed rectangle with optinal text. |
318
|
|
|
|
319
|
|
|
This uses the default background color and blend mode to fill the |
320
|
|
|
rectangle and the default foreground to draw the outline. |
321
|
|
|
|
322
|
|
|
string will be printed on the inside of the rectangle, word-wrapped. |
323
|
|
|
|
324
|
|
|
Args: |
325
|
|
|
x (int): The x coordinate from the left. |
326
|
|
|
y (int): The y coordinate from the top. |
327
|
|
|
width (int): The width if the frame. |
328
|
|
|
height (int): The height of the frame. |
329
|
|
|
string (Text): A Unicode string to print. |
330
|
|
|
clear (bool): If True all text in the affected area will be |
331
|
|
|
removed. |
332
|
|
|
bg_blend (int): The background blending flag. |
333
|
|
|
|
334
|
|
|
Note: |
335
|
|
|
This method does not support Unicode outside of the 0-255 range. |
336
|
|
|
""" |
337
|
|
|
lib.TCOD_console_print_frame(self.console_c, x, y, width, height, |
338
|
|
|
clear, bg_blend, string.encode('latin-1')) |
339
|
|
|
|
340
|
|
|
def blit(self, dest, dest_x=0, dest_y=0, |
341
|
|
|
src_x=0, src_y=0, width=0, height=0, |
342
|
|
|
fg_alpha=1.0, bg_alpha=1.0, key_color=None): |
343
|
|
|
"""Blit from this console onto the ``dest`` console. |
344
|
|
|
|
345
|
|
|
Args: |
346
|
|
|
dest (Console): The destintaion console to blit onto. |
347
|
|
|
dest_x (int): Leftmost coordinate of the destintaion console. |
348
|
|
|
dest_y (int): Topmost coordinate of the destintaion console. |
349
|
|
|
src_x (int): X coordinate from this console to blit, from the left. |
350
|
|
|
src_y (int): Y coordinate from this console to blit, from the top. |
351
|
|
|
width (int): The width of the region to blit. |
352
|
|
|
|
353
|
|
|
If this is 0 the maximum possible width will be used. |
354
|
|
|
height (int): The height of the region to blit. |
355
|
|
|
|
356
|
|
|
If this is 0 the maximum possible height will be used. |
357
|
|
|
fg_alpha (float): Foreground color alpha vaule. |
358
|
|
|
bg_alpha (float): Background color alpha vaule. |
359
|
|
|
key_color (Optional[Tuple[int, int, int]]): |
360
|
|
|
None, or a (red, green, blue) tuple with values of 0-255. |
361
|
|
|
|
362
|
|
|
.. versionchanged:: 4.0 |
363
|
|
|
Parameters were rearraged and made optional. |
364
|
|
|
|
365
|
|
|
Previously they were: |
366
|
|
|
`(x, y, width, height, dest, dest_x, dest_y, *)` |
367
|
|
|
""" |
368
|
|
|
# The old syntax is easy to detect and correct. |
369
|
|
|
if hasattr(src_y, 'console_c'): |
370
|
|
|
src_x, src_y, width, height, dest, dest_x, dest_y = \ |
371
|
|
|
dest, dest_x, dest_y, src_x, src_y, width, height |
372
|
|
|
warnings.warn( |
373
|
|
|
"Parameter names have been moved around, see documentation.", |
374
|
|
|
DeprecationWarning, |
375
|
|
|
) |
376
|
|
|
|
377
|
|
|
if key_color or self._key_color: |
378
|
|
|
key_color = ffi.new('TCOD_color_t*', key_color) |
379
|
|
|
lib.TCOD_console_blit_key_color( |
380
|
|
|
self.console_c, src_x, src_y, width, height, |
381
|
|
|
dest.console_c, dest_x, dest_y, fg_alpha, bg_alpha, key_color |
|
|
|
|
382
|
|
|
) |
383
|
|
|
else: |
384
|
|
|
lib.TCOD_console_blit( |
385
|
|
|
self.console_c, src_x, src_y, width, height, |
386
|
|
|
dest.console_c, dest_x, dest_y, fg_alpha, bg_alpha |
|
|
|
|
387
|
|
|
) |
388
|
|
|
|
389
|
|
|
def set_key_color(self, color): |
390
|
|
|
"""Set a consoles blit transparent color. |
391
|
|
|
|
392
|
|
|
Args: |
393
|
|
|
color (Tuple[int, int, int]): |
394
|
|
|
""" |
395
|
|
|
self._key_color = color |
396
|
|
|
|
397
|
|
|
def __enter__(self): |
398
|
|
|
"""Returns this console in a managed context. |
399
|
|
|
|
400
|
|
|
When the root console is used as a context, the graphical window will |
401
|
|
|
close once the context is left as if :any:`tcod.console_delete` was |
402
|
|
|
called on it. |
403
|
|
|
|
404
|
|
|
This is useful for some Python IDE's like IDLE, where the window would |
405
|
|
|
not be closed on its own otherwise. |
406
|
|
|
""" |
407
|
|
|
if self.console_c != ffi.NULL: |
408
|
|
|
raise NotImplementedError('Only the root console has a context.') |
409
|
|
|
return self |
410
|
|
|
|
411
|
|
|
def __exit__(self, *args): |
412
|
|
|
"""Closes the graphical window on exit. |
413
|
|
|
|
414
|
|
|
Some tcod functions may have undefined behavior after this point. |
415
|
|
|
""" |
416
|
|
|
lib.TCOD_console_delete(self.console_c) |
417
|
|
|
|
418
|
|
|
def __bool__(self): |
419
|
|
|
"""Returns False if this is the root console. |
420
|
|
|
|
421
|
|
|
This mimics libtcodpy behavior. |
422
|
|
|
""" |
423
|
|
|
return self.console_c != ffi.NULL |
424
|
|
|
|
425
|
|
|
__nonzero__ = __bool__ |
426
|
|
|
|
427
|
|
|
def __getstate__(self): |
428
|
|
|
state = self.__dict__.copy() |
429
|
|
|
del state['console_c'] |
430
|
|
|
state['_console_data'] = { |
431
|
|
|
'w': self.width, 'h': self.height, |
432
|
|
|
'bkgnd_flag': self.default_bg_blend, |
433
|
|
|
'alignment': self.default_alignment, |
434
|
|
|
'fore': self.default_fg, |
435
|
|
|
'back': self.default_bg, |
436
|
|
|
} |
437
|
|
|
if self.console_c == ffi.NULL: |
438
|
|
|
state['_ch'] = np.copy(self._ch) |
439
|
|
|
state['_fg'] = np.copy(self._fg) |
440
|
|
|
state['_bg'] = np.copy(self._bg) |
441
|
|
|
return state |
442
|
|
|
|
443
|
|
|
def __setstate__(self, state): |
444
|
|
|
self._key_color = None |
445
|
|
|
self.__dict__.update(state) |
446
|
|
|
self._console_data.update( |
447
|
|
|
{ |
448
|
|
|
'ch_array': ffi.cast('int*', self._ch.ctypes.data), |
449
|
|
|
'fg_array': ffi.cast('TCOD_color_t*', self._fg.ctypes.data), |
450
|
|
|
'bg_array': ffi.cast('TCOD_color_t*', self._bg.ctypes.data), |
451
|
|
|
} |
452
|
|
|
) |
453
|
|
|
self._console_data = self.console_c = ffi.new( |
454
|
|
|
'TCOD_console_data_t*', self._console_data) |
455
|
|
|
|
This can be caused by one of the following:
1. Missing Dependencies
This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.
2. Missing __init__.py files
This error could also result from missing
__init__.py
files in your module folders. Make sure that you place one file in each sub-folder.