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