]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Main.py
added wxStringBuffer helper
[wxWidgets.git] / wxPython / demo / Main.py
1 #!/bin/env python
2 #----------------------------------------------------------------------------
3 # Name: Main.py
4 # Purpose: Testing lots of stuff, controls, window types, etc.
5 #
6 # Author: Robin Dunn
7 #
8 # Created: A long time ago, in a galaxy far, far away...
9 # RCS-ID: $Id$
10 # Copyright: (c) 1999 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
13
14 import sys, os, time
15 from wxPython.wx import *
16 from wxPython.lib.splashscreen import SplashScreen
17 from wxPython.html import wxHtmlWindow
18
19 import images
20
21 #---------------------------------------------------------------------------
22
23
24 _treeList = [
25 ('New since last release', ['ContextHelp',
26 'PyCrust',
27 'PyCrustWithFilling',
28 'VirtualListCtrl',
29 'wxListCtrl',
30 'TablePrint',
31 'OOR',
32 'wxFindReplaceDialog',
33 'DrawXXXList',
34 'ErrorDialogs',
35 'wxRightTextCtrl',
36 'URLDragAndDrop',
37 'wxMimeTypesManager',
38 'wxPopupWindow',
39 'wxDynamicSashWindow',
40 'wxEditableListBox',
41 ]),
42
43 ('Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame',
44 'wxGrid', 'wxSashWindow',
45 'wxScrolledWindow', 'wxSplitterWindow',
46 'wxStatusBar', 'wxNotebook',
47 'wxHtmlWindow',
48 'wxStyledTextCtrl_1', 'wxStyledTextCtrl_2',
49 'wxPopupWindow',
50 'wxDynamicSashWindow',
51 ]),
52
53 ('Common Dialogs', ['wxColourDialog', 'wxDirDialog', 'wxFileDialog',
54 'wxSingleChoiceDialog', 'wxTextEntryDialog',
55 'wxFontDialog', 'wxPageSetupDialog', 'wxPrintDialog',
56 'wxMessageDialog', 'wxProgressDialog', 'wxFindReplaceDialog',
57 ]),
58
59 ('Controls', ['wxButton', 'wxCheckBox', 'wxCheckListBox', 'wxChoice',
60 'wxComboBox', 'wxGauge', 'wxListBox', 'wxListCtrl', 'wxTextCtrl',
61 'wxTreeCtrl', 'wxSpinButton', 'wxSpinCtrl', 'wxStaticText',
62 'wxStaticBitmap', 'wxRadioBox', 'wxSlider', 'wxToolBar',
63 'wxCalendarCtrl', 'wxToggleButton',
64 'wxEditableListBox',
65 ]),
66
67 ('Window Layout', ['wxLayoutConstraints', 'LayoutAnchors', 'Sizers', 'XML_Resource']),
68
69 ('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'URLDragAndDrop',
70 'FontEnumerator',
71 'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
72 'wxImage', 'wxMask', 'PrintFramework', 'wxOGL',
73 'PythonEvents', 'Threads',
74 'ActiveXWrapper_Acrobat', 'ActiveXWrapper_IE',
75 'wxDragImage', "wxProcess", "FancyText", "OOR", "wxWave",
76 'wxJoystick', 'DrawXXXList', 'ErrorDialogs', 'wxMimeTypesManager',
77 ]),
78
79 ('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
80 'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
81 'wxCalendar', 'wxMVCTree', 'wxVTKRenderWindow',
82 'FileBrowseButton', 'GenericButtons', 'wxEditor',
83 'ColourSelect', 'ImageBrowser',
84 'infoframe', 'ColourDB', 'PyCrust', 'TablePrint',
85 'wxRightTextCtrl',
86 ]),
87
88 ('Cool Contribs', ['pyTree', 'hangman',
89 #'SlashDot',
90 'XMLtreeview'
91 ]),
92
93 ]
94
95 #---------------------------------------------------------------------------
96
97 class MyLog(wxPyLog):
98 def __init__(self, textCtrl, logTime=0):
99 wxPyLog.__init__(self)
100 self.tc = textCtrl
101 self.logTime = logTime
102
103 def DoLogString(self, message, timeStamp):
104 if self.logTime:
105 message = time.strftime("%X", time.localtime(timeStamp)) + \
106 ": " + message
107 self.tc.AppendText(message + '\n')
108
109
110 #---------------------------------------------------------------------------
111
112 class wxPythonDemo(wxFrame):
113
114 def __init__(self, parent, id, title):
115 wxFrame.__init__(self, parent, -1, title, size = (800, 600),
116 style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
117
118 self.cwd = os.getcwd()
119 self.curOverview = ""
120
121 if 1:
122 icon = wxIconFromXPMData(images.getMondrianData())
123 else:
124 # another way to do it
125 bmp = images.getMondrianBitmap()
126 icon = wxEmptyIcon()
127 icon.CopyFromBitmap(bmp)
128
129 self.SetIcon(icon)
130
131 if wxPlatform == '__WXMSW__':
132 # setup a taskbar icon, and catch some events from it
133 self.tbicon = wxTaskBarIcon()
134 self.tbicon.SetIcon(icon, "wxPython Demo")
135 EVT_TASKBAR_LEFT_DCLICK(self.tbicon, self.OnTaskBarActivate)
136 EVT_TASKBAR_RIGHT_UP(self.tbicon, self.OnTaskBarMenu)
137 EVT_MENU(self.tbicon, self.TBMENU_RESTORE, self.OnTaskBarActivate)
138 EVT_MENU(self.tbicon, self.TBMENU_CLOSE, self.OnTaskBarClose)
139
140
141 self.otherWin = None
142 EVT_IDLE(self, self.OnIdle)
143 EVT_CLOSE(self, self.OnCloseWindow)
144 EVT_ICONIZE(self, self.OnIconfiy)
145 EVT_MAXIMIZE(self, self.OnMaximize)
146
147 self.Centre(wxBOTH)
148 self.CreateStatusBar(1, wxST_SIZEGRIP)
149
150 splitter = wxSplitterWindow(self, -1, style=wxNO_3D|wxSP_3D)
151 splitter2 = wxSplitterWindow(splitter, -1, style=wxNO_3D|wxSP_3D)
152
153 def EmptyHandler(evt): pass
154 EVT_ERASE_BACKGROUND(splitter, EmptyHandler)
155 EVT_ERASE_BACKGROUND(splitter2, EmptyHandler)
156
157 # Prevent TreeCtrl from displaying all items after destruction when true
158 self.dying = false
159
160 # Make a File menu
161 self.mainmenu = wxMenuBar()
162 menu = wxMenu()
163 exitID = wxNewId()
164 menu.Append(exitID, 'E&xit\tAlt-X', 'Get the heck outta here!')
165 EVT_MENU(self, exitID, self.OnFileExit)
166 self.mainmenu.Append(menu, '&File')
167
168 # Make a Demo menu
169 menu = wxMenu()
170 for item in _treeList:
171 submenu = wxMenu()
172 for childItem in item[1]:
173 mID = wxNewId()
174 submenu.Append(mID, childItem)
175 EVT_MENU(self, mID, self.OnDemoMenu)
176 menu.AppendMenu(wxNewId(), item[0], submenu)
177 self.mainmenu.Append(menu, '&Demo')
178
179
180 # Make a Help menu
181 helpID = wxNewId()
182 menu = wxMenu()
183 menu.Append(helpID, '&About\tCtrl-H', 'wxPython RULES!!!')
184 EVT_MENU(self, helpID, self.OnHelpAbout)
185 self.mainmenu.Append(menu, '&Help')
186 self.SetMenuBar(self.mainmenu)
187
188 # set the menu accellerator table...
189 aTable = wxAcceleratorTable([(wxACCEL_ALT, ord('X'), exitID),
190 (wxACCEL_CTRL, ord('H'), helpID)])
191 self.SetAcceleratorTable(aTable)
192
193
194 # Create a TreeCtrl
195 tID = wxNewId()
196 self.treeMap = {}
197 self.tree = wxTreeCtrl(splitter, tID,
198 style=wxTR_HAS_BUTTONS |
199 wxTR_EDIT_LABELS |
200 wxTR_HAS_VARIABLE_ROW_HEIGHT |
201 wxSUNKEN_BORDER)
202 #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
203 root = self.tree.AddRoot("Overview")
204 firstChild = None
205 for item in _treeList:
206 child = self.tree.AppendItem(root, item[0])
207 if not firstChild: firstChild = child
208 for childItem in item[1]:
209 theDemo = self.tree.AppendItem(child, childItem)
210 self.treeMap[childItem] = theDemo
211
212 self.tree.Expand(root)
213 self.tree.Expand(firstChild)
214 EVT_TREE_ITEM_EXPANDED (self.tree, tID, self.OnItemExpanded)
215 EVT_TREE_ITEM_COLLAPSED (self.tree, tID, self.OnItemCollapsed)
216 EVT_TREE_SEL_CHANGED (self.tree, tID, self.OnSelChanged)
217 EVT_LEFT_DOWN (self.tree, self.OnTreeLeftDown)
218
219 # Create a Notebook
220 self.nb = wxNotebook(splitter2, -1, style=wxCLIP_CHILDREN)
221
222 # Set up a wxHtmlWindow on the Overview Notebook page
223 # we put it in a panel first because there seems to be a
224 # refresh bug of some sort (wxGTK) when it is directly in
225 # the notebook...
226 if 0: # the old way
227 self.ovr = wxHtmlWindow(self.nb, -1, size=(400, 400))
228 self.nb.AddPage(self.ovr, "Overview")
229
230 else: # hopefully I can remove this hacky code soon, see bug #216861
231 panel = wxPanel(self.nb, -1, style=wxCLIP_CHILDREN)
232 self.ovr = wxHtmlWindow(panel, -1, size=(400, 400))
233 self.nb.AddPage(panel, "Overview")
234
235 def OnOvrSize(evt, ovr=self.ovr):
236 ovr.SetSize(evt.GetSize())
237
238 EVT_SIZE(panel, OnOvrSize)
239 EVT_ERASE_BACKGROUND(panel, EmptyHandler)
240
241
242 self.SetOverview("Overview", overview)
243
244
245 # Set up a TextCtrl on the Demo Code Notebook page
246 self.txt = wxTextCtrl(self.nb, -1,
247 style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
248 self.nb.AddPage(self.txt, "Demo Code")
249
250
251 # Set up a log on the View Log Notebook page
252 self.log = wxTextCtrl(splitter2, -1,
253 style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
254 # Set the wxWindows log target to be this textctrl
255 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
256 wxLog_SetActiveTarget(MyLog(self.log))
257
258
259
260 self.Show(true)
261
262 # add the windows to the splitter and split it.
263 splitter2.SplitHorizontally(self.nb, self.log)
264 splitter2.SetSashPosition(450, true)
265 splitter2.SetMinimumPaneSize(20)
266
267 splitter.SplitVertically(self.tree, splitter2)
268 splitter.SetSashPosition(180, true)
269 splitter.SetMinimumPaneSize(20)
270
271
272 # select initial items
273 self.nb.SetSelection(0)
274 self.tree.SelectItem(root)
275
276 if len(sys.argv) == 2:
277 try:
278 selectedDemo = self.treeMap[sys.argv[1]]
279 except:
280 selectedDemo = None
281 if selectedDemo:
282 self.tree.SelectItem(selectedDemo)
283 self.tree.EnsureVisible(selectedDemo)
284
285
286 wxLogMessage('window handle: %s' % self.GetHandle())
287
288
289 #---------------------------------------------
290 def WriteText(self, text):
291 if text[-1:] == '\n':
292 text = text[:-1]
293 wxLogMessage(text)
294
295
296 def write(self, txt):
297 self.WriteText(txt)
298
299 #---------------------------------------------
300 def OnItemExpanded(self, event):
301 item = event.GetItem()
302 wxLogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item))
303 event.Skip()
304
305 #---------------------------------------------
306 def OnItemCollapsed(self, event):
307 item = event.GetItem()
308 wxLogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
309 event.Skip()
310
311 #---------------------------------------------
312 def OnTreeLeftDown(self, event):
313 pt = event.GetPosition();
314 item, flags = self.tree.HitTest(pt)
315 if item == self.tree.GetSelection():
316 self.SetOverview(self.tree.GetItemText(item), self.curOverview)
317 event.Skip()
318
319 #---------------------------------------------
320 def OnSelChanged(self, event):
321 if self.dying:
322 return
323
324 item = event.GetItem()
325 itemText = self.tree.GetItemText(item)
326 self.RunDemo(itemText)
327
328
329 #---------------------------------------------
330 def RunDemo(self, itemText):
331 os.chdir(self.cwd)
332 if self.nb.GetPageCount() == 3:
333 if self.nb.GetSelection() == 2:
334 self.nb.SetSelection(0)
335 self.nb.DeletePage(2)
336
337 if itemText == 'Overview':
338 self.GetDemoFile('Main.py')
339 self.SetOverview('Overview', overview)
340 self.nb.Refresh();
341 self.window = None
342
343 else:
344 if os.path.exists(itemText + '.py'):
345 wxBeginBusyCursor()
346 wxLogMessage("Running demo %s.py..." % itemText)
347 try:
348 self.GetDemoFile(itemText + '.py')
349 module = __import__(itemText, globals())
350 self.SetOverview(itemText, module.overview)
351 finally:
352 wxEndBusyCursor()
353
354 # in case runTest is modal, make sure things look right...
355 self.nb.Refresh();
356 wxYield()
357
358 self.window = module.runTest(self, self.nb, self) ###
359 if self.window:
360 self.nb.AddPage(self.window, 'Demo')
361 wxYield()
362 self.nb.SetSelection(2)
363
364 else:
365 self.ovr.SetPage("")
366 self.txt.Clear()
367 self.window = None
368
369
370
371 #---------------------------------------------
372 # Get the Demo files
373 def GetDemoFile(self, filename):
374 self.txt.Clear()
375 try:
376 self.txt.SetValue(open(filename).read())
377 except IOError:
378 self.txt.WriteText("Cannot open %s file." % filename)
379
380 self.txt.SetInsertionPoint(0)
381 self.txt.ShowPosition(0)
382
383 #---------------------------------------------
384 def SetOverview(self, name, text):
385 self.curOverview = text
386 lead = text[:6]
387 if lead != '<html>' and lead != '<HTML>':
388 text = string.join(string.split(text, '\n'), '<br>')
389 #text = '<font size="-1"><pre>' + text + '</pre></font>'
390 self.ovr.SetPage(text)
391 self.nb.SetPageText(0, name)
392
393 #---------------------------------------------
394 # Menu methods
395 def OnFileExit(self, *event):
396 self.Close()
397
398
399 def OnHelpAbout(self, event):
400 from About import MyAboutBox
401 about = MyAboutBox(self)
402 about.ShowModal()
403 about.Destroy()
404
405
406 #---------------------------------------------
407 def OnCloseWindow(self, event):
408 self.dying = true
409 self.window = None
410 self.mainmenu = None
411 if hasattr(self, "tbicon"):
412 del self.tbicon
413 self.Destroy()
414
415
416 #---------------------------------------------
417 def OnIdle(self, event):
418 if self.otherWin:
419 self.otherWin.Raise()
420 self.window = self.otherWin
421 self.otherWin = None
422
423 #---------------------------------------------
424 def OnDemoMenu(self, event):
425 try:
426 selectedDemo = self.treeMap[self.mainmenu.GetLabel(event.GetId())]
427 except:
428 selectedDemo = None
429 if selectedDemo:
430 self.tree.SelectItem(selectedDemo)
431 self.tree.EnsureVisible(selectedDemo)
432
433
434 #---------------------------------------------
435 def OnTaskBarActivate(self, evt):
436 if self.IsIconized():
437 self.Iconize(false)
438 if not self.IsShown():
439 self.Show(true)
440 self.Raise()
441
442 #---------------------------------------------
443
444 TBMENU_RESTORE = 1000
445 TBMENU_CLOSE = 1001
446
447 def OnTaskBarMenu(self, evt):
448 menu = wxMenu()
449 menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
450 menu.Append(self.TBMENU_CLOSE, "Close")
451 self.tbicon.PopupMenu(menu)
452 menu.Destroy()
453
454 #---------------------------------------------
455 def OnTaskBarClose(self, evt):
456 self.Close()
457
458 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
459 # prod the main idle handler a bit to get the window to actually close
460 wxGetApp().ProcessIdle()
461
462
463 #---------------------------------------------
464 def OnIconfiy(self, evt):
465 wxLogMessage("OnIconfiy")
466 evt.Skip()
467
468 #---------------------------------------------
469 def OnMaximize(self, evt):
470 wxLogMessage("OnMaximize")
471 evt.Skip()
472
473
474
475
476 #---------------------------------------------------------------------------
477 #---------------------------------------------------------------------------
478
479 class MyApp(wxApp):
480 def OnInit(self):
481 wxInitAllImageHandlers()
482
483 self.splash = SplashScreen(None, bitmapfile='bitmaps/splash.gif',
484 duration=4000, callback=self.AfterSplash)
485 self.splash.Show(true)
486 wxYield()
487 return true
488
489
490 def AfterSplash(self):
491 self.splash.Close(true)
492 frame = wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
493 frame.Show(true)
494 self.SetTopWindow(frame)
495 self.ShowTip(frame)
496
497
498 def ShowTip(self, frame):
499 try:
500 showTipText = open("data/showTips").read()
501 showTip, index = eval(showTipText)
502 except IOError:
503 showTip, index = (1, 0)
504 #print showTip, index
505 if showTip:
506 tp = wxCreateFileTipProvider("data/tips.txt", index)
507 showTip = wxShowTip(frame, tp)
508 index = tp.GetCurrentTip()
509 open("data/showTips", "w").write(str( (showTip, index) ))
510
511
512 #---------------------------------------------------------------------------
513
514 def main():
515 try:
516 demoPath = os.path.dirname(__file__)
517 os.chdir(demoPath)
518 except:
519 pass
520 app = MyApp(0)
521 app.MainLoop()
522
523
524 #---------------------------------------------------------------------------
525
526
527
528 overview = """<html><body>
529 <h2>Python</h2>
530
531 Python is an interpreted, interactive, object-oriented programming
532 language often compared to Tcl, Perl, Scheme, or Java.
533
534 <p> Python combines remarkable power with very clear syntax. It has
535 modules, classes, exceptions, very high level dynamic data types, and
536 dynamic typing. There are interfaces to many system calls and
537 libraries, and new built-in modules are easily written in C or
538 C++. Python is also usable as an extension language for applications
539 that need a programmable interface. <p>
540
541 <h2>wxWindows</h2>
542
543 wxWindows is a free C++ framework designed to make cross-platform
544 programming child's play. Well, almost. wxWindows 2 supports Windows
545 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
546 underway. Other ports are under consideration. <p>
547
548 wxWindows is a set of libraries that allows C++ applications to
549 compile and run on several different types of computers, with minimal
550 source code changes. There is one library per supported GUI (such as
551 Motif, or Windows). As well as providing a common API (Application
552 Programming Interface) for GUI functionality, it provides
553 functionality for accessing some commonly-used operating system
554 facilities, such as copying or deleting files. wxWindows is a
555 'framework' in the sense that it provides a lot of built-in
556 functionality, which the application can use or replace as required,
557 thus saving a great deal of coding effort. Basic data structures such
558 as strings, linked lists and hash tables are also supported.
559
560 <p>
561 <h2>wxPython</h2>
562
563 wxPython is a Python extension module that encapsulates the wxWindows
564 GUI classes. Currently it is only available for the Win32 and GTK
565 ports of wxWindows, but as soon as the other ports are brought up to
566 the same level as Win32 and GTK, it should be fairly trivial to
567 enable wxPython to be used with the new GUI.
568
569 <p>
570
571 The wxPython extension module attempts to mirror the class heiarchy
572 of wxWindows as closely as possible. This means that there is a
573 wxFrame class in wxPython that looks, smells, tastes and acts almost
574 the same as the wxFrame class in the C++ version. Unfortunately,
575 because of differences in the languages, wxPython doesn't match
576 wxWindows exactly, but the differences should be easy to absorb
577 because they are natural to Python. For example, some methods that
578 return multiple values via argument pointers in C++ will return a
579 tuple of values in Python.
580
581 <p>
582
583 There is still much to be done for wxPython, many classes still need
584 to be mirrored. Also, wxWindows is still somewhat of a moving target
585 so it is a bit of an effort just keeping wxPython up to date. On the
586 other hand, there are enough of the core classes completed that
587 useful applications can be written.
588
589 <p>
590
591 wxPython is close enough to the C++ version that the majority of
592 the wxPython documentation is actually just notes attached to the C++
593 documents that describe the places where wxPython is different. There
594 is also a series of sample programs included, and a series of
595 documentation pages that assist the programmer in getting started
596 with wxPython.
597
598 """
599
600
601 #----------------------------------------------------------------------------
602 #----------------------------------------------------------------------------
603
604 if __name__ == '__main__':
605 main()
606
607 #----------------------------------------------------------------------------
608
609
610
611
612
613
614