]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/Main.py
Add docstrings for ComboCtrl and ComboPopup, and added OwnerDrawnComboBox
[wxWidgets.git] / wxPython / demo / Main.py
CommitLineData
cf694132
RD
1#!/bin/env python
2#----------------------------------------------------------------------------
3# Name: Main.py
4# Purpose: Testing lots of stuff, controls, window types, etc.
5#
f6bcfd97 6# Author: Robin Dunn
cf694132 7#
f6bcfd97 8# Created: A long time ago, in a galaxy far, far away...
cf694132
RD
9# RCS-ID: $Id$
10# Copyright: (c) 1999 by Total Control Software
11# Licence: wxWindows license
12#----------------------------------------------------------------------------
13
08ecc920
RD
14# FIXME List:
15# * Problems with flickering related to ERASE_BACKGROUND
16# and the splitters. Might be a problem with this 2.5 beta...?
17# UPDATE: can't see on 2.5.2 GTK - maybe just a faster machine :)
18# * Demo Code menu?
19# * Annoying switching between tabs and resulting flicker
20# how to replace a page in the notebook without deleting/adding?
21# Where is SetPage!? tried freeze...tried reparent of dummy panel....
22
23# TODO List:
24# * UI design more prefessional
25# * save file positions (new field in demoModules) (@ LoadDemoSource)
26# * Update main overview
27
28# * Why don't we move _treeList into a separate module
29
30import sys, os, time, traceback, types
cf694132 31
1fded56b
RD
32import wx # This module uses the new wx namespace
33import wx.html
606d919c 34
96bfd053
RD
35import images
36
d14a1e28
RD
37# For debugging
38##wx.Trap();
a0676188
RD
39##print "wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi')
40##print "pid:", os.getpid()
ef8b9c3e 41##raw_input("Press Enter...")
6fa68946 42
1e4a197e 43
cf694132
RD
44#---------------------------------------------------------------------------
45
46
47_treeList = [
9c67cbec 48 # new stuff
77d4f443 49 ('Recent Additions/Updates', [
23a02364 50 'AnalogClock',
1c976bff
RD
51 'AUI_DockingWindowMgr',
52 'AUI_Notebook',
23a02364 53 'CheckListCtrlMixin',
4f708f05 54 'ComboTreeBox',
febb39df 55 'Pickers',
7e664d85 56 'PseudoDC',
30fc5e8f 57 'RichTextCtrl',
6aabc8da
RD
58 'Treebook',
59 'Toolbook',
ecc0e221
RD
60 'BitmapFromBuffer',
61 'RawBitmapAccess',
f77c79d0 62 'DragScroller',
8bbd1bbf 63 'DelayedResult',
ac9d5e95 64 'ExpandoTextCtrl',
66dae888 65 'ButtonPanel',
6cb4f153 66 'FlatNotebook',
c8f129d0 67 'CustomTreeCtrl',
f541d829 68 'AboutBox',
e19b9131 69 'AnimateCtrl',
2c7816ff 70 'AlphaDrawing',
51aad6d3 71 'GraphicsContext',
73470a17 72 'CollapsiblePane',
84bc0d49 73 'ComboCtrl',
84dd1dd8 74 'OwnerDrawnComboBox',
9c67cbec
RD
75 ]),
76
1e4a197e 77 # managed windows == things with a (optional) caption you can close
03a604a6 78 ('Frames and Dialogs', [
1c976bff 79 'AUI_DockingWindowMgr',
299647ac
RD
80 'Dialog',
81 'Frame',
82 'MDIWindows',
83 'MiniFrame',
84 'Wizard',
9c67cbec
RD
85 ]),
86
87 # the common dialogs
88 ('Common Dialogs', [
f541d829 89 'AboutBox',
299647ac
RD
90 'ColourDialog',
91 'DirDialog',
92 'FileDialog',
299647ac
RD
93 'FindReplaceDialog',
94 'FontDialog',
95 'MessageDialog',
89eb18ec 96 'MultiChoiceDialog',
299647ac
RD
97 'PageSetupDialog',
98 'PrintDialog',
99 'ProgressDialog',
100 'SingleChoiceDialog',
101 'TextEntryDialog',
9c67cbec
RD
102 ]),
103
af83019e 104 # dialogs from libraries
9c67cbec 105 ('More Dialogs', [
9c67cbec 106 'ImageBrowser',
299647ac 107 'ScrolledMessageDialog',
9c67cbec
RD
108 ]),
109
110 # core controls
111 ('Core Windows/Controls', [
8b7fa2d9 112 'BitmapButton',
299647ac
RD
113 'Button',
114 'CheckBox',
115 'CheckListBox',
116 'Choice',
117 'ComboBox',
118 'Gauge',
119 'Grid',
120 'Grid_MegaExample',
121 'ListBox',
122 'ListCtrl',
123 'ListCtrl_virtual',
15513a80 124 'ListCtrl_edit',
299647ac 125 'Menu',
1fded56b 126 'PopupMenu',
299647ac
RD
127 'PopupWindow',
128 'RadioBox',
129 'RadioButton',
130 'SashWindow',
131 'ScrolledWindow',
132 'Slider',
133 'SpinButton',
134 'SpinCtrl',
135 'SplitterWindow',
136 'StaticBitmap',
e79c8a7c 137 'StaticBox',
299647ac
RD
138 'StaticText',
139 'StatusBar',
f2b4a4ea 140 'StockButtons',
299647ac
RD
141 'TextCtrl',
142 'ToggleButton',
143 'ToolBar',
144 'TreeCtrl',
145 'Validator',
9c67cbec 146 ]),
6aabc8da
RD
147
148 ('"Book" Controls', [
1c976bff 149 'AUI_Notebook',
6aabc8da
RD
150 'Choicebook',
151 'Listbook',
152 'Notebook',
153 'Toolbook',
154 'Treebook',
155 ]),
9c67cbec 156
d14a1e28 157 ('Custom Controls', [
23a02364 158 'AnalogClock',
66dae888 159 'ButtonPanel',
d14a1e28 160 'ColourSelect',
4f708f05 161 'ComboTreeBox',
c8f129d0 162 'CustomTreeCtrl',
299647ac 163 'Editor',
6cb4f153 164 'FlatNotebook',
d14a1e28 165 'GenericButtons',
299647ac
RD
166 'GenericDirCtrl',
167 'LEDNumberCtrl',
168 'MultiSash',
169 'PopupControl',
170 'PyColourChooser',
171 'TreeListCtrl',
d14a1e28
RD
172 ]),
173
8b9a4190 174 # controls coming from other libraries
9c67cbec 175 ('More Windows/Controls', [
b7c75283
RD
176 'ActiveX_FlashWindow',
177 'ActiveX_IEHtmlWindow',
178 'ActiveX_PDFWindow',
299647ac
RD
179 #'RightTextCtrl', deprecated as we have wxTE_RIGHT now.
180 'Calendar',
181 'CalendarCtrl',
23a02364 182 'CheckListCtrlMixin',
73470a17 183 'CollapsiblePane',
84bc0d49 184 'ComboCtrl',
9c67cbec 185 'ContextHelp',
91334b48 186 'DatePickerCtrl',
299647ac
RD
187 'DynamicSashWindow',
188 'EditableListBox',
ac9d5e95 189 'ExpandoTextCtrl',
9c67cbec
RD
190 'FancyText',
191 'FileBrowseButton',
299647ac
RD
192 'FloatBar',
193 'FloatCanvas',
42f5333f 194 'FoldPanelBar',
299647ac 195 'HtmlWindow',
a6987674 196 'HyperLinkCtrl',
299647ac
RD
197 'IntCtrl',
198 'MVCTree',
1fded56b 199 'MaskedEditControls',
299647ac 200 'MaskedNumCtrl',
486afba9
RD
201 'MediaCtrl',
202 'MultiSplitterWindow',
84dd1dd8 203 'OwnerDrawnComboBox',
d211a853 204 'Pickers',
9c67cbec 205 'PyCrust',
80b27b4e 206 'PyPlot',
299647ac 207 'PyShell',
30fc5e8f 208 'RichTextCtrl',
299647ac 209 'ScrolledPanel',
9c67cbec 210 'SplitTree',
299647ac
RD
211 'StyledTextCtrl_1',
212 'StyledTextCtrl_2',
9c67cbec 213 'TablePrint',
1e4a197e 214 'Throbber',
cccce1a6 215 'Ticker',
299647ac
RD
216 'TimeCtrl',
217 'VListBox',
9c67cbec
RD
218 ]),
219
220 # How to lay out the controls in a frame/dialog
221 ('Window Layout', [
299647ac 222 'GridBagSizer',
9c67cbec 223 'LayoutAnchors',
299647ac 224 'LayoutConstraints',
9c67cbec
RD
225 'Layoutf',
226 'RowColSizer',
299647ac 227 'ScrolledPanel',
9c67cbec 228 'Sizers',
299647ac
RD
229 'XmlResource',
230 'XmlResourceHandler',
231 'XmlResourceSubclass',
9c67cbec
RD
232 ]),
233
234 # ditto
235 ('Process and Events', [
8bbd1bbf 236 'DelayedResult',
1e4a197e 237 'EventManager',
299647ac 238 'KeyEvents',
299647ac 239 'Process',
9c67cbec
RD
240 'PythonEvents',
241 'Threads',
299647ac 242 'Timer',
c163da42 243 ##'infoframe', # needs better explanation and some fixing
9c67cbec
RD
244 ]),
245
246 # Clipboard and DnD
247 ('Clipboard and DnD', [
248 'CustomDragAndDrop',
249 'DragAndDrop',
250 'URLDragAndDrop',
251 ]),
252
253 # Images
1e4a197e 254 ('Using Images', [
2c7816ff 255 'AlphaDrawing',
c35bf68e 256 'AnimateCtrl',
299647ac 257 'ArtProvider',
0dcc6f22 258 'BitmapFromBuffer',
76343679 259 'Cursor',
299647ac
RD
260 'DragImage',
261 'Image',
8a88769e 262 'ImageAlpha',
299647ac
RD
263 'ImageFromStream',
264 'Mask',
ecc0e221 265 'RawBitmapAccess',
1e4a197e 266 'Throbber',
9c67cbec
RD
267 ]),
268
269 # Other stuff
270 ('Miscellaneous', [
2c7816ff 271 'AlphaDrawing',
9c67cbec 272 'ColourDB',
c163da42 273 ##'DialogUnits', # needs more explanations
f77c79d0 274 'DragScroller',
9c67cbec 275 'DrawXXXList',
299647ac 276 'FileHistory',
9c67cbec 277 'FontEnumerator',
51aad6d3 278 'GraphicsContext',
486afba9 279 'GLCanvas',
299647ac 280 'Joystick',
486afba9 281 'MimeTypesManager',
51c5e1f2 282 'MouseGestures',
299647ac 283 'OGL',
9c67cbec 284 'PrintFramework',
7e664d85 285 'PseudoDC',
3628e088 286 'ShapedWindow',
78862f24 287 'Sound',
62038e59 288 'StandardPaths',
9c67cbec 289 'Unicode',
9c67cbec
RD
290 ]),
291
70a357c2 292
9c67cbec
RD
293 ('Check out the samples dir too', [
294 ]),
295
9c67cbec
RD
296]
297
298
cf694132
RD
299
300#---------------------------------------------------------------------------
8b9a4190 301# Show how to derive a custom wxLog class
cf694132 302
1fded56b 303class MyLog(wx.PyLog):
76bfdc78 304 def __init__(self, textCtrl, logTime=0):
1fded56b 305 wx.PyLog.__init__(self)
76bfdc78
RD
306 self.tc = textCtrl
307 self.logTime = logTime
308
309 def DoLogString(self, message, timeStamp):
62038e59
RD
310 #print message, timeStamp
311 #if self.logTime:
312 # message = time.strftime("%X", time.localtime(timeStamp)) + \
313 # ": " + message
1e4a197e
RD
314 if self.tc:
315 self.tc.AppendText(message + '\n')
76bfdc78
RD
316
317
1fded56b 318class MyTP(wx.PyTipProvider):
861a0196
RD
319 def GetTip(self):
320 return "This is my tip"
321
c4ef95da
RD
322#---------------------------------------------------------------------------
323# A class to be used to simply display a message in the demo pane
324# rather than running the sample itself.
325
326class MessagePanel(wx.Panel):
327 def __init__(self, parent, message, caption='', flags=0):
328 wx.Panel.__init__(self, parent)
329
330 # Make widgets
331 if flags:
332 artid = None
333 if flags & wx.ICON_EXCLAMATION:
334 artid = wx.ART_WARNING
335 elif flags & wx.ICON_ERROR:
336 artid = wx.ART_ERROR
337 elif flags & wx.ICON_QUESTION:
338 artid = wx.ART_QUESTION
339 elif flags & wx.ICON_INFORMATION:
340 artid = wx.ART_INFORMATION
341
342 if artid is not None:
343 bmp = wx.ArtProvider.GetBitmap(artid, wx.ART_MESSAGE_BOX, (32,32))
344 icon = wx.StaticBitmap(self, -1, bmp)
345 else:
346 icon = (32,32) # make a spacer instead
347
348 if caption:
349 caption = wx.StaticText(self, -1, caption)
350 caption.SetFont(wx.Font(28, wx.SWISS, wx.NORMAL, wx.BOLD))
351
352 message = wx.StaticText(self, -1, message)
353
354 # add to sizers for layout
355 tbox = wx.BoxSizer(wx.VERTICAL)
356 if caption:
357 tbox.Add(caption)
358 tbox.Add((10,10))
359 tbox.Add(message)
360
361 hbox = wx.BoxSizer(wx.HORIZONTAL)
362 hbox.Add((10,10), 1)
363 hbox.Add(icon)
364 hbox.Add((10,10))
365 hbox.Add(tbox)
366 hbox.Add((10,10), 1)
367
368 box = wx.BoxSizer(wx.VERTICAL)
369 box.Add((10,10), 1)
370 box.Add(hbox, 0, wx.EXPAND)
371 box.Add((10,10), 2)
372
373 self.SetSizer(box)
a7593631 374 self.Fit()
c4ef95da 375
08ecc920 376
1fded56b
RD
377#---------------------------------------------------------------------------
378# A class to be used to display source code in the demo. Try using the
299647ac 379# wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
1fded56b 380# if there is an error, such as the stc module not being present.
8b9a4190 381#
1fded56b
RD
382
383try:
4638eaea 384 ##raise ImportError # for testing the alternate implementation
1fded56b 385 from wx import stc
299647ac 386 from StyledTextCtrl_2 import PythonSTC
08ecc920
RD
387
388 class DemoCodeEditor(PythonSTC):
389 def __init__(self, parent):
2e839e96 390 PythonSTC.__init__(self, parent, -1, style=wx.BORDER_NONE)
80b27b4e 391 self.SetUpEditor()
1fded56b
RD
392
393 # Some methods to make it compatible with how the wxTextCtrl is used
394 def SetValue(self, value):
6c7d1792
RD
395 if wx.USE_UNICODE:
396 value = value.decode('iso8859_1')
1fded56b 397 self.SetText(value)
08ecc920
RD
398 self.EmptyUndoBuffer()
399 self.SetSavePoint()
400
401 def IsModified(self):
402 return self.GetModify()
1fded56b
RD
403
404 def Clear(self):
405 self.ClearAll()
406
407 def SetInsertionPoint(self, pos):
408 self.SetCurrentPos(pos)
08ecc920 409 self.SetAnchor(pos)
1fded56b
RD
410
411 def ShowPosition(self, pos):
08ecc920 412 line = self.LineFromPosition(pos)
887a1bd9
RD
413 #self.EnsureVisible(line)
414 self.GotoLine(line)
1fded56b
RD
415
416 def GetLastPosition(self):
417 return self.GetLength()
418
08ecc920
RD
419 def GetPositionFromLine(self, line):
420 return self.PositionFromLine(line)
421
1fded56b
RD
422 def GetRange(self, start, end):
423 return self.GetTextRange(start, end)
424
425 def GetSelection(self):
426 return self.GetAnchor(), self.GetCurrentPos()
427
428 def SetSelection(self, start, end):
429 self.SetSelectionStart(start)
430 self.SetSelectionEnd(end)
431
08ecc920
RD
432 def SelectLine(self, line):
433 start = self.PositionFromLine(line)
434 end = self.GetLineEndPosition(line)
435 self.SetSelection(start, end)
436
80b27b4e
RD
437 def SetUpEditor(self):
438 """
439 This method carries out the work of setting up the demo editor.
440 It's seperate so as not to clutter up the init code.
441 """
442 import keyword
443
444 self.SetLexer(stc.STC_LEX_PYTHON)
445 self.SetKeyWords(0, " ".join(keyword.kwlist))
446
447 # Enable folding
448 self.SetProperty("fold", "1" )
449
450 # Highlight tab/space mixing (shouldn't be any)
451 self.SetProperty("tab.timmy.whinge.level", "1")
452
453 # Set left and right margins
454 self.SetMargins(2,2)
455
456 # Set up the numbers in the margin for margin #1
457 self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
458 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
459 self.SetMarginWidth(1, 40)
460
461 # Indentation and tab stuff
462 self.SetIndent(4) # Proscribed indent size for wx
463 self.SetIndentationGuides(True) # Show indent guides
464 self.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
465 self.SetTabIndents(True) # Tab key indents
466 self.SetTabWidth(4) # Proscribed tab size for wx
467 self.SetUseTabs(False) # Use spaces rather than tabs, or
468 # TabTimmy will complain!
469 # White space
470 self.SetViewWhiteSpace(False) # Don't view white space
471
887a1bd9
RD
472 # EOL: Since we are loading/saving ourselves, and the
473 # strings will always have \n's in them, set the STC to
474 # edit them that way.
475 self.SetEOLMode(wx.stc.STC_EOL_LF)
476 self.SetViewEOL(False)
477
80b27b4e
RD
478 # No right-edge mode indicator
479 self.SetEdgeMode(stc.STC_EDGE_NONE)
480
481 # Setup a margin to hold fold markers
482 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
483 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
484 self.SetMarginSensitive(2, True)
485 self.SetMarginWidth(2, 12)
486
487 # and now set up the fold markers
488 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "black")
489 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "black")
490 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "black")
491 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "black")
492 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "black")
493 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "black")
494 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "black")
495
496 # Global default style
497 if wx.Platform == '__WXMSW__':
498 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
499 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
1f2b9015
KO
500 elif wx.Platform == '__WXMAC__':
501 # TODO: if this looks fine on Linux too, remove the Mac-specific case
502 # and use this whenever OS != MSW.
503 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
504 'fore:#000000,back:#FFFFFF,face:Courier')
80b27b4e
RD
505 else:
506 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
27eac64c 507 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
80b27b4e
RD
508
509 # Clear styles and revert to default.
510 self.StyleClearAll()
511
512 # Following style specs only indicate differences from default.
513 # The rest remains unchanged.
514
515 # Line numbers in margin
e44b5196 516 self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2')
80b27b4e
RD
517 # Highlighted brace
518 self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00')
519 # Unmatched brace
520 self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000')
521 # Indentation guide
522 self.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD")
523
524 # Python styles
525 self.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000')
526 # Comments
a253aa20
RD
527 self.StyleSetSpec(wx.stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0')
528 self.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0')
80b27b4e
RD
529 # Numbers
530 self.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080')
531 # Strings and characters
532 self.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080')
533 self.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080')
534 # Keywords
535 self.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold')
536 # Triple quotes
537 self.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA')
538 self.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA')
539 # Class names
540 self.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold')
541 # Function names
542 self.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold')
543 # Operators
544 self.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold')
545 # Identifiers. I leave this as not bold because everything seems
546 # to be an identifier if it doesn't match the above criterae
547 self.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000')
548
549 # Caret color
550 self.SetCaretForeground("BLUE")
551 # Selection background
552 self.SetSelBackground(1, '#66CCFF')
553
554 self.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
555 self.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
556
08ecc920
RD
557 def RegisterModifiedEvent(self, eventHandler):
558 self.Bind(wx.stc.EVT_STC_CHANGE, eventHandler)
559
1fded56b
RD
560
561except ImportError:
08ecc920
RD
562 class DemoCodeEditor(wx.TextCtrl):
563 def __init__(self, parent):
2e839e96
RD
564 wx.TextCtrl.__init__(self, parent, -1, style =
565 wx.TE_MULTILINE | wx.HSCROLL | wx.TE_RICH2 | wx.TE_NOHIDESEL)
1fded56b 566
08ecc920
RD
567 def RegisterModifiedEvent(self, eventHandler):
568 self.Bind(wx.EVT_TEXT, eventHandler)
569
570 def SetReadOnly(self, flag):
571 self.SetEditable(not flag)
572 # NOTE: STC already has this method
573
574 def GetText(self):
575 return self.GetValue()
576
b6176ab7 577 def GetPositionFromLine(self, line):
08ecc920
RD
578 return self.XYToPosition(0,line)
579
580 def GotoLine(self, line):
b6176ab7
RD
581 pos = self.GetPositionFromLine(line)
582 self.SetInsertionPoint(pos)
583 self.ShowPosition(pos)
08ecc920
RD
584
585 def SelectLine(self, line):
586 start = self.GetPositionFromLine(line)
587 end = start + self.GetLineLength(line)
588 self.SetSelection(start, end)
589
590
591#---------------------------------------------------------------------------
592# Constants for module versions
593
594modOriginal = 0
595modModified = 1
596modDefault = modOriginal
597
598#---------------------------------------------------------------------------
599
600class DemoCodePanel(wx.Panel):
601 """Panel for the 'Demo Code' tab"""
602 def __init__(self, parent, mainFrame):
2e839e96 603 wx.Panel.__init__(self, parent, size=(1,1))
e0465cbd
RD
604 if 'wxMSW' in wx.PlatformInfo:
605 self.Hide()
08ecc920
RD
606 self.mainFrame = mainFrame
607 self.editor = DemoCodeEditor(self)
608 self.editor.RegisterModifiedEvent(self.OnCodeModified)
609
610 self.btnSave = wx.Button(self, -1, "Save Changes")
611 self.btnRestore = wx.Button(self, -1, "Delete Modified")
612 self.btnSave.Enable(False)
613 self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
614 self.btnRestore.Bind(wx.EVT_BUTTON, self.OnRestore)
615
616 self.radioButtons = { modOriginal: wx.RadioButton(self, -1, "Original", style = wx.RB_GROUP),
617 modModified: wx.RadioButton(self, -1, "Modified") }
618
619 self.controlBox = wx.BoxSizer(wx.HORIZONTAL)
620 self.controlBox.Add(wx.StaticText(self, -1, "Active Version:"), 0,
621 wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5)
622 for modID, radioButton in self.radioButtons.items():
623 self.controlBox.Add(radioButton, 0, wx.EXPAND | wx.RIGHT, 5)
624 radioButton.modID = modID # makes it easier for the event handler
625 radioButton.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton)
626
627 self.controlBox.Add(self.btnSave, 0, wx.RIGHT, 5)
628 self.controlBox.Add(self.btnRestore, 0)
629
630 self.box = wx.BoxSizer(wx.VERTICAL)
631 self.box.Add(self.controlBox, 0, wx.EXPAND)
887a1bd9 632 self.box.Add(wx.StaticLine(self), 0, wx.EXPAND)
08ecc920
RD
633 self.box.Add(self.editor, 1, wx.EXPAND)
634
635 self.box.Fit(self)
636 self.SetSizer(self.box)
637
638
639 # Loads a demo from a DemoModules object
640 def LoadDemo(self, demoModules):
641 self.demoModules = demoModules
642 if (modDefault == modModified) and demoModules.Exists(modModified):
643 demoModules.SetActive(modModified)
644 else:
645 demoModules.SetActive(modOriginal)
646 self.radioButtons[demoModules.GetActiveID()].Enable(True)
647 self.ActiveModuleChanged()
648
649
650 def ActiveModuleChanged(self):
651 self.LoadDemoSource(self.demoModules.GetSource())
652 self.UpdateControlState()
a6780fa2 653 self.ReloadDemo()
08ecc920
RD
654
655
656 def LoadDemoSource(self, source):
657 self.editor.Clear()
658 self.editor.SetValue(source)
659 self.JumpToLine(0)
660 self.btnSave.Enable(False)
661
662
663 def JumpToLine(self, line, highlight=False):
664 self.editor.GotoLine(line)
665 self.editor.SetFocus()
666 if highlight:
667 self.editor.SelectLine(line)
668
669
670 def UpdateControlState(self):
671 active = self.demoModules.GetActiveID()
672 # Update the radio/restore buttons
673 for moduleID in self.radioButtons:
674 btn = self.radioButtons[moduleID]
675 if moduleID == active:
676 btn.SetValue(True)
677 else:
678 btn.SetValue(False)
679
680 if self.demoModules.Exists(moduleID):
681 btn.Enable(True)
682 if moduleID == modModified:
683 self.btnRestore.Enable(True)
684 else:
685 btn.Enable(False)
686 if moduleID == modModified:
687 self.btnRestore.Enable(False)
688
689
690 def OnRadioButton(self, event):
691 radioSelected = event.GetEventObject()
692 modSelected = radioSelected.modID
693 if modSelected != self.demoModules.GetActiveID():
694 busy = wx.BusyInfo("Reloading demo module...")
695 self.demoModules.SetActive(modSelected)
696 self.ActiveModuleChanged()
697
698
699 def ReloadDemo(self):
700 if self.demoModules.name != __name__:
a6780fa2 701 self.mainFrame.RunModule()
08ecc920
RD
702
703
704 def OnCodeModified(self, event):
705 self.btnSave.Enable(self.editor.IsModified())
706
707
708 def OnSave(self, event):
709 if self.demoModules.Exists(modModified):
710 if self.demoModules.GetActiveID() == modOriginal:
711 overwriteMsg = "You are about to overwrite an already existing modified copy\n" + \
712 "Do you want to continue?"
713 dlg = wx.MessageDialog(self, overwriteMsg, "wxPython Demo",
714 wx.YES_NO | wx.NO_DEFAULT| wx.ICON_EXCLAMATION)
715 result = dlg.ShowModal()
716 if result == wx.ID_NO:
717 return
718 dlg.Destroy()
719
720 self.demoModules.SetActive(modModified)
721 modifiedFilename = GetModifiedFilename(self.demoModules.name)
722
723 # Create the demo directory if one doesn't already exist
724 if not os.path.exists(GetModifiedDirectory()):
725 try:
726 os.makedirs(GetModifiedDirectory())
727 if not os.path.exists(GetModifiedDirectory()):
c163da42 728 wx.LogMessage("BUG: Created demo directory but it still doesn't exist")
08ecc920
RD
729 raise AssetionError
730 except:
731 wx.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
732 return
733 else:
734 wx.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
735
736 # Save
887a1bd9 737 f = open(modifiedFilename, "wt")
08ecc920
RD
738 source = self.editor.GetText()
739 try:
740 f.write(source)
741 finally:
742 f.close()
743
744 busy = wx.BusyInfo("Reloading demo module...")
745 self.demoModules.LoadFromFile(modModified, modifiedFilename)
746 self.ActiveModuleChanged()
747
748
749 def OnRestore(self, event): # Handles the "Delete Modified" button
750 modifiedFilename = GetModifiedFilename(self.demoModules.name)
751 self.demoModules.Delete(modModified)
752 os.unlink(modifiedFilename) # Delete the modified copy
753 busy = wx.BusyInfo("Reloading demo module...")
754 self.ActiveModuleChanged()
755
1fded56b 756
6c5ae2d2
RD
757#---------------------------------------------------------------------------
758
759def opj(path):
760 """Convert paths to the platform-specific separator"""
08ecc920
RD
761 str = apply(os.path.join, tuple(path.split('/')))
762 # HACK: on Linux, a leading / gets lost...
763 if path.startswith('/'):
764 str = '/' + str
765 return str
766
767
768def GetModifiedDirectory():
769 """
770 Returns the directory where modified versions of the demo files
771 are stored
772 """
773 return opj(wx.GetHomeDir() + "/.wxPyDemo/modified/")
774
775
776def GetModifiedFilename(name):
777 """
778 Returns the filename of the modified version of the specified demo
779 """
780 if not name.endswith(".py"):
781 name = name + ".py"
782 return GetModifiedDirectory() + name
783
784
785def GetOriginalFilename(name):
786 """
787 Returns the filename of the original version of the specified demo
788 """
789 if not name.endswith(".py"):
790 name = name + ".py"
791 return name
792
793
794def DoesModifiedExist(name):
795 """Returns whether the specified demo has a modified copy"""
796 if os.path.exists(GetModifiedFilename(name)):
797 return True
798 else:
799 return False
800
801
802#---------------------------------------------------------------------------
803
804class ModuleDictWrapper:
805 """Emulates a module with a dynamically compiled __dict__"""
806 def __init__(self, dict):
807 self.dict = dict
808
809 def __getattr__(self, name):
810 if name in self.dict:
811 return self.dict[name]
812 else:
813 raise AttributeError
814
815class DemoModules:
816 """
817 Dynamically manages the original/modified versions of a demo
818 module
819 """
820 def __init__(self, name):
821 self.modActive = -1
822 self.name = name
823
824 # (dict , source , filename , description , error information )
825 # ( 0 , 1 , 2 , 3 , 4 )
826 self.modules = [[None, "" , "" , "<original>" , None],
827 [None, "" , "" , "<modified>" , None]]
828
829 # load original module
830 self.LoadFromFile(modOriginal, GetOriginalFilename(name))
317a64e5 831 self.SetActive(modOriginal)
08ecc920
RD
832
833 # load modified module (if one exists)
834 if DoesModifiedExist(name):
835 self.LoadFromFile(modModified, GetModifiedFilename(name))
836
837
838 def LoadFromFile(self, modID, filename):
839 self.modules[modID][2] = filename
887a1bd9 840 file = open(filename, "rt")
08ecc920
RD
841 self.LoadFromSource(modID, file.read())
842 file.close()
843
844
845 def LoadFromSource(self, modID, source):
846 self.modules[modID][1] = source
847 self.LoadDict(modID)
848
849
850 def LoadDict(self, modID):
851 if self.name != __name__:
852 source = self.modules[modID][1]
02b800ce
RD
853 #description = self.modules[modID][3]
854 description = self.modules[modID][2]
08ecc920
RD
855
856 try:
857 self.modules[modID][0] = {}
858 code = compile(source, description, "exec")
859 exec code in self.modules[modID][0]
860 except:
861 self.modules[modID][4] = DemoError(sys.exc_info())
862 self.modules[modID][0] = None
863 else:
864 self.modules[modID][4] = None
865
866
867 def SetActive(self, modID):
868 if modID != modOriginal and modID != modModified:
869 raise LookupError
870 else:
871 self.modActive = modID
872
873
874 def GetActive(self):
875 dict = self.modules[self.modActive][0]
876 if dict is None:
877 return None
878 else:
879 return ModuleDictWrapper(dict)
880
881
882 def GetActiveID(self):
883 return self.modActive
884
885
886 def GetSource(self, modID = None):
887 if modID is None:
888 modID = self.modActive
889 return self.modules[modID][1]
890
891
892 def GetFilename(self, modID = None):
893 if modID is None:
894 modID = self.modActive
895 return self.modules[self.modActive][2]
896
897
898 def GetErrorInfo(self, modID = None):
899 if modID is None:
900 modID = self.modActive
901 return self.modules[self.modActive][4]
902
903
904 def Exists(self, modID):
905 return self.modules[modID][1] != ""
906
907
908 def UpdateFile(self, modID = None):
909 """Updates the file from which a module was loaded
910 with (possibly updated) source"""
911 if modID is None:
912 modID = self.modActive
913
914 source = self.modules[modID][1]
915 filename = self.modules[modID][2]
916
917 try:
887a1bd9 918 file = open(filename, "wt")
08ecc920
RD
919 file.write(source)
920 finally:
921 file.close()
922
923
924 def Delete(self, modID):
925 if self.modActive == modID:
926 self.SetActive(0)
927
928 self.modules[modID][0] = None
929 self.modules[modID][1] = ""
930 self.modules[modID][2] = ""
931
932
08ecc920
RD
933#---------------------------------------------------------------------------
934
935class DemoError:
936 """Wraps and stores information about the current exception"""
937 def __init__(self, exc_info):
938 import copy
939
940 excType, excValue = exc_info[:2]
941 # traceback list entries: (filename, line number, function name, text)
942 self.traceback = traceback.extract_tb(exc_info[2])
943
944 # --Based on traceback.py::format_exception_only()--
945 if type(excType) == types.ClassType:
946 self.exception_type = excType.__name__
947 else:
948 self.exception_type = excType
949
950 # If it's a syntax error, extra information needs
951 # to be added to the traceback
952 if excType is SyntaxError:
953 try:
954 msg, (filename, lineno, self.offset, line) = excValue
955 except:
956 pass
957 else:
958 if not filename:
959 filename = "<string>"
960 line = line.strip()
961 self.traceback.append( (filename, lineno, "", line) )
962 excValue = msg
963 try:
964 self.exception_details = str(excValue)
965 except:
966 self.exception_details = "<unprintable %s object>" & type(excValue).__name__
967
968 del exc_info
969
970 def __str__(self):
971 ret = "Type %s \n \
972 Traceback: %s \n \
973 Details : %s" % ( str(self.exception_type), str(self.traceback), self.exception_details )
974 return ret
975
976#---------------------------------------------------------------------------
977
978class DemoErrorPanel(wx.Panel):
979 """Panel put into the demo tab when the demo fails to run due to errors"""
980
981 def __init__(self, parent, codePanel, demoError, log):
982 wx.Panel.__init__(self, parent, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
983 self.codePanel = codePanel
984 self.nb = parent
985 self.log = log
986
987 self.box = wx.BoxSizer(wx.VERTICAL)
988
989 # Main Label
d6922577 990 self.box.Add(wx.StaticText(self, -1, "An error has occurred while trying to run the demo")
08ecc920
RD
991 , 0, wx.ALIGN_CENTER | wx.TOP, 10)
992
993 # Exception Information
994 boxInfo = wx.StaticBox(self, -1, "Exception Info" )
995 boxInfoSizer = wx.StaticBoxSizer(boxInfo, wx.VERTICAL ) # Used to center the grid within the box
996 boxInfoGrid = wx.FlexGridSizer(0, 2, 0, 0)
997 textFlags = wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT | wx.TOP
998 boxInfoGrid.Add(wx.StaticText(self, -1, "Type: "), 0, textFlags, 5 )
999 boxInfoGrid.Add(wx.StaticText(self, -1, demoError.exception_type) , 0, textFlags, 5 )
1000 boxInfoGrid.Add(wx.StaticText(self, -1, "Details: ") , 0, textFlags, 5 )
1001 boxInfoGrid.Add(wx.StaticText(self, -1, demoError.exception_details) , 0, textFlags, 5 )
1002 boxInfoSizer.Add(boxInfoGrid, 0, wx.ALIGN_CENTRE | wx.ALL, 5 )
1003 self.box.Add(boxInfoSizer, 0, wx.ALIGN_CENTER | wx.ALL, 5)
1004
1005 # Set up the traceback list
1006 # This one automatically resizes last column to take up remaining space
1007 from ListCtrl import TestListCtrl
1008 self.list = TestListCtrl(self, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
1009 self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
1010 self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
1011 self.list.InsertColumn(0, "Filename")
1012 self.list.InsertColumn(1, "Line", wx.LIST_FORMAT_RIGHT)
1013 self.list.InsertColumn(2, "Function")
1014 self.list.InsertColumn(3, "Code")
1015 self.InsertTraceback(self.list, demoError.traceback)
1016 self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
1017 self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)
1018 self.box.Add(wx.StaticText(self, -1, "Traceback:")
1019 , 0, wx.ALIGN_CENTER | wx.TOP, 5)
1020 self.box.Add(self.list, 1, wx.GROW | wx.ALIGN_CENTER | wx.ALL, 5)
1021 self.box.Add(wx.StaticText(self, -1, "Entries from the demo module are shown in blue\n"
1022 + "Double-click on them to go to the offending line")
1023 , 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)
1024
1025 self.box.Fit(self)
1026 self.SetSizer(self.box)
1027
1028
1029 def InsertTraceback(self, list, traceback):
1030 #Add the traceback data
1031 for x in range(len(traceback)):
1032 data = traceback[x]
1033 list.InsertStringItem(x, os.path.basename(data[0])) # Filename
1034 list.SetStringItem(x, 1, str(data[1])) # Line
1035 list.SetStringItem(x, 2, str(data[2])) # Function
1036 list.SetStringItem(x, 3, str(data[3])) # Code
1037
1038 # Check whether this entry is from the demo module
1039 if data[0] == "<original>" or data[0] == "<modified>": # FIXME: make more generalised
1040 self.list.SetItemData(x, int(data[1])) # Store line number for easy access
1041 # Give it a blue colour
1042 item = self.list.GetItem(x)
1043 item.SetTextColour(wx.BLUE)
1044 self.list.SetItem(item)
1045 else:
1046 self.list.SetItemData(x, -1) # Editor can't jump into this one's code
1047
1048
1049 def OnItemSelected(self, event):
1050 # This occurs before OnDoubleClick and can be used to set the
1051 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1052 self.currentItem = event.m_itemIndex
1053 event.Skip()
1054
1055
1056 def OnDoubleClick(self, event):
1057 # If double-clicking on a demo's entry, jump to the line number
1058 line = self.list.GetItemData(self.currentItem)
1059 if line != -1:
1060 self.nb.SetSelection(1) # Switch to the code viewer tab
1061 wx.CallAfter(self.codePanel.JumpToLine, line-1, True)
1062 event.Skip()
1063
6c5ae2d2 1064
76bfdc78
RD
1065#---------------------------------------------------------------------------
1066
1cc18e15
RD
1067class DemoTaskBarIcon(wx.TaskBarIcon):
1068 TBMENU_RESTORE = wx.NewId()
1069 TBMENU_CLOSE = wx.NewId()
1070 TBMENU_CHANGE = wx.NewId()
1071 TBMENU_REMOVE = wx.NewId()
1072
1073 def __init__(self, frame):
1074 wx.TaskBarIcon.__init__(self)
1075 self.frame = frame
1076
1077 # Set the image
8596dc0b 1078 icon = self.MakeIcon(images.getWXPdemoImage())
1cc18e15 1079 self.SetIcon(icon, "wxPython Demo")
8596dc0b 1080 self.imgidx = 1
1cc18e15
RD
1081
1082 # bind some events
1083 self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate)
1084 self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE)
1085 self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE)
1086 self.Bind(wx.EVT_MENU, self.OnTaskBarChange, id=self.TBMENU_CHANGE)
1087 self.Bind(wx.EVT_MENU, self.OnTaskBarRemove, id=self.TBMENU_REMOVE)
1088
1089
1090 def CreatePopupMenu(self):
1091 """
1092 This method is called by the base class when it needs to popup
1093 the menu for the default EVT_RIGHT_DOWN event. Just create
1094 the menu how you want it and return it from this function,
1095 the base class takes care of the rest.
1096 """
1097 menu = wx.Menu()
1098 menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
1099 menu.Append(self.TBMENU_CLOSE, "Close wxPython Demo")
1100 menu.AppendSeparator()
1101 menu.Append(self.TBMENU_CHANGE, "Change the TB Icon")
1102 menu.Append(self.TBMENU_REMOVE, "Remove the TB Icon")
1103 return menu
1104
1105
1106 def MakeIcon(self, img):
1107 """
1108 The various platforms have different requirements for the
1109 icon size...
1110 """
1111 if "wxMSW" in wx.PlatformInfo:
8596dc0b 1112 img = img.Scale(16, 16)
1cc18e15 1113 elif "wxGTK" in wx.PlatformInfo:
8596dc0b
RD
1114 img = img.Scale(22, 22)
1115 # wxMac can be any size upto 128x128, so leave the source img alone....
1cc18e15
RD
1116 icon = wx.IconFromBitmap(img.ConvertToBitmap() )
1117 return icon
1118
1119
1120 def OnTaskBarActivate(self, evt):
1121 if self.frame.IsIconized():
1122 self.frame.Iconize(False)
1123 if not self.frame.IsShown():
1124 self.frame.Show(True)
1125 self.frame.Raise()
1126
1127
1128 def OnTaskBarClose(self, evt):
1129 self.frame.Close()
1130
1cc18e15
RD
1131
1132 def OnTaskBarChange(self, evt):
6c75a4cf 1133 names = [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
8596dc0b
RD
1134 name = names[self.imgidx]
1135
1136 getFunc = getattr(images, "get%sImage" % name)
1137 self.imgidx += 1
1138 if self.imgidx >= len(names):
1139 self.imgidx = 0
1140
1141 icon = self.MakeIcon(getFunc())
1142 self.SetIcon(icon, "This is a new icon: " + name)
1cc18e15
RD
1143
1144
1145 def OnTaskBarRemove(self, evt):
1146 self.RemoveIcon()
1147
1148
1149#---------------------------------------------------------------------------
1fded56b 1150class wxPythonDemo(wx.Frame):
e9159fe8 1151 overviewText = "wxPython Overview"
c368d904 1152
08ecc920 1153 def __init__(self, parent, title):
8ee202f3 1154 wx.Frame.__init__(self, parent, -1, title, size = (950, 720),
08ecc920 1155 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
2f90df85 1156
f290d1c7
RD
1157 self.SetMinSize((640,480))
1158
08ecc920 1159 self.loaded = False
694759cf 1160 self.cwd = os.getcwd()
3ca6a5f0 1161 self.curOverview = ""
08ecc920
RD
1162 self.demoPage = None
1163 self.codePage = None
887a1bd9 1164 self.shell = None
a6780fa2 1165 self.firstTime = True
df5204e0 1166 self.finddlg = None
694759cf 1167
8596dc0b 1168 icon = images.getWXPdemoIcon()
96bfd053 1169 self.SetIcon(icon)
c368d904 1170
8bbd1bbf
RD
1171 try:
1172 self.tbicon = DemoTaskBarIcon(self)
1173 except:
1174 self.tbicon = None
1175
1fded56b 1176 wx.CallAfter(self.ShowTip)
cf694132
RD
1177
1178 self.otherWin = None
80b27b4e
RD
1179 self.Bind(wx.EVT_IDLE, self.OnIdle)
1180 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
1181 self.Bind(wx.EVT_ICONIZE, self.OnIconfiy)
1182 self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize)
cf694132 1183
1fded56b
RD
1184 self.Centre(wx.BOTH)
1185 self.CreateStatusBar(1, wx.ST_SIZEGRIP)
5a7823f5 1186
0c8f2860
RD
1187 splitter = wx.SplitterWindow(self, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D)
1188 splitter2 = wx.SplitterWindow(splitter, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D)
5a7823f5 1189
d56cebe7 1190 def EmptyHandler(evt): pass
80b27b4e
RD
1191 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1192 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
cf694132 1193
1e4a197e
RD
1194 # Prevent TreeCtrl from displaying all items after destruction when True
1195 self.dying = False
cf694132 1196
08ecc920
RD
1197 # Create a Notebook
1198 self.nb = wx.Notebook(splitter2, -1, style=wx.CLIP_CHILDREN)
1199
cf694132 1200 # Make a File menu
1fded56b
RD
1201 self.mainmenu = wx.MenuBar()
1202 menu = wx.Menu()
330af869
RD
1203 item = menu.Append(-1, '&Redirect Output',
1204 'Redirect print statements to a window',
1205 wx.ITEM_CHECK)
1206 self.Bind(wx.EVT_MENU, self.OnToggleRedirect, item)
08ecc920 1207
c8000995
RD
1208 item = menu.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1209 self.Bind(wx.EVT_MENU, self.OnFileExit, item)
05871e13 1210 wx.App.SetMacExitMenuItemId(item.GetId())
cf694132
RD
1211 self.mainmenu.Append(menu, '&File')
1212
ec3e670f 1213 # Make a Demo menu
1fded56b 1214 menu = wx.Menu()
ec3e670f 1215 for item in _treeList:
1fded56b 1216 submenu = wx.Menu()
ec3e670f 1217 for childItem in item[1]:
c8000995
RD
1218 mi = submenu.Append(-1, childItem)
1219 self.Bind(wx.EVT_MENU, self.OnDemoMenu, mi)
1fded56b 1220 menu.AppendMenu(wx.NewId(), item[0], submenu)
ec3e670f
RD
1221 self.mainmenu.Append(menu, '&Demo')
1222
1223
cf694132 1224 # Make a Help menu
1fded56b 1225 menu = wx.Menu()
c8000995
RD
1226 findItem = menu.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1227 findnextItem = menu.Append(-1, 'Find &Next\tF3', 'Find Next')
1e4a197e 1228 menu.AppendSeparator()
887a1bd9
RD
1229
1230 shellItem = menu.Append(-1, 'Open Py&Shell Window\tF5',
1231 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1232 menu.AppendSeparator()
3764716d 1233 helpItem = menu.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
05871e13 1234 wx.App.SetMacAboutMenuItemId(helpItem.GetId())
887a1bd9
RD
1235
1236 self.Bind(wx.EVT_MENU, self.OnOpenShellWindow, shellItem)
c8000995
RD
1237 self.Bind(wx.EVT_MENU, self.OnHelpAbout, helpItem)
1238 self.Bind(wx.EVT_MENU, self.OnHelpFind, findItem)
1239 self.Bind(wx.EVT_MENU, self.OnFindNext, findnextItem)
df5204e0
RD
1240 self.Bind(wx.EVT_FIND, self.OnFind)
1241 self.Bind(wx.EVT_FIND_NEXT, self.OnFind)
1242 self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
1243 self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findItem)
1244 self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findnextItem)
cf694132
RD
1245 self.mainmenu.Append(menu, '&Help')
1246 self.SetMenuBar(self.mainmenu)
1247
1fded56b 1248 self.finddata = wx.FindReplaceData()
02b800ce 1249 self.finddata.SetFlags(wx.FR_DOWN)
1e4a197e
RD
1250
1251 if 0:
1252 # This is another way to set Accelerators, in addition to
1253 # using the '\t<key>' syntax in the menu items.
1fded56b
RD
1254 aTable = wx.AcceleratorTable([(wx.ACCEL_ALT, ord('X'), exitID),
1255 (wx.ACCEL_CTRL, ord('H'), helpID),
1256 (wx.ACCEL_CTRL, ord('F'), findID),
1257 (wx.ACCEL_NORMAL, WXK_F3, findnextID)
1258 ])
1e4a197e 1259 self.SetAcceleratorTable(aTable)
2f90df85 1260
bb0054cd 1261
cf694132 1262 # Create a TreeCtrl
1fded56b 1263 tID = wx.NewId()
73470a17
RD
1264 leftPanel = wx.Panel(splitter)
1265
1266 self.filter = wx.TextCtrl(leftPanel)
1267 self.filter.Bind(wx.EVT_TEXT, self.RecreateTree)
1268
f6bcfd97 1269 self.treeMap = {}
73470a17 1270 self.tree = wx.TreeCtrl(leftPanel, tID, style =
3628e088 1271 wx.TR_DEFAULT_STYLE #| wx.TR_HAS_VARIABLE_ROW_HEIGHT
eb0f373c 1272 )
afb810d9 1273
73470a17
RD
1274 self.root = self.tree.AddRoot("wxPython Overview")
1275 self.RecreateTree()
80b27b4e
RD
1276 self.tree.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded, id=tID)
1277 self.tree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, id=tID)
1278 self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=tID)
1279 self.tree.Bind(wx.EVT_LEFT_DOWN, self.OnTreeLeftDown)
73470a17 1280
1fded56b 1281 # Set up a wx.html.HtmlWindow on the Overview Notebook page
0bdca46d
RD
1282 # we put it in a panel first because there seems to be a
1283 # refresh bug of some sort (wxGTK) when it is directly in
1284 # the notebook...
1285 if 0: # the old way
1fded56b 1286 self.ovr = wx.html.HtmlWindow(self.nb, -1, size=(400, 400))
0bdca46d
RD
1287 self.nb.AddPage(self.ovr, self.overviewText)
1288
1fded56b
RD
1289 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1290 panel = wx.Panel(self.nb, -1, style=wx.CLIP_CHILDREN)
1291 self.ovr = wx.html.HtmlWindow(panel, -1, size=(400, 400))
0bdca46d
RD
1292 self.nb.AddPage(panel, self.overviewText)
1293
1294 def OnOvrSize(evt, ovr=self.ovr):
1295 ovr.SetSize(evt.GetSize())
80b27b4e
RD
1296 panel.Bind(wx.EVT_SIZE, OnOvrSize)
1297 panel.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
0bdca46d 1298
08ecc920 1299 if "gtk2" in wx.PlatformInfo:
385721a8 1300 self.ovr.SetStandardFonts()
08ecc920 1301 self.SetOverview(self.overviewText, mainOverview)
c368d904 1302
cf694132 1303
08ecc920
RD
1304 # Set up a log window
1305 self.log = wx.TextCtrl(splitter2, -1,
1306 style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
1307
1308 # Set the wxWindows log target to be this textctrl
1309 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
cf694132 1310
08ecc920
RD
1311 # But instead of the above we want to show how to use our own wx.Log class
1312 wx.Log_SetActiveTarget(MyLog(self.log))
1313
1314 # for serious debugging
1315 #wx.Log_SetActiveTarget(wx.LogStderr())
1316 #wx.Log_SetTraceMask(wx.TraceMessages)
cf694132
RD
1317
1318
e44b5196
RD
1319 self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
1320 wx.GetApp().Bind(wx.EVT_ACTIVATE_APP, self.OnAppActivate)
1321
f6bcfd97 1322 # add the windows to the splitter and split it.
08ecc920 1323 splitter2.SplitHorizontally(self.nb, self.log, -160)
73470a17
RD
1324 leftBox = wx.BoxSizer(wx.VERTICAL)
1325 leftBox.Add(self.tree, 1, wx.EXPAND)
1326 leftBox.Add(wx.StaticText(leftPanel, label = "Filter Demos:"), 0, wx.TOP|wx.LEFT, 5)
1327 leftBox.Add(self.filter, 0, wx.EXPAND|wx.ALL, 5)
1328 leftPanel.SetSizer(leftBox)
1329 splitter.SplitVertically(leftPanel, splitter2, 220)
afb810d9 1330
f290d1c7
RD
1331 splitter.SetMinimumPaneSize(120)
1332 splitter2.SetMinimumPaneSize(60)
afb810d9 1333
11926a78 1334 # Make the splitter on the right expand the top window when resized
2f0f3b0f
RD
1335 def SplitterOnSize(evt):
1336 splitter = evt.GetEventObject()
1337 sz = splitter.GetSize()
08ecc920 1338 splitter.SetSashPosition(sz.height - 160, False)
2f0f3b0f 1339 evt.Skip()
80b27b4e
RD
1340
1341 splitter2.Bind(wx.EVT_SIZE, SplitterOnSize)
2f0f3b0f 1342
bb0054cd
RD
1343 # select initial items
1344 self.nb.SetSelection(0)
73470a17 1345 self.tree.SelectItem(self.root)
ec3e670f 1346
08ecc920
RD
1347 # Load 'Main' module
1348 self.LoadDemo(self.overviewText)
1349 self.loaded = True
1350
1351 # select some other initial module?
1352 if len(sys.argv) > 1:
1353 arg = sys.argv[1]
1354 if arg.endswith('.py'):
1355 arg = arg[:-3]
1356 selectedDemo = self.treeMap.get(arg, None)
f6bcfd97 1357 if selectedDemo:
ec3e670f
RD
1358 self.tree.SelectItem(selectedDemo)
1359 self.tree.EnsureVisible(selectedDemo)
1360
bb0054cd 1361
cf694132 1362 #---------------------------------------------
73470a17
RD
1363
1364 def RecreateTree(self, evt=None):
1365 self.tree.DeleteAllItems()
1366 self.root = self.tree.AddRoot("wxPython Overview")
1367 firstChild = None
1368 filter = self.filter.GetValue()
1369 for category, items in _treeList:
1370 if filter:
1371 items = [item for item in items if filter in item.lower()]
1372 if items:
1373 child = self.tree.AppendItem(self.root, category)
1374 if not firstChild: firstChild = child
1375 for childItem in items:
1376 theDemo = self.tree.AppendItem(child, childItem)
1377 self.treeMap[childItem] = theDemo
1378
1379 self.tree.Expand(self.root)
1380 if firstChild:
1381 self.tree.Expand(firstChild)
1382
1383
cf694132 1384 def WriteText(self, text):
f6bcfd97
BP
1385 if text[-1:] == '\n':
1386 text = text[:-1]
1fded56b 1387 wx.LogMessage(text)
f6bcfd97 1388
cf694132
RD
1389 def write(self, txt):
1390 self.WriteText(txt)
1391
1392 #---------------------------------------------
1393 def OnItemExpanded(self, event):
1394 item = event.GetItem()
1fded56b 1395 wx.LogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item))
c368d904 1396 event.Skip()
cf694132
RD
1397
1398 #---------------------------------------------
1399 def OnItemCollapsed(self, event):
1400 item = event.GetItem()
1fded56b 1401 wx.LogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
c368d904 1402 event.Skip()
f6bcfd97
BP
1403
1404 #---------------------------------------------
1405 def OnTreeLeftDown(self, event):
08ecc920 1406 # reset the overview text if the tree item is clicked on again
f6bcfd97
BP
1407 pt = event.GetPosition();
1408 item, flags = self.tree.HitTest(pt)
1409 if item == self.tree.GetSelection():
d975da9b 1410 self.SetOverview(self.tree.GetItemText(item)+" Overview", self.curOverview)
185d7c3e 1411 event.Skip()
cf694132
RD
1412
1413 #---------------------------------------------
1414 def OnSelChanged(self, event):
08ecc920 1415 if self.dying or not self.loaded:
cf694132
RD
1416 return
1417
5a7823f5
RD
1418 item = event.GetItem()
1419 itemText = self.tree.GetItemText(item)
08ecc920 1420 self.LoadDemo(itemText)
5a7823f5
RD
1421
1422 #---------------------------------------------
08ecc920
RD
1423 def LoadDemo(self, demoName):
1424 try:
1425 wx.BeginBusyCursor()
1426
1427 os.chdir(self.cwd)
1428 self.ShutdownDemoModule()
1429
1430 if demoName == self.overviewText:
1431 # User selected the "wxPython Overview" node
1432 # ie: _this_ module
1433 # Changing the main window at runtime not yet supported...
1434 self.demoModules = DemoModules(__name__)
1435 self.SetOverview(self.overviewText, mainOverview)
1436 self.LoadDemoSource()
1437 self.UpdateNotebook(0)
1438 else:
1439 if os.path.exists(GetOriginalFilename(demoName)):
1440 wx.LogMessage("Loading demo %s.py..." % demoName)
1441 self.demoModules = DemoModules(demoName)
a6780fa2 1442 self.LoadDemoSource()
08ecc920
RD
1443 self.tree.Refresh()
1444 else:
1445 self.SetOverview("wxPython", mainOverview)
1446 self.codePage = None
1447 self.UpdateNotebook(0)
1448 finally:
1449 wx.EndBusyCursor()
cf694132 1450
08ecc920
RD
1451 #---------------------------------------------
1452 def LoadDemoSource(self):
1453 self.codePage = None
1454 self.codePage = DemoCodePanel(self.nb, self)
1455 self.codePage.LoadDemo(self.demoModules)
1456
1457 #---------------------------------------------
a6780fa2 1458 def RunModule(self):
08ecc920 1459 """Runs the active module"""
cf694132 1460
08ecc920
RD
1461 module = self.demoModules.GetActive()
1462 self.ShutdownDemoModule()
1463 overviewText = ""
1464
8412feb0
RD
1465 # o The RunTest() for all samples must now return a window that can
1466 # be palced in a tab in the main notebook.
d6922577 1467 # o If an error occurs (or has occurred before) an error tab is created.
08ecc920
RD
1468
1469 if module is not None:
1470 wx.LogMessage("Running demo module...")
1471 if hasattr(module, "overview"):
1472 overviewText = module.overview
cf694132 1473
08ecc920
RD
1474 try:
1475 self.demoPage = module.runTest(self, self.nb, self)
08ecc920 1476 except:
317a64e5 1477 self.demoPage = DemoErrorPanel(self.nb, self.codePage,
7d0f8766
RD
1478 DemoError(sys.exc_info()), self)
1479
1480 assert self.demoPage is not None, "runTest must return a window!"
1481
08ecc920
RD
1482 else:
1483 # There was a previous error in compiling or exec-ing
317a64e5
RD
1484 self.demoPage = DemoErrorPanel(self.nb, self.codePage,
1485 self.demoModules.GetErrorInfo(), self)
a6780fa2 1486
08ecc920 1487 self.SetOverview(self.demoModules.name + " Overview", overviewText)
a6780fa2
RD
1488
1489 if self.firstTime:
1490 # cahnge to the demo page the first time a module is run
1491 self.UpdateNotebook(2)
1492 self.firstTime = False
1493 else:
1494 # otherwise just stay on the same tab in case the user has changed to another one
1495 self.UpdateNotebook()
cf694132
RD
1496
1497 #---------------------------------------------
08ecc920
RD
1498 def ShutdownDemoModule(self):
1499 if self.demoPage:
1500 # inform the window that it's time to quit if it cares
1501 if hasattr(self.demoPage, "ShutdownDemo"):
1502 self.demoPage.ShutdownDemo()
1503 wx.YieldIfNeeded() # in case the page has pending events
1504 self.demoPage = None
1505
1506 #---------------------------------------------
1507 def UpdateNotebook(self, select = -1):
1508 nb = self.nb
1509 debug = False
1510
1511 def UpdatePage(page, pageText):
1512 pageExists = False
1513 pagePos = -1
1514 for i in range(nb.GetPageCount()):
1515 if nb.GetPageText(i) == pageText:
1516 pageExists = True
1517 pagePos = i
1518 break
1519
1520 if page:
1521 if not pageExists:
1522 # Add a new page
08ecc920
RD
1523 nb.AddPage(page, pageText)
1524 if debug: wx.LogMessage("DBG: ADDED %s" % pageText)
1525 else:
08ecc920
RD
1526 if nb.GetPage(pagePos) != page:
1527 # Reload an existing page
1528 nb.Freeze()
08ecc920
RD
1529 nb.DeletePage(pagePos)
1530 nb.InsertPage(pagePos, page, pageText)
1531 nb.Thaw()
1532 if debug: wx.LogMessage("DBG: RELOADED %s" % pageText)
1533 else:
1534 # Excellent! No redraw/flicker
1535 if debug: wx.LogMessage("DBG: SAVED from reloading %s" % pageText)
1536 elif pageExists:
1537 # Delete a page
1538 nb.DeletePage(pagePos)
1539 if debug: wx.LogMessage("DBG: DELETED %s" % pageText)
1540 else:
1541 if debug: wx.LogMessage("DBG: STILL GONE - %s" % pageText)
1542
1543 if select == -1:
1544 select = nb.GetSelection()
cf694132 1545
08ecc920
RD
1546 UpdatePage(self.codePage, "Demo Code")
1547 UpdatePage(self.demoPage, "Demo")
cf694132 1548
887a1bd9 1549 if select >= 0 and select < nb.GetPageCount():
08ecc920
RD
1550 nb.SetSelection(select)
1551
cf694132
RD
1552 #---------------------------------------------
1553 def SetOverview(self, name, text):
f6bcfd97
BP
1554 self.curOverview = text
1555 lead = text[:6]
1556 if lead != '<html>' and lead != '<HTML>':
1e4a197e 1557 text = '<br>'.join(text.split('\n'))
6c7d1792
RD
1558 if wx.USE_UNICODE:
1559 text = text.decode('iso8859_1')
f6bcfd97 1560 self.ovr.SetPage(text)
cf694132 1561 self.nb.SetPageText(0, name)
cf694132
RD
1562
1563 #---------------------------------------------
1564 # Menu methods
c368d904 1565 def OnFileExit(self, *event):
cf694132
RD
1566 self.Close()
1567
330af869
RD
1568 def OnToggleRedirect(self, event):
1569 app = wx.GetApp()
1570 if event.Checked():
1571 app.RedirectStdio()
1572 print "Print statements and other standard output will now be directed to this window."
1573 else:
1574 app.RestoreStdio()
1575 print "Print statements and other standard output will now be sent to the usual location."
08ecc920 1576
cf694132 1577 def OnHelpAbout(self, event):
e166644c 1578 from About import MyAboutBox
ec3e670f 1579 about = MyAboutBox(self)
cf694132
RD
1580 about.ShowModal()
1581 about.Destroy()
1582
1e4a197e 1583 def OnHelpFind(self, event):
df5204e0
RD
1584 if self.finddlg != None:
1585 return
1586
1e4a197e 1587 self.nb.SetSelection(1)
1fded56b 1588 self.finddlg = wx.FindReplaceDialog(self, self.finddata, "Find",
02b800ce 1589 wx.FR_NOMATCHCASE | wx.FR_NOWHOLEWORD)
1e4a197e
RD
1590 self.finddlg.Show(True)
1591
df5204e0
RD
1592
1593 def OnUpdateFindItems(self, evt):
1594 evt.Enable(self.finddlg == None)
1595
1596
1e4a197e 1597 def OnFind(self, event):
08ecc920 1598 editor = self.codePage.editor
1e4a197e 1599 self.nb.SetSelection(1)
08ecc920
RD
1600 end = editor.GetLastPosition()
1601 textstring = editor.GetRange(0, end).lower()
1e4a197e 1602 findstring = self.finddata.GetFindString().lower()
02b800ce
RD
1603 backward = not (self.finddata.GetFlags() & wx.FR_DOWN)
1604 if backward:
1605 start = editor.GetSelection()[0]
1606 loc = textstring.rfind(findstring, 0, start)
1607 else:
1608 start = editor.GetSelection()[1]
1609 loc = textstring.find(findstring, start)
1e4a197e
RD
1610 if loc == -1 and start != 0:
1611 # string not found, start at beginning
02b800ce
RD
1612 if backward:
1613 start = end
1614 loc = textstring.rfind(findstring, 0, start)
1615 else:
1616 start = 0
1617 loc = textstring.find(findstring, start)
1e4a197e 1618 if loc == -1:
1fded56b 1619 dlg = wx.MessageDialog(self, 'Find String Not Found',
1e4a197e 1620 'Find String Not Found in Demo File',
1fded56b 1621 wx.OK | wx.ICON_INFORMATION)
1e4a197e
RD
1622 dlg.ShowModal()
1623 dlg.Destroy()
1624 if self.finddlg:
1625 if loc == -1:
1626 self.finddlg.SetFocus()
1627 return
1628 else:
1629 self.finddlg.Destroy()
df5204e0 1630 self.finddlg = None
08ecc920
RD
1631 editor.ShowPosition(loc)
1632 editor.SetSelection(loc, loc + len(findstring))
1e4a197e
RD
1633
1634
1635
1636 def OnFindNext(self, event):
1637 if self.finddata.GetFindString():
1638 self.OnFind(event)
1639 else:
1640 self.OnHelpFind(event)
1641
1642 def OnFindClose(self, event):
1643 event.GetDialog().Destroy()
df5204e0 1644 self.finddlg = None
1e4a197e 1645
cf694132 1646
887a1bd9
RD
1647 def OnOpenShellWindow(self, evt):
1648 if self.shell:
1649 # if it already exists then just make sure it's visible
1650 s = self.shell
1651 if s.IsIconized():
1652 s.Iconize(False)
1653 s.Raise()
1654 else:
1655 # Make a PyShell window
1656 from wx import py
1657 namespace = { 'wx' : wx,
1658 'app' : wx.GetApp(),
1659 'frame' : self,
1660 }
1661 self.shell = py.shell.ShellFrame(None, locals=namespace)
1662 self.shell.SetSize((640,480))
1663 self.shell.Show()
1664
1665 # Hook the close event of the main frame window so that we
1666 # close the shell at the same time if it still exists
1667 def CloseShell(evt):
1668 if self.shell:
1669 self.shell.Close()
1670 evt.Skip()
1671 self.Bind(wx.EVT_CLOSE, CloseShell)
1672
1673
cf694132
RD
1674 #---------------------------------------------
1675 def OnCloseWindow(self, event):
1e4a197e 1676 self.dying = True
08ecc920
RD
1677 self.demoPage = None
1678 self.codePage = None
26197023 1679 self.mainmenu = None
8bbd1bbf
RD
1680 if self.tbicon is not None:
1681 self.tbicon.Destroy()
cf694132
RD
1682 self.Destroy()
1683
c368d904 1684
cf694132
RD
1685 #---------------------------------------------
1686 def OnIdle(self, event):
1687 if self.otherWin:
1688 self.otherWin.Raise()
08ecc920 1689 self.demoPage = self.otherWin
cf694132
RD
1690 self.otherWin = None
1691
ccf691a4
RD
1692
1693 #---------------------------------------------
1694 def ShowTip(self):
1695 try:
1696 showTipText = open(opj("data/showTips")).read()
1697 showTip, index = eval(showTipText)
1698 except IOError:
1699 showTip, index = (1, 0)
1700 if showTip:
1fded56b 1701 tp = wx.CreateFileTipProvider(opj("data/tips.txt"), index)
861a0196 1702 ##tp = MyTP(0)
1fded56b 1703 showTip = wx.ShowTip(self, tp)
ccf691a4
RD
1704 index = tp.GetCurrentTip()
1705 open(opj("data/showTips"), "w").write(str( (showTip, index) ))
1706
1707
ec3e670f
RD
1708 #---------------------------------------------
1709 def OnDemoMenu(self, event):
f6bcfd97
BP
1710 try:
1711 selectedDemo = self.treeMap[self.mainmenu.GetLabel(event.GetId())]
1712 except:
1713 selectedDemo = None
1714 if selectedDemo:
1715 self.tree.SelectItem(selectedDemo)
1716 self.tree.EnsureVisible(selectedDemo)
ec3e670f 1717
c368d904 1718
c368d904 1719
f3d9dc1d
RD
1720 #---------------------------------------------
1721 def OnIconfiy(self, evt):
8412feb0 1722 wx.LogMessage("OnIconfiy: %s" % evt.Iconized())
f3d9dc1d
RD
1723 evt.Skip()
1724
1725 #---------------------------------------------
1726 def OnMaximize(self, evt):
1fded56b 1727 wx.LogMessage("OnMaximize")
f3d9dc1d
RD
1728 evt.Skip()
1729
8412feb0
RD
1730 #---------------------------------------------
1731 def OnActivate(self, evt):
1732 wx.LogMessage("OnActivate: %s" % evt.GetActive())
1733 evt.Skip()
f3d9dc1d 1734
8412feb0
RD
1735 #---------------------------------------------
1736 def OnAppActivate(self, evt):
1737 wx.LogMessage("OnAppActivate: %s" % evt.GetActive())
1738 evt.Skip()
f3d9dc1d 1739
cf694132
RD
1740#---------------------------------------------------------------------------
1741#---------------------------------------------------------------------------
1742
1fded56b 1743class MySplashScreen(wx.SplashScreen):
b5a5d647 1744 def __init__(self):
6c75a4cf 1745 bmp = wx.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
1fded56b 1746 wx.SplashScreen.__init__(self, bmp,
a253aa20 1747 wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT,
6c75a4cf 1748 5000, None, -1)
80b27b4e 1749 self.Bind(wx.EVT_CLOSE, self.OnClose)
6f696172
RD
1750 self.fc = wx.FutureCall(2000, self.ShowMain)
1751
b5a5d647
RD
1752
1753 def OnClose(self, evt):
6f696172
RD
1754 # Make sure the default handler runs too so this window gets
1755 # destroyed
1756 evt.Skip()
8eca4fef 1757 self.Hide()
6f696172
RD
1758
1759 # if the timer is still running then go ahead and show the
1760 # main frame now
1761 if self.fc.IsRunning():
1762 self.fc.Stop()
1763 self.ShowMain()
1764
cf694132 1765
6c75a4cf
RD
1766 def ShowMain(self):
1767 frame = wxPythonDemo(None, "wxPython: (A Demonstration)")
1768 frame.Show()
6f696172
RD
1769 if self.fc.IsRunning():
1770 self.Raise()
6c75a4cf 1771
b5a5d647 1772
1fded56b 1773class MyApp(wx.App):
b5a5d647
RD
1774 def OnInit(self):
1775 """
68320e40 1776 Create and show the splash screen. It will then create and show
b5a5d647
RD
1777 the main frame when it is time to do so.
1778 """
1e4a197e 1779
7b85d630
RD
1780 wx.SystemOptions.SetOptionInt("mac.window-plain-transition", 1)
1781
35ee3288
RD
1782 # For debugging
1783 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1784
a253aa20
RD
1785 # Normally when using a SplashScreen you would create it, show
1786 # it and then continue on with the applicaiton's
1787 # initialization, finally creating and showing the main
1788 # application window(s). In this case we have nothing else to
1789 # do so we'll delay showing the main frame until later (see
6c75a4cf 1790 # ShowMain above) so the users can see the SplashScreen effect.
b5a5d647
RD
1791 splash = MySplashScreen()
1792 splash.Show()
a253aa20 1793
1e4a197e 1794 return True
b5a5d647
RD
1795
1796
1797
cf694132
RD
1798#---------------------------------------------------------------------------
1799
1800def main():
e02c03a4 1801 try:
d56cebe7 1802 demoPath = os.path.dirname(__file__)
e02c03a4
RD
1803 os.chdir(demoPath)
1804 except:
1805 pass
03a604a6 1806 app = MyApp(False)
cf694132
RD
1807 app.MainLoop()
1808
cf694132
RD
1809#---------------------------------------------------------------------------
1810
1811
08ecc920 1812mainOverview = """<html><body>
1fded56b
RD
1813<h2>wxPython</h2>
1814
f6063c19
RD
1815<p> wxPython is a <b>GUI toolkit</b> for the Python programming
1816language. It allows Python programmers to create programs with a
1817robust, highly functional graphical user interface, simply and easily.
1818It is implemented as a Python extension module (native code) that
1819wraps the popular wxWindows cross platform GUI library, which is
1820written in C++.
1fded56b
RD
1821
1822<p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1823means that it is free for anyone to use and the source code is
1824available for anyone to look at and modify. Or anyone can contribute
8b9a4190 1825fixes or enhancements to the project.
1fded56b
RD
1826
1827<p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1828same program will run on multiple platforms without modification.
1829Currently supported platforms are 32-bit Microsoft Windows, most Unix
1830or unix-like systems, and Macintosh OS X. Since the language is
1831Python, wxPython programs are <b>simple, easy</b> to write and easy to
1832understand.
1833
1834<p> <b>This demo</b> is not only a collection of test cases for
1835wxPython, but is also designed to help you learn about and how to use
1836wxPython. Each sample is listed in the tree control on the left.
1837When a sample is selected in the tree then a module is loaded and run
1838(usually in a tab of this notebook,) and the source code of the module
1839is loaded in another tab for you to browse and learn from.
1840
1841"""
cf694132
RD
1842
1843
1844#----------------------------------------------------------------------------
1845#----------------------------------------------------------------------------
1846
1847if __name__ == '__main__':
08ecc920 1848 __name__ = 'Main'
cf694132
RD
1849 main()
1850
1851#----------------------------------------------------------------------------
1852
1853
1854
1855
1856
1857
1858