Repository: kivy/kivy

Issue:
Behaviour of PageLayout might not be the expected.
I noticed that the PageLayout has an unexpected behaviour. The "Pages" in the middle get covered by the next page (the one to the page). To fix it, the programmer would have to make sure that there is an empty space (equal to the border property of PageLayout) on the middle pages, but not on the extremes. This makes me think that the current behaviour is wrong, and should be fixed in order to keep things centered. 

Here is an example to replicate

```
<MyPageLayout>:
    Button:
        font_size: 26
        text: 'This is a very long description for the page 1 and centered'
    Button:
        font_size: 26
        text: 'This is a very long description for the page 2 not centered'
    Button:
        font_size: 26
        text: 'This is a very long description for the page 3 and centered'
```

And 3 screenshots. Notice how the second one is convered by the 3rd one.

![page1](https://cloud.githubusercontent.com/assets/1033512/5929588/0d1eb972-a653-11e4-83e0-6626f3406c6e.png)
![page2](https://cloud.githubusercontent.com/assets/1033512/5929587/0d1d2ff8-a653-11e4-8e00-d822c25ec22b.png)
![page3](https://cloud.githubusercontent.com/assets/1033512/5929589/0d217892-a653-11e4-8c5e-c74d571cca8e.png)

Thank you!



Discussion:

Resolving patch:
diff --git a/kivy/uix/pagelayout.py b/kivy/uix/pagelayout.py
--- a/kivy/uix/pagelayout.py
+++ b/kivy/uix/pagelayout.py
@@ -75,88 +75,111 @@ def __init__(self, **kwargs):
             pos=self._trigger_layout)
 
     def do_layout(self, *largs):
-        l_children = len(self.children)
+        l_children = len(self.children) - 1
+        h = self.height
+        x_parent, y_parent = self.pos
+        p = self.page
+        border = self.border
+        half_border = border / 2.
+        right = self.right
+        width = self.width - border
         for i, c in enumerate(reversed(self.children)):
-            if i < l_children:
-                width = self.width - self.border
+            not i or i == l_children
+
+            if i < p:
+                x = x_parent
+            elif i == p:
+                if not p:  # it's first page
+                    x = x_parent
+                elif p != l_children:  # not first, but there are post pages
+                    x = x_parent + half_border
+                else:  # not first and there are no post pages
+                    x = x_parent + border
+            elif i == p + 1:
+                if not p:  # second page - no left margin
+                    x = right - border
+                else:  # there's already a left margin
+                    x = right - half_border
             else:
-                width = self.width - 2 * self.border
+                x = right
 
-            if i == 0:
-                x = self.x
-
-            elif i < self.page:
-                x = self.x
-
-            elif i == self.page:
-                x = self.x + self.border
-
-            elif i == self.page + 1:
-                x = self.right - self.border
-
-            else:
-                x = self.right
-
-            c.height = self.height
+            c.height = h
             c.width = width
 
             Animation(
                 x=x,
-                y=self.y,
+                y=y_parent,
                 d=.5, t='in_quad').start(c)
 
     def on_touch_down(self, touch):
-        if self.y < touch.y < self.top:
-            if self.page > 0 and self.x < touch.x < (self.x + self.border):
-                touch.ud['page'] = 'previous'
-                touch.grab(self)
-                return True
-
-            elif (
-                self.page < len(self.children) - 1 and
-                self.right > touch.x > (self.right - self.border)
-            ):
-                touch.ud['page'] = 'next'
-                touch.grab(self)
-                return True
-
-        return self.children[-self.page - 1].on_touch_down(touch)
+        if (self.disabled or not self.collide_point(*touch.pos) or
+            not self.children):
+            return
+
+        page = self.children[-self.page - 1]
+        if self.x <= touch.x < page.x:
+            touch.ud['page'] = 'previous'
+            touch.grab(self)
+            return True
+        elif page.right <= touch.x < self.right:
+            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:
-            if touch.ud['page'] == 'previous':
-                self.children[-self.page - 1].x = max(min(
-                    self.x + self.border + (touch.x - touch.ox),
-                    self.right - self.border),
-                    self.x + self.border)
-
-                if self.page > 1:
-                    self.children[-self.page].x = min(
-                        self.x + self.border * (touch.sx - touch.osx),
-                        self.x + self.border)
-
-                if self.page < len(self.children) - 1:
-                    self.children[-self.page + 1].x = min(
-                        self.right - self.border * (1 - (touch.sx - touch.osx)),
-                        self.right)
-
-            elif touch.ud['page'] == 'next':
-                self.children[-self.page + 1].x = min(max(
-                    self.right - self.border + (touch.x - touch.ox),
-                    self.x + self.border),
-                    self.right - self.border)
-
-                if self.page >= 1:
-                    self.children[-self.page - 1].x = max(
-                        self.x + self.border * (1 - (touch.osx - touch.sx)),
-                        self.x)
-
-                if self.page < len(self.children) - 2:
-                    self.children[-self.page].x = max(
-                        self.right + self.border * (touch.sx - touch.osx),
-                        self.right - self.border)
-
-        return self.children[-self.page - 1].on_touch_move(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].x = min(
+                    self.right - self.border * (1 - (touch.sx - touch.osx)),
+                    self.right)
+
+            # 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].x = max(min(
+                    self.x + b_left + (touch.x - touch.ox),
+                    self.right - b_right),
+                    self.x + b_left)
+
+            # move previous page left edge upto left border
+            if p > 1:
+                self.children[-p].x = min(
+                    self.x + half_border * (touch.sx - touch.osx),
+                    self.x + half_border)
+
+        elif touch.ud['page'] == 'next':
+            # move current page upto left edge
+            if p >= 1:
+                self.children[-p - 1].x = max(
+                    self.x + half_border * (1 - (touch.osx - touch.sx)),
+                    self.x)
+
+            # 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].x = min(max(
+                    self.right - b_right + (touch.x - touch.ox),
+                    self.x + b_left),
+                    self.right - b_right)
+
+            # move second next page upto right border
+            if p < len(self.children) - 2:
+                self.children[-p - 3].x = max(
+                    self.right + half_border * (touch.sx - touch.osx),
+                    self.right - half_border)
+
+        return page.on_touch_move(touch)
 
     def on_touch_up(self, touch):
         if touch.grab_current == self:


Test patch: