Andrew Mikhov
Andrew Mikhov

Reputation: 21

Python Kivy. How do I change orientation of Pagelayout?

I need to change orientation to vertical, but it does not work the same way as BoxLayout. There is also no information about this in the Kivy official documentation. In addition, is there any way to change the page by swiping from any place on the screen and not only the border?

Python:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition

class MainScreen(Screen):
    pass

class ScreenManagement(ScreenManager):
    pass

presentation = Builder.load_file("final.kv")

class MainApp(App):
    def build(self):
        return presentation

if __name__ == "__main__":
    MainApp().run()

Kivy:

ScreenManagement:
    MainScreen:

<MainScreen>:
    canvas:
        Rectangle:
            source: "nakedman.jpg"
            pos: self.pos
            size: self.size

    name: "main"

    PageLayout:
        orientation: "vertical"
        BoxLayout:
            Button:
                text: "Button1"
            Button:
                text: "Button2"
        BoxLayout:
            Button:
                text: "Button3"
            Button:
                text: "Button4"     

Upvotes: 1

Views: 697

Answers (1)

eyllanesc
eyllanesc

Reputation: 244132

PageLayout does not have the orientation attribute, so you have to build everything, in this case use the source code of PageLayout to obtain this new code:

__all__ = ('PageLayoutVertical', )

from kivy.uix.layout import Layout
from kivy.properties import NumericProperty, DictProperty
from kivy.animation import Animation


class PageLayoutVertical(Layout):
    '''PageLayout class. See module documentation for more information.
    '''

    page = NumericProperty(0)
    '''The currently displayed page.
    :data:`page` is a :class:`~kivy.properties.NumericProperty` and defaults
    to 0.
    '''

    border = NumericProperty('50dp')
    '''The width of the border around the current page used to display
    the previous/next page swipe areas when needed.
    :data:`border` is a :class:`~kivy.properties.NumericProperty` and
    defaults to 50dp.
    '''

    swipe_threshold = NumericProperty(.5)
    '''The thresold used to trigger swipes as percentage of the widget
    size.
    :data:`swipe_threshold` is a :class:`~kivy.properties.NumericProperty`
    and defaults to .5.
    '''

    anim_kwargs = DictProperty({'d': .5, 't': 'in_quad'})
    '''The animation kwargs used to construct the animation
    :data:`anim_kwargs` is a :class:`~kivy.properties.DictProperty`
    and defaults to {'d': .5, 't': 'in_quad'}.
    .. versionadded:: 1.11.0
    '''

    def __init__(self, **kwargs):
        super(PageLayoutVertical, self).__init__(**kwargs)

        trigger = self._trigger_layout
        fbind = self.fbind
        fbind('border', trigger)
        fbind('page', trigger)
        fbind('parent', trigger)
        fbind('children', trigger)
        fbind('size', trigger)
        fbind('pos', trigger)

    def do_layout(self, *largs):
        l_children = len(self.children) - 1
        w = self.width
        x_parent, y_parent = self.pos
        p = self.page
        border = self.border
        half_border = border / 2.
        top = self.top
        height = self.height - border
        for i, c in enumerate(reversed(self.children)):

            if i < p:
                y = y_parent
            elif i == p:
                if not p:  # it's first page
                    y = y_parent
                elif p != l_children:  # not first, but there are post pages
                    y = y_parent + half_border
                else:  # not first and there are no post pages
                    y = y_parent + border
            elif i == p + 1:
                if not p:  # second page - no left margin
                    y = top - border
                else:  # there's already a left margin
                    y = top - half_border
            else:
                y = top

            c.width = w
            c.height = height

            Animation(
                x=x_parent,
                y=y,
                **self.anim_kwargs).start(c)

    def on_touch_down(self, touch):
        if (
            self.disabled or
            not self.collide_point(*touch.pos) or
            not self.children
        ):
            return

        page = self.children[-self.page - 1]
        if self.y <= touch.y < page.y:
            touch.ud['page'] = 'previous'
            touch.grab(self)
            return True
        elif page.top <= touch.y < self.top:
            touch.ud['page'] = 'next'
            touch.grab(self)
            return True
        return page.on_touch_down(touch)

    def on_touch_move(self, touch):
        if touch.grab_current != self:
            return

        p = self.page
        border = self.border
        half_border = border / 2.
        page = self.children[-p - 1]
        if touch.ud['page'] == 'previous':
            # move next page upto right edge
            if p < len(self.children) - 1:
                self.children[-p - 2].y = min(
                    self.top - self.border * (1 - (touch.sy - touch.osy)),
                    self.top)

            # move current page until edge hits the right border
            if p >= 1:
                b_right = half_border if p > 1 else border
                b_left = half_border if p < len(self.children) - 1 else border
                self.children[-p - 1].y = max(min(
                    self.y + b_left + (touch.y - touch.oy),
                    self.top - b_right),
                    self.y + b_left)

            # move previous page left edge upto left border
            if p > 1:
                self.children[-p].y = min(
                    self.y + half_border * (touch.sy - touch.osy),
                    self.y + half_border)

        elif touch.ud['page'] == 'next':
            # move current page upto left edge
            if p >= 1:
                self.children[-p - 1].y = max(
                    self.y + half_border * (1 - (touch.osy - touch.sy)),
                    self.y)

            # move next page until its edge hit the left border
            if p < len(self.children) - 1:
                b_right = half_border if p >= 1 else border
                b_left = half_border if p < len(self.children) - 2 else border
                self.children[-p - 2].y = min(max(
                    self.top - b_right + (touch.y - touch.oy),
                    self.y + b_left),
                    self.top - b_right)

            # move second next page upto right border
            if p < len(self.children) - 2:
                self.children[-p - 3].y = max(
                    self.top + half_border * (touch.sy - touch.osy),
                    self.top - half_border)

        return page.on_touch_move(touch)

    def on_touch_up(self, touch):
        if touch.grab_current == self:
            if (
                touch.ud['page'] == 'previous' and
                abs(touch.y - touch.oy) / self.height > self.swipe_threshold
            ):
                self.page -= 1
            elif (
                touch.ud['page'] == 'next' and
                abs(touch.y - touch.oy) / self.height > self.swipe_threshold
            ):
                self.page += 1
            else:
                self._trigger_layout()

            touch.ungrab(self)

        if len(self.children) > 1:
            return self.children[-self.page + 1].on_touch_up(touch)


if __name__ == '__main__':
    from kivy.base import runTouchApp
    from kivy.uix.button import Button

    pl = PageLayoutVertical()
    for i in range(1, 10):
        b = Button(text='page%s' % i)
        pl.add_widget(b)

    runTouchApp(pl)

Upvotes: 0

Related Questions