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