comparison orpg/mapper/miniatures.py @ 0:4385a7d0efd1 grumpy-goblin

Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author sirebral
date Tue, 14 Jul 2009 16:41:58 -0500
parents
children 2b9e766f9dee
comparison
equal deleted inserted replaced
-1:000000000000 0:4385a7d0efd1
1 # Copyright (C) 2000-2001 The OpenRPG Project
2 #
3 # openrpg-dev@lists.sourceforge.net
4 #
5 # This program 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 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program 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.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 # --
19 #
20 # File: mapper/miniatures.py
21 # Author: Chris Davis
22 # Maintainer:
23 # Version:
24 # $Id: miniatures.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $
25 #
26 # Description: This file contains some of the basic definitions for the chat
27 # utilities in the orpg project.
28 #
29 __version__ = "$Id: miniatures.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $"
30
31 from base import *
32 import thread
33 import time
34 import urllib
35 import os.path
36
37 MIN_STICKY_BACK = -0XFFFFFF
38 MIN_STICKY_FRONT = 0xFFFFFF
39
40 ##----------------------------------------
41 ## miniature object
42 ##----------------------------------------
43
44 FACE_NONE = 0
45 FACE_NORTH = 1
46 FACE_NORTHEAST = 2
47 FACE_EAST = 3
48 FACE_SOUTHEAST = 4
49 FACE_SOUTH = 5
50 FACE_SOUTHWEST = 6
51 FACE_WEST = 7
52 FACE_NORTHWEST = 8
53 SNAPTO_ALIGN_CENTER = 0
54 SNAPTO_ALIGN_TL = 1
55
56 def cmp_zorder(first,second):
57 f = first.zorder
58 s = second.zorder
59 if f == None:
60 f = 0
61 if s == None:
62 s = 0
63 if f == s:
64 value = 0
65 elif f < s:
66 value = -1
67 else:
68 value = 1
69 return value
70
71 class BmpMiniature:
72 def __init__(self, id,path, bmp, pos=cmpPoint(0,0), heading=FACE_NONE, face=FACE_NONE, label="", locked=False, hide=False, snap_to_align=SNAPTO_ALIGN_CENTER, zorder=0, width=0, height=0, log=None, local=False, localPath='', localTime=-1):
73 self.log = log
74 self.log.log("Enter BmpMiniature", ORPG_DEBUG)
75 self.heading = heading
76 self.face = face
77 self.label = label
78 self.path = path
79 self.bmp = bmp
80 self.pos = pos
81 self.selected = False
82 self.locked = locked
83 self.snap_to_align = snap_to_align
84 self.hide = hide
85 self.id = id
86 self.zorder = zorder
87 self.left = 0
88 self.local = local
89 self.localPath = localPath
90 self.localTime = localTime
91 if not width:
92 self.width = 0
93 else:
94 self.width = width
95 if not height:
96 self.height = 0
97 else:
98 self.height = height
99 self.right = bmp.GetWidth()
100 self.top = 0
101 self.bottom = bmp.GetHeight()
102 self.isUpdated = False
103 self.gray = False
104 self.log.log("Exit BmpMiniature", ORPG_DEBUG)
105
106 def __del__(self):
107 self.log.log("Enter BmpMiniature->__del__(self)", ORPG_DEBUG)
108 del self.bmp
109 self.bmp = None
110 self.log.log("Exit BmpMiniature->__del__(self)", ORPG_DEBUG)
111
112 def set_bmp(self, bmp):
113 self.log.log("Enter BmpMiniature->set_bmp(self, bmp)", ORPG_DEBUG)
114 self.bmp = bmp
115 self.log.log("Exit BmpMiniature->set_bmp(self, bmp)", ORPG_DEBUG)
116
117 def set_min_props(self, heading=FACE_NONE, face=FACE_NONE, label="", locked=False, hide=False, width=0, height=0):
118 self.log.log("Enter BmpMiniature->set_min_props(self, heading, face, label, locked, hide, width, height)", ORPG_DEBUG)
119 self.heading = heading
120 self.face = face
121 self.label = label
122 if locked:
123 self.locked = True
124 else:
125 self.locked = False
126 if hide:
127 self.hide = True
128 else:
129 self.hide = False
130 self.width = int(width)
131 self.height = int(height)
132 self.isUpdated = True
133 self.log.log("Exit BmpMiniature->set_min_props(self, heading, face, label, locked, hide, width, height)", ORPG_DEBUG)
134
135 def hit_test(self, pt):
136 self.log.log("Enter BmpMiniature->hit_test(self, pt)", ORPG_DEBUG)
137 rect = self.get_rect()
138 result = None
139 result = rect.InsideXY(pt.x, pt.y)
140 self.log.log("Exit BmpMiniature->hit_test(self, pt)", ORPG_DEBUG)
141 return result
142
143 def get_rect(self):
144 self.log.log("Enter BmpMiniature->get_rect(self)", ORPG_DEBUG)
145 ret = wx.Rect(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
146 self.log.log("Exit BmpMiniature->get_rect(self)", ORPG_DEBUG)
147 return ret
148
149 def draw(self, dc, mini_layer, op=wx.COPY):
150 self.log.log("Enter BmpMiniature->draw(self, dc, mini_layer, op)", ORPG_DEBUG)
151 if isinstance(self.bmp, tuple):
152 self.log.log("bmp is a tuple, it shouldnt be!", ORPG_INFO)
153 self.bmp = wx.ImageFromMime(self.bmp[1], self.bmp[2]).ConvertToBitmap()
154 if self.bmp != None and self.bmp.Ok():
155 # check if hidden and GM: we outline the mini in grey (little bit smaller than the actual size)
156 # and write the label in the center of the mini
157 if self.hide and mini_layer.canvas.frame.session.my_role() == mini_layer.canvas.frame.session.ROLE_GM:
158 self.log.log("Enter BmpMiniature->draw->Draw Hidden", ORPG_DEBUG)
159 # set the width and height of the image
160 if self.width and self.height:
161 tmp_image = self.bmp.ConvertToImage()
162 tmp_image.Rescale(int(self.width), int(self.height))
163 tmp_image.ConvertAlphaToMask()
164 self.bmp = tmp_image.ConvertToBitmap()
165 mask = wx.Mask(self.bmp, wx.Colour(tmp_image.GetMaskRed(), tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
166 self.bmp.SetMask(mask)
167 del tmp_image
168 del mask
169 self.left = 0
170 self.right = self.bmp.GetWidth()
171 self.top = 0
172 self.bottom = self.bmp.GetHeight()
173 # grey outline
174 graypen = wx.Pen("gray", 1, wx.DOT)
175 dc.SetPen(graypen)
176 dc.SetBrush(wx.TRANSPARENT_BRUSH)
177 #if width or height < 20 then offset = 1
178 if self.bmp.GetWidth() <= 20:
179 xoffset = 1
180 else:
181 xoffset = 5
182 if self.bmp.GetHeight() <= 20:
183 yoffset = 1
184 else:
185 yoffset = 5
186 dc.DrawRectangle(self.pos.x + xoffset, self.pos.y + yoffset, self.bmp.GetWidth() - (xoffset * 2), self.bmp.GetHeight() - (yoffset * 2))
187 dc.SetBrush(wx.NullBrush)
188 dc.SetPen(wx.NullPen)
189 ## draw label in the center of the mini
190 label = mini_layer.get_mini_label(self)
191 if len(label):
192 dc.SetTextForeground(wx.RED)
193 (textWidth,textHeight) = dc.GetTextExtent(label)
194 x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
195 y = self.pos.y + (self.bmp.GetHeight() / 2)
196 dc.SetPen(wx.GREY_PEN)
197 dc.SetBrush(wx.LIGHT_GREY_BRUSH)
198 dc.DrawRectangle(x, y, textWidth+2, textHeight+2)
199 if (textWidth+2 > self.right):
200 self.right += int((textWidth+2-self.right)/2)+1
201 self.left -= int((textWidth+2-self.right)/2)+1
202 self.bottom = y+textHeight+2-self.pos.y
203 dc.SetPen(wx.NullPen)
204 dc.SetBrush(wx.NullBrush)
205 dc.DrawText(label, x+1, y+1)
206
207 #selected outline
208 if self.selected:
209 dc.SetPen(wx.RED_PEN)
210 dc.SetBrush(wx.TRANSPARENT_BRUSH)
211 dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
212 dc.SetBrush(wx.NullBrush)
213 dc.SetPen(wx.NullPen)
214 self.log.log("Exit BmpMiniature->draw->Draw Hidden", ORPG_DEBUG)
215 return True
216 elif self.hide:
217 self.log.log("Enter/Exit BmpMiniature->draw->Skip Hidden", ORPG_DEBUG)
218 return True
219
220 else:
221 self.log.log("Enter BmpMiniature->draw->Not Hidden", ORPG_DEBUG)
222 # set the width and height of the image
223 bmp = self.bmp
224 if self.width and self.height:
225 tmp_image = self.bmp.ConvertToImage()
226 tmp_image.Rescale(int(self.width), int(self.height))
227 tmp_image.ConvertAlphaToMask()
228 self.bmp = tmp_image.ConvertToBitmap()
229 mask = wx.Mask(self.bmp, wx.Colour(tmp_image.GetMaskRed(), tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
230 self.bmp.SetMask(mask)
231 if self.gray:
232 tmp_image = tmp_image.ConvertToGreyscale()
233 bmp = tmp_image.ConvertToBitmap()
234 else:
235 bmp = self.bmp
236 dc.DrawBitmap(bmp, self.pos.x, self.pos.y, True)
237 self.left = 0
238 self.right = self.bmp.GetWidth()
239 self.top = 0
240 self.bottom = self.bmp.GetHeight()
241
242 # Draw the facing marker if needed
243 if self.face != 0:
244 x_mid = self.pos.x + (self.bmp.GetWidth()/2)
245 x_right = self.pos.x + self.bmp.GetWidth()
246 y_mid = self.pos.y + (self.bmp.GetHeight()/2)
247 y_bottom = self.pos.y + self.bmp.GetHeight()
248 dc.SetPen(wx.WHITE_PEN)
249 dc.SetBrush(wx.RED_BRUSH)
250 triangle = []
251
252 # Figure out which direction to draw the marker!!
253 if self.face == FACE_WEST:
254 triangle.append(cmpPoint(self.pos.x,self.pos.y))
255 triangle.append(cmpPoint(self.pos.x - 5, y_mid))
256 triangle.append(cmpPoint(self.pos.x, y_bottom))
257 elif self.face == FACE_EAST:
258 triangle.append(cmpPoint(x_right, self.pos.y))
259 triangle.append(cmpPoint(x_right + 5, y_mid))
260 triangle.append(cmpPoint(x_right, y_bottom))
261 elif self.face == FACE_SOUTH:
262 triangle.append(cmpPoint(self.pos.x, y_bottom))
263 triangle.append(cmpPoint(x_mid, y_bottom + 5))
264 triangle.append(cmpPoint(x_right, y_bottom))
265 elif self.face == FACE_NORTH:
266 triangle.append(cmpPoint(self.pos.x, self.pos.y))
267 triangle.append(cmpPoint(x_mid, self.pos.y - 5))
268 triangle.append(cmpPoint(x_right, self.pos.y))
269 elif self.face == FACE_NORTHEAST:
270 triangle.append(cmpPoint(x_mid, self.pos.y))
271 triangle.append(cmpPoint(x_right + 5, self.pos.y - 5))
272 triangle.append(cmpPoint(x_right, y_mid))
273 triangle.append(cmpPoint(x_right, self.pos.y))
274 elif self.face == FACE_SOUTHEAST:
275 triangle.append(cmpPoint(x_right, y_mid))
276 triangle.append(cmpPoint(x_right + 5, y_bottom + 5))
277 triangle.append(cmpPoint(x_mid, y_bottom))
278 triangle.append(cmpPoint(x_right, y_bottom))
279 elif self.face == FACE_SOUTHWEST:
280 triangle.append(cmpPoint(x_mid, y_bottom))
281 triangle.append(cmpPoint(self.pos.x - 5, y_bottom + 5))
282 triangle.append(cmpPoint(self.pos.x, y_mid))
283 triangle.append(cmpPoint(self.pos.x, y_bottom))
284 elif self.face == FACE_NORTHWEST:
285 triangle.append(cmpPoint(self.pos.x, y_mid))
286 triangle.append(cmpPoint(self.pos.x - 5, self.pos.y - 5))
287 triangle.append(cmpPoint(x_mid, self.pos.y))
288 triangle.append(cmpPoint(self.pos.x, self.pos.y))
289 dc.DrawPolygon(triangle)
290 dc.SetBrush(wx.NullBrush)
291 dc.SetPen(wx.NullPen)
292
293 # Draw the heading if needed
294 if self.heading:
295 x_adjust = 0
296 y_adjust = 4
297 x_half = self.bmp.GetWidth()/2
298 y_half = self.bmp.GetHeight()/2
299 x_quarter = self.bmp.GetWidth()/4
300 y_quarter = self.bmp.GetHeight()/4
301 x_3quarter = x_quarter*3
302 y_3quarter = y_quarter*3
303 x_full = self.bmp.GetWidth()
304 y_full = self.bmp.GetHeight()
305 x_center = self.pos.x + x_half
306 y_center = self.pos.y + y_half
307 # Remember, the pen/brush must be a different color than the
308 # facing marker!!!! We'll use black/cyan for starters.
309 # Also notice that we will draw the heading on top of the
310 # larger facing marker.
311 dc.SetPen(wx.BLACK_PEN)
312 dc.SetBrush(wx.CYAN_BRUSH)
313 triangle = []
314
315 # Figure out which direction to draw the marker!!
316 if self.heading == FACE_NORTH:
317 triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
318 triangle.append(cmpPoint(x_center, y_center - y_3quarter ))
319 triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
320 elif self.heading == FACE_SOUTH:
321 triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
322 triangle.append(cmpPoint(x_center, y_center + y_3quarter ))
323 triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
324 elif self.heading == FACE_NORTHEAST:
325 triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
326 triangle.append(cmpPoint(x_center + x_3quarter, y_center - y_3quarter ))
327 triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
328 elif self.heading == FACE_EAST:
329 triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
330 triangle.append(cmpPoint(x_center + x_3quarter, y_center ))
331 triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
332 elif self.heading == FACE_SOUTHEAST:
333 triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
334 triangle.append(cmpPoint(x_center + x_3quarter, y_center + y_3quarter ))
335 triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
336 elif self.heading == FACE_SOUTHWEST:
337 triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
338 triangle.append(cmpPoint(x_center - x_3quarter, y_center + y_3quarter ))
339 triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
340 elif self.heading == FACE_WEST:
341 triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
342 triangle.append(cmpPoint(x_center - x_3quarter, y_center ))
343 triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
344 elif self.heading == FACE_NORTHWEST:
345 triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
346 triangle.append(cmpPoint(x_center - x_3quarter, y_center - y_3quarter ))
347 triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
348 dc.DrawPolygon(triangle)
349 dc.SetBrush(wx.NullBrush)
350 dc.SetPen(wx.NullPen)
351 #selected outline
352 if self.selected:
353 dc.SetPen(wx.RED_PEN)
354 dc.SetBrush(wx.TRANSPARENT_BRUSH)
355 dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
356 dc.SetBrush(wx.NullBrush)
357 dc.SetPen(wx.NullPen)
358 # draw label
359 label = mini_layer.get_mini_label(self)
360 if len(label):
361 dc.SetTextForeground(wx.RED)
362 (textWidth,textHeight) = dc.GetTextExtent(label)
363 x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
364 y = self.pos.y + self.bmp.GetHeight() + 6
365 dc.SetPen(wx.WHITE_PEN)
366 dc.SetBrush(wx.WHITE_BRUSH)
367 dc.DrawRectangle(x,y,textWidth+2,textHeight+2)
368 if (textWidth+2 > self.right):
369 self.right += int((textWidth+2-self.right)/2)+1
370 self.left -= int((textWidth+2-self.right)/2)+1
371 self.bottom = y+textHeight+2-self.pos.y
372 dc.SetPen(wx.NullPen)
373 dc.SetBrush(wx.NullBrush)
374 dc.DrawText(label,x+1,y+1)
375 self.top-=5
376 self.bottom+=5
377 self.left-=5
378 self.right+=5
379 self.log.log("Exit BmpMiniature->draw->Not Hidden", ORPG_DEBUG)
380 return True
381 else:
382 self.log.log("Exit BmpMiniature->draw(self, dc, mini_layer, op) return False", ORPG_DEBUG)
383 return False
384 self.log.log("Exit BmpMiniature->draw(self, dc, mini_layer, op)", ORPG_DEBUG)
385
386 def toxml(self, action="update"):
387 self.log.log("Enter BmpMiniature->toxml(self, " + action + ")", ORPG_DEBUG)
388 if action == "del":
389 xml_str = "<miniature action='del' id='" + self.id + "'/>"
390 self.log.log(xml_str, ORPG_DEBUG)
391 self.log.log("Exit BmpMiniature->toxml(self, " + action + ")", ORPG_DEBUG)
392 return xml_str
393 xml_str = "<miniature"
394 xml_str += " action='" + action + "'"
395 xml_str += " label='" + self.label + "'"
396 xml_str+= " id='" + self.id + "'"
397 if self.pos != None:
398 xml_str += " posx='" + str(self.pos.x) + "'"
399 xml_str += " posy='" + str(self.pos.y) + "'"
400 if self.heading != None:
401 xml_str += " heading='" + str(self.heading) + "'"
402 if self.face != None:
403 xml_str += " face='" + str(self.face) + "'"
404 if self.path != None:
405 xml_str += " path='" + urllib.quote(self.path).replace('%3A', ':') + "'"
406 if self.locked:
407 xml_str += " locked='1'"
408 else:
409 xml_str += " locked='0'"
410 if self.hide:
411 xml_str += " hide='1'"
412 else:
413 xml_str += " hide='0'"
414 if self.snap_to_align != None:
415 xml_str += " align='" + str(self.snap_to_align) + "'"
416 if self.id != None:
417 xml_str += " zorder='" + str(self.zorder) + "'"
418 if self.width != None:
419 xml_str += " width='" + str(self.width) + "'"
420 if self.height != None:
421 xml_str += " height='" + str(self.height) + "'"
422 if self.local:
423 xml_str += ' local="' + str(self.local) + '"'
424 xml_str += ' localPath="' + str(urllib.quote(self.localPath).replace('%3A', ':')) + '"'
425 xml_str += ' localTime="' + str(self.localTime) + '"'
426 xml_str += " />"
427 self.log.log(xml_str, ORPG_DEBUG)
428 self.log.log("Exit BmpMiniature->toxml(self, " + action + ")", ORPG_DEBUG)
429 if (action == "update" and self.isUpdated) or action == "new":
430 self.isUpdated = False
431 return xml_str
432 else:
433 return ''
434
435 def takedom(self, xml_dom):
436 self.log.log("Enter BmpMiniature->takedom(self, xml_dom)", ORPG_DEBUG)
437 self.id = xml_dom.getAttribute("id")
438 self.log.log("self.id=" + str(self.id), ORPG_DEBUG)
439 if xml_dom.hasAttribute("posx"):
440 self.pos.x = int(xml_dom.getAttribute("posx"))
441 self.log.log("self.pos.x=" + str(self.pos.x), ORPG_DEBUG)
442 if xml_dom.hasAttribute("posy"):
443 self.pos.y = int(xml_dom.getAttribute("posy"))
444 self.log.log("self.pos.y=" + str(self.pos.y), ORPG_DEBUG)
445 if xml_dom.hasAttribute("heading"):
446 self.heading = int(xml_dom.getAttribute("heading"))
447 self.log.log("self.heading=" + str(self.heading), ORPG_DEBUG)
448 if xml_dom.hasAttribute("face"):
449 self.face = int(xml_dom.getAttribute("face"))
450 self.log.log("self.face=" + str(self.face), ORPG_DEBUG)
451 if xml_dom.hasAttribute("path"):
452 self.path = urllib.unquote(xml_dom.getAttribute("path"))
453 self.set_bmp(ImageHandler.load(self.path, 'miniature', self.id))
454 self.log.log("self.path=" + self.path, ORPG_DEBUG)
455 if xml_dom.hasAttribute("locked"):
456 if xml_dom.getAttribute("locked") == '1' or xml_dom.getAttribute("locked") == 'True':
457 self.locked = True
458 else:
459 self.locked = False
460 self.log.log("self.locked=" + str(self.locked), ORPG_DEBUG)
461 if xml_dom.hasAttribute("hide"):
462 if xml_dom.getAttribute("hide") == '1' or xml_dom.getAttribute("hide") == 'True':
463 self.hide = True
464 else:
465 self.hide = False
466 self.log.log("self.hide=" + str(self.hide), ORPG_DEBUG)
467 if xml_dom.hasAttribute("label"):
468 self.label = xml_dom.getAttribute("label")
469 self.log.log("self.label=" + self.label, ORPG_DEBUG)
470 if xml_dom.hasAttribute("zorder"):
471 self.zorder = int(xml_dom.getAttribute("zorder"))
472 self.log.log("self.zorder=" + str(self.zorder), ORPG_DEBUG)
473 if xml_dom.hasAttribute("align"):
474 if xml_dom.getAttribute("align") == '1' or xml_dom.getAttribute("align") == 'True':
475 self.snap_to_align = 1
476 else:
477 self.snap_to_align = 0
478 self.log.log("self.snap_to_align=" + str(self.snap_to_align), ORPG_DEBUG)
479 if xml_dom.hasAttribute("width"):
480 self.width = int(xml_dom.getAttribute("width"))
481 self.log.log("self.width=" + str(self.width), ORPG_DEBUG)
482 if xml_dom.hasAttribute("height"):
483 self.height = int(xml_dom.getAttribute("height"))
484 self.log.log("self.height=" + str(self.height), ORPG_DEBUG)
485 self.log.log("Exit BmpMiniature->takedom(self, xml_dom)", ORPG_DEBUG)
486
487 ##-----------------------------
488 ## miniature layer
489 ##-----------------------------
490 class miniature_layer(layer_base):
491 def __init__(self, canvas):
492 self.canvas = canvas
493 self.log = self.canvas.log
494 self.log.log("Enter miniature_layer", ORPG_DEBUG)
495 self.settings = self.canvas.settings
496 layer_base.__init__(self)
497 self.miniatures = []
498 self.serial_number = 0
499 self.log.log("Exit miniature_layer", ORPG_DEBUG)
500
501 def next_serial(self):
502 self.log.log("Enter miniature_layer->next_serial(self)", ORPG_DEBUG)
503 self.serial_number += 1
504 self.log.log("Exit miniature_layer->next_serial(self)", ORPG_DEBUG)
505 return self.serial_number
506
507 def get_next_highest_z(self):
508 self.log.log("Enter miniature_layer->get_next_highest_z(self)", ORPG_DEBUG)
509 z = len(self.miniatures)+1
510 self.log.log("Exit miniature_layer->get_next_highest_z(self)", ORPG_DEBUG)
511 return z
512
513 def cleanly_collapse_zorder(self):
514 self.log.log("Enter miniature_layer->cleanly_collapse_zorder(self)", ORPG_DEBUG)
515 # lock the zorder stuff
516 sorted_miniatures = self.miniatures[:]
517 sorted_miniatures.sort(cmp_zorder)
518 i = 0
519 for mini in sorted_miniatures:
520 mini.zorder = i
521 i = i + 1
522 self.log.log("Exit miniature_layer->cleanly_collapse_zorder(self)", ORPG_DEBUG)
523 # unlock the zorder stuff
524
525 def collapse_zorder(self):
526 self.log.log("Enter miniature_layer->collapse_zorder(self)", ORPG_DEBUG)
527 # lock the zorder stuff
528 sorted_miniatures = self.miniatures[:]
529 sorted_miniatures.sort(cmp_zorder)
530 i = 0
531 for mini in sorted_miniatures:
532 if (mini.zorder != MIN_STICKY_BACK) and (mini.zorder != MIN_STICKY_FRONT):
533 mini.zorder = i
534 else:
535 pass
536 i = i + 1
537 self.log.log("Exit miniature_layer->collapse_zorder(self)", ORPG_DEBUG)
538 # unlock the zorder stuff
539
540 def rollback_serial(self):
541 self.log.log("Enter miniature_layer->rollback_serial(self)", ORPG_DEBUG)
542 self.serial_number -= 1
543 self.log.log("Exit miniature_layer->rollback_serial(self)", ORPG_DEBUG)
544
545 def add_miniature(self, id, path, pos=cmpPoint(0,0), label="", heading=FACE_NONE, face=FACE_NONE, width=0, height=0, local=False, localPath='', localTime=-1):
546 self.log.log("Enter miniature_layer->add_miniature(self, id, path, pos, label, heading, face, width, height)", ORPG_DEBUG)
547 self.log.log("Before mini creation: " + str(self.get_next_highest_z()), ORPG_DEBUG)
548 bmp = ImageHandler.load(path, 'miniature', id)
549 if bmp:
550 mini = BmpMiniature(id, path, bmp, pos, heading, face, label, zorder=self. get_next_highest_z(), width=width, height=height, log=self.log, local=local, localPath=localPath, localTime=localTime)
551 self.log.log("After mini creation:" + str(self.get_next_highest_z()), ORPG_DEBUG)
552 self.miniatures.append(mini)
553 self.log.log("After mini addition:" + str(self.get_next_highest_z()), ORPG_DEBUG)
554 xml_str = "<map><miniatures>"
555 xml_str += mini.toxml("new")
556 xml_str += "</miniatures></map>"
557 self.canvas.frame.session.send(xml_str)
558 else:
559 self.log.log("Invalid image " + path + " has been ignored!", ORPG_DEBUG)
560 self.log.log("Exit miniature_layer->add_miniature(self, id, path, pos, label, heading, face, width, height)", ORPG_DEBUG)
561
562 def get_miniature_by_id(self, id):
563 self.log.log("Enter miniature_layer->get_miniature_by_id(self, id)", ORPG_DEBUG)
564 for mini in self.miniatures:
565 if str(mini.id) == str(id):
566 self.log.log("Exit miniature_layer->get_miniature_by_id(self, id) return miniID: " + str(id), ORPG_DEBUG)
567 return mini
568 self.log.log("Exit miniature_layer->get_miniature_by_id(self, id) return None", ORPG_DEBUG)
569 return None
570
571 def del_miniature(self, min):
572 self.log.log("Enter miniature_layer->del_miniature(self, min)", ORPG_DEBUG)
573 xml_str = "<map><miniatures>"
574 xml_str += min.toxml("del")
575 xml_str += "</miniatures></map>"
576 self.canvas.frame.session.send(xml_str)
577 self.miniatures.remove(min)
578 del min
579 self.collapse_zorder()
580 self.log.log("Exit miniature_layer->del_miniature(self, min)", ORPG_DEBUG)
581
582 def del_all_miniatures(self):
583 self.log.log("Enter miniature_layer->del_all_miniatures(self)", ORPG_DEBUG)
584 while len(self.miniatures):
585 min = self.miniatures.pop()
586 del min
587 self.collapse_zorder()
588 self.log.log("Exit miniature_layer->del_all_miniatures(self)", ORPG_DEBUG)
589
590 def layerDraw(self, dc, topleft, size):
591 self.log.log("Enter miniature_layer->layerDraw(self, dc, topleft, size)", ORPG_DEBUG)
592 sorted_miniatures = self.miniatures[:]
593 sorted_miniatures.sort(cmp_zorder)
594 for m in sorted_miniatures:
595 if (m.pos.x>topleft[0]-m.right and
596 m.pos.y>topleft[1]-m.bottom and
597 m.pos.x<topleft[0]+size[0]-m.left and
598 m.pos.y<topleft[1]+size[1]-m.top):
599 m.draw(dc, self)
600 self.log.log("Exit miniature_layer->layerDraw(self, dc, topleft, size)", ORPG_DEBUG)
601
602 def find_miniature(self, pt, only_unlocked=False):
603 self.log.log("Enter miniature_layer->find_miniature(self, pt, only_unlocked)", ORPG_DEBUG)
604 min_list = []
605 for m in self.miniatures:
606 if m.hit_test(pt):
607 if m.hide and self.canvas.frame.session.my_role() != self.canvas.frame.session.ROLE_GM:
608 continue
609 if only_unlocked and not m.locked:
610 min_list.append(m)
611 elif not only_unlocked and m.locked:
612 min_list.append(m)
613 else:
614 continue
615 if len(min_list) > 0:
616 self.log.log("Exit miniature_layer->find_miniature(self, pt, only_unlocked)", ORPG_DEBUG)
617 return min_list
618 else:
619 self.log.log("Exit miniature_layer->find_miniature(self, pt, only_unlocked)", ORPG_DEBUG)
620 return None
621
622 def layerToXML(self, action="update"):
623 """ format """
624 self.log.log("Enter miniature_layer->layerToXML(self, " + action + ")", ORPG_DEBUG)
625 minis_string = ""
626 if self.miniatures:
627 for m in self.miniatures:
628 minis_string += m.toxml(action)
629 if minis_string != '':
630 s = "<miniatures"
631 s += " serial='" + str(self.serial_number) + "'"
632 s += ">"
633 s += minis_string
634 s += "</miniatures>"
635 self.log.log("Exit miniature_layer->layerToXML(self, " + action + ")", ORPG_DEBUG)
636 return s
637 else:
638 self.log.log("Exit miniature_layer->layerToXML(self, " + action + ") return None", ORPG_DEBUG)
639 return ""
640
641 def layerTakeDOM(self, xml_dom):
642 self.log.log("Enter miniature_layer->layerTakeDOM(self, xml_dom)", ORPG_DEBUG)
643 if xml_dom.hasAttribute('serial'):
644 self.serial_number = int(xml_dom.getAttribute('serial'))
645 children = xml_dom._get_childNodes()
646 for c in children:
647 action = c.getAttribute("action")
648 id = c.getAttribute('id')
649 if action == "del":
650 mini = self.get_miniature_by_id(id)
651 if mini:
652 self.miniatures.remove(mini)
653 del mini
654 else:
655 self.log.log("Map Synchronization Error :: Update of unknown mini attempted", ORPG_DEBUG)
656 #wx.MessageBox("Deletion of unknown mini attempted","Map Synchronization Error")
657 elif action == "new":
658 pos = cmpPoint(int(c.getAttribute('posx')),int(c.getAttribute('posy')))
659 path = urllib.unquote(c.getAttribute('path'))
660 label = c.getAttribute('label')
661 height = width = heading = face = snap_to_align = zorder = 0
662 locked = hide = False
663 if c.hasAttribute('height'):
664 height = int(c.getAttribute('height'))
665 if c.hasAttribute('width'):
666 width = int(c.getAttribute('width'))
667 if c.getAttribute('locked') == 'True' or c.getAttribute('locked') == '1':
668 locked = True
669 if c.getAttribute('hide') == 'True' or c.getAttribute('hide') == '1':
670 hide = True
671 if c.getAttribute('heading'):
672 heading = int(c.getAttribute('heading'))
673 if c.hasAttribute('face'):
674 face = int(c.getAttribute('face'))
675 if c.hasAttribute('align'):
676 snap_to_align = int(c.getAttribute('align'))
677 if c.getAttribute('zorder'):
678 zorder = int(c.getAttribute('zorder'))
679 min = BmpMiniature(id, path, ImageHandler.load(path, 'miniature', id), pos, heading, face, label, locked, hide, snap_to_align, zorder, width, height, self.log)
680 self.miniatures.append(min)
681 if c.hasAttribute('local') and c.getAttribute('local') == 'True' and os.path.exists(urllib.unquote(c.getAttribute('localPath'))):
682 localPath = urllib.unquote(c.getAttribute('localPath'))
683 local = True
684 localTime = float(c.getAttribute('localTime'))
685 if localTime-time.time() <= 144000:
686 file = open(localPath, "rb")
687 imgdata = file.read()
688 file.close()
689 filename = os.path.split(localPath)
690 (imgtype,j) = mimetypes.guess_type(filename[1])
691 postdata = urllib.urlencode({'filename':filename[1], 'imgdata':imgdata, 'imgtype':imgtype})
692 thread.start_new_thread(self.upload, (postdata, localPath, True))
693 # collapse the zorder. If the client behaved well, then nothing should change.
694 # Otherwise, this will ensure that there's some kind of z-order
695 self.collapse_zorder()
696 else:
697 mini = self.get_miniature_by_id(id)
698 if mini:
699 mini.takedom(c)
700 else:
701 self.log.log("Map Synchronization Error :: Update of unknown mini attempted", ORPG_DEBUG)
702 #wx.MessageBox("Update of unknown mini attempted","Map Synchronization Error")
703 self.log.log("Exit miniature_layer->layerTakeDOM(self, xml_dom)", ORPG_DEBUG)
704
705 def upload(self, postdata, filename, modify=False, pos=cmpPoint(0,0)):
706 self.lock.acquire()
707 url = self.settings.get_setting('ImageServerBaseURL')
708 file = urllib.urlopen(url, postdata)
709 recvdata = file.read()
710 file.close()
711 try:
712 xml_dom = minidom.parseString(recvdata)._get_documentElement()
713 if xml_dom.nodeName == 'path':
714 path = xml_dom.getAttribute('url')
715 path = urllib.unquote(path)
716 if not modify:
717 start = path.rfind("/") + 1
718 if self.canvas.parent.layer_handlers[2].auto_label:
719 min_label = path[start:len(path)-4]
720 else:
721 min_label = ""
722 id = 'mini-' + self.canvas.frame.session.get_next_id()
723 self.add_miniature(id, path, pos=pos, label=min_label, local=True, localPath=filename, localTime=time.time())
724 else:
725 self.miniatures[len(self.miniatures)-1].local = True
726 self.miniatures[len(self.miniatures)-1].localPath = filename
727 self.miniatures[len(self.miniatures)-1].localTime = time.time()
728 self.miniatures[len(self.miniatures)-1].path = path
729 else:
730 print xml_dom.getAttribute('msg')
731 except Exception, e:
732 print e
733 print recvdata
734 urllib.urlcleanup()
735 self.lock.release()
736 ####################################################################
737 ## helper function
738
739 def get_mini_label(self, mini):
740 # override this to change the label displayed under each mini (and the label on hidden minis)
741 return mini.label