155
|
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: rpg_grid.py
|
|
21 # Author: Chris Davis
|
|
22 # Maintainer:
|
|
23 # Version:
|
|
24 # $Id: rpg_grid.py,v 1.20 2006/11/15 12:11:24 digitalxero Exp $
|
|
25 #
|
|
26 # Description: The file contains code for the grid nodehanlers
|
|
27 #
|
|
28
|
|
29 __version__ = "$Id: rpg_grid.py,v 1.20 2006/11/15 12:11:24 digitalxero Exp $"
|
|
30
|
|
31 from core import *
|
138
|
32 from forms import *
|
155
|
33
|
|
34 class rpg_grid_handler(node_handler):
|
|
35 """ Node handler for rpg grid tool
|
|
36 <nodehandler module='rpg_grid' class='rpg_grid_handler' name='sample'>
|
|
37 <grid border='' autosize='1' >
|
|
38 <row>
|
|
39 <cell size='?'></cell>
|
|
40 <cell></cell>
|
|
41 </row>
|
|
42 <row>
|
|
43 <cell></cell>
|
|
44 <cell></cell>
|
|
45 </row>
|
|
46 </grid>
|
|
47 <macros>
|
|
48 <macro name=''/>
|
|
49 </macros>
|
|
50 </nodehandler>
|
|
51 """
|
|
52 def __init__(self,xml,tree_node):
|
|
53 node_handler.__init__(self,xml,tree_node)
|
|
54 self.grid = self.xml.find('grid')
|
|
55 if self.grid.get("border") == "": self.grid.set("border","1")
|
|
56 if self.grid.get("autosize") == "": self.grid.set("autosize","1")
|
|
57 self.macros = self.xml.find('macros')
|
|
58 self.myeditor = None
|
|
59 self.refresh_rows()
|
|
60
|
|
61 def refresh_die_macros(self):
|
|
62 pass
|
|
63
|
|
64 def refresh_rows(self):
|
|
65 self.rows = {}
|
|
66 tree = self.tree
|
|
67 icons = self.tree.icons
|
|
68 tree.CollapseAndReset(self.mytree_node)
|
|
69 for row in self.grid.findall('row'):
|
|
70 first_cell = row.find('cell')
|
|
71 name = first_cell.text
|
|
72 if name == None or name == '': name = "Row"
|
|
73 new_tree_node = tree.AppendItem(self.mytree_node,name,icons['gear'],icons['gear'])
|
|
74 handler = grid_row_handler(row,new_tree_node,self)
|
|
75 tree.SetPyData(new_tree_node,handler)
|
|
76
|
|
77 def tohtml(self):
|
|
78 border = self.grid.get("border")
|
|
79 name = self.xml.get('name')
|
|
80 rows = self.grid.findall('row')
|
|
81 colspan = str(len(rows[0].findall('cell')))
|
|
82 html_str = "<table border=\""+border+"\" align=center><tr bgcolor=\""+TH_BG+"\" ><th colspan="+colspan+">"+name+"</th></tr>"
|
|
83 for r in rows:
|
|
84 cells = r.findall('cell')
|
|
85 html_str += "<tr>"
|
|
86 for c in cells:
|
|
87 html_str += "<td >"
|
|
88 text = c.text
|
|
89 if text == None or text == '': text = '<br />'
|
|
90 html_str += text + "</td>"
|
|
91 html_str += "</tr>"
|
|
92 html_str += "</table>"
|
|
93 return html_str
|
|
94
|
|
95 def get_design_panel(self,parent):
|
|
96 return rpg_grid_edit_panel(parent,self)
|
|
97
|
|
98 def get_use_panel(self,parent):
|
|
99 return rpg_grid_panel(parent,self)
|
|
100
|
|
101 def get_size_constraint(self):
|
|
102 return 1
|
|
103
|
|
104 def is_autosized(self):
|
|
105 return self.grid.get("autosize")
|
|
106
|
|
107 def set_autosize(self,autosize=1):
|
|
108 self.grid.set("autosize",str(autosize))
|
|
109
|
|
110 class grid_row_handler(node_handler):
|
|
111 """ Node Handler grid row.
|
|
112 """
|
|
113 def __init__(self,xml,tree_node,parent):
|
|
114 node_handler.__init__(self,xml,tree_node)
|
|
115 self.drag = False
|
|
116
|
|
117 def on_drop(self,evt):
|
|
118 pass
|
|
119
|
|
120 def can_clone(self):
|
|
121 return 0;
|
|
122
|
|
123 def tohtml(self):
|
|
124 cells = self.xml.findall('cell')
|
|
125 html_str = "<table border=1 align=center><tr >"
|
|
126 for c in cells: # should loop over rows first, then cells
|
|
127 html_str += "<td >"
|
|
128 text = c.text
|
|
129 if text == '' or text is None: text = '<br />'
|
|
130 html_str += text + "</td>"
|
|
131 html_str += "</tr>"
|
|
132 html_str += "</table>"
|
|
133 return html_str
|
|
134
|
|
135 def get_value(self):
|
|
136 cells = self.xml.findall('cell')
|
|
137 if len(cells) == 2: return getText(cells[1])
|
|
138 else: return None
|
|
139
|
|
140 def set_value(self, new_value):
|
|
141 cells = self.xml.findall('cell')
|
|
142 if len(cells) == 2:
|
|
143 cells[1].text = new_value
|
|
144
|
|
145 class MyCellEditor(wx.grid.PyGridCellEditor):
|
|
146 """
|
|
147 This is a sample GridCellEditor that shows you how to make your own custom
|
|
148 grid editors. All the methods that can be overridden are show here. The
|
|
149 ones that must be overridden are marked with "*Must Override*" in the
|
|
150 docstring.
|
|
151
|
|
152 Notice that in order to call the base class version of these special
|
|
153 methods we use the method name preceded by "base_". This is because these
|
|
154 methods are "virtual" in C++ so if we try to call wxGridCellEditor.Create
|
|
155 for example, then when the wxPython extension module tries to call
|
|
156 ptr->Create(...) then it actually calls the derived class version which
|
|
157 looks up the method in this class and calls it, causing a recursion loop.
|
|
158 If you don't understand any of this, don't worry, just call the "base_"
|
|
159 version instead.
|
|
160
|
|
161 ----------------------------------------------------------------------------
|
|
162 This class is copied from the wxPython examples directory and was written by
|
|
163 Robin Dunn.
|
|
164
|
|
165 I have pasted it directly in and removed all references to "log"
|
|
166
|
|
167 -- Andrew
|
|
168
|
|
169 """
|
|
170 def __init__(self):
|
|
171 wx.grid.PyGridCellEditor.__init__(self)
|
|
172
|
|
173 def Create(self, parent, id, evtHandler):
|
|
174 """
|
|
175 Called to create the control, which must derive from wxControl.
|
|
176 *Must Override*
|
|
177 """
|
|
178 self._tc = wx.TextCtrl(parent, id, "", style=wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB)
|
|
179 self._tc.SetInsertionPoint(0)
|
|
180 self.SetControl(self._tc)
|
|
181 if evtHandler: self._tc.PushEventHandler(evtHandler)
|
|
182
|
|
183 def SetSize(self, rect):
|
|
184 """
|
|
185 Called to position/size the edit control within the cell rectangle.
|
|
186 If you don't fill the cell (the rect) then be sure to override
|
|
187 PaintBackground and do something meaningful there.
|
|
188 """
|
|
189 self._tc.SetDimensions(rect.x+1, rect.y+1, rect.width+2, rect.height+2)
|
|
190
|
|
191 def BeginEdit(self, row, col, grid):
|
|
192 """
|
|
193 Fetch the value from the table and prepare the edit control
|
|
194 to begin editing. Set the focus to the edit control.
|
|
195 *Must Override*
|
|
196 """
|
|
197 self.startValue = grid.GetTable().GetValue(row, col)
|
|
198 self._tc.SetValue(self.startValue)
|
|
199 self._tc.SetInsertionPointEnd()
|
|
200 self._tc.SetFocus()
|
|
201
|
|
202 # For this example, select the text
|
|
203 self._tc.SetSelection(0, self._tc.GetLastPosition())
|
151
|
204
|
155
|
205 def EndEdit(self, row, col, grid):
|
|
206 """
|
|
207 Complete the editing of the current cell. Returns True if the value
|
|
208 has changed. If necessary, the control may be destroyed.
|
|
209 *Must Override*
|
|
210 """
|
|
211 changed = False
|
|
212 val = self._tc.GetValue()
|
|
213 if val != self.startValue:
|
|
214 changed = True
|
|
215 grid.GetTable().SetValue(row, col, val) # update the table
|
|
216
|
|
217 self.startValue = ''
|
|
218 self._tc.SetValue('')
|
|
219 return changed
|
|
220
|
|
221 def Reset(self):
|
|
222 """
|
|
223 Reset the value in the control back to its starting value.
|
|
224 *Must Override*
|
|
225 """
|
|
226 self._tc.SetValue(self.startValue)
|
|
227 self._tc.SetInsertionPointEnd()
|
|
228
|
|
229 def IsAcceptedKey(self, evt):
|
|
230 """
|
|
231 Return True to allow the given key to start editing: the base class
|
|
232 version only checks that the event has no modifiers. F2 is special
|
|
233 and will always start the editor.
|
|
234 """
|
|
235 return (not (evt.ControlDown() or evt.AltDown()) and
|
|
236 evt.GetKeyCode() != wx.WXK_SHIFT)
|
|
237
|
|
238 def StartingKey(self, evt):
|
|
239 """
|
|
240 If the editor is enabled by pressing keys on the grid, this will be
|
|
241 called to let the editor do something about that first key if desired.
|
|
242 """
|
|
243 key = evt.GetKeyCode()
|
|
244 ch = None
|
|
245 if key in [wx.WXK_NUMPAD0, wx.WXK_NUMPAD1, wx.WXK_NUMPAD2, wx.WXK_NUMPAD3, wx.WXK_NUMPAD4,
|
|
246 wx.WXK_NUMPAD5, wx.WXK_NUMPAD6, wx.WXK_NUMPAD7, wx.WXK_NUMPAD8, wx.WXK_NUMPAD9]:
|
|
247 ch = ch = chr(ord('0') + key - wx.WXK_NUMPAD0)
|
|
248 elif key < 256 and key >= 0 and chr(key) in string.printable:
|
|
249 ch = chr(key)
|
|
250 if not evt.ShiftDown(): ch = string.lower(ch)
|
|
251 if ch is not None: self._tc.AppendText(ch)
|
|
252 else: evt.Skip()
|
|
253
|
|
254 def Destroy(self):
|
|
255 """final cleanup"""
|
|
256 self.base_Destroy()
|
|
257
|
|
258 def Clone(self):
|
|
259 """
|
|
260 Create a new object which is the copy of this one
|
|
261 *Must Override*
|
|
262 """
|
|
263 return MyCellEditor()
|
|
264
|
|
265
|
|
266 class rpg_grid(wx.grid.Grid):
|
|
267 """grid for attacks"""
|
|
268 def __init__(self, parent, handler):
|
|
269 wx.grid.Grid.__init__(self, parent, -1, style=wx.SUNKEN_BORDER | wx.WANTS_CHARS)
|
|
270 self.parent = parent
|
|
271 self.handler = handler
|
|
272
|
|
273 self.RegisterDataType(wx.grid.GRID_VALUE_STRING, wx.grid.GridCellStringRenderer(),MyCellEditor())
|
|
274
|
|
275 self.rows = handler.grid.findall('row')
|
|
276 rows = len(self.rows)
|
|
277 cols = len(self.rows[0].findall('cell'))
|
|
278 self.CreateGrid(rows,cols)
|
|
279 self.SetRowLabelSize(0)
|
|
280 self.SetColLabelSize(0)
|
|
281 self.set_col_widths()
|
|
282
|
|
283 for i in range(0,len(self.rows)): self.refresh_row(i)
|
|
284
|
|
285 self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_change)
|
|
286 self.Bind(wx.grid.EVT_GRID_COL_SIZE, self.on_col_size)
|
|
287 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.on_leftdclick)
|
|
288
|
|
289
|
|
290 def on_leftdclick(self,evt):
|
|
291 if self.CanEnableCellControl(): self.EnableCellEditControl()
|
|
292
|
|
293 def on_col_size(self, evt):
|
|
294 col = evt.GetRowOrCol()
|
|
295 cells = self.rows[0].findall('cell')
|
|
296 size = self.GetColSize(col)
|
|
297 cells[col].set('size',str(size))
|
|
298 evt.Skip()
|
|
299
|
|
300 def on_cell_change(self,evt):
|
|
301 row = evt.GetRow()
|
|
302 col = evt.GetCol()
|
|
303 value = self.GetCellValue(row,col)
|
|
304 cells = self.rows[row].findall('cell')
|
|
305 cells[col].text = value
|
|
306 if col == 0: self.handler.refresh_rows()
|
|
307
|
|
308 def set_col_widths(self):
|
|
309 cells = self.rows[0].findall('cell')
|
|
310 for i in range(0,len(cells)):
|
|
311 try:
|
|
312 size = int(cells[i].get('size'))
|
|
313 self.SetColSize(i,size)
|
|
314 except: continue
|
|
315
|
|
316 def refresh_row(self,rowi):
|
|
317 cells = self.rows[rowi].findall('cell')
|
|
318 for i in range(0,len(cells)):
|
|
319 text = cells[i].text
|
|
320 if text == None or text == '':
|
|
321 text = ''
|
|
322 cells[i].text = text
|
|
323 self.SetCellValue(rowi,i,text)
|
|
324
|
|
325 def add_row(self,evt=None):
|
|
326 cols = self.GetNumberCols()
|
|
327 row = Element('row')
|
|
328 for i in range(0,cols):
|
|
329 cell = Element('cell')
|
|
330 cell.text = ''
|
|
331 row.append(cell)
|
|
332 self.handler.grid.append(row)
|
|
333 self.AppendRows(1)
|
|
334 self.rows = self.handler.grid.findall('row')
|
|
335 self.handler.refresh_rows()
|
|
336
|
|
337 def add_col(self,evt=None):
|
|
338 for r in self.rows:
|
|
339 cell = Element('cell')
|
|
340 cell.text = ''
|
|
341 r.append(cell)
|
|
342 self.AppendCols(1)
|
|
343 self.set_col_widths()
|
|
344
|
|
345 def del_row(self,evt=None):
|
|
346 num = self.GetNumberRows()
|
|
347 if num == 1: return
|
|
348 self.handler.grid.remove(self.handler.grid[num-1])# always remove last row -- nasty
|
|
349 self.DeleteRows(num-1,1)
|
|
350 self.rows = self.handler.grid.findall('row')
|
|
351 self.handler.refresh_rows()
|
|
352
|
|
353 def del_col(self,evt=None):
|
|
354 num = self.GetNumberCols()
|
|
355 if num == 1: return
|
|
356 for r in self.rows:
|
|
357 cells = r.findall('cell')
|
|
358 r.remove(r[num-1]) # always remove the last column -- nasty
|
|
359 self.DeleteCols(num-1,1)
|
|
360 self.set_col_widths()
|
|
361
|
|
362
|
|
363 G_TITLE = wx.NewId()
|
|
364 GRID_BOR = wx.NewId()
|
|
365 class rpg_grid_panel(wx.Panel):
|
|
366 def __init__(self, parent, handler):
|
|
367 wx.Panel.__init__(self, parent, -1)
|
|
368 self.handler = handler
|
|
369 self.grid = rpg_grid(self,handler)
|
|
370 label = handler.xml.get('name')
|
|
371 self.main_sizer = wx.BoxSizer(wx.VERTICAL)
|
|
372 self.main_sizer.Add(wx.StaticText(self, -1, label+": "), 0, wx.EXPAND)
|
|
373 self.main_sizer.Add(self.grid,1,wx.EXPAND)
|
|
374 self.SetSizer(self.main_sizer)
|
|
375 self.SetAutoLayout(True)
|
|
376 self.Fit()
|
|
377 parent.SetSize(self.GetBestSize())
|
|
378
|
|
379 G_AUTO_SIZE = wx.NewId()
|
|
380 G_ADD_ROW = wx.NewId()
|
|
381 G_ADD_COL = wx.NewId()
|
|
382 G_DEL_ROW = wx.NewId()
|
|
383 G_DEL_COL = wx.NewId()
|
173
|
384 G_BUT_REF = wx.NewId()
|
155
|
385
|
|
386 class rpg_grid_edit_panel(wx.Panel):
|
|
387 def __init__(self, parent, handler):
|
|
388 wx.Panel.__init__(self, parent, -1)
|
|
389 self.handler = handler
|
138
|
390 self.grid = rpg_grid(self,handler)
|
|
391 self.main_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Grid"), wx.VERTICAL)
|
|
392
|
155
|
393 self.title = wx.TextCtrl(self, G_TITLE, handler.xml.get('name'))
|
|
394
|
|
395 radio_b = wx.RadioBox(self, GRID_BOR, "Border (HTML)", choices=["no","yes"])
|
138
|
396 border = handler.grid.get("border")
|
155
|
397 radio_b.SetSelection(int(border))
|
|
398
|
|
399 self.auto_size = wx.CheckBox(self, G_AUTO_SIZE, "Auto Size")
|
|
400 if handler.is_autosized() == '1': self.auto_size.SetValue(True)
|
|
401 else: self.auto_size.SetValue(False)
|
|
402
|
138
|
403 sizer = wx.BoxSizer(wx.HORIZONTAL)
|
155
|
404 sizer.Add(wx.Button(self, G_ADD_ROW, "Add Row"), 1, wx.EXPAND)
|
|
405 sizer.Add(wx.Size(10,10))
|
|
406 sizer.Add(wx.Button(self, G_DEL_ROW, "Remove Row"), 1, wx.EXPAND)
|
|
407 sizer.Add(wx.Size(10,10))
|
|
408 sizer.Add(wx.Button(self, G_ADD_COL, "Add Column"), 1, wx.EXPAND)
|
|
409 sizer.Add(wx.Size(10,10))
|
138
|
410 sizer.Add(wx.Button(self, G_DEL_COL, "Remove Column"), 1, wx.EXPAND)
|
173
|
411 sizer.Add(wx.Size(10,10))
|
|
412 sizer.Add(wx.Button(self, G_BUT_REF, "Reference"), 1)
|
155
|
413
|
|
414 self.main_sizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.EXPAND)
|
|
415 self.main_sizer.Add(self.title, 0, wx.EXPAND)
|
|
416 self.main_sizer.Add(radio_b, 0, 0)
|
|
417 self.main_sizer.Add(self.auto_size, 0, 0)
|
|
418 self.main_sizer.Add(self.grid,1,wx.EXPAND)
|
138
|
419 self.main_sizer.Add(sizer,0,wx.EXPAND)
|
155
|
420
|
138
|
421 self.SetSizer(self.main_sizer)
|
155
|
422 self.SetAutoLayout(True)
|
|
423 self.Fit()
|
|
424
|
|
425 self.Bind(wx.EVT_TEXT, self.on_text, id=G_TITLE)
|
|
426 self.Bind(wx.EVT_BUTTON, self.grid.add_row, id=G_ADD_ROW)
|
|
427 self.Bind(wx.EVT_BUTTON, self.grid.del_row, id=G_DEL_ROW)
|
|
428 self.Bind(wx.EVT_BUTTON, self.grid.add_col, id=G_ADD_COL)
|
|
429 self.Bind(wx.EVT_BUTTON, self.grid.del_col, id=G_DEL_COL)
|
|
430 self.Bind(wx.EVT_RADIOBOX, self.on_radio_box, id=GRID_BOR)
|
|
431 self.Bind(wx.EVT_CHECKBOX, self.on_auto_size, id=G_AUTO_SIZE)
|
173
|
432 self.Bind(wx.EVT_BUTTON, self.on_reference, id=G_BUT_REF)
|
|
433
|
|
434 ## EZ_Tree Core TaS - Prof.Ebral ##
|
|
435 def on_reference(self, evt, car=None):
|
|
436 self.do_tree = wx.Frame(self, -1, 'Tree')
|
|
437 self.ez_tree = orpg.gametree.gametree
|
|
438 self.temp_wnd = self.ez_tree.game_tree(self.do_tree, self.ez_tree.EZ_REF)
|
|
439 #self.temp_wnd.Bind(wx.EVT_LEFT_DCLICK, self.on_ldclick) ## Remove for Alpha ##
|
|
440 self.temp_wnd.load_tree(settings.get("gametree"))
|
|
441 self.do_tree.Show()
|
|
442
|
|
443 def on_ldclick(self, evt):
|
|
444 self.rename_flag = 0
|
|
445 pt = evt.GetPosition()
|
|
446 (item, flag) = self.temp_wnd.HitTest(pt)
|
|
447 if item.IsOk():
|
|
448 obj = self.temp_wnd.GetPyData(item)
|
|
449 self.temp_wnd.SelectItem(item)
|
|
450 start = self.handler.xml.get('map').split('::')
|
|
451 end = obj.xml.get('map').split('::')
|
|
452 x = 0
|
|
453 if start[x] == end[x]:
|
|
454 try:
|
|
455 while start[x] == end[x]:
|
|
456 del end[x], start[x]
|
|
457 x += 1
|
|
458 except:
|
|
459 complete = "!!"
|
|
460 for e in end: complete += e +'::'
|
|
461 complete = complete + obj.xml.get('name') + '!!'
|
|
462 self.value_entry.SetValue(complete); self.reload_options()
|
|
463 self.do_tree.Destroy()
|
|
464 ##### #####
|
155
|
465
|
|
466 def on_auto_size(self,evt):
|
|
467 self.handler.set_autosize(bool2int(evt.Checked()))
|
|
468
|
|
469 def on_radio_box(self,evt):
|
|
470 id = evt.GetId()
|
|
471 index = evt.GetInt()
|
|
472 if id == GRID_BOR:
|
|
473 self.handler.grid.set("border",str(index))
|
|
474
|
|
475 def on_text(self,evt):
|
|
476 txt = self.title.GetValue()
|
|
477 if txt != "":
|
|
478 self.handler.xml.set('name',txt)
|
|
479 self.handler.rename(txt)
|