Migrate from 0.4 to 0.5

Migrate from 0.3.1 to 0.4MigrateMigrate from 0.5 to 0.5.1

This document contains a migration guide for users of PyMT 0.4 who want to update their PyMT installation to version 0.5. Many changes have been introduced and we've been working hard to improve PyMT. In some places, this unfortunately means some changes to the API (since we're not at version 1.0 yet). To help our beloved users with the migration, this document tries to list all possible things that one might have to change, depending on the situation.

Configuration File Changes

  • show_eventstats has been removed
  • New jitter_distance and jitter_ignore_devices tokens to suppres jittery touches.
  • New [widgets] section to control default configuration for specific widgets
    • list_trigger_distance (MTList widget): Defines the maximum distance a touch might move the list so that the touch events are still sent to the children.
    • list_friction (MTList widget): Defines friction for the list movement. The higher the friction, the more difficult the list is scrolled.
    • list_friction_bound (MTList widget): Defines friction for the case when the user scrolls the list to the left/right/top/bottom boundary.
    • keyboard_type (MTVkeyboard widget): Can be "real" or "virtual". If "real", no virtual keyboard will be shown by default. You can still use your hardware keyboard.

You can check our DevGuide for more details about the new tokens.

CSS and cssutils removal

Our CSS parser has been rewritten from scratch. We're not using cssutils anymore. Parsing is now faster. The parser is dumb and less error-checks are performed. If you experience any issues with CSS, feel free to open an issue!

Events and weakref / weakmethod

PyMT now uses weak references for:

  • id <-> widget map
  • clock event callbacks
  • widget event callbacks

You must be aware of this behavior. If you take this example :

def my_func(dt):
  print 'called', dt
getClock().schedule_interval(my_func, .5)
del my_func
  • BEFORE: Even if the del statement is used, the callback is still called by the clock, because we were keeping a reference to my_func.
  • NOW: The function will be really deleted and at the next call, the clock will remove the schedule since the callback does not exist anymore.

The big advantage of this is that your memory is now reclaimed properly.

Safe list iteration

Our old class SafeList() was used to iterate our widget tree and even to remove children while iterating. We've found that this slowed down the toolkit substantially. After benchmarking, we've come to the conclusion to use Python's [:] method instead:

# BEFORE
for child in self.children.iterate():
  pass

# NOW
for child in self.children[:]:
  pass

You should do it the same everywhere you're doing a list iteration and modify the list at the same time.

Loader

The Loader has been rewritten and ProxyImage is not changing the image as it did before. You can check the loaded property on a ProxyImage to know if the image is loaded or not.

OSC

The OSC library API has changed for listening on multiple ports with multiple callbacks:

  • osc.listen() returns an oscid
  • oscid must be passed to osc.bind()

Touch

The new Touch-class attributes dxpos and dypos represent the previous position of the touch, and the value is now in the range 0-screenwidth/0-screenheight. (Not from 0-1 as before.)

Widgets

Private attributes

We've started to clean our widgets. Even if it's not finished, some attributes you were using before may be not available anymore. If the attribute was not designed to be used by another widget, we've prefixed it with _ (that's an underscore). Double check the documentation about available attributes.

size_hint attribute

The size_hint is used with layout. It defines how the size of your widget will be used or modified by the parent layout. This attribute works only if the parent of the widget is a Layout object.

Example: Assume that in a BoxLayout with undetermined size, you want to put two widgets:

  • First widget should be 75% of the width of the parent
  • Second widget should be 25% of the width of the parent

You can write this:

layout = MTBoxLayout(size=(500, 500))
layout.add_widget(MTButton(label='Part 1', size=(.75, 1)))
layout.add_widget(MTButton(label='Part 2', size=(.25, 1)))

size_hint is by default:

  • (None, None) for all MTWidgets
  • (1, 1) for all MTAbstractLayouts

Drawing

Every widget is now able to draw its own background (i.e., drawRectangle(widget.pos, widget.size)). But it's deactivated by default for the majority of widgets. For example, if you want to draw the background of a MTWidget, you can activate it with CSS like so:

widget {
  draw-background: 1;
}

Collision behavior

The function collide_point() now returns False if the widget is not visible.

Lambda properties

The internal implementation of some of our classes' properties has changed in order to increase performance. This means, however, that now you cannot just redefine a setter or getter, you need to also redefine the property:

class A(object):
  def _get_x(self):
    return self.x
  def _set_x(self, x):
    self._x = x
  x = property(_get_x, _set_x)

class B(A):
  def _set_x(self, x):
    print 'here', x
    super(B, self)._set_x(x)
  x = property(A._get_x, _set_x) # This is the important line that redefines the property

These changes have been applied to BaseObject, MTWidget and also to other classes like Touch.

UI

Layouts

Our layouts have been rewritten. If you use it, you may experience some issues. Ensure that:

  • You're calling the on_update() of the layout object.
  • You don't forget the new size_hint attribute, which defaults to (1, 1) for layouts.
  • You checked the layout documentation twice.
  • You checked all the examples about layout usage twice.

MTScatter

Scatter has been rewritten from scratch. OpenGL is not used for the internal calculation anymore. We are now using our own transformation library and numpy.

  • transform_mat is now deprecated. Use transform_gl to get the GL matrix of the current transformation
  • MTScatterWidget has been renamed to MTScatter. Use of the old name is deprecated.

Check MTScatter for more information.

MTLabel / MTButton

MTLabel has been rewritten from scratch. It's now using the same attributes as the Label core object. Refer to the documentation of |Core Label to see how to control the label rendering. Since MTButton is based on MTLabel, the same applies essay structure here.

MTButton

The event on_release is no longer fired if the touch didn't collide with the button when the up-event was dispatched.

XMLWidget

XMLWidget has its own "id to widget" map. If you have id= in your XML, it will be removed. You can use xml.getById(<id>) instead. We also introduce the method autoconnect(). See this example:

<?xml version="1.0"?>
<MTBoxLayout>
  <MTButton label='"BUTTON 1"' id='"button1"'/>
  <MTButton label='"BUTTON 2"' id='"button2"'/>
</MTBoxLayout

We have 2 buttons, identified by the ids button1 and button2. The autoconnect(<object>) will explore the current object for methods to connect to: "on_" + widget id + event name. See this Python source:

from pymt import *

class MyCustomWidget(MTBoxLayout):
  def __init__(self, **kwargs):
    super(MyCustomWidget, self).__init__(**kwargs)
    xmltext = open('widgets.xml', 'r').read()
    xml = XMLWidget(xml=xmltext)
    self.add_widget(xml.root())
    xml.autoconnect(self)

  def on_button1_release(self, *largs):
    print 'button1 released'

  def on_button2_touch_down(self, touch):
    print 'got touch from button 2', touch

You can check XMLWidget for more details about the new tokens.

Deprecated widgets and functions

  • MTKineticList is deprecated. You should replace it with the new MTList widget.
  • MTScatterWidget was renamed to MTScatter and the old name is deprecated
  • MTForm* is removed
  • The Matrix class is removed
  • draw_gradient from MTWindow is removed
  • event stats is removed