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