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',
67 # managed windows == things with a (optional) caption you can close
68 ('Frames and Dialogs', [
69 'AUI_DockingWindowMgr',
93 # dialogs from libraries
96 'ScrolledMessageDialog',
100 ('Core Windows/Controls', [
137 ('"Book" Controls', [
146 ('Custom Controls', [
160 # controls coming from other libraries
161 ('More Windows/Controls', [
162 'ActiveX_FlashWindow',
163 'ActiveX_IEHtmlWindow',
165 #'RightTextCtrl', deprecated as we have wxTE_RIGHT now.
168 'CheckListCtrlMixin',
183 'MaskedEditControls',
186 'MultiSplitterWindow',
203 # How to lay out the controls in a frame/dialog
213 'XmlResourceHandler',
214 'XmlResourceSubclass',
218 ('Process and Events', [
226 ##'infoframe', # needs better explanation and some fixing
230 ('Clipboard and DnD', [
256 ##'DialogUnits', # needs more explanations
275 ('Check out the samples dir too', [
282 #---------------------------------------------------------------------------
283 # Show how to derive a custom wxLog class
285 class MyLog(wx
.PyLog
):
286 def __init__(self
, textCtrl
, logTime
=0):
287 wx
.PyLog
.__init
__(self
)
289 self
.logTime
= logTime
291 def DoLogString(self
, message
, timeStamp
):
292 #print message, timeStamp
294 # message = time.strftime("%X", time.localtime(timeStamp)) + \
297 self
.tc
.AppendText(message
+ '\n')
300 class MyTP(wx
.PyTipProvider
):
302 return "This is my tip"
304 #---------------------------------------------------------------------------
305 # A class to be used to simply display a message in the demo pane
306 # rather than running the sample itself.
308 class MessagePanel(wx
.Panel
):
309 def __init__(self
, parent
, message
, caption
='', flags
=0):
310 wx
.Panel
.__init
__(self
, parent
)
315 if flags
& wx
.ICON_EXCLAMATION
:
316 artid
= wx
.ART_WARNING
317 elif flags
& wx
.ICON_ERROR
:
319 elif flags
& wx
.ICON_QUESTION
:
320 artid
= wx
.ART_QUESTION
321 elif flags
& wx
.ICON_INFORMATION
:
322 artid
= wx
.ART_INFORMATION
324 if artid
is not None:
325 bmp
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32))
326 icon
= wx
.StaticBitmap(self
, -1, bmp
)
328 icon
= (32,32) # make a spacer instead
331 caption
= wx
.StaticText(self
, -1, caption
)
332 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
334 message
= wx
.StaticText(self
, -1, message
)
336 # add to sizers for layout
337 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
343 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
350 box
= wx
.BoxSizer(wx
.VERTICAL
)
352 box
.Add(hbox
, 0, wx
.EXPAND
)
359 #---------------------------------------------------------------------------
360 # A class to be used to display source code in the demo. Try using the
361 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
362 # if there is an error, such as the stc module not being present.
366 ##raise ImportError # for testing the alternate implementation
368 from StyledTextCtrl_2
import PythonSTC
370 class DemoCodeEditor(PythonSTC
):
371 def __init__(self
, parent
):
372 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
375 # Some methods to make it compatible with how the wxTextCtrl is used
376 def SetValue(self
, value
):
378 value
= value
.decode('iso8859_1')
380 self
.EmptyUndoBuffer()
383 def IsModified(self
):
384 return self
.GetModify()
389 def SetInsertionPoint(self
, pos
):
390 self
.SetCurrentPos(pos
)
393 def ShowPosition(self
, pos
):
394 line
= self
.LineFromPosition(pos
)
395 #self.EnsureVisible(line)
398 def GetLastPosition(self
):
399 return self
.GetLength()
401 def GetPositionFromLine(self
, line
):
402 return self
.PositionFromLine(line
)
404 def GetRange(self
, start
, end
):
405 return self
.GetTextRange(start
, end
)
407 def GetSelection(self
):
408 return self
.GetAnchor(), self
.GetCurrentPos()
410 def SetSelection(self
, start
, end
):
411 self
.SetSelectionStart(start
)
412 self
.SetSelectionEnd(end
)
414 def SelectLine(self
, line
):
415 start
= self
.PositionFromLine(line
)
416 end
= self
.GetLineEndPosition(line
)
417 self
.SetSelection(start
, end
)
419 def SetUpEditor(self
):
421 This method carries out the work of setting up the demo editor.
422 It's seperate so as not to clutter up the init code.
426 self
.SetLexer(stc
.STC_LEX_PYTHON
)
427 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
430 self
.SetProperty("fold", "1" )
432 # Highlight tab/space mixing (shouldn't be any)
433 self
.SetProperty("tab.timmy.whinge.level", "1")
435 # Set left and right margins
438 # Set up the numbers in the margin for margin #1
439 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
440 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
441 self
.SetMarginWidth(1, 40)
443 # Indentation and tab stuff
444 self
.SetIndent(4) # Proscribed indent size for wx
445 self
.SetIndentationGuides(True) # Show indent guides
446 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
447 self
.SetTabIndents(True) # Tab key indents
448 self
.SetTabWidth(4) # Proscribed tab size for wx
449 self
.SetUseTabs(False) # Use spaces rather than tabs, or
450 # TabTimmy will complain!
452 self
.SetViewWhiteSpace(False) # Don't view white space
454 # EOL: Since we are loading/saving ourselves, and the
455 # strings will always have \n's in them, set the STC to
456 # edit them that way.
457 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
458 self
.SetViewEOL(False)
460 # No right-edge mode indicator
461 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
463 # Setup a margin to hold fold markers
464 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
465 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
466 self
.SetMarginSensitive(2, True)
467 self
.SetMarginWidth(2, 12)
469 # and now set up the fold markers
470 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
471 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
472 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
473 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
474 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
475 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
476 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
478 # Global default style
479 if wx
.Platform
== '__WXMSW__':
480 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
481 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
483 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
484 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
486 # Clear styles and revert to default.
489 # Following style specs only indicate differences from default.
490 # The rest remains unchanged.
492 # Line numbers in margin
493 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
495 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
497 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
499 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
502 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
504 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
505 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
507 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
508 # Strings and characters
509 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
510 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
512 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
514 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
515 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
517 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
519 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
521 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
522 # Identifiers. I leave this as not bold because everything seems
523 # to be an identifier if it doesn't match the above criterae
524 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
527 self
.SetCaretForeground("BLUE")
528 # Selection background
529 self
.SetSelBackground(1, '#66CCFF')
531 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
532 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
534 def RegisterModifiedEvent(self
, eventHandler
):
535 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
539 class DemoCodeEditor(wx
.TextCtrl
):
540 def __init__(self
, parent
):
541 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
542 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
544 def RegisterModifiedEvent(self
, eventHandler
):
545 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
547 def SetReadOnly(self
, flag
):
548 self
.SetEditable(not flag
)
549 # NOTE: STC already has this method
552 return self
.GetValue()
554 def GetPositionFromLine(self
, line
):
555 return self
.XYToPosition(0,line
)
557 def GotoLine(self
, line
):
558 pos
= self
.GetPositionFromLine(line
)
559 self
.SetInsertionPoint(pos
)
560 self
.ShowPosition(pos
)
562 def SelectLine(self
, line
):
563 start
= self
.GetPositionFromLine(line
)
564 end
= start
+ self
.GetLineLength(line
)
565 self
.SetSelection(start
, end
)
568 #---------------------------------------------------------------------------
569 # Constants for module versions
573 modDefault
= modOriginal
575 #---------------------------------------------------------------------------
577 class DemoCodePanel(wx
.Panel
):
578 """Panel for the 'Demo Code' tab"""
579 def __init__(self
, parent
, mainFrame
):
580 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
581 if 'wxMSW' in wx
.PlatformInfo
:
583 self
.mainFrame
= mainFrame
584 self
.editor
= DemoCodeEditor(self
)
585 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
587 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
588 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
589 self
.btnSave
.Enable(False)
590 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
591 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
593 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
594 modModified
: wx
.RadioButton(self
, -1, "Modified") }
596 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
597 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
598 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
599 for modID
, radioButton
in self
.radioButtons
.items():
600 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
601 radioButton
.modID
= modID
# makes it easier for the event handler
602 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
604 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
605 self
.controlBox
.Add(self
.btnRestore
, 0)
607 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
608 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
609 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
610 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
613 self
.SetSizer(self
.box
)
616 # Loads a demo from a DemoModules object
617 def LoadDemo(self
, demoModules
):
618 self
.demoModules
= demoModules
619 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
620 demoModules
.SetActive(modModified
)
622 demoModules
.SetActive(modOriginal
)
623 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
624 self
.ActiveModuleChanged()
627 def ActiveModuleChanged(self
):
628 self
.LoadDemoSource(self
.demoModules
.GetSource())
629 self
.UpdateControlState()
633 def LoadDemoSource(self
, source
):
635 self
.editor
.SetValue(source
)
637 self
.btnSave
.Enable(False)
640 def JumpToLine(self
, line
, highlight
=False):
641 self
.editor
.GotoLine(line
)
642 self
.editor
.SetFocus()
644 self
.editor
.SelectLine(line
)
647 def UpdateControlState(self
):
648 active
= self
.demoModules
.GetActiveID()
649 # Update the radio/restore buttons
650 for moduleID
in self
.radioButtons
:
651 btn
= self
.radioButtons
[moduleID
]
652 if moduleID
== active
:
657 if self
.demoModules
.Exists(moduleID
):
659 if moduleID
== modModified
:
660 self
.btnRestore
.Enable(True)
663 if moduleID
== modModified
:
664 self
.btnRestore
.Enable(False)
667 def OnRadioButton(self
, event
):
668 radioSelected
= event
.GetEventObject()
669 modSelected
= radioSelected
.modID
670 if modSelected
!= self
.demoModules
.GetActiveID():
671 busy
= wx
.BusyInfo("Reloading demo module...")
672 self
.demoModules
.SetActive(modSelected
)
673 self
.ActiveModuleChanged()
676 def ReloadDemo(self
):
677 if self
.demoModules
.name
!= __name__
:
678 self
.mainFrame
.RunModule()
681 def OnCodeModified(self
, event
):
682 self
.btnSave
.Enable(self
.editor
.IsModified())
685 def OnSave(self
, event
):
686 if self
.demoModules
.Exists(modModified
):
687 if self
.demoModules
.GetActiveID() == modOriginal
:
688 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
689 "Do you want to continue?"
690 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
691 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
692 result
= dlg
.ShowModal()
693 if result
== wx
.ID_NO
:
697 self
.demoModules
.SetActive(modModified
)
698 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
700 # Create the demo directory if one doesn't already exist
701 if not os
.path
.exists(GetModifiedDirectory()):
703 os
.makedirs(GetModifiedDirectory())
704 if not os
.path
.exists(GetModifiedDirectory()):
705 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
708 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
711 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
714 f
= open(modifiedFilename
, "wt")
715 source
= self
.editor
.GetText()
721 busy
= wx
.BusyInfo("Reloading demo module...")
722 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
723 self
.ActiveModuleChanged()
726 def OnRestore(self
, event
): # Handles the "Delete Modified" button
727 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
728 self
.demoModules
.Delete(modModified
)
729 os
.unlink(modifiedFilename
) # Delete the modified copy
730 busy
= wx
.BusyInfo("Reloading demo module...")
731 self
.ActiveModuleChanged()
734 #---------------------------------------------------------------------------
737 """Convert paths to the platform-specific separator"""
738 str = apply(os
.path
.join
, tuple(path
.split('/')))
739 # HACK: on Linux, a leading / gets lost...
740 if path
.startswith('/'):
745 def GetModifiedDirectory():
747 Returns the directory where modified versions of the demo files
750 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
753 def GetModifiedFilename(name
):
755 Returns the filename of the modified version of the specified demo
757 if not name
.endswith(".py"):
759 return GetModifiedDirectory() + name
762 def GetOriginalFilename(name
):
764 Returns the filename of the original version of the specified demo
766 if not name
.endswith(".py"):
771 def DoesModifiedExist(name
):
772 """Returns whether the specified demo has a modified copy"""
773 if os
.path
.exists(GetModifiedFilename(name
)):
779 #---------------------------------------------------------------------------
781 class ModuleDictWrapper
:
782 """Emulates a module with a dynamically compiled __dict__"""
783 def __init__(self
, dict):
786 def __getattr__(self
, name
):
787 if name
in self
.dict:
788 return self
.dict[name
]
794 Dynamically manages the original/modified versions of a demo
797 def __init__(self
, name
):
801 # (dict , source , filename , description , error information )
802 # ( 0 , 1 , 2 , 3 , 4 )
803 self
.modules
= [[None, "" , "" , "<original>" , None],
804 [None, "" , "" , "<modified>" , None]]
806 # load original module
807 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
808 self
.SetActive(modOriginal
)
810 # load modified module (if one exists)
811 if DoesModifiedExist(name
):
812 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
815 def LoadFromFile(self
, modID
, filename
):
816 self
.modules
[modID
][2] = filename
817 file = open(filename
, "rt")
818 self
.LoadFromSource(modID
, file.read())
822 def LoadFromSource(self
, modID
, source
):
823 self
.modules
[modID
][1] = source
827 def LoadDict(self
, modID
):
828 if self
.name
!= __name__
:
829 source
= self
.modules
[modID
][1]
830 #description = self.modules[modID][3]
831 description
= self
.modules
[modID
][2]
834 self
.modules
[modID
][0] = {}
835 code
= compile(source
, description
, "exec")
836 exec code
in self
.modules
[modID
][0]
838 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
839 self
.modules
[modID
][0] = None
841 self
.modules
[modID
][4] = None
844 def SetActive(self
, modID
):
845 if modID
!= modOriginal
and modID
!= modModified
:
848 self
.modActive
= modID
852 dict = self
.modules
[self
.modActive
][0]
856 return ModuleDictWrapper(dict)
859 def GetActiveID(self
):
860 return self
.modActive
863 def GetSource(self
, modID
= None):
865 modID
= self
.modActive
866 return self
.modules
[modID
][1]
869 def GetFilename(self
, modID
= None):
871 modID
= self
.modActive
872 return self
.modules
[self
.modActive
][2]
875 def GetErrorInfo(self
, modID
= None):
877 modID
= self
.modActive
878 return self
.modules
[self
.modActive
][4]
881 def Exists(self
, modID
):
882 return self
.modules
[modID
][1] != ""
885 def UpdateFile(self
, modID
= None):
886 """Updates the file from which a module was loaded
887 with (possibly updated) source"""
889 modID
= self
.modActive
891 source
= self
.modules
[modID
][1]
892 filename
= self
.modules
[modID
][2]
895 file = open(filename
, "wt")
901 def Delete(self
, modID
):
902 if self
.modActive
== modID
:
905 self
.modules
[modID
][0] = None
906 self
.modules
[modID
][1] = ""
907 self
.modules
[modID
][2] = ""
910 #---------------------------------------------------------------------------
913 """Wraps and stores information about the current exception"""
914 def __init__(self
, exc_info
):
917 excType
, excValue
= exc_info
[:2]
918 # traceback list entries: (filename, line number, function name, text)
919 self
.traceback
= traceback
.extract_tb(exc_info
[2])
921 # --Based on traceback.py::format_exception_only()--
922 if type(excType
) == types
.ClassType
:
923 self
.exception_type
= excType
.__name
__
925 self
.exception_type
= excType
927 # If it's a syntax error, extra information needs
928 # to be added to the traceback
929 if excType
is SyntaxError:
931 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
936 filename
= "<string>"
938 self
.traceback
.append( (filename
, lineno
, "", line
) )
941 self
.exception_details
= str(excValue
)
943 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
950 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
953 #---------------------------------------------------------------------------
955 class DemoErrorPanel(wx
.Panel
):
956 """Panel put into the demo tab when the demo fails to run due to errors"""
958 def __init__(self
, parent
, codePanel
, demoError
, log
):
959 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
960 self
.codePanel
= codePanel
964 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
967 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo")
968 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
970 # Exception Information
971 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
972 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
973 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
974 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
975 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
976 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_type
) , 0, textFlags
, 5 )
977 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
978 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
979 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
980 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
982 # Set up the traceback list
983 # This one automatically resizes last column to take up remaining space
984 from ListCtrl
import TestListCtrl
985 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
986 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
987 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
988 self
.list.InsertColumn(0, "Filename")
989 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
990 self
.list.InsertColumn(2, "Function")
991 self
.list.InsertColumn(3, "Code")
992 self
.InsertTraceback(self
.list, demoError
.traceback
)
993 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
994 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
995 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
996 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
997 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
998 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
999 + "Double-click on them to go to the offending line")
1000 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
1003 self
.SetSizer(self
.box
)
1006 def InsertTraceback(self
, list, traceback
):
1007 #Add the traceback data
1008 for x
in range(len(traceback
)):
1010 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
1011 list.SetStringItem(x
, 1, str(data
[1])) # Line
1012 list.SetStringItem(x
, 2, str(data
[2])) # Function
1013 list.SetStringItem(x
, 3, str(data
[3])) # Code
1015 # Check whether this entry is from the demo module
1016 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
1017 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
1018 # Give it a blue colour
1019 item
= self
.list.GetItem(x
)
1020 item
.SetTextColour(wx
.BLUE
)
1021 self
.list.SetItem(item
)
1023 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
1026 def OnItemSelected(self
, event
):
1027 # This occurs before OnDoubleClick and can be used to set the
1028 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1029 self
.currentItem
= event
.m_itemIndex
1033 def OnDoubleClick(self
, event
):
1034 # If double-clicking on a demo's entry, jump to the line number
1035 line
= self
.list.GetItemData(self
.currentItem
)
1037 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1038 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1042 #---------------------------------------------------------------------------
1044 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1045 TBMENU_RESTORE
= wx
.NewId()
1046 TBMENU_CLOSE
= wx
.NewId()
1047 TBMENU_CHANGE
= wx
.NewId()
1048 TBMENU_REMOVE
= wx
.NewId()
1050 def __init__(self
, frame
):
1051 wx
.TaskBarIcon
.__init
__(self
)
1055 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1056 self
.SetIcon(icon
, "wxPython Demo")
1060 self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1061 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1062 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1063 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
)
1064 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
)
1067 def CreatePopupMenu(self
):
1069 This method is called by the base class when it needs to popup
1070 the menu for the default EVT_RIGHT_DOWN event. Just create
1071 the menu how you want it and return it from this function,
1072 the base class takes care of the rest.
1075 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1076 menu
.Append(self
.TBMENU_CLOSE
, "Close wxPython Demo")
1077 menu
.AppendSeparator()
1078 menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon")
1079 menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon")
1083 def MakeIcon(self
, img
):
1085 The various platforms have different requirements for the
1088 if "wxMSW" in wx
.PlatformInfo
:
1089 img
= img
.Scale(16, 16)
1090 elif "wxGTK" in wx
.PlatformInfo
:
1091 img
= img
.Scale(22, 22)
1092 # wxMac can be any size upto 128x128, so leave the source img alone....
1093 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
1097 def OnTaskBarActivate(self
, evt
):
1098 if self
.frame
.IsIconized():
1099 self
.frame
.Iconize(False)
1100 if not self
.frame
.IsShown():
1101 self
.frame
.Show(True)
1105 def OnTaskBarClose(self
, evt
):
1109 def OnTaskBarChange(self
, evt
):
1110 names
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
1111 name
= names
[self
.imgidx
]
1113 getFunc
= getattr(images
, "get%sImage" % name
)
1115 if self
.imgidx
>= len(names
):
1118 icon
= self
.MakeIcon(getFunc())
1119 self
.SetIcon(icon
, "This is a new icon: " + name
)
1122 def OnTaskBarRemove(self
, evt
):
1126 #---------------------------------------------------------------------------
1127 class wxPythonDemo(wx
.Frame
):
1128 overviewText
= "wxPython Overview"
1130 def __init__(self
, parent
, title
):
1131 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 720),
1132 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1134 self
.SetMinSize((640,480))
1137 self
.cwd
= os
.getcwd()
1138 self
.curOverview
= ""
1139 self
.demoPage
= None
1140 self
.codePage
= None
1142 self
.firstTime
= True
1145 icon
= images
.getWXPdemoIcon()
1149 self
.tbicon
= DemoTaskBarIcon(self
)
1153 wx
.CallAfter(self
.ShowTip
)
1155 self
.otherWin
= None
1156 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1157 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1158 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1159 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1161 self
.Centre(wx
.BOTH
)
1162 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1164 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1165 splitter2
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1167 def EmptyHandler(evt
): pass
1168 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1169 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1171 # Prevent TreeCtrl from displaying all items after destruction when True
1175 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1178 self
.mainmenu
= wx
.MenuBar()
1180 item
= menu
.Append(-1, '&Redirect Output',
1181 'Redirect print statements to a window',
1183 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1185 item
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1186 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
)
1187 wx
.App
.SetMacExitMenuItemId(item
.GetId())
1188 self
.mainmenu
.Append(menu
, '&File')
1192 for item
in _treeList
:
1194 for childItem
in item
[1]:
1195 mi
= submenu
.Append(-1, childItem
)
1196 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1197 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1198 self
.mainmenu
.Append(menu
, '&Demo')
1203 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1204 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1205 menu
.AppendSeparator()
1207 shellItem
= menu
.Append(-1, 'Open Py&Shell Window\tF5',
1208 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1209 menu
.AppendSeparator()
1210 helpItem
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
1211 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1213 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1214 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1215 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1216 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1217 self
.Bind(wx
.EVT_FIND
, self
.OnFind
)
1218 self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
)
1219 self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
)
1220 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
)
1221 self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
)
1222 self
.mainmenu
.Append(menu
, '&Help')
1223 self
.SetMenuBar(self
.mainmenu
)
1225 self
.finddata
= wx
.FindReplaceData()
1226 self
.finddata
.SetFlags(wx
.FR_DOWN
)
1229 # This is another way to set Accelerators, in addition to
1230 # using the '\t<key>' syntax in the menu items.
1231 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitID
),
1232 (wx
.ACCEL_CTRL
, ord('H'), helpID
),
1233 (wx
.ACCEL_CTRL
, ord('F'), findID
),
1234 (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
)
1236 self
.SetAcceleratorTable(aTable
)
1242 self
.tree
= wx
.TreeCtrl(splitter
, tID
, style
=
1243 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1246 root
= self
.tree
.AddRoot("wxPython Overview")
1248 for item
in _treeList
:
1249 child
= self
.tree
.AppendItem(root
, item
[0])
1250 if not firstChild
: firstChild
= child
1251 for childItem
in item
[1]:
1252 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1253 self
.treeMap
[childItem
] = theDemo
1255 self
.tree
.Expand(root
)
1256 self
.tree
.Expand(firstChild
)
1257 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1258 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1259 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1260 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1262 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1263 # we put it in a panel first because there seems to be a
1264 # refresh bug of some sort (wxGTK) when it is directly in
1267 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1268 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1270 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1271 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1272 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1273 self
.nb
.AddPage(panel
, self
.overviewText
)
1275 def OnOvrSize(evt
, ovr
=self
.ovr
):
1276 ovr
.SetSize(evt
.GetSize())
1277 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1278 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1280 if "gtk2" in wx
.PlatformInfo
:
1281 self
.ovr
.SetStandardFonts()
1282 self
.SetOverview(self
.overviewText
, mainOverview
)
1285 # Set up a log window
1286 self
.log
= wx
.TextCtrl(splitter2
, -1,
1287 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1289 # Set the wxWindows log target to be this textctrl
1290 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1292 # But instead of the above we want to show how to use our own wx.Log class
1293 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1295 # for serious debugging
1296 #wx.Log_SetActiveTarget(wx.LogStderr())
1297 #wx.Log_SetTraceMask(wx.TraceMessages)
1300 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1301 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1303 # add the windows to the splitter and split it.
1304 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1305 splitter
.SplitVertically(self
.tree
, splitter2
, 200)
1307 splitter
.SetMinimumPaneSize(120)
1308 splitter2
.SetMinimumPaneSize(60)
1310 # Make the splitter on the right expand the top window when resized
1311 def SplitterOnSize(evt
):
1312 splitter
= evt
.GetEventObject()
1313 sz
= splitter
.GetSize()
1314 splitter
.SetSashPosition(sz
.height
- 160, False)
1317 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1319 # select initial items
1320 self
.nb
.SetSelection(0)
1321 self
.tree
.SelectItem(root
)
1323 # Load 'Main' module
1324 self
.LoadDemo(self
.overviewText
)
1327 # select some other initial module?
1328 if len(sys
.argv
) > 1:
1330 if arg
.endswith('.py'):
1332 selectedDemo
= self
.treeMap
.get(arg
, None)
1334 self
.tree
.SelectItem(selectedDemo
)
1335 self
.tree
.EnsureVisible(selectedDemo
)
1338 #---------------------------------------------
1339 def WriteText(self
, text
):
1340 if text
[-1:] == '\n':
1344 def write(self
, txt
):
1347 #---------------------------------------------
1348 def OnItemExpanded(self
, event
):
1349 item
= event
.GetItem()
1350 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1353 #---------------------------------------------
1354 def OnItemCollapsed(self
, event
):
1355 item
= event
.GetItem()
1356 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1359 #---------------------------------------------
1360 def OnTreeLeftDown(self
, event
):
1361 # reset the overview text if the tree item is clicked on again
1362 pt
= event
.GetPosition();
1363 item
, flags
= self
.tree
.HitTest(pt
)
1364 if item
== self
.tree
.GetSelection():
1365 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1368 #---------------------------------------------
1369 def OnSelChanged(self
, event
):
1370 if self
.dying
or not self
.loaded
:
1373 item
= event
.GetItem()
1374 itemText
= self
.tree
.GetItemText(item
)
1375 self
.LoadDemo(itemText
)
1377 #---------------------------------------------
1378 def LoadDemo(self
, demoName
):
1380 wx
.BeginBusyCursor()
1383 self
.ShutdownDemoModule()
1385 if demoName
== self
.overviewText
:
1386 # User selected the "wxPython Overview" node
1388 # Changing the main window at runtime not yet supported...
1389 self
.demoModules
= DemoModules(__name__
)
1390 self
.SetOverview(self
.overviewText
, mainOverview
)
1391 self
.LoadDemoSource()
1392 self
.UpdateNotebook(0)
1394 if os
.path
.exists(GetOriginalFilename(demoName
)):
1395 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1396 self
.demoModules
= DemoModules(demoName
)
1397 self
.LoadDemoSource()
1400 self
.SetOverview("wxPython", mainOverview
)
1401 self
.codePage
= None
1402 self
.UpdateNotebook(0)
1406 #---------------------------------------------
1407 def LoadDemoSource(self
):
1408 self
.codePage
= None
1409 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1410 self
.codePage
.LoadDemo(self
.demoModules
)
1412 #---------------------------------------------
1413 def RunModule(self
):
1414 """Runs the active module"""
1416 module
= self
.demoModules
.GetActive()
1417 self
.ShutdownDemoModule()
1420 # o The RunTest() for all samples must now return a window that can
1421 # be palced in a tab in the main notebook.
1422 # o If an error occurs (or has occurred before) an error tab is created.
1424 if module
is not None:
1425 wx
.LogMessage("Running demo module...")
1426 if hasattr(module
, "overview"):
1427 overviewText
= module
.overview
1430 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1432 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1433 DemoError(sys
.exc_info()), self
)
1435 assert self
.demoPage
is not None, "runTest must return a window!"
1438 # There was a previous error in compiling or exec-ing
1439 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1440 self
.demoModules
.GetErrorInfo(), self
)
1442 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1445 # cahnge to the demo page the first time a module is run
1446 self
.UpdateNotebook(2)
1447 self
.firstTime
= False
1449 # otherwise just stay on the same tab in case the user has changed to another one
1450 self
.UpdateNotebook()
1452 #---------------------------------------------
1453 def ShutdownDemoModule(self
):
1455 # inform the window that it's time to quit if it cares
1456 if hasattr(self
.demoPage
, "ShutdownDemo"):
1457 self
.demoPage
.ShutdownDemo()
1458 wx
.YieldIfNeeded() # in case the page has pending events
1459 self
.demoPage
= None
1461 #---------------------------------------------
1462 def UpdateNotebook(self
, select
= -1):
1466 def UpdatePage(page
, pageText
):
1469 for i
in range(nb
.GetPageCount()):
1470 if nb
.GetPageText(i
) == pageText
:
1478 nb
.AddPage(page
, pageText
)
1479 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1481 if nb
.GetPage(pagePos
) != page
:
1482 # Reload an existing page
1484 nb
.DeletePage(pagePos
)
1485 nb
.InsertPage(pagePos
, page
, pageText
)
1487 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1489 # Excellent! No redraw/flicker
1490 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1493 nb
.DeletePage(pagePos
)
1494 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1496 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1499 select
= nb
.GetSelection()
1501 UpdatePage(self
.codePage
, "Demo Code")
1502 UpdatePage(self
.demoPage
, "Demo")
1504 if select
>= 0 and select
< nb
.GetPageCount():
1505 nb
.SetSelection(select
)
1507 #---------------------------------------------
1508 def SetOverview(self
, name
, text
):
1509 self
.curOverview
= text
1511 if lead
!= '<html>' and lead
!= '<HTML>':
1512 text
= '<br>'.join(text
.split('\n'))
1514 text
= text
.decode('iso8859_1')
1515 self
.ovr
.SetPage(text
)
1516 self
.nb
.SetPageText(0, name
)
1518 #---------------------------------------------
1520 def OnFileExit(self
, *event
):
1523 def OnToggleRedirect(self
, event
):
1527 print "Print statements and other standard output will now be directed to this window."
1530 print "Print statements and other standard output will now be sent to the usual location."
1532 def OnHelpAbout(self
, event
):
1533 from About
import MyAboutBox
1534 about
= MyAboutBox(self
)
1538 def OnHelpFind(self
, event
):
1539 if self
.finddlg
!= None:
1542 self
.nb
.SetSelection(1)
1543 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1544 wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
)
1545 self
.finddlg
.Show(True)
1548 def OnUpdateFindItems(self
, evt
):
1549 evt
.Enable(self
.finddlg
== None)
1552 def OnFind(self
, event
):
1553 editor
= self
.codePage
.editor
1554 self
.nb
.SetSelection(1)
1555 end
= editor
.GetLastPosition()
1556 textstring
= editor
.GetRange(0, end
).lower()
1557 findstring
= self
.finddata
.GetFindString().lower()
1558 backward
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
)
1560 start
= editor
.GetSelection()[0]
1561 loc
= textstring
.rfind(findstring
, 0, start
)
1563 start
= editor
.GetSelection()[1]
1564 loc
= textstring
.find(findstring
, start
)
1565 if loc
== -1 and start
!= 0:
1566 # string not found, start at beginning
1569 loc
= textstring
.rfind(findstring
, 0, start
)
1572 loc
= textstring
.find(findstring
, start
)
1574 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1575 'Find String Not Found in Demo File',
1576 wx
.OK | wx
.ICON_INFORMATION
)
1581 self
.finddlg
.SetFocus()
1584 self
.finddlg
.Destroy()
1586 editor
.ShowPosition(loc
)
1587 editor
.SetSelection(loc
, loc
+ len(findstring
))
1591 def OnFindNext(self
, event
):
1592 if self
.finddata
.GetFindString():
1595 self
.OnHelpFind(event
)
1597 def OnFindClose(self
, event
):
1598 event
.GetDialog().Destroy()
1602 def OnOpenShellWindow(self
, evt
):
1604 # if it already exists then just make sure it's visible
1610 # Make a PyShell window
1612 namespace
= { 'wx' : wx
,
1613 'app' : wx
.GetApp(),
1616 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1617 self
.shell
.SetSize((640,480))
1620 # Hook the close event of the main frame window so that we
1621 # close the shell at the same time if it still exists
1622 def CloseShell(evt
):
1626 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1629 #---------------------------------------------
1630 def OnCloseWindow(self
, event
):
1632 self
.demoPage
= None
1633 self
.codePage
= None
1634 self
.mainmenu
= None
1635 if self
.tbicon
is not None:
1636 self
.tbicon
.Destroy()
1640 #---------------------------------------------
1641 def OnIdle(self
, event
):
1643 self
.otherWin
.Raise()
1644 self
.demoPage
= self
.otherWin
1645 self
.otherWin
= None
1648 #---------------------------------------------
1651 showTipText
= open(opj("data/showTips")).read()
1652 showTip
, index
= eval(showTipText
)
1654 showTip
, index
= (1, 0)
1656 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
1658 showTip
= wx
.ShowTip(self
, tp
)
1659 index
= tp
.GetCurrentTip()
1660 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
1663 #---------------------------------------------
1664 def OnDemoMenu(self
, event
):
1666 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
1670 self
.tree
.SelectItem(selectedDemo
)
1671 self
.tree
.EnsureVisible(selectedDemo
)
1675 #---------------------------------------------
1676 def OnIconfiy(self
, evt
):
1677 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
1680 #---------------------------------------------
1681 def OnMaximize(self
, evt
):
1682 wx
.LogMessage("OnMaximize")
1685 #---------------------------------------------
1686 def OnActivate(self
, evt
):
1687 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
1690 #---------------------------------------------
1691 def OnAppActivate(self
, evt
):
1692 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
1695 #---------------------------------------------------------------------------
1696 #---------------------------------------------------------------------------
1698 class MySplashScreen(wx
.SplashScreen
):
1700 bmp
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
1701 wx
.SplashScreen
.__init
__(self
, bmp
,
1702 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
1704 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
1705 self
.fc
= wx
.FutureCall(2000, self
.ShowMain
)
1708 def OnClose(self
, evt
):
1709 # Make sure the default handler runs too so this window gets
1714 # if the timer is still running then go ahead and show the
1716 if self
.fc
.IsRunning():
1722 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
1724 if self
.fc
.IsRunning():
1728 class MyApp(wx
.App
):
1731 Create and show the splash screen. It will then create and show
1732 the main frame when it is time to do so.
1735 wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1)
1738 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1740 # Normally when using a SplashScreen you would create it, show
1741 # it and then continue on with the applicaiton's
1742 # initialization, finally creating and showing the main
1743 # application window(s). In this case we have nothing else to
1744 # do so we'll delay showing the main frame until later (see
1745 # ShowMain above) so the users can see the SplashScreen effect.
1746 splash
= MySplashScreen()
1753 #---------------------------------------------------------------------------
1757 demoPath
= os
.path
.dirname(__file__
)
1764 #---------------------------------------------------------------------------
1767 mainOverview
= """<html><body>
1770 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1771 language. It allows Python programmers to create programs with a
1772 robust, highly functional graphical user interface, simply and easily.
1773 It is implemented as a Python extension module (native code) that
1774 wraps the popular wxWindows cross platform GUI library, which is
1777 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1778 means that it is free for anyone to use and the source code is
1779 available for anyone to look at and modify. Or anyone can contribute
1780 fixes or enhancements to the project.
1782 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1783 same program will run on multiple platforms without modification.
1784 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1785 or unix-like systems, and Macintosh OS X. Since the language is
1786 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1789 <p> <b>This demo</b> is not only a collection of test cases for
1790 wxPython, but is also designed to help you learn about and how to use
1791 wxPython. Each sample is listed in the tree control on the left.
1792 When a sample is selected in the tree then a module is loaded and run
1793 (usually in a tab of this notebook,) and the source code of the module
1794 is loaded in another tab for you to browse and learn from.
1799 #----------------------------------------------------------------------------
1800 #----------------------------------------------------------------------------
1802 if __name__
== '__main__':
1806 #----------------------------------------------------------------------------