2 #----------------------------------------------------------------------------
4 # Purpose: Testing lots of stuff, controls, window types, etc.
8 # Created: A long time ago, in a galaxy far, far away...
10 # Copyright: (c) 1999 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
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 :)
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....
24 # * UI design more prefessional
25 # * save file positions (new field in demoModules) (@ LoadDemoSource)
26 # * Update main overview
28 # * Why don't we move _treeList into a separate module
30 import sys
, os
, time
, traceback
, types
32 import wx
# This module uses the new wx namespace
39 ##print "wx.VERSION_STRING = ", wx.VERSION_STRING
41 ##raw_input("Press Enter...")
44 #---------------------------------------------------------------------------
49 ('Recent Additions/Updates', [
54 # managed windows == things with a (optional) caption you can close
55 ('Frames and Dialogs', [
79 # dialogs from libraries
82 'MultipleChoiceDialog',
83 'ScrolledMessageDialog',
87 ('Core Windows/Controls', [
123 ('Custom Controls', [
136 # controls coming from other libraries
137 ('More Windows/Controls', [
138 'ActiveX_FlashWindow',
139 'ActiveX_IEHtmlWindow',
141 #'RightTextCtrl', deprecated as we have wxTE_RIGHT now.
154 'MaskedEditControls',
170 # How to lay out the controls in a frame/dialog
180 'XmlResourceHandler',
181 'XmlResourceSubclass',
185 ('Process and Events', [
196 ('Clipboard and DnD', [
229 # need libs not coming with the demo
230 ('Samples using an external library', [
235 ('Check out the samples dir too', [
242 #---------------------------------------------------------------------------
243 # Show how to derive a custom wxLog class
245 class MyLog(wx
.PyLog
):
246 def __init__(self
, textCtrl
, logTime
=0):
247 wx
.PyLog
.__init
__(self
)
249 self
.logTime
= logTime
251 def DoLogString(self
, message
, timeStamp
):
253 message
= time
.strftime("%X", time
.localtime(timeStamp
)) + \
256 self
.tc
.AppendText(message
+ '\n')
259 class MyTP(wx
.PyTipProvider
):
261 return "This is my tip"
264 #---------------------------------------------------------------------------
265 # A class to be used to display source code in the demo. Try using the
266 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
267 # if there is an error, such as the stc module not being present.
271 ##raise ImportError # for testing the alternate implementation
273 from StyledTextCtrl_2
import PythonSTC
275 class DemoCodeEditor(PythonSTC
):
276 def __init__(self
, parent
):
277 PythonSTC
.__init
__(self
, parent
, -1, wx
.BORDER_NONE
)
280 # Some methods to make it compatible with how the wxTextCtrl is used
281 def SetValue(self
, value
):
283 value
= value
.decode('iso8859_1')
285 self
.EmptyUndoBuffer()
288 def IsModified(self
):
289 return self
.GetModify()
294 def SetInsertionPoint(self
, pos
):
295 self
.SetCurrentPos(pos
)
298 def ShowPosition(self
, pos
):
299 line
= self
.LineFromPosition(pos
)
300 #self.EnsureVisible(line)
303 def GetLastPosition(self
):
304 return self
.GetLength()
306 def GetPositionFromLine(self
, line
):
307 return self
.PositionFromLine(line
)
309 def GetRange(self
, start
, end
):
310 return self
.GetTextRange(start
, end
)
312 def GetSelection(self
):
313 return self
.GetAnchor(), self
.GetCurrentPos()
315 def SetSelection(self
, start
, end
):
316 self
.SetSelectionStart(start
)
317 self
.SetSelectionEnd(end
)
319 def SelectLine(self
, line
):
320 start
= self
.PositionFromLine(line
)
321 end
= self
.GetLineEndPosition(line
)
322 self
.SetSelection(start
, end
)
324 def SetUpEditor(self
):
326 This method carries out the work of setting up the demo editor.
327 It's seperate so as not to clutter up the init code.
331 self
.SetLexer(stc
.STC_LEX_PYTHON
)
332 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
335 self
.SetProperty("fold", "1" )
337 # Highlight tab/space mixing (shouldn't be any)
338 self
.SetProperty("tab.timmy.whinge.level", "1")
340 # Set left and right margins
343 # Set up the numbers in the margin for margin #1
344 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
345 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
346 self
.SetMarginWidth(1, 40)
348 # Indentation and tab stuff
349 self
.SetIndent(4) # Proscribed indent size for wx
350 self
.SetIndentationGuides(True) # Show indent guides
351 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
352 self
.SetTabIndents(True) # Tab key indents
353 self
.SetTabWidth(4) # Proscribed tab size for wx
354 self
.SetUseTabs(False) # Use spaces rather than tabs, or
355 # TabTimmy will complain!
357 self
.SetViewWhiteSpace(False) # Don't view white space
359 # EOL: Since we are loading/saving ourselves, and the
360 # strings will always have \n's in them, set the STC to
361 # edit them that way.
362 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
363 self
.SetViewEOL(False)
365 # No right-edge mode indicator
366 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
368 # Setup a margin to hold fold markers
369 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
370 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
371 self
.SetMarginSensitive(2, True)
372 self
.SetMarginWidth(2, 12)
374 # and now set up the fold markers
375 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
376 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
377 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
378 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
379 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
380 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
381 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
383 # Global default style
384 if wx
.Platform
== '__WXMSW__':
385 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
386 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
388 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
389 'fore:#000000,back:#FFFFFF,face:Courier,size:12')
391 # Clear styles and revert to default.
394 # Following style specs only indicate differences from default.
395 # The rest remains unchanged.
397 # Line numbers in margin
398 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
401 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
403 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
405 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
408 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
410 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
411 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
413 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
414 # Strings and characters
415 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
416 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
418 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
420 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
421 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
423 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
425 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
427 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
428 # Identifiers. I leave this as not bold because everything seems
429 # to be an identifier if it doesn't match the above criterae
430 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
433 self
.SetCaretForeground("BLUE")
434 # Selection background
435 self
.SetSelBackground(1, '#66CCFF')
437 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
438 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
440 def RegisterModifiedEvent(self
, eventHandler
):
441 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
445 class DemoCodeEditor(wx
.TextCtrl
):
446 def __init__(self
, parent
):
447 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
= wx
.TE_MULTILINE |
448 wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
450 def RegisterModifiedEvent(self
, eventHandler
):
451 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
453 def SetReadOnly(self
, flag
):
454 self
.SetEditable(not flag
)
455 # NOTE: STC already has this method
458 return self
.GetValue()
460 def GetPositionFromLine(line
):
461 return self
.XYToPosition(0,line
)
463 def GotoLine(self
, line
):
464 pos
= self
.editor
.GetPositionFromLine(line
)
465 self
.editor
.SetInsertionPoint(pos
)
466 self
.editor
.ShowPosition(pos
)
468 def SelectLine(self
, line
):
469 start
= self
.GetPositionFromLine(line
)
470 end
= start
+ self
.GetLineLength(line
)
471 self
.SetSelection(start
, end
)
474 #---------------------------------------------------------------------------
475 # Constants for module versions
479 modDefault
= modOriginal
481 #---------------------------------------------------------------------------
483 class DemoCodePanel(wx
.Panel
):
484 """Panel for the 'Demo Code' tab"""
485 def __init__(self
, parent
, mainFrame
):
486 wx
.Panel
.__init
__(self
, parent
)
487 self
.mainFrame
= mainFrame
488 self
.editor
= DemoCodeEditor(self
)
489 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
491 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
492 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
493 self
.btnSave
.Enable(False)
494 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
495 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
497 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
498 modModified
: wx
.RadioButton(self
, -1, "Modified") }
500 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
501 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
502 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
503 for modID
, radioButton
in self
.radioButtons
.items():
504 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
505 radioButton
.modID
= modID
# makes it easier for the event handler
506 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
508 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
509 self
.controlBox
.Add(self
.btnRestore
, 0)
511 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
512 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
513 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
514 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
517 self
.SetSizer(self
.box
)
520 # Loads a demo from a DemoModules object
521 def LoadDemo(self
, demoModules
):
522 self
.demoModules
= demoModules
523 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
524 demoModules
.SetActive(modModified
)
526 demoModules
.SetActive(modOriginal
)
527 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
528 self
.ActiveModuleChanged()
531 def ActiveModuleChanged(self
):
532 self
.LoadDemoSource(self
.demoModules
.GetSource())
533 self
.UpdateControlState()
536 def LoadDemoSource(self
, source
):
538 self
.editor
.SetValue(source
)
540 self
.btnSave
.Enable(False)
543 def JumpToLine(self
, line
, highlight
=False):
544 self
.editor
.GotoLine(line
)
545 self
.editor
.SetFocus()
547 self
.editor
.SelectLine(line
)
550 def UpdateControlState(self
):
551 active
= self
.demoModules
.GetActiveID()
552 # Update the radio/restore buttons
553 for moduleID
in self
.radioButtons
:
554 btn
= self
.radioButtons
[moduleID
]
555 if moduleID
== active
:
560 if self
.demoModules
.Exists(moduleID
):
562 if moduleID
== modModified
:
563 self
.btnRestore
.Enable(True)
566 if moduleID
== modModified
:
567 self
.btnRestore
.Enable(False)
570 def OnRadioButton(self
, event
):
571 radioSelected
= event
.GetEventObject()
572 modSelected
= radioSelected
.modID
573 if modSelected
!= self
.demoModules
.GetActiveID():
574 busy
= wx
.BusyInfo("Reloading demo module...")
575 self
.demoModules
.SetActive(modSelected
)
576 self
.ActiveModuleChanged()
580 def ReloadDemo(self
):
581 if self
.demoModules
.name
!= __name__
:
582 self
.mainFrame
.RunModule(False)
585 def OnCodeModified(self
, event
):
586 self
.btnSave
.Enable(self
.editor
.IsModified())
589 def OnSave(self
, event
):
590 if self
.demoModules
.Exists(modModified
):
591 if self
.demoModules
.GetActiveID() == modOriginal
:
592 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
593 "Do you want to continue?"
594 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
595 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
596 result
= dlg
.ShowModal()
597 if result
== wx
.ID_NO
:
601 self
.demoModules
.SetActive(modModified
)
602 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
604 # Create the demo directory if one doesn't already exist
605 if not os
.path
.exists(GetModifiedDirectory()):
607 os
.makedirs(GetModifiedDirectory())
608 if not os
.path
.exists(GetModifiedDirectory()):
609 wx
.LogMessage("BUG: Created demo directory but it still doesn't exit")
612 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
615 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
618 f
= open(modifiedFilename
, "wt")
619 source
= self
.editor
.GetText()
625 busy
= wx
.BusyInfo("Reloading demo module...")
626 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
627 self
.ActiveModuleChanged()
631 def OnRestore(self
, event
): # Handles the "Delete Modified" button
632 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
633 self
.demoModules
.Delete(modModified
)
634 os
.unlink(modifiedFilename
) # Delete the modified copy
635 busy
= wx
.BusyInfo("Reloading demo module...")
636 self
.ActiveModuleChanged()
640 #---------------------------------------------------------------------------
643 """Convert paths to the platform-specific separator"""
644 str = apply(os
.path
.join
, tuple(path
.split('/')))
645 # HACK: on Linux, a leading / gets lost...
646 if path
.startswith('/'):
651 def GetModifiedDirectory():
653 Returns the directory where modified versions of the demo files
656 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
659 def GetModifiedFilename(name
):
661 Returns the filename of the modified version of the specified demo
663 if not name
.endswith(".py"):
665 return GetModifiedDirectory() + name
668 def GetOriginalFilename(name
):
670 Returns the filename of the original version of the specified demo
672 if not name
.endswith(".py"):
677 def DoesModifiedExist(name
):
678 """Returns whether the specified demo has a modified copy"""
679 if os
.path
.exists(GetModifiedFilename(name
)):
685 #---------------------------------------------------------------------------
687 class ModuleDictWrapper
:
688 """Emulates a module with a dynamically compiled __dict__"""
689 def __init__(self
, dict):
692 def __getattr__(self
, name
):
693 if name
in self
.dict:
694 return self
.dict[name
]
700 Dynamically manages the original/modified versions of a demo
703 def __init__(self
, name
):
707 # (dict , source , filename , description , error information )
708 # ( 0 , 1 , 2 , 3 , 4 )
709 self
.modules
= [[None, "" , "" , "<original>" , None],
710 [None, "" , "" , "<modified>" , None]]
712 # load original module
713 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
714 self
.SetActive(modOriginal
)
716 # load modified module (if one exists)
717 if DoesModifiedExist(name
):
718 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
719 if (modDefault
== modModified
):
720 self
.SetActive(modModified
)
723 def LoadFromFile(self
, modID
, filename
):
724 self
.modules
[modID
][2] = filename
725 file = open(filename
, "rt")
726 self
.LoadFromSource(modID
, file.read())
730 def LoadFromSource(self
, modID
, source
):
731 self
.modules
[modID
][1] = source
735 def LoadDict(self
, modID
):
736 if self
.name
!= __name__
:
737 source
= self
.modules
[modID
][1]
738 description
= self
.modules
[modID
][3]
741 self
.modules
[modID
][0] = {}
742 code
= compile(source
, description
, "exec")
743 exec code
in self
.modules
[modID
][0]
745 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
746 self
.modules
[modID
][0] = None
748 self
.modules
[modID
][4] = None
751 def SetActive(self
, modID
):
752 if modID
!= modOriginal
and modID
!= modModified
:
755 self
.modActive
= modID
759 dict = self
.modules
[self
.modActive
][0]
763 return ModuleDictWrapper(dict)
766 def GetActiveID(self
):
767 return self
.modActive
770 def GetSource(self
, modID
= None):
772 modID
= self
.modActive
773 return self
.modules
[modID
][1]
776 def GetFilename(self
, modID
= None):
778 modID
= self
.modActive
779 return self
.modules
[self
.modActive
][2]
782 def GetErrorInfo(self
, modID
= None):
784 modID
= self
.modActive
785 return self
.modules
[self
.modActive
][4]
788 def Exists(self
, modID
):
789 return self
.modules
[modID
][1] != ""
792 def UpdateFile(self
, modID
= None):
793 """Updates the file from which a module was loaded
794 with (possibly updated) source"""
796 modID
= self
.modActive
798 source
= self
.modules
[modID
][1]
799 filename
= self
.modules
[modID
][2]
802 file = open(filename
, "wt")
808 def Delete(self
, modID
):
809 if self
.modActive
== modID
:
812 self
.modules
[modID
][0] = None
813 self
.modules
[modID
][1] = ""
814 self
.modules
[modID
][2] = ""
817 #---------------------------------------------------------------------------
818 class ReloadDemoPanel(wx
.Panel
):
820 Panel put into the demo tab when the demo just shows some
821 top-level window. Enables the demo to be reloaded after being
825 infoText
= "This demo runs outside the main window"
827 def __init__(self
, parent
, codePanel
, log
):
828 wx
.Panel
.__init
__(self
, parent
, -1)
829 self
.codePanel
= codePanel
832 self
.label
= wx
.StaticText(self
, -1, self
.infoText
)
833 self
.btnReload
= wx
.Button(self
, -1, "Reload Demo")
834 self
.btnReload
.Bind(wx
.EVT_BUTTON
, self
.OnReload
)
836 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
837 self
.box
.Add(self
.label
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 10)
838 self
.box
.Add(self
.btnReload
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 10)
841 self
.SetSizer(self
.box
)
843 def OnReload(self
, event
):
844 self
.codePanel
.ReloadDemo()
846 #---------------------------------------------------------------------------
849 """Wraps and stores information about the current exception"""
850 def __init__(self
, exc_info
):
853 excType
, excValue
= exc_info
[:2]
854 # traceback list entries: (filename, line number, function name, text)
855 self
.traceback
= traceback
.extract_tb(exc_info
[2])
857 # --Based on traceback.py::format_exception_only()--
858 if type(excType
) == types
.ClassType
:
859 self
.exception_type
= excType
.__name
__
861 self
.exception_type
= excType
863 # If it's a syntax error, extra information needs
864 # to be added to the traceback
865 if excType
is SyntaxError:
867 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
872 filename
= "<string>"
874 self
.traceback
.append( (filename
, lineno
, "", line
) )
877 self
.exception_details
= str(excValue
)
879 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
886 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
889 #---------------------------------------------------------------------------
891 class DemoErrorPanel(wx
.Panel
):
892 """Panel put into the demo tab when the demo fails to run due to errors"""
894 def __init__(self
, parent
, codePanel
, demoError
, log
):
895 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
896 self
.codePanel
= codePanel
900 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
903 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occured while trying to run the demo")
904 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
906 # Exception Information
907 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
908 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
909 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
910 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
911 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
912 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_type
) , 0, textFlags
, 5 )
913 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
914 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
915 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
916 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
918 # Set up the traceback list
919 # This one automatically resizes last column to take up remaining space
920 from ListCtrl
import TestListCtrl
921 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
922 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
923 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
924 self
.list.InsertColumn(0, "Filename")
925 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
926 self
.list.InsertColumn(2, "Function")
927 self
.list.InsertColumn(3, "Code")
928 self
.InsertTraceback(self
.list, demoError
.traceback
)
929 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
930 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
931 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
932 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
933 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
934 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
935 + "Double-click on them to go to the offending line")
936 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
939 self
.SetSizer(self
.box
)
942 def InsertTraceback(self
, list, traceback
):
943 #Add the traceback data
944 for x
in range(len(traceback
)):
946 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
947 list.SetStringItem(x
, 1, str(data
[1])) # Line
948 list.SetStringItem(x
, 2, str(data
[2])) # Function
949 list.SetStringItem(x
, 3, str(data
[3])) # Code
951 # Check whether this entry is from the demo module
952 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
953 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
954 # Give it a blue colour
955 item
= self
.list.GetItem(x
)
956 item
.SetTextColour(wx
.BLUE
)
957 self
.list.SetItem(item
)
959 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
962 def OnItemSelected(self
, event
):
963 # This occurs before OnDoubleClick and can be used to set the
964 # currentItem. OnDoubleClick doesn't get a wxListEvent....
965 self
.currentItem
= event
.m_itemIndex
969 def OnDoubleClick(self
, event
):
970 # If double-clicking on a demo's entry, jump to the line number
971 line
= self
.list.GetItemData(self
.currentItem
)
973 self
.nb
.SetSelection(1) # Switch to the code viewer tab
974 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
978 #---------------------------------------------------------------------------
980 class wxPythonDemo(wx
.Frame
):
981 overviewText
= "wxPython Overview"
983 def __init__(self
, parent
, title
):
984 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 750),
985 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
988 self
.cwd
= os
.getcwd()
989 self
.curOverview
= ""
992 self
.useModified
= False
995 icon
= images
.getMondrianIcon()
998 if wx
.Platform
!= '__WXMAC__':
999 # setup a taskbar icon, and catch some events from it
1000 dim
= 16 # (may want to use 22 on wxGTK, but 16 looks okay too)
1001 icon
= wx
.IconFromBitmap(
1002 images
.getMondrianImage().Scale(dim
,dim
).ConvertToBitmap() )
1003 #icon = wx.Icon('bmp_source/mondrian.ico', wx.BITMAP_TYPE_ICO)
1004 #icon = images.getMondrianIcon()
1005 self
.tbicon
= wx
.TaskBarIcon()
1006 self
.tbicon
.SetIcon(icon
, "wxPython Demo")
1007 self
.tbicon
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1008 self
.tbicon
.Bind(wx
.EVT_TASKBAR_RIGHT_UP
, self
.OnTaskBarMenu
)
1009 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1010 self
.tbicon
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1012 wx
.CallAfter(self
.ShowTip
)
1014 self
.otherWin
= None
1015 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1016 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1017 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1018 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1020 self
.Centre(wx
.BOTH
)
1021 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1023 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1024 splitter2
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1026 def EmptyHandler(evt
): pass
1027 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1028 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1030 # Prevent TreeCtrl from displaying all items after destruction when True
1034 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1037 self
.mainmenu
= wx
.MenuBar()
1039 item
= menu
.Append(-1, '&Redirect Output',
1040 'Redirect print statements to a window',
1042 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1044 item
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1045 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
)
1046 wx
.App_SetMacExitMenuItemId(item
.GetId())
1047 self
.mainmenu
.Append(menu
, '&File')
1051 for item
in _treeList
:
1053 for childItem
in item
[1]:
1054 mi
= submenu
.Append(-1, childItem
)
1055 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1056 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1057 self
.mainmenu
.Append(menu
, '&Demo')
1059 # Make a Demo Code menu
1060 #TODO: Add new menu items
1061 # Like the option-enabled entries to select the
1063 #TODO: should we bother?
1066 #saveID = wx.NewId()
1067 #restoreID = wx.NewId()
1069 #menu.Append(saveID, '&Save\tCtrl-S', 'Save edited demo')
1070 #menu.Append(restoreID, '&Delete Modified\tCtrl-R', 'Delete modified copy')
1071 #self.Bind(wx.EVT_MENU, self.codePage.OnSave, id=saveID)
1072 #self.Bind(wx.EVT_MENU, self.codePage.OnRestore, id=restoreID)
1073 #self.mainmenu.Append(menu, 'Demo &Code')
1078 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1079 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1080 menu
.AppendSeparator()
1082 shellItem
= menu
.Append(-1, 'Open Py&Shell Window\tF5',
1083 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1084 menu
.AppendSeparator()
1085 helpItem
= menu
.Append(-1, '&About\tCtrl-H', 'wxPython RULES!!!')
1086 wx
.App_SetMacAboutMenuItemId(helpItem
.GetId())
1088 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1089 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1090 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1091 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1092 self
.Bind(wx
.EVT_COMMAND_FIND
, self
.OnFind
)
1093 self
.Bind(wx
.EVT_COMMAND_FIND_NEXT
, self
.OnFind
)
1094 self
.Bind(wx
.EVT_COMMAND_FIND_CLOSE
, self
.OnFindClose
)
1095 self
.mainmenu
.Append(menu
, '&Help')
1096 self
.SetMenuBar(self
.mainmenu
)
1098 self
.finddata
= wx
.FindReplaceData()
1101 # This is another way to set Accelerators, in addition to
1102 # using the '\t<key>' syntax in the menu items.
1103 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitID
),
1104 (wx
.ACCEL_CTRL
, ord('H'), helpID
),
1105 (wx
.ACCEL_CTRL
, ord('F'), findID
),
1106 (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
)
1108 self
.SetAcceleratorTable(aTable
)
1114 self
.tree
= wx
.TreeCtrl(splitter
, tID
, style
=
1115 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1118 root
= self
.tree
.AddRoot("wxPython Overview")
1120 for item
in _treeList
:
1121 child
= self
.tree
.AppendItem(root
, item
[0])
1122 if not firstChild
: firstChild
= child
1123 for childItem
in item
[1]:
1124 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1125 self
.treeMap
[childItem
] = theDemo
1127 self
.tree
.Expand(root
)
1128 self
.tree
.Expand(firstChild
)
1129 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1130 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1131 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1132 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1134 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1135 # we put it in a panel first because there seems to be a
1136 # refresh bug of some sort (wxGTK) when it is directly in
1139 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1140 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1142 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1143 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1144 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1145 self
.nb
.AddPage(panel
, self
.overviewText
)
1147 def OnOvrSize(evt
, ovr
=self
.ovr
):
1148 ovr
.SetSize(evt
.GetSize())
1149 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1150 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1152 if "gtk2" in wx
.PlatformInfo
:
1153 self
.ovr
.NormalizeFontSizes()
1154 self
.SetOverview(self
.overviewText
, mainOverview
)
1157 # Set up a log window
1158 self
.log
= wx
.TextCtrl(splitter2
, -1,
1159 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1161 # Set the wxWindows log target to be this textctrl
1162 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1164 # But instead of the above we want to show how to use our own wx.Log class
1165 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1167 # for serious debugging
1168 #wx.Log_SetActiveTarget(wx.LogStderr())
1169 #wx.Log_SetTraceMask(wx.TraceMessages)
1172 # add the windows to the splitter and split it.
1173 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1174 splitter
.SplitVertically(self
.tree
, splitter2
, 200)
1176 splitter
.SetMinimumPaneSize(20)
1177 splitter2
.SetMinimumPaneSize(20)
1179 # Make the splitter on the right expand the top window when resized
1180 def SplitterOnSize(evt
):
1181 splitter
= evt
.GetEventObject()
1182 sz
= splitter
.GetSize()
1183 splitter
.SetSashPosition(sz
.height
- 160, False)
1186 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1188 # select initial items
1189 self
.nb
.SetSelection(0)
1190 self
.tree
.SelectItem(root
)
1192 # Load 'Main' module
1193 self
.LoadDemo(self
.overviewText
)
1196 # select some other initial module?
1197 if len(sys
.argv
) > 1:
1199 if arg
.endswith('.py'):
1201 selectedDemo
= self
.treeMap
.get(arg
, None)
1203 self
.tree
.SelectItem(selectedDemo
)
1204 self
.tree
.EnsureVisible(selectedDemo
)
1207 #---------------------------------------------
1208 def WriteText(self
, text
):
1209 if text
[-1:] == '\n':
1213 def write(self
, txt
):
1216 #---------------------------------------------
1217 def OnItemExpanded(self
, event
):
1218 item
= event
.GetItem()
1219 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1222 #---------------------------------------------
1223 def OnItemCollapsed(self
, event
):
1224 item
= event
.GetItem()
1225 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1228 #---------------------------------------------
1229 def OnTreeLeftDown(self
, event
):
1230 # reset the overview text if the tree item is clicked on again
1231 pt
= event
.GetPosition();
1232 item
, flags
= self
.tree
.HitTest(pt
)
1233 if item
== self
.tree
.GetSelection():
1234 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1237 #---------------------------------------------
1238 def OnSelChanged(self
, event
):
1239 if self
.dying
or not self
.loaded
:
1242 item
= event
.GetItem()
1243 itemText
= self
.tree
.GetItemText(item
)
1244 self
.LoadDemo(itemText
)
1246 #---------------------------------------------
1247 def LoadDemo(self
, demoName
):
1249 wx
.BeginBusyCursor()
1252 self
.ShutdownDemoModule()
1254 if demoName
== self
.overviewText
:
1255 # User selected the "wxPython Overview" node
1257 # Changing the main window at runtime not yet supported...
1258 self
.demoModules
= DemoModules(__name__
)
1259 self
.SetOverview(self
.overviewText
, mainOverview
)
1260 self
.LoadDemoSource()
1261 self
.UpdateNotebook(0)
1263 if os
.path
.exists(GetOriginalFilename(demoName
)):
1264 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1265 self
.demoModules
= DemoModules(demoName
)
1266 self
.RunModule(True)
1269 self
.SetOverview("wxPython", mainOverview
)
1270 self
.codePage
= None
1271 self
.UpdateNotebook(0)
1275 #---------------------------------------------
1276 def LoadDemoSource(self
):
1277 self
.codePage
= None
1278 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1279 self
.codePage
.LoadDemo(self
.demoModules
)
1281 #---------------------------------------------
1282 def RunModule(self
, loadSource
):
1283 """Runs the active module"""
1285 module
= self
.demoModules
.GetActive()
1286 self
.ShutdownDemoModule()
1289 # o If the demo returns a window it is placed in a tab.
1290 # o Otherwise, a placeholder tab is created, informing the user that the
1291 # demo runs outside the main window, and allowing it to be reloaded.
1292 # o If an error occurs (or has occured before) an error tab is created.
1294 if module
is not None:
1295 wx
.LogMessage("Running demo module...")
1296 if hasattr(module
, "overview"):
1297 overviewText
= module
.overview
1300 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1301 if self
.demoPage
is None:
1302 self
.demoPage
= ReloadDemoPanel(self
.nb
, self
.codePage
, self
)
1304 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1305 DemoError(sys
.exc_info()), self
)
1307 # There was a previous error in compiling or exec-ing
1308 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1309 self
.demoModules
.GetErrorInfo(), self
)
1312 self
.LoadDemoSource()
1313 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1314 self
.UpdateNotebook()
1316 #---------------------------------------------
1317 def ShutdownDemoModule(self
):
1319 # inform the window that it's time to quit if it cares
1320 if hasattr(self
.demoPage
, "ShutdownDemo"):
1321 self
.demoPage
.ShutdownDemo()
1322 wx
.YieldIfNeeded() # in case the page has pending events
1323 self
.demoPage
= None
1325 #---------------------------------------------
1326 def UpdateNotebook(self
, select
= -1):
1330 def UpdatePage(page
, pageText
):
1333 for i
in range(nb
.GetPageCount()):
1334 if nb
.GetPageText(i
) == pageText
:
1342 nb
.AddPage(page
, pageText
)
1343 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1345 if nb
.GetPage(pagePos
) != page
:
1346 # Reload an existing page
1348 nb
.DeletePage(pagePos
)
1349 nb
.InsertPage(pagePos
, page
, pageText
)
1351 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1353 # Excellent! No redraw/flicker
1354 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1357 nb
.DeletePage(pagePos
)
1358 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1360 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1363 select
= nb
.GetSelection()
1365 UpdatePage(self
.codePage
, "Demo Code")
1366 UpdatePage(self
.demoPage
, "Demo")
1368 if select
>= 0 and select
< nb
.GetPageCount():
1369 nb
.SetSelection(select
)
1371 #---------------------------------------------
1372 def SetOverview(self
, name
, text
):
1373 self
.curOverview
= text
1375 if lead
!= '<html>' and lead
!= '<HTML>':
1376 text
= '<br>'.join(text
.split('\n'))
1378 text
= text
.decode('iso8859_1')
1379 self
.ovr
.SetPage(text
)
1380 self
.nb
.SetPageText(0, name
)
1382 #---------------------------------------------
1384 def OnFileExit(self
, *event
):
1387 def OnToggleRedirect(self
, event
):
1391 print "Print statements and other standard output will now be directed to this window."
1394 print "Print statements and other standard output will now be sent to the usual location."
1396 def OnHelpAbout(self
, event
):
1397 from About
import MyAboutBox
1398 about
= MyAboutBox(self
)
1402 def OnHelpFind(self
, event
):
1403 self
.nb
.SetSelection(1)
1404 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1408 self
.finddlg
.Show(True)
1410 def OnFind(self
, event
):
1411 editor
= self
.codePage
.editor
1412 self
.nb
.SetSelection(1)
1413 end
= editor
.GetLastPosition()
1414 textstring
= editor
.GetRange(0, end
).lower()
1415 start
= editor
.GetSelection()[1]
1416 findstring
= self
.finddata
.GetFindString().lower()
1417 loc
= textstring
.find(findstring
, start
)
1418 if loc
== -1 and start
!= 0:
1419 # string not found, start at beginning
1421 loc
= textstring
.find(findstring
, start
)
1423 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1424 'Find String Not Found in Demo File',
1425 wx
.OK | wx
.ICON_INFORMATION
)
1430 self
.finddlg
.SetFocus()
1433 self
.finddlg
.Destroy()
1434 editor
.ShowPosition(loc
)
1435 editor
.SetSelection(loc
, loc
+ len(findstring
))
1439 def OnFindNext(self
, event
):
1440 if self
.finddata
.GetFindString():
1443 self
.OnHelpFind(event
)
1445 def OnFindClose(self
, event
):
1446 event
.GetDialog().Destroy()
1449 def OnOpenShellWindow(self
, evt
):
1451 # if it already exists then just make sure it's visible
1457 # Make a PyShell window
1459 namespace
= { 'wx' : wx
,
1460 'app' : wx
.GetApp(),
1463 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1464 self
.shell
.SetSize((640,480))
1467 # Hook the close event of the main frame window so that we
1468 # close the shell at the same time if it still exists
1469 def CloseShell(evt
):
1473 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1476 #---------------------------------------------
1477 def OnCloseWindow(self
, event
):
1479 self
.demoPage
= None
1480 self
.codePage
= None
1481 self
.mainmenu
= None
1485 #---------------------------------------------
1486 def OnIdle(self
, event
):
1488 self
.otherWin
.Raise()
1489 self
.demoPage
= self
.otherWin
1490 self
.otherWin
= None
1493 #---------------------------------------------
1496 showTipText
= open(opj("data/showTips")).read()
1497 showTip
, index
= eval(showTipText
)
1499 showTip
, index
= (1, 0)
1501 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
1503 showTip
= wx
.ShowTip(self
, tp
)
1504 index
= tp
.GetCurrentTip()
1505 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
1508 #---------------------------------------------
1509 def OnDemoMenu(self
, event
):
1511 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
1515 self
.tree
.SelectItem(selectedDemo
)
1516 self
.tree
.EnsureVisible(selectedDemo
)
1519 #---------------------------------------------
1520 def OnTaskBarActivate(self
, evt
):
1521 if self
.IsIconized():
1523 if not self
.IsShown():
1527 #---------------------------------------------
1529 TBMENU_RESTORE
= 1000
1532 def OnTaskBarMenu(self
, evt
):
1534 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1535 menu
.Append(self
.TBMENU_CLOSE
, "Close")
1536 self
.tbicon
.PopupMenu(menu
)
1539 #---------------------------------------------
1540 def OnTaskBarClose(self
, evt
):
1543 # because of the way wx.TaskBarIcon.PopupMenu is implemented we have to
1544 # prod the main idle handler a bit to get the window to actually close
1545 wx
.GetApp().ProcessIdle()
1548 #---------------------------------------------
1549 def OnIconfiy(self
, evt
):
1550 wx
.LogMessage("OnIconfiy: %d" % evt
.Iconized())
1553 #---------------------------------------------
1554 def OnMaximize(self
, evt
):
1555 wx
.LogMessage("OnMaximize")
1561 #---------------------------------------------------------------------------
1562 #---------------------------------------------------------------------------
1564 class MySplashScreen(wx
.SplashScreen
):
1566 bmp
= wx
.Image(opj("bitmaps/splash.gif")).ConvertToBitmap()
1567 wx
.SplashScreen
.__init
__(self
, bmp
,
1568 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
1570 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
1572 def OnClose(self
, evt
):
1574 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
1576 evt
.Skip() # Make sure the default handler runs too...
1579 class MyApp(wx
.App
):
1582 Create and show the splash screen. It will then create and show
1583 the main frame when it is time to do so.
1587 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1589 # Normally when using a SplashScreen you would create it, show
1590 # it and then continue on with the applicaiton's
1591 # initialization, finally creating and showing the main
1592 # application window(s). In this case we have nothing else to
1593 # do so we'll delay showing the main frame until later (see
1594 # OnClose above) so the users can see the SplashScreen effect.
1595 splash
= MySplashScreen()
1602 #---------------------------------------------------------------------------
1606 demoPath
= os
.path
.dirname(__file__
)
1613 #---------------------------------------------------------------------------
1616 mainOverview
= """<html><body>
1619 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1620 language. It allows Python programmers to create programs with a
1621 robust, highly functional graphical user interface, simply and easily.
1622 It is implemented as a Python extension module (native code) that
1623 wraps the popular wxWindows cross platform GUI library, which is
1626 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1627 means that it is free for anyone to use and the source code is
1628 available for anyone to look at and modify. Or anyone can contribute
1629 fixes or enhancements to the project.
1631 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1632 same program will run on multiple platforms without modification.
1633 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1634 or unix-like systems, and Macintosh OS X. Since the language is
1635 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1638 <p> <b>This demo</b> is not only a collection of test cases for
1639 wxPython, but is also designed to help you learn about and how to use
1640 wxPython. Each sample is listed in the tree control on the left.
1641 When a sample is selected in the tree then a module is loaded and run
1642 (usually in a tab of this notebook,) and the source code of the module
1643 is loaded in another tab for you to browse and learn from.
1648 #----------------------------------------------------------------------------
1649 #----------------------------------------------------------------------------
1651 if __name__
== '__main__':
1655 #----------------------------------------------------------------------------