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',
71 # managed windows == things with a (optional) caption you can close
72 ('Frames and Dialogs', [
73 'AUI_DockingWindowMgr',
97 # dialogs from libraries
100 'ScrolledMessageDialog',
104 ('Core Windows/Controls', [
141 ('"Book" Controls', [
150 ('Custom Controls', [
167 # controls coming from other libraries
168 ('More Windows/Controls', [
169 'ActiveX_FlashWindow',
170 'ActiveX_IEHtmlWindow',
172 #'RightTextCtrl', deprecated as we have wxTE_RIGHT now.
175 'CheckListCtrlMixin',
191 'MaskedEditControls',
194 'MultiSplitterWindow',
211 # 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', [
264 ##'DialogUnits', # needs more explanations
283 ('Check out the samples dir too', [
290 #---------------------------------------------------------------------------
291 # Show how to derive a custom wxLog class
293 class MyLog(wx
.PyLog
):
294 def __init__(self
, textCtrl
, logTime
=0):
295 wx
.PyLog
.__init
__(self
)
297 self
.logTime
= logTime
299 def DoLogString(self
, message
, timeStamp
):
300 #print message, timeStamp
302 # message = time.strftime("%X", time.localtime(timeStamp)) + \
305 self
.tc
.AppendText(message
+ '\n')
308 class MyTP(wx
.PyTipProvider
):
310 return "This is my tip"
312 #---------------------------------------------------------------------------
313 # A class to be used to simply display a message in the demo pane
314 # rather than running the sample itself.
316 class MessagePanel(wx
.Panel
):
317 def __init__(self
, parent
, message
, caption
='', flags
=0):
318 wx
.Panel
.__init
__(self
, parent
)
323 if flags
& wx
.ICON_EXCLAMATION
:
324 artid
= wx
.ART_WARNING
325 elif flags
& wx
.ICON_ERROR
:
327 elif flags
& wx
.ICON_QUESTION
:
328 artid
= wx
.ART_QUESTION
329 elif flags
& wx
.ICON_INFORMATION
:
330 artid
= wx
.ART_INFORMATION
332 if artid
is not None:
333 bmp
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32))
334 icon
= wx
.StaticBitmap(self
, -1, bmp
)
336 icon
= (32,32) # make a spacer instead
339 caption
= wx
.StaticText(self
, -1, caption
)
340 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
342 message
= wx
.StaticText(self
, -1, message
)
344 # add to sizers for layout
345 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
351 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
358 box
= wx
.BoxSizer(wx
.VERTICAL
)
360 box
.Add(hbox
, 0, wx
.EXPAND
)
367 #---------------------------------------------------------------------------
368 # A class to be used to display source code in the demo. Try using the
369 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
370 # if there is an error, such as the stc module not being present.
374 ##raise ImportError # for testing the alternate implementation
376 from StyledTextCtrl_2
import PythonSTC
378 class DemoCodeEditor(PythonSTC
):
379 def __init__(self
, parent
):
380 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
383 # Some methods to make it compatible with how the wxTextCtrl is used
384 def SetValue(self
, value
):
386 value
= value
.decode('iso8859_1')
388 self
.EmptyUndoBuffer()
391 def IsModified(self
):
392 return self
.GetModify()
397 def SetInsertionPoint(self
, pos
):
398 self
.SetCurrentPos(pos
)
401 def ShowPosition(self
, pos
):
402 line
= self
.LineFromPosition(pos
)
403 #self.EnsureVisible(line)
406 def GetLastPosition(self
):
407 return self
.GetLength()
409 def GetPositionFromLine(self
, line
):
410 return self
.PositionFromLine(line
)
412 def GetRange(self
, start
, end
):
413 return self
.GetTextRange(start
, end
)
415 def GetSelection(self
):
416 return self
.GetAnchor(), self
.GetCurrentPos()
418 def SetSelection(self
, start
, end
):
419 self
.SetSelectionStart(start
)
420 self
.SetSelectionEnd(end
)
422 def SelectLine(self
, line
):
423 start
= self
.PositionFromLine(line
)
424 end
= self
.GetLineEndPosition(line
)
425 self
.SetSelection(start
, end
)
427 def SetUpEditor(self
):
429 This method carries out the work of setting up the demo editor.
430 It's seperate so as not to clutter up the init code.
434 self
.SetLexer(stc
.STC_LEX_PYTHON
)
435 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
438 self
.SetProperty("fold", "1" )
440 # Highlight tab/space mixing (shouldn't be any)
441 self
.SetProperty("tab.timmy.whinge.level", "1")
443 # Set left and right margins
446 # Set up the numbers in the margin for margin #1
447 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
448 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
449 self
.SetMarginWidth(1, 40)
451 # Indentation and tab stuff
452 self
.SetIndent(4) # Proscribed indent size for wx
453 self
.SetIndentationGuides(True) # Show indent guides
454 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
455 self
.SetTabIndents(True) # Tab key indents
456 self
.SetTabWidth(4) # Proscribed tab size for wx
457 self
.SetUseTabs(False) # Use spaces rather than tabs, or
458 # TabTimmy will complain!
460 self
.SetViewWhiteSpace(False) # Don't view white space
462 # EOL: Since we are loading/saving ourselves, and the
463 # strings will always have \n's in them, set the STC to
464 # edit them that way.
465 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
466 self
.SetViewEOL(False)
468 # No right-edge mode indicator
469 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
471 # Setup a margin to hold fold markers
472 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
473 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
474 self
.SetMarginSensitive(2, True)
475 self
.SetMarginWidth(2, 12)
477 # and now set up the fold markers
478 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
479 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
480 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
481 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
482 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
483 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
484 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
486 # Global default style
487 if wx
.Platform
== '__WXMSW__':
488 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
489 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
491 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
492 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
494 # Clear styles and revert to default.
497 # Following style specs only indicate differences from default.
498 # The rest remains unchanged.
500 # Line numbers in margin
501 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
503 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
505 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
507 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
510 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
512 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
513 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
515 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
516 # Strings and characters
517 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
518 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
520 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
522 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
523 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
525 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
527 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
529 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
530 # Identifiers. I leave this as not bold because everything seems
531 # to be an identifier if it doesn't match the above criterae
532 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
535 self
.SetCaretForeground("BLUE")
536 # Selection background
537 self
.SetSelBackground(1, '#66CCFF')
539 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
540 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
542 def RegisterModifiedEvent(self
, eventHandler
):
543 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
547 class DemoCodeEditor(wx
.TextCtrl
):
548 def __init__(self
, parent
):
549 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
550 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
552 def RegisterModifiedEvent(self
, eventHandler
):
553 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
555 def SetReadOnly(self
, flag
):
556 self
.SetEditable(not flag
)
557 # NOTE: STC already has this method
560 return self
.GetValue()
562 def GetPositionFromLine(self
, line
):
563 return self
.XYToPosition(0,line
)
565 def GotoLine(self
, line
):
566 pos
= self
.GetPositionFromLine(line
)
567 self
.SetInsertionPoint(pos
)
568 self
.ShowPosition(pos
)
570 def SelectLine(self
, line
):
571 start
= self
.GetPositionFromLine(line
)
572 end
= start
+ self
.GetLineLength(line
)
573 self
.SetSelection(start
, end
)
576 #---------------------------------------------------------------------------
577 # Constants for module versions
581 modDefault
= modOriginal
583 #---------------------------------------------------------------------------
585 class DemoCodePanel(wx
.Panel
):
586 """Panel for the 'Demo Code' tab"""
587 def __init__(self
, parent
, mainFrame
):
588 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
589 if 'wxMSW' in wx
.PlatformInfo
:
591 self
.mainFrame
= mainFrame
592 self
.editor
= DemoCodeEditor(self
)
593 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
595 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
596 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
597 self
.btnSave
.Enable(False)
598 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
599 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
601 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
602 modModified
: wx
.RadioButton(self
, -1, "Modified") }
604 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
605 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
606 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
607 for modID
, radioButton
in self
.radioButtons
.items():
608 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
609 radioButton
.modID
= modID
# makes it easier for the event handler
610 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
612 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
613 self
.controlBox
.Add(self
.btnRestore
, 0)
615 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
616 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
617 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
618 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
621 self
.SetSizer(self
.box
)
624 # Loads a demo from a DemoModules object
625 def LoadDemo(self
, demoModules
):
626 self
.demoModules
= demoModules
627 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
628 demoModules
.SetActive(modModified
)
630 demoModules
.SetActive(modOriginal
)
631 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
632 self
.ActiveModuleChanged()
635 def ActiveModuleChanged(self
):
636 self
.LoadDemoSource(self
.demoModules
.GetSource())
637 self
.UpdateControlState()
641 def LoadDemoSource(self
, source
):
643 self
.editor
.SetValue(source
)
645 self
.btnSave
.Enable(False)
648 def JumpToLine(self
, line
, highlight
=False):
649 self
.editor
.GotoLine(line
)
650 self
.editor
.SetFocus()
652 self
.editor
.SelectLine(line
)
655 def UpdateControlState(self
):
656 active
= self
.demoModules
.GetActiveID()
657 # Update the radio/restore buttons
658 for moduleID
in self
.radioButtons
:
659 btn
= self
.radioButtons
[moduleID
]
660 if moduleID
== active
:
665 if self
.demoModules
.Exists(moduleID
):
667 if moduleID
== modModified
:
668 self
.btnRestore
.Enable(True)
671 if moduleID
== modModified
:
672 self
.btnRestore
.Enable(False)
675 def OnRadioButton(self
, event
):
676 radioSelected
= event
.GetEventObject()
677 modSelected
= radioSelected
.modID
678 if modSelected
!= self
.demoModules
.GetActiveID():
679 busy
= wx
.BusyInfo("Reloading demo module...")
680 self
.demoModules
.SetActive(modSelected
)
681 self
.ActiveModuleChanged()
684 def ReloadDemo(self
):
685 if self
.demoModules
.name
!= __name__
:
686 self
.mainFrame
.RunModule()
689 def OnCodeModified(self
, event
):
690 self
.btnSave
.Enable(self
.editor
.IsModified())
693 def OnSave(self
, event
):
694 if self
.demoModules
.Exists(modModified
):
695 if self
.demoModules
.GetActiveID() == modOriginal
:
696 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
697 "Do you want to continue?"
698 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
699 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
700 result
= dlg
.ShowModal()
701 if result
== wx
.ID_NO
:
705 self
.demoModules
.SetActive(modModified
)
706 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
708 # Create the demo directory if one doesn't already exist
709 if not os
.path
.exists(GetModifiedDirectory()):
711 os
.makedirs(GetModifiedDirectory())
712 if not os
.path
.exists(GetModifiedDirectory()):
713 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
716 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
719 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
722 f
= open(modifiedFilename
, "wt")
723 source
= self
.editor
.GetText()
729 busy
= wx
.BusyInfo("Reloading demo module...")
730 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
731 self
.ActiveModuleChanged()
734 def OnRestore(self
, event
): # Handles the "Delete Modified" button
735 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
736 self
.demoModules
.Delete(modModified
)
737 os
.unlink(modifiedFilename
) # Delete the modified copy
738 busy
= wx
.BusyInfo("Reloading demo module...")
739 self
.ActiveModuleChanged()
742 #---------------------------------------------------------------------------
745 """Convert paths to the platform-specific separator"""
746 str = apply(os
.path
.join
, tuple(path
.split('/')))
747 # HACK: on Linux, a leading / gets lost...
748 if path
.startswith('/'):
753 def GetModifiedDirectory():
755 Returns the directory where modified versions of the demo files
758 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
761 def GetModifiedFilename(name
):
763 Returns the filename of the modified version of the specified demo
765 if not name
.endswith(".py"):
767 return GetModifiedDirectory() + name
770 def GetOriginalFilename(name
):
772 Returns the filename of the original version of the specified demo
774 if not name
.endswith(".py"):
779 def DoesModifiedExist(name
):
780 """Returns whether the specified demo has a modified copy"""
781 if os
.path
.exists(GetModifiedFilename(name
)):
787 #---------------------------------------------------------------------------
789 class ModuleDictWrapper
:
790 """Emulates a module with a dynamically compiled __dict__"""
791 def __init__(self
, dict):
794 def __getattr__(self
, name
):
795 if name
in self
.dict:
796 return self
.dict[name
]
802 Dynamically manages the original/modified versions of a demo
805 def __init__(self
, name
):
809 # (dict , source , filename , description , error information )
810 # ( 0 , 1 , 2 , 3 , 4 )
811 self
.modules
= [[None, "" , "" , "<original>" , None],
812 [None, "" , "" , "<modified>" , None]]
814 # load original module
815 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
816 self
.SetActive(modOriginal
)
818 # load modified module (if one exists)
819 if DoesModifiedExist(name
):
820 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
823 def LoadFromFile(self
, modID
, filename
):
824 self
.modules
[modID
][2] = filename
825 file = open(filename
, "rt")
826 self
.LoadFromSource(modID
, file.read())
830 def LoadFromSource(self
, modID
, source
):
831 self
.modules
[modID
][1] = source
835 def LoadDict(self
, modID
):
836 if self
.name
!= __name__
:
837 source
= self
.modules
[modID
][1]
838 #description = self.modules[modID][3]
839 description
= self
.modules
[modID
][2]
842 self
.modules
[modID
][0] = {}
843 code
= compile(source
, description
, "exec")
844 exec code
in self
.modules
[modID
][0]
846 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
847 self
.modules
[modID
][0] = None
849 self
.modules
[modID
][4] = None
852 def SetActive(self
, modID
):
853 if modID
!= modOriginal
and modID
!= modModified
:
856 self
.modActive
= modID
860 dict = self
.modules
[self
.modActive
][0]
864 return ModuleDictWrapper(dict)
867 def GetActiveID(self
):
868 return self
.modActive
871 def GetSource(self
, modID
= None):
873 modID
= self
.modActive
874 return self
.modules
[modID
][1]
877 def GetFilename(self
, modID
= None):
879 modID
= self
.modActive
880 return self
.modules
[self
.modActive
][2]
883 def GetErrorInfo(self
, modID
= None):
885 modID
= self
.modActive
886 return self
.modules
[self
.modActive
][4]
889 def Exists(self
, modID
):
890 return self
.modules
[modID
][1] != ""
893 def UpdateFile(self
, modID
= None):
894 """Updates the file from which a module was loaded
895 with (possibly updated) source"""
897 modID
= self
.modActive
899 source
= self
.modules
[modID
][1]
900 filename
= self
.modules
[modID
][2]
903 file = open(filename
, "wt")
909 def Delete(self
, modID
):
910 if self
.modActive
== modID
:
913 self
.modules
[modID
][0] = None
914 self
.modules
[modID
][1] = ""
915 self
.modules
[modID
][2] = ""
918 #---------------------------------------------------------------------------
921 """Wraps and stores information about the current exception"""
922 def __init__(self
, exc_info
):
925 excType
, excValue
= exc_info
[:2]
926 # traceback list entries: (filename, line number, function name, text)
927 self
.traceback
= traceback
.extract_tb(exc_info
[2])
929 # --Based on traceback.py::format_exception_only()--
930 if type(excType
) == types
.ClassType
:
931 self
.exception_type
= excType
.__name
__
933 self
.exception_type
= excType
935 # If it's a syntax error, extra information needs
936 # to be added to the traceback
937 if excType
is SyntaxError:
939 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
944 filename
= "<string>"
946 self
.traceback
.append( (filename
, lineno
, "", line
) )
949 self
.exception_details
= str(excValue
)
951 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
958 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
961 #---------------------------------------------------------------------------
963 class DemoErrorPanel(wx
.Panel
):
964 """Panel put into the demo tab when the demo fails to run due to errors"""
966 def __init__(self
, parent
, codePanel
, demoError
, log
):
967 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
968 self
.codePanel
= codePanel
972 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
975 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo")
976 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
978 # Exception Information
979 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
980 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
981 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
982 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
983 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
984 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_type
) , 0, textFlags
, 5 )
985 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
986 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
987 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
988 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
990 # Set up the traceback list
991 # This one automatically resizes last column to take up remaining space
992 from ListCtrl
import TestListCtrl
993 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
994 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
995 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
996 self
.list.InsertColumn(0, "Filename")
997 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
998 self
.list.InsertColumn(2, "Function")
999 self
.list.InsertColumn(3, "Code")
1000 self
.InsertTraceback(self
.list, demoError
.traceback
)
1001 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
1002 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
1003 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
1004 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
1005 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
1006 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
1007 + "Double-click on them to go to the offending line")
1008 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
1011 self
.SetSizer(self
.box
)
1014 def InsertTraceback(self
, list, traceback
):
1015 #Add the traceback data
1016 for x
in range(len(traceback
)):
1018 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
1019 list.SetStringItem(x
, 1, str(data
[1])) # Line
1020 list.SetStringItem(x
, 2, str(data
[2])) # Function
1021 list.SetStringItem(x
, 3, str(data
[3])) # Code
1023 # Check whether this entry is from the demo module
1024 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
1025 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
1026 # Give it a blue colour
1027 item
= self
.list.GetItem(x
)
1028 item
.SetTextColour(wx
.BLUE
)
1029 self
.list.SetItem(item
)
1031 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
1034 def OnItemSelected(self
, event
):
1035 # This occurs before OnDoubleClick and can be used to set the
1036 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1037 self
.currentItem
= event
.m_itemIndex
1041 def OnDoubleClick(self
, event
):
1042 # If double-clicking on a demo's entry, jump to the line number
1043 line
= self
.list.GetItemData(self
.currentItem
)
1045 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1046 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1050 #---------------------------------------------------------------------------
1052 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1053 TBMENU_RESTORE
= wx
.NewId()
1054 TBMENU_CLOSE
= wx
.NewId()
1055 TBMENU_CHANGE
= wx
.NewId()
1056 TBMENU_REMOVE
= wx
.NewId()
1058 def __init__(self
, frame
):
1059 wx
.TaskBarIcon
.__init
__(self
)
1063 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1064 self
.SetIcon(icon
, "wxPython Demo")
1068 self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1069 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1070 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1071 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
)
1072 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
)
1075 def CreatePopupMenu(self
):
1077 This method is called by the base class when it needs to popup
1078 the menu for the default EVT_RIGHT_DOWN event. Just create
1079 the menu how you want it and return it from this function,
1080 the base class takes care of the rest.
1083 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1084 menu
.Append(self
.TBMENU_CLOSE
, "Close wxPython Demo")
1085 menu
.AppendSeparator()
1086 menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon")
1087 menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon")
1091 def MakeIcon(self
, img
):
1093 The various platforms have different requirements for the
1096 if "wxMSW" in wx
.PlatformInfo
:
1097 img
= img
.Scale(16, 16)
1098 elif "wxGTK" in wx
.PlatformInfo
:
1099 img
= img
.Scale(22, 22)
1100 # wxMac can be any size upto 128x128, so leave the source img alone....
1101 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
1105 def OnTaskBarActivate(self
, evt
):
1106 if self
.frame
.IsIconized():
1107 self
.frame
.Iconize(False)
1108 if not self
.frame
.IsShown():
1109 self
.frame
.Show(True)
1113 def OnTaskBarClose(self
, evt
):
1117 def OnTaskBarChange(self
, evt
):
1118 names
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
1119 name
= names
[self
.imgidx
]
1121 getFunc
= getattr(images
, "get%sImage" % name
)
1123 if self
.imgidx
>= len(names
):
1126 icon
= self
.MakeIcon(getFunc())
1127 self
.SetIcon(icon
, "This is a new icon: " + name
)
1130 def OnTaskBarRemove(self
, evt
):
1134 #---------------------------------------------------------------------------
1135 class wxPythonDemo(wx
.Frame
):
1136 overviewText
= "wxPython Overview"
1138 def __init__(self
, parent
, title
):
1139 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 720),
1140 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1142 self
.SetMinSize((640,480))
1145 self
.cwd
= os
.getcwd()
1146 self
.curOverview
= ""
1147 self
.demoPage
= None
1148 self
.codePage
= None
1150 self
.firstTime
= True
1153 icon
= images
.getWXPdemoIcon()
1157 self
.tbicon
= DemoTaskBarIcon(self
)
1161 wx
.CallAfter(self
.ShowTip
)
1163 self
.otherWin
= None
1164 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1165 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1166 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1167 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1169 self
.Centre(wx
.BOTH
)
1170 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1172 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1173 splitter2
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1175 def EmptyHandler(evt
): pass
1176 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1177 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1179 # Prevent TreeCtrl from displaying all items after destruction when True
1183 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1186 self
.mainmenu
= wx
.MenuBar()
1188 item
= menu
.Append(-1, '&Redirect Output',
1189 'Redirect print statements to a window',
1191 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1193 item
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1194 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
)
1195 wx
.App
.SetMacExitMenuItemId(item
.GetId())
1196 self
.mainmenu
.Append(menu
, '&File')
1200 for item
in _treeList
:
1202 for childItem
in item
[1]:
1203 mi
= submenu
.Append(-1, childItem
)
1204 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1205 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1206 self
.mainmenu
.Append(menu
, '&Demo')
1211 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1212 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1213 menu
.AppendSeparator()
1215 shellItem
= menu
.Append(-1, 'Open Py&Shell Window\tF5',
1216 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1217 menu
.AppendSeparator()
1218 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1219 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1221 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1222 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1223 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1224 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1225 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1226 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1227 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1228 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1229 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
)
1230 self
.mainmenu
.Append(menu
, '&Help')
1231 self
.SetMenuBar(self
.mainmenu
)
1233 self
.finddata
= wx
.FindReplaceData()
1234 self
.finddata
.SetFlags(wx
.FR_DOWN
)
1237 # This is another way to set Accelerators, in addition to
1238 # using the '\t<key>' syntax in the menu items.
1239 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitID
),
1240 (wx
.ACCEL_CTRL
, ord('H'), helpID
),
1241 (wx
.ACCEL_CTRL
, ord('F'), findID
),
1242 (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
)
1244 self
.SetAcceleratorTable(aTable
)
1250 self
.tree
= wx
.TreeCtrl(splitter
, tID
, style
=
1251 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1254 root
= self
.tree
.AddRoot("wxPython Overview")
1256 for item
in _treeList
:
1257 child
= self
.tree
.AppendItem(root
, item
[0])
1258 if not firstChild
: firstChild
= child
1259 for childItem
in item
[1]:
1260 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1261 self
.treeMap
[childItem
] = theDemo
1263 self
.tree
.Expand(root
)
1264 self
.tree
.Expand(firstChild
)
1265 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1266 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1267 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1268 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1270 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1271 # we put it in a panel first because there seems to be a
1272 # refresh bug of some sort (wxGTK) when it is directly in
1275 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1276 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1278 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1279 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1280 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1281 self
.nb
.AddPage(panel
, self
.overviewText
)
1283 def OnOvrSize(evt
, ovr
=self
.ovr
):
1284 ovr
.SetSize(evt
.GetSize())
1285 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1286 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1288 if "gtk2" in wx
.PlatformInfo
:
1289 self
.ovr
.SetStandardFonts()
1290 self
.SetOverview(self
.overviewText
, mainOverview
)
1293 # Set up a log window
1294 self
.log
= wx
.TextCtrl(splitter2
, -1,
1295 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1297 # Set the wxWindows log target to be this textctrl
1298 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1300 # But instead of the above we want to show how to use our own wx.Log class
1301 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1303 # for serious debugging
1304 #wx.Log_SetActiveTarget(wx.LogStderr())
1305 #wx.Log_SetTraceMask(wx.TraceMessages)
1308 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1309 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1311 # add the windows to the splitter and split it.
1312 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1313 splitter
.SplitVertically(self
.tree
, splitter2
, 200)
1315 splitter
.SetMinimumPaneSize(120)
1316 splitter2
.SetMinimumPaneSize(60)
1318 # Make the splitter on the right expand the top window when resized
1319 def SplitterOnSize(evt
):
1320 splitter
= evt
.GetEventObject()
1321 sz
= splitter
.GetSize()
1322 splitter
.SetSashPosition(sz
.height
- 160, False)
1325 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1327 # select initial items
1328 self
.nb
.SetSelection(0)
1329 self
.tree
.SelectItem(root
)
1331 # Load 'Main' module
1332 self
.LoadDemo(self
.overviewText
)
1335 # select some other initial module?
1336 if len(sys
.argv
) > 1:
1338 if arg
.endswith('.py'):
1340 selectedDemo
= self
.treeMap
.get(arg
, None)
1342 self
.tree
.SelectItem(selectedDemo
)
1343 self
.tree
.EnsureVisible(selectedDemo
)
1346 #---------------------------------------------
1347 def WriteText(self
, text
):
1348 if text
[-1:] == '\n':
1352 def write(self
, txt
):
1355 #---------------------------------------------
1356 def OnItemExpanded(self
, event
):
1357 item
= event
.GetItem()
1358 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1361 #---------------------------------------------
1362 def OnItemCollapsed(self
, event
):
1363 item
= event
.GetItem()
1364 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1367 #---------------------------------------------
1368 def OnTreeLeftDown(self
, event
):
1369 # reset the overview text if the tree item is clicked on again
1370 pt
= event
.GetPosition();
1371 item
, flags
= self
.tree
.HitTest(pt
)
1372 if item
== self
.tree
.GetSelection():
1373 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1376 #---------------------------------------------
1377 def OnSelChanged(self
, event
):
1378 if self
.dying
or not self
.loaded
:
1381 item
= event
.GetItem()
1382 itemText
= self
.tree
.GetItemText(item
)
1383 self
.LoadDemo(itemText
)
1385 #---------------------------------------------
1386 def LoadDemo(self
, demoName
):
1388 wx
.BeginBusyCursor()
1391 self
.ShutdownDemoModule()
1393 if demoName
== self
.overviewText
:
1394 # User selected the "wxPython Overview" node
1396 # Changing the main window at runtime not yet supported...
1397 self
.demoModules
= DemoModules(__name__
)
1398 self
.SetOverview(self
.overviewText
, mainOverview
)
1399 self
.LoadDemoSource()
1400 self
.UpdateNotebook(0)
1402 if os
.path
.exists(GetOriginalFilename(demoName
)):
1403 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1404 self
.demoModules
= DemoModules(demoName
)
1405 self
.LoadDemoSource()
1408 self
.SetOverview("wxPython", mainOverview
)
1409 self
.codePage
= None
1410 self
.UpdateNotebook(0)
1414 #---------------------------------------------
1415 def LoadDemoSource(self
):
1416 self
.codePage
= None
1417 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1418 self
.codePage
.LoadDemo(self
.demoModules
)
1420 #---------------------------------------------
1421 def RunModule(self
):
1422 """Runs the active module"""
1424 module
= self
.demoModules
.GetActive()
1425 self
.ShutdownDemoModule()
1428 # o The RunTest() for all samples must now return a window that can
1429 # be palced in a tab in the main notebook.
1430 # o If an error occurs (or has occurred before) an error tab is created.
1432 if module
is not None:
1433 wx
.LogMessage("Running demo module...")
1434 if hasattr(module
, "overview"):
1435 overviewText
= module
.overview
1438 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1440 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1441 DemoError(sys
.exc_info()), self
)
1443 assert self
.demoPage
is not None, "runTest must return a window!"
1446 # There was a previous error in compiling or exec-ing
1447 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1448 self
.demoModules
.GetErrorInfo(), self
)
1450 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1453 # cahnge to the demo page the first time a module is run
1454 self
.UpdateNotebook(2)
1455 self
.firstTime
= False
1457 # otherwise just stay on the same tab in case the user has changed to another one
1458 self
.UpdateNotebook()
1460 #---------------------------------------------
1461 def ShutdownDemoModule(self
):
1463 # inform the window that it's time to quit if it cares
1464 if hasattr(self
.demoPage
, "ShutdownDemo"):
1465 self
.demoPage
.ShutdownDemo()
1466 wx
.YieldIfNeeded() # in case the page has pending events
1467 self
.demoPage
= None
1469 #---------------------------------------------
1470 def UpdateNotebook(self
, select
= -1):
1474 def UpdatePage(page
, pageText
):
1477 for i
in range(nb
.GetPageCount()):
1478 if nb
.GetPageText(i
) == pageText
:
1486 nb
.AddPage(page
, pageText
)
1487 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1489 if nb
.GetPage(pagePos
) != page
:
1490 # Reload an existing page
1492 nb
.DeletePage(pagePos
)
1493 nb
.InsertPage(pagePos
, page
, pageText
)
1495 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1497 # Excellent! No redraw/flicker
1498 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1501 nb
.DeletePage(pagePos
)
1502 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1504 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1507 select
= nb
.GetSelection()
1509 UpdatePage(self
.codePage
, "Demo Code")
1510 UpdatePage(self
.demoPage
, "Demo")
1512 if select
>= 0 and select
< nb
.GetPageCount():
1513 nb
.SetSelection(select
)
1515 #---------------------------------------------
1516 def SetOverview(self
, name
, text
):
1517 self
.curOverview
= text
1519 if lead
!= '<html>' and lead
!= '<HTML>':
1520 text
= '<br>'.join(text
.split('\n'))
1522 text
= text
.decode('iso8859_1')
1523 self
.ovr
.SetPage(text
)
1524 self
.nb
.SetPageText(0, name
)
1526 #---------------------------------------------
1528 def OnFileExit(self
, *event
):
1531 def OnToggleRedirect(self
, event
):
1535 print "Print statements and other standard output will now be directed to this window."
1538 print "Print statements and other standard output will now be sent to the usual location."
1540 def OnHelpAbout(self
, event
):
1541 from About
import MyAboutBox
1542 about
= MyAboutBox(self
)
1546 def OnHelpFind(self
, event
):
1547 if self
.finddlg
!= None:
1550 self
.nb
.SetSelection(1)
1551 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1552 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1553 self
.finddlg
.Show(True)
1556 def OnUpdateFindItems(self
, evt
):
1557 evt
.Enable(self
.finddlg
== None)
1560 def OnFind(self
, event
):
1561 editor
= self
.codePage
.editor
1562 self
.nb
.SetSelection(1)
1563 end
= editor
.GetLastPosition()
1564 textstring
= editor
.GetRange(0, end
).lower()
1565 findstring
= self
.finddata
.GetFindString().lower()
1566 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1568 start
= editor
.GetSelection()[0]
1569 loc
= textstring
.rfind(findstring
, 0, start
)
1571 start
= editor
.GetSelection()[1]
1572 loc
= textstring
.find(findstring
, start
)
1573 if loc
== -1 and start
!= 0:
1574 # string not found, start at beginning
1577 loc
= textstring
.rfind(findstring
, 0, start
)
1580 loc
= textstring
.find(findstring
, start
)
1582 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1583 'Find String Not Found in Demo File',
1584 wx
.OK | wx
.ICON_INFORMATION
)
1589 self
.finddlg
.SetFocus()
1592 self
.finddlg
.Destroy()
1594 editor
.ShowPosition(loc
)
1595 editor
.SetSelection(loc
, loc
+ len(findstring
))
1599 def OnFindNext(self
, event
):
1600 if self
.finddata
.GetFindString():
1603 self
.OnHelpFind(event
)
1605 def OnFindClose(self
, event
):
1606 event
.GetDialog().Destroy()
1610 def OnOpenShellWindow(self
, evt
):
1612 # if it already exists then just make sure it's visible
1618 # Make a PyShell window
1620 namespace
= { 'wx' : wx
,
1621 'app' : wx
.GetApp(),
1624 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1625 self
.shell
.SetSize((640,480))
1628 # Hook the close event of the main frame window so that we
1629 # close the shell at the same time if it still exists
1630 def CloseShell(evt
):
1634 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1637 #---------------------------------------------
1638 def OnCloseWindow(self
, event
):
1640 self
.demoPage
= None
1641 self
.codePage
= None
1642 self
.mainmenu
= None
1643 if self
.tbicon
is not None:
1644 self
.tbicon
.Destroy()
1648 #---------------------------------------------
1649 def OnIdle(self
, event
):
1651 self
.otherWin
.Raise()
1652 self
.demoPage
= self
.otherWin
1653 self
.otherWin
= None
1656 #---------------------------------------------
1659 showTipText
= open(opj("data/showTips")).read()
1660 showTip
, index
= eval(showTipText
)
1662 showTip
, index
= (1, 0)
1664 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
1666 showTip
= wx
.ShowTip(self
, tp
)
1667 index
= tp
.GetCurrentTip()
1668 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
1671 #---------------------------------------------
1672 def OnDemoMenu(self
, event
):
1674 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
1678 self
.tree
.SelectItem(selectedDemo
)
1679 self
.tree
.EnsureVisible(selectedDemo
)
1683 #---------------------------------------------
1684 def OnIconfiy(self
, evt
):
1685 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
1688 #---------------------------------------------
1689 def OnMaximize(self
, evt
):
1690 wx
.LogMessage("OnMaximize")
1693 #---------------------------------------------
1694 def OnActivate(self
, evt
):
1695 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
1698 #---------------------------------------------
1699 def OnAppActivate(self
, evt
):
1700 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
1703 #---------------------------------------------------------------------------
1704 #---------------------------------------------------------------------------
1706 class MySplashScreen(wx
.SplashScreen
):
1708 bmp
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
1709 wx
.SplashScreen
.__init
__(self
, bmp
,
1710 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
1712 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
1713 self
.fc
= wx
.FutureCall(2000, self
.ShowMain
)
1716 def OnClose(self
, evt
):
1717 # Make sure the default handler runs too so this window gets
1722 # if the timer is still running then go ahead and show the
1724 if self
.fc
.IsRunning():
1730 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
1732 if self
.fc
.IsRunning():
1736 class MyApp(wx
.App
):
1739 Create and show the splash screen. It will then create and show
1740 the main frame when it is time to do so.
1743 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
1746 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1748 # Normally when using a SplashScreen you would create it, show
1749 # it and then continue on with the applicaiton's
1750 # initialization, finally creating and showing the main
1751 # application window(s). In this case we have nothing else to
1752 # do so we'll delay showing the main frame until later (see
1753 # ShowMain above) so the users can see the SplashScreen effect.
1754 splash
= MySplashScreen()
1761 #---------------------------------------------------------------------------
1765 demoPath
= os
.path
.dirname(__file__
)
1772 #---------------------------------------------------------------------------
1775 mainOverview
= """<html><body>
1778 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1779 language. It allows Python programmers to create programs with a
1780 robust, highly functional graphical user interface, simply and easily.
1781 It is implemented as a Python extension module (native code) that
1782 wraps the popular wxWindows cross platform GUI library, which is
1785 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1786 means that it is free for anyone to use and the source code is
1787 available for anyone to look at and modify. Or anyone can contribute
1788 fixes or enhancements to the project.
1790 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1791 same program will run on multiple platforms without modification.
1792 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1793 or unix-like systems, and Macintosh OS X. Since the language is
1794 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1797 <p> <b>This demo</b> is not only a collection of test cases for
1798 wxPython, but is also designed to help you learn about and how to use
1799 wxPython. Each sample is listed in the tree control on the left.
1800 When a sample is selected in the tree then a module is loaded and run
1801 (usually in a tab of this notebook,) and the source code of the module
1802 is loaded in another tab for you to browse and learn from.
1807 #----------------------------------------------------------------------------
1808 #----------------------------------------------------------------------------
1810 if __name__
== '__main__':
1814 #----------------------------------------------------------------------------