Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modified kivy scatter widget does not update transformation

Tags:

python

kivy

I try to create a kivy widget from Scatter, which is freely zoomable, but once the mouse button is lifted falls back to the closest zoom level.

It works, but it does not update the zoom until the next click. I think I need to bind some event here, but I'm pretty new to kivy and can not figure it out. Here is my current code:

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scatter import Scatter
from kivy.graphics.transformation import Matrix

ZOOM_LEVELS = [0.25, 0.5, 1, 2, 4]

class PPMap(Scatter):
    def __init__(self, **kwargs):
        super(PPMap, self).__init__(**kwargs)
        self.bind(on_touch_up=self.adjust_zoom)

    def adjust_zoom(self, *args):
        old_zoom = self.scale
        new_zoom = min(ZOOM_LEVELS, key=lambda x:abs(x-old_zoom))
        self.set_zoom(new_zoom)

    def set_zoom(self, zoom):
        self.transform.set(array=[[zoom, 0, 0, 0],
                                  [0, zoom, 0, 0],
                                  [0, 0, zoom, 0],
                                  self.transform.tolist()[3]])

class PPApp(App):
    def build(self):
        pp_map = PPMap(do_rotation=False, scale_min=ZOOM_LEVELS[0], scale_max=ZOOM_LEVELS[-1])
        label = Label(text="Hello!", font_size=300, pos=(0, 0))
        pp_map.add_widget(label)
        return pp_map

if __name__ == "__main__":
    PPApp().run()
like image 864
M. Bernhardt Avatar asked Oct 12 '17 23:10

M. Bernhardt


2 Answers

self.transform.set( # ...

Problem here is that you modify existing ObjectProperty instance and Kivy doesn't know it changed:

Warning To mark the property as changed, you must reassign a new python object.

You can either do it or, for example, dispatch manually:

def set_zoom(self, zoom):
    self.transform.set(array=[[zoom, 0, 0, 0],
                              [0, zoom, 0, 0],
                              [0, 0, zoom, 0],
                              self.transform.tolist()[3]])
    self.property('transform').dispatch(self)  # transform has changed
like image 108
Mikhail Gerasimov Avatar answered Nov 15 '22 13:11

Mikhail Gerasimov


Take a look at this method https://kivy.org/docs/api-kivy.uix.scatter.html#kivy.uix.scatter.Scatter.apply_transform

You could rewrite set_zoom similar to

def set_zoom(self, new_zoom, old_zoom):
    zoom = new_zoom / old_zoom
    self.apply_transform(Matrix().scale(zoom, zoom, zoom))

if you divide by old_zoom and multiply with desired you should get the right zoom since it seems to be multiplicative.

Here is another helpful link, where they work with Scatter and optimize it for desktop.

like image 40
PalimPalim Avatar answered Nov 15 '22 14:11

PalimPalim