Scaler for Retina screen

winstonwolff edited this page Oct 19, 2013 · 2 revisions
Clone this wiki locally

Summary

  • author: Mathieu Virbel
  • kivy: >= 1.3.0

On Retina screen (iOS / iPad 3), the resolution is high (> 2000px) with an high DPI. Kivy currently don't support DPI, and then, all the text will look very tiny etc. We don't have anything for properly handling DPI and the moment, so you could use that Scaler class. You might do some change in order to use it.

Usage

#!python

# Put in your App.build() method
from kivy.utils import platform
from scaler import Scaler

class MyApp(App):
    def build(self):
        # construct your app here
        self.root = MyRootWidget()

        # special case for retina display, high dpi is not well handled
        # in kivy. use scatter to "zoom in"
        from kivy.core.window import Window
        self._scaler = None
        if platform() == 'ios' and (
            Window.width > 2000 or Window.height > 2000):
            self._scaler = Scaler(
                size=Window.size, scale=2)
            Window.add_widget(self._scaler)

        # add the widget to Window or scaler
        parent = self._scaler or Window
        parent.add_widget(self.root)

Files

scaler.py

#!python
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ObjectProperty
from kivy.base import EventLoop
from kivy.lang import Builder

class Scaler(Widget):
    scale = NumericProperty(2)
    container = ObjectProperty(None)

    def __init__(self, **kwargs):
        from kivy.base import EventLoop
        from kivy.lang import Builder
        Builder.load_string('''
<Scaler>:
    container: container
    canvas.before:
        PushMatrix
        Scale:
            scale: root.scale

    canvas.after:
        PopMatrix

    FloatLayout:
        id: container
        size: root.width / root.scale, root.height / root.scale
''')

        super(Scaler, self).__init__(**kwargs)
        EventLoop.add_postproc_module(self)

    def get_parent_window(self):
        return self.container

    def add_widget(self, widget):
        if self.container is not None:
            return self.container.add_widget(widget)
        return super(Scaler, self).add_widget(widget)

    def remove_widget(self, widget):
        if self.container is not None:
            return self.container.remove_widget(widget)
        return super(Scaler, self).remove_widget(widget)

    def process_to_local(self, x, y, relative=False):
        if x is None:
            return None, None
        s = float(self.scale)
        return x / s, y / s

    def process(self, events):
        transform = self.process_to_local
        transformed = []
        for etype, event in events:

            # you might have a move and up event in the same process
            # then avoid the double-transformation
            if event in transformed:
                continue
            transformed.append(event)

            event.sx, event.sy = transform(event.sx, event.sy)
            if etype == 'begin':
                event.osx, event.osy = transform(event.osx, event.osy)
            else:
                # update the delta
                event.dsx = event.sx - event.psx
                event.dsy = event.sy - event.psy

        return events



Comments

Add your comments here ...

Is this relevant anymore now that kivy includes kivy.metrics? - Winston Oct 2013