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 #---------------------------------------------------------------------------- 
  14 import sys
, os
, time
, string
 
  15 from   wxPython
.wx 
import * 
  16 from   wxPython
.html 
import wxHtmlWindow
 
  20 #--------------------------------------------------------------------------- 
  24     ('New since last release', ['wxGenericDirCtrl', 
  31     ('Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame', 
  32                  'wxGrid', 'wxSashWindow', 
  33                  'wxScrolledWindow', 'wxSplitterWindow', 
  34                  'wxStatusBar', 'wxNotebook', 
  36                  'wxStyledTextCtrl_1', 'wxStyledTextCtrl_2', 
  38                  'wxDynamicSashWindow', 
  41     ('Common Dialogs', ['wxColourDialog', 'wxDirDialog', 'wxFileDialog', 
  42                         'wxSingleChoiceDialog', 'wxTextEntryDialog', 
  43                         'wxFontDialog', 'wxPageSetupDialog', 'wxPrintDialog', 
  44                         'wxMessageDialog', 'wxProgressDialog', 'wxFindReplaceDialog', 
  47     ('Controls', ['wxButton', 'wxCheckBox', 'wxCheckListBox', 'wxChoice', 
  48                   'wxComboBox', 'wxGauge', 'wxListBox', 'wxListCtrl', 'VirtualListCtrl', 
  50                   'wxTreeCtrl', 'wxSpinButton', 'wxSpinCtrl', 'wxStaticText', 
  51                   'wxStaticBitmap', 'wxRadioBox', 'wxSlider', 'wxToolBar', 
  52                   'wxCalendarCtrl', 'wxToggleButton', 
  53                   'wxEditableListBox', 'wxLEDNumberCtrl', 
  56     ('Window Layout', ['wxLayoutConstraints', 'LayoutAnchors', 'Sizers', 'XML_Resource', 
  60     ('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'URLDragAndDrop', 
  62                         'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits', 
  63                         'wxImage', 'wxMask', 'PrintFramework', 'wxOGL', 
  64                         'PythonEvents', 'Threads', 
  65                         'ActiveXWrapper_Acrobat', 'ActiveXWrapper_IE', 
  66                         'wxDragImage', "wxProcess", "FancyText", "OOR", "wxWave", 
  67                         'wxJoystick', 'DrawXXXList', 'ErrorDialogs', 'wxMimeTypesManager', 
  68                         'ContextHelp', 'SplitTree', 'Unicode', 'wxFileHistory', 
  71     ('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog', 
  72                           'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar', 
  73                           'wxCalendar', 'wxMVCTree', 'wxVTKRenderWindow', 
  74                           'FileBrowseButton', 'GenericButtons', 'wxEditor', 
  75                           'ColourSelect', 'ImageBrowser', 
  76                           'infoframe', 'ColourDB', 'PyCrust', 'PyCrustWithFilling', 
  81     ('Cool Contribs', ['pyTree', 'hangman', 
  88 #--------------------------------------------------------------------------- 
  91     def __init__(self
, textCtrl
, logTime
=0): 
  92         wxPyLog
.__init
__(self
) 
  94         self
.logTime 
= logTime
 
  96     def DoLogString(self
, message
, timeStamp
): 
  98             message 
= time
.strftime("%X", time
.localtime(timeStamp
)) + \
 
 100         self
.tc
.AppendText(message 
+ '\n') 
 103 #--------------------------------------------------------------------------- 
 106     """Convert paths to the platform-specific separator""" 
 107     return apply(os
.path
.join
, tuple(string
.split(path
, '/'))) 
 110 #--------------------------------------------------------------------------- 
 112 class wxPythonDemo(wxFrame
): 
 113     overviewText 
= "wxPython Overview" 
 115     def __init__(self
, parent
, id, title
): 
 116         wxFrame
.__init
__(self
, parent
, -1, title
, size 
= (800, 600), 
 117                          style
=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE
) 
 119         self
.cwd 
= os
.getcwd() 
 120         self
.curOverview 
= "" 
 122         icon 
= images
.getMondrianIcon() 
 125         if wxPlatform 
== '__WXMSW__': 
 126             # setup a taskbar icon, and catch some events from it 
 127             self
.tbicon 
= wxTaskBarIcon() 
 128             self
.tbicon
.SetIcon(icon
, "wxPython Demo") 
 129             EVT_TASKBAR_LEFT_DCLICK(self
.tbicon
, self
.OnTaskBarActivate
) 
 130             EVT_TASKBAR_RIGHT_UP(self
.tbicon
, self
.OnTaskBarMenu
) 
 131             EVT_MENU(self
.tbicon
, self
.TBMENU_RESTORE
, self
.OnTaskBarActivate
) 
 132             EVT_MENU(self
.tbicon
, self
.TBMENU_CLOSE
, self
.OnTaskBarClose
) 
 137         EVT_IDLE(self
, self
.OnIdle
) 
 138         EVT_CLOSE(self
, self
.OnCloseWindow
) 
 139         EVT_ICONIZE(self
, self
.OnIconfiy
) 
 140         EVT_MAXIMIZE(self
, self
.OnMaximize
) 
 143         self
.CreateStatusBar(1, wxST_SIZEGRIP
) 
 145         splitter 
= wxSplitterWindow(self
, -1, style
=wxNO_3D|wxSP_3D
) 
 146         splitter2 
= wxSplitterWindow(splitter
, -1, style
=wxNO_3D|wxSP_3D
) 
 148         def EmptyHandler(evt
): pass 
 149         EVT_ERASE_BACKGROUND(splitter
, EmptyHandler
) 
 150         EVT_ERASE_BACKGROUND(splitter2
, EmptyHandler
) 
 152         # Prevent TreeCtrl from displaying all items after destruction when true 
 156         self
.mainmenu 
= wxMenuBar() 
 159         menu
.Append(exitID
, 'E&xit\tAlt-X', 'Get the heck outta here!') 
 160         EVT_MENU(self
, exitID
, self
.OnFileExit
) 
 161         self
.mainmenu
.Append(menu
, '&File') 
 165         for item 
in _treeList
: 
 167             for childItem 
in item
[1]: 
 169                 submenu
.Append(mID
, childItem
) 
 170                 EVT_MENU(self
, mID
, self
.OnDemoMenu
) 
 171             menu
.AppendMenu(wxNewId(), item
[0], submenu
) 
 172         self
.mainmenu
.Append(menu
, '&Demo') 
 178         menu
.Append(helpID
, '&About\tCtrl-H', 'wxPython RULES!!!') 
 179         EVT_MENU(self
, helpID
, self
.OnHelpAbout
) 
 180         self
.mainmenu
.Append(menu
, '&Help') 
 181         self
.SetMenuBar(self
.mainmenu
) 
 183         # set the menu accellerator table... 
 184         aTable 
= wxAcceleratorTable([(wxACCEL_ALT
,  ord('X'), exitID
), 
 185                                      (wxACCEL_CTRL
, ord('H'), helpID
)]) 
 186         self
.SetAcceleratorTable(aTable
) 
 192         self
.tree 
= wxTreeCtrl(splitter
, tID
, 
 193                                style
=wxTR_HAS_BUTTONS |
 
 195                                wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
 197         #self.tree.SetBackgroundColour(wxNamedColour("Pink")) 
 198         root 
= self
.tree
.AddRoot("wxPython Overview") 
 200         for item 
in _treeList
: 
 201             child 
= self
.tree
.AppendItem(root
, item
[0]) 
 202             if not firstChild
: firstChild 
= child
 
 203             for childItem 
in item
[1]: 
 204                 theDemo 
= self
.tree
.AppendItem(child
, childItem
) 
 205                 self
.treeMap
[childItem
] = theDemo
 
 207         self
.tree
.Expand(root
) 
 208         self
.tree
.Expand(firstChild
) 
 209         EVT_TREE_ITEM_EXPANDED   (self
.tree
, tID
, self
.OnItemExpanded
) 
 210         EVT_TREE_ITEM_COLLAPSED  (self
.tree
, tID
, self
.OnItemCollapsed
) 
 211         EVT_TREE_SEL_CHANGED     (self
.tree
, tID
, self
.OnSelChanged
) 
 212         EVT_LEFT_DOWN            (self
.tree
,      self
.OnTreeLeftDown
) 
 215         self
.nb 
= wxNotebook(splitter2
, -1, style
=wxCLIP_CHILDREN
) 
 217         # Set up a wxHtmlWindow on the Overview Notebook page 
 218         # we put it in a panel first because there seems to be a 
 219         # refresh bug of some sort (wxGTK) when it is directly in 
 222             self
.ovr 
= wxHtmlWindow(self
.nb
, -1, size
=(400, 400)) 
 223             self
.nb
.AddPage(self
.ovr
, self
.overviewText
) 
 225         else:  # hopefully I can remove this hacky code soon, see bug #216861 
 226             panel 
= wxPanel(self
.nb
, -1, style
=wxCLIP_CHILDREN
) 
 227             self
.ovr 
= wxHtmlWindow(panel
, -1, size
=(400, 400)) 
 228             self
.nb
.AddPage(panel
, self
.overviewText
) 
 230             def OnOvrSize(evt
, ovr
=self
.ovr
): 
 231                 ovr
.SetSize(evt
.GetSize()) 
 233             EVT_SIZE(panel
, OnOvrSize
) 
 234             EVT_ERASE_BACKGROUND(panel
, EmptyHandler
) 
 237         self
.SetOverview(self
.overviewText
, overview
) 
 240         # Set up a TextCtrl on the Demo Code Notebook page 
 241         self
.txt 
= wxTextCtrl(self
.nb
, -1, 
 242                               style 
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
) 
 243         self
.nb
.AddPage(self
.txt
, "Demo Code") 
 246         # Set up a log on the View Log Notebook page 
 247         self
.log 
= wxTextCtrl(splitter2
, -1, 
 248                               style 
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
) 
 250         # Set the wxWindows log target to be this textctrl 
 251         #wxLog_SetActiveTarget(wxLogTextCtrl(self.log)) 
 253         # But instead of the above we want to show how to use our own wxLog class 
 254         wxLog_SetActiveTarget(MyLog(self
.log
)) 
 260         # add the windows to the splitter and split it. 
 261         splitter2
.SplitHorizontally(self
.nb
, self
.log
) 
 262         splitter
.SplitVertically(self
.tree
, splitter2
) 
 264         splitter
.SetSashPosition(180, true
) 
 265         splitter
.SetMinimumPaneSize(20) 
 266         splitter2
.SetSashPosition(450, true
) 
 267         splitter2
.SetMinimumPaneSize(20) 
 271         # select initial items 
 272         self
.nb
.SetSelection(0) 
 273         self
.tree
.SelectItem(root
) 
 275         if len(sys
.argv
) == 2: 
 277                 selectedDemo 
= self
.treeMap
[sys
.argv
[1]] 
 281                 self
.tree
.SelectItem(selectedDemo
) 
 282                 self
.tree
.EnsureVisible(selectedDemo
) 
 285         wxLogMessage('window handle: %s' % self
.GetHandle()) 
 288     #--------------------------------------------- 
 289     def WriteText(self
, text
): 
 290         if text
[-1:] == '\n': 
 295     def write(self
, txt
): 
 298     #--------------------------------------------- 
 299     def OnItemExpanded(self
, event
): 
 300         item 
= event
.GetItem() 
 301         wxLogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
)) 
 304     #--------------------------------------------- 
 305     def OnItemCollapsed(self
, event
): 
 306         item 
= event
.GetItem() 
 307         wxLogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
)) 
 310     #--------------------------------------------- 
 311     def OnTreeLeftDown(self
, event
): 
 312         pt 
= event
.GetPosition(); 
 313         item
, flags 
= self
.tree
.HitTest(pt
) 
 314         if item 
== self
.tree
.GetSelection(): 
 315             self
.SetOverview(self
.tree
.GetItemText(item
), self
.curOverview
) 
 318     #--------------------------------------------- 
 319     def OnSelChanged(self
, event
): 
 323         item 
= event
.GetItem() 
 324         itemText 
= self
.tree
.GetItemText(item
) 
 325         self
.RunDemo(itemText
) 
 328     #--------------------------------------------- 
 329     def RunDemo(self
, itemText
): 
 331         if self
.nb
.GetPageCount() == 3: 
 332             if self
.nb
.GetSelection() == 2: 
 333                 self
.nb
.SetSelection(0) 
 334             self
.nb
.DeletePage(2) 
 336         if itemText 
== self
.overviewText
: 
 337             self
.GetDemoFile('Main.py') 
 338             self
.SetOverview(self
.overviewText
, overview
) 
 343             if os
.path
.exists(itemText 
+ '.py'): 
 345                 wxLogMessage("Running demo %s.py..." % itemText
) 
 347                     self
.GetDemoFile(itemText 
+ '.py') 
 348                     module 
= __import__(itemText
, globals()) 
 349                     self
.SetOverview(itemText 
+ " Overview", module
.overview
) 
 353                 # in case runTest is modal, make sure things look right... 
 357                 self
.window 
= module
.runTest(self
, self
.nb
, self
) ### 
 359                     self
.nb
.AddPage(self
.window
, 'Demo') 
 361                     self
.nb
.SetSelection(2) 
 370     #--------------------------------------------- 
 372     def GetDemoFile(self
, filename
): 
 375             self
.txt
.SetValue(open(filename
).read()) 
 377             self
.txt
.WriteText("Cannot open %s file." % filename
) 
 379         self
.txt
.SetInsertionPoint(0) 
 380         self
.txt
.ShowPosition(0) 
 382     #--------------------------------------------- 
 383     def SetOverview(self
, name
, text
): 
 384         self
.curOverview 
= text
 
 386         if lead 
!= '<html>' and lead 
!= '<HTML>': 
 387             text 
= string
.join(string
.split(text
, '\n'), '<br>') 
 388         self
.ovr
.SetPage(text
) 
 389         self
.nb
.SetPageText(0, name
) 
 391     #--------------------------------------------- 
 393     def OnFileExit(self
, *event
): 
 397     def OnHelpAbout(self
, event
): 
 398         from About 
import MyAboutBox
 
 399         about 
= MyAboutBox(self
) 
 404     #--------------------------------------------- 
 405     def OnCloseWindow(self
, event
): 
 409         if hasattr(self
, "tbicon"): 
 414     #--------------------------------------------- 
 415     def OnIdle(self
, event
): 
 417             self
.otherWin
.Raise() 
 418             self
.window 
= self
.otherWin
 
 426     #--------------------------------------------- 
 429             showTipText 
= open(opj("data/showTips")).read() 
 430             showTip
, index 
= eval(showTipText
) 
 432             showTip
, index 
= (1, 0) 
 434             tp 
= wxCreateFileTipProvider(opj("data/tips.txt"), index
) 
 435             showTip 
= wxShowTip(self
, tp
) 
 436             index 
= tp
.GetCurrentTip() 
 437             open(opj("data/showTips"), "w").write(str( (showTip
, index
) )) 
 440     #--------------------------------------------- 
 441     def OnDemoMenu(self
, event
): 
 443             selectedDemo 
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())] 
 447             self
.tree
.SelectItem(selectedDemo
) 
 448             self
.tree
.EnsureVisible(selectedDemo
) 
 451     #--------------------------------------------- 
 452     def OnTaskBarActivate(self
, evt
): 
 453         if self
.IsIconized(): 
 455         if not self
.IsShown(): 
 459     #--------------------------------------------- 
 461     TBMENU_RESTORE 
= 1000 
 464     def OnTaskBarMenu(self
, evt
): 
 466         menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo") 
 467         menu
.Append(self
.TBMENU_CLOSE
,   "Close") 
 468         self
.tbicon
.PopupMenu(menu
) 
 471     #--------------------------------------------- 
 472     def OnTaskBarClose(self
, evt
): 
 475         # because of the way wxTaskBarIcon.PopupMenu is implemented we have to 
 476         # prod the main idle handler a bit to get the window to actually close 
 477         wxGetApp().ProcessIdle() 
 480     #--------------------------------------------- 
 481     def OnIconfiy(self
, evt
): 
 482         wxLogMessage("OnIconfiy") 
 485     #--------------------------------------------- 
 486     def OnMaximize(self
, evt
): 
 487         wxLogMessage("OnMaximize") 
 493 #--------------------------------------------------------------------------- 
 494 #--------------------------------------------------------------------------- 
 496 class MySplashScreen(wxSplashScreen
): 
 498         bmp 
= wxImage(opj("bitmaps/splash.gif")).ConvertToBitmap() 
 499         wxSplashScreen
.__init
__(self
, bmp
, 
 500                                 wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT
, 
 502         EVT_CLOSE(self
, self
.OnClose
) 
 504     def OnClose(self
, evt
): 
 505         frame 
= wxPythonDemo(None, -1, "wxPython: (A Demonstration)") 
 507         evt
.Skip()  # Make sure the default handler runs too... 
 513         Create and show the splash screen.  It will then create and show 
 514         the main frame when it is time to do so. 
 516         wxInitAllImageHandlers() 
 517         splash 
= MySplashScreen() 
 523 #--------------------------------------------------------------------------- 
 527         demoPath 
= os
.path
.dirname(__file__
) 
 535 #--------------------------------------------------------------------------- 
 539 overview 
= """<html><body> 
 542  Python is an interpreted, interactive, object-oriented programming 
 543  language often compared to Tcl, Perl, Scheme, or Java. 
 545  <p> Python combines remarkable power with very clear syntax. It has 
 546  modules, classes, exceptions, very high level dynamic data types, and 
 547  dynamic typing.  There are interfaces to many system calls and 
 548  libraries, and new built-in modules are easily written in C or 
 549  C++. Python is also usable as an extension language for applications 
 550  that need a programmable interface.  <p> 
 554  wxWindows is a free C++ framework designed to make cross-platform 
 555  programming child's play. Well, almost. wxWindows 2 supports Windows 
 556  3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version 
 557  underway. Other ports are under consideration.  <p> 
 559  wxWindows is a set of libraries that allows C++ applications to 
 560  compile and run on several different types of computers, with minimal 
 561  source code changes.  There is one library per supported GUI (such as 
 562  Motif, or Windows). As well as providing a common API (Application 
 563  Programming Interface) for GUI functionality, it provides 
 564  functionality for accessing some commonly-used operating system 
 565  facilities, such as copying or deleting files. wxWindows is a 
 566  'framework' in the sense that it provides a lot of built-in 
 567  functionality, which the application can use or replace as required, 
 568  thus saving a great deal of coding effort. Basic data structures such 
 569  as strings, linked lists and hash tables are also supported. 
 574  wxPython is a Python extension module that encapsulates the wxWindows 
 575  GUI classes. Currently it is only available for the Win32 and GTK 
 576  ports of wxWindows, but as soon as the other ports are brought up to 
 577  the same level as Win32 and GTK, it should be fairly trivial to 
 578  enable wxPython to be used with the new GUI. 
 582  The wxPython extension module attempts to mirror the class heiarchy 
 583  of wxWindows as closely as possible. This means that there is a 
 584  wxFrame class in wxPython that looks, smells, tastes and acts almost 
 585  the same as the wxFrame class in the C++ version. Unfortunately, 
 586  because of differences in the languages, wxPython doesn't match 
 587  wxWindows exactly, but the differences should be easy to absorb 
 588  because they are natural to Python. For example, some methods that 
 589  return multiple values via argument pointers in C++ will return a 
 590  tuple of values in Python. 
 594  There is still much to be done for wxPython, many classes still need 
 595  to be mirrored. Also, wxWindows is still somewhat of a moving target 
 596  so it is a bit of an effort just keeping wxPython up to date. On the 
 597  other hand, there are enough of the core classes completed that 
 598  useful applications can be written. 
 602  wxPython is close enough to the C++ version that the majority of 
 603  the wxPython documentation is actually just notes attached to the C++ 
 604  documents that describe the places where wxPython is different. There 
 605  is also a series of sample programs included, and a series of 
 606  documentation pages that assist the programmer in getting started 
 612 #---------------------------------------------------------------------------- 
 613 #---------------------------------------------------------------------------- 
 615 if __name__ 
== '__main__': 
 618 #----------------------------------------------------------------------------