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 = ", wx.VERSION_STRING
41 ##raw_input("Press Enter...")
44 #---------------------------------------------------------------------------
49 ('Recent Additions/Updates', [
54 # managed windows == things with a (optional) caption you can close
55 ('Frames and Dialogs', [
78 # dialogs from libraries
81 'MultipleChoiceDialog',
82 'ScrolledMessageDialog',
86 ('Core Windows/Controls', [
126 ('Custom Controls', [
139 # controls coming from other libraries
140 ('More Windows/Controls', [
141 'ActiveX_FlashWindow',
142 'ActiveX_IEHtmlWindow',
144 #'RightTextCtrl', deprecated as we have wxTE_RIGHT now.
158 'MaskedEditControls',
175 # How to lay out the controls in a frame/dialog
185 'XmlResourceHandler',
186 'XmlResourceSubclass',
190 ('Process and Events', [
197 ##'infoframe', # needs better explanation and some fixing
201 ('Clipboard and DnD', [
222 ##'DialogUnits', # needs more explanations
235 # need libs not coming with the demo
236 ('Samples using an external library', [
241 ('Check out the samples dir too', [
248 #---------------------------------------------------------------------------
249 # Show how to derive a custom wxLog class
251 class MyLog(wx
.PyLog
):
252 def __init__(self
, textCtrl
, logTime
=0):
253 wx
.PyLog
.__init
__(self
)
255 self
.logTime
= logTime
257 def DoLogString(self
, message
, timeStamp
):
258 #print message, timeStamp
260 # message = time.strftime("%X", time.localtime(timeStamp)) + \
263 self
.tc
.AppendText(message
+ '\n')
266 class MyTP(wx
.PyTipProvider
):
268 return "This is my tip"
270 #---------------------------------------------------------------------------
271 # A class to be used to simply display a message in the demo pane
272 # rather than running the sample itself.
274 class MessagePanel(wx
.Panel
):
275 def __init__(self
, parent
, message
, caption
='', flags
=0):
276 wx
.Panel
.__init
__(self
, parent
)
281 if flags
& wx
.ICON_EXCLAMATION
:
282 artid
= wx
.ART_WARNING
283 elif flags
& wx
.ICON_ERROR
:
285 elif flags
& wx
.ICON_QUESTION
:
286 artid
= wx
.ART_QUESTION
287 elif flags
& wx
.ICON_INFORMATION
:
288 artid
= wx
.ART_INFORMATION
290 if artid
is not None:
291 bmp
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32))
292 icon
= wx
.StaticBitmap(self
, -1, bmp
)
294 icon
= (32,32) # make a spacer instead
297 caption
= wx
.StaticText(self
, -1, caption
)
298 caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
300 message
= wx
.StaticText(self
, -1, message
)
302 # add to sizers for layout
303 tbox
= wx
.BoxSizer(wx
.VERTICAL
)
309 hbox
= wx
.BoxSizer(wx
.HORIZONTAL
)
316 box
= wx
.BoxSizer(wx
.VERTICAL
)
318 box
.Add(hbox
, 0, wx
.EXPAND
)
325 #---------------------------------------------------------------------------
326 # A class to be used to display source code in the demo. Try using the
327 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
328 # if there is an error, such as the stc module not being present.
332 ##raise ImportError # for testing the alternate implementation
334 from StyledTextCtrl_2
import PythonSTC
336 class DemoCodeEditor(PythonSTC
):
337 def __init__(self
, parent
):
338 PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
)
341 # Some methods to make it compatible with how the wxTextCtrl is used
342 def SetValue(self
, value
):
344 value
= value
.decode('iso8859_1')
346 self
.EmptyUndoBuffer()
349 def IsModified(self
):
350 return self
.GetModify()
355 def SetInsertionPoint(self
, pos
):
356 self
.SetCurrentPos(pos
)
359 def ShowPosition(self
, pos
):
360 line
= self
.LineFromPosition(pos
)
361 #self.EnsureVisible(line)
364 def GetLastPosition(self
):
365 return self
.GetLength()
367 def GetPositionFromLine(self
, line
):
368 return self
.PositionFromLine(line
)
370 def GetRange(self
, start
, end
):
371 return self
.GetTextRange(start
, end
)
373 def GetSelection(self
):
374 return self
.GetAnchor(), self
.GetCurrentPos()
376 def SetSelection(self
, start
, end
):
377 self
.SetSelectionStart(start
)
378 self
.SetSelectionEnd(end
)
380 def SelectLine(self
, line
):
381 start
= self
.PositionFromLine(line
)
382 end
= self
.GetLineEndPosition(line
)
383 self
.SetSelection(start
, end
)
385 def SetUpEditor(self
):
387 This method carries out the work of setting up the demo editor.
388 It's seperate so as not to clutter up the init code.
392 self
.SetLexer(stc
.STC_LEX_PYTHON
)
393 self
.SetKeyWords(0, " ".join(keyword
.kwlist
))
396 self
.SetProperty("fold", "1" )
398 # Highlight tab/space mixing (shouldn't be any)
399 self
.SetProperty("tab.timmy.whinge.level", "1")
401 # Set left and right margins
404 # Set up the numbers in the margin for margin #1
405 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
406 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
407 self
.SetMarginWidth(1, 40)
409 # Indentation and tab stuff
410 self
.SetIndent(4) # Proscribed indent size for wx
411 self
.SetIndentationGuides(True) # Show indent guides
412 self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
413 self
.SetTabIndents(True) # Tab key indents
414 self
.SetTabWidth(4) # Proscribed tab size for wx
415 self
.SetUseTabs(False) # Use spaces rather than tabs, or
416 # TabTimmy will complain!
418 self
.SetViewWhiteSpace(False) # Don't view white space
420 # EOL: Since we are loading/saving ourselves, and the
421 # strings will always have \n's in them, set the STC to
422 # edit them that way.
423 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
424 self
.SetViewEOL(False)
426 # No right-edge mode indicator
427 self
.SetEdgeMode(stc
.STC_EDGE_NONE
)
429 # Setup a margin to hold fold markers
430 self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
)
431 self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
)
432 self
.SetMarginSensitive(2, True)
433 self
.SetMarginWidth(2, 12)
435 # and now set up the fold markers
436 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
, stc
.STC_MARK_BOXPLUSCONNECTED
, "white", "black")
437 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black")
438 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
, "white", "black")
439 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
, stc
.STC_MARK_LCORNER
, "white", "black")
440 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
, stc
.STC_MARK_VLINE
, "white", "black")
441 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
, stc
.STC_MARK_BOXPLUS
, "white", "black")
442 self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
, stc
.STC_MARK_BOXMINUS
, "white", "black")
444 # Global default style
445 if wx
.Platform
== '__WXMSW__':
446 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
447 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
449 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,
450 'fore:#000000,back:#FFFFFF,face:Courier,size:12')
452 # Clear styles and revert to default.
455 # Following style specs only indicate differences from default.
456 # The rest remains unchanged.
458 # Line numbers in margin
459 self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')
461 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00')
463 self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000')
465 self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD")
468 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000')
470 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, 'fore:#008000,back:#F0FFF0')
471 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0')
473 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080')
474 # Strings and characters
475 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080')
476 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080')
478 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold')
480 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA')
481 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA')
483 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold')
485 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold')
487 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold')
488 # Identifiers. I leave this as not bold because everything seems
489 # to be an identifier if it doesn't match the above criterae
490 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000')
493 self
.SetCaretForeground("BLUE")
494 # Selection background
495 self
.SetSelBackground(1, '#66CCFF')
497 self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
))
498 self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
))
500 def RegisterModifiedEvent(self
, eventHandler
):
501 self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
)
505 class DemoCodeEditor(wx
.TextCtrl
):
506 def __init__(self
, parent
):
507 wx
.TextCtrl
.__init
__(self
, parent
, -1, style
=
508 wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
)
510 def RegisterModifiedEvent(self
, eventHandler
):
511 self
.Bind(wx
.EVT_TEXT
, eventHandler
)
513 def SetReadOnly(self
, flag
):
514 self
.SetEditable(not flag
)
515 # NOTE: STC already has this method
518 return self
.GetValue()
520 def GetPositionFromLine(self
, line
):
521 return self
.XYToPosition(0,line
)
523 def GotoLine(self
, line
):
524 pos
= self
.GetPositionFromLine(line
)
525 self
.SetInsertionPoint(pos
)
526 self
.ShowPosition(pos
)
528 def SelectLine(self
, line
):
529 start
= self
.GetPositionFromLine(line
)
530 end
= start
+ self
.GetLineLength(line
)
531 self
.SetSelection(start
, end
)
534 #---------------------------------------------------------------------------
535 # Constants for module versions
539 modDefault
= modOriginal
541 #---------------------------------------------------------------------------
543 class DemoCodePanel(wx
.Panel
):
544 """Panel for the 'Demo Code' tab"""
545 def __init__(self
, parent
, mainFrame
):
546 wx
.Panel
.__init
__(self
, parent
, size
=(1,1))
547 if 'wxMSW' in wx
.PlatformInfo
:
549 self
.mainFrame
= mainFrame
550 self
.editor
= DemoCodeEditor(self
)
551 self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
)
553 self
.btnSave
= wx
.Button(self
, -1, "Save Changes")
554 self
.btnRestore
= wx
.Button(self
, -1, "Delete Modified")
555 self
.btnSave
.Enable(False)
556 self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
)
557 self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
)
559 self
.radioButtons
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style
= wx
.RB_GROUP
),
560 modModified
: wx
.RadioButton(self
, -1, "Modified") }
562 self
.controlBox
= wx
.BoxSizer(wx
.HORIZONTAL
)
563 self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0,
564 wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5)
565 for modID
, radioButton
in self
.radioButtons
.items():
566 self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5)
567 radioButton
.modID
= modID
# makes it easier for the event handler
568 radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
)
570 self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5)
571 self
.controlBox
.Add(self
.btnRestore
, 0)
573 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
574 self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
)
575 self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
)
576 self
.box
.Add(self
.editor
, 1, wx
.EXPAND
)
579 self
.SetSizer(self
.box
)
582 # Loads a demo from a DemoModules object
583 def LoadDemo(self
, demoModules
):
584 self
.demoModules
= demoModules
585 if (modDefault
== modModified
) and demoModules
.Exists(modModified
):
586 demoModules
.SetActive(modModified
)
588 demoModules
.SetActive(modOriginal
)
589 self
.radioButtons
[demoModules
.GetActiveID()].Enable(True)
590 self
.ActiveModuleChanged()
593 def ActiveModuleChanged(self
):
594 self
.LoadDemoSource(self
.demoModules
.GetSource())
595 self
.UpdateControlState()
599 def LoadDemoSource(self
, source
):
601 self
.editor
.SetValue(source
)
603 self
.btnSave
.Enable(False)
606 def JumpToLine(self
, line
, highlight
=False):
607 self
.editor
.GotoLine(line
)
608 self
.editor
.SetFocus()
610 self
.editor
.SelectLine(line
)
613 def UpdateControlState(self
):
614 active
= self
.demoModules
.GetActiveID()
615 # Update the radio/restore buttons
616 for moduleID
in self
.radioButtons
:
617 btn
= self
.radioButtons
[moduleID
]
618 if moduleID
== active
:
623 if self
.demoModules
.Exists(moduleID
):
625 if moduleID
== modModified
:
626 self
.btnRestore
.Enable(True)
629 if moduleID
== modModified
:
630 self
.btnRestore
.Enable(False)
633 def OnRadioButton(self
, event
):
634 radioSelected
= event
.GetEventObject()
635 modSelected
= radioSelected
.modID
636 if modSelected
!= self
.demoModules
.GetActiveID():
637 busy
= wx
.BusyInfo("Reloading demo module...")
638 self
.demoModules
.SetActive(modSelected
)
639 self
.ActiveModuleChanged()
642 def ReloadDemo(self
):
643 if self
.demoModules
.name
!= __name__
:
644 self
.mainFrame
.RunModule()
647 def OnCodeModified(self
, event
):
648 self
.btnSave
.Enable(self
.editor
.IsModified())
651 def OnSave(self
, event
):
652 if self
.demoModules
.Exists(modModified
):
653 if self
.demoModules
.GetActiveID() == modOriginal
:
654 overwriteMsg
= "You are about to overwrite an already existing modified copy\n" + \
655 "Do you want to continue?"
656 dlg
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo",
657 wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
)
658 result
= dlg
.ShowModal()
659 if result
== wx
.ID_NO
:
663 self
.demoModules
.SetActive(modModified
)
664 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
666 # Create the demo directory if one doesn't already exist
667 if not os
.path
.exists(GetModifiedDirectory()):
669 os
.makedirs(GetModifiedDirectory())
670 if not os
.path
.exists(GetModifiedDirectory()):
671 wx
.LogMessage("BUG: Created demo directory but it still doesn't exist")
674 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
677 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
680 f
= open(modifiedFilename
, "wt")
681 source
= self
.editor
.GetText()
687 busy
= wx
.BusyInfo("Reloading demo module...")
688 self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
)
689 self
.ActiveModuleChanged()
692 def OnRestore(self
, event
): # Handles the "Delete Modified" button
693 modifiedFilename
= GetModifiedFilename(self
.demoModules
.name
)
694 self
.demoModules
.Delete(modModified
)
695 os
.unlink(modifiedFilename
) # Delete the modified copy
696 busy
= wx
.BusyInfo("Reloading demo module...")
697 self
.ActiveModuleChanged()
700 #---------------------------------------------------------------------------
703 """Convert paths to the platform-specific separator"""
704 str = apply(os
.path
.join
, tuple(path
.split('/')))
705 # HACK: on Linux, a leading / gets lost...
706 if path
.startswith('/'):
711 def GetModifiedDirectory():
713 Returns the directory where modified versions of the demo files
716 return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/")
719 def GetModifiedFilename(name
):
721 Returns the filename of the modified version of the specified demo
723 if not name
.endswith(".py"):
725 return GetModifiedDirectory() + name
728 def GetOriginalFilename(name
):
730 Returns the filename of the original version of the specified demo
732 if not name
.endswith(".py"):
737 def DoesModifiedExist(name
):
738 """Returns whether the specified demo has a modified copy"""
739 if os
.path
.exists(GetModifiedFilename(name
)):
745 #---------------------------------------------------------------------------
747 class ModuleDictWrapper
:
748 """Emulates a module with a dynamically compiled __dict__"""
749 def __init__(self
, dict):
752 def __getattr__(self
, name
):
753 if name
in self
.dict:
754 return self
.dict[name
]
760 Dynamically manages the original/modified versions of a demo
763 def __init__(self
, name
):
767 # (dict , source , filename , description , error information )
768 # ( 0 , 1 , 2 , 3 , 4 )
769 self
.modules
= [[None, "" , "" , "<original>" , None],
770 [None, "" , "" , "<modified>" , None]]
772 # load original module
773 self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
))
774 self
.SetActive(modOriginal
)
776 # load modified module (if one exists)
777 if DoesModifiedExist(name
):
778 self
.LoadFromFile(modModified
, GetModifiedFilename(name
))
781 def LoadFromFile(self
, modID
, filename
):
782 self
.modules
[modID
][2] = filename
783 file = open(filename
, "rt")
784 self
.LoadFromSource(modID
, file.read())
788 def LoadFromSource(self
, modID
, source
):
789 self
.modules
[modID
][1] = source
793 def LoadDict(self
, modID
):
794 if self
.name
!= __name__
:
795 source
= self
.modules
[modID
][1]
796 description
= self
.modules
[modID
][3]
799 self
.modules
[modID
][0] = {}
800 code
= compile(source
, description
, "exec")
801 exec code
in self
.modules
[modID
][0]
803 self
.modules
[modID
][4] = DemoError(sys
.exc_info())
804 self
.modules
[modID
][0] = None
806 self
.modules
[modID
][4] = None
809 def SetActive(self
, modID
):
810 if modID
!= modOriginal
and modID
!= modModified
:
813 self
.modActive
= modID
817 dict = self
.modules
[self
.modActive
][0]
821 return ModuleDictWrapper(dict)
824 def GetActiveID(self
):
825 return self
.modActive
828 def GetSource(self
, modID
= None):
830 modID
= self
.modActive
831 return self
.modules
[modID
][1]
834 def GetFilename(self
, modID
= None):
836 modID
= self
.modActive
837 return self
.modules
[self
.modActive
][2]
840 def GetErrorInfo(self
, modID
= None):
842 modID
= self
.modActive
843 return self
.modules
[self
.modActive
][4]
846 def Exists(self
, modID
):
847 return self
.modules
[modID
][1] != ""
850 def UpdateFile(self
, modID
= None):
851 """Updates the file from which a module was loaded
852 with (possibly updated) source"""
854 modID
= self
.modActive
856 source
= self
.modules
[modID
][1]
857 filename
= self
.modules
[modID
][2]
860 file = open(filename
, "wt")
866 def Delete(self
, modID
):
867 if self
.modActive
== modID
:
870 self
.modules
[modID
][0] = None
871 self
.modules
[modID
][1] = ""
872 self
.modules
[modID
][2] = ""
875 #---------------------------------------------------------------------------
878 """Wraps and stores information about the current exception"""
879 def __init__(self
, exc_info
):
882 excType
, excValue
= exc_info
[:2]
883 # traceback list entries: (filename, line number, function name, text)
884 self
.traceback
= traceback
.extract_tb(exc_info
[2])
886 # --Based on traceback.py::format_exception_only()--
887 if type(excType
) == types
.ClassType
:
888 self
.exception_type
= excType
.__name
__
890 self
.exception_type
= excType
892 # If it's a syntax error, extra information needs
893 # to be added to the traceback
894 if excType
is SyntaxError:
896 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
901 filename
= "<string>"
903 self
.traceback
.append( (filename
, lineno
, "", line
) )
906 self
.exception_details
= str(excValue
)
908 self
.exception_details
= "<unprintable %s object>" & type(excValue
).__name
__
915 Details : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details
)
918 #---------------------------------------------------------------------------
920 class DemoErrorPanel(wx
.Panel
):
921 """Panel put into the demo tab when the demo fails to run due to errors"""
923 def __init__(self
, parent
, codePanel
, demoError
, log
):
924 wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
925 self
.codePanel
= codePanel
929 self
.box
= wx
.BoxSizer(wx
.VERTICAL
)
932 self
.box
.Add(wx
.StaticText(self
, -1, "An error has occured while trying to run the demo")
933 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10)
935 # Exception Information
936 boxInfo
= wx
.StaticBox(self
, -1, "Exception Info" )
937 boxInfoSizer
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL
) # Used to center the grid within the box
938 boxInfoGrid
= wx
.FlexGridSizer(0, 2, 0, 0)
939 textFlags
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
940 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 )
941 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_type
) , 0, textFlags
, 5 )
942 boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 )
943 boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 )
944 boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 )
945 self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5)
947 # Set up the traceback list
948 # This one automatically resizes last column to take up remaining space
949 from ListCtrl
import TestListCtrl
950 self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT | wx
.SUNKEN_BORDER
)
951 self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
)
952 self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
)
953 self
.list.InsertColumn(0, "Filename")
954 self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
)
955 self
.list.InsertColumn(2, "Function")
956 self
.list.InsertColumn(3, "Code")
957 self
.InsertTraceback(self
.list, demoError
.traceback
)
958 self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
)
959 self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
)
960 self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:")
961 , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5)
962 self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5)
963 self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n"
964 + "Double-click on them to go to the offending line")
965 , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5)
968 self
.SetSizer(self
.box
)
971 def InsertTraceback(self
, list, traceback
):
972 #Add the traceback data
973 for x
in range(len(traceback
)):
975 list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename
976 list.SetStringItem(x
, 1, str(data
[1])) # Line
977 list.SetStringItem(x
, 2, str(data
[2])) # Function
978 list.SetStringItem(x
, 3, str(data
[3])) # Code
980 # Check whether this entry is from the demo module
981 if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised
982 self
.list.SetItemData(x
, int(data
[1])) # Store line number for easy access
983 # Give it a blue colour
984 item
= self
.list.GetItem(x
)
985 item
.SetTextColour(wx
.BLUE
)
986 self
.list.SetItem(item
)
988 self
.list.SetItemData(x
, -1) # Editor can't jump into this one's code
991 def OnItemSelected(self
, event
):
992 # This occurs before OnDoubleClick and can be used to set the
993 # currentItem. OnDoubleClick doesn't get a wxListEvent....
994 self
.currentItem
= event
.m_itemIndex
998 def OnDoubleClick(self
, event
):
999 # If double-clicking on a demo's entry, jump to the line number
1000 line
= self
.list.GetItemData(self
.currentItem
)
1002 self
.nb
.SetSelection(1) # Switch to the code viewer tab
1003 wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True)
1007 #---------------------------------------------------------------------------
1009 class DemoTaskBarIcon(wx
.TaskBarIcon
):
1010 TBMENU_RESTORE
= wx
.NewId()
1011 TBMENU_CLOSE
= wx
.NewId()
1012 TBMENU_CHANGE
= wx
.NewId()
1013 TBMENU_REMOVE
= wx
.NewId()
1015 def __init__(self
, frame
):
1016 wx
.TaskBarIcon
.__init
__(self
)
1020 icon
= self
.MakeIcon(images
.getWXPdemoImage())
1021 self
.SetIcon(icon
, "wxPython Demo")
1025 self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
)
1026 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
)
1027 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
)
1028 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
)
1029 self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
)
1032 def CreatePopupMenu(self
):
1034 This method is called by the base class when it needs to popup
1035 the menu for the default EVT_RIGHT_DOWN event. Just create
1036 the menu how you want it and return it from this function,
1037 the base class takes care of the rest.
1040 menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo")
1041 menu
.Append(self
.TBMENU_CLOSE
, "Close wxPython Demo")
1042 menu
.AppendSeparator()
1043 menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon")
1044 menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon")
1048 def MakeIcon(self
, img
):
1050 The various platforms have different requirements for the
1053 if "wxMSW" in wx
.PlatformInfo
:
1054 img
= img
.Scale(16, 16)
1055 elif "wxGTK" in wx
.PlatformInfo
:
1056 img
= img
.Scale(22, 22)
1057 # wxMac can be any size upto 128x128, so leave the source img alone....
1058 icon
= wx
.IconFromBitmap(img
.ConvertToBitmap() )
1062 def OnTaskBarActivate(self
, evt
):
1063 if self
.frame
.IsIconized():
1064 self
.frame
.Iconize(False)
1065 if not self
.frame
.IsShown():
1066 self
.frame
.Show(True)
1070 def OnTaskBarClose(self
, evt
):
1074 def OnTaskBarChange(self
, evt
):
1075 names
= [ "WXPdemo", "WXP", "Mondrian", "Test2m",
1076 "Blom08m", "Blom10m", "Blom15m" ]
1077 name
= names
[self
.imgidx
]
1079 getFunc
= getattr(images
, "get%sImage" % name
)
1081 if self
.imgidx
>= len(names
):
1084 icon
= self
.MakeIcon(getFunc())
1085 self
.SetIcon(icon
, "This is a new icon: " + name
)
1088 def OnTaskBarRemove(self
, evt
):
1092 #---------------------------------------------------------------------------
1093 class wxPythonDemo(wx
.Frame
):
1094 overviewText
= "wxPython Overview"
1096 def __init__(self
, parent
, title
):
1097 wx
.Frame
.__init
__(self
, parent
, -1, title
, size
= (950, 720),
1098 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
1100 self
.SetMinSize((640,480))
1103 self
.cwd
= os
.getcwd()
1104 self
.curOverview
= ""
1105 self
.demoPage
= None
1106 self
.codePage
= None
1108 self
.firstTime
= True
1110 icon
= images
.getWXPdemoIcon()
1113 self
.tbicon
= DemoTaskBarIcon(self
)
1115 wx
.CallAfter(self
.ShowTip
)
1117 self
.otherWin
= None
1118 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
1119 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
1120 self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
)
1121 self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
)
1123 self
.Centre(wx
.BOTH
)
1124 self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
)
1126 splitter
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1127 splitter2
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
)
1129 def EmptyHandler(evt
): pass
1130 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1131 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1133 # Prevent TreeCtrl from displaying all items after destruction when True
1137 self
.nb
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
)
1140 self
.mainmenu
= wx
.MenuBar()
1142 item
= menu
.Append(-1, '&Redirect Output',
1143 'Redirect print statements to a window',
1145 self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
)
1147 item
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1148 self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
)
1149 wx
.App
.SetMacExitMenuItemId(item
.GetId())
1150 self
.mainmenu
.Append(menu
, '&File')
1154 for item
in _treeList
:
1156 for childItem
in item
[1]:
1157 mi
= submenu
.Append(-1, childItem
)
1158 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
)
1159 menu
.AppendMenu(wx
.NewId(), item
[0], submenu
)
1160 self
.mainmenu
.Append(menu
, '&Demo')
1162 # Make a Demo Code menu
1163 #TODO: Add new menu items
1164 # Like the option-enabled entries to select the
1166 #TODO: should we bother?
1169 #saveID = wx.NewId()
1170 #restoreID = wx.NewId()
1172 #menu.Append(saveID, '&Save\tCtrl-S', 'Save edited demo')
1173 #menu.Append(restoreID, '&Delete Modified\tCtrl-R', 'Delete modified copy')
1174 #self.Bind(wx.EVT_MENU, self.codePage.OnSave, id=saveID)
1175 #self.Bind(wx.EVT_MENU, self.codePage.OnRestore, id=restoreID)
1176 #self.mainmenu.Append(menu, 'Demo &Code')
1181 findItem
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1182 findnextItem
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next')
1183 menu
.AppendSeparator()
1185 shellItem
= menu
.Append(-1, 'Open Py&Shell Window\tF5',
1186 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1187 menu
.AppendSeparator()
1188 helpItem
= menu
.Append(-1, '&About\tCtrl-H', 'wxPython RULES!!!')
1189 wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId())
1191 self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
)
1192 self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
)
1193 self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
, findItem
)
1194 self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
, findnextItem
)
1195 self
.Bind(wx
.EVT_COMMAND_FIND
, self
.OnFind
)
1196 self
.Bind(wx
.EVT_COMMAND_FIND_NEXT
, self
.OnFind
)
1197 self
.Bind(wx
.EVT_COMMAND_FIND_CLOSE
, self
.OnFindClose
)
1198 self
.mainmenu
.Append(menu
, '&Help')
1199 self
.SetMenuBar(self
.mainmenu
)
1201 self
.finddata
= wx
.FindReplaceData()
1204 # This is another way to set Accelerators, in addition to
1205 # using the '\t<key>' syntax in the menu items.
1206 aTable
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
, ord('X'), exitID
),
1207 (wx
.ACCEL_CTRL
, ord('H'), helpID
),
1208 (wx
.ACCEL_CTRL
, ord('F'), findID
),
1209 (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
)
1211 self
.SetAcceleratorTable(aTable
)
1217 self
.tree
= wx
.TreeCtrl(splitter
, tID
, style
=
1218 wx
.TR_DEFAULT_STYLE
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT
1221 root
= self
.tree
.AddRoot("wxPython Overview")
1223 for item
in _treeList
:
1224 child
= self
.tree
.AppendItem(root
, item
[0])
1225 if not firstChild
: firstChild
= child
1226 for childItem
in item
[1]:
1227 theDemo
= self
.tree
.AppendItem(child
, childItem
)
1228 self
.treeMap
[childItem
] = theDemo
1230 self
.tree
.Expand(root
)
1231 self
.tree
.Expand(firstChild
)
1232 self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
)
1233 self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
)
1234 self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
)
1235 self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
)
1237 # Set up a wx.html.HtmlWindow on the Overview Notebook page
1238 # we put it in a panel first because there seems to be a
1239 # refresh bug of some sort (wxGTK) when it is directly in
1242 self
.ovr
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400))
1243 self
.nb
.AddPage(self
.ovr
, self
.overviewText
)
1245 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1246 panel
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
)
1247 self
.ovr
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400))
1248 self
.nb
.AddPage(panel
, self
.overviewText
)
1250 def OnOvrSize(evt
, ovr
=self
.ovr
):
1251 ovr
.SetSize(evt
.GetSize())
1252 panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
)
1253 panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
)
1255 if "gtk2" in wx
.PlatformInfo
:
1256 self
.ovr
.SetStandardFonts()
1257 self
.SetOverview(self
.overviewText
, mainOverview
)
1260 # Set up a log window
1261 self
.log
= wx
.TextCtrl(splitter2
, -1,
1262 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
1264 # Set the wxWindows log target to be this textctrl
1265 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
1267 # But instead of the above we want to show how to use our own wx.Log class
1268 wx
.Log_SetActiveTarget(MyLog(self
.log
))
1270 # for serious debugging
1271 #wx.Log_SetActiveTarget(wx.LogStderr())
1272 #wx.Log_SetTraceMask(wx.TraceMessages)
1275 self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
)
1276 wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
)
1278 # add the windows to the splitter and split it.
1279 splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160)
1280 splitter
.SplitVertically(self
.tree
, splitter2
, 200)
1282 splitter
.SetMinimumPaneSize(120)
1283 splitter2
.SetMinimumPaneSize(60)
1285 # Make the splitter on the right expand the top window when resized
1286 def SplitterOnSize(evt
):
1287 splitter
= evt
.GetEventObject()
1288 sz
= splitter
.GetSize()
1289 splitter
.SetSashPosition(sz
.height
- 160, False)
1292 splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
)
1294 # select initial items
1295 self
.nb
.SetSelection(0)
1296 self
.tree
.SelectItem(root
)
1298 # Load 'Main' module
1299 self
.LoadDemo(self
.overviewText
)
1302 # select some other initial module?
1303 if len(sys
.argv
) > 1:
1305 if arg
.endswith('.py'):
1307 selectedDemo
= self
.treeMap
.get(arg
, None)
1309 self
.tree
.SelectItem(selectedDemo
)
1310 self
.tree
.EnsureVisible(selectedDemo
)
1313 #---------------------------------------------
1314 def WriteText(self
, text
):
1315 if text
[-1:] == '\n':
1319 def write(self
, txt
):
1322 #---------------------------------------------
1323 def OnItemExpanded(self
, event
):
1324 item
= event
.GetItem()
1325 wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
))
1328 #---------------------------------------------
1329 def OnItemCollapsed(self
, event
):
1330 item
= event
.GetItem()
1331 wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
))
1334 #---------------------------------------------
1335 def OnTreeLeftDown(self
, event
):
1336 # reset the overview text if the tree item is clicked on again
1337 pt
= event
.GetPosition();
1338 item
, flags
= self
.tree
.HitTest(pt
)
1339 if item
== self
.tree
.GetSelection():
1340 self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
)
1343 #---------------------------------------------
1344 def OnSelChanged(self
, event
):
1345 if self
.dying
or not self
.loaded
:
1348 item
= event
.GetItem()
1349 itemText
= self
.tree
.GetItemText(item
)
1350 self
.LoadDemo(itemText
)
1352 #---------------------------------------------
1353 def LoadDemo(self
, demoName
):
1355 wx
.BeginBusyCursor()
1358 self
.ShutdownDemoModule()
1360 if demoName
== self
.overviewText
:
1361 # User selected the "wxPython Overview" node
1363 # Changing the main window at runtime not yet supported...
1364 self
.demoModules
= DemoModules(__name__
)
1365 self
.SetOverview(self
.overviewText
, mainOverview
)
1366 self
.LoadDemoSource()
1367 self
.UpdateNotebook(0)
1369 if os
.path
.exists(GetOriginalFilename(demoName
)):
1370 wx
.LogMessage("Loading demo %s.py..." % demoName
)
1371 self
.demoModules
= DemoModules(demoName
)
1372 self
.LoadDemoSource()
1375 self
.SetOverview("wxPython", mainOverview
)
1376 self
.codePage
= None
1377 self
.UpdateNotebook(0)
1381 #---------------------------------------------
1382 def LoadDemoSource(self
):
1383 self
.codePage
= None
1384 self
.codePage
= DemoCodePanel(self
.nb
, self
)
1385 self
.codePage
.LoadDemo(self
.demoModules
)
1387 #---------------------------------------------
1388 def RunModule(self
):
1389 """Runs the active module"""
1391 module
= self
.demoModules
.GetActive()
1392 self
.ShutdownDemoModule()
1395 # o The RunTest() for all samples must now return a window that can
1396 # be palced in a tab in the main notebook.
1397 # o If an error occurs (or has occured before) an error tab is created.
1399 if module
is not None:
1400 wx
.LogMessage("Running demo module...")
1401 if hasattr(module
, "overview"):
1402 overviewText
= module
.overview
1405 self
.demoPage
= module
.runTest(self
, self
.nb
, self
)
1407 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1408 DemoError(sys
.exc_info()), self
)
1410 assert self
.demoPage
is not None, "runTest must return a window!"
1413 # There was a previous error in compiling or exec-ing
1414 self
.demoPage
= DemoErrorPanel(self
.nb
, self
.codePage
,
1415 self
.demoModules
.GetErrorInfo(), self
)
1417 self
.SetOverview(self
.demoModules
.name
+ " Overview", overviewText
)
1420 # cahnge to the demo page the first time a module is run
1421 self
.UpdateNotebook(2)
1422 self
.firstTime
= False
1424 # otherwise just stay on the same tab in case the user has changed to another one
1425 self
.UpdateNotebook()
1427 #---------------------------------------------
1428 def ShutdownDemoModule(self
):
1430 # inform the window that it's time to quit if it cares
1431 if hasattr(self
.demoPage
, "ShutdownDemo"):
1432 self
.demoPage
.ShutdownDemo()
1433 wx
.YieldIfNeeded() # in case the page has pending events
1434 self
.demoPage
= None
1436 #---------------------------------------------
1437 def UpdateNotebook(self
, select
= -1):
1441 def UpdatePage(page
, pageText
):
1444 for i
in range(nb
.GetPageCount()):
1445 if nb
.GetPageText(i
) == pageText
:
1453 nb
.AddPage(page
, pageText
)
1454 if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
)
1456 if nb
.GetPage(pagePos
) != page
:
1457 # Reload an existing page
1459 nb
.DeletePage(pagePos
)
1460 nb
.InsertPage(pagePos
, page
, pageText
)
1462 if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
)
1464 # Excellent! No redraw/flicker
1465 if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
)
1468 nb
.DeletePage(pagePos
)
1469 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
)
1471 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
)
1474 select
= nb
.GetSelection()
1476 UpdatePage(self
.codePage
, "Demo Code")
1477 UpdatePage(self
.demoPage
, "Demo")
1479 if select
>= 0 and select
< nb
.GetPageCount():
1480 nb
.SetSelection(select
)
1482 #---------------------------------------------
1483 def SetOverview(self
, name
, text
):
1484 self
.curOverview
= text
1486 if lead
!= '<html>' and lead
!= '<HTML>':
1487 text
= '<br>'.join(text
.split('\n'))
1489 text
= text
.decode('iso8859_1')
1490 self
.ovr
.SetPage(text
)
1491 self
.nb
.SetPageText(0, name
)
1493 #---------------------------------------------
1495 def OnFileExit(self
, *event
):
1498 def OnToggleRedirect(self
, event
):
1502 print "Print statements and other standard output will now be directed to this window."
1505 print "Print statements and other standard output will now be sent to the usual location."
1507 def OnHelpAbout(self
, event
):
1508 from About
import MyAboutBox
1509 about
= MyAboutBox(self
)
1513 def OnHelpFind(self
, event
):
1514 self
.nb
.SetSelection(1)
1515 self
.finddlg
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find",
1519 self
.finddlg
.Show(True)
1521 def OnFind(self
, event
):
1522 editor
= self
.codePage
.editor
1523 self
.nb
.SetSelection(1)
1524 end
= editor
.GetLastPosition()
1525 textstring
= editor
.GetRange(0, end
).lower()
1526 start
= editor
.GetSelection()[1]
1527 findstring
= self
.finddata
.GetFindString().lower()
1528 loc
= textstring
.find(findstring
, start
)
1529 if loc
== -1 and start
!= 0:
1530 # string not found, start at beginning
1532 loc
= textstring
.find(findstring
, start
)
1534 dlg
= wx
.MessageDialog(self
, 'Find String Not Found',
1535 'Find String Not Found in Demo File',
1536 wx
.OK | wx
.ICON_INFORMATION
)
1541 self
.finddlg
.SetFocus()
1544 self
.finddlg
.Destroy()
1545 editor
.ShowPosition(loc
)
1546 editor
.SetSelection(loc
, loc
+ len(findstring
))
1550 def OnFindNext(self
, event
):
1551 if self
.finddata
.GetFindString():
1554 self
.OnHelpFind(event
)
1556 def OnFindClose(self
, event
):
1557 event
.GetDialog().Destroy()
1560 def OnOpenShellWindow(self
, evt
):
1562 # if it already exists then just make sure it's visible
1568 # Make a PyShell window
1570 namespace
= { 'wx' : wx
,
1571 'app' : wx
.GetApp(),
1574 self
.shell
= py
.shell
.ShellFrame(None, locals=namespace
)
1575 self
.shell
.SetSize((640,480))
1578 # Hook the close event of the main frame window so that we
1579 # close the shell at the same time if it still exists
1580 def CloseShell(evt
):
1584 self
.Bind(wx
.EVT_CLOSE
, CloseShell
)
1587 #---------------------------------------------
1588 def OnCloseWindow(self
, event
):
1590 self
.demoPage
= None
1591 self
.codePage
= None
1592 self
.mainmenu
= None
1593 self
.tbicon
.Destroy()
1597 #---------------------------------------------
1598 def OnIdle(self
, event
):
1600 self
.otherWin
.Raise()
1601 self
.demoPage
= self
.otherWin
1602 self
.otherWin
= None
1605 #---------------------------------------------
1608 showTipText
= open(opj("data/showTips")).read()
1609 showTip
, index
= eval(showTipText
)
1611 showTip
, index
= (1, 0)
1613 tp
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
)
1615 showTip
= wx
.ShowTip(self
, tp
)
1616 index
= tp
.GetCurrentTip()
1617 open(opj("data/showTips"), "w").write(str( (showTip
, index
) ))
1620 #---------------------------------------------
1621 def OnDemoMenu(self
, event
):
1623 selectedDemo
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())]
1627 self
.tree
.SelectItem(selectedDemo
)
1628 self
.tree
.EnsureVisible(selectedDemo
)
1632 #---------------------------------------------
1633 def OnIconfiy(self
, evt
):
1634 wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized())
1637 #---------------------------------------------
1638 def OnMaximize(self
, evt
):
1639 wx
.LogMessage("OnMaximize")
1642 #---------------------------------------------
1643 def OnActivate(self
, evt
):
1644 wx
.LogMessage("OnActivate: %s" % evt
.GetActive())
1647 #---------------------------------------------
1648 def OnAppActivate(self
, evt
):
1649 wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive())
1652 #---------------------------------------------------------------------------
1653 #---------------------------------------------------------------------------
1655 class MySplashScreen(wx
.SplashScreen
):
1657 bmp
= wx
.Image(opj("bitmaps/splash.gif")).ConvertToBitmap()
1658 wx
.SplashScreen
.__init
__(self
, bmp
,
1659 wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
,
1661 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
1663 def OnClose(self
, evt
):
1665 frame
= wxPythonDemo(None, "wxPython: (A Demonstration)")
1667 evt
.Skip() # Make sure the default handler runs too...
1670 class MyApp(wx
.App
):
1673 Create and show the splash screen. It will then create and show
1674 the main frame when it is time to do so.
1678 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1680 # Normally when using a SplashScreen you would create it, show
1681 # it and then continue on with the applicaiton's
1682 # initialization, finally creating and showing the main
1683 # application window(s). In this case we have nothing else to
1684 # do so we'll delay showing the main frame until later (see
1685 # OnClose above) so the users can see the SplashScreen effect.
1686 splash
= MySplashScreen()
1693 #---------------------------------------------------------------------------
1697 demoPath
= os
.path
.dirname(__file__
)
1704 #---------------------------------------------------------------------------
1707 mainOverview
= """<html><body>
1710 <p> wxPython is a <b>GUI toolkit</b> for the Python programming
1711 language. It allows Python programmers to create programs with a
1712 robust, highly functional graphical user interface, simply and easily.
1713 It is implemented as a Python extension module (native code) that
1714 wraps the popular wxWindows cross platform GUI library, which is
1717 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1718 means that it is free for anyone to use and the source code is
1719 available for anyone to look at and modify. Or anyone can contribute
1720 fixes or enhancements to the project.
1722 <p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1723 same program will run on multiple platforms without modification.
1724 Currently supported platforms are 32-bit Microsoft Windows, most Unix
1725 or unix-like systems, and Macintosh OS X. Since the language is
1726 Python, wxPython programs are <b>simple, easy</b> to write and easy to
1729 <p> <b>This demo</b> is not only a collection of test cases for
1730 wxPython, but is also designed to help you learn about and how to use
1731 wxPython. Each sample is listed in the tree control on the left.
1732 When a sample is selected in the tree then a module is loaded and run
1733 (usually in a tab of this notebook,) and the source code of the module
1734 is loaded in another tab for you to browse and learn from.
1739 #----------------------------------------------------------------------------
1740 #----------------------------------------------------------------------------
1742 if __name__
== '__main__':
1746 #----------------------------------------------------------------------------