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