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