Mercurial > traipse_dev
view orpg/mapper/map.py @ 68:3ea7a54284bb ornery-dev
Traipse Dev 'OpenRPG' {090818-02}
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:
*Stable*
This is the first wave of Code Refinement updates. Includes new material from Core Beta; new debugger material (partially implemented), beginnings of switch to etree, TerminalWriter, and a little more. open_rpg has been renamed to component; functioning now as component.get(), component.add(), component.delete(). This version has known bugs, specifically with the gametree and nodes.
Fixes nodehandlers to bring the dev back to a stable push. Known issue with a nodehandler and it's sub dialogs.
Fixed a mis-spelled import. whoops.
author | sirebral |
---|---|
date | Tue, 18 Aug 2009 07:38:58 -0500 |
parents | c54768cffbd4 |
children | 449a8900f9ac |
line wrap: on
line source
# 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/map.py # Author: OpenRPG # Maintainer: # Version: # $Id: map.py,v 1.73 2007/12/07 20:39:49 digitalxero Exp $ # # Description: # __version__ = "$Id: map.py,v 1.73 2007/12/07 20:39:49 digitalxero Exp $" from map_version import MAP_VERSION from map_msg import * from min_dialogs import * from map_prop_dialog import * from orpg.dirpath import dir_struct import random import os import thread import gc import traceback from miniatures_handler import * from whiteboard_handler import * from background_handler import * from fog_handler import * from images import ImageHandler from grid_handler import * from map_handler import * from orpg.orpgCore import component # Various marker modes for player tools on the map MARKER_MODE_NONE = 0 MARKER_MODE_MEASURE = 1 MARKER_MODE_TARGET = 2 MARKER_MODE_AREA_TARGET = 3 class MapCanvas(wx.ScrolledWindow): def __init__(self, parent, ID, isEditor=0): self.parent = parent self.log = component.get("log") self.log.log("Enter MapCanvas", ORPG_DEBUG) self.settings = component.get("settings") self.session = component.get("session") wx.ScrolledWindow.__init__(self, parent, ID, style=wx.HSCROLL | wx.VSCROLL | wx.FULL_REPAINT_ON_RESIZE | wx.SUNKEN_BORDER ) self.frame = parent self.MAP_MODE = 1 #Mode 1 = MINI, 2 = DRAW, 3 = TAPE MEASURE self.layers = {} self.layers['bg'] = layer_back_ground(self) self.layers['grid'] = grid_layer(self) self.layers['whiteboard'] = whiteboard_layer(self) self.layers['miniatures'] = miniature_layer(self) self.layers['fog'] = fog_layer(self) self.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase_background) self.Bind(wx.EVT_PAINT, self.on_paint) self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down) self.Bind(wx.EVT_LEFT_DCLICK, self.on_left_dclick) self.Bind(wx.EVT_LEFT_UP, self.on_left_up) self.Bind(wx.EVT_RIGHT_DOWN, self.on_right_down) self.Bind(wx.EVT_MOTION, self.on_motion) self.Bind(wx.EVT_SCROLLWIN, self.on_scroll) self.Bind(wx.EVT_CHAR, self.on_char) self.Bind(wx.EVT_SIZE, self.on_resize) self.set_size((1000,1000)) self.root_dir = os.getcwd() self.size_change = 0 self.isEditor = isEditor self.map_version = MAP_VERSION self.cacheSize = 32 # Create the marker mode attributes for the map self.markerMode = MARKER_MODE_NONE self.markerStart = wx.Point( -1, -1 ) self.markerStop = wx.Point( -1, -1 ) self.markerMidpoint = wx.Point( -1, -1 ) self.markerAngle = 0.0 # Optimization of map refreshing during busy map load self.lastRefreshValue = 0 self.requireRefresh = 0 self.lastRefreshTime = 0 self.zoom_display_timer = wx.Timer(self, wx.NewId()) self.Bind(wx.EVT_TIMER, self.better_refresh, self.zoom_display_timer) random.seed( time.time() ) self.image_timer = wx.Timer(self, wx.NewId()) self.Bind(wx.EVT_TIMER, self.processImages, self.image_timer) self.image_timer.Start(100) # Used to check if we've used the user cache size value self.cacheSizeSet = False self.inside = 0 # miniatures drag self.drag = None self.log.log("Exit MapCanvas", ORPG_DEBUG) def better_refresh(self, event=None): self.log.log("Enter MapCanvas->better_refresh(self)", ORPG_DEBUG) self.Refresh(True) self.log.log("Eexit MapCanvas->better_refresh(self)", ORPG_DEBUG) def pre_destory_cleanup(self): self.log.log("Enter MapCanvas->pre_destory_cleanup(self)", ORPG_DEBUG) self.layers["miniatures"].del_all_miniatures() self.log.log("Exit MapCanvas->pre_destory_cleanup(self)", ORPG_DEBUG) def processImages(self, evt=None): self.log.log("Enter MapCanvas->processImages(self)", ORPG_DEBUG) 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) cidx = self.parent.get_tab_index("Grid") self.parent.layer_tabs.EnableTab(cidx, False) cidx = self.parent.get_tab_index("Miniatures") self.parent.layer_tabs.EnableTab(cidx, False) cidx = self.parent.get_tab_index("Whiteboard") self.parent.layer_tabs.EnableTab(cidx, False) cidx = self.parent.get_tab_index("Fog") self.parent.layer_tabs.EnableTab(cidx, False) cidx = self.parent.get_tab_index("General") self.parent.layer_tabs.EnableTab(cidx, False) else: cidx = self.parent.get_tab_index("Background") if not self.parent.layer_tabs.GetEnabled(cidx): cidx = self.parent.get_tab_index("Miniatures") self.parent.layer_tabs.EnableTab(cidx, True) cidx = self.parent.get_tab_index("Whiteboard") self.parent.layer_tabs.EnableTab(cidx, True) cidx = self.parent.get_tab_index("Background") self.parent.layer_tabs.EnableTab(cidx, False) cidx = self.parent.get_tab_index("Grid") self.parent.layer_tabs.EnableTab(cidx, False) cidx = self.parent.get_tab_index("Fog") self.parent.layer_tabs.EnableTab(cidx, False) cidx = self.parent.get_tab_index("General") self.parent.layer_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) cidx = self.parent.get_tab_index("Grid") self.parent.layer_tabs.EnableTab(cidx, True) cidx = self.parent.get_tab_index("Fog") self.parent.layer_tabs.EnableTab(cidx, True) cidx = self.parent.get_tab_index("General") self.parent.layer_tabs.EnableTab(cidx, True) if not self.cacheSizeSet: self.cacheSizeSet = True cacheSize = self.settings.get_setting("ImageCacheSize") if len(cacheSize): self.cacheSize = int(cacheSize) else: self.log.log("Default cache size being used.", ORPG_GENERAL) self.log.log("Current image cache size is set at " + str(self.cacheSize) + " images, using random purge.", ORPG_GENERAL) 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.layers['miniatures'].get_miniature_by_id(imageId) min.set_bmp(img) elif image_type == "background" or image_type == "texture": self.layers['bg'].bg_bmp = img if image_type == "background": self.set_size([img.GetWidth(), img.GetHeight()]) 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: ImageHandler.cleanCache() else: # Now, make sure not only that we require a refresh, but that enough time has # gone by since our last refresh. This keeps back to back refreshing occuring during # large map loads. Of course, we are now trying to pack as many image refreshes as # we can into a single cycle. if self.requireRefresh and (self.requireRefresh == self.lastRefreshValue): if (self.lastRefreshTime) < time.time(): self.requireRefresh = 0 self.lastRefreshValue = 0 self.lastRefreshTime = time.time() self.Refresh(True) else: self.lastRefreshValue = self.requireRefresh self.log.log("Exit MapCanvas->processImages(self)", ORPG_DEBUG) def on_scroll(self, evt): self.log.log("Enter MapCanvas->on_scroll(self, evt)", ORPG_DEBUG) if self.drag: self.drag.Hide() if self.settings.get_setting("AlwaysShowMapScale") == "1": self.printscale() evt.Skip() self.log.log("Exit MapCanvas->on_scroll(self, evt)", ORPG_DEBUG) def on_char(self, evt): self.log.log("Enter MapCanvas->on_char(self, evt)", ORPG_DEBUG) if self.settings.get_setting("AlwaysShowMapScale") == "1": self.printscale() evt.Skip() self.log.log("Exit MapCanvas->on_char(self, evt)", ORPG_DEBUG) def printscale(self): self.log.log("Enter MapCanvas->printscale(self)", ORPG_DEBUG) wx.BeginBusyCursor() dc = wx.ClientDC(self) self.PrepareDC(dc) self.showmapscale(dc) self.Refresh(True) wx.EndBusyCursor() self.log.log("Exit MapCanvas->printscale(self)", ORPG_DEBUG) def send_map_data(self, action="update"): self.log.log("Enter MapCanvas->send_map_data(self, " + action +")", ORPG_DEBUG) wx.BeginBusyCursor() send_text = self.toxml(action) if send_text: if not self.isEditor: self.frame.session.send(send_text) wx.EndBusyCursor() self.log.log("Exit MapCanvas->send_map_data(self, " + action +")", ORPG_DEBUG) def get_size(self): self.log.log("Enter MapCanvas->get_size(self)", ORPG_DEBUG) self.log.log("Exit MapCanvas->get_size(self) return " + str(self.size), ORPG_DEBUG) return self.size def set_size(self, size): self.log.log("Enter MapCanvas->set_size(self, size)", ORPG_DEBUG) if size[0] < 300: size = (300, size[1]) if size[1] < 300: size = (size[0], 300) self.size_changed = 1 self.size = size self.fix_scroll() self.layers['fog'].resize(size) self.log.log("Exit MapCanvas->set_size(self, size)", ORPG_DEBUG) def fix_scroll(self): self.log.log("Enter MapCanvas->fix_scroll(self)", ORPG_DEBUG) scale = self.layers['grid'].mapscale pos = self.GetViewStart() unit = self.GetScrollPixelsPerUnit() pos = [pos[0]*unit[0],pos[1]*unit[1]] size = self.GetClientSize() unit = [10*scale,10*scale] if (unit[0] == 0 or unit[1] == 0): self.log.log("Exit MapCanvas->fix_scroll(self)", ORPG_DEBUG) return pos[0] /= unit[0] pos[1] /= unit[1] mx = [int(self.size[0]*scale/unit[0])+1, int(self.size[1]*scale/unit[1]+1)] self.SetScrollbars(unit[0], unit[1], mx[0], mx[1], pos[0], pos[1]) self.log.log("Exit MapCanvas->fix_scroll(self)", ORPG_DEBUG) def on_resize(self, evt): self.log.log("Enter MapCanvas->on_resize(self, evt)", ORPG_DEBUG) self.fix_scroll() wx.CallAfter(self.Refresh, True) evt.Skip() self.log.log("Exit MapCanvas->on_resize(self, evt)", ORPG_DEBUG) def on_erase_background(self, evt): self.log.log("Enter MapCanvas->on_erase_background(self, evt)", ORPG_DEBUG) evt.Skip() self.log.log("Exit MapCanvas->on_erase_background(self, evt)", ORPG_DEBUG) def on_paint(self, evt): self.log.log("Enter MapCanvas->on_paint(self, evt)", ORPG_DEBUG) scale = self.layers['grid'].mapscale scrollsize = self.GetScrollPixelsPerUnit() clientsize = self.GetClientSize() topleft1 = self.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.GetBackgroundColour(), wx.SOLID)) dc.DrawRectangle(0,0,clientsize[0]+1,clientsize[1]+1) dc.SetDeviceOrigin(-topleft[0], -topleft[1]) dc.SetUserScale(scale, scale) self.layers['bg'].layerDraw(dc, scale, topleft, clientsize) self.layers['grid'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], [clientsize[0]/scale, clientsize[1]/scale]) self.layers['miniatures'].layerDraw(dc, [topleft[0]/scale, topleft[1]/scale], [clientsize[0]/scale, clientsize[1]/scale]) self.layers['whiteboard'].layerDraw(dc) self.layers['fog'].layerDraw(dc, topleft, clientsize) dc.SetPen(wx.NullPen) dc.SetBrush(wx.NullBrush) dc.SelectObject(wx.NullBitmap) del dc wdc = self.preppaint() wdc.DrawBitmap(bmp, topleft[0], topleft[1]) if self.frame.settings.get_setting("AlwaysShowMapScale") == "1": self.showmapscale(wdc) try: evt.Skip() except: pass self.log.log("Exit MapCanvas->on_paint(self, evt)", ORPG_DEBUG) def preppaint(self): self.log.log("Enter MapCanvas->preppaint(self)", ORPG_DEBUG) dc = wx.PaintDC(self) self.PrepareDC(dc) self.log.log("Exit MapCanvas->preppaint(self)", ORPG_DEBUG) return (dc) def showmapscale(self, dc): self.log.log("Enter MapCanvas->showmapscale(self, dc)", ORPG_DEBUG) scalestring = "Scale x" + `self.layers['grid'].mapscale`[:3] (textWidth, textHeight) = dc.GetTextExtent(scalestring) dc.SetUserScale(1, 1) dc.SetPen(wx.LIGHT_GREY_PEN) dc.SetBrush(wx.LIGHT_GREY_BRUSH) x = dc.DeviceToLogicalX(0) y = dc.DeviceToLogicalY(0) dc.DrawRectangle(x, y, textWidth+2, textHeight+2) dc.SetPen(wx.RED_PEN) dc.DrawText(scalestring, x+1, y+1) dc.SetPen(wx.NullPen) dc.SetBrush(wx.NullBrush) self.log.log("Exit MapCanvas->showmapscale(self, dc)", ORPG_DEBUG) def snapMarker(self, snapPoint): """Based on the position and unit size, figure out where we need to snap to. As is, on a square grid, there are four possible places to snap. On a hex gid, there are 6 or 12 snap points.""" self.log.log("Enter MapCanvas->snapMarker(self, snapPoint)", ORPG_DEBUG) # If snap to grid is disabled, simply return snapPoint unmodified if self.layers['grid'].snap: # This means we need to determine where to snap our line. We will support # snapping to four different snapPoints per square for now. # TODO!!! if self.layers['grid'].mode == GRID_HEXAGON: size = self.layers['grid'].unit_size_y else: size = int(self.layers['grid'].unit_size) # Find the uppper left hand corner of the grid we are to snap to offsetX = (snapPoint.x / size) * size offsetY = (snapPoint.y / size) * size # Calculate the delta value between where we clicked and the square it is near deltaX = snapPoint.x - offsetX deltaY = snapPoint.y - offsetY # Now, figure our what quadrant (x, y) we need to snap to snapSize = size / 2 # Figure out the X snap placement if deltaX <= snapSize: quadXPos = offsetX else: quadXPos = offsetX + size # Now, figure out the Y snap placement if deltaY <= snapSize: quadYPos = offsetY else: quadYPos = offsetY + size # Create our snap snapPoint and return it snapPoint = wx.Point( quadXPos, quadYPos ) self.log.log("Exit MapCanvas->snapMarker(self, snapPoint)", ORPG_DEBUG) return snapPoint # Bunch of math stuff for marking and measuring def calcSlope(self, start, stop): """Calculates the slop of a line and returns it.""" self.log.log("Enter MapCanvas->calcSlope(self, start, stop)", ORPG_DEBUG) if start.x == stop.x: s = 0.0001 else: s = float((stop.y - start.y)) / float((stop.x - start.x)) self.log.log("Exit MapCanvas->calcSlope(self, start, stop)", ORPG_DEBUG) return s def calcSlopeToAngle(self, slope): """Based on the input slope, the angle (in degrees) will be returned.""" self.log.log("Enter MapCanvas->calcSlopeToAngle(self, slope)", ORPG_DEBUG) # See if the slope is neg or positive if slope == abs(slope): # Slope is positive, so make sure it's not zero if slope == 0: a = 0 else: a = 360 - atan(slope) * (180.0/pi) else: a = atan(abs(slope)) * (180.0/pi) self.log.log("Exit MapCanvas->calcSlopeToAngle(self, slope)", ORPG_DEBUG) return a def calcLineAngle(self, start, stop): """Based on two points that are on a line, return the angle of that line.""" self.log.log("Enter MapCanvas->calcLineAngle(self, start, stop)", ORPG_DEBUG) a = self.calcSlopeToAngle( self.calcSlope( start, stop ) ) self.log.log("Exit MapCanvas->calcLineAngle(self, start, stop)", ORPG_DEBUG) return a def calcPixelDistance(self, start, stop): """Calculate the distance between two pixels and returns it. The calculated distance is the Euclidean Distance, which is: d = sqrt( (x2 - x1)**2 + (y2 - y1)**2 )""" self.log.log("Enter MapCanvas->calcPixelDistance(self, start, stop)", ORPG_DEBUG) d = sqrt( abs((stop.x - start.x)**2 - (stop.y - start.y)**2) ) self.log.log("Exit MapCanvas->calcPixelDistance(self, start, stop)", ORPG_DEBUG) return d def calcUnitDistance(self, start, stop, lineAngle): self.log.log("Enter MapCanvas->calcUnitDistance(self, start, stop, lineAngle)", ORPG_DEBUG) distance = self.calcPixelDistance( start, stop ) ln = "%0.2f" % lineAngle if self.layers['grid'].mode == GRID_HEXAGON: if ln == "0.00" or ln == "359.99": ud = distance / self.layers['grid'].unit_size_y else: ud = (sqrt(abs((stop.x - start.x)**2 + (stop.y - start.y)**2))) / self.layers['grid'].unit_size_y else: if ln == "0.00" or ln == "359.99": ud = distance / self.layers['grid'].unit_size else: ud = (sqrt(abs((stop.x - start.x)**2 + (stop.y - start.y)**2))) / self.layers['grid'].unit_size #ud = sqrt( abs((stop.x - start.x)**2 - (stop.y - start.y)**2) ) self.log.log("Exit MapCanvas->calcUnitDistance(self, start, stop, lineAngle)", ORPG_DEBUG) return ud def on_tape_motion(self, evt): """Track mouse motion so we can update the marker visual every time it's moved""" self.log.log("Enter MapCanvas->on_tape_motion(self, evt)", ORPG_DEBUG) # Make sure we have a mode to do anything, otherwise, we ignore this if self.markerMode: # Grap the current DC for all of the marker modes dc = wx.ClientDC( self ) self.PrepareDC( dc ) dc.SetUserScale(self.layers['grid'].mapscale,self.layers['grid'].mapscale) # Grab the current map position pos = self.snapMarker( evt.GetLogicalPosition( dc ) ) # Enable brush optimizations #dc.SetOptimization( True ) # Set up the pen used for drawing our marker dc.SetPen( wx.Pen(wx.RED, 1, wx.LONG_DASH) ) # Now, based on the marker mode, draw the right thing if self.markerMode == MARKER_MODE_MEASURE: if self.markerStop.x != -1 and self.markerStop.y != -1: # Set the DC function that we need dc.SetLogicalFunction(wx.INVERT) # Erase old and Draw new marker line dc.BeginDrawing() dc.DrawLine( self.markerStart.x, self.markerStart.y, self.markerStop.x, self.markerStop.y ) dc.DrawLine( self.markerStart.x, self.markerStart.y, pos.x, pos.y ) dc.EndDrawing() # Restore the default DC function dc.SetLogicalFunction(wx.COPY) # As long as we are in marker mode, we ned to update the stop point self.markerStop = pos dc.SetPen(wx.NullPen) # Disable brush optimizations #dc.SetOptimization( False ) del dc self.log.log("Exit MapCanvas->on_tape_motion(self, evt)", ORPG_DEBUG) def on_tape_down(self, evt): """Greg's experimental tape measure code. Hopefully, when this is done, it will all be modal based on a toolbar.""" self.log.log("Enter MapCanvas->on_tape_down(self, evt)", ORPG_DEBUG) dc = wx.ClientDC( self ) self.PrepareDC( dc ) dc.SetUserScale(self.layers['grid'].mapscale,self.layers['grid'].mapscale) pos = evt.GetLogicalPosition( dc ) # If grid snap is enabled, then snap the tool to a proper position pos = self.snapMarker( evt.GetLogicalPosition( dc ) ) # Maker mode should really be set by a toolbar self.markerMode = MARKER_MODE_MEASURE # Erase the old line if her have one if self.markerStart.x != -1 and self.markerStart.y != -1: # Enable brush optimizations #dc.SetOptimization( True ) # Set up the pen used for drawing our marker dc.SetPen( wx.Pen(wx.RED, 1, wx.LONG_DASH) ) # Set the DC function that we need dc.SetLogicalFunction(wx.INVERT) # Draw the marker line dc.BeginDrawing() dc.DrawLine( self.markerStart.x, self.markerStart.y, self.markerStop.x, self.markerStop.y ) dc.EndDrawing() # Restore the default DC function and pen dc.SetLogicalFunction(wx.COPY) dc.SetPen(wx.NullPen) # Disable brush optimizations #dc.SetOptimization( False ) # Save our current start and reset the stop value self.markerStart = pos self.markerStop = pos del dc self.log.log("Exit MapCanvas->on_tape_down(self, evt)", ORPG_DEBUG) def on_tape_up(self, evt): """When we release the middle button, disable any marking updates that we have been doing.""" self.log.log("Enter MapCanvas->on_tape_up(self, evt)", ORPG_DEBUG) # If we are in measure mode, draw the actual UNIT distance if self.markerMode == MARKER_MODE_MEASURE: dc = wx.ClientDC( self ) self.PrepareDC( dc ) dc.SetUserScale(self.layers['grid'].mapscale,self.layers['grid'].mapscale) # Draw the measured distance on the DC. Since we want # the text to match the line angle, calculate the angle # of the line. lineAngle = self.calcLineAngle( self.markerStart, self.markerStop ) distance = self.calcUnitDistance( self.markerStart, self.markerStop, lineAngle ) midPoint = (self.markerStart + self.markerStop) midPoint.x /= 2 midPoint.y /= 2 # Adjust out font to be bigger & scaled font = dc.GetFont() # Set the DC function that we need dc.SetLogicalFunction(wx.INVERT) # Set the pen we want to use dc.SetPen(wx.BLACK_PEN) # Now, draw the text at the proper angle on the canvas self.markerMidpoint = midPoint self.markerAngle = lineAngle dText = "%0.2f Units" % (distance) dc.BeginDrawing() dc.DrawRotatedText( dText, midPoint.x, midPoint.y, lineAngle ) dc.EndDrawing() # Restore the default font and DC dc.SetFont(wx.NullFont) dc.SetLogicalFunction(wx.COPY) del font del dc self.markerMode = MARKER_MODE_NONE self.log.log("Exit MapCanvas->on_tape_up(self, evt)", ORPG_DEBUG) # MODE 1 = MOVE, MODE 2 = whiteboard, MODE 3 = Tape measure def on_left_down(self, evt): self.log.log("Enter MapCanvas->on_left_down(self, evt)", ORPG_DEBUG) if evt.ShiftDown(): self.on_tape_down (evt) else: self.frame.on_left_down(evt) self.log.log("Exit MapCanvas->on_left_down(self, evt)", ORPG_DEBUG) def on_right_down(self, evt): self.log.log("Enter MapCanvas->on_right_down(self, evt)", ORPG_DEBUG) if evt.ShiftDown(): pass else: self.frame.on_right_down(evt) self.log.log("Exit MapCanvas->on_right_down(self, evt)", ORPG_DEBUG) def on_left_dclick(self, evt): self.log.log("Enter MapCanvas->on_left_dclick(self, evt)", ORPG_DEBUG) if evt.ShiftDown(): pass else: self.frame.on_left_dclick(evt) self.log.log("Exit MapCanvas->on_left_dclick(self, evt)", ORPG_DEBUG) def on_left_up(self, evt): self.log.log("Enter MapCanvas->on_left_up(self, evt)", ORPG_DEBUG) if evt.ShiftDown(): self.on_tape_up(evt) elif component.get("tree").dragging: tree = component.get("tree") if tree.drag_obj.map_aware(): tree.drag_obj.on_send_to_map(evt) tree.dragging = False tree.drag_obj = None else: self.frame.on_left_up(evt) self.log.log("Exit MapCanvas->on_left_up(self, evt)", ORPG_DEBUG) def on_motion(self, evt): self.log.log("Enter MapCanvas->on_motion(self, evt)", ORPG_DEBUG) if evt.ShiftDown(): self.on_tape_motion(evt) elif evt.LeftIsDown() and component.get("tree").dragging: pass else: self.frame.on_motion(evt) self.log.log("Exit MapCanvas->on_motion(self, evt)", ORPG_DEBUG) def on_zoom_out(self, evt): self.log.log("Enter MapCanvas->on_zoom_out(self, evt)", ORPG_DEBUG) if self.layers['grid'].mapscale > 0.2: # attempt to keep same logical point at center of screen scale = self.layers['grid'].mapscale scrollsize = self.GetScrollPixelsPerUnit() clientsize = self.GetClientSize() topleft1 = self.GetViewStart() topleft = [topleft1[0]*scrollsize[0], topleft1[1]*scrollsize[1]] scroll_x = (((topleft[0]+clientsize[0]/2)*(scale-.1)/scale)-clientsize[0]/2)/scrollsize[0] scroll_y = (((topleft[1]+clientsize[1]/2)*(scale-.1)/scale)-clientsize[1]/2)/scrollsize[1] self.Scroll(scroll_x, scroll_y) self.layers['grid'].mapscale -= .1 scalestring = "x" + `self.layers['grid'].mapscale`[:3] self.frame.get_current_layer_handler().zoom_out_button.SetToolTip(wx.ToolTip("Zoom out from " + scalestring) ) self.frame.get_current_layer_handler().zoom_in_button.SetToolTip(wx.ToolTip("Zoom in from " + scalestring) ) self.set_size(self.size) dc = wx.ClientDC(self) dc.BeginDrawing() scalestring = "Scale x" + `self.layers['grid'].mapscale`[:3] (textWidth,textHeight) = dc.GetTextExtent(scalestring) dc.SetPen(wx.LIGHT_GREY_PEN) dc.SetBrush(wx.LIGHT_GREY_BRUSH) dc.DrawRectangle(dc.DeviceToLogicalX(0),dc.DeviceToLogicalY(0),textWidth,textHeight) dc.SetPen(wx.RED_PEN) dc.DrawText(scalestring,dc.DeviceToLogicalX(0),dc.DeviceToLogicalY(0)) dc.SetPen(wx.NullPen) dc.SetBrush(wx.NullBrush) dc.EndDrawing() del dc self.zoom_display_timer.Start(500,1) self.log.log("Exit MapCanvas->on_zoom_out(self, evt)", ORPG_DEBUG) def on_zoom_in(self, evt): self.log.log("Enter MapCanvas->on_zoom_in(self, evt)", ORPG_DEBUG) # attempt to keep same logical point at center of screen scale = self.layers['grid'].mapscale scrollsize = self.GetScrollPixelsPerUnit() clientsize = self.GetClientSize() topleft1 = self.GetViewStart() topleft = [topleft1[0]*scrollsize[0], topleft1[1]*scrollsize[1]] scroll_x = (((topleft[0]+clientsize[0]/2)*(scale+.1)/scale)-clientsize[0]/2)/scrollsize[0] scroll_y = (((topleft[1]+clientsize[1]/2)*(scale+.1)/scale)-clientsize[1]/2)/scrollsize[1] self.Scroll(scroll_x, scroll_y) self.layers['grid'].mapscale += .1 scalestring = "x" + `self.layers['grid'].mapscale`[:3] self.frame.get_current_layer_handler().zoom_out_button.SetToolTip(wx.ToolTip("Zoom out from " + scalestring) ) self.frame.get_current_layer_handler().zoom_in_button.SetToolTip(wx.ToolTip("Zoom in from " + scalestring) ) self.set_size(self.size) dc = wx.ClientDC(self) dc.BeginDrawing() scalestring = "Scale x" + `self.layers['grid'].mapscale`[:3] (textWidth,textHeight) = dc.GetTextExtent(scalestring) dc.SetPen(wx.LIGHT_GREY_PEN) dc.SetBrush(wx.LIGHT_GREY_BRUSH) dc.DrawRectangle(dc.DeviceToLogicalX(0), dc.DeviceToLogicalY(0), textWidth,textHeight) dc.SetPen(wx.RED_PEN) dc.DrawText(scalestring, dc.DeviceToLogicalX(0), dc.DeviceToLogicalY(0)) dc.SetPen(wx.NullPen) dc.SetBrush(wx.NullBrush) dc.EndDrawing() del dc self.zoom_display_timer.Start(500, 1) self.log.log("Exit MapCanvas->on_zoom_in(self, evt)", ORPG_DEBUG) def on_prop(self, evt): self.log.log("Enter MapCanvas->on_prop(self, evt)", ORPG_DEBUG) self.session = component.get("session") self.chat = component.get("chat") if (self.session.my_role() != self.session.ROLE_GM): self.chat.InfoPost("You must be a GM to use this feature") self.log.log("Exit MapCanvas->on_prop(self, evt)", ORPG_DEBUG) return dlg = general_map_prop_dialog(self.frame.GetParent(),self.size,self.layers['bg'],self.layers['grid']) if dlg.ShowModal() == wx.ID_OK: self.set_size(dlg.size) self.send_map_data() self.Refresh(False) dlg.Destroy() os.chdir(self.root_dir) self.log.log("Exit MapCanvas->on_prop(self, evt)", ORPG_DEBUG) def add_miniature(self, min_url, min_label='', min_unique=-1): self.log.log("Enter MapCanvas->add_miniature(self, min_url, min_label, min_unique)", ORPG_DEBUG) if min_unique == -1: min_unique = not self.use_serial if min_url == "" or min_url == "http://": return if min_url[:7] != "http://" : min_url = "http://" + min_url # make label wx.BeginBusyCursor() if self.auto_label: if min_label == '': min_label = self.get_label_from_url( min_url ) if not min_unique and self.use_serial: min_label = '%s %d' % ( min_label, self.layers['miniatures'].next_serial() ) else: min_label = "" if self.frame.min_url.FindString(min_url) == -1: self.frame.min_url.Append(min_url) try: id = 'mini-' + self.frame.session.get_next_id() self.layers['miniatures'].add_miniature(id, min_url, label=min_label) except Exception, e: self.log.log(traceback.format_exc(), ORPG_GENERAL) self.log.log("Unable to load/resolve URL: " + min_url + " on resource ' + min_label + ' !!!", ORPG_GENERAL) self.layers['miniatures'].rollback_serial() wx.EndBusyCursor() self.send_map_data() self.Refresh(False) self.log.log("Exit MapCanvas->add_miniature(self, min_url, min_label, min_unique)", ORPG_DEBUG) def get_label_from_url(self, url=''): self.log.log("Enter MapCanvas->get_label_from_url(self, url)", ORPG_DEBUG) if url == '': self.log.log("Exit MapCanvas->get_label_from_url(self, url)", ORPG_DEBUG) return '' start = url.rfind("/")+1 label = url[start:len(url)-4] self.log.log("Exit MapCanvas->get_label_from_url(self, url)", ORPG_DEBUG) return label def toxml(self, action="update"): self.log.log("Enter MapCanvas->toxml(self, " + action + ")", ORPG_DEBUG) if action == "new": self.size_changed = 1 xml_str = "<map version='" + self.map_version + "'" changed = self.size_changed if self.size_changed: xml_str += " sizex='" + str(self.size[0]) + "'" xml_str += " sizey='" + str(self.size[1]) + "'" s = "" keys = self.layers.keys() for k in keys: if (k != "fog" or action != "update"): s += self.layers[k].layerToXML(action) self.size_changed = 0 if s: self.log.log("Exit MapCanvas->toxml(self, " + action + ")", ORPG_DEBUG) return xml_str + " action='" + action + "'>" + s + "</map>" else: if changed: self.log.log("Exit MapCanvas->toxml(self, " + action + ")", ORPG_DEBUG) return xml_str + " action='" + action + "'/>" else: self.log.log("Exit MapCanvas->toxml(self, " + action + ")", ORPG_DEBUG) return "" def takexml(self, xml): # # Added Process Dialog to display during long map parsings # as well as a try block with an exception traceback to try # and isolate some of the map related problems users have been # experiencing --Snowdog 5/15/03 # # Apparently Process Dialog causes problems with linux.. commenting it out. sheez. # --Snowdog 5/27/03 self.log.log("Enter MapCanvas->takexml(self, xml)", ORPG_DEBUG) try: #parse the map DOM xml_dom = parseXml(xml) if xml_dom == None: self.log.log("xml_dom == None\n" + xml, ORPG_INFO) self.log.log("Exit MapCanvas->takexml(self, xml)", ORPG_DEBUG) return node_list = xml_dom.getElementsByTagName("map") if len(node_list) < 1: self.log.log("Invalid XML format for mapper", ORPG_INFO) else: # set map version to incoming data so layers can convert self.map_version = node_list[0].getAttribute("version") action = node_list[0].getAttribute("action") if action == "new": self.layers = {} try: self.layers['bg'] = layer_back_ground(self) except: pass try: self.layers['grid'] = grid_layer(self) except: pass try: self.layers['miniatures'] = miniature_layer(self) except: pass try: self.layers['whiteboard'] = whiteboard_layer(self) except: pass try: self.layers['fog'] = fog_layer(self) except: pass sizex = node_list[0].getAttribute("sizex") if sizex != "": sizex = int(float(sizex)) sizey = self.size[1] self.set_size((sizex,sizey)) self.size_changed = 0 sizey = node_list[0].getAttribute("sizey") if sizey != "": sizey = int(float(sizey)) sizex = self.size[0] self.set_size((sizex,sizey)) self.size_changed = 0 children = node_list[0]._get_childNodes() #fog layer must be computed first, so that no data is inadvertently revealed for c in children: name = c._get_nodeName() if name == "fog": self.layers[name].layerTakeDOM(c) for c in children: name = c._get_nodeName() if name != "fog": self.layers[name].layerTakeDOM(c) # all map data should be converted, set map version to current version self.map_version = MAP_VERSION self.Refresh(False) xml_dom.unlink() # eliminate circular refs except: self.log.log(traceback.format_exc(), ORPG_GENERAL) self.log.log("EXCEPTION: Critical Error Loading Map!!!", ORPG_GENERAL) self.log.log("Exit MapCanvas->takexml(self, xml)", ORPG_DEBUG) def re_ids_in_xml(self, xml): self.log.log("Enter MapCanvas->re_ids_in_xml(self, xml)", ORPG_DEBUG) new_xml = "" tmp_map = map_msg() xml_dom = parseXml(str(xml)) node_list = xml_dom.getElementsByTagName("map") if len(node_list) < 1: self.log.log("Invalid XML format for mapper", ORPG_INFO) else: tmp_map.init_from_dom(node_list[0]) if tmp_map.children.has_key("miniatures"): miniatures_layer = tmp_map.children["miniatures"] if miniatures_layer: minis = miniatures_layer.get_children().keys() if minis: for mini in minis: m = miniatures_layer.children[mini] id = 'mini-' + self.frame.session.get_next_id() m.init_prop("id", id) # This allows for backward compatibility with older maps which do not # have a whiteboard node. As such, if it's not there, we'll just happily # move on and process as always. if tmp_map.children.has_key("whiteboard"): whiteboard_layer = tmp_map.children["whiteboard"] if whiteboard_layer: lines = whiteboard_layer.get_children().keys() if lines: for line in lines: l = whiteboard_layer.children[line] if l.tagname == 'line': id = 'line-' + self.frame.session.get_next_id() elif l.tagname == 'text': id = 'text-' + self.frame.session.get_next_id() elif l.tagname == 'circle': id = 'circle-' + self.frame.session.get_next_id() l.init_prop("id", id) new_xml = tmp_map.get_all_xml() if xml_dom: xml_dom.unlink() self.log.log("Exit MapCanvas->re_ids_in_xml(self, xml)", ORPG_DEBUG) return str(new_xml) class map_wnd(wx.Panel): def __init__(self, parent, id): self.log = component.get('log') self.log.log("Enter map_wnd", ORPG_DEBUG) wx.Panel.__init__(self, parent, id) self.canvas = MapCanvas(self, -1) self.session = component.get('session') self.settings = component.get('settings') self.chat = component.get('chat') 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.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.EXPAND) self.sizer.Add(self.layer_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() self.log.log("Exit map_wnd", ORPG_DEBUG) def OnLeave(self, evt): if "__WXGTK__" in wx.PlatformInfo: wx.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) def load_default(self): self.log.log("Enter map_wnd->load_default(self)", ORPG_DEBUG) if self.session.is_connected() and (self.session.my_role() != self.session.ROLE_GM) and (self.session.use_roles()): self.chat.InfoPost("You must be a GM to use this feature") self.log.log("Exit map_wnd->load_default(self)", ORPG_DEBUG) return f = open(dir_struct["template"] + "default_map.xml") self.new_data(f.read()) f.close() self.canvas.send_map_data("new") if not self.session.is_connected() and (self.session.my_role() != self.session.ROLE_GM): self.session.update_role("GM") self.log.log("Exit map_wnd->load_default(self)", ORPG_DEBUG) def new_data(self, data): self.log.log("Enter map_wnd->new_data(self, data)", ORPG_DEBUG) self.canvas.takexml(data) self.update_tools() self.log.log("Exit map_wnd->new_data(self, data)", ORPG_DEBUG) def on_save(self,evt): self.log.log("Enter map_wnd->new_data(self, data)", ORPG_DEBUG) if (self.session.my_role() != self.session.ROLE_GM): self.chat.InfoPost("You must be a GM to use this feature") self.log.log("Exit map_wnd->new_data(self, data)", ORPG_DEBUG) return d = wx.FileDialog(self.GetParent(), "Save map data", dir_struct["user"], "", "*.xml", wx.SAVE) if d.ShowModal() == wx.ID_OK: f = open(d.GetPath(), "w") data = '<nodehandler class="min_map" icon="compass" module="core" name="miniature Map">' data += self.canvas.toxml("new") data += "</nodehandler>" data = data.replace(">",">\n") f.write(data) f.close() d.Destroy() os.chdir(self.root_dir) self.log.log("Exit map_wnd->new_data(self, data)", ORPG_DEBUG) def on_open(self, evt): self.log.log("Enter map_wnd->on_open(self, evt)", ORPG_DEBUG) if self.session.is_connected() and (self.session.my_role() != self.session.ROLE_GM) and (self.session.use_roles()): self.chat.InfoPost("You must be a GM to use this feature") self.log.log("Exit map_wnd->on_open(self, evt)", ORPG_DEBUG) return d = wx.FileDialog(self.GetParent(), "Select a file", dir_struct["user"], "", "*.xml", wx.OPEN) if d.ShowModal() == wx.ID_OK: f = open(d.GetPath()) map_string = f.read() new_xml = self.canvas.re_ids_in_xml(map_string) if new_xml: self.canvas.takexml(new_xml) self.canvas.send_map_data("new") self.update_tools() if not self.session.is_connected() and (self.session.my_role() != self.session.ROLE_GM): self.session.update_role("GM") d.Destroy() os.chdir(self.root_dir) self.log.log("Exit map_wnd->on_open(self, evt)", ORPG_DEBUG) def get_current_layer_handler(self): self.log.log("Enter map_wnd->get_current_layer_handler(self)", ORPG_DEBUG) self.log.log("Exit map_wnd->get_current_layer_handler(self)", ORPG_DEBUG) return self.layer_handlers[self.current_layer] def get_tab_index(self, layer): """Return the index of a chatpanel in the wxNotebook.""" self.log.log("Enter map_wnd->get_tab_index(self, layer)", ORPG_DEBUG) for i in xrange(self.layer_tabs.GetPageCount()): if (self.layer_tabs.GetPageText(i) == layer): self.log.log("Exit map_wnd->get_tab_index(self, layer) return " + str(i), ORPG_DEBUG) return i self.log.log("Exit map_wnd->get_tab_index(self, layer) return 0", ORPG_DEBUG) return 0 def on_layer_change(self, evt): self.log.log("Enter map_wnd->on_layer_change(self, evt)", ORPG_DEBUG) 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 if self.current_layer == 0: bg = self.layer_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() self.log.log("Exit map_wnd->on_layer_change(self, evt)", ORPG_DEBUG) def on_left_down(self, evt): self.log.log("Enter map_wnd->on_left_down(self, evt)", ORPG_DEBUG) self.log.log("Exit map_wnd->on_left_down(self, evt)", ORPG_DEBUG) self.layer_handlers[self.current_layer].on_left_down(evt) #double click handler added by Snowdog 5/03 def on_left_dclick(self, evt): self.log.log("Enter map_wnd->on_left_dclick(self, evt)", ORPG_DEBUG) self.log.log("Exit map_wnd->on_left_dclick(self, evt)", ORPG_DEBUG) self.layer_handlers[self.current_layer].on_left_dclick(evt) def on_right_down(self, evt): self.log.log("Enter map_wnd->on_right_down(self, evt)", ORPG_DEBUG) self.log.log("Exit map_wnd->on_right_down(self, evt)", ORPG_DEBUG) self.layer_handlers[self.current_layer].on_right_down(evt) def on_left_up(self, evt): self.log.log("Enter map_wnd->on_left_up(self, evt)", ORPG_DEBUG) self.log.log("Exit map_wnd->on_left_up(self, evt)", ORPG_DEBUG) self.layer_handlers[self.current_layer].on_left_up(evt) def on_motion(self, evt): self.log.log("Enter map_wnd->on_motion(self, evt)", ORPG_DEBUG) self.log.log("Exit map_wnd->on_motion(self, evt)", ORPG_DEBUG) self.layer_handlers[self.current_layer].on_motion(evt) def MapBar(self, id, data): self.log.log("Enter map_wnd->MapBar(self, id, data)", ORPG_DEBUG) self.canvas.MAP_MODE = data if id == 1: self.canvas.MAP_MODE = data self.log.log("Exit map_wnd->MapBar(self, id, data)", ORPG_DEBUG) def set_map_focus(self, evt): self.log.log("Enter map_wnd->set_map_focus(self, evt)", ORPG_DEBUG) self.canvas.SetFocus() self.log.log("Exit map_wnd->set_map_focus(self, evt)", ORPG_DEBUG) def pre_exit_cleanup(self): self.log.log("Enter map_wnd->pre_exit_cleanup(self)", ORPG_DEBUG) # do some pre exit clean up for bitmaps or other objects try: ImageHandler.flushCache() self.canvas.pre_destory_cleanup() except Exception, e: self.log.log(traceback.format_exc(), ORPG_CRITICAL) self.log.log("EXCEPTION: " + str(e), ORPG_CRITICAL) self.log.log("Exit map_wnd->pre_exit_cleanup(self)", ORPG_DEBUG) def update_tools(self): self.log.log("Enter map_wnd->update_tools(self)", ORPG_DEBUG) for h in self.layer_handlers: h.update_info() self.log.log("Exit map_wnd->update_tools(self)", ORPG_DEBUG) def on_hk_map_layer(self, evt): self.log.log("Enter map_wnd->on_hk_map_layer(self, evt)", ORPG_DEBUG) id = self.top_frame.mainmenu.GetHelpString(evt.GetId()) #print evt.GetMenu().GetTitle() if id == "Background Layer": self.current_layer = self.get_tab_index("Background") if id == "Grid Layer": self.current_layer = self.get_tab_index("Grid") if id == "Miniature Layer": self.current_layer = self.get_tab_index("Miniatures") 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.log.log("Exit map_wnd->on_hk_map_layer(self, evt)", ORPG_DEBUG) def on_flush_cache(self, evt): self.log.log("Enter map_wnd->on_flush_cache(self, evt)", ORPG_DEBUG) ImageHandler.flushCache() self.log.log("Exit map_wnd->on_flush_cache(self, evt)", ORPG_DEBUG) def build_menu(self): self.log.log("Enter map_wnd->build_menu(self)", ORPG_DEBUG) # temp menu menu = wx.Menu() item = wx.MenuItem(menu, wx.ID_ANY, "&Load Map", "Load Map") self.top_frame.Bind(wx.EVT_MENU, self.on_open, item) menu.AppendItem(item) item = wx.MenuItem(menu, wx.ID_ANY, "&Save Map", "Save Map") self.top_frame.Bind(wx.EVT_MENU, self.on_save, item) menu.AppendItem(item) menu.AppendSeparator() item = wx.MenuItem(menu, wx.ID_ANY, "Background Layer\tCtrl+1", "Background Layer") self.top_frame.Bind(wx.EVT_MENU, self.on_hk_map_layer, item) menu.AppendItem(item) item = wx.MenuItem(menu, wx.ID_ANY, "Grid Layer\tCtrl+2", "Grid Layer") self.top_frame.Bind(wx.EVT_MENU, self.on_hk_map_layer, item) menu.AppendItem(item) item = wx.MenuItem(menu, wx.ID_ANY, "Miniature Layer\tCtrl+3", "Miniature Layer") self.top_frame.Bind(wx.EVT_MENU, self.on_hk_map_layer, item) menu.AppendItem(item) item = wx.MenuItem(menu, wx.ID_ANY, "Whiteboard Layer\tCtrl+4", "Whiteboard Layer") self.top_frame.Bind(wx.EVT_MENU, self.on_hk_map_layer, item) menu.AppendItem(item) item = wx.MenuItem(menu, wx.ID_ANY, "Fog Layer\tCtrl+5", "Fog Layer") self.top_frame.Bind(wx.EVT_MENU, self.on_hk_map_layer, item) menu.AppendItem(item) item = wx.MenuItem(menu, wx.ID_ANY, "General Properties\tCtrl+6", "General Properties") self.top_frame.Bind(wx.EVT_MENU, self.on_hk_map_layer, item) menu.AppendItem(item) menu.AppendSeparator() item = wx.MenuItem(menu, wx.ID_ANY, "&Flush Image Cache\tCtrl+F", "Flush Image Cache") self.top_frame.Bind(wx.EVT_MENU, self.on_flush_cache, item) menu.AppendItem(item) menu.AppendSeparator() item = wx.MenuItem(menu, wx.ID_ANY, "&Properties", "Properties") self.top_frame.Bind(wx.EVT_MENU, self.canvas.on_prop, item) menu.AppendItem(item) self.top_frame.mainmenu.Insert(2, menu, '&Map') self.log.log("Exit map_wnd->build_menu(self)", ORPG_DEBUG) def get_hot_keys(self): self.log.log("Enter map_wnd->get_hot_keys(self)", ORPG_DEBUG) self.build_menu() self.log.log("Exit map_wnd->get_hot_keys(self)", ORPG_DEBUG) return []