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