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