changeset 105:2f2bebe9c77f alpha

Traipse Alpha 'OpenRPG' {091006-03} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary: 00: Adds Bookmarks (Alpha) with cool Smiley Star and Plus Symbol images! 01: Forgot the default_server_bookmarks.xml; added. 02: Bookmarks working with no errors now! Sweet! 03: Changes made to the map for increased portability. SnowDog has changes planned in Core, though. Added an initial push to the BCG. Not much to see, just shows off how it is re-writing Main code.
author sirebral
date Tue, 06 Oct 2009 22:16:34 -0500
parents 15e32ec131cb
children 8e2b7da4f509
files orpg/mapper/map.py orpg/orpg_version.py plugins/bcg/__init__.py plugins/bcg/tok_dialogs.py plugins/bcg/token_handler.py plugins/bcg/tokens.py plugins/bcg/tokens_msg.py plugins/xxbcg.py
diffstat 7 files changed, 2453 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/orpg/mapper/map.py	Tue Oct 06 06:22:23 2009 -0500
+++ b/orpg/mapper/map.py	Tue Oct 06 22:16:34 2009 -0500
@@ -108,6 +108,15 @@
         # miniatures drag
         self.drag = None
 
+        #self.Bind(wx.EVT_MOUSEWHEEL, self.MouseWheel)
+
+    def MouseWheel(self, evt):
+        if evt.CmdDown():
+            print evt.GetWheelRotation()
+            if evt.GetWheelRotation() > 0: self.on_zoom_in(None)
+            elif evt.GetWheelRotation() < 0: self.on_zoom_out(None)
+            else: pass
+
     def better_refresh(self, event=None):
         self.Refresh(True)
 
@@ -118,41 +127,41 @@
         self.session = component.get("session")
         if self.session.my_role() == self.session.ROLE_LURKER or (str(self.session.group_id) == '0' and str(self.session.status) == '1'):
             cidx = self.parent.get_tab_index("Background")
-            self.parent.layer_tabs.EnableTab(cidx, False)
+            self.parent.tabs.EnableTab(cidx, False)
             cidx = self.parent.get_tab_index("Grid")
-            self.parent.layer_tabs.EnableTab(cidx, False)
+            self.parent.tabs.EnableTab(cidx, False)
             cidx = self.parent.get_tab_index("Miniatures")
-            self.parent.layer_tabs.EnableTab(cidx, False)
+            self.parent.tabs.EnableTab(cidx, False)
             cidx = self.parent.get_tab_index("Whiteboard")
-            self.parent.layer_tabs.EnableTab(cidx, False)
+            self.parent.tabs.EnableTab(cidx, False)
             cidx = self.parent.get_tab_index("Fog")
-            self.parent.layer_tabs.EnableTab(cidx, False)
+            self.parent.tabs.EnableTab(cidx, False)
             cidx = self.parent.get_tab_index("General")
-            self.parent.layer_tabs.EnableTab(cidx, False)
+            self.parent.tabs.EnableTab(cidx, False)
         else:
             cidx = self.parent.get_tab_index("Background")
-            if not self.parent.layer_tabs.GetEnabled(cidx):
+            if not self.parent.tabs.GetEnabled(cidx):
                 cidx = self.parent.get_tab_index("Miniatures")
-                self.parent.layer_tabs.EnableTab(cidx, True)
+                self.parent.tabs.EnableTab(cidx, True)
                 cidx = self.parent.get_tab_index("Whiteboard")
-                self.parent.layer_tabs.EnableTab(cidx, True)
+                self.parent.tabs.EnableTab(cidx, True)
                 cidx = self.parent.get_tab_index("Background")
-                self.parent.layer_tabs.EnableTab(cidx, False)
+                self.parent.tabs.EnableTab(cidx, False)
                 cidx = self.parent.get_tab_index("Grid")
-                self.parent.layer_tabs.EnableTab(cidx, False)
+                self.parent.tabs.EnableTab(cidx, False)
                 cidx = self.parent.get_tab_index("Fog")
-                self.parent.layer_tabs.EnableTab(cidx, False)
+                self.parent.tabs.EnableTab(cidx, False)
                 cidx = self.parent.get_tab_index("General")
-                self.parent.layer_tabs.EnableTab(cidx, False)
+                self.parent.tabs.EnableTab(cidx, False)
                 if self.session.my_role() == self.session.ROLE_GM:
                     cidx = self.parent.get_tab_index("Background")
-                    self.parent.layer_tabs.EnableTab(cidx, True)
+                    self.parent.tabs.EnableTab(cidx, True)
                     cidx = self.parent.get_tab_index("Grid")
-                    self.parent.layer_tabs.EnableTab(cidx, True)
+                    self.parent.tabs.EnableTab(cidx, True)
                     cidx = self.parent.get_tab_index("Fog")
-                    self.parent.layer_tabs.EnableTab(cidx, True)
+                    self.parent.tabs.EnableTab(cidx, True)
                     cidx = self.parent.get_tab_index("General")
-                    self.parent.layer_tabs.EnableTab(cidx, True)
+                    self.parent.tabs.EnableTab(cidx, True)
         if not self.cacheSizeSet:
             self.cacheSizeSet = True
             cacheSize = component.get('settings').get_setting("ImageCacheSize")
@@ -172,7 +181,6 @@
             except: pass
             # Flag that we now need to refresh!
             self.requireRefresh += 1
-
             """ Randomly purge an item from the cache, while this is lamo, it does
                 keep the cache from growing without bounds, which is pretty important!"""
             if len(ImageHandler.Cache) >= self.cacheSize:
@@ -191,6 +199,7 @@
             else: self.lastRefreshValue = self.requireRefresh
 
     def on_scroll(self, evt):
+        print 'scrolling'
         if self.drag: self.drag.Hide()
         if component.get('settings').get_setting("AlwaysShowMapScale") == "1": self.printscale()
         evt.Skip()
@@ -721,30 +730,35 @@
         self.top_frame = component.get('frame')
         self.root_dir = os.getcwd()
         self.current_layer = 2
-        self.layer_tabs = orpgTabberWnd(self, style=FNB.FNB_NO_X_BUTTON|FNB.FNB_BOTTOM|FNB.FNB_NO_NAV_BUTTONS)
-        self.layer_handlers = []
-        self.layer_handlers.append(background_handler(self.layer_tabs,-1,self.canvas))
-        self.layer_tabs.AddPage(self.layer_handlers[0],"Background")
-        self.layer_handlers.append(grid_handler(self.layer_tabs,-1,self.canvas))
-        self.layer_tabs.AddPage(self.layer_handlers[1],"Grid")
-        self.layer_handlers.append(miniatures_handler(self.layer_tabs,-1,self.canvas))
-        self.layer_tabs.AddPage(self.layer_handlers[2],"Miniatures", True)
-        self.layer_handlers.append(whiteboard_handler(self.layer_tabs,-1,self.canvas))
-        self.layer_tabs.AddPage(self.layer_handlers[3],"Whiteboard")
-        self.layer_handlers.append(fog_handler(self.layer_tabs,-1,self.canvas))
-        self.layer_tabs.AddPage(self.layer_handlers[4],"Fog")
-        self.layer_handlers.append(map_handler(self.layer_tabs,-1,self.canvas))
-        self.layer_tabs.AddPage(self.layer_handlers[5],"General")
-        self.layer_tabs.SetSelection(2)
+        self.tabs = orpgTabberWnd(self, style=FNB.FNB_NO_X_BUTTON|FNB.FNB_BOTTOM|FNB.FNB_NO_NAV_BUTTONS)
+        self.handlers = {}
+        self.handlers[0]=(background_handler(self.tabs,-1,self.canvas))
+        self.tabs.AddPage(self.handlers[0],"Background")
+        self.handlers[1]=(grid_handler(self.tabs,-1,self.canvas))
+        self.tabs.AddPage(self.handlers[1],"Grid")
+        self.handlers[2]=(miniatures_handler(self.tabs,-1,self.canvas))
+        self.tabs.AddPage(self.handlers[2],"Miniatures", True)
+        self.handlers[3]=(whiteboard_handler(self.tabs,-1,self.canvas))
+        self.tabs.AddPage(self.handlers[3],"Whiteboard")
+        self.handlers[4]=(fog_handler(self.tabs,-1,self.canvas))
+        self.tabs.AddPage(self.handlers[4],"Fog")
+        self.handlers[5]=(map_handler(self.tabs,-1,self.canvas))
+        self.tabs.AddPage(self.handlers[5],"General")
+        self.tabs.SetSelection(2)
         self.sizer = wx.BoxSizer(wx.VERTICAL)
         self.sizer.Add(self.canvas, 1, wx.EXPAND)
-        self.sizer.Add(self.layer_tabs, 0, wx.EXPAND)
+        self.sizer.Add(self.tabs, 0, wx.EXPAND)
         self.SetSizer(self.sizer)
         self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.on_layer_change)
         #self.Bind(wx.EVT_SIZE, self.on_size)
         self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
         self.load_default()
 
+        ## Components for making Map Based plugins that create new tabs.
+        component.add('map_tabs', self.tabs)
+        component.add('map_layers', self.handlers)
+        component.add('map_wnd', self)
+
     def OnLeave(self, evt):
         if "__WXGTK__" in wx.PlatformInfo: wx.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
 
@@ -798,41 +812,41 @@
         os.chdir(self.root_dir)
 
     def get_current_layer_handler(self):
-        return self.layer_handlers[self.current_layer]
+        return self.handlers[self.current_layer]
 
     def get_tab_index(self, layer):
         """Return the index of a chatpanel in the wxNotebook."""
-        for i in xrange(self.layer_tabs.GetPageCount()):
-            if (self.layer_tabs.GetPageText(i) == layer):
+        for i in xrange(self.tabs.GetPageCount()):
+            if (self.tabs.GetPageText(i) == layer):
                 return i
         return 0
 
     def on_layer_change(self, evt):
-        layer = self.layer_tabs.GetPage(evt.GetSelection())
-        for i in xrange(0, len(self.layer_handlers)):
-            if layer == self.layer_handlers[i]: self.current_layer = i
+        layer = self.tabs.GetPage(evt.GetSelection())
+        for i in xrange(0, len(self.handlers)):
+            if layer == self.handlers[i]: self.current_layer = i
         if self.current_layer == 0:
-            bg = self.layer_handlers[0]
+            bg = self.handlers[0]
             if (self.session.my_role() != self.session.ROLE_GM): bg.url_path.Show(False)
             else: bg.url_path.Show(True)
         self.canvas.Refresh(False)
         evt.Skip()
 
     def on_left_down(self, evt):
-        self.layer_handlers[self.current_layer].on_left_down(evt)
+        self.handlers[self.current_layer].on_left_down(evt)
 
     #double click handler added by Snowdog 5/03
     def on_left_dclick(self, evt):
-        self.layer_handlers[self.current_layer].on_left_dclick(evt)
+        self.handlers[self.current_layer].on_left_dclick(evt)
 
     def on_right_down(self, evt):
-        self.layer_handlers[self.current_layer].on_right_down(evt)
+        self.handlers[self.current_layer].on_right_down(evt)
 
     def on_left_up(self, evt):
-        self.layer_handlers[self.current_layer].on_left_up(evt)
+        self.handlers[self.current_layer].on_left_up(evt)
 
     def on_motion(self, evt):
-        self.layer_handlers[self.current_layer].on_motion(evt)
+        self.handlers[self.current_layer].on_motion(evt)
 
     def MapBar(self, id, data):
         self.canvas.MAP_MODE = data
@@ -849,8 +863,8 @@
         except: pass
 
     def update_tools(self):
-        for h in self.layer_handlers:
-            h.update_info()
+        for h in self.handlers:
+            self.handlers[h].update_info()
 
     def on_hk_map_layer(self, evt):
         id = self.top_frame.mainmenu.GetHelpString(evt.GetId())
@@ -860,7 +874,7 @@
         elif id == "Whiteboard Layer": self.current_layer = self.get_tab_index("Whiteboard")
         elif id == "Fog Layer": self.current_layer = self.get_tab_index("Fog")
         elif id == "General Properties": self.current_layer = self.get_tab_index("General")
-        self.layer_tabs.SetSelection(self.current_layer)
+        self.tabs.SetSelection(self.current_layer)
 
     def on_flush_cache(self, evt):
         ImageHandler.flushCache()
--- a/orpg/orpg_version.py	Tue Oct 06 06:22:23 2009 -0500
+++ b/orpg/orpg_version.py	Tue Oct 06 22:16:34 2009 -0500
@@ -4,7 +4,7 @@
 #BUILD NUMBER FORMAT: "YYMMDD-##" where ## is the incremental daily build index (if needed)
 DISTRO = "Traipse Alpha"
 DIS_VER = "Ornery Orc"
-BUILD = "091006-02"
+BUILD = "091006-03"
 
 # This version is for network capability.
 PROTOCOL_VERSION = "1.2"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/bcg/tok_dialogs.py	Tue Oct 06 22:16:34 2009 -0500
@@ -0,0 +1,531 @@
+# 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/min_dialogs.py
+# Author: Chris Davis
+# Maintainer:
+# Version:
+#   $Id: min_dialogs.py,v 1.27 2006/11/13 02:23:16 digitalxero Exp $
+#
+# Description: This file contains some of the basic definitions for the chat
+# utilities in the orpg project.
+
+##-----------------------------
+## token List Panel
+##-----------------------------
+
+from tokens import *
+
+class min_list_panel(wx.Dialog):
+
+    def __init__(self, parent,layers, log, pos =(-1,-1)):
+        wx.Dialog.__init__(self,  parent,-1, log,pos = (-1,-1), size = (785,175), style=wx.RESIZE_BORDER)
+        listID = wx.NewId()
+        self.parent = parent
+        self.min = layers['tokens'].tokens
+        self.grid = layers['grid']
+        self.layers = layers
+        self.listID = listID
+        list_sizer = wx.BoxSizer(wx.VERTICAL)
+        self.list_sizer = list_sizer
+        listctrl = wx.ListCtrl(self, listID, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
+        self.listctrl = listctrl
+        self.Centre(wx.BOTH)
+        self.log = log
+        self.list_sizer.Add(self.listctrl,1,wx.EXPAND)
+        self.listctrl.InsertColumn(0,"POS    ")
+        self.listctrl.InsertColumn(0,"LOCKED")
+        self.listctrl.InsertColumn(0,"HEADING")
+        self.listctrl.InsertColumn(0,"FACING")
+        self.listctrl.InsertColumn(0,"LABEL")
+        self.listctrl.InsertColumn(0,"PATH")
+        self.listctrl.SetColumnWidth(1, wx.LIST_AUTOSIZE_USEHEADER)
+        self.listctrl.SetColumnWidth(2, wx.LIST_AUTOSIZE_USEHEADER)
+        self.listctrl.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER)
+        self.listctrl.SetColumnWidth(4, wx.LIST_AUTOSIZE_USEHEADER)
+        self.listctrl.SetColumnWidth(5, wx.LIST_AUTOSIZE_USEHEADER)
+        self.list_sizer.Add(wx.Button(self, wx.ID_OK, "DONE"),0,wx.ALIGN_CENTER)
+        self.refresh()
+        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)
+        self.listctrl.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightClick, id=listID)
+        self.listctrl.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)
+        self.listctrl.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
+        self.SetSizer(self.list_sizer)
+        self.SetAutoLayout(True)
+        self.Fit()
+
+    def OnRightClick(self,event):
+        if self.listctrl.GetSelectedItemCount() > 0:
+            menu = wx.Menu()
+            lPopupID1 = wx.NewId()
+            lPopupID2 = wx.NewId()
+            lPopupID3 = wx.NewId()
+            menu.Append(lPopupID1, "&Edit")
+            menu.Append(lPopupID2, "&Delete")
+            menu.Append(lPopupID3, "To &Gametree")
+            self.Bind(wx.EVT_MENU, self.onEdit, id=lPopupID1)
+            self.Bind(wx.EVT_MENU, self.onDelete, id=lPopupID2)
+            self.Bind(wx.EVT_MENU, self.onToGametree, id=lPopupID3)
+            self.PopupMenu(menu, cmpPoint(self.x, self.y))
+            menu.Destroy()
+        event.Skip()
+
+    def refresh(self):
+        self.SetMinSize((600,175));
+        for m in self.min:
+            self.listctrl.InsertStringItem(self.min.index(m),self.min[self.min.index(m)].path)
+            self.listctrl.SetStringItem(self.min.index(m),1,self.min[self.min.index(m)].label)
+            self.listctrl.SetStringItem(self.min.index(m),2,`self.min[self.min.index(m)].heading`)
+            #self.listctrl.SetStringItem(self.min.index(m),3,`self.min[self.min.index(m)].face`)
+            self.listctrl.SetStringItem(self.min.index(m),4,`self.min[self.min.index(m)].locked`)
+            self.listctrl.SetStringItem(self.min.index(m),5,`self.min[self.min.index(m)].pos`)
+            oldcolumnwidth = self.listctrl.GetColumnWidth(0)
+            self.listctrl.SetColumnWidth(0, wx.LIST_AUTOSIZE)
+            if oldcolumnwidth < self.listctrl.GetColumnWidth(0): self.listctrl.SetColumnWidth(0, wx.LIST_AUTOSIZE)
+            else: self.listctrl.SetColumnWidth(0, oldcolumnwidth)
+        self.list_sizer=self.list_sizer
+
+    def onEdit(self,event):
+        min_list = []
+        min_index = []
+        loop_count = 0
+        item =-1
+        while True:
+            loop_count += 1
+            item = self.listctrl.GetNextItem(item,wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
+            if item == -1: break
+            min_list.append(self.min[item])
+            min_index.append(item-loop_count+1)
+        if len(min_list) > 0: dlg = min_list_edit_dialog(self.parent,min_index, min_list,self.layers)
+        if dlg.ShowModal() == wx.ID_OK: pass
+        self.listctrl.DeleteAllItems()
+        self.refresh()
+        event.Skip()
+
+    def onDelete(self,event):
+        loop_count = 0
+        item = -1
+        while True:
+            loop_count += 1
+            item = self.listctrl.GetNextItem(item,wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
+            if item == -1: break
+            self.layers["tokens"].del_token(self.min[item-loop_count+1])
+        self.listctrl.DeleteAllItems()
+        self.refresh()
+        event.Skip()
+
+    def onToGametree(self,event):
+        min_list = []
+        min_index = []
+        loop_count = 0
+        item =-1
+        while True:
+            loop_count += 1
+            item = self.listctrl.GetNextItem(item,wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
+            if item == -1: break
+            min_list.append(self.min[item])
+            min_index.append(item-loop_count+1)
+        if len(min_list) > 0:
+            for sel_rmin in min_list:
+             #############
+                min_xml = sel_rmin.toxml(action="new")
+                node_begin = "<nodehandler module='map_token_nodehandler' class='map_token_handler' name='"
+
+                if sel_rmin.label: node_begin += sel_rmin.label + "'"
+                else: node_begin += "Unnamed token'"
+
+                node_begin += ">"
+                gametree = component.get('tree')
+                node_xml = node_begin + min_xml + '</nodehandler>'
+                print "Sending this XML to insert_xml:" + node_xml
+                gametree.insert_xml(node_xml)
+             #############
+        self.listctrl.DeleteAllItems()
+        self.refresh()
+        event.Skip()
+
+    def OnRightDown(self,event):
+        self.x = event.GetX()
+        self.y = event.GetY()
+        event.Skip()
+
+    def on_ok(self,evt):
+        self.EndModal(wx.ID_OK)
+
+class min_list_edit_dialog(wx.Dialog):
+    def __init__(self,parent,min_index, min_list, layers):
+        wx.Dialog.__init__(self,parent,-1,"token List",wx.DefaultPosition,wx.Size(600,530))
+        self.layers = layers
+        grid = layers['grid']
+        min = layers['tokens']
+        self.min_list = min_list
+        self.min_index = min_index
+        self.min = min
+        sizer1 = wx.BoxSizer(wx.VERTICAL)
+        sizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.grid = grid
+        editor = min_list_edit_panel(self, min_index, min_list,layers)
+        sizer1.Add(editor, 1, wx.EXPAND)
+        sizer.Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND)
+        sizer.Add(wx.Size(10,10))
+        sizer.Add(wx.Size(10,10))
+        sizer.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND)
+        sizer1.Add(sizer, 0, wx.EXPAND)
+        self.editor = editor
+        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)
+        self.SetSizer(sizer1)
+        self.SetAutoLayout(True)
+        self.Fit()
+
+    def on_revert(self,evt):
+        pass
+
+    def on_ok(self,evt):
+        self.editor.on_ok(self.layers)
+        self.EndModal(wx.ID_OK)
+
+class min_list_edit_panel(wx.Panel):
+    def __init__(self, parent, min_index, min_list,layers):
+        LABEL_COMBO = wx.NewId()
+        PATH_COMBO = wx.NewId()
+        POS_COMB = wx.NewId()
+        MIN_POS = wx.NewId()
+        POS_SPIN = wx.NewId()
+        self.grid = layers['grid']
+        self.min = layers['tokens'].tokens
+        self.min_list = min_list
+        self.min_index = min_index
+        self.layers = layers
+        wx.Panel.__init__(self, parent, -1)
+        self.min=min
+        listsizer = wx.StaticBoxSizer(wx.StaticBox(self,-1,"Token list properties"), wx.VERTICAL)
+        labelsizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.labelcheck = wx.CheckBox(self,-1,"Serialize")
+        labelsizer.Add(wx.StaticText(self, -1, "Label:          "), 0, wx.EXPAND)
+        labelsizer.Add(self.labelcheck,wx.ALIGN_RIGHT,wx.EXPAND)
+        listsizer.Add(labelsizer,0, wx.EXPAND)
+        self.labelcombo = wx.ComboBox(self, LABEL_COMBO,"no change",style=wx.CB_DROPDOWN)
+        listsizer.Add(self.labelcombo,0, wx.EXPAND)
+        self.pathcombo = wx.ComboBox(self, PATH_COMBO, "no change",style=wx.CB_DROPDOWN)
+        self.positioncombo = wx.ComboBox(self, POS_COMB, "no change", choices=["no change"], style=wx.CB_READONLY)
+        #self.positioncombo.SetValue(`min_list[0].pos`)
+        self.labelcombo.Append("no change")
+        self.pathcombo.Append("no change")
+        for m in min_list:
+            self.labelcombo.Append(min_list[min_list.index(m)].label)
+            self.pathcombo.Append(min_list[min_list.index(m)].path)
+            self.positioncombo.Append(`min_list[min_list.index(m)].pos`)
+        listsizer.Add(wx.StaticText(self, -1, "Path:"), 0, wx.EXPAND)
+        listsizer.Add(self.pathcombo, 0, wx.EXPAND)
+        listsizer.Add(wx.Size(10,10))
+        self.heading = wx.RadioBox(self, MIN_HEADING, "Heading", 
+            choices=["None","N","NE","E","SE","S","SW","W","NW","no change"], majorDimension=5, style=wx.RA_SPECIFY_COLS)
+        self.heading.SetSelection( 9 )
+        listsizer.Add( self.heading, 0, wx.EXPAND )
+        listsizer.Add(wx.Size(10,10))
+
+        ## Remove
+        #self.face = wx.RadioBox(self, MIN_FACE, "Facing", 
+        #    choices=["None","N","NE","E","SE","S","SW","W","NW","no change"], majorDimension=5, style=wx.RA_SPECIFY_COLS)
+        #self.face.SetSelection(9)
+        #listsizer.Add(self.face, 0, wx.EXPAND)
+
+        ###
+        ###Group together locked, Hide, and snap radioboxes in group2 box
+        ###
+        group2 = wx.BoxSizer(wx.HORIZONTAL)
+        self.locked = wx.RadioBox(self, MIN_LOCK, "Lock", 
+            choices=["Don't lock","Lock","no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
+        self.locked.SetSelection(2)
+        self.hide = wx.RadioBox(self, MIN_HIDE, "Hide", 
+            choices=["Don't hide", "Hide", "no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
+        self.hide.SetSelection(2)
+        self.snap = wx.RadioBox(self,MIN_ALIGN,"Snap",
+            choices=["Center","Top left","no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
+        self.snap.SetSelection(2)
+        group2.Add(self.locked, 0, wx.EXPAND)
+        group2.Add(wx.Size(10,0))
+        group2.Add(self.hide, 0, wx.EXPAND)
+        group2.Add(wx.Size(10,0))
+        group2.Add(self.snap, 0, wx.EXPAND)
+        group2.Add(wx.Size(10,0))
+        listsizer.Add(group2,0,0)
+        ###
+        ###Group together the postion radiobox and the and its selection elements
+        ###
+        xpos = int(min_list[0].pos[0])
+        #xpos = int(`min_list[0].pos`[1:`min_list[0].pos`.index(',')])
+        ypos = int(min_list[0].pos[1])
+        #ypos = int(`min_list[0].pos`[`min_list[0].pos`.rfind(',')+1:len(`min_list[0].pos`)-1])
+        self.scx = wx.SpinCtrl(self, POS_SPIN, "", (-1,-1), wx.Size(75,25))
+        self.scx.SetRange(0,self.grid.return_grid()[0])
+        self.scx.SetValue(xpos)
+        self.scy = wx.SpinCtrl(self, POS_SPIN, "", (-1,-1), wx.Size(75,25))
+        self.scy.SetRange(0,self.grid.return_grid()[1])
+        self.scy.SetValue(1)
+        self.scy.SetValue(ypos)
+        positionbox = wx.BoxSizer(wx.HORIZONTAL)
+        self.poschoice = wx.RadioBox(self,MIN_POS,"Position",
+            choices=["Manual", "Existing", "no change"],majorDimension=1,style=wx.RA_SPECIFY_COLS)
+        self.poschoice.SetSelection(2)
+        positionbox.Add(self.poschoice,0,0)
+        ###
+        ### group together choices under position choice boxsizer
+        ###
+        poschoicebox = wx.BoxSizer(wx.VERTICAL)
+            ###
+            ### spinbox contains the x and y spinctrls
+            ###
+        spinbox = wx.BoxSizer(wx.HORIZONTAL)
+        group2.Add(positionbox,0, wx.EXPAND)
+        xpos = wx.StaticText(self, -1,"XPOS:  ")
+        spinbox.Add(xpos,0, 0)
+        spinbox.Add(self.scx, 0, 0)
+        ypos = wx.StaticText(self, -1,"YPOS:  ")
+        spinbox.Add(ypos,0, 0)
+        spinbox.Add(self.scy, 0, 0)
+        poschoicebox.Add(wx.Size(0,15))
+        poschoicebox.Add(spinbox,0,0)
+        ###
+        ### kludge is just a way to horizontaly position text.  .Add doesn't seem to work.
+        ###
+        kluge = wx.BoxSizer(wx.HORIZONTAL)
+        klugetext = wx.StaticText(self, -1, "            ")
+        kluge.Add(klugetext,0,0)
+        kluge.Add(self.positioncombo,0,0)
+        poschoicebox.Add(wx.Size(0,1))
+        poschoicebox.Add(kluge,0,0)
+        positionbox.Add(poschoicebox,0,0)
+        listsizer.Add(positionbox,0, 0)
+        self.listsizer = listsizer
+        #self.outline = wx.StaticBox(self,-1,"token list properties")
+        #listsizer.Add(self.outline,0, wx.EXPAND)
+        self.SetSizer(listsizer)
+        self.SetAutoLayout(True)
+        self.Fit()
+        self.Bind(wx.EVT_SPINCTRL, self.on_spin, id=POS_SPIN)
+        self.Bind(wx.EVT_TEXT, self.on_combo_box, id=POS_COMB)
+        #self.Bind(wx.EVT_SIZE, self.on_size)
+        self.Bind(wx.EVT_TEXT, self.on_text, id=MIN_LABEL)
+        self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_HEADING)
+        self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_FACE)
+
+    def on_ok(self,min):
+        self.min = min
+        for m in self.min_list:
+            if self.hide.GetSelection() !=2: m.hide = self.hide.GetSelection()
+            if self.heading.GetSelection() !=9: m.heading = self.heading.GetSelection()
+            #if self.face.GetSelection() !=9: m.face = self.face.GetSelection()
+            if self.locked.GetSelection() !=2: m.locked = self.locked.GetSelection()
+            if self.snap.GetSelection() !=2: m.snap_to_align = self.snap.GetSelection()
+            if self.labelcombo.GetValue() != "no change":
+                m.label = self.labelcombo.GetValue()
+                if self.labelcheck.GetValue(): m.label += " " + `self.layers['tokens'].next_serial()`
+            if self.pathcombo.GetValue() != "no change":
+                path = self.pathcombo.GetValue()
+                image = self.evaluate(path)
+                if str(image[1]) != '-1':
+                    m.path = image[0]
+                    m.bmp = image[1]
+                else:
+                    image[-1] = -1
+                    while image[1] == -1:
+                        image = 0
+                        self.dlg = wx.TextEntryDialog(self, 
+                            'You entered an invalid URL for the image path.  Please Enter a valid URL or cancel to leave the old url unchanged')
+                        if self.dlg.ShowModal() == wx.ID_OK:
+                            path = self.dlg.GetValue()
+                            image = self.evaluate(path)
+                            if image[1] != -1:
+                                m.path = image[0]
+                                m.bmp = image[1]
+                            self.dlg.Destroy()
+                        else: break
+            if self.poschoice.GetSelection() !=2:
+                if self.poschoice.GetSelection() == 0: m.pos = cmpPoint(self.scx.GetValue(),self.scy.GetValue())
+                else:
+                    pos = self.positioncombo.GetValue()
+                    m.pos = cmpPoint(int(`pos`[2:`pos`.index(",")]),int(`pos`[`pos`.rfind(',')+1:len(`pos`)-2]))
+        self.layers["tokens"].canvas.send_map_data()
+
+    def evaluate(self, ckpath):
+        path = []
+        if ckpath[:7] != "http://": ckpath = "http://" + ckpath
+        path = self.check_path(ckpath)
+        return [ckpath, path]
+
+    def check_path(self, path):
+        if ImageHandler.Cache.has_key(path): return ImageHandler.Cache[path]
+        img = ImageHandler.directLoad(path)
+        if img is None: return -1
+        return img
+
+    def on_text(self,evt):
+        id=evt.GetId()
+
+    def on_spin(self,evt):
+        self.poschoice.SetSelection(0)
+
+    def on_combo_box(self,evt):
+        self.poschoice.SetSelection(1)
+
+    def on_radio_box(self,evt):
+        id=evt.GetId()
+        index = evt.GetInt()
+
+    def on_size(self,evt):
+        s = self.GetClientSizeTuple()
+        self.listsizer.SetDimension(20,20,s[0]-40,s[1]-40)
+        self.outline.SetDimensions(5,5,s[0]-10,s[1]-10)
+
+##-----------------------------
+## token Prop Panel
+##-----------------------------
+
+MIN_LABEL = wx.NewId()
+MIN_HEADING = wx.NewId()
+MIN_FACE = wx.NewId()
+MIN_HIDE = wx.NewId()
+MIN_LOCK = wx.NewId()
+MIN_ALIGN = wx.NewId()
+wxID_MIN_WIDTH = wx.NewId()
+wxID_MIN_HEIGHT = wx.NewId()
+wxID_MIN_SCALING = wx.NewId()
+
+class min_edit_panel(wx.Panel):
+    def __init__(self, parent, min):
+        wx.Panel.__init__(self, parent, -1)
+        self.min = min
+        sizer = wx.StaticBoxSizer(wx.StaticBox(self,-1,"token"), wx.VERTICAL)
+        sizerSize = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.label = wx.TextCtrl(self, MIN_LABEL, min.label)
+        sizer.Add(wx.StaticText(self, -1, "Label:"), 0, wx.EXPAND)
+        sizer.Add(self.label, 0, wx.EXPAND)
+        sizer.Add(wx.Size(10,10))
+        self.heading = wx.RadioBox(self, MIN_HEADING, "Heading", 
+            choices=["None","N","NE",
+                     "E","SE","S",
+                     "SW","W","NW"],majorDimension=5,style=wx.RA_SPECIFY_COLS)
+        self.heading.SetSelection(min.heading)
+        #self.face = wx.RadioBox(self, MIN_FACE, "Facing", 
+        #    choices=["None","N","NE",
+        #             "E","SE","S",
+        #             "SW","W","NW"],majorDimension=5,style=wx.RA_SPECIFY_COLS)
+        #self.face.SetSelection(min.face)
+        self.locked = wx.CheckBox(self, MIN_LOCK, " Lock")
+        self.locked.SetValue(min.locked)
+        self.hide = wx.CheckBox(self, MIN_HIDE, " Hide")
+        self.hide.SetValue(min.hide)
+        sizer.Add(self.heading, 0, wx.EXPAND)
+        sizer.Add(wx.Size(10,10))
+        #sizer.Add(self.face, 0, wx.EXPAND)
+        sizer.Add(wx.Size(10,10))
+        #
+        #image resizing
+        #
+        self.min_width_old_value = str(self.min.bmp.GetWidth())
+        self.min_width = wx.TextCtrl(self, wxID_MIN_WIDTH, self.min_width_old_value)
+        sizerSize.Add(wx.StaticText(self, -1, "Width: "), 0, wx.ALIGN_CENTER)
+        sizerSize.Add(self.min_width, 1, wx.EXPAND)
+        sizerSize.Add(wx.Size(20, 25))
+
+        #TODO:keep in mind that self.min is a local copy???
+        self.min_height_old_value = str(self.min.bmp.GetHeight())
+        self.min_height = wx.TextCtrl(self, wxID_MIN_HEIGHT, self.min_height_old_value)
+        sizerSize.Add(wx.StaticText(self, -1, "Height: "),0,wx.ALIGN_CENTER)
+        sizerSize.Add(self.min_height, 1, wx.EXPAND)
+        self.min_scaling = wx.CheckBox(self, wxID_MIN_SCALING, "Lock scaling")
+        self.min_scaling.SetValue(True)
+        sizerSize.Add(self.min_scaling, 1, wx.EXPAND)
+        sizer.Add(sizerSize, 0, wx.EXPAND)
+        sizer.Add(wx.Size(10, 10))
+
+        # Now, add the last items on in their own sizer
+        hSizer.Add(self.locked, 0, wx.EXPAND)
+        hSizer.Add(wx.Size(10,10))
+        hSizer.Add(self.hide, 0, wx.EXPAND)
+
+        # Add the hSizer to the main sizer
+        sizer.Add( hSizer )
+        self.sizer = sizer
+        self.SetSizer(self.sizer)
+        self.SetAutoLayout(True)
+        self.Fit()
+
+        #self.Bind(wx.EVT_SIZE, self.on_size)
+        self.Bind(wx.EVT_TEXT, self.on_text, id=MIN_LABEL)
+        self.Bind(wx.EVT_TEXT, self.on_scaling, id=wxID_MIN_WIDTH)
+        self.Bind(wx.EVT_TEXT, self.on_scaling, id=wxID_MIN_HEIGHT)
+        self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_HEADING)
+        #self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=MIN_FACE)
+
+    def on_scaling(self, evt):
+        if self.min_scaling.GetValue() == False: return
+        elif self.min_width.GetValue() and wxID_MIN_WIDTH == evt.GetId() and self.min_width.GetInsertionPoint():
+            self.min_height.SetValue(str(int((float(self.min_width.GetValue()) / float(self.min_width_old_value)) * float(self.min_height_old_value))) )
+        elif self.min_height.GetValue() and wxID_MIN_HEIGHT == evt.GetId() and self.min_height.GetInsertionPoint():
+            self.min_width.SetValue(str(int((float(self.min_height.GetValue()) / float(self.min_height_old_value)) * float(self.min_width_old_value))) )
+
+    def update_min(self):
+        self.min.set_min_props(self.heading.GetSelection(),
+                               #self.face.GetSelection(),
+                               self.label.GetValue(),
+                               self.locked.GetValue(),
+                               self.hide.GetValue(),
+                               self.min_width.GetValue(),
+                               self.min_height.GetValue())
+
+    def on_radio_box(self,evt):
+        id = evt.GetId()
+        index = evt.GetInt()
+
+    def on_text(self,evt):
+        id = evt.GetId()
+
+    def on_size(self,evt):
+        s = self.GetClientSizeTuple()
+        self.sizer.SetDimension(20,20,s[0]-40,s[1]-40)
+        self.outline.SetDimensions(5,5,s[0]-10,s[1]-10)
+
+class min_edit_dialog(wx.Dialog):
+    def __init__(self,parent,min):
+        #520,265
+        wx.Dialog.__init__(self,parent,-1,"token",wx.DefaultPosition,wx.Size(520,350))
+        (w,h) = self.GetClientSizeTuple()
+        mastersizer = wx.BoxSizer(wx.VERTICAL)
+        editor = min_edit_panel(self,min)
+        #editor.SetDimensions(0,0,w,h-25)
+        self.editor = editor
+        mastersizer.Add(editor, 1, wx.EXPAND)
+        mastersizer.Add(wx.Size(10,10))
+        sizer = wx.BoxSizer(wx.HORIZONTAL)
+        sizer.Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND)
+        sizer.Add(wx.Size(10,10))
+        sizer.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND)
+        #sizer.SetDimension(0,h-25,w,25)
+        mastersizer.Add(sizer, 0, wx.EXPAND)
+        self.SetSizer(mastersizer)
+        self.SetAutoLayout(True)
+        self.Fit()
+        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)
+
+    def on_ok(self,evt):
+        self.editor.update_min()
+        self.EndModal(wx.ID_OK)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/bcg/token_handler.py	Tue Oct 06 22:16:34 2009 -0500
@@ -0,0 +1,883 @@
+# 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/whiteboard_hander.py
+# Author: OpenRPG Team
+# Maintainer:
+# Version:
+#   $Id: token_handler.py,v 1.43 2007/12/07 20:39:50 digitalxero Exp $
+#
+# Description: Token layer handler; derived from token Layer handler
+#
+__version__ = "$Id: token_handler.py,v 1.43 2007/12/07 20:39:50 madmathlabs Exp $"
+
+from orpg.mapper.base_handler import *
+from tok_dialogs import *
+import thread
+import time
+import mimetypes
+import urllib
+import xml.dom.minidom as minidom
+import wx
+
+## rewrite Grid
+from orpg.mapper.grid import GRID_RECTANGLE
+from orpg.mapper.grid import GRID_HEXAGON
+from orpg.mapper.grid import GRID_ISOMETRIC
+import os
+
+from orpg.tools.orpg_settings import settings
+
+## Jesus H! No Face, rotate!
+TOK_ROT_LEFT = wx.NewId()
+ROT_LEFT_45 = wx.NewId()
+LABEL_TOOL = wx.NewId()
+LAYER_TOOL = wx.NewId()
+TOK_LIST_TOOL = wx.NewId()
+TOK_TOOL = wx.NewId()
+TOK_URL = wx.NewId()
+SERIAL_TOOL = wx.NewId()
+TOK_MOVE = wx.NewId()
+TOK_REMOVE = wx.NewId()
+TOK_PROP_DLG = wx.NewId()
+TOK_FACING_NONE = wx.NewId()
+TOK_FACING_MATCH = wx.NewId()
+TOK_FACING_EAST = wx.NewId()
+TOK_FACING_WEST = wx.NewId()
+TOK_FACING_NORTH = wx.NewId()
+TOK_FACING_SOUTH = wx.NewId()
+TOK_FACING_NORTHEAST = wx.NewId()
+TOK_FACING_SOUTHEAST = wx.NewId()
+TOK_FACING_SOUTHWEST = wx.NewId()
+TOK_FACING_NORTHWEST = wx.NewId()
+TOK_HEADING_NONE = wx.NewId()
+TOK_HEADING_MATCH = wx.NewId()
+TOK_HEADING_EAST = wx.NewId()
+TOK_HEADING_WEST = wx.NewId()
+TOK_HEADING_NORTH = wx.NewId()
+TOK_HEADING_SOUTH = wx.NewId()
+TOK_HEADING_NORTHEAST = wx.NewId()
+TOK_HEADING_SOUTHEAST = wx.NewId()
+TOK_HEADING_SOUTHWEST = wx.NewId()
+TOK_HEADING_NORTHWEST = wx.NewId()
+TOK_HEADING_SUBMENU = wx.NewId()
+TOK_FACING_SUBMENU = wx.NewId()
+TOK_ALIGN_SUBMENU = wx.NewId()
+TOK_ALIGN_GRID_CENTER = wx.NewId()
+TOK_ALIGN_GRID_TL = wx.NewId()
+TOK_TITLE_HACK = wx.NewId()
+TOK_TO_GAMETREE = wx.NewId()
+TOK_BACK_ONE = wx.NewId()
+TOK_FORWARD_ONE = wx.NewId()
+TOK_TO_BACK = wx.NewId()
+TOK_TO_FRONT = wx.NewId()
+TOK_LOCK_BACK = wx.NewId()
+TOK_LOCK_FRONT = wx.NewId()
+TOK_FRONTBACK_UNLOCK = wx.NewId()
+TOK_ZORDER_SUBMENU = wx.NewId()
+TOK_SHOW_HIDE = wx.NewId()
+TOK_LOCK_UNLOCK = wx.NewId()
+MAP_REFRESH_MINI_URLS = wx.NewId()
+
+class myFileDropTarget(wx.FileDropTarget):
+    def __init__(self, handler):
+        wx.FileDropTarget.__init__(self)
+        self.m_handler = handler
+    def OnDropFiles(self, x, y, filenames):
+        self.m_handler.on_drop_files(x, y, filenames)
+
+class token_handler(base_layer_handler):
+
+    def __init__(self, parent, id, canvas):
+        self.sel_min = None
+        self.auto_label = 1
+        self.use_serial = 1
+        self.auto_label_cb = None
+        self.canvas = canvas
+        self.settings = settings
+        self.mini_rclick_menu_extra_items = {}
+        self.background_rclick_menu_extra_items = {}
+        base_layer_handler.__init__(self, parent, id, canvas)
+        # id is the index of the last good menu choice or 'None'
+        # if the last menu was left without making a choice
+        # should be -1 at other times to prevent events overlapping
+        self.lastMenuChoice = None
+        self.drag_mini = None
+        self.tooltip_delay_miliseconds = 500
+        self.tooltip_timer = wx.CallLater(self.tooltip_delay_miliseconds, self.on_tooltip_timer)
+        self.tooltip_timer.Stop()
+        dt = myFileDropTarget(self)
+        self.canvas.SetDropTarget(dt)
+        #wxInitAllImageHandlers()
+
+    def build_ctrls(self):
+        base_layer_handler.build_ctrls(self)
+        # add controls in reverse order! (unless you want them after the default tools)
+        self.auto_label_cb = wx.CheckBox(self, wx.ID_ANY, ' Auto Label ', (-1,-1),(-1,-1))
+        self.auto_label_cb.SetValue(self.auto_label)
+        self.min_url = wx.ComboBox(self, wx.ID_ANY, "http://", style=wx.CB_DROPDOWN | wx.CB_SORT)
+        self.localBrowse = wx.Button(self, wx.ID_ANY, 'Browse', style=wx.BU_EXACTFIT)
+        minilist = createMaskedButton( self, dir_struct["icon"]+'questionhead.gif', 'Edit token properties', wx.ID_ANY)
+        miniadd = wx.Button(self, wx.ID_OK, "Add Token", style=wx.BU_EXACTFIT)
+        self.sizer.Add(self.auto_label_cb,0,wx.ALIGN_CENTER)
+        self.sizer.Add((6, 0))
+        self.sizer.Add(self.min_url, 1, wx.ALIGN_CENTER)
+        self.sizer.Add((6, 0))
+        self.sizer.Add(miniadd, 0, wx.ALIGN_CENTER)
+        self.sizer.Add((6, 0))
+        self.sizer.Add(self.localBrowse, 0, wx.ALIGN_CENTER)
+        self.sizer.Add((6, 0))
+        self.sizer.Add(minilist, 0, wx.ALIGN_CENTER)
+        self.Bind(wx.EVT_BUTTON, self.on_min_list, minilist)
+        self.Bind(wx.EVT_BUTTON, self.on_token, miniadd)
+        self.Bind(wx.EVT_BUTTON, self.on_browse, self.localBrowse)
+        self.Bind(wx.EVT_CHECKBOX, self.on_label, self.auto_label_cb)
+
+    def on_browse(self, evt):
+        if not self.role_is_gm_or_player(): return
+        dlg = wx.FileDialog(None, "Select a Token to load", dir_struct["user"]+'webfiles/', 
+            wildcard="Image files (*.bmp, *.gif, *.jpg, *.png)|*.bmp;*.gif;*.jpg;*.png", style=wx.OPEN)
+        if not dlg.ShowModal() == wx.ID_OK:
+            dlg.Destroy()
+            return
+        file = open(dlg.GetPath(), "rb")
+        imgdata = file.read()
+        file.close()
+        filename = dlg.GetFilename()
+        (imgtype,j) = mimetypes.guess_type(filename)
+        postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype})
+
+        ## Removal of Remote Server?
+        if self.settings.get_setting('LocalorRemote') == 'Remote':
+            # make the new mini appear in top left of current viewable map
+            dc = wx.ClientDC(self.canvas)
+            self.canvas.PrepareDC(dc)
+            dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
+            x = dc.DeviceToLogicalX(0)
+            y = dc.DeviceToLogicalY(0)
+            thread.start_new_thread(self.canvas.layers['token'].upload, 
+                                    (postdata, dlg.GetPath()), {'pos':cmpPoint(x,y)})
+        else:
+            try: min_url = component.get("cherrypy") + filename
+            except: return #chat.InfoPost('CherryPy is not started!')
+            min_url = dlg.GetDirectory().replace(dir_struct["user"]+'webfiles' + os.sep, 
+                component.get("cherrypy")) + '/' + filename
+            # build url
+            if min_url == "" or min_url == "http://": return
+            if min_url[:7] != "http://": min_url = "http://" + min_url
+            # make label
+            if self.auto_label and min_url[-4:-3] == '.':
+                start = min_url.rfind("/") + 1
+                min_label = min_url[start:len(min_url)-4]
+                if self.use_serial: min_label = '%s %d' % ( min_label, self.canvas.layers['token'].next_serial() )
+            else: min_label = ""
+            if self.min_url.FindString(min_url) == -1: self.min_url.Append(min_url)
+            try:
+                id = 'mini-' + self.canvas.frame.session.get_next_id()
+                # make the new mini appear in top left of current viewable map
+                dc = wx.ClientDC(self.canvas)
+                self.canvas.PrepareDC(dc)
+                dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
+                x = dc.DeviceToLogicalX(0)
+                y = dc.DeviceToLogicalY(0)
+                self.canvas.layers['token'].add_token(id, min_url, pos=cmpPoint(x,y), label=min_label)
+            except:
+                # When there is an exception here, we should be decrementing the serial_number for reuse!!
+                unablemsg= "Unable to load/resolve URL: " + min_url + " on resource \"" + min_label + "\"!!!\n\n"
+                dlg = wx.MessageDialog(self,unablemsg, 'Url not found',wx.ICON_EXCLAMATION)
+                dlg.ShowModal()
+                dlg.Destroy()
+                self.canvas.layers['token'].rollback_serial()
+            self.canvas.send_map_data()
+            self.canvas.Refresh(False)
+
+
+    def build_menu(self,label = "Token"):
+        ## Menu Changes: Rotate
+        ## Menu into Component
+        ## Remove To GameTree option
+        base_layer_handler.build_menu(self,label)
+        self.main_menu.AppendSeparator()
+        self.main_menu.Append(LABEL_TOOL,"&Auto label","",1)
+        self.main_menu.Check(LABEL_TOOL,self.auto_label)
+        self.main_menu.Append(SERIAL_TOOL,"&Number minis","",1)
+        self.main_menu.Check(SERIAL_TOOL, self.use_serial)
+        self.main_menu.Append(MAP_REFRESH_MINI_URLS,"&Refresh tokens")       #  Add the menu item
+        self.main_menu.AppendSeparator()
+        self.main_menu.Append(TOK_MOVE, "Move")
+        self.canvas.Bind(wx.EVT_MENU, self.on_map_board_menu_item, id=MAP_REFRESH_MINI_URLS) #  Set the handler
+        self.canvas.Bind(wx.EVT_MENU, self.on_label, id=LABEL_TOOL)
+        self.canvas.Bind(wx.EVT_MENU, self.on_serial, id=SERIAL_TOOL)
+        # build token menu
+        self.min_menu = wx.Menu()
+        # Rectangles and hexagons require slightly different menus because of
+        # facing and heading possibilities.
+
+        rot_left = wx.Menu()
+        rot_left_45 = rot_left.Append(-1, '45*')
+        self.canvas.Bind(wx.EVT_MENU, self.rot_left_45, rot_left_45)
+        rot_right = wx.Menu()
+
+        rot_right_45 = rot_right.Append(-1, '45*')
+        self.canvas.Bind(wx.EVT_MENU, self.rot_right_45, rot_right_45)
+        ## Replace with Rotate. Left - Right, 45 - 90 degress.
+        """
+        face_menu = wx.Menu()
+        face_menu.Append(TOK_FACING_NONE,"&None")
+        face_menu.Append(TOK_FACING_NORTH,"&North")
+        face_menu.Append(TOK_FACING_NORTHEAST,"Northeast")
+        face_menu.Append(TOK_FACING_EAST,"East")
+        face_menu.Append(TOK_FACING_SOUTHEAST,"Southeast")
+        face_menu.Append(TOK_FACING_SOUTH,"&South")
+        face_menu.Append(TOK_FACING_SOUTHWEST,"Southwest")
+        face_menu.Append(TOK_FACING_WEST,"West")
+        face_menu.Append(TOK_FACING_NORTHWEST,"Northwest")
+        """
+        ###
+
+        heading_menu = wx.Menu()
+        heading_menu.Append(TOK_HEADING_NONE,"&None")
+        heading_menu.Append(TOK_HEADING_NORTH,"&North")
+        heading_menu.Append(TOK_HEADING_NORTHEAST,"Northeast")
+        heading_menu.Append(TOK_HEADING_EAST,"East")
+        heading_menu.Append(TOK_HEADING_SOUTHEAST,"Southeast")
+        heading_menu.Append(TOK_HEADING_SOUTH,"&South")
+        heading_menu.Append(TOK_HEADING_SOUTHWEST,"Southwest")
+        heading_menu.Append(TOK_HEADING_WEST,"West")
+        heading_menu.Append(TOK_HEADING_NORTHWEST,"Northwest")
+
+        align_menu = wx.Menu()
+        align_menu.Append(TOK_ALIGN_GRID_CENTER,"&Center")
+        align_menu.Append(TOK_ALIGN_GRID_TL,"&Top-Left")
+        #  This is a hack to simulate a menu title, due to problem in Linux
+        if wx.Platform == '__WXMSW__': self.min_menu.SetTitle(label)
+        else:
+            self.min_menu.Append(TOK_TITLE_HACK,label)
+            self.min_menu.AppendSeparator()
+        self.min_menu.Append(TOK_SHOW_HIDE,"Show / Hide")
+        self.min_menu.Append(TOK_LOCK_UNLOCK, "Lock / Unlock")
+        self.min_menu.Append(TOK_REMOVE,"&Remove")
+
+        ##Remove
+        #self.min_menu.Append(TOK_TO_GAMETREE,"To &Gametree")
+        ###
+
+        self.min_menu.AppendMenu(TOK_HEADING_SUBMENU,"Set &Heading",heading_menu)
+
+        ##Remove
+        self.min_menu.AppendMenu(TOK_ROT_LEFT,"&Rotate Left",rot_left)
+        self.min_menu.AppendMenu(wx.ID_ANY,"&Rotate Right",rot_right)
+        ###
+
+        self.min_menu.AppendMenu(TOK_ALIGN_SUBMENU,"Snap-to &Alignment",align_menu)
+        self.min_menu.AppendSeparator()
+        zorder_menu = wx.Menu()
+        zorder_menu.Append(TOK_BACK_ONE,"Back one")
+        zorder_menu.Append(TOK_FORWARD_ONE,"Forward one")
+        zorder_menu.Append(TOK_TO_BACK,"To back")
+        zorder_menu.Append(TOK_TO_FRONT,"To front")
+        zorder_menu.AppendSeparator()
+        zorder_menu.Append(TOK_LOCK_BACK,"Lock to back")
+        zorder_menu.Append(TOK_LOCK_FRONT,"Lock to front")
+        zorder_menu.Append(TOK_FRONTBACK_UNLOCK,"Unlock Front/Back")
+        self.min_menu.AppendMenu(TOK_ZORDER_SUBMENU, "Token Z-Order",zorder_menu)
+        #self.min_menu.Append(TOK_LOCK,"&Lock")
+        self.min_menu.AppendSeparator()
+        self.min_menu.Append(TOK_PROP_DLG,"&Properties")
+
+
+        #self.min_menu.AppendSeparator()
+        #self.min_menu.Append(TOK_MOVE, "Move")
+
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_MOVE)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_SHOW_HIDE)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_UNLOCK)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_REMOVE)
+
+        ##Remove
+        #self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_GAMETREE)
+        ###
+
+        #self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_PROP_DLG)
+
+        ##Remove
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NONE)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_EAST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_WEST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTH)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTH)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTHEAST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTHEAST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTHWEST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTHWEST)
+        ###
+
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NONE)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_EAST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_WEST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTH)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTH)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTHEAST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTHEAST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTHWEST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTHWEST)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_ALIGN_GRID_CENTER)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_ALIGN_GRID_TL)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_BACK_ONE)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FORWARD_ONE)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_BACK)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_FRONT)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_BACK)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_FRONT)
+        self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FRONTBACK_UNLOCK)
+        ######### add plugin added menu items #########
+        if len(self.mini_rclick_menu_extra_items)>0:
+            self.min_menu.AppendSeparator()
+            for item in self.mini_rclick_menu_extra_items.items(): self.min_menu.Append(item[1], item[0])
+        if len(self.background_rclick_menu_extra_items)>0:
+            self.main_menu.AppendSeparator()
+            for item in self.background_rclick_menu_extra_items.items():
+                self.main_menu.Append(item[1], item[0])
+
+    def do_min_menu(self,pos):
+        self.canvas.PopupMenu(self.min_menu,pos)
+
+    def rot_left_45(self, evt):
+        #self.sel_rmin.rotate += 0.785
+        self.sel_rmin.rotate += 1.046
+        #component.get('drawn')[self.sel_rmin] = False
+
+    def rot_right_45(self, evt):
+        #self.sel_rmin.rotate -= 0.785
+        self.sel_rmin.rotate -= 1.046
+
+    def do_min_select_menu(self, min_list, pos):
+        # to prevent another event being processed
+        self.lastMenuChoice = None
+        self.min_select_menu = wx.Menu()
+        self.min_select_menu.SetTitle("Select Token")
+        loop_count = 1
+        try:
+            for m in min_list:
+                # Either use the token label for the selection list
+                if m.label: self.min_select_menu.Append(loop_count, m.label)
+                # Or use part of the images filename as an identifier
+                else:
+                    string_split = string.split(m.path,"/",)
+                    last_string = string_split[len(string_split)-1]
+                    self.min_select_menu.Append(loop_count, 'Unlabeled - ' + last_string[:len(last_string)-4])
+                self.canvas.Bind(wx.EVT_MENU, self.min_selected, id=loop_count)
+                loop_count += 1
+            self.canvas.PopupMenu(self.min_select_menu,pos)
+        except: pass
+
+    def min_selected(self,evt):
+        # this is the callback function for the menu that is used to choose
+        # between minis when you right click, left click or left double click
+        # on a stack of two or more
+        self.canvas.Refresh(False)
+        self.canvas.send_map_data()
+        self.lastMenuChoice = evt.GetId()-1
+
+    def on_min_menu_item(self,evt):
+        id = evt.GetId()
+        if id == TOK_MOVE:
+            if self.sel_min:
+                self.moveSelectedMini(self.last_rclick_pos)
+                self.deselectAndRefresh()
+            return
+        elif id == TOK_REMOVE: self.canvas.layers['token'].del_token(self.sel_rmin)
+
+        ##Remove
+        elif id == TOK_TO_GAMETREE:
+            min_xml = self.sel_rmin.toxml(action="new")
+            node_begin = "<nodehandler module='map_token_nodehandler' class='map_token_handler' name='"
+            if self.sel_rmin.label: node_begin += self.sel_rmin.label + "'"
+            else:  node_begin += "Unnamed token'"
+            node_begin += ">"
+	    gametree = component.get('tree')
+            node_xml = node_begin + min_xml + '</nodehandler>'
+            #print "Sending this XML to insert_xml:" + node_xml
+            gametree.insert_xml(str(node_xml))
+
+        elif id == TOK_SHOW_HIDE:
+            if self.sel_rmin.hide:  self.sel_rmin.hide = 0
+            else: self.sel_rmin.hide = 1
+        elif id == TOK_LOCK_UNLOCK:
+            if self.sel_rmin.locked: self.sel_rmin.locked = False
+            else: self.sel_rmin.locked = True
+            if self.sel_rmin == self.sel_min:
+                # when we lock / unlock the selected mini make sure it isn't still selected
+                # or it might easily get moved by accident and be hard to move back
+                self.sel_min.selected = False
+                self.sel_min.isUpdated = True
+                self.sel_min = None
+	recycle_bin = {TOK_HEADING_NONE: FACE_NONE, TOK_HEADING_NORTH: FACE_NORTH, 
+        TOK_HEADING_NORTHWEST: FACE_NORTHWEST, TOK_HEADING_NORTHEAST: FACE_NORTHEAST, 
+        TOK_HEADING_EAST: FACE_EAST, TOK_HEADING_SOUTHEAST: FACE_SOUTHEAST, TOK_HEADING_SOUTHWEST: FACE_SOUTHWEST, 
+        TOK_HEADING_SOUTH: FACE_SOUTH, TOK_HEADING_WEST: FACE_WEST}
+	if recycle_bin.has_key(id):
+	    self.sel_rmin.heading = recycle_bin[id]
+	    del recycle_bin
+	recycle_bin = {TOK_FACING_NONE: FACE_NONE, TOK_FACING_NORTH: FACE_NORTH, 
+        TOK_FACING_NORTHWEST: FACE_NORTHWEST, TOK_FACING_NORTHEAST: FACE_NORTHEAST, 
+        TOK_FACING_EAST: FACE_EAST, TOK_FACING_SOUTHEAST: FACE_SOUTHEAST, TOK_FACING_SOUTHWEST: FACE_SOUTHWEST, 
+        TOK_FACING_SOUTH: FACE_SOUTH, TOK_FACING_WEST: FACE_WEST}
+	if recycle_bin.has_key(id):
+	    self.sel_rmin.face = recycle_bin[id]
+	    del recycle_bin
+        elif id == TOK_ALIGN_GRID_CENTER: self.sel_rmin.snap_to_align = SNAPTO_ALIGN_CENTER
+        elif id == TOK_ALIGN_GRID_TL: self.sel_rmin.snap_to_align = SNAPTO_ALIGN_TL
+        elif id == TOK_PROP_DLG:
+            old_lock_value = self.sel_rmin.locked
+            dlg = min_edit_dialog(self.canvas.frame.GetParent(),self.sel_rmin)
+            if dlg.ShowModal() == wx.ID_OK:
+                if self.sel_rmin == self.sel_min and self.sel_rmin.locked != old_lock_value:
+                    # when we lock / unlock the selected mini make sure it isn't still selected
+                    # or it might easily get moved by accident and be hard to move back
+                    self.sel_min.selected = False
+                    self.sel_min.isUpdated = True
+                    self.sel_min = None
+                self.canvas.Refresh(False)
+                self.canvas.send_map_data()
+                return
+
+        elif id == TOK_BACK_ONE:
+            #  This assumes that we always start out with a z-order
+            #     that starts at 0 and goes up to the number of
+            #     minis - 1.  If this isn't the case, then execute
+            #     a self.canvas.layers['token'].collapse_zorder()
+            #     before getting the oldz to test
+            #  Save the selected minis current z-order
+            oldz = self.sel_rmin.zorder
+            # Make sure the mini isn't sticky front or back
+            if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT):
+		##   print "old z-order = " + str(oldz)
+                self.sel_rmin.zorder -= 1
+                #  Re-collapse to normalize
+                #  Note:  only one update (with the final values) will be sent
+                self.canvas.layers['token'].collapse_zorder()
+
+        elif id == TOK_FORWARD_ONE:
+            #  This assumes that we always start out with a z-order
+            #     that starts at 0 and goes up to the number of
+            #     minis - 1.  If this isn't the case, then execute
+            #     a self.canvas.layers['token'].collapse_zorder()
+            #     before getting the oldz to test
+            #  Save the selected minis current z-order
+            oldz = self.sel_rmin.zorder
+	    ##  print "old z-order = " + str(oldz)
+            self.sel_rmin.zorder += 1
+
+            #  Re-collapse to normalize
+            #  Note:  only one update (with the final values) will be sent
+            self.canvas.layers['token'].collapse_zorder()
+
+        elif id == TOK_TO_FRONT:
+            #  This assumes that we always start out with a z-order
+            #     that starts at 0 and goes up to the number of
+            #     minis - 1.  If this isn't the case, then execute
+            #     a self.canvas.layers['token'].collapse_zorder()
+            #     before getting the oldz to test
+            #  Save the selected minis current z-order
+            oldz = self.sel_rmin.zorder
+
+            # Make sure the mini isn't sticky front or back
+            if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT):
+	    ##  print "old z-order = " + str(oldz)
+                #  The new z-order will be one more than the last index
+                newz = len(self.canvas.layers['token'].token)
+	    ##  print "new z-order = " + str(newz)
+                self.sel_rmin.zorder = newz
+                #  Re-collapse to normalize
+                #  Note:  only one update (with the final values) will be sent
+                self.canvas.layers['token'].collapse_zorder()
+
+        elif id == TOK_TO_BACK:
+            #  This assumes that we always start out with a z-order
+            #     that starts at 0 and goes up to the number of
+            #     minis - 1.  If this isn't the case, then execute
+            #     a self.canvas.layers['token'].collapse_zorder()
+            #     before getting the oldz to test
+            #  Save the selected minis current z-order
+            oldz = self.sel_rmin.zorder
+            # Make sure the mini isn't sticky front or back
+            if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT):
+	    ##  print "old z-order = " + str(oldz)
+
+                #  Since 0 is the lowest in a normalized order, be one less
+                newz = -1
+	    ##  print "new z-order = " + str(newz)
+                self.sel_rmin.zorder = newz
+                #  Re-collapse to normalize
+                #  Note:  only one update (with the final values) will be sent
+                self.canvas.layers['token'].collapse_zorder()
+
+        elif id == TOK_FRONTBACK_UNLOCK:
+            #print "Unlocked/ unstickified..."
+            if self.sel_rmin.zorder == TOK_STICKY_BACK: self.sel_rmin.zorder = TOK_STICKY_BACK + 1
+            elif self.sel_rmin.zorder == TOK_STICKY_FRONT: self.sel_rmin.zorder = TOK_STICKY_FRONT - 1
+        elif id == TOK_LOCK_BACK: self.sel_rmin.zorder = TOK_STICKY_BACK
+        elif id == TOK_LOCK_FRONT: self.sel_rmin.zorder = TOK_STICKY_FRONT
+        # Pretty much, we always want to refresh when we go through here
+        # This helps us remove the redundant self.Refresh() on EVERY menu event
+        # that we process above.
+        self.sel_rmin.isUpdated = True
+        self.canvas.Refresh(False)
+        self.canvas.send_map_data()
+
+    def on_token(self, evt):
+        session = self.canvas.frame.session
+        if (session.my_role() != session.ROLE_GM) and (session.my_role() != session.ROLE_PLAYER) and (session.use_roles()):
+            self.infoPost("You must be either a player or GM to use the token Layer")
+            return
+        min_url = self.min_url.GetValue()
+        # build url
+        if min_url == "" or min_url == "http://": return
+        if min_url[:7] != "http://" : min_url = "http://" + min_url
+        # make label
+        if self.auto_label and min_url[-4:-3] == '.':
+            start = min_url.rfind("/") + 1
+            min_label = min_url[start:len(min_url)-4]
+            if self.use_serial:
+                min_label = '%s %d' % ( min_label, self.canvas.layers['token'].next_serial() )
+        else: min_label = ""
+        if self.min_url.FindString(min_url) == -1: self.min_url.Append(min_url)
+        try:
+            id = 'mini-' + self.canvas.frame.session.get_next_id()
+            # make the new mini appear in top left of current viewable map
+            dc = wx.ClientDC(self.canvas)
+            self.canvas.PrepareDC(dc)
+            dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
+            x = dc.DeviceToLogicalX(0)
+            y = dc.DeviceToLogicalY(0)
+            self.canvas.layers['token'].add_token(id, min_url, pos=cmpPoint(x,y), label=min_label)
+        except:
+            # When there is an exception here, we should be decrementing the serial_number for reuse!!
+            unablemsg= "Unable to load/resolve URL: " + min_url + " on resource \"" + min_label + "\"!!!\n\n"
+            #print unablemsg
+            dlg = wx.MessageDialog(self,unablemsg, 'Url not found',wx.ICON_EXCLAMATION)
+            dlg.ShowModal()
+            dlg.Destroy()
+            self.canvas.layers['token'].rollback_serial()
+        self.canvas.send_map_data()
+        self.canvas.Refresh(False)
+        #except Exception, e:
+            #wx.MessageBox(str(e),"token Error")
+
+    def on_label(self,evt):
+        self.auto_label = not self.auto_label
+        self.auto_label_cb.SetValue(self.auto_label)
+        #self.send_map_data()
+        #self.Refresh()
+
+    def on_min_list(self,evt):
+        session = self.canvas.frame.session
+        if (session.my_role() != session.ROLE_GM):
+            self.infoPost("You must be a GM to use this feature")
+            return
+        #d = min_list_panel(self.frame.GetParent(),self.canvas.layers,"token list")
+        d = min_list_panel(self.canvas.frame,self.canvas.layers,"token list")
+        if d.ShowModal() == wx.ID_OK: d.Destroy()
+        self.canvas.Refresh(False)
+
+    def on_serial(self, evt):
+        self.use_serial = not self.use_serial
+
+    def on_map_board_menu_item(self,evt):
+        id = evt.GetId()
+        if id == MAP_REFRESH_MINI_URLS:   # Note: this doesn't change the mini, so no need to update the map
+            for mini in self.canvas.layers['token'].tokens:       #  For all minis
+                mini.set_bmp(ImageHandler.load(mini.path, 'token', mini.id))      #  Reload their bmp member
+            self.canvas.Refresh(False)
+
+####################################################################
+    ## old functions, changed an awful lot
+
+    def on_left_down(self, evt):
+        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
+        mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm())
+        if mini:
+            deselecting_selected_mini = (mini == self.sel_min) #clicked on the selected mini
+            self.deselectAndRefresh()
+            self.drag_mini = mini
+            if deselecting_selected_mini: return
+            self.sel_min = mini
+            self.sel_min.selected = True
+            self.canvas.Refresh()
+        else:
+            self.drag_mini = None
+            pos = self.getLogicalPosition(evt)
+            self.moveSelectedMini(pos)
+            self.deselectAndRefresh()
+
+    def on_right_down(self, evt):
+        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
+        self.last_rclick_pos = self.getLogicalPosition(evt)
+        mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm())
+        if mini:
+            self.sel_rmin = mini
+            if self.sel_min: self.min_menu.Enable(TOK_MOVE, True)
+            else: self.min_menu.Enable(TOK_MOVE, False)
+            self.prepare_mini_rclick_menu(evt)
+            self.do_min_menu(evt.GetPosition())
+        else:# pass it on
+            if self.sel_min: self.main_menu.Enable(TOK_MOVE, True)
+            else: self.main_menu.Enable(TOK_MOVE, False)
+            self.prepare_background_rclick_menu(evt)
+            base_layer_handler.on_right_down(self, evt)
+
+####################################################################
+    ## new functions
+
+    def on_drop_files(self, x, y, filepaths):
+        # currently we ignore multiple files
+        filepath = filepaths[0]
+        start1 = filepath.rfind("\\") + 1 # check for both slashes in path to be on the safe side
+        start2 = filepath.rfind("/") + 1
+        if start1 < start2: start1 = start2
+        filename = filepath[start1:]
+        pos = filename.rfind('.')
+        ext = filename[pos:].lower()
+        #ext = filename[-4:].lower()
+        if(ext != ".bmp" and ext != ".gif" and ext != ".jpg" and ext != ".jpeg" and ext != ".png"):
+            self.infoPost("Supported file extensions are: *.bmp, *.gif, *.jpg, *.jpeg, *.png")
+            return
+        file = open(filepath, "rb")
+        imgdata = file.read()
+        file.close()
+        dc = wx.ClientDC(self.canvas)
+        self.canvas.PrepareDC(dc)
+        dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
+        x = dc.DeviceToLogicalX(x)
+        y = dc.DeviceToLogicalY(y)
+        (imgtype,j) = mimetypes.guess_type(filename)
+        postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype})
+        thread.start_new_thread(self.canvas.layers['token'].upload, (postdata, filepath), {'pos':cmpPoint(x,y)})
+
+    def on_tooltip_timer(self, *args):
+        pos = args[0]
+        dc = wx.ClientDC(self.canvas)
+        self.canvas.PrepareDC(dc)
+        dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
+        pos = wx.Point(dc.DeviceToLogicalX(pos.x), dc.DeviceToLogicalY(pos.y))
+        mini_list = self.getMiniListOrSelectedMini(pos)
+        if len(mini_list) > 0:
+            print mini_list
+            tooltip = self.get_mini_tooltip(mini_list); print tooltip
+            self.canvas.SetToolTipString(tooltip)
+        else: self.canvas.SetToolTipString("")
+
+    def on_motion(self,evt):
+        if evt.Dragging() and evt.LeftIsDown():
+            if self.canvas.drag is None and self.drag_mini is not None:
+                drag_bmp = self.drag_mini.bmp
+                if self.drag_mini.width and self.drag_mini.height:
+                    tmp_image = drag_bmp.ConvertToImage()
+                    tmp_image.Rescale(int(self.drag_mini.width * self.canvas.layers['grid'].mapscale), 
+                        int(self.drag_mini.height * self.canvas.layers['grid'].mapscale))
+                    tmp_image.ConvertAlphaToMask()
+
+                    ### Should show rotated image when dragging.
+                    if self.drag_mini.rotate != 0 :
+                        tmp_image = tmp_image.Rotate(self.drag_mini.rotate, 
+                                                    (self.drag_mini.width/2, self.drag_mini.height/2))
+
+                    drag_bmp = tmp_image.ConvertToBitmap()
+                    mask = wx.Mask(drag_bmp, wx.Colour(tmp_image.GetMaskRed(), 
+                        tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue()))
+                    drag_bmp.SetMask(mask)
+                    tmp_image = tmp_image.ConvertToGreyscale()
+                    self.drag_mini.gray = True
+                    self.drag_mini.isUpdated = True
+                    def refresh():
+                        self.canvas.drag.Hide()
+                        self.canvas.Refresh(False)
+                    wx.CallAfter(refresh)
+                self.canvas.drag = wx.DragImage(drag_bmp)
+                self.drag_offset = self.getLogicalPosition(evt)- self.drag_mini.pos
+                self.canvas.drag.BeginDrag((int(self.drag_offset.x * self.canvas.layers['grid'].mapscale), 
+                    int(self.drag_offset.y * self.canvas.layers['grid'].mapscale)), self.canvas, False)
+            elif self.canvas.drag is not None:
+                self.canvas.drag.Move(evt.GetPosition())
+                self.canvas.drag.Show()
+        # reset tool tip timer
+        self.canvas.SetToolTipString("")
+        self.tooltip_timer.Restart(self.tooltip_delay_miliseconds, evt.GetPosition())
+
+    def on_left_up(self,evt):
+        if self.canvas.drag:
+            self.canvas.drag.Hide()
+            self.canvas.drag.EndDrag()
+            self.canvas.drag = None
+            pos = self.getLogicalPosition(evt)
+            pos = pos - self.drag_offset
+            if self.canvas.layers['grid'].snap:
+                nudge = int(self.canvas.layers['grid'].unit_size/2)
+                if self.canvas.layers['grid'].mode != GRID_ISOMETRIC:
+                    if self.drag_mini.snap_to_align == SNAPTO_ALIGN_CENTER:
+                        pos = pos + (int(self.drag_mini.bmp.GetWidth()/2),int(self.drag_mini.bmp.GetHeight()/2))
+                    else: pos = pos + (nudge, nudge)
+                else:# GRID_ISOMETRIC
+                    if self.drag_mini.snap_to_align == SNAPTO_ALIGN_CENTER:
+                        pos = pos + (int(self.drag_mini.bmp.GetWidth()/2), self.drag_mini.bmp.GetHeight())
+                    else: pass # no nudge for the isomorphic / top-left
+            self.sel_min = self.drag_mini
+            # check to see if the mouse is inside the window still
+            w = self.canvas.GetClientSizeTuple() # this is the window size, minus any scrollbars
+            p = evt.GetPosition() # compare the window size, w with the non-logical position
+            c = self.canvas.size # this is the grid size, compare with the logical position, pos
+            # both are [width, height]
+            if p.x>=0 and pos.x<c[0] and p.x<w[0] and p.y>=0 and pos.y<c[1] and p.y<w[1]:
+                self.moveSelectedMini(pos)
+            self.sel_min.gray = False
+            self.sel_min.selected = False
+            self.sel_min.isUpdated = True
+            self.canvas.Refresh(False)
+            self.canvas.send_map_data()
+            self.sel_min = None
+        self.drag_mini = None
+
+    def on_left_dclick(self,evt):
+        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
+        mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm())
+        if mini: self.on_mini_dclick(evt, mini)
+        else: base_layer_handler.on_left_dclick(self, evt)
+
+
+####################################################################
+    ## hook functions (although with python you can override any of the functions)
+
+    def prepare_mini_rclick_menu(self, evt):
+        # override the entire right-click on a mini menu
+        pass
+
+    def prepare_background_rclick_menu(self, evt):
+        # override the entire right-click on the map menu
+        pass
+
+    def get_mini_tooltip(self, mini_list):
+        # override to create a tooltip
+        return ""
+
+    def on_mini_dclick(self, evt, mini):
+        # do something after the mini was left double clicked
+        pass
+
+####################################################################
+    ## easy way to add a single menu item
+
+    def set_mini_rclick_menu_item(self, label, callback_function):
+        # remember you might want to call these at the end of your callback function:
+        # mini_handler.sel_rmin.isUpdated = True
+        # canvas.Refresh(False)
+        # canvas.send_map_data()
+        if callback_function == None: del self.mini_rclick_menu_extra_items[label]
+        else:
+            if not self.mini_rclick_menu_extra_items.has_key(label):
+                self.mini_rclick_menu_extra_items[label]=wx.NewId()
+            menu_id = self.mini_rclick_menu_extra_items[label]
+            self.canvas.Bind(wx.EVT_MENU, callback_function, id=menu_id)
+        self.build_menu()
+
+    def set_background_rclick_menu_item(self, label, callback_function):
+        if callback_function == None: del self.background_rclick_menu_extra_items[label]
+        else:
+            if not self.background_rclick_menu_extra_items.has_key(label):
+                self.background_rclick_menu_extra_items[label]=wx.NewId()
+            menu_id = self.background_rclick_menu_extra_items[label]
+            self.canvas.Bind(wx.EVT_MENU, callback_function, id=menu_id)
+        self.build_menu()
+
+
+####################################################################
+    ## helper functions
+
+    def infoPost(self, message):
+        component.get("chat").InfoPost(message)
+
+    def role_is_gm_or_player(self):
+        session = self.canvas.frame.session
+        if (session.my_role() <> session.ROLE_GM) and (session.my_role() <> session.ROLE_PLAYER) and (session.use_roles()):
+            self.infoPost("You must be either a player or GM to use the token Layer")
+            return False
+        return True
+
+    def role_is_gm(self):
+        session = self.canvas.frame.session
+        if (session.my_role() <> session.ROLE_GM) and (session.use_roles()): return False
+        return True
+
+    def alreadyDealingWithMenu(self):
+        return self.lastMenuChoice is not None
+
+    def getLastMenuChoice(self):
+        choice = self.lastMenuChoice
+        self.lastMenuChoice = None
+        return choice
+
+    def getLogicalPosition(self, evt):
+        dc = wx.ClientDC(self.canvas)
+        self.canvas.PrepareDC(dc)
+        dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale)
+        pos = evt.GetLogicalPosition(dc)
+        return pos
+
+    def getMiniListOrSelectedMini(self, pos, include_locked=False):
+        if self.sel_min and self.sel_min.hit_test(pos):
+            # clicked on the selected mini - assume that is the intended target
+            # and don't give a choice of it and any other minis stacked with it
+            mini_list = []
+            mini_list.append(self.sel_min)
+            return mini_list
+        mini_list = self.canvas.layers['token'].find_token(pos, (not include_locked))
+        if mini_list: return mini_list
+        mini_list = []
+        return mini_list
+
+    def deselectAndRefresh(self):
+        if self.sel_min:
+            self.sel_min.selected = False
+            self.sel_min.isUpdated = True
+            self.canvas.Refresh(False)
+            self.canvas.send_map_data()
+            self.sel_min = None
+
+    def moveSelectedMini(self, pos):
+        if self.sel_min: self.moveMini(pos, self.sel_min)
+
+    def moveMini(self, pos, mini):
+        grid = self.canvas.layers['grid']
+        mini.pos = grid.get_snapped_to_pos(pos, mini.snap_to_align, mini.bmp.GetWidth(), mini.bmp.GetHeight())
+
+    def find_mini(self, evt, include_locked):
+        if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return
+        pos = self.getLogicalPosition(evt)
+        mini_list = self.getMiniListOrSelectedMini(pos, include_locked)
+        mini = None
+        if len(mini_list) > 1:
+            try: self.do_min_select_menu(mini_list, evt.GetPosition())
+            except: pass
+            choice = self.getLastMenuChoice()
+            if choice == None: return None # left menu without making a choice, eg by clicking outside menu
+            mini = mini_list[choice]
+        elif len(mini_list) == 1: mini = mini_list[0]
+        return mini
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/bcg/tokens.py	Tue Oct 06 22:16:34 2009 -0500
@@ -0,0 +1,600 @@
+# 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/tokens.py
+# Author: Chris Davis
+# Maintainer:
+# Version:
+#   $Id: tokens.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: tokens.py,v 1.46 2007/12/07 20:39:50 digitalxero Exp $"
+
+from orpg.mapper.base import *
+import thread
+import time
+import urllib
+import os.path
+
+from orpg.tools.orpg_settings import settings
+
+MIN_STICKY_BACK = -0XFFFFFF
+MIN_STICKY_FRONT = 0xFFFFFF
+
+##----------------------------------------
+##  token 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 BmpToken:
+    def __init__(self, id,path, bmp, pos=cmpPoint(0,0), 
+                heading=FACE_NONE, rotate=0, 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.heading = heading
+        self.rotate = rotate
+        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.drawn = {}
+
+    def __del__(self):
+        del self.bmp
+        self.bmp = None
+
+    def set_bmp(self, bmp):
+        self.bmp = bmp
+
+    def set_min_props(self, heading=FACE_NONE, rotate=0, label="", locked=False, hide=False, width=0, height=0):
+        self.heading = heading
+        self.rotate = rotate
+        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
+
+    def hit_test(self, pt):
+        rect = self.get_rect()
+        result = None
+        result = rect.InsideXY(pt.x, pt.y)
+        return result
+
+    def get_rect(self):
+        ret = wx.Rect(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
+        return ret
+
+    def draw(self, dc, mini_layer, op=wx.COPY):
+        if isinstance(self.bmp, tuple):
+            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:
+                # 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)
+                return True
+            elif self.hide: return True
+
+            else:
+                # 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
+
+                if self.rotate != 0:
+                    x = bmp.GetWidth(); print x
+                    y = bmp.GetHeight(); print y
+                    img = bmp.ConvertToImage()
+                    img = img.Rotate(self.rotate, (3, 80), True)
+                    img.ConvertAlphaToMask()
+
+                    bmp = img.ConvertToBitmap()
+                    mask = wx.Mask(bmp, wx.Colour(img.GetMaskRed(), 
+                        img.GetMaskGreen(), img.GetMaskBlue()))
+                    bmp.SetMask(mask)
+
+                dc.DrawBitmap(bmp, self.pos.x, self.pos.y, True)
+                component.get('drawn')[bmp] = True
+                self.left = 0
+                self.right = self.bmp.GetWidth()
+                self.top = 0
+                self.bottom = self.bmp.GetHeight()
+
+                # 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
+                return True
+        else: return False
+
+    def toxml(self, action="update"):
+        if action == "del":
+            xml_str = "<token action='del' id='" + self.id + "'/>"
+            return xml_str
+        xml_str = "<token"
+        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.rotate != None: xml_str += " rotate='" + str(self.rotate) + "'"
+        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 += " />"
+        if (action == "update" and self.isUpdated) or action == "new":
+            self.isUpdated = False
+            return xml_str
+        else: return ''
+
+    def takedom(self, xml_dom):
+        self.id = xml_dom.getAttribute("id")
+        if xml_dom.hasAttribute("posx"):
+            self.pos.x = int(xml_dom.getAttribute("posx"))
+        if xml_dom.hasAttribute("posy"):
+            self.pos.y = int(xml_dom.getAttribute("posy"))
+        if xml_dom.hasAttribute("heading"):
+            self.heading = int(xml_dom.getAttribute("heading"))
+        if xml_dom.hasAttribute("rotate"):
+            self.rotate = int(xml_dom.getAttribute("rotate"))
+        if xml_dom.hasAttribute("path"):
+            self.path = urllib.unquote(xml_dom.getAttribute("path"))
+            self.set_bmp(ImageHandler.load(self.path, 'token', self.id))
+        if xml_dom.hasAttribute("locked"):
+            if xml_dom.getAttribute("locked") == '1' or xml_dom.getAttribute("locked") == 'True': self.locked = True
+            else: self.locked = False
+        if xml_dom.hasAttribute("hide"):
+            if xml_dom.getAttribute("hide") == '1' or xml_dom.getAttribute("hide") == 'True': self.hide = True
+            else: self.hide = False
+        if xml_dom.hasAttribute("label"):
+            self.label = xml_dom.getAttribute("label")
+        if xml_dom.hasAttribute("zorder"):
+            self.zorder = int(xml_dom.getAttribute("zorder"))
+        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
+        if xml_dom.hasAttribute("width"):
+            self.width = int(xml_dom.getAttribute("width"))
+        if xml_dom.hasAttribute("height"):
+            self.height = int(xml_dom.getAttribute("height"))
+
+##-----------------------------
+## token layer
+##-----------------------------
+class token_layer(layer_base):
+    def __init__(self, canvas):
+        self.canvas = canvas
+        layer_base.__init__(self)
+        self.id = -1 #added.
+        self.tokens = []
+        self.serial_number = 0
+
+        self.drawn = {}
+        component.add('drawn', self.drawn)
+        # Set the font of the labels to be the same as the chat window
+        # only smaller.
+        font_size = int(settings.get_setting('defaultfontsize'))
+        if (font_size >= 10): font_size -= 2
+        self.label_font = wx.Font(font_size, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL,
+                                  False, settings.get_setting('defaultfont'))
+
+    def next_serial(self):
+        self.serial_number += 1
+        return self.serial_number
+
+    def get_next_highest_z(self):
+        z = len(self.tokens)+1
+        return z
+
+    def cleanly_collapse_zorder(self):
+        #  lock the zorder stuff
+        sorted_tokens = self.tokens[:]
+        sorted_tokens.sort(cmp_zorder)
+        i = 0
+        for mini in sorted_tokens:
+            mini.zorder = i
+            i = i + 1
+        #  unlock the zorder stuff
+
+    def collapse_zorder(self):
+        #  lock the zorder stuff
+        sorted_tokens = self.tokens[:]
+        sorted_tokens.sort(cmp_zorder)
+        i = 0
+        for mini in sorted_tokens:
+            if (mini.zorder != MIN_STICKY_BACK) and (mini.zorder != MIN_STICKY_FRONT): mini.zorder = i
+            else: pass
+            i = i + 1
+        #  unlock the zorder stuff
+
+    def rollback_serial(self):
+        self.serial_number -= 1
+
+    def add_token(self, id, path, pos=cmpPoint(0,0), label="", heading=FACE_NONE, 
+            rotate=0, width=0, height=0, local=False, localPath='', localTime=-1):
+        bmp = ImageHandler.load(path, 'token', id)
+        if bmp:
+            mini = BmpToken(id, path, bmp, pos, heading, rotate, label, 
+                zorder=self. get_next_highest_z(), width=width, 
+                height=height, local=local, localPath=localPath, localTime=localTime)
+            self.tokens.append(mini)
+            self.drawn[mini.bmp] = False
+            xml_str = "<map><tokens>"
+            xml_str += mini.toxml("new")
+            xml_str += "</tokens></map>"
+            component.get('session').send(xml_str)
+
+    def get_token_by_id(self, id):
+        for mini in self.tokens:
+            if str(mini.id) == str(id):
+                return mini
+        return None
+
+    def del_token(self, min):
+        xml_str = "<map><tokens>"
+        xml_str += min.toxml("del")
+        xml_str += "</tokens></map>"
+        self.canvas.frame.session.send(xml_str)
+        self.tokens.remove(min)
+        del min
+        self.collapse_zorder()
+
+    def del_all_tokens(self):
+        while len(self.tokens):
+            min = self.tokens.pop()
+            del min
+        self.collapse_zorder()
+
+    def layerDraw(self, dc, topleft, size):
+        dc.SetFont(self.label_font)
+        sorted_tokens = self.tokens[:]
+        sorted_tokens.sort(cmp_zorder)
+        for m in sorted_tokens:
+            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):
+                """
+                if self.drawn.has_key(m.bmp):
+                    if self.drawn[m.bmp] == True:
+                        dc2 = wx.MemoryDC()
+                        img = m.bmp.ConvertToImage()
+                        bmp = img.ConvertToBitmap()
+
+                        dc2.SelectObject(bmp)
+                        dc.Blit(m.pos.x, m.pos.y, img.GetHeight(), img.GetWidth(), dc2, 0, 0, wx.COPY, True, 0, 0)
+                        del dc2
+                
+                else:
+                """
+                m.draw(dc, self)
+
+    def find_token(self, pt, only_unlocked=False):
+        min_list = []
+        for m in self.tokens:
+            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:
+            return min_list
+        else: return None
+
+    def layerToXML(self, action="update"):
+        """ format  """
+        minis_string = ""
+        if self.tokens:
+            for m in self.tokens: minis_string += m.toxml(action)
+        if minis_string != '':
+            s = "<tokens"
+            s += " serial='" + str(self.serial_number) + "'"
+            s += ">"
+            s += minis_string
+            s += "</tokens>"
+            return s
+        else: return ""
+
+    def layerTakeDOM(self, xml_dom):
+        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_token_by_id(id)
+                if mini:
+                    self.tokens.remove(mini)
+                    del mini
+            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 = rotate = 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('rotate'): rotate = int(c.getAttribute('rotate'))
+                if c.hasAttribute('align'): snap_to_align = int(c.getAttribute('align'))
+                if c.getAttribute('zorder'): zorder = int(c.getAttribute('zorder'))
+                min = BmpToken(id, path, ImageHandler.load(path, 'token', id), pos, heading, 
+                    rotate, label, locked, hide, snap_to_align, zorder, width, height)
+                self.tokens.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_token_by_id(id)
+                if mini: mini.takedom(c)
+
+    def upload(self, postdata, filename, modify=False, pos=cmpPoint(0,0)):
+        self.lock.acquire()
+        url = 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_token(id, path, pos=pos, label=min_label, local=True, 
+                        localPath=filename, localTime=time.time())
+                else:
+                    self.tokens[len(self.tokens)-1].local = True
+                    self.tokens[len(self.tokens)-1].localPath = filename
+                    self.tokens[len(self.tokens)-1].localTime = time.time()
+                    self.tokens[len(self.tokens)-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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/bcg/tokens_msg.py	Tue Oct 06 22:16:34 2009 -0500
@@ -0,0 +1,133 @@
+# 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/tokens_msg.py
+# Author: Chris Davis
+# Maintainer:
+# Version:
+#   $Id: tokens_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $
+#
+# Description: This file contains some of the basic definitions for the chat
+# utilities in the orpg project.
+#
+__version__ = "$Id: tokens_msg.py,v 1.8 2006/11/04 21:24:21 digitalxero Exp $"
+
+from base_msg import *
+
+class mini_msg(map_element_msg_base):
+
+    def __init__(self,reentrant_lock_object = None):
+        self.tagname = "token"   # set this to be for minis.  Tagname gets used in some base class functions.
+        map_element_msg_base.__init__(self,reentrant_lock_object)   # call base class
+
+    # convenience method to use if only this mini is modified
+    #   outputs a <map/> element containing only the changes to this mini
+    def standalone_update_text(self,update_id_string):
+        buffer = "<map id='" + update_id_string + "'>"
+        buffer += "<tokens>"
+        buffer += self.get_changed_xml()
+        buffer += "</tokens></map>"
+        return buffer
+
+    # convenience method to use if only this mini is modified
+    #   outputs a <map/> element that deletes this mini
+    def standalone_delete_text(self,update_id_string):
+        buffer = None
+        if self._props.has_key("id"):
+            buffer = "<map id='" + update_id_string + "'>"
+            buffer += "<tokens>"
+            buffer += "<token action='del' id='" + self._props("id") + "'/>"
+            buffer += "</tokens></map>"
+        return buffer
+
+    # convenience method to use if only this mini is modified
+    #   outputs a <map/> element to add this mini
+    def standalone_add_text(self,update_id_string):
+        buffer = "<map id='" + update_id_string + "'>"
+        buffer += "<tokens>"
+        buffer += self.get_all_xml()
+        buffer += "</tokens></map>"
+        return buffer
+
+    def get_all_xml(self,action="new",output_action=1):
+        return map_element_msg_base.get_all_xml(self,action,output_action)
+
+    def get_changed_xml(self,action="update",output_action=1):
+        return map_element_msg_base.get_changed_xml(self,action,output_action)
+
+class minis_msg(map_element_msg_base):
+
+    def __init__(self,reentrant_lock_object = None):
+        self.tagname = "tokens"
+        map_element_msg_base.__init__(self,reentrant_lock_object)
+
+    def init_from_dom(self,xml_dom):
+        self.p_lock.acquire()
+        if xml_dom.tagName == self.tagname:
+            if xml_dom.getAttributeKeys():
+                for k in xml_dom.getAttributeKeys():
+                    self.init_prop(k,xml_dom.getAttribute(k))
+
+            for c in xml_dom._get_childNodes():
+                mini = mini_msg(self.p_lock)
+                try: mini.init_from_dom(c)
+                except Exception, e: print e; continue
+                id = mini.get_prop("id")
+                action = mini.get_prop("action")
+
+                if action == "new": self.children[id] = mini
+                elif action == "del":
+                    if self.children.has_key(id):
+                        self.children[id] = None
+                        del self.children[id]
+
+                elif action == "update":
+                    if self.children.has_key(id):
+                        self.children[id].init_props(mini.get_all_props())
+        else:
+            self.p_lock.release()
+            raise Exception, "Error attempting to initialize a " + self.tagname + " from a non-<" + self.tagname + "/> element"
+        self.p_lock.release()
+
+    def set_from_dom(self,xml_dom):
+        self.p_lock.acquire()
+        if xml_dom.tagName == self.tagname:
+            if xml_dom.getAttributeKeys():
+                for k in xml_dom.getAttributeKeys():
+                    self.set_prop(k,xml_dom.getAttribute(k))
+
+            for c in xml_dom._get_childNodes():
+                mini = mini_msg(self.p_lock)
+
+                try: mini.set_from_dom(c)
+                except Exception, e: print e; continue
+                id = mini.get_prop("id")
+                action = mini.get_prop("action")
+                if action == "new": self.children[id] = mini
+                elif action == "del":
+                    if self.children.has_key(id):
+                        self.children[id] = None
+                        del self.children[id]
+                elif action == "update":
+                    if self.children.has_key(id):
+                        self.children[id].set_props(mini.get_all_props())
+        else:
+            self.p_lock.release()
+            raise Exception, "Error attempting to set a " + self.tagname + " from a non-<" + self.tagname + "/> element"
+        self.p_lock.release()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/xxbcg.py	Tue Oct 06 22:16:34 2009 -0500
@@ -0,0 +1,242 @@
+import os
+import sys
+import orpg.pluginhandler
+from orpg.mapper.map import *
+from orpg.orpgCore import component
+import wx
+
+from orpg.mapper.images import ImageHandler
+from orpg.mapper.whiteboard_handler import *
+from orpg.mapper.background_handler import *
+from orpg.mapper.grid_handler import *
+from orpg.mapper.map_handler import *
+from orpg.mapper.fog_handler import *
+
+from bcg.token_handler import *
+from bcg.tokens import *
+
+
+class Plugin(orpg.pluginhandler.PluginHandler):
+    # Initialization subroutine.
+    #
+    # !self : instance of self
+    # !openrpg : instance of the the base openrpg control
+    def __init__(self, plugindb, parent):
+        orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent)
+
+        # The Following code should be edited to contain the proper information
+        self.name = 'Board / Card Game'
+        self.author = 'Tyler Starke (Prof. Ebral)'
+        self.help = 'Start Here'
+        self.parent = parent
+        #You can set variables below here. Always set them to a blank value in this section. Use plugin_enabled
+        #to set their proper values.
+        self.sample_variable = {}
+
+        self.canvas = component.get('map').canvas ## Obtain MapCanvas
+
+    def plugin_enabled(self):
+        tabs = component.get('map_tabs')
+        layers = component.get('map_layers')
+        map_wnd = component.get('map_wnd')
+        pages = tabs.GetPageCount()
+        self.layers = []
+        while pages:
+            pages -= 1
+            if tabs.GetPageText(pages) != 'Background':
+                if tabs.GetPageText(pages) != 'Whiteboard': 
+                    tabs.RemovePage(pages)
+        #tabs.InsertPage(2, layers[0], 'Tiles') # Removed for testing.
+        map_wnd.handlers[6]=(token_handler(tabs, -1, map_wnd.canvas))
+        tabs.InsertPage(3, map_wnd.handlers[6], 'Tokens')
+
+        ## Re Direct MapCanvas OnPaint event.
+        self.canvas.Disconnect(-1, -1, wx.wxEVT_PAINT)
+        self.canvas.Bind(wx.EVT_PAINT, self.on_paint)
+
+        ## Add to MapCanvas proccessImages
+        self.canvas.Bind(wx.EVT_TIMER, self.processImages, self.canvas.image_timer)
+
+        ## Create Token Layer
+        self.canvas.layers['token'] = token_layer(self.canvas)
+        #self.canvas.layers['tiles'] = tile_layer(self.canvas) #Not ready.
+
+        ### Define Grid / Background
+        self.canvas.layers['grid'].snap = False
+        self.canvas.layers['grid'].line = 0
+        #self.canvas.layers['bg'].set_texture(component.get('cherrypy')+'Textures/versa_anigre.jpg')
+        pass
+
+    def processImages(self, evt=None):
+        self.session = component.get("session")
+        if self.session.my_role() == self.session.ROLE_LURKER or (str(self.session.group_id) == '0' and str(self.session.status) == '1'):
+            cidx = self.canvas.parent.get_tab_index("Tiles")
+            self.canvas.parent.tabs.EnableTab(cidx, False)
+            cidx = self.canvas.parent.get_tab_index("Tokens")
+            self.canvas.parent.tabs.EnableTab(cidx, False)
+        else:
+            cidx = self.canvas.parent.get_tab_index("Tiles")
+            self.canvas.parent.tabs.EnableTab(cidx, True)
+            cidx = self.canvas.parent.get_tab_index("Tokens")
+            self.canvas.parent.tabs.EnableTab(cidx, True)
+        if not self.canvas.cacheSizeSet:
+            self.canvas.cacheSizeSet = True
+            cacheSize = component.get('settings').get_setting("ImageCacheSize")
+            if len(cacheSize): self.canvas.cacheSize = int(cacheSize)
+            else: pass
+        if not ImageHandler.Queue.empty():
+            (path, image_type, imageId) = ImageHandler.Queue.get()
+            img = wx.ImageFromMime(path[1], path[2]).ConvertToBitmap()
+            try:
+                # Now, apply the image to the proper object
+                if image_type == "miniature":
+                    min = self.canvas.layers['miniatures'].get_miniature_by_id(imageId)
+                    min.set_bmp(img)
+                elif image_type == "background" or image_type == "texture":
+                    self.canvas.layers['bg'].bg_bmp = img
+                    if image_type == "background": self.canvas.set_size([img.GetWidth(), img.GetHeight()])
+                elif image_type == "token":
+                    min = self.canvas.layers['token'].get_token_by_id(imageId)
+                    min.set_bmp(img)
+            except: pass
+
+    def on_paint(self, evt):
+        if self.canvas.layers.has_key('token') == False: self.canvas.layers['token'] = token_layer(self.canvas)
+        print 'BCG onpaint'
+        scale = self.canvas.layers['grid'].mapscale
+        scrollsize = self.canvas.GetScrollPixelsPerUnit()
+        clientsize = self.canvas.GetClientSize()
+        topleft1 = self.canvas.GetViewStart()
+        topleft = [topleft1[0]*scrollsize[0], topleft1[1]*scrollsize[1]]
+        if (clientsize[0] > 1) and (clientsize[1] > 1):
+            dc = wx.MemoryDC()
+            bmp = wx.EmptyBitmap(clientsize[0]+1, clientsize[1]+1)
+            dc.SelectObject(bmp)
+            dc.SetPen(wx.TRANSPARENT_PEN)
+            dc.SetBrush(wx.Brush(self.canvas.GetBackgroundColour(), wx.SOLID))
+            dc.DrawRectangle(0,0,clientsize[0]+1,clientsize[1]+1)
+            dc.SetDeviceOrigin(-topleft[0], -topleft[1])
+            dc.SetUserScale(scale, scale)
+            self.canvas.layers['bg'].layerDraw(dc, scale, topleft, clientsize)
+            self.canvas.layers['grid'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], 
+                [clientsize[0]/scale, clientsize[1]/scale])
+
+
+            self.canvas.layers['token'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], 
+                [clientsize[0]/scale, clientsize[1]/scale])
+
+
+            self.canvas.layers['whiteboard'].layerDraw(dc)
+            self.canvas.layers['fog'].layerDraw(dc, topleft, clientsize)
+            dc.SetPen(wx.NullPen)
+            dc.SetBrush(wx.NullBrush)
+            dc.SelectObject(wx.NullBitmap)
+            del dc
+            wdc = self.canvas.preppaint()
+            wdc.DrawBitmap(bmp, topleft[0], topleft[1])
+            if settings.get_setting("AlwaysShowMapScale") == "1":
+                self.canvas.showmapscale(wdc)
+        try: evt.Skip()
+        except: pass
+
+    def plugin_disabled(self):
+        tabs = component.get('map_tabs')
+        map_wnd = component.get('map_wnd')
+        pages = tabs.GetPageCount()
+        while pages:
+            pages -= 1
+            if tabs.GetPageText(pages) != 'Background':
+                if tabs.GetPageText(pages) != 'Whiteboard': 
+                    tabs.RemovePage(pages)
+        layers = component.get('map_layers')
+        tabs.InsertPage(1, layers[1],"Grid")
+        tabs.InsertPage(2, layers[2],"Miniatures")
+        tabs.InsertPage(4, layers[4],"Fog")
+        tabs.InsertPage(5, layers[5],"General")
+        map_wnd.current_layer = 2
+        map_wnd.tabs.SetSelection(map_wnd.current_layer)
+    
+        ## Re Connect original MapCanvas OnPaint event.
+        self.canvas.Disconnect(-1, -1, wx.wxEVT_PAINT)
+        self.canvas.Bind(wx.EVT_PAINT, self.canvas.on_paint)
+
+        ## Disconnect new proccessImages addition
+        self.canvas.Disconnect(-1, -1, wx.wxEVT_TIMER)
+        self.canvas.Bind(wx.EVT_TIMER, self.canvas.processImages, self.canvas.image_timer)
+
+        self.canvas.layers['grid'].snap = True
+        self.canvas.layers['grid'].line = 1
+
+        #Here you need to remove any commands you added, and anything else you want to happen when you disable the plugin
+        #such as closing windows created by the plugin
+        #self.plugin_removecmd('/test')
+        #self.plugin_removecmd('/example')
+
+        #This is the command to delete a message handler
+        #self.plugin_delete_msg_handler('xxblank')
+
+        #This is how you should destroy a frame when the plugin is disabled
+        #This same method should be used in close_module as well
+        try:
+            self.frame.Destroy()
+        except:
+            pass
+
+    def on_test(self, cmdargs):
+        #this is just an example function for a command you create.
+        # cmdargs contains everything you typed after the command
+        # so if you typed /test this is a test, cmdargs = this is a test
+        # args are the individual arguments split. For the above example
+        # args[0] = this , args[1] = is , args[2] = a , args[3] = test
+        self.plugin_send_msg(cmdargs, '<xxblank>' + cmdargs + '</xxblank>')
+        args = cmdargs.split(None,-1)
+        msg = 'cmdargs = %s' % (cmdargs)
+        self.chat.InfoPost(msg)
+
+        if len(args) == 0:
+            self.chat.InfoPost("You have no args")
+        else:
+            i = 0
+            for n in args:
+                msg = 'args[' + str(i) + '] = ' + n
+                self.chat.InfoPost(msg)
+                i += 1
+
+    def on_xml_recive(self,id, data,xml_dom):
+        self.chat.InfoPost(self.name + ":: Message recived<br />" + data.replace("<","&lt;").replace(">","&gt;") +'<br />From id:' + str(id))
+
+    def pre_parse(self, text):
+        #This is called just before a message is parsed by openrpg
+        return text
+
+    def send_msg(self, text, send):
+        #This is called when a message is about to be sent out.
+        #It covers all messages sent by the user, before they have been formatted.
+        #If send is set to 0, the message will not be sent out to other
+        #users, but it will still be posted to the user's chat normally.
+        #Otherwise, send defaults to 1. (The message is sent as normal)
+        return text, send
+
+    def plugin_incoming_msg(self, text, type, name, player):
+        #This is called whenever a message from someone else is received, no matter
+        #what type of message it is.
+        #The text variable is the text of the message. If the type is a regular
+        #message, it is already formatted. Otherwise, it's not.
+        #The type variable is an integer which tells you the type: 1=chat, 2=whisper
+        #3=emote, 4=info, and 5=system.
+        #The name variable is the name of the player who sent you the message.
+        #The player variable contains lots of info about the player sending the
+        #message, including name, ID#, and currently-set role.
+        #Uncomment the following line to see the format for the player variable.
+        #print player
+        return text, type, name
+
+    def post_msg(self, text, myself):
+        #This is called whenever a message from anyone is about to be posted
+        #to chat; it doesn't affect the copy of the message that gets sent to others
+        #Be careful; system and info messages trigger this too.
+        return text
+
+    def refresh_counter(self):
+        #This is called once per second. That's all you need to know.
+        pass