| Home | Trees | Indices | Help |
|
|---|
|
|
1 """
2 The documentation for python-tdl. A Pythonic port of
3 U{libtcod<http://doryen.eptalys.net/libtcod/>}.
4
5 You can find the project page on Google Code
6 U{here<http://code.google.com/p/python-tdl/>}.
7
8 Report any bugs or issues to the Google Code issue tracker
9 U{here<https://code.google.com/p/python-tdl/issues/list>}.
10
11 Getting Started
12 ===============
13 Once the library is imported you can load the font you want to use with
14 L{tdl.setFont}.
15 This is optional and when skipped will use a decent default font.
16
17 After that you call L{tdl.init} to set the size of the window and get the
18 root console in return.
19 This console is the canvas to what will appear on the screen.
20
21 Indexing Consoles
22 =================
23 For most methods taking a position you can use Python-style negative
24 indexes to refer to the opposite side of a console with (-1, -1)
25 starting at the bottom right.
26 You can also check if a point is part of a console using containment
27 logic i.e. ((x, y) in console).
28
29 You may also iterate over a console using a for statement. This returns
30 every x,y coordinate available to draw on but it will be extremely slow
31 to actually operate on every coordinate individualy.
32 Try to minimize draws by using an offscreen L{Console}, only drawing
33 what needs to be updated, and using L{Console.blit}.
34
35 Drawing
36 =======
37 Once you have the root console from L{tdl.init} you can start drawing on
38 it using a method such as L{Console.drawChar}.
39 When using this method you can have the char parameter be an integer or a
40 single character string.
41
42 The fgcolor and bgcolor parameters expect a three item list
43 [red, green, blue] with integers in the 0-255 range with [0, 0, 0] being
44 black and [255, 255, 255] being white.
45 Or instead you can use None in the place of any of the three parameters
46 to tell the library to not overwrite colors.
47 After the drawing functions are called a call to L{tdl.flush} will update
48 the screen.
49 """
50
51 import sys
52 import os
53
54 import ctypes
55 import weakref
56 import array
57 import itertools
58 import textwrap
59 import struct
60 import re
61 import warnings
62
63 from . import event, map, noise
64 from .__tcod import _lib, _Color, _unpackfile
65
66 _IS_PYTHON3 = (sys.version_info[0] == 3)
67
68 if _IS_PYTHON3: # some type lists to use with isinstance
69 _INTTYPES = (int,)
70 _NUMTYPES = (int, float)
71 _STRTYPES = (str, bytes)
72 else:
73 _INTTYPES = (int, long)
74 _NUMTYPES = (int, long, float)
75 _STRTYPES = (str,)
78 "changes string into bytes if running in python 3, for sending to ctypes"
79 if _IS_PYTHON3 and isinstance(string, str):
80 return string.encode()
81 return string
82
87 """Prepares a single character for passing to ctypes calls, needs to return
88 an integer but can also pass None which will keep the current character
89 instead of overwriting it.
90
91 This is called often and needs to be optimized whenever possible.
92 """
93 if char is None:
94 return None
95 #if isinstance(char, _INTTYPES):
96 # return char
97 if isinstance(char, _STRTYPES) and len(char) == 1:
98 return ord(char)
99 return int(char) # conversion faster than type check
100 #raise TypeError('Expected char parameter to be a single character string, number, or None, got: %s' % repr(char))
101
102 _fontinitialized = False
103 _rootinitialized = False
104 _rootConsoleRef = None
105 # remove dots from common functions
106 _setchar = _lib.TCOD_console_set_char
107 _setfore = _lib.TCOD_console_set_char_foreground
108 _setback = _lib.TCOD_console_set_char_background
109 _setcharEX = _lib.TCOD_console_put_char_ex
111 """Used internally.
112 Raise an assertion error if the parameters can not be converted into colors.
113 """
114 for color in colors:
115 assert _iscolor(color), 'a color must be a 3 item tuple, web format, or None, received %s' % repr(color)
116 return True
117
119 """Used internally.
120 A debug function to see if an object can be used as a TCOD color struct.
121 None counts as a parameter to keep the current colors instead.
122
123 This function is often part of an inner-loop and can slow a program down.
124 It has been made to work with assert and can be skipped with the -O flag.
125 Still it's called often and must be optimized.
126 """
127 if color is None:
128 return True
129 if isinstance(color, (tuple, list, _Color)):
130 return len(color) == 3
131 if isinstance(color, _INTTYPES):
132 return True
133 return False
134
135 ## not using this for now
136 #class Color(object):
137 #
138 # def __init__(self, r, g, b):
139 # self._color = (r, g, b)
140 # self._ctype = None
141 #
142 # def _getCType(self):
143 # if not self._ctype:
144 # self._ctype = _Color(*self._color)
145 # return self._ctype
146 #
147 # def __len__(self):
148 # return 3
149
150 # Format the color to ctypes, will preserve None and False
151 _formatColor = _Color.new
154 """Try to get the width and height of a bmp of png image file"""
155 file = open(filename, 'rb')
156 if file.read(8) == b'\x89PNG\r\n\x1a\n': # PNG
157 while 1:
158 length, = struct.unpack('>i', file.read(4))
159 chunkID = file.read(4)
160 if chunkID == '': # EOF
161 return None
162 if chunkID == b'IHDR':
163 # return width, height
164 return struct.unpack('>ii', file.read(8))
165 file.seek(4 + length, 1)
166 file.seek(0)
167 if file.read(8) == b'BM': # Bitmap
168 file.seek(18, 0) # skip to size data
169 # return width, height
170 return struct.unpack('<ii', file.read(8))
171 # return None on error, unknown file
177
179 """
180 Contains methods shared by both the L{Console} and L{Window} classes.
181 """
182 __slots__ = ('width', 'height', 'console', '_cursor', '_fgcolor',
183 '_bgcolor', '_bgblend', '_colorLock', '__weakref__', '__dict__')
184
186 self._cursor = (0, 0)
187 self._scrollMode = 'error'
188 self._fgcolor = _formatColor((255, 255, 255))
189 self._bgcolor = _formatColor((0, 0, 0))
190 self._bgblend = 1 # SET
191 self._colorLock = None # which object sets the ctype color options
192
194 """Check if a point is in bounds and make minor adjustments.
195
196 Respects Pythons negative indexes. -1 starts at the bottom right.
197 Replaces the _drawable function
198 """
199 #assert isinstance(x, _INTTYPES), 'x must be an integer, got %s' % repr(x)
200 #assert isinstance(y, _INTTYPES), 'y must be an integer, got %s' % repr(y)
201 # force int, always faster than type checking
202 x = int(x)
203 y = int(y)
204
205 assert (-self.width <= x < self.width) and (-self.height <= y < self.height), \
206 ('(%i, %i) is an invalid postition on %s' % (x, y, self))
207
208 # handle negative indexes
209 if x < 0:
210 x += self.width
211 if y < 0:
212 y += self.height
213 return (x, y)
214
216 """Check if the rectangle is in bounds and make minor adjustments.
217 raise AssertionError's for any problems
218 """
219 x, y = self._normalizePoint(x, y) # inherit _normalizePoint logic
220
221 assert width is None or isinstance(width, _INTTYPES), 'width must be an integer or None, got %s' % repr(width)
222 assert height is None or isinstance(height, _INTTYPES), 'height must be an integer or None, got %s' % repr(height)
223
224 # if width or height are None then extend them to the edge
225 if width is None:
226 width = self.width - x
227 elif width < 0: # handle negative numbers
228 width += self.width
229 width = max(0, width) # a 'too big' negative is clamped zero
230 if height is None:
231 height = self.height - y
232 height = max(0, height)
233 elif height < 0:
234 height += self.height
235
236 # reduce rect size to bounds
237 width = min(width, self.width - x)
238 height = min(height, self.height - y)
239
240 return x, y, width, height
241
243 """return the normalized the cursor position."""
244 width, height = self.getSize()
245 assert width != 0 and height != 0, 'can not print on a console with a width or height of zero'
246 while x >= width:
247 x -= width
248 y += 1
249 while y >= height:
250 if self._scrollMode == 'scroll':
251 y -= 1
252 self.scroll(0, -1)
253 elif self._scrollMode == 'error':
254 # reset the cursor on error
255 self._cursor = (0, 0)
256 raise TDLError('Cursor has reached the end of the console')
257 return (x, y)
258
260 """Make sure the color options on the root console match ths instance"""
261 if self.console._lockColors is not self or forceUpdate:
262 self.console._lockColors = self
263 _lib.TCOD_console_set_default_background(self.console, self.bgcolor)
264 _lib.TCOD_console_set_default_foreground(self.console, self.fgcolor)
265 #
266
268 """Configure how this console will react to the cursor writing past the
269 end if the console.
270
271 This is for methods that use the virtual cursor, such as L{printStr}.
272
273 @type mode: string
274 @param mode: Possible settings are:
275
276 - 'error' - A TDLError will be raised once the cursor
277 reaches the end of the console. Everything up until
278 the error will still be drawn.
279
280 This is the default setting.
281
282 - 'scroll' - The console will scroll up as stuff is
283 written to the end.
284
285 You can restrict the region with L{tdl.Window} when
286 doing this.
287 """
288 MODES = ['error', 'scroll']
289 if mode.lower() not in MODES:
290 raise TDLError('mode must be one of %s, got %s' % (MODES, repr(mode)))
291 self._scrollMode = mode.lower()
292
294 """Sets the colors to be used with the L{printStr} function.
295
296 Values of None will only leave the current values unchanged.
297 """
298 if self.console._lockColors is self:
299 self.console._lockColors = None
300 if fg is not None:
301 self._fgcolor = _formatColor(fg)
302 if bg is not None:
303 self._bgcolor = _formatColor(bg)
304
306 """Print a string at the virtual cursor.
307
308 Handles special characters such as '\\n' and '\\r'.
309 Printing past the bottom of the console will scroll everying upwards.
310
311 Colors can be set with L{setColors} and the virtual cursor can be moved
312 with L{move}.
313
314 @type string: string
315 @param string:
316 """
317 x, y = self._cursor
318 for char in string:
319 if char == '\n': # line break
320 x = 0
321 y += 1
322 continue
323 if char == '\r': # return
324 x = 0
325 continue
326 x, y = self._normalizeCursor(x, y)
327 self.drawChar(x, y, char, self._fgcolor, self._bgcolor)
328 x += 1
329 self._cursor = (x, y)
330
332 """This method mimics basic file-like behaviour.
333
334 Because of this method you can replace sys.stdout or sys.stderr with
335 a L{Typewriter} instance.
336
337 This is a convoluted process and behaviour seen now can be excepted to
338 change on later versions.
339
340 @type string: string
341 """
342 # some 'basic' line buffer stuff.
343 # there must be an easier way to do this. The textwrap module didn't
344 # help much.
345 x, y = self._normalizeCursor(*self._cursor)
346 width, height = self.getSize()
347 wrapper = textwrap.TextWrapper(initial_indent=(' '*x), width=width)
348 writeLines = []
349 for line in string.split('\n'):
350 if line:
351 writeLines += wrapper.wrap(line)
352 wrapper.initial_indent = ''
353 else:
354 writeLines.append([])
355
356 for line in writeLines:
357 x, y = self._normalizeCursor(x, y)
358 self.drawStr(x, y, line[x:], self._fgcolor, self._bgcolor)
359 y += 1
360 x = 0
361 y -= 1
362 self._cursor = (x, y)
363
365 """Draws a single character.
366
367 @type x: int
368 @param x: X coordinate to draw at.
369 @type y: int
370 @param y: Y coordinate to draw at.
371
372 @type char: int, string, or None
373 @param char: Should be an integer, single character string, or None.
374
375 You can set the char parameter as None if you only want to change
376 the colors of the tile.
377
378 @type fgcolor: (r, g, b) or None
379 @param fgcolor: For fgcolor and bgcolor you use a 3 item list with
380 integers ranging 0-255 or None.
381
382 None will keep the current color at this position unchanged.
383 @type bgcolor: (r, g, b) or None
384 @param bgcolor: Background color. See fgcolor
385
386 @raise AssertionError: Having x or y values that can't be placed inside
387 of the console will raise an AssertionError.
388 You can use always use ((x, y) in console) to
389 check if a tile is drawable.
390 """
391
392 assert _verify_colors(fgcolor, bgcolor)
393 x, y = self._normalizePoint(x, y)
394 x, y = ctypes.c_int(x), ctypes.c_int(y)
395 self._setChar(x, y, _formatChar(char),
396 _formatColor(fgcolor), _formatColor(bgcolor))
397
399 """Draws a string starting at x and y. Optinally colored.
400
401 A string that goes past the right side will wrap around. A string
402 wraping to below the console will raise a L{TDLError} but will still be
403 written out. This means you can safely ignore the errors with a
404 try... except block if you're fine with partily written strings.
405
406 \\r and \\n are drawn on the console as normal character tiles. No
407 special encoding is done and any string will translate to the character
408 table as is.
409
410 For a string drawing operation that respects special characters see the
411 L{Typewriter} class.
412
413 @type x: int
414 @param x: X coordinate to draw at.
415 @type y: int
416 @param y: Y coordinate to draw at.
417
418 @type string: string or iterable
419 @param string: Can be a string or an iterable of numbers.
420
421 Special characters are ignored and rendered as any other
422 character.
423
424 @type fgcolor: (r, g, b) or None
425 @param fgcolor: For fgcolor and bgcolor you use a 3 item list with
426 integers ranging 0-255 or None.
427
428 None will keep the current color at this position unchanged.
429 @type bgcolor: (r, g, b) or None
430 @param bgcolor: Background color. See fgcolor
431
432 @raise AssertionError: Having x or y values that can't be placed inside
433 of the console will raise an AssertionError.
434
435 You can use always use ((x, y) in console) to
436 check if a tile is drawable.
437 """
438
439 x, y = self._normalizePoint(x, y)
440 assert _verify_colors(fgcolor, bgcolor)
441 fgcolor, bgcolor = _formatColor(fgcolor), _formatColor(bgcolor)
442 width, height = self.getSize()
443 batch = [] # prepare a batch operation
444 def _drawStrGen(x=x, y=y, string=string, width=width, height=height):
445 """Generator for drawStr
446
447 Iterates over ((x, y), ch) data for _setCharBatch, raising an
448 error if the end of the console is reached.
449 """
450 for char in string:
451 if y == height:
452 raise TDLError('End of console reached.')
453 #batch.append(((x, y), _formatChar(char))) # ((x, y), ch)
454 yield((x, y), _formatChar(char))
455 x += 1 # advance cursor
456 if x == width: # line break
457 x = 0
458 y += 1
459 self._setCharBatch(_drawStrGen(), fgcolor, bgcolor)
460
462 """Draws a rectangle starting from x and y and extending to width and height.
463
464 If width or height are None then it will extend to the edge of the console.
465
466 @type x: int
467 @param x: x coordinate to draw at.
468 @type y: int
469 @param y: y coordinate to draw at.
470
471 @type width: int or None
472 @param width: Width of the rectangle.
473
474 Can be None to extend to the bottom right of the
475 console or can be a negative number to be sized reltive
476 to the total size of the console.
477 @type height: int or None
478 @param height: Height of the rectangle. See width.
479
480 @type string: int, string, or None
481 @param string: Should be an integer, single character string, or None.
482
483 You can set the char parameter as None if you only want
484 to change the colors of an area.
485
486 @type fgcolor: (r, g, b) or None
487 @param fgcolor: For fgcolor and bgcolor you use a 3 item list with
488 integers ranging 0-255 or None.
489
490 None will keep the current color at this position unchanged.
491 @type bgcolor: (r, g, b) or None
492 @param bgcolor: Background color. See fgcolor
493
494 @raise AssertionError: Having x or y values that can't be placed inside
495 of the console will raise an AssertionError.
496
497 You can use always use ((x, y) in console) to
498 check if a tile is drawable.
499 """
500 x, y, width, height = self._normalizeRect(x, y, width, height)
501 assert _verify_colors(fgcolor, bgcolor)
502 fgcolor, bgcolor = _formatColor(fgcolor), _formatColor(bgcolor)
503 char = _formatChar(string)
504 # use itertools to make an x,y grid
505 # using ctypes here reduces type converstions later
506 grid = itertools.product((ctypes.c_int(x) for x in range(x, x + width)),
507 (ctypes.c_int(y) for y in range(y, y + height)))
508 # zip the single character in a batch variable
509 batch = zip(grid, itertools.repeat(char, width * height))
510 self._setCharBatch(batch, fgcolor, bgcolor, nullChar=(char is None))
511
513 """Similar to L{drawRect} but only draws the outline of the rectangle.
514
515 @type x: int
516 @param x: x coordinate to draw at.
517 @type y: int
518 @param y: y coordinate to draw at.
519
520 @type width: int or None
521 @param width: Width of the rectangle.
522
523 Can be None to extend to the bottom right of the
524 console or can be a negative number to be sized reltive
525 to the total size of the console.
526 @type height: int or None
527 @param height: Height of the rectangle. See width.
528
529 @type string: int, string, or None
530 @param string: Should be an integer, single character string, or None.
531
532 You can set the char parameter as None if you only want
533 to change the colors of an area.
534
535 @type fgcolor: (r, g, b) or None
536 @param fgcolor: For fgcolor and bgcolor you use a 3 item list with
537 integers ranging 0-255 or None.
538
539 None will keep the current color at this position unchanged.
540 @type bgcolor: (r, g, b) or None
541 @param bgcolor: Background color. See fgcolor
542
543 @raise AssertionError: Having x or y values that can't be placed inside
544 of the console will raise an AssertionError.
545
546 You can use always use ((x, y) in console) to
547 check if a tile is drawable.
548 """
549 x, y, width, height = self._normalizeRect(x, y, width, height)
550 assert _verify_colors(fgcolor, bgcolor)
551 fgcolor, bgcolor = _formatColor(fgcolor), _formatColor(bgcolor)
552 char = _formatChar(string)
553 if width == 1 or height == 1: # it's just a single width line here
554 return self.drawRect(x, y, width, height, char, fgcolor, bgcolor)
555
556 # draw sides of frame with drawRect
557 self.drawRect(x, y, 1, height, char, fgcolor, bgcolor)
558 self.drawRect(x, y, width, 1, char, fgcolor, bgcolor)
559 self.drawRect(x + width - 1, y, 1, height, char, fgcolor, bgcolor)
560 self.drawRect(x, y + height - 1, width, 1, char, fgcolor, bgcolor)
561
563 """Blit another console or Window onto the current console.
564
565 By default it blits the entire source to the topleft corner.
566
567 @type source: L{Console} or L{Window}
568 @param source: Source window can be a L{Console} or L{Window} instance.
569 It can even blit to itself without any problems.
570
571 @type x: int
572 @param x: X coordinate to blit to.
573 @type y: int
574 @param y: Y coordinate to blit to.
575
576 @type width: int or None
577 @param width: Width of the rectangle.
578
579 Can be None to extend as far as possible to the
580 bottom right corner of the blit area or can be a negative
581 number to be sized reltive to the total size of the
582 B{destination} console.
583 @type height: int or None
584 @param height: Height of the rectangle. See width.
585
586 @type srcX: int
587 @param srcX: The source consoles x coordinate to blit from.
588 @type srcY: int
589 @param srcY: The source consoles y coordinate to blit from.
590 """
591 # hardcode alpha settings for now
592 fgalpha=1.0
593 bgalpha=1.0
594
595 assert isinstance(source, (Console, Window)), "source muse be a Window or Console instance"
596
597 # handle negative indexes and rects
598 # negative width and height will be set realtive to the destination
599 # and will also be clamped to the smallest Console
600 x, y, width, height = self._normalizeRect(x, y, width, height)
601 srcX, srcY, width, height = source._normalizeRect(srcX, srcY, width, height)
602
603 # translate source and self if any of them are Window instances
604 srcX, srcY = source._translate(srcX, srcY)
605 source = source.console
606 x, y = self._translate(x, y)
607 self = self.console
608
609 if self == source:
610 # if we are the same console then we need a third console to hold
611 # onto the data, otherwise it tries to copy into itself and
612 # starts destroying everything
613 tmp = Console(width, height)
614 _lib.TCOD_console_blit(source, srcX, srcY, width, height, tmp, 0, 0, fgalpha, bgalpha)
615 _lib.TCOD_console_blit(tmp, 0, 0, width, height, self, x, y, fgalpha, bgalpha)
616 else:
617 _lib.TCOD_console_blit(source, srcX, srcY, width, height, self, x, y, fgalpha, bgalpha)
618
620 """Return the virtual cursor position.
621
622 @rtype: (x, y)
623 @return: Returns (x, y) a 2-integer tuple containing where the next
624 L{addChar} or L{addStr} will start at.
625
626 This can be changed with the L{move} method."""
627 x, y = self._cursor
628 width, height = self.parent.getSize()
629 while x >= width:
630 x -= width
631 y += 1
632 if y >= height and self.scrollMode == 'scroll':
633 y = height - 1
634 return x, y
635
637 """Return the size of the console as (width, height)
638
639 @rtype: (width, height)
640 """
641 return self.width, self.height
642
644 """Return an iterator with every possible (x, y) value for this console.
645
646 It goes without saying that working on the console this way is a
647 slow process, especially for Python, and should be minimized.
648 @rtype: iter((x, y), ...)
649 """
650 return itertools.product(range(self.width), range(self.height))
651
653 """Move the virtual cursor.
654
655 @type x: int
656 @param x: X position to place the cursor.
657 @type y: int
658 @param y: Y position to place the cursor.
659 """
660 self._cursor = self._normalizePoint(x, y)
661
663 """Scroll the contents of the console in the direction of x,y.
664
665 Uncovered areas will be cleared.
666 Does not move the virutal cursor.
667 @type x: int
668 @param x: Distance to scroll along x-axis
669 @type y: int
670 @param y: Distance to scroll along y-axis
671 @rtype: iter((x, y), ...)
672 @return: Iterates over the (x, y) of any tile uncovered after scrolling.
673 """
674 assert isinstance(x, _INTTYPES), "x must be an integer, got %s" % repr(x)
675 assert isinstance(y, _INTTYPES), "y must be an integer, got %s" % repr(x)
676 def getSlide(x, length):
677 """get the parameters needed to scroll the console in the given
678 direction with x
679 returns (x, length, srcx)
680 """
681 if x > 0:
682 srcx = 0
683 length -= x
684 elif x < 0:
685 srcx = abs(x)
686 x = 0
687 length -= srcx
688 else:
689 srcx = 0
690 return x, length, srcx
691 def getCover(x, length):
692 """return the (x, width) ranges of what is covered and uncovered"""
693 cover = (0, length) # everything covered
694 uncover = None # nothing uncovered
695 if x > 0: # left side uncovered
696 cover = (x, length - x)
697 uncover = (0, x)
698 elif x < 0: # right side uncovered
699 x = abs(x)
700 cover = (0, length - x)
701 uncover = (length - x, x)
702 return cover, uncover
703
704 width, height = self.getSize()
705 if abs(x) >= width or abs(y) >= height:
706 return self.clear() # just clear the console normally
707
708 # get the ranges of the areas that will be uncovered
709 coverX, uncoverX = getCover(x, width)
710 coverY, uncoverY = getCover(y, height)
711 # so at this point we know that coverX and coverY makes a rect that
712 # encases the area that we end up blitting to. uncoverX/Y makes a
713 # rect in the corner of the uncovered area. So we need to combine
714 # the uncoverX/Y with coverY/X to make what's left of the uncovered
715 # area. Explaining it makes it mush easier to do now.
716
717 # But first we need to blit.
718 x, width, srcx = getSlide(x, width)
719 y, height, srcy = getSlide(y, height)
720 self.blit(self, x, y, width, height, srcx, srcy)
721
722 if uncoverX: # clear sides (0x20 is space)
723 self.drawRect(uncoverX[0], coverY[0], uncoverX[1], coverY[1], 0x20, 0x000000, 0x000000)
724 if uncoverY: # clear top/bottom
725 self.drawRect(coverX[0], uncoverY[0], coverX[1], uncoverY[1], 0x20, 0x000000, 0x000000)
726 if uncoverX and uncoverY: # clear corner
727 self.drawRect(uncoverX[0], uncoverY[0], uncoverX[1], uncoverY[1], 0x20, 0x000000, 0x000000)
728
730 """Return the character and colors of a tile as (ch, fg, bg)
731
732 This method runs very slowly as is not recommended to be called
733 frequently.
734
735 @rtype: (int, (r, g, b), (r, g, b))
736 @returns: Returns a 3-item tuple. The first item is an integer of the
737 character at the position (x, y) the second and third are the
738 foreground and background colors respectfully.
739 """
740 raise NotImplementedError('Method here only exists for the docstring')
741
743 """Use ((x, y) in console) to check if a position is drawable on this console.
744 """
745 x, y = position
746 return (0 <= x < self.width) and (0 <= y < self.height)
747
749 """Contains character and color data and can be drawn to.
750
751 The console created by the L{tdl.init} function is the root console and is the
752 console that is rendered to the screen with L{flush}.
753
754 Any console created from the Console class is an off-screen console that
755 can be drawn on before being L{blit} to the root console.
756 """
757
758 __slots__ = ('_as_parameter_', '_typewriter')
759
761 """Create a new offscreen console.
762
763 @type width: int
764 @param width: Width of the console in tiles
765 @type height: int
766 @param height: Height of the console in tiles
767 """
768 _MetaConsole.__init__(self)
769 if not _rootinitialized:
770 raise TDLError('Can not create Console\'s before tdl.init')
771 self._as_parameter_ = _lib.TCOD_console_new(width, height)
772 self.console = self
773 self.width = width
774 self.height = height
775 self._typewriter = None # "typewriter lock", makes sure the colors are set to the typewriter
776 # will be phased out with the Typewriter class
777
778 @classmethod
780 """Make a Console instance, from a console ctype"""
781 self = cls.__new__(cls)
782 _MetaConsole.__init__(self)
783 self._as_parameter_ = console
784 self.console = self
785 self.width = _lib.TCOD_console_get_width(self)
786 self.height = _lib.TCOD_console_get_height(self)
787 self._typewriter = None
788 return self
789
791 """
792 If the main console is garbage collected then the window will be closed as well
793 """
794 # If this is the root console the window will close when collected
795 try:
796 if isinstance(self._as_parameter_, ctypes.c_void_p):
797 global _rootinitialized, _rootConsoleRef
798 _rootinitialized = False
799 _rootConsoleRef = None
800 _lib.TCOD_console_delete(self)
801 except StandardError:
802 pass # I forget why I put this here but I'm to afraid to delete it
803
805 # make a new class and blit
806 clone = self.__class__(self.width, self.height)
807 clone.blit(self)
808 return clone
809
811 # save data from getChar
812 data = [self.getChar(x, y) for x,y in
813 itertools.product(range(self.width), range(self.height))]
814 return self.width, self.height, data
815
817 # make console from __init__ and unpack a getChar array
818 width, height, data = state
819 self.__init__(width, height)
820 for (x, y), graphic in zip(itertools.product(range(width),
821 range(height)), data):
822 self.drawChar(x, y, *graphic)
823
825 """Used internally
826
827 Mostly used just to replace this Console object with the root console
828 If another Console object is used then they are swapped
829 """
830 if isinstance(console, Console):
831 self._as_parameter_, console._as_parameter_ = \
832 console._as_parameter_, self._as_parameter_ # swap tcod consoles
833 else:
834 self._as_parameter_ = console
835 self.width = _lib.TCOD_console_get_width(self)
836 self.height = _lib.TCOD_console_get_height(self)
837 return self
838
840 """Convertion x and y to their position on the root Console for this Window
841
842 Because this is a Console instead of a Window we return the paramaters
843 untouched"""
844 return x, y
845
847 """Clears the entire Console.
848
849 @type fgcolor: (r, g, b)
850 @param fgcolor: Foreground color.
851
852 Must be a 3-item list with integers that range 0-255.
853
854 Unlike most other operations you cannot use None here.
855 @type bgcolor: (r, g, b)
856 @param bgcolor: Background color. See fgcolor.
857 """
858 assert _verify_colors(fgcolor, bgcolor)
859 assert fgcolor and bgcolor, 'Can not use None with clear'
860 self._typewriter = None
861 _lib.TCOD_console_set_default_background(self, _formatColor(bgcolor))
862 _lib.TCOD_console_set_default_foreground(self, _formatColor(fgcolor))
863 _lib.TCOD_console_clear(self)
864
866 """
867 Sets a character.
868 This is called often and is designed to be as fast as possible.
869
870 Because of the need for speed this function will do NO TYPE CHECKING
871 AT ALL, it's up to the drawing functions to use the functions:
872 _formatChar and _formatColor before passing to this."""
873 # buffer values as ctypes objects
874 console = self._as_parameter_
875
876 if char is not None and fgcolor is not None and bgcolor is not None:
877 _setcharEX(console, x, y, char, fgcolor, bgcolor)
878 return
879 if char is not None:
880 _setchar(console, x, y, char)
881 if fgcolor is not None:
882 _setfore(console, x, y, fgcolor)
883 if bgcolor is not None:
884 _setback(console, x, y, bgcolor, bgblend)
885
887 """
888 Try to perform a batch operation otherwise fall back to _setChar.
889 If fgcolor and bgcolor are defined then this is faster but not by very
890 much.
891
892 batch is a iterable of [(x, y), ch] items
893 """
894 if fgcolor and not nullChar:
895 # buffer values as ctypes objects
896 self._typewriter = None # clear the typewriter as colors will be set
897 console = self._as_parameter_
898 bgblend = ctypes.c_int(bgblend)
899
900 if not bgcolor:
901 bgblend = 0
902 else:
903 _lib.TCOD_console_set_default_background(console, bgcolor)
904 _lib.TCOD_console_set_default_foreground(console, fgcolor)
905 _putChar = _lib.TCOD_console_put_char # remove dots and make local
906 for (x, y), char in batch:
907 _putChar(console, x, y, char, bgblend)
908 else:
909 for (x, y), char in batch:
910 self._setChar(x, y, char, fgcolor, bgcolor, bgblend)
911
913 # inherit docstring
914 x, y = self._normalizePoint(x, y)
915 char = _lib.TCOD_console_get_char(self, x, y)
916 bgcolor = _lib.TCOD_console_get_char_background_wrapper(self, x, y)
917 fgcolor = _lib.TCOD_console_get_char_foreground_wrapper(self, x, y)
918 return char, tuple(fgcolor), tuple(bgcolor)
919
922
925 """A Window contains a small isolated part of a Console.
926
927 Drawing on the Window draws on the Console.
928
929 Making a Window and setting its width or height to None will extend it to
930 the edge of the console.
931 """
932
933 __slots__ = ('parent', 'x', 'y')
934
936 """Isolate part of a L{Console} or L{Window} instance.
937
938 @type console: L{Console} or L{Window}
939 @param console: The parent object which can be a L{Console} or another
940 L{Window} instance.
941
942 @type x: int
943 @param x: X coordinate to place the Window.
944
945 This follows the normal rules for indexing so you can use a
946 negative integer to place the Window relative to the bottom
947 right of the parent Console instance.
948 @type y: int
949 @param y: Y coordinate to place the Window.
950
951 See x.
952
953 @type width: int or None
954 @param width: Width of the Window.
955
956 Can be None to extend as far as possible to the
957 bottom right corner of the parent Console or can be a
958 negative number to be sized reltive to the Consoles total
959 size.
960 @type height: int or None
961 @param height: Height of the Window.
962
963 See width.
964 """
965 _MetaConsole.__init__(self)
966 assert isinstance(console, (Console, Window)), 'console parameter must be a Console or Window instance, got %s' % repr(console)
967 self.parent = console
968 self.x, self.y, self.width, self.height = console._normalizeRect(x, y, width, height)
969 if isinstance(console, Console):
970 self.console = console
971 else:
972 self.console = self.parent.console
973
975 """Convertion x and y to their position on the root Console"""
976 # we add our position relative to our parent and then call then next parent up
977 return self.parent._translate((x + self.x), (y + self.y))
978
980 """Clears the entire Window.
981
982 @type fgcolor: (r, g, b)
983 @param fgcolor: Foreground color.
984
985 Must be a 3-item list with integers that range 0-255.
986
987 Unlike most other operations you can not use None here.
988 @type bgcolor: (r, g, b)
989 @param bgcolor: Background color. See fgcolor.
990 """
991 assert _verify_colors(fgcolor, bgcolor)
992 assert fgcolor and bgcolor, 'Can not use None with clear'
993 self.drawRect(0, 0, None, None, 0x20, fgcolor, bgcolor)
994
997
999 myX = self.x # remove dots for speed up
1000 myY = self.y
1001 self.parent._setCharBatch((((x + myX, y + myY), ch) for ((x, y), ch) in batch),
1002 fgcolor, bgcolor, bgblend)
1003
1004
1006 # inherit docstring
1007 x, y = self._normalizePoint(x, y)
1008 self.parent.drawChar(x + self.x, y + self.y, char, fgcolor, bgcolor)
1009
1011 # inherit docstring
1012 x, y, width, height = self._normalizeRect(x, y, width, height)
1013 self.parent.drawRect(x + self.x, y + self.y, width, height, string, fgcolor, bgcolor)
1014
1015 - def drawFrame(self, x, y, width, height, string, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
1016 # inherit docstring
1017 x, y, width, height = self._normalizeRect(x, y, width, height)
1018 self.parent.drawFrame(x + self.x, y + self.y, width, height, string, fgcolor, bgcolor)
1019
1021 # inherit docstring
1022 x, y = self._normalizePoint(x, y)
1023 return self.console.getChar(self._translate(x, y))
1024
1029
1032 """Start the main console with the given width and height and return the
1033 root console.
1034
1035 Call the consoles drawing functions. Then remember to use L{tdl.flush} to
1036 make what's drawn visible on the console.
1037
1038 @type width: int
1039 @param width: width of the root console (in tiles)
1040
1041 @type height: int
1042 @param height: height of the root console (in tiles)
1043
1044 @type title: string
1045 @param title: Text to display as the window title.
1046
1047 If left None it defaults to the running scripts filename.
1048
1049 @type fullscreen: boolean
1050 @param fullscreen: Can be set to True to start in fullscreen mode.
1051
1052 @type renderer: string
1053 @param renderer: Can be one of 'GLSL', 'OPENGL', or 'SDL'.
1054
1055 Due to way Python works you're unlikely to see much of an
1056 improvement by using 'GLSL' or 'OPENGL' as most of the
1057 time Python is slow interacting with the console and the
1058 rendering itself is pretty fast even on 'SDL'.
1059
1060 @rtype: L{Console}
1061 @return: The root console. Only what is drawn on the root console is
1062 what's visible after a call to L{tdl.flush}.
1063 After the root console is garbage collected, the window made by
1064 this function will close.
1065 """
1066 RENDERERS = {'GLSL': 0, 'OPENGL': 1, 'SDL': 2}
1067 global _rootinitialized, _rootConsoleRef
1068 if not _fontinitialized: # set the default font to the one that comes with tdl
1069 setFont(_unpackfile('terminal8x8.png'), None, None, True, True)
1070
1071 if renderer.upper() not in RENDERERS:
1072 raise TDLError('No such render type "%s", expected one of "%s"' % (renderer, '", "'.join(RENDERERS)))
1073 renderer = RENDERERS[renderer.upper()]
1074
1075 # If a console already exists then make a clone to replace it
1076 if _rootConsoleRef and _rootConsoleRef():
1077 oldroot = _rootConsoleRef()
1078 rootreplacement = Console(oldroot.width, oldroot.height)
1079 rootreplacement.blit(oldroot)
1080 oldroot._replace(rootreplacement)
1081 del rootreplacement
1082
1083 if title is None: # use a default title
1084 if sys.argv:
1085 # Use the script filename as the title.
1086 title = os.path.basename(sys.argv[0])
1087 else:
1088 title = 'python-tdl'
1089
1090 _lib.TCOD_console_init_root(width, height, _encodeString(title), fullscreen, renderer)
1091
1092 #event.get() # flush the libtcod event queue to fix some issues
1093 # issues may be fixed already
1094
1095 event._eventsflushed = False
1096 _rootinitialized = True
1097 rootconsole = Console._newConsole(ctypes.c_void_p())
1098 _rootConsoleRef = weakref.ref(rootconsole)
1099
1100 return rootconsole
1101
1103 """Make all changes visible and update the screen.
1104
1105 Remember to call this function after drawing operations.
1106 Calls to flush will enfore the frame rate limit set by L{tdl.setFPS}.
1107
1108 This function can only be called after L{tdl.init}
1109 """
1110 if not _rootinitialized:
1111 raise TDLError('Cannot flush without first initializing with tdl.init')
1112
1113 _lib.TCOD_console_flush()
1114
1115 -def setFont(path, columns=None, rows=None, columnFirst=False,
1116 greyscale=False, altLayout=False):
1117 """Changes the font to be used for this session.
1118 This should be called before L{tdl.init}
1119
1120 If the font specifies its size in its filename (i.e. font_NxN.png) then this
1121 function can auto-detect the tileset formatting and the parameters columns
1122 and rows can be left None.
1123
1124 While it's possible you can change the font mid program it can sometimes
1125 break in rare circumstances. So use caution when doing this.
1126
1127 @type path: string
1128 @param path: Must be a string filepath where a bmp or png file is found.
1129
1130 @type columns: int
1131 @param columns: Number of columns in the tileset.
1132
1133 Can be left None for auto-detection.
1134
1135 @type rows: int
1136 @param rows: Number of rows in the tileset.
1137
1138 Can be left None for auto-detection.
1139
1140 @type columnFirst: boolean
1141 @param columnFirst: Defines if the characer order goes along the rows or
1142 colomns.
1143 It should be True if the charater codes 0-15 are in the
1144 first column.
1145 And should be False if the characters 0-15
1146 are in the first row.
1147
1148 @type greyscale: boolean
1149 @param greyscale: Creates an anti-aliased font from a greyscale bitmap.
1150 Otherwise it uses the alpha channel for anti-aliasing.
1151
1152 Unless you actually need anti-aliasing from a font you
1153 know uses a smooth greyscale channel you should leave
1154 this on False.
1155
1156 @type altLayout: boolean
1157 @param altLayout: An alternative layout with space in the upper left
1158 corner.
1159 The colomn parameter is ignored if this is True,
1160 find examples of this layout in the font/libtcod/
1161 directory included with the python-tdl source.
1162
1163 @raise TDLError: Will be raised if no file is found at path or if auto-
1164 detection fails.
1165
1166 @note: A png file that's been optimized can fail to load correctly on
1167 MAC OS X creating a garbled mess when rendering.
1168 Don't use a program like optipng or just use bmp files instead if
1169 you want your program to work on macs.
1170 """
1171 # put up some constants that are only used here
1172 FONT_LAYOUT_ASCII_INCOL = 1
1173 FONT_LAYOUT_ASCII_INROW = 2
1174 FONT_TYPE_GREYSCALE = 4
1175 FONT_LAYOUT_TCOD = 8
1176 global _fontinitialized
1177 _fontinitialized = True
1178 flags = 0
1179 if altLayout:
1180 flags |= FONT_LAYOUT_TCOD
1181 elif columnFirst:
1182 flags |= FONT_LAYOUT_ASCII_INCOL
1183 else:
1184 flags |= FONT_LAYOUT_ASCII_INROW
1185 if greyscale:
1186 flags |= FONT_TYPE_GREYSCALE
1187 if not os.path.exists(path):
1188 raise TDLError('no file exists at: "%s"' % path)
1189 path = os.path.abspath(path)
1190
1191 # and the rest is the auto-detect script
1192 imgSize = _getImageSize(path) # try to find image size
1193 if imgSize:
1194 imgWidth, imgHeight = imgSize
1195 # try to get font size from filename
1196 match = re.match('.*?([0-9]+)[xX]([0-9]+)', os.path.basename(path))
1197 if match:
1198 fontWidth, fontHeight = match.groups()
1199 fontWidth, fontHeight = int(fontWidth), int(fontHeight)
1200
1201 # estimate correct tileset size
1202 estColumns, remC = divmod(imgWidth, fontWidth)
1203 estRows, remR = divmod(imgHeight, fontHeight)
1204 if remC or remR:
1205 warnings.warn("Font may be incorrectly formatted.")
1206
1207 if not columns:
1208 columns = estColumns
1209 if not rows:
1210 rows = estRows
1211 else:
1212 # the font name excluded the fonts size
1213 if not (columns and rows):
1214 # no matched font size and no tileset is given
1215 raise TDLError('%s has no font size in filename' % os.path.basename(path))
1216
1217 if columns and rows:
1218 # confirm user set options
1219 if (fontWidth * columns != imgWidth or
1220 fontHeight * rows != imgHeight):
1221 warnings.warn("setFont parameters are set as if the image size is (%d, %d) when the detected size is actually (%i, %i)"
1222 % (fontWidth * columns, fontHeight * rows,
1223 imgWidth, imgHeight))
1224 else:
1225 warnings.warn("%s is probably not an image." % os.path.basename(path))
1226
1227 if not (columns and rows):
1228 # didn't auto-detect
1229 raise TDLError('Can not auto-detect the tileset of %s' % os.path.basename(path))
1230
1231 _lib.TCOD_console_set_custom_font(_encodeString(path), flags, columns, rows)
1232
1234 """Returns True if program is fullscreen.
1235
1236 @rtype: boolean
1237 @return: Returns True if the window is in fullscreen mode.
1238 Otherwise returns False.
1239 """
1240 if not _rootinitialized:
1241 raise TDLError('Initialize first with tdl.init')
1242 return _lib.TCOD_console_is_fullscreen()
1243
1245 """Changes the fullscreen state.
1246
1247 @type fullscreen: boolean
1248 """
1249 if not _rootinitialized:
1250 raise TDLError('Initialize first with tdl.init')
1251 _lib.TCOD_console_set_fullscreen(fullscreen)
1252
1254 """Change the window title.
1255
1256 @type title: string
1257 """
1258 if not _rootinitialized:
1259 raise TDLError('Not initilized. Set title with tdl.init')
1260 _lib.TCOD_console_set_window_title(_encodeString(title))
1261
1263 """Capture the screen and save it as a png file
1264
1265 @type path: string
1266 @param path: The filepath to save the screenshot.
1267
1268 If path is None then the image will be placed in the current
1269 folder with the names:
1270 screenshot001.png, screenshot002.png, ...
1271 """
1272 if not _rootinitialized:
1273 raise TDLError('Initialize first with tdl.init')
1274 if isinstance(path, str):
1275 _lib.TCOD_sys_save_screenshot(_encodeString(path))
1276 elif path is None: # save to screenshot001.png, screenshot002.png, ...
1277 filelist = os.listdir('.')
1278 n = 1
1279 filename = 'screenshot%.3i.png' % n
1280 while filename in filelist:
1281 n += 1
1282 filename = 'screenshot%.3i.png' % n
1283 _lib.TCOD_sys_save_screenshot(_encodeString(filename))
1284 else: # assume file like obj
1285 #save to temp file and copy to file-like obj
1286 tmpname = os.tempnam()
1287 _lib.TCOD_sys_save_screenshot(_encodeString(tmpname))
1288 with tmpname as tmpfile:
1289 path.write(tmpfile.read())
1290 os.remove(tmpname)
1291 #else:
1292 # raise TypeError('path is an invalid type: %s' % type(path))
1293
1294 -def setFPS(frameRate):
1295 """Set the maximum frame rate.
1296
1297 @type frameRate: int
1298 @param frameRate: Further calls to L{tdl.flush} will limit the speed of
1299 the program to run at <frameRate> frames per second. Can
1300 also be set to 0 to run without a limit.
1301
1302 Defaults to None.
1303 """
1304 if frameRate is None:
1305 frameRate = 0
1306 assert isinstance(frameRate, _INTTYPES), 'frameRate must be an integer or None, got: %s' % repr(frameRate)
1307 _lib.TCOD_sys_set_fps(frameRate)
1308
1310 """Return the current frames per second of the running program set by
1311 L{setFPS}
1312
1313 @rtype: int
1314 @return: Returns the frameRate set by setFPS.
1315 If set to no limit, this will return 0.
1316 """
1317 return _lib.TCOD_sys_get_fps()
1318
1326
1327 __all__ = [_var for _var in locals().keys() if _var[0] != '_' and _var not in
1328 ['sys', 'os', 'ctypes', 'array', 'weakref', 'itertools', 'textwrap',
1329 'struct', 're', 'warnings']] # remove modules from __all__
1330 __all__ += ['_MetaConsole'] # keep this object public to show the documentation in epydoc
1331
1332 __license__ = "New BSD License"
1333 __email__ = "4b796c65+pythonTDL@gmail.com"
1334
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sun Nov 10 19:20:28 2013 | http://epydoc.sourceforge.net |