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....
22 # AG: It looks like this issue is fixed by Freeze()ing and Thaw()ing the
23 # main frame and not the notebook
26 # * UI design more professional (is the new version more professional?)
27 # * save file positions (new field in demoModules) (@ LoadDemoSource)
28 # * Update main overview
30 # * Why don't we move _treeList into a separate module
32 import sys
, os
, time
, traceback
, types
34 import wx
# This module uses the new wx namespace
42 ##print "wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi')
43 ##print "pid:", os.getpid()
44 ##raw_input("Press Enter...")
47 #---------------------------------------------------------------------------
49 USE_CUSTOMTREECTRL
= False
50 ALLOW_AUI_FLOATING
= False
51 DEFAULT_PERSPECTIVE
= "Default Perspective"
53 #---------------------------------------------------------------------------
55 _demoPngs
= ["overview", "recent", "frame", "dialog", "moredialog", "core",
56 "book", "customcontrol", "morecontrols", "layout", "process", "clipboard",
57 "images", "miscellaneous"]
61 ('Recent Additions/Updates', [
64 # managed windows == things with a (optional) caption you can close
65 ('Frames and Dialogs', [
66 'AUI_DockingWindowMgr',
92 # dialogs from libraries
95 'ScrolledMessageDialog',
99 ('Core Windows/Controls', [
137 ('"Book" Controls', [
146 ('Custom Controls', [
163 # controls coming from other libraries
164 ('More Windows/Controls', [
165 'ActiveX_FlashWindow',
166 'ActiveX_IEHtmlWindow',
171 'CheckListCtrlMixin',
188 'MaskedEditControls',
191 'MultiSplitterWindow',
192 'OwnerDrawnComboBox',
210 # How to lay out the controls in a frame/dialog
221 'XmlResourceHandler',
222 'XmlResourceSubclass',
226 ('Process and Events', [
234 ##'infoframe', # needs better explanation and some fixing
238 ('Clipboard and DnD', [
265 ##'DialogUnits', # needs more explanations
286 ('Check out the samples dir too', [
293 #---------------------------------------------------------------------------
294 # Show how to derive a custom wxLog class
296 class MyLog(wx
.PyLog
):
297 def __init__(self
, textCtrl
, logTime
=0):
298 wx
.PyLog
.__init
__(self
)
300 self
.logTime
= logTime
302 def DoLogString(self
, message
, timeStamp
):
303 #print message, timeStamp
305 # message = time.strftime("%X", time.localtime(timeStamp)) + \
308 self
.tc
.AppendText(message
+ '\n')
311 class MyTP(wx
.PyTipProvider
):
313 return "This is my tip"
315 #---------------------------------------------------------------------------
316 # A class to be used to simply display a message in the demo pane
317 # rather than running the sample itself.
319 class MessagePanel(wx
.Panel
):
320 def __init__(self
, parent
, message
, caption
='', flags
=0):
321 wx
.Panel
.__init
__(self
, parent
)
326 if flags
& wx
.ICON_EXCLAMATION
:
327 artid
= wx
.ART_WARNING
328 elif flags
& wx
.ICON_ERROR
:
330 elif flags
& wx
.ICON_QUESTION
:
331 artid
= wx
.ART_QUESTION
332 elif flags
& wx
.ICON_INFORMATION
:
333 artid
= wx
.ART_INFORMATION
335 if artid
is not None:
336 bmp
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32))
337 icon
= wx
.StaticBitmap(self
, -1, bmp
)
339 icon
= (32,32) # make a spacer instead
342 caption
= wx
.StaticText(self
, -1, caption
)
343 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
345 message
= wx
.StaticText(self
, -1, message
)
347 # add to sizers for layout
348 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
354 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
361 box
= wx
.BoxSizer(wx
.VERTICAL
)
363 box
.Add(hbox
, 0, wx
.EXPAND
)
370 #---------------------------------------------------------------------------
371 # A class to be used to display source code in the demo. Try using the
372 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
373 # if there is an error, such as the stc module not being present.
377 ##raise ImportError # for testing the alternate implementation
379 from StyledTextCtrl_2
import PythonSTC
381 class DemoCodeEditor(PythonSTC
):
382 def __init__(self
, parent
):
383 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
386 # Some methods to make it compatible with how the wxTextCtrl is used
387 def SetValue(self
, value
):
389 value
= value
.decode('iso8859_1')
391 self
.EmptyUndoBuffer()
394 def IsModified(self
):
395 return self
.GetModify()
400 def SetInsertionPoint(self
, pos
):
401 self
.SetCurrentPos(pos
)
404 def ShowPosition(self
, pos
):
405 line
= self
.LineFromPosition(pos
)
406 #self.EnsureVisible(line)
409 def GetLastPosition(self
):
410 return self
.GetLength()
412 def GetPositionFromLine(self
, line
):
413 return self
.PositionFromLine(line
)
415 def GetRange(self
, start
, end
):
416 return self
.GetTextRange(start
, end
)
418 def GetSelection(self
):
419 return self
.GetAnchor(), self
.GetCurrentPos()
421 def SetSelection(self
, start
, end
):
422 self
.SetSelectionStart(start
)
423 self
.SetSelectionEnd(end
)
425 def SelectLine(self
, line
):
426 start
= self
.PositionFromLine(line
)
427 end
= self
.GetLineEndPosition(line
)
428 self
.SetSelection(start
, end
)
430 def SetUpEditor(self
):
432 This method carries out the work of setting up the demo editor.
433 It's seperate so as not to clutter up the init code.
437 self
.SetLexer(stc
.STC_LEX_PYTHON
)
438 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
441 self
.SetProperty("fold", "1" )
443 # Highlight tab/space mixing (shouldn't be any)
444 self
.SetProperty("tab.timmy.whinge.level", "1")
446 # Set left and right margins
449 # Set up the numbers in the margin for margin #1
450 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
451 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
452 self
.SetMarginWidth(1, 40)
454 # Indentation and tab stuff
455 self
.SetIndent(4) # Proscribed indent size for wx
456 self
.SetIndentationGuides(True) # Show indent guides
457 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
458 self
.SetTabIndents(True) # Tab key indents
459 self
.SetTabWidth(4) # Proscribed tab size for wx
460 self
.SetUseTabs(False) # Use spaces rather than tabs, or
461 # TabTimmy will complain!
463 self
.SetViewWhiteSpace(False) # Don't view white space
465 # EOL: Since we are loading/saving ourselves, and the
466 # strings will always have \n's in them, set the STC to
467 # edit them that way.
468 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
469 self
.SetViewEOL(False)
471 # No right-edge mode indicator
472 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
474 # Setup a margin to hold fold markers
475 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
476 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
477 self
.SetMarginSensitive(2, True)
478 self
.SetMarginWidth(2, 12)
480 # and now set up the fold markers
481 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
482 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
483 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
484 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
485 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
486 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
487 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
489 # Global default style
490 if wx
.Platform
== '__WXMSW__':
491 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
492 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
493 elif wx
.Platform
== '__WXMAC__':
494 # TODO: if this looks fine on Linux too, remove the Mac-specific case
495 # and use this whenever OS != MSW.
496 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
497 'fore:#000000,back:#FFFFFF,face:Courier')
499 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
500 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
502 # Clear styles and revert to default.
505 # Following style specs only indicate differences from default.
506 # The rest remains unchanged.
508 # Line numbers in margin
509 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
511 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
513 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
515 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
518 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
520 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
521 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
523 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
524 # Strings and characters
525 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
526 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
528 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
530 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
531 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
533 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
535 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
537 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
538 # Identifiers. I leave this as not bold because everything seems
539 # to be an identifier if it doesn't match the above criterae
540 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
543 self
.SetCaretForeground("BLUE")
544 # Selection background
545 self
.SetSelBackground(1, '#66CCFF')
547 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
548 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
550 def RegisterModifiedEvent(self
, eventHandler
):
551 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
555 class DemoCodeEditor(wx
.TextCtrl
):
556 def __init__(self
, parent
):
557 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
558 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
560 def RegisterModifiedEvent(self
, eventHandler
):
561 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
563 def SetReadOnly(self
, flag
):
564 self
.SetEditable(not flag
)
565 # NOTE: STC already has this method
568 return self
.GetValue()
570 def GetPositionFromLine(self
, line
):
571 return self
.XYToPosition(0,line
)
573 def GotoLine(self
, line
):
574 pos
= self
.GetPositionFromLine(line
)
575 self
.SetInsertionPoint(pos
)
576 self
.ShowPosition(pos
)
578 def SelectLine(self
, line
):
579 start
= self
.GetPositionFromLine(line
)
580 end
= start
+ self
.GetLineLength(line
)
581 self
.SetSelection(start
, end
)
584 #---------------------------------------------------------------------------
585 # Constants for module versions
589 modDefault
= modOriginal
591 #---------------------------------------------------------------------------
593 class DemoCodePanel(wx
.Panel
):
594 """Panel for the 'Demo Code' tab"""
595 def __init__(self
, parent
, mainFrame
):
596 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
597 if 'wxMSW' in wx
.PlatformInfo
:
599 self
.mainFrame
= mainFrame
600 self
.editor
= DemoCodeEditor(self
)
601 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
603 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
604 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
605 self
.btnSave
.Enable(False)
606 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
607 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
609 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
610 modModified
: wx
.RadioButton(self
, -1, "Modified") }
612 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
613 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
614 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
615 for modID
, radioButton
in self
.radioButtons
.items():
616 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
617 radioButton
.modID
= modID
# makes it easier for the event handler
618 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
620 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
621 self
.controlBox
.Add(self
.btnRestore
, 0)
623 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
624 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
625 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
626 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
629 self
.SetSizer(self
.box
)
632 # Loads a demo from a DemoModules object
633 def LoadDemo(self
, demoModules
):
634 self
.demoModules
= demoModules
635 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
636 demoModules
.SetActive(modModified
)
638 demoModules
.SetActive(modOriginal
)
639 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
640 self
.ActiveModuleChanged()
643 def ActiveModuleChanged(self
):
644 self
.LoadDemoSource(self
.demoModules
.GetSource())
645 self
.UpdateControlState()
646 self
.mainFrame
.Freeze()
648 self
.mainFrame
.Thaw()
651 def LoadDemoSource(self
, source
):
653 self
.editor
.SetValue(source
)
655 self
.btnSave
.Enable(False)
658 def JumpToLine(self
, line
, highlight
=False):
659 self
.editor
.GotoLine(line
)
660 self
.editor
.SetFocus()
662 self
.editor
.SelectLine(line
)
665 def UpdateControlState(self
):
666 active
= self
.demoModules
.GetActiveID()
667 # Update the radio/restore buttons
668 for moduleID
in self
.radioButtons
:
669 btn
= self
.radioButtons
[moduleID
]
670 if moduleID
== active
:
675 if self
.demoModules
.Exists(moduleID
):
677 if moduleID
== modModified
:
678 self
.btnRestore
.Enable(True)
681 if moduleID
== modModified
:
682 self
.btnRestore
.Enable(False)
685 def OnRadioButton(self
, event
):
686 radioSelected
= event
.GetEventObject()
687 modSelected
= radioSelected
.modID
688 if modSelected
!= self
.demoModules
.GetActiveID():
689 busy
= wx
.BusyInfo("Reloading demo module...")
690 self
.demoModules
.SetActive(modSelected
)
691 self
.ActiveModuleChanged()
694 def ReloadDemo(self
):
695 if self
.demoModules
.name
!= __name__
:
696 self
.mainFrame
.RunModule()
699 def OnCodeModified(self
, event
):
700 self
.btnSave
.Enable(self
.editor
.IsModified())
703 def OnSave(self
, event
):
704 if self
.demoModules
.Exists(modModified
):
705 if self
.demoModules
.GetActiveID() == modOriginal
:
706 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
707 "Do you want to continue?"
708 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
709 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
710 result
= dlg
.ShowModal()
711 if result
== wx
.ID_NO
:
715 self
.demoModules
.SetActive(modModified
)
716 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
718 # Create the demo directory if one doesn't already exist
719 if not os
.path
.exists(GetModifiedDirectory()):
721 os
.makedirs(GetModifiedDirectory())
722 if not os
.path
.exists(GetModifiedDirectory()):
723 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
726 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
729 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
732 f
= open(modifiedFilename
, "wt")
733 source
= self
.editor
.GetText()
739 busy
= wx
.BusyInfo("Reloading demo module...")
740 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
741 self
.ActiveModuleChanged()
743 self
.mainFrame
.SetTreeModified(True)
746 def OnRestore(self
, event
): # Handles the "Delete Modified" button
747 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
748 self
.demoModules
.Delete(modModified
)
749 os
.unlink(modifiedFilename
) # Delete the modified copy
750 busy
= wx
.BusyInfo("Reloading demo module...")
752 self
.ActiveModuleChanged()
754 self
.mainFrame
.SetTreeModified(False)
757 #---------------------------------------------------------------------------
760 """Convert paths to the platform-specific separator"""
761 st
= apply(os
.path
.join
, tuple(path
.split('/')))
762 # HACK: on Linux, a leading / gets lost...
763 if path
.startswith('/'):
770 Return the standard location on this platform for application data
772 sp
= wx
.StandardPaths
.Get()
773 return sp
.GetUserDataDir()
776 def GetModifiedDirectory():
778 Returns the directory where modified versions of the demo files
781 return os
.path
.join(GetDataDir(), "modified")
784 def GetModifiedFilename(name
):
786 Returns the filename of the modified version of the specified demo
788 if not name
.endswith(".py"):
790 return os
.path
.join(GetModifiedDirectory(), name
)
793 def GetOriginalFilename(name
):
795 Returns the filename of the original version of the specified demo
797 if not name
.endswith(".py"):
802 def DoesModifiedExist(name
):
803 """Returns whether the specified demo has a modified copy"""
804 if os
.path
.exists(GetModifiedFilename(name
)):
811 if not os
.path
.exists(GetDataDir()):
812 os
.makedirs(GetDataDir())
814 config
= wx
.FileConfig(
815 localFilename
=os
.path
.join(GetDataDir(), "options"))
819 def SearchDemo(name
, keyword
):
820 """ Returns whether a demo contains the search keyword or not. """
821 fid
= open(GetOriginalFilename(name
), "rt")
822 fullText
= fid
.read()
824 if fullText
.find(keyword
) >= 0:
829 #---------------------------------------------------------------------------
831 class ModuleDictWrapper
:
832 """Emulates a module with a dynamically compiled __dict__"""
833 def __init__(self
, dict):
836 def __getattr__(self
, name
):
837 if name
in self
.dict:
838 return self
.dict[name
]
844 Dynamically manages the original/modified versions of a demo
847 def __init__(self
, name
):
851 # (dict , source , filename , description , error information )
852 # ( 0 , 1 , 2 , 3 , 4 )
853 self
.modules
= [[None, "" , "" , "<original>" , None],
854 [None, "" , "" , "<modified>" , None]]
856 # load original module
857 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
858 self
.SetActive(modOriginal
)
860 # load modified module (if one exists)
861 if DoesModifiedExist(name
):
862 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
865 def LoadFromFile(self
, modID
, filename
):
866 self
.modules
[modID
][2] = filename
867 file = open(filename
, "rt")
868 self
.LoadFromSource(modID
, file.read())
872 def LoadFromSource(self
, modID
, source
):
873 self
.modules
[modID
][1] = source
877 def LoadDict(self
, modID
):
878 if self
.name
!= __name__
:
879 source
= self
.modules
[modID
][1]
880 #description = self.modules[modID][3]
881 description
= self
.modules
[modID
][2]
884 self
.modules
[modID
][0] = {}
885 code
= compile(source
, description
, "exec")
886 exec code
in self
.modules
[modID
][0]
888 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
889 self
.modules
[modID
][0] = None
891 self
.modules
[modID
][4] = None
894 def SetActive(self
, modID
):
895 if modID
!= modOriginal
and modID
!= modModified
:
898 self
.modActive
= modID
902 dict = self
.modules
[self
.modActive
][0]
906 return ModuleDictWrapper(dict)
909 def GetActiveID(self
):
910 return self
.modActive
913 def GetSource(self
, modID
= None):
915 modID
= self
.modActive
916 return self
.modules
[modID
][1]
919 def GetFilename(self
, modID
= None):
921 modID
= self
.modActive
922 return self
.modules
[self
.modActive
][2]
925 def GetErrorInfo(self
, modID
= None):
927 modID
= self
.modActive
928 return self
.modules
[self
.modActive
][4]
931 def Exists(self
, modID
):
932 return self
.modules
[modID
][1] != ""
935 def UpdateFile(self
, modID
= None):
936 """Updates the file from which a module was loaded
937 with (possibly updated) source"""
939 modID
= self
.modActive
941 source
= self
.modules
[modID
][1]
942 filename
= self
.modules
[modID
][2]
945 file = open(filename
, "wt")
951 def Delete(self
, modID
):
952 if self
.modActive
== modID
:
955 self
.modules
[modID
][0] = None
956 self
.modules
[modID
][1] = ""
957 self
.modules
[modID
][2] = ""
960 #---------------------------------------------------------------------------
963 """Wraps and stores information about the current exception"""
964 def __init__(self
, exc_info
):
967 excType
, excValue
= exc_info
[:2]
968 # traceback list entries: (filename, line number, function name, text)
969 self
.traceback
= traceback
.extract_tb(exc_info
[2])
971 # --Based on traceback.py::format_exception_only()--
972 if type(excType
) == types
.ClassType
:
973 self
.exception_type
= excType
.__name
__
975 self
.exception_type
= excType
977 # If it's a syntax error, extra information needs
978 # to be added to the traceback
979 if excType
is SyntaxError:
981 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
986 filename
= "<string>"
988 self
.traceback
.append( (filename
, lineno
, "", line
) )
991 self
.exception_details
= str(excValue
)
993 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
1000 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
1003 #---------------------------------------------------------------------------
1005 class DemoErrorPanel(wx
.Panel
):
1006 """Panel put into the demo tab when the demo fails to run due to errors"""
1008 def __init__(self
, parent
, codePanel
, demoError
, log
):
1009 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
1010 self
.codePanel
= codePanel
1014 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
1017 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo")
1018 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
1020 # Exception Information
1021 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
1022 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
1023 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
1024 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
1025 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
1026 boxInfoGrid
.Add(wx
.StaticText(self
, -1, str(demoError
.exception_type
)) , 0, textFlags
, 5 )
1027 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
1028 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
1029 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
1030 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
1032 # Set up the traceback list
1033 # This one automatically resizes last column to take up remaining space
1034 from ListCtrl
import TestListCtrl
1035 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
1036 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
1037 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
1038 self
.list.InsertColumn(0, "Filename")
1039 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
1040 self
.list.InsertColumn(2, "Function")
1041 self
.list.InsertColumn(3, "Code")
1042 self
.InsertTraceback(self
.list, demoError
.traceback
)
1043 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
1044 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
1045 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
1046 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
1047 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
1048 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
1049 + "Double-click on them to go to the offending line")
1050 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
1053 self
.SetSizer(self
.box
)
1056 def InsertTraceback(self
, list, traceback
):
1057 #Add the traceback data
1058 for x
in range(len(traceback
)):
1060 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
1061 list.SetStringItem(x
, 1, str(data
[1])) # Line
1062 list.SetStringItem(x
, 2, str(data
[2])) # Function
1063 list.SetStringItem(x
, 3, str(data
[3])) # Code
1065 # Check whether this entry is from the demo module
1066 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
1067 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
1068 # Give it a blue colour
1069 item
= self
.list.GetItem(x
)
1070 item
.SetTextColour(wx
.BLUE
)
1071 self
.list.SetItem(item
)
1073 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
1076 def OnItemSelected(self
, event
):
1077 # This occurs before OnDoubleClick and can be used to set the
1078 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1079 self
.currentItem
= event
.m_itemIndex
1083 def OnDoubleClick(self
, event
):
1084 # If double-clicking on a demo's entry, jump to the line number
1085 line
= self
.list.GetItemData(self
.currentItem
)
1087 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1088 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1092 #---------------------------------------------------------------------------
1094 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1095 TBMENU_RESTORE
= wx
.NewId()
1096 TBMENU_CLOSE
= wx
.NewId()
1097 TBMENU_CHANGE
= wx
.NewId()
1098 TBMENU_REMOVE
= wx
.NewId()
1100 def __init__(self
, frame
):
1101 wx
.TaskBarIcon
.__init
__(self
)
1105 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1106 self
.SetIcon(icon
, "wxPython Demo")
1110 self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1111 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1112 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1113 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
)
1114 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
)
1117 def CreatePopupMenu(self
):
1119 This method is called by the base class when it needs to popup
1120 the menu for the default EVT_RIGHT_DOWN event. Just create
1121 the menu how you want it and return it from this function,
1122 the base class takes care of the rest.
1125 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1126 menu
.Append(self
.TBMENU_CLOSE
, "Close wxPython Demo")
1127 menu
.AppendSeparator()
1128 menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon")
1129 menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon")
1133 def MakeIcon(self
, img
):
1135 The various platforms have different requirements for the
1138 if "wxMSW" in wx
.PlatformInfo
:
1139 img
= img
.Scale(16, 16)
1140 elif "wxGTK" in wx
.PlatformInfo
:
1141 img
= img
.Scale(22, 22)
1142 # wxMac can be any size upto 128x128, so leave the source img alone....
1143 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
1147 def OnTaskBarActivate(self
, evt
):
1148 if self
.frame
.IsIconized():
1149 self
.frame
.Iconize(False)
1150 if not self
.frame
.IsShown():
1151 self
.frame
.Show(True)
1155 def OnTaskBarClose(self
, evt
):
1159 def OnTaskBarChange(self
, evt
):
1160 names
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
1161 name
= names
[self
.imgidx
]
1163 getFunc
= getattr(images
, "get%sImage" % name
)
1165 if self
.imgidx
>= len(names
):
1168 icon
= self
.MakeIcon(getFunc())
1169 self
.SetIcon(icon
, "This is a new icon: " + name
)
1172 def OnTaskBarRemove(self
, evt
):
1176 #---------------------------------------------------------------------------
1177 class wxPythonDemo(wx
.Frame
):
1178 overviewText
= "wxPython Overview"
1180 def __init__(self
, parent
, title
):
1181 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (970, 720),
1182 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1184 self
.SetMinSize((640,480))
1186 self
.mgr
= wx
.aui
.AuiManager()
1187 self
.mgr
.SetManagedWindow(self
)
1190 self
.cwd
= os
.getcwd()
1191 self
.curOverview
= ""
1192 self
.demoPage
= None
1193 self
.codePage
= None
1195 self
.firstTime
= True
1198 icon
= images
.getWXPdemoIcon()
1202 self
.tbicon
= DemoTaskBarIcon(self
)
1206 self
.otherWin
= None
1207 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1208 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1209 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1210 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1212 self
.Centre(wx
.BOTH
)
1213 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1216 self
.skipLoad
= False
1218 def EmptyHandler(evt
): pass
1220 self
.ReadConfigurationFile()
1223 self
.nb
= wx
.Notebook(self
, -1, style
=wx
.CLIP_CHILDREN
)
1224 imgList
= wx
.ImageList(16, 16)
1225 for png
in ["overview", "code", "demo"]:
1226 bmp
= images
.catalog
[png
].getBitmap()
1228 self
.nb
.AssignImageList(imgList
)
1232 self
.finddata
= wx
.FindReplaceData()
1233 self
.finddata
.SetFlags(wx
.FR_DOWN
)
1236 leftPanel
= wx
.Panel(self
, style
=wx
.TAB_TRAVERSAL|wx
.CLIP_CHILDREN
)
1238 self
.searchItems
= {}
1240 self
.tree
= wxPythonDemoTree(leftPanel
)
1242 self
.filter = wx
.SearchCtrl(leftPanel
, style
=wx
.TE_PROCESS_ENTER
)
1243 self
.filter.ShowCancelButton(True)
1244 self
.filter.Bind(wx
.EVT_TEXT
, self
.RecreateTree
)
1245 self
.filter.Bind(wx
.EVT_SEARCHCTRL_CANCEL_BTN
,
1246 lambda e
: self
.filter.SetValue(''))
1247 self
.filter.Bind(wx
.EVT_TEXT_ENTER
, self
.OnSearch
)
1249 searchMenu
= wx
.Menu()
1250 item
= searchMenu
.AppendRadioItem(-1, "Sample Name")
1251 self
.Bind(wx
.EVT_MENU
, self
.OnSearchMenu
, item
)
1252 item
= searchMenu
.AppendRadioItem(-1, "Sample Content")
1253 self
.Bind(wx
.EVT_MENU
, self
.OnSearchMenu
, item
)
1254 self
.filter.SetMenu(searchMenu
)
1257 self
.tree
.SetExpansionState(self
.expansionState
)
1258 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
)
1259 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
)
1260 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
)
1261 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1263 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1264 # we put it in a panel first because there seems to be a
1265 # refresh bug of some sort (wxGTK) when it is directly in
1269 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1270 self
.nb
.AddPage(self
.ovr
, self
.overviewText
, imageId
=0)
1272 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1273 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1274 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1275 self
.nb
.AddPage(panel
, self
.overviewText
, imageId
=0)
1277 def OnOvrSize(evt
, ovr
=self
.ovr
):
1278 ovr
.SetSize(evt
.GetSize())
1279 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1280 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1282 if "gtk2" in wx
.PlatformInfo
:
1283 self
.ovr
.SetStandardFonts()
1284 self
.SetOverview(self
.overviewText
, mainOverview
)
1287 # Set up a log window
1288 self
.log
= wx
.TextCtrl(self
, -1,
1289 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1290 if wx
.Platform
== "__WXMAC__":
1291 self
.log
.MacCheckSpelling(False)
1293 # Set the wxWindows log target to be this textctrl
1294 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1296 # But instead of the above we want to show how to use our own wx.Log class
1297 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1299 # for serious debugging
1300 #wx.Log_SetActiveTarget(wx.LogStderr())
1301 #wx.Log_SetTraceMask(wx.TraceMessages)
1303 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1304 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1306 # add the windows to the splitter and split it.
1307 leftBox
= wx
.BoxSizer(wx
.VERTICAL
)
1308 leftBox
.Add(self
.tree
, 1, wx
.EXPAND
)
1309 leftBox
.Add(wx
.StaticText(leftPanel
, label
= "Filter Demos:"), 0, wx
.TOP|wx
.LEFT
, 5)
1310 leftBox
.Add(self
.filter, 0, wx
.EXPAND|wx
.ALL
, 5)
1311 leftPanel
.SetSizer(leftBox
)
1313 # select initial items
1314 self
.nb
.SetSelection(0)
1315 self
.tree
.SelectItem(self
.root
)
1317 # Load 'Main' module
1318 self
.LoadDemo(self
.overviewText
)
1321 # select some other initial module?
1322 if len(sys
.argv
) > 1:
1324 if arg
.endswith('.py'):
1326 selectedDemo
= self
.treeMap
.get(arg
, None)
1328 self
.tree
.SelectItem(selectedDemo
)
1329 self
.tree
.EnsureVisible(selectedDemo
)
1331 # Use the aui manager to set up everything
1332 self
.mgr
.AddPane(self
.nb
, wx
.aui
.AuiPaneInfo().CenterPane().Name("Notebook"))
1333 self
.mgr
.AddPane(leftPanel
,
1334 wx
.aui
.AuiPaneInfo().
1335 Left().Layer(2).BestSize((240, -1)).
1337 Floatable(ALLOW_AUI_FLOATING
).FloatingSize((240, 700)).
1338 Caption("wxPython Demos").
1341 self
.mgr
.AddPane(self
.log
,
1342 wx
.aui
.AuiPaneInfo().
1343 Bottom().BestSize((-1, 150)).
1345 Floatable(ALLOW_AUI_FLOATING
).FloatingSize((500, 160)).
1346 Caption("Demo Log Messages").
1350 self
.auiConfigurations
[DEFAULT_PERSPECTIVE
] = self
.mgr
.SavePerspective()
1353 self
.mgr
.SetFlags(self
.mgr
.GetFlags() ^ wx
.aui
.AUI_MGR_TRANSPARENT_DRAG
)
1357 def ReadConfigurationFile(self
):
1359 self
.auiConfigurations
= {}
1360 self
.expansionState
= [0, 1]
1362 config
= GetConfig()
1363 val
= config
.Read('ExpansionState')
1365 self
.expansionState
= eval(val
)
1367 val
= config
.Read('AUIPerspectives')
1369 self
.auiConfigurations
= eval(val
)
1372 def BuildMenuBar(self
):
1375 self
.mainmenu
= wx
.MenuBar()
1377 item
= menu
.Append(-1, '&Redirect Output',
1378 'Redirect print statements to a window',
1380 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1382 exitItem
= wx
.MenuItem(menu
, -1, 'E&xit\tCtrl-Q', 'Get the heck outta here!')
1383 exitItem
.SetBitmap(images
.catalog
['exit'].getBitmap())
1384 menu
.AppendItem(exitItem
)
1385 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, exitItem
)
1386 wx
.App
.SetMacExitMenuItemId(exitItem
.GetId())
1387 self
.mainmenu
.Append(menu
, '&File')
1391 for indx
, item
in enumerate(_treeList
[:-1]):
1392 menuItem
= wx
.MenuItem(menu
, -1, item
[0])
1394 for childItem
in item
[1]:
1395 mi
= submenu
.Append(-1, childItem
)
1396 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1397 menuItem
.SetBitmap(images
.catalog
[_demoPngs
[indx
+1]].getBitmap())
1398 menuItem
.SetSubMenu(submenu
)
1399 menu
.AppendItem(menuItem
)
1400 self
.mainmenu
.Append(menu
, '&Demo')
1402 # Make an Option menu
1403 # If we've turned off floatable panels then this menu is not needed
1404 if ALLOW_AUI_FLOATING
:
1406 auiPerspectives
= self
.auiConfigurations
.keys()
1407 auiPerspectives
.sort()
1408 perspectivesMenu
= wx
.Menu()
1409 item
= wx
.MenuItem(perspectivesMenu
, -1, DEFAULT_PERSPECTIVE
, "Load startup default perspective", wx
.ITEM_RADIO
)
1410 self
.Bind(wx
.EVT_MENU
, self
.OnAUIPerspectives
, item
)
1411 perspectivesMenu
.AppendItem(item
)
1412 for indx
, key
in enumerate(auiPerspectives
):
1413 if key
== DEFAULT_PERSPECTIVE
:
1415 item
= wx
.MenuItem(perspectivesMenu
, -1, key
, "Load user perspective %d"%indx
, wx
.ITEM_RADIO
)
1416 perspectivesMenu
.AppendItem(item
)
1417 self
.Bind(wx
.EVT_MENU
, self
.OnAUIPerspectives
, item
)
1419 menu
.AppendMenu(wx
.ID_ANY
, "&AUI Perspectives", perspectivesMenu
)
1420 self
.perspectives_menu
= perspectivesMenu
1422 item
= wx
.MenuItem(menu
, -1, 'Save Perspective', 'Save AUI perspective')
1423 item
.SetBitmap(images
.catalog
['saveperspective'].getBitmap())
1424 menu
.AppendItem(item
)
1425 self
.Bind(wx
.EVT_MENU
, self
.OnSavePerspective
, item
)
1427 item
= wx
.MenuItem(menu
, -1, 'Delete Perspective', 'Delete AUI perspective')
1428 item
.SetBitmap(images
.catalog
['deleteperspective'].getBitmap())
1429 menu
.AppendItem(item
)
1430 self
.Bind(wx
.EVT_MENU
, self
.OnDeletePerspective
, item
)
1432 menu
.AppendSeparator()
1434 item
= wx
.MenuItem(menu
, -1, 'Restore Tree Expansion', 'Restore the initial tree expansion state')
1435 item
.SetBitmap(images
.catalog
['expansion'].getBitmap())
1436 menu
.AppendItem(item
)
1437 self
.Bind(wx
.EVT_MENU
, self
.OnTreeExpansion
, item
)
1439 self
.mainmenu
.Append(menu
, '&Options')
1443 findItem
= wx
.MenuItem(menu
, -1, '&Find\tCtrl-F', 'Find in the Demo Code')
1444 findItem
.SetBitmap(images
.catalog
['find'].getBitmap())
1445 if 'wxMac' not in wx
.PlatformInfo
:
1446 findNextItem
= wx
.MenuItem(menu
, -1, 'Find &Next\tF3', 'Find Next')
1448 findNextItem
= wx
.MenuItem(menu
, -1, 'Find &Next\tCtrl-G', 'Find Next')
1449 findNextItem
.SetBitmap(images
.catalog
['findnext'].getBitmap())
1450 menu
.AppendItem(findItem
)
1451 menu
.AppendItem(findNextItem
)
1452 menu
.AppendSeparator()
1454 shellItem
= wx
.MenuItem(menu
, -1, 'Open Py&Shell Window\tF5',
1455 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1456 shellItem
.SetBitmap(images
.catalog
['pyshell'].getBitmap())
1457 menu
.AppendItem(shellItem
)
1458 inspToolItem
= wx
.MenuItem(menu
, -1, 'Open &Widget Inspector\tF6',
1459 'A tool that lets you browse the live widgets and sizers in an application')
1460 inspToolItem
.SetBitmap(images
.catalog
['inspect'].getBitmap())
1461 menu
.AppendItem(inspToolItem
)
1462 if 'wxMac' not in wx
.PlatformInfo
:
1463 menu
.AppendSeparator()
1464 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1465 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1467 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1468 self
.Bind(wx
.EVT_MENU
, self
.OnOpenWidgetInspector
, inspToolItem
)
1469 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1470 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1471 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findNextItem
)
1472 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1473 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1474 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1475 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1476 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findNextItem
)
1477 self
.mainmenu
.Append(menu
, '&Help')
1478 self
.SetMenuBar(self
.mainmenu
)
1481 # This is another way to set Accelerators, in addition to
1482 # using the '\t<key>' syntax in the menu items.
1483 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitItem
.GetId()),
1484 (wx
.ACCEL_CTRL
, ord('H'), helpItem
.GetId()),
1485 (wx
.ACCEL_CTRL
, ord('F'), findItem
.GetId()),
1486 (wx
.ACCEL_NORMAL
, wx
.WXK_F3
, findnextItem
.GetId()),
1487 (wx
.ACCEL_NORMAL
, wx
.WXK_F9
, shellItem
.GetId()),
1489 self
.SetAcceleratorTable(aTable
)
1492 #---------------------------------------------
1493 def RecreateTree(self
, evt
=None):
1494 # Catch the search type (name or content)
1495 searchMenu
= self
.filter.GetMenu().GetMenuItems()
1496 fullSearch
= searchMenu
[1].IsChecked()
1500 # Do not`scan all the demo files for every char
1501 # the user input, use wx.EVT_TEXT_ENTER instead
1504 expansionState
= self
.tree
.GetExpansionState()
1507 item
= self
.tree
.GetSelection()
1509 prnt
= self
.tree
.GetItemParent(item
)
1511 current
= (self
.tree
.GetItemText(item
),
1512 self
.tree
.GetItemText(prnt
))
1515 self
.tree
.DeleteAllItems()
1516 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1517 self
.tree
.SetItemImage(self
.root
, 0)
1518 self
.tree
.SetItemPyData(self
.root
, 0)
1520 treeFont
= self
.tree
.GetFont()
1521 catFont
= self
.tree
.GetFont()
1523 # The old native treectrl on MSW has a bug where it doesn't
1524 # draw all of the text for an item if the font is larger than
1525 # the default. It seems to be clipping the item's label as if
1526 # it was the size of the same label in the default font.
1527 if 'wxMSW' not in wx
.PlatformInfo
or wx
.GetApp().GetComCtl32Version() >= 600:
1528 treeFont
.SetPointSize(treeFont
.GetPointSize()+2)
1529 treeFont
.SetWeight(wx
.BOLD
)
1530 catFont
.SetWeight(wx
.BOLD
)
1532 self
.tree
.SetItemFont(self
.root
, treeFont
)
1536 filter = self
.filter.GetValue()
1539 for category
, items
in _treeList
:
1543 items
= self
.searchItems
[category
]
1545 items
= [item
for item
in items
if filter.lower() in item
.lower()]
1547 child
= self
.tree
.AppendItem(self
.root
, category
, image
=count
)
1548 self
.tree
.SetItemFont(child
, catFont
)
1549 self
.tree
.SetItemPyData(child
, count
)
1550 if not firstChild
: firstChild
= child
1551 for childItem
in items
:
1553 if DoesModifiedExist(childItem
):
1554 image
= len(_demoPngs
)
1555 theDemo
= self
.tree
.AppendItem(child
, childItem
, image
=image
)
1556 self
.tree
.SetItemPyData(theDemo
, count
)
1557 self
.treeMap
[childItem
] = theDemo
1558 if current
and (childItem
, category
) == current
:
1559 selectItem
= theDemo
1562 self
.tree
.Expand(self
.root
)
1564 self
.tree
.Expand(firstChild
)
1566 self
.tree
.ExpandAll()
1567 elif expansionState
:
1568 self
.tree
.SetExpansionState(expansionState
)
1570 self
.skipLoad
= True
1571 self
.tree
.SelectItem(selectItem
)
1572 self
.skipLoad
= False
1575 self
.searchItems
= {}
1578 def OnSearchMenu(self
, event
):
1580 # Catch the search type (name or content)
1581 searchMenu
= self
.filter.GetMenu().GetMenuItems()
1582 fullSearch
= searchMenu
[1].IsChecked()
1590 def OnSearch(self
, event
=None):
1592 value
= self
.filter.GetValue()
1597 wx
.BeginBusyCursor()
1599 for category
, items
in _treeList
:
1600 self
.searchItems
[category
] = []
1601 for childItem
in items
:
1602 if SearchDemo(childItem
, value
):
1603 self
.searchItems
[category
].append(childItem
)
1609 def SetTreeModified(self
, modified
):
1610 item
= self
.tree
.GetSelection()
1612 image
= len(_demoPngs
)
1614 image
= self
.tree
.GetItemPyData(item
)
1615 self
.tree
.SetItemImage(item
, image
)
1618 def WriteText(self
, text
):
1619 if text
[-1:] == '\n':
1623 def write(self
, txt
):
1626 #---------------------------------------------
1627 def OnItemExpanded(self
, event
):
1628 item
= event
.GetItem()
1629 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1632 #---------------------------------------------
1633 def OnItemCollapsed(self
, event
):
1634 item
= event
.GetItem()
1635 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1638 #---------------------------------------------
1639 def OnTreeLeftDown(self
, event
):
1640 # reset the overview text if the tree item is clicked on again
1641 pt
= event
.GetPosition();
1642 item
, flags
= self
.tree
.HitTest(pt
)
1643 if item
== self
.tree
.GetSelection():
1644 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1647 #---------------------------------------------
1648 def OnSelChanged(self
, event
):
1649 if self
.dying
or not self
.loaded
or self
.skipLoad
:
1652 item
= event
.GetItem()
1653 itemText
= self
.tree
.GetItemText(item
)
1654 self
.LoadDemo(itemText
)
1656 #---------------------------------------------
1657 def LoadDemo(self
, demoName
):
1659 wx
.BeginBusyCursor()
1663 self
.ShutdownDemoModule()
1665 if demoName
== self
.overviewText
:
1666 # User selected the "wxPython Overview" node
1668 # Changing the main window at runtime not yet supported...
1669 self
.demoModules
= DemoModules(__name__
)
1670 self
.SetOverview(self
.overviewText
, mainOverview
)
1671 self
.LoadDemoSource()
1672 self
.UpdateNotebook(0)
1674 if os
.path
.exists(GetOriginalFilename(demoName
)):
1675 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1676 self
.demoModules
= DemoModules(demoName
)
1677 self
.LoadDemoSource()
1679 self
.SetOverview("wxPython", mainOverview
)
1680 self
.codePage
= None
1681 self
.UpdateNotebook(0)
1686 #---------------------------------------------
1687 def LoadDemoSource(self
):
1688 self
.codePage
= None
1689 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1690 self
.codePage
.LoadDemo(self
.demoModules
)
1692 #---------------------------------------------
1693 def RunModule(self
):
1694 """Runs the active module"""
1696 module
= self
.demoModules
.GetActive()
1697 self
.ShutdownDemoModule()
1700 # o The RunTest() for all samples must now return a window that can
1701 # be palced in a tab in the main notebook.
1702 # o If an error occurs (or has occurred before) an error tab is created.
1704 if module
is not None:
1705 wx
.LogMessage("Running demo module...")
1706 if hasattr(module
, "overview"):
1707 overviewText
= module
.overview
1710 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1712 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1713 DemoError(sys
.exc_info()), self
)
1715 bg
= self
.nb
.GetThemeBackgroundColour()
1717 self
.demoPage
.SetBackgroundColour(bg
)
1719 assert self
.demoPage
is not None, "runTest must return a window!"
1722 # There was a previous error in compiling or exec-ing
1723 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1724 self
.demoModules
.GetErrorInfo(), self
)
1726 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1729 # change to the demo page the first time a module is run
1730 self
.UpdateNotebook(2)
1731 self
.firstTime
= False
1733 # otherwise just stay on the same tab in case the user has changed to another one
1734 self
.UpdateNotebook()
1736 #---------------------------------------------
1737 def ShutdownDemoModule(self
):
1739 # inform the window that it's time to quit if it cares
1740 if hasattr(self
.demoPage
, "ShutdownDemo"):
1741 self
.demoPage
.ShutdownDemo()
1742 wx
.YieldIfNeeded() # in case the page has pending events
1743 self
.demoPage
= None
1745 #---------------------------------------------
1746 def UpdateNotebook(self
, select
= -1):
1751 def UpdatePage(page
, pageText
):
1754 for i
in range(nb
.GetPageCount()):
1755 if nb
.GetPageText(i
) == pageText
:
1763 nb
.AddPage(page
, pageText
, imageId
=nb
.GetPageCount())
1764 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1766 if nb
.GetPage(pagePos
) != page
:
1767 # Reload an existing page
1768 nb
.DeletePage(pagePos
)
1769 nb
.InsertPage(pagePos
, page
, pageText
, imageId
=pagePos
)
1770 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1772 # Excellent! No redraw/flicker
1773 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1776 nb
.DeletePage(pagePos
)
1777 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1779 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1782 select
= nb
.GetSelection()
1784 UpdatePage(self
.codePage
, "Demo Code")
1785 UpdatePage(self
.demoPage
, "Demo")
1787 if select
>= 0 and select
< nb
.GetPageCount():
1788 nb
.SetSelection(select
)
1792 #---------------------------------------------
1793 def SetOverview(self
, name
, text
):
1794 self
.curOverview
= text
1796 if lead
!= '<html>' and lead
!= '<HTML>':
1797 text
= '<br>'.join(text
.split('\n'))
1799 text
= text
.decode('iso8859_1')
1800 self
.ovr
.SetPage(text
)
1801 self
.nb
.SetPageText(0, name
)
1803 #---------------------------------------------
1805 def OnFileExit(self
, *event
):
1808 def OnToggleRedirect(self
, event
):
1812 print "Print statements and other standard output will now be directed to this window."
1815 print "Print statements and other standard output will now be sent to the usual location."
1818 def OnAUIPerspectives(self
, event
):
1819 perspective
= self
.perspectives_menu
.GetLabel(event
.GetId())
1820 self
.mgr
.LoadPerspective(self
.auiConfigurations
[perspective
])
1824 def OnSavePerspective(self
, event
):
1825 dlg
= wx
.TextEntryDialog(self
, "Enter a name for the new perspective:", "AUI Configuration")
1827 dlg
.SetValue(("Perspective %d")%(len(self
.auiConfigurations
)+1))
1828 if dlg
.ShowModal() != wx
.ID_OK
:
1831 perspectiveName
= dlg
.GetValue()
1832 menuItems
= self
.perspectives_menu
.GetMenuItems()
1833 for item
in menuItems
:
1834 if item
.GetLabel() == perspectiveName
:
1835 wx
.MessageBox("The selected perspective name:\n\n%s\n\nAlready exists."%perspectiveName
,
1836 "Error", style
=wx
.ICON_ERROR
)
1839 item
= wx
.MenuItem(self
.perspectives_menu
, -1, dlg
.GetValue(),
1840 "Load user perspective %d"%(len(self
.auiConfigurations
)+1),
1842 self
.Bind(wx
.EVT_MENU
, self
.OnAUIPerspectives
, item
)
1843 self
.perspectives_menu
.AppendItem(item
)
1845 self
.auiConfigurations
.update({dlg.GetValue(): self.mgr.SavePerspective()}
)
1848 def OnDeletePerspective(self
, event
):
1849 menuItems
= self
.perspectives_menu
.GetMenuItems()[1:]
1853 for item
in menuItems
:
1854 lst
.append(item
.GetLabel())
1856 dlg
= wx
.MultiChoiceDialog(self
,
1857 "Please select the perspectives\nyou would like to delete:",
1858 "Delete AUI Perspectives", lst
)
1860 if dlg
.ShowModal() == wx
.ID_OK
:
1861 selections
= dlg
.GetSelections()
1862 strings
= [lst
[x
] for x
in selections
]
1864 self
.auiConfigurations
.pop(sel
)
1865 item
= menuItems
[lst
.index(sel
)]
1866 if item
.IsChecked():
1868 self
.perspectives_menu
.GetMenuItems()[0].Check(True)
1869 self
.perspectives_menu
.DeleteItem(item
)
1873 self
.mgr
.LoadPerspective(self
.auiConfigurations
[DEFAULT_PERSPECTIVE
])
1877 def OnTreeExpansion(self
, event
):
1878 self
.tree
.SetExpansionState(self
.expansionState
)
1881 def OnHelpAbout(self
, event
):
1882 from About
import MyAboutBox
1883 about
= MyAboutBox(self
)
1887 def OnHelpFind(self
, event
):
1888 if self
.finddlg
!= None:
1891 self
.nb
.SetSelection(1)
1892 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1893 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1894 self
.finddlg
.Show(True)
1897 def OnUpdateFindItems(self
, evt
):
1898 evt
.Enable(self
.finddlg
== None)
1901 def OnFind(self
, event
):
1902 editor
= self
.codePage
.editor
1903 self
.nb
.SetSelection(1)
1904 end
= editor
.GetLastPosition()
1905 textstring
= editor
.GetRange(0, end
).lower()
1906 findstring
= self
.finddata
.GetFindString().lower()
1907 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1909 start
= editor
.GetSelection()[0]
1910 loc
= textstring
.rfind(findstring
, 0, start
)
1912 start
= editor
.GetSelection()[1]
1913 loc
= textstring
.find(findstring
, start
)
1914 if loc
== -1 and start
!= 0:
1915 # string not found, start at beginning
1918 loc
= textstring
.rfind(findstring
, 0, start
)
1921 loc
= textstring
.find(findstring
, start
)
1923 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1924 'Find String Not Found in Demo File',
1925 wx
.OK | wx
.ICON_INFORMATION
)
1930 self
.finddlg
.SetFocus()
1933 self
.finddlg
.Destroy()
1935 editor
.ShowPosition(loc
)
1936 editor
.SetSelection(loc
, loc
+ len(findstring
))
1940 def OnFindNext(self
, event
):
1941 if self
.finddata
.GetFindString():
1944 self
.OnHelpFind(event
)
1946 def OnFindClose(self
, event
):
1947 event
.GetDialog().Destroy()
1951 def OnOpenShellWindow(self
, evt
):
1953 # if it already exists then just make sure it's visible
1959 # Make a PyShell window
1961 namespace
= { 'wx' : wx
,
1962 'app' : wx
.GetApp(),
1965 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1966 self
.shell
.SetSize((640,480))
1969 # Hook the close event of the main frame window so that we
1970 # close the shell at the same time if it still exists
1971 def CloseShell(evt
):
1975 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1978 def OnOpenWidgetInspector(self
, evt
):
1979 # Activate the widget inspection tool
1980 from wx
.lib
.inspection
import InspectionTool
1981 if not InspectionTool().initialized
:
1982 InspectionTool().Init()
1984 # Find a widget to be selected in the tree. Use either the
1985 # one under the cursor, if any, or this frame.
1986 wnd
= wx
.FindWindowAtPointer()
1989 InspectionTool().Show(wnd
, True)
1992 #---------------------------------------------
1993 def OnCloseWindow(self
, event
):
1995 self
.demoPage
= None
1996 self
.codePage
= None
1997 self
.mainmenu
= None
1998 if self
.tbicon
is not None:
1999 self
.tbicon
.Destroy()
2001 config
= GetConfig()
2002 config
.Write('ExpansionState', str(self
.tree
.GetExpansionState()))
2003 config
.Write('AUIPerspectives', str(self
.auiConfigurations
))
2009 #---------------------------------------------
2010 def OnIdle(self
, event
):
2012 self
.otherWin
.Raise()
2013 self
.demoPage
= self
.otherWin
2014 self
.otherWin
= None
2017 #---------------------------------------------
2019 config
= GetConfig()
2020 showTipText
= config
.Read("tips")
2022 showTip
, index
= eval(showTipText
)
2024 showTip
, index
= (1, 0)
2027 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
2029 showTip
= wx
.ShowTip(self
, tp
)
2030 index
= tp
.GetCurrentTip()
2031 config
.Write("tips", str( (showTip
, index
) ))
2034 #---------------------------------------------
2035 def OnDemoMenu(self
, event
):
2037 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
2041 self
.tree
.SelectItem(selectedDemo
)
2042 self
.tree
.EnsureVisible(selectedDemo
)
2046 #---------------------------------------------
2047 def OnIconfiy(self
, evt
):
2048 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
2051 #---------------------------------------------
2052 def OnMaximize(self
, evt
):
2053 wx
.LogMessage("OnMaximize")
2056 #---------------------------------------------
2057 def OnActivate(self
, evt
):
2058 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
2061 #---------------------------------------------
2062 def OnAppActivate(self
, evt
):
2063 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
2066 #---------------------------------------------------------------------------
2067 #---------------------------------------------------------------------------
2069 class MySplashScreen(wx
.SplashScreen
):
2071 bmp
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
2072 wx
.SplashScreen
.__init
__(self
, bmp
,
2073 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
2075 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
2076 self
.fc
= wx
.FutureCall(2000, self
.ShowMain
)
2079 def OnClose(self
, evt
):
2080 # Make sure the default handler runs too so this window gets
2085 # if the timer is still running then go ahead and show the
2087 if self
.fc
.IsRunning():
2093 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
2095 if self
.fc
.IsRunning():
2097 wx
.CallAfter(frame
.ShowTip
)
2102 #---------------------------------------------------------------------------
2104 from wx
.lib
.mixins
.treemixin
import ExpansionState
2105 if USE_CUSTOMTREECTRL
:
2106 import wx
.lib
.customtreectrl
as CT
2107 TreeBaseClass
= CT
.CustomTreeCtrl
2109 TreeBaseClass
= wx
.TreeCtrl
2112 class wxPythonDemoTree(ExpansionState
, TreeBaseClass
):
2113 def __init__(self
, parent
):
2114 TreeBaseClass
.__init
__(self
, parent
, style
=wx
.TR_DEFAULT_STYLE|
2115 wx
.TR_HAS_VARIABLE_ROW_HEIGHT
)
2116 self
.BuildTreeImageList()
2117 if USE_CUSTOMTREECTRL
:
2119 self
.SetWindowStyle(self
.GetWindowStyle() & ~wx
.TR_LINES_AT_ROOT
)
2121 def AppendItem(self
, parent
, text
, image
=-1, wnd
=None):
2122 if USE_CUSTOMTREECTRL
:
2123 item
= TreeBaseClass
.AppendItem(self
, parent
, text
, image
=image
, wnd
=wnd
)
2125 item
= TreeBaseClass
.AppendItem(self
, parent
, text
, image
=image
)
2128 def BuildTreeImageList(self
):
2129 imgList
= wx
.ImageList(16, 16)
2130 for png
in _demoPngs
:
2131 imgList
.Add(images
.catalog
[png
].getBitmap())
2133 # add the image for modified demos.
2134 imgList
.Add(images
.catalog
["custom"].getBitmap())
2136 self
.AssignImageList(imgList
)
2139 def GetItemIdentity(self
, item
):
2140 return self
.GetPyData(item
)
2143 #---------------------------------------------------------------------------
2145 class MyApp(wx
.App
):
2148 Create and show the splash screen. It will then create and show
2149 the main frame when it is time to do so.
2152 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
2153 self
.SetAppName("wxPyDemo")
2156 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
2158 # Normally when using a SplashScreen you would create it, show
2159 # it and then continue on with the applicaiton's
2160 # initialization, finally creating and showing the main
2161 # application window(s). In this case we have nothing else to
2162 # do so we'll delay showing the main frame until later (see
2163 # ShowMain above) so the users can see the SplashScreen effect.
2164 splash
= MySplashScreen()
2171 #---------------------------------------------------------------------------
2175 demoPath
= os
.path
.dirname(__file__
)
2182 #---------------------------------------------------------------------------
2185 mainOverview
= """<html><body>
2188 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
2189 language. It allows Python programmers to create programs with a
2190 robust, highly functional graphical user interface, simply and easily.
2191 It is implemented as a Python extension module (native code) that
2192 wraps the popular wxWindows cross platform GUI library, which is
2195 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
2196 means that it is free for anyone to use and the source code is
2197 available for anyone to look at and modify. Or anyone can contribute
2198 fixes or enhancements to the project.
2200 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
2201 same program will run on multiple platforms without modification.
2202 Currently supported platforms are 32-bit Microsoft Windows, most Unix
2203 or unix-like systems, and Macintosh OS X. Since the language is
2204 Python, wxPython programs are <b>simple, easy</b> to write and easy to
2207 <p> <b>This demo</b> is not only a collection of test cases for
2208 wxPython, but is also designed to help you learn about and how to use
2209 wxPython. Each sample is listed in the tree control on the left.
2210 When a sample is selected in the tree then a module is loaded and run
2211 (usually in a tab of this notebook,) and the source code of the module
2212 is loaded in another tab for you to browse and learn from.
2217 #----------------------------------------------------------------------------
2218 #----------------------------------------------------------------------------
2220 if __name__
== '__main__':
2224 #----------------------------------------------------------------------------