2 #----------------------------------------------------------------------------
4 # Purpose: Testing lots of stuff, controls, window types, etc.
8 # Created: A long time ago, in a galaxy far, far away...
10 # Copyright: (c) 1999 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
15 # * Problems with flickering related to ERASE_BACKGROUND
16 # and the splitters. Might be a problem with this 2.5 beta...?
17 # UPDATE: can't see on 2.5.2 GTK - maybe just a faster machine :)
19 # * Annoying switching between tabs and resulting flicker
20 # how to replace a page in the notebook without deleting/adding?
21 # Where is SetPage!? tried freeze...tried reparent of dummy panel....
24 # * UI design more prefessional
25 # * save file positions (new field in demoModules) (@ LoadDemoSource)
26 # * Update main overview
28 # * Why don't we move _treeList into a separate module
30 import sys
, os
, time
, traceback
, types
32 import wx
# This module uses the new wx namespace
39 ##print "wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi')
40 ##print "pid:", os.getpid()
41 ##raw_input("Press Enter...")
44 #---------------------------------------------------------------------------
49 ('Recent Additions/Updates', [
51 'AUI_DockingWindowMgr',
70 # managed windows == things with a (optional) caption you can close
71 ('Frames and Dialogs', [
72 'AUI_DockingWindowMgr',
96 # dialogs from libraries
99 'ScrolledMessageDialog',
103 ('Core Windows/Controls', [
140 ('"Book" Controls', [
149 ('Custom Controls', [
165 # controls coming from other libraries
166 ('More Windows/Controls', [
167 'ActiveX_FlashWindow',
168 'ActiveX_IEHtmlWindow',
170 #'RightTextCtrl', deprecated as we have wxTE_RIGHT now.
173 'CheckListCtrlMixin',
189 'MaskedEditControls',
192 'MultiSplitterWindow',
209 # How to lay out the controls in a frame/dialog
219 'XmlResourceHandler',
220 'XmlResourceSubclass',
224 ('Process and Events', [
232 ##'infoframe', # needs better explanation and some fixing
236 ('Clipboard and DnD', [
262 ##'DialogUnits', # needs more explanations
281 ('Check out the samples dir too', [
288 #---------------------------------------------------------------------------
289 # Show how to derive a custom wxLog class
291 class MyLog(wx
.PyLog
):
292 def __init__(self
, textCtrl
, logTime
=0):
293 wx
.PyLog
.__init
__(self
)
295 self
.logTime
= logTime
297 def DoLogString(self
, message
, timeStamp
):
298 #print message, timeStamp
300 # message = time.strftime("%X", time.localtime(timeStamp)) + \
303 self
.tc
.AppendText(message
+ '\n')
306 class MyTP(wx
.PyTipProvider
):
308 return "This is my tip"
310 #---------------------------------------------------------------------------
311 # A class to be used to simply display a message in the demo pane
312 # rather than running the sample itself.
314 class MessagePanel(wx
.Panel
):
315 def __init__(self
, parent
, message
, caption
='', flags
=0):
316 wx
.Panel
.__init
__(self
, parent
)
321 if flags
& wx
.ICON_EXCLAMATION
:
322 artid
= wx
.ART_WARNING
323 elif flags
& wx
.ICON_ERROR
:
325 elif flags
& wx
.ICON_QUESTION
:
326 artid
= wx
.ART_QUESTION
327 elif flags
& wx
.ICON_INFORMATION
:
328 artid
= wx
.ART_INFORMATION
330 if artid
is not None:
331 bmp
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32))
332 icon
= wx
.StaticBitmap(self
, -1, bmp
)
334 icon
= (32,32) # make a spacer instead
337 caption
= wx
.StaticText(self
, -1, caption
)
338 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
340 message
= wx
.StaticText(self
, -1, message
)
342 # add to sizers for layout
343 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
349 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
356 box
= wx
.BoxSizer(wx
.VERTICAL
)
358 box
.Add(hbox
, 0, wx
.EXPAND
)
365 #---------------------------------------------------------------------------
366 # A class to be used to display source code in the demo. Try using the
367 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
368 # if there is an error, such as the stc module not being present.
372 ##raise ImportError # for testing the alternate implementation
374 from StyledTextCtrl_2
import PythonSTC
376 class DemoCodeEditor(PythonSTC
):
377 def __init__(self
, parent
):
378 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
381 # Some methods to make it compatible with how the wxTextCtrl is used
382 def SetValue(self
, value
):
384 value
= value
.decode('iso8859_1')
386 self
.EmptyUndoBuffer()
389 def IsModified(self
):
390 return self
.GetModify()
395 def SetInsertionPoint(self
, pos
):
396 self
.SetCurrentPos(pos
)
399 def ShowPosition(self
, pos
):
400 line
= self
.LineFromPosition(pos
)
401 #self.EnsureVisible(line)
404 def GetLastPosition(self
):
405 return self
.GetLength()
407 def GetPositionFromLine(self
, line
):
408 return self
.PositionFromLine(line
)
410 def GetRange(self
, start
, end
):
411 return self
.GetTextRange(start
, end
)
413 def GetSelection(self
):
414 return self
.GetAnchor(), self
.GetCurrentPos()
416 def SetSelection(self
, start
, end
):
417 self
.SetSelectionStart(start
)
418 self
.SetSelectionEnd(end
)
420 def SelectLine(self
, line
):
421 start
= self
.PositionFromLine(line
)
422 end
= self
.GetLineEndPosition(line
)
423 self
.SetSelection(start
, end
)
425 def SetUpEditor(self
):
427 This method carries out the work of setting up the demo editor.
428 It's seperate so as not to clutter up the init code.
432 self
.SetLexer(stc
.STC_LEX_PYTHON
)
433 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
436 self
.SetProperty("fold", "1" )
438 # Highlight tab/space mixing (shouldn't be any)
439 self
.SetProperty("tab.timmy.whinge.level", "1")
441 # Set left and right margins
444 # Set up the numbers in the margin for margin #1
445 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
446 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
447 self
.SetMarginWidth(1, 40)
449 # Indentation and tab stuff
450 self
.SetIndent(4) # Proscribed indent size for wx
451 self
.SetIndentationGuides(True) # Show indent guides
452 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
453 self
.SetTabIndents(True) # Tab key indents
454 self
.SetTabWidth(4) # Proscribed tab size for wx
455 self
.SetUseTabs(False) # Use spaces rather than tabs, or
456 # TabTimmy will complain!
458 self
.SetViewWhiteSpace(False) # Don't view white space
460 # EOL: Since we are loading/saving ourselves, and the
461 # strings will always have \n's in them, set the STC to
462 # edit them that way.
463 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
464 self
.SetViewEOL(False)
466 # No right-edge mode indicator
467 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
469 # Setup a margin to hold fold markers
470 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
471 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
472 self
.SetMarginSensitive(2, True)
473 self
.SetMarginWidth(2, 12)
475 # and now set up the fold markers
476 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
477 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
478 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
479 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
480 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
481 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
482 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
484 # Global default style
485 if wx
.Platform
== '__WXMSW__':
486 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
487 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
489 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
490 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
492 # Clear styles and revert to default.
495 # Following style specs only indicate differences from default.
496 # The rest remains unchanged.
498 # Line numbers in margin
499 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
501 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
503 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
505 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
508 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
510 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
511 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
513 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
514 # Strings and characters
515 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
516 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
518 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
520 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
521 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
523 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
525 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
527 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
528 # Identifiers. I leave this as not bold because everything seems
529 # to be an identifier if it doesn't match the above criterae
530 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
533 self
.SetCaretForeground("BLUE")
534 # Selection background
535 self
.SetSelBackground(1, '#66CCFF')
537 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
538 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
540 def RegisterModifiedEvent(self
, eventHandler
):
541 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
545 class DemoCodeEditor(wx
.TextCtrl
):
546 def __init__(self
, parent
):
547 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
548 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
550 def RegisterModifiedEvent(self
, eventHandler
):
551 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
553 def SetReadOnly(self
, flag
):
554 self
.SetEditable(not flag
)
555 # NOTE: STC already has this method
558 return self
.GetValue()
560 def GetPositionFromLine(self
, line
):
561 return self
.XYToPosition(0,line
)
563 def GotoLine(self
, line
):
564 pos
= self
.GetPositionFromLine(line
)
565 self
.SetInsertionPoint(pos
)
566 self
.ShowPosition(pos
)
568 def SelectLine(self
, line
):
569 start
= self
.GetPositionFromLine(line
)
570 end
= start
+ self
.GetLineLength(line
)
571 self
.SetSelection(start
, end
)
574 #---------------------------------------------------------------------------
575 # Constants for module versions
579 modDefault
= modOriginal
581 #---------------------------------------------------------------------------
583 class DemoCodePanel(wx
.Panel
):
584 """Panel for the 'Demo Code' tab"""
585 def __init__(self
, parent
, mainFrame
):
586 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
587 if 'wxMSW' in wx
.PlatformInfo
:
589 self
.mainFrame
= mainFrame
590 self
.editor
= DemoCodeEditor(self
)
591 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
593 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
594 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
595 self
.btnSave
.Enable(False)
596 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
597 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
599 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
600 modModified
: wx
.RadioButton(self
, -1, "Modified") }
602 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
603 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
604 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
605 for modID
, radioButton
in self
.radioButtons
.items():
606 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
607 radioButton
.modID
= modID
# makes it easier for the event handler
608 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
610 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
611 self
.controlBox
.Add(self
.btnRestore
, 0)
613 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
614 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
615 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
616 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
619 self
.SetSizer(self
.box
)
622 # Loads a demo from a DemoModules object
623 def LoadDemo(self
, demoModules
):
624 self
.demoModules
= demoModules
625 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
626 demoModules
.SetActive(modModified
)
628 demoModules
.SetActive(modOriginal
)
629 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
630 self
.ActiveModuleChanged()
633 def ActiveModuleChanged(self
):
634 self
.LoadDemoSource(self
.demoModules
.GetSource())
635 self
.UpdateControlState()
639 def LoadDemoSource(self
, source
):
641 self
.editor
.SetValue(source
)
643 self
.btnSave
.Enable(False)
646 def JumpToLine(self
, line
, highlight
=False):
647 self
.editor
.GotoLine(line
)
648 self
.editor
.SetFocus()
650 self
.editor
.SelectLine(line
)
653 def UpdateControlState(self
):
654 active
= self
.demoModules
.GetActiveID()
655 # Update the radio/restore buttons
656 for moduleID
in self
.radioButtons
:
657 btn
= self
.radioButtons
[moduleID
]
658 if moduleID
== active
:
663 if self
.demoModules
.Exists(moduleID
):
665 if moduleID
== modModified
:
666 self
.btnRestore
.Enable(True)
669 if moduleID
== modModified
:
670 self
.btnRestore
.Enable(False)
673 def OnRadioButton(self
, event
):
674 radioSelected
= event
.GetEventObject()
675 modSelected
= radioSelected
.modID
676 if modSelected
!= self
.demoModules
.GetActiveID():
677 busy
= wx
.BusyInfo("Reloading demo module...")
678 self
.demoModules
.SetActive(modSelected
)
679 self
.ActiveModuleChanged()
682 def ReloadDemo(self
):
683 if self
.demoModules
.name
!= __name__
:
684 self
.mainFrame
.RunModule()
687 def OnCodeModified(self
, event
):
688 self
.btnSave
.Enable(self
.editor
.IsModified())
691 def OnSave(self
, event
):
692 if self
.demoModules
.Exists(modModified
):
693 if self
.demoModules
.GetActiveID() == modOriginal
:
694 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
695 "Do you want to continue?"
696 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
697 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
698 result
= dlg
.ShowModal()
699 if result
== wx
.ID_NO
:
703 self
.demoModules
.SetActive(modModified
)
704 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
706 # Create the demo directory if one doesn't already exist
707 if not os
.path
.exists(GetModifiedDirectory()):
709 os
.makedirs(GetModifiedDirectory())
710 if not os
.path
.exists(GetModifiedDirectory()):
711 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
714 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
717 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
720 f
= open(modifiedFilename
, "wt")
721 source
= self
.editor
.GetText()
727 busy
= wx
.BusyInfo("Reloading demo module...")
728 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
729 self
.ActiveModuleChanged()
732 def OnRestore(self
, event
): # Handles the "Delete Modified" button
733 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
734 self
.demoModules
.Delete(modModified
)
735 os
.unlink(modifiedFilename
) # Delete the modified copy
736 busy
= wx
.BusyInfo("Reloading demo module...")
737 self
.ActiveModuleChanged()
740 #---------------------------------------------------------------------------
743 """Convert paths to the platform-specific separator"""
744 str = apply(os
.path
.join
, tuple(path
.split('/')))
745 # HACK: on Linux, a leading / gets lost...
746 if path
.startswith('/'):
751 def GetModifiedDirectory():
753 Returns the directory where modified versions of the demo files
756 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
759 def GetModifiedFilename(name
):
761 Returns the filename of the modified version of the specified demo
763 if not name
.endswith(".py"):
765 return GetModifiedDirectory() + name
768 def GetOriginalFilename(name
):
770 Returns the filename of the original version of the specified demo
772 if not name
.endswith(".py"):
777 def DoesModifiedExist(name
):
778 """Returns whether the specified demo has a modified copy"""
779 if os
.path
.exists(GetModifiedFilename(name
)):
785 #---------------------------------------------------------------------------
787 class ModuleDictWrapper
:
788 """Emulates a module with a dynamically compiled __dict__"""
789 def __init__(self
, dict):
792 def __getattr__(self
, name
):
793 if name
in self
.dict:
794 return self
.dict[name
]
800 Dynamically manages the original/modified versions of a demo
803 def __init__(self
, name
):
807 # (dict , source , filename , description , error information )
808 # ( 0 , 1 , 2 , 3 , 4 )
809 self
.modules
= [[None, "" , "" , "<original>" , None],
810 [None, "" , "" , "<modified>" , None]]
812 # load original module
813 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
814 self
.SetActive(modOriginal
)
816 # load modified module (if one exists)
817 if DoesModifiedExist(name
):
818 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
821 def LoadFromFile(self
, modID
, filename
):
822 self
.modules
[modID
][2] = filename
823 file = open(filename
, "rt")
824 self
.LoadFromSource(modID
, file.read())
828 def LoadFromSource(self
, modID
, source
):
829 self
.modules
[modID
][1] = source
833 def LoadDict(self
, modID
):
834 if self
.name
!= __name__
:
835 source
= self
.modules
[modID
][1]
836 #description = self.modules[modID][3]
837 description
= self
.modules
[modID
][2]
840 self
.modules
[modID
][0] = {}
841 code
= compile(source
, description
, "exec")
842 exec code
in self
.modules
[modID
][0]
844 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
845 self
.modules
[modID
][0] = None
847 self
.modules
[modID
][4] = None
850 def SetActive(self
, modID
):
851 if modID
!= modOriginal
and modID
!= modModified
:
854 self
.modActive
= modID
858 dict = self
.modules
[self
.modActive
][0]
862 return ModuleDictWrapper(dict)
865 def GetActiveID(self
):
866 return self
.modActive
869 def GetSource(self
, modID
= None):
871 modID
= self
.modActive
872 return self
.modules
[modID
][1]
875 def GetFilename(self
, modID
= None):
877 modID
= self
.modActive
878 return self
.modules
[self
.modActive
][2]
881 def GetErrorInfo(self
, modID
= None):
883 modID
= self
.modActive
884 return self
.modules
[self
.modActive
][4]
887 def Exists(self
, modID
):
888 return self
.modules
[modID
][1] != ""
891 def UpdateFile(self
, modID
= None):
892 """Updates the file from which a module was loaded
893 with (possibly updated) source"""
895 modID
= self
.modActive
897 source
= self
.modules
[modID
][1]
898 filename
= self
.modules
[modID
][2]
901 file = open(filename
, "wt")
907 def Delete(self
, modID
):
908 if self
.modActive
== modID
:
911 self
.modules
[modID
][0] = None
912 self
.modules
[modID
][1] = ""
913 self
.modules
[modID
][2] = ""
916 #---------------------------------------------------------------------------
919 """Wraps and stores information about the current exception"""
920 def __init__(self
, exc_info
):
923 excType
, excValue
= exc_info
[:2]
924 # traceback list entries: (filename, line number, function name, text)
925 self
.traceback
= traceback
.extract_tb(exc_info
[2])
927 # --Based on traceback.py::format_exception_only()--
928 if type(excType
) == types
.ClassType
:
929 self
.exception_type
= excType
.__name
__
931 self
.exception_type
= excType
933 # If it's a syntax error, extra information needs
934 # to be added to the traceback
935 if excType
is SyntaxError:
937 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
942 filename
= "<string>"
944 self
.traceback
.append( (filename
, lineno
, "", line
) )
947 self
.exception_details
= str(excValue
)
949 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
956 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
959 #---------------------------------------------------------------------------
961 class DemoErrorPanel(wx
.Panel
):
962 """Panel put into the demo tab when the demo fails to run due to errors"""
964 def __init__(self
, parent
, codePanel
, demoError
, log
):
965 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
966 self
.codePanel
= codePanel
970 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
973 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo")
974 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
976 # Exception Information
977 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
978 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
979 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
980 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
981 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
982 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_type
) , 0, textFlags
, 5 )
983 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
984 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
985 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
986 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
988 # Set up the traceback list
989 # This one automatically resizes last column to take up remaining space
990 from ListCtrl
import TestListCtrl
991 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
992 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
993 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
994 self
.list.InsertColumn(0, "Filename")
995 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
996 self
.list.InsertColumn(2, "Function")
997 self
.list.InsertColumn(3, "Code")
998 self
.InsertTraceback(self
.list, demoError
.traceback
)
999 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
1000 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
1001 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
1002 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
1003 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
1004 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
1005 + "Double-click on them to go to the offending line")
1006 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
1009 self
.SetSizer(self
.box
)
1012 def InsertTraceback(self
, list, traceback
):
1013 #Add the traceback data
1014 for x
in range(len(traceback
)):
1016 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
1017 list.SetStringItem(x
, 1, str(data
[1])) # Line
1018 list.SetStringItem(x
, 2, str(data
[2])) # Function
1019 list.SetStringItem(x
, 3, str(data
[3])) # Code
1021 # Check whether this entry is from the demo module
1022 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
1023 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
1024 # Give it a blue colour
1025 item
= self
.list.GetItem(x
)
1026 item
.SetTextColour(wx
.BLUE
)
1027 self
.list.SetItem(item
)
1029 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
1032 def OnItemSelected(self
, event
):
1033 # This occurs before OnDoubleClick and can be used to set the
1034 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1035 self
.currentItem
= event
.m_itemIndex
1039 def OnDoubleClick(self
, event
):
1040 # If double-clicking on a demo's entry, jump to the line number
1041 line
= self
.list.GetItemData(self
.currentItem
)
1043 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1044 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1048 #---------------------------------------------------------------------------
1050 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1051 TBMENU_RESTORE
= wx
.NewId()
1052 TBMENU_CLOSE
= wx
.NewId()
1053 TBMENU_CHANGE
= wx
.NewId()
1054 TBMENU_REMOVE
= wx
.NewId()
1056 def __init__(self
, frame
):
1057 wx
.TaskBarIcon
.__init
__(self
)
1061 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1062 self
.SetIcon(icon
, "wxPython Demo")
1066 self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1067 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1068 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1069 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
)
1070 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
)
1073 def CreatePopupMenu(self
):
1075 This method is called by the base class when it needs to popup
1076 the menu for the default EVT_RIGHT_DOWN event. Just create
1077 the menu how you want it and return it from this function,
1078 the base class takes care of the rest.
1081 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1082 menu
.Append(self
.TBMENU_CLOSE
, "Close wxPython Demo")
1083 menu
.AppendSeparator()
1084 menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon")
1085 menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon")
1089 def MakeIcon(self
, img
):
1091 The various platforms have different requirements for the
1094 if "wxMSW" in wx
.PlatformInfo
:
1095 img
= img
.Scale(16, 16)
1096 elif "wxGTK" in wx
.PlatformInfo
:
1097 img
= img
.Scale(22, 22)
1098 # wxMac can be any size upto 128x128, so leave the source img alone....
1099 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
1103 def OnTaskBarActivate(self
, evt
):
1104 if self
.frame
.IsIconized():
1105 self
.frame
.Iconize(False)
1106 if not self
.frame
.IsShown():
1107 self
.frame
.Show(True)
1111 def OnTaskBarClose(self
, evt
):
1115 def OnTaskBarChange(self
, evt
):
1116 names
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
1117 name
= names
[self
.imgidx
]
1119 getFunc
= getattr(images
, "get%sImage" % name
)
1121 if self
.imgidx
>= len(names
):
1124 icon
= self
.MakeIcon(getFunc())
1125 self
.SetIcon(icon
, "This is a new icon: " + name
)
1128 def OnTaskBarRemove(self
, evt
):
1132 #---------------------------------------------------------------------------
1133 class wxPythonDemo(wx
.Frame
):
1134 overviewText
= "wxPython Overview"
1136 def __init__(self
, parent
, title
):
1137 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 720),
1138 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1140 self
.SetMinSize((640,480))
1143 self
.cwd
= os
.getcwd()
1144 self
.curOverview
= ""
1145 self
.demoPage
= None
1146 self
.codePage
= None
1148 self
.firstTime
= True
1151 icon
= images
.getWXPdemoIcon()
1155 self
.tbicon
= DemoTaskBarIcon(self
)
1159 wx
.CallAfter(self
.ShowTip
)
1161 self
.otherWin
= None
1162 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1163 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1164 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1165 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1167 self
.Centre(wx
.BOTH
)
1168 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1170 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1171 splitter2
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1173 def EmptyHandler(evt
): pass
1174 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1175 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1177 # Prevent TreeCtrl from displaying all items after destruction when True
1181 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1184 self
.mainmenu
= wx
.MenuBar()
1186 item
= menu
.Append(-1, '&Redirect Output',
1187 'Redirect print statements to a window',
1189 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1191 item
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1192 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
)
1193 wx
.App
.SetMacExitMenuItemId(item
.GetId())
1194 self
.mainmenu
.Append(menu
, '&File')
1198 for item
in _treeList
:
1200 for childItem
in item
[1]:
1201 mi
= submenu
.Append(-1, childItem
)
1202 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1203 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1204 self
.mainmenu
.Append(menu
, '&Demo')
1209 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1210 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1211 menu
.AppendSeparator()
1213 shellItem
= menu
.Append(-1, 'Open Py&Shell Window\tF5',
1214 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1215 menu
.AppendSeparator()
1216 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1217 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1219 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1220 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1221 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1222 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1223 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1224 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1225 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1226 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1227 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
)
1228 self
.mainmenu
.Append(menu
, '&Help')
1229 self
.SetMenuBar(self
.mainmenu
)
1231 self
.finddata
= wx
.FindReplaceData()
1232 self
.finddata
.SetFlags(wx
.FR_DOWN
)
1235 # This is another way to set Accelerators, in addition to
1236 # using the '\t<key>' syntax in the menu items.
1237 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitID
),
1238 (wx
.ACCEL_CTRL
, ord('H'), helpID
),
1239 (wx
.ACCEL_CTRL
, ord('F'), findID
),
1240 (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
)
1242 self
.SetAcceleratorTable(aTable
)
1248 self
.tree
= wx
.TreeCtrl(splitter
, tID
, style
=
1249 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1252 root
= self
.tree
.AddRoot("wxPython Overview")
1254 for item
in _treeList
:
1255 child
= self
.tree
.AppendItem(root
, item
[0])
1256 if not firstChild
: firstChild
= child
1257 for childItem
in item
[1]:
1258 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1259 self
.treeMap
[childItem
] = theDemo
1261 self
.tree
.Expand(root
)
1262 self
.tree
.Expand(firstChild
)
1263 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1264 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1265 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1266 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1268 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1269 # we put it in a panel first because there seems to be a
1270 # refresh bug of some sort (wxGTK) when it is directly in
1273 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1274 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1276 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1277 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1278 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1279 self
.nb
.AddPage(panel
, self
.overviewText
)
1281 def OnOvrSize(evt
, ovr
=self
.ovr
):
1282 ovr
.SetSize(evt
.GetSize())
1283 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1284 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1286 if "gtk2" in wx
.PlatformInfo
:
1287 self
.ovr
.SetStandardFonts()
1288 self
.SetOverview(self
.overviewText
, mainOverview
)
1291 # Set up a log window
1292 self
.log
= wx
.TextCtrl(splitter2
, -1,
1293 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1295 # Set the wxWindows log target to be this textctrl
1296 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1298 # But instead of the above we want to show how to use our own wx.Log class
1299 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1301 # for serious debugging
1302 #wx.Log_SetActiveTarget(wx.LogStderr())
1303 #wx.Log_SetTraceMask(wx.TraceMessages)
1306 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1307 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1309 # add the windows to the splitter and split it.
1310 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1311 splitter
.SplitVertically(self
.tree
, splitter2
, 200)
1313 splitter
.SetMinimumPaneSize(120)
1314 splitter2
.SetMinimumPaneSize(60)
1316 # Make the splitter on the right expand the top window when resized
1317 def SplitterOnSize(evt
):
1318 splitter
= evt
.GetEventObject()
1319 sz
= splitter
.GetSize()
1320 splitter
.SetSashPosition(sz
.height
- 160, False)
1323 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1325 # select initial items
1326 self
.nb
.SetSelection(0)
1327 self
.tree
.SelectItem(root
)
1329 # Load 'Main' module
1330 self
.LoadDemo(self
.overviewText
)
1333 # select some other initial module?
1334 if len(sys
.argv
) > 1:
1336 if arg
.endswith('.py'):
1338 selectedDemo
= self
.treeMap
.get(arg
, None)
1340 self
.tree
.SelectItem(selectedDemo
)
1341 self
.tree
.EnsureVisible(selectedDemo
)
1344 #---------------------------------------------
1345 def WriteText(self
, text
):
1346 if text
[-1:] == '\n':
1350 def write(self
, txt
):
1353 #---------------------------------------------
1354 def OnItemExpanded(self
, event
):
1355 item
= event
.GetItem()
1356 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1359 #---------------------------------------------
1360 def OnItemCollapsed(self
, event
):
1361 item
= event
.GetItem()
1362 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1365 #---------------------------------------------
1366 def OnTreeLeftDown(self
, event
):
1367 # reset the overview text if the tree item is clicked on again
1368 pt
= event
.GetPosition();
1369 item
, flags
= self
.tree
.HitTest(pt
)
1370 if item
== self
.tree
.GetSelection():
1371 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1374 #---------------------------------------------
1375 def OnSelChanged(self
, event
):
1376 if self
.dying
or not self
.loaded
:
1379 item
= event
.GetItem()
1380 itemText
= self
.tree
.GetItemText(item
)
1381 self
.LoadDemo(itemText
)
1383 #---------------------------------------------
1384 def LoadDemo(self
, demoName
):
1386 wx
.BeginBusyCursor()
1389 self
.ShutdownDemoModule()
1391 if demoName
== self
.overviewText
:
1392 # User selected the "wxPython Overview" node
1394 # Changing the main window at runtime not yet supported...
1395 self
.demoModules
= DemoModules(__name__
)
1396 self
.SetOverview(self
.overviewText
, mainOverview
)
1397 self
.LoadDemoSource()
1398 self
.UpdateNotebook(0)
1400 if os
.path
.exists(GetOriginalFilename(demoName
)):
1401 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1402 self
.demoModules
= DemoModules(demoName
)
1403 self
.LoadDemoSource()
1406 self
.SetOverview("wxPython", mainOverview
)
1407 self
.codePage
= None
1408 self
.UpdateNotebook(0)
1412 #---------------------------------------------
1413 def LoadDemoSource(self
):
1414 self
.codePage
= None
1415 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1416 self
.codePage
.LoadDemo(self
.demoModules
)
1418 #---------------------------------------------
1419 def RunModule(self
):
1420 """Runs the active module"""
1422 module
= self
.demoModules
.GetActive()
1423 self
.ShutdownDemoModule()
1426 # o The RunTest() for all samples must now return a window that can
1427 # be palced in a tab in the main notebook.
1428 # o If an error occurs (or has occurred before) an error tab is created.
1430 if module
is not None:
1431 wx
.LogMessage("Running demo module...")
1432 if hasattr(module
, "overview"):
1433 overviewText
= module
.overview
1436 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1438 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1439 DemoError(sys
.exc_info()), self
)
1441 assert self
.demoPage
is not None, "runTest must return a window!"
1444 # There was a previous error in compiling or exec-ing
1445 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1446 self
.demoModules
.GetErrorInfo(), self
)
1448 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1451 # cahnge to the demo page the first time a module is run
1452 self
.UpdateNotebook(2)
1453 self
.firstTime
= False
1455 # otherwise just stay on the same tab in case the user has changed to another one
1456 self
.UpdateNotebook()
1458 #---------------------------------------------
1459 def ShutdownDemoModule(self
):
1461 # inform the window that it's time to quit if it cares
1462 if hasattr(self
.demoPage
, "ShutdownDemo"):
1463 self
.demoPage
.ShutdownDemo()
1464 wx
.YieldIfNeeded() # in case the page has pending events
1465 self
.demoPage
= None
1467 #---------------------------------------------
1468 def UpdateNotebook(self
, select
= -1):
1472 def UpdatePage(page
, pageText
):
1475 for i
in range(nb
.GetPageCount()):
1476 if nb
.GetPageText(i
) == pageText
:
1484 nb
.AddPage(page
, pageText
)
1485 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1487 if nb
.GetPage(pagePos
) != page
:
1488 # Reload an existing page
1490 nb
.DeletePage(pagePos
)
1491 nb
.InsertPage(pagePos
, page
, pageText
)
1493 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1495 # Excellent! No redraw/flicker
1496 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1499 nb
.DeletePage(pagePos
)
1500 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1502 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1505 select
= nb
.GetSelection()
1507 UpdatePage(self
.codePage
, "Demo Code")
1508 UpdatePage(self
.demoPage
, "Demo")
1510 if select
>= 0 and select
< nb
.GetPageCount():
1511 nb
.SetSelection(select
)
1513 #---------------------------------------------
1514 def SetOverview(self
, name
, text
):
1515 self
.curOverview
= text
1517 if lead
!= '<html>' and lead
!= '<HTML>':
1518 text
= '<br>'.join(text
.split('\n'))
1520 text
= text
.decode('iso8859_1')
1521 self
.ovr
.SetPage(text
)
1522 self
.nb
.SetPageText(0, name
)
1524 #---------------------------------------------
1526 def OnFileExit(self
, *event
):
1529 def OnToggleRedirect(self
, event
):
1533 print "Print statements and other standard output will now be directed to this window."
1536 print "Print statements and other standard output will now be sent to the usual location."
1538 def OnHelpAbout(self
, event
):
1539 from About
import MyAboutBox
1540 about
= MyAboutBox(self
)
1544 def OnHelpFind(self
, event
):
1545 if self
.finddlg
!= None:
1548 self
.nb
.SetSelection(1)
1549 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1550 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1551 self
.finddlg
.Show(True)
1554 def OnUpdateFindItems(self
, evt
):
1555 evt
.Enable(self
.finddlg
== None)
1558 def OnFind(self
, event
):
1559 editor
= self
.codePage
.editor
1560 self
.nb
.SetSelection(1)
1561 end
= editor
.GetLastPosition()
1562 textstring
= editor
.GetRange(0, end
).lower()
1563 findstring
= self
.finddata
.GetFindString().lower()
1564 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1566 start
= editor
.GetSelection()[0]
1567 loc
= textstring
.rfind(findstring
, 0, start
)
1569 start
= editor
.GetSelection()[1]
1570 loc
= textstring
.find(findstring
, start
)
1571 if loc
== -1 and start
!= 0:
1572 # string not found, start at beginning
1575 loc
= textstring
.rfind(findstring
, 0, start
)
1578 loc
= textstring
.find(findstring
, start
)
1580 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1581 'Find String Not Found in Demo File',
1582 wx
.OK | wx
.ICON_INFORMATION
)
1587 self
.finddlg
.SetFocus()
1590 self
.finddlg
.Destroy()
1592 editor
.ShowPosition(loc
)
1593 editor
.SetSelection(loc
, loc
+ len(findstring
))
1597 def OnFindNext(self
, event
):
1598 if self
.finddata
.GetFindString():
1601 self
.OnHelpFind(event
)
1603 def OnFindClose(self
, event
):
1604 event
.GetDialog().Destroy()
1608 def OnOpenShellWindow(self
, evt
):
1610 # if it already exists then just make sure it's visible
1616 # Make a PyShell window
1618 namespace
= { 'wx' : wx
,
1619 'app' : wx
.GetApp(),
1622 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1623 self
.shell
.SetSize((640,480))
1626 # Hook the close event of the main frame window so that we
1627 # close the shell at the same time if it still exists
1628 def CloseShell(evt
):
1632 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1635 #---------------------------------------------
1636 def OnCloseWindow(self
, event
):
1638 self
.demoPage
= None
1639 self
.codePage
= None
1640 self
.mainmenu
= None
1641 if self
.tbicon
is not None:
1642 self
.tbicon
.Destroy()
1646 #---------------------------------------------
1647 def OnIdle(self
, event
):
1649 self
.otherWin
.Raise()
1650 self
.demoPage
= self
.otherWin
1651 self
.otherWin
= None
1654 #---------------------------------------------
1657 showTipText
= open(opj("data/showTips")).read()
1658 showTip
, index
= eval(showTipText
)
1660 showTip
, index
= (1, 0)
1662 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
1664 showTip
= wx
.ShowTip(self
, tp
)
1665 index
= tp
.GetCurrentTip()
1666 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
1669 #---------------------------------------------
1670 def OnDemoMenu(self
, event
):
1672 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
1676 self
.tree
.SelectItem(selectedDemo
)
1677 self
.tree
.EnsureVisible(selectedDemo
)
1681 #---------------------------------------------
1682 def OnIconfiy(self
, evt
):
1683 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
1686 #---------------------------------------------
1687 def OnMaximize(self
, evt
):
1688 wx
.LogMessage("OnMaximize")
1691 #---------------------------------------------
1692 def OnActivate(self
, evt
):
1693 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
1696 #---------------------------------------------
1697 def OnAppActivate(self
, evt
):
1698 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
1701 #---------------------------------------------------------------------------
1702 #---------------------------------------------------------------------------
1704 class MySplashScreen(wx
.SplashScreen
):
1706 bmp
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
1707 wx
.SplashScreen
.__init
__(self
, bmp
,
1708 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
1710 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
1711 self
.fc
= wx
.FutureCall(2000, self
.ShowMain
)
1714 def OnClose(self
, evt
):
1715 # Make sure the default handler runs too so this window gets
1720 # if the timer is still running then go ahead and show the
1722 if self
.fc
.IsRunning():
1728 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
1730 if self
.fc
.IsRunning():
1734 class MyApp(wx
.App
):
1737 Create and show the splash screen. It will then create and show
1738 the main frame when it is time to do so.
1741 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
1744 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1746 # Normally when using a SplashScreen you would create it, show
1747 # it and then continue on with the applicaiton's
1748 # initialization, finally creating and showing the main
1749 # application window(s). In this case we have nothing else to
1750 # do so we'll delay showing the main frame until later (see
1751 # ShowMain above) so the users can see the SplashScreen effect.
1752 splash
= MySplashScreen()
1759 #---------------------------------------------------------------------------
1763 demoPath
= os
.path
.dirname(__file__
)
1770 #---------------------------------------------------------------------------
1773 mainOverview
= """<html><body>
1776 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1777 language. It allows Python programmers to create programs with a
1778 robust, highly functional graphical user interface, simply and easily.
1779 It is implemented as a Python extension module (native code) that
1780 wraps the popular wxWindows cross platform GUI library, which is
1783 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1784 means that it is free for anyone to use and the source code is
1785 available for anyone to look at and modify. Or anyone can contribute
1786 fixes or enhancements to the project.
1788 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1789 same program will run on multiple platforms without modification.
1790 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1791 or unix-like systems, and Macintosh OS X. Since the language is
1792 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1795 <p> <b>This demo</b> is not only a collection of test cases for
1796 wxPython, but is also designed to help you learn about and how to use
1797 wxPython. Each sample is listed in the tree control on the left.
1798 When a sample is selected in the tree then a module is loaded and run
1799 (usually in a tab of this notebook,) and the source code of the module
1800 is loaded in another tab for you to browse and learn from.
1805 #----------------------------------------------------------------------------
1806 #----------------------------------------------------------------------------
1808 if __name__
== '__main__':
1812 #----------------------------------------------------------------------------