Search code examples
kivy

drag file onto bounding area of kivy widget


I want to display an Image when I drag a .png into a specific area of my Kivy window. I've been trying to visualize the bounding area of my widgets and layouts using

canvas.before:
    Color:
        rgb: 1, 0, 0
    Rectangle:
        pos: self.pos
        size: self.size

However I'm not convinced I understand this yet, because of the behavior I get with the following:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 20 08:42:50 2022
@author: erik
"""
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.core.window import Window

Builder.load_string('''
<MyLayout>:
    padding: 20,20, 20, 20
    id: img_box
    orientation: 'vertical'
    size_hint_min_x: self.minimum_width
    size_hint_min_y: self.minimum_height
    canvas.before:
        Color:
            rgb: 1, 0, 0
        Rectangle:
            pos: self.pos
            size: self.size
    Splitter:
        sizable_from: 'bottom'
        id: dig_img_spltr
        canvas.before:
            Color:
                rgb: 1, 1, 0
            Rectangle:
                pos: self.pos
                size: self.size
        #keep_within_parent: True
        rescale_with_parent: True
        Image:
            id: dig_img
    Button:
        text: 'hello'
        size_hint: .6,.6
        pos_hint: {'center_x': .5, 'center_y':.5}
''')

class MyLayout(BoxLayout):
    digimgfilePath = StringProperty('')
    def __init__(self, **kwargs):
        super(MyLayout, self).__init__(**kwargs)
        Window.bind(on_drop_file=self._on_file_drop)

    def _on_file_drop(self, window,  filename, x, y):
        '''
        Documentataion for on_drop_file
        doesn't show window parameter. I
        found this out with locals()
        '''
        print(f'x: {x}')
        print(f'y: {y}')
        x_lower_bound = self.ids.dig_img_spltr.pos[0]
        x_upper_bound = self.ids.dig_img_spltr.pos[0] + self.ids.dig_img_spltr.width
        y_lower_bound = self.ids.dig_img_spltr.pos[1]
        y_upper_bound = self.ids.dig_img_spltr.pos[1] + self.ids.dig_img_spltr.height
        print(f'xlb {x_lower_bound}')
        print(f'xub {x_upper_bound}')
        print(f'ylb {y_lower_bound}')
        print(f'yub {y_upper_bound}')
        print()
        #if x_lower_bound < x < x_upper_bound and y_lower_bound < y < y_upper_bound:
        if self.ids.dig_img_spltr.collide_point(x,y):
            self.digimgfilePath = filename.decode("utf-8")     # convert byte to string
            self.ids.dig_img.source = self.digimgfilePath
            self.ids.dig_img.reload()   # reload image

class sliderdropApp(App):
    def build(self):
        return MyLayout()

if __name__ == '__main__':
    sliderdropApp().run()

What I want, and expect, is for a image (.png for example) to be displayed when I drop the file into the area above the splitter. But I can't make sense of the area where collide_point returns True. It returns True when I drop the file within some un-explainable margin above and below the splitter. After I do get an image to display, the splitter canvas does to turn yellow above the splitter. Is this yellow area defined by the canvas not the same area of the splitter? Why doesn't collide_point return True when I drop on the area colored by the splitter's canvas?


Solution

  • The y dimension from the on_drop_file event is inverted from the window coordinates. If I send (x, Window.size[1] - y) to collide_point, it works as I expect and intent it to.