Quick search

Table Of Contents

Source code for kivy.uix.behaviors.cover

'''
Cover Behavior
==============

The :class:`~kivy.uix.behaviors.cover.CoverBehavior`
`mixin <https://en.wikipedia.org/wiki/Mixin>`_ is intended for rendering
textures to full widget size keeping the aspect ratio of the original texture.

Use cases are i.e. rendering full size background images or video content in
a dynamic layout.

For an overview of behaviors, please refer to the :mod:`~kivy.uix.behaviors`
documentation.

Example
-------

The following examples add cover behavior to an image:

In python:

.. code-block:: python

    from kivy.app import App
    from kivy.uix.behaviors import CoverBehavior
    from kivy.uix.image import Image


    class CoverImage(CoverBehavior, Image):

        def __init__(self, **kwargs):
            super(CoverImage, self).__init__(**kwargs)
            texture = self._coreimage.texture
            self.reference_size = texture.size
            self.texture = texture


    class MainApp(App):

        def build(self):
            return CoverImage(source='image.jpg')

    MainApp().run()

In Kivy Language:

.. code-block:: kv

    CoverImage:
        source: 'image.png'

    <CoverImage@CoverBehavior+Image>:
        reference_size: self.texture_size

See :class:`~kivy.uix.behaviors.cover.CoverBehavior` for details.
'''

__all__ = ('CoverBehavior', )

from decimal import Decimal
from kivy.lang import Builder
from kivy.properties import ListProperty


Builder.load_string("""
<-CoverBehavior>:
    canvas.before:
        StencilPush
        Rectangle:
            pos: self.pos
            size: self.size
        StencilUse
    canvas:
        Rectangle:
            texture: self.texture
            size: self.cover_size
            pos: self.cover_pos
    canvas.after:
        StencilUnUse
        Rectangle:
            pos: self.pos
            size: self.size
        StencilPop
""")


[docs]class CoverBehavior(object): '''The CoverBehavior `mixin <https://en.wikipedia.org/wiki/Mixin>`_ provides rendering a texture covering full widget size keeping aspect ratio of the original texture. .. versionadded:: 1.10.0 ''' reference_size = ListProperty([]) '''Reference size used for aspect ratio approximation calculation. :attr:`reference_size` is a :class:`~kivy.properties.ListProperty` and defaults to `[]`. ''' cover_size = ListProperty([0, 0]) '''Size of the aspect ratio aware texture. Gets calculated in ``CoverBehavior.calculate_cover``. :attr:`cover_size` is a :class:`~kivy.properties.ListProperty` and defaults to `[0, 0]`. ''' cover_pos = ListProperty([0, 0]) '''Position of the aspect ratio aware texture. Gets calculated in ``CoverBehavior.calculate_cover``. :attr:`cover_pos` is a :class:`~kivy.properties.ListProperty` and defaults to `[0, 0]`. ''' def __init__(self, **kwargs): super(CoverBehavior, self).__init__(**kwargs) # bind covering self.bind( size=self.calculate_cover, pos=self.calculate_cover ) def _aspect_ratio_approximate(self, size): # return a decimal approximation of an aspect ratio. return Decimal('%.2f' % (float(size[0]) / size[1])) def _scale_size(self, size, sizer): # return scaled size based on sizer, where sizer (n, None) scales x # to n and (None, n) scales y to n size_new = list(sizer) i = size_new.index(None) j = i * -1 + 1 size_new[i] = (size_new[j] * size[i]) / size[j] return tuple(size_new) def calculate_cover(self, *args): # return if no reference size yet if not self.reference_size: return size = self.size origin_appr = self._aspect_ratio_approximate(self.reference_size) crop_appr = self._aspect_ratio_approximate(size) # same aspect ratio if origin_appr == crop_appr: crop_size = self.size offset = (0, 0) # scale x elif origin_appr < crop_appr: crop_size = self._scale_size(self.reference_size, (size[0], None)) offset = (0, ((crop_size[1] - size[1]) / 2) * -1) # scale y else: crop_size = self._scale_size(self.reference_size, (None, size[1])) offset = (((crop_size[0] - size[0]) / 2) * -1, 0) # set background size and position self.cover_size = crop_size self.cover_pos = offset