Mercurial > traipse_dev
annotate orpg/chat/chatwnd.py @ 184:dcae32e219f1 beta
Traipse Beta 'OpenRPG' {100117-00}
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 (Beta)
New Features:
Added Bookmarks
Added 'boot' command to remote admin
Added confirmation window for sent nodes
Minor changes to allow for portability to an OpenSUSE linux OS
Miniatures Layer pop up box allows users to turn off Mini labels, from
FlexiRPG
Zoom Mouse plugin added
Images added to Plugin UI
Switching to Element Tree
Map efficiency, from FlexiRPG
Added Status Bar to Update Manager
New TrueDebug Class in orpg_log (See documentation for usage)
Portable Mercurial
Tip of the Day added, from Core and community
New Reference Syntax added for custom PC sheets
New Child Reference for gametree
New Parent Reference for gametree
New Gametree Recursion method, mapping, context sensitivity, and
effeciency..
New Features node with bonus nodes and Node Referencing help added
Dieroller structure from Core
New DieRoller portability for odd Dice
Added 7th Sea die roller; ie [7k3] = [7d10.takeHighest(3).open(10)]
New 'Mythos' System die roller added
Added new vs. die roller method for WoD; ie [3v3] = [3d10.vs(3)].
Included for Mythos roller also
New Warhammer FRPG Die Roller (Special thanks to Puu-san for the
support)
New EZ_Tree Reference system. Push a button, Traipse the tree, get a
reference (Beta!)
Fixes:
Fix to Text based Server
Fix to Remote Admin Commands
Fix to Pretty Print, from Core
Fix to Splitter Nodes not being created
Fix to massive amounts of images loading, from Core
Fix to Map from gametree not showing to all clients
Fix to gametree about menus
Fix to Password Manager check on startup
Fix to PC Sheets from tool nodes. They now use the tabber_panel
Fix to Whiteboard ID to prevent random line or text deleting.
Fixes to Server, Remote Server, and Server GUI
Fix to Update Manager; cleaner clode for saved repositories
Fixes made to Settings Panel and now reactive settings when Ok is
pressed
Fixes to Alternity roller's attack roll. Uses a simple Tuple instead of
a Splice
Fix to Use panel of Forms and Tabbers. Now longer enters design mode
Fix made Image Fetching. New fetching image and new failed image
Modified ID's to prevent non updated clients from ruining the fix.
default_manifest.xml renamed to default_upmana.xml
author | sirebral |
---|---|
date | Sun, 17 Jan 2010 21:37:34 -0600 |
parents | 0d9b746b5751 |
children | a3d7e05085da |
rev | line source |
---|---|
156 | 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: chatutils.py | |
21 # Author: Chris Davis | |
22 # Maintainer: | |
23 # Version: | |
184 | 24 # $Id: chatwnd.py,v Traipse 'Ornery-Orc' prof.ebral Exp $ |
156 | 25 # |
26 # Description: This file contains some of the basic definitions for the chat | |
27 # utilities in the orpg project. | |
28 # | |
29 # History | |
30 # 2002-01-20 HeroMan | |
31 # + Added 4 dialog items on toolbar in support of Alias Library Functionallity | |
32 # + Shrunk the text view button to an image | |
33 # 2005-04-25 Snowdog | |
34 # + Added simple_html_repair() to post() to fix malformed html in the chat window | |
35 # + Added strip_script_tags() to post() to remove crash point. See chat_util.py | |
36 # 2005-04-25 Snowdog | |
37 # + Added simple_html_repair() to post() to fix malformed html in the chat window | |
38 # | |
39 | |
184 | 40 __version__ = "$Id: chatwnd.py,v Traipse 'Ornery-Orc' prof.ebral Exp $" |
156 | 41 |
42 | |
43 ## | |
44 ## Module Loading | |
135 | 45 ## |
46 import os, time, re, sys, traceback, webbrowser, commands, chat_msg, chat_util | |
47 | |
156 | 48 from orpg.orpg_version import VERSION |
49 from orpg.orpg_windows import * | |
50 from orpg.player_list import WG_LIST | |
51 from orpg.dirpath import dir_struct | |
52 from string import * | |
135 | 53 |
156 | 54 import cStringIO # for reading inline imagedata as a stream |
55 from HTMLParser import HTMLParser | |
56 from wx.lib.expando import EVT_ETC_LAYOUT_NEEDED | |
135 | 57 |
156 | 58 import orpg.tools.rgbhex |
59 import orpg.tools.inputValidator | |
60 from orpg.tools.validate import validate | |
135 | 61 from orpg.tools.orpg_settings import settings |
156 | 62 import orpg.tools.predTextCtrl |
135 | 63 from orpg.tools.orpg_log import logger, debug |
64 from orpg.orpgCore import component | |
65 from xml.etree.ElementTree import tostring | |
66 | |
184 | 67 from orpg.networking.mplay_client import MPLAY_CONNECTED |
156 | 68 NEWCHAT = False |
69 try: | |
70 import wx.webview | |
71 NEWCHAT = True | |
72 except: pass | |
73 NEWCHAT = False | |
74 | |
75 # Global parser for stripping HTML tags: | |
76 # The 'tag stripping' is implicit, because this parser echoes every | |
77 # type of html data *except* the tags. | |
78 class HTMLStripper(HTMLParser): | |
79 | |
80 def __init__(self): | |
81 self.accum = "" | |
82 self.special_tags = ['hr', 'br', 'img'] | |
83 | |
184 | 84 def handle_data(self, data): |
156 | 85 self.accum += data |
86 | |
184 | 87 def handle_entityref(self, name): |
156 | 88 self.accum += "&" + name + ";" |
89 | |
90 def handle_starttag(self, tag, attrs): | |
91 if tag in self.special_tags: | |
92 self.accum += '<' + tag | |
93 for attrib in attrs: self.accum += ' ' + attrib[0] + '="' + attrib[1] + '"' | |
94 self.accum += '>' | |
95 | |
184 | 96 def handle_charref(self, name): |
156 | 97 self.accum += "&#" + name + ";" |
98 htmlstripper = HTMLStripper() | |
99 | |
100 | |
101 def strip_html(string): | |
102 "Return string tripped of html tags." | |
103 htmlstripper.reset() | |
104 htmlstripper.accum = "" | |
105 htmlstripper.feed(string) | |
106 htmlstripper.close() | |
107 return htmlstripper.accum | |
108 | |
109 | |
110 def log( settings, c, text ): | |
111 filename = settings.get_setting('GameLogPrefix') | |
112 if filename > '' and filename[0] != commands.ANTI_LOG_CHAR: | |
113 filename = filename + time.strftime( '-%Y-%m-%d.html', time.localtime( time.time() ) ) | |
114 timestamp = time.ctime(time.time()) | |
115 header = '[%s] : ' % ( timestamp ); | |
116 if settings.get_setting('TimeStampGameLog') != '1': header = '' | |
117 try: | |
118 f = open( dir_struct["user"] + filename, 'a' ) | |
119 f.write( '<div class="'+c+'">%s%s</div>\n' % ( header, text ) ) | |
120 f.close() | |
121 except: | |
122 print "could not open " + dir_struct["user"] + filename + ", ignoring..." | |
123 pass | |
124 | |
125 # This class displayes the chat information in html? | |
126 # | |
127 # Defines: | |
128 # __init__(self, parent, id) | |
129 # OnLinkClicked(self, linkinfo) | |
130 # CalculateAllFonts(self, defaultsize) | |
131 # SetDefaultFontAndSize(self, fontname) | |
132 # | |
133 class chat_html_window(wx.html.HtmlWindow): | |
134 """ a wxHTMLwindow that will load links """ | |
184 | 135 |
156 | 136 def __init__(self, parent, id): |
137 wx.html.HtmlWindow.__init__(self, parent, id, | |
138 style=wx.SUNKEN_BORDER|wx.html.HW_SCROLLBAR_AUTO|wx.NO_FULL_REPAINT_ON_RESIZE) | |
139 self.parent = parent | |
140 self.build_menu() | |
141 self.Bind(wx.EVT_LEFT_UP, self.LeftUp) | |
142 self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup) | |
143 if "gtk2" in wx.PlatformInfo: self.SetStandardFonts() | |
144 | |
145 def onPopup(self, evt): | |
146 self.PopupMenu(self.menu) | |
147 | |
148 def LeftUp(self, event): | |
149 event.Skip() | |
150 wx.CallAfter(self.parent.set_chat_text_focus, None) | |
151 | |
152 def build_menu(self): | |
153 self.menu = wx.Menu() | |
154 item = wx.MenuItem(self.menu, wx.ID_ANY, "Copy", "Copy") | |
155 self.Bind(wx.EVT_MENU, self.OnM_EditCopy, item) | |
156 self.menu.AppendItem(item) | |
157 | |
158 def OnM_EditCopy(self, evt): | |
159 wx.TheClipboard.UsePrimarySelection(False) | |
160 wx.TheClipboard.Open() | |
161 wx.TheClipboard.SetData(wx.TextDataObject(self.SelectionToText())) | |
162 wx.TheClipboard.Close() | |
163 | |
164 def scroll_down(self): | |
165 maxrange = self.GetScrollRange(wx.VERTICAL) | |
166 pagesize = self.GetScrollPageSize(wx.VERTICAL) | |
167 self.Scroll(-1, maxrange-pagesize) | |
168 | |
169 def mouse_wheel(self, event): | |
170 amt = event.GetWheelRotation() | |
171 units = amt/(-(event.GetWheelDelta())) | |
172 self.ScrollLines(units*3) | |
173 | |
174 | |
175 def Header(self): | |
176 return '<html><body bgcolor="' + self.parent.bgcolor + '" text="' + self.parent.textcolor + '">' | |
177 | |
178 | |
179 def StripHeader(self): | |
180 return self.GetPageSource().replace(self.Header(), '') | |
181 | |
182 | |
183 def GetPageSource(self): | |
184 return self.GetParser().GetSource() | |
185 | |
186 def OnLinkClicked(self, linkinfo): | |
187 href = linkinfo.GetHref() | |
188 wb = webbrowser.get() | |
189 wb.open(href) | |
190 | |
191 def CalculateAllFonts(self, defaultsize): | |
192 return [int(defaultsize * 0.4), | |
193 int(defaultsize * 0.7), | |
194 int(defaultsize), | |
195 int(defaultsize * 1.3), | |
196 int(defaultsize * 1.7), | |
197 int(defaultsize * 2), | |
198 int(defaultsize * 2.5)] | |
199 | |
200 def SetDefaultFontAndSize(self, fontname, fontsize): | |
201 """Set 'fontname' to the default chat font. | |
202 Returns current font settings in a (fontname, fontsize) tuple.""" | |
203 self.SetFonts(fontname, "", self.CalculateAllFonts(int(fontsize))) | |
204 return (self.GetFont().GetFaceName(), self.GetFont().GetPointSize()) | |
205 | |
206 # class chat_html_window - end | |
140 | 207 if NEWCHAT: |
156 | 208 class ChatHtmlWindow(wx.webview.WebView): |
209 | |
210 def __init__(self, parent, id): | |
211 wx.webview.WebView.__init__(self, parent, id) | |
212 self.parent = parent | |
213 self.__font = wx.Font(10, wx.FONTFAMILY_ROMAN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, faceName='Ariel') | |
214 self.build_menu() | |
215 self.Bind(wx.EVT_LEFT_UP, self.LeftUp) | |
216 self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup) | |
217 self.Bind(wx.webview.EVT_WEBVIEW_BEFORE_LOAD, self.OnLinkClicked) | |
218 | |
219 def SetPage(self, htmlstring): | |
220 self.SetPageSource(htmlstring) | |
221 | |
140 | 222 def AppendToPage(self, htmlstring): |
156 | 223 self.SetPageSource(self.GetPageSource() + htmlstring) |
224 | |
225 def GetFont(self): | |
226 return self.__font | |
227 | |
228 def CalculateAllFonts(self, defaultsize): | |
229 return | |
230 | |
231 def SetDefaultFontAndSize(self, fontname, fontsize): | |
232 self.__font = wx.Font(int(fontsize), | |
233 wx.FONTFAMILY_ROMAN, wx.FONTSTYLE_NORMAL, | |
234 wx.FONTWEIGHT_NORMAL, faceName=fontname) | |
235 try: self.SetPageSource(self.Header() + self.StripHeader()) | |
236 except Exception, e: print e | |
237 return (self.GetFont().GetFaceName(), self.GetFont().GetPointSize()) | |
238 | |
239 #Events | |
240 def OnLinkClicked(self, linkinfo): | |
241 href = linkinfo.GetHref() | |
242 wb = webbrowser.get() | |
243 wb.open(href) | |
244 | |
245 def onPopup(self, evt): | |
246 self.PopupMenu(self.menu) | |
247 | |
248 def LeftUp(self, event): | |
249 event.Skip() | |
250 wx.CallAfter(self.parent.set_chat_text_focus, None) | |
251 | |
252 def OnM_EditCopy(self, evt): | |
253 wx.TheClipboard.UsePrimarySelection(False) | |
254 wx.TheClipboard.Open() | |
255 wx.TheClipboard.SetData(wx.TextDataObject(self.SelectionToText())) | |
256 wx.TheClipboard.Close() | |
257 | |
258 #Cutom Methods | |
259 def Header(self): | |
260 return "<html><head><style>body {font-size: " + str(self.GetFont().GetPointSize()) + "px;font-family: " + self.GetFont().GetFaceName() + ";color: " + self.parent.textcolor + ";background-color: " + self.parent.bgcolor + ";margin: 0;padding: 0 0;height: 100%;}</style></head><body>" | |
261 | |
262 def StripHeader(self): | |
263 tmp = self.GetPageSource().split('<BODY>') | |
264 if tmp[-1].find('<body>') > -1: tmp = tmp[-1].split('<body>') | |
265 return tmp[-1] | |
266 | |
267 def build_menu(self): | |
268 self.menu = wx.Menu() | |
269 item = wx.MenuItem(self.menu, wx.ID_ANY, "Copy", "Copy") | |
270 self.Bind(wx.EVT_MENU, self.OnM_EditCopy, item) | |
271 self.menu.AppendItem(item) | |
272 | |
273 def scroll_down(self): | |
274 maxrange = self.GetScrollRange(wx.VERTICAL) | |
275 pagesize = self.GetScrollPageSize(wx.VERTICAL) | |
276 self.Scroll(-1, maxrange-pagesize) | |
277 | |
278 def mouse_wheel(self, event): | |
279 amt = event.GetWheelRotation() | |
280 units = amt/(-(event.GetWheelDelta())) | |
281 self.ScrollLines(units*3) | |
282 chat_html_window = ChatHtmlWindow | |
283 | |
284 ######################### | |
285 #chat frame window | |
286 ######################### | |
287 # These are kinda global...and static..and should be located somewhere else | |
288 # then the middle of a file between two classes. | |
289 | |
290 ################### | |
291 # Tab Types | |
292 ################### | |
293 MAIN_TAB = wx.NewId() | |
294 WHISPER_TAB = wx.NewId() | |
295 GROUP_TAB = wx.NewId() | |
296 NULL_TAB = wx.NewId() | |
297 | |
298 # This class defines the tabbed 'notebook' that holds multiple chatpanels. | |
299 # It's the widget attached to the main application frame. | |
300 # | |
301 # Inherits: wxNotebook | |
302 # | |
303 # Defines: | |
304 # create_private_tab(self, playerid) | |
305 # get_tab_index(self, chatpanel) | |
306 # destroy_private_tab(self, chatpanel) | |
307 # OnPageChanged(self, event) | |
308 # set_default_font(self, font, fontsize) | |
309 | |
310 class chat_notebook(orpgTabberWnd): | |
311 | |
312 def __init__(self, parent, size): | |
313 orpgTabberWnd.__init__(self, parent, True, size=size, | |
314 style=FNB.FNB_DROPDOWN_TABS_LIST|FNB.FNB_NO_NAV_BUTTONS|FNB.FNB_MOUSE_MIDDLE_CLOSES_TABS) | |
315 self.settings = component.get("settings") | |
316 self.whisper_tabs = [] | |
317 self.group_tabs = [] | |
318 self.null_tabs = [] | |
319 self.il = wx.ImageList(16, 16) | |
320 bmp = wx.Bitmap(dir_struct["icon"]+'player.gif') | |
321 self.il.Add(bmp) | |
322 bmp = wx.Bitmap(dir_struct["icon"]+'clear.gif') | |
323 self.il.Add(bmp) | |
324 self.SetImageList(self.il) | |
325 # Create "main" chatpanel tab, undeletable, connected to 'public' room. | |
326 self.MainChatPanel = chat_panel(self, -1, MAIN_TAB, 'all') | |
327 self.AddPage(self.MainChatPanel, "Main Room") | |
328 self.SetPageImage(0, 1) | |
329 self.chat_timer = wx.Timer(self, wx.NewId()) | |
330 self.Bind(wx.EVT_TIMER, self.MainChatPanel.typingTimerFunc) | |
331 self.chat_timer.Start(1000) | |
332 # Hook up event handler for flipping tabs | |
333 self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.onPageChanged) | |
334 self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGING, self.onPageChanging) | |
335 self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.onCloseTab) | |
336 # html font/fontsize is global to all the notebook tabs. | |
337 self.font, self.fontsize = self.MainChatPanel.chatwnd.SetDefaultFontAndSize(self.settings.get_setting('defaultfont'), self.settings.get_setting('defaultfontsize')) | |
338 self.GMChatPanel = None | |
339 if self.settings.get_setting("GMWhisperTab") == '1': | |
340 self.create_gm_tab() | |
341 self.SetSelection(0) | |
342 | |
343 def get_tab_index(self, chatpanel): | |
344 "Return the index of a chatpanel in the wxNotebook." | |
345 | |
346 for i in xrange(self.GetPageCount()): | |
347 if (self.GetPage(i) == chatpanel): | |
348 return i | |
349 | |
350 def create_gm_tab(self): | |
351 if self.GMChatPanel == None: | |
352 self.GMChatPanel = chat_panel(self, -1, MAIN_TAB, 'gm') | |
353 self.AddPage(self.GMChatPanel, "GM", False) | |
354 self.SetPageImage(self.GetPageCount()-1, 1) | |
355 self.GMChatPanel.chatwnd.SetDefaultFontAndSize(self.font, self.fontsize) | |
356 | |
357 def create_whisper_tab(self, playerid): | |
358 "Add a new chatpanel directly connected to integer 'playerid' via whispering." | |
359 private_tab = chat_panel(self, -1, WHISPER_TAB, playerid) | |
360 playername = strip_html(self.MainChatPanel.session.get_player_by_player_id(playerid)[0]) | |
361 self.AddPage(private_tab, playername, False) | |
362 private_tab.chatwnd.SetDefaultFontAndSize(self.font, self.fontsize) | |
363 self.whisper_tabs.append(private_tab) | |
364 self.newMsg(self.GetPageCount()-1) | |
365 self.AliasLib = component.get('alias') | |
366 wx.CallAfter(self.AliasLib.RefreshAliases) | |
367 return private_tab | |
368 | |
369 def create_group_tab(self, group_name): | |
370 "Add a new chatpanel directly connected to integer 'playerid' via whispering." | |
371 private_tab = chat_panel(self, -1, GROUP_TAB, group_name) | |
372 self.AddPage(private_tab, group_name, False) | |
373 private_tab.chatwnd.SetDefaultFontAndSize(self.font, self.fontsize) | |
374 self.group_tabs.append(private_tab) | |
375 self.newMsg(self.GetPageCount()-1) | |
376 self.AliasLib = component.get('alias') | |
377 wx.CallAfter(self.AliasLib.RefreshAliases) | |
378 return private_tab | |
379 | |
380 def create_null_tab(self, tab_name): | |
381 "Add a new chatpanel directly connected to integer 'playerid' via whispering." | |
382 private_tab = chat_panel(self, -1, NULL_TAB, tab_name) | |
383 self.AddPage(private_tab, tab_name, False) | |
384 private_tab.chatwnd.SetDefaultFontAndSize(self.font, self.fontsize) | |
385 self.null_tabs.append(private_tab) | |
386 self.newMsg(self.GetPageCount()-1) | |
387 self.AliasLib = component.get('alias') | |
388 wx.CallAfter(self.AliasLib.RefreshAliases) | |
389 return private_tab | |
390 | |
391 def onCloseTab(self, evt): | |
392 try: tabid = evt.GetSelection() | |
393 except: tabid = self.GetSelection() | |
394 if self.GetPageText(tabid) == 'Main Room': | |
395 #send no close error to chat | |
396 evt.Veto() | |
397 return | |
398 if self.GetPageText(tabid) == 'GM': | |
399 msg = "Are You Sure You Want To Close This Page?" | |
400 dlg = wx.MessageDialog(self, msg, "NotebookCtrl Question", | |
401 wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) | |
402 if wx.Platform != '__WXMAC__': | |
403 dlg.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, False)) | |
404 | |
405 if dlg.ShowModal() in [wx.ID_NO]: | |
406 dlg.Destroy() | |
407 evt.Veto() | |
408 return | |
409 dlg.Destroy() | |
410 self.GMChatPanel = None | |
411 self.settings.set_setting("GMWhisperTab", "0") | |
412 panel = self.GetPage(tabid) | |
413 if panel in self.whisper_tabs: self.whisper_tabs.remove(panel) | |
414 elif panel in self.group_tabs: self.group_tabs.remove(panel) | |
415 elif panel in self.null_tabs: self.null_tabs.remove(panel) | |
416 | |
417 def newMsg(self, tabid): | |
418 if tabid != self.GetSelection(): self.SetPageImage(tabid, 0) | |
419 | |
420 def onPageChanging(self, event): | |
421 """When private chattabs are selected, set the bitmap back to 'normal'.""" | |
422 event.Skip() | |
423 | |
424 def onPageChanged(self, event): | |
425 """When private chattabs are selected, set the bitmap back to 'normal'.""" | |
426 selected_idx = event.GetSelection() | |
427 self.SetPageImage(selected_idx, 1) | |
428 page = self.GetPage(selected_idx) | |
429 event.Skip() | |
430 | |
431 """ | |
432 This class defines and builds the Chat Frame for OpenRPG | |
433 | |
434 Inherits: wxPanel | |
435 | |
436 Defines: | |
437 __init__((self, parent, id, openrpg, sendtarget) | |
438 build_ctrls(self) | |
439 on_buffer_size(self,evt) | |
440 set_colors(self) | |
441 set_buffersize(self) | |
442 set_chat_text(self,txt) | |
443 OnChar(self,event) | |
444 on_chat_save(self,evt) | |
445 on_text_color(self,event) | |
446 colorize(self, color, text) | |
447 on_text_format(self,event) | |
448 OnSize(self,event) | |
449 scroll_down(self) | |
450 InfoPost(self,s) | |
451 Post(self,s="",send=False,myself=False) | |
452 ParsePost(self,s,send=False,myself=False) | |
453 ParseDice(self,s) | |
454 ParseNodes(self,s) | |
455 get_sha_checksum(self) | |
456 get_color(self) | |
457 | |
458 """ | |
459 | |
460 class chat_panel(wx.Panel): | |
461 | |
462 """ | |
463 This is the initialization subroutine | |
464 | |
465 !self : instance of self | |
466 !parent : parent that defines the chatframe | |
467 !id : | |
468 !openrpg : | |
469 !sendtarget: who gets outbound messages: either 'all' or a playerid | |
470 """ | |
471 | |
472 | |
473 def __init__(self, parent, id, tab_type, sendtarget): | |
474 wx.Panel.__init__(self, parent, id) | |
475 logger._set_log_to_console(False) | |
476 self.session = component.get('session') | |
477 self.settings = component.get('settings') | |
478 self.activeplugins = component.get('plugins') | |
479 self.parent = parent | |
480 # who receives outbound messages, either "all" or "playerid" string | |
481 self.sendtarget = sendtarget | |
482 self.type = tab_type | |
483 self.r_h = orpg.tools.rgbhex.RGBHex() | |
484 self.h = 0 | |
485 self.set_colors() | |
486 self.version = VERSION | |
487 self.histidx = -1 | |
488 self.temptext = "" | |
489 self.history = [] | |
490 self.storedata = [] | |
491 #self.lasthistevt = None | |
492 self.parsed=0 | |
493 #chat commands | |
494 self.lockscroll = False # set the default to scrolling on. | |
495 self.chat_cmds = commands.chat_commands(self) | |
496 self.html_strip = strip_html | |
183 | 497 self.f_keys = {wx.WXK_F1: 'event.GetKeyCode() == wx.WXK_F1', wx.WXK_F2: 'event.GetKeyCode() == wx.WXK_F2', |
498 wx.WXK_F3: 'event.GetKeyCode() == wx.WXK_F3', wx.WXK_F4: 'event.GetKeyCode() == wx.WXK_F4', | |
499 wx.WXK_F5: 'event.GetKeyCode() == wx.WXK_F5', wx.WXK_F6: 'event.GetKeyCode() == wx.WXK_F6', | |
500 wx.WXK_F7: 'event.GetKeyCode() == wx.WXK_F7', wx.WXK_F8: 'event.GetKeyCode() == wx.WXK_F8', | |
501 wx.WXK_F9: 'event.GetKeyCode() == wx.WXK_F9', wx.WXK_F10: 'event.GetKeyCode() == wx.WXK_F10', | |
502 wx.WXK_F11: 'event.GetKeyCode() == wx.WXK_F11', wx.WXK_F12: 'event.GetKeyCode() == wx.WXK_F12'} | |
156 | 503 #Alias Lib stuff |
504 self.defaultAliasName = 'Use Real Name' | |
505 self.defaultFilterName = 'No Filter' | |
506 self.advancedFilter = False | |
507 self.lastSend = 0 # this is used to help implement the player typing indicator | |
508 self.lastPress = 0 # this is used to help implement the player typing indicator | |
509 self.Bind(wx.EVT_SIZE, self.OnSize) | |
184 | 510 self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnSize) |
156 | 511 self.build_ctrls() |
512 StartupFont = self.settings.get_setting("defaultfont") | |
513 StartupFontSize = self.settings.get_setting("defaultfontsize") | |
514 if(StartupFont != "") and (StartupFontSize != ""): | |
515 try: self.set_default_font(StartupFont, int(StartupFontSize)) | |
516 except: pass | |
517 self.font = self.chatwnd.GetFont().GetFaceName() | |
518 self.fontsize = self.chatwnd.GetFont().GetPointSize() | |
519 self.scroll_down() | |
520 | |
521 def set_default_font(self, fontname=None, fontsize=None): | |
522 """Set all chatpanels to new default fontname/fontsize. | |
523 Returns current font settings in a (fontname, fontsize) tuple.""" | |
524 if (fontname is not None): newfont = fontname | |
525 else: newfont = self.font | |
526 if (fontsize is not None): newfontsize = int(fontsize) | |
527 else: newfontsize = int(self.fontsize) | |
528 self.chatwnd.SetDefaultFontAndSize(newfont, newfontsize) | |
529 self.InfoPost("Font is now " + newfont + " point size " + `newfontsize`) | |
530 self.font = newfont | |
531 self.fontsize = newfontsize | |
532 return (self.font, self.fontsize) | |
533 | |
534 def build_menu(self): | |
535 top_frame = component.get('frame') | |
536 menu = wx.Menu() | |
537 item = wx.MenuItem(menu, wx.ID_ANY, "&Background color", "Background color") | |
538 top_frame.Bind(wx.EVT_MENU, self.OnMB_BackgroundColor, item) | |
539 menu.AppendItem(item) | |
540 item = wx.MenuItem(menu, wx.ID_ANY, "&Text color", "Text color") | |
541 top_frame.Bind(wx.EVT_MENU, self.OnMB_TextColor, item) | |
542 menu.AppendItem(item) | |
543 menu.AppendSeparator() | |
544 item = wx.MenuItem(menu, wx.ID_ANY, "&Chat Focus\tCtrl-H", "Chat Focus") | |
545 self.setChatFocusMenu = item | |
546 top_frame.Bind(wx.EVT_MENU, self.set_chat_text_focus, item) | |
547 menu.AppendItem(item) | |
548 menu.AppendSeparator() | |
549 item = wx.MenuItem(menu, wx.ID_ANY, "Toggle &Scroll Lock", "Toggle Scroll Lock") | |
550 top_frame.Bind(wx.EVT_MENU, self.lock_scroll, item) | |
551 menu.AppendItem(item) | |
552 item = wx.MenuItem(menu, wx.ID_ANY, "Save Chat &Log", "Save Chat Log") | |
553 top_frame.Bind(wx.EVT_MENU, self.on_chat_save, item) | |
554 menu.AppendItem(item) | |
555 item = wx.MenuItem(menu, wx.ID_ANY, "Text &View", "Text View") | |
556 top_frame.Bind(wx.EVT_MENU, self.pop_textpop, item) | |
557 menu.AppendItem(item) | |
558 item = wx.MenuItem(menu, wx.ID_ANY, "Forward Tab\tCtrl+Tab", "Swap Tabs") | |
559 top_frame.Bind(wx.EVT_MENU, self.forward_tabs, item) | |
560 menu.AppendItem(item) | |
561 item = wx.MenuItem(menu, wx.ID_ANY, "Forward Tab\tCtrl+Shift+Tab", "Swap Tabs") | |
562 top_frame.Bind(wx.EVT_MENU, self.back_tabs, item) | |
563 menu.AppendItem(item) | |
564 menu.AppendSeparator() | |
565 settingmenu = wx.Menu() | |
566 wndmenu = wx.Menu() | |
567 tabmenu = wx.Menu() | |
568 toolmenu = wx.Menu() | |
569 item = wx.MenuItem(wndmenu, wx.ID_ANY, "Show Images", "Show Images", wx.ITEM_CHECK) | |
570 top_frame.Bind(wx.EVT_MENU, self.OnMB_ShowImages, item) | |
571 | |
572 wndmenu.AppendItem(item) | |
573 if self.settings.get_setting("Show_Images_In_Chat") == '1': item.Check(True) | |
574 item = wx.MenuItem(wndmenu, wx.ID_ANY, "Strip HTML", "Strip HTML", wx.ITEM_CHECK) | |
575 top_frame.Bind(wx.EVT_MENU, self.OnMB_StripHTML, item) | |
576 wndmenu.AppendItem(item) | |
577 if self.settings.get_setting("striphtml") == '1': item.Check(True) | |
578 item = wx.MenuItem(wndmenu, wx.ID_ANY, "Chat Time Index", "Chat Time Index", wx.ITEM_CHECK) | |
579 top_frame.Bind(wx.EVT_MENU, self.OnMB_ChatTimeIndex, item) | |
580 wndmenu.AppendItem(item) | |
581 if self.settings.get_setting("Chat_Time_Indexing") == '1': item.Check(True) | |
582 item = wx.MenuItem(wndmenu, wx.ID_ANY, "Chat Auto Complete", "Chat Auto Complete", wx.ITEM_CHECK) | |
583 top_frame.Bind(wx.EVT_MENU, self.OnMB_ChatAutoComplete, item) | |
584 wndmenu.AppendItem(item) | |
585 if self.settings.get_setting("SuppressChatAutoComplete") == '0': item.Check(True) | |
586 item = wx.MenuItem(wndmenu, wx.ID_ANY, "Show ID in Chat", "Show ID in Chat", wx.ITEM_CHECK) | |
587 top_frame.Bind(wx.EVT_MENU, self.OnMB_ShowIDinChat, item) | |
588 wndmenu.AppendItem(item) | |
589 if self.settings.get_setting("ShowIDInChat") == '1': item.Check(True) | |
590 item = wx.MenuItem(wndmenu, wx.ID_ANY, "Log Time Index", "Log Time Index", wx.ITEM_CHECK) | |
591 top_frame.Bind(wx.EVT_MENU, self.OnMB_LogTimeIndex, item) | |
592 wndmenu.AppendItem(item) | |
593 if self.settings.get_setting("TimeStampGameLog") == '1': item.Check(True) | |
594 settingmenu.AppendMenu(wx.ID_ANY, 'Chat Window', wndmenu ) | |
595 item = wx.MenuItem(tabmenu, wx.ID_ANY, "Tabbed Whispers", "Tabbed Whispers", wx.ITEM_CHECK) | |
596 top_frame.Bind(wx.EVT_MENU, self.OnMB_TabbedWhispers, item) | |
597 tabmenu.AppendItem(item) | |
598 if self.settings.get_setting("tabbedwhispers") == '1': item.Check(True) | |
599 item = wx.MenuItem(tabmenu, wx.ID_ANY, "GM Tab", "GM Tab", wx.ITEM_CHECK) | |
600 top_frame.Bind(wx.EVT_MENU, self.OnMB_GMTab, item) | |
601 tabmenu.AppendItem(item) | |
602 if self.settings.get_setting("GMWhisperTab") == '1':item.Check(True) | |
603 item = wx.MenuItem(tabmenu, wx.ID_ANY, "Group Whisper Tabs", "Group Whisper Tabs", wx.ITEM_CHECK) | |
604 top_frame.Bind(wx.EVT_MENU, self.OnMB_GroupWhisperTabs, item) | |
605 tabmenu.AppendItem(item) | |
606 if self.settings.get_setting("GroupWhisperTab") == '1': item.Check(True) | |
607 settingmenu.AppendMenu(wx.ID_ANY, 'Chat Tabs', tabmenu) | |
608 item = wx.MenuItem(toolmenu, wx.ID_ANY, "Dice Bar", "Dice Bar", wx.ITEM_CHECK) | |
609 top_frame.Bind(wx.EVT_MENU, self.OnMB_DiceBar, item) | |
610 toolmenu.AppendItem(item) | |
611 if self.settings.get_setting("DiceButtons_On") == '1': item.Check(True) | |
612 item = wx.MenuItem(toolmenu, wx.ID_ANY, "Format Buttons", "Format Buttons", wx.ITEM_CHECK) | |
613 top_frame.Bind(wx.EVT_MENU, self.OnMB_FormatButtons, item) | |
614 toolmenu.AppendItem(item) | |
615 if self.settings.get_setting("FormattingButtons_On") == '1': item.Check(True) | |
616 item = wx.MenuItem(toolmenu, wx.ID_ANY, "Alias Tool", "Alias Tool", wx.ITEM_CHECK) | |
617 top_frame.Bind(wx.EVT_MENU, self.OnMB_AliasTool, item) | |
618 toolmenu.AppendItem(item) | |
619 if self.settings.get_setting("AliasTool_On") == '1': item.Check(True) | |
620 settingmenu.AppendMenu(wx.ID_ANY, 'Chat Tool Bars', toolmenu) | |
621 menu.AppendMenu(wx.ID_ANY, 'Chat Settings', settingmenu) | |
622 top_frame.mainmenu.Insert(2, menu, '&Chat') | |
623 | |
624 ## Settings Menu Events | |
625 def OnMB_ShowImages(self, event): | |
626 if event.IsChecked(): self.settings.set_setting("Show_Images_In_Chat", '1') | |
627 else: self.settings.set_setting("Show_Images_In_Chat", '0') | |
628 | |
629 def OnMB_StripHTML(self, event): | |
630 if event.IsChecked(): self.settings.set_setting("striphtml", '1') | |
631 else: self.settings.set_setting("striphtml", '0') | |
632 | |
633 def OnMB_ChatTimeIndex(self, event): | |
634 if event.IsChecked(): self.settings.set_setting("Chat_Time_Indexing", '1') | |
635 else: self.settings.set_setting("Chat_Time_Indexing", '0') | |
636 | |
637 def OnMB_ChatAutoComplete(self, event): | |
638 if event.IsChecked(): self.settings.set_setting("SuppressChatAutoComplete", '0') | |
639 else: self.settings.set_setting("SuppressChatAutoComplete", '1') | |
640 | |
641 def OnMB_ShowIDinChat(self, event): | |
642 if event.IsChecked(): self.settings.set_setting("ShowIDInChat", '1') | |
643 else: self.settings.set_setting("ShowIDInChat", '0') | |
644 | |
645 def OnMB_LogTimeIndex(self, event): | |
646 if event.IsChecked(): self.settings.set_setting("TimeStampGameLog", '1') | |
647 else: self.settings.set_setting("TimeStampGameLog", '0') | |
648 | |
649 def OnMB_TabbedWhispers(self, event): | |
650 if event.IsChecked(): self.settings.set_setting("tabbedwhispers", '1') | |
651 else: self.settings.set_setting("tabbedwhispers", '0') | |
652 | |
653 def OnMB_GMTab(self, event): | |
654 if event.IsChecked(): | |
655 self.settings.set_setting("GMWhisperTab", '1') | |
656 self.parent.create_gm_tab() | |
657 else: self.settings.set_setting("GMWhisperTab", '0') | |
658 | |
659 def OnMB_GroupWhisperTabs(self, event): | |
660 if event.IsChecked(): self.settings.set_setting("GroupWhisperTab", '1') | |
661 else: self.settings.set_setting("GroupWhisperTab", '0') | |
662 | |
663 def OnMB_DiceBar(self, event): | |
664 act = '0' | |
665 if event.IsChecked(): | |
666 self.settings.set_setting("DiceButtons_On", '1') | |
667 act = '1' | |
668 else: self.settings.set_setting("DiceButtons_On", '0') | |
669 self.toggle_dice(act) | |
670 try: self.parent.GMChatPanel.toggle_dice(act) | |
671 except: pass | |
672 for panel in self.parent.whisper_tabs: panel.toggle_dice(act) | |
673 for panel in self.parent.group_tabs: panel.toggle_dice(act) | |
674 for panel in self.parent.null_tabs: panel.toggle_dice(act) | |
675 | |
676 def OnMB_FormatButtons(self, event): | |
677 act = '0' | |
678 if event.IsChecked(): | |
679 self.settings.set_setting("FormattingButtons_On", '1') | |
680 act = '1' | |
681 else: | |
682 self.settings.set_setting("FormattingButtons_On", '0') | |
683 self.toggle_formating(act) | |
684 try: self.parent.GMChatPanel.toggle_formating(act) | |
685 except: pass | |
686 for panel in self.parent.whisper_tabs: panel.toggle_formating(act) | |
687 for panel in self.parent.group_tabs: panel.toggle_formating(act) | |
688 for panel in self.parent.null_tabs: panel.toggle_formating(act) | |
689 | |
690 def OnMB_AliasTool(self, event): | |
691 act = '0' | |
692 if event.IsChecked(): | |
693 self.settings.set_setting("AliasTool_On", '1') | |
694 act = '1' | |
695 else: self.settings.set_setting("AliasTool_On", '0') | |
696 self.toggle_alias(act) | |
697 try: self.parent.GMChatPanel.toggle_alias(act) | |
698 except: pass | |
699 for panel in self.parent.whisper_tabs: panel.toggle_alias(act) | |
700 for panel in self.parent.group_tabs: panel.toggle_alias(act) | |
701 for panel in self.parent.null_tabs:panel.toggle_alias(act) | |
702 | |
703 def OnMB_BackgroundColor(self, event): | |
704 top_frame = component.get('frame') | |
705 hexcolor = self.get_color() | |
706 if hexcolor != None: | |
707 self.bgcolor = hexcolor | |
708 self.settings.set_setting('bgcolor', hexcolor) | |
709 self.chatwnd.SetPage(self.ResetPage()) | |
710 if self.settings.get_setting('ColorTree') == '1': | |
711 top_frame.tree.SetBackgroundColour(self.settings.get_setting('bgcolor')) | |
712 top_frame.tree.Refresh() | |
713 top_frame.players.SetBackgroundColour(self.settings.get_setting('bgcolor')) | |
714 top_frame.players.Refresh() | |
715 else: | |
716 top_frame.tree.SetBackgroundColour('white') | |
717 top_frame.tree.SetForegroundColour('black') | |
718 top_frame.tree.Refresh() | |
719 top_frame.players.SetBackgroundColour('white') | |
720 top_frame.players.SetForegroundColour('black') | |
721 top_frame.players.Refresh() | |
722 self.chatwnd.scroll_down() | |
723 | |
724 | |
725 def OnMB_TextColor(self, event): | |
726 top_frame = component.get('frame') | |
727 hexcolor = self.get_color() | |
728 if hexcolor != None: | |
729 self.textcolor = hexcolor | |
730 self.settings.set_setting('textcolor', hexcolor) | |
731 self.chatwnd.SetPage(self.ResetPage()) | |
732 if self.settings.get_setting('ColorTree') == '1': | |
733 top_frame.tree.SetForegroundColour(self.settings.get_setting('textcolor')) | |
734 top_frame.tree.Refresh() | |
735 top_frame.players.SetForegroundColour(self.settings.get_setting('textcolor')) | |
736 top_frame.players.Refresh() | |
737 else: | |
738 top_frame.tree.SetBackgroundColour('white') | |
739 top_frame.tree.SetForegroundColour('black') | |
740 top_frame.tree.Refresh() | |
741 top_frame.players.SetBackgroundColour('white') | |
742 top_frame.players.SetForegroundColour('black') | |
743 top_frame.players.Refresh() | |
744 self.chatwnd.scroll_down() | |
745 | |
746 | |
747 def get_hot_keys(self): | |
748 # dummy menus for hotkeys | |
749 self.build_menu() | |
750 entries = [] | |
751 entries.append((wx.ACCEL_CTRL, ord('H'), self.setChatFocusMenu.GetId())) | |
752 return entries | |
753 | |
754 | |
755 def forward_tabs(self, evt): | |
756 self.parent.AdvanceSelection() | |
757 | |
758 def back_tabs(self, evt): | |
759 self.parent.AdvanceSelection(False) | |
760 | |
761 def build_ctrls(self): | |
762 self.chatwnd = chat_html_window(self,-1) | |
763 self.set_colors() | |
764 wx.CallAfter(self.chatwnd.SetPage, self.chatwnd.Header()) | |
765 if (self.sendtarget == "all"): | |
766 wx.CallAfter(self.Post, self.colorize(self.syscolor, | |
767 "<b>Welcome to <a href='http://www.openrpg.com'>OpenRPG</a> version " + self.version + "... </b>")) | |
768 self.chattxt = orpg.tools.predTextCtrl.predTextCtrl(self, -1, "", | |
769 style=wx.TE_PROCESS_ENTER |wx.TE_PROCESS_TAB|wx.TE_LINEWRAP, | |
770 keyHook = self.myKeyHook, validator=None ) | |
771 self.build_bar() | |
772 self.basesizer = wx.BoxSizer(wx.VERTICAL) | |
773 self.basesizer.Add( self.chatwnd, 1, wx.EXPAND ) | |
774 self.basesizer.Add( self.toolbar_sizer, 0, wx.EXPAND ) | |
140 | 775 self.basesizer.Add( self.chattxt, 0, wx.EXPAND ) |
156 | 776 self.SetSizer(self.basesizer) |
777 self.SetAutoLayout(True) | |
778 self.Fit() | |
779 #events | |
780 self.Bind(wx.EVT_BUTTON, self.on_text_format, self.boldButton) | |
781 self.Bind(wx.EVT_BUTTON, self.on_text_format, self.italicButton) | |
782 self.Bind(wx.EVT_BUTTON, self.on_text_format, self.underlineButton) | |
783 self.Bind(wx.EVT_BUTTON, self.on_text_color, self.color_button) | |
784 self.Bind(wx.EVT_BUTTON, self.on_chat_save, self.saveButton) | |
785 self.Bind(wx.EVT_BUTTON, self.onDieRoll, self.d4Button) | |
786 self.Bind(wx.EVT_BUTTON, self.onDieRoll, self.d6Button) | |
787 self.Bind(wx.EVT_BUTTON, self.onDieRoll, self.d8Button) | |
788 self.Bind(wx.EVT_BUTTON, self.onDieRoll, self.d10Button) | |
789 self.Bind(wx.EVT_BUTTON, self.onDieRoll, self.d12Button) | |
790 self.Bind(wx.EVT_BUTTON, self.onDieRoll, self.d20Button) | |
791 self.Bind(wx.EVT_BUTTON, self.onDieRoll, self.d100Button) | |
792 self.dieIDs = {} | |
793 self.dieIDs[self.d4Button.GetId()] = 'd4' | |
794 self.dieIDs[self.d6Button.GetId()] = 'd6' | |
795 self.dieIDs[self.d8Button.GetId()] = 'd8' | |
796 self.dieIDs[self.d10Button.GetId()] = 'd10' | |
797 self.dieIDs[self.d12Button.GetId()] = 'd12' | |
798 self.dieIDs[self.d20Button.GetId()] = 'd20' | |
799 self.dieIDs[self.d100Button.GetId()] = 'd100' | |
800 self.Bind(wx.EVT_BUTTON, self.pop_textpop, self.textpop_lock) | |
801 self.Bind(wx.EVT_BUTTON, self.lock_scroll, self.scroll_lock) | |
802 self.chattxt.Bind(wx.EVT_MOUSEWHEEL, self.chatwnd.mouse_wheel) | |
803 self.chattxt.Bind(wx.EVT_CHAR, self.chattxt.OnChar) | |
183 | 804 self.chattxt.Bind(wx.EVT_KEY_DOWN, self.on_chat_key_down) |
156 | 805 self.chattxt.Bind(wx.EVT_TEXT_COPY, self.chatwnd.OnM_EditCopy) |
806 | |
807 def build_bar(self): | |
808 self.toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL) | |
809 self.scroll_lock = None | |
810 self.numDieText = None | |
811 self.dieModText = None | |
812 if self.settings.get_setting('Toolbar_On') == "1": | |
813 self.build_alias() | |
814 self.build_dice() | |
815 self.build_scroll() | |
816 self.build_text() | |
817 self.toolbar_sizer.Add(self.textpop_lock, 0, wx.EXPAND) | |
818 self.toolbar_sizer.Add(self.scroll_lock, 0, wx.EXPAND) | |
819 self.build_formating() | |
820 self.build_colorbutton() | |
821 | |
822 def build_scroll(self): | |
823 self.scroll_lock = wx.Button( self, wx.ID_ANY, "Scroll ON",size= wx.Size(80,25)) | |
824 | |
135 | 825 def build_alias(self): |
156 | 826 self.aliasSizer = wx.BoxSizer(wx.HORIZONTAL) |
827 self.aliasList = wx.Choice(self, wx.ID_ANY, size=(100, 25), choices=[self.defaultAliasName]) | |
828 self.aliasButton = createMaskedButton( self, dir_struct["icon"] + 'player.gif', | |
140 | 829 'Refresh list of aliases from Game Tree', |
156 | 830 wx.ID_ANY, '#bdbdbd' ) |
831 self.aliasList.SetSelection(0) | |
832 self.filterList = wx.Choice(self, wx.ID_ANY, size=(100, 25), choices=[self.defaultFilterName]) | |
833 self.filterButton = createMaskedButton( self, dir_struct["icon"] + 'add_filter.gif', | |
140 | 834 'Refresh list of filters from Game Tree', |
156 | 835 wx.ID_ANY, '#bdbdbd' ) |
135 | 836 self.filterList.SetSelection(0) |
837 | |
156 | 838 self.aliasSizer.Add( self.aliasButton, 0, wx.EXPAND ) |
839 self.aliasSizer.Add( self.aliasList,0,wx.EXPAND) | |
840 self.aliasSizer.Add( self.filterButton, 0, wx.EXPAND ) | |
135 | 841 self.aliasSizer.Add( self.filterList,0,wx.EXPAND) |
842 | |
843 self.toolbar_sizer.Add(self.aliasSizer, 0, wx.EXPAND) | |
844 | |
156 | 845 if self.settings.get_setting('AliasTool_On') == '0': self.toggle_alias('0') |
846 else: self.toggle_alias('1') | |
847 | |
135 | 848 def toggle_alias(self, act): |
849 if act == '0': self.toolbar_sizer.Show(self.aliasSizer, False) | |
850 else: self.toolbar_sizer.Show(self.aliasSizer, True) | |
156 | 851 self.toolbar_sizer.Layout() |
852 | |
853 def build_text(self): | |
854 self.textpop_lock = createMaskedButton(self, dir_struct["icon"]+'note.gif', 'Open Text View Of Chat Session', wx.ID_ANY, '#bdbdbd') | |
855 | |
856 | |
140 | 857 def build_dice(self): |
156 | 858 self.diceSizer = wx.BoxSizer(wx.HORIZONTAL) |
140 | 859 self.numDieText = wx.TextCtrl( self, wx.ID_ANY, "1", |
156 | 860 size= wx.Size(25, 25), validator=orpg.tools.inputValidator.MathOnlyValidator() ) |
140 | 861 self.dieModText = wx.TextCtrl( self, wx.ID_ANY, "", |
156 | 862 size= wx.Size(50, 25), validator=orpg.tools.inputValidator.MathOnlyValidator() ) |
863 self.d4Button = createMaskedButton(self, dir_struct["icon"]+'b_d4.gif', 'Roll d4', wx.ID_ANY) | |
864 self.d6Button = createMaskedButton(self, dir_struct["icon"]+'b_d6.gif', 'Roll d6', wx.ID_ANY) | |
865 self.d8Button = createMaskedButton(self, dir_struct["icon"]+'b_d8.gif', 'Roll d8', wx.ID_ANY) | |
866 self.d10Button = createMaskedButton(self, dir_struct["icon"]+'b_d10.gif', 'Roll d10', wx.ID_ANY) | |
867 self.d12Button = createMaskedButton(self, dir_struct["icon"]+'b_d12.gif', 'Roll d12', wx.ID_ANY) | |
868 self.d20Button = createMaskedButton(self, dir_struct["icon"]+'b_d20.gif', 'Roll d20', wx.ID_ANY) | |
140 | 869 self.d100Button = createMaskedButton(self, dir_struct["icon"]+'b_d100.gif', 'Roll d100', wx.ID_ANY) |
156 | 870 |
871 self.diceSizer.Add( self.numDieText, 0, wx.ALIGN_CENTER | wx.EXPAND) | |
872 self.diceSizer.Add( self.d4Button, 0 ,wx.EXPAND) | |
873 self.diceSizer.Add( self.d6Button, 0 ,wx.EXPAND) | |
874 self.diceSizer.Add( self.d8Button, 0 ,wx.EXPAND) | |
875 self.diceSizer.Add( self.d10Button, 0 ,wx.EXPAND) | |
876 self.diceSizer.Add( self.d12Button, 0 ,wx.EXPAND) | |
877 self.diceSizer.Add( self.d20Button, 0 ,wx.EXPAND) | |
878 self.diceSizer.Add( self.d100Button, 0 ,wx.EXPAND) | |
140 | 879 self.diceSizer.Add( self.dieModText, 0, wx.ALIGN_CENTER, 5 ) |
880 | |
156 | 881 self.toolbar_sizer.Add( self.diceSizer, 0, wx.EXPAND) |
882 if self.settings.get_setting('DiceButtons_On') == '0': self.toggle_dice('0') | |
883 else: self.toggle_dice('1') | |
884 | |
885 | |
886 def toggle_dice(self, act): | |
140 | 887 if act == '0': self.toolbar_sizer.Show(self.diceSizer, False) |
888 else: self.toolbar_sizer.Show(self.diceSizer, True) | |
156 | 889 self.toolbar_sizer.Layout() |
890 | |
891 | |
140 | 892 def build_formating(self): |
156 | 893 self.formatSizer = wx.BoxSizer(wx.HORIZONTAL) |
894 self.boldButton = createMaskedButton( self, dir_struct["icon"]+'bold.gif', | |
895 'Make the selected text Bold', wx.ID_ANY, '#bdbdbd') | |
896 self.italicButton = createMaskedButton( self, dir_struct["icon"]+'italic.gif', | |
897 'Italicize the selected text', wx.ID_ANY, '#bdbdbd' ) | |
898 self.underlineButton = createMaskedButton( self, dir_struct["icon"]+'underlined.gif', | |
140 | 899 'Underline the selected text', wx.ID_ANY, '#bdbdbd' ) |
156 | 900 |
901 self.formatSizer.Add( self.boldButton, 0, wx.EXPAND ) | |
902 self.formatSizer.Add( self.italicButton, 0, wx.EXPAND ) | |
140 | 903 self.formatSizer.Add( self.underlineButton, 0, wx.EXPAND ) |
156 | 904 self.toolbar_sizer.Add( self.formatSizer, 0, wx.EXPAND ) |
905 if self.settings.get_setting('FormattingButtons_On') == '0': self.toggle_formating('0') | |
906 else: self.toggle_formating('1') | |
907 | |
908 | |
909 def toggle_formating(self, act): | |
140 | 910 if act == '0': self.toolbar_sizer.Show(self.formatSizer, False) |
911 else: self.toolbar_sizer.Show(self.formatSizer, True) | |
156 | 912 self.toolbar_sizer.Layout() |
913 | |
914 def build_colorbutton(self): | |
915 self.color_button = createMaskedButton(self, dir_struct["icon"]+'textcolor.gif', | |
916 'Text Color', wx.ID_ANY, '#bdbdbd', | |
917 wx.BITMAP_TYPE_GIF) | |
918 | |
919 self.saveButton = createMaskedButton(self, dir_struct["icon"]+'save.bmp', | |
920 'Save the chatbuffer', wx.ID_ANY, | |
921 '#c0c0c0', wx.BITMAP_TYPE_BMP ) | |
922 self.color_button.SetBackgroundColour(self.settings.get_setting('mytextcolor')) | |
923 self.toolbar_sizer.Add(self.color_button, 0, wx.EXPAND) | |
924 self.toolbar_sizer.Add(self.saveButton, 0, wx.EXPAND) | |
925 | |
926 | |
927 def OnMotion(self, evt): | |
928 contain = self.chatwnd.GetInternalRepresentation() | |
929 if contain: | |
930 sx = sy = 0 | |
931 x = y = 0 | |
932 (sx,sy) = self.chatwnd.GetViewStart() | |
933 (sx1,sy1) = self.chatwnd.GetScrollPixelsPerUnit() | |
934 sx = sx*sx1 | |
935 sy = sy*sy1 | |
936 (x,y) = evt.GetPosition() | |
937 lnk = contain.GetLink(sx+x,sy+y) | |
938 if lnk: | |
939 try: | |
940 link = lnk.GetHref() | |
941 self.session.set_status_url(link) | |
942 except: pass | |
943 else: logger.general("Error, self.chatwnd.GetInternalRepresentation() return None") | |
944 evt.Skip() | |
945 | |
946 def myKeyHook(self, event): | |
947 if self.session.get_status() == MPLAY_CONNECTED: # only do if we're connected | |
948 thisPress = time.time() # thisPress is local temp variable | |
949 if (thisPress - self.lastSend) > 4: # Check to see if it's been 5 seconds since our last notice | |
950 # If we're not already typing, then self.lastSend will be 0 | |
951 self.sendTyping(1) # send a not typing event here (1 for True) | |
952 self.lastPress = thisPress # either way, record the time of this keystroke for use in | |
953 # self.typingTimerFunc() | |
954 if self.settings.get_setting('SuppressChatAutoComplete') == '1': | |
955 logger.debug("Exit chat_panel->myKeyHook(self, event) return 1") | |
956 return 1 | |
957 else: | |
958 logger.debug("Exit chat_panel->myKeyHook(self, event) return 0") | |
959 return 0 | |
960 | |
961 def typingTimerFunc(self, event): | |
962 #following added by mDuo13 | |
963 ##############refresh_counter()############## | |
964 for plugin_fname in self.activeplugins.keys(): | |
965 plugin = self.activeplugins[plugin_fname] | |
966 try: plugin.refresh_counter() | |
967 except Exception, e: | |
968 if str(e) != "'module' object has no attribute 'refresh_counter'": | |
969 logger.general(traceback.format_exc()) | |
970 logger.general("EXCEPTION: " + str(e)) | |
971 #end mDuo13 added code | |
972 if self.lastSend: # This will be zero when not typing, so equiv to if is_typing | |
973 thisTime = time.time() # thisTime is a local temp variable | |
974 if (thisTime - self.lastPress) > 4: # Check to see if it's been 5 seconds since our last keystroke | |
975 # If we're not already typing, then self.lastSend will be 0 | |
976 | |
977 self.sendTyping(0) # send a typing event here (0 for False) | |
978 | |
979 def sendTyping(self, typing): | |
980 if typing: | |
981 self.lastSend = time.time() # remember our send time for use in myKeyHook() | |
982 #I think this is cleaner | |
983 status_text = self.settings.get_setting('TypingStatusAlias') | |
984 if status_text == "" or status_text == None: status_text = "Typing" | |
985 self.session.set_text_status(status_text) | |
986 else: | |
987 self.lastSend = 0 # set lastSend to zero to indicate we're not typing | |
988 #I think this is cleaner | |
989 status_text = self.settings.get_setting('IdleStatusAlias') | |
990 if status_text == "" or status_text == None: status_text = "Idle" | |
991 self.session.set_text_status(status_text) | |
992 | |
993 def set_colors(self): | |
994 # chat window backround color | |
995 self.bgcolor = self.settings.get_setting('bgcolor') | |
996 # chat window normal text color | |
997 self.textcolor = self.settings.get_setting('textcolor') | |
998 # color of text player types | |
999 self.mytextcolor = self.settings.get_setting('mytextcolor') | |
1000 # color of system warnings | |
1001 self.syscolor = self.settings.get_setting('syscolor') | |
1002 # color of system info messages | |
1003 self.infocolor = self.settings.get_setting('infocolor') | |
1004 # color of emotes | |
1005 self.emotecolor = self.settings.get_setting('emotecolor') | |
1006 # color of whispers | |
1007 self.whispercolor = self.settings.get_setting('whispercolor') | |
1008 | |
1009 def set_chat_text(self, txt): | |
1010 self.chattxt.SetValue(txt) | |
1011 self.chattxt.SetFocus() | |
1012 self.chattxt.SetInsertionPointEnd() | |
1013 | |
1014 | |
1015 def get_chat_text(self): | |
1016 return self.chattxt.GetValue() | |
1017 | |
1018 # This subroutine sets the focus to the chat window | |
1019 | |
1020 def set_chat_text_focus(self, event): | |
1021 wx.CallAfter(self.chattxt.SetFocus) | |
183 | 1022 |
1023 def submit_chat_text(self, s): | |
1024 self.histidx = -1 | |
1025 self.temptext = "" | |
1026 self.history = [s] + self.history | |
1027 | |
1028 # play sound | |
1029 sound_file = self.settings.get_setting("SendSound") | |
1030 if sound_file != '': component.get('sound').play(sound_file) | |
1031 if s[0] != "/": ## it's not a slash command | |
1032 s = self.ParsePost( s, True, True ) | |
1033 else: self.chat_cmds.docmd(s) # emote is in chatutils.py | |
1034 | |
1035 def on_chat_key_down(self, event): | |
1036 s = self.chattxt.GetValue() | |
1037 if event.GetKeyCode() == wx.WXK_RETURN and not event.ShiftDown(): | |
1038 logger.debug("event.GetKeyCode() == wx.WXK_RETURN") | |
1039 self.set_colors() | |
1040 if self.session.get_status() == MPLAY_CONNECTED: | |
1041 self.sendTyping(0) | |
1042 if len(s): | |
1043 self.chattxt.SetValue('') | |
1044 s = s.replace('\n', '<br />') | |
1045 self.submit_chat_text(s) | |
1046 return | |
1047 event.Skip() | |
156 | 1048 |
1049 def OnChar(self, event): | |
1050 s = self.chattxt.GetValue() | |
1051 | |
183 | 1052 macroText = "" |
1053 s_key = False | |
1054 if self.f_keys.has_key(event.GetKeyCode()): s_key = self.f_keys[event.GetKeyCode()] | |
156 | 1055 |
183 | 1056 if s_key: macroText = settings.get(s_key[29:]) |
156 | 1057 |
1058 # Append to the existing typed text as needed and make sure the status doesn't change back. | |
1059 if len(macroText): | |
1060 self.sendTyping(0) | |
183 | 1061 self.submit_chat_text(macroText) |
156 | 1062 |
1063 ## UP KEY | |
1064 elif event.GetKeyCode() == wx.WXK_UP: | |
1065 logger.debug("event.GetKeyCode() == wx.WXK_UP") | |
1066 if self.histidx < len(self.history)-1: | |
1067 if self.histidx is -1: self.temptext = self.chattxt.GetValue() | |
1068 self.histidx += 1 | |
1069 self.chattxt.SetValue(self.history[self.histidx]) | |
1070 self.chattxt.SetInsertionPointEnd() | |
1071 else: | |
184 | 1072 self.histidx = len(self.history) -1 |
156 | 1073 |
1074 ## DOWN KEY | |
1075 elif event.GetKeyCode() == wx.WXK_DOWN: | |
1076 logger.debug("event.GetKeyCode() == wx.WXK_DOWN") | |
1077 #histidx of -1 indicates currently viewing text that's not in self.history | |
1078 if self.histidx > -1: | |
1079 self.histidx -= 1 | |
1080 if self.histidx is -1: #remember, it just decreased | |
1081 self.chattxt.SetValue(self.temptext) | |
1082 else: self.chattxt.SetValue(self.history[self.histidx]) | |
1083 self.chattxt.SetInsertionPointEnd() | |
184 | 1084 else: self.histidx = -1 |
156 | 1085 |
1086 ## TAB KEY | |
1087 elif event.GetKeyCode() == wx.WXK_TAB: | |
1088 logger.debug("event.GetKeyCode() == wx.WXK_TAB") | |
1089 if s !="": | |
1090 found = 0 | |
1091 nicks = [] | |
1092 testnick = "" | |
1093 inlength = len(s) | |
1094 for getnames in self.session.players.keys(): | |
1095 striphtmltag = re.compile ('<[^>]+>*') | |
1096 testnick = striphtmltag.sub ("", self.session.players[getnames][0]) | |
1097 if string.lower(s) == string.lower(testnick[:inlength]): | |
1098 found = found + 1 | |
1099 nicks[len(nicks):]=[testnick] | |
1100 if found == 0: ## no nick match | |
1101 self.Post(self.colorize(self.syscolor," ** No match found")) | |
1102 elif found > 1: ## matched more than 1, tell user what matched | |
1103 nickstring = "" | |
1104 nicklist = [] | |
1105 for foundnicks in nicks: | |
1106 nickstring = nickstring + foundnicks + ", " | |
1107 nicklist.append(foundnicks) | |
1108 nickstring = nickstring[:-2] | |
1109 self.Post(self.colorize(self.syscolor, " ** Multiple matches found: " + nickstring)) | |
1110 # set text to the prefix match between first two matches | |
1111 settext = re.match(''.join(map(lambda x: '(%s?)' % x, string.lower(nicklist[0]))), string.lower(nicklist[1])).group() | |
1112 # run through the rest of the nicks | |
1113 for i in nicklist: | |
1114 settext = re.match(''.join(map(lambda x: '(%s?)' % x, string.lower(i))), string.lower(settext)).group() | |
1115 if settext: | |
1116 self.chattxt.SetValue(settext) | |
1117 self.chattxt.SetInsertionPointEnd() | |
1118 else: ## put the matched name in the chattxt box | |
1119 settext = nicks[0] + ": " | |
1120 self.chattxt.SetValue(settext) | |
1121 self.chattxt.SetInsertionPointEnd() | |
1122 else: ## not online, and no text in chattxt box | |
1123 self.Post(self.colorize(self.syscolor, " ** That's the Tab key, Dave")) | |
1124 | |
1125 ## PAGE UP | |
1126 elif event.GetKeyCode() in (wx.WXK_PRIOR, wx.WXK_PAGEUP): | |
1127 logger.debug("event.GetKeyCode() in (wx.WXK_PRIOR, wx.WXK_PAGEUP)") | |
1128 self.chatwnd.ScrollPages(-1) | |
1129 if not self.lockscroll: self.lock_scroll(0) | |
1130 | |
1131 ## PAGE DOWN | |
1132 elif event.GetKeyCode() in (wx.WXK_NEXT, wx.WXK_PAGEDOWN): | |
1133 logger.debug("event.GetKeyCode() in (wx.WXK_NEXT, wx.WXK_PAGEDOWN)") | |
1134 if not self.lockscroll: self.lock_scroll(0) | |
1135 if ((self.chatwnd.GetScrollRange(1)-self.chatwnd.GetScrollPos(1)-self.chatwnd.GetScrollThumb(1) < 30) and self.lockscroll): | |
1136 self.lock_scroll(0) | |
1137 self.chatwnd.ScrollPages(1) | |
1138 | |
1139 ## END | |
1140 elif event.GetKeyCode() == wx.WXK_END: | |
1141 logger.debug("event.GetKeyCode() == wx.WXK_END") | |
1142 if self.lockscroll: | |
1143 self.lock_scroll(0) | |
1144 self.Post() | |
1145 event.Skip() | |
1146 | |
183 | 1147 elif event.GetKeyCode() == wx.WXK_RETURN and event.ShiftDown(): |
1148 st = self.chattxt.GetValue().split('\x0b') | |
1149 st += '\n' | |
1150 i = self.chattxt.GetInsertionPoint() | |
1151 self.chattxt.SetValue(''.join(st)) | |
1152 self.chattxt.SetInsertionPoint(i+1) | |
1153 return | |
1154 | |
156 | 1155 ## NOTHING |
1156 else: event.Skip() | |
1157 logger.debug("Exit chat_panel->OnChar(self, event)") | |
1158 | |
1159 def onDieRoll(self, evt): | |
1160 """Roll the dice based on the button pressed and the die modifiers entered, if any.""" | |
1161 # Get any die modifiers if they have been entered | |
1162 numDie = self.numDieText.GetValue() | |
1163 dieMod = self.dieModText.GetValue() | |
1164 dieText = numDie | |
1165 # Now, apply and roll die mods based on the button that was pressed | |
1166 id = evt.GetId() | |
1167 if self.dieIDs.has_key(id): dieText += self.dieIDs[id] | |
1168 if len(dieMod) and dieMod[0] not in "*/-+": dieMod = "+" + dieMod | |
1169 dieText += dieMod | |
1170 dieText = "[" + dieText + "]" | |
1171 self.ParsePost(dieText, 1, 1) | |
1172 self.chattxt.SetFocus() | |
1173 | |
1174 def on_chat_save(self, evt): | |
1175 f = wx.FileDialog(self,"Save Chat Buffer",".","","HTM* (*.htm*)|*.htm*|HTML (*.html)|*.html|HTM (*.htm)|*.htm",wx.SAVE) | |
1176 if f.ShowModal() == wx.ID_OK: | |
1177 file = open(f.GetPath(), "w") | |
1178 file.write(self.ResetPage() + "</body></html>") | |
1179 file.close() | |
1180 f.Destroy() | |
1181 os.chdir(dir_struct["home"]) | |
1182 | |
1183 def ResetPage(self): | |
1184 self.set_colors() | |
1185 buffertext = self.chatwnd.Header() + "\n" | |
1186 buffertext += chat_util.strip_body_tags(self.chatwnd.StripHeader()).replace("<br>", | |
1187 "<br />").replace('</html>', | |
1188 '').replace("<br />", | |
1189 "<br />\n").replace("\n\n", '') | |
1190 return buffertext | |
1191 | |
1192 def on_text_color(self, event): | |
1193 hexcolor = self.r_h.do_hex_color_dlg(self) | |
1194 if hexcolor != None: | |
1195 (beg,end) = self.chattxt.GetSelection() | |
1196 if beg != end: | |
1197 txt = self.chattxt.GetValue() | |
1198 txt = txt[:beg]+self.colorize(hexcolor,txt[beg:end]) +txt[end:] | |
1199 self.chattxt.SetValue(txt) | |
1200 self.chattxt.SetInsertionPointEnd() | |
1201 self.chattxt.SetFocus() | |
1202 else: | |
1203 self.color_button.SetBackgroundColour(hexcolor) | |
1204 self.mytextcolor = hexcolor | |
1205 self.settings.set_setting('mytextcolor',hexcolor) | |
1206 self.set_colors() | |
1207 self.Post() | |
1208 | |
1209 def colorize(self, color, text): | |
1210 """Puts font tags of 'color' around 'text' value, and returns the string""" | |
1211 return "<font color='" + color + "'>" + text + "</font>" | |
1212 | |
1213 def on_text_format(self, event): | |
1214 id = event.GetId() | |
1215 txt = self.chattxt.GetValue() | |
1216 (beg,end) = self.chattxt.GetSelection() | |
1217 if beg != end: sel_txt = txt[beg:end] | |
1218 else: sel_txt = txt | |
1219 if id == self.boldButton.GetId(): sel_txt = "<b>" + sel_txt + "</b>" | |
1220 elif id == self.italicButton.GetId(): sel_txt = "<i>" + sel_txt + "</i>" | |
1221 elif id == self.underlineButton.GetId(): sel_txt = "<u>" + sel_txt + "</u>" | |
1222 if beg != end: txt = txt[:beg] + sel_txt + txt[end:] | |
1223 else: txt = sel_txt | |
1224 self.chattxt.SetValue(txt) | |
1225 self.chattxt.SetInsertionPointEnd() | |
1226 self.chattxt.SetFocus() | |
1227 | |
1228 def lock_scroll(self, event): | |
1229 if self.lockscroll: | |
1230 self.lockscroll = False | |
1231 self.scroll_lock.SetLabel("Scroll ON") | |
1232 if len(self.storedata) != 0: | |
1233 for line in self.storedata: self.chatwnd.AppendToPage(line) | |
1234 self.storedata = [] | |
1235 self.scroll_down() | |
1236 else: | |
1237 self.lockscroll = True | |
1238 self.scroll_lock.SetLabel("Scroll OFF") | |
1239 | |
1240 def pop_textpop(self, event): | |
1241 """searchable popup text view of chatbuffer""" | |
1242 h_buffertext = self.ResetPage() | |
1243 h_dlg = orpgScrolledMessageFrameEditor(self, h_buffertext, "Text View of Chat Window", None, (500,300)) | |
1244 h_dlg.Show(True) | |
1245 | |
1246 def OnSize(self, event=None): | |
1247 event.Skip() | |
1248 wx.CallAfter(self.scroll_down) | |
1249 | |
1250 def scroll_down(self): | |
1251 self.Freeze() | |
1252 self.chatwnd.scroll_down() | |
1253 self.Thaw() | |
1254 | |
1255 ###### message helpers ###### | |
1256 | |
1257 def PurgeChat(self): | |
1258 self.set_colors() | |
1259 self.chatwnd.SetPage(self.chatwnd.Header()) | |
1260 | |
1261 def system_message(self, text): | |
1262 self.send_chat_message(text,chat_msg.SYSTEM_MESSAGE) | |
1263 self.SystemPost(text) | |
1264 | |
1265 def info_message(self, text): | |
1266 self.send_chat_message(text,chat_msg.INFO_MESSAGE) | |
1267 self.InfoPost(text) | |
1268 | |
1269 def get_gms(self): | |
1270 the_gms = [] | |
1271 for playerid in self.session.players: | |
1272 if len(self.session.players[playerid])>7: | |
1273 if self.session.players[playerid][7]=="GM" and self.session.group_id != '0': the_gms += [playerid] | |
1274 return the_gms | |
1275 | |
1276 def GetName(self): | |
1277 self.AliasLib = component.get('alias') | |
1278 player = self.session.get_my_info() | |
1279 if self.AliasLib != None: | |
1280 self.AliasLib.alias = self.aliasList.GetStringSelection(); | |
1281 if self.AliasLib.alias[0] != self.defaultAliasName: | |
1282 logger.debug("Exit chat_panel->GetName(self)") | |
1283 return [self.chat_display_name([self.AliasLib.alias[0], player[1], player[2]]), self.AliasLib.alias[1]] | |
1284 return [self.chat_display_name(player), "Default"] | |
1285 | |
1286 def GetFilteredText(self, text): | |
1287 advregex = re.compile('\"(.*?)\"', re.I) | |
1288 self.AliasLib = component.get('alias') | |
1289 if self.AliasLib != None: | |
1290 self.AliasLib.filter = self.filterList.GetSelection()-1; | |
1291 for rule in self.AliasLib.filterRegEx: | |
1292 if not self.advancedFilter: text = re.sub(rule[0], rule[1], text) | |
1293 else: | |
1294 for m in advregex.finditer(text): | |
1295 match = m.group(0) | |
1296 newmatch = re.sub(rule[0], rule[1], match) | |
1297 text = text.replace(match, newmatch) | |
1298 return text | |
1299 | |
1300 def emote_message(self, text): | |
1301 text = self.NormalizeParse(text) | |
1302 text = self.colorize(self.emotecolor, text) | |
1303 if self.type == MAIN_TAB and self.sendtarget == 'all': self.send_chat_message(text,chat_msg.EMOTE_MESSAGE) | |
1304 elif self.type == MAIN_TAB and self.sendtarget == "gm": | |
1305 msg_type = chat_msg.WHISPER_EMOTE_MESSAGE | |
1306 the_gms = self.get_gms() | |
1307 for each_gm in the_gms: self.send_chat_message(text,chat_msg.WHISPER_EMOTE_MESSAGE, str(each_gm)) | |
1308 elif self.type == GROUP_TAB and WG_LIST.has_key(self.sendtarget): | |
1309 for pid in WG_LIST[self.sendtarget]: | |
1310 self.send_chat_message(text,chat_msg.WHISPER_EMOTE_MESSAGE, str(pid)) | |
1311 elif self.type == WHISPER_TAB: self.send_chat_message(text,chat_msg.WHISPER_EMOTE_MESSAGE, str(self.sendtarget)) | |
1312 elif self.type == NULL_TAB: pass | |
1313 name = self.GetName()[0] | |
1314 text = "** " + name + " " + text + " **" | |
1315 self.EmotePost(text) | |
1316 | |
1317 def whisper_to_players(self, text, player_ids): | |
1318 tabbed_whispers_p = self.settings.get_setting("tabbedwhispers") | |
1319 text = self.NormalizeParse(text) | |
1320 player_names = "" | |
1321 for m in player_ids: | |
1322 id = m.strip() | |
1323 if self.session.is_valid_id(id): | |
1324 returned_name = self.session.get_player_by_player_id(id)[0] | |
1325 player_names += returned_name | |
1326 player_names += ", " | |
1327 else: | |
1328 player_names += " Unknown!" | |
1329 player_names += ", " | |
1330 comma = "," | |
1331 comma.join(player_ids) | |
1332 if (self.sendtarget == "all"): | |
1333 self.InfoPost("<i>whispering to "+ player_names + " " + text + "</i> ") | |
1334 text = self.colorize(self.mytextcolor, text) | |
1335 for id in player_ids: | |
1336 id = id.strip() | |
1337 if self.session.is_valid_id(id): self.send_chat_message(text,chat_msg.WHISPER_MESSAGE,id) | |
1338 else: self.InfoPost(id + " Unknown!") | |
1339 | |
1340 | |
1341 def send_chat_message(self, text, type=chat_msg.CHAT_MESSAGE, player_id="all"): | |
1342 #########send_msg()############# | |
1343 send = 1 | |
1344 for plugin_fname in self.activeplugins.keys(): | |
1345 plugin = self.activeplugins[plugin_fname] | |
1346 try: text, send = plugin.send_msg(text, send) | |
1347 except Exception, e: | |
1348 if str(e) != "'module' object has no attribute 'send_msg'": | |
1349 logger.general(traceback.format_exc()) | |
1350 logger.general("EXCEPTION: " + str(e)) | |
1351 msg = chat_msg.chat_msg() | |
1352 msg.set_text(text) | |
1353 msg.set_type(type) | |
1354 turnedoff = False | |
1355 if self.settings.get_setting("ShowIDInChat") == "1": | |
1356 turnedoff = True | |
1357 self.settings.set_setting("ShowIDInChat", "0") | |
1358 playername = self.GetName()[0] | |
1359 | |
1360 if turnedoff: self.settings.set_setting("ShowIDInChat", "1") | |
1361 msg.set_alias(playername) | |
1362 if send: self.session.send(msg.toxml(),player_id) | |
1363 del msg | |
1364 | |
1365 def post_incoming_msg(self, msg, player): | |
1366 type = msg.get_type() | |
1367 text = msg.get_text() | |
1368 alias = msg.get_alias() | |
1369 # who sent us the message? | |
1370 if alias: display_name = self.chat_display_name([alias, player[1], player[2]]) | |
1371 elif player: display_name = self.chat_display_name(player) | |
1372 else: display_name = "Server Administrator" | |
1373 | |
1374 ######### START plugin_incoming_msg() ########### | |
1375 for plugin_fname in self.activeplugins.keys(): | |
1376 plugin = self.activeplugins[plugin_fname] | |
1377 try: text, type, name = plugin.plugin_incoming_msg(text, type, display_name, player) | |
1378 except Exception, e: | |
1379 if str(e) != "'module' object has no attribute 'receive_msg'": | |
1380 logger.general(traceback.format_exc()) | |
1381 logger.general("EXCEPTION: " + str(e)) | |
1382 strip_img = self.settings.get_setting("Show_Images_In_Chat") | |
1383 if (strip_img == "0"): display_name = chat_util.strip_img_tags(display_name) | |
1384 recvSound = "RecvSound" | |
1385 # act on the type of messsage | |
1386 if (type == chat_msg.CHAT_MESSAGE): | |
1387 text = "<b>" + display_name + "</b>: " + text | |
1388 self.Post(text) | |
1389 self.parent.newMsg(0) | |
1390 elif type == chat_msg.WHISPER_MESSAGE or type == chat_msg.WHISPER_EMOTE_MESSAGE: | |
1391 tabbed_whispers_p = self.settings.get_setting("tabbedwhispers") | |
1392 displaypanel = self | |
1393 whisperingstring = " (whispering): " | |
1394 panelexists = 0 | |
1395 GMWhisperTab = self.settings.get_setting("GMWhisperTab") | |
1396 GroupWhisperTab = self.settings.get_setting("GroupWhisperTab") | |
1397 name = '<i><b>' + display_name + '</b>: ' | |
1398 text += '</i>' | |
1399 panelexists = 0 | |
1400 created = 0 | |
1401 try: | |
1402 if GMWhisperTab == '1': | |
1403 the_gms = self.get_gms() | |
1404 #Check if whisper if from a GM | |
1405 if player[2] in the_gms: | |
1406 msg = name + ' (GM Whisper:) ' + text | |
1407 if type == chat_msg.WHISPER_MESSAGE: self.parent.GMChatPanel.Post(msg) | |
1408 else: self.parent.GMChatPanel.EmotePost("**" + msg + "**") | |
1409 idx = self.parent.get_tab_index(self.parent.GMChatPanel) | |
1410 self.parent.newMsg(idx) | |
1411 panelexists = 1 | |
1412 #See if message if from someone in our groups or for a whisper tab we already have | |
1413 if not panelexists and GroupWhisperTab == "1": | |
1414 for panel in self.parent.group_tabs: | |
1415 if WG_LIST.has_key(panel.sendtarget) and WG_LIST[panel.sendtarget].has_key(int(player[2])): | |
1416 msg = name + text | |
1417 if type == chat_msg.WHISPER_MESSAGE: panel.Post(msg) | |
1418 else: panel.EmotePost("**" + msg + "**") | |
1419 idx = self.parent.get_tab_index(panel) | |
1420 self.parent.newMsg(idx) | |
1421 panelexists = 1 | |
1422 break | |
1423 if not panelexists and tabbed_whispers_p == "1": | |
1424 for panel in self.parent.whisper_tabs: | |
1425 #check for whisper tabs as well, to save the number of loops | |
1426 if panel.sendtarget == player[2]: | |
1427 msg = name + whisperingstring + text | |
1428 if type == chat_msg.WHISPER_MESSAGE: panel.Post(msg) | |
1429 else: panel.EmotePost("**" + msg + "**") | |
1430 idx = self.parent.get_tab_index(panel) | |
1431 self.parent.newMsg(idx) | |
1432 panelexists = 1 | |
1433 break | |
1434 #We did not fint the tab | |
1435 if not panelexists: | |
1436 #If we get here the tab was not found | |
1437 if GroupWhisperTab == "1": | |
1438 for group in WG_LIST.keys(): | |
1439 #Check if this group has the player in it | |
1440 if WG_LIST[group].has_key(int(player[2])): | |
1441 #Yup, post message. Player may be in more then 1 group so continue as well | |
1442 panel = self.parent.create_group_tab(group) | |
1443 msg = name + text | |
1444 if type == chat_msg.WHISPER_MESSAGE: wx.CallAfter(panel.Post, msg) | |
1445 else: wx.CallAfter(panel.EmotePost, "**" + msg + "**") | |
1446 created = 1 | |
1447 #Check to see if we should create a whisper tab | |
1448 if not created and tabbed_whispers_p == "1": | |
1449 panel = self.parent.create_whisper_tab(player[2]) | |
1450 msg = name + whisperingstring + text | |
1451 if type == chat_msg.WHISPER_MESSAGE: wx.CallAfter(panel.Post, msg) | |
1452 else: wx.CallAfter(panel.EmotePost, "**" + msg + "**") | |
1453 created = 1 | |
1454 #Final check | |
1455 if not created: | |
1456 #No tabs to create, just send the message to the main chat tab | |
1457 msg = name + whisperingstring + text | |
1458 if type == chat_msg.WHISPER_MESSAGE: self.parent.MainChatPanel.Post(msg) | |
1459 else: self.parent.MainChatPanel.EmotePost("**" + msg + "**") | |
1460 self.parent.newMsg(0) | |
1461 except Exception, e: | |
1462 logger.general(traceback.format_exc()) | |
1463 logger.general("EXCEPTION: 'Error in posting whisper message': " + str(e)) | |
1464 elif (type == chat_msg.EMOTE_MESSAGE): | |
1465 text = "** " + display_name + " " + text + " **" | |
1466 self.EmotePost(text) | |
1467 self.parent.newMsg(0) | |
1468 elif (type == chat_msg.INFO_MESSAGE): | |
1469 text = "<b>" + display_name + "</b>: " + text | |
1470 self.InfoPost(text) | |
1471 self.parent.newMsg(0) | |
1472 elif (type == chat_msg.SYSTEM_MESSAGE): | |
1473 text = "<b>" + display_name + "</b>: " + text | |
1474 self.SystemPost(text) | |
1475 self.parent.newMsg(0) | |
1476 # playe sound | |
1477 sound_file = self.settings.get_setting(recvSound) | |
1478 if sound_file != '': | |
1479 component.get('sound').play(sound_file) | |
184 | 1480 |
156 | 1481 #### Posting helpers ##### |
1482 | |
1483 def InfoPost(self, s): | |
1484 self.Post(self.colorize(self.infocolor, s), c='info') | |
1485 | |
1486 def SystemPost(self, s): | |
1487 self.Post(self.colorize(self.syscolor, s), c='system') | |
1488 | |
1489 def EmotePost(self, s): | |
1490 self.Post(self.colorize(self.emotecolor, s), c='emote') | |
1491 | |
1492 #### Standard Post method ##### | |
1493 | |
1494 def Post(self, s="", send=False, myself=False, c='post'): | |
1495 strip_p = self.settings.get_setting("striphtml") | |
1496 strip_img = self.settings.get_setting("Show_Images_In_Chat")#moved back 7-11-05. --mDuo13 | |
1497 if (strip_p == "1"): s = strip_html(s) | |
1498 if (strip_img == "0"): s = chat_util.strip_img_tags(s) | |
1499 s = chat_util.simple_html_repair(s) | |
1500 s = chat_util.strip_script_tags(s) | |
1501 s = chat_util.strip_li_tags(s) | |
1502 s = chat_util.strip_body_tags(s) #7-27-05 mDuo13 | |
1503 s = chat_util.strip_misalignment_tags(s) #7-27-05 mDuo13 | |
1504 aliasInfo = self.GetName() | |
1505 display_name = aliasInfo[0] | |
1506 if aliasInfo[1] != 'Default': | |
1507 defaultcolor = self.settings.get_setting("mytextcolor") | |
1508 self.settings.set_setting("mytextcolor", aliasInfo[1]) | |
1509 self.set_colors() | |
1510 newline = '' | |
1511 #following added by mDuo13 | |
1512 #########post_msg() - other########## | |
1513 if not myself and not send: | |
1514 for plugin_fname in self.activeplugins.keys(): | |
1515 plugin = self.activeplugins[plugin_fname] | |
1516 try: s = plugin.post_msg(s, myself) | |
1517 except Exception, e: | |
1518 if str(e) != "'module' object has no attribute 'post_msg'": | |
1519 logger.general(traceback.format_exc()) | |
1520 logger.general("EXCEPTION: " + str(e)) | |
1521 #end mDuo13 added code | |
1522 if myself: | |
1523 name = "<b>" + display_name + "</b>: " | |
1524 s = self.colorize(self.mytextcolor, s) | |
1525 else: name = "" | |
1526 if aliasInfo[1] != 'Default': | |
1527 self.settings.set_setting("mytextcolor", defaultcolor) | |
1528 self.set_colors() | |
1529 lineHasText = 1 | |
1530 try: lineHasText = strip_html(s).replace(" ","").replace(" ","").strip()!="" | |
1531 except: | |
1532 lineHasText = 1 | |
140 | 1533 if lineHasText: |
156 | 1534 #following added by mDuo13 |
1535 if myself: | |
1536 s2 = s | |
1537 ########post_msg() - self ####### | |
1538 for plugin_fname in self.activeplugins.keys(): | |
1539 plugin = self.activeplugins[plugin_fname] | |
1540 try: | |
1541 s2 = plugin.post_msg(s2, myself) | |
1542 except Exception, e: | |
1543 if str(e) != "'module' object has no attribute 'post_msg'": | |
1544 logger.general(traceback.format_exc()) | |
1545 logger.general("EXCEPTION: " + str(e)) | |
1546 if s2 != "": | |
1547 #Italici the messages from tabbed whispers | |
1548 if self.type == WHISPER_TAB or self.type == GROUP_TAB or self.sendtarget == 'gm': | |
1549 s2 = s2 + '</i>' | |
1550 name = '<i>' + name | |
1551 if self.type == WHISPER_TAB: name += " (whispering): " | |
1552 elif self.type == GROUP_TAB: name += self.settings.get_setting("gwtext") + ' ' | |
1553 elif self.sendtarget == 'gm': name += " (whispering to GM) " | |
1554 newline = "<div class='"+c+"'> " + self.TimeIndexString() + name + s2 + "</div>" | |
1555 log( self.settings, c, name+s2 ) | |
1556 else: | |
1557 newline = "<div class='"+c+"'> " + self.TimeIndexString() + name + s + "</div>" | |
1558 log( self.settings, c, name+s ) | |
1559 else: send = False | |
1560 newline = chat_util.strip_unicode(newline) | |
140 | 1561 if self.lockscroll == 0: |
156 | 1562 self.chatwnd.AppendToPage(newline) |
1563 self.scroll_down() | |
1564 else: self.storedata.append(newline) | |
59
5aff3ef1ae46
New dev branch for Ornery Orc. Adds CSS styling to chat messages. Updates
sirebral
parents:
0
diff
changeset
|
1565 if send: |
156 | 1566 if self.type == MAIN_TAB and self.sendtarget == 'all': self.send_chat_message(s) |
1567 elif self.type == MAIN_TAB and self.sendtarget == "gm": | |
1568 the_gms = self.get_gms() | |
1569 self.whisper_to_players(s, the_gms) | |
1570 elif self.type == GROUP_TAB and WG_LIST.has_key(self.sendtarget): | |
1571 members = [] | |
1572 for pid in WG_LIST[self.sendtarget]: members.append(str(WG_LIST[self.sendtarget][pid])) | |
1573 self.whisper_to_players(self.settings.get_setting("gwtext") + s, members) | |
1574 elif self.type == WHISPER_TAB: self.whisper_to_players(s, [self.sendtarget]) | |
1575 elif self.type == NULL_TAB: pass | |
1576 else: self.InfoPost("Failed to send message, unknown send type for this tab") | |
1577 self.parsed=0 | |
1578 | |
1579 def TimeIndexString(self): | |
1580 try: | |
1581 mtime = "" | |
1582 if self.settings.get_setting('Chat_Time_Indexing') == "0": pass | |
1583 elif self.settings.get_setting('Chat_Time_Indexing') == "1": | |
1584 mtime = time.strftime("[%I:%M:%S] ", time.localtime()) | |
1585 return mtime | |
1586 except Exception, e: | |
1587 logger.general(traceback.format_exc()) | |
1588 logger.general("EXCEPTION: " + str(e)) | |
1589 return "[ERROR]" | |
1590 | |
1591 #### Post with parsing dice #### | |
1592 | |
1593 def ParsePost(self, s, send=False, myself=False): | |
1594 s = self.NormalizeParse(s) | |
1595 self.set_colors() | |
1596 self.Post(s,send,myself) | |
1597 | |
1598 def NormalizeParse(self, s): | |
1599 for plugin_fname in self.activeplugins.keys(): | |
1600 plugin = self.activeplugins[plugin_fname] | |
1601 try: s = plugin.pre_parse(s) | |
1602 except Exception, e: | |
1603 if str(e) != "'module' object has no attribute 'post_msg'": | |
1604 logger.general(traceback.format_exc()) | |
1605 logger.general("EXCEPTION: " + str(e)) | |
1606 if self.parsed == 0: | |
1607 s = self.ParseNode(s) | |
1608 s = self.ParseDice(s) | |
1609 s = self.ParseFilter(s) | |
1610 self.parsed = 1 | |
1611 return s | |
1612 | |
1613 def ParseFilter(self, s): | |
1614 s = self.GetFilteredText(s) | |
1615 return s | |
1616 | |
1617 def ParseNode(self, s): | |
1618 """Parses player input for embedded nodes rolls""" | |
1619 cur_loc = 0 | |
1620 #[a-zA-Z0-9 _\-\.] | |
1621 reg = re.compile("(!@(.*?)@!)") | |
1622 matches = reg.findall(s) | |
1623 for i in xrange(0,len(matches)): | |
1624 newstr = self.ParseNode(self.resolve_nodes(matches[i][1])) | |
1625 s = s.replace(matches[i][0], newstr, 1) | |
1626 return s | |
1627 | |
1628 def ParseDice(self, s): | |
1629 """Parses player input for embedded dice rolls""" | |
1630 reg = re.compile("\[([^]]*?)\]") | |
1631 matches = reg.findall(s) | |
1632 for i in xrange(0,len(matches)): | |
1633 newstr = self.PraseUnknowns(matches[i]) | |
1634 qmode = 0 | |
1635 newstr1 = newstr | |
1636 if newstr[0].lower() == 'q': | |
1637 newstr = newstr[1:] | |
144 | 1638 qmode = 1 |
156 | 1639 if newstr[0].lower() == '#': |
1640 newstr = newstr[1:] | |
1641 qmode = 2 | |
1642 try: newstr = component.get('DiceManager').proccessRoll(newstr) | |
1643 except: pass | |
1644 if qmode == 1: | |
171 | 1645 s = s.replace("[" + matches[i] + "]", |
1646 "<!-- Official Roll [" + newstr1 + "] => " + newstr + "-->" + newstr, 1) | |
144 | 1647 elif qmode == 2: |
156 | 1648 s = s.replace("[" + matches[i] + "]", newstr[len(newstr)-2:-1], 1) |
171 | 1649 else: s = s.replace("[" + matches[i] + "]", |
1650 "[" + newstr1 + "<!-- Official Roll -->] => " + newstr, 1) | |
156 | 1651 return s |
1652 | |
1653 def PraseUnknowns(self, s): | |
1654 # Uses a tuple. Usage: ?Label}dY. If no Label is assigned then use ?}DY | |
1655 newstr = "0" | |
1656 reg = re.compile("(\?\{*)([a-zA-Z ]*)(\}*)") | |
1657 matches = reg.findall(s) | |
1658 for i in xrange(0,len(matches)): | |
1659 lb = "Replace '?' with: " | |
1660 if len(matches[i][0]): | |
1661 lb = matches[i][1] + "?: " | |
1662 dlg = wx.TextEntryDialog(self, lb, "Missing Value?") | |
1663 dlg.SetValue('') | |
1664 if matches[i][0] != '': | |
1665 dlg.SetTitle("Enter Value for " + matches[i][1]) | |
1666 if dlg.ShowModal() == wx.ID_OK: newstr = dlg.GetValue() | |
1667 if newstr == '': newstr = '0' | |
1668 s = s.replace(matches[i][0], newstr, 1).replace(matches[i][1], '', 1).replace(matches[i][2], '', 1) | |
1669 dlg.Destroy() | |
1670 return s | |
1671 | |
1672 # This subroutine builds a chat display name. | |
1673 # | |
1674 def chat_display_name(self, player): | |
1675 if self.settings.get_setting("ShowIDInChat") == "0": | |
1676 display_name = player[0] | |
1677 else: | |
1678 display_name = "("+player[2]+") " + player[0] | |
1679 return display_name | |
1680 | |
1681 # This subroutine will get a hex color and return it, or return nothing | |
1682 # | |
1683 def get_color(self): | |
1684 data = wx.ColourData() | |
1685 data.SetChooseFull(True) | |
1686 dlg = wx.ColourDialog(self, data) | |
1687 if dlg.ShowModal() == wx.ID_OK: | |
1688 data = dlg.GetColourData() | |
1689 (red,green,blue) = data.GetColour().Get() | |
1690 hexcolor = self.r_h.hexstring(red, green, blue) | |
1691 dlg.Destroy() | |
1692 return hexcolor | |
1693 else: | |
1694 dlg.Destroy() | |
1695 return None | |
184 | 1696 |
156 | 1697 # def get_color - end |
1698 def replace_quotes(self, s): | |
1699 in_tag = 0 | |
1700 i = 0 | |
1701 rs = s[:] | |
1702 for c in s: | |
171 | 1703 if c == "<": in_tag += 1 |
156 | 1704 elif c == ">": |
171 | 1705 if in_tag: in_tag -= 1 |
156 | 1706 elif c == '"': |
171 | 1707 if in_tag: rs = rs[:i] + "'" + rs[i+1:] |
156 | 1708 i += 1 |
1709 return rs | |
1710 | |
1711 def resolve_loop(self, node, path, step, depth): | |
1712 if step == depth: | |
183 | 1713 return self.resolution(node) |
156 | 1714 else: |
1715 child_list = node.findall('nodehandler') | |
1716 for child in child_list: | |
1717 if step == depth: break | |
1718 if child.get('name') == path[step]: | |
140 | 1719 node = child |
1720 step += 1 | |
183 | 1721 if node.get('class') in ('dnd35char_handler', |
1722 "SWd20char_handler", | |
1723 "d20char_handler", | |
1724 "dnd3echar_handler"): self.resolve_cust_loop(node, path, step, depth) | |
156 | 1725 elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, step, depth) |
140 | 1726 else: self.resolve_loop(node, path, step, depth) |
1727 | |
1728 def resolve_grid(self, node, path, step, depth): | |
1729 if step == depth: | |
1730 self.data = 'Invalid Grid Reference!' | |
1731 return | |
1732 cell = tuple(path[step].strip('(').strip(')').split(',')) | |
1733 grid = node.find('grid') | |
1734 rows = grid.findall('row') | |
162 | 1735 col = rows[int(self.ParseDice(cell[0]))-1].findall('cell') |
1736 try: self.data = self.ParseMap(col[int(self.ParseDice(cell[1]))-1].text, node) or 'No Cell Data' | |
144 | 1737 except: self.data = 'Invalid Grid Reference!' |
140 | 1738 return |
1739 | |
183 | 1740 def resolution(self, node): |
1741 if self.passed == False: | |
1742 self.passed = True | |
1743 if node.get('class') == 'textctrl_handler': | |
1744 s = str(node.find('text').text) | |
1745 else: s = 'Nodehandler for '+ node.get('class') + ' not done!' or 'Invalid Reference!' | |
1746 else: | |
1747 s = '' | |
1748 s = self.ParseMap(s, node) | |
1749 s = self.ParseParent(s, node.get('map')) | |
1750 self.data = s | |
1751 | |
1752 def ParseMap(self, s, node): | |
1753 """Parses player input for embedded nodes rolls""" | |
1754 cur_loc = 0 | |
1755 reg = re.compile("(!!(.*?)!!)") | |
1756 matches = reg.findall(s) | |
1757 for i in xrange(0,len(matches)): | |
1758 tree_map = node.get('map') | |
1759 tree_map = tree_map + '::' + matches[i][1] | |
1760 newstr = '!@'+ tree_map +'@!' | |
1761 s = s.replace(matches[i][0], newstr, 1) | |
1762 s = self.ParseNode(s) | |
1763 s = self.ParseParent(s, tree_map) | |
1764 return s | |
1765 | |
1766 def ParseParent(self, s, tree_map): | |
1767 """Parses player input for embedded nodes rolls""" | |
1768 cur_loc = 0 | |
1769 reg = re.compile("(!#(.*?)#!)") | |
1770 matches = reg.findall(s) | |
1771 for i in xrange(0,len(matches)): | |
1772 ## Build the new tree_map | |
1773 new_map = tree_map.split('::') | |
1774 del new_map[len(new_map)-1] | |
1775 parent_map = matches[i][1].split('::') | |
1776 ## Find an index or use 1 for ease of use. | |
1777 try: index = new_map.index(parent_map[0]) | |
1778 except: index = 1 | |
1779 ## Just replace the old tree_map from the index. | |
1780 new_map[index:len(new_map)] = parent_map | |
1781 newstr = '::'.join(new_map) | |
1782 newstr = '!@'+ newstr +'@!' | |
1783 s = s.replace(matches[i][0], newstr, 1) | |
1784 s = self.ParseNode(s) | |
1785 return s | |
1786 | |
1787 def resolve_nodes(self, s): | |
1788 self.passed = False | |
1789 self.data = 'Invalid Reference!' | |
1790 value = "" | |
1791 path = s.split('::') | |
1792 depth = len(path) | |
1793 self.gametree = component.get('tree') | |
1794 try: node = self.gametree.tree_map[path[0]]['node'] | |
1795 except Exception, e: return self.data | |
1796 if node.get('class') in ('dnd35char_handler', | |
1797 "SWd20char_handler", | |
1798 "d20char_handler", | |
1799 "dnd3echar_handler"): self.resolve_cust_loop(node, path, 1, depth) | |
1800 elif node.get('class') == 'rpg_grid_handler': self.resolve_grid(node, path, 1, depth) | |
1801 else: self.resolve_loop(node, path, 1, depth) | |
1802 return self.data | |
1803 | |
140 | 1804 def resolve_cust_loop(self, node, path, step, depth): |
1805 node_class = node.get('class') | |
142 | 1806 ## Code needs clean up. Either choose .lower() or .title(), then reset the path list's content ## |
1807 if step == depth: self.resolution(node) | |
140 | 1808 ##Build Abilities dictionary## |
1809 if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('abilities') | |
1810 else: ab = node.find('abilities') | |
1811 ab_list = ab.findall('stat'); pc_stats = {} | |
1812 | |
1813 for ability in ab_list: | |
171 | 1814 pc_stats[ability.get('name')] = ( |
1815 str(ability.get('base')), | |
1816 str((int(ability.get('base'))-10)/2) ) | |
1817 pc_stats[ability.get('abbr')] = ( | |
1818 str(ability.get('base')), | |
1819 str((int(ability.get('base'))-10)/2) ) | |
140 | 1820 |
1821 if node_class not in ('d20char_handler', "SWd20char_handler"): ab = node.find('character').find('saves') | |
1822 else: ab = node.find('saves') | |
1823 ab_list = ab.findall('save') | |
1824 for save in ab_list: | |
183 | 1825 pc_stats[save.get('name')] = (str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) ) |
140 | 1826 if save.get('name') == 'Fortitude': abbr = 'Fort' |
1827 if save.get('name') == 'Reflex': abbr = 'Ref' | |
1828 if save.get('name') == 'Will': abbr = 'Will' | |
1829 pc_stats[abbr] = ( str(save.get('base')), str(int(save.get('magmod')) + int(save.get('miscmod')) + int(pc_stats[save.get('stat')][1]) ) ) | |
1830 | |
1831 if path[step].lower() == 'skill': | |
1832 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf') | |
1833 node = node.find('skills') | |
1834 child_list = node.findall('skill') | |
1835 for child in child_list: | |
1836 if path[step+1].lower() == child.get('name').lower(): | |
1837 if step+2 == depth: self.data = child.get('rank') | |
1838 elif path[step+2].lower() == 'check': | |
1839 self.data = '<b>Skill Check:</b> ' + child.get('name') + ' [1d20+'+str( int(child.get('rank')) + int(pc_stats[child.get('stat')][1]) )+']' | |
1840 return | |
1841 | |
1842 if path[step].lower() == 'feat': | |
1843 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snf') | |
1844 node = node.find('feats') | |
1845 child_list = node.findall('feat') | |
1846 for child in child_list: | |
1847 if path[step+1].lower() == child.get('name').lower(): | |
1848 if step+2 == depth: self.data = '<b>'+child.get('name')+'</b>'+': '+child.get('desc') | |
1849 return | |
1850 if path[step].lower() == 'cast': | |
1851 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('snp') | |
1852 node = node.find('spells') | |
1853 child_list = node.findall('spell') | |
1854 for child in child_list: | |
1855 if path[step+1].lower() == child.get('name').lower(): | |
1856 if step+2 == depth: self.data = '<b>'+child.get('name')+'</b>'+': '+child.get('desc') | |
1857 return | |
1858 if path[step].lower() == 'attack': | |
1859 if node_class not in ('d20char_handler', "SWd20char_handler"): node = node.find('combat') | |
1860 if path[step+1].lower() == 'melee' or path[step+1].lower() == 'm': | |
1861 bonus_text = '(Melee)' | |
1862 bonus = node.find('attacks') | |
1863 bonus = bonus.find('melee') | |
142 | 1864 bonus = bonus.attrib; d = int(pc_stats['Str'][1]) |
140 | 1865 elif path[step+1].lower() == 'ranged' or path[step+1].lower() == 'r': |
1866 bonus_text = '(Ranged)' | |
1867 bonus = node.find('attacks') | |
1868 bonus = bonus.find('ranged') | |
142 | 1869 bonus = bonus.attrib; d = int(pc_stats['Dex'][1]) |
140 | 1870 for b in bonus: |
1871 d += int(bonus[b]) | |
1872 bonus = str(d) | |
1873 if path[step+2] == None: self.data = bonus | |
1874 else: | |
1875 weapons = node.find('attacks') | |
1876 weapons = weapons.findall('weapon') | |
1877 for child in weapons: | |
1878 if path[step+2].lower() == child.get('name').lower(): | |
1879 self.data = '<b>Attack: '+bonus_text+'</b> '+child.get('name')+' [1d20+'+bonus+'] ' + 'Damage: ['+child.get('damage')+']' | |
1880 return | |
142 | 1881 elif pc_stats.has_key(path[step].title()): |
1882 if step+1 == depth: self.data = pc_stats[path[step].title()][0] + ' +('+pc_stats[path[step].title()][1]+')' | |
1883 elif path[step+1].title() == 'Mod': self.data = pc_stats[path[step].title()][1] | |
1884 elif path[step+1].title() == 'Check': self.data = '<b>'+path[step].title()+' Check:</b> [1d20+'+str(pc_stats[path[step].title()][1])+']' | |
140 | 1885 return |
184 | 1886 |