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