I am writing a wrapper around the
GeUserArea class of Cinema 4D's Python API to enable creating user interfaces using an object orientated interface.
I've already written 2 prototypes, but I am not satisfied with my class-design. They do work very well, but I decided to start over to make it even more efficient, more clean and better commented, etc.
GeUserArea class provides drawing on it as it was a field of pixels, so it's a highly dynamic class to enable almost any type of interface you want, when you have the skills.
The baseclass for all objects being rendered is the
Two of the subclasses are
Lable. The difference between these is, that
View does hold a
frame attribute that defines a rectangular area while
Lable does only hold a position attribute that defines the position of the text being rendered.
Renderable class implements a tree-like design, so you can add a
Renderable instance below another, etc. When an input event (mouse/keyboard) appears, a chain starts that tells the full tree that this event occured. Any
Renderable instance should be able to react on an input event. But the view-subclass should also call a method when the mouse clicked into it's area.
(Theese methods are to let the user override them while subclassing, enabling to react on those input events.)
The event itself comes from
msg parameter, I can read out if and where a mouse event took place.
After doing so, the event chain starts.
class Renderable: def InputEvent(self, msg): pass class View(Renderable): def MouseEvent(self, msg, mouse): pass
Using the above layout, I'd need to implement a method that manages calling of theese methods, like this:
class Renderable: # .. def _private_ManageInput(self, msg): self.InputEvent(msg) for sub in self.subs: sub._private_ManageInput(msg) class View(Renderable): # .. def _private_ManageInput(self, msg): if IsMouseEvent(msg): mouse = GetMouse(msg) if mouse in self.frame: self.MouseEvent(self, msg, mouse) Renderable._private_ManageInput(self, msg)
This does already seem a bit dirty to me.
As the mouse position doesn't change within the recursive chain, it makes more sense to give the mouse position as an argument to the
Renderable._private_ManageInput() method, which gives a speedup of about 30%.
class Renderable: # .. def _private_ManageInput(self, msg, mouse): self.InputEvent(msg) for sub in self.subs: sub._private_ManageInput(msg) class View(Renderable): # .. def _private_ManageInput(self, msg, mouse): if mouse is not None: if mouse in self.frame: self.MouseEvent(msg, mouse) Renderable._private_ManageInput(self, msg, mouse)
Renderable class does not implement reacting on
MouseEvents (as it does not define any area where the mouse could "hit" it), but a method does need arguments for this purpose? It seems quite dirty to me.
Can you tell me how I can improve this design?