| 1 | #---------------------------------------------------------------------------- |
| 2 | |
| 3 | # Use Python's bool constants if available, make some if not |
| 4 | try: |
| 5 | True |
| 6 | except NameError: |
| 7 | __builtins__.True = 1==1 |
| 8 | __builtins__.False = 1==0 |
| 9 | def bool(value): return not not value |
| 10 | __builtins__.bool = bool |
| 11 | |
| 12 | |
| 13 | |
| 14 | # workarounds for bad wxRTTI names |
| 15 | __wxPyPtrTypeMap['wxGauge95'] = 'wxGauge' |
| 16 | __wxPyPtrTypeMap['wxSlider95'] = 'wxSlider' |
| 17 | __wxPyPtrTypeMap['wxStatusBar95'] = 'wxStatusBar' |
| 18 | |
| 19 | |
| 20 | #---------------------------------------------------------------------------- |
| 21 | # Load version numbers from __version__... Ensure that major and minor |
| 22 | # versions are the same for both wxPython and wxWidgets. |
| 23 | |
| 24 | from __version__ import * |
| 25 | __version__ = VERSION_STRING |
| 26 | |
| 27 | assert MAJOR_VERSION == _core_.MAJOR_VERSION, "wxPython/wxWidgets version mismatch" |
| 28 | assert MINOR_VERSION == _core_.MINOR_VERSION, "wxPython/wxWidgets version mismatch" |
| 29 | if RELEASE_VERSION != _core_.RELEASE_VERSION: |
| 30 | import warnings |
| 31 | warnings.warn("wxPython/wxWidgets release number mismatch") |
| 32 | |
| 33 | |
| 34 | def version(): |
| 35 | """Returns a string containing version and port info""" |
| 36 | ctype = wx.USE_UNICODE and 'unicode' or 'ansi' |
| 37 | if wx.Platform == '__WXMSW__': |
| 38 | port = 'msw' |
| 39 | elif wx.Platform == '__WXMAC__': |
| 40 | port = 'mac' |
| 41 | elif wx.Platform == '__WXGTK__': |
| 42 | port = 'gtk' |
| 43 | if 'gtk2' in wx.PlatformInfo: |
| 44 | port = 'gtk2' |
| 45 | else: |
| 46 | port = '?' |
| 47 | |
| 48 | return "%s (%s-%s)" % (wx.VERSION_STRING, port, ctype) |
| 49 | |
| 50 | |
| 51 | #---------------------------------------------------------------------------- |
| 52 | |
| 53 | # Set wxPython's default string<-->unicode conversion encoding from |
| 54 | # the locale, but only if Python's default hasn't been changed. (We |
| 55 | # assume that if the user has customized it already then that is the |
| 56 | # encoding we need to use as well.) |
| 57 | # |
| 58 | # The encoding selected here is used when string or unicode objects |
| 59 | # need to be converted in order to pass them to wxWidgets. Please be |
| 60 | # aware that the default encoding within the same locale may be |
| 61 | # slightly different on different platforms. For example, please see |
| 62 | # http://www.alanwood.net/demos/charsetdiffs.html for differences |
| 63 | # between the common latin/roman encodings. |
| 64 | |
| 65 | default = _sys.getdefaultencoding() |
| 66 | if default == 'ascii': |
| 67 | import locale |
| 68 | import codecs |
| 69 | try: |
| 70 | default = locale.getdefaultlocale()[1] |
| 71 | codecs.lookup(default) |
| 72 | except (ValueError, LookupError, TypeError): |
| 73 | default = _sys.getdefaultencoding() |
| 74 | del locale |
| 75 | del codecs |
| 76 | if default: |
| 77 | wx.SetDefaultPyEncoding(default) |
| 78 | del default |
| 79 | |
| 80 | #---------------------------------------------------------------------------- |
| 81 | |
| 82 | class PyDeadObjectError(AttributeError): |
| 83 | pass |
| 84 | |
| 85 | class _wxPyDeadObject(object): |
| 86 | """ |
| 87 | Instances of wx objects that are OOR capable will have their __class__ |
| 88 | changed to this class when the C++ object is deleted. This should help |
| 89 | prevent crashes due to referencing a bogus C++ pointer. |
| 90 | """ |
| 91 | reprStr = "wxPython wrapper for DELETED %s object! (The C++ object no longer exists.)" |
| 92 | attrStr = "The C++ part of the %s object has been deleted, attribute access no longer allowed." |
| 93 | |
| 94 | def __repr__(self): |
| 95 | if not hasattr(self, "_name"): |
| 96 | self._name = "[unknown]" |
| 97 | return self.reprStr % self._name |
| 98 | |
| 99 | def __getattr__(self, *args): |
| 100 | if not hasattr(self, "_name"): |
| 101 | self._name = "[unknown]" |
| 102 | raise PyDeadObjectError(self.attrStr % self._name) |
| 103 | |
| 104 | def __nonzero__(self): |
| 105 | return 0 |
| 106 | |
| 107 | |
| 108 | |
| 109 | class PyUnbornObjectError(AttributeError): |
| 110 | pass |
| 111 | |
| 112 | class _wxPyUnbornObject(object): |
| 113 | """ |
| 114 | Some stock objects are created when the wx._core module is |
| 115 | imported, but their C++ instance is not created until the wx.App |
| 116 | object is created and initialized. These object instances will |
| 117 | temporarily have their __class__ changed to this class so an |
| 118 | exception will be raised if they are used before the C++ instance |
| 119 | is ready. |
| 120 | """ |
| 121 | |
| 122 | reprStr = "wxPython wrapper for UNBORN object! (The C++ object is not initialized yet.)" |
| 123 | attrStr = "The C++ part of this object has not been initialized, attribute access not allowed." |
| 124 | |
| 125 | def __repr__(self): |
| 126 | #if not hasattr(self, "_name"): |
| 127 | # self._name = "[unknown]" |
| 128 | return self.reprStr #% self._name |
| 129 | |
| 130 | def __getattr__(self, *args): |
| 131 | #if not hasattr(self, "_name"): |
| 132 | # self._name = "[unknown]" |
| 133 | raise PyUnbornObjectError(self.attrStr) # % self._name ) |
| 134 | |
| 135 | def __nonzero__(self): |
| 136 | return 0 |
| 137 | |
| 138 | |
| 139 | #---------------------------------------------------------------------------- |
| 140 | |
| 141 | def CallAfter(callable, *args, **kw): |
| 142 | """ |
| 143 | Call the specified function after the current and pending event |
| 144 | handlers have been completed. This is also good for making GUI |
| 145 | method calls from non-GUI threads. Any extra positional or |
| 146 | keyword args are passed on to the callable when it is called. |
| 147 | |
| 148 | :see: `wx.CallLater` |
| 149 | """ |
| 150 | app = wx.GetApp() |
| 151 | assert app is not None, 'No wx.App created yet' |
| 152 | |
| 153 | if not hasattr(app, "_CallAfterId"): |
| 154 | app._CallAfterId = wx.NewEventType() |
| 155 | app.Connect(-1, -1, app._CallAfterId, |
| 156 | lambda event: event.callable(*event.args, **event.kw) ) |
| 157 | evt = wx.PyEvent() |
| 158 | evt.SetEventType(app._CallAfterId) |
| 159 | evt.callable = callable |
| 160 | evt.args = args |
| 161 | evt.kw = kw |
| 162 | wx.PostEvent(app, evt) |
| 163 | |
| 164 | #---------------------------------------------------------------------------- |
| 165 | |
| 166 | |
| 167 | class CallLater: |
| 168 | """ |
| 169 | A convenience class for `wx.Timer`, that calls the given callable |
| 170 | object once after the given amount of milliseconds, passing any |
| 171 | positional or keyword args. The return value of the callable is |
| 172 | availbale after it has been run with the `GetResult` method. |
| 173 | |
| 174 | If you don't need to get the return value or restart the timer |
| 175 | then there is no need to hold a reference to this object. It will |
| 176 | hold a reference to itself while the timer is running (the timer |
| 177 | has a reference to self.Notify) but the cycle will be broken when |
| 178 | the timer completes, automatically cleaning up the wx.CallLater |
| 179 | object. |
| 180 | |
| 181 | :see: `wx.CallAfter` |
| 182 | """ |
| 183 | def __init__(self, millis, callable, *args, **kwargs): |
| 184 | self.millis = millis |
| 185 | self.callable = callable |
| 186 | self.SetArgs(*args, **kwargs) |
| 187 | self.runCount = 0 |
| 188 | self.running = False |
| 189 | self.hasRun = False |
| 190 | self.result = None |
| 191 | self.timer = None |
| 192 | self.Start() |
| 193 | |
| 194 | def __del__(self): |
| 195 | self.Stop() |
| 196 | |
| 197 | |
| 198 | def Start(self, millis=None, *args, **kwargs): |
| 199 | """ |
| 200 | (Re)start the timer |
| 201 | """ |
| 202 | self.hasRun = False |
| 203 | if millis is not None: |
| 204 | self.millis = millis |
| 205 | if args or kwargs: |
| 206 | self.SetArgs(*args, **kwargs) |
| 207 | self.Stop() |
| 208 | self.timer = wx.PyTimer(self.Notify) |
| 209 | self.timer.Start(self.millis, wx.TIMER_ONE_SHOT) |
| 210 | self.running = True |
| 211 | Restart = Start |
| 212 | |
| 213 | |
| 214 | def Stop(self): |
| 215 | """ |
| 216 | Stop and destroy the timer. |
| 217 | """ |
| 218 | if self.timer is not None: |
| 219 | self.timer.Stop() |
| 220 | self.timer = None |
| 221 | |
| 222 | |
| 223 | def GetInterval(self): |
| 224 | if self.timer is not None: |
| 225 | return self.timer.GetInterval() |
| 226 | else: |
| 227 | return 0 |
| 228 | |
| 229 | |
| 230 | def IsRunning(self): |
| 231 | return self.timer is not None and self.timer.IsRunning() |
| 232 | |
| 233 | |
| 234 | def SetArgs(self, *args, **kwargs): |
| 235 | """ |
| 236 | (Re)set the args passed to the callable object. This is |
| 237 | useful in conjunction with Restart if you want to schedule a |
| 238 | new call to the same callable object but with different |
| 239 | parameters. |
| 240 | """ |
| 241 | self.args = args |
| 242 | self.kwargs = kwargs |
| 243 | |
| 244 | |
| 245 | def HasRun(self): |
| 246 | return self.hasRun |
| 247 | |
| 248 | def GetResult(self): |
| 249 | return self.result |
| 250 | |
| 251 | def Notify(self): |
| 252 | """ |
| 253 | The timer has expired so call the callable. |
| 254 | """ |
| 255 | if self.callable and getattr(self.callable, 'im_self', True): |
| 256 | self.runCount += 1 |
| 257 | self.running = False |
| 258 | self.result = self.callable(*self.args, **self.kwargs) |
| 259 | self.hasRun = True |
| 260 | if not self.running: |
| 261 | # if it wasn't restarted, then cleanup |
| 262 | wx.CallAfter(self.Stop) |
| 263 | |
| 264 | Interval = property(GetInterval) |
| 265 | Result = property(GetResult) |
| 266 | |
| 267 | |
| 268 | class FutureCall(CallLater): |
| 269 | """A compatibility alias for `CallLater`.""" |
| 270 | |
| 271 | #---------------------------------------------------------------------------- |
| 272 | # Control which items in this module should be documented by epydoc. |
| 273 | # We allow only classes and functions, which will help reduce the size |
| 274 | # of the docs by filtering out the zillions of constants, EVT objects, |
| 275 | # and etc that don't make much sense by themselves, but are instead |
| 276 | # documented (or will be) as part of the classes/functions/methods |
| 277 | # where they should be used. |
| 278 | |
| 279 | class __DocFilter: |
| 280 | """ |
| 281 | A filter for epydoc that only allows non-Ptr classes and |
| 282 | functions, in order to reduce the clutter in the API docs. |
| 283 | """ |
| 284 | def __init__(self, globals): |
| 285 | self._globals = globals |
| 286 | |
| 287 | def __call__(self, name): |
| 288 | import types |
| 289 | obj = self._globals.get(name, None) |
| 290 | |
| 291 | # only document classes and function |
| 292 | if type(obj) not in [type, types.ClassType, types.FunctionType, types.BuiltinFunctionType]: |
| 293 | return False |
| 294 | |
| 295 | # skip other things that are private or will be documented as part of somethign else |
| 296 | if name.startswith('_') or name.startswith('EVT') or name.endswith('_swigregister') or name.endswith('Ptr') : |
| 297 | return False |
| 298 | |
| 299 | # skip functions that are duplicates of static functions in a class |
| 300 | if name.find('_') != -1: |
| 301 | cls = self._globals.get(name.split('_')[0], None) |
| 302 | methname = name.split('_')[1] |
| 303 | if hasattr(cls, methname) and type(getattr(cls, methname)) is types.FunctionType: |
| 304 | return False |
| 305 | |
| 306 | return True |
| 307 | |
| 308 | #---------------------------------------------------------------------------- |
| 309 | #---------------------------------------------------------------------------- |
| 310 | |
| 311 | # Import other modules in this package that should show up in the |
| 312 | # "core" wx namespace |
| 313 | from _gdi import * |
| 314 | from _windows import * |
| 315 | from _controls import * |
| 316 | from _misc import * |
| 317 | |
| 318 | #---------------------------------------------------------------------------- |
| 319 | #---------------------------------------------------------------------------- |