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