Skip to content

Commit b9bd638

Browse files
committed
Merge pull request kivy#1238 from kivy/pagelayout
Create PageLayout layout
2 parents 17618f4 + cc4dd2f commit b9bd638

File tree

3 files changed

+247
-0
lines changed

3 files changed

+247
-0
lines changed

examples/widgets/pagelayout.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from kivy.base import runTouchApp
2+
from kivy.lang import Builder
3+
4+
kv = '''
5+
PageLayout:
6+
BoxLayout:
7+
canvas:
8+
Color:
9+
rgba: 216/255., 195/255., 88/255., 1
10+
Rectangle:
11+
pos: self.pos
12+
size: self.size
13+
14+
orientation: 'vertical'
15+
Label:
16+
size_hint_y: None
17+
height: 1.5 * self.texture_size[1]
18+
text: 'page 1'
19+
20+
Button:
21+
text: 'test'
22+
on_press: print "test"
23+
24+
BoxLayout:
25+
orientation: 'vertical'
26+
canvas:
27+
Color:
28+
rgba: 109/255., 8/255., 57/255., 1
29+
Rectangle:
30+
pos: self.pos
31+
size: self.size
32+
33+
Label:
34+
text: 'page 2'
35+
36+
AsyncImage:
37+
source: 'http://kivy.org/logos/kivy-logo-black-64.png'
38+
39+
GridLayout:
40+
canvas:
41+
Color:
42+
rgba: 37/255., 39/255., 30/255., 1
43+
Rectangle:
44+
pos: self.pos
45+
size: self.size
46+
47+
cols: 2
48+
Label:
49+
text: 'page 3'
50+
AsyncImage:
51+
source: 'http://kivy.org/slides/kivyandroid-thumb.jpg'
52+
Button:
53+
text: 'test'
54+
on_press: print "test last page"
55+
AsyncImage:
56+
source: 'http://kivy.org/slides/kivypictures-thumb.jpg'
57+
Widget
58+
AsyncImage:
59+
source: 'http://kivy.org/slides/particlepanda-thumb.jpg'
60+
'''
61+
62+
63+
if __name__ == '__main__':
64+
runTouchApp(Builder.load_string(kv))

kivy/factory_registers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
r('AnchorLayout', module='kivy.uix.anchorlayout')
9393
r('BoxLayout', module='kivy.uix.boxlayout')
9494
r('GridLayout', module='kivy.uix.gridlayout')
95+
r('PageLayout', module='kivy.uix.pagelayout')
9596
r('Accordion', module='kivy.uix.accordion')
9697
r('AccordionItem', module='kivy.uix.accordion')
9798
r('Button', module='kivy.uix.button')

kivy/uix/pagelayout.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
"""
2+
PageLayout
3+
==========
4+
5+
The :class:`PageLayout` class allow to create a simple multiple page
6+
layout, in a way that allows easy flipping of one page to another using
7+
borders.
8+
9+
:class:`PageLayout` doesn't honor size_hint or pos_hint in any way currently.
10+
11+
.. versionadded:: 1.8.1
12+
13+
example::
14+
15+
PageLayout:
16+
Button:
17+
text: 'page1'
18+
19+
Button:
20+
text: 'page2'
21+
22+
Button:
23+
text: 'page3'
24+
"""
25+
26+
__all__ = ('PageLayout', )
27+
28+
from kivy.uix.layout import Layout
29+
from kivy.properties import NumericProperty
30+
from kivy.animation import Animation
31+
32+
33+
class PageLayout(Layout):
34+
'''PageLayout class. See module documentation for more information
35+
'''
36+
37+
'''Currently displayed page.
38+
39+
:data:`page` is a :class:`~kivy.properties.NumericProperty`, default to 0.
40+
'''
41+
page = NumericProperty(0)
42+
43+
'''Width of the border used around current page to display previous/next
44+
page when needed.
45+
46+
:data:`border` is a :class:`~kivy.properties.NumericProperty`,
47+
default to 0.
48+
'''
49+
border = NumericProperty('50dp')
50+
51+
'''Thresold to the swipe action triggering, as percentage of the widget
52+
size.
53+
54+
:data:`swipe_threshold` is a :class:`~kivy.properties.NumericProperty`,
55+
default to .5.
56+
'''
57+
swipe_threshold = NumericProperty(.5)
58+
59+
def __init__(self, **kwargs):
60+
super(PageLayout, self).__init__(**kwargs)
61+
62+
self.bind(
63+
border=self._trigger_layout,
64+
page=self._trigger_layout,
65+
parent=self._trigger_layout,
66+
children=self._trigger_layout,
67+
size=self._trigger_layout,
68+
pos=self._trigger_layout)
69+
70+
def do_layout(self, *largs):
71+
l_children = len(self.children)
72+
for i, c in enumerate(reversed(self.children)):
73+
if i < l_children:
74+
width = self.width - self.border
75+
else:
76+
width = self.width - 2 * self.border
77+
78+
if i == 0:
79+
x = self.x
80+
81+
elif i < self.page:
82+
x = self.x
83+
84+
elif i == self.page:
85+
x = self.x + self.border
86+
87+
elif i == self.page + 1:
88+
x = self.right - self.border
89+
90+
else:
91+
x = self.right
92+
93+
c.height = self.height
94+
c.width = width
95+
96+
Animation(
97+
x=x,
98+
y=self.y,
99+
d=.5, t='in_quad').start(c)
100+
101+
def on_touch_down(self, touch):
102+
if self.y < touch.y < self.top:
103+
if self.page > 0 and self.x < touch.x < (self.x + self.border):
104+
touch.ud['page'] = 'previous'
105+
touch.grab(self)
106+
return True
107+
108+
elif (
109+
self.page < len(self.children) - 1 and
110+
self.right > touch.x > (self.right - self.border)
111+
):
112+
touch.ud['page'] = 'next'
113+
touch.grab(self)
114+
return True
115+
116+
return self.children[-self.page - 1].on_touch_down(touch)
117+
118+
def on_touch_move(self, touch):
119+
if touch.grab_current == self:
120+
if touch.ud['page'] == 'previous':
121+
self.children[-self.page - 1].x = max(min(
122+
self.x + self.border + (touch.x - touch.ox),
123+
self.right - self.border),
124+
self.x + self.border)
125+
126+
if self.page > 1:
127+
self.children[-self.page].x = min(
128+
self.x + self.border * (touch.sx - touch.osx),
129+
self.x + self.border)
130+
131+
if self.page < len(self.children) - 1:
132+
self.children[-self.page + 1].x = min(
133+
self.right - self.border * (1 - (touch.sx - touch.osx)),
134+
self.right)
135+
136+
elif touch.ud['page'] == 'next':
137+
self.children[-self.page + 1].x = min(max(
138+
self.right - self.border + (touch.x - touch.ox),
139+
self.x + self.border),
140+
self.right - self.border)
141+
142+
if self.page >= 1:
143+
self.children[-self.page - 1].x = max(
144+
self.x + self.border * (1 - (touch.osx - touch.sx)),
145+
self.x)
146+
147+
if self.page < len(self.children) - 2:
148+
self.children[-self.page].x = max(
149+
self.right + self.border * (touch.sx - touch.osx),
150+
self.right - self.border)
151+
152+
return self.children[-self.page - 1].on_touch_move(touch)
153+
154+
def on_touch_up(self, touch):
155+
if touch.grab_current == self:
156+
if (
157+
touch.ud['page'] == 'previous' and
158+
abs(touch.sx - touch.osx) > self.swipe_threshold
159+
):
160+
self.page -= 1
161+
elif (
162+
touch.ud['page'] == 'next' and
163+
abs(touch.sx - touch.osx) > self.swipe_threshold
164+
):
165+
self.page += 1
166+
else:
167+
self._trigger_layout()
168+
169+
touch.ungrab(self)
170+
return self.children[-self.page + 1].on_touch_up(touch)
171+
172+
173+
if __name__ == '__main__':
174+
from kivy.base import runTouchApp
175+
from kivy.uix.button import Button
176+
177+
pl = PageLayout()
178+
for i in range(1, 4):
179+
b = Button(text='page%s' % i)
180+
pl.add_widget(b)
181+
182+
runTouchApp(pl)

0 commit comments

Comments
 (0)