Don't swap menus while you're navigating on the same traitbox
[crapvine.git] / template.py
blob8ef9b3fefefe0a6c2e583423e5f2be7a8015bb3b
1 ## This file is part of Crapvine.
2 ##
3 ## Copyright (C) 2007 Andrew Sayman <lorien420@myrealbox.com>
4 ##
5 ## Crapvine is free software; you can redistribute it and/or modify
6 ## it under the terms of the GNU General Public License as published by
7 ## the Free Software Foundation; either version 3 of the License, or
8 ## (at your option) any later version.
9 ##
10 ## Crapvine is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ## GNU General Public License for more details.
15 ## You should have received a copy of the GNU General Public License
16 ## along with this program. If not, see <http://www.gnu.org/licenses/>.
18 from __future__ import with_statement
20 class Keyword(object):
21 def __init__(self):
22 object.__init__(self)
23 text = ''
24 begin = 0
25 end = 0
27 class Template(object):
28 def __init__(self, template_filepath, character, output_filepath, progress = None):
29 self.character = character
30 self.template_filepath = template_filepath
31 self.output_filepath = output_filepath
32 self.__progress = progress
34 def get_keywords(self, out_str):
35 keywords = []
36 cur_key = None
37 for i in range(len(out_str)):
38 if cur_key:
39 if out_str[i] == ']':
40 cur_key.end = i
41 cur_key.text = "%s" % (out_str[cur_key.begin + 1:cur_key.end])
42 keywords.append(cur_key)
43 cur_key = None
44 if out_str[i] == '[':
45 if cur_key:
46 print 'Syntax error'
47 return keywords
48 cur_key = Keyword()
49 cur_key.begin = i
50 return keywords
52 # Map of output name to traitlist name
53 iterable_map = {
54 'physicalneg' : 'negative physical',
55 'socialneg' : 'negative social',
56 'mentalneg' : 'negative mental',
57 'healthlevels' : 'health levels'
60 def translate_iterable_name(self, name):
61 if self.iterable_map.has_key(name):
62 return self.iterable_map[name]
63 return name
65 # Map of output name to attribute name
66 attribute_map = {
67 'playstatus' : 'status'
70 def translate_attribute_name(self, name):
71 if self.attribute_map.has_key(name):
72 return self.attribute_map[name]
73 return name
75 def __get_named_traitlist(self, traitlist_name):
76 for tl in self.character.traitlists:
77 if tl.name.lower() == traitlist_name:
78 return tl
79 return None
81 def __start_progress(self, total_passes, text=None):
82 if self.__progress:
83 self.__progress.set_pulse_step(100.0 / float(total_passes) / 100.0)
84 self.__progress.show_now()
85 else:
86 my_out = ''
87 if text:
88 my_out = ". %s" % (text)
89 print "Processing %s%s" % (self.character.name, my_out)
90 self.__total_passes = total_passes
91 self.__current_pass = 0
92 def __increment_progress(self, text=None):
93 if self.__progress:
94 if text:
95 self.__progress.set_text(text)
96 self.__progress.pulse()
97 else:
98 self.__current_pass += 1
99 my_out = ''
100 if text:
101 my_out = ". %s" % (text)
102 print "%d%% complete%s" % ((100.0 / self.__total_passes) * self.__current_pass, my_out)
103 def save(self, progress=None):
104 self.__start_progress(8, "Reading file %s" % (self.template_filepath))
105 in_str = ''
106 with open(self.template_filepath) as f:
107 in_str = f.read()
108 self.__increment_progress('Processing repeats')
110 out_str = "%s" % (in_str)
112 # Parse repeat keyword
113 keywords = self.get_keywords(out_str)
114 keywords.reverse()
115 repeat_blocks = []
116 cur_repeat = None
117 for i in range(len(keywords)):
118 if keywords[i].text == '/repeat':
119 assert cur_repeat == None
120 #print 'Found repeat'
121 cur_repeat = Keyword()
122 cur_repeat.end = keywords[i].end
123 elif keywords[i].text == 'repeat':
124 assert cur_repeat != None
125 #print 'End repeat'
126 cur_repeat.begin = keywords[i].begin
127 cur_repeat.text = "%s" % (out_str[cur_repeat.begin+8:cur_repeat.end-8])
128 repeat_blocks.append(cur_repeat)
129 cur_repeat = None
131 for repeat_block in repeat_blocks:
132 out_str = self.__expandinate_repeat_block(repeat_block, out_str)
133 self.__increment_progress('Processing attributes')
135 # Parse attributes
136 keywords = self.get_keywords(out_str)
137 keywords.reverse()
138 for keyword in keywords:
139 tokens = keyword.text.split(' ')
140 try:
141 rep_str = self.character[self.translate_attribute_name(tokens[0].lower())]
142 out_str = "%s%s%s" % (out_str[:keyword.begin], rep_str, out_str[keyword.end+1:])
143 except AttributeError:
144 # It's either incorrect or a language keyword
145 pass
146 self.__increment_progress('Processing traitlist counts')
148 # Parse iterable counts
149 keywords = self.get_keywords(out_str)
150 keywords.reverse()
151 for keyword in keywords:
152 tokens = keyword.text.lower().split(' ')
153 if tokens[0].find('#') == 0:
154 tl_name = self.translate_iterable_name(tokens[0][1:])
155 tl = self.__get_named_traitlist(tl_name)
156 rep_str = ''
157 if tl:
158 rep_str = "%d" % (tl.get_display_total())
159 out_str = "%s%s%s" % (out_str[:keyword.begin], rep_str, out_str[keyword.end+1:])
160 self.__increment_progress('Processing tallies')
162 # Parse tally keyword
163 dot = 'O'
164 emptydot = '/'
165 tempdot = '+'
166 keywords = self.get_keywords(out_str)
167 keywords.reverse()
168 for keyword in keywords:
169 tokens = keyword.text.split(' ')
170 if tokens[0].lower() == 'tally':
171 if len(tokens) == 2:
172 try:
173 #print "%s" % (tokens[1].lower())
174 tally_val = self.character[tokens[1].lower()]
175 rep_str = "%s" % (dot * int(round(float(tally_val))))
176 out_str = "%s%s%s" % (out_str[:keyword.begin], rep_str, out_str[keyword.end+1:])
177 except AttributeError:
178 pass
179 elif len(tokens) == 3:
180 try:
181 prm_val = int(round(float(self.character[tokens[1].lower()])))
182 tmp_val = int(round(float(self.character[tokens[2].lower()])))
183 rep_str = ''
184 if prm_val == tmp_val:
185 rep_str = "%s" % (dot * prm_val)
186 elif prm_val > tmp_val:
187 tmp_dots = prm_val - tmp_val
188 prm_dots = prm_val - tmp_dots
189 rep_str = "%s%s" % (dot * prm_dots, emptydot * tmp_dots)
190 elif prm_val < tmp_val:
191 tmp_dots = tmp_val - prm_val
192 rep_str = "%s%s" % (dot * prm_val, tempdot * tmp_dots)
193 out_str = "%s%s%s" % (out_str[:keyword.begin], rep_str, out_str[keyword.end+1:])
194 except AttributeError:
195 pass
196 self.__increment_progress('Processing tabs')
198 # Parse tab keyword
199 keywords = self.get_keywords(out_str)
200 keywords.reverse()
201 for keyword in keywords:
202 tokens = keyword.text.split(' ')
203 if tokens[0].lower() == 'tab':
204 rep_str = "\t"
205 out_str = "%s%s%s" % (out_str[:keyword.begin], rep_str, out_str[keyword.end+1:])
206 self.__increment_progress('Formatting columns')
208 # Parse col keyword
209 lines = out_str.split("\n")
210 out_lines = []
211 for line in lines:
212 keywords = self.get_keywords(line)
213 replaces = []
214 gathered_offset = 0
215 #print line
216 for keyword in keywords:
217 tokens = keyword.text.split(' ')
218 if tokens[0].lower() == 'col':
219 width = int(tokens[1])
220 #print width
221 #newline_index = out_str.rfind("\n", 0, keyword.begin)
222 #print newline_index
223 #print out_str[keyword.end+1:keyword.end+30]
224 #justified_str = line[:keyword.begin].rstrip().ljust(width, ' ')
225 #print "Len: %d\n|%s|" % (len(justified_str), justified_str)
226 line = "%s%s" % (line[:keyword.begin - gathered_offset], line[keyword.end+1 - gathered_offset:])
227 replaces.append((width, keyword.begin - gathered_offset))
228 gathered_offset += len(keyword.text) + 2
229 #if len(replaces) > 0:
230 #print "Beginning replace for:\n%s" % (line)
231 gathered_offset = 0
232 for rep in replaces:
233 width = rep[0]
234 begin = rep[1] + gathered_offset
235 #print "Chunk: |%s|" % (line[:begin])
236 old_len = len(line[:begin])
237 justified_str = line[:begin].rstrip().ljust(width, ' ')
238 gathered_offset += len(justified_str) - old_len
239 line = "%s%s" % (justified_str, line[begin:])
240 out_lines.append(line)
241 #print line
242 out_str = "\n".join(out_lines)
243 self.__increment_progress("Writing file %s" % (self.output_filepath))
245 with open(self.output_filepath, 'w') as f:
246 f.write(out_str)
247 self.__increment_progress()
249 def __expandinate_repeat_block(self, repeat_block, out_str):
250 pre_string = out_str[:repeat_block.begin]
251 post_string = out_str[repeat_block.end+1:]
252 # Find all of the trait categories we need
253 traitlist_iters = {}
254 traitlists = {}
255 keywords = self.get_keywords(repeat_block.text)
256 for k in keywords:
257 tl = self.__get_named_traitlist(self.translate_iterable_name(k.text.lower()))
258 if tl:
259 #print tl.name.lower()
260 traitlists[tl.name.lower()] = tl
261 traitlist_iters[tl.name.lower()] = tl.get_iter_first()
263 if len(traitlists) == 0:
264 return "%s%s" % (pre_string, post_string)
266 # Begin replacination von fuquon
267 imprints = []
268 keep_going = True
269 while keep_going:
270 l_str = "%s" % (repeat_block.text)
271 #print "l_str at start\n%s" % (l_str)
272 keywords = self.get_keywords(l_str)
273 to_increment = {}
274 replaces = []
275 for k in keywords:
276 tokens = k.text.lower().split(' ')
277 mod = ''
278 tl_name = tokens[0]
279 if tokens[0].find('+') == 0:
280 mod = '+'
281 tl_name = tokens[0][1:]
282 #print tl_name
283 tl_name = self.translate_iterable_name(tl_name)
284 if traitlist_iters.has_key(tl_name):
285 tl = traitlists[tl_name]
286 if len(tokens) > 1:
287 display = tokens[1]
288 else:
289 display = tl.display
290 iter = traitlist_iters[tl_name]
291 if mod == '+' and iter:
292 iter = tl.iter_next(iter)
293 traitlist_iters[tl_name] = iter
294 if iter:
295 trait = tl.get_item_from_path(tl.get_path(iter))
296 rep_str = "%s" % (trait.display_str(display))
297 replaces.append((k.begin, rep_str, k.end+1))
298 #l_str = "%s%s%s" % (l_str[:k.begin], rep_str, l_str[k.end+1:])
299 #print "l_str on keyword %s with %s\n%s" % (k.text.lower(), rep_str, l_str)
300 to_increment[tl_name] = True
301 else:
302 replaces.append((k.begin, '', k.end+1))
303 #l_str = "%s%s" % (l_str[:k.begin], l_str[k.end+1:])
304 replaces.reverse()
305 for rep in replaces:
306 l_str = "%s%s%s" % (l_str[:rep[0]], rep[1], l_str[rep[2]:])
307 num_none = 0
308 for n in to_increment.keys():
309 iter = traitlist_iters[n]
310 tl = traitlists[n]
311 if iter:
312 traitlist_iters[n] = tl.iter_next(iter)
313 else:
314 ++num_none
315 #print "Num none: %d | to_increment: %d" % (num_none, len(to_increment))
316 if num_none == len(to_increment):
317 keep_going = False
318 else:
319 imprints.append(l_str)
320 imprint_str = ''.join(imprints)
321 return "%s%s%s" % (pre_string, imprint_str, post_string)
323 @classmethod
324 def temporary_tally_str(cls, prm_val, tmp_val, dot='o', emptydot='/', tempdot='+', wrap=0, doubledot='8', doubleemptydot='X', doubletempdot='#'):
325 if prm_val == tmp_val:
326 if wrap == 0 or prm_val < wrap:
327 return "%s" % (dot * prm_val)
328 else:
329 num_doubles = prm_val / 2
330 num_singles = prm_val % 2
331 return "%s%s" % (doubledot * num_doubles, dot * num_singles)
332 elif prm_val > tmp_val:
333 tmp_dots = prm_val - tmp_val
334 prm_dots = prm_val - tmp_dots
335 if wrap == 0 or prm_val < wrap:
336 return "%s%s" % (dot * prm_dots, emptydot * tmp_dots)
337 else:
338 return "%s%s%s%s" % (
339 doubledot * (prm_dots / 2),
340 doubledot * (prm_dots % 2),
341 doubleemptydot * (tmp_dots / 2),
342 doubleemptydot * (tmp_dots % 2)
344 elif prm_val < tmp_val:
345 tmp_dots = tmp_val - prm_val
346 if wrap == 0 or (prm_val + tmp_dots) < wrap:
347 return "%s%s" % (dot * prm_val, tempdot * tmp_dots)
348 else:
349 return "%s%s%s%s" % (
350 doubledot * (prm_val / 2),
351 doubledot * (prm_val % 2),
352 doubletempdot * (tmp_dots / 2),
353 doubletempdot * (tmp_dots % 2)
355 return ''