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