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