diff --git a/kivy/c_ext/graphics.pyx b/kivy/c_ext/graphics.pyx index 33eb04cb1..ccd25a54e 100644 --- a/kivy/c_ext/graphics.pyx +++ b/kivy/c_ext/graphics.pyx @@ -43,6 +43,7 @@ cdef class Canvas: cdef VBO vertex_buffer cdef list texture_map cdef list _batch + cdef list _children #move to graphics compiler?: cdef int _need_compile @@ -54,6 +55,7 @@ cdef class Canvas: self.vertex_buffer = VBO() self.texture_map = [] self._batch = [] + self._children = [] self._need_compile = 1 self.batch_slices = [] @@ -83,6 +85,14 @@ cdef class Canvas: global _active_canvas _active_canvas = None + cpdef add_canvas(self, Canvas canvas): + if not canvas in self._children: + self._children.append(canvas) + + cpdef remove_canvas(self, Canvas canvas): + if canvas in self._children: + self._children.remove(canvas) + cdef add(self, GraphicInstruction instruction): self.need_compile = 1 self._batch.append(instruction) @@ -140,7 +150,13 @@ cdef class Canvas: # maybe we ended on an slice of vartex data, whcih we didnt push yet self.compile_slice('draw', slice_start, slice_stop) + # draw children! + self.compile_children() + cdef compile_children(self): + cdef Canvas child + for child in self._children: + self.batch_slices.append(('instruction', CanvasDraw(child))) cdef compile_slice(self, str command, slice_start, slice_end): Logger.trace('Canvas: compiling slice: %s' % str(( @@ -177,8 +193,12 @@ cdef class Canvas: self.batch_slices.append((command, b)) cpdef draw(self): + self._draw() + + cdef _draw(self): cdef int i cdef Buffer b + cdef ContextInstruction ci if self.need_compile: self.compile() @@ -190,7 +210,8 @@ cdef class Canvas: for command, item in self.batch_slices: if command == 'instruction': - item.apply() + ci = item + ci.apply() if command == 'draw': b = item self.context.flush() @@ -200,6 +221,14 @@ cdef class Canvas: cdef class GraphicInstruction: + '''Base class for all Graphics Instructions + + :Parameters: + `code`: constant + instruction code for hinting the compiler currently a + combination of : GI_NOOP, GI_IGNORE, GI_CONTEXT_MOD, + GI_VERTEX_DATA + ''' #: Graphic instruction op code cdef int code @@ -207,31 +236,23 @@ cdef class GraphicInstruction: cdef Canvas canvas def __init__(self, int code): - '''Base class for all Graphics Instructions - - :Parameters: - `code`: constant - instruction code for hinting the compiler currently a - combination of : GI_NOOP, GI_IGNORE, GI_CONTEXT_MOD, - GI_VERTEX_DATA - ''' self.code = code self.canvas = _active_canvas cdef class ContextInstruction(GraphicInstruction): + '''Abstract Base class for GraphicInstructions that modidifies the + context. (so that canvas/compiler can know about how to optimize). + ''' #: Graphics context to use (usually equal to _default_context) cdef GraphicContext context def __init__(self, *args, **kwargs): - '''Abstract Base class for GraphicInstructions that modidifies the - context. (so that canvas/compiler can know about how to optimize). - ''' GraphicInstruction.__init__(self, GI_CONTEXT_MOD) self.context = self.canvas.context self.canvas.add(self) - cpdef apply(self): + cdef apply(self): pass @@ -247,7 +268,7 @@ cdef class LineWidth(ContextInstruction): def set(self, float lw): self.lw = lw - cpdef apply(self): + cdef apply(self): self.canvas.context.set('linewidth', self.lw) @@ -260,7 +281,7 @@ cdef class Color(ContextInstruction): ContextInstruction.__init__(self) self.rgba = args - cpdef apply(self): + cdef apply(self): self.context.set('color', (self.r, self.g, self.b, self.a)) property rgba: @@ -301,23 +322,33 @@ cdef class Color(ContextInstruction): self.rgba = [self.r, self.g, self.b, a] +cdef class CanvasDraw(ContextInstruction): + cdef Canvas obj + + def __init__(self, *args, **kwargs): + ContextInstruction.__init__(self) + self.obj = args[0] + + cdef apply(self): + self.obj.draw() + cdef class BindTexture(ContextInstruction): + '''BindTexture Graphic instruction. + The BindTexture Instruction will bind a texture and enable + GL_TEXTURE_2D for subsequent drawing. + + :Parameters: + `texture`: Texture + specifies the texture to bind to the given index + ''' cdef object _texture def __init__(self, *args, **kwargs): - '''BindTexture Graphic instruction. - The BindTexture Instruction will bind a texture and enable - GL_TEXTURE_2D for subsequent drawing. - - :Parameters: - `texture`: Texture - specifies the texture to bind to the given index - ''' ContextInstruction.__init__(self) self.texture = args[0] - cpdef apply(self): + cdef apply(self): self.canvas.context.set('texture0', self.texture) def set(self, object texture): @@ -334,13 +365,13 @@ cdef class BindTexture(ContextInstruction): cdef class PushMatrix(ContextInstruction): '''PushMatrix on context's matrix stack ''' - cpdef apply(self): + cdef apply(self): self.context.get('mvm').push() cdef class PopMatrix(ContextInstruction): '''Pop Matrix from context's matrix stack onto model view ''' - cpdef apply(self): + cdef apply(self): self.context.get('mvm').push() @@ -353,7 +384,7 @@ cdef class MatrixInstruction(ContextInstruction): def __init__(self, *args, **kwargs): ContextInstruction.__init__(self) - cpdef apply(self): + cdef apply(self): '''Apply matrix to the matrix of this instance to the context model view matrix ''' @@ -515,6 +546,17 @@ cdef class Translate(Transform): cdef class VertexDataInstruction(GraphicInstruction): + '''A VertexDataInstruction pushes vertices into the graphics pipeline + this class manages a vbo, allocating a set of vertices on the vbo + and can update the vbo data, when local changes have been made + + :Parameters: + `source`: str + Filename to load for the texture + `texture`: Texture + The texture to be bound while drawing the vertices + + ''' #canvas, vbo and texture to use with this element cdef VBO vbo cdef object _texture @@ -542,17 +584,6 @@ cdef class VertexDataInstruction(GraphicInstruction): self.v_data = NULL def __init__(self, **kwargs): - '''A VertexDataInstruction pushes vertices into the graphics pipeline - this class manages a vbo, allocating a set of vertices on the vbo - and can update the vbo data, when local changes have been made - - :Parameters: - `source`: str - Filename to load for the texture - `texture`: Texture - The texture to be bound while drawing the vertices - - ''' GraphicInstruction.__init__(self, GI_VERTEX_DATA) self.vbo = self.canvas.vertex_buffer self.v_count = 0 #no vertices to draw until initialized @@ -1159,14 +1190,17 @@ cdef class PathInstruction(GraphicInstruction): cdef class PathStart(PathInstruction): + '''Starts a new path at position x,y. Will raise an Excpetion, if called + while another path is already started. + + :Parameters: + `x`: float + x position + `y`: float + y position + ''' cdef int index def __init__(self, float x, float y): - ''' - Starts a new path at position x,y. Will raise an Excpetion, if called while another path is already started - :Parameters: - `x`, float: x position - `y`, float: y position - ''' global _active_path PathInstruction.__init__(self) if _active_path != None: @@ -1176,29 +1210,29 @@ cdef class PathStart(PathInstruction): cdef class PathLineTo(PathInstruction): + '''Adds a line from the current location to the x, y coordinates passed as + parameters. + ''' cdef int index def __init__(self, x, y): - ''' - Adds a line from the current location to the x, y coordinates passed as parameters - ''' PathInstruction.__init__(self) self.index = self.path.add_point(x, y) cdef class PathClose(PathInstruction): + '''Closes the path, by adding a line from the current location to the first + vertex taht started the path. + ''' def __init__(self): - ''' - Closes the path, by adding a line from the current location to the first vertex taht started the path - ''' PathInstruction.__init__(self) cdef vertex* v = self.path.point_buffer.pointer() self.path.add_point(v[0].x, v[0].y) cdef class PathFill(PathInstruction): + '''Ends path construction on the current path, the path will be build + and added to the canvas + ''' def __init__(self): - '''Ends path construction on the current path, the path will be build - and added to the canvas - ''' global _active_path PathInstruction.__init__(self) self.path.build_fill() @@ -1206,10 +1240,10 @@ cdef class PathFill(PathInstruction): cdef class PathStroke(PathInstruction): + '''Ends path construction on the current path, the path will be build + and added to the canvas + ''' def __init__(self): - '''Ends path construction on the current path, the path will be build - and added to the canvas - ''' global _active_path PathInstruction.__init__(self) self.path.build_stroke() diff --git a/kivy/core/window/__init__.py b/kivy/core/window/__init__.py index 1abdbbf58..62cd9672d 100644 --- a/kivy/core/window/__init__.py +++ b/kivy/core/window/__init__.py @@ -76,9 +76,9 @@ class WindowBase(EventDispatcher): self._rotation = 0 # event subsystem + self.register_event_type('on_draw') self.register_event_type('on_flip') self.register_event_type('on_rotate') - self.register_event_type('on_draw') self.register_event_type('on_resize') self.register_event_type('on_close') self.register_event_type('on_touch_down') @@ -157,6 +157,10 @@ class WindowBase(EventDispatcher): # configure the window self.create_window(params) + # create the canvas + from kivy.graphics import Canvas + self.canvas = Canvas() + # attach modules + listener event Modules.register_window(self) EventLoop.set_window(self) @@ -228,6 +232,7 @@ class WindowBase(EventDispatcher): '''Add a widget on window''' self.children.append(w) w.parent = self + self.canvas.add_canvas(w.canvas) def remove_widget(self, w): '''Remove a widget from window''' @@ -235,6 +240,7 @@ class WindowBase(EventDispatcher): return self.children.remove(w) w.parent = None + self.canvas.remove_canvas(w.canvas) def clear(self): '''Clear the window with background color''' @@ -264,16 +270,7 @@ class WindowBase(EventDispatcher): return None def on_draw(self): - '''Event called when window we are drawing window. - This function are cleaning the buffer with bg-color css, - and call children drawing + show fps timer on demand''' - - # draw our window - self.draw() - - # then, draw childrens - for w in self.children: - w.dispatch('on_draw') + self.canvas.draw() def on_touch_down(self, touch): '''Event called when a touch is down''' diff --git a/kivy/uix/widget.py b/kivy/uix/widget.py index ad279e53c..b8c95635d 100644 --- a/kivy/uix/widget.py +++ b/kivy/uix/widget.py @@ -66,7 +66,6 @@ class Widget(EventDispatcher): self.register_event_type('on_touch_down') self.register_event_type('on_touch_move') self.register_event_type('on_touch_up') - self.register_event_type('on_draw') # Before doing anything, ensure the windows exist. EventLoop.ensure_window() @@ -96,13 +95,6 @@ class Widget(EventDispatcher): # Default event handlers # - def on_draw(self): - '''Dispatch the on_draw even in every child - ''' - self.draw() - for child in self.children: - child.dispatch('on_draw') - def on_touch_down(self, touch): '''Send the touch down event in every child Return true if one child use it @@ -178,13 +170,16 @@ class Widget(EventDispatcher): ''' widget.parent = self self.children = [widget] + self.children + self.canvas.add_canvas(widget.canvas) def remove_widget(self, widget): '''Remove a widget from the childs of current widget ''' - if widget in self.children: - self.children = self.children.remove(widget) - widget.parent = None + if widget not in self.children: + return + self.children = self.children.remove(widget) + self.canvas.remove_canvas(widget.canvas) + widget.parent = None def get_root_window(self): '''Return the root window diff --git a/kivy/uxl.py b/kivy/uxl.py index 68456ec01..33861daca 100644 --- a/kivy/uxl.py +++ b/kivy/uxl.py @@ -388,11 +388,9 @@ class UxlBase(object): continue value, ln, ctx = value if key == 'children': - children = [] for citem, cparams, in value: child = self.build_item(citem, cparams) - children.append(child) - widget.children = children + widget.add_widget(child) elif key == 'canvas': pass else: