diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/mapper/miniatures.py	Tue Jul 14 16:41:58 2009 -0500
@@ -0,0 +1,741 @@
+# Copyright (C) 2000-2001 The OpenRPG Project
+#
+#    openrpg-dev@lists.sourceforge.net
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# --
+#
+# File: mapper/miniatures.py
+# Author: Chris Davis
+# Maintainer:
+# Version:
+#   $Id: miniatures.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $
+#
+# Description: This file contains some of the basic definitions for the chat
+# utilities in the orpg project.
+#
+__version__ = "$Id: miniatures.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $"
+
+from base import *
+import thread
+import time
+import urllib
+import os.path
+
+MIN_STICKY_BACK = -0XFFFFFF
+MIN_STICKY_FRONT = 0xFFFFFF
+
+##----------------------------------------
+##  miniature object
+##----------------------------------------
+
+FACE_NONE = 0
+FACE_NORTH = 1
+FACE_NORTHEAST = 2
+FACE_EAST = 3
+FACE_SOUTHEAST = 4
+FACE_SOUTH = 5
+FACE_SOUTHWEST = 6
+FACE_WEST = 7
+FACE_NORTHWEST = 8
+SNAPTO_ALIGN_CENTER = 0
+SNAPTO_ALIGN_TL = 1
+
+def cmp_zorder(first,second):
+    f = first.zorder
+    s = second.zorder
+    if f == None:
+        f = 0
+    if s == None:
+        s = 0
+    if f == s:
+        value = 0
+    elif f < s:
+        value = -1
+    else:
+        value = 1
+    return value
+
+class BmpMiniature:
+    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):
+        self.log = log
+        self.log.log("Enter BmpMiniature", ORPG_DEBUG)
+        self.heading = heading
+        self.face = face
+        self.label = label
+        self.path = path
+        self.bmp = bmp
+        self.pos = pos
+        self.selected = False
+        self.locked = locked
+        self.snap_to_align = snap_to_align
+        self.hide = hide
+        self.id = id
+        self.zorder = zorder
+        self.left = 0
+        self.local = local
+        self.localPath = localPath
+        self.localTime = localTime
+        if not width:
+            self.width = 0
+        else:
+            self.width = width
+        if not height:
+            self.height = 0
+        else:
+            self.height = height
+        self.right = bmp.GetWidth()
+        self.top = 0
+        self.bottom = bmp.GetHeight()
+        self.isUpdated = False
+        self.gray = False
+        self.log.log("Exit BmpMiniature", ORPG_DEBUG)
+
+    def __del__(self):
+        self.log.log("Enter BmpMiniature->__del__(self)", ORPG_DEBUG)
+        del self.bmp
+        self.bmp = None
+        self.log.log("Exit BmpMiniature->__del__(self)", ORPG_DEBUG)
+
+    def set_bmp(self, bmp):
+        self.log.log("Enter BmpMiniature->set_bmp(self, bmp)", ORPG_DEBUG)
+        self.bmp = bmp
+        self.log.log("Exit BmpMiniature->set_bmp(self, bmp)", ORPG_DEBUG)
+
+    def set_min_props(self, heading=FACE_NONE, face=FACE_NONE, label="", locked=False, hide=False, width=0, height=0):
+        self.log.log("Enter BmpMiniature->set_min_props(self, heading, face, label, locked, hide, width, height)", ORPG_DEBUG)
+        self.heading = heading
+        self.face = face
+        self.label = label
+        if locked:
+            self.locked = True
+        else:
+            self.locked = False
+        if hide:
+            self.hide = True
+        else:
+            self.hide = False
+        self.width = int(width)
+        self.height = int(height)
+        self.isUpdated = True
+        self.log.log("Exit BmpMiniature->set_min_props(self, heading, face, label, locked, hide, width, height)", ORPG_DEBUG)
+
+    def hit_test(self, pt):
+        self.log.log("Enter BmpMiniature->hit_test(self, pt)", ORPG_DEBUG)
+        rect = self.get_rect()
+        result = None
+        result = rect.InsideXY(pt.x, pt.y)
+        self.log.log("Exit BmpMiniature->hit_test(self, pt)", ORPG_DEBUG)
+        return result
+
+    def get_rect(self):
+        self.log.log("Enter BmpMiniature->get_rect(self)", ORPG_DEBUG)
+        ret = wx.Rect(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
+        self.log.log("Exit BmpMiniature->get_rect(self)", ORPG_DEBUG)
+        return ret
+
+    def draw(self, dc, mini_layer, op=wx.COPY):
+        self.log.log("Enter BmpMiniature->draw(self, dc, mini_layer, op)", ORPG_DEBUG)
+        if isinstance(self.bmp, tuple):
+            self.log.log("bmp is a tuple, it shouldnt be!", ORPG_INFO)
+            self.bmp = wx.ImageFromMime(self.bmp[1], self.bmp[2]).ConvertToBitmap()
+        if self.bmp != None and self.bmp.Ok():
+            # check if hidden and GM: we outline the mini in grey (little bit smaller than the actual size)
+            # and write the label in the center of the mini
+            if self.hide and mini_layer.canvas.frame.session.my_role() == mini_layer.canvas.frame.session.ROLE_GM:
+                self.log.log("Enter BmpMiniature->draw->Draw Hidden", ORPG_DEBUG)
+                # set the width and height of the image
+                if self.width and self.height:
+                    tmp_image = self.bmp.ConvertToImage()
+                    tmp_image.Rescale(int(self.width), int(self.height))
+                    tmp_image.ConvertAlphaToMask()
+                    self.bmp = tmp_image.ConvertToBitmap()
+                    mask = wx.Mask(self.bmp, wx.Colour(tmp_image.GetMaskRed(), tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
+                    self.bmp.SetMask(mask)
+                    del tmp_image
+                    del mask
+                self.left = 0
+                self.right = self.bmp.GetWidth()
+                self.top = 0
+                self.bottom = self.bmp.GetHeight()
+                # grey outline
+                graypen = wx.Pen("gray", 1, wx.DOT)
+                dc.SetPen(graypen)
+                dc.SetBrush(wx.TRANSPARENT_BRUSH)
+                #if width or height < 20 then offset = 1
+                if self.bmp.GetWidth() <= 20:
+                    xoffset = 1
+                else:
+                    xoffset = 5
+                if self.bmp.GetHeight() <= 20:
+                    yoffset = 1
+                else:
+                    yoffset = 5
+                dc.DrawRectangle(self.pos.x + xoffset, self.pos.y + yoffset, self.bmp.GetWidth() - (xoffset * 2), self.bmp.GetHeight() - (yoffset * 2))
+                dc.SetBrush(wx.NullBrush)
+                dc.SetPen(wx.NullPen)
+                ## draw label in the center of the mini
+                label = mini_layer.get_mini_label(self)
+                if len(label):
+                    dc.SetTextForeground(wx.RED)
+                    (textWidth,textHeight) = dc.GetTextExtent(label)
+                    x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
+                    y = self.pos.y + (self.bmp.GetHeight() / 2)
+                    dc.SetPen(wx.GREY_PEN)
+                    dc.SetBrush(wx.LIGHT_GREY_BRUSH)
+                    dc.DrawRectangle(x, y, textWidth+2, textHeight+2)
+                    if (textWidth+2 > self.right):
+                        self.right += int((textWidth+2-self.right)/2)+1
+                        self.left -= int((textWidth+2-self.right)/2)+1
+                    self.bottom = y+textHeight+2-self.pos.y
+                    dc.SetPen(wx.NullPen)
+                    dc.SetBrush(wx.NullBrush)
+                    dc.DrawText(label, x+1, y+1)
+
+                #selected outline
+                if self.selected:
+                    dc.SetPen(wx.RED_PEN)
+                    dc.SetBrush(wx.TRANSPARENT_BRUSH)
+                    dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
+                    dc.SetBrush(wx.NullBrush)
+                    dc.SetPen(wx.NullPen)
+                self.log.log("Exit BmpMiniature->draw->Draw Hidden", ORPG_DEBUG)
+                return True
+            elif self.hide:
+                self.log.log("Enter/Exit BmpMiniature->draw->Skip Hidden", ORPG_DEBUG)
+                return True
+
+            else:
+                self.log.log("Enter BmpMiniature->draw->Not Hidden", ORPG_DEBUG)
+                # set the width and height of the image
+                bmp = self.bmp
+                if self.width and self.height:
+                    tmp_image = self.bmp.ConvertToImage()
+                    tmp_image.Rescale(int(self.width), int(self.height))
+                    tmp_image.ConvertAlphaToMask()
+                    self.bmp = tmp_image.ConvertToBitmap()
+                    mask = wx.Mask(self.bmp, wx.Colour(tmp_image.GetMaskRed(), tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
+                    self.bmp.SetMask(mask)
+                    if self.gray:
+                        tmp_image = tmp_image.ConvertToGreyscale()
+                        bmp = tmp_image.ConvertToBitmap()
+                    else:
+                        bmp = self.bmp
+                dc.DrawBitmap(bmp, self.pos.x, self.pos.y, True)
+                self.left = 0
+                self.right = self.bmp.GetWidth()
+                self.top = 0
+                self.bottom = self.bmp.GetHeight()
+
+                # Draw the facing marker if needed
+                if self.face != 0:
+                    x_mid = self.pos.x + (self.bmp.GetWidth()/2)
+                    x_right = self.pos.x + self.bmp.GetWidth()
+                    y_mid = self.pos.y + (self.bmp.GetHeight()/2)
+                    y_bottom = self.pos.y + self.bmp.GetHeight()
+                    dc.SetPen(wx.WHITE_PEN)
+                    dc.SetBrush(wx.RED_BRUSH)
+                    triangle = []
+
+                    # Figure out which direction to draw the marker!!
+                    if self.face == FACE_WEST:
+                        triangle.append(cmpPoint(self.pos.x,self.pos.y))
+                        triangle.append(cmpPoint(self.pos.x - 5, y_mid))
+                        triangle.append(cmpPoint(self.pos.x, y_bottom))
+                    elif self.face ==  FACE_EAST:
+                        triangle.append(cmpPoint(x_right, self.pos.y))
+                        triangle.append(cmpPoint(x_right + 5, y_mid))
+                        triangle.append(cmpPoint(x_right, y_bottom))
+                    elif self.face ==  FACE_SOUTH:
+                        triangle.append(cmpPoint(self.pos.x, y_bottom))
+                        triangle.append(cmpPoint(x_mid, y_bottom + 5))
+                        triangle.append(cmpPoint(x_right, y_bottom))
+                    elif self.face ==  FACE_NORTH:
+                        triangle.append(cmpPoint(self.pos.x, self.pos.y))
+                        triangle.append(cmpPoint(x_mid, self.pos.y - 5))
+                        triangle.append(cmpPoint(x_right, self.pos.y))
+                    elif self.face == FACE_NORTHEAST:
+                        triangle.append(cmpPoint(x_mid, self.pos.y))
+                        triangle.append(cmpPoint(x_right + 5, self.pos.y - 5))
+                        triangle.append(cmpPoint(x_right, y_mid))
+                        triangle.append(cmpPoint(x_right, self.pos.y))
+                    elif self.face == FACE_SOUTHEAST:
+                        triangle.append(cmpPoint(x_right, y_mid))
+                        triangle.append(cmpPoint(x_right + 5, y_bottom + 5))
+                        triangle.append(cmpPoint(x_mid, y_bottom))
+                        triangle.append(cmpPoint(x_right, y_bottom))
+                    elif self.face == FACE_SOUTHWEST:
+                        triangle.append(cmpPoint(x_mid, y_bottom))
+                        triangle.append(cmpPoint(self.pos.x - 5, y_bottom + 5))
+                        triangle.append(cmpPoint(self.pos.x, y_mid))
+                        triangle.append(cmpPoint(self.pos.x, y_bottom))
+                    elif self.face == FACE_NORTHWEST:
+                        triangle.append(cmpPoint(self.pos.x, y_mid))
+                        triangle.append(cmpPoint(self.pos.x - 5, self.pos.y - 5))
+                        triangle.append(cmpPoint(x_mid, self.pos.y))
+                        triangle.append(cmpPoint(self.pos.x, self.pos.y))
+                    dc.DrawPolygon(triangle)
+                    dc.SetBrush(wx.NullBrush)
+                    dc.SetPen(wx.NullPen)
+
+                # Draw the heading if needed
+                if self.heading:
+                    x_adjust = 0
+                    y_adjust = 4
+                    x_half = self.bmp.GetWidth()/2
+                    y_half = self.bmp.GetHeight()/2
+                    x_quarter = self.bmp.GetWidth()/4
+                    y_quarter = self.bmp.GetHeight()/4
+                    x_3quarter = x_quarter*3
+                    y_3quarter = y_quarter*3
+                    x_full = self.bmp.GetWidth()
+                    y_full = self.bmp.GetHeight()
+                    x_center = self.pos.x + x_half
+                    y_center = self.pos.y + y_half
+                    # Remember, the pen/brush must be a different color than the
+                    # facing marker!!!!  We'll use black/cyan for starters.
+                    # Also notice that we will draw the heading on top of the
+                    # larger facing marker.
+                    dc.SetPen(wx.BLACK_PEN)
+                    dc.SetBrush(wx.CYAN_BRUSH)
+                    triangle = []
+
+                    # Figure out which direction to draw the marker!!
+                    if self.heading == FACE_NORTH:
+                        triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
+                        triangle.append(cmpPoint(x_center, y_center - y_3quarter ))
+                        triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
+                    elif self.heading ==  FACE_SOUTH:
+                        triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
+                        triangle.append(cmpPoint(x_center, y_center + y_3quarter ))
+                        triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
+                    elif self.heading == FACE_NORTHEAST:
+                        triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
+                        triangle.append(cmpPoint(x_center + x_3quarter, y_center - y_3quarter ))
+                        triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
+                    elif self.heading == FACE_EAST:
+                        triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
+                        triangle.append(cmpPoint(x_center + x_3quarter, y_center ))
+                        triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
+                    elif self.heading == FACE_SOUTHEAST:
+                        triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
+                        triangle.append(cmpPoint(x_center + x_3quarter, y_center + y_3quarter ))
+                        triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
+                    elif self.heading == FACE_SOUTHWEST:
+                        triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
+                        triangle.append(cmpPoint(x_center - x_3quarter, y_center + y_3quarter ))
+                        triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
+                    elif self.heading == FACE_WEST:
+                        triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
+                        triangle.append(cmpPoint(x_center - x_3quarter, y_center ))
+                        triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
+                    elif self.heading == FACE_NORTHWEST:
+                        triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
+                        triangle.append(cmpPoint(x_center - x_3quarter, y_center - y_3quarter ))
+                        triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
+                    dc.DrawPolygon(triangle)
+                    dc.SetBrush(wx.NullBrush)
+                    dc.SetPen(wx.NullPen)
+                #selected outline
+                if self.selected:
+                    dc.SetPen(wx.RED_PEN)
+                    dc.SetBrush(wx.TRANSPARENT_BRUSH)
+                    dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
+                    dc.SetBrush(wx.NullBrush)
+                    dc.SetPen(wx.NullPen)
+                # draw label
+                label = mini_layer.get_mini_label(self)
+                if len(label):
+                    dc.SetTextForeground(wx.RED)
+                    (textWidth,textHeight) = dc.GetTextExtent(label)
+                    x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
+                    y = self.pos.y + self.bmp.GetHeight() + 6
+                    dc.SetPen(wx.WHITE_PEN)
+                    dc.SetBrush(wx.WHITE_BRUSH)
+                    dc.DrawRectangle(x,y,textWidth+2,textHeight+2)
+                    if (textWidth+2 > self.right):
+                        self.right += int((textWidth+2-self.right)/2)+1
+                        self.left -= int((textWidth+2-self.right)/2)+1
+                    self.bottom = y+textHeight+2-self.pos.y
+                    dc.SetPen(wx.NullPen)
+                    dc.SetBrush(wx.NullBrush)
+                    dc.DrawText(label,x+1,y+1)
+                self.top-=5
+                self.bottom+=5
+                self.left-=5
+                self.right+=5
+                self.log.log("Exit BmpMiniature->draw->Not Hidden", ORPG_DEBUG)
+                return True
+        else:
+            self.log.log("Exit BmpMiniature->draw(self, dc, mini_layer, op) return False", ORPG_DEBUG)
+            return False
+        self.log.log("Exit BmpMiniature->draw(self, dc, mini_layer, op)", ORPG_DEBUG)
+
+    def toxml(self, action="update"):
+        self.log.log("Enter BmpMiniature->toxml(self, " + action + ")", ORPG_DEBUG)
+        if action == "del":
+            xml_str = "<miniature action='del' id='" + self.id + "'/>"
+            self.log.log(xml_str, ORPG_DEBUG)
+            self.log.log("Exit BmpMiniature->toxml(self, " + action + ")", ORPG_DEBUG)
+            return xml_str
+        xml_str = "<miniature"
+        xml_str += " action='" + action + "'"
+        xml_str += " label='" + self.label + "'"
+        xml_str+= " id='" + self.id + "'"
+        if self.pos != None:
+            xml_str += " posx='" + str(self.pos.x) + "'"
+            xml_str += " posy='" + str(self.pos.y) + "'"
+        if self.heading != None:
+            xml_str += " heading='" + str(self.heading) + "'"
+        if self.face != None:
+            xml_str += " face='" + str(self.face) + "'"
+        if self.path != None:
+            xml_str += " path='" + urllib.quote(self.path).replace('%3A', ':') + "'"
+        if self.locked:
+            xml_str += "  locked='1'"
+        else:
+            xml_str += "  locked='0'"
+        if self.hide:
+            xml_str += " hide='1'"
+        else:
+            xml_str += " hide='0'"
+        if self.snap_to_align != None:
+            xml_str += " align='" + str(self.snap_to_align) + "'"
+        if self.id != None:
+            xml_str += " zorder='" + str(self.zorder) + "'"
+        if self.width != None:
+            xml_str += " width='" + str(self.width) + "'"
+        if self.height != None:
+            xml_str += " height='" + str(self.height) + "'"
+        if self.local:
+            xml_str += ' local="' + str(self.local) + '"'
+            xml_str += ' localPath="' + str(urllib.quote(self.localPath).replace('%3A', ':')) + '"'
+            xml_str += ' localTime="' + str(self.localTime) + '"'
+        xml_str += " />"
+        self.log.log(xml_str, ORPG_DEBUG)
+        self.log.log("Exit BmpMiniature->toxml(self, " + action + ")", ORPG_DEBUG)
+        if (action == "update" and self.isUpdated) or action == "new":
+            self.isUpdated = False
+            return xml_str
+        else:
+            return ''
+
+    def takedom(self, xml_dom):
+        self.log.log("Enter BmpMiniature->takedom(self, xml_dom)", ORPG_DEBUG)
+        self.id = xml_dom.getAttribute("id")
+        self.log.log("self.id=" + str(self.id), ORPG_DEBUG)
+        if xml_dom.hasAttribute("posx"):
+            self.pos.x = int(xml_dom.getAttribute("posx"))
+            self.log.log("self.pos.x=" + str(self.pos.x), ORPG_DEBUG)
+        if xml_dom.hasAttribute("posy"):
+            self.pos.y = int(xml_dom.getAttribute("posy"))
+            self.log.log("self.pos.y=" + str(self.pos.y), ORPG_DEBUG)
+        if xml_dom.hasAttribute("heading"):
+            self.heading = int(xml_dom.getAttribute("heading"))
+            self.log.log("self.heading=" + str(self.heading), ORPG_DEBUG)
+        if xml_dom.hasAttribute("face"):
+            self.face = int(xml_dom.getAttribute("face"))
+            self.log.log("self.face=" + str(self.face), ORPG_DEBUG)
+        if xml_dom.hasAttribute("path"):
+            self.path = urllib.unquote(xml_dom.getAttribute("path"))
+            self.set_bmp(ImageHandler.load(self.path, 'miniature', self.id))
+            self.log.log("self.path=" + self.path, ORPG_DEBUG)
+        if xml_dom.hasAttribute("locked"):
+            if xml_dom.getAttribute("locked") == '1' or xml_dom.getAttribute("locked") == 'True':
+                self.locked = True
+            else:
+                self.locked = False
+            self.log.log("self.locked=" + str(self.locked), ORPG_DEBUG)
+        if xml_dom.hasAttribute("hide"):
+            if xml_dom.getAttribute("hide") == '1' or xml_dom.getAttribute("hide") == 'True':
+                self.hide = True
+            else:
+                self.hide = False
+            self.log.log("self.hide=" + str(self.hide), ORPG_DEBUG)
+        if xml_dom.hasAttribute("label"):
+            self.label = xml_dom.getAttribute("label")
+            self.log.log("self.label=" + self.label, ORPG_DEBUG)
+        if xml_dom.hasAttribute("zorder"):
+            self.zorder = int(xml_dom.getAttribute("zorder"))
+            self.log.log("self.zorder=" + str(self.zorder), ORPG_DEBUG)
+        if xml_dom.hasAttribute("align"):
+            if xml_dom.getAttribute("align") == '1' or xml_dom.getAttribute("align") == 'True':
+                self.snap_to_align = 1
+            else:
+                self.snap_to_align = 0
+            self.log.log("self.snap_to_align=" + str(self.snap_to_align), ORPG_DEBUG)
+        if xml_dom.hasAttribute("width"):
+            self.width = int(xml_dom.getAttribute("width"))
+            self.log.log("self.width=" + str(self.width), ORPG_DEBUG)
+        if xml_dom.hasAttribute("height"):
+            self.height = int(xml_dom.getAttribute("height"))
+            self.log.log("self.height=" + str(self.height), ORPG_DEBUG)
+        self.log.log("Exit BmpMiniature->takedom(self, xml_dom)", ORPG_DEBUG)
+
+##-----------------------------
+## miniature layer
+##-----------------------------
+class miniature_layer(layer_base):
+    def __init__(self, canvas):
+        self.canvas = canvas
+        self.log = self.canvas.log
+        self.log.log("Enter miniature_layer", ORPG_DEBUG)
+        self.settings = self.canvas.settings
+        layer_base.__init__(self)
+        self.miniatures = []
+        self.serial_number = 0
+        self.log.log("Exit miniature_layer", ORPG_DEBUG)
+
+    def next_serial(self):
+        self.log.log("Enter miniature_layer->next_serial(self)", ORPG_DEBUG)
+        self.serial_number += 1
+        self.log.log("Exit miniature_layer->next_serial(self)", ORPG_DEBUG)
+        return self.serial_number
+
+    def get_next_highest_z(self):
+        self.log.log("Enter miniature_layer->get_next_highest_z(self)", ORPG_DEBUG)
+        z = len(self.miniatures)+1
+        self.log.log("Exit miniature_layer->get_next_highest_z(self)", ORPG_DEBUG)
+        return z
+
+    def cleanly_collapse_zorder(self):
+        self.log.log("Enter miniature_layer->cleanly_collapse_zorder(self)", ORPG_DEBUG)
+        #  lock the zorder stuff
+        sorted_miniatures = self.miniatures[:]
+        sorted_miniatures.sort(cmp_zorder)
+        i = 0
+        for mini in sorted_miniatures:
+            mini.zorder = i
+            i = i + 1
+        self.log.log("Exit miniature_layer->cleanly_collapse_zorder(self)", ORPG_DEBUG)
+        #  unlock the zorder stuff
+
+    def collapse_zorder(self):
+        self.log.log("Enter miniature_layer->collapse_zorder(self)", ORPG_DEBUG)
+        #  lock the zorder stuff
+        sorted_miniatures = self.miniatures[:]
+        sorted_miniatures.sort(cmp_zorder)
+        i = 0
+        for mini in sorted_miniatures:
+            if (mini.zorder != MIN_STICKY_BACK) and (mini.zorder != MIN_STICKY_FRONT):
+                mini.zorder = i
+            else:
+                pass
+            i = i + 1
+        self.log.log("Exit miniature_layer->collapse_zorder(self)", ORPG_DEBUG)
+        #  unlock the zorder stuff
+
+    def rollback_serial(self):
+        self.log.log("Enter miniature_layer->rollback_serial(self)", ORPG_DEBUG)
+        self.serial_number -= 1
+        self.log.log("Exit miniature_layer->rollback_serial(self)", ORPG_DEBUG)
+
+    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):
+        self.log.log("Enter miniature_layer->add_miniature(self, id, path, pos, label, heading, face, width, height)", ORPG_DEBUG)
+        self.log.log("Before mini creation: " + str(self.get_next_highest_z()), ORPG_DEBUG)
+        bmp = ImageHandler.load(path, 'miniature', id)
+        if bmp:
+            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)
+            self.log.log("After mini creation:" + str(self.get_next_highest_z()), ORPG_DEBUG)
+            self.miniatures.append(mini)
+            self.log.log("After mini addition:" + str(self.get_next_highest_z()), ORPG_DEBUG)
+            xml_str = "<map><miniatures>"
+            xml_str += mini.toxml("new")
+            xml_str += "</miniatures></map>"
+            self.canvas.frame.session.send(xml_str)
+        else:
+            self.log.log("Invalid image " + path + " has been ignored!", ORPG_DEBUG)
+        self.log.log("Exit miniature_layer->add_miniature(self, id, path, pos, label, heading, face, width, height)", ORPG_DEBUG)
+
+    def get_miniature_by_id(self, id):
+        self.log.log("Enter miniature_layer->get_miniature_by_id(self, id)", ORPG_DEBUG)
+        for mini in self.miniatures:
+            if str(mini.id) == str(id):
+                self.log.log("Exit miniature_layer->get_miniature_by_id(self, id) return miniID: " + str(id), ORPG_DEBUG)
+                return mini
+        self.log.log("Exit miniature_layer->get_miniature_by_id(self, id) return None", ORPG_DEBUG)
+        return None
+
+    def del_miniature(self, min):
+        self.log.log("Enter miniature_layer->del_miniature(self, min)", ORPG_DEBUG)
+        xml_str = "<map><miniatures>"
+        xml_str += min.toxml("del")
+        xml_str += "</miniatures></map>"
+        self.canvas.frame.session.send(xml_str)
+        self.miniatures.remove(min)
+        del min
+        self.collapse_zorder()
+        self.log.log("Exit miniature_layer->del_miniature(self, min)", ORPG_DEBUG)
+
+    def del_all_miniatures(self):
+        self.log.log("Enter miniature_layer->del_all_miniatures(self)", ORPG_DEBUG)
+        while len(self.miniatures):
+            min = self.miniatures.pop()
+            del min
+        self.collapse_zorder()
+        self.log.log("Exit miniature_layer->del_all_miniatures(self)", ORPG_DEBUG)
+
+    def layerDraw(self, dc, topleft, size):
+        self.log.log("Enter miniature_layer->layerDraw(self, dc, topleft, size)", ORPG_DEBUG)
+        sorted_miniatures = self.miniatures[:]
+        sorted_miniatures.sort(cmp_zorder)
+        for m in sorted_miniatures:
+            if (m.pos.x>topleft[0]-m.right and
+                m.pos.y>topleft[1]-m.bottom and
+                m.pos.x<topleft[0]+size[0]-m.left and
+                m.pos.y<topleft[1]+size[1]-m.top):
+                m.draw(dc, self)
+        self.log.log("Exit miniature_layer->layerDraw(self, dc, topleft, size)", ORPG_DEBUG)
+
+    def find_miniature(self, pt, only_unlocked=False):
+        self.log.log("Enter miniature_layer->find_miniature(self, pt, only_unlocked)", ORPG_DEBUG)
+        min_list = []
+        for m in self.miniatures:
+            if m.hit_test(pt):
+                if m.hide and self.canvas.frame.session.my_role() != self.canvas.frame.session.ROLE_GM:
+                    continue
+                if only_unlocked and not m.locked:
+                    min_list.append(m)
+                elif not only_unlocked and m.locked:
+                    min_list.append(m)
+                else:
+                    continue
+        if len(min_list) > 0:
+            self.log.log("Exit miniature_layer->find_miniature(self, pt, only_unlocked)", ORPG_DEBUG)
+            return min_list
+        else:
+            self.log.log("Exit miniature_layer->find_miniature(self, pt, only_unlocked)", ORPG_DEBUG)
+            return None
+
+    def layerToXML(self, action="update"):
+        """ format  """
+        self.log.log("Enter miniature_layer->layerToXML(self, " + action + ")", ORPG_DEBUG)
+        minis_string = ""
+        if self.miniatures:
+            for m in self.miniatures:
+                minis_string += m.toxml(action)
+        if minis_string != '':
+            s = "<miniatures"
+            s += " serial='" + str(self.serial_number) + "'"
+            s += ">"
+            s += minis_string
+            s += "</miniatures>"
+            self.log.log("Exit miniature_layer->layerToXML(self, " + action + ")", ORPG_DEBUG)
+            return s
+        else:
+            self.log.log("Exit miniature_layer->layerToXML(self, " + action + ") return None", ORPG_DEBUG)
+            return ""
+
+    def layerTakeDOM(self, xml_dom):
+        self.log.log("Enter miniature_layer->layerTakeDOM(self, xml_dom)", ORPG_DEBUG)
+        if xml_dom.hasAttribute('serial'):
+            self.serial_number = int(xml_dom.getAttribute('serial'))
+        children = xml_dom._get_childNodes()
+        for c in children:
+            action = c.getAttribute("action")
+            id = c.getAttribute('id')
+            if action == "del":
+                mini = self.get_miniature_by_id(id)
+                if mini:
+                    self.miniatures.remove(mini)
+                    del mini
+                else:
+                    self.log.log("Map Synchronization Error :: Update of unknown mini attempted", ORPG_DEBUG)
+                    #wx.MessageBox("Deletion of unknown mini attempted","Map Synchronization Error")
+            elif action == "new":
+                pos = cmpPoint(int(c.getAttribute('posx')),int(c.getAttribute('posy')))
+                path = urllib.unquote(c.getAttribute('path'))
+                label = c.getAttribute('label')
+                height = width = heading = face = snap_to_align = zorder = 0
+                locked = hide = False
+                if c.hasAttribute('height'):
+                    height = int(c.getAttribute('height'))
+                if c.hasAttribute('width'):
+                    width = int(c.getAttribute('width'))
+                if c.getAttribute('locked') == 'True' or c.getAttribute('locked') == '1':
+                    locked = True
+                if c.getAttribute('hide') == 'True' or c.getAttribute('hide') == '1':
+                    hide = True
+                if c.getAttribute('heading'):
+                    heading = int(c.getAttribute('heading'))
+                if c.hasAttribute('face'):
+                    face = int(c.getAttribute('face'))
+                if c.hasAttribute('align'):
+                    snap_to_align = int(c.getAttribute('align'))
+                if c.getAttribute('zorder'):
+                    zorder = int(c.getAttribute('zorder'))
+                min = BmpMiniature(id, path, ImageHandler.load(path, 'miniature', id), pos, heading, face, label, locked, hide, snap_to_align, zorder, width, height, self.log)
+                self.miniatures.append(min)
+                if c.hasAttribute('local') and c.getAttribute('local') == 'True' and os.path.exists(urllib.unquote(c.getAttribute('localPath'))):
+                    localPath = urllib.unquote(c.getAttribute('localPath'))
+                    local = True
+                    localTime = float(c.getAttribute('localTime'))
+                    if localTime-time.time() <= 144000:
+                        file = open(localPath, "rb")
+                        imgdata = file.read()
+                        file.close()
+                        filename = os.path.split(localPath)
+                        (imgtype,j) = mimetypes.guess_type(filename[1])
+                        postdata = urllib.urlencode({'filename':filename[1], 'imgdata':imgdata, 'imgtype':imgtype})
+                        thread.start_new_thread(self.upload, (postdata, localPath, True))
+                #  collapse the zorder.  If the client behaved well, then nothing should change.
+                #    Otherwise, this will ensure that there's some kind of z-order
+                self.collapse_zorder()
+            else:
+                mini = self.get_miniature_by_id(id)
+                if mini:
+                    mini.takedom(c)
+                else:
+                    self.log.log("Map Synchronization Error :: Update of unknown mini attempted", ORPG_DEBUG)
+                    #wx.MessageBox("Update of unknown mini attempted","Map Synchronization Error")
+        self.log.log("Exit miniature_layer->layerTakeDOM(self, xml_dom)", ORPG_DEBUG)
+
+    def upload(self, postdata, filename, modify=False, pos=cmpPoint(0,0)):
+        self.lock.acquire()
+        url = self.settings.get_setting('ImageServerBaseURL')
+        file = urllib.urlopen(url, postdata)
+        recvdata = file.read()
+        file.close()
+        try:
+            xml_dom = minidom.parseString(recvdata)._get_documentElement()
+            if xml_dom.nodeName == 'path':
+                path = xml_dom.getAttribute('url')
+                path = urllib.unquote(path)
+                if not modify:
+                    start = path.rfind("/") + 1
+                    if self.canvas.parent.layer_handlers[2].auto_label:
+                        min_label = path[start:len(path)-4]
+                    else:
+                        min_label = ""
+                    id = 'mini-' + self.canvas.frame.session.get_next_id()
+                    self.add_miniature(id, path, pos=pos, label=min_label, local=True, localPath=filename, localTime=time.time())
+                else:
+                    self.miniatures[len(self.miniatures)-1].local = True
+                    self.miniatures[len(self.miniatures)-1].localPath = filename
+                    self.miniatures[len(self.miniatures)-1].localTime = time.time()
+                    self.miniatures[len(self.miniatures)-1].path = path
+            else:
+                print xml_dom.getAttribute('msg')
+        except Exception, e:
+            print e
+            print recvdata
+        urllib.urlcleanup()
+        self.lock.release()
+####################################################################
+        ## helper function
+
+    def get_mini_label(self, mini):
+        # override this to change the label displayed under each mini (and the label on hidden minis)
+        return mini.label