Mercurial > traipse_dev
comparison plugins/bcg/token_handler.py @ 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 | |
children |
comparison
equal
deleted
inserted
replaced
104:15e32ec131cb | 105:2f2bebe9c77f |
---|---|
1 # Copyright (C) 2000-2001 The OpenRPG Project | |
2 # | |
3 # openrpg-dev@lists.sourceforge.net | |
4 # | |
5 # This program is free software; you can redistribute it and/or modify | |
6 # it under the terms of the GNU General Public License as published by | |
7 # the Free Software Foundation; either version 2 of the License, or | |
8 # (at your option) any later version. | |
9 # | |
10 # This program is distributed in the hope that it will be useful, | |
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 # GNU General Public License for more details. | |
14 # | |
15 # You should have received a copy of the GNU General Public License | |
16 # along with this program; if not, write to the Free Software | |
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 # -- | |
19 # | |
20 # File: mapper/whiteboard_hander.py | |
21 # Author: OpenRPG Team | |
22 # Maintainer: | |
23 # Version: | |
24 # $Id: token_handler.py,v 1.43 2007/12/07 20:39:50 digitalxero Exp $ | |
25 # | |
26 # Description: Token layer handler; derived from token Layer handler | |
27 # | |
28 __version__ = "$Id: token_handler.py,v 1.43 2007/12/07 20:39:50 madmathlabs Exp $" | |
29 | |
30 from orpg.mapper.base_handler import * | |
31 from tok_dialogs import * | |
32 import thread | |
33 import time | |
34 import mimetypes | |
35 import urllib | |
36 import xml.dom.minidom as minidom | |
37 import wx | |
38 | |
39 ## rewrite Grid | |
40 from orpg.mapper.grid import GRID_RECTANGLE | |
41 from orpg.mapper.grid import GRID_HEXAGON | |
42 from orpg.mapper.grid import GRID_ISOMETRIC | |
43 import os | |
44 | |
45 from orpg.tools.orpg_settings import settings | |
46 | |
47 ## Jesus H! No Face, rotate! | |
48 TOK_ROT_LEFT = wx.NewId() | |
49 ROT_LEFT_45 = wx.NewId() | |
50 LABEL_TOOL = wx.NewId() | |
51 LAYER_TOOL = wx.NewId() | |
52 TOK_LIST_TOOL = wx.NewId() | |
53 TOK_TOOL = wx.NewId() | |
54 TOK_URL = wx.NewId() | |
55 SERIAL_TOOL = wx.NewId() | |
56 TOK_MOVE = wx.NewId() | |
57 TOK_REMOVE = wx.NewId() | |
58 TOK_PROP_DLG = wx.NewId() | |
59 TOK_FACING_NONE = wx.NewId() | |
60 TOK_FACING_MATCH = wx.NewId() | |
61 TOK_FACING_EAST = wx.NewId() | |
62 TOK_FACING_WEST = wx.NewId() | |
63 TOK_FACING_NORTH = wx.NewId() | |
64 TOK_FACING_SOUTH = wx.NewId() | |
65 TOK_FACING_NORTHEAST = wx.NewId() | |
66 TOK_FACING_SOUTHEAST = wx.NewId() | |
67 TOK_FACING_SOUTHWEST = wx.NewId() | |
68 TOK_FACING_NORTHWEST = wx.NewId() | |
69 TOK_HEADING_NONE = wx.NewId() | |
70 TOK_HEADING_MATCH = wx.NewId() | |
71 TOK_HEADING_EAST = wx.NewId() | |
72 TOK_HEADING_WEST = wx.NewId() | |
73 TOK_HEADING_NORTH = wx.NewId() | |
74 TOK_HEADING_SOUTH = wx.NewId() | |
75 TOK_HEADING_NORTHEAST = wx.NewId() | |
76 TOK_HEADING_SOUTHEAST = wx.NewId() | |
77 TOK_HEADING_SOUTHWEST = wx.NewId() | |
78 TOK_HEADING_NORTHWEST = wx.NewId() | |
79 TOK_HEADING_SUBMENU = wx.NewId() | |
80 TOK_FACING_SUBMENU = wx.NewId() | |
81 TOK_ALIGN_SUBMENU = wx.NewId() | |
82 TOK_ALIGN_GRID_CENTER = wx.NewId() | |
83 TOK_ALIGN_GRID_TL = wx.NewId() | |
84 TOK_TITLE_HACK = wx.NewId() | |
85 TOK_TO_GAMETREE = wx.NewId() | |
86 TOK_BACK_ONE = wx.NewId() | |
87 TOK_FORWARD_ONE = wx.NewId() | |
88 TOK_TO_BACK = wx.NewId() | |
89 TOK_TO_FRONT = wx.NewId() | |
90 TOK_LOCK_BACK = wx.NewId() | |
91 TOK_LOCK_FRONT = wx.NewId() | |
92 TOK_FRONTBACK_UNLOCK = wx.NewId() | |
93 TOK_ZORDER_SUBMENU = wx.NewId() | |
94 TOK_SHOW_HIDE = wx.NewId() | |
95 TOK_LOCK_UNLOCK = wx.NewId() | |
96 MAP_REFRESH_MINI_URLS = wx.NewId() | |
97 | |
98 class myFileDropTarget(wx.FileDropTarget): | |
99 def __init__(self, handler): | |
100 wx.FileDropTarget.__init__(self) | |
101 self.m_handler = handler | |
102 def OnDropFiles(self, x, y, filenames): | |
103 self.m_handler.on_drop_files(x, y, filenames) | |
104 | |
105 class token_handler(base_layer_handler): | |
106 | |
107 def __init__(self, parent, id, canvas): | |
108 self.sel_min = None | |
109 self.auto_label = 1 | |
110 self.use_serial = 1 | |
111 self.auto_label_cb = None | |
112 self.canvas = canvas | |
113 self.settings = settings | |
114 self.mini_rclick_menu_extra_items = {} | |
115 self.background_rclick_menu_extra_items = {} | |
116 base_layer_handler.__init__(self, parent, id, canvas) | |
117 # id is the index of the last good menu choice or 'None' | |
118 # if the last menu was left without making a choice | |
119 # should be -1 at other times to prevent events overlapping | |
120 self.lastMenuChoice = None | |
121 self.drag_mini = None | |
122 self.tooltip_delay_miliseconds = 500 | |
123 self.tooltip_timer = wx.CallLater(self.tooltip_delay_miliseconds, self.on_tooltip_timer) | |
124 self.tooltip_timer.Stop() | |
125 dt = myFileDropTarget(self) | |
126 self.canvas.SetDropTarget(dt) | |
127 #wxInitAllImageHandlers() | |
128 | |
129 def build_ctrls(self): | |
130 base_layer_handler.build_ctrls(self) | |
131 # add controls in reverse order! (unless you want them after the default tools) | |
132 self.auto_label_cb = wx.CheckBox(self, wx.ID_ANY, ' Auto Label ', (-1,-1),(-1,-1)) | |
133 self.auto_label_cb.SetValue(self.auto_label) | |
134 self.min_url = wx.ComboBox(self, wx.ID_ANY, "http://", style=wx.CB_DROPDOWN | wx.CB_SORT) | |
135 self.localBrowse = wx.Button(self, wx.ID_ANY, 'Browse', style=wx.BU_EXACTFIT) | |
136 minilist = createMaskedButton( self, dir_struct["icon"]+'questionhead.gif', 'Edit token properties', wx.ID_ANY) | |
137 miniadd = wx.Button(self, wx.ID_OK, "Add Token", style=wx.BU_EXACTFIT) | |
138 self.sizer.Add(self.auto_label_cb,0,wx.ALIGN_CENTER) | |
139 self.sizer.Add((6, 0)) | |
140 self.sizer.Add(self.min_url, 1, wx.ALIGN_CENTER) | |
141 self.sizer.Add((6, 0)) | |
142 self.sizer.Add(miniadd, 0, wx.ALIGN_CENTER) | |
143 self.sizer.Add((6, 0)) | |
144 self.sizer.Add(self.localBrowse, 0, wx.ALIGN_CENTER) | |
145 self.sizer.Add((6, 0)) | |
146 self.sizer.Add(minilist, 0, wx.ALIGN_CENTER) | |
147 self.Bind(wx.EVT_BUTTON, self.on_min_list, minilist) | |
148 self.Bind(wx.EVT_BUTTON, self.on_token, miniadd) | |
149 self.Bind(wx.EVT_BUTTON, self.on_browse, self.localBrowse) | |
150 self.Bind(wx.EVT_CHECKBOX, self.on_label, self.auto_label_cb) | |
151 | |
152 def on_browse(self, evt): | |
153 if not self.role_is_gm_or_player(): return | |
154 dlg = wx.FileDialog(None, "Select a Token to load", dir_struct["user"]+'webfiles/', | |
155 wildcard="Image files (*.bmp, *.gif, *.jpg, *.png)|*.bmp;*.gif;*.jpg;*.png", style=wx.OPEN) | |
156 if not dlg.ShowModal() == wx.ID_OK: | |
157 dlg.Destroy() | |
158 return | |
159 file = open(dlg.GetPath(), "rb") | |
160 imgdata = file.read() | |
161 file.close() | |
162 filename = dlg.GetFilename() | |
163 (imgtype,j) = mimetypes.guess_type(filename) | |
164 postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype}) | |
165 | |
166 ## Removal of Remote Server? | |
167 if self.settings.get_setting('LocalorRemote') == 'Remote': | |
168 # make the new mini appear in top left of current viewable map | |
169 dc = wx.ClientDC(self.canvas) | |
170 self.canvas.PrepareDC(dc) | |
171 dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale) | |
172 x = dc.DeviceToLogicalX(0) | |
173 y = dc.DeviceToLogicalY(0) | |
174 thread.start_new_thread(self.canvas.layers['token'].upload, | |
175 (postdata, dlg.GetPath()), {'pos':cmpPoint(x,y)}) | |
176 else: | |
177 try: min_url = component.get("cherrypy") + filename | |
178 except: return #chat.InfoPost('CherryPy is not started!') | |
179 min_url = dlg.GetDirectory().replace(dir_struct["user"]+'webfiles' + os.sep, | |
180 component.get("cherrypy")) + '/' + filename | |
181 # build url | |
182 if min_url == "" or min_url == "http://": return | |
183 if min_url[:7] != "http://": min_url = "http://" + min_url | |
184 # make label | |
185 if self.auto_label and min_url[-4:-3] == '.': | |
186 start = min_url.rfind("/") + 1 | |
187 min_label = min_url[start:len(min_url)-4] | |
188 if self.use_serial: min_label = '%s %d' % ( min_label, self.canvas.layers['token'].next_serial() ) | |
189 else: min_label = "" | |
190 if self.min_url.FindString(min_url) == -1: self.min_url.Append(min_url) | |
191 try: | |
192 id = 'mini-' + self.canvas.frame.session.get_next_id() | |
193 # make the new mini appear in top left of current viewable map | |
194 dc = wx.ClientDC(self.canvas) | |
195 self.canvas.PrepareDC(dc) | |
196 dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale) | |
197 x = dc.DeviceToLogicalX(0) | |
198 y = dc.DeviceToLogicalY(0) | |
199 self.canvas.layers['token'].add_token(id, min_url, pos=cmpPoint(x,y), label=min_label) | |
200 except: | |
201 # When there is an exception here, we should be decrementing the serial_number for reuse!! | |
202 unablemsg= "Unable to load/resolve URL: " + min_url + " on resource \"" + min_label + "\"!!!\n\n" | |
203 dlg = wx.MessageDialog(self,unablemsg, 'Url not found',wx.ICON_EXCLAMATION) | |
204 dlg.ShowModal() | |
205 dlg.Destroy() | |
206 self.canvas.layers['token'].rollback_serial() | |
207 self.canvas.send_map_data() | |
208 self.canvas.Refresh(False) | |
209 | |
210 | |
211 def build_menu(self,label = "Token"): | |
212 ## Menu Changes: Rotate | |
213 ## Menu into Component | |
214 ## Remove To GameTree option | |
215 base_layer_handler.build_menu(self,label) | |
216 self.main_menu.AppendSeparator() | |
217 self.main_menu.Append(LABEL_TOOL,"&Auto label","",1) | |
218 self.main_menu.Check(LABEL_TOOL,self.auto_label) | |
219 self.main_menu.Append(SERIAL_TOOL,"&Number minis","",1) | |
220 self.main_menu.Check(SERIAL_TOOL, self.use_serial) | |
221 self.main_menu.Append(MAP_REFRESH_MINI_URLS,"&Refresh tokens") # Add the menu item | |
222 self.main_menu.AppendSeparator() | |
223 self.main_menu.Append(TOK_MOVE, "Move") | |
224 self.canvas.Bind(wx.EVT_MENU, self.on_map_board_menu_item, id=MAP_REFRESH_MINI_URLS) # Set the handler | |
225 self.canvas.Bind(wx.EVT_MENU, self.on_label, id=LABEL_TOOL) | |
226 self.canvas.Bind(wx.EVT_MENU, self.on_serial, id=SERIAL_TOOL) | |
227 # build token menu | |
228 self.min_menu = wx.Menu() | |
229 # Rectangles and hexagons require slightly different menus because of | |
230 # facing and heading possibilities. | |
231 | |
232 rot_left = wx.Menu() | |
233 rot_left_45 = rot_left.Append(-1, '45*') | |
234 self.canvas.Bind(wx.EVT_MENU, self.rot_left_45, rot_left_45) | |
235 rot_right = wx.Menu() | |
236 | |
237 rot_right_45 = rot_right.Append(-1, '45*') | |
238 self.canvas.Bind(wx.EVT_MENU, self.rot_right_45, rot_right_45) | |
239 ## Replace with Rotate. Left - Right, 45 - 90 degress. | |
240 """ | |
241 face_menu = wx.Menu() | |
242 face_menu.Append(TOK_FACING_NONE,"&None") | |
243 face_menu.Append(TOK_FACING_NORTH,"&North") | |
244 face_menu.Append(TOK_FACING_NORTHEAST,"Northeast") | |
245 face_menu.Append(TOK_FACING_EAST,"East") | |
246 face_menu.Append(TOK_FACING_SOUTHEAST,"Southeast") | |
247 face_menu.Append(TOK_FACING_SOUTH,"&South") | |
248 face_menu.Append(TOK_FACING_SOUTHWEST,"Southwest") | |
249 face_menu.Append(TOK_FACING_WEST,"West") | |
250 face_menu.Append(TOK_FACING_NORTHWEST,"Northwest") | |
251 """ | |
252 ### | |
253 | |
254 heading_menu = wx.Menu() | |
255 heading_menu.Append(TOK_HEADING_NONE,"&None") | |
256 heading_menu.Append(TOK_HEADING_NORTH,"&North") | |
257 heading_menu.Append(TOK_HEADING_NORTHEAST,"Northeast") | |
258 heading_menu.Append(TOK_HEADING_EAST,"East") | |
259 heading_menu.Append(TOK_HEADING_SOUTHEAST,"Southeast") | |
260 heading_menu.Append(TOK_HEADING_SOUTH,"&South") | |
261 heading_menu.Append(TOK_HEADING_SOUTHWEST,"Southwest") | |
262 heading_menu.Append(TOK_HEADING_WEST,"West") | |
263 heading_menu.Append(TOK_HEADING_NORTHWEST,"Northwest") | |
264 | |
265 align_menu = wx.Menu() | |
266 align_menu.Append(TOK_ALIGN_GRID_CENTER,"&Center") | |
267 align_menu.Append(TOK_ALIGN_GRID_TL,"&Top-Left") | |
268 # This is a hack to simulate a menu title, due to problem in Linux | |
269 if wx.Platform == '__WXMSW__': self.min_menu.SetTitle(label) | |
270 else: | |
271 self.min_menu.Append(TOK_TITLE_HACK,label) | |
272 self.min_menu.AppendSeparator() | |
273 self.min_menu.Append(TOK_SHOW_HIDE,"Show / Hide") | |
274 self.min_menu.Append(TOK_LOCK_UNLOCK, "Lock / Unlock") | |
275 self.min_menu.Append(TOK_REMOVE,"&Remove") | |
276 | |
277 ##Remove | |
278 #self.min_menu.Append(TOK_TO_GAMETREE,"To &Gametree") | |
279 ### | |
280 | |
281 self.min_menu.AppendMenu(TOK_HEADING_SUBMENU,"Set &Heading",heading_menu) | |
282 | |
283 ##Remove | |
284 self.min_menu.AppendMenu(TOK_ROT_LEFT,"&Rotate Left",rot_left) | |
285 self.min_menu.AppendMenu(wx.ID_ANY,"&Rotate Right",rot_right) | |
286 ### | |
287 | |
288 self.min_menu.AppendMenu(TOK_ALIGN_SUBMENU,"Snap-to &Alignment",align_menu) | |
289 self.min_menu.AppendSeparator() | |
290 zorder_menu = wx.Menu() | |
291 zorder_menu.Append(TOK_BACK_ONE,"Back one") | |
292 zorder_menu.Append(TOK_FORWARD_ONE,"Forward one") | |
293 zorder_menu.Append(TOK_TO_BACK,"To back") | |
294 zorder_menu.Append(TOK_TO_FRONT,"To front") | |
295 zorder_menu.AppendSeparator() | |
296 zorder_menu.Append(TOK_LOCK_BACK,"Lock to back") | |
297 zorder_menu.Append(TOK_LOCK_FRONT,"Lock to front") | |
298 zorder_menu.Append(TOK_FRONTBACK_UNLOCK,"Unlock Front/Back") | |
299 self.min_menu.AppendMenu(TOK_ZORDER_SUBMENU, "Token Z-Order",zorder_menu) | |
300 #self.min_menu.Append(TOK_LOCK,"&Lock") | |
301 self.min_menu.AppendSeparator() | |
302 self.min_menu.Append(TOK_PROP_DLG,"&Properties") | |
303 | |
304 | |
305 #self.min_menu.AppendSeparator() | |
306 #self.min_menu.Append(TOK_MOVE, "Move") | |
307 | |
308 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_MOVE) | |
309 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_SHOW_HIDE) | |
310 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_UNLOCK) | |
311 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_REMOVE) | |
312 | |
313 ##Remove | |
314 #self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_GAMETREE) | |
315 ### | |
316 | |
317 #self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK) | |
318 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_PROP_DLG) | |
319 | |
320 ##Remove | |
321 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NONE) | |
322 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_EAST) | |
323 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_WEST) | |
324 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTH) | |
325 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTH) | |
326 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTHEAST) | |
327 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTHEAST) | |
328 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_SOUTHWEST) | |
329 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FACING_NORTHWEST) | |
330 ### | |
331 | |
332 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NONE) | |
333 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_EAST) | |
334 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_WEST) | |
335 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTH) | |
336 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTH) | |
337 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTHEAST) | |
338 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTHEAST) | |
339 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_SOUTHWEST) | |
340 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_HEADING_NORTHWEST) | |
341 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_ALIGN_GRID_CENTER) | |
342 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_ALIGN_GRID_TL) | |
343 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_BACK_ONE) | |
344 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FORWARD_ONE) | |
345 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_BACK) | |
346 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_TO_FRONT) | |
347 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_BACK) | |
348 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_LOCK_FRONT) | |
349 self.canvas.Bind(wx.EVT_MENU, self.on_min_menu_item, id=TOK_FRONTBACK_UNLOCK) | |
350 ######### add plugin added menu items ######### | |
351 if len(self.mini_rclick_menu_extra_items)>0: | |
352 self.min_menu.AppendSeparator() | |
353 for item in self.mini_rclick_menu_extra_items.items(): self.min_menu.Append(item[1], item[0]) | |
354 if len(self.background_rclick_menu_extra_items)>0: | |
355 self.main_menu.AppendSeparator() | |
356 for item in self.background_rclick_menu_extra_items.items(): | |
357 self.main_menu.Append(item[1], item[0]) | |
358 | |
359 def do_min_menu(self,pos): | |
360 self.canvas.PopupMenu(self.min_menu,pos) | |
361 | |
362 def rot_left_45(self, evt): | |
363 #self.sel_rmin.rotate += 0.785 | |
364 self.sel_rmin.rotate += 1.046 | |
365 #component.get('drawn')[self.sel_rmin] = False | |
366 | |
367 def rot_right_45(self, evt): | |
368 #self.sel_rmin.rotate -= 0.785 | |
369 self.sel_rmin.rotate -= 1.046 | |
370 | |
371 def do_min_select_menu(self, min_list, pos): | |
372 # to prevent another event being processed | |
373 self.lastMenuChoice = None | |
374 self.min_select_menu = wx.Menu() | |
375 self.min_select_menu.SetTitle("Select Token") | |
376 loop_count = 1 | |
377 try: | |
378 for m in min_list: | |
379 # Either use the token label for the selection list | |
380 if m.label: self.min_select_menu.Append(loop_count, m.label) | |
381 # Or use part of the images filename as an identifier | |
382 else: | |
383 string_split = string.split(m.path,"/",) | |
384 last_string = string_split[len(string_split)-1] | |
385 self.min_select_menu.Append(loop_count, 'Unlabeled - ' + last_string[:len(last_string)-4]) | |
386 self.canvas.Bind(wx.EVT_MENU, self.min_selected, id=loop_count) | |
387 loop_count += 1 | |
388 self.canvas.PopupMenu(self.min_select_menu,pos) | |
389 except: pass | |
390 | |
391 def min_selected(self,evt): | |
392 # this is the callback function for the menu that is used to choose | |
393 # between minis when you right click, left click or left double click | |
394 # on a stack of two or more | |
395 self.canvas.Refresh(False) | |
396 self.canvas.send_map_data() | |
397 self.lastMenuChoice = evt.GetId()-1 | |
398 | |
399 def on_min_menu_item(self,evt): | |
400 id = evt.GetId() | |
401 if id == TOK_MOVE: | |
402 if self.sel_min: | |
403 self.moveSelectedMini(self.last_rclick_pos) | |
404 self.deselectAndRefresh() | |
405 return | |
406 elif id == TOK_REMOVE: self.canvas.layers['token'].del_token(self.sel_rmin) | |
407 | |
408 ##Remove | |
409 elif id == TOK_TO_GAMETREE: | |
410 min_xml = self.sel_rmin.toxml(action="new") | |
411 node_begin = "<nodehandler module='map_token_nodehandler' class='map_token_handler' name='" | |
412 if self.sel_rmin.label: node_begin += self.sel_rmin.label + "'" | |
413 else: node_begin += "Unnamed token'" | |
414 node_begin += ">" | |
415 gametree = component.get('tree') | |
416 node_xml = node_begin + min_xml + '</nodehandler>' | |
417 #print "Sending this XML to insert_xml:" + node_xml | |
418 gametree.insert_xml(str(node_xml)) | |
419 | |
420 elif id == TOK_SHOW_HIDE: | |
421 if self.sel_rmin.hide: self.sel_rmin.hide = 0 | |
422 else: self.sel_rmin.hide = 1 | |
423 elif id == TOK_LOCK_UNLOCK: | |
424 if self.sel_rmin.locked: self.sel_rmin.locked = False | |
425 else: self.sel_rmin.locked = True | |
426 if self.sel_rmin == self.sel_min: | |
427 # when we lock / unlock the selected mini make sure it isn't still selected | |
428 # or it might easily get moved by accident and be hard to move back | |
429 self.sel_min.selected = False | |
430 self.sel_min.isUpdated = True | |
431 self.sel_min = None | |
432 recycle_bin = {TOK_HEADING_NONE: FACE_NONE, TOK_HEADING_NORTH: FACE_NORTH, | |
433 TOK_HEADING_NORTHWEST: FACE_NORTHWEST, TOK_HEADING_NORTHEAST: FACE_NORTHEAST, | |
434 TOK_HEADING_EAST: FACE_EAST, TOK_HEADING_SOUTHEAST: FACE_SOUTHEAST, TOK_HEADING_SOUTHWEST: FACE_SOUTHWEST, | |
435 TOK_HEADING_SOUTH: FACE_SOUTH, TOK_HEADING_WEST: FACE_WEST} | |
436 if recycle_bin.has_key(id): | |
437 self.sel_rmin.heading = recycle_bin[id] | |
438 del recycle_bin | |
439 recycle_bin = {TOK_FACING_NONE: FACE_NONE, TOK_FACING_NORTH: FACE_NORTH, | |
440 TOK_FACING_NORTHWEST: FACE_NORTHWEST, TOK_FACING_NORTHEAST: FACE_NORTHEAST, | |
441 TOK_FACING_EAST: FACE_EAST, TOK_FACING_SOUTHEAST: FACE_SOUTHEAST, TOK_FACING_SOUTHWEST: FACE_SOUTHWEST, | |
442 TOK_FACING_SOUTH: FACE_SOUTH, TOK_FACING_WEST: FACE_WEST} | |
443 if recycle_bin.has_key(id): | |
444 self.sel_rmin.face = recycle_bin[id] | |
445 del recycle_bin | |
446 elif id == TOK_ALIGN_GRID_CENTER: self.sel_rmin.snap_to_align = SNAPTO_ALIGN_CENTER | |
447 elif id == TOK_ALIGN_GRID_TL: self.sel_rmin.snap_to_align = SNAPTO_ALIGN_TL | |
448 elif id == TOK_PROP_DLG: | |
449 old_lock_value = self.sel_rmin.locked | |
450 dlg = min_edit_dialog(self.canvas.frame.GetParent(),self.sel_rmin) | |
451 if dlg.ShowModal() == wx.ID_OK: | |
452 if self.sel_rmin == self.sel_min and self.sel_rmin.locked != old_lock_value: | |
453 # when we lock / unlock the selected mini make sure it isn't still selected | |
454 # or it might easily get moved by accident and be hard to move back | |
455 self.sel_min.selected = False | |
456 self.sel_min.isUpdated = True | |
457 self.sel_min = None | |
458 self.canvas.Refresh(False) | |
459 self.canvas.send_map_data() | |
460 return | |
461 | |
462 elif id == TOK_BACK_ONE: | |
463 # This assumes that we always start out with a z-order | |
464 # that starts at 0 and goes up to the number of | |
465 # minis - 1. If this isn't the case, then execute | |
466 # a self.canvas.layers['token'].collapse_zorder() | |
467 # before getting the oldz to test | |
468 # Save the selected minis current z-order | |
469 oldz = self.sel_rmin.zorder | |
470 # Make sure the mini isn't sticky front or back | |
471 if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT): | |
472 ## print "old z-order = " + str(oldz) | |
473 self.sel_rmin.zorder -= 1 | |
474 # Re-collapse to normalize | |
475 # Note: only one update (with the final values) will be sent | |
476 self.canvas.layers['token'].collapse_zorder() | |
477 | |
478 elif id == TOK_FORWARD_ONE: | |
479 # This assumes that we always start out with a z-order | |
480 # that starts at 0 and goes up to the number of | |
481 # minis - 1. If this isn't the case, then execute | |
482 # a self.canvas.layers['token'].collapse_zorder() | |
483 # before getting the oldz to test | |
484 # Save the selected minis current z-order | |
485 oldz = self.sel_rmin.zorder | |
486 ## print "old z-order = " + str(oldz) | |
487 self.sel_rmin.zorder += 1 | |
488 | |
489 # Re-collapse to normalize | |
490 # Note: only one update (with the final values) will be sent | |
491 self.canvas.layers['token'].collapse_zorder() | |
492 | |
493 elif id == TOK_TO_FRONT: | |
494 # This assumes that we always start out with a z-order | |
495 # that starts at 0 and goes up to the number of | |
496 # minis - 1. If this isn't the case, then execute | |
497 # a self.canvas.layers['token'].collapse_zorder() | |
498 # before getting the oldz to test | |
499 # Save the selected minis current z-order | |
500 oldz = self.sel_rmin.zorder | |
501 | |
502 # Make sure the mini isn't sticky front or back | |
503 if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT): | |
504 ## print "old z-order = " + str(oldz) | |
505 # The new z-order will be one more than the last index | |
506 newz = len(self.canvas.layers['token'].token) | |
507 ## print "new z-order = " + str(newz) | |
508 self.sel_rmin.zorder = newz | |
509 # Re-collapse to normalize | |
510 # Note: only one update (with the final values) will be sent | |
511 self.canvas.layers['token'].collapse_zorder() | |
512 | |
513 elif id == TOK_TO_BACK: | |
514 # This assumes that we always start out with a z-order | |
515 # that starts at 0 and goes up to the number of | |
516 # minis - 1. If this isn't the case, then execute | |
517 # a self.canvas.layers['token'].collapse_zorder() | |
518 # before getting the oldz to test | |
519 # Save the selected minis current z-order | |
520 oldz = self.sel_rmin.zorder | |
521 # Make sure the mini isn't sticky front or back | |
522 if (oldz != TOK_STICKY_BACK) and (oldz != TOK_STICKY_FRONT): | |
523 ## print "old z-order = " + str(oldz) | |
524 | |
525 # Since 0 is the lowest in a normalized order, be one less | |
526 newz = -1 | |
527 ## print "new z-order = " + str(newz) | |
528 self.sel_rmin.zorder = newz | |
529 # Re-collapse to normalize | |
530 # Note: only one update (with the final values) will be sent | |
531 self.canvas.layers['token'].collapse_zorder() | |
532 | |
533 elif id == TOK_FRONTBACK_UNLOCK: | |
534 #print "Unlocked/ unstickified..." | |
535 if self.sel_rmin.zorder == TOK_STICKY_BACK: self.sel_rmin.zorder = TOK_STICKY_BACK + 1 | |
536 elif self.sel_rmin.zorder == TOK_STICKY_FRONT: self.sel_rmin.zorder = TOK_STICKY_FRONT - 1 | |
537 elif id == TOK_LOCK_BACK: self.sel_rmin.zorder = TOK_STICKY_BACK | |
538 elif id == TOK_LOCK_FRONT: self.sel_rmin.zorder = TOK_STICKY_FRONT | |
539 # Pretty much, we always want to refresh when we go through here | |
540 # This helps us remove the redundant self.Refresh() on EVERY menu event | |
541 # that we process above. | |
542 self.sel_rmin.isUpdated = True | |
543 self.canvas.Refresh(False) | |
544 self.canvas.send_map_data() | |
545 | |
546 def on_token(self, evt): | |
547 session = self.canvas.frame.session | |
548 if (session.my_role() != session.ROLE_GM) and (session.my_role() != session.ROLE_PLAYER) and (session.use_roles()): | |
549 self.infoPost("You must be either a player or GM to use the token Layer") | |
550 return | |
551 min_url = self.min_url.GetValue() | |
552 # build url | |
553 if min_url == "" or min_url == "http://": return | |
554 if min_url[:7] != "http://" : min_url = "http://" + min_url | |
555 # make label | |
556 if self.auto_label and min_url[-4:-3] == '.': | |
557 start = min_url.rfind("/") + 1 | |
558 min_label = min_url[start:len(min_url)-4] | |
559 if self.use_serial: | |
560 min_label = '%s %d' % ( min_label, self.canvas.layers['token'].next_serial() ) | |
561 else: min_label = "" | |
562 if self.min_url.FindString(min_url) == -1: self.min_url.Append(min_url) | |
563 try: | |
564 id = 'mini-' + self.canvas.frame.session.get_next_id() | |
565 # make the new mini appear in top left of current viewable map | |
566 dc = wx.ClientDC(self.canvas) | |
567 self.canvas.PrepareDC(dc) | |
568 dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale) | |
569 x = dc.DeviceToLogicalX(0) | |
570 y = dc.DeviceToLogicalY(0) | |
571 self.canvas.layers['token'].add_token(id, min_url, pos=cmpPoint(x,y), label=min_label) | |
572 except: | |
573 # When there is an exception here, we should be decrementing the serial_number for reuse!! | |
574 unablemsg= "Unable to load/resolve URL: " + min_url + " on resource \"" + min_label + "\"!!!\n\n" | |
575 #print unablemsg | |
576 dlg = wx.MessageDialog(self,unablemsg, 'Url not found',wx.ICON_EXCLAMATION) | |
577 dlg.ShowModal() | |
578 dlg.Destroy() | |
579 self.canvas.layers['token'].rollback_serial() | |
580 self.canvas.send_map_data() | |
581 self.canvas.Refresh(False) | |
582 #except Exception, e: | |
583 #wx.MessageBox(str(e),"token Error") | |
584 | |
585 def on_label(self,evt): | |
586 self.auto_label = not self.auto_label | |
587 self.auto_label_cb.SetValue(self.auto_label) | |
588 #self.send_map_data() | |
589 #self.Refresh() | |
590 | |
591 def on_min_list(self,evt): | |
592 session = self.canvas.frame.session | |
593 if (session.my_role() != session.ROLE_GM): | |
594 self.infoPost("You must be a GM to use this feature") | |
595 return | |
596 #d = min_list_panel(self.frame.GetParent(),self.canvas.layers,"token list") | |
597 d = min_list_panel(self.canvas.frame,self.canvas.layers,"token list") | |
598 if d.ShowModal() == wx.ID_OK: d.Destroy() | |
599 self.canvas.Refresh(False) | |
600 | |
601 def on_serial(self, evt): | |
602 self.use_serial = not self.use_serial | |
603 | |
604 def on_map_board_menu_item(self,evt): | |
605 id = evt.GetId() | |
606 if id == MAP_REFRESH_MINI_URLS: # Note: this doesn't change the mini, so no need to update the map | |
607 for mini in self.canvas.layers['token'].tokens: # For all minis | |
608 mini.set_bmp(ImageHandler.load(mini.path, 'token', mini.id)) # Reload their bmp member | |
609 self.canvas.Refresh(False) | |
610 | |
611 #################################################################### | |
612 ## old functions, changed an awful lot | |
613 | |
614 def on_left_down(self, evt): | |
615 if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return | |
616 mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm()) | |
617 if mini: | |
618 deselecting_selected_mini = (mini == self.sel_min) #clicked on the selected mini | |
619 self.deselectAndRefresh() | |
620 self.drag_mini = mini | |
621 if deselecting_selected_mini: return | |
622 self.sel_min = mini | |
623 self.sel_min.selected = True | |
624 self.canvas.Refresh() | |
625 else: | |
626 self.drag_mini = None | |
627 pos = self.getLogicalPosition(evt) | |
628 self.moveSelectedMini(pos) | |
629 self.deselectAndRefresh() | |
630 | |
631 def on_right_down(self, evt): | |
632 if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return | |
633 self.last_rclick_pos = self.getLogicalPosition(evt) | |
634 mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm()) | |
635 if mini: | |
636 self.sel_rmin = mini | |
637 if self.sel_min: self.min_menu.Enable(TOK_MOVE, True) | |
638 else: self.min_menu.Enable(TOK_MOVE, False) | |
639 self.prepare_mini_rclick_menu(evt) | |
640 self.do_min_menu(evt.GetPosition()) | |
641 else:# pass it on | |
642 if self.sel_min: self.main_menu.Enable(TOK_MOVE, True) | |
643 else: self.main_menu.Enable(TOK_MOVE, False) | |
644 self.prepare_background_rclick_menu(evt) | |
645 base_layer_handler.on_right_down(self, evt) | |
646 | |
647 #################################################################### | |
648 ## new functions | |
649 | |
650 def on_drop_files(self, x, y, filepaths): | |
651 # currently we ignore multiple files | |
652 filepath = filepaths[0] | |
653 start1 = filepath.rfind("\\") + 1 # check for both slashes in path to be on the safe side | |
654 start2 = filepath.rfind("/") + 1 | |
655 if start1 < start2: start1 = start2 | |
656 filename = filepath[start1:] | |
657 pos = filename.rfind('.') | |
658 ext = filename[pos:].lower() | |
659 #ext = filename[-4:].lower() | |
660 if(ext != ".bmp" and ext != ".gif" and ext != ".jpg" and ext != ".jpeg" and ext != ".png"): | |
661 self.infoPost("Supported file extensions are: *.bmp, *.gif, *.jpg, *.jpeg, *.png") | |
662 return | |
663 file = open(filepath, "rb") | |
664 imgdata = file.read() | |
665 file.close() | |
666 dc = wx.ClientDC(self.canvas) | |
667 self.canvas.PrepareDC(dc) | |
668 dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale) | |
669 x = dc.DeviceToLogicalX(x) | |
670 y = dc.DeviceToLogicalY(y) | |
671 (imgtype,j) = mimetypes.guess_type(filename) | |
672 postdata = urllib.urlencode({'filename':filename, 'imgdata':imgdata, 'imgtype':imgtype}) | |
673 thread.start_new_thread(self.canvas.layers['token'].upload, (postdata, filepath), {'pos':cmpPoint(x,y)}) | |
674 | |
675 def on_tooltip_timer(self, *args): | |
676 pos = args[0] | |
677 dc = wx.ClientDC(self.canvas) | |
678 self.canvas.PrepareDC(dc) | |
679 dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale) | |
680 pos = wx.Point(dc.DeviceToLogicalX(pos.x), dc.DeviceToLogicalY(pos.y)) | |
681 mini_list = self.getMiniListOrSelectedMini(pos) | |
682 if len(mini_list) > 0: | |
683 print mini_list | |
684 tooltip = self.get_mini_tooltip(mini_list); print tooltip | |
685 self.canvas.SetToolTipString(tooltip) | |
686 else: self.canvas.SetToolTipString("") | |
687 | |
688 def on_motion(self,evt): | |
689 if evt.Dragging() and evt.LeftIsDown(): | |
690 if self.canvas.drag is None and self.drag_mini is not None: | |
691 drag_bmp = self.drag_mini.bmp | |
692 if self.drag_mini.width and self.drag_mini.height: | |
693 tmp_image = drag_bmp.ConvertToImage() | |
694 tmp_image.Rescale(int(self.drag_mini.width * self.canvas.layers['grid'].mapscale), | |
695 int(self.drag_mini.height * self.canvas.layers['grid'].mapscale)) | |
696 tmp_image.ConvertAlphaToMask() | |
697 | |
698 ### Should show rotated image when dragging. | |
699 if self.drag_mini.rotate != 0 : | |
700 tmp_image = tmp_image.Rotate(self.drag_mini.rotate, | |
701 (self.drag_mini.width/2, self.drag_mini.height/2)) | |
702 | |
703 drag_bmp = tmp_image.ConvertToBitmap() | |
704 mask = wx.Mask(drag_bmp, wx.Colour(tmp_image.GetMaskRed(), | |
705 tmp_image.GetMaskGreen(), tmp_image.GetMaskBlue())) | |
706 drag_bmp.SetMask(mask) | |
707 tmp_image = tmp_image.ConvertToGreyscale() | |
708 self.drag_mini.gray = True | |
709 self.drag_mini.isUpdated = True | |
710 def refresh(): | |
711 self.canvas.drag.Hide() | |
712 self.canvas.Refresh(False) | |
713 wx.CallAfter(refresh) | |
714 self.canvas.drag = wx.DragImage(drag_bmp) | |
715 self.drag_offset = self.getLogicalPosition(evt)- self.drag_mini.pos | |
716 self.canvas.drag.BeginDrag((int(self.drag_offset.x * self.canvas.layers['grid'].mapscale), | |
717 int(self.drag_offset.y * self.canvas.layers['grid'].mapscale)), self.canvas, False) | |
718 elif self.canvas.drag is not None: | |
719 self.canvas.drag.Move(evt.GetPosition()) | |
720 self.canvas.drag.Show() | |
721 # reset tool tip timer | |
722 self.canvas.SetToolTipString("") | |
723 self.tooltip_timer.Restart(self.tooltip_delay_miliseconds, evt.GetPosition()) | |
724 | |
725 def on_left_up(self,evt): | |
726 if self.canvas.drag: | |
727 self.canvas.drag.Hide() | |
728 self.canvas.drag.EndDrag() | |
729 self.canvas.drag = None | |
730 pos = self.getLogicalPosition(evt) | |
731 pos = pos - self.drag_offset | |
732 if self.canvas.layers['grid'].snap: | |
733 nudge = int(self.canvas.layers['grid'].unit_size/2) | |
734 if self.canvas.layers['grid'].mode != GRID_ISOMETRIC: | |
735 if self.drag_mini.snap_to_align == SNAPTO_ALIGN_CENTER: | |
736 pos = pos + (int(self.drag_mini.bmp.GetWidth()/2),int(self.drag_mini.bmp.GetHeight()/2)) | |
737 else: pos = pos + (nudge, nudge) | |
738 else:# GRID_ISOMETRIC | |
739 if self.drag_mini.snap_to_align == SNAPTO_ALIGN_CENTER: | |
740 pos = pos + (int(self.drag_mini.bmp.GetWidth()/2), self.drag_mini.bmp.GetHeight()) | |
741 else: pass # no nudge for the isomorphic / top-left | |
742 self.sel_min = self.drag_mini | |
743 # check to see if the mouse is inside the window still | |
744 w = self.canvas.GetClientSizeTuple() # this is the window size, minus any scrollbars | |
745 p = evt.GetPosition() # compare the window size, w with the non-logical position | |
746 c = self.canvas.size # this is the grid size, compare with the logical position, pos | |
747 # both are [width, height] | |
748 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]: | |
749 self.moveSelectedMini(pos) | |
750 self.sel_min.gray = False | |
751 self.sel_min.selected = False | |
752 self.sel_min.isUpdated = True | |
753 self.canvas.Refresh(False) | |
754 self.canvas.send_map_data() | |
755 self.sel_min = None | |
756 self.drag_mini = None | |
757 | |
758 def on_left_dclick(self,evt): | |
759 if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return | |
760 mini = self.find_mini(evt, evt.CmdDown() and self.role_is_gm()) | |
761 if mini: self.on_mini_dclick(evt, mini) | |
762 else: base_layer_handler.on_left_dclick(self, evt) | |
763 | |
764 | |
765 #################################################################### | |
766 ## hook functions (although with python you can override any of the functions) | |
767 | |
768 def prepare_mini_rclick_menu(self, evt): | |
769 # override the entire right-click on a mini menu | |
770 pass | |
771 | |
772 def prepare_background_rclick_menu(self, evt): | |
773 # override the entire right-click on the map menu | |
774 pass | |
775 | |
776 def get_mini_tooltip(self, mini_list): | |
777 # override to create a tooltip | |
778 return "" | |
779 | |
780 def on_mini_dclick(self, evt, mini): | |
781 # do something after the mini was left double clicked | |
782 pass | |
783 | |
784 #################################################################### | |
785 ## easy way to add a single menu item | |
786 | |
787 def set_mini_rclick_menu_item(self, label, callback_function): | |
788 # remember you might want to call these at the end of your callback function: | |
789 # mini_handler.sel_rmin.isUpdated = True | |
790 # canvas.Refresh(False) | |
791 # canvas.send_map_data() | |
792 if callback_function == None: del self.mini_rclick_menu_extra_items[label] | |
793 else: | |
794 if not self.mini_rclick_menu_extra_items.has_key(label): | |
795 self.mini_rclick_menu_extra_items[label]=wx.NewId() | |
796 menu_id = self.mini_rclick_menu_extra_items[label] | |
797 self.canvas.Bind(wx.EVT_MENU, callback_function, id=menu_id) | |
798 self.build_menu() | |
799 | |
800 def set_background_rclick_menu_item(self, label, callback_function): | |
801 if callback_function == None: del self.background_rclick_menu_extra_items[label] | |
802 else: | |
803 if not self.background_rclick_menu_extra_items.has_key(label): | |
804 self.background_rclick_menu_extra_items[label]=wx.NewId() | |
805 menu_id = self.background_rclick_menu_extra_items[label] | |
806 self.canvas.Bind(wx.EVT_MENU, callback_function, id=menu_id) | |
807 self.build_menu() | |
808 | |
809 | |
810 #################################################################### | |
811 ## helper functions | |
812 | |
813 def infoPost(self, message): | |
814 component.get("chat").InfoPost(message) | |
815 | |
816 def role_is_gm_or_player(self): | |
817 session = self.canvas.frame.session | |
818 if (session.my_role() <> session.ROLE_GM) and (session.my_role() <> session.ROLE_PLAYER) and (session.use_roles()): | |
819 self.infoPost("You must be either a player or GM to use the token Layer") | |
820 return False | |
821 return True | |
822 | |
823 def role_is_gm(self): | |
824 session = self.canvas.frame.session | |
825 if (session.my_role() <> session.ROLE_GM) and (session.use_roles()): return False | |
826 return True | |
827 | |
828 def alreadyDealingWithMenu(self): | |
829 return self.lastMenuChoice is not None | |
830 | |
831 def getLastMenuChoice(self): | |
832 choice = self.lastMenuChoice | |
833 self.lastMenuChoice = None | |
834 return choice | |
835 | |
836 def getLogicalPosition(self, evt): | |
837 dc = wx.ClientDC(self.canvas) | |
838 self.canvas.PrepareDC(dc) | |
839 dc.SetUserScale(self.canvas.layers['grid'].mapscale,self.canvas.layers['grid'].mapscale) | |
840 pos = evt.GetLogicalPosition(dc) | |
841 return pos | |
842 | |
843 def getMiniListOrSelectedMini(self, pos, include_locked=False): | |
844 if self.sel_min and self.sel_min.hit_test(pos): | |
845 # clicked on the selected mini - assume that is the intended target | |
846 # and don't give a choice of it and any other minis stacked with it | |
847 mini_list = [] | |
848 mini_list.append(self.sel_min) | |
849 return mini_list | |
850 mini_list = self.canvas.layers['token'].find_token(pos, (not include_locked)) | |
851 if mini_list: return mini_list | |
852 mini_list = [] | |
853 return mini_list | |
854 | |
855 def deselectAndRefresh(self): | |
856 if self.sel_min: | |
857 self.sel_min.selected = False | |
858 self.sel_min.isUpdated = True | |
859 self.canvas.Refresh(False) | |
860 self.canvas.send_map_data() | |
861 self.sel_min = None | |
862 | |
863 def moveSelectedMini(self, pos): | |
864 if self.sel_min: self.moveMini(pos, self.sel_min) | |
865 | |
866 def moveMini(self, pos, mini): | |
867 grid = self.canvas.layers['grid'] | |
868 mini.pos = grid.get_snapped_to_pos(pos, mini.snap_to_align, mini.bmp.GetWidth(), mini.bmp.GetHeight()) | |
869 | |
870 def find_mini(self, evt, include_locked): | |
871 if not self.role_is_gm_or_player() or self.alreadyDealingWithMenu(): return | |
872 pos = self.getLogicalPosition(evt) | |
873 mini_list = self.getMiniListOrSelectedMini(pos, include_locked) | |
874 mini = None | |
875 if len(mini_list) > 1: | |
876 try: self.do_min_select_menu(mini_list, evt.GetPosition()) | |
877 except: pass | |
878 choice = self.getLastMenuChoice() | |
879 if choice == None: return None # left menu without making a choice, eg by clicking outside menu | |
880 mini = mini_list[choice] | |
881 elif len(mini_list) == 1: mini = mini_list[0] | |
882 return mini | |
883 |