]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Main.py
Added URL drag and drop sample to the wxPython demo
[wxWidgets.git] / wxPython / demo / Main.py
1 #!/bin/env python
2 #----------------------------------------------------------------------------
3 # Name: Main.py
4 # Purpose: Testing lots of stuff, controls, window types, etc.
5 #
6 # Author: Robin Dunn
7 #
8 # Created: A long time ago, in a galaxy far, far away...
9 # RCS-ID: $Id$
10 # Copyright: (c) 1999 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
13
14 import sys, os, time
15 from wxPython.wx import *
16 from wxPython.lib.splashscreen import SplashScreen
17 from wxPython.html import wxHtmlWindow
18
19 import images
20
21 #---------------------------------------------------------------------------
22
23
24 _treeList = [
25 ('New since last release', ['ContextHelp',
26 'PyCrust',
27 'PyCrustWithFilling',
28 'VirtualListCtrl',
29 'wxListCtrl',
30 'TablePrint',
31 'OOR',
32 'wxFindReplaceDialog',
33 'DrawXXXList',
34 'ErrorDialogs',
35 'wxRightTextCtrl',
36 'URLDragAndDrop',
37 ##'wxPopupWindow',
38 ]),
39
40 ('Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame',
41 'wxGrid', 'wxSashWindow',
42 'wxScrolledWindow', 'wxSplitterWindow',
43 'wxStatusBar', 'wxNotebook',
44 'wxHtmlWindow',
45 'wxStyledTextCtrl_1', 'wxStyledTextCtrl_2',
46 ##'wxPopupWindow',
47 ]),
48
49 ('Common Dialogs', ['wxColourDialog', 'wxDirDialog', 'wxFileDialog',
50 'wxSingleChoiceDialog', 'wxTextEntryDialog',
51 'wxFontDialog', 'wxPageSetupDialog', 'wxPrintDialog',
52 'wxMessageDialog', 'wxProgressDialog', 'wxFindReplaceDialog',
53 ]),
54
55 ('Controls', ['wxButton', 'wxCheckBox', 'wxCheckListBox', 'wxChoice',
56 'wxComboBox', 'wxGauge', 'wxListBox', 'wxListCtrl', 'wxTextCtrl',
57 'wxTreeCtrl', 'wxSpinButton', 'wxSpinCtrl', 'wxStaticText',
58 'wxStaticBitmap', 'wxRadioBox', 'wxSlider', 'wxToolBar',
59 'wxCalendarCtrl', 'wxToggleButton',
60 ]),
61
62 ('Window Layout', ['wxLayoutConstraints', 'LayoutAnchors', 'Sizers', 'XML_Resource']),
63
64 ('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'URLDragAndDrop',
65 'FontEnumerator',
66 'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
67 'wxImage', 'wxMask', 'PrintFramework', 'wxOGL',
68 'PythonEvents', 'Threads',
69 'ActiveXWrapper_Acrobat', 'ActiveXWrapper_IE',
70 'wxDragImage', "wxProcess", "FancyText", "OOR", "wxWave",
71 'wxJoystick', 'DrawXXXList', 'ErrorDialogs',
72 ]),
73
74 ('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
75 'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
76 'wxCalendar', 'wxMVCTree', 'wxVTKRenderWindow',
77 'FileBrowseButton', 'GenericButtons', 'wxEditor',
78 'ColourSelect', 'ImageBrowser',
79 'infoframe', 'ColourDB', 'PyCrust', 'TablePrint',
80 'wxRightTextCtrl',
81 ]),
82
83 ('Cool Contribs', ['pyTree', 'hangman', 'SlashDot', 'XMLtreeview']),
84
85 ]
86
87 #---------------------------------------------------------------------------
88
89 class MyLog(wxPyLog):
90 def __init__(self, textCtrl, logTime=0):
91 wxPyLog.__init__(self)
92 self.tc = textCtrl
93 self.logTime = logTime
94
95 def DoLogString(self, message, timeStamp):
96 if self.logTime:
97 message = time.strftime("%X", time.localtime(timeStamp)) + \
98 ": " + message
99 self.tc.AppendText(message + '\n')
100
101
102 #---------------------------------------------------------------------------
103
104 class wxPythonDemo(wxFrame):
105
106 def __init__(self, parent, id, title):
107 wxFrame.__init__(self, parent, -1, title, size = (800, 600),
108 style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
109
110 self.cwd = os.getcwd()
111 self.curOverview = ""
112
113 if 1:
114 icon = wxIconFromXPMData(images.getMondrianData())
115 else:
116 # another way to do it
117 bmp = images.getMondrianBitmap()
118 icon = wxEmptyIcon()
119 icon.CopyFromBitmap(bmp)
120
121 self.SetIcon(icon)
122
123 if wxPlatform == '__WXMSW__':
124 # setup a taskbar icon, and catch some events from it
125 self.tbicon = wxTaskBarIcon()
126 self.tbicon.SetIcon(icon, "wxPython Demo")
127 EVT_TASKBAR_LEFT_DCLICK(self.tbicon, self.OnTaskBarActivate)
128 EVT_TASKBAR_RIGHT_UP(self.tbicon, self.OnTaskBarMenu)
129 EVT_MENU(self.tbicon, self.TBMENU_RESTORE, self.OnTaskBarActivate)
130 EVT_MENU(self.tbicon, self.TBMENU_CLOSE, self.OnTaskBarClose)
131
132
133 self.otherWin = None
134 EVT_IDLE(self, self.OnIdle)
135 EVT_CLOSE(self, self.OnCloseWindow)
136 EVT_ICONIZE(self, self.OnIconfiy)
137 EVT_MAXIMIZE(self, self.OnMaximize)
138
139 self.Centre(wxBOTH)
140 self.CreateStatusBar(1, wxST_SIZEGRIP)
141
142 splitter = wxSplitterWindow(self, -1, style=wxNO_3D|wxSP_3D)
143 splitter2 = wxSplitterWindow(splitter, -1, style=wxNO_3D|wxSP_3D)
144
145 def EmptyHandler(evt): pass
146 EVT_ERASE_BACKGROUND(splitter, EmptyHandler)
147 EVT_ERASE_BACKGROUND(splitter2, EmptyHandler)
148
149 # Prevent TreeCtrl from displaying all items after destruction when true
150 self.dying = false
151
152 # Make a File menu
153 self.mainmenu = wxMenuBar()
154 menu = wxMenu()
155 exitID = wxNewId()
156 menu.Append(exitID, 'E&xit\tAlt-X', 'Get the heck outta here!')
157 EVT_MENU(self, exitID, self.OnFileExit)
158 self.mainmenu.Append(menu, '&File')
159
160 # Make a Demo menu
161 menu = wxMenu()
162 for item in _treeList:
163 submenu = wxMenu()
164 for childItem in item[1]:
165 mID = wxNewId()
166 submenu.Append(mID, childItem)
167 EVT_MENU(self, mID, self.OnDemoMenu)
168 menu.AppendMenu(wxNewId(), item[0], submenu)
169 self.mainmenu.Append(menu, '&Demo')
170
171
172 # Make a Help menu
173 helpID = wxNewId()
174 menu = wxMenu()
175 menu.Append(helpID, '&About\tCtrl-H', 'wxPython RULES!!!')
176 EVT_MENU(self, helpID, self.OnHelpAbout)
177 self.mainmenu.Append(menu, '&Help')
178 self.SetMenuBar(self.mainmenu)
179
180 # set the menu accellerator table...
181 aTable = wxAcceleratorTable([(wxACCEL_ALT, ord('X'), exitID),
182 (wxACCEL_CTRL, ord('H'), helpID)])
183 self.SetAcceleratorTable(aTable)
184
185
186 # Create a TreeCtrl
187 tID = wxNewId()
188 self.treeMap = {}
189 self.tree = wxTreeCtrl(splitter, tID,
190 style=wxTR_HAS_BUTTONS |
191 wxTR_EDIT_LABELS |
192 wxTR_HAS_VARIABLE_ROW_HEIGHT |
193 wxSUNKEN_BORDER)
194 #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
195 root = self.tree.AddRoot("Overview")
196 firstChild = None
197 for item in _treeList:
198 child = self.tree.AppendItem(root, item[0])
199 if not firstChild: firstChild = child
200 for childItem in item[1]:
201 theDemo = self.tree.AppendItem(child, childItem)
202 self.treeMap[childItem] = theDemo
203
204 self.tree.Expand(root)
205 self.tree.Expand(firstChild)
206 EVT_TREE_ITEM_EXPANDED (self.tree, tID, self.OnItemExpanded)
207 EVT_TREE_ITEM_COLLAPSED (self.tree, tID, self.OnItemCollapsed)
208 EVT_TREE_SEL_CHANGED (self.tree, tID, self.OnSelChanged)
209 EVT_LEFT_DOWN (self.tree, self.OnTreeLeftDown)
210
211 # Create a Notebook
212 self.nb = wxNotebook(splitter2, -1, style=wxCLIP_CHILDREN)
213
214 # Set up a wxHtmlWindow on the Overview Notebook page
215 # we put it in a panel first because there seems to be a
216 # refresh bug of some sort (wxGTK) when it is directly in
217 # the notebook...
218 if 0: # the old way
219 self.ovr = wxHtmlWindow(self.nb, -1, size=(400, 400))
220 self.nb.AddPage(self.ovr, "Overview")
221
222 else: # hopefully I can remove this hacky code soon, see bug #216861
223 panel = wxPanel(self.nb, -1, style=wxCLIP_CHILDREN)
224 self.ovr = wxHtmlWindow(panel, -1, size=(400, 400))
225 self.nb.AddPage(panel, "Overview")
226
227 def OnOvrSize(evt, ovr=self.ovr):
228 ovr.SetSize(evt.GetSize())
229
230 EVT_SIZE(panel, OnOvrSize)
231 EVT_ERASE_BACKGROUND(panel, EmptyHandler)
232
233
234 self.SetOverview("Overview", overview)
235
236
237 # Set up a TextCtrl on the Demo Code Notebook page
238 self.txt = wxTextCtrl(self.nb, -1,
239 style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
240 self.nb.AddPage(self.txt, "Demo Code")
241
242
243 # Set up a log on the View Log Notebook page
244 self.log = wxTextCtrl(splitter2, -1,
245 style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
246 # Set the wxWindows log target to be this textctrl
247 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
248 wxLog_SetActiveTarget(MyLog(self.log))
249
250
251
252 self.Show(true)
253
254 # add the windows to the splitter and split it.
255 splitter2.SplitHorizontally(self.nb, self.log)
256 splitter2.SetSashPosition(450, true)
257 splitter2.SetMinimumPaneSize(20)
258
259 splitter.SplitVertically(self.tree, splitter2)
260 splitter.SetSashPosition(180, true)
261 splitter.SetMinimumPaneSize(20)
262
263
264 # select initial items
265 self.nb.SetSelection(0)
266 self.tree.SelectItem(root)
267
268 if len(sys.argv) == 2:
269 try:
270 selectedDemo = self.treeMap[sys.argv[1]]
271 except:
272 selectedDemo = None
273 if selectedDemo:
274 self.tree.SelectItem(selectedDemo)
275 self.tree.EnsureVisible(selectedDemo)
276
277
278 wxLogMessage('window handle: %s' % self.GetHandle())
279
280
281 #---------------------------------------------
282 def WriteText(self, text):
283 if text[-1:] == '\n':
284 text = text[:-1]
285 wxLogMessage(text)
286
287
288 def write(self, txt):
289 self.WriteText(txt)
290
291 #---------------------------------------------
292 def OnItemExpanded(self, event):
293 item = event.GetItem()
294 wxLogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item))
295 event.Skip()
296
297 #---------------------------------------------
298 def OnItemCollapsed(self, event):
299 item = event.GetItem()
300 wxLogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
301 event.Skip()
302
303 #---------------------------------------------
304 def OnTreeLeftDown(self, event):
305 pt = event.GetPosition();
306 item, flags = self.tree.HitTest(pt)
307 if item == self.tree.GetSelection():
308 self.SetOverview(self.tree.GetItemText(item), self.curOverview)
309 event.Skip()
310
311 #---------------------------------------------
312 def OnSelChanged(self, event):
313 if self.dying:
314 return
315
316 item = event.GetItem()
317 itemText = self.tree.GetItemText(item)
318 self.RunDemo(itemText)
319
320
321 #---------------------------------------------
322 def RunDemo(self, itemText):
323 os.chdir(self.cwd)
324 if self.nb.GetPageCount() == 3:
325 if self.nb.GetSelection() == 2:
326 self.nb.SetSelection(0)
327 self.nb.DeletePage(2)
328
329 if itemText == 'Overview':
330 self.GetDemoFile('Main.py')
331 self.SetOverview('Overview', overview)
332 self.nb.Refresh();
333 self.window = None
334
335 else:
336 if os.path.exists(itemText + '.py'):
337 wxBeginBusyCursor()
338 wxLogMessage("Running demo %s.py..." % itemText)
339 try:
340 self.GetDemoFile(itemText + '.py')
341 module = __import__(itemText, globals())
342 self.SetOverview(itemText, module.overview)
343 finally:
344 wxEndBusyCursor()
345
346 # in case runTest is modal, make sure things look right...
347 self.nb.Refresh();
348 wxYield()
349
350 self.window = module.runTest(self, self.nb, self) ###
351 if self.window:
352 self.nb.AddPage(self.window, 'Demo')
353 wxYield()
354 self.nb.SetSelection(2)
355
356 else:
357 self.ovr.SetPage("")
358 self.txt.Clear()
359 self.window = None
360
361
362
363 #---------------------------------------------
364 # Get the Demo files
365 def GetDemoFile(self, filename):
366 self.txt.Clear()
367 try:
368 self.txt.SetValue(open(filename).read())
369 except IOError:
370 self.txt.WriteText("Cannot open %s file." % filename)
371
372 self.txt.SetInsertionPoint(0)
373 self.txt.ShowPosition(0)
374
375 #---------------------------------------------
376 def SetOverview(self, name, text):
377 self.curOverview = text
378 lead = text[:6]
379 if lead != '<html>' and lead != '<HTML>':
380 text = string.join(string.split(text, '\n'), '<br>')
381 #text = '<font size="-1"><pre>' + text + '</pre></font>'
382 self.ovr.SetPage(text)
383 self.nb.SetPageText(0, name)
384
385 #---------------------------------------------
386 # Menu methods
387 def OnFileExit(self, *event):
388 self.Close()
389
390
391 def OnHelpAbout(self, event):
392 from About import MyAboutBox
393 about = MyAboutBox(self)
394 about.ShowModal()
395 about.Destroy()
396
397
398 #---------------------------------------------
399 def OnCloseWindow(self, event):
400 self.dying = true
401 self.window = None
402 self.mainmenu = None
403 if hasattr(self, "tbicon"):
404 del self.tbicon
405 self.Destroy()
406
407
408 #---------------------------------------------
409 def OnIdle(self, event):
410 if self.otherWin:
411 self.otherWin.Raise()
412 self.window = self.otherWin
413 self.otherWin = None
414
415 #---------------------------------------------
416 def OnDemoMenu(self, event):
417 try:
418 selectedDemo = self.treeMap[self.mainmenu.GetLabel(event.GetId())]
419 except:
420 selectedDemo = None
421 if selectedDemo:
422 self.tree.SelectItem(selectedDemo)
423 self.tree.EnsureVisible(selectedDemo)
424
425
426 #---------------------------------------------
427 def OnTaskBarActivate(self, evt):
428 if self.IsIconized():
429 self.Iconize(false)
430 if not self.IsShown():
431 self.Show(true)
432 self.Raise()
433
434 #---------------------------------------------
435
436 TBMENU_RESTORE = 1000
437 TBMENU_CLOSE = 1001
438
439 def OnTaskBarMenu(self, evt):
440 menu = wxMenu()
441 menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
442 menu.Append(self.TBMENU_CLOSE, "Close")
443 self.tbicon.PopupMenu(menu)
444 menu.Destroy()
445
446 #---------------------------------------------
447 def OnTaskBarClose(self, evt):
448 self.Close()
449
450 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
451 # prod the main idle handler a bit to get the window to actually close
452 wxGetApp().ProcessIdle()
453
454
455 #---------------------------------------------
456 def OnIconfiy(self, evt):
457 wxLogMessage("OnIconfiy")
458 evt.Skip()
459
460 #---------------------------------------------
461 def OnMaximize(self, evt):
462 wxLogMessage("OnMaximize")
463 evt.Skip()
464
465
466
467
468 #---------------------------------------------------------------------------
469 #---------------------------------------------------------------------------
470
471 class MyApp(wxApp):
472 def OnInit(self):
473 wxInitAllImageHandlers()
474
475 self.splash = SplashScreen(None, bitmapfile='bitmaps/splash.gif',
476 duration=4000, callback=self.AfterSplash)
477 self.splash.Show(true)
478 wxYield()
479 return true
480
481
482 def AfterSplash(self):
483 self.splash.Close(true)
484 frame = wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
485 frame.Show(true)
486 self.SetTopWindow(frame)
487 self.ShowTip(frame)
488
489
490 def ShowTip(self, frame):
491 try:
492 showTipText = open("data/showTips").read()
493 showTip, index = eval(showTipText)
494 except IOError:
495 showTip, index = (1, 0)
496 #print showTip, index
497 if showTip:
498 tp = wxCreateFileTipProvider("data/tips.txt", index)
499 showTip = wxShowTip(frame, tp)
500 index = tp.GetCurrentTip()
501 open("data/showTips", "w").write(str( (showTip, index) ))
502
503
504 #---------------------------------------------------------------------------
505
506 def main():
507 try:
508 demoPath = os.path.dirname(__file__)
509 os.chdir(demoPath)
510 except:
511 pass
512 app = MyApp(0)
513 app.MainLoop()
514
515
516 #---------------------------------------------------------------------------
517
518
519
520 overview = """<html><body>
521 <h2>Python</h2>
522
523 Python is an interpreted, interactive, object-oriented programming
524 language often compared to Tcl, Perl, Scheme, or Java.
525
526 <p> Python combines remarkable power with very clear syntax. It has
527 modules, classes, exceptions, very high level dynamic data types, and
528 dynamic typing. There are interfaces to many system calls and
529 libraries, and new built-in modules are easily written in C or
530 C++. Python is also usable as an extension language for applications
531 that need a programmable interface. <p>
532
533 <h2>wxWindows</h2>
534
535 wxWindows is a free C++ framework designed to make cross-platform
536 programming child's play. Well, almost. wxWindows 2 supports Windows
537 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
538 underway. Other ports are under consideration. <p>
539
540 wxWindows is a set of libraries that allows C++ applications to
541 compile and run on several different types of computers, with minimal
542 source code changes. There is one library per supported GUI (such as
543 Motif, or Windows). As well as providing a common API (Application
544 Programming Interface) for GUI functionality, it provides
545 functionality for accessing some commonly-used operating system
546 facilities, such as copying or deleting files. wxWindows is a
547 'framework' in the sense that it provides a lot of built-in
548 functionality, which the application can use or replace as required,
549 thus saving a great deal of coding effort. Basic data structures such
550 as strings, linked lists and hash tables are also supported.
551
552 <p>
553 <h2>wxPython</h2>
554
555 wxPython is a Python extension module that encapsulates the wxWindows
556 GUI classes. Currently it is only available for the Win32 and GTK
557 ports of wxWindows, but as soon as the other ports are brought up to
558 the same level as Win32 and GTK, it should be fairly trivial to
559 enable wxPython to be used with the new GUI.
560
561 <p>
562
563 The wxPython extension module attempts to mirror the class heiarchy
564 of wxWindows as closely as possible. This means that there is a
565 wxFrame class in wxPython that looks, smells, tastes and acts almost
566 the same as the wxFrame class in the C++ version. Unfortunately,
567 because of differences in the languages, wxPython doesn't match
568 wxWindows exactly, but the differences should be easy to absorb
569 because they are natural to Python. For example, some methods that
570 return multiple values via argument pointers in C++ will return a
571 tuple of values in Python.
572
573 <p>
574
575 There is still much to be done for wxPython, many classes still need
576 to be mirrored. Also, wxWindows is still somewhat of a moving target
577 so it is a bit of an effort just keeping wxPython up to date. On the
578 other hand, there are enough of the core classes completed that
579 useful applications can be written.
580
581 <p>
582
583 wxPython is close enough to the C++ version that the majority of
584 the wxPython documentation is actually just notes attached to the C++
585 documents that describe the places where wxPython is different. There
586 is also a series of sample programs included, and a series of
587 documentation pages that assist the programmer in getting started
588 with wxPython.
589
590 """
591
592
593 #----------------------------------------------------------------------------
594 #----------------------------------------------------------------------------
595
596 if __name__ == '__main__':
597 main()
598
599 #----------------------------------------------------------------------------
600
601
602
603
604
605
606