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