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 = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi')
40 ##print "pid:", os.getpid()
41 ##raw_input("Press Enter...")
44 #---------------------------------------------------------------------------
49 ('Recent Additions/Updates', [
75 # managed windows == things with a (optional) caption you can close
76 ('Frames and Dialogs', [
77 'AUI_DockingWindowMgr',
103 # dialogs from libraries
106 'ScrolledMessageDialog',
110 ('Core Windows/Controls', [
148 ('"Book" Controls', [
157 ('Custom Controls', [
174 # controls coming from other libraries
175 ('More Windows/Controls', [
176 'ActiveX_FlashWindow',
177 'ActiveX_IEHtmlWindow',
182 'CheckListCtrlMixin',
199 'MaskedEditControls',
202 'MultiSplitterWindow',
203 'OwnerDrawnComboBox',
220 # How to lay out the controls in a frame/dialog
231 'XmlResourceHandler',
232 'XmlResourceSubclass',
236 ('Process and Events', [
244 ##'infoframe', # needs better explanation and some fixing
248 ('Clipboard and DnD', [
275 ##'DialogUnits', # needs more explanations
296 ('Check out the samples dir too', [
303 #---------------------------------------------------------------------------
304 # Show how to derive a custom wxLog class
306 class MyLog(wx
.PyLog
):
307 def __init__(self
, textCtrl
, logTime
=0):
308 wx
.PyLog
.__init
__(self
)
310 self
.logTime
= logTime
312 def DoLogString(self
, message
, timeStamp
):
313 #print message, timeStamp
315 # message = time.strftime("%X", time.localtime(timeStamp)) + \
318 self
.tc
.AppendText(message
+ '\n')
321 class MyTP(wx
.PyTipProvider
):
323 return "This is my tip"
325 #---------------------------------------------------------------------------
326 # A class to be used to simply display a message in the demo pane
327 # rather than running the sample itself.
329 class MessagePanel(wx
.Panel
):
330 def __init__(self
, parent
, message
, caption
='', flags
=0):
331 wx
.Panel
.__init
__(self
, parent
)
336 if flags
& wx
.ICON_EXCLAMATION
:
337 artid
= wx
.ART_WARNING
338 elif flags
& wx
.ICON_ERROR
:
340 elif flags
& wx
.ICON_QUESTION
:
341 artid
= wx
.ART_QUESTION
342 elif flags
& wx
.ICON_INFORMATION
:
343 artid
= wx
.ART_INFORMATION
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
)
349 icon
= (32,32) # make a spacer instead
352 caption
= wx
.StaticText(self
, -1, caption
)
353 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
355 message
= wx
.StaticText(self
, -1, message
)
357 # add to sizers for layout
358 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
364 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
371 box
= wx
.BoxSizer(wx
.VERTICAL
)
373 box
.Add(hbox
, 0, wx
.EXPAND
)
380 #---------------------------------------------------------------------------
381 # A class to be used to display source code in the demo. Try using the
382 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
383 # if there is an error, such as the stc module not being present.
387 ##raise ImportError # for testing the alternate implementation
389 from StyledTextCtrl_2
import PythonSTC
391 class DemoCodeEditor(PythonSTC
):
392 def __init__(self
, parent
):
393 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
396 # Some methods to make it compatible with how the wxTextCtrl is used
397 def SetValue(self
, value
):
399 value
= value
.decode('iso8859_1')
401 self
.EmptyUndoBuffer()
404 def IsModified(self
):
405 return self
.GetModify()
410 def SetInsertionPoint(self
, pos
):
411 self
.SetCurrentPos(pos
)
414 def ShowPosition(self
, pos
):
415 line
= self
.LineFromPosition(pos
)
416 #self.EnsureVisible(line)
419 def GetLastPosition(self
):
420 return self
.GetLength()
422 def GetPositionFromLine(self
, line
):
423 return self
.PositionFromLine(line
)
425 def GetRange(self
, start
, end
):
426 return self
.GetTextRange(start
, end
)
428 def GetSelection(self
):
429 return self
.GetAnchor(), self
.GetCurrentPos()
431 def SetSelection(self
, start
, end
):
432 self
.SetSelectionStart(start
)
433 self
.SetSelectionEnd(end
)
435 def SelectLine(self
, line
):
436 start
= self
.PositionFromLine(line
)
437 end
= self
.GetLineEndPosition(line
)
438 self
.SetSelection(start
, end
)
440 def SetUpEditor(self
):
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.
447 self
.SetLexer(stc
.STC_LEX_PYTHON
)
448 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
451 self
.SetProperty("fold", "1" )
453 # Highlight tab/space mixing (shouldn't be any)
454 self
.SetProperty("tab.timmy.whinge.level", "1")
456 # Set left and right margins
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)
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!
473 self
.SetViewWhiteSpace(False) # Don't view white space
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)
481 # No right-edge mode indicator
482 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
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)
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")
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')
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')
509 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
510 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
512 # Clear styles and revert to default.
515 # Following style specs only indicate differences from default.
516 # The rest remains unchanged.
518 # Line numbers in margin
519 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
521 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
523 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
525 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
528 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
530 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
531 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
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')
538 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
540 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
541 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
543 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
545 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
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')
553 self
.SetCaretForeground("BLUE")
554 # Selection background
555 self
.SetSelBackground(1, '#66CCFF')
557 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
558 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
560 def RegisterModifiedEvent(self
, eventHandler
):
561 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
565 class DemoCodeEditor(wx
.TextCtrl
):
566 def __init__(self
, parent
):
567 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
568 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
570 def RegisterModifiedEvent(self
, eventHandler
):
571 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
573 def SetReadOnly(self
, flag
):
574 self
.SetEditable(not flag
)
575 # NOTE: STC already has this method
578 return self
.GetValue()
580 def GetPositionFromLine(self
, line
):
581 return self
.XYToPosition(0,line
)
583 def GotoLine(self
, line
):
584 pos
= self
.GetPositionFromLine(line
)
585 self
.SetInsertionPoint(pos
)
586 self
.ShowPosition(pos
)
588 def SelectLine(self
, line
):
589 start
= self
.GetPositionFromLine(line
)
590 end
= start
+ self
.GetLineLength(line
)
591 self
.SetSelection(start
, end
)
594 #---------------------------------------------------------------------------
595 # Constants for module versions
599 modDefault
= modOriginal
601 #---------------------------------------------------------------------------
603 class DemoCodePanel(wx
.Panel
):
604 """Panel for the 'Demo Code' tab"""
605 def __init__(self
, parent
, mainFrame
):
606 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
607 if 'wxMSW' in wx
.PlatformInfo
:
609 self
.mainFrame
= mainFrame
610 self
.editor
= DemoCodeEditor(self
)
611 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
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
)
619 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
620 modModified
: wx
.RadioButton(self
, -1, "Modified") }
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
)
630 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
631 self
.controlBox
.Add(self
.btnRestore
, 0)
633 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
634 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
635 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
636 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
639 self
.SetSizer(self
.box
)
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
)
648 demoModules
.SetActive(modOriginal
)
649 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
650 self
.ActiveModuleChanged()
653 def ActiveModuleChanged(self
):
654 self
.LoadDemoSource(self
.demoModules
.GetSource())
655 self
.UpdateControlState()
659 def LoadDemoSource(self
, source
):
661 self
.editor
.SetValue(source
)
663 self
.btnSave
.Enable(False)
666 def JumpToLine(self
, line
, highlight
=False):
667 self
.editor
.GotoLine(line
)
668 self
.editor
.SetFocus()
670 self
.editor
.SelectLine(line
)
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
:
683 if self
.demoModules
.Exists(moduleID
):
685 if moduleID
== modModified
:
686 self
.btnRestore
.Enable(True)
689 if moduleID
== modModified
:
690 self
.btnRestore
.Enable(False)
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()
702 def ReloadDemo(self
):
703 if self
.demoModules
.name
!= __name__
:
704 self
.mainFrame
.RunModule()
707 def OnCodeModified(self
, event
):
708 self
.btnSave
.Enable(self
.editor
.IsModified())
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
:
723 self
.demoModules
.SetActive(modModified
)
724 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
726 # Create the demo directory if one doesn't already exist
727 if not os
.path
.exists(GetModifiedDirectory()):
729 os
.makedirs(GetModifiedDirectory())
730 if not os
.path
.exists(GetModifiedDirectory()):
731 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
734 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
737 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
740 f
= open(modifiedFilename
, "wt")
741 source
= self
.editor
.GetText()
747 busy
= wx
.BusyInfo("Reloading demo module...")
748 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
749 self
.ActiveModuleChanged()
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()
760 #---------------------------------------------------------------------------
763 """Convert paths to the platform-specific separator"""
764 str = apply(os
.path
.join
, tuple(path
.split('/')))
765 # HACK: on Linux, a leading / gets lost...
766 if path
.startswith('/'):
771 def GetModifiedDirectory():
773 Returns the directory where modified versions of the demo files
776 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
779 def GetModifiedFilename(name
):
781 Returns the filename of the modified version of the specified demo
783 if not name
.endswith(".py"):
785 return GetModifiedDirectory() + name
788 def GetOriginalFilename(name
):
790 Returns the filename of the original version of the specified demo
792 if not name
.endswith(".py"):
797 def DoesModifiedExist(name
):
798 """Returns whether the specified demo has a modified copy"""
799 if os
.path
.exists(GetModifiedFilename(name
)):
805 #---------------------------------------------------------------------------
807 class ModuleDictWrapper
:
808 """Emulates a module with a dynamically compiled __dict__"""
809 def __init__(self
, dict):
812 def __getattr__(self
, name
):
813 if name
in self
.dict:
814 return self
.dict[name
]
820 Dynamically manages the original/modified versions of a demo
823 def __init__(self
, name
):
827 # (dict , source , filename , description , error information )
828 # ( 0 , 1 , 2 , 3 , 4 )
829 self
.modules
= [[None, "" , "" , "<original>" , None],
830 [None, "" , "" , "<modified>" , None]]
832 # load original module
833 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
834 self
.SetActive(modOriginal
)
836 # load modified module (if one exists)
837 if DoesModifiedExist(name
):
838 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
841 def LoadFromFile(self
, modID
, filename
):
842 self
.modules
[modID
][2] = filename
843 file = open(filename
, "rt")
844 self
.LoadFromSource(modID
, file.read())
848 def LoadFromSource(self
, modID
, source
):
849 self
.modules
[modID
][1] = source
853 def LoadDict(self
, modID
):
854 if self
.name
!= __name__
:
855 source
= self
.modules
[modID
][1]
856 #description = self.modules[modID][3]
857 description
= self
.modules
[modID
][2]
860 self
.modules
[modID
][0] = {}
861 code
= compile(source
, description
, "exec")
862 exec code
in self
.modules
[modID
][0]
864 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
865 self
.modules
[modID
][0] = None
867 self
.modules
[modID
][4] = None
870 def SetActive(self
, modID
):
871 if modID
!= modOriginal
and modID
!= modModified
:
874 self
.modActive
= modID
878 dict = self
.modules
[self
.modActive
][0]
882 return ModuleDictWrapper(dict)
885 def GetActiveID(self
):
886 return self
.modActive
889 def GetSource(self
, modID
= None):
891 modID
= self
.modActive
892 return self
.modules
[modID
][1]
895 def GetFilename(self
, modID
= None):
897 modID
= self
.modActive
898 return self
.modules
[self
.modActive
][2]
901 def GetErrorInfo(self
, modID
= None):
903 modID
= self
.modActive
904 return self
.modules
[self
.modActive
][4]
907 def Exists(self
, modID
):
908 return self
.modules
[modID
][1] != ""
911 def UpdateFile(self
, modID
= None):
912 """Updates the file from which a module was loaded
913 with (possibly updated) source"""
915 modID
= self
.modActive
917 source
= self
.modules
[modID
][1]
918 filename
= self
.modules
[modID
][2]
921 file = open(filename
, "wt")
927 def Delete(self
, modID
):
928 if self
.modActive
== modID
:
931 self
.modules
[modID
][0] = None
932 self
.modules
[modID
][1] = ""
933 self
.modules
[modID
][2] = ""
936 #---------------------------------------------------------------------------
939 """Wraps and stores information about the current exception"""
940 def __init__(self
, exc_info
):
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])
947 # --Based on traceback.py::format_exception_only()--
948 if type(excType
) == types
.ClassType
:
949 self
.exception_type
= excType
.__name
__
951 self
.exception_type
= excType
953 # If it's a syntax error, extra information needs
954 # to be added to the traceback
955 if excType
is SyntaxError:
957 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
962 filename
= "<string>"
964 self
.traceback
.append( (filename
, lineno
, "", line
) )
967 self
.exception_details
= str(excValue
)
969 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
976 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
979 #---------------------------------------------------------------------------
981 class DemoErrorPanel(wx
.Panel
):
982 """Panel put into the demo tab when the demo fails to run due to errors"""
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
990 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
993 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo")
994 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
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 )
1002 boxInfoGrid
.Add(wx
.StaticText(self
, -1, str(demoError
.exception_type
)) , 0, textFlags
, 5 )
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)
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)
1029 self
.SetSizer(self
.box
)
1032 def InsertTraceback(self
, list, traceback
):
1033 #Add the traceback data
1034 for x
in range(len(traceback
)):
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
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
)
1049 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
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
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
)
1063 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1064 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1068 #---------------------------------------------------------------------------
1070 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1071 TBMENU_RESTORE
= wx
.NewId()
1072 TBMENU_CLOSE
= wx
.NewId()
1073 TBMENU_CHANGE
= wx
.NewId()
1074 TBMENU_REMOVE
= wx
.NewId()
1076 def __init__(self
, frame
):
1077 wx
.TaskBarIcon
.__init
__(self
)
1081 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1082 self
.SetIcon(icon
, "wxPython Demo")
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
)
1093 def CreatePopupMenu(self
):
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.
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")
1109 def MakeIcon(self
, img
):
1111 The various platforms have different requirements for the
1114 if "wxMSW" in wx
.PlatformInfo
:
1115 img
= img
.Scale(16, 16)
1116 elif "wxGTK" in wx
.PlatformInfo
:
1117 img
= img
.Scale(22, 22)
1118 # wxMac can be any size upto 128x128, so leave the source img alone....
1119 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
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)
1131 def OnTaskBarClose(self
, evt
):
1135 def OnTaskBarChange(self
, evt
):
1136 names
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
1137 name
= names
[self
.imgidx
]
1139 getFunc
= getattr(images
, "get%sImage" % name
)
1141 if self
.imgidx
>= len(names
):
1144 icon
= self
.MakeIcon(getFunc())
1145 self
.SetIcon(icon
, "This is a new icon: " + name
)
1148 def OnTaskBarRemove(self
, evt
):
1152 #---------------------------------------------------------------------------
1153 class wxPythonDemo(wx
.Frame
):
1154 overviewText
= "wxPython Overview"
1156 def __init__(self
, parent
, title
):
1157 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 720),
1158 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1160 self
.SetMinSize((640,480))
1163 self
.cwd
= os
.getcwd()
1164 self
.curOverview
= ""
1165 self
.demoPage
= None
1166 self
.codePage
= None
1168 self
.firstTime
= True
1171 icon
= images
.getWXPdemoIcon()
1175 self
.tbicon
= DemoTaskBarIcon(self
)
1179 wx
.CallAfter(self
.ShowTip
)
1181 self
.otherWin
= None
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
)
1187 self
.Centre(wx
.BOTH
)
1188 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
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
)
1193 def EmptyHandler(evt
): pass
1194 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1195 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1197 # Prevent TreeCtrl from displaying all items after destruction when True
1201 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1204 self
.mainmenu
= wx
.MenuBar()
1206 item
= menu
.Append(-1, '&Redirect Output',
1207 'Redirect print statements to a window',
1209 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1211 exitItem
= menu
.Append(-1, 'E&xit\tCtrl-Q', 'Get the heck outta here!')
1212 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, exitItem
)
1213 wx
.App
.SetMacExitMenuItemId(exitItem
.GetId())
1214 self
.mainmenu
.Append(menu
, '&File')
1218 for item
in _treeList
[:-1]:
1220 for childItem
in item
[1]:
1221 mi
= submenu
.Append(-1, childItem
)
1222 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1223 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1224 self
.mainmenu
.Append(menu
, '&Demo')
1229 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1230 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1231 menu
.AppendSeparator()
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 inspToolItem
= menu
.Append(-1, 'Open &Widget Inspector\tF6',
1236 'A tool that lets you browse the live widgets and sizers in an application')
1237 menu
.AppendSeparator()
1238 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1239 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1241 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1242 self
.Bind(wx
.EVT_MENU
, self
.OnOpenWidgetInspector
, inspToolItem
)
1243 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1244 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1245 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1246 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1247 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1248 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1249 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1250 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
)
1251 self
.mainmenu
.Append(menu
, '&Help')
1252 self
.SetMenuBar(self
.mainmenu
)
1254 self
.finddata
= wx
.FindReplaceData()
1255 self
.finddata
.SetFlags(wx
.FR_DOWN
)
1258 # This is another way to set Accelerators, in addition to
1259 # using the '\t<key>' syntax in the menu items.
1260 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitItem
.GetId()),
1261 (wx
.ACCEL_CTRL
, ord('H'), helpItem
.GetId()),
1262 (wx
.ACCEL_CTRL
, ord('F'), findItem
.GetId()),
1263 (wx
.ACCEL_NORMAL
, wx
.WXK_F3
, findnextItem
.GetId()),
1264 (wx
.ACCEL_NORMAL
, wx
.WXK_F9
, shellItem
.GetId()),
1266 self
.SetAcceleratorTable(aTable
)
1271 leftPanel
= wx
.Panel(splitter
)
1273 self
.filter = wx
.SearchCtrl(leftPanel
)
1274 self
.filter.ShowCancelButton(True)
1275 self
.filter.Bind(wx
.EVT_TEXT
, self
.RecreateTree
)
1276 self
.filter.Bind(wx
.EVT_SEARCHCTRL_CANCEL_BTN
,
1277 lambda e
: self
.filter.SetValue(''))
1280 self
.tree
= wx
.TreeCtrl(leftPanel
, tID
, style
=
1281 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1284 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1286 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1287 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1288 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1289 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1291 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1292 # we put it in a panel first because there seems to be a
1293 # refresh bug of some sort (wxGTK) when it is directly in
1296 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1297 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1299 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1300 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1301 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1302 self
.nb
.AddPage(panel
, self
.overviewText
)
1304 def OnOvrSize(evt
, ovr
=self
.ovr
):
1305 ovr
.SetSize(evt
.GetSize())
1306 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1307 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1309 if "gtk2" in wx
.PlatformInfo
:
1310 self
.ovr
.SetStandardFonts()
1311 self
.SetOverview(self
.overviewText
, mainOverview
)
1314 # Set up a log window
1315 self
.log
= wx
.TextCtrl(splitter2
, -1,
1316 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1317 if wx
.Platform
== "__WXMAC__":
1318 self
.log
.MacCheckSpelling(False)
1320 # Set the wxWindows log target to be this textctrl
1321 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1323 # But instead of the above we want to show how to use our own wx.Log class
1324 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1326 # for serious debugging
1327 #wx.Log_SetActiveTarget(wx.LogStderr())
1328 #wx.Log_SetTraceMask(wx.TraceMessages)
1331 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1332 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1334 # add the windows to the splitter and split it.
1335 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1336 leftBox
= wx
.BoxSizer(wx
.VERTICAL
)
1337 leftBox
.Add(self
.tree
, 1, wx
.EXPAND
)
1338 leftBox
.Add(wx
.StaticText(leftPanel
, label
= "Filter Demos:"), 0, wx
.TOP|wx
.LEFT
, 5)
1339 leftBox
.Add(self
.filter, 0, wx
.EXPAND|wx
.ALL
, 5)
1340 leftPanel
.SetSizer(leftBox
)
1341 splitter
.SplitVertically(leftPanel
, splitter2
, 220)
1343 splitter
.SetMinimumPaneSize(120)
1344 splitter2
.SetMinimumPaneSize(60)
1346 # Make the splitter on the right expand the top window when resized
1347 def SplitterOnSize(evt
):
1348 splitter
= evt
.GetEventObject()
1349 sz
= splitter
.GetSize()
1350 splitter
.SetSashPosition(sz
.height
- 160, False)
1353 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1355 # select initial items
1356 self
.nb
.SetSelection(0)
1357 self
.tree
.SelectItem(self
.root
)
1359 # Load 'Main' module
1360 self
.LoadDemo(self
.overviewText
)
1363 # select some other initial module?
1364 if len(sys
.argv
) > 1:
1366 if arg
.endswith('.py'):
1368 selectedDemo
= self
.treeMap
.get(arg
, None)
1370 self
.tree
.SelectItem(selectedDemo
)
1371 self
.tree
.EnsureVisible(selectedDemo
)
1374 #---------------------------------------------
1376 def RecreateTree(self
, evt
=None):
1378 self
.tree
.DeleteAllItems()
1379 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1381 filter = self
.filter.GetValue()
1382 for category
, items
in _treeList
:
1384 items
= [item
for item
in items
if filter.lower() in item
.lower()]
1386 child
= self
.tree
.AppendItem(self
.root
, category
)
1387 if not firstChild
: firstChild
= child
1388 for childItem
in items
:
1389 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1390 self
.treeMap
[childItem
] = theDemo
1392 self
.tree
.Expand(self
.root
)
1394 self
.tree
.Expand(firstChild
)
1396 self
.tree
.ExpandAll()
1399 def WriteText(self
, text
):
1400 if text
[-1:] == '\n':
1404 def write(self
, txt
):
1407 #---------------------------------------------
1408 def OnItemExpanded(self
, event
):
1409 item
= event
.GetItem()
1410 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1413 #---------------------------------------------
1414 def OnItemCollapsed(self
, event
):
1415 item
= event
.GetItem()
1416 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1419 #---------------------------------------------
1420 def OnTreeLeftDown(self
, event
):
1421 # reset the overview text if the tree item is clicked on again
1422 pt
= event
.GetPosition();
1423 item
, flags
= self
.tree
.HitTest(pt
)
1424 if item
== self
.tree
.GetSelection():
1425 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1428 #---------------------------------------------
1429 def OnSelChanged(self
, event
):
1430 if self
.dying
or not self
.loaded
:
1433 item
= event
.GetItem()
1434 itemText
= self
.tree
.GetItemText(item
)
1435 self
.LoadDemo(itemText
)
1437 #---------------------------------------------
1438 def LoadDemo(self
, demoName
):
1440 wx
.BeginBusyCursor()
1443 self
.ShutdownDemoModule()
1445 if demoName
== self
.overviewText
:
1446 # User selected the "wxPython Overview" node
1448 # Changing the main window at runtime not yet supported...
1449 self
.demoModules
= DemoModules(__name__
)
1450 self
.SetOverview(self
.overviewText
, mainOverview
)
1451 self
.LoadDemoSource()
1452 self
.UpdateNotebook(0)
1454 if os
.path
.exists(GetOriginalFilename(demoName
)):
1455 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1456 self
.demoModules
= DemoModules(demoName
)
1457 self
.LoadDemoSource()
1460 self
.SetOverview("wxPython", mainOverview
)
1461 self
.codePage
= None
1462 self
.UpdateNotebook(0)
1466 #---------------------------------------------
1467 def LoadDemoSource(self
):
1468 self
.codePage
= None
1469 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1470 self
.codePage
.LoadDemo(self
.demoModules
)
1472 #---------------------------------------------
1473 def RunModule(self
):
1474 """Runs the active module"""
1476 module
= self
.demoModules
.GetActive()
1477 self
.ShutdownDemoModule()
1480 # o The RunTest() for all samples must now return a window that can
1481 # be palced in a tab in the main notebook.
1482 # o If an error occurs (or has occurred before) an error tab is created.
1484 if module
is not None:
1485 wx
.LogMessage("Running demo module...")
1486 if hasattr(module
, "overview"):
1487 overviewText
= module
.overview
1490 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1492 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1493 DemoError(sys
.exc_info()), self
)
1495 assert self
.demoPage
is not None, "runTest must return a window!"
1498 # There was a previous error in compiling or exec-ing
1499 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1500 self
.demoModules
.GetErrorInfo(), self
)
1502 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1505 # cahnge to the demo page the first time a module is run
1506 self
.UpdateNotebook(2)
1507 self
.firstTime
= False
1509 # otherwise just stay on the same tab in case the user has changed to another one
1510 self
.UpdateNotebook()
1512 #---------------------------------------------
1513 def ShutdownDemoModule(self
):
1515 # inform the window that it's time to quit if it cares
1516 if hasattr(self
.demoPage
, "ShutdownDemo"):
1517 self
.demoPage
.ShutdownDemo()
1518 wx
.YieldIfNeeded() # in case the page has pending events
1519 self
.demoPage
= None
1521 #---------------------------------------------
1522 def UpdateNotebook(self
, select
= -1):
1526 def UpdatePage(page
, pageText
):
1529 for i
in range(nb
.GetPageCount()):
1530 if nb
.GetPageText(i
) == pageText
:
1538 nb
.AddPage(page
, pageText
)
1539 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1541 if nb
.GetPage(pagePos
) != page
:
1542 # Reload an existing page
1544 nb
.DeletePage(pagePos
)
1545 nb
.InsertPage(pagePos
, page
, pageText
)
1547 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1549 # Excellent! No redraw/flicker
1550 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1553 nb
.DeletePage(pagePos
)
1554 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1556 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1559 select
= nb
.GetSelection()
1561 UpdatePage(self
.codePage
, "Demo Code")
1562 UpdatePage(self
.demoPage
, "Demo")
1564 if select
>= 0 and select
< nb
.GetPageCount():
1565 nb
.SetSelection(select
)
1567 #---------------------------------------------
1568 def SetOverview(self
, name
, text
):
1569 self
.curOverview
= text
1571 if lead
!= '<html>' and lead
!= '<HTML>':
1572 text
= '<br>'.join(text
.split('\n'))
1574 text
= text
.decode('iso8859_1')
1575 self
.ovr
.SetPage(text
)
1576 self
.nb
.SetPageText(0, name
)
1578 #---------------------------------------------
1580 def OnFileExit(self
, *event
):
1583 def OnToggleRedirect(self
, event
):
1587 print "Print statements and other standard output will now be directed to this window."
1590 print "Print statements and other standard output will now be sent to the usual location."
1592 def OnHelpAbout(self
, event
):
1593 from About
import MyAboutBox
1594 about
= MyAboutBox(self
)
1598 def OnHelpFind(self
, event
):
1599 if self
.finddlg
!= None:
1602 self
.nb
.SetSelection(1)
1603 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1604 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1605 self
.finddlg
.Show(True)
1608 def OnUpdateFindItems(self
, evt
):
1609 evt
.Enable(self
.finddlg
== None)
1612 def OnFind(self
, event
):
1613 editor
= self
.codePage
.editor
1614 self
.nb
.SetSelection(1)
1615 end
= editor
.GetLastPosition()
1616 textstring
= editor
.GetRange(0, end
).lower()
1617 findstring
= self
.finddata
.GetFindString().lower()
1618 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1620 start
= editor
.GetSelection()[0]
1621 loc
= textstring
.rfind(findstring
, 0, start
)
1623 start
= editor
.GetSelection()[1]
1624 loc
= textstring
.find(findstring
, start
)
1625 if loc
== -1 and start
!= 0:
1626 # string not found, start at beginning
1629 loc
= textstring
.rfind(findstring
, 0, start
)
1632 loc
= textstring
.find(findstring
, start
)
1634 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1635 'Find String Not Found in Demo File',
1636 wx
.OK | wx
.ICON_INFORMATION
)
1641 self
.finddlg
.SetFocus()
1644 self
.finddlg
.Destroy()
1646 editor
.ShowPosition(loc
)
1647 editor
.SetSelection(loc
, loc
+ len(findstring
))
1651 def OnFindNext(self
, event
):
1652 if self
.finddata
.GetFindString():
1655 self
.OnHelpFind(event
)
1657 def OnFindClose(self
, event
):
1658 event
.GetDialog().Destroy()
1662 def OnOpenShellWindow(self
, evt
):
1664 # if it already exists then just make sure it's visible
1670 # Make a PyShell window
1672 namespace
= { 'wx' : wx
,
1673 'app' : wx
.GetApp(),
1676 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1677 self
.shell
.SetSize((640,480))
1680 # Hook the close event of the main frame window so that we
1681 # close the shell at the same time if it still exists
1682 def CloseShell(evt
):
1686 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1689 def OnOpenWidgetInspector(self
, evt
):
1690 # Activate the widget inspection tool
1691 from wx
.lib
.inspect
import InspectionTool
1692 if not InspectionTool().initialized
:
1693 InspectionTool().Init()
1695 # Find a widget to be selected in the tree. Use either the
1696 # one under the cursor, if any, or this frame.
1697 wnd
= wx
.FindWindowAtPointer()
1700 InspectionTool().Show(wnd
, True)
1703 #---------------------------------------------
1704 def OnCloseWindow(self
, event
):
1706 self
.demoPage
= None
1707 self
.codePage
= None
1708 self
.mainmenu
= None
1709 if self
.tbicon
is not None:
1710 self
.tbicon
.Destroy()
1714 #---------------------------------------------
1715 def OnIdle(self
, event
):
1717 self
.otherWin
.Raise()
1718 self
.demoPage
= self
.otherWin
1719 self
.otherWin
= None
1722 #---------------------------------------------
1725 showTipText
= open(opj("data/showTips")).read()
1726 showTip
, index
= eval(showTipText
)
1728 showTip
, index
= (1, 0)
1730 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
1732 showTip
= wx
.ShowTip(self
, tp
)
1733 index
= tp
.GetCurrentTip()
1734 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
1737 #---------------------------------------------
1738 def OnDemoMenu(self
, event
):
1740 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
1744 self
.tree
.SelectItem(selectedDemo
)
1745 self
.tree
.EnsureVisible(selectedDemo
)
1749 #---------------------------------------------
1750 def OnIconfiy(self
, evt
):
1751 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
1754 #---------------------------------------------
1755 def OnMaximize(self
, evt
):
1756 wx
.LogMessage("OnMaximize")
1759 #---------------------------------------------
1760 def OnActivate(self
, evt
):
1761 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
1764 #---------------------------------------------
1765 def OnAppActivate(self
, evt
):
1766 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
1769 #---------------------------------------------------------------------------
1770 #---------------------------------------------------------------------------
1772 class MySplashScreen(wx
.SplashScreen
):
1774 bmp
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
1775 wx
.SplashScreen
.__init
__(self
, bmp
,
1776 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
1778 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
1779 self
.fc
= wx
.FutureCall(2000, self
.ShowMain
)
1782 def OnClose(self
, evt
):
1783 # Make sure the default handler runs too so this window gets
1788 # if the timer is still running then go ahead and show the
1790 if self
.fc
.IsRunning():
1796 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
1798 if self
.fc
.IsRunning():
1802 class MyApp(wx
.App
):
1805 Create and show the splash screen. It will then create and show
1806 the main frame when it is time to do so.
1809 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
1812 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1814 # Normally when using a SplashScreen you would create it, show
1815 # it and then continue on with the applicaiton's
1816 # initialization, finally creating and showing the main
1817 # application window(s). In this case we have nothing else to
1818 # do so we'll delay showing the main frame until later (see
1819 # ShowMain above) so the users can see the SplashScreen effect.
1820 splash
= MySplashScreen()
1827 #---------------------------------------------------------------------------
1831 demoPath
= os
.path
.dirname(__file__
)
1838 #---------------------------------------------------------------------------
1841 mainOverview
= """<html><body>
1844 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1845 language. It allows Python programmers to create programs with a
1846 robust, highly functional graphical user interface, simply and easily.
1847 It is implemented as a Python extension module (native code) that
1848 wraps the popular wxWindows cross platform GUI library, which is
1851 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1852 means that it is free for anyone to use and the source code is
1853 available for anyone to look at and modify. Or anyone can contribute
1854 fixes or enhancements to the project.
1856 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1857 same program will run on multiple platforms without modification.
1858 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1859 or unix-like systems, and Macintosh OS X. Since the language is
1860 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1863 <p> <b>This demo</b> is not only a collection of test cases for
1864 wxPython, but is also designed to help you learn about and how to use
1865 wxPython. Each sample is listed in the tree control on the left.
1866 When a sample is selected in the tree then a module is loaded and run
1867 (usually in a tab of this notebook,) and the source code of the module
1868 is loaded in another tab for you to browse and learn from.
1873 #----------------------------------------------------------------------------
1874 #----------------------------------------------------------------------------
1876 if __name__
== '__main__':
1880 #----------------------------------------------------------------------------