Changeset 3208
- Timestamp:
- 06/23/2007 06:32:54 AM (2 years ago)
- Files:
-
- trunk/dabo/ui/uiwx/__init__.py (modified) (64 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/dabo/ui/uiwx/__init__.py
r3199 r3208 14 14 _failedLibs = [] 15 15 # note: may need wx.animate as well 16 for lib in ("wx", "wx.stc", "wx.lib.foldpanelbar", "wx.gizmos", 16 for lib in ("wx", "wx.stc", "wx.lib.foldpanelbar", "wx.gizmos", 17 17 "wx.lib.calendar", "wx.lib.masked", "wx.lib.buttons"): 18 18 try: … … 28 28 %s 29 29 """ % "\n\t".join(_failedLibs) 30 30 31 31 sys.exit(msg) 32 32 del(_failedLibs) … … 52 52 53 53 # Import dPemMixin first, and then manually put into dabo.ui module. This is 54 # because dControlMixinBase, which is in dabo.ui, descends from dPemMixin, which 54 # because dControlMixinBase, which is in dabo.ui, descends from dPemMixin, which 55 55 # is in dabo.ui.uiwx. Must also do the same with dControlMixin, as dDataControlMixinBase 56 56 # descends from it. … … 189 189 wx.CallAfter(callback) 190 190 return ret 191 191 192 192 193 193 def callAfter(fnc, *args, **kwargs): 194 194 """There are times when this functionality is needed when creating UI 195 code. This function simply wraps the wx.CallAfter function so that 195 code. This function simply wraps the wx.CallAfter function so that 196 196 developers do not need to use wx code in their apps. 197 197 """ 198 198 wx.CallAfter(fnc, *args, **kwargs) 199 199 200 200 201 201 _callAfterIntervalReferences = {} … … 228 228 dabo.errorLog.write(_("setAfter() failed to set property '%s' to value '%s': %s.") 229 229 % (prop, val, e)) 230 230 231 231 232 232 def setAfterInterval(interval, obj, prop, val): 233 """Like callAfterInterval(), but allows you to set a property instead 233 """Like callAfterInterval(), but allows you to set a property instead 234 234 of calling a function. 235 235 """ … … 243 243 244 244 def callEvery(interval, func, *args, **kwargs): 245 """Creates and returns a timer object that fires the specified function 245 """Creates and returns a timer object that fires the specified function 246 246 at the specified interval. Interval is given in milliseconds. It will pass along 247 247 any additional arguments to the function when it is called. … … 257 257 def yieldUI(*args, **kwargs): 258 258 """Yield to other apps/messages.""" 259 wx.Yield(*args, **kwargs) 259 wx.Yield(*args, **kwargs) 260 260 261 261 262 262 def beep(): 263 263 wx.Bell() 264 264 265 265 266 266 def busyInfo(msg="Please wait...", *args, **kwargs): 267 267 """Display a message that the system is busy. 268 268 269 Assign the return value to a local object, and the message will stay until the 269 Assign the return value to a local object, and the message will stay until the 270 270 object is explicitly unbound. For example: 271 271 … … 290 290 dabo.errorLog.write("Incorrect event class (%s) passed to continueEvent. Error: %s" 291 291 % (str(evt), str(e))) 292 293 292 293 294 294 def discontinueEvent(evt): 295 295 try: … … 302 302 dabo.errorLog.write("Incorrect event class (%s) passed to continueEvent. Error: %s" 303 303 % (str(evt), str(e))) 304 305 304 305 306 306 def getEventData(wxEvt): 307 307 ed = {} 308 308 eventType = wxEvt.GetEventType() 309 309 310 310 if isinstance(wxEvt, (wx.KeyEvent, wx.MouseEvent, wx.TreeEvent, 311 311 wx.CommandEvent, wx.CloseEvent, wx.grid.GridEvent, 312 312 wx.grid.GridSizeEvent, wx.SplitterEvent) ): 313 313 314 314 if dabo.allNativeEventInfo: 315 315 # Cycle through all the attributes of the wx events, and evaluate them … … 319 319 upPems = [p for p in d if p[0].isupper()] 320 320 for pem in upPems: 321 if pem in ("Skip", "Clone", "Destroy", "Button", "ButtonIsDown", 322 "GetLogicalPosition", "ResumePropagation", "SetEventObject", 323 "SetEventType", "SetId", "SetExtraLong", "SetInt", "SetString", 321 if pem in ("Skip", "Clone", "Destroy", "Button", "ButtonIsDown", 322 "GetLogicalPosition", "ResumePropagation", "SetEventObject", 323 "SetEventType", "SetId", "SetExtraLong", "SetInt", "SetString", 324 324 "SetTimestamp", "StopPropagation"): 325 325 continue … … 331 331 except: 332 332 pass 333 333 334 334 if isinstance(wxEvt, (wx.SplitterEvent,) ): 335 335 try: … … 362 362 else: 363 363 ed["prompt"] = menu.Caption 364 364 365 365 366 366 if isinstance(wxEvt, wx.CommandEvent): … … 388 388 if wx.Platform in ("__WXMAC__", "__WXGTK__"): 389 389 ed["keyChar"] = chr(wxEvt.GetKeyCode()) 390 else: 390 else: 391 391 ed["keyChar"] = chr(wxEvt.GetRawKeyCode()) 392 392 except (ValueError, OverflowError): … … 394 394 if not ed["keyChar"]: 395 395 # See if it is one of the keypad keys 396 numpadKeys = { wx.WXK_NUMPAD0: "0", wx.WXK_NUMPAD1: "1", 397 wx.WXK_NUMPAD2: "2", wx.WXK_NUMPAD3: "3", wx.WXK_NUMPAD4: "4", 398 wx.WXK_NUMPAD5: "5", wx.WXK_NUMPAD6: "6", wx.WXK_NUMPAD7: "7", 396 numpadKeys = { wx.WXK_NUMPAD0: "0", wx.WXK_NUMPAD1: "1", 397 wx.WXK_NUMPAD2: "2", wx.WXK_NUMPAD3: "3", wx.WXK_NUMPAD4: "4", 398 wx.WXK_NUMPAD5: "5", wx.WXK_NUMPAD6: "6", wx.WXK_NUMPAD7: "7", 399 399 wx.WXK_NUMPAD8: "8", wx.WXK_NUMPAD9: "9", wx.WXK_NUMPAD_SPACE: " ", 400 wx.WXK_NUMPAD_TAB: "\t", wx.WXK_NUMPAD_ENTER: "\r", 401 wx.WXK_NUMPAD_EQUAL: "=", wx.WXK_NUMPAD_MULTIPLY: "*", 402 wx.WXK_NUMPAD_ADD: "+", wx.WXK_NUMPAD_SUBTRACT: "-", 400 wx.WXK_NUMPAD_TAB: "\t", wx.WXK_NUMPAD_ENTER: "\r", 401 wx.WXK_NUMPAD_EQUAL: "=", wx.WXK_NUMPAD_MULTIPLY: "*", 402 wx.WXK_NUMPAD_ADD: "+", wx.WXK_NUMPAD_SUBTRACT: "-", 403 403 wx.WXK_NUMPAD_DECIMAL: ".", wx.WXK_NUMPAD_DIVIDE: "/"} 404 404 ed["keyChar"] = numpadKeys.get(ed["keyCode"], None) 405 405 406 406 if isinstance(wxEvt, wx.ContextMenuEvent): 407 407 ed["mousePosition"] = wxEvt.GetPosition() … … 409 409 if isinstance(wxEvt, wx.CloseEvent): 410 410 ed["force"] = not wxEvt.CanVeto() 411 411 412 412 if isinstance(wxEvt, wx.TreeEvent): 413 413 tree = wxEvt.GetEventObject() … … 425 425 except: 426 426 pass 427 427 428 428 if isinstance(wxEvt, wx.SplitterEvent): 429 429 try: … … 436 436 except: 437 437 ed["windowRemoved"] = None 438 438 439 439 if hasattr(wxEvt, "GetId"): 440 440 ed["id"] = wxEvt.GetId() … … 446 446 ed["index"] = wxEvt.GetSelection() 447 447 448 448 449 449 if isinstance(wxEvt, wx.grid.GridEvent): 450 450 ed["row"] = wxEvt.GetRow() … … 459 459 ed["commandDown"] = wxEvt.CmdDown() 460 460 except: pass 461 461 462 462 if isinstance(wxEvt, wx.grid.GridSizeEvent): 463 463 #ed["rowOrCol"] = wxEvt.GetRowOrCol() … … 475 475 ed["commandDown"] = wxEvt.CmdDown() 476 476 except: pass 477 477 478 478 if isinstance(wxEvt, wx.calendar.CalendarEvent): 479 479 ed["date"] = wxEvt.PyGetDate() … … 486 486 ed["collapsed"] = not ed["expanded"] 487 487 ed["panel"] = wxEvt.GetEventObject().GetParent() 488 488 489 489 try: 490 490 if isinstance(wxEvt, wx.html.HtmlLinkEvent): … … 493 493 # wxPython 2.6 and earlier doesn't seem to have this event 494 494 pass 495 495 496 496 return ed 497 497 498 498 499 499 def getMousePosition(): … … 508 508 actwin = dabo.dAppRef.ActiveForm 509 509 return actwin.relativeCoordinates(wx.GetMousePosition()) 510 510 511 511 512 512 def getMouseObject(): 513 513 """Returns a reference to the object below the mouse pointer 514 at the moment the command is issued. Useful for interactive 515 development when testing changes to classes 'in the wild' of a 514 at the moment the command is issued. Useful for interactive 515 development when testing changes to classes 'in the wild' of a 516 516 live application. 517 517 """ … … 522 522 if isinstance(actwin, dabo.ui.dShell.dShell): 523 523 actwin.lockDisplay() 524 actwin.sendToBack() 524 actwin.sendToBack() 525 525 else: 526 526 actwin = None … … 565 565 566 566 567 #### This will have to wait until I can figure out how to simulate a 567 #### This will have to wait until I can figure out how to simulate a 568 568 #### modal form for the calendar. 569 569 # def popupCalendar(dt=None, x=None, y=None, pos="topleft"): 570 570 # """Pops up a calendar control at the specified x,y location, relative 571 # to the position. Positions can be one of 'topleft', 'topright', 572 # 'bottomleft', 'bottomright'. If no date is specified, defaults to 571 # to the position. Positions can be one of 'topleft', 'topright', 572 # 'bottomleft', 'bottomright'. If no date is specified, defaults to 573 573 # today. Returns the selected date, or None if the user presses Esc. 574 574 # """ … … 577 577 # dCalendar(self, RegID="cal", Position=(0,0)) 578 578 # self.Size = self.cal.Size 579 # 579 # 580 580 # def onHit_cal(self, evt): 581 581 # self.Visible = False 582 # 582 # 583 583 # pos = pos.lower().strip() 584 584 # if dt is None: … … 588 588 # else: 589 589 # x, y = wx.ClientToScreen(x, y) 590 # 590 # 591 591 # calForm = popCal(None) 592 592 # calForm.cal.Date = dt … … 605 605 # return ret 606 606 607 607 608 608 def _getActiveForm(): 609 609 app = dabo.dAppRef … … 613 613 614 614 615 def getString(message=_("Please enter a string:"), caption="Dabo", 615 def getString(message=_("Please enter a string:"), caption="Dabo", 616 616 defaultValue="", **kwargs): 617 617 """Simple dialog for returning a small bit of text from the user. … … 622 622 # Give the textbox a default value: 623 623 txt = dabo.ui.getString(defaultValue="initial string value") 624 624 625 625 # Password Entry (*'s instead of the actual text) 626 626 txt = dabo.ui.getString(PasswordEntry=True) … … 637 637 self.Sizer.append(hs, "expand") 638 638 dabo.ui.callAfter(self.strVal.setFocus) 639 639 640 640 if defaultValue: 641 641 kwargs["Value"] = defaultValue … … 650 650 651 651 652 def getInt(message=_("Enter an integer value:"), caption="Dabo", 652 def getInt(message=_("Enter an integer value:"), caption="Dabo", 653 653 defaultValue=0, **kwargs): 654 654 """Simple dialog for returning an integer value from the user.""" … … 664 664 self.Sizer.append(hs) 665 665 dabo.ui.callAfter(self.spnVal.setFocus) 666 666 667 667 if defaultValue: 668 668 kwargs["Value"] = defaultValue … … 675 675 dlg.Destroy() 676 676 return val 677 677 678 678 679 679 # The next two methods prompt the user to select from a list. The first allows … … 706 706 self.Caption = caption 707 707 lbl = dabo.ui.dLabel(self, Caption=message) 708 self.lst = dabo.ui.dListBox(self, Choices=choices, 709 PositionValue=defaultPos, MultipleSelect=mult, 708 self.lst = dabo.ui.dListBox(self, Choices=choices, 709 PositionValue=defaultPos, MultipleSelect=mult, 710 710 OnMouseLeftDoubleClick=self.onOK) 711 711 sz = self.Sizer … … 733 733 borderSides=("left", "right")) 734 734 sz.appendSpacer(24) 735 735 736 736 def selectAll(self, evt): 737 737 self.lst.selectAll() 738 738 739 739 def unselectAll(self, evt): 740 740 self.lst.unselectAll() 741 741 742 742 def invertSelection(self, evt): 743 743 self.lst.invertSelections() 744 744 745 745 dlg = ChoiceDialog(_getActiveForm()) 746 746 dlg.show() … … 750 750 val = None 751 751 dlg.release() 752 return val 752 return val 753 753 754 754 … … 775 775 776 776 def getDate(dt=None): 777 """Displays a calendar dialog for the user to select a date. 777 """Displays a calendar dialog for the user to select a date. 778 778 Defaults to the given date parameter, or today if no value 779 779 is passed. … … 793 793 month = result[2] 794 794 year = int(result[3]) 795 monthNames = ["January", "February", "March", "April", "May", "June", 795 monthNames = ["January", "February", "March", "April", "May", "June", 796 796 "July", "August", "September", "October", "November", "December"] 797 797 ret = datetime.date(year, monthNames.index(month)+1, day) … … 832 832 list = fEnum.GetFacenames() 833 833 list.sort() 834 return list 834 return list 835 835 836 836 … … 852 852 """Display the file selection dialog for the platform, and return selection(s). 853 853 854 Send an optional multiple=True for the user to pick more than one file. In 854 Send an optional multiple=True for the user to pick more than one file. In 855 855 that case, the return value will be a sequence of unicode strings. 856 856 857 Returns the path to the selected file or files, or None if no selection was 857 Returns the path to the selected file or files, or None if no selection was 858 858 made. Only file may be selected if multiple is False. 859 859 … … 865 865 wc = _getWild(*args) 866 866 return _getPath(dFileDialog, wildcard=wc, **kwargs)[0] 867 867 868 868 869 869 def getFileAndType(*args, **kwargs): … … 879 879 ret = (pth, args[idx]) 880 880 return ret 881 881 882 882 883 883 def getSaveAs(*args, **kwargs): … … 911 911 was made. 912 912 """ 913 return _getPath(dFolderDialog, message=message, defaultPath=defaultPath, 913 return _getPath(dFolderDialog, message=message, defaultPath=defaultPath, 914 914 wildcard=wildcard)[0] 915 915 … … 929 929 arglist = [] 930 930 tmplt = "%s Files (*.%s)|*.%s" 931 fileDict = {"html" : "HTML", 931 fileDict = {"html" : "HTML", 932 932 "xml" : "XML", 933 933 "txt" : "Text", … … 935 935 "gif" : "GIF", 936 936 "png" : "PNG", 937 "ico" : "Icon", 937 "ico" : "Icon", 938 938 "bmp" : "Bitmap" } 939 939 940 940 for a in args: 941 941 descrp = ext = "" … … 1013 1013 1014 1014 def createMenuBar(srcFile, form=None, previewFunc=None): 1015 """Pass in an .mnxml file saved from the Menu Designer, 1016 and this will instantiate a MenuBar from that spec. Returns 1015 """Pass in an .mnxml file saved from the Menu Designer, 1016 and this will instantiate a MenuBar from that spec. Returns 1017 1017 a reference to the newly-created MenuBar. You can optionally 1018 1018 pass in a reference to the form to which this menu is 1019 associated, so that you can enter strings that represent 1020 form functions in the Designer, such as 'form.close', which 1019 associated, so that you can enter strings that represent 1020 form functions in the Designer, such as 'form.close', which 1021 1021 will call the associated form's close() method. If 'previewFunc' 1022 is passed, the menu command that would have been eval'd 1022 is passed, the menu command that would have been eval'd 1023 1023 and executed on a live menu will instead be passed back as 1024 1024 a parameter to that function. … … 1039 1039 return 1040 1040 app = dabo.dAppRef 1041 for itm in items: 1041 for itm in items: 1042 1042 if "Separator" in itm["name"]: 1043 1043 menu.appendSeparator() … … 1059 1059 help = itmatts["HelpText"] 1060 1060 menuItem = menu.append(cap, OnHit=binding, help=help, 1061 picture=pic) 1062 1061 picture=pic) 1062 1063 1063 mnd = dabo.lib.xmltodict.xmltodict(srcFile) 1064 1064 mb = dabo.ui.dMenuBar() … … 1066 1066 addMenu(mb, mn, form, previewFunc) 1067 1067 return mb 1068 1069 1070 def browse(dataSource, parent=None): 1068 1069 1070 def browse(dataSource, parent=None, keyCaption=None, includeFields=None, 1071 colOrder=None, colWidths=None, colTypes=None, autoSizeCols=True): 1071 1072 """Given a data source, a form with a grid containing the data 1072 is created and displayed. If the source is a Dabo cursor object, 1073 is created and displayed. If the source is a Dabo cursor object, 1073 1074 its getDataSet() method will be called to extract the data. 1074 1075 1075 1076 If parent is passed, the form isn't created, and the browsegrid 1076 1077 becomes a child of parent instead. 1078 1079 The columns will be taken from the first record of the dataset, with each 1080 column header caption being set to the field name, unless the optional 1081 keyCaption parameter is passed. This parameter is a 1:1 dict containing 1082 the data set keys as its keys, and the desired caption as the 1083 corresponding value. 1084 1085 If the includeFields parameter is a sequence, the only columns added will 1086 be the fieldnames included in the includeFields sequence. If the 1087 includeFields parameter is None, all fields will be added to the grid. 1088 1089 The columns will be in the order returned by ds.keys(), unless the 1090 optional colOrder parameter is passed. Like the keyCaption property, 1091 this is a 1:1 dict containing key:order. 1077 1092 """ 1078 1093 if not isinstance(dataSource, (list, tuple)): … … 1096 1111 1097 1112 grd = dGrid(parent, AlternateRowColoring=True) 1098 grd.buildFromDataSet(dataSet) 1113 grd.buildFromDataSet(dataSet, keyCaption=keyCaption, 1114 includeFields=includeFields, colOrder=colOrder, colWidths=colWidths, 1115 colTypes=colTypes, autoSizeCols=autoSizeCols) 1099 1116 1100 1117 parent.Sizer.append(grd, 1, "x") … … 1123 1140 return fontMetric(txt=obj.Text, face=obj.FontFace, size=obj.FontSize, 1124 1141 bold=obj.FontBold, italic=obj.FontItalic) 1125 1142 1126 1143 1127 1144 def fontMetric(txt=None, wind=None, face=None, size=None, bold=None, 1128 1145 italic=None): 1129 1146 """Calculate the width and height of the given text using the supplied 1130 font information. If any font parameters are missing, they are taken 1147 font information. If any font parameters are missing, they are taken 1131 1148 from the specified window, or, if no window is specified, the currently 1132 1149 active form. If no form is active, the app's MainForm is used. … … 1173 1190 """Takes a screenshot of the specified and writes it to a file, converting 1174 1191 it to the requested image type. If no object is specified, the current 1175 ActiveForm is used. You can add an optional delaySeconds setting that 1192 ActiveForm is used. You can add an optional delaySeconds setting that 1176 1193 will let you set things up as needed before the image is taken; if not specified, 1177 1194 the image is taken immediately. … … 1189 1206 # Nothing active! 1190 1207 stop(_("There is no active form to capture."), _("No Active Form")) 1191 return 1208 return 1192 1209 bmp = obj.getCaptureBitmap() 1193 1210 knownTypes = ("png", "jpg", "bmp", "pcx") … … 1199 1216 else: 1200 1217 imgType = (imgType, ) 1201 wxTypeDict = {"png": wx.BITMAP_TYPE_PNG, 1202 "jpg": wx.BITMAP_TYPE_JPEG, 1218 wxTypeDict = {"png": wx.BITMAP_TYPE_PNG, 1219 "jpg": wx.BITMAP_TYPE_JPEG, 1203 1220 "bmp": wx.BITMAP_TYPE_BMP, 1204 1221 "pcx": wx.BITMAP_TYPE_PCX} … … 1218 1235 img = wx.ImageFromBitmap(bmp) 1219 1236 img.SaveFile(pth, wxTypeDict[typ]) 1220 1221 1222 1223 1237 1238 1239 1240 1224 1241 1225 1242 … … 1231 1248 def bitmapFromData(data): 1232 1249 return BitmapFromImage(imageFromData(data)) 1233 1234 1250 1251 1235 1252 def imageFromData(data): 1236 1253 stream = cStringIO.StringIO(data) … … 1241 1258 # For applications that use the same image more than once, 1242 1259 # this speeds up resolution of the requested image name. 1243 _bmpCache = {} 1260 _bmpCache = {} 1244 1261 def strToBmp(val, scale=None, width=None, height=None): 1245 1262 """This can be either a path, or the name of a built-in graphic. 1246 1263 If an adjusted size is desired, you can either pass a 'scale' value 1247 (where 1.00 is full size, 0.5 scales it to 50% in both Height and 1248 Width), or you can pass specific 'height' and 'width' values. The 1249 final image will be a bitmap resized to those specs. 1264 (where 1.00 is full size, 0.5 scales it to 50% in both Height and 1265 Width), or you can pass specific 'height' and 'width' values. The 1266 final image will be a bitmap resized to those specs. 1250 1267 """ 1251 1268 ret = None … … 1256 1273 else: 1257 1274 # Include all the pathing possibilities 1258 iconpaths = [os.path.join(pth, val) 1275 iconpaths = [os.path.join(pth, val) 1259 1276 for pth in dabo.icons.__path__] 1260 dabopaths = [os.path.join(pth, val) 1277 dabopaths = [os.path.join(pth, val) 1261 1278 for pth in dabo.__path__] 1262 1279 localpaths = [os.path.join(os.getcwd(), pth, val) … … 1278 1295 else: 1279 1296 _bmpCache[val] = ret 1280 1297 1281 1298 if ret is not None: 1282 1299 if scale is None and width is None and height is None: … … 1305 1322 newWd = oldWd * (newHt / oldHt) 1306 1323 img.Rescale(newWd, newHt) 1307 ret = img.ConvertToBitmap() 1324 ret = img.ConvertToBitmap() 1308 1325 return ret 1309 1310 1326 1327 1311 1328 def pathToBmp(pth): 1312 1329 img = wx.NullImage … … 1319 1336 img.Rescale(wd, ht) 1320 1337 return img.ConvertToBitmap() 1321 1322 1338 1339 1323 1340 def getCommonBitmap(name): 1324 """wxPython comes with several built-in bitmaps for common icons. 1341 """wxPython comes with several built-in bitmaps for common icons. 1325 1342 This wraps the procedure for generating these bitmaps. If a name is 1326 1343 passed for which there is no icon, an image denoting a missing image … … 1336 1353 1337 1354 def getImagePath(nm, url=False): 1338 """Given the name of an image in either the Dabo common directory, or the 1355 """Given the name of an image in either the Dabo common directory, or the 1339 1356 current directory, returns the full path to the image. If 'url' is true, returns 1340 1357 the path in a 'file:///image.ext' format. … … 1368 1385 ret = "file://%s" % ret 1369 1386 return ret 1370 1387 1371 1388 1372 1389
