[x] Refactors the initialization so implementing classes become simpler.
[x] Use double-underscore where we can.
[x] Prefix all methods that subclasses must implement with _rc_.
[x] In the backends, put methods in a consistent order.
[x] Test for glfw
[x] Test for qt
[x] Test for offscreen
[x] Test for wx
[x] Test for jupyter
Decisions
Some notes on decisions I came to. I feel like the text below makes little sense for anyone else, since its all a bit hard to explain and the problems are rather subtle. Nevertheless, I think its good to have this on record.
Init order
The initialization order is tricky. Taking qt as an example, the mro is:
QObject
...
QWidget
BaseRenderCanvas
QRenderWidget
All is good, except for one thing: I want BaseRenderCanvas to set the size and title (and maybe more in the future), because I don't want every subclass to have to bother with that. However, that must happen after the QRenderWidget did its initialization. I played with some ideas, and implemented one where the the backend class (QRenderWidget) must implement _rc_init instead of __init__. But this is too weird. Thought of metaclasses, but that's too dark. Using __new__ is also no help.
So I ended up with classic instantiation mechanics, and requiring backend canvas classes to call _final_canvas_init() to allow BaseRenderCanvas to apply the final configuration (setting size, title, transparency etc.) A little anoying, but its explicit. And if the class author forgets to call it, you simply don't get the custom title and size set.
Subwidget kwargs
Another tricky one, specific to the wrapper classes in qt and wx, was how to pass the right kwargs to the real canvas (._subwidget). I previously had tricks like a function that popped canvas kwargs form the kwargs dict. In the end the solution is quite simple: any kwargs that the toplevel widget wants, must be explicitly taken, the rest is passed to the subwidget:
Tasks
_rc_
.Decisions
Some notes on decisions I came to. I feel like the text below makes little sense for anyone else, since its all a bit hard to explain and the problems are rather subtle. Nevertheless, I think its good to have this on record.
Init order
The initialization order is tricky. Taking qt as an example, the mro is:
All is good, except for one thing: I want
BaseRenderCanvas
to set the size and title (and maybe more in the future), because I don't want every subclass to have to bother with that. However, that must happen after the QRenderWidget did its initialization. I played with some ideas, and implemented one where the the backend class (QRenderWidget) must implement_rc_init
instead of__init__
. But this is too weird. Thought of metaclasses, but that's too dark. Using__new__
is also no help.So I ended up with classic instantiation mechanics, and requiring backend canvas classes to call
_final_canvas_init()
to allowBaseRenderCanvas
to apply the final configuration (setting size, title, transparency etc.) A little anoying, but its explicit. And if the class author forgets to call it, you simply don't get the custom title and size set.Subwidget kwargs
Another tricky one, specific to the wrapper classes in qt and wx, was how to pass the right kwargs to the real canvas (
._subwidget
). I previously had tricks like a function that popped canvas kwargs form the kwargs dict. In the end the solution is quite simple: any kwargs that the toplevel widget wants, must be explicitly taken, the rest is passed to the subwidget: