from kivy.app import App
from kivy.clock import Clock
from kivy.config import Config
from kivy.graphics import Color, Line, Rectangle
from kivy.lang import Builder
from kivy.properties import BooleanProperty, ObjectProperty
from kivy.uix.behaviors.compoundselection import CompoundSelectionBehavior
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
kv = '''
<MyWidget>:
size_hint: 0.2, 0.2
MyLayout:
canvas:
Color:
rgba: 1, 1, 1, 0.07
Rectangle:
pos: self.pos
size: self.size
MyWidget:
pos_hint: {'center_x': 0.5, 'center_y': 0.8}
MyWidget:
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MyWidget:
pos_hint: {'center_x': 0.5, 'center_y': 0.2}
'''
class MyWidget(Widget):
bg_color = ObjectProperty(Color(1, 1, 1, 0.97))
def __init__(self, **kwargs):
super(MyWidget, self).__init__(**kwargs)
self.rect = Rectangle(pos=self.pos, size=self.size)
self.canvas.add(self.bg_color)
self.canvas.add(self.rect)
self.bind(pos=self.update_rect,
size=self.update_rect,
bg_color=self.redraw)
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
def redraw(self, *args):
self.canvas.clear()
self.canvas.add(self.bg_color)
self.canvas.add(self.rect)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.parent.select_with_touch(self, touch)
return True
else:
self.parent.deselect_node(self)
return super(MyWidget, self).on_touch_down(touch)
class DragSelection(Widget):
"""Widget that represents the highlight on a click and drag"""
bg_color = ObjectProperty(Color(0, 0, 1, 0.3))
bg_outline_color = ObjectProperty(Color(0, 0, 1, 0.5))
def __init__(self, **kwargs):
self._redraw = Clock.create_trigger(self.redraw)
super(DragSelection, self).__init__(**kwargs)
self.rect = Rectangle(pos=self.pos, size=self.size)
self.bind(pos=self.update_rect,
size=self.update_rect)
def update_rect(self, *args) -> None:
self.rect.pos = self.pos
self.rect.size = self.size
self._redraw()
def redraw(self, *args) -> None:
self.canvas.clear()
self.canvas.add(self.bg_color)
self.canvas.add(self.rect)
self.canvas.add(self.bg_outline_color)
self.canvas.add(Line(rectangle=[*self.rect.pos, *self.rect.size]))
class MyLayout(CompoundSelectionBehavior, FloatLayout):
drag_selecting = BooleanProperty(False)
dsw = ObjectProperty(DragSelection(size_hint=(None, None))) # drag selection widget
def __init__(self, **kwargs):
self._redraw = Clock.create_trigger(self.redraw)
super(MyLayout, self).__init__(**kwargs)
def select_node(self, node):
node.bg_color = Color(1, 0, 0, 1)
return super(MyLayout, self).select_node(node)
def deselect_node(self, node):
node.bg_color = Color(1, 1, 1, 0.98)
return super(MyLayout, self).deselect_node(node)
def redraw(self, *args) -> None:
self.canvas.clear()
self.canvas.after.clear()
self.draw_drag_selection()
for child in self.children:
if isinstance(child, MyWidget):
child.redraw()
self.canvas.add(child.canvas)
def draw_drag_selection(self) -> None:
self.dsw._redraw()
self.canvas.after.add(self.dsw.canvas)
def reset_drag_selection(self) -> None:
self.drag_selecting = False
self.dsw.size = 0., 0.
def on_touch_down(self, touch):
if super(MyLayout, self).on_touch_down(touch):
return True
if getattr(touch, 'button', None) == 'right':
touch.grab(self)
self.reset_drag_selection()
self.drag_selecting = True
self.dsw.pos = touch.pos
return True
return super(MyLayout, self).on_touch_down(touch)
def on_touch_move(self, touch):
if touch.grab_current is self and self.drag_selecting:
self.dsw.width += touch.dx
self.dsw.height += touch.dy
self._redraw()
for child in self.children:
if isinstance(child, MyWidget) and self.dsw.collide_widget(child):
self.select_node(child)
else:
self.deselect_node(child)
return True
return super(MyLayout, self).on_touch_move(touch)
def on_touch_up(self, touch):
if touch.grab_current is self and self.drag_selecting:
touch.ungrab(self)
self.reset_drag_selection()
return super(MyLayout, self).on_touch_up(touch)
class MyApp(App):
def build(self):
return Builder.load_string(kv)
if __name__ == '__main__':
MyApp().run()
I have not had a chance to closely look at your code but I have 2 thoughts:
I don’t fully understand your intent, but if you simply want to select the child widgets that are ‘captured’ by the controller, I think it would be more straight forward to just code that up.
I think you would need to overload add_widget in MyLayout to add the appropriate behaviors to the child widgets…. But it might be better to just take a different approach.
I’ll take a closer look in a few hours….
From: GJG
Sent: Thursday, November 12, 2020 8:04 PM
To: kivy-...@googlegroups.com
Subject: [kivy-users] collide_widget() not working as expected
I'm trying to implement drag selection like below:
I try to do this by creating a layout that inherits from CompoundSelectionBehavior and FloatLayout. This custom layout has a widget representing the blue selection box in the gif above. I tried to use collide_widget() to select other widgets, but it doesn't work as expected. Here's the code and a gif:
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CA%2Bqqht6GcmfYbDCiqOtfxrkaoo50J%3DDPFS4yfwH%2BPf49JdoUKA%40mail.gmail.com.
You received this message because you are subscribed to a topic in the Google Groups "Kivy users support" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/kivy-users/YjSwDepGGqg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5faea424.1c69fb81.61f6d.7c12SMTPIN_ADDED_MISSING%40gmr-mx.google.com.
Well Done. Glad to hear you sorted it out!
from kivy.app import App
--
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/80fbde4f-1d91-4ad5-b80d-38f1b0d41a24n%40googlegroups.com.