UncleSax
UncleSax

Reputation: 148

Nested Widget's canvas do not draw anything

I've got two three nested widget which handle the on_touch_down event, clicking on the first parent, the event is sensed to the second and then the third. With this click the third widget should draw on it's canvas but this it's not happening.

I understand the dynamic of the canvas object and it's groups. So I don't really understand why this is happening

class Spline_guide(DragBehavior, Button):

    def __init__(self, **kw):
        super(Spline_guide, self).__init__(**kw)
         self.bind(pos = self.update_spline , size = self.update_spline)

     def update_spline(self, *l): 
         self.pos = self.parent.pos
         return self

     def show_spline(self,*l):
         print 'show spline'
         with self.canvas:
             Color(0,1,0)
             ######## THIS ISTRUCTION DOESN'T WORK
             Ellipse(pos = (100,100), size = (100,100)) 

         return self

     def hide_spline(self, *l): 
         print 'hide spline'
         self.canvas.clear()
         return self


class Editable_point(DragBehavior, Widget): 

    def __init__(self, name,x,y, **kw):
        super(Editable_point, self).__init__(**kw)
        self.drag_rectangle = (0,0 ,800,300)
        self.drag_timeout = 10000000
        self.drag_distance = 0
        self.name = name
        self.pos = (x - DOT_DIMENSION / 2,y - DOT_DIMENSION / 2)
        self.size = (DOT_DIMENSION, DOT_DIMENSION)
        self.spline = Spline_guide()
        self.add_widget(self.spline)
        self.SHOW_SPLINE = False
        self.bind(pos = self.check_pos)

     def check_pos(self, *l):
         self.area = self.parent.parent
         self.x = self.x if self.x > self.area.x else self.area.x
         self.y = self.y if self.y > self.area.y else self.area.y
         return self

    def draw_point(self):
        self.area = self.parent.parent
        self.drag_rectangle = (self.area.x, self.area.y, self.area.width, self.area.height)
        self.canvas.clear()
        with self.canvas:
            Color(1,0,0)
            Ellipse(pos=self.pos, size=self.size)
        return self


     def on_enter(self, pop):
         def wrap(l):
             if l.text in ['start','stop']: 
                 print 'you can not use start or stop as name'
                 pop.dismiss()
                 return wrap
             if self.name in ['start','stop']:
                pop.dismiss()
                print 'you can not edit the name of start or stop point'
                return wrap
            self.name = l.text
            pop.dismiss()
         return wrap    


    def show_info(self, *l):
        graph = self.parent.parent.graph
        X_OFFSET = graph._plot_area.x + self.parent.x - DOT_DIMENSION / 2
        Y_OFFSET = graph._plot_area.y + self.parent.y - DOT_DIMENSION / 2
        _x = self.x - X_OFFSET
        _y = self.y - Y_OFFSET

        x, y = normalize(graph.xmin,graph.ymin,graph.xmax,graph.ymax,graph._plot_area.width,graph._plot_area.height, _x, _y)

        point_name = TextInput(text=self.name, multiline = False)
         point_info = Popup(title ="X: {} Y: {}".format(x,y), content = point_name, size_hint=(None,None), size=(200,100))
        point_name.bind(on_text_validate=self.on_enter(point_info))
         point_info.open()
        return self



     def on_touch_down(self, *l):

         if self.SHOW_SPLINE:  
            self.SHOW_SPLINE = False
            self.spline.hide_spline()
         else:
            self.SHOW_SPLINE = True     
            self.spline.show_spline()
         return self



class Editable_line(Widget):


    def __init__(self, **kw):
        super(Editable_line, self).__init__(**kw)
        self._old_ = [100,100]
        self.old_pos = [0,0]
        self.bind(pos=self.update_line, size=self.update_line)

    def replace_start_stop(self, new_elem):

        elem = filter(lambda x: x.name == new_elem.name, [ i for i in self.children if hasattr(i,'name')])
        if elem: self.remove_widget(elem[0])
        self.add_widget(new_elem)
        return self

    def update_points(self): 
        r_x = float(Window.size[0]) / float(self._old_[0])
        r_y = float(Window.size[1]) / float(self._old_[1])

        for p in [ i for i in self.children if hasattr(i,'name')]:
            new_x = p.x * r_x
            new_y = p.y * r_y
            p.x = new_x
            p.y = new_y
            p.size = (DOT_DIMENSION, DOT_DIMENSION)

        return self


    def update_line(self, *a):
        self.pos = self.parent.pos
        self.size = self.parent.size
        self.parent.graph.pos = self.pos
        self.parent.graph.size = self.size
        self.parent.graph._redraw_size()    
        #Coordinate per start e stop personalizzare sul graph
        y = self.parent.graph._plot_area.y + self.y
        x = self.parent.graph._plot_area.x + self.x
        h = self.parent.graph._plot_area.height
        w = self.parent.graph._plot_area.width
        self.replace_start_stop(Editable_point('start', x, y + h / 2))
        self.replace_start_stop(Editable_point('stop', x +  w, y + h / 2))
        self.update_points()
        self._old_ = Window.size

        return self.draw_line()


    def sort_points(self):
        self.children = sorted(self.children , key=attrgetter('x'))
        return self

    def control_presence(self,coordinates):
        x = int(coordinates.x)
        y = int(coordinates.y)

        x_range = range(x-DOT_DIMENSION, x+DOT_DIMENSION)
        y_range = range(y-DOT_DIMENSION, y+DOT_DIMENSION)

        for p in [ i for i in self.children if hasattr(i,'name')]:
            if int(p.x) in x_range and int(p.y) in y_range: return p

        return False

    def on_touch_down(self,coordinates):
        #add points
        p = self.control_presence(coordinates)
        if p: 
                if not coordinates.is_double_tap: 
                return p.on_touch_down(coordinates)

            return p.show_info(coordinates)

        x = int(coordinates.x)
        y = int(coordinates.y)
        p = Editable_point('new point', x, y)
        p.size = (DOT_DIMENSION, DOT_DIMENSION)
        self.add_widget(p)
        return self.draw_line()

        def remove_point(self,coordinates): 
            p = self.control_presence(coordinates)
            if p: 
                if  p.name in ['start','stop']: print 'you can\'t delete start or stop point'               else: self.remove_widget(p)
            return self.draw_line()



    def draw_line(self):
        self.sort_points()
        self.canvas.before.clear()
        _l = list()
        for p in [ i for i in self.children if hasattr(i,'name')]:
            _l.append(p.x + DOT_DIMENSION/2)
            _l.append(p.y + DOT_DIMENSION/2)
            p.draw_point()
        with self.canvas.before:
            Color(0,0.8,1)
            Line(points=_l, witdth = LINE_WIDTH)
        return self


    def on_touch_move(self, coordinates):
        p = self.control_presence(coordinates)
        if p:
            if p.name in ['start','stop']: 
                return self.parent.on_touch_up(coordinates)

            p.on_touch_move(coordinates)
            self.draw_line()
        return self

This is a piece of my code and show how the classes are linked. The Spline_guide doesn't draw anything. Ideas?

Upvotes: 0

Views: 107

Answers (1)

kitti
kitti

Reputation: 14834

Widgets which are added to another Widget are drawn in the latter Widget's canvas. When you call self.canvas.clear() (i.e. in Editable_point) you are removing all the child canvases.

You could use canvas.before or canvas.after for your drawing instead, or you can save the instructions and modify them later:

def __init__(self, **kwargs):
    ...
    with self.canvas:
        self.draw_color = Color(0, 1, 0, 1)
        self.draw_ellipse = Ellipse(pos=self.pos, size=self.size)

def draw_point(self):
    ...
    self.draw_ellipse.pos = self.pos
    self.draw_ellipse.size = self.size

Then you never need to clear the canvas at all. This is the preferred solution as it offers the best performance.

Upvotes: 1

Related Questions