first commit
This commit is contained in:
commit
417e54da96
5696 changed files with 900003 additions and 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
17
kivy_venv/share/kivy-examples/widgets/accordion_1.py
Normal file
17
kivy_venv/share/kivy-examples/widgets/accordion_1.py
Normal 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()
|
32
kivy_venv/share/kivy-examples/widgets/actionbar.py
Normal file
32
kivy_venv/share/kivy-examples/widgets/actionbar.py
Normal 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'
|
||||
'''))
|
35
kivy_venv/share/kivy-examples/widgets/asyncimage.py
Normal file
35
kivy_venv/share/kivy-examples/widgets/asyncimage.py
Normal 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()
|
54
kivy_venv/share/kivy-examples/widgets/boxlayout_poshint.py
Normal file
54
kivy_venv/share/kivy-examples/widgets/boxlayout_poshint.py
Normal 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()
|
63
kivy_venv/share/kivy-examples/widgets/bubble_test.py
Normal file
63
kivy_venv/share/kivy-examples/widgets/bubble_test.py
Normal 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()
|
33
kivy_venv/share/kivy-examples/widgets/camera.py
Normal file
33
kivy_venv/share/kivy-examples/widgets/camera.py
Normal 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()
|
50
kivy_venv/share/kivy-examples/widgets/carousel_buttons.py
Normal file
50
kivy_venv/share/kivy-examples/widgets/carousel_buttons.py
Normal 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()
|
BIN
kivy_venv/share/kivy-examples/widgets/cityCC0.mpg
Normal file
BIN
kivy_venv/share/kivy-examples/widgets/cityCC0.mpg
Normal file
Binary file not shown.
BIN
kivy_venv/share/kivy-examples/widgets/cityCC0.png
Normal file
BIN
kivy_venv/share/kivy-examples/widgets/cityCC0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 690 KiB |
225
kivy_venv/share/kivy-examples/widgets/codeinput.py
Normal file
225
kivy_venv/share/kivy-examples/widgets/codeinput.py
Normal 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()
|
53
kivy_venv/share/kivy-examples/widgets/codeinputtest.kv
Normal file
53
kivy_venv/share/kivy-examples/widgets/codeinputtest.kv
Normal 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)
|
234
kivy_venv/share/kivy-examples/widgets/colorpicker.py
Normal file
234
kivy_venv/share/kivy-examples/widgets/colorpicker.py
Normal 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()
|
62
kivy_venv/share/kivy-examples/widgets/colorusage.py
Normal file
62
kivy_venv/share/kivy-examples/widgets/colorusage.py
Normal 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()
|
83
kivy_venv/share/kivy-examples/widgets/compound_selection.py
Normal file
83
kivy_venv/share/kivy-examples/widgets/compound_selection.py
Normal 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)
|
82
kivy_venv/share/kivy-examples/widgets/customcollide.py
Normal file
82
kivy_venv/share/kivy-examples/widgets/customcollide.py
Normal 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)))
|
193
kivy_venv/share/kivy-examples/widgets/effectwidget.py
Normal file
193
kivy_venv/share/kivy-examples/widgets/effectwidget.py
Normal 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()
|
47
kivy_venv/share/kivy-examples/widgets/effectwidget2.py
Normal file
47
kivy_venv/share/kivy-examples/widgets/effectwidget2.py
Normal 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)
|
|
@ -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)
|
111
kivy_venv/share/kivy-examples/widgets/fbowidget.py
Normal file
111
kivy_venv/share/kivy-examples/widgets/fbowidget.py
Normal 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()
|
98
kivy_venv/share/kivy-examples/widgets/focus_behavior.py
Normal file
98
kivy_venv/share/kivy-examples/widgets/focus_behavior.py
Normal 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()
|
31
kivy_venv/share/kivy-examples/widgets/image_mipmap.py
Normal file
31
kivy_venv/share/kivy-examples/widgets/image_mipmap.py
Normal 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()
|
42
kivy_venv/share/kivy-examples/widgets/keyboardlistener.py
Normal file
42
kivy_venv/share/kivy-examples/widgets/keyboardlistener.py
Normal 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())
|
28
kivy_venv/share/kivy-examples/widgets/label_mipmap.py
Normal file
28
kivy_venv/share/kivy-examples/widgets/label_mipmap.py
Normal 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()
|
193
kivy_venv/share/kivy-examples/widgets/label_sizing.py
Normal file
193
kivy_venv/share/kivy-examples/widgets/label_sizing.py
Normal 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()
|
49
kivy_venv/share/kivy-examples/widgets/label_text_size.py
Normal file
49
kivy_venv/share/kivy-examples/widgets/label_text_size.py
Normal 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()
|
21
kivy_venv/share/kivy-examples/widgets/label_with_markup.py
Normal file
21
kivy_venv/share/kivy-examples/widgets/label_with_markup.py
Normal 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()
|
|
@ -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)
|
64
kivy_venv/share/kivy-examples/widgets/pagelayout.py
Normal file
64
kivy_venv/share/kivy-examples/widgets/pagelayout.py
Normal 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))
|
35
kivy_venv/share/kivy-examples/widgets/popup_with_kv.py
Normal file
35
kivy_venv/share/kivy-examples/widgets/popup_with_kv.py
Normal 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()
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
124
kivy_venv/share/kivy-examples/widgets/recycleview/basic_data.py
Normal file
124
kivy_venv/share/kivy-examples/widgets/recycleview/basic_data.py
Normal 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()
|
|
@ -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()
|
|
@ -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()
|
196
kivy_venv/share/kivy-examples/widgets/recycleview/messenger.py
Normal file
196
kivy_venv/share/kivy-examples/widgets/recycleview/messenger.py
Normal 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()
|
|
@ -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()
|
|
@ -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()
|
128
kivy_venv/share/kivy-examples/widgets/rstexample.py
Normal file
128
kivy_venv/share/kivy-examples/widgets/rstexample.py
Normal 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: &bl; Hello world &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()
|
53
kivy_venv/share/kivy-examples/widgets/scatter.kv
Normal file
53
kivy_venv/share/kivy-examples/widgets/scatter.kv
Normal 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)
|
16
kivy_venv/share/kivy-examples/widgets/scatter.py
Normal file
16
kivy_venv/share/kivy-examples/widgets/scatter.py
Normal 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()
|
106
kivy_venv/share/kivy-examples/widgets/screenmanager.py
Normal file
106
kivy_venv/share/kivy-examples/widgets/screenmanager.py
Normal 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()
|
16
kivy_venv/share/kivy-examples/widgets/scrollview.kv
Normal file
16
kivy_venv/share/kivy-examples/widgets/scrollview.kv
Normal 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
|
40
kivy_venv/share/kivy-examples/widgets/scrollview.py
Normal file
40
kivy_venv/share/kivy-examples/widgets/scrollview.py
Normal 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()
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
title=main
|
||||
author=seesaw
|
||||
orientation=portrait
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 305 KiB |
|
@ -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)
|
150
kivy_venv/share/kivy-examples/widgets/sequenced_images/main.py
Normal file
150
kivy_venv/share/kivy-examples/widgets/sequenced_images/main.py
Normal 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()
|
|
@ -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.
|
||||
'''
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue