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