1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
# Copyright (c) 2004 Bruno T. C. de Oliveira
#
# LICENSE INFORMATION:
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Copyright (c) 2002 Bruno T. C. de Oliveira
#
# INFORMAES DE LICENA:
# Este programa um software de livre distribuio; voc pode
# redistribu-lo e/ou modific-lo sob os termos da GNU General
# Public License, conforme publicado pela Free Software Foundation,
# pela verso 2 da licena ou qualquer verso posterior.
#
# Este programa distribudo na esperana de que ele ser til
# aos seus usurios, porm, SEM QUAISQUER GARANTIAS; sem sequer
# a garantia implcita de COMERCIABILIDADE ou DE ADEQUAO A
# QUALQUER FINALIDADE ESPECFICA. Consulte a GNU General Public
# License para obter mais detalhes (uma cpia acompanha este
# programa, armazenada no arquivo COPYING).
import sys, os, string
import gzip
import curses
class AeError(Exception):
def __init__(self, arg):
Exception.__init__(self, arg)
class AeDoc:
"""
Represents an aewan document loaded from a file.
Attributes:
layers[] - list of layers (AeLayer objects)
"""
def __init__(self, file):
"""
Creates a new aewan document object by loading it from the
specified file. The file must be in AES format, as generated
by the ae2aes conversion utility. The file may be gzip-compressed.
If there is a format-related error while loading the document,
raises an AeError. If there is an I/O related error, raises an IOError.
"""
self.layers = []
f = gzip.open(file, 'r')
_read_marker(f, "AES v1.0")
_read_marker(f, "begin document")
layercount = _read_field_int(f, "layer-count")
for i in range(layercount):
self.layers.append(AeLayer(f))
_read_marker(f, "end document")
class AeLayer:
"""
Represents each of the layers in an aewan document. Attributes:
name
width
height
visible - 1 if layer is marked as visible, 0 otherwise
transparent - 1 if layer is marked as transparent, 0 otherwise
char[height][width] - the character at each position in the layer
attr[height][width] - the attribute of each position in the layer
Please note that the char and attr matrices are addressed
with indexes [y][x], NOT the more intuitive [x][y].
"""
def __init__(self, f):
"""
Initializes a new layer by loading its data from file object f.
Raises an AeError if a format-related error occurs, or an IOError
if an i/o-related error occurs.
"""
_read_marker(f, "begin layer")
self.name = _read_field(f, "name")
self.width = _read_field_int(f, "width")
self.height = _read_field_int(f, "height")
self.visible = _read_field_int(f, "visible")
self.transparent = _read_field_int(f, "transparent")
_read_marker(f, "begin canvas")
self.char = []
self.attr = []
for y in range(self.height):
a = string.split(string.strip(f.readline()))
if len(a) != self.width * 2:
raise AeError("Canvas line with insufficient cells:\n" + a)
char_row = []
attr_row = []
for x in range(self.width):
try:
char_row.append(int(a[x * 2], 16))
attr_row.append(int(a[x * 2 + 1], 16))
except ValueError:
raise AeError("Error: map cell x=%d, y=%d has invalid data\n"
"(not a hexadecimal number)" % (x,y))
self.char.append(char_row)
self.attr.append(attr_row)
_read_marker(f, "end canvas")
_read_marker(f, "end layer")
def render(self, wnd, dest_x, dest_y, dest_w, dest_h, src_x, src_y, \
setattr_cb):
"""
Render the contents of this layer using curses. The image will
be rendered on the curses window identified by wnd, and will
be confined to the rectangle defined by the dest_* arguments.
The image will be translated in such a way that the left-top
corner of the destination rectangle will show the layer cell
whose coordinates are src_x, src_y.
In order to set curses attributes for each cell, this function
will call setattr_cb passing it the window and the attribute as
parameters.
"""
for y in range(dest_h):
wnd.move(y + dest_y, dest_x)
for x in range(dest_w):
sx = x + src_x
sy = y + src_y
if 0 <= sx < self.width and 0 <= sy < self.height:
ch = self.char[sy][sx]
if 0 <= ch < 32: ch = 32 # don't display control chars
# FIXME: this doesn't display special line-graphics
# characters. Ideally, we should convert special
# characters into the appropriate ACS_* characters
# at this point.
at = self.attr[sy][sx]
else:
ch = 0x20
at = 0x70
setattr_cb(wnd, at)
wnd.addch(chr(ch))
# ------------------------------------------------------------------------
def _read_marker(f, str):
line = string.strip(f.readline())
if line == str: return
raise AeError("Incorrectly formatted AES document.\n"
"Expected marker: '%s'\nBut found: '%s'\n" % (str,line))
def _read_field(f, fieldname):
line = string.strip(f.readline())
a = string.split(line, maxsplit=1)
if len(a) != 2:
raise AeError("Incorrect field syntax in AES document:\n%s\n" % line)
if a[0] != fieldname:
raise AeError("AES field name mismatch.\nExpected: '%s'\nFound: '%s'" \
% (fieldname, a[0]))
return a[1]
def _read_field_int(f, fieldname):
x = _read_field(f, fieldname);
try:
return int(x)
except ValueError:
raise AeError("AES field type mismatch: expected an integer\n"
"Field name: '%s'\nValue: '%s'" % (fieldname, x))
|