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 findNextItem
= wx
.MenuItem(menu
, -1, 'Find &Next\tF3', 'Find Next')
1446 findNextItem
.SetBitmap(images
.catalog
['findnext'].getBitmap())
1447 menu
.AppendItem(findItem
)
1448 menu
.AppendItem(findNextItem
)
1449 menu
.AppendSeparator()
1451 shellItem
= wx
.MenuItem(menu
, -1, 'Open Py&Shell Window\tF5',
1452 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1453 shellItem
.SetBitmap(images
.catalog
['pyshell'].getBitmap())
1454 menu
.AppendItem(shellItem
)
1455 inspToolItem
= wx
.MenuItem(menu
, -1, 'Open &Widget Inspector\tF6',
1456 'A tool that lets you browse the live widgets and sizers in an application')
1457 inspToolItem
.SetBitmap(images
.catalog
['inspect'].getBitmap())
1458 menu
.AppendItem(inspToolItem
)
1459 menu
.AppendSeparator()
1460 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1461 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1463 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1464 self
.Bind(wx
.EVT_MENU
, self
.OnOpenWidgetInspector
, inspToolItem
)
1465 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1466 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1467 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findNextItem
)
1468 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1469 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1470 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1471 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1472 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findNextItem
)
1473 self
.mainmenu
.Append(menu
, '&Help')
1474 self
.SetMenuBar(self
.mainmenu
)
1477 # This is another way to set Accelerators, in addition to
1478 # using the '\t<key>' syntax in the menu items.
1479 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitItem
.GetId()),
1480 (wx
.ACCEL_CTRL
, ord('H'), helpItem
.GetId()),
1481 (wx
.ACCEL_CTRL
, ord('F'), findItem
.GetId()),
1482 (wx
.ACCEL_NORMAL
, wx
.WXK_F3
, findnextItem
.GetId()),
1483 (wx
.ACCEL_NORMAL
, wx
.WXK_F9
, shellItem
.GetId()),
1485 self
.SetAcceleratorTable(aTable
)
1488 #---------------------------------------------
1489 def RecreateTree(self
, evt
=None):
1490 # Catch the search type (name or content)
1491 searchMenu
= self
.filter.GetMenu().GetMenuItems()
1492 fullSearch
= searchMenu
[1].IsChecked()
1496 # Do not`scan all the demo files for every char
1497 # the user input, use wx.EVT_TEXT_ENTER instead
1500 expansionState
= self
.tree
.GetExpansionState()
1503 item
= self
.tree
.GetSelection()
1505 prnt
= self
.tree
.GetItemParent(item
)
1507 current
= (self
.tree
.GetItemText(item
),
1508 self
.tree
.GetItemText(prnt
))
1511 self
.tree
.DeleteAllItems()
1512 self
.root
= self
.tree
.AddRoot("wxPython Overview")
1513 self
.tree
.SetItemImage(self
.root
, 0)
1514 self
.tree
.SetItemPyData(self
.root
, 0)
1516 treeFont
= self
.tree
.GetFont()
1517 catFont
= self
.tree
.GetFont()
1519 # The old native treectrl on MSW has a bug where it doesn't
1520 # draw all of the text for an item if the font is larger than
1521 # the default. It seems to be clipping the item's label as if
1522 # it was the size of the same label in the default font.
1523 if 'wxMSW' not in wx
.PlatformInfo
or wx
.GetApp().GetComCtl32Version() >= 600:
1524 treeFont
.SetPointSize(treeFont
.GetPointSize()+2)
1525 treeFont
.SetWeight(wx
.BOLD
)
1526 catFont
.SetWeight(wx
.BOLD
)
1528 self
.tree
.SetItemFont(self
.root
, treeFont
)
1532 filter = self
.filter.GetValue()
1535 for category
, items
in _treeList
:
1539 items
= self
.searchItems
[category
]
1541 items
= [item
for item
in items
if filter.lower() in item
.lower()]
1543 child
= self
.tree
.AppendItem(self
.root
, category
, image
=count
)
1544 self
.tree
.SetItemFont(child
, catFont
)
1545 self
.tree
.SetItemPyData(child
, count
)
1546 if not firstChild
: firstChild
= child
1547 for childItem
in items
:
1549 if DoesModifiedExist(childItem
):
1550 image
= len(_demoPngs
)
1551 theDemo
= self
.tree
.AppendItem(child
, childItem
, image
=image
)
1552 self
.tree
.SetItemPyData(theDemo
, count
)
1553 self
.treeMap
[childItem
] = theDemo
1554 if current
and (childItem
, category
) == current
:
1555 selectItem
= theDemo
1558 self
.tree
.Expand(self
.root
)
1560 self
.tree
.Expand(firstChild
)
1562 self
.tree
.ExpandAll()
1563 elif expansionState
:
1564 self
.tree
.SetExpansionState(expansionState
)
1566 self
.skipLoad
= True
1567 self
.tree
.SelectItem(selectItem
)
1568 self
.skipLoad
= False
1571 self
.searchItems
= {}
1574 def OnSearchMenu(self
, event
):
1576 # Catch the search type (name or content)
1577 searchMenu
= self
.filter.GetMenu().GetMenuItems()
1578 fullSearch
= searchMenu
[1].IsChecked()
1586 def OnSearch(self
, event
=None):
1588 value
= self
.filter.GetValue()
1593 wx
.BeginBusyCursor()
1595 for category
, items
in _treeList
:
1596 self
.searchItems
[category
] = []
1597 for childItem
in items
:
1598 if SearchDemo(childItem
, value
):
1599 self
.searchItems
[category
].append(childItem
)
1605 def SetTreeModified(self
, modified
):
1606 item
= self
.tree
.GetSelection()
1608 image
= len(_demoPngs
)
1610 image
= self
.tree
.GetItemPyData(item
)
1611 self
.tree
.SetItemImage(item
, image
)
1614 def WriteText(self
, text
):
1615 if text
[-1:] == '\n':
1619 def write(self
, txt
):
1622 #---------------------------------------------
1623 def OnItemExpanded(self
, event
):
1624 item
= event
.GetItem()
1625 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1628 #---------------------------------------------
1629 def OnItemCollapsed(self
, event
):
1630 item
= event
.GetItem()
1631 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1634 #---------------------------------------------
1635 def OnTreeLeftDown(self
, event
):
1636 # reset the overview text if the tree item is clicked on again
1637 pt
= event
.GetPosition();
1638 item
, flags
= self
.tree
.HitTest(pt
)
1639 if item
== self
.tree
.GetSelection():
1640 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1643 #---------------------------------------------
1644 def OnSelChanged(self
, event
):
1645 if self
.dying
or not self
.loaded
or self
.skipLoad
:
1648 item
= event
.GetItem()
1649 itemText
= self
.tree
.GetItemText(item
)
1650 self
.LoadDemo(itemText
)
1652 #---------------------------------------------
1653 def LoadDemo(self
, demoName
):
1655 wx
.BeginBusyCursor()
1659 self
.ShutdownDemoModule()
1661 if demoName
== self
.overviewText
:
1662 # User selected the "wxPython Overview" node
1664 # Changing the main window at runtime not yet supported...
1665 self
.demoModules
= DemoModules(__name__
)
1666 self
.SetOverview(self
.overviewText
, mainOverview
)
1667 self
.LoadDemoSource()
1668 self
.UpdateNotebook(0)
1670 if os
.path
.exists(GetOriginalFilename(demoName
)):
1671 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1672 self
.demoModules
= DemoModules(demoName
)
1673 self
.LoadDemoSource()
1675 self
.SetOverview("wxPython", mainOverview
)
1676 self
.codePage
= None
1677 self
.UpdateNotebook(0)
1682 #---------------------------------------------
1683 def LoadDemoSource(self
):
1684 self
.codePage
= None
1685 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1686 self
.codePage
.LoadDemo(self
.demoModules
)
1688 #---------------------------------------------
1689 def RunModule(self
):
1690 """Runs the active module"""
1692 module
= self
.demoModules
.GetActive()
1693 self
.ShutdownDemoModule()
1696 # o The RunTest() for all samples must now return a window that can
1697 # be palced in a tab in the main notebook.
1698 # o If an error occurs (or has occurred before) an error tab is created.
1700 if module
is not None:
1701 wx
.LogMessage("Running demo module...")
1702 if hasattr(module
, "overview"):
1703 overviewText
= module
.overview
1706 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1708 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1709 DemoError(sys
.exc_info()), self
)
1711 bg
= self
.nb
.GetThemeBackgroundColour()
1713 self
.demoPage
.SetBackgroundColour(bg
)
1715 assert self
.demoPage
is not None, "runTest must return a window!"
1718 # There was a previous error in compiling or exec-ing
1719 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1720 self
.demoModules
.GetErrorInfo(), self
)
1722 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1725 # change to the demo page the first time a module is run
1726 self
.UpdateNotebook(2)
1727 self
.firstTime
= False
1729 # otherwise just stay on the same tab in case the user has changed to another one
1730 self
.UpdateNotebook()
1732 #---------------------------------------------
1733 def ShutdownDemoModule(self
):
1735 # inform the window that it's time to quit if it cares
1736 if hasattr(self
.demoPage
, "ShutdownDemo"):
1737 self
.demoPage
.ShutdownDemo()
1738 wx
.YieldIfNeeded() # in case the page has pending events
1739 self
.demoPage
= None
1741 #---------------------------------------------
1742 def UpdateNotebook(self
, select
= -1):
1747 def UpdatePage(page
, pageText
):
1750 for i
in range(nb
.GetPageCount()):
1751 if nb
.GetPageText(i
) == pageText
:
1759 nb
.AddPage(page
, pageText
, imageId
=nb
.GetPageCount())
1760 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1762 if nb
.GetPage(pagePos
) != page
:
1763 # Reload an existing page
1764 nb
.DeletePage(pagePos
)
1765 nb
.InsertPage(pagePos
, page
, pageText
, imageId
=pagePos
)
1766 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1768 # Excellent! No redraw/flicker
1769 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1772 nb
.DeletePage(pagePos
)
1773 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1775 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1778 select
= nb
.GetSelection()
1780 UpdatePage(self
.codePage
, "Demo Code")
1781 UpdatePage(self
.demoPage
, "Demo")
1783 if select
>= 0 and select
< nb
.GetPageCount():
1784 nb
.SetSelection(select
)
1788 #---------------------------------------------
1789 def SetOverview(self
, name
, text
):
1790 self
.curOverview
= text
1792 if lead
!= '<html>' and lead
!= '<HTML>':
1793 text
= '<br>'.join(text
.split('\n'))
1795 text
= text
.decode('iso8859_1')
1796 self
.ovr
.SetPage(text
)
1797 self
.nb
.SetPageText(0, name
)
1799 #---------------------------------------------
1801 def OnFileExit(self
, *event
):
1804 def OnToggleRedirect(self
, event
):
1808 print "Print statements and other standard output will now be directed to this window."
1811 print "Print statements and other standard output will now be sent to the usual location."
1814 def OnAUIPerspectives(self
, event
):
1815 perspective
= self
.perspectives_menu
.GetLabel(event
.GetId())
1816 self
.mgr
.LoadPerspective(self
.auiConfigurations
[perspective
])
1820 def OnSavePerspective(self
, event
):
1821 dlg
= wx
.TextEntryDialog(self
, "Enter a name for the new perspective:", "AUI Configuration")
1823 dlg
.SetValue(("Perspective %d")%(len(self
.auiConfigurations
)+1))
1824 if dlg
.ShowModal() != wx
.ID_OK
:
1827 perspectiveName
= dlg
.GetValue()
1828 menuItems
= self
.perspectives_menu
.GetMenuItems()
1829 for item
in menuItems
:
1830 if item
.GetLabel() == perspectiveName
:
1831 wx
.MessageBox("The selected perspective name:\n\n%s\n\nAlready exists."%perspectiveName
,
1832 "Error", style
=wx
.ICON_ERROR
)
1835 item
= wx
.MenuItem(self
.perspectives_menu
, -1, dlg
.GetValue(),
1836 "Load user perspective %d"%(len(self
.auiConfigurations
)+1),
1838 self
.Bind(wx
.EVT_MENU
, self
.OnAUIPerspectives
, item
)
1839 self
.perspectives_menu
.AppendItem(item
)
1841 self
.auiConfigurations
.update({dlg.GetValue(): self.mgr.SavePerspective()}
)
1844 def OnDeletePerspective(self
, event
):
1845 menuItems
= self
.perspectives_menu
.GetMenuItems()[1:]
1849 for item
in menuItems
:
1850 lst
.append(item
.GetLabel())
1852 dlg
= wx
.MultiChoiceDialog(self
,
1853 "Please select the perspectives\nyou would like to delete:",
1854 "Delete AUI Perspectives", lst
)
1856 if dlg
.ShowModal() == wx
.ID_OK
:
1857 selections
= dlg
.GetSelections()
1858 strings
= [lst
[x
] for x
in selections
]
1860 self
.auiConfigurations
.pop(sel
)
1861 item
= menuItems
[lst
.index(sel
)]
1862 if item
.IsChecked():
1864 self
.perspectives_menu
.GetMenuItems()[0].Check(True)
1865 self
.perspectives_menu
.DeleteItem(item
)
1869 self
.mgr
.LoadPerspective(self
.auiConfigurations
[DEFAULT_PERSPECTIVE
])
1873 def OnTreeExpansion(self
, event
):
1874 self
.tree
.SetExpansionState(self
.expansionState
)
1877 def OnHelpAbout(self
, event
):
1878 from About
import MyAboutBox
1879 about
= MyAboutBox(self
)
1883 def OnHelpFind(self
, event
):
1884 if self
.finddlg
!= None:
1887 self
.nb
.SetSelection(1)
1888 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1889 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1890 self
.finddlg
.Show(True)
1893 def OnUpdateFindItems(self
, evt
):
1894 evt
.Enable(self
.finddlg
== None)
1897 def OnFind(self
, event
):
1898 editor
= self
.codePage
.editor
1899 self
.nb
.SetSelection(1)
1900 end
= editor
.GetLastPosition()
1901 textstring
= editor
.GetRange(0, end
).lower()
1902 findstring
= self
.finddata
.GetFindString().lower()
1903 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1905 start
= editor
.GetSelection()[0]
1906 loc
= textstring
.rfind(findstring
, 0, start
)
1908 start
= editor
.GetSelection()[1]
1909 loc
= textstring
.find(findstring
, start
)
1910 if loc
== -1 and start
!= 0:
1911 # string not found, start at beginning
1914 loc
= textstring
.rfind(findstring
, 0, start
)
1917 loc
= textstring
.find(findstring
, start
)
1919 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1920 'Find String Not Found in Demo File',
1921 wx
.OK | wx
.ICON_INFORMATION
)
1926 self
.finddlg
.SetFocus()
1929 self
.finddlg
.Destroy()
1931 editor
.ShowPosition(loc
)
1932 editor
.SetSelection(loc
, loc
+ len(findstring
))
1936 def OnFindNext(self
, event
):
1937 if self
.finddata
.GetFindString():
1940 self
.OnHelpFind(event
)
1942 def OnFindClose(self
, event
):
1943 event
.GetDialog().Destroy()
1947 def OnOpenShellWindow(self
, evt
):
1949 # if it already exists then just make sure it's visible
1955 # Make a PyShell window
1957 namespace
= { 'wx' : wx
,
1958 'app' : wx
.GetApp(),
1961 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1962 self
.shell
.SetSize((640,480))
1965 # Hook the close event of the main frame window so that we
1966 # close the shell at the same time if it still exists
1967 def CloseShell(evt
):
1971 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1974 def OnOpenWidgetInspector(self
, evt
):
1975 # Activate the widget inspection tool
1976 from wx
.lib
.inspection
import InspectionTool
1977 if not InspectionTool().initialized
:
1978 InspectionTool().Init()
1980 # Find a widget to be selected in the tree. Use either the
1981 # one under the cursor, if any, or this frame.
1982 wnd
= wx
.FindWindowAtPointer()
1985 InspectionTool().Show(wnd
, True)
1988 #---------------------------------------------
1989 def OnCloseWindow(self
, event
):
1991 self
.demoPage
= None
1992 self
.codePage
= None
1993 self
.mainmenu
= None
1994 if self
.tbicon
is not None:
1995 self
.tbicon
.Destroy()
1997 config
= GetConfig()
1998 config
.Write('ExpansionState', str(self
.tree
.GetExpansionState()))
1999 config
.Write('AUIPerspectives', str(self
.auiConfigurations
))
2005 #---------------------------------------------
2006 def OnIdle(self
, event
):
2008 self
.otherWin
.Raise()
2009 self
.demoPage
= self
.otherWin
2010 self
.otherWin
= None
2013 #---------------------------------------------
2015 config
= GetConfig()
2016 showTipText
= config
.Read("tips")
2018 showTip
, index
= eval(showTipText
)
2020 showTip
, index
= (1, 0)
2023 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
2025 showTip
= wx
.ShowTip(self
, tp
)
2026 index
= tp
.GetCurrentTip()
2027 config
.Write("tips", str( (showTip
, index
) ))
2030 #---------------------------------------------
2031 def OnDemoMenu(self
, event
):
2033 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
2037 self
.tree
.SelectItem(selectedDemo
)
2038 self
.tree
.EnsureVisible(selectedDemo
)
2042 #---------------------------------------------
2043 def OnIconfiy(self
, evt
):
2044 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
2047 #---------------------------------------------
2048 def OnMaximize(self
, evt
):
2049 wx
.LogMessage("OnMaximize")
2052 #---------------------------------------------
2053 def OnActivate(self
, evt
):
2054 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
2057 #---------------------------------------------
2058 def OnAppActivate(self
, evt
):
2059 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
2062 #---------------------------------------------------------------------------
2063 #---------------------------------------------------------------------------
2065 class MySplashScreen(wx
.SplashScreen
):
2067 bmp
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
2068 wx
.SplashScreen
.__init
__(self
, bmp
,
2069 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
2071 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
2072 self
.fc
= wx
.FutureCall(2000, self
.ShowMain
)
2075 def OnClose(self
, evt
):
2076 # Make sure the default handler runs too so this window gets
2081 # if the timer is still running then go ahead and show the
2083 if self
.fc
.IsRunning():
2089 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
2091 if self
.fc
.IsRunning():
2093 wx
.CallAfter(frame
.ShowTip
)
2098 #---------------------------------------------------------------------------
2100 from wx
.lib
.mixins
.treemixin
import ExpansionState
2101 if USE_CUSTOMTREECTRL
:
2102 import wx
.lib
.customtreectrl
as CT
2103 TreeBaseClass
= CT
.CustomTreeCtrl
2105 TreeBaseClass
= wx
.TreeCtrl
2108 class wxPythonDemoTree(ExpansionState
, TreeBaseClass
):
2109 def __init__(self
, parent
):
2110 TreeBaseClass
.__init
__(self
, parent
, style
=wx
.TR_DEFAULT_STYLE|
2111 wx
.TR_HAS_VARIABLE_ROW_HEIGHT
)
2112 self
.BuildTreeImageList()
2113 if USE_CUSTOMTREECTRL
:
2115 self
.SetWindowStyle(self
.GetWindowStyle() & ~wx
.TR_LINES_AT_ROOT
)
2117 def AppendItem(self
, parent
, text
, image
=-1, wnd
=None):
2118 if USE_CUSTOMTREECTRL
:
2119 item
= TreeBaseClass
.AppendItem(self
, parent
, text
, image
=image
, wnd
=wnd
)
2121 item
= TreeBaseClass
.AppendItem(self
, parent
, text
, image
=image
)
2124 def BuildTreeImageList(self
):
2125 imgList
= wx
.ImageList(16, 16)
2126 for png
in _demoPngs
:
2127 imgList
.Add(images
.catalog
[png
].getBitmap())
2129 # add the image for modified demos.
2130 imgList
.Add(images
.catalog
["custom"].getBitmap())
2132 self
.AssignImageList(imgList
)
2135 def GetItemIdentity(self
, item
):
2136 return self
.GetPyData(item
)
2139 #---------------------------------------------------------------------------
2141 class MyApp(wx
.App
):
2144 Create and show the splash screen. It will then create and show
2145 the main frame when it is time to do so.
2148 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
2149 self
.SetAppName("wxPyDemo")
2152 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
2154 # Normally when using a SplashScreen you would create it, show
2155 # it and then continue on with the applicaiton's
2156 # initialization, finally creating and showing the main
2157 # application window(s). In this case we have nothing else to
2158 # do so we'll delay showing the main frame until later (see
2159 # ShowMain above) so the users can see the SplashScreen effect.
2160 splash
= MySplashScreen()
2167 #---------------------------------------------------------------------------
2171 demoPath
= os
.path
.dirname(__file__
)
2178 #---------------------------------------------------------------------------
2181 mainOverview
= """<html><body>
2184 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
2185 language. It allows Python programmers to create programs with a
2186 robust, highly functional graphical user interface, simply and easily.
2187 It is implemented as a Python extension module (native code) that
2188 wraps the popular wxWindows cross platform GUI library, which is
2191 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
2192 means that it is free for anyone to use and the source code is
2193 available for anyone to look at and modify. Or anyone can contribute
2194 fixes or enhancements to the project.
2196 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
2197 same program will run on multiple platforms without modification.
2198 Currently supported platforms are 32-bit Microsoft Windows, most Unix
2199 or unix-like systems, and Macintosh OS X. Since the language is
2200 Python, wxPython programs are <b>simple, easy</b> to write and easy to
2203 <p> <b>This demo</b> is not only a collection of test cases for
2204 wxPython, but is also designed to help you learn about and how to use
2205 wxPython. Each sample is listed in the tree control on the left.
2206 When a sample is selected in the tree then a module is loaded and run
2207 (usually in a tab of this notebook,) and the source code of the module
2208 is loaded in another tab for you to browse and learn from.
2213 #----------------------------------------------------------------------------
2214 #----------------------------------------------------------------------------
2216 if __name__
== '__main__':
2220 #----------------------------------------------------------------------------