Mercurial > traipse_dev
comparison orpg/orpg_windows.py @ 0:4385a7d0efd1 grumpy-goblin
Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author | sirebral |
---|---|
date | Tue, 14 Jul 2009 16:41:58 -0500 |
parents | |
children | 551cd440acce |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4385a7d0efd1 |
---|---|
1 # Copyright (C) 2000-2001 The OpenRPG Project | |
2 # | |
3 # openrpg-dev@lists.sourceforge.net | |
4 # | |
5 # This program is free software; you can redistribute it and/or modify | |
6 # it under the terms of the GNU General Public License as published by | |
7 # the Free Software Foundation; either version 2 of the License, or | |
8 # (at your option) any later version. | |
9 # | |
10 # This program is distributed in the hope that it will be useful, | |
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 # GNU General Public License for more details. | |
14 # | |
15 # You should have received a copy of the GNU General Public License | |
16 # along with this program; if not, write to the Free Software | |
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 # -- | |
19 # | |
20 # File: orpg_windows.py | |
21 # Author: Chris Davis | |
22 # Maintainer: | |
23 # Version: | |
24 # $Id: orpg_windows.py,v 1.42 2007/12/07 20:59:16 digitalxero Exp $ | |
25 # | |
26 # Description: orpg custom windows | |
27 # | |
28 | |
29 __version__ = "$Id: orpg_windows.py,v 1.42 2007/12/07 20:59:16 digitalxero Exp $" | |
30 | |
31 from orpg.orpg_wx import * | |
32 from orpg.orpgCore import * | |
33 import orpg.tools.rgbhex | |
34 import orpg.orpg_xml | |
35 import orpg.dirpath | |
36 from orpg.tools.metamenus import MenuEx | |
37 | |
38 class img_helper: | |
39 def __init__(self): | |
40 pass | |
41 | |
42 def load_url(self,path): | |
43 img_type = self.get_type(path) | |
44 try: | |
45 data = urllib.urlretrieve(path) | |
46 if data: | |
47 img = wx.Bitmap(data[0], img_type) | |
48 else: | |
49 raise IOError, "Image refused to load!" | |
50 except IOError, e: | |
51 img = None | |
52 return img | |
53 | |
54 def load_file(self,path): | |
55 img_type = self.get_type(path) | |
56 return wx.Bitmap(path, img_type) | |
57 | |
58 def get_type(self,file_name): | |
59 pos = string.rfind(file_name,'.') | |
60 ext = string.lower(file_name[pos+1:]) | |
61 img_type = 0 | |
62 # TaS - sirebral. Replaces 10 lines with 6 lines. | |
63 recycle_bin = {"gif": wx.BITMAP_TYPE_GIF, "jpg": wx.BITMAP_TYPE_JPEG, "jpeg": wx.BITMAP_TYPE_JPEG, "bmp": wx.BITMAP_TYPE_BMP, "png": wx.BITMAP_TYPE_PNG} | |
64 if recycle_bin.has_key(ext): | |
65 img_type = recycle_bin[ext] | |
66 else: | |
67 img_type = None ## this was imf_type = None. imf? | |
68 recycle_bin = {}; return img_type | |
69 | |
70 ################################ | |
71 ## Tabs | |
72 ################################ | |
73 class orpgTabberWnd(FNB.FlatNotebook): | |
74 def __init__(self, parent, closeable=False, size=wx.DefaultSize, style = False): | |
75 nbstyle = FNB.FNB_HIDE_ON_SINGLE_TAB|FNB.FNB_BACKGROUND_GRADIENT | |
76 FNB.FlatNotebook.__init__(self, parent, -1, size=size, style=nbstyle) | |
77 rgbcovert = orpg.tools.rgbhex.RGBHex() | |
78 self.log = open_rpg.get_component("log") | |
79 self.log.log("Enter orpgTabberWnd", ORPG_DEBUG) | |
80 self.settings = open_rpg.get_component("settings") | |
81 tabtheme = self.settings.get_setting('TabTheme') | |
82 tabtext = self.settings.get_setting('TabTextColor') | |
83 (tred, tgreen, tblue) = rgbcovert.rgb_tuple(tabtext) | |
84 tabbedwindows = open_rpg.get_component("tabbedWindows") | |
85 tabbedwindows.append(self) | |
86 open_rpg.add_component("tabbedWindows", tabbedwindows) | |
87 | |
88 theme_dict = {'slanted&aqua': FNB.FNB_VC8, 'slanted&bw': FNB.FNB_VC8, 'flat&aqua': FNB.FNB_FANCY_TABS, 'flat&bw': FNB.FNB_FANCY_TABS, 'customflat': FNB.FNB_FANCY_TABS, 'customslant': FNB.FNB_VC8, 'slanted&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS, 'slant&colorful': FNB.FNB_VC8|FNB.FNB_COLORFUL_TABS} | |
89 nbstyle |= theme_dict[tabtheme] | |
90 if style: | |
91 nbstyle |= style | |
92 self.SetWindowStyleFlag(nbstyle) | |
93 | |
94 #Tas - sirebral. Planned changes to the huge statement below. | |
95 if tabtheme == 'slanted&aqua': | |
96 self.SetGradientColourTo(wx.Color(0, 128, 255)) | |
97 self.SetGradientColourFrom(wx.WHITE) | |
98 | |
99 elif tabtheme == 'slanted&bw': | |
100 self.SetGradientColourTo(wx.WHITE) | |
101 self.SetGradientColourFrom(wx.WHITE) | |
102 | |
103 elif tabtheme == 'flat&aqua': | |
104 self.SetGradientColourFrom(wx.Color(0, 128, 255)) | |
105 self.SetGradientColourTo(wx.WHITE) | |
106 self.SetNonActiveTabTextColour(wx.BLACK) | |
107 | |
108 elif tabtheme == 'flat&bw': | |
109 self.SetGradientColourTo(wx.WHITE) | |
110 self.SetGradientColourFrom(wx.WHITE) | |
111 self.SetNonActiveTabTextColour(wx.BLACK) | |
112 | |
113 elif tabtheme == 'customflat': | |
114 gfrom = self.settings.get_setting('TabGradientFrom') | |
115 (red, green, blue) = rgbcovert.rgb_tuple(gfrom) | |
116 self.SetGradientColourFrom(wx.Color(red, green, blue)) | |
117 | |
118 gto = self.settings.get_setting('TabGradientTo') | |
119 (red, green, blue) = rgbcovert.rgb_tuple(gto) | |
120 self.SetGradientColourTo(wx.Color(red, green, blue)) | |
121 self.SetNonActiveTabTextColour(wx.Color(tred, tgreen, tblue)) | |
122 | |
123 elif tabtheme == 'customslant': | |
124 gfrom = self.settings.get_setting('TabGradientFrom') | |
125 (red, green, blue) = rgbcovert.rgb_tuple(gfrom) | |
126 self.SetGradientColourFrom(wx.Color(red, green, blue)) | |
127 | |
128 gto = self.settings.get_setting('TabGradientTo') | |
129 (red, green, blue) = rgbcovert.rgb_tuple(gto) | |
130 self.SetGradientColourTo(wx.Color(red, green, blue)) | |
131 self.SetNonActiveTabTextColour(wx.Color(tred, tgreen, tblue)) | |
132 | |
133 tabbg = self.settings.get_setting('TabBackgroundGradient') | |
134 (red, green, blue) = rgbcovert.rgb_tuple(tabbg) | |
135 self.SetTabAreaColour(wx.Color(red, green, blue)) | |
136 self.Refresh() | |
137 self.log.log("Exit orpgTabberWnd", ORPG_DEBUG) | |
138 | |
139 | |
140 ######################## | |
141 ## About HTML Dialog | |
142 ######################## | |
143 | |
144 class AboutHTMLWindow(wx.html.HtmlWindow): | |
145 "Window used to display the About dialog box" | |
146 | |
147 # Init using the derived from class | |
148 def __init__( self, parent, id, position, size, style ): | |
149 wx.html.HtmlWindow.__init__( self, parent, id, position, size, style ) | |
150 | |
151 def OnLinkClicked( self, ref ): | |
152 "Open an external browser to resolve our About box links!!!" | |
153 href = ref.GetHref() | |
154 webbrowser.open( href ) | |
155 | |
156 # This class extends wxSplitterWindow to add an auto expand behavior. The idea is that the sash | |
157 # determines the ratio of the two windows, while the mouse position determines which | |
158 # side will get the larger share of the screen real estate. It is used instead of regular | |
159 # wxSplitterWindows if the EnableSplittersAutoExpand setting doesn't evaluate as False. | |
160 # | |
161 # Note: To be truly functional, some way of passing EVT_MOTION events to this class, even when the | |
162 # event takes place over child windows needs to be accomplished. Once this is accomplished, | |
163 # however, the class should work as written. | |
164 class orpgFocusSplitterWindow(wx.SplitterWindow): | |
165 | |
166 def __init__(self,parent,id = -1,AutoExpand = 1,point = wx.DefaultPosition,size = wx.DefaultSize,style=wx.SP_3D,name="splitterWindow"): | |
167 wx.SplitterWindow.__init__(self,parent,id,point,size,style,name) | |
168 self.auto = AutoExpand | |
169 self.Bind(wx.EVT_IDLE, self.OnIdle) # used in workaround idea from Robin Dunn instead of EVT_MOTION | |
170 | |
171 # Get's called during idle times. It checks to see if the mouse is over self and calls | |
172 # OnMotion with the coordinates | |
173 | |
174 def EnableAutoExpand(self,value): | |
175 self.auto = value | |
176 | |
177 def OnIdle(self,event): | |
178 if self.auto: | |
179 (screen_x,screen_y) = wx.GetMousePosition() | |
180 (x,y) = self.ScreenToClientXY(screen_x,screen_y) # translate coordinates | |
181 (w,h) = self.GetSizeTuple() | |
182 if x >= 0 and x < w and y >= 0 and y < h: | |
183 self.OnMotion(x,y) | |
184 event.Skip() | |
185 | |
186 def OnMotion(self,mouse_X,mouse_Y): | |
187 # Gather some info using standard wxWindows calls | |
188 (w,h) = self.GetClientSizeTuple() | |
189 (second_w,second_h) = self.GetWindow2().GetClientSizeTuple() | |
190 (second_x,second_y) = self.GetWindow2().GetPositionTuple() | |
191 splitmode = self.GetSplitMode() | |
192 sash = self.GetSashPosition() | |
193 | |
194 if splitmode == wx.SPLIT_VERTICAL: | |
195 pos = mouse_X # Position of the mouse pointer | |
196 second = second_x # Beginning of the second (Right) pane | |
197 second_size = second_w # Size of the second pane | |
198 else: | |
199 pos = mouse_Y # Position of the mouse pointer | |
200 second = second_y # Beginning of the second (Bottom) pane | |
201 second_size = second_h # Size of the second pane | |
202 sash_size = second - sash # Beginning of sash to beginning of second is the sash size | |
203 | |
204 if (pos > sash + sash_size and second_size < sash) or (pos < sash and second_size > sash): | |
205 # Equivalent to the following | |
206 # if | |
207 # (the mouse position is below/to the right of the sash, including it's thickness | |
208 # i.e. in the second window | |
209 # AND | |
210 # the second window is smaller than the 1st (size = the sash position)) | |
211 # | |
212 # OR | |
213 # | |
214 # (the mouse position is above/to the left of the sash | |
215 # i.e. in the first window | |
216 # AND | |
217 # the second window is bigger than the 1st) | |
218 | |
219 | |
220 # flip the split | |
221 self.SetSashPosition(second_size) | |
222 # Both cases above set the sash to a position that corresponds to the size of the | |
223 # second window. This has the effect of making the first window trade sizes with | |
224 # the second window. | |
225 # In the first part of the OR clause, the first window takes the second window's | |
226 # size because the user wants the currently small lower window to be big, so | |
227 # the first must take on the size of the small. | |
228 # | |
229 # In the second case of the OR clause, the first window takes the second window's | |
230 # size because the user wants the currently small upper window to be big (which | |
231 # the second window currently is), so make the first take the size of the second. | |
232 | |
233 | |
234 ##################### | |
235 ## A text editor for openrpg related text | |
236 ##################### | |
237 | |
238 class html_text_edit(wx.Panel): | |
239 """ a text ctrl with html helpers """ | |
240 def __init__(self, parent, id, text, callback,home_dir): | |
241 wx.Panel.__init__(self, parent,-1) | |
242 self.r_h = orpg.tools.rgbhex.RGBHex() | |
243 self.text = wx.TextCtrl(self, id, text, wx.DefaultPosition, | |
244 wx.DefaultSize, | |
245 wx.TE_MULTILINE ) | |
246 self.Bind(wx.EVT_SIZE, self.OnSize) | |
247 self.Bind(wx.EVT_TEXT, callback, id=id) | |
248 self.callback = callback | |
249 self.BOLD = wx.NewId() | |
250 self.ITALIC = wx.NewId() | |
251 self.UNDER = wx.NewId() | |
252 self.COLOR = wx.NewId() | |
253 self.DIE100 = wx.NewId() | |
254 self.DIE20 = wx.NewId() | |
255 self.DIE10 = wx.NewId() | |
256 self.DIE8 = wx.NewId() | |
257 self.DIE6 = wx.NewId() | |
258 self.DIE4 = wx.NewId() | |
259 self.DIE2 = wx.NewId() | |
260 self.DIE = wx.NewId() | |
261 self.sizer = wx.BoxSizer(wx.HORIZONTAL) | |
262 gif = wx.Image(orpg.dirpath.dir_struct["icon"]+"bold.gif", wx.BITMAP_TYPE_GIF) | |
263 self.sizer.Add(wx.BitmapButton(self, self.BOLD, gif.ConvertToBitmap()), 0, wx.EXPAND) | |
264 gif = wx.Image(orpg.dirpath.dir_struct["icon"]+"italic.gif", wx.BITMAP_TYPE_GIF) | |
265 self.sizer.Add(wx.BitmapButton(self, self.ITALIC, gif.ConvertToBitmap()), 0, wx.EXPAND) | |
266 gif = wx.Image(orpg.dirpath.dir_struct["icon"]+"underlined.gif", wx.BITMAP_TYPE_GIF) | |
267 self.sizer.Add(wx.BitmapButton(self, self.UNDER, gif.ConvertToBitmap()), 0, wx.EXPAND) | |
268 self.color_button = wx.Button(self, self.COLOR, "C",wx.Point(0,0),wx.Size(22,0)) | |
269 self.color_button.SetBackgroundColour(wx.BLACK) | |
270 self.color_button.SetForegroundColour(wx.WHITE) | |
271 self.sizer.Add(self.color_button, 0, wx.EXPAND) | |
272 self.Bind(wx.EVT_BUTTON, self.on_text_format, id=self.BOLD) | |
273 self.Bind(wx.EVT_BUTTON, self.on_text_format, id=self.ITALIC) | |
274 self.Bind(wx.EVT_BUTTON, self.on_text_format, id=self.UNDER) | |
275 self.Bind(wx.EVT_BUTTON, self.on_text_format, id=self.COLOR) | |
276 | |
277 def on_text_format(self,event): | |
278 id = event.GetId() | |
279 if wx.Platform == '__WXMSW__': | |
280 txt = self.text.GetLabel() | |
281 else: | |
282 txt = self.text.GetValue() | |
283 (beg,end) = self.text.GetSelection() | |
284 if beg != end: | |
285 sel_txt = txt[beg:end] | |
286 else: | |
287 return | |
288 print txt | |
289 # TaS - sirebral. Replaces 6 lines with 4 lines. | |
290 recycle_bin = {self.BOLD: "b", self.ITALIC: "i", self.UNDER: "u"} | |
291 if recycle_bin.has_key(id): | |
292 sel_txt = "<" + recycle_bin[id] + ">" + sel_txt + "</" + recycle_bin[id] + ">" | |
293 recycle_bin = {} | |
294 | |
295 elif id == self.COLOR: | |
296 hexcolor = self.r_h.do_hex_color_dlg(self) | |
297 if hexcolor: | |
298 sel_txt = "<font color='"+hexcolor+"'>"+sel_txt+"</font>" | |
299 self.color_button.SetBackgroundColour(hexcolor) | |
300 | |
301 txt = txt[:beg] + sel_txt + txt[end:] | |
302 # print txt | |
303 if wx.Platform == '__WXMSW__': | |
304 txt = self.text.SetLabel(txt) | |
305 else: | |
306 txt = self.text.SetValue(txt) | |
307 self.text.SetInsertionPoint(beg) | |
308 self.text.SetFocus() | |
309 self.callback(wx.Event(self.text.GetId())) | |
310 | |
311 def set_text(self,txt): | |
312 self.text.SetValue(txt) | |
313 | |
314 def get_text(self): | |
315 return self.text.GetValue() | |
316 | |
317 def OnSize(self,event): | |
318 (w,h) = self.GetClientSizeTuple() | |
319 self.text.SetDimensions(0,0,w,h-25) | |
320 self.sizer.SetDimension(0,h-25,w,25) | |
321 | |
322 ########################### | |
323 ## HTML related clasees | |
324 ########################### | |
325 | |
326 class http_html_window(wx.html.HtmlWindow): | |
327 """ a wx.html.HTMLwindow that will load links """ | |
328 def __init__(self, parent, id): | |
329 wx.html.HtmlWindow.__init__(self, parent, id, wx.DefaultPosition,wx.DefaultSize, wx.SUNKEN_BORDER | wx.html.HW_SCROLLBAR_AUTO) | |
330 self.path = "" | |
331 self.local = 0 | |
332 #self.title = title | |
333 | |
334 def OnLinkClicked(self, linkinfo): | |
335 address = linkinfo.GetHref() | |
336 if address[:4] == "http": | |
337 self.load_url(address) | |
338 self.local = 0 | |
339 elif address[0] == "#" or self.local: | |
340 self.base_OnLinkClicked(linkinfo) | |
341 else: | |
342 self.load_url(self.path+address) | |
343 | |
344 def load_url(self,path): | |
345 print path | |
346 dlg = wx.ProgressDialog("HTML Document","Loading...",3,self) | |
347 dlg.Update(1) | |
348 try: | |
349 data = urllib.urlretrieve(path) | |
350 file = open(data[0]) | |
351 dlg.Update(2) | |
352 self.SetPage(file.read()) | |
353 i = string.rfind(path,"/") | |
354 self.path = path[:i+1] | |
355 except: | |
356 wx.MessageBox("Invalid URL","Browser Error",wx.OK) | |
357 #self.SetPage("<h3>Invalid URL</h3>") | |
358 dlg.Update(3) | |
359 dlg.Destroy() | |
360 | |
361 def load_file(self,path): | |
362 self.LoadPage(path) | |
363 self.local = 1 | |
364 | |
365 ########################### | |
366 ## Some misc dialogs | |
367 ########################### | |
368 | |
369 class orpgMultiCheckBoxDlg(wx.Dialog): | |
370 """ notes """ | |
371 def __init__(self, parent, opts, text, caption, selected=[], pos=wx.DefaultPosition): | |
372 wx.Dialog.__init__(self, parent, wx.ID_ANY, caption, pos, wx.DefaultSize) | |
373 sizers = { 'ctrls' : wx.BoxSizer(wx.VERTICAL), 'buttons' : wx.BoxSizer(wx.HORIZONTAL) } | |
374 self.opts = opts | |
375 self.list = wx.CheckListBox(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize,opts) | |
376 for s in selected: | |
377 self.list.Check(s,1) | |
378 sizers['ctrls'].Add(wx.StaticText(self, -1, text), 0, 0) | |
379 sizers['ctrls'].Add(wx.Size(10,10)) | |
380 sizers['ctrls'].Add(self.list, 1, wx.EXPAND) | |
381 sizers['buttons'].Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND) | |
382 sizers['buttons'].Add(wx.Size(10,10)) | |
383 sizers['buttons'].Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND) | |
384 sizers['ctrls'].Add(sizers['buttons'], 0, wx.EXPAND) | |
385 self.SetSizer(sizers['ctrls']) | |
386 self.SetAutoLayout(True) | |
387 self.Fit() | |
388 self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK) | |
389 | |
390 def on_ok(self,evt): | |
391 checked = [] | |
392 for i in range(len(self.opts)): | |
393 if self.list.IsChecked(i): | |
394 checked.append(i) | |
395 self.checked = checked | |
396 self.EndModal(wx.ID_OK) | |
397 | |
398 def get_selections(self): | |
399 return self.checked | |
400 | |
401 | |
402 class orpgMultiTextEntry(wx.Dialog): | |
403 """ a dialog that takes two lists (labels and values) and creates a | |
404 'label: value' style text edit control for each node in the dic""" | |
405 def __init__(self,parent,tlist,vlist,caption,pos=wx.DefaultPosition): | |
406 wx.Dialog.__init__(self,parent,-1,caption,pos,wx.DefaultSize) | |
407 num = len(tlist) | |
408 sizers = { 'ctrls' : wx.FlexGridSizer(num,2,5,0), | |
409 'buttons' : wx.BoxSizer(wx.HORIZONTAL) } | |
410 #keys = mlist.keys() | |
411 self.tlist = tlist | |
412 self.vlist = vlist | |
413 add_list = [] | |
414 ctrls = [] | |
415 for i in range(len(tlist)): | |
416 add_list.append((wx.StaticText(self, -1, tlist[i]+": "),0,wx.ALIGN_CENTER_VERTICAL )) | |
417 ctrls.append(wx.TextCtrl(self, 10, vlist[i])) | |
418 add_list.append((ctrls[i],1,wx.EXPAND)) | |
419 self.ctrls = ctrls | |
420 sizers['ctrls'].AddMany(add_list) | |
421 sizers['ctrls'].AddGrowableCol(1) | |
422 sizers['buttons'].Add(wx.Button(self, wx.ID_OK, "OK"), 1, wx.EXPAND) | |
423 sizers['buttons'].Add(wx.Size(10,10)) | |
424 sizers['buttons'].Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND) | |
425 width = 300 | |
426 (w,h) = ctrls[0].GetSizeTuple() | |
427 h = h + 5 | |
428 height = ((num)*h)+35 | |
429 self.SetClientSizeWH(width,height) | |
430 sizers['ctrls'].SetDimension(10,5,width-20,num*30) | |
431 sizers['buttons'].SetDimension(10,(num*h)+5,width-20,25) | |
432 self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK) | |
433 | |
434 def on_ok(self,evt): | |
435 for i in range(len(self.ctrls)): | |
436 self.vlist[i] = self.ctrls[i].GetValue() | |
437 self.EndModal(wx.ID_OK) | |
438 | |
439 def get_values(self): | |
440 return self.vlist | |
441 | |
442 class orpgScrolledMessageFrameEditor(wx.Frame): | |
443 "class to implement wxScrolledMessageFrame with Find feature for the text of chatbuffer in a popup" | |
444 def __init__(self, parent, msg, caption, pos = None, size = None): | |
445 ID_ORPGTEXTCTRL = wx.NewId() | |
446 ID_MATCHINSTRUCTION = wx.NewId() | |
447 ID_MATCHINPUT = wx.NewId() | |
448 ID_MATCHBUTTON = wx.NewId() | |
449 ID_MATCHCASEINSTRUCTION = wx.NewId() | |
450 ID_MATCHCASECHECKBOX = wx.NewId() | |
451 ID_DEHTML = wx.NewId() | |
452 wx.Frame.__init__(self, parent, -1, caption, pos=wx.DefaultPosition, size=(640,480)) | |
453 self.SetBackgroundColour(wx.WHITE) | |
454 self.text = wx.TextCtrl(self, ID_ORPGTEXTCTRL, msg, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE ) | |
455 self.sizer = wx.BoxSizer(wx.VERTICAL) | |
456 self.sizer.Add(self.text, 1, wx.EXPAND) | |
457 sizer1 = wx.BoxSizer(wx.HORIZONTAL) | |
458 self.matchInstruction = wx.StaticText(self, ID_MATCHINSTRUCTION, "Text to search for: ") | |
459 self.sizer.Add(self.matchInstruction, 0, wx.ALIGN_CENTER_VERTICAL) | |
460 self.matchCaseInstruction = wx.StaticText(self, ID_MATCHCASEINSTRUCTION, "Match case:") | |
461 sizer1.Add(self.matchCaseInstruction, 0, wx.ALIGN_CENTER_VERTICAL) | |
462 self.matchCaseCheckBox = wx.CheckBox(self, ID_MATCHCASECHECKBOX, "") | |
463 sizer1.Add(self.matchCaseCheckBox, 0, wx.ALIGN_CENTER_VERTICAL) | |
464 self.matchInput = wx.TextCtrl(self, ID_MATCHINPUT, "") | |
465 sizer1.Add(self.matchInput, 1, wx.EXPAND) | |
466 self.sizer.Add(sizer1, 0, wx.EXPAND) | |
467 sizer2 = wx.BoxSizer(wx.HORIZONTAL) | |
468 self.matchButton = wx.Button(self, ID_MATCHBUTTON, "Find") | |
469 self.Bind(wx.EVT_BUTTON, self.OnMatchMe, id=ID_MATCHBUTTON) | |
470 sizer2.Add(self.matchButton, 1, wx.EXPAND) | |
471 self.dehtmlButton = wx.Button(self, ID_DEHTML, "Remove HTML") | |
472 self.Bind(wx.EVT_BUTTON, self.OnDeHTML, id=ID_DEHTML) | |
473 sizer2.Add(self.dehtmlButton, 1, wx.EXPAND) | |
474 self.cancel = wx.Button(self, wx.ID_CANCEL, "Cancel") | |
475 self.Bind(wx.EVT_BUTTON, self.OnCloseMe, id=wx.ID_CANCEL) | |
476 sizer2.Add(self.cancel, 1, wx.EXPAND) | |
477 self.sizer.Add(sizer2, 0, wx.EXPAND) | |
478 self.SetSizer(self.sizer) | |
479 self.SetAutoLayout(True) | |
480 self.Fit() | |
481 #self.Bind(wx.EVT_SIZE, self.OnSize) | |
482 | |
483 # current position | |
484 self.matchPosition = 0 | |
485 # former position | |
486 self.matchPositionOld = 0 | |
487 | |
488 def OnDeHTML(self, event): | |
489 text = re.sub( "\<[^<]*?\>", "", self.text.GetValue() ) | |
490 self.text.SetValue(text) | |
491 | |
492 def OnMatchMe(self, event): | |
493 # match case sensitive | |
494 if self.matchCaseCheckBox.GetValue() == 1: | |
495 textValue = self.text.GetValue() | |
496 matchValue = self.matchInput.GetValue() | |
497 # match case insensitive | |
498 else: | |
499 textValue = string.upper(self.text.GetValue()) | |
500 matchValue = string.upper(self.matchInput.GetValue()) | |
501 | |
502 # continue search from insertion point instead of top | |
503 self.matchPosition = self.matchPositionOld = self.text.GetInsertionPoint() | |
504 | |
505 # find search string in chatbuffer | |
506 self.matchPosition = string.find(textValue[self.matchPositionOld:], matchValue) | |
507 # cumulate position for substring matching in continuing search | |
508 self.matchPositionOld = self.matchPositionOld + self.matchPosition | |
509 | |
510 # if match was found | |
511 if self.matchPosition >= 0: | |
512 # highlight(select) match | |
513 self.text.SetSelection(self.matchPositionOld, self.matchPositionOld + len(matchValue)) | |
514 # continue search from end of match | |
515 self.text.SetInsertionPoint(self.matchPositionOld + len(matchValue)) | |
516 # if match was not found, but match exists somewhere in buffer, start from top | |
517 elif string.find(textValue, matchValue) >= 0: | |
518 self.text.SetInsertionPoint(0) | |
519 self.OnMatchMe(self) | |
520 | |
521 def OnCloseMe(self, event): | |
522 self.Close(True) | |
523 | |
524 def OnCloseWindow(self, event): | |
525 self.Destroy() | |
526 | |
527 class orpgProgressDlg(wx.Dialog): | |
528 def __init__(self, parent, title="", text="", range=10 ): | |
529 wx.Dialog.__init__(self, parent, -1, title, size= wx.Size(200,75)) | |
530 self.sizer = wx.BoxSizer(wx.VERTICAL) | |
531 self.text = wx.StaticText( self, -1, text) | |
532 self.gauge = wx.Gauge(self,-1,range) | |
533 self.sizer.Add(self.text,1,wx.ALIGN_CENTER | wx.EXPAND) | |
534 self.sizer.Add(self.gauge,1,wx.ALIGN_CENTER | wx.EXPAND) | |
535 (w,h) = self.GetClientSizeTuple() | |
536 self.sizer.SetDimension(10,10,w-20,h-20) | |
537 | |
538 def Update(self,pos,text=None): | |
539 self.gauge.SetValue(pos) | |
540 if text: | |
541 self.text.SetLabel(text) | |
542 | |
543 ######################### | |
544 #status frame window | |
545 ######################### | |
546 class status_bar(wx.StatusBar): | |
547 def __init__(self, parent): | |
548 wx.StatusBar.__init__(self, parent, -1) | |
549 GENERAL_MENU = 1 | |
550 URL_MENU = 2 | |
551 self.parent = parent | |
552 self.connect_status = "Not Connected" | |
553 self.urlis = "" | |
554 self.window = 1 | |
555 self.menu = wx.Menu("Switch layout to...") | |
556 item = wx.MenuItem(self.menu, wx.ID_ANY, "General", "General", wx.ITEM_CHECK) | |
557 self.Bind(wx.EVT_MENU, self.OnM_SwitchlayouttoGeneral, item) | |
558 self.menu.AppendItem(item) | |
559 item = wx.MenuItem(self.menu, wx.ID_ANY, "Url Display", "Url Display", wx.ITEM_CHECK) | |
560 self.Bind(wx.EVT_MENU, self.OnM_SwitchlayouttoUrlDisplay, item) | |
561 self.menu.AppendItem(item) | |
562 | |
563 #menu = [["Switch layout to..."], | |
564 # [" General"], | |
565 # [" Url Display"]] | |
566 #self.menu = MenuEx(self, menu) | |
567 | |
568 self.Bind(wx.EVT_RIGHT_DOWN, self.onPopup) | |
569 self.widths = [-1,200] | |
570 (msgwidth,msgheight) = self.GetTextExtent(`self.connect_status`) | |
571 #parent.SetClientSize(wx.Size(450,msgheight+8)) | |
572 #self.SetClientSize(wx.Size(450,msgheight+7)) | |
573 self.SetFieldsCount(2) | |
574 self.timer = wx.Timer(self, wx.NewId()) | |
575 self.Bind(wx.EVT_TIMER, self.Notify) | |
576 self.timer.Start(3000) | |
577 | |
578 def onPopup(self, evt): | |
579 self.PopupMenu(self.menu) | |
580 | |
581 def OnM_SwitchlayouttoUrlDisplay(self, evt): | |
582 self.window = 2 | |
583 self.bar1() | |
584 | |
585 def OnM_SwitchlayouttoGeneral(self, evt): | |
586 self.window = 1 | |
587 self.bar0() | |
588 | |
589 def set_connect_status(self,connect): | |
590 self.connect_status = connect | |
591 | |
592 def Notify(self, event): | |
593 if self.window == 1: | |
594 self.bar0() | |
595 elif self.window == 2: | |
596 self.bar1() | |
597 pass | |
598 | |
599 def bar1(self): | |
600 self.SetFieldsCount(1) | |
601 self.widths = [-1] | |
602 self.SetStatusWidths(self.widths) | |
603 self.SetStatusText("URL: " + self.urlis, 0) | |
604 | |
605 def bar0(self): | |
606 self.SetFieldsCount(2) | |
607 self.widths = [-1,200] | |
608 t = time.gmtime(time.time()) | |
609 st = time.strftime("GMT: %d-%b-%Y %I:%M:%S", t) | |
610 #(x,y) = self.GetTextExtent(self.connect_status) | |
611 #self.widths[0] = x+10 | |
612 (x,y) = self.GetTextExtent(st) | |
613 self.widths[1] = x+10 | |
614 self.SetStatusWidths(self.widths) | |
615 self.SetStatusText(self.connect_status, 0) | |
616 self.SetStatusText(st, 1) | |
617 | |
618 def set_url(self, url): | |
619 self.urlis = url | |
620 | |
621 def __del__(self): | |
622 self.timer.Stop() | |
623 del self.timer | |
624 | |
625 ##################### | |
626 ## Some misc utilties for the GUI | |
627 ##################### | |
628 | |
629 def do_progress_dlg(parent,title,text,range): | |
630 " Returns a new progress dialog" | |
631 if wx.Platform == '__WXMSW__': | |
632 dlg = orpgProgressDlg(parent,title,text,range) | |
633 dlg.Centre() | |
634 dlg.Show(1) | |
635 dlg.Raise() | |
636 else: | |
637 dlg = wx.ProgressDialog(title,text,range,parent) | |
638 return dlg | |
639 | |
640 def parseXml_with_dlg(parent,s,ownerDocument=None): | |
641 "Parse xml with progress dialog" | |
642 dlg = do_progress_dlg(parent,"XML Parser","Reading Configuration Files...",2) | |
643 #dlg.Update(1) | |
644 doc = orpg.orpg_xml.parseXml(s) | |
645 dlg.Update(1,"Done.") | |
646 dlg.Destroy() | |
647 return doc | |
648 | |
649 def createMaskedButton( parent, image, tooltip, id, mask_color=wx.WHITE, image_type=wx.BITMAP_TYPE_GIF ): | |
650 gif = wx.Image( image, image_type, ).ConvertToBitmap() | |
651 mask = wx.Mask( gif, mask_color ) | |
652 gif.SetMask( mask ) | |
653 btn = wx.BitmapButton( parent, id, gif ) | |
654 btn.SetToolTip( wx.ToolTip( tooltip ) ) | |
655 return btn |