first commit

This commit is contained in:
Yura 2024-09-15 15:12:16 +03:00
commit 417e54da96
5696 changed files with 900003 additions and 0 deletions

View file

@ -0,0 +1,17 @@
from kivy.uix.accordion import Accordion, AccordionItem
from kivy.uix.label import Label
from kivy.app import App
class AccordionApp(App):
def build(self):
root = Accordion()
for x in range(5):
item = AccordionItem(title='Title %d' % x)
item.add_widget(Label(text='Very big content\n' * 10))
root.add_widget(item)
return root
if __name__ == '__main__':
AccordionApp().run()

View file

@ -0,0 +1,32 @@
from kivy.base import runTouchApp
from kivy.lang import Builder
runTouchApp(Builder.load_string('''
ActionBar:
pos_hint: {'top':1}
ActionView:
use_separator: True
ActionPrevious:
title: 'Action Bar'
with_previous: False
ActionOverflow:
ActionButton:
icon: 'atlas://data/images/defaulttheme/audio-volume-high'
ActionButton:
important: True
text: 'Important'
ActionButton:
text: 'Btn2'
ActionButton:
text: 'Btn3'
ActionButton:
text: 'Btn4'
ActionGroup:
text: 'Group1'
ActionButton:
text: 'Btn5'
ActionButton:
text: 'Btn6'
ActionButton:
text: 'Btn7'
'''))

View file

@ -0,0 +1,35 @@
'''
Asynchronous image loading
==========================
Test of the widget AsyncImage.
We are just putting it in a CenteredAsyncImage for being able to center the
image on screen without doing upscale like the original AsyncImage.
'''
from kivy.app import App
from kivy.uix.image import AsyncImage
from kivy.lang import Builder
Builder.load_string('''
<CenteredAsyncImage>:
size_hint: 0.8, 0.8
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
mipmap: True
''')
class CenteredAsyncImage(AsyncImage):
pass
class TestAsyncApp(App):
def build(self):
url = ('https://upload.wikimedia.org/wikipedia/commons/thumb/8/89/'
'STS-116_spacewalk_1.jpg/1024px-STS-116_spacewalk_1.jpg')
return CenteredAsyncImage(source=url)
if __name__ == '__main__':
TestAsyncApp().run()

View file

@ -0,0 +1,54 @@
from kivy.uix.gridlayout import GridLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Demo>:
cols: 1
BoxLayout:
orientation: 'vertical'
Button:
size_hint_x: 0.4
pos_hint: {'x': 0}
text: 'pos_hint: x=0'
Button:
size_hint_x: 0.2
pos_hint: {'center_x': 0.5}
text: 'pos_hint: center_x=0.5'
Button:
size_hint_x: 0.4
pos_hint: {'right': 1}
text: 'pos_hint: right=1'
BoxLayout:
Button:
size_hint_y: 0.4
pos_hint: {'y': 0}
text: 'pos_hint: y=0'
Button:
size_hint_y: 0.2
pos_hint: {'center_y': .5}
text: 'pos_hint: center_y=0.5'
Button:
size_hint_y: 0.4
pos_hint: {'top': 1}
text: 'pos_hint: top=1'
''')
class Demo(GridLayout):
pass
class DemoApp(App):
def build(self):
return Demo()
if __name__ == '__main__':
DemoApp().run()

View file

@ -0,0 +1,63 @@
'''
Bubble
======
Test of the widget Bubble.
'''
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.uix.bubble import Bubble
Builder.load_string('''
<cut_copy_paste>
size_hint: (None, None)
size: (160, 120)
pos_hint: {'center_x': .5, 'y': .6}
BubbleContent:
BubbleButton:
text: 'Cut'
size_hint_y: 1
BubbleButton:
text: 'Copy'
size_hint_y: 1
BubbleButton:
text: 'Paste'
size_hint_y: 1
''')
class cut_copy_paste(Bubble):
pass
class BubbleShowcase(FloatLayout):
def __init__(self, **kwargs):
super(BubbleShowcase, self).__init__(**kwargs)
self.but_bubble = Button(text='Press to show bubble')
self.but_bubble.bind(on_release=self.show_bubble)
self.add_widget(self.but_bubble)
def show_bubble(self, *l):
if not hasattr(self, 'bubb'):
self.bubb = bubb = cut_copy_paste()
self.add_widget(bubb)
else:
values = ('left_top', 'left_mid', 'left_bottom', 'top_left',
'top_mid', 'top_right', 'right_top', 'right_mid',
'right_bottom', 'bottom_left', 'bottom_mid', 'bottom_right')
index = values.index(self.bubb.arrow_pos)
self.bubb.arrow_pos = values[(index + 1) % len(values)]
class TestBubbleApp(App):
def build(self):
return BubbleShowcase()
if __name__ == '__main__':
TestBubbleApp().run()

View file

@ -0,0 +1,33 @@
from kivy.app import App
from kivy.lang import Builder
kv = '''
BoxLayout:
orientation: 'vertical'
Camera:
id: camera
resolution: 399, 299
BoxLayout:
orientation: 'horizontal'
size_hint_y: None
height: '48dp'
Button:
text: 'Start'
on_release: camera.play = True
Button:
text: 'Stop'
on_release: camera.play = False
'''
class CameraApp(App):
def build(self):
return Builder.load_string(kv)
if __name__ == '__main__':
CameraApp().run()

View file

@ -0,0 +1,50 @@
'''
Carousel example with button inside.
This is a tiny test for testing the scroll distance/timeout
And ensure the down/up are dispatched if no gesture is done.
'''
from kivy.uix.carousel import Carousel
from kivy.uix.gridlayout import GridLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Page>:
cols: 3
Label:
text: str(id(root))
Button
Button
Button
Button
text: 'load(page 3)'
on_release:
carousel = root.parent.parent
carousel.load_slide(carousel.slides[2])
Button
Button
text: 'prev'
on_release:
root.parent.parent.load_previous()
Button
Button
text: 'next'
on_release:
root.parent.parent.load_next()
''')
class Page(GridLayout):
pass
class TestApp(App):
def build(self):
root = Carousel()
for x in range(10):
root.add_widget(Page())
return root
if __name__ == '__main__':
TestApp().run()

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 KiB

View file

@ -0,0 +1,225 @@
from kivy.app import App
from kivy.extras.highlight import KivyLexer
from kivy.uix.spinner import Spinner, SpinnerOption
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.codeinput import CodeInput
from kivy.uix.behaviors import EmacsBehavior
from kivy.uix.popup import Popup
from kivy.properties import ListProperty
from kivy.core.window import Window
from kivy.core.text import LabelBase
from pygments import lexers
import codecs
import os
example_text = '''
---------------------Python----------------------------------
import kivy
kivy.require('1.0.6') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.button import Button
class MyApp(App):
def build(self):
return Button(text='Hello World')
if __name__ == '__main__':
MyApp().run()
----------------------Java-----------------------------------
public static byte toUnsignedByte(int intVal) {
byte byteVal;
return (byte)(intVal & 0xFF);
}
---------------------kv lang---------------------------------
#:kivy 1.0
<YourWidget>:
canvas:
Color:
rgb: .5, .5, .5
Rectangle:
pos: self.pos
size: self.size
---------------------HTML------------------------------------
<!-- Place this tag where you want the +1 button to render. -->
<div class="g-plusone" data-annotation="inline" data-width="300"></div>
<!-- Place this tag after the last +1 button tag. -->
<script type="text/javascript">
(function() {
var po = document.createElement('script');
po.type = 'text/javascript';
po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(po, s);
})();
</script>
----------------------Emacs key bindings---------------------
This CodeInput inherits from EmacsBehavior, so you can use Emacs key bindings
if you want! To try out Emacs key bindings, set the "Key bindings" option to
"Emacs". Experiment with the shortcuts below on some of the text in this window
(just be careful not to delete the cheat sheet before you have made note of the
commands!)
Shortcut Description
-------- -----------
Control + a Move cursor to the beginning of the line
Control + e Move cursor to the end of the line
Control + f Move cursor one character to the right
Control + b Move cursor one character to the left
Alt + f Move cursor to the end of the word to the right
Alt + b Move cursor to the start of the word to the left
Alt + Backspace Delete text left of the cursor to the beginning of word
Alt + d Delete text right of the cursor to the end of the word
Alt + w Copy selection
Control + w Cut selection
Control + y Paste selection
'''
class Fnt_SpinnerOption(SpinnerOption):
pass
class LoadDialog(Popup):
def load(self, path, selection):
self.choosen_file = [None, ]
self.choosen_file = selection
Window.title = selection[0][selection[0].rfind(os.sep) + 1:]
self.dismiss()
def cancel(self):
self.dismiss()
class SaveDialog(Popup):
def save(self, path, selection):
_file = codecs.open(selection, 'w', encoding='utf8')
_file.write(self.text)
Window.title = selection[selection.rfind(os.sep) + 1:]
_file.close()
self.dismiss()
def cancel(self):
self.dismiss()
class CodeInputWithBindings(EmacsBehavior, CodeInput):
'''CodeInput with keybindings.
To add more bindings, add the behavior before CodeInput in the class
definition.
'''
pass
class CodeInputTest(App):
files = ListProperty([None, ])
def build(self):
b = BoxLayout(orientation='vertical')
languages = Spinner(
text='language',
values=sorted(['KvLexer', ] + list(lexers.LEXERS.keys())))
languages.bind(text=self.change_lang)
menu = BoxLayout(
size_hint_y=None,
height='30pt')
fnt_size = Spinner(
text='12',
values=list(map(str, list(range(5, 40)))))
fnt_size.bind(text=self._update_size)
fonts = [
file for file in LabelBase._font_dirs_files
if file.endswith('.ttf')]
fnt_name = Spinner(
text='RobotoMono',
option_cls=Fnt_SpinnerOption,
values=fonts)
fnt_name.bind(text=self._update_font)
mnu_file = Spinner(
text='File',
values=('Open', 'SaveAs', 'Save', 'Close'))
mnu_file.bind(text=self._file_menu_selected)
key_bindings = Spinner(
text='Key bindings',
values=('Default key bindings', 'Emacs key bindings'))
key_bindings.bind(text=self._bindings_selected)
menu.add_widget(mnu_file)
menu.add_widget(fnt_size)
menu.add_widget(fnt_name)
menu.add_widget(languages)
menu.add_widget(key_bindings)
b.add_widget(menu)
self.codeinput = CodeInputWithBindings(
lexer=KivyLexer(),
font_size=12,
text=example_text,
key_bindings='default',
)
b.add_widget(self.codeinput)
return b
def _update_size(self, instance, size):
self.codeinput.font_size = float(size)
def _update_font(self, instance, fnt_name):
instance.font_name = self.codeinput.font_name = fnt_name
def _file_menu_selected(self, instance, value):
if value == 'File':
return
instance.text = 'File'
if value == 'Open':
if not hasattr(self, 'load_dialog'):
self.load_dialog = LoadDialog()
self.load_dialog.open()
self.load_dialog.bind(choosen_file=self.setter('files'))
elif value == 'SaveAs':
if not hasattr(self, 'saveas_dialog'):
self.saveas_dialog = SaveDialog()
self.saveas_dialog.text = self.codeinput.text
self.saveas_dialog.open()
elif value == 'Save':
if self.files[0]:
_file = codecs.open(self.files[0], 'w', encoding='utf8')
_file.write(self.codeinput.text)
_file.close()
elif value == 'Close':
if self.files[0]:
self.codeinput.text = ''
Window.title = 'untitled'
def _bindings_selected(self, instance, value):
value = value.split(' ')[0]
self.codeinput.key_bindings = value.lower()
def on_files(self, instance, values):
if not values[0]:
return
_file = codecs.open(values[0], 'r', encoding='utf8')
self.codeinput.text = _file.read()
_file.close()
def change_lang(self, instance, z):
if z == 'KvLexer':
lx = KivyLexer()
else:
lx = lexers.get_lexer_by_name(lexers.LEXERS[z][2][0])
self.codeinput.lexer = lx
if __name__ == '__main__':
CodeInputTest().run()

View file

@ -0,0 +1,53 @@
#:import os os
<Fnt_SpinnerOption>:
font_name: self.text
<LoadDialog>:
title: filechooser.path
choosen_file: None
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
path: os.getcwd()
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Load"
on_release: root.load(filechooser.path, filechooser.selection)
<SaveDialog>:
text_input: text_input
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
path: os.getcwd()
on_selection: text_input.text = self.selection and self.selection[0] or ''
TextInput:
id: text_input
size_hint_y: None
height: 30
multiline: False
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Save"
on_release: root.save(filechooser.path, text_input.text)

View file

@ -0,0 +1,234 @@
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scatter import Scatter
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty, StringProperty
from kivy.graphics import Color, Point, GraphicException
from math import sqrt
from os import walk
from os.path import dirname, join
from kivy.lang import Builder
Builder.load_string('''
#:import os os
<Picture>:
# each time a picture is created, the image can delay the loading
# as soon as the image is loaded, ensure that the center is changed
# to the center of the screen.
on_size: self.center = app.main_root_widget.center
size: img.size
size_hint: None, None
on_touch_down: if self.collide_point(*args[1].pos): app.current_image = img
Image:
id: img
source: root.source
# create initial image to be 400 pixels width
size: 400, 400 / self.image_ratio
# add shadow background
canvas.before:
Color:
rgba: 1, 1, 1, 1
BorderImage:
source: '../demo/pictures/shadow32.png'
border: (36, 36, 36, 36)
size:(self.width + 72, self.height + 72)
pos: (-36, -36)
<ColorSelector>:
color: 1, 1, 1, 1
title: 'Color Slector'
content:content
BoxLayout:
id: content
orientation: 'vertical'
ColorPicker:
id: clr_picker
color: root.color
BoxLayout:
size_hint_y: None
height: '27sp'
Button:
text: 'ok'
on_release:
root.color = clr_picker.color
root.dismiss()
Button:
text: 'cancel'
on_release: root.dismiss()
<LeftPanel@BoxLayout>
orientation: 'vertical'
padding: '2pt'
canvas.before:
Color:
rgba: .5, .4, .9, .2
Rectangle:
pos: self.pos
size: self.size
Label:
size_hint_y: None
font_size: '18sp'
text_size: self.width, None
valign: 'middle'
halign: 'center'
height: self.texture.size[1] if self.texture else 10
text:
("Selected Image:\\n" + app.current_image.source.split(os.sep)[-1]
if app.current_image else 'None')
Button:
text: 'Brush'
size_hint_y: None
height: self.parent.width
on_release:
app.color_selector.open()
app.color_mode = 'brush'
Image:
color: app.color_selector.color
source: '../demo/touchtracer/particle.png'
fit_mode: "contain"
size: self.parent.size
pos: self.parent.pos
Button:
text: 'cursor'
on_release: app.color_mode = 'cursor'
Button:
text: 'clear'
on_release:
app.handle_clear()
<MainRootWidget>
current_image: None
client_area: client_area
RelativeLayout:
id: client_area
Splitter:
sizable_from: 'left'
size_hint: None, 1
width: '99dp'
LeftPanel:
''')
def calculate_points(x1, y1, x2, y2, steps=5):
dx = x2 - x1
dy = y2 - y1
dist = sqrt(dx * dx + dy * dy)
if dist < steps:
return
o = []
m = dist / steps
for i in range(1, int(m)):
mi = i / m
lastx = x1 + dx * mi
lasty = y1 + dy * mi
o.extend([lastx, lasty])
return o
class ColorSelector(Popup):
pass
class Picture(Scatter):
source = StringProperty(None)
'''path to the Image to be loaded
'''
def __init__(self, **kwargs):
super(Picture, self).__init__(**kwargs)
self._app = App.get_running_app()
def on_touch_down(self, touch):
_app = self._app
if (_app.color_mode[0] == 'c' or
not self.collide_point(*touch.pos)):
return super(Picture, self).on_touch_down(touch)
ud = touch.ud
ud['group'] = g = str(touch.uid)
_pos = list(self.ids.img.to_widget(*touch.pos))
_pos[0] += self.parent.x
with self.ids.img.canvas.after:
ud['color'] = Color(*_app.color_selector.color, group=g)
ud['lines'] = Point(points=(_pos),
source='../demo/touchtracer/particle.png',
pointsize=5, group=g)
touch.grab(self)
return True
def on_touch_move(self, touch):
if touch.grab_current is not self:
return
_app = self._app
if _app.color_mode[0] == 'c' or not self.collide_point(*touch.pos):
return super(Picture, self).on_touch_move(touch)
ud = touch.ud
_pos = list(self.ids.img.to_widget(*touch.pos))
_pos[0] += self.parent.x
points = ud['lines'].points
oldx, oldy = points[-2], points[-1]
points = calculate_points(oldx, oldy, _pos[0], _pos[1])
if points:
try:
lp = ud['lines'].add_point
for idx in range(0, len(points), 2):
lp(points[idx], points[idx + 1])
except GraphicException:
pass
def on_touch_up(self, touch):
if touch.grab_current is not self:
return
_app = self._app
if _app.color_mode[0] == 'c':
return super(Picture, self).on_touch_up(touch)
touch.ungrab(self)
ud = touch.ud
self.canvas.remove_group(ud['group'])
class MainRootWidget(BoxLayout):
clent_area = ObjectProperty(None)
# The Client Area in which all editing is Done
def on_parent(self, instance, parent):
if parent:
_dir = join(dirname(__file__), '../demo/pictures/images/')
for image in list(walk(_dir))[0][2]:
if image.find('jpg') > -1:
self.client_area.add_widget(Picture(source=_dir + image))
class MainApp(App):
main_root_widget = ObjectProperty(None)
# we will be accessing this later as App.main_root_widget
current_image = ObjectProperty(None)
'''This is a handle to the currently selected image on which the effects
would be applied.'''
color_mode = StringProperty('cursor')
'''This defines the current mode `brush` or `cursor`. `brush` mode allows
adding brush strokes to the currently selected Image.
'''
def build(self):
self.color_selector = ColorSelector()
self.main_root_widget = MainRootWidget()
return self.main_root_widget
def handle_clear(self):
if self.current_image:
self.current_image.canvas.after.clear()
if __name__ == '__main__':
MainApp().run()

View file

@ -0,0 +1,62 @@
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
Builder.load_string("""
#:import hex kivy.utils.get_color_from_hex
<Root>:
cols: 2
canvas:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
Label:
canvas.before:
Color:
rgb: 39/255., 174/255., 96/255.
Rectangle:
pos: self.pos
size: self.size
text: "rgb: 39/255., 174/255., 96/255."
Label:
canvas.before:
Color:
rgba: 39/255., 174/255., 96/255., 1
Rectangle:
pos: self.pos
size: self.size
text: "rgba: 39/255., 174/255., 96/255., 1"
Label:
canvas.before:
Color:
hsv: 145/360., 77.6/100, 68.2/100
Rectangle:
pos: self.pos
size: self.size
text: "hsv: 145/360., 77.6/100, 68.2/100"
Label:
canvas.before:
Color:
rgba: hex('#27ae60')
Rectangle:
pos: self.pos
size: self.size
text: "rgba: hex('#27ae60')"
""")
class Root(GridLayout):
pass
class ColorusageApp(App):
def build(self):
return Root()
if __name__ == "__main__":
ColorusageApp().run()

View file

@ -0,0 +1,83 @@
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.behaviors import CompoundSelectionBehavior
from kivy.uix.behaviors import FocusBehavior
from kivy.app import runTouchApp
class SelectableGrid(FocusBehavior, CompoundSelectionBehavior, GridLayout):
def __init__(self, **kwargs):
super(SelectableGrid, self).__init__(**kwargs)
def print_selection(*l):
print('selected: ', [x.text for x in self.selected_nodes])
self.bind(selected_nodes=print_selection)
def keyboard_on_key_down(self, window, keycode, text, modifiers):
if super(SelectableGrid, self).keyboard_on_key_down(
window, keycode, text, modifiers):
return True
if self.select_with_key_down(window, keycode, text, modifiers):
return True
return False
def keyboard_on_key_up(self, window, keycode):
if super(SelectableGrid, self).keyboard_on_key_up(window, keycode):
return True
if self.select_with_key_up(window, keycode):
return True
return False
def goto_node(self, key, last_node, last_node_idx):
''' This function is used to go to the node by typing the number
of the text of the button.
'''
node, idx = super(SelectableGrid, self).goto_node(key, last_node,
last_node_idx)
if node != last_node:
return node, idx
items = list(enumerate(self.get_selectable_nodes()))
'''If self.nodes_order_reversed (the default due to using
self.children which is reversed), the index is counted from the
starts of the selectable nodes, like normal but the nodes are traversed
in the reverse order.
'''
# start searching after the last selected node
if not self.nodes_order_reversed:
items = items[last_node_idx + 1:] + items[:last_node_idx + 1]
else:
items = items[:last_node_idx][::-1] + items[last_node_idx:][::-1]
for i, child in items:
if child.text.startswith(key):
return child, i
return node, idx
def select_node(self, node):
node.background_color = (1, 0, 0, 1)
return super(SelectableGrid, self).select_node(node)
def deselect_node(self, node):
node.background_color = (1, 1, 1, 1)
super(SelectableGrid, self).deselect_node(node)
def do_touch(self, instance, touch):
if ('button' in touch.profile and touch.button in
('scrollup', 'scrolldown', 'scrollleft', 'scrollright')) or\
instance.collide_point(*touch.pos):
self.select_with_touch(instance, touch)
else:
return False
return True
root = SelectableGrid(cols=5, up_count=5, multiselect=True, scroll_count=1)
for i in range(40):
c = Button(text=str(i))
c.bind(on_touch_down=root.do_touch)
root.add_widget(c)
runTouchApp(root)

View file

@ -0,0 +1,82 @@
'''
Custom shape & collide widget
=============================
This is a Triangle widget with a triangle shape based on 3 points (p1, p2, p3),
plus a custom collision function.
The p1, p2, p3 are automatically calculated from the position and the size of
the Widget bounding box. We are using them to draw the triangle shape.
(Please note in the kv the special case for Scatter.)
Then we need to setup a new collision function to collide only on the triangle.
We are using a external method that will check if a point is inside a polygon
(we consider our triangle as a polygon).
'''
import kivy
kivy.require('1.0.8')
from kivy.uix.scatter import Scatter
from kivy.properties import ListProperty
from kivy.lang import Builder
Builder.load_string('''
<Triangle>:
# example for doing a triangle
# this will automatically recalculate pX from pos/size
p1: 0, 0
p2: self.width, 0
p3: self.width / 2, self.height
# If you use a Widget instead of Scatter as base class, you need that:
#p1: self.pos
#p2: self.right, self.y
#p3: self.center_x, self.top
# draw something
canvas:
Color:
rgb: 1, 0, 0
Triangle:
points: self.p1 + self.p2 + self.p3
''')
def point_inside_polygon(x, y, poly):
'''Taken from http://www.ariel.com.au/a/python-point-int-poly.html
'''
n = len(poly)
inside = False
p1x = poly[0]
p1y = poly[1]
for i in range(0, n + 2, 2):
p2x = poly[i % n]
p2y = poly[(i + 1) % n]
if y > min(p1y, p2y):
if y <= max(p1y, p2y):
if x <= max(p1x, p2x):
if p1y != p2y:
xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
if p1x == p2x or x <= xinters:
inside = not inside
p1x, p1y = p2x, p2y
return inside
class Triangle(Scatter):
p1 = ListProperty([0, 0])
p2 = ListProperty([0, 0])
p3 = ListProperty([0, 0])
def collide_point(self, x, y):
x, y = self.to_local(x, y)
return point_inside_polygon(x, y,
self.p1 + self.p2 + self.p3)
if __name__ == '__main__':
from kivy.base import runTouchApp
runTouchApp(Triangle(size_hint=(None, None)))

View file

@ -0,0 +1,193 @@
'''
Example usage of the effectwidget.
Currently highly experimental.
'''
from kivy.app import App
from kivy.uix.effectwidget import EffectWidget
from kivy.uix.spinner import Spinner
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.effectwidget import (MonochromeEffect,
InvertEffect,
ChannelMixEffect,
ScanlinesEffect,
FXAAEffect,
PixelateEffect,
HorizontalBlurEffect,
VerticalBlurEffect)
class ComparisonWidget(EffectWidget):
pass
class EffectSpinner(Spinner):
pass
class SpinnerRow(BoxLayout):
effectwidget = ObjectProperty()
def update_effectwidget(self, *args):
effects = []
for child in self.children[::-1]:
text = child.text
if text == 'none':
pass
if text == 'fxaa':
effects.append(FXAAEffect())
if text == 'monochrome':
effects.append(MonochromeEffect())
if text == 'invert':
effects.append(InvertEffect())
if text == 'mix':
effects.append(ChannelMixEffect())
if text == 'blur_h':
effects.append(HorizontalBlurEffect())
if text == 'blur_v':
effects.append(VerticalBlurEffect())
if text == 'postprocessing':
effects.append(ScanlinesEffect())
if text == 'pixelate':
effects.append(PixelateEffect())
if self.effectwidget:
self.effectwidget.effects = effects
example = Builder.load_string('''
#:import Vector kivy.vector.Vector
BoxLayout:
orientation: 'vertical'
FloatLayout:
ComparisonWidget:
pos_hint: {'x': 0, 'y': 0}
size_hint: 0.5, 1
id: effect1
ComparisonWidget:
pos_hint: {'x': pos_slider.value, 'y': 0}
size_hint: 0.5, 1
id: effect2
background_color: (rs.value, gs.value, bs.value, als.value)
SpinnerRow:
effectwidget: effect1
text: 'left effects'
SpinnerRow:
effectwidget: effect2
text: 'right effects'
BoxLayout:
size_hint_y: None
height: sp(40)
Label:
text: 'control overlap:'
Slider:
min: 0
max: 0.5
value: 0.5
id: pos_slider
BoxLayout:
size_hint_y: None
height: sp(40)
Label:
text: 'right bg r,g,b,a'
Slider:
min: 0
max: 1
value: 0
id: rs
Slider:
min: 0
max: 1
value: 0
id: gs
Slider:
min: 0
max: 1
value: 0
id: bs
Slider:
min: 0
max: 1
value: 0
id: als
<ComparisonWidget>:
Widget:
canvas:
Color:
rgba: 1, 0, 0, 1
Ellipse:
pos: Vector(self.pos) + 0.5*Vector(self.size)
size: 0.4*Vector(self.size)
Color:
rgba: 0, 1, 0.3, 1
Ellipse:
pos: Vector(self.pos) + 0.1*Vector(self.size)
size: 0.6*Vector(self.size)
Color:
rgba: 0.5, 0.3, 0.8, 1
Ellipse:
pos: Vector(self.pos) + Vector([0, 0.6])*Vector(self.size)
size: 0.4*Vector(self.size)
Color:
rgba: 1, 0.8, 0.1, 1
Ellipse:
pos: Vector(self.pos) + Vector([0.5, 0])*Vector(self.size)
size: 0.4*Vector(self.size)
Color:
rgba: 0, 0, 0.8, 1
Line:
points:
[self.x, self.y,
self.x + self.width, self.y + 0.3*self.height,
self.x + 0.2*self.width, self.y + 0.1*self.height,
self.x + 0.85*self.width, self.y + 0.72*self.height,
self.x + 0.31*self.width, self.y + 0.6*self.height,
self.x, self.top]
width: 1
Color:
rgba: 0, 0.9, 0.1, 1
Line:
points:
[self.x + self.width, self.y + self.height,
self.x + 0.35*self.width, self.y + 0.6*self.height,
self.x + 0.7*self.width, self.y + 0.15*self.height,
self.x + 0.2*self.width, self.y + 0.22*self.height,
self.x + 0.3*self.width, self.y + 0.92*self.height]
width: 2
<SpinnerRow>:
orientation: 'horizontal'
size_hint_y: None
height: dp(40)
text: ''
Label:
text: root.text
EffectSpinner:
on_text: root.update_effectwidget()
EffectSpinner:
on_text: root.update_effectwidget()
EffectSpinner:
on_text: root.update_effectwidget()
<EffectSpinner>:
text: 'none'
values:
['none', 'fxaa', 'monochrome',
'invert', 'mix',
'blur_h', 'blur_v',
'postprocessing', 'pixelate',]
''')
class EffectApp(App):
def build(self):
return example
EffectApp().run()

View file

@ -0,0 +1,47 @@
'''
This is an example of creating your own effect by writing a glsl string.
'''
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.effectwidget import EffectWidget, EffectBase
# The effect string is glsl code defining an effect function.
effect_string = '''
vec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)
{
// Note that time is a uniform variable that is automatically
// provided to all effects.
float red = color.x * abs(sin(time*2.0));
float green = color.y; // No change
float blue = color.z * (1.0 - abs(sin(time*2.0)));
return vec4(red, green, blue, color.w);
}
'''
class DemoEffect(EffectWidget):
def __init__(self, *args, **kwargs):
self.effect_reference = EffectBase(glsl=effect_string)
super(DemoEffect, self).__init__(*args, **kwargs)
widget = Builder.load_string('''
DemoEffect:
effects: [self.effect_reference] if checkbox.active else []
orientation: 'vertical'
Button:
text: 'Some text so you can see what happens.'
BoxLayout:
size_hint_y: None
height: dp(50)
Label:
text: 'Enable effect?'
CheckBox:
id: checkbox
active: True
''')
runTouchApp(widget)

View file

@ -0,0 +1,62 @@
'''
This example demonstrates creating and using an AdvancedEffectBase. In
this case, we use it to efficiently pass the touch coordinates into the shader.
'''
from kivy.base import runTouchApp
from kivy.properties import ListProperty
from kivy.lang import Builder
from kivy.uix.effectwidget import EffectWidget, AdvancedEffectBase
effect_string = '''
uniform vec2 touch;
vec4 effect(vec4 color, sampler2D texture, vec2 tex_coords, vec2 coords)
{
vec2 distance = 0.025*(coords - touch);
float dist_mag = (distance.x*distance.x + distance.y*distance.y);
vec3 multiplier = vec3(abs(sin(dist_mag - time)));
return vec4(multiplier * color.xyz, 1.0);
}
'''
class TouchEffect(AdvancedEffectBase):
touch = ListProperty([0.0, 0.0])
def __init__(self, *args, **kwargs):
super(TouchEffect, self).__init__(*args, **kwargs)
self.glsl = effect_string
self.uniforms = {'touch': [0.0, 0.0]}
def on_touch(self, *args, **kwargs):
self.uniforms['touch'] = [float(i) for i in self.touch]
class TouchWidget(EffectWidget):
def __init__(self, *args, **kwargs):
super(TouchWidget, self).__init__(*args, **kwargs)
self.effect = TouchEffect()
self.effects = [self.effect]
def on_touch_down(self, touch):
super(TouchWidget, self).on_touch_down(touch)
self.on_touch_move(touch)
def on_touch_move(self, touch):
self.effect.touch = touch.pos
root = Builder.load_string('''
TouchWidget:
Button:
text: 'Some text!'
Image:
source: 'data/logo/kivy-icon-512.png'
fit_mode: "fill"
''')
runTouchApp(root)

View file

@ -0,0 +1,111 @@
'''
FBO example
===========
This is an example of how to use FBO (Frame Buffer Object) to speedup graphics.
An Fbo is like a texture that you can draw on it.
By default, all the children are added in the canvas of the parent.
When you are displaying thousand of widget, you'll do thousands of graphics
instructions each frame.
The idea is to do this drawing only one time in a Fbo, and then, draw the Fbo
every frame instead of all children's graphics instructions.
We created a FboFloatLayout that create his canvas, and a Fbo.
After the Fbo is created, we are adding Color and Rectangle instruction to
display the texture of the Fbo itself.
The overload of on_pos/on_size are here to update size of Fbo if needed, and
adapt the position/size of the rectangle too.
Then, when a child is added or removed, we are redirecting addition/removal of
graphics instruction to our Fbo. This is why add_widget/remove_widget are
overloaded too.
.. note::
This solution can be helpful but not ideal. Multisampling are not available
in Framebuffer. We will work to add the support of it if the hardware is
capable of, but it could be not the same.
'''
# needed to create Fbo, must be resolved in future kivy version
from kivy.core.window import Window
from kivy.graphics import Color, Rectangle, Canvas
from kivy.graphics.fbo import Fbo
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
class FboFloatLayout(FloatLayout):
texture = ObjectProperty(None, allownone=True)
def __init__(self, **kwargs):
self.canvas = Canvas()
with self.canvas:
self.fbo = Fbo(size=self.size)
Color(1, 1, 1)
self.fbo_rect = Rectangle()
# wait that all the instructions are in the canvas to set texture
self.texture = self.fbo.texture
super(FboFloatLayout, self).__init__(**kwargs)
def add_widget(self, *args, **kwargs):
# trick to attach graphics instruction to fbo instead of canvas
canvas = self.canvas
self.canvas = self.fbo
ret = super(FboFloatLayout, self).add_widget(*args, **kwargs)
self.canvas = canvas
return ret
def remove_widget(self, *args, **kwargs):
canvas = self.canvas
self.canvas = self.fbo
super(FboFloatLayout, self).remove_widget(*args, **kwargs)
self.canvas = canvas
def on_size(self, instance, value):
self.fbo.size = value
self.texture = self.fbo.texture
self.fbo_rect.size = value
def on_pos(self, instance, value):
self.fbo_rect.pos = value
def on_texture(self, instance, value):
self.fbo_rect.texture = value
if __name__ == '__main__':
from kivy.uix.button import Button
from kivy.app import App
class TestFboApp(App):
def build(self):
# test with FboFloatLayout or FloatLayout
# comment/uncomment to test it
root = FboFloatLayout()
# root = FloatLayout()
# this part of creation can be slow. try to optimize the loop a
# little bit.
s = 30
size = (s, s)
sh = (None, None)
add = root.add_widget
print('Creating 5000 widgets...')
for i in range(5000):
x = (i % 40) * s
y = int(i / 40) * s
add(Button(text=str(i), pos=(x, y), size_hint=sh, size=size))
if i % 1000 == 1000 - 1:
print(5000 - i - 1, 'left...')
return root
TestFboApp().run()

View file

@ -0,0 +1,98 @@
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.behaviors import FocusBehavior
from kivy.graphics import Color, Rectangle
class FocusWithColor(FocusBehavior):
''' Class that when focused, changes its background color to red.
'''
_color = None
_rect = None
def __init__(self, **kwargs):
super(FocusWithColor, self).__init__(**kwargs)
with self.canvas:
self._color = Color(1, 1, 1, .2)
self._rect = Rectangle(size=self.size, pos=self.pos)
self.bind(size=self._update_rect, pos=self._update_rect)
def _update_rect(self, instance, value):
self._rect.pos = instance.pos
self._rect.size = instance.size
def on_focused(self, instance, value, *largs):
self._color.rgba = [1, 0, 0, .2] if value else [1, 1, 1, .2]
class FocusLabel(FocusWithColor, Label):
'''A label, which in addition to turn red when focused, it also sets the
keyboard input to the text of the label.
'''
def keyboard_on_key_down(self, window, keycode, text, modifiers):
'''We call super before doing anything else to enable tab cycling
by FocusBehavior. If we wanted to use tab for ourselves, we could just
not call it, or call it if we didn't need tab.
'''
if super(FocusLabel, self).keyboard_on_key_down(window, keycode,
text, modifiers):
return True
self.text = keycode[1]
return True
class FocusGridLayout(FocusWithColor, GridLayout):
pass
class FocusBoxLayout(FocusWithColor, BoxLayout):
pass
class FocusApp(App):
def build(self):
root = FocusBoxLayout(padding=[10, 10], spacing=10)
self.grid1 = grid1 = FocusGridLayout(cols=4, padding=[10, 10],
spacing=10)
self.grid2 = grid2 = FocusGridLayout(cols=4, padding=[10, 10],
spacing=10)
root.add_widget(FocusLabel(text='Left', size_hint_x=0.4))
root.add_widget(grid1)
root.add_widget(grid2)
root.add_widget(FocusLabel(text='Right', size_hint_x=0.4))
for i in range(40):
grid1.add_widget(FocusLabel(text='l' + str(i)))
for i in range(40):
grid2.add_widget(FocusLabel(text='r' + str(i)))
# make elements 29, 9 un-focusable. The widgets are displayed in
# reverse order, so 9 = 39 - 10
grid2.children[30].text = grid1.children[14].text =\
grid2.children[15].text = grid1.children[34].text = 'Skip me'
grid2.children[15].is_focusable = False
grid2.children[30].is_focusable = False
# similarly, make 39 - 14 = 25, and 5 un-focusable
grid1.children[14].is_focusable = False
grid1.children[34].is_focusable = False
# don't move focus passed this element
grid2.children[35].focus_next = StopIteration
grid2.children[35].text = 'Stop forward'
# exchange the links between the sides so that it'll skip to the other
# side in the middle. Remember that children are displayed reversed
# in layouts.
grid1.children[10].focus_next = grid2.children[9]
grid2.children[10].focus_next = grid1.children[9]
grid1.children[10].text = '-->'
grid2.children[10].text = '<--'
return root
if __name__ == '__main__':
FocusApp().run()

View file

@ -0,0 +1,31 @@
'''
Image mipmap
============
Difference between a mipmapped image and no mipmap image.
The lower image is normal, and the top image is mipmapped.
'''
import kivy
kivy.require('1.0.7')
from kivy.app import App
from kivy.uix.scatter import ScatterPlane
from kivy.uix.image import Image
from os.path import join
class LabelMipmapTest(App):
def build(self):
s = ScatterPlane(scale=.5)
filename = join(kivy.kivy_data_dir, 'logo', 'kivy-icon-256.png')
l1 = Image(source=filename, pos=(400, 100), size=(256, 256))
l2 = Image(source=filename, pos=(400, 356), size=(256, 256),
mipmap=True)
s.add_widget(l1)
s.add_widget(l2)
return s
if __name__ == '__main__':
LabelMipmapTest().run()

View file

@ -0,0 +1,42 @@
import kivy
kivy.require('1.0.8')
from kivy.core.window import Window
from kivy.uix.widget import Widget
class MyKeyboardListener(Widget):
def __init__(self, **kwargs):
super(MyKeyboardListener, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(
self._keyboard_closed, self, 'text')
if self._keyboard.widget:
# If it exists, this widget is a VKeyboard object which you can use
# to change the keyboard layout.
pass
self._keyboard.bind(on_key_down=self._on_keyboard_down)
def _keyboard_closed(self):
print('My keyboard have been closed!')
self._keyboard.unbind(on_key_down=self._on_keyboard_down)
self._keyboard = None
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
print('The key', keycode, 'have been pressed')
print(' - text is %r' % text)
print(' - modifiers are %r' % modifiers)
# Keycode is composed of an integer + a string
# If we hit escape, release the keyboard
if keycode[1] == 'escape':
keyboard.release()
# Return True to accept the key. Otherwise, it will be used by
# the system.
return True
if __name__ == '__main__':
from kivy.base import runTouchApp
runTouchApp(MyKeyboardListener())

View file

@ -0,0 +1,28 @@
'''
Label mipmap
============
This show how to create a mipmapped label, and the visual difference between a
non mipmapped and mipmapped label.
'''
import kivy
kivy.require('1.0.7')
from kivy.app import App
from kivy.uix.scatter import ScatterPlane
from kivy.uix.label import Label
class LabelMipmapTest(App):
def build(self):
s = ScatterPlane(scale=.5)
l1 = Label(text='Kivy rulz', font_size=98, pos=(400, 100), mipmap=True)
l2 = Label(text='Kivy rulz', font_size=98, pos=(400, 328))
s.add_widget(l1)
s.add_widget(l2)
return s
if __name__ == '__main__':
LabelMipmapTest().run()

View file

@ -0,0 +1,193 @@
"""
Label textsize
============
This example shows how to size a Label to its content (texture_size) and how
setting text_size controls text wrapping.
"""
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import StringProperty, NumericProperty, BooleanProperty
# Copied from https://en.wikipedia.org/wiki/A_Tale_of_Two_Cities
# Published in 1859 and public domain.
# The newline after the title will help demonstrate halign
_example_title_text = 'A Tale of Two Cities, by Charles Dickens\n'
_example_text = """It was the best of times, it was the worst of times,
it was the age of wisdom, it was the age of foolishness, it was the epoch of
belief, it was the epoch of incredulity, it was the season of Light, it was
the season of Darkness, it was the spring of hope, it was the winter of
despair, we had everything before us, we had nothing before us, we were all
going direct to Heaven, we were all going direct the other way - in short,
the period was so far like the present period, that some of its noisiest
authorities insisted on its being received, for good or for evil, in the
superlative degree of comparison only.
"""
# Note: Many of the Widgets (StackLayout, ToggleButton, Spinner) have
# defaults set at the bottom of the KV, where DemoLabel and HeadingLabel
# are also defined.
_kv_code = """
BoxLayout:
orientation: 'vertical'
HeadingLabel:
text: 'These modify all demonstration Labels'
StackLayout:
# Button is a subclass of Label and can be sized
# to text in the same way
Button:
text: 'Reset'
on_press: app.reset_words()
ToggleButton:
text: 'Shorten'
on_state:
app.shorten=self.state=='down'
ToggleButton:
text: 'max_lines=3'
on_state:
app.max_lines=3 if self.state=='down' else 0
Spinner:
text: 'bottom'
values: 'bottom', 'middle', 'top'
on_text: app.valign=self.text
Spinner:
text: 'left'
values: 'left', 'center', 'right', 'justify'
on_text: app.halign=self.text
GridLayout:
id: grid_layout
cols: 2
height: cm(6)
size_hint_y: None
HeadingLabel:
text: "Default, no text_size set"
HeadingLabel:
text: 'text_size bound to size'
DemoLabel:
id: left_content
disabled_color: 0, 0, 0, 0
DemoLabel:
id: right_content
text_size: self.size
padding: dp(6), dp(6)
ToggleButton:
text: 'Disable left'
on_state:
left_content.disabled=self.state=='down'
# Need one Widget without size_hint_y: None, so that BoxLayout fills
# available space.
HeadingLabel:
text: 'text_size width set, size bound to texture_size'
text_size: self.size
size_hint_y: 1
DemoLabel:
id: bottom_content
# This Label wraps and expands its height to fit the text because
# only text_size width is set and the Label size binds to texture_size.
text_size: self.width, None
size: self.texture_size
padding: mm(4), mm(4)
size_hint_y: None
# The column heading labels have their width set by the parent,
# but determine their height from the text.
<HeadingLabel@Label>:
bold: True
padding: dp(6), dp(4)
valign: 'bottom'
height: self.texture_size[1]
text_size: self.width, None
size_hint_y: None
<ToggleButton,Button>:
padding: dp(10), dp(8)
size_hint: None, None
size: self.texture_size
# This inherits Button and the modifications above, so reset size
<Spinner>:
size: sp(68), self.texture_size[1]
<DemoLabel@Label>:
halign: app.halign
valign: app.valign
shorten: app.shorten
max_lines: app.max_lines
canvas:
Color:
rgb: 68/255.0, 164/255.0, 201/255.0
Line:
rectangle: self.x, self.y, self.width, self.height
<StackLayout>:
size_hint_y: None
spacing: dp(6)
padding: dp(6), dp(4)
height: self.minimum_height
"""
class LabelTextureSizeExample(App):
# All Labels use these properties, set to Label defaults
valign = StringProperty('bottom')
halign = StringProperty('left')
shorten = BooleanProperty(False)
max_lines = NumericProperty(0)
def build(self):
self._add_word_ev = None
return Builder.load_string(_kv_code)
def on_start(self):
widget_ids = self.root.ids
self.text_content_widgets = (widget_ids.left_content,
widget_ids.right_content,
widget_ids.bottom_content)
self.reset_words()
def reset_words(self):
if self._add_word_ev is not None:
self._add_word_ev.cancel()
self._add_word_ev = None
for content_widget in self.text_content_widgets:
content_widget.text = _example_title_text
# initialize words generator
self.words = (word for word in _example_text.split())
self.add_word()
def add_word(self, dt=None):
try:
word = next(self.words)
except StopIteration:
return
for content_widget in self.text_content_widgets:
content_widget.text += word + ' '
pause_time = 0.03 * len(word)
if word.endswith(','):
pause_time += 0.6
self._add_word_ev = Clock.schedule_once(self.add_word, pause_time)
if __name__ == '__main__':
LabelTextureSizeExample().run()

View file

@ -0,0 +1,49 @@
'''
Label textsize
============
This example shows how the textsize and line_height property are used
to format label widget
'''
import kivy
kivy.require('1.0.7')
from kivy.app import App
from kivy.uix.label import Label
_long_text = ("""Lorem ipsum dolor sit amet, consectetur adipiscing elit. """
"""Phasellus odio nisi, pellentesque molestie adipiscing vitae, aliquam """
"""at tellus. Fusce quis est ornare erat pulvinar elementum ut sed """
"""felis. Donec vel neque mauris. In sit amet nunc sit amet diam dapibus"""
""" lacinia. In sodales placerat mauris, ut euismod augue laoreet at. """
"""Integer in neque non odio fermentum volutpat nec nec nulla. Donec et """
"""risus non mi viverra posuere. Phasellus cursus augue purus, eget """
"""volutpat leo. Phasellus sed dui vitae ipsum mattis facilisis vehicula"""
""" eu justo.\n\n"""
"""Quisque neque dolor, egestas sed venenatis eget, porta id ipsum. Ut """
"""faucibus, massa vitae imperdiet rutrum, sem dolor rhoncus magna, non """
"""lacinia nulla risus non dui. Nulla sit amet risus orci. Nunc libero """
"""justo, interdum eu pulvinar vel, pulvinar et lectus. Phasellus sed """
"""luctus diam. Pellentesque non feugiat dolor. Cras at dolor velit, """
"""gravida congue velit. Aliquam erat volutpat. Nullam eu nunc dui, quis"""
""" sagittis dolor. Ut nec dui eget odio pulvinar placerat. Pellentesque"""
""" mi metus, tristique et placerat ac, pulvinar vel quam. Nam blandit """
"""magna a urna imperdiet molestie. Nullam ut nisi eget enim laoreet """
"""sodales sit amet a felis.\n""")
class LabelTextSizeTest(App):
def build(self):
z = Label(
text=_long_text,
text_size=(600, None),
line_height=1.5
)
return z
if __name__ == '__main__':
LabelTextSizeTest().run()

View file

@ -0,0 +1,21 @@
from kivy.app import App
from kivy.lang import Builder
root = Builder.load_string('''
Label:
text:
('[b]Hello[/b] [color=ff0099]World[/color]\\n'
'[color=ff0099]Hello[/color] [b]World[/b]\\n'
'[b]Hello[/b] [color=ff0099]World[/color]')
markup: True
font_size: '64pt'
''')
class LabelWithMarkup(App):
def build(self):
return root
if __name__ == '__main__':
LabelWithMarkup().run()

View file

@ -0,0 +1,18 @@
# Dynamic kv classes
from kivy.lang import Builder
from kivy.base import runTouchApp
root = Builder.load_string('''
<ImageButton@Button>:
source: None
Image:
source: root.source
center: root.center
ImageButton:
source: 'kivy/data/logo/kivy-icon-512.png'
''')
runTouchApp(root)

View file

@ -0,0 +1,64 @@
from kivy.base import runTouchApp
from kivy.lang import Builder
kv = '''
PageLayout:
BoxLayout:
canvas:
Color:
rgba: 216/255., 195/255., 88/255., 1
Rectangle:
pos: self.pos
size: self.size
orientation: 'vertical'
Label:
size_hint_y: None
height: 1.5 * self.texture_size[1]
text: 'page 1'
Button:
text: 'test'
on_press: print("test")
BoxLayout:
orientation: 'vertical'
canvas:
Color:
rgba: 109/255., 8/255., 57/255., 1
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'page 2'
AsyncImage:
source: 'http://kivy.org/logos/kivy-logo-black-64.png'
GridLayout:
canvas:
Color:
rgba: 37/255., 39/255., 30/255., 1
Rectangle:
pos: self.pos
size: self.size
cols: 2
Label:
text: 'page 3'
AsyncImage:
source: 'http://kivy.org/slides/kivyandroid-thumb.jpg'
Button:
text: 'test'
on_press: print("test last page")
AsyncImage:
source: 'http://kivy.org/slides/kivypictures-thumb.jpg'
Widget
AsyncImage:
source: 'http://kivy.org/slides/particlepanda-thumb.jpg'
'''
if __name__ == '__main__':
runTouchApp(Builder.load_string(kv))

View file

@ -0,0 +1,35 @@
'''
Example to show a Popup usage with the content from kv lang.
'''
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<CustomPopup>:
size_hint: .5, .5
auto_dismiss: False
title: 'Hello world'
Button:
text: 'Click me to dismiss'
on_press: root.dismiss()
''')
class CustomPopup(Popup):
pass
class TestApp(App):
def build(self):
b = Button(on_press=self.show_popup, text="Show Popup")
return b
def show_popup(self, b):
p = CustomPopup()
p.open()
TestApp().run()

View file

@ -0,0 +1,124 @@
from random import sample, randint
from string import ascii_lowercase
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
kv = """
<Row@RecycleKVIDsDataViewBehavior+BoxLayout>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Label:
id: name
Label:
text: root.value
<Test>:
canvas:
Color:
rgba: 0.3, 0.3, 0.3, 1
Rectangle:
size: self.size
pos: self.pos
rv: rv
orientation: 'vertical'
GridLayout:
cols: 3
rows: 2
size_hint_y: None
height: dp(108)
padding: dp(8)
spacing: dp(16)
Button:
text: 'Populate list'
on_press: root.populate()
Button:
text: 'Sort list'
on_press: root.sort()
Button:
text: 'Clear list'
on_press: root.clear()
BoxLayout:
spacing: dp(8)
Button:
text: 'Insert new item'
on_press: root.insert(new_item_input.text)
TextInput:
id: new_item_input
size_hint_x: 0.6
hint_text: 'value'
padding: dp(10), dp(10), 0, 0
BoxLayout:
spacing: dp(8)
Button:
text: 'Update first item'
on_press: root.update(update_item_input.text)
TextInput:
id: update_item_input
size_hint_x: 0.6
hint_text: 'new value'
padding: dp(10), dp(10), 0, 0
Button:
text: 'Remove first item'
on_press: root.remove()
RecycleView:
id: rv
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'Row'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(2)
"""
Builder.load_string(kv)
class Test(BoxLayout):
def populate(self):
self.rv.data = [
{'name.text': ''.join(sample(ascii_lowercase, 6)),
'value': str(randint(0, 2000))}
for x in range(50)]
def sort(self):
self.rv.data = sorted(self.rv.data, key=lambda x: x['name.text'])
def clear(self):
self.rv.data = []
def insert(self, value):
self.rv.data.insert(0, {
'name.text': value or 'default value', 'value': 'unknown'})
def update(self, value):
if self.rv.data:
self.rv.data[0]['name.text'] = value or 'default new value'
self.rv.refresh_from_data()
def remove(self):
if self.rv.data:
self.rv.data.pop(0)
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
TestApp().run()

View file

@ -0,0 +1,143 @@
"""
A constantly appending log, using recycleview.
- use variable size widgets using the key_size property to cache texture_size
- keeps current position in scroll when new data is happened, unless the view
is at the very bottom, in which case it follows the log
- works well with mouse scrolling, but less nicely when using swipes,
improvements welcome.
"""
from random import sample
from string import printable
from time import asctime
from kivy.app import App
from kivy.uix.recycleview import RecycleView
from kivy.lang import Builder
from kivy.properties import NumericProperty, ListProperty
from kivy.clock import Clock
KV = """
#:import rgba kivy.utils.rgba
<LogLabel@RelativeLayout>:
# using a boxlayout here allows us to have better control of the text
# position
text: ''
index: None
Label:
y: 0
x: 5
size_hint: None, None
size: self.texture_size
padding: dp(5), dp(5)
color: rgba("#3f3e36")
text: root.text
on_texture_size: app.update_size(root.index, self.texture_size)
canvas.before:
Color:
rgba: rgba("#dbeeff")
RoundedRectangle:
pos: self.pos
size: self.size
radius: dp(5), dp(5)
BoxLayout:
orientation: 'vertical'
spacing: dp(2)
# a label to help understand what's happening with the scrolling
Label:
size_hint_y: None
height: self.texture_size[1]
text:
'''height: {height}
scrollable_distance: {scrollable_distance}
distance_to_top: {distance_to_top}
scroll_y: {scroll_y}
'''.format(
height=rv.height,
scrollable_distance=rv.scrollable_distance,
distance_to_top=rv.distance_to_top,
scroll_y=rv.scroll_y,
)
canvas.before:
Color:
rgba: rgba("#77b4ff")
RoundedRectangle:
pos: self.pos
size: self.size
radius: dp(5), dp(5)
FixedRecycleView:
id: rv
data: app.data
viewclass: 'LogLabel'
scrollable_distance: box.height - self.height
RecycleBoxLayout:
id: box
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
default_size: 0, 48
default_size_hint: 1, None
spacing: dp(1)
key_size: 'cached_size'
"""
class FixedRecycleView(RecycleView):
distance_to_top = NumericProperty()
scrollable_distance = NumericProperty()
def on_scrollable_distance(self, *args):
"""This method maintains the position in scroll, by using the saved
distance_to_top property to adjust the scroll_y property. Only if we
are currently scrolled back.
"""
if self.scroll_y > 0:
self.scroll_y = (
(self.scrollable_distance - self.distance_to_top)
/ self.scrollable_distance
)
def on_scroll_y(self, *args):
"""Save the distance_to_top everytime we scroll.
"""
self.distance_to_top = (1 - self.scroll_y) * self.scrollable_distance
class Application(App):
data = ListProperty()
def build(self):
Clock.schedule_interval(self.add_log, .1)
return Builder.load_string(KV)
def add_log(self, dt):
"""Produce random text to append in the log, with the date, we don't
want to forget when we babbled incoherently.
"""
self.data.append({
'index': len(self.data),
'text': f"[{asctime()}]: {''.join(sample(printable, 50))}",
'cached_size': (0, 0)
})
def update_size(self, index, size):
"""Maintain the size data for a log entry, so recycleview can adjust
the size computation.
As a log entry needs to be displayed to compute its size, it's by
default considered to be (0, 0) which is a good enough approximation
for such a small widget, but you might want do give a better default
value if that doesn't fit your needs.
"""
self.data[index]['cached_size'] = size
if __name__ == '__main__':
Application().run()

View file

@ -0,0 +1,149 @@
'''
A form generator, using random data, but can be data driven (json or whatever)
Shows that you can use the key_viewclass attribute of RecycleView to select a
different Widget for each item.
'''
from random import choice, choices
from string import ascii_lowercase
from kivy.app import App
from kivy.lang import Builder
from kivy import properties as P
KV = r'''
<RVTextInput,RVCheckBox,RVSpinner>:
size_hint_y: None
height: self.minimum_height
index: None
title: ''
<RVTextInput@BoxLayout>:
value: ''
Label:
text: root.title
size_hint_y: None
height: self.texture_size[1]
TextInput:
text: root.value
on_text: app.handle_update(self.text, root.index)
size_hint_y: None
height: dp(40)
multiline: False
<RVCheckBox@BoxLayout>:
value: False
Label:
text: root.title
size_hint_y: None
height: self.texture_size[1]
CheckBox:
active: root.value
on_active: app.handle_update(self.active, root.index)
size_hint_y: None
height: dp(40)
<RVSpinner@BoxLayout>:
value: ''
values: []
Label:
text: root.title
size_hint_y: None
height: self.texture_size[1]
Spinner:
text: root.value
values: root.values
size_hint_y: None
height: dp(40)
on_text: app.handle_update(self.text, root.index)
FloatLayout:
RecycleView:
id: rv
data: app.data
key_viewclass: 'widget'
size_hint_x: 1
RecycleBoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
default_size_hint: 1, None
'''
class Application(App):
'''A form manager demonstrating the power of RecycleView's key_viewclass
property.
'''
data = P.ListProperty()
def build(self):
root = Builder.load_string(KV)
rv = root.ids.rv
self.data = [
self.create_random_input(rv, index)
for index in range(20)
]
return root
def handle_update(self, value, index):
if None not in (index, value):
self.data[index]['value'] = value
def create_random_input(self, rv, index):
return choice((
self.create_textinput,
self.create_checkbox,
self.create_spinner
))(rv, index)
def create_spinner(self, rv, index):
"""
create a dict of data for a spinner
"""
return {
'index': index,
'widget': 'RVSpinner',
'value': '',
'values': [
letter * 5
for letter in ascii_lowercase[:5]
],
'ready': True,
}
def create_checkbox(self, rv, index):
"""
create a dict of data for a checkbox
"""
return {
'index': index,
'widget': 'RVCheckBox',
'value': choice((True, False)),
'title': ''.join(choices(ascii_lowercase, k=10)),
'ready': True,
}
def create_textinput(self, rv, index):
"""
create a dict of data for a textinput
"""
return {
'index': index,
'widget': 'RVTextInput',
'value': ''.join(choices(ascii_lowercase, k=10)),
'title': ''.join(choices(ascii_lowercase, k=10)),
'ready': True,
}
if __name__ == "__main__":
Application().run()

View file

@ -0,0 +1,196 @@
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.properties import ListProperty
from kivy.animation import Animation
from kivy.metrics import dp
KV = '''
#:import RGBA kivy.utils.rgba
<ImageButton@ButtonBehavior+Image>:
size_hint: None, None
size: self.texture_size
canvas.before:
PushMatrix
Scale:
origin: self.center
x: .75 if self.state == 'down' else 1
y: .75 if self.state == 'down' else 1
canvas.after:
PopMatrix
BoxLayout:
orientation: 'vertical'
padding: dp(5), dp(5)
RecycleView:
id: rv
data: app.messages
viewclass: 'Message'
do_scroll_x: False
RecycleBoxLayout:
id: box
orientation: 'vertical'
size_hint_y: None
size: self.minimum_size
default_size_hint: 1, None
# magic value for the default height of the message
default_size: 0, 38
key_size: '_size'
FloatLayout:
size_hint_y: None
height: 0
Button:
size_hint_y: None
height: self.texture_size[1]
opacity: 0 if not self.height else 1
text:
(
'go to last message'
if rv.height < box.height and rv.scroll_y > 0 else
''
)
pos_hint: {'pos': (0, 0)}
on_release: app.scroll_bottom()
BoxLayout:
size_hint: 1, None
size: self.minimum_size
TextInput:
id: ti
size_hint: 1, None
height: min(max(self.line_height, self.minimum_height), 150)
multiline: False
on_text_validate:
app.send_message(self)
ImageButton:
source: 'data/logo/kivy-icon-48.png'
on_release:
app.send_message(ti)
<Message@FloatLayout>:
message_id: -1
bg_color: '#223344'
side: 'left'
text: ''
size_hint_y: None
_size: 0, 0
size: self._size
text_size: None, None
opacity: min(1, self._size[0])
Label:
text: root.text
padding: 10, 10
size_hint: None, 1
size: self.texture_size
text_size: root.text_size
on_texture_size:
app.update_message_size(
root.message_id,
self.texture_size,
root.width,
)
pos_hint:
(
{'x': 0, 'center_y': .5}
if root.side == 'left' else
{'right': 1, 'center_y': .5}
)
canvas.before:
Color:
rgba: RGBA(root.bg_color)
RoundedRectangle:
size: self.texture_size
radius: dp(5), dp(5), dp(5), dp(5)
pos: self.pos
canvas.after:
Color:
Line:
rounded_rectangle: self.pos + self.texture_size + [dp(5)]
width: 1.01
'''
class MessengerApp(App):
messages = ListProperty()
def build(self):
return Builder.load_string(KV)
def add_message(self, text, side, color):
# create a message for the recycleview
self.messages.append({
'message_id': len(self.messages),
'text': text,
'side': side,
'bg_color': color,
'text_size': [None, None],
})
def update_message_size(self, message_id, texture_size, max_width):
# when the label is updated, we want to make sure the displayed size is
# proper
if max_width == 0:
return
one_line = dp(50) # a bit of hack, YMMV
# if the texture is too big, limit its size
if texture_size[0] >= max_width * 2 / 3:
self.messages[message_id] = {
**self.messages[message_id],
'text_size': (max_width * 2 / 3, None),
}
# if it was limited, but is now too small to be limited, raise the limit
elif texture_size[0] < max_width * 2 / 3 and \
texture_size[1] > one_line:
self.messages[message_id] = {
**self.messages[message_id],
'text_size': (max_width * 2 / 3, None),
'_size': texture_size,
}
# just set the size
else:
self.messages[message_id] = {
**self.messages[message_id],
'_size': texture_size,
}
@staticmethod
def focus_textinput(textinput):
textinput.focus = True
def send_message(self, textinput):
text = textinput.text
textinput.text = ''
self.add_message(text, 'right', '#223344')
self.focus_textinput(textinput)
Clock.schedule_once(lambda *args: self.answer(text), 1)
self.scroll_bottom()
def answer(self, text, *args):
self.add_message('do you really think so?', 'left', '#332211')
def scroll_bottom(self):
rv = self.root.ids.rv
box = self.root.ids.box
if rv.height < box.height:
Animation.cancel_all(rv, 'scroll_y')
Animation(scroll_y=0, t='out_quad', d=.5).start(rv)
if __name__ == '__main__':
MessengerApp().run()

View file

@ -0,0 +1,95 @@
"""Detecting and acting upon "Pull down actions" in a RecycleView
- When using overscroll or being at the to, a "pull down to refresh" message
appears
- if the user pulls down far enough, then a refresh is triggered, which adds
new elements at the top of the list.
"""
from threading import Thread
from time import sleep
from datetime import datetime
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ListProperty, BooleanProperty
from kivy.metrics import dp
from kivy.clock import mainthread
KV = r'''
FloatLayout:
Label:
opacity: 1 if app.refreshing or rv.scroll_y > 1 else 0
size_hint_y: None
pos_hint: {'top': 1}
text: 'Refreshing…' if app.refreshing else 'Pull down to refresh'
RecycleView:
id: rv
data: app.data
viewclass: 'Row'
do_scroll_y: True
do_scroll_x: False
on_scroll_y: app.check_pull_refresh(self, grid)
RecycleGridLayout:
id: grid
cols: 1
size_hint_y: None
height: self.minimum_height
default_size: 0, 36
default_size_hint: 1, None
<Row@Label>:
_id: 0
text: ''
canvas:
Line:
rectangle: self.pos + self.size
width: 0.6
'''
class Application(App):
data = ListProperty([])
refreshing = BooleanProperty()
def build(self):
self.refresh_data()
return Builder.load_string(KV)
def check_pull_refresh(self, view, grid):
"""Check the amount of overscroll to decide if we want to trigger the
refresh or not.
"""
max_pixel = dp(200)
to_relative = max_pixel / (grid.height - view.height)
if view.scroll_y <= 1.0 + to_relative or self.refreshing:
return
self.refresh_data()
def refresh_data(self):
# using a Thread to do a potentially long operation without blocking
# the UI.
self.refreshing = True
Thread(target=self._refresh_data).start()
def _refresh_data(self):
sleep(2)
update_time = datetime.now().strftime("%H:%M:%S")
self.prepend_data([
{'_id': i, 'text': '[{}] hello {}'.format(update_time, i)}
for i in range(len(self.data) + 10, len(self.data), -1)
])
@mainthread
def prepend_data(self, data):
self.data = data + self.data
self.refreshing = False
if __name__ == "__main__":
Application().run()

View file

@ -0,0 +1,109 @@
'''How to use Animation with RecycleView items?
In case you really want to use the Animation class with RecycleView, you'll
likely encounter an issue, as widgets are moved around, they are used to
represent different items, so an animation on a specific item is going to
affect others, and this will lead to really confusing results.
This example works around that by creating a "proxy" widget for the animation,
and, by putting it in the data, allowing the displayed widget to mimic the
animation. As the item always refers to its proxy, whichever widget is used to
display the item will keep in sync with the animation.
'''
from copy import copy
from kivy.app import App
from kivy.clock import triggered
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.animation import Animation
from kivy.uix.button import Button
from kivy.properties import (
ObjectProperty, ListProperty
)
KV = '''
<Item>:
index: None
animation_proxy: None
on_release: app.animate_item(self.index)
RecycleView:
data: app.data
viewclass: 'Item'
RecycleBoxLayout:
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
default_size_hint: 1, None
default_size: 0, dp(40)
'''
class Item(Button):
animation_proxy = ObjectProperty(allownone=True)
_animation_proxy = None
def update_opacity(self, proxy, opacity):
# sync one animated property to the value in the proxy
self.opacity = opacity
def on_animation_proxy(self, *args):
"""When we create an animation proxy for an item, we need to bind to
the animated property to update our own.
"""
if self._animation_proxy:
self._animation_proxy.unbind(opacity=self.update_opacity)
self._animation_proxy = self.animation_proxy
if self.animation_proxy:
# when we are assigned an animation_proxy, sync our properties to
# the animated version.
self.opacity = self.animation_proxy.opacity
self.animation_proxy.bind(opacity=self.update_opacity)
else:
# if we lose our animation proxy, we need to reset the animated
# property to their default values.
self.opacity = 1
class Application(App):
data = ListProperty()
def build(self):
self.data = [
{'index': i, 'text': 'hello {}'.format(i), 'animation_proxy': None}
for i in range(1000)
]
return Builder.load_string(KV)
# the triggered decorator allows delaying the animation until after the
# blue effect on the button is removed, to avoid a flash as widgets gets
# reordered when that happens
@triggered(timeout=0.05)
def animate_item(self, index):
# the animation we actually want to do on the item, note that any
# property animated here needs to be synchronized from the proxy to the
# animated widget (in on_animation_proxy and using methods for each
# animation)
proxy = Widget(opacity=1)
item = copy(self.data[index])
animation = (
Animation(opacity=0, d=.1, t='out_quad')
+ Animation(opacity=1, d=5, t='out_quad')
)
animation.bind(on_complete=lambda *x: self.reset_animation(item))
item['animation_proxy'] = proxy
self.data[index] = item
animation.start(proxy)
def reset_animation(self, item):
# animation is complete, widget should be garbage collected
item['animation_proxy'] = None
if __name__ == "__main__":
Application().run()

View file

@ -0,0 +1,128 @@
'''
QuickReference for Rst
======================
This is a markup example: [b]Hello[/b] [i]world[/i]
And if i really want to write my code: &amp;bl; Hello world &amp;br;
And video widget
----------------
.. video:: cityCC0.mpg
Inline Markup
-------------
- *emphasis*
- **strong emphasis**
- `interpreted text`
- ``inline literal``
- reference_
- `phrase reference`_
- anonymous__
- _`inline internal target`
.. _top:
Internal cross-references, like example_, or bottom_.
Image
-----
Woot!
What about a little image ?
.. image:: kivy/data/logo/kivy-icon-256.png
Grid
----
+------------+------------+-----------+
| Header 1 | Header 2 | Header 3 |
+============+============+===========+
| body row 1 | column 2 | column 3 |
+------------+------------+-----------+
| body row 2 | column 2 | column 3 |
+------------+------------+-----------+
| body row 3 | column 2 | column 3 |
+------------+------------+-----------+
Term list
---------
:Authors:
Tony J. (Tibs) Ibbs,
David Goodger
(and sundry other good-natured folks)
.. _example:
:Version: 1.0 of 2001/08/08
:Dedication: To my father.
Definition list
---------------
what
Definition lists associate a term with a definition.
how
The term is a one-line phrase, and the definition is one or more paragraphs
or body elements, indented relative to the term. Blank lines are not allowed
between term and definition.
Block quotes
------------
Block quotes are just:
Indented paragraphs,
and they may nest.
Admonitions
-----------
.. warning::
This is just a Test.
.. note::
And this is just a note. Let's test some literal::
$ echo 'Hello world'
Hello world
Ordered list
------------
#. My item number one
#. My item number two with some more content
and it's continuing on the second line?
#. My third item::
Oh wait, we can put code!
#. My four item::
No way.
.. _bottom:
Go to top_'''
from kivy.uix.rst import RstDocument
from kivy.app import App
class RstApp(App):
def build(self):
return RstDocument(text=__doc__)
if __name__ == '__main__':
RstApp().run()

View file

@ -0,0 +1,53 @@
#:kivy 1.0
<MyScatter>:
canvas:
Color:
hsv: 0, 1, .5
Rectangle:
size: self.size
canvas.after:
Color:
hsv: .1, 1, .5
a: .2
Rectangle:
pos: self.pos
size: self.bbox[1]
Color:
rgb: 0, 1, 0
Line:
points: [self.x, self.top, self.right, self.top]
Line:
points: [self.x, self.y, self.x, self.top]
Line:
points: [self.center_x, self.y, self.center_x, self.top]
Line:
points: [self.x, self.center_y, self.right, self.center_y]
Line:
points: [self.center[0], self.center[1], self.right, self.top]
BoxLayout:
size: root.size
orientation: 'vertical'
Label:
text: 'Position\n' + str(root.pos)
text_size: (root.width, None)
Label:
text: 'Size\n' + str(root.size)
text_size: (root.width, None)
Label:
text: 'Center\n' + str(root.center)
text_size: (root.width, None)
Label:
text: 'Bounding Box\n' + str(root.bbox)
text_size: (root.width, None)
Label:
text: 'Top\n' + str(root.top)
text_size: (root.width, None)
Label:
text: 'Right\n' + str(root.right)
text_size: (root.width, None)

View file

@ -0,0 +1,16 @@
from kivy.uix.scatter import Scatter
from kivy.app import App
class MyScatter(Scatter):
pass
class ScatterApp(App):
def build(self):
s = MyScatter(size=(400, 400), size_hint=(None, None))
s.top = 500
return s
ScatterApp().run()

View file

@ -0,0 +1,106 @@
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import NumericProperty
from kivy.lang import Builder
Builder.load_string('''
#:import random random.random
#:import SlideTransition kivy.uix.screenmanager.SlideTransition
#:import SwapTransition kivy.uix.screenmanager.SwapTransition
#:import WipeTransition kivy.uix.screenmanager.WipeTransition
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:import RiseInTransition kivy.uix.screenmanager.RiseInTransition
#:import FallOutTransition kivy.uix.screenmanager.FallOutTransition
#:import NoTransition kivy.uix.screenmanager.NoTransition
<CustomScreen>:
hue: random()
canvas:
Color:
hsv: self.hue, .5, .3
Rectangle:
size: self.size
Label:
font_size: 42
text: root.name
Button:
text: 'Next screen'
size_hint: None, None
pos_hint: {'right': 1}
size: 150, 50
on_release: root.manager.current = root.manager.next()
Button:
text: 'Previous screen'
size_hint: None, None
size: 150, 50
on_release: root.manager.current = root.manager.previous()
BoxLayout:
size_hint: .5, None
height: 250
pos_hint: {'center_x': .5}
orientation: 'vertical'
Button:
text: 'Use SlideTransition with "up" direction'
on_release: root.manager.transition = \
SlideTransition(direction="up")
Button:
text: 'Use SlideTransition with "down" direction'
on_release: root.manager.transition = \
SlideTransition(direction="down")
Button:
text: 'Use SlideTransition with "left" direction'
on_release: root.manager.transition = \
SlideTransition(direction="left")
Button:
text: 'Use SlideTransition with "right" direction'
on_release: root.manager.transition = \
SlideTransition(direction="right")
Button:
text: 'Use SwapTransition'
on_release: root.manager.transition = SwapTransition()
Button:
text: 'Use WipeTransition'
on_release: root.manager.transition = WipeTransition()
Button:
text: 'Use FadeTransition'
on_release: root.manager.transition = FadeTransition()
Button:
text: 'Use FallOutTransition'
on_release: root.manager.transition = FallOutTransition()
Button:
text: 'Use RiseInTransition'
on_release: root.manager.transition = RiseInTransition()
Button:
text: 'Use NoTransition'
on_release: root.manager.transition = NoTransition(duration=0)
''')
class CustomScreen(Screen):
hue = NumericProperty(0)
class ScreenManagerApp(App):
def build(self):
root = ScreenManager()
for x in range(4):
root.add_widget(CustomScreen(name='Screen %d' % x))
return root
if __name__ == '__main__':
ScreenManagerApp().run()

View file

@ -0,0 +1,16 @@
#:kivy 1.0.4
<ScrollView>:
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
pos: self.pos
size: self.size
<GridLayout>:
canvas:
Color:
rgb: 1, 1, 0
Rectangle:
pos: self.pos
size: self.size

View file

@ -0,0 +1,40 @@
import kivy
kivy.require('1.0.8')
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
class ScrollViewApp(App):
def build(self):
# create a default grid layout with custom width/height
layout = GridLayout(cols=1, padding=10, spacing=10,
size_hint=(None, None), width=500)
# when we add children to the grid layout, its size doesn't change at
# all. we need to ensure that the height will be the minimum required
# to contain all the childs. (otherwise, we'll child outside the
# bounding box of the childs)
layout.bind(minimum_height=layout.setter('height'))
# add button into that grid
for i in range(30):
btn = Button(text=str(i), size=(480, 40),
size_hint=(None, None))
layout.add_widget(btn)
# create a scroll view, with a size < size of the grid
root = ScrollView(size_hint=(None, None), size=(500, 320),
pos_hint={'center_x': .5, 'center_y': .5}, do_scroll_x=False)
root.add_widget(layout)
return root
if __name__ == '__main__':
ScrollViewApp().run()

View file

@ -0,0 +1,3 @@
title=main
author=seesaw
orientation=portrait

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

View file

@ -0,0 +1,63 @@
#:kivy 1.0.9
<AnimatedButton>:
canvas.before:
Color:
rgb: (1, 1, 1)
BorderImage:
border: root.border if root.border else (16, 16, 16, 16)
pos: self.pos
size: self.size
texture: self.texture_background
<gifScatter>
on_size: self.center = win.Window.center
size: imag.size
size_hint: None, None
Image:
id: imag
source: 'data/images/simple_cv_joint_animated.gif'
on_touch_down: root.parent.parent.parent.currentObj = self
<zipScatter>
on_size: self.center = win.Window.center
size: imag.size
size_hint: None, None
Image:
id: imag
source: 'data/images/cube.zip'
anim_delay: 0.05
on_touch_down: root.parent.parent.parent.currentObj = self
<jpgScatter>
on_size: self.center = win.Window.center
size: imag.size
size_hint: None, None
Image:
id: imag
source: 'data/images/bird.zip'
on_touch_down: root.parent.parent.parent.currentObj = self
<Right_Frame>
size_hint: (.2, 1)
padding: 10
cols: 1
canvas:
Color:
rgba: .1,.45,.31,.9
Rectangle:
pos: self.pos
size:self.size
Label:
halign: 'center'
text_size: self.size
text: root.currentObj.source if root.currentObj else 'click on a Image to change it\'s properties'
Label:
id: spdlbl
halign: 'center'
text_size: self.size
text: 'No Image selected' if not root.currentObj else 'Animation speed: %f FPS' %(1/root.currentObj.anim_delay) if root.currentObj.anim_delay > 0 else 'Animation speed: 0 FPS'
Slider:
min:0
max: 100 if root.currentObj else 0
value: (1/root.currentObj.anim_delay) if (root.currentObj and root.currentObj.anim_delay>0) else 0
on_value: root.on_value(self, args[1], spdlbl)

View file

@ -0,0 +1,150 @@
import kivy
kivy.require('1.0.8')
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from uix.custom_button import AnimatedButton
from kivy.uix.scatter import Scatter
from kivy.properties import ObjectProperty
class gifScatter(Scatter):
def __init__(self, **kwargs):
super(gifScatter, self).__init__()
class zipScatter(Scatter):
def __init__(self, **kwargs):
super(zipScatter, self).__init__()
class jpgScatter(Scatter):
def __init__(self, **kwargs):
super(jpgScatter, self).__init__()
class Right_Frame(GridLayout):
currentObj = ObjectProperty(None)
def __init__(self, **kwargs):
super(Right_Frame, self).__init__()
def on_value(self, *l):
if self.currentObj:
if abs(l[1]) <= 0:
self.currentObj.anim_delay = -1
l[2].text = 'Animation speed: %f FPS' % 0
else:
self.currentObj.anim_delay = 1 / l[1]
l[2].text = 'Animation speed: %f FPS' % (
1 / self.currentObj.anim_delay)
else:
l[0].max = 0
l[2].text = 'No Image selected'
class mainclass(FloatLayout):
currentObj = ObjectProperty(None)
def __init__(self, **kwargs):
super(mainclass, self).__init__()
# initialize variables
self.sign = .10
# setup Layouts
layout = GridLayout(size_hint=(1, 1), cols=3, rows=1)
left_frame = GridLayout(size_hint=(.25, 1), cols=1)
client_frame = FloatLayout(size_hint=(1, 1))
self.right_frame = Right_Frame()
# setup buttons in left frame
but_load_gif = AnimatedButton(text='load gif', halign='center')
but_load_zip_png = AnimatedButton(text='load zipped\n png/s',
halign='center')
but_load_zip_jpg = AnimatedButton(text='load zipped\n jpg/s',
halign='center')
but_animated = AnimatedButton(text='animated button\n'
'made using\nSequenced Images\n press to animate',
halign='center',
background_normal='data/images/button_white.png',
background_down='data/images/button_white_animated.zip')
but_animated_normal = AnimatedButton(text='borderless\n'
'animated button\npress to stop',
halign='center',
background_down='data/images/button_white.png',
background_normal='data/images/button_white_animated.zip')
but_animated_borderless = AnimatedButton(text='Borderless',
background_normal='data/images/info.png',
background_down='data/images/info.zip', halign='center')
but_animated_bordered = AnimatedButton(text='With Border',
background_normal='data/images/info.png',
background_down='data/images/info.zip', halign='center')
# Handle button press/release
def load_images(*l):
if l[0].text == 'load gif' or l[0].text == 'load gif\n from cache':
l[0].text = 'load gif\n from cache'
sctr = gifScatter()
if (l[0].text == 'load zipped\n png/s' or
l[0].text == 'load zipped\n png/s from cache'):
l[0].text = 'load zipped\n png/s from cache'
sctr = zipScatter()
if (l[0].text == 'load zipped\n jpg/s' or
l[0].text == 'load zipped\n jpg/s from cache'):
l[0].text = 'load zipped\n jpg/s from cache'
sctr = jpgScatter()
client_frame.add_widget(sctr, 1)
# position scatter
sctr.pos = (240 + self.sign, 200 + self.sign)
self.sign += 10
if self.sign > 200:
self.sign = 10
sctr.pos = (300, 200 - self.sign)
# bind function on on_release
but_load_gif.bind(on_release=load_images)
but_load_zip_png.bind(on_release=load_images)
but_load_zip_jpg.bind(on_release=load_images)
# add widgets to left frame
left_frame.add_widget(but_load_gif)
left_frame.add_widget(but_load_zip_png)
left_frame.add_widget(but_load_zip_jpg)
left_frame.add_widget(but_animated)
left_frame.add_widget(but_animated_normal)
left_frame.add_widget(but_animated_borderless)
left_frame.add_widget(but_animated_bordered)
# set/remove border for borderless widgets (16,16,16,16) by default
but_animated_normal.border = \
but_animated_borderless.border = (0, 0, 0, 0)
# add widgets to the main layout
layout.add_widget(left_frame)
layout.add_widget(client_frame)
layout.add_widget(self.right_frame)
# add main layout to root
self.add_widget(layout)
def on_currentObj(self, *l):
self.right_frame.currentObj = self.currentObj
class mainApp(App):
def build(self):
upl = mainclass()
upl.size_hint = (1, 1)
upl.pos_hint = {'top': 0, 'right': 1}
return upl
if __name__ == '__main__':
mainApp().run()

View file

@ -0,0 +1,7 @@
'''
UIX
===
The `uix` contains all the class for creating and arranging Custom Widgets.
A widget is an element of a graphical user interface.
'''

Some files were not shown because too many files have changed in this diff Show more